Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull more input updates from Dmitry Torokhov:
 "A second round of updates for the input subsystem:

   - a new driver for PWM-controlled vibrators

   - ucb1400 touchscreen driver had completely busted suspend/resume
     handling

   - we now handle "home" button found on some devices with Goodix
     touchscreens

   - assorted other fixups"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: i8042 - add Gigabyte P57 to the keyboard reset table
  Input: xpad - validate USB endpoint type during probe
  Input: ucb1400_ts - fix suspend and resume handling
  Input: edt-ft5x06 - fix access to non-existing register
  Input: elantech - make arrays debounce_packet static, reduces object code size
  Input: surface3_spi - make const array header static, reduces object code size
  Input: goodix - add support for capacitive home button
  Input: add a driver for PWM controllable vibrators
  Input: adi - make array seq static, reduces object code size
This commit is contained in:
Linus Torvalds
2017-09-16 11:24:26 -07:00
12 changed files with 380 additions and 11 deletions

View File

@@ -313,7 +313,7 @@ static void adi_close(struct input_dev *dev)
static void adi_init_digital(struct gameport *gameport)
{
int seq[] = { 4, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
static const int seq[] = { 4, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
int i;
for (i = 0; seq[i]; i++) {

View File

@@ -1764,10 +1764,12 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
struct usb_endpoint_descriptor *ep =
&intf->cur_altsetting->endpoint[i].desc;
if (usb_endpoint_dir_in(ep))
ep_irq_in = ep;
else
ep_irq_out = ep;
if (usb_endpoint_xfer_int(ep)) {
if (usb_endpoint_dir_in(ep))
ep_irq_in = ep;
else
ep_irq_out = ep;
}
}
if (!ep_irq_in || !ep_irq_out) {

View File

@@ -581,6 +581,18 @@ config INPUT_PWM_BEEPER
To compile this driver as a module, choose M here: the module will be
called pwm-beeper.
config INPUT_PWM_VIBRA
tristate "PWM vibrator support"
depends on PWM
select INPUT_FF_MEMLESS
help
Say Y here to get support for PWM based vibrator devices.
If unsure, say N.
To compile this driver as a module, choose M here: the module will be
called pwm-vibra.
config INPUT_RK805_PWRKEY
tristate "Rockchip RK805 PMIC power key support"
depends on MFD_RK808

View File

@@ -59,6 +59,7 @@ obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
obj-$(CONFIG_INPUT_PWM_VIBRA) += pwm-vibra.o
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o
obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o

View File

@@ -0,0 +1,267 @@
/*
* PWM vibrator driver
*
* Copyright (C) 2017 Collabora Ltd.
*
* Based on previous work from:
* Copyright (C) 2012 Dmitry Torokhov <dmitry.torokhov@gmail.com>
*
* Based on PWM beeper driver:
* Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/pwm.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
struct pwm_vibrator {
struct input_dev *input;
struct pwm_device *pwm;
struct pwm_device *pwm_dir;
struct regulator *vcc;
struct work_struct play_work;
u16 level;
u32 direction_duty_cycle;
};
static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
{
struct device *pdev = vibrator->input->dev.parent;
struct pwm_state state;
int err;
err = regulator_enable(vibrator->vcc);
if (err) {
dev_err(pdev, "failed to enable regulator: %d", err);
return err;
}
pwm_get_state(vibrator->pwm, &state);
pwm_set_relative_duty_cycle(&state, vibrator->level, 0xffff);
state.enabled = true;
err = pwm_apply_state(vibrator->pwm, &state);
if (err) {
dev_err(pdev, "failed to apply pwm state: %d", err);
return err;
}
if (vibrator->pwm_dir) {
pwm_get_state(vibrator->pwm_dir, &state);
state.duty_cycle = vibrator->direction_duty_cycle;
state.enabled = true;
err = pwm_apply_state(vibrator->pwm_dir, &state);
if (err) {
dev_err(pdev, "failed to apply dir-pwm state: %d", err);
pwm_disable(vibrator->pwm);
return err;
}
}
return 0;
}
static void pwm_vibrator_stop(struct pwm_vibrator *vibrator)
{
regulator_disable(vibrator->vcc);
if (vibrator->pwm_dir)
pwm_disable(vibrator->pwm_dir);
pwm_disable(vibrator->pwm);
}
static void pwm_vibrator_play_work(struct work_struct *work)
{
struct pwm_vibrator *vibrator = container_of(work,
struct pwm_vibrator, play_work);
if (vibrator->level)
pwm_vibrator_start(vibrator);
else
pwm_vibrator_stop(vibrator);
}
static int pwm_vibrator_play_effect(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
struct pwm_vibrator *vibrator = input_get_drvdata(dev);
vibrator->level = effect->u.rumble.strong_magnitude;
if (!vibrator->level)
vibrator->level = effect->u.rumble.weak_magnitude;
schedule_work(&vibrator->play_work);
return 0;
}
static void pwm_vibrator_close(struct input_dev *input)
{
struct pwm_vibrator *vibrator = input_get_drvdata(input);
cancel_work_sync(&vibrator->play_work);
pwm_vibrator_stop(vibrator);
}
static int pwm_vibrator_probe(struct platform_device *pdev)
{
struct pwm_vibrator *vibrator;
struct pwm_state state;
int err;
vibrator = devm_kzalloc(&pdev->dev, sizeof(*vibrator), GFP_KERNEL);
if (!vibrator)
return -ENOMEM;
vibrator->input = devm_input_allocate_device(&pdev->dev);
if (!vibrator->input)
return -ENOMEM;
vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc");
err = PTR_ERR_OR_ZERO(vibrator->vcc);
if (err) {
if (err != -EPROBE_DEFER)
dev_err(&pdev->dev, "Failed to request regulator: %d",
err);
return err;
}
vibrator->pwm = devm_pwm_get(&pdev->dev, "enable");
err = PTR_ERR_OR_ZERO(vibrator->pwm);
if (err) {
if (err != -EPROBE_DEFER)
dev_err(&pdev->dev, "Failed to request main pwm: %d",
err);
return err;
}
INIT_WORK(&vibrator->play_work, pwm_vibrator_play_work);
/* Sync up PWM state and ensure it is off. */
pwm_init_state(vibrator->pwm, &state);
state.enabled = false;
err = pwm_apply_state(vibrator->pwm, &state);
if (err) {
dev_err(&pdev->dev, "failed to apply initial PWM state: %d",
err);
return err;
}
vibrator->pwm_dir = devm_pwm_get(&pdev->dev, "direction");
err = PTR_ERR_OR_ZERO(vibrator->pwm_dir);
switch (err) {
case 0:
/* Sync up PWM state and ensure it is off. */
pwm_init_state(vibrator->pwm_dir, &state);
state.enabled = false;
err = pwm_apply_state(vibrator->pwm_dir, &state);
if (err) {
dev_err(&pdev->dev, "failed to apply initial PWM state: %d",
err);
return err;
}
vibrator->direction_duty_cycle =
pwm_get_period(vibrator->pwm_dir) / 2;
device_property_read_u32(&pdev->dev, "direction-duty-cycle-ns",
&vibrator->direction_duty_cycle);
break;
case -ENODATA:
/* Direction PWM is optional */
vibrator->pwm_dir = NULL;
break;
default:
dev_err(&pdev->dev, "Failed to request direction pwm: %d", err);
/* Fall through */
case -EPROBE_DEFER:
return err;
}
vibrator->input->name = "pwm-vibrator";
vibrator->input->id.bustype = BUS_HOST;
vibrator->input->dev.parent = &pdev->dev;
vibrator->input->close = pwm_vibrator_close;
input_set_drvdata(vibrator->input, vibrator);
input_set_capability(vibrator->input, EV_FF, FF_RUMBLE);
err = input_ff_create_memless(vibrator->input, NULL,
pwm_vibrator_play_effect);
if (err) {
dev_err(&pdev->dev, "Couldn't create FF dev: %d", err);
return err;
}
err = input_register_device(vibrator->input);
if (err) {
dev_err(&pdev->dev, "Couldn't register input dev: %d", err);
return err;
}
platform_set_drvdata(pdev, vibrator);
return 0;
}
static int __maybe_unused pwm_vibrator_suspend(struct device *dev)
{
struct pwm_vibrator *vibrator = dev_get_drvdata(dev);
cancel_work_sync(&vibrator->play_work);
if (vibrator->level)
pwm_vibrator_stop(vibrator);
return 0;
}
static int __maybe_unused pwm_vibrator_resume(struct device *dev)
{
struct pwm_vibrator *vibrator = dev_get_drvdata(dev);
if (vibrator->level)
pwm_vibrator_start(vibrator);
return 0;
}
static SIMPLE_DEV_PM_OPS(pwm_vibrator_pm_ops,
pwm_vibrator_suspend, pwm_vibrator_resume);
#ifdef CONFIG_OF
static const struct of_device_id pwm_vibra_dt_match_table[] = {
{ .compatible = "pwm-vibrator" },
{},
};
MODULE_DEVICE_TABLE(of, pwm_vibra_dt_match_table);
#endif
static struct platform_driver pwm_vibrator_driver = {
.probe = pwm_vibrator_probe,
.driver = {
.name = "pwm-vibrator",
.pm = &pwm_vibrator_pm_ops,
.of_match_table = of_match_ptr(pwm_vibra_dt_match_table),
},
};
module_platform_driver(pwm_vibrator_driver);
MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
MODULE_DESCRIPTION("PWM vibrator driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pwm-vibrator");

View File

@@ -700,7 +700,9 @@ static int elantech_debounce_check_v2(struct psmouse *psmouse)
* When we encounter packet that matches this exactly, it means the
* hardware is in debounce status. Just ignore the whole packet.
*/
const u8 debounce_packet[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff };
static const u8 debounce_packet[] = {
0x84, 0xff, 0xff, 0x02, 0xff, 0xff
};
unsigned char *packet = psmouse->packet;
return !memcmp(packet, debounce_packet, sizeof(debounce_packet));
@@ -741,7 +743,9 @@ static int elantech_packet_check_v2(struct psmouse *psmouse)
static int elantech_packet_check_v3(struct psmouse *psmouse)
{
struct elantech_data *etd = psmouse->private;
const u8 debounce_packet[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff };
static const u8 debounce_packet[] = {
0xc4, 0xff, 0xff, 0x02, 0xff, 0xff
};
unsigned char *packet = psmouse->packet;
/*

View File

@@ -839,6 +839,13 @@ static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "P34"),
},
},
{
/* Gigabyte P57 - Elantech touchpad */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
DMI_MATCH(DMI_PRODUCT_NAME, "P57"),
},
},
{
/* Schenker XMG C504 - Elantech touchpad */
.matches = {

View File

@@ -593,7 +593,7 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
tsdata->gain);
edt_ft5x06_register_write(tsdata, reg_addr->reg_offset,
tsdata->offset);
if (reg_addr->reg_report_rate)
if (reg_addr->reg_report_rate != NO_REGISTER)
edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate,
tsdata->report_rate);
@@ -874,6 +874,7 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
case M09:
reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
reg_addr->reg_report_rate = NO_REGISTER;
reg_addr->reg_gain = M09_REGISTER_GAIN;
reg_addr->reg_offset = M09_REGISTER_OFFSET;
reg_addr->reg_num_x = M09_REGISTER_NUM_X;

View File

@@ -267,6 +267,12 @@ static void goodix_process_events(struct goodix_ts_data *ts)
if (touch_num < 0)
return;
/*
* Bit 4 of the first byte reports the status of the capacitive
* Windows/Home button.
*/
input_report_key(ts->input_dev, KEY_LEFTMETA, point_data[0] & BIT(4));
for (i = 0; i < touch_num; i++)
goodix_ts_report_touch(ts,
&point_data[1 + GOODIX_CONTACT_SIZE * i]);
@@ -612,6 +618,9 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts)
ts->input_dev->id.product = ts->id;
ts->input_dev->id.version = ts->version;
/* Capacitive Windows/Home button on some devices */
input_set_capability(ts->input_dev, EV_KEY, KEY_LEFTMETA);
error = input_register_device(ts->input_dev);
if (error) {
dev_err(&ts->client->dev,

View File

@@ -173,7 +173,7 @@ static void surface3_spi_process_pen(struct surface3_ts_data *ts_data, u8 *data)
static void surface3_spi_process(struct surface3_ts_data *ts_data)
{
const char header[] = {
static const char header[] = {
0xff, 0xff, 0xff, 0xff, 0xa5, 0x5a, 0xe7, 0x7e, 0x01
};
u8 *data = ts_data->rd_buf;

View File

@@ -414,7 +414,7 @@ static int __maybe_unused ucb1400_ts_suspend(struct device *dev)
mutex_lock(&idev->mutex);
if (idev->users)
ucb1400_ts_start(ucb);
ucb1400_ts_stop(ucb);
mutex_unlock(&idev->mutex);
return 0;
@@ -428,7 +428,7 @@ static int __maybe_unused ucb1400_ts_resume(struct device *dev)
mutex_lock(&idev->mutex);
if (idev->users)
ucb1400_ts_stop(ucb);
ucb1400_ts_start(ucb);
mutex_unlock(&idev->mutex);
return 0;