From cdab490e50e7ce4533b95ca24c90bee3ed1a8e99 Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Sun, 8 Nov 2020 18:29:55 -0800 Subject: dt-bindings: input: ektf2127: Add elan,ektf2132 compatible string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The eKTF2132 is a touchscreen controller found, for example, in the Kobo Aura ebook reader. It is similar to the ektf2127, but it uses a different packet type to report touch events. Signed-off-by: Jonathan Neuschäfer Link: https://lore.kernel.org/r/20201106112412.390724-2-j.neuschaefer@gmx.net Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt b/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt index 94c4fc644940..5eef5e7d6aae 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt @@ -1,7 +1,7 @@ * Elan eKTF2127 I2C touchscreen controller Required properties: - - compatible : "elan,ektf2127" + - compatible : "elan,ektf2127" or "elan,ektf2132" - reg : I2C slave address of the chip (0x40) - interrupts : interrupt specification for the ektf2127 interrupt - power-gpios : GPIO specification for the pin connected to the -- cgit v1.2.3 From af5689fb5c1c0b5ad8d6bfd79ea7d018b4c16f1d Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Sun, 8 Nov 2020 18:30:08 -0800 Subject: Input: ektf2127 - add support for eKTF2132 touchscreen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The eKTF2132 is a touchscreen controller found, for example, in the Kobo Aura ebook reader. It is similar to the ektf2127, but it uses a different packet type to report touch events. Signed-off-by: Jonathan Neuschäfer Link: https://lore.kernel.org/r/20201106112412.390724-3-j.neuschaefer@gmx.net Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ektf2127.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c index eadd389cf81f..491de67ddbcd 100644 --- a/drivers/input/touchscreen/ektf2127.c +++ b/drivers/input/touchscreen/ektf2127.c @@ -28,6 +28,7 @@ #define EKTF2127_RESPONSE 0x52 #define EKTF2127_REQUEST 0x53 #define EKTF2127_HELLO 0x55 +#define EKTF2127_REPORT2 0x5a #define EKTF2127_REPORT 0x5d #define EKTF2127_CALIB_DONE 0x66 @@ -95,6 +96,29 @@ static void ektf2127_report_event(struct ektf2127_ts *ts, const u8 *buf) input_sync(ts->input); } +static void ektf2127_report2_contact(struct ektf2127_ts *ts, int slot, + const u8 *buf, bool active) +{ + input_mt_slot(ts->input, slot); + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, active); + + if (active) { + int x = (buf[0] & 0xf0) << 4 | buf[1]; + int y = (buf[0] & 0x0f) << 8 | buf[2]; + + touchscreen_report_pos(ts->input, &ts->prop, x, y, true); + } +} + +static void ektf2127_report2_event(struct ektf2127_ts *ts, const u8 *buf) +{ + ektf2127_report2_contact(ts, 0, &buf[1], !!(buf[7] & 2)); + ektf2127_report2_contact(ts, 1, &buf[4], !!(buf[7] & 4)); + + input_mt_sync_frame(ts->input); + input_sync(ts->input); +} + static irqreturn_t ektf2127_irq(int irq, void *dev_id) { struct ektf2127_ts *ts = dev_id; @@ -113,6 +137,10 @@ static irqreturn_t ektf2127_irq(int irq, void *dev_id) ektf2127_report_event(ts, buf); break; + case EKTF2127_REPORT2: + ektf2127_report2_event(ts, buf); + break; + case EKTF2127_NOISE: if (buf[1] == EKTF2127_ENV_NOISY) dev_dbg(dev, "Environment is electrically noisy\n"); @@ -305,6 +333,7 @@ static int ektf2127_probe(struct i2c_client *client, #ifdef CONFIG_OF static const struct of_device_id ektf2127_of_match[] = { { .compatible = "elan,ektf2127" }, + { .compatible = "elan,ektf2132" }, {} }; MODULE_DEVICE_TABLE(of, ektf2127_of_match); @@ -312,6 +341,7 @@ MODULE_DEVICE_TABLE(of, ektf2127_of_match); static const struct i2c_device_id ektf2127_i2c_id[] = { { "ektf2127", 0 }, + { "ektf2132", 0 }, {} }; MODULE_DEVICE_TABLE(i2c, ektf2127_i2c_id); @@ -327,6 +357,6 @@ static struct i2c_driver ektf2127_driver = { }; module_i2c_driver(ektf2127_driver); -MODULE_DESCRIPTION("ELAN eKTF2127 I2C Touchscreen Driver"); +MODULE_DESCRIPTION("ELAN eKTF2127/eKTF2132 I2C Touchscreen Driver"); MODULE_AUTHOR("Michel Verlaan, Siebren Vroegindeweij"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 3fe781f4fab2cfad993807e2f14fa26dec6b9172 Mon Sep 17 00:00:00 2001 From: Wang Qing Date: Sun, 8 Nov 2020 21:50:55 -0800 Subject: Input: ads7846 - use kobj_to_dev() API Use kobj_to_dev() instead of container_of(). Signed-off-by: Wang Qing Link: https://lore.kernel.org/r/1604893436-20206-1-git-send-email-wangqing@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 8fd7fc39c4fd..ee74da2ad7b8 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -481,7 +481,7 @@ SHOW(in1_input, vbatt, vbatt_adjust) static umode_t ads7846_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct ads7846 *ts = dev_get_drvdata(dev); if (ts->model == 7843 && index < 2) /* in0, in1 */ -- cgit v1.2.3 From 463a74c2d34db531269849c1a7d4c2089f210ea8 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Sun, 8 Nov 2020 22:09:26 -0800 Subject: Input: drv260x - fix kernel-doc formatting and remove one abuse Fixes the following W=1 kernel build warning(s): drivers/input/misc/drv260x.c:194: warning: Function parameter or member 'input_dev' not described in 'drv260x_data' drivers/input/misc/drv260x.c:194: warning: Function parameter or member 'client' not described in 'drv260x_data' drivers/input/misc/drv260x.c:194: warning: Function parameter or member 'regmap' not described in 'drv260x_data' drivers/input/misc/drv260x.c:194: warning: Function parameter or member 'work' not described in 'drv260x_data' drivers/input/misc/drv260x.c:194: warning: Function parameter or member 'enable_gpio' not described in 'drv260x_data' drivers/input/misc/drv260x.c:194: warning: Function parameter or member 'regulator' not described in 'drv260x_data' drivers/input/misc/drv260x.c:194: warning: Function parameter or member 'magnitude' not described in 'drv260x_data' drivers/input/misc/drv260x.c:194: warning: Function parameter or member 'mode' not described in 'drv260x_data' drivers/input/misc/drv260x.c:194: warning: Function parameter or member 'library' not described in 'drv260x_data' drivers/input/misc/drv260x.c:194: warning: Function parameter or member 'rated_voltage' not described in 'drv260x_data' drivers/input/misc/drv260x.c:194: warning: Function parameter or member 'overdrive_voltage' not described in 'drv260x_data' drivers/input/misc/drv260x.c:244: warning: Function parameter or member 'voltage' not described in 'drv260x_calculate_voltage' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201104162427.2984742-17-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/drv260x.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index 79d7fa710a71..cc51de7759a0 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -167,17 +167,17 @@ /** * struct drv260x_data - - * @input_dev - Pointer to the input device - * @client - Pointer to the I2C client - * @regmap - Register map of the device - * @work - Work item used to off load the enable/disable of the vibration - * @enable_gpio - Pointer to the gpio used for enable/disabling - * @regulator - Pointer to the regulator for the IC - * @magnitude - Magnitude of the vibration event - * @mode - The operating mode of the IC (LRA_NO_CAL, ERM or LRA) - * @library - The vibration library to be used - * @rated_voltage - The rated_voltage of the actuator - * @overdriver_voltage - The over drive voltage of the actuator + * @input_dev: Pointer to the input device + * @client: Pointer to the I2C client + * @regmap: Register map of the device + * @work: Work item used to off load the enable/disable of the vibration + * @enable_gpio: Pointer to the gpio used for enable/disabling + * @regulator: Pointer to the regulator for the IC + * @magnitude: Magnitude of the vibration event + * @mode: The operating mode of the IC (LRA_NO_CAL, ERM or LRA) + * @library: The vibration library to be used + * @rated_voltage: The rated_voltage of the actuator + * @overdrive_voltage: The over drive voltage of the actuator **/ struct drv260x_data { struct input_dev *input_dev; @@ -234,12 +234,12 @@ static const struct reg_default drv260x_reg_defs[] = { #define DRV260X_DEF_RATED_VOLT 0x90 #define DRV260X_DEF_OD_CLAMP_VOLT 0x90 -/** +/* * Rated and Overdriver Voltages: * Calculated using the formula r = v * 255 / 5.6 * where r is what will be written to the register * and v is the rated or overdriver voltage of the actuator - **/ + */ static int drv260x_calculate_voltage(unsigned int voltage) { return (voltage * 255 / 5600); -- cgit v1.2.3 From 6e9c6fcbff24b756eb757bb702dbd7f74790d67f Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Sun, 8 Nov 2020 22:09:47 -0800 Subject: Input: drv2665 - fix formatting expected by kernel-doc Fixes the following W=1 kernel build warning(s): drivers/input/misc/drv2665.c:59: warning: Function parameter or member 'input_dev' not described in 'drv2665_data' drivers/input/misc/drv2665.c:59: warning: Function parameter or member 'client' not described in 'drv2665_data' drivers/input/misc/drv2665.c:59: warning: Function parameter or member 'regmap' not described in 'drv2665_data' drivers/input/misc/drv2665.c:59: warning: Function parameter or member 'work' not described in 'drv2665_data' drivers/input/misc/drv2665.c:59: warning: Function parameter or member 'regulator' not described in 'drv2665_data' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201104162427.2984742-18-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/drv2665.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index 918ad9c3fa81..0e65ab180f49 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -44,11 +44,11 @@ /** * struct drv2665_data - - * @input_dev - Pointer to the input device - * @client - Pointer to the I2C client - * @regmap - Register map of the device - * @work - Work item used to off load the enable/disable of the vibration - * @regulator - Pointer to the regulator for the IC + * @input_dev: Pointer to the input device + * @client: Pointer to the I2C client + * @regmap: Register map of the device + * @work: Work item used to off load the enable/disable of the vibration + * @regulator: Pointer to the regulator for the IC */ struct drv2665_data { struct input_dev *input_dev; -- cgit v1.2.3 From 176271110d74e70e0c56d076ff7575dd1b2ee672 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Sun, 8 Nov 2020 22:09:58 -0800 Subject: Input: drv2667 - fix formatting and add missing member docs Fixes the following W=1 kernel build warning(s): drivers/input/misc/drv2667.c:109: warning: Function parameter or member 'input_dev' not described in 'drv2667_data' drivers/input/misc/drv2667.c:109: warning: Function parameter or member 'client' not described in 'drv2667_data' drivers/input/misc/drv2667.c:109: warning: Function parameter or member 'regmap' not described in 'drv2667_data' drivers/input/misc/drv2667.c:109: warning: Function parameter or member 'work' not described in 'drv2667_data' drivers/input/misc/drv2667.c:109: warning: Function parameter or member 'regulator' not described in 'drv2667_data' drivers/input/misc/drv2667.c:109: warning: Function parameter or member 'page' not described in 'drv2667_data' drivers/input/misc/drv2667.c:109: warning: Function parameter or member 'magnitude' not described in 'drv2667_data' drivers/input/misc/drv2667.c:109: warning: Function parameter or member 'frequency' not described in 'drv2667_data' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201104162427.2984742-19-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/drv2667.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index bb9d5784df17..dc19eb6a8713 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -90,12 +90,14 @@ /** * struct drv2667_data - - * @input_dev - Pointer to the input device - * @client - Pointer to the I2C client - * @regmap - Register map of the device - * @work - Work item used to off load the enable/disable of the vibration - * @regulator - Pointer to the regulator for the IC - * @magnitude - Magnitude of the vibration event + * @input_dev: Pointer to the input device + * @client: Pointer to the I2C client + * @regmap: Register map of the device + * @work: Work item used to off load the enable/disable of the vibration + * @regulator: Pointer to the regulator for the IC + * @page: Page number + * @magnitude: Magnitude of the vibration event + * @frequency: Frequency of the vibration event **/ struct drv2667_data { struct input_dev *input_dev; -- cgit v1.2.3 From 5b27585a8524cbb1c720502d3014a5fb85951ab9 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Sun, 8 Nov 2020 22:17:31 -0800 Subject: Input: nomadik-ske-keypad - provide some missing struct member docs Fixes the following W=1 kernel build warning(s): drivers/input/keyboard/nomadik-ske-keypad.c:71: warning: Function parameter or member 'pclk' not described in 'ske_keypad' drivers/input/keyboard/nomadik-ske-keypad.c:71: warning: Function parameter or member 'ske_keypad_lock' not described in 'ske_keypad' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201104162427.2984742-20-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/nomadik-ske-keypad.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index 608446e14614..0d55a95347f1 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -58,6 +58,8 @@ * @board: keypad platform device * @keymap: matrix scan code table for keycodes * @clk: clock structure pointer + * @pclk: clock structure pointer + * @ske_keypad_lock: spinlock protecting the keypad read/writes */ struct ske_keypad { int irq; -- cgit v1.2.3 From 55be5087a8ab1f8a6bc225b507c924e43199774e Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Sun, 8 Nov 2020 22:19:07 -0800 Subject: Input: pmic8xxx-keypad - fix kernel-doc formatting Fixes the following W=1 kernel build warning(s): drivers/input/keyboard/pmic8xxx-keypad.c:106: warning: Function parameter or member 'num_rows' not described in 'pmic8xxx_kp' drivers/input/keyboard/pmic8xxx-keypad.c:106: warning: Function parameter or member 'num_cols' not described in 'pmic8xxx_kp' drivers/input/keyboard/pmic8xxx-keypad.c:106: warning: Function parameter or member 'input' not described in 'pmic8xxx_kp' drivers/input/keyboard/pmic8xxx-keypad.c:106: warning: Function parameter or member 'regmap' not described in 'pmic8xxx_kp' drivers/input/keyboard/pmic8xxx-keypad.c:106: warning: Function parameter or member 'key_sense_irq' not described in 'pmic8xxx_kp' drivers/input/keyboard/pmic8xxx-keypad.c:106: warning: Function parameter or member 'key_stuck_irq' not described in 'pmic8xxx_kp' drivers/input/keyboard/pmic8xxx-keypad.c:106: warning: Function parameter or member 'keycodes' not described in 'pmic8xxx_kp' drivers/input/keyboard/pmic8xxx-keypad.c:106: warning: Function parameter or member 'dev' not described in 'pmic8xxx_kp' drivers/input/keyboard/pmic8xxx-keypad.c:106: warning: Function parameter or member 'keystate' not described in 'pmic8xxx_kp' drivers/input/keyboard/pmic8xxx-keypad.c:106: warning: Function parameter or member 'stuckstate' not described in 'pmic8xxx_kp' drivers/input/keyboard/pmic8xxx-keypad.c:106: warning: Function parameter or member 'ctrl_reg' not described in 'pmic8xxx_kp' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201104162427.2984742-21-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/pmic8xxx-keypad.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index 91d5811d6f0e..36bee6f5a8af 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -76,17 +76,17 @@ /** * struct pmic8xxx_kp - internal keypad data structure - * @num_cols - number of columns of keypad - * @num_rows - number of row of keypad - * @input - input device pointer for keypad - * @regmap - regmap handle - * @key_sense_irq - key press/release irq number - * @key_stuck_irq - key stuck notification irq number - * @keycodes - array to hold the key codes - * @dev - parent device pointer - * @keystate - present key press/release state - * @stuckstate - present state when key stuck irq - * @ctrl_reg - control register value + * @num_cols: number of columns of keypad + * @num_rows: number of row of keypad + * @input: input device pointer for keypad + * @regmap: regmap handle + * @key_sense_irq: key press/release irq number + * @key_stuck_irq: key stuck notification irq number + * @keycodes: array to hold the key codes + * @dev: parent device pointer + * @keystate: present key press/release state + * @stuckstate: present state when key stuck irq + * @ctrl_reg: control register value */ struct pmic8xxx_kp { unsigned int num_rows; -- cgit v1.2.3 From 93107bc736f4eb1d57a26c56eda9bb89b86d1ef0 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Sun, 8 Nov 2020 22:09:03 -0800 Subject: Input: elantech - demote obvious abuse of kernel-doc header Fixes the following W=1 kernel build warning(s): drivers/input/mouse/elantech.c:1837: warning: Function parameter or member 'psmouse' not described in 'elantech_setup_smbus' drivers/input/mouse/elantech.c:1837: warning: Function parameter or member 'info' not described in 'elantech_setup_smbus' drivers/input/mouse/elantech.c:1837: warning: Function parameter or member 'leave_breadcrumbs' not described in 'elantech_setup_smbus' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201104162427.2984742-13-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 90f8765f9efc..47cd0e7f79bd 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1827,7 +1827,7 @@ static int elantech_create_smbus(struct psmouse *psmouse, leave_breadcrumbs); } -/** +/* * elantech_setup_smbus - called once the PS/2 devices are enumerated * and decides to instantiate a SMBus InterTouch device. */ -- cgit v1.2.3 From 2216c0e414c6596b03a354b5c08ba98af4cbef85 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Sun, 8 Nov 2020 22:08:01 -0800 Subject: Input: gpio_keys - fix misnamed function parameter 'dev' Fixes the following W=1 kernel build warning(s): drivers/input/keyboard/gpio_keys.c:119: warning: Function parameter or member 'dev' not described in 'get_bm_events_by_type' drivers/input/keyboard/gpio_keys.c:119: warning: Excess function parameter 'input' description in 'get_bm_events_by_type' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201104162427.2984742-12-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index f2d4e4daa818..a079504e98e8 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -108,7 +108,7 @@ static int get_n_events_by_type(int type) /** * get_bm_events_by_type() - returns bitmap of supported events per @type - * @input: input device from which bitmap is retrieved + * @dev: input device from which bitmap is retrieved * @type: type of button (%EV_KEY, %EV_SW) * * Return value of this function can be used to allocate bitmap -- cgit v1.2.3 From e0d80b647c12d5deb163365005742739745960cf Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 4 Nov 2020 14:51:52 -0800 Subject: Input: cros_ec_keyb - struct headers should start with 'struct ' Fixes the following W=1 kernel build warning(s): drivers/input/keyboard/cros_ec_keyb.c:72: warning: cannot understand function prototype: 'struct cros_ec_bs_map ' Signed-off-by: Lee Jones Reviewed-by: Benson Leung Link: https://lore.kernel.org/r/20201104162427.2984742-8-lee.jones@linaro.org [dtor: fixed up docbook comments for cros_ec_keyb structure as well] Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/cros_ec_keyb.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index fc1793ca2f17..023f083dadd3 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -27,7 +27,9 @@ #include -/* +/** + * struct cros_ec_keyb - Structure representing EC keyboard device + * * @rows: Number of rows in the keypad * @cols: Number of columns in the keypad * @row_shift: log2 or number of rows, rounded up @@ -58,10 +60,9 @@ struct cros_ec_keyb { struct notifier_block notifier; }; - /** - * cros_ec_bs_map - Struct mapping Linux keycodes to EC button/switch bitmap - * #defines + * struct cros_ec_bs_map - Mapping between Linux keycodes and EC button/switch + * bitmap #defines * * @ev_type: The type of the input event to generate (e.g., EV_KEY). * @code: A linux keycode -- cgit v1.2.3 From d8c58078e8aad8378fc4d0d112ed19c34ad9fca9 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 4 Nov 2020 11:12:31 -0800 Subject: Input: ab8500-ponkey - fix incorrect name in 'ab8500_ponkey' doc header Fixes the following W=1 kernel build warning(s): drivers/input/misc/ab8500-ponkey.c:32: warning: Function parameter or member 'idev' not described in 'ab8500_ponkey' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201104162427.2984742-5-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/ab8500-ponkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c index ea3b8292acdd..a9b9013680d6 100644 --- a/drivers/input/misc/ab8500-ponkey.c +++ b/drivers/input/misc/ab8500-ponkey.c @@ -19,7 +19,7 @@ /** * struct ab8500_ponkey - ab8500 ponkey information - * @input_dev: pointer to input device + * @idev: pointer to input device * @ab8500: ab8500 parent * @irq_dbf: irq number for falling transition * @irq_dbr: irq number for rising transition -- cgit v1.2.3 From 6cffd88c2f7d4b552a0bc3ba31af3c113de4d0b5 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 4 Nov 2020 11:12:06 -0800 Subject: Input: cyapa - fix misnaming of 'cyapa_i2c_write's 'reg' param Fixes the following W=1 kernel build warning(s): drivers/input/mouse/cyapa.c:130: warning: Function parameter or member 'reg' not described in 'cyapa_i2c_write' drivers/input/mouse/cyapa.c:130: warning: Excess function parameter 'ret' description in 'cyapa_i2c_write' Signed-off-by: Lee Jones Reviewed-by: Benson Leung Link: https://lore.kernel.org/r/20201104162427.2984742-3-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index c675f156948b..dacf7c0e43f9 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -119,7 +119,7 @@ static ssize_t cyapa_i2c_read(struct cyapa *cyapa, u8 reg, size_t len, /** * cyapa_i2c_write - Execute i2c block data write operation * @cyapa: Handle to this driver - * @ret: Offset of the data to written in the register map + * @reg: Offset of the data to written in the register map * @len: number of bytes to write * @values: Data to be written * -- cgit v1.2.3 From a1b5196d988afdcded74e01bc47fb11c80b366cf Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 4 Nov 2020 11:12:15 -0800 Subject: Input: cyapa_gen5 - fix obvious abuse of kernel-doc format Fixes the following W=1 kernel build warning(s): drivers/input/mouse/cyapa_gen5.c:392: warning: Function parameter or member 'cyapa' not described in 'cyapa_i2c_pip_write' drivers/input/mouse/cyapa_gen5.c:392: warning: Function parameter or member 'buf' not described in 'cyapa_i2c_pip_write' drivers/input/mouse/cyapa_gen5.c:392: warning: Function parameter or member 'size' not described in 'cyapa_i2c_pip_write' drivers/input/mouse/cyapa_gen5.c:444: warning: Function parameter or member 'cyapa' not described in 'cyapa_empty_pip_output_data' drivers/input/mouse/cyapa_gen5.c:444: warning: Function parameter or member 'buf' not described in 'cyapa_empty_pip_output_data' drivers/input/mouse/cyapa_gen5.c:444: warning: Function parameter or member 'len' not described in 'cyapa_empty_pip_output_data' drivers/input/mouse/cyapa_gen5.c:444: warning: Function parameter or member 'func' not described in 'cyapa_empty_pip_output_data' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201104162427.2984742-4-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa_gen5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index bb3a63d1268d..5c37af994b5b 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -385,7 +385,7 @@ ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size) return size; } -/** +/* * Return a negative errno code else zero on success. */ ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size) @@ -435,7 +435,7 @@ static enum cyapa_pm_stage cyapa_get_pip_pm_state(struct cyapa *cyapa) return pm_stage; } -/** +/* * This function is aimed to dump all not read data in Gen5 trackpad * before send any command, otherwise, the interrupt line will be blocked. */ -- cgit v1.2.3 From 29c2e1249cfaed365a6fcfa5a3e6a2e590f54879 Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Wed, 28 Oct 2020 12:21:47 -0700 Subject: Input: analog - fix formatting of error code The location of the minus sign and the error code are linked together for better human view. Signed-off-by: Zhang Qilong Link: https://lore.kernel.org/r/20201027135020.66632-1-zhangqilong3@huawei.com Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/analog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 2b625ebef914..f798922a4598 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -665,7 +665,7 @@ static int analog_connect(struct gameport *gameport, struct gameport_driver *drv int err; if (!(port = kzalloc(sizeof(struct analog_port), GFP_KERNEL))) - return - ENOMEM; + return -ENOMEM; err = analog_init_port(gameport, drv, port); if (err) -- cgit v1.2.3 From 136feb4cf3b3ea9ea07d210805911a60e85a2d0d Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Sun, 8 Nov 2020 22:32:32 -0800 Subject: Input: resistive-adc-touch - struct headers should start with 'struct ' Fixes the following W=1 kernel build warning(s): drivers/input/touchscreen/resistive-adc-touch.c:34: warning: cannot understand function prototype: 'struct grts_state ' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201104162427.2984742-10-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/resistive-adc-touch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c index cfc8bb4553f7..e50af30183f4 100644 --- a/drivers/input/touchscreen/resistive-adc-touch.c +++ b/drivers/input/touchscreen/resistive-adc-touch.c @@ -23,7 +23,7 @@ #define GRTS_MAX_POS_MASK GENMASK(11, 0) /** - * grts_state - generic resistive touch screen information struct + * struct grts_state - generic resistive touch screen information struct * @pressure_min: number representing the minimum for the pressure * @pressure: are we getting pressure info or not * @iio_chans: list of channels acquired -- cgit v1.2.3 From 45353186575d97a4cd35a429c0e4ec195376f4ed Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Sun, 8 Nov 2020 22:34:17 -0800 Subject: Input: cyttsp4 - move 'cyttsp4_tch_abs_string' to the only file that references it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): In file included from drivers/input/touchscreen/cyttsp_i2c_common.c:24: drivers/input/touchscreen/cyttsp4_core.h:236:27: warning: ‘cyttsp4_tch_abs_string’ defined but not used [-Wunused-const-variable=] 236 | static const char const cyttsp4_tch_abs_string[] = { | ^~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/input/touchscreen/cyttsp4_i2c.c:17: drivers/input/touchscreen/cyttsp4_core.h:236:27: warning: ‘cyttsp4_tch_abs_string’ defined but not used [-Wunused-const-variable=] 236 | static const char * const cyttsp4_tch_abs_string[] = { | ^~~~~~~~~~~~~~~~~~~~~~ In file included from drivers/input/touchscreen/cyttsp4_spi.c:17: drivers/input/touchscreen/cyttsp4_core.h:236:27: warning: ‘cyttsp4_tch_abs_string’ defined but not used [-Wunused-const-variable=] 236 | static const char * const cyttsp4_tch_abs_string[] = { | ^~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201104162427.2984742-16-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/cyttsp4_core.c | 14 ++++++++++++++ drivers/input/touchscreen/cyttsp4_core.h | 14 -------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c index 02a73d9a4def..dccbcb942fe5 100644 --- a/drivers/input/touchscreen/cyttsp4_core.c +++ b/drivers/input/touchscreen/cyttsp4_core.c @@ -30,6 +30,20 @@ #define CY_CORE_STARTUP_RETRY_COUNT 3 +static const char * const cyttsp4_tch_abs_string[] = { + [CY_TCH_X] = "X", + [CY_TCH_Y] = "Y", + [CY_TCH_P] = "P", + [CY_TCH_T] = "T", + [CY_TCH_E] = "E", + [CY_TCH_O] = "O", + [CY_TCH_W] = "W", + [CY_TCH_MAJ] = "MAJ", + [CY_TCH_MIN] = "MIN", + [CY_TCH_OR] = "OR", + [CY_TCH_NUM_ABS] = "INVALID" +}; + static const u8 ldr_exit[] = { 0xFF, 0x01, 0x3B, 0x00, 0x00, 0x4F, 0x6D, 0x17 }; diff --git a/drivers/input/touchscreen/cyttsp4_core.h b/drivers/input/touchscreen/cyttsp4_core.h index f3e444359440..6262f6e45075 100644 --- a/drivers/input/touchscreen/cyttsp4_core.h +++ b/drivers/input/touchscreen/cyttsp4_core.h @@ -233,20 +233,6 @@ enum cyttsp4_tch_abs { /* for ordering within the extracted touch data array */ CY_TCH_NUM_ABS }; -static const char * const cyttsp4_tch_abs_string[] = { - [CY_TCH_X] = "X", - [CY_TCH_Y] = "Y", - [CY_TCH_P] = "P", - [CY_TCH_T] = "T", - [CY_TCH_E] = "E", - [CY_TCH_O] = "O", - [CY_TCH_W] = "W", - [CY_TCH_MAJ] = "MAJ", - [CY_TCH_MIN] = "MIN", - [CY_TCH_OR] = "OR", - [CY_TCH_NUM_ABS] = "INVALID" -}; - struct cyttsp4_touch { int abs[CY_TCH_NUM_ABS]; }; -- cgit v1.2.3 From 7e90989141613e68ad8fceae63c1623954c96519 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 4 Nov 2020 11:11:56 -0800 Subject: Input: synaptics-rmi4 - fix kerneldoc warnings Fixes the kerneldoc warnings from building the driver with W=1. Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201104162427.2984742-2-lee.jones@linaro.org [dtor: folded together several Lee's patches; added more descriptions] Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_bus.c | 2 +- drivers/input/rmi4/rmi_f01.c | 16 +-- drivers/input/rmi4/rmi_f11.c | 236 +++++++++++++++++++++++-------------------- drivers/input/rmi4/rmi_f54.c | 6 ++ drivers/input/rmi4/rmi_i2c.c | 4 + 5 files changed, 149 insertions(+), 115 deletions(-) diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index 47d1b97ed6cf..24f31a5c0e04 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -286,7 +286,7 @@ void rmi_unregister_function(struct rmi_function *fn) /** * rmi_register_function_handler - register a handler for an RMI function * @handler: RMI handler that should be registered. - * @module: pointer to module that implements the handler + * @owner: pointer to module that implements the handler * @mod_name: name of the module implementing the handler * * This function performs additional setup of RMI function handler and diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c index e623c956376e..d7603c50f864 100644 --- a/drivers/input/rmi4/rmi_f01.c +++ b/drivers/input/rmi4/rmi_f01.c @@ -103,13 +103,15 @@ struct f01_basic_properties { #define RMI_F01_CTRL0_CONFIGURED_BIT BIT(7) /** - * @ctrl0 - see the bit definitions above. - * @doze_interval - controls the interval between checks for finger presence - * when the touch sensor is in doze mode, in units of 10ms. - * @wakeup_threshold - controls the capacitance threshold at which the touch - * sensor will decide to wake up from that low power state. - * @doze_holdoff - controls how long the touch sensor waits after the last - * finger lifts before entering the doze state, in units of 100ms. + * struct f01_device_control - controls basic sensor functions + * + * @ctrl0: see the bit definitions above. + * @doze_interval: controls the interval between checks for finger presence + * when the touch sensor is in doze mode, in units of 10ms. + * @wakeup_threshold: controls the capacitance threshold at which the touch + * sensor will decide to wake up from that low power state. + * @doze_holdoff: controls how long the touch sensor waits after the last + * finger lifts before entering the doze state, in units of 100ms. */ struct f01_device_control { u8 ctrl0; diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c index ffa39ab153f2..49ca9168685a 100644 --- a/drivers/input/rmi4/rmi_f11.c +++ b/drivers/input/rmi4/rmi_f11.c @@ -30,12 +30,12 @@ #define DEFAULT_MIN_ABS_MT_TRACKING_ID 1 #define DEFAULT_MAX_ABS_MT_TRACKING_ID 10 -/** A note about RMI4 F11 register structure. +/* + * A note about RMI4 F11 register structure. * - * The properties for - * a given sensor are described by its query registers. The number of query - * registers and the layout of their contents are described by the F11 device - * queries as well as the sensor query information. + * The properties for a given sensor are described by its query registers. The + * number of query registers and the layout of their contents are described by + * the F11 device queries as well as the sensor query information. * * Similarly, each sensor has control registers that govern its behavior. The * size and layout of the control registers for a given sensor can be determined @@ -62,8 +62,8 @@ /* maximum ABS_MT_POSITION displacement (in mm) */ #define DMAX 10 -/** - * @rezero - writing this to the F11 command register will cause the sensor to +/* + * Writing this to the F11 command register will cause the sensor to * calibrate to the current capacitive state. */ #define RMI_F11_REZERO 0x01 @@ -178,135 +178,157 @@ #define F11_UNIFORM_CLICKPAD 0x02 /** + * struct f11_2d_sensor_queries - describes sensor capabilities + * * Query registers 1 through 4 are always present. * - * @nr_fingers - describes the maximum number of fingers the 2-D sensor - * supports. - * @has_rel - the sensor supports relative motion reporting. - * @has_abs - the sensor supports absolute poition reporting. - * @has_gestures - the sensor supports gesture reporting. - * @has_sensitivity_adjust - the sensor supports a global sensitivity - * adjustment. - * @configurable - the sensor supports various configuration options. - * @num_of_x_electrodes - the maximum number of electrodes the 2-D sensor - * supports on the X axis. - * @num_of_y_electrodes - the maximum number of electrodes the 2-D sensor - * supports on the Y axis. - * @max_electrodes - the total number of X and Y electrodes that may be - * configured. + * @nr_fingers: describes the maximum number of fingers the 2-D sensor + * supports. + * @has_rel: the sensor supports relative motion reporting. + * @has_abs: the sensor supports absolute poition reporting. + * @has_gestures: the sensor supports gesture reporting. + * @has_sensitivity_adjust: the sensor supports a global sensitivity + * adjustment. + * @configurable: the sensor supports various configuration options. + * @nr_x_electrodes: the maximum number of electrodes the 2-D sensor + * supports on the X axis. + * @nr_y_electrodes: the maximum number of electrodes the 2-D sensor + * supports on the Y axis. + * @max_electrodes: the total number of X and Y electrodes that may be + * configured. * * Query 5 is present if the has_abs bit is set. * - * @abs_data_size - describes the format of data reported by the absolute - * data source. Only one format (the kind used here) is supported at this - * time. - * @has_anchored_finger - then the sensor supports the high-precision second - * finger tracking provided by the manual tracking and motion sensitivity - * options. - * @has_adjust_hyst - the difference between the finger release threshold and - * the touch threshold. - * @has_dribble - the sensor supports the generation of dribble interrupts, - * which may be enabled or disabled with the dribble control bit. - * @has_bending_correction - Bending related data registers 28 and 36, and - * control register 52..57 are present. - * @has_large_object_suppression - control register 58 and data register 28 - * exist. - * @has_jitter_filter - query 13 and control 73..76 exist. + * @abs_data_size: describes the format of data reported by the absolute + * data source. Only one format (the kind used here) is supported at this + * time. + * @has_anchored_finger: then the sensor supports the high-precision second + * finger tracking provided by the manual tracking and motion sensitivity + * options. + * @has_adj_hyst: the difference between the finger release threshold and + * the touch threshold. + * @has_dribble: the sensor supports the generation of dribble interrupts, + * which may be enabled or disabled with the dribble control bit. + * @has_bending_correction: Bending related data registers 28 and 36, and + * control register 52..57 are present. + * @has_large_object_suppression: control register 58 and data register 28 + * exist. + * @has_jitter_filter: query 13 and control 73..76 exist. + * + * Query 6 is present if the has_rel it is set. + * + * @f11_2d_query6: this register is reserved. * * Gesture information queries 7 and 8 are present if has_gestures bit is set. * - * @has_single_tap - a basic single-tap gesture is supported. - * @has_tap_n_hold - tap-and-hold gesture is supported. - * @has_double_tap - double-tap gesture is supported. - * @has_early_tap - early tap is supported and reported as soon as the finger - * lifts for any tap event that could be interpreted as either a single tap - * or as the first tap of a double-tap or tap-and-hold gesture. - * @has_flick - flick detection is supported. - * @has_press - press gesture reporting is supported. - * @has_pinch - pinch gesture detection is supported. - * @has_palm_det - the 2-D sensor notifies the host whenever a large conductive - * object such as a palm or a cheek touches the 2-D sensor. - * @has_rotate - rotation gesture detection is supported. - * @has_touch_shapes - TouchShapes are supported. A TouchShape is a fixed - * rectangular area on the sensor that behaves like a capacitive button. - * @has_scroll_zones - scrolling areas near the sensor edges are supported. - * @has_individual_scroll_zones - if 1, then 4 scroll zones are supported; - * if 0, then only two are supported. - * @has_mf_scroll - the multifinger_scrolling bit will be set when - * more than one finger is involved in a scrolling action. + * @has_single_tap: a basic single-tap gesture is supported. + * @has_tap_n_hold: tap-and-hold gesture is supported. + * @has_double_tap: double-tap gesture is supported. + * @has_early_tap: early tap is supported and reported as soon as the finger + * lifts for any tap event that could be interpreted as either a single + * tap or as the first tap of a double-tap or tap-and-hold gesture. + * @has_flick: flick detection is supported. + * @has_press: press gesture reporting is supported. + * @has_pinch: pinch gesture detection is supported. + * @has_chiral: chiral (circular) scrolling gesture detection is supported. + * @has_palm_det: the 2-D sensor notifies the host whenever a large conductive + * object such as a palm or a cheek touches the 2-D sensor. + * @has_rotate: rotation gesture detection is supported. + * @has_touch_shapes: TouchShapes are supported. A TouchShape is a fixed + * rectangular area on the sensor that behaves like a capacitive button. + * @has_scroll_zones: scrolling areas near the sensor edges are supported. + * @has_individual_scroll_zones: if 1, then 4 scroll zones are supported; + * if 0, then only two are supported. + * @has_mf_scroll: the multifinger_scrolling bit will be set when + * more than one finger is involved in a scrolling action. + * @has_mf_edge_motion: indicates whether multi-finger edge motion gesture + * is supported. + * @has_mf_scroll_inertia: indicates whether multi-finger scroll inertia + * feature is supported. * * Convenience for checking bytes in the gesture info registers. This is done * often enough that we put it here to declutter the conditionals * - * @query7_nonzero - true if none of the query 7 bits are set - * @query8_nonzero - true if none of the query 8 bits are set + * @query7_nonzero: true if none of the query 7 bits are set + * @query8_nonzero: true if none of the query 8 bits are set * * Query 9 is present if the has_query9 is set. * - * @has_pen - detection of a stylus is supported and registers F11_2D_Ctrl20 - * and F11_2D_Ctrl21 exist. - * @has_proximity - detection of fingers near the sensor is supported and - * registers F11_2D_Ctrl22 through F11_2D_Ctrl26 exist. - * @has_palm_det_sensitivity - the sensor supports the palm detect sensitivity - * feature and register F11_2D_Ctrl27 exists. - * @has_two_pen_thresholds - is has_pen is also set, then F11_2D_Ctrl35 exists. - * @has_contact_geometry - the sensor supports the use of contact geometry to - * map absolute X and Y target positions and registers F11_2D_Data18 - * through F11_2D_Data27 exist. + * @has_pen: detection of a stylus is supported and registers F11_2D_Ctrl20 + * and F11_2D_Ctrl21 exist. + * @has_proximity: detection of fingers near the sensor is supported and + * registers F11_2D_Ctrl22 through F11_2D_Ctrl26 exist. + * @has_palm_det_sensitivity: the sensor supports the palm detect sensitivity + * feature and register F11_2D_Ctrl27 exists. + * @has_suppress_on_palm_detect: the device supports the large object detect + * suppression feature and register F11_2D_Ctrl27 exists. + * @has_two_pen_thresholds: if has_pen is also set, then F11_2D_Ctrl35 exists. + * @has_contact_geometry: the sensor supports the use of contact geometry to + * map absolute X and Y target positions and registers F11_2D_Data18 + * through F11_2D_Data27 exist. + * @has_pen_hover_discrimination: if has_pen is also set, then registers + * F11_2D_Data29 through F11_2D_Data31, F11_2D_Ctrl68.*, F11_2D_Ctrl69 + * and F11_2D_Ctrl72 exist. + * @has_pen_filters: if has_pen is also set, then registers F11_2D_Ctrl70 and + * F11_2D_Ctrl71 exist. * * Touch shape info (query 10) is present if has_touch_shapes is set. * - * @nr_touch_shapes - the total number of touch shapes supported. + * @nr_touch_shapes: the total number of touch shapes supported. * * Query 11 is present if the has_query11 bit is set in query 0. * - * @has_z_tuning - if set, the sensor supports Z tuning and registers - * F11_2D_Ctrl29 through F11_2D_Ctrl33 exist. - * @has_algorithm_selection - controls choice of noise suppression algorithm - * @has_w_tuning - the sensor supports Wx and Wy scaling and registers - * F11_2D_Ctrl36 through F11_2D_Ctrl39 exist. - * @has_pitch_info - the X and Y pitches of the sensor electrodes can be - * configured and registers F11_2D_Ctrl40 and F11_2D_Ctrl41 exist. - * @has_finger_size - the default finger width settings for the - * sensor can be configured and registers F11_2D_Ctrl42 through F11_2D_Ctrl44 - * exist. - * @has_segmentation_aggressiveness - the sensor’s ability to distinguish - * multiple objects close together can be configured and register F11_2D_Ctrl45 - * exists. - * @has_XY_clip - the inactive outside borders of the sensor can be - * configured and registers F11_2D_Ctrl46 through F11_2D_Ctrl49 exist. - * @has_drumming_filter - the sensor can be configured to distinguish - * between a fast flick and a quick drumming movement and registers - * F11_2D_Ctrl50 and F11_2D_Ctrl51 exist. + * @has_z_tuning: if set, the sensor supports Z tuning and registers + * F11_2D_Ctrl29 through F11_2D_Ctrl33 exist. + * @has_algorithm_selection: controls choice of noise suppression algorithm + * @has_w_tuning: the sensor supports Wx and Wy scaling and registers + * F11_2D_Ctrl36 through F11_2D_Ctrl39 exist. + * @has_pitch_info: the X and Y pitches of the sensor electrodes can be + * configured and registers F11_2D_Ctrl40 and F11_2D_Ctrl41 exist. + * @has_finger_size: the default finger width settings for the sensor + * can be configured and registers F11_2D_Ctrl42 through F11_2D_Ctrl44 + * exist. + * @has_segmentation_aggressiveness: the sensor’s ability to distinguish + * multiple objects close together can be configured and register + * F11_2D_Ctrl45 exists. + * @has_XY_clip: the inactive outside borders of the sensor can be + * configured and registers F11_2D_Ctrl46 through F11_2D_Ctrl49 exist. + * @has_drumming_filter: the sensor can be configured to distinguish + * between a fast flick and a quick drumming movement and registers + * F11_2D_Ctrl50 and F11_2D_Ctrl51 exist. * * Query 12 is present if hasQuery12 bit is set. * - * @has_gapless_finger - control registers relating to gapless finger are - * present. - * @has_gapless_finger_tuning - additional control and data registers relating - * to gapless finger are present. - * @has_8bit_w - larger W value reporting is supported. - * @has_adjustable_mapping - TBD - * @has_info2 - the general info query14 is present - * @has_physical_props - additional queries describing the physical properties - * of the sensor are present. - * @has_finger_limit - indicates that F11 Ctrl 80 exists. - * @has_linear_coeff - indicates that F11 Ctrl 81 exists. + * @has_gapless_finger: control registers relating to gapless finger are + * present. + * @has_gapless_finger_tuning: additional control and data registers relating + * to gapless finger are present. + * @has_8bit_w: larger W value reporting is supported. + * @has_adjustable_mapping: TBD + * @has_info2: the general info query14 is present + * @has_physical_props: additional queries describing the physical properties + * of the sensor are present. + * @has_finger_limit: indicates that F11 Ctrl 80 exists. + * @has_linear_coeff_2: indicates that F11 Ctrl 81 exists. * * Query 13 is present if Query 5's has_jitter_filter bit is set. - * @jitter_window_size - used by Design Studio 4. - * @jitter_filter_type - used by Design Studio 4. + * + * @jitter_window_size: used by Design Studio 4. + * @jitter_filter_type: used by Design Studio 4. * * Query 14 is present if query 12's has_general_info2 flag is set. * - * @light_control - Indicates what light/led control features are present, if - * any. - * @is_clear - if set, this is a clear sensor (indicating direct pointing - * application), otherwise it's opaque (indicating indirect pointing). - * @clickpad_props - specifies if this is a clickpad, and if so what sort of - * mechanism it uses - * @mouse_buttons - specifies the number of mouse buttons present (if any). - * @has_advanced_gestures - advanced driver gestures are supported. + * @light_control: Indicates what light/led control features are present, + * if any. + * @is_clear: if set, this is a clear sensor (indicating direct pointing + * application), otherwise it's opaque (indicating indirect pointing). + * @clickpad_props: specifies if this is a clickpad, and if so what sort of + * mechanism it uses + * @mouse_buttons: specifies the number of mouse buttons present (if any). + * @has_advanced_gestures: advanced driver gestures are supported. + * + * @x_sensor_size_mm: size of the sensor in millimeters on the X axis. + * @y_sensor_size_mm: size of the sensor in millimeters on the Y axis. */ struct f11_2d_sensor_queries { /* query1 */ diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c index 6b23e679606e..93b328c796c6 100644 --- a/drivers/input/rmi4/rmi_f54.c +++ b/drivers/input/rmi4/rmi_f54.c @@ -42,6 +42,8 @@ /** * enum rmi_f54_report_type - RMI4 F54 report types * + * @F54_REPORT_NONE: No Image Report. + * * @F54_8BIT_IMAGE: Normalized 8-Bit Image Report. The capacitance variance * from baseline for each pixel. * @@ -64,6 +66,10 @@ * Report. Set Low reference to its minimum value and high * references to its maximum value, then report the raw * capacitance for each pixel. + * + * @F54_MAX_REPORT_TYPE: + * Maximum number of Report Types. Used for sanity + * checking. */ enum rmi_f54_report_type { F54_REPORT_NONE = 0, diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c index a95c2c9bcab4..50305fcfbef5 100644 --- a/drivers/input/rmi4/rmi_i2c.c +++ b/drivers/input/rmi4/rmi_i2c.c @@ -17,12 +17,16 @@ * struct rmi_i2c_xport - stores information for i2c communication * * @xport: The transport interface structure + * @client: The I2C client device structure * * @page_mutex: Locks current page to avoid changing pages in unexpected ways. * @page: Keeps track of the current virtual page * * @tx_buf: Buffer used for transmitting data to the sensor over i2c. * @tx_buf_size: Size of the buffer + * + * @supplies: Array of voltage regulators + * @startup_delay: Milliseconds to pause after powering up the regulators */ struct rmi_i2c_xport { struct rmi_transport_dev xport; -- cgit v1.2.3 From 3a54a215410b1650798dc09d051806b1f900142d Mon Sep 17 00:00:00 2001 From: Andrej Valek Date: Wed, 11 Nov 2020 17:52:50 -0800 Subject: Input: st1232 - add support resolution reading Hard-coding resolution for st1633 device was wrong. Some of LCDs like YTS700TLBC-02-100C has assembled Sitronix st1633 touchcontroller too. But the resolution is not 320x480 as was hard-coded. Add new function which reads correct resolution directly from register. Signed-off-by: Andrej Valek Link: https://lore.kernel.org/r/20201103073949.12198-1-andrej.valek@siemens.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/st1232.c | 52 ++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 63b29c7279e2..bda96762744e 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -26,15 +26,14 @@ #define ST1232_TS_NAME "st1232-ts" #define ST1633_TS_NAME "st1633-ts" +#define REG_XY_RESOLUTION 0x04 +#define REG_XY_COORDINATES 0x12 #define ST_TS_MAX_FINGERS 10 struct st_chip_info { bool have_z; - u16 max_x; - u16 max_y; u16 max_area; u16 max_fingers; - u8 start_reg; }; struct st1232_ts_data { @@ -48,15 +47,14 @@ struct st1232_ts_data { u8 *read_buf; }; -static int st1232_ts_read_data(struct st1232_ts_data *ts) +static int st1232_ts_read_data(struct st1232_ts_data *ts, u8 reg) { struct i2c_client *client = ts->client; - u8 start_reg = ts->chip_info->start_reg; struct i2c_msg msg[] = { { .addr = client->addr, - .len = sizeof(start_reg), - .buf = &start_reg, + .len = sizeof(reg), + .buf = ®, }, { .addr = client->addr, @@ -74,6 +72,25 @@ static int st1232_ts_read_data(struct st1232_ts_data *ts) return 0; } +static int st1232_ts_read_resolution(struct st1232_ts_data *ts, u16 *max_x, + u16 *max_y) +{ + u8 *buf; + int error; + + /* select resolution register */ + error = st1232_ts_read_data(ts, REG_XY_RESOLUTION); + if (error) + return error; + + buf = ts->read_buf; + + *max_x = ((buf[0] & 0x0070) << 4) | buf[1]; + *max_y = ((buf[0] & 0x0007) << 8) | buf[2]; + + return 0; +} + static int st1232_ts_parse_and_report(struct st1232_ts_data *ts) { struct input_dev *input = ts->input_dev; @@ -123,7 +140,7 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id) int count; int error; - error = st1232_ts_read_data(ts); + error = st1232_ts_read_data(ts, REG_XY_COORDINATES); if (error) goto out; @@ -157,20 +174,14 @@ static void st1232_ts_power_off(void *data) static const struct st_chip_info st1232_chip_info = { .have_z = true, - .max_x = 0x31f, /* 800 - 1 */ - .max_y = 0x1df, /* 480 -1 */ .max_area = 0xff, .max_fingers = 2, - .start_reg = 0x12, }; static const struct st_chip_info st1633_chip_info = { .have_z = false, - .max_x = 0x13f, /* 320 - 1 */ - .max_y = 0x1df, /* 480 -1 */ .max_area = 0x00, .max_fingers = 5, - .start_reg = 0x12, }; static int st1232_ts_probe(struct i2c_client *client, @@ -179,6 +190,7 @@ static int st1232_ts_probe(struct i2c_client *client, const struct st_chip_info *match; struct st1232_ts_data *ts; struct input_dev *input_dev; + u16 max_x, max_y; int error; match = device_get_match_data(&client->dev); @@ -239,14 +251,22 @@ static int st1232_ts_probe(struct i2c_client *client, input_dev->name = "st1232-touchscreen"; input_dev->id.bustype = BUS_I2C; + /* Read resolution from the chip */ + error = st1232_ts_read_resolution(ts, &max_x, &max_y); + if (error) { + dev_err(&client->dev, + "Failed to read resolution: %d\n", error); + return error; + } + if (ts->chip_info->have_z) input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, ts->chip_info->max_area, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, - 0, ts->chip_info->max_x, 0, 0); + 0, max_x, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, - 0, ts->chip_info->max_y, 0, 0); + 0, max_y, 0, 0); touchscreen_parse_properties(input_dev, true, &ts->prop); -- cgit v1.2.3 From f1556986babffb0dd75970cd7a0563e3e1ee387a Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 12 Nov 2020 23:27:03 -0800 Subject: Input: samsung-keypad - remove set but unused variable 'var' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/input/keyboard/samsung-keypad.c: In function ‘samsung_keypad_irq’: drivers/input/keyboard/samsung-keypad.c:149:15: warning: variable ‘val’ set but not used [-Wunused-but-set-variable] Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201112110204.2083435-3-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/samsung-keypad.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 70c1d086bdd2..1ed939d9798c 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -146,13 +146,12 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id) { struct samsung_keypad *keypad = dev_id; unsigned int row_state[SAMSUNG_MAX_COLS]; - unsigned int val; bool key_down; pm_runtime_get_sync(&keypad->pdev->dev); do { - val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR); + readl(keypad->base + SAMSUNG_KEYIFSTSCLR); /* Clear interrupt. */ writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR); -- cgit v1.2.3 From cd536aa5b438351ea170d5e5f0cd75650eaab005 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 12 Nov 2020 23:34:13 -0800 Subject: Input: imx6ul_tsc - remove set but unused variable 'value' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/input/touchscreen/imx6ul_tsc.c: In function ‘adc_irq_fn’: drivers/input/touchscreen/imx6ul_tsc.c:307:6: warning: variable ‘value’ set but not used [-Wunused-but-set-variable] Signed-off-by: Lee Jones Reviewed-by: Haibo Chen Link: https://lore.kernel.org/r/20201112110204.2083435-6-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/imx6ul_tsc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index cd369f9ac5e6..e1852f7d4d31 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -304,11 +304,10 @@ static irqreturn_t adc_irq_fn(int irq, void *dev_id) { struct imx6ul_tsc *tsc = dev_id; u32 coco; - u32 value; coco = readl(tsc->adc_regs + REG_ADC_HS); if (coco & 0x01) { - value = readl(tsc->adc_regs + REG_ADC_R0); + readl(tsc->adc_regs + REG_ADC_R0); complete(&tsc->completion); } -- cgit v1.2.3 From e52cd628a03f72a547dbf90ccb703ee64800504a Mon Sep 17 00:00:00 2001 From: David Jander Date: Wed, 11 Nov 2020 11:00:59 -0800 Subject: Input: ads7846 - fix race that causes missing releases If touchscreen is released while busy reading HWMON device, the release can be missed. The IRQ thread is not started because no touch is active and BTN_TOUCH release event is never sent. Fixes: f5a28a7d4858f94a ("Input: ads7846 - avoid pen up/down when reading hwmon") Co-developed-by: Oleksij Rempel Signed-off-by: David Jander Signed-off-by: Oleksij Rempel Link: https://lore.kernel.org/r/20201027105416.18773-1-o.rempel@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 44 ++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index ee74da2ad7b8..1e3fc62d0ea8 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -199,6 +199,26 @@ struct ads7846 { #define REF_ON (READ_12BIT_DFR(x, 1, 1)) #define REF_OFF (READ_12BIT_DFR(y, 0, 0)) +static int get_pendown_state(struct ads7846 *ts) +{ + if (ts->get_pendown_state) + return ts->get_pendown_state(); + + return !gpio_get_value(ts->gpio_pendown); +} + +static void ads7846_report_pen_up(struct ads7846 *ts) +{ + struct input_dev *input = ts->input; + + input_report_key(input, BTN_TOUCH, 0); + input_report_abs(input, ABS_PRESSURE, 0); + input_sync(input); + + ts->pendown = false; + dev_vdbg(&ts->spi->dev, "UP\n"); +} + /* Must be called with ts->lock held */ static void ads7846_stop(struct ads7846 *ts) { @@ -215,6 +235,10 @@ static void ads7846_stop(struct ads7846 *ts) static void ads7846_restart(struct ads7846 *ts) { if (!ts->disabled && !ts->suspended) { + /* Check if pen was released since last stop */ + if (ts->pendown && !get_pendown_state(ts)) + ads7846_report_pen_up(ts); + /* Tell IRQ thread that it may poll the device. */ ts->stopped = false; mb(); @@ -606,14 +630,6 @@ static const struct attribute_group ads784x_attr_group = { /*--------------------------------------------------------------------------*/ -static int get_pendown_state(struct ads7846 *ts) -{ - if (ts->get_pendown_state) - return ts->get_pendown_state(); - - return !gpio_get_value(ts->gpio_pendown); -} - static void null_wait_for_sync(void) { } @@ -868,16 +884,8 @@ static irqreturn_t ads7846_irq(int irq, void *handle) msecs_to_jiffies(TS_POLL_PERIOD)); } - if (ts->pendown && !ts->stopped) { - struct input_dev *input = ts->input; - - input_report_key(input, BTN_TOUCH, 0); - input_report_abs(input, ABS_PRESSURE, 0); - input_sync(input); - - ts->pendown = false; - dev_vdbg(&ts->spi->dev, "UP\n"); - } + if (ts->pendown && !ts->stopped) + ads7846_report_pen_up(ts); return IRQ_HANDLED; } -- cgit v1.2.3 From 9c9509717b53e701469493a8d87ed42c7d782502 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 11 Nov 2020 16:39:05 -0800 Subject: Input: ads7846 - convert to full duplex Starting with 3eac5c7e44f3 ("Input: ads7846 - extend the driver for ads7845 controller support"), the ads7845 was partially converted to full duplex mode. Since it is not touchscreen controller specific, it is better to extend this conversion to cover entire driver. This will reduce CPU load and make driver more readable. Signed-off-by: Oleksij Rempel Link: https://lore.kernel.org/r/20201110085041.16303-2-o.rempel@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 192 ++++++++++++------------------------ 1 file changed, 62 insertions(+), 130 deletions(-) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 1e3fc62d0ea8..95e89f675ad5 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -62,19 +62,26 @@ /* this driver doesn't aim at the peak continuous sample rate */ #define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */) -struct ts_event { +struct ads7846_buf { + u8 cmd; /* - * For portability, we can't read 12 bit values using SPI (which - * would make the controller deliver them as native byte order u16 - * with msbs zeroed). Instead, we read them as two 8-bit values, - * *** WHICH NEED BYTESWAPPING *** and range adjustment. + * This union is a temporary hack. The driver does an in-place + * endianness conversion. This will be cleaned up in the next + * patch. */ - u16 x; - u16 y; - u16 z1, z2; - bool ignore; - u8 x_buf[3]; - u8 y_buf[3]; + union { + __be16 data_be16; + u16 data; + }; +} __packed; + + +struct ts_event { + bool ignore; + struct ads7846_buf x; + struct ads7846_buf y; + struct ads7846_buf z1; + struct ads7846_buf z2; }; /* @@ -83,11 +90,12 @@ struct ts_event { * systems where main memory is not DMA-coherent (most non-x86 boards). */ struct ads7846_packet { - u8 read_x, read_y, read_z1, read_z2, pwrdown; - u16 dummy; /* for the pwrdown read */ - struct ts_event tc; - /* for ads7845 with mpc5121 psc spi we use 3-byte buffers */ - u8 read_x_cmd[3], read_y_cmd[3], pwrdown_cmd[3]; + struct ts_event tc; + struct ads7846_buf read_x_cmd; + struct ads7846_buf read_y_cmd; + struct ads7846_buf read_z1_cmd; + struct ads7846_buf read_z2_cmd; + struct ads7846_buf pwrdown_cmd; }; struct ads7846 { @@ -686,16 +694,9 @@ static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m) int value; struct spi_transfer *t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); + struct ads7846_buf *buf = t->rx_buf; - if (ts->model == 7845) { - value = be16_to_cpup((__be16 *)&(((char *)t->rx_buf)[1])); - } else { - /* - * adjust: on-wire is a must-ignore bit, a BE12 value, then - * padding; built from two 8 bit values written msb-first. - */ - value = be16_to_cpup((__be16 *)t->rx_buf); - } + value = be16_to_cpup(&buf->data_be16); /* enforce ADC output is 12 bits width */ return (value >> 3) & 0xfff; @@ -705,8 +706,9 @@ static void ads7846_update_value(struct spi_message *m, int val) { struct spi_transfer *t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); + struct ads7846_buf *buf = t->rx_buf; - *(u16 *)t->rx_buf = val; + buf->data = val; } static void ads7846_read_state(struct ads7846 *ts) @@ -774,16 +776,14 @@ static void ads7846_report_state(struct ads7846 *ts) * from on-the-wire format as part of debouncing to get stable * readings. */ + x = packet->tc.x.data; + y = packet->tc.y.data; if (ts->model == 7845) { - x = *(u16 *)packet->tc.x_buf; - y = *(u16 *)packet->tc.y_buf; z1 = 0; z2 = 0; } else { - x = packet->tc.x; - y = packet->tc.y; - z1 = packet->tc.z1; - z2 = packet->tc.z2; + z1 = packet->tc.z1.data; + z2 = packet->tc.z2.data; } /* range filtering */ @@ -1000,26 +1000,11 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, spi_message_init(m); m->context = ts; - if (ts->model == 7845) { - packet->read_y_cmd[0] = READ_Y(vref); - packet->read_y_cmd[1] = 0; - packet->read_y_cmd[2] = 0; - x->tx_buf = &packet->read_y_cmd[0]; - x->rx_buf = &packet->tc.y_buf[0]; - x->len = 3; - spi_message_add_tail(x, m); - } else { - /* y- still on; turn on only y+ (and ADC) */ - packet->read_y = READ_Y(vref); - x->tx_buf = &packet->read_y; - x->len = 1; - spi_message_add_tail(x, m); - - x++; - x->rx_buf = &packet->tc.y; - x->len = 2; - spi_message_add_tail(x, m); - } + packet->read_y_cmd.cmd = READ_Y(vref); + x->tx_buf = &packet->read_y_cmd; + x->rx_buf = &packet->tc.y; + x->len = 3; + spi_message_add_tail(x, m); /* * The first sample after switching drivers can be low quality; @@ -1029,15 +1014,11 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, if (pdata->settle_delay_usecs) { x->delay.value = pdata->settle_delay_usecs; x->delay.unit = SPI_DELAY_UNIT_USECS; - x++; - x->tx_buf = &packet->read_y; - x->len = 1; - spi_message_add_tail(x, m); - x++; + x->tx_buf = &packet->read_y_cmd; x->rx_buf = &packet->tc.y; - x->len = 2; + x->len = 3; spi_message_add_tail(x, m); } @@ -1046,28 +1027,13 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, spi_message_init(m); m->context = ts; - if (ts->model == 7845) { - x++; - packet->read_x_cmd[0] = READ_X(vref); - packet->read_x_cmd[1] = 0; - packet->read_x_cmd[2] = 0; - x->tx_buf = &packet->read_x_cmd[0]; - x->rx_buf = &packet->tc.x_buf[0]; - x->len = 3; - spi_message_add_tail(x, m); - } else { - /* turn y- off, x+ on, then leave in lowpower */ - x++; - packet->read_x = READ_X(vref); - x->tx_buf = &packet->read_x; - x->len = 1; - spi_message_add_tail(x, m); - - x++; - x->rx_buf = &packet->tc.x; - x->len = 2; - spi_message_add_tail(x, m); - } + /* turn y- off, x+ on, then leave in lowpower */ + x++; + packet->read_x_cmd.cmd = READ_X(vref); + x->tx_buf = &packet->read_x_cmd; + x->rx_buf = &packet->tc.x; + x->len = 3; + spi_message_add_tail(x, m); /* ... maybe discard first sample ... */ if (pdata->settle_delay_usecs) { @@ -1075,13 +1041,9 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, x->delay.unit = SPI_DELAY_UNIT_USECS; x++; - x->tx_buf = &packet->read_x; - x->len = 1; - spi_message_add_tail(x, m); - - x++; + x->tx_buf = &packet->read_x_cmd; x->rx_buf = &packet->tc.x; - x->len = 2; + x->len = 3; spi_message_add_tail(x, m); } @@ -1093,14 +1055,10 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, m->context = ts; x++; - packet->read_z1 = READ_Z1(vref); - x->tx_buf = &packet->read_z1; - x->len = 1; - spi_message_add_tail(x, m); - - x++; + packet->read_z1_cmd.cmd = READ_Z1(vref); + x->tx_buf = &packet->read_z1_cmd; x->rx_buf = &packet->tc.z1; - x->len = 2; + x->len = 3; spi_message_add_tail(x, m); /* ... maybe discard first sample ... */ @@ -1109,13 +1067,9 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, x->delay.unit = SPI_DELAY_UNIT_USECS; x++; - x->tx_buf = &packet->read_z1; - x->len = 1; - spi_message_add_tail(x, m); - - x++; + x->tx_buf = &packet->read_z1_cmd; x->rx_buf = &packet->tc.z1; - x->len = 2; + x->len = 3; spi_message_add_tail(x, m); } @@ -1125,14 +1079,10 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, m->context = ts; x++; - packet->read_z2 = READ_Z2(vref); - x->tx_buf = &packet->read_z2; - x->len = 1; - spi_message_add_tail(x, m); - - x++; + packet->read_z2_cmd.cmd = READ_Z2(vref); + x->tx_buf = &packet->read_z2_cmd; x->rx_buf = &packet->tc.z2; - x->len = 2; + x->len = 3; spi_message_add_tail(x, m); /* ... maybe discard first sample ... */ @@ -1141,13 +1091,9 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, x->delay.unit = SPI_DELAY_UNIT_USECS; x++; - x->tx_buf = &packet->read_z2; - x->len = 1; - spi_message_add_tail(x, m); - - x++; + x->tx_buf = &packet->read_z2_cmd; x->rx_buf = &packet->tc.z2; - x->len = 2; + x->len = 3; spi_message_add_tail(x, m); } } @@ -1158,24 +1104,10 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, spi_message_init(m); m->context = ts; - if (ts->model == 7845) { - x++; - packet->pwrdown_cmd[0] = PWRDOWN; - packet->pwrdown_cmd[1] = 0; - packet->pwrdown_cmd[2] = 0; - x->tx_buf = &packet->pwrdown_cmd[0]; - x->len = 3; - } else { - x++; - packet->pwrdown = PWRDOWN; - x->tx_buf = &packet->pwrdown; - x->len = 1; - spi_message_add_tail(x, m); - - x++; - x->rx_buf = &packet->dummy; - x->len = 2; - } + x++; + packet->pwrdown_cmd.cmd = PWRDOWN; + x->tx_buf = &packet->pwrdown_cmd; + x->len = 3; CS_CHANGE(*x); spi_message_add_tail(x, m); -- cgit v1.2.3 From 820830ec918f6c3dcd77a54a1c6198ab57407916 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 17 Nov 2020 15:33:24 -0800 Subject: Input: ads7846 - fix integer overflow on Rt calculation In some rare cases the 32 bit Rt value will overflow if z2 and x is max, z1 is minimal value and x_plate_ohms is relatively high (for example 800 ohm). This would happen on some screen age with low pressure. There are two possible fixes: - make Rt 64bit - reorder calculation to avoid overflow The second variant seems to be preferable, since 64 bit calculation on 32 bit system is a bit more expensive. Fixes: ffa458c1bd9b6f653008d450f337602f3d52a646 ("spi: ads7846 driver") Co-developed-by: David Jander Signed-off-by: David Jander Signed-off-by: Oleksij Rempel Link: https://lore.kernel.org/r/20201113112240.1360-1-o.rempel@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 95e89f675ad5..636b901c1374 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -802,10 +802,11 @@ static void ads7846_report_state(struct ads7846 *ts) /* compute touch pressure resistance using equation #2 */ Rt = z2; Rt -= z1; - Rt *= x; Rt *= ts->x_plate_ohms; + Rt = DIV_ROUND_CLOSEST(Rt, 16); + Rt *= x; Rt /= z1; - Rt = (Rt + 2047) >> 12; + Rt = DIV_ROUND_CLOSEST(Rt, 256); } else { Rt = 0; } -- cgit v1.2.3 From 03e2c9c782f721b661a0e42b1b58f394b5298544 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 11 Nov 2020 17:17:11 -0800 Subject: Input: ads7846 - fix unaligned access on 7845 req->sample[1] is not naturally aligned at word boundary, and therefore we should use get_unaligned_be16() when accessing it. Fixes: 3eac5c7e44f3 ("Input: ads7846 - extend the driver for ads7845 controller support") Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 636b901c1374..9eed1f3e3661 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -33,6 +33,7 @@ #include #include #include +#include /* * This code has been heavily tested on a Nokia 770, and lightly @@ -443,7 +444,7 @@ static int ads7845_read12_ser(struct device *dev, unsigned command) if (status == 0) { /* BE12 value, then padding */ - status = be16_to_cpu(*((u16 *)&req->sample[1])); + status = get_unaligned_be16(&req->sample[1]); status = status >> 3; status &= 0x0fff; } -- cgit v1.2.3 From 23fd34a56ce11e1e90444c55a96fddc8398bbfa8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 11 Nov 2020 17:34:49 -0800 Subject: Input: ads7846 - drop unneeded asm/irq.h include This is essentially a revert of: 3ac8bf077d0f ("[PATCH] ads7846: sparc32 warning fix") By now enable_irq() and disable_irq() are properly defined in linux/interrupt.h and we do not need to pull in architecture-specific bits. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 9eed1f3e3661..de058644ef8a 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -32,7 +32,6 @@ #include #include #include -#include #include /* -- cgit v1.2.3 From c7f0169e3bd274e576f6aaeee86ad2adf7bb14b5 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 17 Nov 2020 13:46:18 -0800 Subject: Input: elan_i2c_core - move header inclusion inside MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The same clause as its use. Fixes the following W=1 kernel build warning(s): include/linux/input/elan-i2c-ids.h:26:36: warning: ‘elan_acpi_id’ defined but not used [-Wunused-const-variable=] Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201112104420.GG1997862@dell Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index c599e21a8478..65d21a050cea 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -1413,6 +1412,7 @@ static const struct i2c_device_id elan_id[] = { MODULE_DEVICE_TABLE(i2c, elan_id); #ifdef CONFIG_ACPI +#include MODULE_DEVICE_TABLE(acpi, elan_acpi_id); #endif -- cgit v1.2.3 From feedaacdadfc332e1a6e436f3adfbc67e244db47 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 9 Nov 2020 18:00:06 -0800 Subject: Input: atmel_mxt_ts - fix up inverted RESET handler This driver uses GPIO descriptors to drive the touchscreen RESET line. In the existing device trees this has in conflict with intution been flagged as GPIO_ACTIVE_HIGH and the driver then applies the reverse action by driving the line low (setting to 0) to enter reset state and driving the line high (setting to 1) to get out of reset state. The correct way to handle active low GPIO lines is to provide the GPIO_ACTIVE_LOW in the device tree (thus properly describing the hardware) and letting the GPIO framework invert the assertion (driving high) to a low level and vice versa. This is considered a bug since the device trees are incorrectly mis-specifying the line as active high. Fix the driver and all device trees specifying a reset line. Signed-off-by: Linus Walleij Reviewed-by: Philippe Schenker Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20201104153032.1387747-1-linus.walleij@linaro.org Signed-off-by: Dmitry Torokhov --- arch/arm/boot/dts/imx53-ppd.dts | 2 +- arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts | 2 +- arch/arm/boot/dts/imx6q-apalis-eval.dts | 2 +- arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts | 2 +- arch/arm/boot/dts/imx6q-apalis-ixora.dts | 2 +- arch/arm/boot/dts/imx7-colibri-aster.dtsi | 2 +- arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi | 2 +- arch/arm/boot/dts/motorola-mapphone-common.dtsi | 2 +- arch/arm/boot/dts/s5pv210-aries.dtsi | 2 +- arch/arm/boot/dts/tegra20-acer-a500-picasso.dts | 2 +- drivers/input/touchscreen/atmel_mxt_ts.c | 6 ++++-- 11 files changed, 14 insertions(+), 12 deletions(-) diff --git a/arch/arm/boot/dts/imx53-ppd.dts b/arch/arm/boot/dts/imx53-ppd.dts index f7dcdf96e5c0..8f4a63ea912e 100644 --- a/arch/arm/boot/dts/imx53-ppd.dts +++ b/arch/arm/boot/dts/imx53-ppd.dts @@ -589,7 +589,7 @@ touchscreen@4b { compatible = "atmel,maxtouch"; - reset-gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>; + reset-gpio = <&gpio5 19 GPIO_ACTIVE_LOW>; reg = <0x4b>; interrupt-parent = <&gpio5>; interrupts = <4 IRQ_TYPE_LEVEL_LOW>; diff --git a/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts b/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts index 65359aece950..7da74e6f46d9 100644 --- a/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts +++ b/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts @@ -143,7 +143,7 @@ reg = <0x4a>; interrupt-parent = <&gpio1>; interrupts = <9 IRQ_TYPE_EDGE_FALLING>; /* SODIMM 28 */ - reset-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>; /* SODIMM 30 */ + reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; /* SODIMM 30 */ status = "disabled"; }; diff --git a/arch/arm/boot/dts/imx6q-apalis-eval.dts b/arch/arm/boot/dts/imx6q-apalis-eval.dts index fab83abb6466..a0683b4aeca1 100644 --- a/arch/arm/boot/dts/imx6q-apalis-eval.dts +++ b/arch/arm/boot/dts/imx6q-apalis-eval.dts @@ -140,7 +140,7 @@ reg = <0x4a>; interrupt-parent = <&gpio6>; interrupts = <10 IRQ_TYPE_EDGE_FALLING>; - reset-gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>; /* SODIMM 13 */ + reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>; /* SODIMM 13 */ status = "disabled"; }; diff --git a/arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts b/arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts index 1614b1ae501d..86e84781cf5d 100644 --- a/arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts +++ b/arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts @@ -145,7 +145,7 @@ reg = <0x4a>; interrupt-parent = <&gpio6>; interrupts = <10 IRQ_TYPE_EDGE_FALLING>; - reset-gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>; /* SODIMM 13 */ + reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>; /* SODIMM 13 */ status = "disabled"; }; diff --git a/arch/arm/boot/dts/imx6q-apalis-ixora.dts b/arch/arm/boot/dts/imx6q-apalis-ixora.dts index fa9f98dd15ac..62e72773e53b 100644 --- a/arch/arm/boot/dts/imx6q-apalis-ixora.dts +++ b/arch/arm/boot/dts/imx6q-apalis-ixora.dts @@ -144,7 +144,7 @@ reg = <0x4a>; interrupt-parent = <&gpio6>; interrupts = <10 IRQ_TYPE_EDGE_FALLING>; - reset-gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>; /* SODIMM 13 */ + reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>; /* SODIMM 13 */ status = "disabled"; }; diff --git a/arch/arm/boot/dts/imx7-colibri-aster.dtsi b/arch/arm/boot/dts/imx7-colibri-aster.dtsi index 9fa701bec2ec..139188eb9f40 100644 --- a/arch/arm/boot/dts/imx7-colibri-aster.dtsi +++ b/arch/arm/boot/dts/imx7-colibri-aster.dtsi @@ -99,7 +99,7 @@ reg = <0x4a>; interrupt-parent = <&gpio2>; interrupts = <15 IRQ_TYPE_EDGE_FALLING>; /* SODIMM 107 */ - reset-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* SODIMM 106 */ + reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* SODIMM 106 */ }; /* M41T0M6 real time clock on carrier board */ diff --git a/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi b/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi index 97601375f264..3caf450735d7 100644 --- a/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi +++ b/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi @@ -124,7 +124,7 @@ reg = <0x4a>; interrupt-parent = <&gpio1>; interrupts = <9 IRQ_TYPE_EDGE_FALLING>; /* SODIMM 28 */ - reset-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; /* SODIMM 30 */ + reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; /* SODIMM 30 */ status = "disabled"; }; diff --git a/arch/arm/boot/dts/motorola-mapphone-common.dtsi b/arch/arm/boot/dts/motorola-mapphone-common.dtsi index 1990239cc6af..70fc71cbb945 100644 --- a/arch/arm/boot/dts/motorola-mapphone-common.dtsi +++ b/arch/arm/boot/dts/motorola-mapphone-common.dtsi @@ -428,7 +428,7 @@ pinctrl-names = "default"; pinctrl-0 = <&touchscreen_pins>; - reset-gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>; /* gpio173 */ + reset-gpios = <&gpio6 13 GPIO_ACTIVE_LOW>; /* gpio173 */ /* gpio_183 with sys_nirq2 pad as wakeup */ interrupts-extended = <&gpio6 23 IRQ_TYPE_LEVEL_LOW>, diff --git a/arch/arm/boot/dts/s5pv210-aries.dtsi b/arch/arm/boot/dts/s5pv210-aries.dtsi index 822207f63ee0..96e8c2287d61 100644 --- a/arch/arm/boot/dts/s5pv210-aries.dtsi +++ b/arch/arm/boot/dts/s5pv210-aries.dtsi @@ -620,7 +620,7 @@ interrupts = <5 IRQ_TYPE_EDGE_FALLING>; pinctrl-names = "default"; pinctrl-0 = <&ts_irq>; - reset-gpios = <&gpj1 3 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpj1 3 GPIO_ACTIVE_LOW>; }; }; diff --git a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts index 2d683c9a1a5d..a150e3419c8f 100644 --- a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts +++ b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts @@ -436,7 +436,7 @@ interrupt-parent = <&gpio>; interrupts = ; - reset-gpios = <&gpio TEGRA_GPIO(Q, 7) GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio TEGRA_GPIO(Q, 7) GPIO_ACTIVE_LOW>; avdd-supply = <&vdd_3v3_sys>; vdd-supply = <&vdd_3v3_sys>; diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 98f17fa3a892..ef7915400c9f 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -3134,8 +3134,9 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) if (error) return error; + /* Request the RESET line as asserted so we go into reset */ data->reset_gpio = devm_gpiod_get_optional(&client->dev, - "reset", GPIOD_OUT_LOW); + "reset", GPIOD_OUT_HIGH); if (IS_ERR(data->reset_gpio)) { error = PTR_ERR(data->reset_gpio); dev_err(&client->dev, "Failed to get reset gpio: %d\n", error); @@ -3153,8 +3154,9 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) disable_irq(client->irq); if (data->reset_gpio) { + /* Wait a while and then de-assert the RESET GPIO line */ msleep(MXT_RESET_GPIO_TIME); - gpiod_set_value(data->reset_gpio, 1); + gpiod_set_value(data->reset_gpio, 0); msleep(MXT_RESET_INVALID_CHG); } -- cgit v1.2.3 From 04f1842a8db6f31c9115af68c2b34fbb0f208cec Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 9 Nov 2020 18:01:03 -0800 Subject: Input: atmel_mxt_ts - convert bindings to YAML and extend This converts the Armel MXT touchscreen bindings to YAML format and extends them with the following two properties: - vdda-supply: the optional analog supply voltage - vdd-supply: the optional digital supply voltage Tested the schema with all in-tree users and they verify fine. Signed-off-by: Linus Walleij Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201104153032.1387747-2-linus.walleij@linaro.org Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/atmel,maxtouch.txt | 41 ----------- .../devicetree/bindings/input/atmel,maxtouch.yaml | 81 ++++++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 82 insertions(+), 42 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/atmel,maxtouch.txt create mode 100644 Documentation/devicetree/bindings/input/atmel,maxtouch.yaml diff --git a/Documentation/devicetree/bindings/input/atmel,maxtouch.txt b/Documentation/devicetree/bindings/input/atmel,maxtouch.txt deleted file mode 100644 index c88919480d37..000000000000 --- a/Documentation/devicetree/bindings/input/atmel,maxtouch.txt +++ /dev/null @@ -1,41 +0,0 @@ -Atmel maXTouch touchscreen/touchpad - -Required properties: -- compatible: - atmel,maxtouch - - The following compatibles have been used in various products but are - deprecated: - atmel,qt602240_ts - atmel,atmel_mxt_ts - atmel,atmel_mxt_tp - atmel,mXT224 - -- reg: The I2C address of the device - -- interrupts: The sink for the touchpad's IRQ output - See ../interrupt-controller/interrupts.txt - -Optional properties for main touchpad device: - -- linux,gpio-keymap: When enabled, the SPT_GPIOPWN_T19 object sends messages - on GPIO bit changes. An array of up to 8 entries can be provided - indicating the Linux keycode mapped to each bit of the status byte, - starting at the LSB. Linux keycodes are defined in - . - - Note: the numbering of the GPIOs and the bit they start at varies between - maXTouch devices. You must either refer to the documentation, or - experiment to determine which bit corresponds to which input. Use - KEY_RESERVED for unused padding values. - -- reset-gpios: GPIO specifier for the touchscreen's reset pin (active low) - -Example: - - touch@4b { - compatible = "atmel,maxtouch"; - reg = <0x4b>; - interrupt-parent = <&gpio>; - interrupts = ; - }; diff --git a/Documentation/devicetree/bindings/input/atmel,maxtouch.yaml b/Documentation/devicetree/bindings/input/atmel,maxtouch.yaml new file mode 100644 index 000000000000..8c6418f76e94 --- /dev/null +++ b/Documentation/devicetree/bindings/input/atmel,maxtouch.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/atmel,maxtouch.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Atmel maXTouch touchscreen/touchpad + +maintainers: + - Nick Dyer + - Linus Walleij + +description: | + Atmel maXTouch touchscreen or touchpads such as the mXT244 + and similar devices. + +properties: + compatible: + const: atmel,maxtouch + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + vdda-supply: + description: + Optional regulator for the AVDD analog voltage. + + vdd-supply: + description: + Optional regulator for the VDD digital voltage. + + reset-gpios: + maxItems: 1 + description: + Optional GPIO specifier for the touchscreen's reset pin + (active low). The line must be flagged with + GPIO_ACTIVE_LOW. + + linux,gpio-keymap: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: | + When enabled, the SPT_GPIOPWN_T19 object sends messages + on GPIO bit changes. An array of up to 8 entries can be provided + indicating the Linux keycode mapped to each bit of the status byte, + starting at the LSB. Linux keycodes are defined in + . + + Note: the numbering of the GPIOs and the bit they start at varies + between maXTouch devices. You must either refer to the documentation, + or experiment to determine which bit corresponds to which input. Use + KEY_RESERVED for unused padding values. + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + touchscreen@4a { + compatible = "atmel,maxtouch"; + reg = <0x4a>; + interrupt-parent = <&gpio>; + interrupts = <26 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&gpio 27 GPIO_ACTIVE_LOW>; + vdda-supply = <&ab8500_ldo_aux2_reg>; + vdd-supply = <&ab8500_ldo_aux5_reg>; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index d6c8f3016f57..4c460d3fc770 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2980,7 +2980,7 @@ ATMEL MAXTOUCH DRIVER M: Nick Dyer S: Maintained T: git git://github.com/ndyer/linux.git -F: Documentation/devicetree/bindings/input/atmel,maxtouch.txt +F: Documentation/devicetree/bindings/input/atmel,maxtouch.yaml F: drivers/input/touchscreen/atmel_mxt_ts.c ATMEL WIRELESS DRIVER -- cgit v1.2.3 From c6c746508981f22ffa754e0c8fcee00da6923b9e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 9 Nov 2020 18:02:50 -0800 Subject: Input: atmel_mxt_ts - support regulator supplies This adds the code for the Atmel touchscreens such as mXT224 to obtain power regulators for the supply voltages AVDD and VDD. On mobile phones such as Samsung GT-I8190 (Golden) this is needed to explicitly bring power online. We just enable the regulators at probe() and disable them at remove() or in the error path for now. As regulators are naturally stubbed if not available, this should have no impact on existing systems. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20201104153032.1387747-3-linus.walleij@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 37 +++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index ef7915400c9f..e34984388791 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -309,6 +310,7 @@ struct mxt_data { u8 multitouch; struct t7_config t7_cfg; struct mxt_dbg dbg; + struct regulator_bulk_data regulators[2]; struct gpio_desc *reset_gpio; bool use_retrigen_workaround; @@ -3134,6 +3136,21 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) if (error) return error; + /* + * VDDA is the analog voltage supply 2.57..3.47 V + * VDD is the digital voltage supply 1.71..3.47 V + */ + data->regulators[0].supply = "vdda"; + data->regulators[1].supply = "vdd"; + error = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(data->regulators), + data->regulators); + if (error) { + if (error != -EPROBE_DEFER) + dev_err(&client->dev, "Failed to get regulators %d\n", + error); + return error; + } + /* Request the RESET line as asserted so we go into reset */ data->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); @@ -3153,6 +3170,19 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) disable_irq(client->irq); + error = regulator_bulk_enable(ARRAY_SIZE(data->regulators), + data->regulators); + if (error) { + dev_err(&client->dev, "failed to enable regulators: %d\n", + error); + return error; + } + /* + * The device takes 40ms to come up after power-on according + * to the mXT224 datasheet, page 13. + */ + msleep(MXT_BACKUP_TIME); + if (data->reset_gpio) { /* Wait a while and then de-assert the RESET GPIO line */ msleep(MXT_RESET_GPIO_TIME); @@ -3162,7 +3192,7 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) error = mxt_initialize(data); if (error) - return error; + goto err_disable_regulators; error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group); if (error) { @@ -3176,6 +3206,9 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) err_free_object: mxt_free_input_device(data); mxt_free_object_table(data); +err_disable_regulators: + regulator_bulk_disable(ARRAY_SIZE(data->regulators), + data->regulators); return error; } @@ -3187,6 +3220,8 @@ static int mxt_remove(struct i2c_client *client) sysfs_remove_group(&client->dev.kobj, &mxt_attr_group); mxt_free_input_device(data); mxt_free_object_table(data); + regulator_bulk_disable(ARRAY_SIZE(data->regulators), + data->regulators); return 0; } -- cgit v1.2.3 From 41d7d26b8fb26e7e8056c1a3b6cf358d40cb367a Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Wed, 18 Nov 2020 22:40:22 -0800 Subject: Input: adp5589-keys - use devm_kzalloc() to allocate the kpad object This removes the need to manually free the kpad object and cleans up some exit/error paths. The error path cleanup should reduce the risk of any memory leaks with this object. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201112074308.71351-2-alexandru.ardelean@analog.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5589-keys.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index eb0e9cd66bcb..922497b65ab0 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -1007,7 +1007,7 @@ static int adp5589_probe(struct i2c_client *client, return -EINVAL; } - kpad = kzalloc(sizeof(*kpad), GFP_KERNEL); + kpad = devm_kzalloc(&client->dev, sizeof(*kpad), GFP_KERNEL); if (!kpad) return -ENOMEM; @@ -1028,17 +1028,15 @@ static int adp5589_probe(struct i2c_client *client, } ret = adp5589_read(client, ADP5589_5_ID); - if (ret < 0) { - error = ret; - goto err_free_mem; - } + if (ret < 0) + return ret; revid = (u8) ret & ADP5589_5_DEVICE_ID_MASK; if (pdata->keymapsize) { error = adp5589_keypad_add(kpad, revid); if (error) - goto err_free_mem; + return error; } error = adp5589_setup(kpad); @@ -1059,8 +1057,6 @@ static int adp5589_probe(struct i2c_client *client, err_keypad_remove: adp5589_keypad_remove(kpad); -err_free_mem: - kfree(kpad); return error; } @@ -1072,7 +1068,6 @@ static int adp5589_remove(struct i2c_client *client) adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0); adp5589_keypad_remove(kpad); adp5589_gpio_remove(kpad); - kfree(kpad); return 0; } -- cgit v1.2.3 From 760a1219ff264c4bb68ae561bf4d5eea5daac8dc Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Wed, 18 Nov 2020 22:41:46 -0800 Subject: Input: adp5589-keys - use device-managed function in adp5589_keypad_add() This change makes use of the devm_input_allocate_device() function, which gets rid of the input_free_device() and input_unregister_device() calls. When a device is allocated via input_allocate_device(), the input_register_device() call will also be device-managed, so there is no longer need to manually call unregister. Also, the irq is allocated with the devm_request_threaded_irq(), so with these two changes, the adp5589_keypad_remove() function is no longer needed. This cleans up the error & exit paths. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201112074308.71351-3-alexandru.ardelean@analog.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5589-keys.c | 41 +++++++++-------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 922497b65ab0..0e2ad9628ba9 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -909,7 +909,7 @@ static int adp5589_keypad_add(struct adp5589_kpad *kpad, unsigned int revid) return -EINVAL; } - input = input_allocate_device(); + input = devm_input_allocate_device(&client->dev); if (!input) return -ENOMEM; @@ -955,36 +955,21 @@ static int adp5589_keypad_add(struct adp5589_kpad *kpad, unsigned int revid) error = input_register_device(input); if (error) { dev_err(&client->dev, "unable to register input device\n"); - goto err_free_input; + return error; } - error = request_threaded_irq(client->irq, NULL, adp5589_irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - client->dev.driver->name, kpad); + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, adp5589_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + client->dev.driver->name, kpad); if (error) { - dev_err(&client->dev, "irq %d busy?\n", client->irq); - goto err_unreg_dev; + dev_err(&client->dev, "unable to request irq %d\n", client->irq); + return error; } device_init_wakeup(&client->dev, 1); return 0; - -err_unreg_dev: - input_unregister_device(input); - input = NULL; -err_free_input: - input_free_device(input); - - return error; -} - -static void adp5589_keypad_remove(struct adp5589_kpad *kpad) -{ - if (kpad->input) { - free_irq(kpad->client->irq, kpad); - input_unregister_device(kpad->input); - } } static int adp5589_probe(struct i2c_client *client, @@ -1041,24 +1026,19 @@ static int adp5589_probe(struct i2c_client *client, error = adp5589_setup(kpad); if (error) - goto err_keypad_remove; + return error; if (kpad->gpimapsize) adp5589_report_switch_state(kpad); error = adp5589_gpio_add(kpad); if (error) - goto err_keypad_remove; + return error; i2c_set_clientdata(client, kpad); dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq); return 0; - -err_keypad_remove: - adp5589_keypad_remove(kpad); - - return error; } static int adp5589_remove(struct i2c_client *client) @@ -1066,7 +1046,6 @@ static int adp5589_remove(struct i2c_client *client) struct adp5589_kpad *kpad = i2c_get_clientdata(client); adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0); - adp5589_keypad_remove(kpad); adp5589_gpio_remove(kpad); return 0; -- cgit v1.2.3 From 3b95bc57c86b064fd140ccec3642ad14f40b687f Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Wed, 18 Nov 2020 22:49:27 -0800 Subject: Input: adp5589-keys - remove setup/teardown hooks for gpios This is currently just dead code. It's from around a time when platform-data was used, and a board could hook it's own special callback for setup/teardown, and a private object (via 'context'). This change removes it, as there are no more users in mainline for this. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201112074308.71351-4-alexandru.ardelean@analog.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5589-keys.c | 21 --------------------- include/linux/input/adp5589.h | 7 ------- 2 files changed, 28 deletions(-) diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 0e2ad9628ba9..4008cd3be18e 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -539,35 +539,14 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad) ADP5589_GPIO_DIRECTION_A) + i); } - if (gpio_data->setup) { - error = gpio_data->setup(kpad->client, - kpad->gc.base, kpad->gc.ngpio, - gpio_data->context); - if (error) - dev_warn(dev, "setup failed, %d\n", error); - } - return 0; } static void adp5589_gpio_remove(struct adp5589_kpad *kpad) { - struct device *dev = &kpad->client->dev; - const struct adp5589_kpad_platform_data *pdata = dev_get_platdata(dev); - const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data; - int error; - if (!kpad->export_gpio) return; - if (gpio_data->teardown) { - error = gpio_data->teardown(kpad->client, - kpad->gc.base, kpad->gc.ngpio, - gpio_data->context); - if (error) - dev_warn(dev, "teardown failed %d\n", error); - } - gpiochip_remove(&kpad->gc); } #else diff --git a/include/linux/input/adp5589.h b/include/linux/input/adp5589.h index c0523af96893..0e4742c8c81e 100644 --- a/include/linux/input/adp5589.h +++ b/include/linux/input/adp5589.h @@ -175,13 +175,6 @@ struct i2c_client; /* forward declaration */ struct adp5589_gpio_platform_data { int gpio_start; /* GPIO Chip base # */ - int (*setup)(struct i2c_client *client, - int gpio, unsigned ngpio, - void *context); - int (*teardown)(struct i2c_client *client, - int gpio, unsigned ngpio, - void *context); - void *context; }; #endif -- cgit v1.2.3 From 74f2c59324a3cb0e69937c2289a13f36231a6f3e Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Wed, 18 Nov 2020 22:50:02 -0800 Subject: Input: adp5589-keys - use devm_gpiochip_add_data() for gpios This change makes use of the devm_gpiochip_add_data() function. With this the gpiochip_remove() function can be removed, and the adp5589_gpio_remove() function as well. The kpad->export_gpio variable is also redundant now, and has been removed. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201112074308.71351-5-alexandru.ardelean@analog.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5589-keys.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 4008cd3be18e..81d9525245d2 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -238,7 +238,6 @@ struct adp5589_kpad { bool support_row5; #ifdef CONFIG_GPIOLIB unsigned char gpiomap[ADP5589_MAXGPIO]; - bool export_gpio; struct gpio_chip gc; struct mutex gpio_lock; /* Protect cached dir, dat_out */ u8 dat_out[3]; @@ -512,8 +511,6 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad) return 0; } - kpad->export_gpio = true; - kpad->gc.direction_input = adp5589_gpio_direction_input; kpad->gc.direction_output = adp5589_gpio_direction_output; kpad->gc.get = adp5589_gpio_get_value; @@ -526,11 +523,9 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad) mutex_init(&kpad->gpio_lock); - error = gpiochip_add_data(&kpad->gc, kpad); - if (error) { - dev_err(dev, "gpiochip_add_data() failed, err: %d\n", error); + error = devm_gpiochip_add_data(dev, &kpad->gc, kpad); + if (error) return error; - } for (i = 0; i <= kpad->var->bank(kpad->var->maxgpio); i++) { kpad->dat_out[i] = adp5589_read(kpad->client, kpad->var->reg( @@ -541,23 +536,11 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad) return 0; } - -static void adp5589_gpio_remove(struct adp5589_kpad *kpad) -{ - if (!kpad->export_gpio) - return; - - gpiochip_remove(&kpad->gc); -} #else static inline int adp5589_gpio_add(struct adp5589_kpad *kpad) { return 0; } - -static inline void adp5589_gpio_remove(struct adp5589_kpad *kpad) -{ -} #endif static void adp5589_report_switches(struct adp5589_kpad *kpad, @@ -1025,7 +1008,6 @@ static int adp5589_remove(struct i2c_client *client) struct adp5589_kpad *kpad = i2c_get_clientdata(client); adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0); - adp5589_gpio_remove(kpad); return 0; } -- cgit v1.2.3 From 30df385e35a48f773b85117fc490152c2395e45b Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Wed, 18 Nov 2020 22:55:39 -0800 Subject: Input: adp5589-keys - use devm_add_action_or_reset() for register clear The driver clears the general configuration register during the remove() hook. This should also be done in case the driver exits on error. This change move the clear of that register to the devm_add_action_or_reset() hook. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201112074308.71351-6-alexandru.ardelean@analog.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5589-keys.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 81d9525245d2..31145a85c819 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -934,6 +934,14 @@ static int adp5589_keypad_add(struct adp5589_kpad *kpad, unsigned int revid) return 0; } +static void adp5589_clear_config(void *data) +{ + struct i2c_client *client = data; + struct adp5589_kpad *kpad = i2c_get_clientdata(client); + + adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0); +} + static int adp5589_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -974,6 +982,11 @@ static int adp5589_probe(struct i2c_client *client, break; } + error = devm_add_action_or_reset(&client->dev, adp5589_clear_config, + client); + if (error) + return error; + ret = adp5589_read(client, ADP5589_5_ID); if (ret < 0) return ret; @@ -1003,15 +1016,6 @@ static int adp5589_probe(struct i2c_client *client, return 0; } -static int adp5589_remove(struct i2c_client *client) -{ - struct adp5589_kpad *kpad = i2c_get_clientdata(client); - - adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0); - - return 0; -} - #ifdef CONFIG_PM_SLEEP static int adp5589_suspend(struct device *dev) { @@ -1063,7 +1067,6 @@ static struct i2c_driver adp5589_driver = { .pm = &adp5589_dev_pm_ops, }, .probe = adp5589_probe, - .remove = adp5589_remove, .id_table = adp5589_id, }; -- cgit v1.2.3 From a26506788320d8dda4e3520dd1b020f20cc7a2fd Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 19 Nov 2020 10:10:58 -0800 Subject: Input: adp5589-keys - mark suspend and resume methods as __maybe_unused This improves compile coverage of the code; unused code will be dropped by the linker. Acked-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201119072418.GA114677@dtor-ws Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5589-keys.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 31145a85c819..a9b69a268c09 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -1016,8 +1016,7 @@ static int adp5589_probe(struct i2c_client *client, return 0; } -#ifdef CONFIG_PM_SLEEP -static int adp5589_suspend(struct device *dev) +static int __maybe_unused adp5589_suspend(struct device *dev) { struct adp5589_kpad *kpad = dev_get_drvdata(dev); struct i2c_client *client = kpad->client; @@ -1033,7 +1032,7 @@ static int adp5589_suspend(struct device *dev) return 0; } -static int adp5589_resume(struct device *dev) +static int __maybe_unused adp5589_resume(struct device *dev) { struct adp5589_kpad *kpad = dev_get_drvdata(dev); struct i2c_client *client = kpad->client; @@ -1048,7 +1047,6 @@ static int adp5589_resume(struct device *dev) return 0; } -#endif static SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume); -- cgit v1.2.3 From 478a57072a4c4fafd83e10c329c9c8ad5c0ff97b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 19 Nov 2020 10:11:22 -0800 Subject: Input: adp5589-keys - use BIT() Let's use BIT() macro instead of explicitly shifting '1'. Acked-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20201119072440.GA116840@dtor-ws Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5589-keys.c | 69 ++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index a9b69a268c09..e2cdf14d90cd 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -7,6 +7,7 @@ * Copyright (C) 2010-2011 Analog Devices Inc. */ +#include #include #include #include @@ -153,48 +154,48 @@ #define ADP5589_5_MAN_ID 0x02 /* GENERAL_CFG Register */ -#define OSC_EN (1 << 7) +#define OSC_EN BIT(7) #define CORE_CLK(x) (((x) & 0x3) << 5) -#define LCK_TRK_LOGIC (1 << 4) /* ADP5589 only */ -#define LCK_TRK_GPI (1 << 3) /* ADP5589 only */ -#define INT_CFG (1 << 1) -#define RST_CFG (1 << 0) +#define LCK_TRK_LOGIC BIT(4) /* ADP5589 only */ +#define LCK_TRK_GPI BIT(3) /* ADP5589 only */ +#define INT_CFG BIT(1) +#define RST_CFG BIT(0) /* INT_EN Register */ -#define LOGIC2_IEN (1 << 5) /* ADP5589 only */ -#define LOGIC1_IEN (1 << 4) -#define LOCK_IEN (1 << 3) /* ADP5589 only */ -#define OVRFLOW_IEN (1 << 2) -#define GPI_IEN (1 << 1) -#define EVENT_IEN (1 << 0) +#define LOGIC2_IEN BIT(5) /* ADP5589 only */ +#define LOGIC1_IEN BIT(4) +#define LOCK_IEN BIT(3) /* ADP5589 only */ +#define OVRFLOW_IEN BIT(2) +#define GPI_IEN BIT(1) +#define EVENT_IEN BIT(0) /* Interrupt Status Register */ -#define LOGIC2_INT (1 << 5) /* ADP5589 only */ -#define LOGIC1_INT (1 << 4) -#define LOCK_INT (1 << 3) /* ADP5589 only */ -#define OVRFLOW_INT (1 << 2) -#define GPI_INT (1 << 1) -#define EVENT_INT (1 << 0) +#define LOGIC2_INT BIT(5) /* ADP5589 only */ +#define LOGIC1_INT BIT(4) +#define LOCK_INT BIT(3) /* ADP5589 only */ +#define OVRFLOW_INT BIT(2) +#define GPI_INT BIT(1) +#define EVENT_INT BIT(0) /* STATUS Register */ -#define LOGIC2_STAT (1 << 7) /* ADP5589 only */ -#define LOGIC1_STAT (1 << 6) -#define LOCK_STAT (1 << 5) /* ADP5589 only */ +#define LOGIC2_STAT BIT(7) /* ADP5589 only */ +#define LOGIC1_STAT BIT(6) +#define LOCK_STAT BIT(5) /* ADP5589 only */ #define KEC 0x1F /* PIN_CONFIG_D Register */ -#define C4_EXTEND_CFG (1 << 6) /* RESET2 */ -#define R4_EXTEND_CFG (1 << 5) /* RESET1 */ +#define C4_EXTEND_CFG BIT(6) /* RESET2 */ +#define R4_EXTEND_CFG BIT(5) /* RESET1 */ /* LOCK_CFG */ -#define LOCK_EN (1 << 0) +#define LOCK_EN BIT(0) #define PTIME_MASK 0x3 #define LTIME_MASK 0x3 /* ADP5589 only */ /* Key Event Register xy */ -#define KEY_EV_PRESSED (1 << 7) -#define KEY_EV_MASK (0x7F) +#define KEY_EV_PRESSED BIT(7) +#define KEY_EV_MASK 0x7F #define KEYP_MAX_EVENT 16 #define ADP5589_MAXGPIO 19 @@ -472,7 +473,7 @@ static int adp5589_build_gpiomap(struct adp5589_kpad *kpad, memset(pin_used, false, sizeof(pin_used)); for (i = 0; i < kpad->var->maxgpio; i++) - if (pdata->keypad_en_mask & (1 << i)) + if (pdata->keypad_en_mask & BIT(i)) pin_used[i] = true; for (i = 0; i < kpad->gpimapsize; i++) @@ -651,13 +652,13 @@ static int adp5589_setup(struct adp5589_kpad *kpad) unsigned short pin = pdata->gpimap[i].pin; if (pin <= kpad->var->gpi_pin_row_end) { - evt_mode1 |= (1 << (pin - kpad->var->gpi_pin_row_base)); + evt_mode1 |= BIT(pin - kpad->var->gpi_pin_row_base); } else { evt_mode2 |= - ((1 << (pin - kpad->var->gpi_pin_col_base)) & 0xFF); + BIT(pin - kpad->var->gpi_pin_col_base) & 0xFF; if (!kpad->is_adp5585) - evt_mode3 |= ((1 << (pin - - kpad->var->gpi_pin_col_base)) >> 8); + evt_mode3 |= + BIT(pin - kpad->var->gpi_pin_col_base) >> 8; } } @@ -677,7 +678,7 @@ static int adp5589_setup(struct adp5589_kpad *kpad) dev_warn(&client->dev, "Conflicting pull resistor config\n"); for (i = 0; i <= kpad->var->max_row_num; i++) { - unsigned val = 0, bit = (1 << i); + unsigned int val = 0, bit = BIT(i); if (pdata->pullup_en_300k & bit) val = 0; else if (pdata->pulldown_en_300k & bit) @@ -697,7 +698,7 @@ static int adp5589_setup(struct adp5589_kpad *kpad) } for (i = 0; i <= kpad->var->max_col_num; i++) { - unsigned val = 0, bit = 1 << (i + kpad->var->col_shift); + unsigned int val = 0, bit = BIT(i + kpad->var->col_shift); if (pdata->pullup_en_300k & bit) val = 0; else if (pdata->pulldown_en_300k & bit) @@ -813,7 +814,7 @@ static void adp5589_report_switch_state(struct adp5589_kpad *kpad) input_report_switch(kpad->input, kpad->gpimap[i].sw_evt, - !(gpi_stat_tmp & (1 << pin_loc))); + !(gpi_stat_tmp & BIT(pin_loc))); } input_sync(kpad->input); @@ -859,7 +860,7 @@ static int adp5589_keypad_add(struct adp5589_kpad *kpad, unsigned int revid) return -EINVAL; } - if ((1 << (pin - kpad->var->gpi_pin_row_base)) & + if (BIT(pin - kpad->var->gpi_pin_row_base) & pdata->keypad_en_mask) { dev_err(&client->dev, "invalid gpi row/col data\n"); return -EINVAL; -- cgit v1.2.3 From 35b076b99546941c0f7841ec7c80225e7e4817a7 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 19 Nov 2020 19:11:55 -0800 Subject: Input: xpad - demote non-conformant kernel-doc header Fixes the following W=1 kernel build warning(s): drivers/input/joystick/xpad.c:1361: warning: Function parameter or member 'xpad' not described in 'xpad_send_led_command' drivers/input/joystick/xpad.c:1361: warning: Function parameter or member 'command' not described in 'xpad_send_led_command' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201112110204.2083435-2-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index c77cdb3b62b5..2cd4296c2d08 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -1337,7 +1337,7 @@ struct xpad_led { struct usb_xpad *xpad; }; -/** +/* * set the LEDs on Xbox360 / Wireless Controllers * @param command * 0: off -- cgit v1.2.3 From 7d52613d1c93bfe0116b9147b0232604592e4716 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 19 Nov 2020 19:12:16 -0800 Subject: Input: mc13783-pwrbutton - file headers are not good candidates for kernel-doc Fixes the following W=1 kernel build warning(s): drivers/input/misc/mc13783-pwrbutton.c:32: warning: cannot understand function prototype: 'struct mc13783_pwrb ' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201112110204.2083435-4-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/mc13783-pwrbutton.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c index afdf8ef25ee8..0636eee4bb6c 100644 --- a/drivers/input/misc/mc13783-pwrbutton.c +++ b/drivers/input/misc/mc13783-pwrbutton.c @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Philippe Rétornaz * * Based on twl4030-pwrbutton driver by: -- cgit v1.2.3 From cb69046526cc1d1582b7bf3ab6169cf1961cc1b1 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 19 Nov 2020 19:12:42 -0800 Subject: Input: goodix - provide some missing function parameter descriptions Fixes the following W=1 kernel build warning(s): drivers/input/touchscreen/goodix.c:569: warning: Function parameter or member 'len' not described in 'goodix_check_cfg' drivers/input/touchscreen/goodix.c:587: warning: Function parameter or member 'len' not described in 'goodix_send_cfg' drivers/input/touchscreen/goodix.c:1165: warning: Function parameter or member 'cfg' not described in 'goodix_config_cb' drivers/input/touchscreen/goodix.c:1165: warning: Function parameter or member 'ctx' not described in 'goodix_config_cb' drivers/input/touchscreen/goodix.c:1165: warning: Excess function parameter 'ts' description in 'goodix_config_cb' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201112110204.2083435-5-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/goodix.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 02c75ea385e0..80a82a66a0f3 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -564,6 +564,7 @@ static void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts) * * @ts: goodix_ts_data pointer * @cfg: firmware config data + * @len: config data length */ static int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) { @@ -582,6 +583,7 @@ static int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) * * @ts: goodix_ts_data pointer * @cfg: config firmware to write to device + * @len: config data length */ static int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) { @@ -1156,6 +1158,7 @@ static int goodix_configure_dev(struct goodix_ts_data *ts) /** * goodix_config_cb - Callback to finish device init * + * @cfg: firmware config * @ts: our goodix_ts_data pointer * * request_firmware_wait callback that finishes -- cgit v1.2.3 From ced8c61fa8c79b02d29a351a7e87ce3b413f04e4 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 19 Nov 2020 19:13:20 -0800 Subject: Input: wm831x-on - source file headers are not good candidates for kernel-doc Fixes the following W=1 kernel build warning(s): drivers/input/misc/wm831x-on.c:30: warning: cannot understand function prototype: 'struct wm831x_on ' Signed-off-by: Lee Jones Acked-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20201112110204.2083435-10-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wm831x-on.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c index 1b44de265a0a..a42fe041b73c 100644 --- a/drivers/input/misc/wm831x-on.c +++ b/drivers/input/misc/wm831x-on.c @@ -1,4 +1,4 @@ -/** +/* * wm831x-on.c - WM831X ON pin driver * * Copyright (C) 2009 Wolfson Microelectronics plc -- cgit v1.2.3 From aea1f3ffb110afbe17f53c2f13d2cad2402a9fee Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 19 Nov 2020 19:13:46 -0800 Subject: Input: surface3_spi - fix naming issue with 'surface3_spi_get_gpio_config's header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/input/touchscreen/surface3_spi.c: In function ‘surface3_spi_process_touch’: drivers/input/touchscreen/surface3_spi.c:97:6: warning: variable ‘timestamp’ set but not used [-Wunused-but-set-variable] drivers/input/touchscreen/surface3_spi.c:225: warning: Function parameter or member 'data' not described in 'surface3_spi_get_gpio_config' drivers/input/touchscreen/surface3_spi.c:225: warning: Excess function parameter 'ts' description in 'surface3_spi_get_gpio_config' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201112110204.2083435-11-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/surface3_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c index ce4828b1415a..731454599fce 100644 --- a/drivers/input/touchscreen/surface3_spi.c +++ b/drivers/input/touchscreen/surface3_spi.c @@ -219,7 +219,7 @@ static void surface3_spi_power(struct surface3_ts_data *data, bool on) /** * surface3_spi_get_gpio_config - Get GPIO config from ACPI/DT * - * @ts: surface3_spi_ts_data pointer + * @data: surface3_spi_ts_data pointer */ static int surface3_spi_get_gpio_config(struct surface3_ts_data *data) { -- cgit v1.2.3 From b324009d21ae50fafe628b665d9758403dbbf670 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 19 Nov 2020 19:14:04 -0800 Subject: Input: wm97xx-ts - provide missing description for 'status' Fixes the following W=1 kernel build warning(s): drivers/input/touchscreen/wm97xx-core.c:204: warning: Function parameter or member 'status' not described in 'wm97xx_set_gpio' Signed-off-by: Lee Jones Acked-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20201112110204.2083435-12-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm97xx-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 0a174bd82915..45ce89467c16 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -194,7 +194,7 @@ EXPORT_SYMBOL_GPL(wm97xx_get_gpio); * wm97xx_set_gpio - Set the status of a codec GPIO. * @wm: wm97xx device. * @gpio: gpio - * + * @status: status * * Set the status of a codec GPIO pin */ -- cgit v1.2.3 From 58e5183ac869b98f3b17aa91fea11df3b718b3f2 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 19 Nov 2020 19:15:44 -0800 Subject: Input: synaptics - demote non-conformant kernel-doc header Fixes the following W=1 kernel build warning(s): drivers/input/mouse/synaptics.c:1781: warning: Function parameter or member 'psmouse' not described in 'synaptics_setup_intertouch' drivers/input/mouse/synaptics.c:1781: warning: Function parameter or member 'info' not described in 'synaptics_setup_intertouch' drivers/input/mouse/synaptics.c:1781: warning: Function parameter or member 'leave_breadcrumbs' not described in 'synaptics_setup_intertouch' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201112110204.2083435-13-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 82577095e175..8fb7b4385ded 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -1770,7 +1770,7 @@ static int synaptics_create_intertouch(struct psmouse *psmouse, leave_breadcrumbs); } -/** +/* * synaptics_setup_intertouch - called once the PS/2 devices are enumerated * and decides to instantiate a SMBus InterTouch device. */ -- cgit v1.2.3 From 584da78cba791fc7b015416953a751a8269d375a Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 19 Nov 2020 19:19:38 -0800 Subject: Input: goodix - fix misspelling of 'ctx' Fixes the following W=1 kernel build warning(s): drivers/input/touchscreen/goodix.c:1168: warning: Function parameter or member 'ctx' not described in 'goodix_config_cb' drivers/input/touchscreen/goodix.c:1168: warning: Excess function parameter 'ts' description in 'goodix_config_cb' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201112110204.2083435-14-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/goodix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 80a82a66a0f3..c1b728e47827 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -1159,7 +1159,7 @@ static int goodix_configure_dev(struct goodix_ts_data *ts) * goodix_config_cb - Callback to finish device init * * @cfg: firmware config - * @ts: our goodix_ts_data pointer + * @ctx: our goodix_ts_data pointer * * request_firmware_wait callback that finishes * initialization of the device. -- cgit v1.2.3 From 39f4879e99a42d3ebcf9876bf4201d95679445d3 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 19 Nov 2020 19:20:09 -0800 Subject: Input: applespi - provide missing struct 'message' descriptions Fixes the following W=1 kernel build warning(s): drivers/input/keyboard/applespi.c:306: warning: Function parameter or member 'keyboard' not described in 'message' drivers/input/keyboard/applespi.c:306: warning: Function parameter or member 'touchpad' not described in 'message' drivers/input/keyboard/applespi.c:306: warning: Function parameter or member 'tp_info' not described in 'message' drivers/input/keyboard/applespi.c:306: warning: Function parameter or member 'tp_info_command' not described in 'message' drivers/input/keyboard/applespi.c:306: warning: Function parameter or member 'init_mt_command' not described in 'message' drivers/input/keyboard/applespi.c:306: warning: Function parameter or member 'capsl_command' not described in 'message' drivers/input/keyboard/applespi.c:306: warning: Function parameter or member 'bl_command' not described in 'message' drivers/input/keyboard/applespi.c:306: warning: Function parameter or member 'data' not described in 'message' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201112110204.2083435-15-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/applespi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c index 14362ebab9a9..8053a3d2ff63 100644 --- a/drivers/input/keyboard/applespi.c +++ b/drivers/input/keyboard/applespi.c @@ -286,6 +286,15 @@ struct command_protocol_bl { * structure (after re-assembly in case of being split over * multiple spi-packets), minus the trailing crc. The total size * of the message struct is therefore @length + 10. + * + * @keyboard: Keyboard message + * @touchpad: Touchpad message + * @tp_info: Touchpad info (response) + * @tp_info_command: Touchpad info (CRC) + * @init_mt_command: Initialise Multitouch + * @capsl_command: Toggle caps-lock LED + * @bl_command: Keyboard brightness + * @data: Buffer data */ struct message { __le16 type; -- cgit v1.2.3 From 3aa40a1ad36717114d9a267b08d884a387489fab Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 19 Nov 2020 19:20:33 -0800 Subject: Input: vmmouse - demote obvious abuse of kernel-doc header Fixes the following W=1 kernel build warning(s): drivers/input/mouse/vmmouse.c:99: warning: Function parameter or member 'cmd' not described in 'VMMOUSE_CMD' drivers/input/mouse/vmmouse.c:99: warning: Function parameter or member 'in1' not described in 'VMMOUSE_CMD' drivers/input/mouse/vmmouse.c:99: warning: Function parameter or member 'out1' not described in 'VMMOUSE_CMD' drivers/input/mouse/vmmouse.c:99: warning: Function parameter or member 'out2' not described in 'VMMOUSE_CMD' drivers/input/mouse/vmmouse.c:99: warning: Function parameter or member 'out3' not described in 'VMMOUSE_CMD' drivers/input/mouse/vmmouse.c:99: warning: Function parameter or member 'out4' not described in 'VMMOUSE_CMD' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20201112110204.2083435-16-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/vmmouse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/vmmouse.c b/drivers/input/mouse/vmmouse.c index 148245c69be7..42443ffba7c4 100644 --- a/drivers/input/mouse/vmmouse.c +++ b/drivers/input/mouse/vmmouse.c @@ -76,7 +76,7 @@ struct vmmouse_data { char dev_name[128]; }; -/** +/* * Hypervisor-specific bi-directional communication channel * implementing the vmmouse protocol. Should never execute on * bare metal hardware. -- cgit v1.2.3 From 59bbf83835f591b95c3bdd09d900f3584fa227af Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Fri, 20 Nov 2020 16:36:49 -0800 Subject: Input: omap4-keypad - fix runtime PM error handling In omap4_keypad_probe, the patch fix several bugs. 1) pm_runtime_get_sync will increment pm usage counter even it failed. Forgetting to pm_runtime_put_noidle will result in reference leak. 2) In err_unmap, forget to disable runtime of device, pm_runtime_enable will increase power disable depth. Thus a pairing decrement is needed on the error handling path to keep it balanced. 3) In err_pm_disable, it will call pm_runtime_put_sync twice not one time. To fix this we factor out code reading revision and disabling touchpad, and drop PM reference once we are done talking to the device. Fixes: f77621cc640a7 ("Input: omap-keypad - dynamically handle register offsets") Fixes: 5ad567ffbaf20 ("Input: omap4-keypad - wire up runtime PM handling") Signed-off-by: Zhang Qilong Link: https://lore.kernel.org/r/20201120133918.2559681-1-zhangqilong3@huawei.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/omap4-keypad.c | 89 +++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 36 deletions(-) diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index d6c924032aaa..dd16f7b3c7ef 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -186,12 +186,8 @@ static int omap4_keypad_open(struct input_dev *input) return 0; } -static void omap4_keypad_close(struct input_dev *input) +static void omap4_keypad_stop(struct omap4_keypad *keypad_data) { - struct omap4_keypad *keypad_data = input_get_drvdata(input); - - disable_irq(keypad_data->irq); - /* Disable interrupts and wake-up events */ kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE, OMAP4_VAL_IRQDISABLE); @@ -200,7 +196,15 @@ static void omap4_keypad_close(struct input_dev *input) /* clear pending interrupts */ kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); +} + +static void omap4_keypad_close(struct input_dev *input) +{ + struct omap4_keypad *keypad_data; + keypad_data = input_get_drvdata(input); + disable_irq(keypad_data->irq); + omap4_keypad_stop(keypad_data); enable_irq(keypad_data->irq); pm_runtime_put_sync(input->dev.parent); @@ -223,13 +227,37 @@ static int omap4_keypad_parse_dt(struct device *dev, return 0; } +static int omap4_keypad_check_revision(struct device *dev, + struct omap4_keypad *keypad_data) +{ + unsigned int rev; + + rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION); + rev &= 0x03 << 30; + rev >>= 30; + switch (rev) { + case KBD_REVISION_OMAP4: + keypad_data->reg_offset = 0x00; + keypad_data->irqreg_offset = 0x00; + break; + case KBD_REVISION_OMAP5: + keypad_data->reg_offset = 0x10; + keypad_data->irqreg_offset = 0x0c; + break; + default: + dev_err(dev, "Keypad reports unsupported revision %d", rev); + return -EINVAL; + } + + return 0; +} + static int omap4_keypad_probe(struct platform_device *pdev) { struct omap4_keypad *keypad_data; struct input_dev *input_dev; struct resource *res; unsigned int max_keys; - int rev; int irq; int error; @@ -269,41 +297,33 @@ static int omap4_keypad_probe(struct platform_device *pdev) goto err_release_mem; } + pm_runtime_enable(&pdev->dev); /* * Enable clocks for the keypad module so that we can read * revision register. */ - pm_runtime_enable(&pdev->dev); error = pm_runtime_get_sync(&pdev->dev); if (error) { dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); - goto err_unmap; - } - rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION); - rev &= 0x03 << 30; - rev >>= 30; - switch (rev) { - case KBD_REVISION_OMAP4: - keypad_data->reg_offset = 0x00; - keypad_data->irqreg_offset = 0x00; - break; - case KBD_REVISION_OMAP5: - keypad_data->reg_offset = 0x10; - keypad_data->irqreg_offset = 0x0c; - break; - default: - dev_err(&pdev->dev, - "Keypad reports unsupported revision %d", rev); - error = -EINVAL; - goto err_pm_put_sync; + pm_runtime_put_noidle(&pdev->dev); + } else { + error = omap4_keypad_check_revision(&pdev->dev, + keypad_data); + if (!error) { + /* Ensure device does not raise interrupts */ + omap4_keypad_stop(keypad_data); + } + pm_runtime_put_sync(&pdev->dev); } + if (error) + goto err_pm_disable; /* input device allocation */ keypad_data->input = input_dev = input_allocate_device(); if (!input_dev) { error = -ENOMEM; - goto err_pm_put_sync; + goto err_pm_disable; } input_dev->name = pdev->name; @@ -349,28 +369,25 @@ static int omap4_keypad_probe(struct platform_device *pdev) goto err_free_keymap; } - device_init_wakeup(&pdev->dev, true); - pm_runtime_put_sync(&pdev->dev); - error = input_register_device(keypad_data->input); if (error < 0) { dev_err(&pdev->dev, "failed to register input device\n"); - goto err_pm_disable; + goto err_free_irq; } + device_init_wakeup(&pdev->dev, true); platform_set_drvdata(pdev, keypad_data); + return 0; -err_pm_disable: - pm_runtime_disable(&pdev->dev); +err_free_irq: free_irq(keypad_data->irq, keypad_data); err_free_keymap: kfree(keypad_data->keymap); err_free_input: input_free_device(input_dev); -err_pm_put_sync: - pm_runtime_put_sync(&pdev->dev); -err_unmap: +err_pm_disable: + pm_runtime_disable(&pdev->dev); iounmap(keypad_data->base); err_release_mem: release_mem_region(res->start, resource_size(res)); -- cgit v1.2.3 From e9a710bc8d90cc8044b4082c2919b0663043c7ed Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sun, 22 Nov 2020 22:15:30 -0800 Subject: Input: pcspkr - fix fall-through warnings for Clang In preparation to enable -Wimplicit-fallthrough for Clang, fix a warning by explicitly adding a break statement instead of just letting the code fall through to the next case. Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/4b659e3e65f2fa3c8bb7ed153e2016c3fb395bbc.1605896059.git.gustavoars@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pcspkr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index e5e0d8ba80e1..9c666b2f14fe 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -33,6 +33,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, case SND_BELL: if (value) value = 1000; + break; case SND_TONE: break; default: -- cgit v1.2.3 From f7bda6662fd4f39113b4dee00f7ded44f846b7f4 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sun, 22 Nov 2020 22:15:43 -0800 Subject: Input: libps2 - fix fall-through warnings for Clang In preparation to enable -Wimplicit-fallthrough for Clang, fix a warning by replacing a /* Fall through */ comment with the new pseudo-keyword macro fallthrough. Notice that Clang doesn't recognize /* Fall through */ comments as implicit fall-through markings. Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/d2944854e3e118b837755abf4cbdb497662001b7.1605896060.git.gustavoars@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/serio/libps2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index 8a16e41f7b7f..250e213cc80c 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -405,7 +405,7 @@ bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data) ps2dev->nak = PS2_RET_ERR; break; } - /* Fall through */ + fallthrough; /* * Workaround for mice which don't ACK the Get ID command. -- cgit v1.2.3 From 278b13ce3a89698711c5a67792ba2dba41555433 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 2 Oct 2019 10:33:02 -0700 Subject: Input: remove input_polled_dev implementation Now that normal input devices support polling mode, and all users of input_polled_dev API have been converted, we can remove it. Signed-off-by: Dmitry Torokhov --- Documentation/driver-api/input.rst | 9 - drivers/input/Kconfig | 13 -- drivers/input/Makefile | 1 - drivers/input/input-polldev.c | 362 ------------------------------------- include/linux/input-polldev.h | 58 ------ 5 files changed, 443 deletions(-) delete mode 100644 drivers/input/input-polldev.c delete mode 100644 include/linux/input-polldev.h diff --git a/Documentation/driver-api/input.rst b/Documentation/driver-api/input.rst index d05bf58fa83e..4bbb26ae2a89 100644 --- a/Documentation/driver-api/input.rst +++ b/Documentation/driver-api/input.rst @@ -25,15 +25,6 @@ Multitouch Library .. kernel-doc:: drivers/input/input-mt.c :export: -Polled input devices --------------------- - -.. kernel-doc:: include/linux/input-polldev.h - :internal: - -.. kernel-doc:: drivers/input/input-polldev.c - :export: - Matrix keyboards/keypads ------------------------ diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 1efd3154b68d..ec0e861f185f 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -52,19 +52,6 @@ config INPUT_FF_MEMLESS To compile this driver as a module, choose M here: the module will be called ff-memless. -config INPUT_POLLDEV - tristate "Polled input device skeleton" - help - Say Y here if you are using a driver for an input - device that periodically polls hardware state. This - option is only useful for out-of-tree drivers since - in-tree drivers select it automatically. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called input-polldev. - config INPUT_SPARSEKMAP tristate "Sparse keymap support library" help diff --git a/drivers/input/Makefile b/drivers/input/Makefile index e35650930371..d8f5310e22ba 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_INPUT) += input-core.o input-core-y := input.o input-compat.o input-mt.o input-poller.o ff-core.o obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o -obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c deleted file mode 100644 index 9bf1c9aeb4c4..000000000000 --- a/drivers/input/input-polldev.c +++ /dev/null @@ -1,362 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Generic implementation of a polled input device - - * Copyright (c) 2007 Dmitry Torokhov - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Dmitry Torokhov "); -MODULE_DESCRIPTION("Generic implementation of a polled input device"); -MODULE_LICENSE("GPL v2"); - -static void input_polldev_queue_work(struct input_polled_dev *dev) -{ - unsigned long delay; - - delay = msecs_to_jiffies(dev->poll_interval); - if (delay >= HZ) - delay = round_jiffies_relative(delay); - - queue_delayed_work(system_freezable_wq, &dev->work, delay); -} - -static void input_polled_device_work(struct work_struct *work) -{ - struct input_polled_dev *dev = - container_of(work, struct input_polled_dev, work.work); - - dev->poll(dev); - input_polldev_queue_work(dev); -} - -static int input_open_polled_device(struct input_dev *input) -{ - struct input_polled_dev *dev = input_get_drvdata(input); - - if (dev->open) - dev->open(dev); - - /* Only start polling if polling is enabled */ - if (dev->poll_interval > 0) { - dev->poll(dev); - input_polldev_queue_work(dev); - } - - return 0; -} - -static void input_close_polled_device(struct input_dev *input) -{ - struct input_polled_dev *dev = input_get_drvdata(input); - - cancel_delayed_work_sync(&dev->work); - - if (dev->close) - dev->close(dev); -} - -/* SYSFS interface */ - -static ssize_t input_polldev_get_poll(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct input_polled_dev *polldev = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", polldev->poll_interval); -} - -static ssize_t input_polldev_set_poll(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) -{ - struct input_polled_dev *polldev = dev_get_drvdata(dev); - struct input_dev *input = polldev->input; - unsigned int interval; - int err; - - err = kstrtouint(buf, 0, &interval); - if (err) - return err; - - if (interval < polldev->poll_interval_min) - return -EINVAL; - - if (interval > polldev->poll_interval_max) - return -EINVAL; - - mutex_lock(&input->mutex); - - polldev->poll_interval = interval; - - if (input->users) { - cancel_delayed_work_sync(&polldev->work); - if (polldev->poll_interval > 0) - input_polldev_queue_work(polldev); - } - - mutex_unlock(&input->mutex); - - return count; -} - -static DEVICE_ATTR(poll, S_IRUGO | S_IWUSR, input_polldev_get_poll, - input_polldev_set_poll); - - -static ssize_t input_polldev_get_max(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct input_polled_dev *polldev = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", polldev->poll_interval_max); -} - -static DEVICE_ATTR(max, S_IRUGO, input_polldev_get_max, NULL); - -static ssize_t input_polldev_get_min(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct input_polled_dev *polldev = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", polldev->poll_interval_min); -} - -static DEVICE_ATTR(min, S_IRUGO, input_polldev_get_min, NULL); - -static struct attribute *sysfs_attrs[] = { - &dev_attr_poll.attr, - &dev_attr_max.attr, - &dev_attr_min.attr, - NULL -}; - -static struct attribute_group input_polldev_attribute_group = { - .attrs = sysfs_attrs -}; - -static const struct attribute_group *input_polldev_attribute_groups[] = { - &input_polldev_attribute_group, - NULL -}; - -/** - * input_allocate_polled_device - allocate memory for polled device - * - * The function allocates memory for a polled device and also - * for an input device associated with this polled device. - */ -struct input_polled_dev *input_allocate_polled_device(void) -{ - struct input_polled_dev *dev; - - dev = kzalloc(sizeof(struct input_polled_dev), GFP_KERNEL); - if (!dev) - return NULL; - - dev->input = input_allocate_device(); - if (!dev->input) { - kfree(dev); - return NULL; - } - - return dev; -} -EXPORT_SYMBOL(input_allocate_polled_device); - -struct input_polled_devres { - struct input_polled_dev *polldev; -}; - -static int devm_input_polldev_match(struct device *dev, void *res, void *data) -{ - struct input_polled_devres *devres = res; - - return devres->polldev == data; -} - -static void devm_input_polldev_release(struct device *dev, void *res) -{ - struct input_polled_devres *devres = res; - struct input_polled_dev *polldev = devres->polldev; - - dev_dbg(dev, "%s: dropping reference/freeing %s\n", - __func__, dev_name(&polldev->input->dev)); - - input_put_device(polldev->input); - kfree(polldev); -} - -static void devm_input_polldev_unregister(struct device *dev, void *res) -{ - struct input_polled_devres *devres = res; - struct input_polled_dev *polldev = devres->polldev; - - dev_dbg(dev, "%s: unregistering device %s\n", - __func__, dev_name(&polldev->input->dev)); - input_unregister_device(polldev->input); - - /* - * Note that we are still holding extra reference to the input - * device so it will stick around until devm_input_polldev_release() - * is called. - */ -} - -/** - * devm_input_allocate_polled_device - allocate managed polled device - * @dev: device owning the polled device being created - * - * Returns prepared &struct input_polled_dev or %NULL. - * - * Managed polled input devices do not need to be explicitly unregistered - * or freed as it will be done automatically when owner device unbinds - * from * its driver (or binding fails). Once such managed polled device - * is allocated, it is ready to be set up and registered in the same - * fashion as regular polled input devices (using - * input_register_polled_device() function). - * - * If you want to manually unregister and free such managed polled devices, - * it can be still done by calling input_unregister_polled_device() and - * input_free_polled_device(), although it is rarely needed. - * - * NOTE: the owner device is set up as parent of input device and users - * should not override it. - */ -struct input_polled_dev *devm_input_allocate_polled_device(struct device *dev) -{ - struct input_polled_dev *polldev; - struct input_polled_devres *devres; - - devres = devres_alloc(devm_input_polldev_release, sizeof(*devres), - GFP_KERNEL); - if (!devres) - return NULL; - - polldev = input_allocate_polled_device(); - if (!polldev) { - devres_free(devres); - return NULL; - } - - polldev->input->dev.parent = dev; - polldev->devres_managed = true; - - devres->polldev = polldev; - devres_add(dev, devres); - - return polldev; -} -EXPORT_SYMBOL(devm_input_allocate_polled_device); - -/** - * input_free_polled_device - free memory allocated for polled device - * @dev: device to free - * - * The function frees memory allocated for polling device and drops - * reference to the associated input device. - */ -void input_free_polled_device(struct input_polled_dev *dev) -{ - if (dev) { - if (dev->devres_managed) - WARN_ON(devres_destroy(dev->input->dev.parent, - devm_input_polldev_release, - devm_input_polldev_match, - dev)); - input_put_device(dev->input); - kfree(dev); - } -} -EXPORT_SYMBOL(input_free_polled_device); - -/** - * input_register_polled_device - register polled device - * @dev: device to register - * - * The function registers previously initialized polled input device - * with input layer. The device should be allocated with call to - * input_allocate_polled_device(). Callers should also set up poll() - * method and set up capabilities (id, name, phys, bits) of the - * corresponding input_dev structure. - */ -int input_register_polled_device(struct input_polled_dev *dev) -{ - struct input_polled_devres *devres = NULL; - struct input_dev *input = dev->input; - int error; - - if (dev->devres_managed) { - devres = devres_alloc(devm_input_polldev_unregister, - sizeof(*devres), GFP_KERNEL); - if (!devres) - return -ENOMEM; - - devres->polldev = dev; - } - - input_set_drvdata(input, dev); - INIT_DELAYED_WORK(&dev->work, input_polled_device_work); - - if (!dev->poll_interval) - dev->poll_interval = 500; - if (!dev->poll_interval_max) - dev->poll_interval_max = dev->poll_interval; - - input->open = input_open_polled_device; - input->close = input_close_polled_device; - - input->dev.groups = input_polldev_attribute_groups; - - error = input_register_device(input); - if (error) { - devres_free(devres); - return error; - } - - /* - * Take extra reference to the underlying input device so - * that it survives call to input_unregister_polled_device() - * and is deleted only after input_free_polled_device() - * has been invoked. This is needed to ease task of freeing - * sparse keymaps. - */ - input_get_device(input); - - if (dev->devres_managed) { - dev_dbg(input->dev.parent, "%s: registering %s with devres.\n", - __func__, dev_name(&input->dev)); - devres_add(input->dev.parent, devres); - } - - return 0; -} -EXPORT_SYMBOL(input_register_polled_device); - -/** - * input_unregister_polled_device - unregister polled device - * @dev: device to unregister - * - * The function unregisters previously registered polled input - * device from input layer. Polling is stopped and device is - * ready to be freed with call to input_free_polled_device(). - */ -void input_unregister_polled_device(struct input_polled_dev *dev) -{ - if (dev->devres_managed) - WARN_ON(devres_destroy(dev->input->dev.parent, - devm_input_polldev_unregister, - devm_input_polldev_match, - dev)); - - input_unregister_device(dev->input); -} -EXPORT_SYMBOL(input_unregister_polled_device); diff --git a/include/linux/input-polldev.h b/include/linux/input-polldev.h deleted file mode 100644 index 14821fd231c0..000000000000 --- a/include/linux/input-polldev.h +++ /dev/null @@ -1,58 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -#ifndef _INPUT_POLLDEV_H -#define _INPUT_POLLDEV_H - -/* - * Copyright (c) 2007 Dmitry Torokhov - */ - -#include -#include - -/** - * struct input_polled_dev - simple polled input device - * @private: private driver data. - * @open: driver-supplied method that prepares device for polling - * (enabled the device and maybe flushes device state). - * @close: driver-supplied method that is called when device is no - * longer being polled. Used to put device into low power mode. - * @poll: driver-supplied method that polls the device and posts - * input events (mandatory). - * @poll_interval: specifies how often the poll() method should be called. - * Defaults to 500 msec unless overridden when registering the device. - * @poll_interval_max: specifies upper bound for the poll interval. - * Defaults to the initial value of @poll_interval. - * @poll_interval_min: specifies lower bound for the poll interval. - * Defaults to 0. - * @input: input device structure associated with the polled device. - * Must be properly initialized by the driver (id, name, phys, bits). - * - * Polled input device provides a skeleton for supporting simple input - * devices that do not raise interrupts but have to be periodically - * scanned or polled to detect changes in their state. - */ -struct input_polled_dev { - void *private; - - void (*open)(struct input_polled_dev *dev); - void (*close)(struct input_polled_dev *dev); - void (*poll)(struct input_polled_dev *dev); - unsigned int poll_interval; /* msec */ - unsigned int poll_interval_max; /* msec */ - unsigned int poll_interval_min; /* msec */ - - struct input_dev *input; - -/* private: */ - struct delayed_work work; - - bool devres_managed; -}; - -struct input_polled_dev *input_allocate_polled_device(void); -struct input_polled_dev *devm_input_allocate_polled_device(struct device *dev); -void input_free_polled_device(struct input_polled_dev *dev); -int input_register_polled_device(struct input_polled_dev *dev); -void input_unregister_polled_device(struct input_polled_dev *dev); - -#endif -- cgit v1.2.3 From c1b46cd4df97534c6b942bb30526a2c47f0cb3c8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 22 Nov 2020 17:52:32 -0800 Subject: Input: omap4-keypad - set up interrupt as wakeup source Marking main interrupt as wakeup interrupt in probe allows us to drop custom suspend/resume methods whose only purpose was to configure interrupt for waking up the system. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/omap4-keypad.c | 43 +++++++---------------------------- 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index dd16f7b3c7ef..b17ac2a295b9 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -18,6 +18,7 @@ #include #include #include +#include /* OMAP4 registers */ #define OMAP4_KBD_REVISION 0x00 @@ -69,7 +70,6 @@ struct omap4_keypad { struct input_dev *input; void __iomem *base; - bool irq_wake_enabled; unsigned int irq; unsigned int rows; @@ -376,6 +376,11 @@ static int omap4_keypad_probe(struct platform_device *pdev) } device_init_wakeup(&pdev->dev, true); + error = dev_pm_set_wake_irq(&pdev->dev, keypad_data->irq); + if (error) + dev_warn(&pdev->dev, + "failed to set up wakeup irq: %d\n", error); + platform_set_drvdata(pdev, keypad_data); return 0; @@ -401,6 +406,8 @@ static int omap4_keypad_remove(struct platform_device *pdev) struct omap4_keypad *keypad_data = platform_get_drvdata(pdev); struct resource *res; + dev_pm_clear_wake_irq(&pdev->dev); + free_irq(keypad_data->irq, keypad_data); pm_runtime_disable(&pdev->dev); @@ -424,45 +431,11 @@ static const struct of_device_id omap_keypad_dt_match[] = { }; MODULE_DEVICE_TABLE(of, omap_keypad_dt_match); -#ifdef CONFIG_PM_SLEEP -static int omap4_keypad_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct omap4_keypad *keypad_data = platform_get_drvdata(pdev); - int error; - - if (device_may_wakeup(&pdev->dev)) { - error = enable_irq_wake(keypad_data->irq); - if (!error) - keypad_data->irq_wake_enabled = true; - } - - return 0; -} - -static int omap4_keypad_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct omap4_keypad *keypad_data = platform_get_drvdata(pdev); - - if (device_may_wakeup(&pdev->dev) && keypad_data->irq_wake_enabled) { - disable_irq_wake(keypad_data->irq); - keypad_data->irq_wake_enabled = false; - } - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(omap4_keypad_pm_ops, - omap4_keypad_suspend, omap4_keypad_resume); - static struct platform_driver omap4_keypad_driver = { .probe = omap4_keypad_probe, .remove = omap4_keypad_remove, .driver = { .name = "omap4-keypad", - .pm = &omap4_keypad_pm_ops, .of_match_table = omap_keypad_dt_match, }, }; -- cgit v1.2.3 From 39be39ceffd572baddfeff8b50aba931d3d6d785 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Sun, 4 Oct 2020 21:15:46 -0700 Subject: Input: add input_device_enabled() A helper function for drivers to decide if the device is used or not. A lockdep check is introduced as inspecting ->users should be done under input device's mutex. Signed-off-by: Andrzej Pietrasiewicz Link: https://lore.kernel.org/r/20200608112211.12125-2-andrzej.p@collabora.com Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 8 ++++++++ include/linux/input.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/drivers/input/input.c b/drivers/input/input.c index 3cfd2c18eebd..41377bfa142d 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -2127,6 +2127,14 @@ void input_enable_softrepeat(struct input_dev *dev, int delay, int period) } EXPORT_SYMBOL(input_enable_softrepeat); +bool input_device_enabled(struct input_dev *dev) +{ + lockdep_assert_held(&dev->mutex); + + return dev->users > 0; +} +EXPORT_SYMBOL_GPL(input_device_enabled); + /** * input_register_device - register device with input core * @dev: device to be registered diff --git a/include/linux/input.h b/include/linux/input.h index 56f2fd32e609..eda4587dba67 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -502,6 +502,8 @@ bool input_match_device_id(const struct input_dev *dev, void input_enable_softrepeat(struct input_dev *dev, int delay, int period); +bool input_device_enabled(struct input_dev *dev); + extern struct class input_class; /** -- cgit v1.2.3 From d69f0a43c677e8afc67a222e1e7b51b9acc69cd3 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Sun, 4 Oct 2020 21:16:07 -0700 Subject: Input: use input_device_enabled() Use the newly added helper in relevant input drivers. Signed-off-by: Andrzej Pietrasiewicz Link: https://lore.kernel.org/r/20200608112211.12125-3-andrzej.p@collabora.com Signed-off-by: Dmitry Torokhov --- drivers/input/input-poller.c | 2 +- drivers/input/joystick/xpad.c | 4 ++-- drivers/input/keyboard/ep93xx_keypad.c | 2 +- drivers/input/keyboard/gpio_keys.c | 4 ++-- drivers/input/keyboard/imx_keypad.c | 4 ++-- drivers/input/keyboard/ipaq-micro-keys.c | 2 +- drivers/input/keyboard/lpc32xx-keys.c | 4 ++-- drivers/input/keyboard/pmic8xxx-keypad.c | 4 ++-- drivers/input/keyboard/pxa27x_keypad.c | 2 +- drivers/input/keyboard/samsung-keypad.c | 4 ++-- drivers/input/keyboard/spear-keyboard.c | 8 ++++---- drivers/input/keyboard/st-keyscan.c | 4 ++-- drivers/input/keyboard/tegra-kbc.c | 4 ++-- drivers/input/misc/drv260x.c | 4 ++-- drivers/input/misc/drv2665.c | 4 ++-- drivers/input/misc/drv2667.c | 4 ++-- drivers/input/misc/kxtj9.c | 4 ++-- drivers/input/misc/sirfsoc-onkey.c | 2 +- drivers/input/mouse/cyapa.c | 6 +++--- drivers/input/mouse/cyapa_gen3.c | 3 ++- drivers/input/mouse/cyapa_gen5.c | 3 ++- drivers/input/mouse/navpoint.c | 4 ++-- drivers/input/touchscreen/ad7879.c | 6 +++--- drivers/input/touchscreen/atmel_mxt_ts.c | 4 ++-- drivers/input/touchscreen/auo-pixcir-ts.c | 8 ++++---- drivers/input/touchscreen/bu21029_ts.c | 4 ++-- drivers/input/touchscreen/chipone_icn8318.c | 4 ++-- drivers/input/touchscreen/cyttsp_core.c | 4 ++-- drivers/input/touchscreen/eeti_ts.c | 4 ++-- drivers/input/touchscreen/ektf2127.c | 4 ++-- drivers/input/touchscreen/imx6ul_tsc.c | 4 ++-- drivers/input/touchscreen/ipaq-micro-ts.c | 2 +- drivers/input/touchscreen/iqs5xx.c | 4 ++-- drivers/input/touchscreen/lpc32xx_ts.c | 4 ++-- drivers/input/touchscreen/melfas_mip4.c | 8 ++++---- drivers/input/touchscreen/mms114.c | 6 +++--- drivers/input/touchscreen/pixcir_i2c_ts.c | 8 ++++---- drivers/input/touchscreen/ucb1400_ts.c | 4 ++-- drivers/input/touchscreen/wm97xx-core.c | 14 +++++++++----- drivers/input/touchscreen/zforce_ts.c | 8 ++++---- drivers/input/touchscreen/zinitix.c | 4 ++-- 41 files changed, 96 insertions(+), 90 deletions(-) diff --git a/drivers/input/input-poller.c b/drivers/input/input-poller.c index 7d6b4e8879f1..688e3cb1c2a0 100644 --- a/drivers/input/input-poller.c +++ b/drivers/input/input-poller.c @@ -166,7 +166,7 @@ static ssize_t input_dev_set_poll_interval(struct device *dev, poller->poll_interval = interval; - if (input->users) { + if (input_device_enabled(input)) { cancel_delayed_work_sync(&poller->work); if (poller->poll_interval > 0) input_dev_poller_queue_work(poller); diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 2cd4296c2d08..e64c76c34fc1 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -1902,7 +1902,7 @@ static int xpad_suspend(struct usb_interface *intf, pm_message_t message) xpad360w_poweroff_controller(xpad); } else { mutex_lock(&input->mutex); - if (input->users) + if (input_device_enabled(input)) xpad_stop_input(xpad); mutex_unlock(&input->mutex); } @@ -1922,7 +1922,7 @@ static int xpad_resume(struct usb_interface *intf) retval = xpad360w_start_input(xpad); } else { mutex_lock(&input->mutex); - if (input->users) { + if (input_device_enabled(input)) { retval = xpad_start_input(xpad); } else if (xpad->xtype == XTYPE_XBOXONE) { /* diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index f831f01501d5..c8194333d612 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -208,7 +208,7 @@ static int ep93xx_keypad_resume(struct device *dev) mutex_lock(&input_dev->mutex); - if (input_dev->users) { + if (input_device_enabled(input_dev)) { if (!keypad->enabled) { ep93xx_keypad_config(keypad); clk_enable(keypad->clk); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index a079504e98e8..77bac4ddf324 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -965,7 +965,7 @@ static int __maybe_unused gpio_keys_suspend(struct device *dev) return error; } else { mutex_lock(&input->mutex); - if (input->users) + if (input_device_enabled(input)) gpio_keys_close(input); mutex_unlock(&input->mutex); } @@ -983,7 +983,7 @@ static int __maybe_unused gpio_keys_resume(struct device *dev) gpio_keys_disable_wakeup(ddata); } else { mutex_lock(&input->mutex); - if (input->users) + if (input_device_enabled(input)) error = gpio_keys_open(input); mutex_unlock(&input->mutex); } diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index 5a46d113e909..1f5c9ea5e9e5 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -532,7 +532,7 @@ static int __maybe_unused imx_kbd_noirq_suspend(struct device *dev) /* imx kbd can wake up system even clock is disabled */ mutex_lock(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) clk_disable_unprepare(kbd->clk); mutex_unlock(&input_dev->mutex); @@ -562,7 +562,7 @@ static int __maybe_unused imx_kbd_noirq_resume(struct device *dev) mutex_lock(&input_dev->mutex); - if (input_dev->users) { + if (input_device_enabled(input_dev)) { ret = clk_prepare_enable(kbd->clk); if (ret) goto err_clk; diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c index e3f9e445e880..13a66a8e3411 100644 --- a/drivers/input/keyboard/ipaq-micro-keys.c +++ b/drivers/input/keyboard/ipaq-micro-keys.c @@ -140,7 +140,7 @@ static int __maybe_unused micro_key_resume(struct device *dev) mutex_lock(&input->mutex); - if (input->users) + if (input_device_enabled(input)) micro_key_start(keys); mutex_unlock(&input->mutex); diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c index 348af2aeb5de..943aeeb0de79 100644 --- a/drivers/input/keyboard/lpc32xx-keys.c +++ b/drivers/input/keyboard/lpc32xx-keys.c @@ -273,7 +273,7 @@ static int lpc32xx_kscan_suspend(struct device *dev) mutex_lock(&input->mutex); - if (input->users) { + if (input_device_enabled(input)) { /* Clear IRQ and disable clock */ writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); clk_disable_unprepare(kscandat->clk); @@ -292,7 +292,7 @@ static int lpc32xx_kscan_resume(struct device *dev) mutex_lock(&input->mutex); - if (input->users) { + if (input_device_enabled(input)) { /* Enable clock and clear IRQ */ retval = clk_prepare_enable(kscandat->clk); if (retval == 0) diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index 36bee6f5a8af..4766c5048ce2 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -633,7 +633,7 @@ static int pmic8xxx_kp_suspend(struct device *dev) } else { mutex_lock(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) pmic8xxx_kp_disable(kp); mutex_unlock(&input_dev->mutex); @@ -653,7 +653,7 @@ static int pmic8xxx_kp_resume(struct device *dev) } else { mutex_lock(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) pmic8xxx_kp_enable(kp); mutex_unlock(&input_dev->mutex); diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 7e65708b25a4..a7f8257c8a02 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -694,7 +694,7 @@ static int pxa27x_keypad_resume(struct device *dev) } else { mutex_lock(&input_dev->mutex); - if (input_dev->users) { + if (input_device_enabled(input_dev)) { /* Enable unit clock */ ret = clk_prepare_enable(keypad->clk); if (!ret) diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 1ed939d9798c..df0258dcf89e 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -536,7 +536,7 @@ static int samsung_keypad_suspend(struct device *dev) mutex_lock(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) samsung_keypad_stop(keypad); samsung_keypad_toggle_wakeup(keypad, true); @@ -556,7 +556,7 @@ static int samsung_keypad_resume(struct device *dev) samsung_keypad_toggle_wakeup(keypad, false); - if (input_dev->users) + if (input_device_enabled(input_dev)) samsung_keypad_start(keypad); mutex_unlock(&input_dev->mutex); diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index 9b8d78f87253..9838c79cb288 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -318,7 +318,7 @@ static int __maybe_unused spear_kbd_suspend(struct device *dev) writel_relaxed(val, kbd->io_base + MODE_CTL_REG); } else { - if (input_dev->users) { + if (input_device_enabled(input_dev)) { writel_relaxed(mode_ctl_reg & ~MODE_CTL_START_SCAN, kbd->io_base + MODE_CTL_REG); clk_disable(kbd->clk); @@ -326,7 +326,7 @@ static int __maybe_unused spear_kbd_suspend(struct device *dev) } /* store current configuration */ - if (input_dev->users) + if (input_device_enabled(input_dev)) kbd->mode_ctl_reg = mode_ctl_reg; /* restore previous clk state */ @@ -351,12 +351,12 @@ static int __maybe_unused spear_kbd_resume(struct device *dev) disable_irq_wake(kbd->irq); } } else { - if (input_dev->users) + if (input_device_enabled(input_dev)) clk_enable(kbd->clk); } /* restore current configuration */ - if (input_dev->users) + if (input_device_enabled(input_dev)) writel_relaxed(kbd->mode_ctl_reg, kbd->io_base + MODE_CTL_REG); mutex_unlock(&input_dev->mutex); diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c index 27562cd67fb6..a045d61165ac 100644 --- a/drivers/input/keyboard/st-keyscan.c +++ b/drivers/input/keyboard/st-keyscan.c @@ -221,7 +221,7 @@ static int keyscan_suspend(struct device *dev) if (device_may_wakeup(dev)) enable_irq_wake(keypad->irq); - else if (input->users) + else if (input_device_enabled(input)) keyscan_stop(keypad); mutex_unlock(&input->mutex); @@ -239,7 +239,7 @@ static int keyscan_resume(struct device *dev) if (device_may_wakeup(dev)) disable_irq_wake(keypad->irq); - else if (input->users) + else if (input_device_enabled(input)) retval = keyscan_start(keypad); mutex_unlock(&input->mutex); diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index d34d6947960f..9671842a082a 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -756,7 +756,7 @@ static int tegra_kbc_suspend(struct device *dev) enable_irq(kbc->irq); enable_irq_wake(kbc->irq); } else { - if (kbc->idev->users) + if (input_device_enabled(kbc->idev)) tegra_kbc_stop(kbc); } mutex_unlock(&kbc->idev->mutex); @@ -796,7 +796,7 @@ static int tegra_kbc_resume(struct device *dev) input_sync(kbc->idev); } } else { - if (kbc->idev->users) + if (input_device_enabled(kbc->idev)) err = tegra_kbc_start(kbc); } mutex_unlock(&kbc->idev->mutex); diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index cc51de7759a0..0efe56f49aa9 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -580,7 +580,7 @@ static int __maybe_unused drv260x_suspend(struct device *dev) mutex_lock(&haptics->input_dev->mutex); - if (haptics->input_dev->users) { + if (input_device_enabled(haptics->input_dev)) { ret = regmap_update_bits(haptics->regmap, DRV260X_MODE, DRV260X_STANDBY_MASK, @@ -612,7 +612,7 @@ static int __maybe_unused drv260x_resume(struct device *dev) mutex_lock(&haptics->input_dev->mutex); - if (haptics->input_dev->users) { + if (input_device_enabled(haptics->input_dev)) { ret = regulator_enable(haptics->regulator); if (ret) { dev_err(dev, "Failed to enable regulator\n"); diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index 0e65ab180f49..21913e8085d7 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -230,7 +230,7 @@ static int __maybe_unused drv2665_suspend(struct device *dev) mutex_lock(&haptics->input_dev->mutex); - if (haptics->input_dev->users) { + if (input_device_enabled(haptics->input_dev)) { ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, DRV2665_STANDBY, DRV2665_STANDBY); if (ret) { @@ -259,7 +259,7 @@ static int __maybe_unused drv2665_resume(struct device *dev) mutex_lock(&haptics->input_dev->mutex); - if (haptics->input_dev->users) { + if (input_device_enabled(haptics->input_dev)) { ret = regulator_enable(haptics->regulator); if (ret) { dev_err(dev, "Failed to enable regulator\n"); diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index dc19eb6a8713..3f67b9b010bf 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -407,7 +407,7 @@ static int __maybe_unused drv2667_suspend(struct device *dev) mutex_lock(&haptics->input_dev->mutex); - if (haptics->input_dev->users) { + if (input_device_enabled(haptics->input_dev)) { ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, DRV2667_STANDBY, DRV2667_STANDBY); if (ret) { @@ -436,7 +436,7 @@ static int __maybe_unused drv2667_resume(struct device *dev) mutex_lock(&haptics->input_dev->mutex); - if (haptics->input_dev->users) { + if (input_device_enabled(haptics->input_dev)) { ret = regulator_enable(haptics->regulator); if (ret) { dev_err(dev, "Failed to enable regulator\n"); diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index 52313c6e3fb3..bbb81617c2b2 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -503,7 +503,7 @@ static int __maybe_unused kxtj9_suspend(struct device *dev) mutex_lock(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) kxtj9_disable(tj9); mutex_unlock(&input_dev->mutex); @@ -518,7 +518,7 @@ static int __maybe_unused kxtj9_resume(struct device *dev) mutex_lock(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) kxtj9_enable(tj9); mutex_unlock(&input_dev->mutex); diff --git a/drivers/input/misc/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c index 60e1f31ee60a..7982bf8fb839 100644 --- a/drivers/input/misc/sirfsoc-onkey.c +++ b/drivers/input/misc/sirfsoc-onkey.c @@ -181,7 +181,7 @@ static int __maybe_unused sirfsoc_pwrc_resume(struct device *dev) * if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c */ mutex_lock(&input->mutex); - if (input->users) + if (input_device_enabled(input)) sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true); mutex_unlock(&input->mutex); diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index dacf7c0e43f9..3f4069511b13 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -526,7 +526,7 @@ static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa) { struct input_dev *input = cyapa->input; - if (!input || !input->users) { + if (!input || !input_device_enabled(input)) { /* * When input is NULL, TP must be in deep sleep mode. * In this mode, later non-power I2C command will always failed @@ -546,7 +546,7 @@ static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa) { struct input_dev *input = cyapa->input; - if (!input || !input->users) { + if (!input || !input_device_enabled(input)) { if (cyapa->gen >= CYAPA_GEN5) disable_irq(cyapa->client->irq); if (!input || cyapa->operational) @@ -652,7 +652,7 @@ static int cyapa_reinitialize(struct cyapa *cyapa) } out: - if (!input || !input->users) { + if (!input || !input_device_enabled(input)) { /* Reset to power OFF state to save power when no user open. */ if (cyapa->operational) cyapa->ops->set_power_mode(cyapa, diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c index a0361f9325f8..a97f4acb6452 100644 --- a/drivers/input/mouse/cyapa_gen3.c +++ b/drivers/input/mouse/cyapa_gen3.c @@ -952,7 +952,8 @@ static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode, * doing so before issuing the next command may result in errors * depending on the command's content. */ - if (cyapa->operational && input && input->users && + if (cyapa->operational && + input && input_device_enabled(input) && (pm_stage == CYAPA_PM_RUNTIME_SUSPEND || pm_stage == CYAPA_PM_RUNTIME_RESUME)) { /* Try to polling in 120Hz, read may fail, just ignore it. */ diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index 5c37af994b5b..abf42f77b4c5 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -518,7 +518,8 @@ int cyapa_empty_pip_output_data(struct cyapa *cyapa, *len = length; /* Response found, success. */ return 0; - } else if (cyapa->operational && input && input->users && + } else if (cyapa->operational && + input && input_device_enabled(input) && (pm_stage == CYAPA_PM_RUNTIME_RESUME || pm_stage == CYAPA_PM_RUNTIME_SUSPEND)) { /* Parse the data and report it if it's valid. */ diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c index c112980c2341..4d67575bb276 100644 --- a/drivers/input/mouse/navpoint.c +++ b/drivers/input/mouse/navpoint.c @@ -322,7 +322,7 @@ static int __maybe_unused navpoint_suspend(struct device *dev) struct input_dev *input = navpoint->input; mutex_lock(&input->mutex); - if (input->users) + if (input_device_enabled(input)) navpoint_down(navpoint); mutex_unlock(&input->mutex); @@ -336,7 +336,7 @@ static int __maybe_unused navpoint_resume(struct device *dev) struct input_dev *input = navpoint->input; mutex_lock(&input->mutex); - if (input->users) + if (input_device_enabled(input)) navpoint_up(navpoint); mutex_unlock(&input->mutex); diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 556a2af46e18..e850853328f1 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -306,7 +306,7 @@ static int __maybe_unused ad7879_suspend(struct device *dev) mutex_lock(&ts->input->mutex); - if (!ts->suspended && !ts->disabled && ts->input->users) + if (!ts->suspended && !ts->disabled && input_device_enabled(ts->input)) __ad7879_disable(ts); ts->suspended = true; @@ -322,7 +322,7 @@ static int __maybe_unused ad7879_resume(struct device *dev) mutex_lock(&ts->input->mutex); - if (ts->suspended && !ts->disabled && ts->input->users) + if (ts->suspended && !ts->disabled && input_device_enabled(ts->input)) __ad7879_enable(ts); ts->suspended = false; @@ -339,7 +339,7 @@ static void ad7879_toggle(struct ad7879 *ts, bool disable) { mutex_lock(&ts->input->mutex); - if (!ts->suspended && ts->input->users != 0) { + if (!ts->suspended && input_device_enabled(ts->input)) { if (disable) { if (ts->disabled) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index e34984388791..dde364dfb79d 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -3237,7 +3237,7 @@ static int __maybe_unused mxt_suspend(struct device *dev) mutex_lock(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) mxt_stop(data); mutex_unlock(&input_dev->mutex); @@ -3260,7 +3260,7 @@ static int __maybe_unused mxt_resume(struct device *dev) mutex_lock(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) mxt_start(data); mutex_unlock(&input_dev->mutex); diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index 8e9f3b7b8180..c33e63ca6142 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -414,7 +414,7 @@ static int __maybe_unused auo_pixcir_suspend(struct device *dev) */ if (device_may_wakeup(&client->dev)) { /* need to start device if not open, to be wakeup source */ - if (!input->users) { + if (!input_device_enabled(input)) { ret = auo_pixcir_start(ts); if (ret) goto unlock; @@ -422,7 +422,7 @@ static int __maybe_unused auo_pixcir_suspend(struct device *dev) enable_irq_wake(client->irq); ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_SLEEP); - } else if (input->users) { + } else if (input_device_enabled(input)) { ret = auo_pixcir_stop(ts); } @@ -445,14 +445,14 @@ static int __maybe_unused auo_pixcir_resume(struct device *dev) disable_irq_wake(client->irq); /* need to stop device if it was not open on suspend */ - if (!input->users) { + if (!input_device_enabled(input)) { ret = auo_pixcir_stop(ts); if (ret) goto unlock; } /* device wakes automatically from SLEEP */ - } else if (input->users) { + } else if (input_device_enabled(input)) { ret = auo_pixcir_start(ts); } diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c index 49a8d4bbca3a..341925edb8e6 100644 --- a/drivers/input/touchscreen/bu21029_ts.c +++ b/drivers/input/touchscreen/bu21029_ts.c @@ -430,7 +430,7 @@ static int __maybe_unused bu21029_suspend(struct device *dev) if (!device_may_wakeup(dev)) { mutex_lock(&bu21029->in_dev->mutex); - if (bu21029->in_dev->users) + if (input_device_enabled(bu21029->in_dev)) bu21029_stop_chip(bu21029->in_dev); mutex_unlock(&bu21029->in_dev->mutex); } @@ -445,7 +445,7 @@ static int __maybe_unused bu21029_resume(struct device *dev) if (!device_may_wakeup(dev)) { mutex_lock(&bu21029->in_dev->mutex); - if (bu21029->in_dev->users) + if (input_device_enabled(bu21029->in_dev)) bu21029_start_chip(bu21029->in_dev); mutex_unlock(&bu21029->in_dev->mutex); } diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c index d91d2fd78649..f2fb41fb031e 100644 --- a/drivers/input/touchscreen/chipone_icn8318.c +++ b/drivers/input/touchscreen/chipone_icn8318.c @@ -154,7 +154,7 @@ static int icn8318_suspend(struct device *dev) struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev)); mutex_lock(&data->input->mutex); - if (data->input->users) + if (input_device_enabled(data->input)) icn8318_stop(data->input); mutex_unlock(&data->input->mutex); @@ -166,7 +166,7 @@ static int icn8318_resume(struct device *dev) struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev)); mutex_lock(&data->input->mutex); - if (data->input->users) + if (input_device_enabled(data->input)) icn8318_start(data->input); mutex_unlock(&data->input->mutex); diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c index 697aa2c158f7..73c854f35f33 100644 --- a/drivers/input/touchscreen/cyttsp_core.c +++ b/drivers/input/touchscreen/cyttsp_core.c @@ -479,7 +479,7 @@ static int __maybe_unused cyttsp_suspend(struct device *dev) mutex_lock(&ts->input->mutex); - if (ts->input->users) { + if (input_device_enabled(ts->input)) { retval = cyttsp_disable(ts); if (retval == 0) ts->suspended = true; @@ -496,7 +496,7 @@ static int __maybe_unused cyttsp_resume(struct device *dev) mutex_lock(&ts->input->mutex); - if (ts->input->users) + if (input_device_enabled(ts->input)) cyttsp_enable(ts); ts->suspended = false; diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 2e1404cd09ec..a639ba7e56ea 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -241,7 +241,7 @@ static int __maybe_unused eeti_ts_suspend(struct device *dev) mutex_lock(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) eeti_ts_stop(eeti); mutex_unlock(&input_dev->mutex); @@ -263,7 +263,7 @@ static int __maybe_unused eeti_ts_resume(struct device *dev) mutex_lock(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) eeti_ts_start(eeti); mutex_unlock(&input_dev->mutex); diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c index 491de67ddbcd..2d01a8cbfcc6 100644 --- a/drivers/input/touchscreen/ektf2127.c +++ b/drivers/input/touchscreen/ektf2127.c @@ -182,7 +182,7 @@ static int __maybe_unused ektf2127_suspend(struct device *dev) struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev)); mutex_lock(&ts->input->mutex); - if (ts->input->users) + if (input_device_enabled(ts->input)) ektf2127_stop(ts->input); mutex_unlock(&ts->input->mutex); @@ -194,7 +194,7 @@ static int __maybe_unused ektf2127_resume(struct device *dev) struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev)); mutex_lock(&ts->input->mutex); - if (ts->input->users) + if (input_device_enabled(ts->input)) ektf2127_start(ts->input); mutex_unlock(&ts->input->mutex); diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index e1852f7d4d31..2d4facf70cdb 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -520,7 +520,7 @@ static int __maybe_unused imx6ul_tsc_suspend(struct device *dev) mutex_lock(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) imx6ul_tsc_stop(tsc); mutex_unlock(&input_dev->mutex); @@ -537,7 +537,7 @@ static int __maybe_unused imx6ul_tsc_resume(struct device *dev) mutex_lock(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) retval = imx6ul_tsc_start(tsc); mutex_unlock(&input_dev->mutex); diff --git a/drivers/input/touchscreen/ipaq-micro-ts.c b/drivers/input/touchscreen/ipaq-micro-ts.c index 5c3977e1af6f..0eb5689fe65f 100644 --- a/drivers/input/touchscreen/ipaq-micro-ts.c +++ b/drivers/input/touchscreen/ipaq-micro-ts.c @@ -135,7 +135,7 @@ static int __maybe_unused micro_ts_resume(struct device *dev) mutex_lock(&input->mutex); - if (input->users) + if (input_device_enabled(input)) micro_ts_toggle_receive(ts, true); mutex_unlock(&input->mutex); diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index 3162b68f7374..4fd21bc3ce0f 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -1017,7 +1017,7 @@ static int __maybe_unused iqs5xx_suspend(struct device *dev) mutex_lock(&input->mutex); - if (input->users) + if (input_device_enabled(input)) error = iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND); mutex_unlock(&input->mutex); @@ -1036,7 +1036,7 @@ static int __maybe_unused iqs5xx_resume(struct device *dev) mutex_lock(&input->mutex); - if (input->users) + if (input_device_enabled(input)) error = iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME); mutex_unlock(&input->mutex); diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index b2cd9472e2d1..b51450b3d943 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -334,7 +334,7 @@ static int lpc32xx_ts_suspend(struct device *dev) */ mutex_lock(&input->mutex); - if (input->users) { + if (input_device_enabled(input)) { if (device_may_wakeup(dev)) enable_irq_wake(tsc->irq); else @@ -353,7 +353,7 @@ static int lpc32xx_ts_resume(struct device *dev) mutex_lock(&input->mutex); - if (input->users) { + if (input_device_enabled(input)) { if (device_may_wakeup(dev)) disable_irq_wake(tsc->irq); else diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index f67efdd040b2..c0050044a5a9 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -1256,7 +1256,7 @@ static int mip4_execute_fw_update(struct mip4_ts *ts, const struct firmware *fw) if (error) return error; - if (ts->input->users) { + if (input_device_enabled(ts->input)) { disable_irq(ts->client->irq); } else { error = mip4_power_on(ts); @@ -1276,7 +1276,7 @@ static int mip4_execute_fw_update(struct mip4_ts *ts, const struct firmware *fw) "Failed to flash firmware: %d\n", error); /* Enable IRQ */ - if (ts->input->users) + if (input_device_enabled(ts->input)) enable_irq(ts->client->irq); else mip4_power_off(ts); @@ -1539,7 +1539,7 @@ static int __maybe_unused mip4_suspend(struct device *dev) if (device_may_wakeup(dev)) ts->wake_irq_enabled = enable_irq_wake(client->irq) == 0; - else if (input->users) + else if (input_device_enabled(input)) mip4_disable(ts); mutex_unlock(&input->mutex); @@ -1557,7 +1557,7 @@ static int __maybe_unused mip4_resume(struct device *dev) if (ts->wake_irq_enabled) disable_irq_wake(client->irq); - else if (input->users) + else if (input_device_enabled(input)) mip4_enable(ts); mutex_unlock(&input->mutex); diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 1f96657310b7..16557f51b09d 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -199,7 +199,7 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id) int error; mutex_lock(&input_dev->mutex); - if (!input_dev->users) { + if (!input_device_enabled(input_dev)) { mutex_unlock(&input_dev->mutex); goto out; } @@ -564,7 +564,7 @@ static int __maybe_unused mms114_suspend(struct device *dev) input_sync(input_dev); mutex_lock(&input_dev->mutex); - if (input_dev->users) + if (input_device_enabled(input_dev)) mms114_stop(data); mutex_unlock(&input_dev->mutex); @@ -579,7 +579,7 @@ static int __maybe_unused mms114_resume(struct device *dev) int error; mutex_lock(&input_dev->mutex); - if (input_dev->users) { + if (input_device_enabled(input_dev)) { error = mms114_start(data); if (error < 0) { mutex_unlock(&input_dev->mutex); diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 9aa098577350..dc148b4bed74 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -415,14 +415,14 @@ static int __maybe_unused pixcir_i2c_ts_suspend(struct device *dev) mutex_lock(&input->mutex); if (device_may_wakeup(&client->dev)) { - if (!input->users) { + if (!input_device_enabled(input)) { ret = pixcir_start(ts); if (ret) { dev_err(dev, "Failed to start\n"); goto unlock; } } - } else if (input->users) { + } else if (input_device_enabled(input)) { ret = pixcir_stop(ts); } @@ -442,14 +442,14 @@ static int __maybe_unused pixcir_i2c_ts_resume(struct device *dev) mutex_lock(&input->mutex); if (device_may_wakeup(&client->dev)) { - if (!input->users) { + if (!input_device_enabled(input)) { ret = pixcir_stop(ts); if (ret) { dev_err(dev, "Failed to stop\n"); goto unlock; } } - } else if (input->users) { + } else if (input_device_enabled(input)) { ret = pixcir_start(ts); } diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 807d39e18091..e3f2c940ef3d 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -410,7 +410,7 @@ static int __maybe_unused ucb1400_ts_suspend(struct device *dev) mutex_lock(&idev->mutex); - if (idev->users) + if (input_device_enabled(idev)) ucb1400_ts_stop(ucb); mutex_unlock(&idev->mutex); @@ -424,7 +424,7 @@ static int __maybe_unused ucb1400_ts_resume(struct device *dev) mutex_lock(&idev->mutex); - if (idev->users) + if (input_device_enabled(idev)) ucb1400_ts_start(ucb); mutex_unlock(&idev->mutex); diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 45ce89467c16..78d2ee99f37a 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -806,23 +806,25 @@ static int __maybe_unused wm97xx_suspend(struct device *dev) else suspend_mode = 0; - if (wm->input_dev->users) + mutex_lock(&wm->input_dev->mutex); + if (input_device_enabled(wm->input_dev)) cancel_delayed_work_sync(&wm->ts_reader); /* Power down the digitiser (bypassing the cache for resume) */ reg = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER2); reg &= ~WM97XX_PRP_DET_DIG; - if (wm->input_dev->users) + if (input_device_enabled(wm->input_dev)) reg |= suspend_mode; wm->ac97->bus->ops->write(wm->ac97, AC97_WM97XX_DIGITISER2, reg); /* WM9713 has an additional power bit - turn it off if there * are no users or if suspend mode is zero. */ if (wm->id == WM9713_ID2 && - (!wm->input_dev->users || !suspend_mode)) { + (!input_device_enabled(wm->input_dev) || !suspend_mode)) { reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) | 0x8000; wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg); } + mutex_unlock(&wm->input_dev->mutex); return 0; } @@ -831,11 +833,12 @@ static int __maybe_unused wm97xx_resume(struct device *dev) { struct wm97xx *wm = dev_get_drvdata(dev); + mutex_lock(&wm->input_dev->mutex); /* restore digitiser and gpios */ if (wm->id == WM9713_ID2) { wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig[0]); wm97xx_reg_write(wm, 0x5a, wm->misc); - if (wm->input_dev->users) { + if (input_device_enabled(wm->input_dev)) { u16 reg; reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) & 0x7fff; wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg); @@ -852,11 +855,12 @@ static int __maybe_unused wm97xx_resume(struct device *dev) wm97xx_reg_write(wm, AC97_GPIO_STATUS, wm->gpio[4]); wm97xx_reg_write(wm, AC97_MISC_AFE, wm->gpio[5]); - if (wm->input_dev->users && !wm->pen_irq) { + if (input_device_enabled(wm->input_dev) && !wm->pen_irq) { wm->ts_reader_interval = wm->ts_reader_min_interval; queue_delayed_work(wm->ts_workq, &wm->ts_reader, wm->ts_reader_interval); } + mutex_unlock(&wm->input_dev->mutex); return 0; } diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 5230519b0f74..495629628af6 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -626,14 +626,14 @@ static int __maybe_unused zforce_suspend(struct device *dev) dev_dbg(&client->dev, "suspend while being a wakeup source\n"); /* Need to start device, if not open, to be a wakeup source. */ - if (!input->users) { + if (!input_device_enabled(input)) { ret = zforce_start(ts); if (ret) goto unlock; } enable_irq_wake(client->irq); - } else if (input->users) { + } else if (input_device_enabled(input)) { dev_dbg(&client->dev, "suspend without being a wakeup source\n"); @@ -670,12 +670,12 @@ static int __maybe_unused zforce_resume(struct device *dev) disable_irq_wake(client->irq); /* need to stop device if it was not open on suspend */ - if (!input->users) { + if (!input_device_enabled(input)) { ret = zforce_stop(ts); if (ret) goto unlock; } - } else if (input->users) { + } else if (input_device_enabled(input)) { dev_dbg(&client->dev, "resume without being a wakeup source\n"); enable_irq(client->irq); diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c index 1acc2eb2bcb3..a3e3adbabc67 100644 --- a/drivers/input/touchscreen/zinitix.c +++ b/drivers/input/touchscreen/zinitix.c @@ -532,7 +532,7 @@ static int __maybe_unused zinitix_suspend(struct device *dev) mutex_lock(&bt541->input_dev->mutex); - if (bt541->input_dev->users) + if (input_device_enabled(bt541->input_dev)) zinitix_stop(bt541); mutex_unlock(&bt541->input_dev->mutex); @@ -548,7 +548,7 @@ static int __maybe_unused zinitix_resume(struct device *dev) mutex_lock(&bt541->input_dev->mutex); - if (bt541->input_dev->users) + if (input_device_enabled(bt541->input_dev)) ret = zinitix_start(bt541); mutex_unlock(&bt541->input_dev->mutex); -- cgit v1.2.3 From a181616487dbdbc953e476d1da15365f887859ed Mon Sep 17 00:00:00 2001 From: Patrik Fimml Date: Wed, 2 Dec 2020 14:42:04 -0800 Subject: Input: Add "inhibited" property Userspace might want to implement a policy to temporarily disregard input from certain devices, including not treating them as wakeup sources. An example use case is a laptop, whose keyboard can be folded under the screen to create tablet-like experience. The user then must hold the laptop in such a way that it is difficult to avoid pressing the keyboard keys. It is therefore desirable to temporarily disregard input from the keyboard, until it is folded back. This obviously is a policy which should be kept out of the kernel, but the kernel must provide suitable means to implement such a policy. This patch adds a sysfs interface for exactly this purpose. To implement the said interface it adds an "inhibited" property to struct input_dev, and effectively creates four states a device can be in: closed uninhibited, closed inhibited, open uninhibited, open inhibited. It also defers calling driver's ->open() and ->close() to until they are actually needed, e.g. it makes no sense to prepare the underlying device for generating events (->open()) if the device is inhibited. uninhibit closed <------------ closed uninhibited ------------> inhibited | ^ inhibit | ^ 1st | | 1st | | open | | open | | | | | | | | last | | last | | close | | close v | uninhibit v | open <------------ open uninhibited ------------> inhibited The top inhibit/uninhibit transition happens when users == 0. The bottom inhibit/uninhibit transition happens when users > 0. The left open/close transition happens when !inhibited. The right open/close transition happens when inhibited. Due to all transitions being serialized with dev->mutex, it is impossible to have "diagonal" transitions between closed uninhibited and open inhibited or between open uninhibited and closed inhibited. No new callbacks are added to drivers, because their open() and close() serve exactly the purpose to tell the driver to start/stop providing events to the input core. Consequently, open() and close() - if provided - are called in both inhibit and uninhibit paths. Signed-off-by: Patrik Fimml Co-developed-by: Andrzej Pietrasiewicz Signed-off-by: Andrzej Pietrasiewicz Link: https://lore.kernel.org/r/20200608112211.12125-8-andrzej.p@collabora.com Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++---- include/linux/input.h | 12 +++++- 2 files changed, 115 insertions(+), 9 deletions(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index 41377bfa142d..ccaeb2426385 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -367,8 +367,13 @@ static int input_get_disposition(struct input_dev *dev, static void input_handle_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { - int disposition = input_get_disposition(dev, type, code, &value); + int disposition; + /* filter-out events from inhibited devices */ + if (dev->inhibited) + return; + + disposition = input_get_disposition(dev, type, code, &value); if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) add_input_randomness(type, code, value); @@ -612,10 +617,10 @@ int input_open_device(struct input_handle *handle) handle->open++; - if (dev->users++) { + if (dev->users++ || dev->inhibited) { /* - * Device is already opened, so we can exit immediately and - * report success. + * Device is already opened and/or inhibited, + * so we can exit immediately and report success. */ goto out; } @@ -675,10 +680,9 @@ void input_close_device(struct input_handle *handle) __input_release_device(handle); - if (!--dev->users) { + if (!dev->inhibited && !--dev->users) { if (dev->poller) input_dev_poller_stop(dev->poller); - if (dev->close) dev->close(dev); } @@ -1416,12 +1420,49 @@ static ssize_t input_dev_show_properties(struct device *dev, } static DEVICE_ATTR(properties, S_IRUGO, input_dev_show_properties, NULL); +static int input_inhibit_device(struct input_dev *dev); +static int input_uninhibit_device(struct input_dev *dev); + +static ssize_t inhibited_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input_dev = to_input_dev(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", input_dev->inhibited); +} + +static ssize_t inhibited_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t len) +{ + struct input_dev *input_dev = to_input_dev(dev); + ssize_t rv; + bool inhibited; + + if (strtobool(buf, &inhibited)) + return -EINVAL; + + if (inhibited) + rv = input_inhibit_device(input_dev); + else + rv = input_uninhibit_device(input_dev); + + if (rv != 0) + return rv; + + return len; +} + +static DEVICE_ATTR_RW(inhibited); + static struct attribute *input_dev_attrs[] = { &dev_attr_name.attr, &dev_attr_phys.attr, &dev_attr_uniq.attr, &dev_attr_modalias.attr, &dev_attr_properties.attr, + &dev_attr_inhibited.attr, NULL }; @@ -1703,6 +1744,63 @@ void input_reset_device(struct input_dev *dev) } EXPORT_SYMBOL(input_reset_device); +static int input_inhibit_device(struct input_dev *dev) +{ + int ret = 0; + + mutex_lock(&dev->mutex); + + if (dev->inhibited) + goto out; + + if (dev->users) { + if (dev->close) + dev->close(dev); + if (dev->poller) + input_dev_poller_stop(dev->poller); + } + + spin_lock_irq(&dev->event_lock); + input_dev_release_keys(dev); + input_dev_toggle(dev, false); + spin_unlock_irq(&dev->event_lock); + + dev->inhibited = true; + +out: + mutex_unlock(&dev->mutex); + return ret; +} + +static int input_uninhibit_device(struct input_dev *dev) +{ + int ret = 0; + + mutex_lock(&dev->mutex); + + if (!dev->inhibited) + goto out; + + if (dev->users) { + if (dev->open) { + ret = dev->open(dev); + if (ret) + goto out; + } + if (dev->poller) + input_dev_poller_start(dev->poller); + } + + dev->inhibited = false; + spin_lock_irq(&dev->event_lock); + input_dev_toggle(dev, true); + spin_unlock_irq(&dev->event_lock); + +out: + mutex_unlock(&dev->mutex); + return ret; +} + #ifdef CONFIG_PM_SLEEP static int input_dev_suspend(struct device *dev) { @@ -2131,7 +2229,7 @@ bool input_device_enabled(struct input_dev *dev) { lockdep_assert_held(&dev->mutex); - return dev->users > 0; + return !dev->inhibited && dev->users > 0; } EXPORT_SYMBOL_GPL(input_device_enabled); diff --git a/include/linux/input.h b/include/linux/input.h index eda4587dba67..0354b298d874 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -90,9 +90,11 @@ enum input_clock_type { * @open: this method is called when the very first user calls * input_open_device(). The driver must prepare the device * to start generating events (start polling thread, - * request an IRQ, submit URB, etc.) + * request an IRQ, submit URB, etc.). The meaning of open() is + * to start providing events to the input core. * @close: this method is called when the very last user calls - * input_close_device(). + * input_close_device(). The meaning of close() is to stop + * providing events to the input core. * @flush: purges the device. Most commonly used to get rid of force * feedback effects loaded into the device when disconnecting * from it @@ -127,6 +129,10 @@ enum input_clock_type { * and needs not be explicitly unregistered or freed. * @timestamp: storage for a timestamp set by input_set_timestamp called * by a driver + * @inhibited: indicates that the input device is inhibited. If that is + * the case then input core ignores any events generated by the device. + * Device's close() is called when it is being inhibited and its open() + * is called when it is being uninhibited. */ struct input_dev { const char *name; @@ -201,6 +207,8 @@ struct input_dev { bool devres_managed; ktime_t timestamp[INPUT_CLK_MAX]; + + bool inhibited; }; #define to_input_dev(d) container_of(d, struct input_dev, dev) -- cgit v1.2.3 From 6d59224fdcc532dd7292e3657d796b3728ec1e8e Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 2 Dec 2020 14:44:26 -0800 Subject: Input: document inhibiting Document inhibiting input devices and its relation to being a wakeup source. Signed-off-by: Andrzej Pietrasiewicz Reviewed-by: Hans de Goede Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/20200617101822.8558-1-andrzej.p@collabora.com Signed-off-by: Dmitry Torokhov --- Documentation/input/input-programming.rst | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Documentation/input/input-programming.rst b/Documentation/input/input-programming.rst index 45a4c6e05e39..5938145b0e35 100644 --- a/Documentation/input/input-programming.rst +++ b/Documentation/input/input-programming.rst @@ -164,6 +164,52 @@ disconnects. Calls to both callbacks are serialized. The open() callback should return a 0 in case of success or any nonzero value in case of failure. The close() callback (which is void) must always succeed. +Inhibiting input devices +~~~~~~~~~~~~~~~~~~~~~~~~ + +Inhibiting a device means ignoring input events from it. As such it is about +maintaining relationships with input handlers - either already existing +relationships, or relationships to be established while the device is in +inhibited state. + +If a device is inhibited, no input handler will receive events from it. + +The fact that nobody wants events from the device is exploited further, by +calling device's close() (if there are users) and open() (if there are users) on +inhibit and uninhibit operations, respectively. Indeed, the meaning of close() +is to stop providing events to the input core and that of open() is to start +providing events to the input core. + +Calling the device's close() method on inhibit (if there are users) allows the +driver to save power. Either by directly powering down the device or by +releasing the runtime-pm reference it got in open() when the driver is using +runtime-pm. + +Inhibiting and uninhibiting are orthogonal to opening and closing the device by +input handlers. Userspace might want to inhibit a device in anticipation before +any handler is positively matched against it. + +Inhibiting and uninhibiting are orthogonal to device's being a wakeup source, +too. Being a wakeup source plays a role when the system is sleeping, not when +the system is operating. How drivers should program their interaction between +inhibiting, sleeping and being a wakeup source is driver-specific. + +Taking the analogy with the network devices - bringing a network interface down +doesn't mean that it should be impossible be wake the system up on LAN through +this interface. So, there may be input drivers which should be considered wakeup +sources even when inhibited. Actually, in many I2C input devices their interrupt +is declared a wakeup interrupt and its handling happens in driver's core, which +is not aware of input-specific inhibit (nor should it be). Composite devices +containing several interfaces can be inhibited on a per-interface basis and e.g. +inhibiting one interface shouldn't affect the device's capability of being a +wakeup source. + +If a device is to be considered a wakeup source while inhibited, special care +must be taken when programming its suspend(), as it might need to call device's +open(). Depending on what close() means for the device in question, not +opening() it before going to sleep might make it impossible to provide any +wakeup events. The device is going to sleep anyway. + Basic event types ~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From 7ce8d91b8a849c4b9a010a8b773e3838a8e3d030 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 4 Dec 2020 12:13:17 -0800 Subject: Input: vsxxxaa - fix Kconfig spelling mistake There is a spelling mistake in the Kconfig help text. Fix it by replacing "theses" with "these". Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20201204193635.1152241-1-colin.king@canonical.com Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index d8b6a5dab190..63c9cda555c3 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -372,7 +372,7 @@ config MOUSE_VSXXXAA select SERIO help Say Y (or M) if you want to use a DEC VSXXX-AA (hockey - puck) or a VSXXX-GA (rectangular) mouse. Theses mice are + puck) or a VSXXX-GA (rectangular) mouse. These mice are typically used on DECstations or VAXstations, but can also be used on any box capable of RS232 (with some adaptor described in the source file). This driver also works with the -- cgit v1.2.3 From b2058cd93d930d7b9f76f34590c0d432cd6470c7 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 9 Dec 2020 17:26:35 -0800 Subject: Input: gtco - remove driver The driver has its own HID descriptor parsing code, that had and still has several issues discovered by syzbot and other tools. Ideally we should move the driver over to the HID subsystem, so that it uses proven parsing code. However the devices in question are EOL, and GTCO is not willing to extend resources for that, so let's simply remove the driver. Note that our HID support has greatly improved over the last 10 years, we may also consider reverting 6f8d9e26e7de ("hid-core.c: Adds all GTCO CalComp Digitizers and InterWrite School Products to blacklist") and see if GTCO devices actually work with normal HID drivers. Link: https://lore.kernel.org/r/X8wbBtO5KidME17K@google.com Signed-off-by: Dmitry Torokhov --- arch/powerpc/configs/ppc6xx_defconfig | 1 - drivers/input/tablet/Kconfig | 12 - drivers/input/tablet/Makefile | 1 - drivers/input/tablet/gtco.c | 1043 ----------------------------- kernel/configs/android-recommended.config | 1 - 5 files changed, 1058 deletions(-) delete mode 100644 drivers/input/tablet/gtco.c diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 66e9a0fd64ff..0ad0f6d41980 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -579,7 +579,6 @@ CONFIG_JOYSTICK_XPAD_LEDS=y CONFIG_INPUT_TABLET=y CONFIG_TABLET_USB_ACECAD=m CONFIG_TABLET_USB_AIPTEK=m -CONFIG_TABLET_USB_GTCO=m CONFIG_TABLET_USB_KBTAB=m CONFIG_INPUT_MISC=y CONFIG_INPUT_PCSPKR=m diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig index 51c339182017..ec27eff6ae37 100644 --- a/drivers/input/tablet/Kconfig +++ b/drivers/input/tablet/Kconfig @@ -38,18 +38,6 @@ config TABLET_USB_AIPTEK To compile this driver as a module, choose M here: the module will be called aiptek. -config TABLET_USB_GTCO - tristate "GTCO CalComp/InterWrite USB Support" - depends on USB && INPUT - help - Say Y here if you want to use the USB version of the GTCO - CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support" - (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" - (CONFIG_INPUT_EVDEV) as well. - - To compile this driver as a module, choose M here: the - module will be called gtco. - config TABLET_USB_HANWANG tristate "Hanwang Art Master III tablet support (USB)" depends on USB_ARCH_HAS_HCD diff --git a/drivers/input/tablet/Makefile b/drivers/input/tablet/Makefile index 8279ccc18b0a..adb636430717 100644 --- a/drivers/input/tablet/Makefile +++ b/drivers/input/tablet/Makefile @@ -6,7 +6,6 @@ obj-$(CONFIG_TABLET_USB_ACECAD) += acecad.o obj-$(CONFIG_TABLET_USB_AIPTEK) += aiptek.o -obj-$(CONFIG_TABLET_USB_GTCO) += gtco.o obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o obj-$(CONFIG_TABLET_USB_PEGASUS) += pegasus_notetaker.o diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c deleted file mode 100644 index 44bb1f69b4b2..000000000000 --- a/drivers/input/tablet/gtco.c +++ /dev/null @@ -1,1043 +0,0 @@ -/* -*- linux-c -*- - -GTCO digitizer USB driver - -TO CHECK: Is pressure done right on report 5? - -Copyright (C) 2006 GTCO CalComp - -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; version 2 -of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation, and that the name of GTCO-CalComp not be used in advertising -or publicity pertaining to distribution of the software without specific, -written prior permission. GTCO-CalComp makes no representations about the -suitability of this software for any purpose. It is provided "as is" -without express or implied warranty. - -GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO -EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR -CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, -DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. - -GTCO CalComp, Inc. -7125 Riverwood Drive -Columbia, MD 21046 - -Jeremy Roberson jroberson@gtcocalcomp.com -Scott Hill shill@gtcocalcomp.com -*/ - - - -/*#define DEBUG*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* Version with a Major number of 2 is for kernel inclusion only. */ -#define GTCO_VERSION "2.00.0006" - - -/* MACROS */ - -#define VENDOR_ID_GTCO 0x078C -#define PID_400 0x400 -#define PID_401 0x401 -#define PID_1000 0x1000 -#define PID_1001 0x1001 -#define PID_1002 0x1002 - -/* Max size of a single report */ -#define REPORT_MAX_SIZE 10 -#define MAX_COLLECTION_LEVELS 10 - - -/* Bitmask whether pen is in range */ -#define MASK_INRANGE 0x20 -#define MASK_BUTTON 0x01F - -#define PATHLENGTH 64 - -/* DATA STRUCTURES */ - -/* Device table */ -static const struct usb_device_id gtco_usbid_table[] = { - { USB_DEVICE(VENDOR_ID_GTCO, PID_400) }, - { USB_DEVICE(VENDOR_ID_GTCO, PID_401) }, - { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) }, - { USB_DEVICE(VENDOR_ID_GTCO, PID_1001) }, - { USB_DEVICE(VENDOR_ID_GTCO, PID_1002) }, - { } -}; -MODULE_DEVICE_TABLE (usb, gtco_usbid_table); - - -/* Structure to hold all of our device specific stuff */ -struct gtco { - - struct input_dev *inputdevice; /* input device struct pointer */ - struct usb_interface *intf; /* the usb interface for this device */ - struct urb *urbinfo; /* urb for incoming reports */ - dma_addr_t buf_dma; /* dma addr of the data buffer*/ - unsigned char * buffer; /* databuffer for reports */ - - char usbpath[PATHLENGTH]; - int openCount; - - /* Information pulled from Report Descriptor */ - u32 usage; - u32 min_X; - u32 max_X; - u32 min_Y; - u32 max_Y; - s8 mintilt_X; - s8 maxtilt_X; - s8 mintilt_Y; - s8 maxtilt_Y; - u32 maxpressure; - u32 minpressure; -}; - - - -/* Code for parsing the HID REPORT DESCRIPTOR */ - -/* From HID1.11 spec */ -struct hid_descriptor -{ - struct usb_descriptor_header header; - __le16 bcdHID; - u8 bCountryCode; - u8 bNumDescriptors; - u8 bDescriptorType; - __le16 wDescriptorLength; -} __attribute__ ((packed)); - - -#define HID_DESCRIPTOR_SIZE 9 -#define HID_DEVICE_TYPE 33 -#define REPORT_DEVICE_TYPE 34 - - -#define PREF_TAG(x) ((x)>>4) -#define PREF_TYPE(x) ((x>>2)&0x03) -#define PREF_SIZE(x) ((x)&0x03) - -#define TYPE_MAIN 0 -#define TYPE_GLOBAL 1 -#define TYPE_LOCAL 2 -#define TYPE_RESERVED 3 - -#define TAG_MAIN_INPUT 0x8 -#define TAG_MAIN_OUTPUT 0x9 -#define TAG_MAIN_FEATURE 0xB -#define TAG_MAIN_COL_START 0xA -#define TAG_MAIN_COL_END 0xC - -#define TAG_GLOB_USAGE 0 -#define TAG_GLOB_LOG_MIN 1 -#define TAG_GLOB_LOG_MAX 2 -#define TAG_GLOB_PHYS_MIN 3 -#define TAG_GLOB_PHYS_MAX 4 -#define TAG_GLOB_UNIT_EXP 5 -#define TAG_GLOB_UNIT 6 -#define TAG_GLOB_REPORT_SZ 7 -#define TAG_GLOB_REPORT_ID 8 -#define TAG_GLOB_REPORT_CNT 9 -#define TAG_GLOB_PUSH 10 -#define TAG_GLOB_POP 11 - -#define TAG_GLOB_MAX 12 - -#define DIGITIZER_USAGE_TIP_PRESSURE 0x30 -#define DIGITIZER_USAGE_TILT_X 0x3D -#define DIGITIZER_USAGE_TILT_Y 0x3E - - -/* - * This is an abbreviated parser for the HID Report Descriptor. We - * know what devices we are talking to, so this is by no means meant - * to be generic. We can make some safe assumptions: - * - * - We know there are no LONG tags, all short - * - We know that we have no MAIN Feature and MAIN Output items - * - We know what the IRQ reports are supposed to look like. - * - * The main purpose of this is to use the HID report desc to figure - * out the mins and maxs of the fields in the IRQ reports. The IRQ - * reports for 400/401 change slightly if the max X is bigger than 64K. - * - */ -static void parse_hid_report_descriptor(struct gtco *device, char * report, - int length) -{ - struct device *ddev = &device->intf->dev; - int x, i = 0; - - /* Tag primitive vars */ - __u8 prefix; - __u8 size; - __u8 tag; - __u8 type; - __u8 data = 0; - __u16 data16 = 0; - __u32 data32 = 0; - - /* For parsing logic */ - int inputnum = 0; - __u32 usage = 0; - - /* Global Values, indexed by TAG */ - __u32 globalval[TAG_GLOB_MAX]; - __u32 oldval[TAG_GLOB_MAX]; - - /* Debug stuff */ - char maintype = 'x'; - char globtype[12]; - int indent = 0; - char indentstr[MAX_COLLECTION_LEVELS + 1] = { 0 }; - - dev_dbg(ddev, "======>>>>>>PARSE<<<<<<======\n"); - - /* Walk this report and pull out the info we need */ - while (i < length) { - prefix = report[i++]; - - /* Determine data size and save the data in the proper variable */ - size = (1U << PREF_SIZE(prefix)) >> 1; - if (i + size > length) { - dev_err(ddev, - "Not enough data (need %d, have %d)\n", - i + size, length); - break; - } - - switch (size) { - case 1: - data = report[i]; - break; - case 2: - data16 = get_unaligned_le16(&report[i]); - break; - case 4: - data32 = get_unaligned_le32(&report[i]); - break; - } - - /* Skip size of data */ - i += size; - - /* What we do depends on the tag type */ - tag = PREF_TAG(prefix); - type = PREF_TYPE(prefix); - switch (type) { - case TYPE_MAIN: - strcpy(globtype, ""); - switch (tag) { - - case TAG_MAIN_INPUT: - /* - * The INPUT MAIN tag signifies this is - * information from a report. We need to - * figure out what it is and store the - * min/max values - */ - - maintype = 'I'; - if (data == 2) - strcpy(globtype, "Variable"); - else if (data == 3) - strcpy(globtype, "Var|Const"); - - dev_dbg(ddev, "::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits\n", - globalval[TAG_GLOB_REPORT_ID], inputnum, - globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX], - globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN], - globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]); - - - /* - We can assume that the first two input items - are always the X and Y coordinates. After - that, we look for everything else by - local usage value - */ - switch (inputnum) { - case 0: /* X coord */ - dev_dbg(ddev, "GER: X Usage: 0x%x\n", usage); - if (device->max_X == 0) { - device->max_X = globalval[TAG_GLOB_LOG_MAX]; - device->min_X = globalval[TAG_GLOB_LOG_MIN]; - } - break; - - case 1: /* Y coord */ - dev_dbg(ddev, "GER: Y Usage: 0x%x\n", usage); - if (device->max_Y == 0) { - device->max_Y = globalval[TAG_GLOB_LOG_MAX]; - device->min_Y = globalval[TAG_GLOB_LOG_MIN]; - } - break; - - default: - /* Tilt X */ - if (usage == DIGITIZER_USAGE_TILT_X) { - if (device->maxtilt_X == 0) { - device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX]; - device->mintilt_X = globalval[TAG_GLOB_LOG_MIN]; - } - } - - /* Tilt Y */ - if (usage == DIGITIZER_USAGE_TILT_Y) { - if (device->maxtilt_Y == 0) { - device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX]; - device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN]; - } - } - - /* Pressure */ - if (usage == DIGITIZER_USAGE_TIP_PRESSURE) { - if (device->maxpressure == 0) { - device->maxpressure = globalval[TAG_GLOB_LOG_MAX]; - device->minpressure = globalval[TAG_GLOB_LOG_MIN]; - } - } - - break; - } - - inputnum++; - break; - - case TAG_MAIN_OUTPUT: - maintype = 'O'; - break; - - case TAG_MAIN_FEATURE: - maintype = 'F'; - break; - - case TAG_MAIN_COL_START: - maintype = 'S'; - - if (indent == MAX_COLLECTION_LEVELS) { - dev_err(ddev, "Collection level %d would exceed limit of %d\n", - indent + 1, - MAX_COLLECTION_LEVELS); - break; - } - - if (data == 0) { - dev_dbg(ddev, "======>>>>>> Physical\n"); - strcpy(globtype, "Physical"); - } else - dev_dbg(ddev, "======>>>>>>\n"); - - /* Indent the debug output */ - indent++; - for (x = 0; x < indent; x++) - indentstr[x] = '-'; - indentstr[x] = 0; - - /* Save global tags */ - for (x = 0; x < TAG_GLOB_MAX; x++) - oldval[x] = globalval[x]; - - break; - - case TAG_MAIN_COL_END: - maintype = 'E'; - - if (indent == 0) { - dev_err(ddev, "Collection level already at zero\n"); - break; - } - - dev_dbg(ddev, "<<<<<<======\n"); - - indent--; - for (x = 0; x < indent; x++) - indentstr[x] = '-'; - indentstr[x] = 0; - - /* Copy global tags back */ - for (x = 0; x < TAG_GLOB_MAX; x++) - globalval[x] = oldval[x]; - - break; - } - - switch (size) { - case 1: - dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n", - indentstr, tag, maintype, size, globtype, data); - break; - - case 2: - dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n", - indentstr, tag, maintype, size, globtype, data16); - break; - - case 4: - dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n", - indentstr, tag, maintype, size, globtype, data32); - break; - } - break; - - case TYPE_GLOBAL: - switch (tag) { - case TAG_GLOB_USAGE: - /* - * First time we hit the global usage tag, - * it should tell us the type of device - */ - if (device->usage == 0) - device->usage = data; - - strcpy(globtype, "USAGE"); - break; - - case TAG_GLOB_LOG_MIN: - strcpy(globtype, "LOG_MIN"); - break; - - case TAG_GLOB_LOG_MAX: - strcpy(globtype, "LOG_MAX"); - break; - - case TAG_GLOB_PHYS_MIN: - strcpy(globtype, "PHYS_MIN"); - break; - - case TAG_GLOB_PHYS_MAX: - strcpy(globtype, "PHYS_MAX"); - break; - - case TAG_GLOB_UNIT_EXP: - strcpy(globtype, "EXP"); - break; - - case TAG_GLOB_UNIT: - strcpy(globtype, "UNIT"); - break; - - case TAG_GLOB_REPORT_SZ: - strcpy(globtype, "REPORT_SZ"); - break; - - case TAG_GLOB_REPORT_ID: - strcpy(globtype, "REPORT_ID"); - /* New report, restart numbering */ - inputnum = 0; - break; - - case TAG_GLOB_REPORT_CNT: - strcpy(globtype, "REPORT_CNT"); - break; - - case TAG_GLOB_PUSH: - strcpy(globtype, "PUSH"); - break; - - case TAG_GLOB_POP: - strcpy(globtype, "POP"); - break; - } - - /* Check to make sure we have a good tag number - so we don't overflow array */ - if (tag < TAG_GLOB_MAX) { - switch (size) { - case 1: - dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n", - indentstr, globtype, tag, size, data); - globalval[tag] = data; - break; - - case 2: - dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n", - indentstr, globtype, tag, size, data16); - globalval[tag] = data16; - break; - - case 4: - dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n", - indentstr, globtype, tag, size, data32); - globalval[tag] = data32; - break; - } - } else { - dev_dbg(ddev, "%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d\n", - indentstr, tag, size); - } - break; - - case TYPE_LOCAL: - switch (tag) { - case TAG_GLOB_USAGE: - strcpy(globtype, "USAGE"); - /* Always 1 byte */ - usage = data; - break; - - case TAG_GLOB_LOG_MIN: - strcpy(globtype, "MIN"); - break; - - case TAG_GLOB_LOG_MAX: - strcpy(globtype, "MAX"); - break; - - default: - strcpy(globtype, "UNKNOWN"); - break; - } - - switch (size) { - case 1: - dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n", - indentstr, tag, globtype, size, data); - break; - - case 2: - dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n", - indentstr, tag, globtype, size, data16); - break; - - case 4: - dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n", - indentstr, tag, globtype, size, data32); - break; - } - - break; - } - } -} - -/* INPUT DRIVER Routines */ - -/* - * Called when opening the input device. This will submit the URB to - * the usb system so we start getting reports - */ -static int gtco_input_open(struct input_dev *inputdev) -{ - struct gtco *device = input_get_drvdata(inputdev); - - device->urbinfo->dev = interface_to_usbdev(device->intf); - if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) - return -EIO; - - return 0; -} - -/* - * Called when closing the input device. This will unlink the URB - */ -static void gtco_input_close(struct input_dev *inputdev) -{ - struct gtco *device = input_get_drvdata(inputdev); - - usb_kill_urb(device->urbinfo); -} - - -/* - * Setup input device capabilities. Tell the input system what this - * device is capable of generating. - * - * This information is based on what is read from the HID report and - * placed in the struct gtco structure - * - */ -static void gtco_setup_caps(struct input_dev *inputdev) -{ - struct gtco *device = input_get_drvdata(inputdev); - - /* Which events */ - inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | - BIT_MASK(EV_MSC); - - /* Misc event menu block */ - inputdev->mscbit[0] = BIT_MASK(MSC_SCAN) | BIT_MASK(MSC_SERIAL) | - BIT_MASK(MSC_RAW); - - /* Absolute values based on HID report info */ - input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X, - 0, 0); - input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y, - 0, 0); - - /* Proximity */ - input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0); - - /* Tilt & pressure */ - input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X, - device->maxtilt_X, 0, 0); - input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y, - device->maxtilt_Y, 0, 0); - input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure, - device->maxpressure, 0, 0); - - /* Transducer */ - input_set_abs_params(inputdev, ABS_MISC, 0, 0xFF, 0, 0); -} - -/* USB Routines */ - -/* - * URB callback routine. Called when we get IRQ reports from the - * digitizer. - * - * This bridges the USB and input device worlds. It generates events - * on the input device based on the USB reports. - */ -static void gtco_urb_callback(struct urb *urbinfo) -{ - struct gtco *device = urbinfo->context; - struct input_dev *inputdev; - int rc; - u32 val = 0; - char le_buffer[2]; - - inputdev = device->inputdevice; - - /* Was callback OK? */ - if (urbinfo->status == -ECONNRESET || - urbinfo->status == -ENOENT || - urbinfo->status == -ESHUTDOWN) { - - /* Shutdown is occurring. Return and don't queue up any more */ - return; - } - - if (urbinfo->status != 0) { - /* - * Some unknown error. Hopefully temporary. Just go and - * requeue an URB - */ - goto resubmit; - } - - /* - * Good URB, now process - */ - - /* PID dependent when we interpret the report */ - if (inputdev->id.product == PID_1000 || - inputdev->id.product == PID_1001 || - inputdev->id.product == PID_1002) { - - /* - * Switch on the report ID - * Conveniently, the reports have more information, the higher - * the report number. We can just fall through the case - * statements if we start with the highest number report - */ - switch (device->buffer[0]) { - case 5: - /* Pressure is 9 bits */ - val = ((u16)(device->buffer[8]) << 1); - val |= (u16)(device->buffer[7] >> 7); - input_report_abs(inputdev, ABS_PRESSURE, - device->buffer[8]); - - /* Mask out the Y tilt value used for pressure */ - device->buffer[7] = (u8)((device->buffer[7]) & 0x7F); - fallthrough; - - case 4: - /* Tilt */ - input_report_abs(inputdev, ABS_TILT_X, - sign_extend32(device->buffer[6], 6)); - - input_report_abs(inputdev, ABS_TILT_Y, - sign_extend32(device->buffer[7], 6)); - fallthrough; - - case 2: - case 3: - /* Convert buttons, only 5 bits possible */ - val = (device->buffer[5]) & MASK_BUTTON; - - /* We don't apply any meaning to the bitmask, - just report */ - input_event(inputdev, EV_MSC, MSC_SERIAL, val); - fallthrough; - - case 1: - /* All reports have X and Y coords in the same place */ - val = get_unaligned_le16(&device->buffer[1]); - input_report_abs(inputdev, ABS_X, val); - - val = get_unaligned_le16(&device->buffer[3]); - input_report_abs(inputdev, ABS_Y, val); - - /* Ditto for proximity bit */ - val = device->buffer[5] & MASK_INRANGE ? 1 : 0; - input_report_abs(inputdev, ABS_DISTANCE, val); - - /* Report 1 is an exception to how we handle buttons */ - /* Buttons are an index, not a bitmask */ - if (device->buffer[0] == 1) { - - /* - * Convert buttons, 5 bit index - * Report value of index set as one, - * the rest as 0 - */ - val = device->buffer[5] & MASK_BUTTON; - dev_dbg(&device->intf->dev, - "======>>>>>>REPORT 1: val 0x%X(%d)\n", - val, val); - - /* - * We don't apply any meaning to the button - * index, just report it - */ - input_event(inputdev, EV_MSC, MSC_SERIAL, val); - } - break; - - case 7: - /* Menu blocks */ - input_event(inputdev, EV_MSC, MSC_SCAN, - device->buffer[1]); - break; - } - } - - /* Other pid class */ - if (inputdev->id.product == PID_400 || - inputdev->id.product == PID_401) { - - /* Report 2 */ - if (device->buffer[0] == 2) { - /* Menu blocks */ - input_event(inputdev, EV_MSC, MSC_SCAN, device->buffer[1]); - } - - /* Report 1 */ - if (device->buffer[0] == 1) { - char buttonbyte; - - /* IF X max > 64K, we still a bit from the y report */ - if (device->max_X > 0x10000) { - - val = (u16)(((u16)(device->buffer[2] << 8)) | (u8)device->buffer[1]); - val |= (u32)(((u8)device->buffer[3] & 0x1) << 16); - - input_report_abs(inputdev, ABS_X, val); - - le_buffer[0] = (u8)((u8)(device->buffer[3]) >> 1); - le_buffer[0] |= (u8)((device->buffer[3] & 0x1) << 7); - - le_buffer[1] = (u8)(device->buffer[4] >> 1); - le_buffer[1] |= (u8)((device->buffer[5] & 0x1) << 7); - - val = get_unaligned_le16(le_buffer); - input_report_abs(inputdev, ABS_Y, val); - - /* - * Shift the button byte right by one to - * make it look like the standard report - */ - buttonbyte = device->buffer[5] >> 1; - } else { - - val = get_unaligned_le16(&device->buffer[1]); - input_report_abs(inputdev, ABS_X, val); - - val = get_unaligned_le16(&device->buffer[3]); - input_report_abs(inputdev, ABS_Y, val); - - buttonbyte = device->buffer[5]; - } - - /* BUTTONS and PROXIMITY */ - val = buttonbyte & MASK_INRANGE ? 1 : 0; - input_report_abs(inputdev, ABS_DISTANCE, val); - - /* Convert buttons, only 4 bits possible */ - val = buttonbyte & 0x0F; -#ifdef USE_BUTTONS - for (i = 0; i < 5; i++) - input_report_key(inputdev, BTN_DIGI + i, val & (1 << i)); -#else - /* We don't apply any meaning to the bitmask, just report */ - input_event(inputdev, EV_MSC, MSC_SERIAL, val); -#endif - - /* TRANSDUCER */ - input_report_abs(inputdev, ABS_MISC, device->buffer[6]); - } - } - - /* Everybody gets report ID's */ - input_event(inputdev, EV_MSC, MSC_RAW, device->buffer[0]); - - /* Sync it up */ - input_sync(inputdev); - - resubmit: - rc = usb_submit_urb(urbinfo, GFP_ATOMIC); - if (rc != 0) - dev_err(&device->intf->dev, - "usb_submit_urb failed rc=0x%x\n", rc); -} - -/* - * The probe routine. This is called when the kernel find the matching USB - * vendor/product. We do the following: - * - * - Allocate mem for a local structure to manage the device - * - Request a HID Report Descriptor from the device and parse it to - * find out the device parameters - * - Create an input device and assign it attributes - * - Allocate an URB so the device can talk to us when the input - * queue is open - */ -static int gtco_probe(struct usb_interface *usbinterface, - const struct usb_device_id *id) -{ - - struct gtco *gtco; - struct input_dev *input_dev; - struct hid_descriptor *hid_desc; - char *report; - int result = 0, retry; - int error; - struct usb_endpoint_descriptor *endpoint; - struct usb_device *udev = interface_to_usbdev(usbinterface); - - /* Allocate memory for device structure */ - gtco = kzalloc(sizeof(struct gtco), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!gtco || !input_dev) { - dev_err(&usbinterface->dev, "No more memory\n"); - error = -ENOMEM; - goto err_free_devs; - } - - /* Set pointer to the input device */ - gtco->inputdevice = input_dev; - - /* Save interface information */ - gtco->intf = usbinterface; - - /* Allocate some data for incoming reports */ - gtco->buffer = usb_alloc_coherent(udev, REPORT_MAX_SIZE, - GFP_KERNEL, >co->buf_dma); - if (!gtco->buffer) { - dev_err(&usbinterface->dev, "No more memory for us buffers\n"); - error = -ENOMEM; - goto err_free_devs; - } - - /* Allocate URB for reports */ - gtco->urbinfo = usb_alloc_urb(0, GFP_KERNEL); - if (!gtco->urbinfo) { - dev_err(&usbinterface->dev, "Failed to allocate URB\n"); - error = -ENOMEM; - goto err_free_buf; - } - - /* Sanity check that a device has an endpoint */ - if (usbinterface->cur_altsetting->desc.bNumEndpoints < 1) { - dev_err(&usbinterface->dev, - "Invalid number of endpoints\n"); - error = -EINVAL; - goto err_free_urb; - } - - endpoint = &usbinterface->cur_altsetting->endpoint[0].desc; - - /* Some debug */ - dev_dbg(&usbinterface->dev, "gtco # interfaces: %d\n", usbinterface->num_altsetting); - dev_dbg(&usbinterface->dev, "num endpoints: %d\n", usbinterface->cur_altsetting->desc.bNumEndpoints); - dev_dbg(&usbinterface->dev, "interface class: %d\n", usbinterface->cur_altsetting->desc.bInterfaceClass); - dev_dbg(&usbinterface->dev, "endpoint: attribute:0x%x type:0x%x\n", endpoint->bmAttributes, endpoint->bDescriptorType); - if (usb_endpoint_xfer_int(endpoint)) - dev_dbg(&usbinterface->dev, "endpoint: we have interrupt endpoint\n"); - - dev_dbg(&usbinterface->dev, "interface extra len:%d\n", - usbinterface->cur_altsetting->extralen); - - /* - * Find the HID descriptor so we can find out the size of the - * HID report descriptor - */ - if (usb_get_extra_descriptor(usbinterface->cur_altsetting, - HID_DEVICE_TYPE, &hid_desc) != 0) { - dev_err(&usbinterface->dev, - "Can't retrieve exta USB descriptor to get hid report descriptor length\n"); - error = -EIO; - goto err_free_urb; - } - - dev_dbg(&usbinterface->dev, - "Extra descriptor success: type:%d len:%d\n", - hid_desc->bDescriptorType, hid_desc->wDescriptorLength); - - report = kzalloc(le16_to_cpu(hid_desc->wDescriptorLength), GFP_KERNEL); - if (!report) { - dev_err(&usbinterface->dev, "No more memory for report\n"); - error = -ENOMEM; - goto err_free_urb; - } - - /* Couple of tries to get reply */ - for (retry = 0; retry < 3; retry++) { - result = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - USB_REQ_GET_DESCRIPTOR, - USB_RECIP_INTERFACE | USB_DIR_IN, - REPORT_DEVICE_TYPE << 8, - 0, /* interface */ - report, - le16_to_cpu(hid_desc->wDescriptorLength), - 5000); /* 5 secs */ - - dev_dbg(&usbinterface->dev, "usb_control_msg result: %d\n", result); - if (result == le16_to_cpu(hid_desc->wDescriptorLength)) { - parse_hid_report_descriptor(gtco, report, result); - break; - } - } - - kfree(report); - - /* If we didn't get the report, fail */ - if (result != le16_to_cpu(hid_desc->wDescriptorLength)) { - dev_err(&usbinterface->dev, - "Failed to get HID Report Descriptor of size: %d\n", - hid_desc->wDescriptorLength); - error = -EIO; - goto err_free_urb; - } - - /* Create a device file node */ - usb_make_path(udev, gtco->usbpath, sizeof(gtco->usbpath)); - strlcat(gtco->usbpath, "/input0", sizeof(gtco->usbpath)); - - /* Set Input device functions */ - input_dev->open = gtco_input_open; - input_dev->close = gtco_input_close; - - /* Set input device information */ - input_dev->name = "GTCO_CalComp"; - input_dev->phys = gtco->usbpath; - - input_set_drvdata(input_dev, gtco); - - /* Now set up all the input device capabilities */ - gtco_setup_caps(input_dev); - - /* Set input device required ID information */ - usb_to_input_id(udev, &input_dev->id); - input_dev->dev.parent = &usbinterface->dev; - - /* Setup the URB, it will be posted later on open of input device */ - usb_fill_int_urb(gtco->urbinfo, - udev, - usb_rcvintpipe(udev, - endpoint->bEndpointAddress), - gtco->buffer, - REPORT_MAX_SIZE, - gtco_urb_callback, - gtco, - endpoint->bInterval); - - gtco->urbinfo->transfer_dma = gtco->buf_dma; - gtco->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - /* Save gtco pointer in USB interface gtco */ - usb_set_intfdata(usbinterface, gtco); - - /* All done, now register the input device */ - error = input_register_device(input_dev); - if (error) - goto err_free_urb; - - return 0; - - err_free_urb: - usb_free_urb(gtco->urbinfo); - err_free_buf: - usb_free_coherent(udev, REPORT_MAX_SIZE, - gtco->buffer, gtco->buf_dma); - err_free_devs: - input_free_device(input_dev); - kfree(gtco); - return error; -} - -/* - * This function is a standard USB function called when the USB device - * is disconnected. We will get rid of the URV, de-register the input - * device, and free up allocated memory - */ -static void gtco_disconnect(struct usb_interface *interface) -{ - /* Grab private device ptr */ - struct gtco *gtco = usb_get_intfdata(interface); - struct usb_device *udev = interface_to_usbdev(interface); - - /* Now reverse all the registration stuff */ - if (gtco) { - input_unregister_device(gtco->inputdevice); - usb_kill_urb(gtco->urbinfo); - usb_free_urb(gtco->urbinfo); - usb_free_coherent(udev, REPORT_MAX_SIZE, - gtco->buffer, gtco->buf_dma); - kfree(gtco); - } - - dev_info(&interface->dev, "gtco driver disconnected\n"); -} - -/* STANDARD MODULE LOAD ROUTINES */ - -static struct usb_driver gtco_driverinfo_table = { - .name = "gtco", - .id_table = gtco_usbid_table, - .probe = gtco_probe, - .disconnect = gtco_disconnect, -}; - -module_usb_driver(gtco_driverinfo_table); - -MODULE_DESCRIPTION("GTCO digitizer USB driver"); -MODULE_LICENSE("GPL"); diff --git a/kernel/configs/android-recommended.config b/kernel/configs/android-recommended.config index 81e9af7dcec2..53d688bdd894 100644 --- a/kernel/configs/android-recommended.config +++ b/kernel/configs/android-recommended.config @@ -111,7 +111,6 @@ CONFIG_STRICT_KERNEL_RWX=y CONFIG_SUSPEND_TIME=y CONFIG_TABLET_USB_ACECAD=y CONFIG_TABLET_USB_AIPTEK=y -CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_TASKSTATS=y -- cgit v1.2.3 From b2cc3bfef6aa9a0d66034b48e95cf24f6a5b0e35 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 9 Dec 2020 17:44:35 -0800 Subject: dt-bindings: input: Add Dell Wyse 3020 Power Button binding Add binding document for the Dell Wyse 3020 a.k.a. "Ariel" Power Button. Signed-off-by: Lubomir Rintel Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201201083533.1724287-2-lkundrak@v3.sk Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/ariel-pwrbutton.yaml | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/ariel-pwrbutton.yaml diff --git a/Documentation/devicetree/bindings/input/ariel-pwrbutton.yaml b/Documentation/devicetree/bindings/input/ariel-pwrbutton.yaml new file mode 100644 index 000000000000..b4ad829d7383 --- /dev/null +++ b/Documentation/devicetree/bindings/input/ariel-pwrbutton.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/ariel-pwrbutton.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Dell Wyse 3020 a.k.a. "Ariel" Power Button + +maintainers: + - Lubomir Rintel + +description: | + The ENE Embedded Controller on the Ariel board has an interface to the + SPI bus that is capable of sending keyboard and mouse data. A single + power button is attached to it. This binding describes this + configuration. + +allOf: + - $ref: input.yaml# + +properties: + compatible: + items: + - const: dell,wyse-ariel-ec-input + - const: ene,kb3930-input + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + spi-max-frequency: true + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + power-button@0 { + compatible = "dell,wyse-ariel-ec-input", "ene,kb3930-input"; + reg = <0>; + interrupt-parent = <&gpio>; + interrupts = <60 IRQ_TYPE_EDGE_RISING>; + spi-max-frequency = <33000000>; + }; + }; -- cgit v1.2.3 From 3d82a4d736a662e352027686b8a373bf3e70820e Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 9 Dec 2020 17:45:14 -0800 Subject: Input: add driver for power button on Dell Wyse 3020 This adds support for the power button attached to the Embedded Controller on a Dell Wyse 3020 "Ariel" board. The Embedded Controller's SPI interface is actually capable sending and receiving the PS/2 keyboard and mouse protocol data, which looks like a good fit for a serio driver. Howerver, I don't know of any machines where this is actually used. My board only has a single power button and no way to connect an actual keyboard or a mouse. Using the atkbd driver with serio would be an overkill and would be inconvenient for the userspace. Therefore this driver registers an input device that is only capable of reporting the power button presses and releases. Signed-off-by: Lubomir Rintel Link: https://lore.kernel.org/r/20201201083533.1724287-3-lkundrak@v3.sk Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 11 +++ drivers/input/misc/Makefile | 1 + drivers/input/misc/ariel-pwrbutton.c | 169 +++++++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 drivers/input/misc/ariel-pwrbutton.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 362e8a01980c..e7bb572e1518 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -73,6 +73,17 @@ config INPUT_AD714X_SPI To compile this driver as a module, choose M here: the module will be called ad714x-spi. +config INPUT_ARIEL_PWRBUTTON + tristate "Dell Wyse 3020 Power Button Driver" + depends on SPI + depends on MACH_MMP3_DT || COMPILE_TEST + help + Say Y to enable support for reporting power button status on + on Dell Wyse 3020 ("Ariel") thin client. + + To compile this driver as a module, choose M here: the module + will be called ariel-pwrbutton. + config INPUT_ARIZONA_HAPTICS tristate "Arizona haptics support" depends on MFD_ARIZONA && SND_SOC diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index a48e5f2d859d..062cea9f181c 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o obj-$(CONFIG_INPUT_APANEL) += apanel.o +obj-$(CONFIG_INPUT_ARIEL_PWRBUTTON) += ariel-pwrbutton.o obj-$(CONFIG_INPUT_ARIZONA_HAPTICS) += arizona-haptics.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o diff --git a/drivers/input/misc/ariel-pwrbutton.c b/drivers/input/misc/ariel-pwrbutton.c new file mode 100644 index 000000000000..eda86ab552b9 --- /dev/null +++ b/drivers/input/misc/ariel-pwrbutton.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0-or-later +/* + * Dell Wyse 3020 a.k.a. "Ariel" Power Button Driver + * + * Copyright (C) 2020 Lubomir Rintel + */ + +#include +#include +#include +#include +#include +#include +#include + +#define RESP_COUNTER(response) (response.header & 0x3) +#define RESP_SIZE(response) ((response.header >> 2) & 0x3) +#define RESP_TYPE(response) ((response.header >> 4) & 0xf) + +struct ec_input_response { + u8 reserved; + u8 header; + u8 data[3]; +} __packed; + +struct ariel_pwrbutton { + struct spi_device *client; + struct input_dev *input; + u8 msg_counter; +}; + +static int ec_input_read(struct ariel_pwrbutton *priv, + struct ec_input_response *response) +{ + u8 read_request[] = { 0x00, 0x5a, 0xa5, 0x00, 0x00 }; + struct spi_device *spi = priv->client; + struct spi_transfer t = { + .tx_buf = read_request, + .rx_buf = response, + .len = sizeof(read_request), + }; + + compiletime_assert(sizeof(read_request) == sizeof(*response), + "SPI xfer request/response size mismatch"); + + return spi_sync_transfer(spi, &t, 1); +} + +static irqreturn_t ec_input_interrupt(int irq, void *dev_id) +{ + struct ariel_pwrbutton *priv = dev_id; + struct spi_device *spi = priv->client; + struct ec_input_response response; + int error; + int i; + + error = ec_input_read(priv, &response); + if (error < 0) { + dev_err(&spi->dev, "EC read failed: %d\n", error); + goto out; + } + + if (priv->msg_counter == RESP_COUNTER(response)) { + dev_warn(&spi->dev, "No new data to read?\n"); + goto out; + } + + priv->msg_counter = RESP_COUNTER(response); + + if (RESP_TYPE(response) != 0x3 && RESP_TYPE(response) != 0xc) { + dev_dbg(&spi->dev, "Ignoring message that's not kbd data\n"); + goto out; + } + + for (i = 0; i < RESP_SIZE(response); i++) { + switch (response.data[i]) { + case 0x74: + input_report_key(priv->input, KEY_POWER, 1); + input_sync(priv->input); + break; + case 0xf4: + input_report_key(priv->input, KEY_POWER, 0); + input_sync(priv->input); + break; + default: + dev_dbg(&spi->dev, "Unknown scan code: %02x\n", + response.data[i]); + } + } + +out: + return IRQ_HANDLED; +} + +static int ariel_pwrbutton_probe(struct spi_device *spi) +{ + struct ec_input_response response; + struct ariel_pwrbutton *priv; + int error; + + if (!spi->irq) { + dev_err(&spi->dev, "Missing IRQ.\n"); + return -EINVAL; + } + + priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->client = spi; + spi_set_drvdata(spi, priv); + + priv->input = devm_input_allocate_device(&spi->dev); + if (!priv->input) + return -ENOMEM; + priv->input->name = "Power Button"; + priv->input->dev.parent = &spi->dev; + input_set_capability(priv->input, EV_KEY, KEY_POWER); + error = input_register_device(priv->input); + if (error) { + dev_err(&spi->dev, "error registering input device: %d\n", error); + return error; + } + + error = ec_input_read(priv, &response); + if (error < 0) { + dev_err(&spi->dev, "EC read failed: %d\n", error); + return error; + } + priv->msg_counter = RESP_COUNTER(response); + + error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, + ec_input_interrupt, + IRQF_ONESHOT, + "Ariel EC Input", priv); + + if (error) { + dev_err(&spi->dev, "Failed to request IRQ %d: %d\n", + spi->irq, error); + return error; + } + + return 0; +} + +static const struct of_device_id ariel_pwrbutton_of_match[] = { + { .compatible = "dell,wyse-ariel-ec-input" }, + { } +}; +MODULE_DEVICE_TABLE(of, ariel_pwrbutton_of_match); + +static const struct spi_device_id ariel_pwrbutton_id_table[] = { + { "wyse-ariel-ec-input", 0 }, + {} +}; +MODULE_DEVICE_TABLE(spi, ariel_pwrbutton_id_table); + +static struct spi_driver ariel_pwrbutton_driver = { + .driver = { + .name = "dell-wyse-ariel-ec-input", + .of_match_table = ariel_pwrbutton_of_match, + }, + .probe = ariel_pwrbutton_probe, +}; +module_spi_driver(ariel_pwrbutton_driver); + +MODULE_AUTHOR("Lubomir Rintel "); +MODULE_DESCRIPTION("Dell Wyse 3020 Power Button Input Driver"); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From 8edcd98be1b237965b54bee7e17f89a790a107fd Mon Sep 17 00:00:00 2001 From: Fuqian Huang Date: Sat, 13 Jul 2019 01:04:12 -0700 Subject: Input: cyapa - switch to using devm_add_action_or_reset() devm_add_action_or_reset() is introduced as a helper function which internally calls devm_add_action(). If devm_add_action() fails then it will execute the action mentioned and return the error code. This reduce source code size (avoid writing the action twice) and reduce the likelyhood of bugs. Signed-off-by: Fuqian Huang Link: https://lore.kernel.org/linux-input/20190708123323.11943-1-huangfq.daxian@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 3f4069511b13..77cc653edca2 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -840,10 +840,9 @@ static int cyapa_prepare_wakeup_controls(struct cyapa *cyapa) return error; } - error = devm_add_action(dev, + error = devm_add_action_or_reset(dev, cyapa_remove_power_wakeup_group, cyapa); if (error) { - cyapa_remove_power_wakeup_group(cyapa); dev_err(dev, "failed to add power cleanup action: %d\n", error); return error; @@ -957,9 +956,9 @@ static int cyapa_start_runtime(struct cyapa *cyapa) return error; } - error = devm_add_action(dev, cyapa_remove_power_runtime_group, cyapa); + error = devm_add_action_or_reset(dev, cyapa_remove_power_runtime_group, + cyapa); if (error) { - cyapa_remove_power_runtime_group(cyapa); dev_err(dev, "failed to add power runtime cleanup action: %d\n", error); @@ -1291,9 +1290,8 @@ static int cyapa_probe(struct i2c_client *client, return error; } - error = devm_add_action(dev, cyapa_disable_regulator, cyapa); + error = devm_add_action_or_reset(dev, cyapa_disable_regulator, cyapa); if (error) { - cyapa_disable_regulator(cyapa); dev_err(dev, "failed to add disable regulator action: %d\n", error); return error; -- cgit v1.2.3 From 31a10f5b4b9ff323668c37173695ea463fc89863 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 9 Dec 2020 19:37:14 -0800 Subject: dt-bindings: input: tm2-touchkey: convert to yaml Convert the device tree bindings for tm2-touchkey to the YAML format. While we're at it, clarify the descriptions a bit to make it clear that this driver can be used for many different MCUs that all implement a similar I2C protocol. Depending on the MCU the voltage requirements may be different, on some devices the controller uses 2.2V, 2.8V or even 3.3V for vcc-supply instead of 1.8V. Signed-off-by: Stephan Gerhold Reviewed-by: Linus Walleij Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201203131242.44397-1-stephan@gerhold.net Signed-off-by: Dmitry Torokhov --- .../bindings/input/cypress,tm2-touchkey.txt | 33 ----------- .../bindings/input/cypress,tm2-touchkey.yaml | 68 ++++++++++++++++++++++ 2 files changed, 68 insertions(+), 33 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/cypress,tm2-touchkey.txt create mode 100644 Documentation/devicetree/bindings/input/cypress,tm2-touchkey.yaml diff --git a/Documentation/devicetree/bindings/input/cypress,tm2-touchkey.txt b/Documentation/devicetree/bindings/input/cypress,tm2-touchkey.txt deleted file mode 100644 index 921172f689b8..000000000000 --- a/Documentation/devicetree/bindings/input/cypress,tm2-touchkey.txt +++ /dev/null @@ -1,33 +0,0 @@ -Samsung tm2-touchkey - -Required properties: -- compatible: - * "cypress,tm2-touchkey" - for the touchkey found on the tm2 board - * "cypress,midas-touchkey" - for the touchkey found on midas boards - * "cypress,aries-touchkey" - for the touchkey found on aries boards - * "coreriver,tc360-touchkey" - for the Coreriver TouchCore 360 touchkey -- reg: I2C address of the chip. -- interrupts: interrupt to which the chip is connected (see interrupt - binding[0]). -- vcc-supply : internal regulator output. 1.8V -- vdd-supply : power supply for IC 3.3V - -Optional properties: -- linux,keycodes: array of keycodes (max 4), default KEY_PHONE and KEY_BACK - -[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt - -Example: - &i2c0 { - /* ... */ - - touchkey@20 { - compatible = "cypress,tm2-touchkey"; - reg = <0x20>; - interrupt-parent = <&gpa3>; - interrupts = <2 IRQ_TYPE_EDGE_FALLING>; - vcc-supply=<&ldo32_reg>; - vdd-supply=<&ldo33_reg>; - linux,keycodes = ; - }; - }; diff --git a/Documentation/devicetree/bindings/input/cypress,tm2-touchkey.yaml b/Documentation/devicetree/bindings/input/cypress,tm2-touchkey.yaml new file mode 100644 index 000000000000..90d4def83182 --- /dev/null +++ b/Documentation/devicetree/bindings/input/cypress,tm2-touchkey.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/cypress,tm2-touchkey.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung TM2 touch key controller + +maintainers: + - Stephan Gerhold + +description: | + Touch key controllers similar to the TM2 can be found in a wide range of + Samsung devices. They are implemented using many different MCUs, but use + a similar I2C protocol. + +allOf: + - $ref: input.yaml# + +properties: + compatible: + enum: + - cypress,tm2-touchkey + - cypress,midas-touchkey + - cypress,aries-touchkey + - coreriver,tc360-touchkey + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + vdd-supply: + description: Optional regulator for LED voltage, 3.3V. + + vcc-supply: + description: Optional regulator for MCU, 1.8V-3.3V (depending on MCU). + + linux,keycodes: + minItems: 1 + maxItems: 4 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchkey@20 { + compatible = "cypress,tm2-touchkey"; + reg = <0x20>; + interrupt-parent = <&gpa3>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + vcc-supply = <&ldo32_reg>; + vdd-supply = <&ldo33_reg>; + linux,keycodes = ; + }; + }; -- cgit v1.2.3 From 3e730ec11d51283ad62a98436967c01b718132ab Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 9 Dec 2020 19:37:46 -0800 Subject: dt-bindings: input: tm2-touchkey: document vddio-supply The Samsung touchkey controllers are often used with external pull-up for the interrupt line and the I2C lines, so we might need to enable a regulator to bring the lines into usable state. Otherwise, this might cause spurious interrupts and reading from I2C will fail. Document support for a "vddio-supply" that is enabled by the tm2-touchkey driver so that the regulator gets enabled when needed. Signed-off-by: Stephan Gerhold Reviewed-by: Linus Walleij Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201203131242.44397-2-stephan@gerhold.net Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/cypress,tm2-touchkey.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/input/cypress,tm2-touchkey.yaml b/Documentation/devicetree/bindings/input/cypress,tm2-touchkey.yaml index 90d4def83182..52dca8b64081 100644 --- a/Documentation/devicetree/bindings/input/cypress,tm2-touchkey.yaml +++ b/Documentation/devicetree/bindings/input/cypress,tm2-touchkey.yaml @@ -37,6 +37,11 @@ properties: vcc-supply: description: Optional regulator for MCU, 1.8V-3.3V (depending on MCU). + vddio-supply: + description: | + Optional regulator that provides digital I/O voltage, + e.g. for pulling up the interrupt line or the I2C pins. + linux,keycodes: minItems: 1 maxItems: 4 -- cgit v1.2.3 From 7002932325ef8efff354a70b93a63dcdbca20d81 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 9 Dec 2020 19:39:07 -0800 Subject: Input: tm2-touchkey - add vddio regulator The Samsung touchkey controllers are often used with external pull-up for the interrupt line and the I2C lines, so we might need to enable a regulator to bring the lines into usable state. Otherwise, this might cause spurious interrupts and reading from I2C will fail. Implement support for a "vddio-supply" that is enabled by the tm2-touchkey driver so that the regulator gets enabled when needed. Signed-off-by: Stephan Gerhold Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20201203131242.44397-3-stephan@gerhold.net Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tm2-touchkey.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c index fb078e049413..6218b1c682ef 100644 --- a/drivers/input/keyboard/tm2-touchkey.c +++ b/drivers/input/keyboard/tm2-touchkey.c @@ -48,7 +48,7 @@ struct tm2_touchkey_data { struct input_dev *input_dev; struct led_classdev led_dev; struct regulator *vdd; - struct regulator_bulk_data regulators[2]; + struct regulator_bulk_data regulators[3]; const struct touchkey_variant *variant; u32 keycodes[4]; int num_keycodes; @@ -204,6 +204,7 @@ static int tm2_touchkey_probe(struct i2c_client *client, touchkey->regulators[0].supply = "vcc"; touchkey->regulators[1].supply = "vdd"; + touchkey->regulators[2].supply = "vddio"; error = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(touchkey->regulators), touchkey->regulators); -- cgit v1.2.3 From 03161a952c7c564aa186f94cf2cdbf834c8e624c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 10 Dec 2020 21:44:00 -0800 Subject: Input: edt-ft5x06 - consolidate handling of number of electrodes Instead of special-casing retrieval of number of X/Y electrodes based on the firmware, let's select default values and mark registers as non-existent on firmwares that do not support this operation. Also mark "report rate" register as non-existent for generic firmwares as having it set to 0 does not make sense. Reviewed-by: Andy Shevchenko Acked-by: Marco Felsch Reviewed-by: Simon Budig Link: https://lore.kernel.org/r/X9FZFs3NZADoIhhH@google.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 43 ++++++++++++++-------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 6ff81d48da86..2eefbc2485bc 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -69,6 +69,9 @@ #define EDT_RAW_DATA_RETRIES 100 #define EDT_RAW_DATA_DELAY 1000 /* usec */ +#define EDT_DEFAULT_NUM_X 1024 +#define EDT_DEFAULT_NUM_Y 1024 + enum edt_pmode { EDT_PMODE_NOT_SUPPORTED, EDT_PMODE_HIBERNATE, @@ -977,8 +980,7 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev, } } -static void -edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) +static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) { struct edt_reg_addr *reg_addr = &tsdata->reg_addr; @@ -997,21 +999,17 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) if (reg_addr->reg_report_rate != NO_REGISTER) tsdata->report_rate = edt_ft5x06_register_read(tsdata, reg_addr->reg_report_rate); - if (tsdata->version == EDT_M06 || - tsdata->version == EDT_M09 || - tsdata->version == EDT_M12) { + tsdata->num_x = EDT_DEFAULT_NUM_X; + if (reg_addr->reg_num_x != NO_REGISTER) tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x); + tsdata->num_y = EDT_DEFAULT_NUM_Y; + if (reg_addr->reg_num_y != NO_REGISTER) tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y); - } else { - tsdata->num_x = -1; - tsdata->num_y = -1; - } } -static void -edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) +static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) { struct edt_reg_addr *reg_addr = &tsdata->reg_addr; @@ -1041,22 +1039,25 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) case EV_FT: reg_addr->reg_threshold = EV_REGISTER_THRESHOLD; + reg_addr->reg_report_rate = NO_REGISTER; reg_addr->reg_gain = EV_REGISTER_GAIN; reg_addr->reg_offset = NO_REGISTER; reg_addr->reg_offset_x = EV_REGISTER_OFFSET_X; reg_addr->reg_offset_y = EV_REGISTER_OFFSET_Y; reg_addr->reg_num_x = NO_REGISTER; reg_addr->reg_num_y = NO_REGISTER; - reg_addr->reg_report_rate = NO_REGISTER; break; case GENERIC_FT: /* this is a guesswork */ 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_offset_x = NO_REGISTER; reg_addr->reg_offset_y = NO_REGISTER; + reg_addr->reg_num_x = NO_REGISTER; + reg_addr->reg_num_y = NO_REGISTER; break; } } @@ -1195,20 +1196,10 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, input->id.bustype = BUS_I2C; input->dev.parent = &client->dev; - if (tsdata->version == EDT_M06 || - tsdata->version == EDT_M09 || - tsdata->version == EDT_M12) { - input_set_abs_params(input, ABS_MT_POSITION_X, - 0, tsdata->num_x * 64 - 1, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, - 0, tsdata->num_y * 64 - 1, 0, 0); - } else { - /* Unknown maximum values. Specify via devicetree */ - input_set_abs_params(input, ABS_MT_POSITION_X, - 0, 65535, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, - 0, 65535, 0, 0); - } + input_set_abs_params(input, ABS_MT_POSITION_X, + 0, tsdata->num_x * 64 - 1, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, + 0, tsdata->num_y * 64 - 1, 0, 0); touchscreen_parse_properties(input, true, &tsdata->prop); -- cgit v1.2.3 From 6782b5da2de361ccf9a35ebf295f9efe9b9afe22 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Thu, 10 Dec 2020 21:55:31 -0800 Subject: Input: ad7877 - use new structure for SPI transfer delays In a recent change to the SPI subsystem [1], a new `delay` struct was added to replace the `delay_usecs`. This change replaces the current `delay_usecs` with `delay` for this driver. The `spi_transfer_delay_exec()` function [in the SPI framework] makes sure that both `delay_usecs` & `delay` are used (in this order to preserve backwards compatibility). [1] commit bebcfd272df6 ("spi: introduce `delay` field for `spi_transfer` + spi_transfer_delay_exec()") Signed-off-by: Sergiu Cuciurean Link: https://lore.kernel.org/r/20200228104508.15564-1-sergiu.cuciurean@analog.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7877.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index 9b652f61837f..08f5372f0bfd 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -281,12 +281,14 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command) req->xfer[1].tx_buf = &req->ref_on; req->xfer[1].len = 2; - req->xfer[1].delay_usecs = ts->vref_delay_usecs; + req->xfer[1].delay.value = ts->vref_delay_usecs; + req->xfer[1].delay.unit = SPI_DELAY_UNIT_USECS; req->xfer[1].cs_change = 1; req->xfer[2].tx_buf = &req->command; req->xfer[2].len = 2; - req->xfer[2].delay_usecs = ts->vref_delay_usecs; + req->xfer[2].delay.value = ts->vref_delay_usecs; + req->xfer[2].delay.unit = SPI_DELAY_UNIT_USECS; req->xfer[2].cs_change = 1; req->xfer[3].rx_buf = &req->sample; -- cgit v1.2.3 From 9db5fbe1a4968fcd0fae4d10565abccb9579a553 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Thu, 10 Dec 2020 21:56:36 -0800 Subject: Input: synaptics-rmi4 - use new structure for SPI transfer delays In a recent change to the SPI subsystem [1], a new `delay` struct was added to replace the `delay_usecs`. This change replaces the current `delay_usecs` with `delay` for this driver. The `spi_transfer_delay_exec()` function [in the SPI framework] makes sure that both `delay_usecs` & `delay` are used (in this order to preserve backwards compatibility). [1] commit bebcfd272df6 ("spi: introduce `delay` field for `spi_transfer` + spi_transfer_delay_exec()") Signed-off-by: Sergiu Cuciurean Link: https://lore.kernel.org/r/20200227130336.27042-1-sergiu.cuciurean@analog.com Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_spi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c index 27b68dc79b18..c82edda66b23 100644 --- a/drivers/input/rmi4/rmi_spi.c +++ b/drivers/input/rmi4/rmi_spi.c @@ -188,7 +188,8 @@ static int rmi_spi_xfer(struct rmi_spi_xport *rmi_spi, memset(xfer, 0, sizeof(struct spi_transfer)); xfer->tx_buf = &rmi_spi->tx_buf[i]; xfer->len = 1; - xfer->delay_usecs = spi_data->write_delay_us; + xfer->delay.value = spi_data->write_delay_us; + xfer->delay.unit = SPI_DELAY_UNIT_USECS; spi_message_add_tail(xfer, &msg); } } else { @@ -210,7 +211,8 @@ static int rmi_spi_xfer(struct rmi_spi_xport *rmi_spi, memset(xfer, 0, sizeof(struct spi_transfer)); xfer->rx_buf = &rmi_spi->rx_buf[i]; xfer->len = 1; - xfer->delay_usecs = spi_data->read_delay_us; + xfer->delay.value = spi_data->read_delay_us; + xfer->delay.unit = SPI_DELAY_UNIT_USECS; spi_message_add_tail(xfer, &msg); } } else { -- cgit v1.2.3 From 6a8f9ed23a8e06a3ca823aeb6058202f99e557f2 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Thu, 10 Dec 2020 21:57:36 -0800 Subject: Input: applespi - use new structure for SPI transfer delays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In a recent change to the SPI subsystem [1], a new `delay` struct was added to replace the `delay_usecs`. This change replaces the current `delay_usecs` with `delay` for this driver. The `spi_transfer_delay_exec()` function [in the SPI framework] makes sure that both `delay_usecs` & `delay` are used (in this order to preserve backwards compatibility). [1] commit bebcfd272df6 ("spi: introduce `delay` field for `spi_transfer` + spi_transfer_delay_exec()") Signed-off-by: Sergiu Cuciurean Tested-by: Ronald Tschalär Reviewed-by: Ronald Tschalär Link: https://lore.kernel.org/r/20200227124534.23399-1-sergiu.cuciurean@analog.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/applespi.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c index 8053a3d2ff63..d22223154177 100644 --- a/drivers/input/keyboard/applespi.c +++ b/drivers/input/keyboard/applespi.c @@ -554,7 +554,8 @@ static void applespi_setup_read_txfrs(struct applespi_data *applespi) memset(dl_t, 0, sizeof(*dl_t)); memset(rd_t, 0, sizeof(*rd_t)); - dl_t->delay_usecs = applespi->spi_settings.spi_cs_delay; + dl_t->delay.value = applespi->spi_settings.spi_cs_delay; + dl_t->delay.unit = SPI_DELAY_UNIT_USECS; rd_t->rx_buf = applespi->rx_buffer; rd_t->len = APPLESPI_PACKET_SIZE; @@ -583,14 +584,17 @@ static void applespi_setup_write_txfrs(struct applespi_data *applespi) * end up with an extra unnecessary (but harmless) cs assertion and * deassertion. */ - wt_t->delay_usecs = SPI_RW_CHG_DELAY_US; + wt_t->delay.value = SPI_RW_CHG_DELAY_US; + wt_t->delay.unit = SPI_DELAY_UNIT_USECS; wt_t->cs_change = 1; - dl_t->delay_usecs = applespi->spi_settings.spi_cs_delay; + dl_t->delay.value = applespi->spi_settings.spi_cs_delay; + dl_t->delay.unit = SPI_DELAY_UNIT_USECS; wr_t->tx_buf = applespi->tx_buffer; wr_t->len = APPLESPI_PACKET_SIZE; - wr_t->delay_usecs = SPI_RW_CHG_DELAY_US; + wr_t->delay.value = SPI_RW_CHG_DELAY_US; + wr_t->delay.unit = SPI_DELAY_UNIT_USECS; st_t->rx_buf = applespi->tx_status; st_t->len = APPLESPI_STATUS_SIZE; -- cgit v1.2.3 From c8834032ffe249a2a1b9702359ff29a28b8fcf1e Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 10 Dec 2020 22:01:38 -0800 Subject: Input: imx_keypad - add COMPILE_TEST support Add COMPILE_TEST support to imx_keypad driver for better compile testing coverage. Signed-off-by: Anson Huang Link: https://lore.kernel.org/r/1583137573-16628-1-git-send-email-Anson.Huang@nxp.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 793ecbbda32c..2b321c17054a 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -457,7 +457,7 @@ config KEYBOARD_SNVS_PWRKEY config KEYBOARD_IMX tristate "IMX keypad support" - depends on ARCH_MXC + depends on ARCH_MXC || COMPILE_TEST select INPUT_MATRIXKMAP help Enable support for IMX keypad port. -- cgit v1.2.3 From 3d722dd4509df5df6c2e27a6485a7336ba31cc7a Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Thu, 10 Dec 2020 22:25:52 -0800 Subject: Input: atmel_mxt_ts - simplify the return expression of mxt_send_bootloader_cmd() Simplify the return expression. Signed-off-by: Zheng Yongjun Link: https://lore.kernel.org/r/20201210135943.1612-1-zhengyongjun3@huawei.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index dde364dfb79d..f5a86aa9690e 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -608,7 +608,6 @@ recheck: static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock) { - int ret; u8 buf[2]; if (unlock) { @@ -619,11 +618,7 @@ static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock) buf[1] = 0x01; } - ret = mxt_bootloader_write(data, buf, 2); - if (ret) - return ret; - - return 0; + return mxt_bootloader_write(data, buf, sizeof(buf)); } static int __mxt_read_reg(struct i2c_client *client, -- cgit v1.2.3 From c18b443ca5f786e10cd84efbf4b8d1f38101b971 Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Thu, 10 Dec 2020 23:11:17 -0800 Subject: Input: elants - document some registers and values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add information found in downstream kernels, to make the code less magic. Signed-off-by: Michał Mirosław Reviewed-by: Dmitry Osipenko Tested-by: Dmitry Osipenko Link: https://lore.kernel.org/r/728fff020bc92be10d84cc2a7ea8af6fd99af96c.1607669375.git.mirq-linux@rere.qmqm.pl Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/elants_i2c.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 50c348297e38..d51cb910fba1 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -82,7 +82,7 @@ #define HEADER_REPORT_10_FINGER 0x62 -/* Header (4 bytes) plus 3 fill 10-finger packets */ +/* Header (4 bytes) plus 3 full 10-finger packets */ #define MAX_PACKET_SIZE 169 #define BOOT_TIME_DELAY_MS 50 @@ -97,6 +97,10 @@ #define E_INFO_PHY_SCAN 0xD7 #define E_INFO_PHY_DRIVER 0xD8 +/* FW write command, 0x54 0x?? 0x0, 0x01 */ +#define E_POWER_STATE_SLEEP 0x50 +#define E_POWER_STATE_RESUME 0x58 + #define MAX_RETRIES 3 #define MAX_FW_UPDATE_RETRIES 30 @@ -269,8 +273,8 @@ static int elants_i2c_calibrate(struct elants_data *ts) { struct i2c_client *client = ts->client; int ret, error; - static const u8 w_flashkey[] = { 0x54, 0xC0, 0xE1, 0x5A }; - static const u8 rek[] = { 0x54, 0x29, 0x00, 0x01 }; + static const u8 w_flashkey[] = { CMD_HEADER_WRITE, 0xC0, 0xE1, 0x5A }; + static const u8 rek[] = { CMD_HEADER_WRITE, 0x29, 0x00, 0x01 }; static const u8 rek_resp[] = { CMD_HEADER_REK, 0x66, 0x66, 0x66 }; disable_irq(client->irq); @@ -1388,7 +1392,9 @@ static int __maybe_unused elants_i2c_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct elants_data *ts = i2c_get_clientdata(client); - const u8 set_sleep_cmd[] = { 0x54, 0x50, 0x00, 0x01 }; + const u8 set_sleep_cmd[] = { + CMD_HEADER_WRITE, E_POWER_STATE_SLEEP, 0x00, 0x01 + }; int retry_cnt; int error; @@ -1425,7 +1431,9 @@ static int __maybe_unused elants_i2c_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct elants_data *ts = i2c_get_clientdata(client); - const u8 set_active_cmd[] = { 0x54, 0x58, 0x00, 0x01 }; + const u8 set_active_cmd[] = { + CMD_HEADER_WRITE, E_POWER_STATE_RESUME, 0x00, 0x01 + }; int retry_cnt; int error; -- cgit v1.2.3 From 056115daede8d01f71732bc7d778fb85acee8eb6 Mon Sep 17 00:00:00 2001 From: Jingle Wu Date: Thu, 10 Dec 2020 23:40:09 -0800 Subject: Input: elan_i2c - add new trackpoint report type 0x5F The 0x5F is a new trackpoint report type used by some modules. Signed-off-by: Jingle Wu Link: https://lore.kernel.org/r/20201211071511.32349-1-jingle.wu@emc.com.tw Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c.h | 16 ++++++++++++++++ drivers/input/mouse/elan_i2c_core.c | 13 +------------ drivers/input/mouse/elan_i2c_smbus.c | 8 ++++++-- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index c75b00c45d75..84bb386e97fe 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -28,6 +28,22 @@ #define ETP_FEATURE_REPORT_MK BIT(0) +#define ETP_REPORT_ID 0x5D +#define ETP_TP_REPORT_ID 0x5E +#define ETP_TP_REPORT_ID2 0x5F +#define ETP_REPORT_ID2 0x60 /* High precision report */ + +#define ETP_REPORT_ID_OFFSET 2 +#define ETP_TOUCH_INFO_OFFSET 3 +#define ETP_FINGER_DATA_OFFSET 4 +#define ETP_HOVER_INFO_OFFSET 30 +#define ETP_MK_DATA_OFFSET 33 /* For high precision reports */ + +#define ETP_MAX_REPORT_LEN 39 + +#define ETP_MAX_FINGERS 5 +#define ETP_FINGER_DATA_LEN 5 + /* IAP Firmware handling */ #define ETP_PRODUCT_ID_FORMAT_STRING "%d.0" #define ETP_FW_NAME "elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin" diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 65d21a050cea..3a8b9e890010 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -46,18 +46,6 @@ #define ETP_FINGER_WIDTH 15 #define ETP_RETRY_COUNT 3 -#define ETP_MAX_FINGERS 5 -#define ETP_FINGER_DATA_LEN 5 -#define ETP_REPORT_ID 0x5D -#define ETP_REPORT_ID2 0x60 /* High precision report */ -#define ETP_TP_REPORT_ID 0x5E -#define ETP_REPORT_ID_OFFSET 2 -#define ETP_TOUCH_INFO_OFFSET 3 -#define ETP_FINGER_DATA_OFFSET 4 -#define ETP_HOVER_INFO_OFFSET 30 -#define ETP_MK_DATA_OFFSET 33 /* For high precision reports */ -#define ETP_MAX_REPORT_LEN 39 - /* The main device structure */ struct elan_tp_data { struct i2c_client *client; @@ -1074,6 +1062,7 @@ static irqreturn_t elan_isr(int irq, void *dev_id) elan_report_absolute(data, report, true); break; case ETP_TP_REPORT_ID: + case ETP_TP_REPORT_ID2: elan_report_trackpoint(data, report); break; default: diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index 8ff823751f3b..1f38fab1825a 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -45,6 +45,7 @@ #define ETP_SMBUS_CALIBRATE_QUERY 0xC5 #define ETP_SMBUS_REPORT_LEN 32 +#define ETP_SMBUS_REPORT_LEN2 7 #define ETP_SMBUS_REPORT_OFFSET 2 #define ETP_SMBUS_HELLOPACKET_LEN 5 #define ETP_SMBUS_IAP_PASSWORD 0x1234 @@ -497,10 +498,13 @@ static int elan_smbus_get_report(struct i2c_client *client, return len; } - if (len != ETP_SMBUS_REPORT_LEN) { + if (report[ETP_REPORT_ID_OFFSET] == ETP_TP_REPORT_ID2) + report_len = ETP_SMBUS_REPORT_LEN2; + + if (len != report_len) { dev_err(&client->dev, "wrong report length (%d vs %d expected)\n", - len, ETP_SMBUS_REPORT_LEN); + len, report_len); return -EIO; } -- cgit v1.2.3 From e4c9062717feda88900b566463228d1c4910af6d Mon Sep 17 00:00:00 2001 From: "jingle.wu" Date: Thu, 10 Dec 2020 23:49:16 -0800 Subject: Input: elantech - fix protocol errors for some trackpoints in SMBus mode There are some version of Elan trackpads that send incorrect data when in SMbus mode, unless they are switched to use 0x5f reports instead of standard 0x5e. This patch implements querying device to retrieve chips identifying data, and switching it, when needed to the alternative report. Signed-off-by: Jingle Wu Link: https://lore.kernel.org/r/20201211071531.32413-1-jingle.wu@emc.com.tw Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 99 +++++++++++++++++++++++++++++++++++++++++- drivers/input/mouse/elantech.h | 4 ++ 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 47cd0e7f79bd..97381e2e03ba 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -89,6 +89,47 @@ static int elantech_ps2_command(struct psmouse *psmouse, return rc; } +/* + * Send an Elantech style special command to read 3 bytes from a register + */ +static int elantech_read_reg_params(struct psmouse *psmouse, u8 reg, u8 *param) +{ + if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, reg) || + elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) { + psmouse_err(psmouse, + "failed to read register %#02x\n", reg); + return -EIO; + } + + return 0; +} + +/* + * Send an Elantech style special command to write a register with a parameter + */ +static int elantech_write_reg_params(struct psmouse *psmouse, u8 reg, u8 *param) +{ + if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, reg) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, param[0]) || + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command(psmouse, NULL, param[1]) || + elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) { + psmouse_err(psmouse, + "failed to write register %#02x with value %#02x%#02x\n", + reg, param[0], param[1]); + return -EIO; + } + + return 0; +} + /* * Send an Elantech style special command to read a value from a register */ @@ -1529,19 +1570,35 @@ static const struct dmi_system_id no_hw_res_dmi_table[] = { { } }; +/* + * Change Report id 0x5E to 0x5F. + */ +static int elantech_change_report_id(struct psmouse *psmouse) +{ + unsigned char param[2] = { 0x10, 0x03 }; + + if (elantech_write_reg_params(psmouse, 0x7, param) || + elantech_read_reg_params(psmouse, 0x7, param) || + param[0] != 0x10 || param[1] != 0x03) { + psmouse_err(psmouse, "Unable to change report ID to 0x5f.\n"); + return -EIO; + } + + return 0; +} /* * determine hardware version and set some properties according to it. */ static int elantech_set_properties(struct elantech_device_info *info) { /* This represents the version of IC body. */ - int ver = (info->fw_version & 0x0f0000) >> 16; + info->ic_version = (info->fw_version & 0x0f0000) >> 16; /* Early version of Elan touchpads doesn't obey the rule. */ if (info->fw_version < 0x020030 || info->fw_version == 0x020600) info->hw_version = 1; else { - switch (ver) { + switch (info->ic_version) { case 2: case 4: info->hw_version = 2; @@ -1557,6 +1614,11 @@ static int elantech_set_properties(struct elantech_device_info *info) } } + /* Get information pattern for hw_version 4 */ + info->pattern = 0x00; + if (info->ic_version == 0x0f && (info->fw_version & 0xff) <= 0x02) + info->pattern = info->fw_version & 0xff; + /* decide which send_cmd we're gonna use early */ info->send_cmd = info->hw_version >= 3 ? elantech_send_cmd : synaptics_send_cmd; @@ -1598,6 +1660,7 @@ static int elantech_query_info(struct psmouse *psmouse, { unsigned char param[3]; unsigned char traces; + unsigned char ic_body[3]; memset(info, 0, sizeof(*info)); @@ -1640,6 +1703,21 @@ static int elantech_query_info(struct psmouse *psmouse, info->samples[2]); } + if (info->pattern > 0x00 && info->ic_version == 0xf) { + if (info->send_cmd(psmouse, ETP_ICBODY_QUERY, ic_body)) { + psmouse_err(psmouse, "failed to query ic body\n"); + return -EINVAL; + } + info->ic_version = be16_to_cpup((__be16 *)ic_body); + psmouse_info(psmouse, + "Elan ic body: %#04x, current fw version: %#02x\n", + info->ic_version, ic_body[2]); + } + + info->product_id = be16_to_cpup((__be16 *)info->samples); + if (info->pattern == 0x00) + info->product_id &= 0xff; + if (info->samples[1] == 0x74 && info->hw_version == 0x03) { /* * This module has a bug which makes absolute mode @@ -1654,6 +1732,23 @@ static int elantech_query_info(struct psmouse *psmouse, /* The MSB indicates the presence of the trackpoint */ info->has_trackpoint = (info->capabilities[0] & 0x80) == 0x80; + if (info->has_trackpoint && info->ic_version == 0x0011 && + (info->product_id == 0x08 || info->product_id == 0x09 || + info->product_id == 0x0d || info->product_id == 0x0e)) { + /* + * This module has a bug which makes trackpoint in SMBus + * mode return invalid data unless trackpoint is switched + * from using 0x5e reports to 0x5f. If we are not able to + * make the switch, let's abort initialization so we'll be + * using standard PS/2 protocol. + */ + if (elantech_change_report_id(psmouse)) { + psmouse_info(psmouse, + "Trackpoint report is broken, forcing standard PS/2 protocol\n"); + return -ENODEV; + } + } + info->x_res = 31; info->y_res = 31; if (info->hw_version == 4) { diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index e0a3e59d4f1b..571e6ca11d33 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -18,6 +18,7 @@ #define ETP_CAPABILITIES_QUERY 0x02 #define ETP_SAMPLE_QUERY 0x03 #define ETP_RESOLUTION_QUERY 0x04 +#define ETP_ICBODY_QUERY 0x05 /* * Command values for register reading or writing @@ -140,7 +141,10 @@ struct elantech_device_info { unsigned char samples[3]; unsigned char debug; unsigned char hw_version; + unsigned char pattern; unsigned int fw_version; + unsigned int ic_version; + unsigned int product_id; unsigned int x_min; unsigned int y_min; unsigned int x_max; -- cgit v1.2.3 From db41869108d4d735abe67648ff72e0d388a80a34 Mon Sep 17 00:00:00 2001 From: Roy Im Date: Sat, 28 Nov 2020 19:34:14 -0800 Subject: MAINTAINERS: da7280 updates to the Dialog Semiconductor search terms This patch adds the da7280 bindings doc and driver to the Dialog Semiconductor support list. Signed-off-by: Roy Im Link: https://lore.kernel.org/r/e2a01173699486519f8da85b9283c6af8481fbdb.1606320459.git.Roy.Im@diasemi.com Signed-off-by: Dmitry Torokhov --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4c460d3fc770..891ade6f9b67 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5080,6 +5080,7 @@ M: Support Opensource S: Supported W: http://www.dialog-semiconductor.com/products F: Documentation/devicetree/bindings/input/da90??-onkey.txt +F: Documentation/devicetree/bindings/input/dlg,da72??.txt F: Documentation/devicetree/bindings/mfd/da90*.txt F: Documentation/devicetree/bindings/regulator/da92*.txt F: Documentation/devicetree/bindings/regulator/slg51000.txt @@ -5090,6 +5091,7 @@ F: Documentation/hwmon/da90??.rst F: drivers/gpio/gpio-da90??.c F: drivers/hwmon/da90??-hwmon.c F: drivers/iio/adc/da91??-*.c +F: drivers/input/misc/da72??.[ch] F: drivers/input/misc/da90??_onkey.c F: drivers/input/touchscreen/da9052_tsi.c F: drivers/leds/leds-da90??.c -- cgit v1.2.3 From 4f3c429ec789f8d0f1b55aea8910cfbb13e097ea Mon Sep 17 00:00:00 2001 From: Roy Im Date: Sat, 28 Nov 2020 19:34:58 -0800 Subject: dt-bindings: input: Add document bindings for DA7280 Add device tree binding information for DA7280 haptic driver. Example bindings for DA7280 are added. Signed-off-by: Roy Im Reviewed-by: Rob Herring . Link: https://lore.kernel.org/r/2bc9a4a9d083ea8f360ec75f6281b6de6c4ef284.1606320459.git.Roy.Im@diasemi.com Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/dlg,da7280.txt | 108 +++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/dlg,da7280.txt diff --git a/Documentation/devicetree/bindings/input/dlg,da7280.txt b/Documentation/devicetree/bindings/input/dlg,da7280.txt new file mode 100644 index 000000000000..96ee5d50e111 --- /dev/null +++ b/Documentation/devicetree/bindings/input/dlg,da7280.txt @@ -0,0 +1,108 @@ +Dialog Semiconductor DA7280 Haptics bindings + +Required properties: +- compatible: Should be "dlg,da7280". +- reg: Specifies the I2C slave address. + +- interrupt-parent : Specifies the phandle of the interrupt controller to + which the IRQs from DA7280 are delivered to. + +- dlg,actuator-type: Set Actuator type. it should be one of: + "LRA" - Linear Resonance Actuator type. + "ERM-bar" - Bar type Eccentric Rotating Mass. + "ERM-coin" - Coin type Eccentric Rotating Mass. + +- dlg,const-op-mode: Haptic operation mode for FF_CONSTANT. + Possible values: + 1 - Direct register override(DRO) mode triggered by i2c(default), + 2 - PWM data source mode controlled by PWM duty, +- dlg,periodic-op-mode: Haptic operation mode for FF_PERIODIC. + Possible values: + 1 - Register triggered waveform memory(RTWM) mode, the pattern + assigned to the PS_SEQ_ID played as much times as PS_SEQ_LOOP, + 2 - Edge triggered waveform memory(ETWM) mode, external GPI(N) + control are required to enable/disable and it needs to keep + device enabled by sending magnitude (X > 0), + the pattern is assigned to the GPI(N)_SEQUENCE_ID below. + The default value is 1 for both of the operation modes. + For more details, please see the datasheet. + +- dlg,nom-microvolt: Nominal actuator voltage rating. + Valid values: 0 - 6000000. +- dlg,abs-max-microvolt: Absolute actuator maximum voltage rating. + Valid values: 0 - 6000000. +- dlg,imax-microamp: Actuator max current rating. + Valid values: 0 - 252000. + Default: 130000. +- dlg,impd-micro-ohms: the impedance of the actuator in micro ohms. + Valid values: 0 - 1500000000. + +Optional properties: +- pwms : phandle to the physical PWM(Pulse Width Modulation) device. + PWM properties should be named "pwms". And number of cell is different + for each pwm device. + (See Documentation/devicetree/bindings/pwm/pwm.txt + for further information relating to pwm properties) + +- dlg,ps-seq-id: the PS_SEQ_ID(pattern ID in waveform memory inside chip) + to play back when RTWM-MODE is enabled. + Valid range: 0 - 15. +- dlg,ps-seq-loop: the PS_SEQ_LOOP, Number of times the pre-stored sequence + pointed to by PS_SEQ_ID or GPI(N)_SEQUENCE_ID is repeated. + Valid range: 0 - 15. +- dlg,gpiN-seq-id: the GPI(N)_SEQUENCE_ID, pattern to play + when gpi0 is triggered, 'N' must be 0 - 2. + Valid range: 0 - 15. +- dlg,gpiN-mode: the pattern mode which can select either + "Single-pattern" or "Multi-pattern", 'N' must be 0 - 2. +- dlg,gpiN-polarity: gpiN polarity which can be chosen among + "Rising-edge", "Falling-edge" and "Both-edge", + 'N' must be 0 - 2 + Haptic will work by this edge option in case of ETWM mode. + +- dlg,resonant-freq-hz: use in case of LRA. + the frequency range: 50 - 300. + Default: 205. + +- dlg,bemf-sens-enable: Enable for internal loop computations. +- dlg,freq-track-enable: Enable for resonant frequency tracking. +- dlg,acc-enable: Enable for active acceleration. +- dlg,rapid-stop-enable: Enable for rapid stop. +- dlg,amp-pid-enable: Enable for the amplitude PID. +- dlg,mem-array: Customized waveform memory(patterns) data downloaded to + the device during initialization. This is an array of 100 values(u8). + +For further information, see device datasheet. + +====== + +Example: + + haptics: da7280-haptics@4a { + compatible = "dlg,da7280"; + reg = <0x4a>; + interrupt-parent = <&gpio6>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + dlg,actuator-type = "LRA"; + dlg,dlg,const-op-mode = <1>; + dlg,dlg,periodic-op-mode = <1>; + dlg,nom-microvolt = <2000000>; + dlg,abs-max-microvolt = <2000000>; + dlg,imax-microamp = <170000>; + dlg,resonant-freq-hz = <180>; + dlg,impd-micro-ohms = <10500000>; + dlg,freq-track-enable; + dlg,rapid-stop-enable; + dlg,mem-array = < + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + >; + }; -- cgit v1.2.3 From cd3f609823a5896a6f4c229b3c2077475531e23d Mon Sep 17 00:00:00 2001 From: Roy Im Date: Sat, 28 Nov 2020 19:36:26 -0800 Subject: Input: new da7280 haptic driver Adds support for the Dialog DA7280 LRA/ERM Haptic Driver with multiple mode and integrated waveform memory and wideband support. It communicates via an I2C bus to the device. Signed-off-by: Roy Im Reviewed-by: Jes Sorensen . Link: https://lore.kernel.org/r/1e293e8c4830b09255af3b7e1721b73afaefdfa3.1606320459.git.Roy.Im@diasemi.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 12 + drivers/input/misc/Makefile | 1 + drivers/input/misc/da7280.c | 1329 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1342 insertions(+) create mode 100644 drivers/input/misc/da7280.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index e7bb572e1518..ad1b6c90bc4d 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -620,6 +620,18 @@ config INPUT_RB532_BUTTON To compile this driver as a module, choose M here: the module will be called rb532_button. +config INPUT_DA7280_HAPTICS + tristate "Dialog Semiconductor DA7280 haptics support" + depends on INPUT && I2C + select REGMAP_I2C + help + Say Y to enable support for the Dialog DA7280 haptics driver. + The haptics can be controlled by PWM or GPIO + with I2C communication. + + To compile this driver as a module, choose M here: the + module will be called da7280. + config INPUT_DA9052_ONKEY tristate "Dialog DA9052/DA9053 Onkey" depends on PMIC_DA9052 diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 062cea9f181c..7f202ba8f775 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o obj-$(CONFIG_INPUT_CPCAP_PWRBUTTON) += cpcap-pwrbutton.o +obj-$(CONFIG_INPUT_DA7280_HAPTICS) += da7280.o obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o obj-$(CONFIG_INPUT_DA9063_ONKEY) += da9063_onkey.o diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c new file mode 100644 index 000000000000..9fdbae2edffe --- /dev/null +++ b/drivers/input/misc/da7280.c @@ -0,0 +1,1329 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * DA7280 Haptic device driver + * + * Copyright (c) 2020 Dialog Semiconductor. + * Author: Roy Im + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Registers */ +#define DA7280_IRQ_EVENT1 0x03 +#define DA7280_IRQ_EVENT_WARNING_DIAG 0x04 +#define DA7280_IRQ_EVENT_SEQ_DIAG 0x05 +#define DA7280_IRQ_STATUS1 0x06 +#define DA7280_IRQ_MASK1 0x07 +#define DA7280_FRQ_LRA_PER_H 0x0A +#define DA7280_FRQ_LRA_PER_L 0x0B +#define DA7280_ACTUATOR1 0x0C +#define DA7280_ACTUATOR2 0x0D +#define DA7280_ACTUATOR3 0x0E +#define DA7280_CALIB_V2I_H 0x0F +#define DA7280_CALIB_V2I_L 0x10 +#define DA7280_TOP_CFG1 0x13 +#define DA7280_TOP_CFG2 0x14 +#define DA7280_TOP_CFG4 0x16 +#define DA7280_TOP_INT_CFG1 0x17 +#define DA7280_TOP_CTL1 0x22 +#define DA7280_TOP_CTL2 0x23 +#define DA7280_SEQ_CTL2 0x28 +#define DA7280_GPI_0_CTL 0x29 +#define DA7280_GPI_1_CTL 0x2A +#define DA7280_GPI_2_CTL 0x2B +#define DA7280_MEM_CTL1 0x2C +#define DA7280_MEM_CTL2 0x2D +#define DA7280_TOP_CFG5 0x6E +#define DA7280_IRQ_MASK2 0x83 +#define DA7280_SNP_MEM_99 0xE7 + +/* Register field */ + +/* DA7280_IRQ_EVENT1 (Address 0x03) */ +#define DA7280_E_SEQ_CONTINUE_MASK BIT(0) +#define DA7280_E_UVLO_MASK BIT(1) +#define DA7280_E_SEQ_DONE_MASK BIT(2) +#define DA7280_E_OVERTEMP_CRIT_MASK BIT(3) +#define DA7280_E_SEQ_FAULT_MASK BIT(4) +#define DA7280_E_WARNING_MASK BIT(5) +#define DA7280_E_ACTUATOR_FAULT_MASK BIT(6) +#define DA7280_E_OC_FAULT_MASK BIT(7) + +/* DA7280_IRQ_EVENT_WARNING_DIAG (Address 0x04) */ +#define DA7280_E_OVERTEMP_WARN_MASK BIT(3) +#define DA7280_E_MEM_TYPE_MASK BIT(4) +#define DA7280_E_LIM_DRIVE_ACC_MASK BIT(6) +#define DA7280_E_LIM_DRIVE_MASK BIT(7) + +/* DA7280_IRQ_EVENT_PAT_DIAG (Address 0x05) */ +#define DA7280_E_PWM_FAULT_MASK BIT(5) +#define DA7280_E_MEM_FAULT_MASK BIT(6) +#define DA7280_E_SEQ_ID_FAULT_MASK BIT(7) + +/* DA7280_IRQ_STATUS1 (Address 0x06) */ +#define DA7280_STA_SEQ_CONTINUE_MASK BIT(0) +#define DA7280_STA_UVLO_VBAT_OK_MASK BIT(1) +#define DA7280_STA_SEQ_DONE_MASK BIT(2) +#define DA7280_STA_OVERTEMP_CRIT_MASK BIT(3) +#define DA7280_STA_SEQ_FAULT_MASK BIT(4) +#define DA7280_STA_WARNING_MASK BIT(5) +#define DA7280_STA_ACTUATOR_MASK BIT(6) +#define DA7280_STA_OC_MASK BIT(7) + +/* DA7280_IRQ_MASK1 (Address 0x07) */ +#define DA7280_SEQ_CONTINUE_M_MASK BIT(0) +#define DA7280_E_UVLO_M_MASK BIT(1) +#define DA7280_SEQ_DONE_M_MASK BIT(2) +#define DA7280_OVERTEMP_CRIT_M_MASK BIT(3) +#define DA7280_SEQ_FAULT_M_MASK BIT(4) +#define DA7280_WARNING_M_MASK BIT(5) +#define DA7280_ACTUATOR_M_MASK BIT(6) +#define DA7280_OC_M_MASK BIT(7) + +/* DA7280_ACTUATOR3 (Address 0x0e) */ +#define DA7280_IMAX_MASK GENMASK(4, 0) + +/* DA7280_TOP_CFG1 (Address 0x13) */ +#define DA7280_AMP_PID_EN_MASK BIT(0) +#define DA7280_RAPID_STOP_EN_MASK BIT(1) +#define DA7280_ACCELERATION_EN_MASK BIT(2) +#define DA7280_FREQ_TRACK_EN_MASK BIT(3) +#define DA7280_BEMF_SENSE_EN_MASK BIT(4) +#define DA7280_ACTUATOR_TYPE_MASK BIT(5) + +/* DA7280_TOP_CFG2 (Address 0x14) */ +#define DA7280_FULL_BRAKE_THR_MASK GENMASK(3, 0) +#define DA7280_MEM_DATA_SIGNED_MASK BIT(4) + +/* DA7280_TOP_CFG4 (Address 0x16) */ +#define DA7280_TST_CALIB_IMPEDANCE_DIS_MASK BIT(6) +#define DA7280_V2I_FACTOR_FREEZE_MASK BIT(7) + +/* DA7280_TOP_INT_CFG1 (Address 0x17) */ +#define DA7280_BEMF_FAULT_LIM_MASK GENMASK(1, 0) + +/* DA7280_TOP_CTL1 (Address 0x22) */ +#define DA7280_OPERATION_MODE_MASK GENMASK(2, 0) +#define DA7280_STANDBY_EN_MASK BIT(3) +#define DA7280_SEQ_START_MASK BIT(4) + +/* DA7280_SEQ_CTL2 (Address 0x28) */ +#define DA7280_PS_SEQ_ID_MASK GENMASK(3, 0) +#define DA7280_PS_SEQ_LOOP_MASK GENMASK(7, 4) + +/* DA7280_GPIO_0_CTL (Address 0x29) */ +#define DA7280_GPI0_POLARITY_MASK GENMASK(1, 0) +#define DA7280_GPI0_MODE_MASK BIT(2) +#define DA7280_GPI0_SEQUENCE_ID_MASK GENMASK(6, 3) + +/* DA7280_GPIO_1_CTL (Address 0x2a) */ +#define DA7280_GPI1_POLARITY_MASK GENMASK(1, 0) +#define DA7280_GPI1_MODE_MASK BIT(2) +#define DA7280_GPI1_SEQUENCE_ID_MASK GENMASK(6, 3) + +/* DA7280_GPIO_2_CTL (Address 0x2b) */ +#define DA7280_GPI2_POLARITY_MASK GENMASK(1, 0) +#define DA7280_GPI2_MODE_MASK BIT(2) +#define DA7280_GPI2_SEQUENCE_ID_MASK GENMASK(6, 3) + +/* DA7280_MEM_CTL2 (Address 0x2d) */ +#define DA7280_WAV_MEM_LOCK_MASK BIT(7) + +/* DA7280_TOP_CFG5 (Address 0x6e) */ +#define DA7280_V2I_FACTOR_OFFSET_EN_MASK BIT(0) + +/* DA7280_IRQ_MASK2 (Address 0x83) */ +#define DA7280_ADC_SAT_M_MASK BIT(7) + +/* Controls */ + +#define DA7280_VOLTAGE_RATE_MAX 6000000 +#define DA7280_VOLTAGE_RATE_STEP 23400 +#define DA7280_NOMMAX_DFT 0x6B +#define DA7280_ABSMAX_DFT 0x78 + +#define DA7280_IMPD_MAX 1500000000 +#define DA7280_IMPD_DEFAULT 22000000 + +#define DA7280_IMAX_DEFAULT 0x0E +#define DA7280_IMAX_STEP 7200 +#define DA7280_IMAX_LIMIT 252000 + +#define DA7280_RESONT_FREQH_DFT 0x39 +#define DA7280_RESONT_FREQL_DFT 0x32 +#define DA7280_MIN_RESONAT_FREQ_HZ 50 +#define DA7280_MAX_RESONAT_FREQ_HZ 300 + +#define DA7280_SEQ_ID_MAX 15 +#define DA7280_SEQ_LOOP_MAX 15 +#define DA7280_GPI_SEQ_ID_DFT 0 +#define DA7280_GPI_SEQ_ID_MAX 2 + +#define DA7280_SNP_MEM_SIZE 100 +#define DA7280_SNP_MEM_MAX DA7280_SNP_MEM_99 + +#define DA7280_IRQ_NUM 3 + +#define DA7280_SKIP_INIT 0x100 + +#define DA7280_FF_EFFECT_COUNT_MAX 15 + +/* Maximum gain is 0x7fff for PWM mode */ +#define DA7280_MAX_MAGNITUDE_SHIFT 15 + +enum da7280_haptic_dev_t { + DA7280_LRA = 0, + DA7280_ERM_BAR = 1, + DA7280_ERM_COIN = 2, + DA7280_DEV_MAX, +}; + +enum da7280_op_mode { + DA7280_INACTIVE = 0, + DA7280_DRO_MODE = 1, + DA7280_PWM_MODE = 2, + DA7280_RTWM_MODE = 3, + DA7280_ETWM_MODE = 4, + DA7280_OPMODE_MAX, +}; + +#define DA7280_FF_CONSTANT_DRO 1 +#define DA7280_FF_PERIODIC_PWM 2 +#define DA7280_FF_PERIODIC_RTWM 1 +#define DA7280_FF_PERIODIC_ETWM 2 + +#define DA7280_FF_PERIODIC_MODE DA7280_RTWM_MODE +#define DA7280_FF_CONSTANT_MODE DA7280_DRO_MODE + +enum da7280_custom_effect_param { + DA7280_CUSTOM_SEQ_ID_IDX = 0, + DA7280_CUSTOM_SEQ_LOOP_IDX = 1, + DA7280_CUSTOM_DATA_LEN = 2, +}; + +enum da7280_custom_gpi_effect_param { + DA7280_CUSTOM_GPI_SEQ_ID_IDX = 0, + DA7280_CUSTOM_GPI_NUM_IDX = 2, + DA7280_CUSTOM_GP_DATA_LEN = 3, +}; + +struct da7280_gpi_ctl { + u8 seq_id; + u8 mode; + u8 polarity; +}; + +struct da7280_haptic { + struct regmap *regmap; + struct input_dev *input_dev; + struct device *dev; + struct i2c_client *client; + struct pwm_device *pwm_dev; + + bool legacy; + struct work_struct work; + int val; + u16 gain; + s16 level; + + u8 dev_type; + u8 op_mode; + u8 const_op_mode; + u8 periodic_op_mode; + u16 nommax; + u16 absmax; + u32 imax; + u32 impd; + u32 resonant_freq_h; + u32 resonant_freq_l; + bool bemf_sense_en; + bool freq_track_en; + bool acc_en; + bool rapid_stop_en; + bool amp_pid_en; + u8 ps_seq_id; + u8 ps_seq_loop; + struct da7280_gpi_ctl gpi_ctl[3]; + bool mem_update; + u8 snp_mem[DA7280_SNP_MEM_SIZE]; + bool active; + bool suspended; +}; + +static bool da7280_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA7280_IRQ_EVENT1: + case DA7280_IRQ_EVENT_WARNING_DIAG: + case DA7280_IRQ_EVENT_SEQ_DIAG: + case DA7280_IRQ_STATUS1: + case DA7280_TOP_CTL1: + return true; + default: + return false; + } +} + +static const struct regmap_config da7280_haptic_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = DA7280_SNP_MEM_MAX, + .volatile_reg = da7280_volatile_register, +}; + +static int da7280_haptic_mem_update(struct da7280_haptic *haptics) +{ + unsigned int val; + int error; + + /* The patterns should be updated when haptic is not working */ + error = regmap_read(haptics->regmap, DA7280_IRQ_STATUS1, &val); + if (error) + return error; + if (val & DA7280_STA_WARNING_MASK) { + dev_warn(haptics->dev, + "Warning! Please check HAPTIC status.\n"); + return -EBUSY; + } + + /* Patterns are not updated if the lock bit is enabled */ + val = 0; + error = regmap_read(haptics->regmap, DA7280_MEM_CTL2, &val); + if (error) + return error; + if (~val & DA7280_WAV_MEM_LOCK_MASK) { + dev_warn(haptics->dev, "Please unlock the bit first\n"); + return -EACCES; + } + + /* Set to Inactive mode to make sure safety */ + error = regmap_update_bits(haptics->regmap, + DA7280_TOP_CTL1, + DA7280_OPERATION_MODE_MASK, + 0); + if (error) + return error; + + error = regmap_read(haptics->regmap, DA7280_MEM_CTL1, &val); + if (error) + return error; + + return regmap_bulk_write(haptics->regmap, val, haptics->snp_mem, + DA7280_SNP_MEM_MAX - val + 1); +} + +static int da7280_haptic_set_pwm(struct da7280_haptic *haptics, bool enabled) +{ + struct pwm_state state; + u64 period_mag_multi; + int error; + + if (!haptics->gain && enabled) { + dev_err(haptics->dev, "Unable to enable pwm with 0 gain\n"); + return -EINVAL; + } + + pwm_get_state(haptics->pwm_dev, &state); + state.enabled = enabled; + if (enabled) { + period_mag_multi = (u64)state.period * haptics->gain; + period_mag_multi >>= DA7280_MAX_MAGNITUDE_SHIFT; + + /* + * The interpretation of duty cycle depends on the acc_en, + * it should be between 50% and 100% for acc_en = 0. + * See datasheet 'PWM mode' section. + */ + if (!haptics->acc_en) { + period_mag_multi += state.period; + period_mag_multi /= 2; + } + + state.duty_cycle = period_mag_multi; + } + + error = pwm_apply_state(haptics->pwm_dev, &state); + if (error) + dev_err(haptics->dev, "Failed to apply pwm state: %d\n", error); + + return error; +} + +static void da7280_haptic_activate(struct da7280_haptic *haptics) +{ + int error; + + if (haptics->active) + return; + + switch (haptics->op_mode) { + case DA7280_DRO_MODE: + /* the valid range check when acc_en is enabled */ + if (haptics->acc_en && haptics->level > 0x7F) + haptics->level = 0x7F; + else if (haptics->level > 0xFF) + haptics->level = 0xFF; + + /* Set level as a % of ACTUATOR_NOMMAX (nommax) */ + error = regmap_write(haptics->regmap, DA7280_TOP_CTL2, + haptics->level); + if (error) { + dev_err(haptics->dev, + "Failed to set level to %d: %d\n", + haptics->level, error); + return; + } + break; + + case DA7280_PWM_MODE: + if (da7280_haptic_set_pwm(haptics, true)) + return; + break; + + case DA7280_RTWM_MODE: + /* + * The pattern will be played by the PS_SEQ_ID and the + * PS_SEQ_LOOP + */ + break; + + case DA7280_ETWM_MODE: + /* + * The pattern will be played by the GPI[N] state, + * GPI(N)_SEQUENCE_ID and the PS_SEQ_LOOP. See the + * datasheet for the details. + */ + break; + + default: + dev_err(haptics->dev, "Invalid op mode %d\n", haptics->op_mode); + return; + } + + error = regmap_update_bits(haptics->regmap, + DA7280_TOP_CTL1, + DA7280_OPERATION_MODE_MASK, + haptics->op_mode); + if (error) { + dev_err(haptics->dev, + "Failed to set operation mode: %d", error); + return; + } + + if (haptics->op_mode == DA7280_PWM_MODE || + haptics->op_mode == DA7280_RTWM_MODE) { + error = regmap_update_bits(haptics->regmap, + DA7280_TOP_CTL1, + DA7280_SEQ_START_MASK, + DA7280_SEQ_START_MASK); + if (error) { + dev_err(haptics->dev, + "Failed to start sequence: %d\n", error); + return; + } + } + + haptics->active = true; +} + +static void da7280_haptic_deactivate(struct da7280_haptic *haptics) +{ + int error; + + if (!haptics->active) + return; + + /* Set to Inactive mode */ + error = regmap_update_bits(haptics->regmap, + DA7280_TOP_CTL1, + DA7280_OPERATION_MODE_MASK, 0); + if (error) { + dev_err(haptics->dev, + "Failed to clear operation mode: %d", error); + return; + } + + switch (haptics->op_mode) { + case DA7280_DRO_MODE: + error = regmap_write(haptics->regmap, + DA7280_TOP_CTL2, 0); + if (error) { + dev_err(haptics->dev, + "Failed to disable DRO mode: %d\n", error); + return; + } + break; + + case DA7280_PWM_MODE: + if (da7280_haptic_set_pwm(haptics, false)) + return; + break; + + case DA7280_RTWM_MODE: + case DA7280_ETWM_MODE: + error = regmap_update_bits(haptics->regmap, + DA7280_TOP_CTL1, + DA7280_SEQ_START_MASK, 0); + if (error) { + dev_err(haptics->dev, + "Failed to disable RTWM/ETWM mode: %d\n", + error); + return; + } + break; + + default: + dev_err(haptics->dev, "Invalid op mode %d\n", haptics->op_mode); + return; + } + + haptics->active = false; +} + +static void da7280_haptic_work(struct work_struct *work) +{ + struct da7280_haptic *haptics = + container_of(work, struct da7280_haptic, work); + int val = haptics->val; + + if (val) + da7280_haptic_activate(haptics); + else + da7280_haptic_deactivate(haptics); +} + +static int da7280_haptics_upload_effect(struct input_dev *dev, + struct ff_effect *effect, + struct ff_effect *old) +{ + struct da7280_haptic *haptics = input_get_drvdata(dev); + s16 data[DA7280_SNP_MEM_SIZE] = { 0 }; + unsigned int val; + int tmp, i, num; + int error; + + /* The effect should be uploaded when haptic is not working */ + if (haptics->active) + return -EBUSY; + + switch (effect->type) { + /* DRO/PWM modes support this type */ + case FF_CONSTANT: + haptics->op_mode = haptics->const_op_mode; + if (haptics->op_mode == DA7280_DRO_MODE) { + tmp = effect->u.constant.level * 254; + haptics->level = tmp / 0x7FFF; + break; + } + + haptics->gain = effect->u.constant.level <= 0 ? + 0 : effect->u.constant.level; + break; + + /* RTWM/ETWM modes support this type */ + case FF_PERIODIC: + if (effect->u.periodic.waveform != FF_CUSTOM) { + dev_err(haptics->dev, + "Device can only accept FF_CUSTOM waveform\n"); + return -EINVAL; + } + + /* + * Load the data and check the length. + * the data will be patterns in this case: 4 < X <= 100, + * and will be saved into the waveform memory inside DA728x. + * If X = 2, the data will be PS_SEQ_ID and PS_SEQ_LOOP. + * If X = 3, the 1st data will be GPIX_SEQUENCE_ID . + */ + if (effect->u.periodic.custom_len == DA7280_CUSTOM_DATA_LEN) + goto set_seq_id_loop; + + if (effect->u.periodic.custom_len == DA7280_CUSTOM_GP_DATA_LEN) + goto set_gpix_seq_id; + + if (effect->u.periodic.custom_len < DA7280_CUSTOM_DATA_LEN || + effect->u.periodic.custom_len > DA7280_SNP_MEM_SIZE) { + dev_err(haptics->dev, "Invalid waveform data size\n"); + return -EINVAL; + } + + if (copy_from_user(data, effect->u.periodic.custom_data, + sizeof(s16) * + effect->u.periodic.custom_len)) + return -EFAULT; + + memset(haptics->snp_mem, 0, DA7280_SNP_MEM_SIZE); + + for (i = 0; i < effect->u.periodic.custom_len; i++) { + if (data[i] < 0 || data[i] > 0xff) { + dev_err(haptics->dev, + "Invalid waveform data %d at offset %d\n", + data[i], i); + return -EINVAL; + } + haptics->snp_mem[i] = (u8)data[i]; + } + + error = da7280_haptic_mem_update(haptics); + if (error) { + dev_err(haptics->dev, + "Failed to upload waveform: %d\n", error); + return error; + } + break; + +set_seq_id_loop: + if (copy_from_user(data, effect->u.periodic.custom_data, + sizeof(s16) * DA7280_CUSTOM_DATA_LEN)) + return -EFAULT; + + if (data[DA7280_CUSTOM_SEQ_ID_IDX] < 0 || + data[DA7280_CUSTOM_SEQ_ID_IDX] > DA7280_SEQ_ID_MAX || + data[DA7280_CUSTOM_SEQ_LOOP_IDX] < 0 || + data[DA7280_CUSTOM_SEQ_LOOP_IDX] > DA7280_SEQ_LOOP_MAX) { + dev_err(haptics->dev, + "Invalid custom id (%d) or loop (%d)\n", + data[DA7280_CUSTOM_SEQ_ID_IDX], + data[DA7280_CUSTOM_SEQ_LOOP_IDX]); + return -EINVAL; + } + + haptics->ps_seq_id = data[DA7280_CUSTOM_SEQ_ID_IDX] & 0x0f; + haptics->ps_seq_loop = data[DA7280_CUSTOM_SEQ_LOOP_IDX] & 0x0f; + haptics->op_mode = haptics->periodic_op_mode; + + val = FIELD_PREP(DA7280_PS_SEQ_ID_MASK, haptics->ps_seq_id) | + FIELD_PREP(DA7280_PS_SEQ_LOOP_MASK, + haptics->ps_seq_loop); + error = regmap_write(haptics->regmap, DA7280_SEQ_CTL2, val); + if (error) { + dev_err(haptics->dev, + "Failed to update PS sequence: %d\n", error); + return error; + } + break; + +set_gpix_seq_id: + if (copy_from_user(data, effect->u.periodic.custom_data, + sizeof(s16) * DA7280_CUSTOM_GP_DATA_LEN)) + return -EFAULT; + + if (data[DA7280_CUSTOM_GPI_SEQ_ID_IDX] < 0 || + data[DA7280_CUSTOM_GPI_SEQ_ID_IDX] > DA7280_SEQ_ID_MAX || + data[DA7280_CUSTOM_GPI_NUM_IDX] < 0 || + data[DA7280_CUSTOM_GPI_NUM_IDX] > DA7280_GPI_SEQ_ID_MAX) { + dev_err(haptics->dev, + "Invalid custom GPI id (%d) or num (%d)\n", + data[DA7280_CUSTOM_GPI_SEQ_ID_IDX], + data[DA7280_CUSTOM_GPI_NUM_IDX]); + return -EINVAL; + } + + num = data[DA7280_CUSTOM_GPI_NUM_IDX] & 0x0f; + haptics->gpi_ctl[num].seq_id = + data[DA7280_CUSTOM_GPI_SEQ_ID_IDX] & 0x0f; + haptics->op_mode = haptics->periodic_op_mode; + + val = FIELD_PREP(DA7280_GPI0_SEQUENCE_ID_MASK, + haptics->gpi_ctl[num].seq_id); + error = regmap_update_bits(haptics->regmap, + DA7280_GPI_0_CTL + num, + DA7280_GPI0_SEQUENCE_ID_MASK, + val); + if (error) { + dev_err(haptics->dev, + "Failed to update GPI sequemce: %d\n", error); + return error; + } + break; + + default: + dev_err(haptics->dev, "Unsupported effect type: %d\n", + effect->type); + return -EINVAL; + } + + return 0; +} + +static int da7280_haptics_playback(struct input_dev *dev, + int effect_id, int val) +{ + struct da7280_haptic *haptics = input_get_drvdata(dev); + + if (!haptics->op_mode) { + dev_warn(haptics->dev, "No effects have been uploaded\n"); + return -EINVAL; + } + + if (likely(!haptics->suspended)) { + haptics->val = val; + schedule_work(&haptics->work); + } + + return 0; +} + +static int da7280_haptic_start(struct da7280_haptic *haptics) +{ + int error; + + error = regmap_update_bits(haptics->regmap, + DA7280_TOP_CTL1, + DA7280_STANDBY_EN_MASK, + DA7280_STANDBY_EN_MASK); + if (error) { + dev_err(haptics->dev, "Unable to enable device: %d\n", error); + return error; + } + + return 0; +} + +static void da7280_haptic_stop(struct da7280_haptic *haptics) +{ + int error; + + cancel_work_sync(&haptics->work); + + + da7280_haptic_deactivate(haptics); + + error = regmap_update_bits(haptics->regmap, DA7280_TOP_CTL1, + DA7280_STANDBY_EN_MASK, 0); + if (error) + dev_err(haptics->dev, "Failed to disable device: %d\n", error); +} + +static int da7280_haptic_open(struct input_dev *dev) +{ + struct da7280_haptic *haptics = input_get_drvdata(dev); + + return da7280_haptic_start(haptics); +} + +static void da7280_haptic_close(struct input_dev *dev) +{ + struct da7280_haptic *haptics = input_get_drvdata(dev); + + da7280_haptic_stop(haptics); +} + +static u8 da7280_haptic_of_mode_str(struct device *dev, + const char *str) +{ + if (!strcmp(str, "LRA")) { + return DA7280_LRA; + } else if (!strcmp(str, "ERM-bar")) { + return DA7280_ERM_BAR; + } else if (!strcmp(str, "ERM-coin")) { + return DA7280_ERM_COIN; + } else { + dev_warn(dev, "Invalid string - set to LRA\n"); + return DA7280_LRA; + } +} + +static u8 da7280_haptic_of_gpi_mode_str(struct device *dev, + const char *str) +{ + if (!strcmp(str, "Single-pattern")) { + return 0; + } else if (!strcmp(str, "Multi-pattern")) { + return 1; + } else { + dev_warn(dev, "Invalid string - set to Single-pattern\n"); + return 0; + } +} + +static u8 da7280_haptic_of_gpi_pol_str(struct device *dev, + const char *str) +{ + if (!strcmp(str, "Rising-edge")) { + return 0; + } else if (!strcmp(str, "Falling-edge")) { + return 1; + } else if (!strcmp(str, "Both-edge")) { + return 2; + } else { + dev_warn(dev, "Invalid string - set to Rising-edge\n"); + return 0; + } +} + +static u8 da7280_haptic_of_volt_rating_set(u32 val) +{ + u32 voltage = val / DA7280_VOLTAGE_RATE_STEP + 1; + + return min_t(u32, voltage, 0xff); +} + +static void da7280_parse_properties(struct device *dev, + struct da7280_haptic *haptics) +{ + unsigned int i, mem[DA7280_SNP_MEM_SIZE]; + char gpi_str1[] = "dlg,gpi0-seq-id"; + char gpi_str2[] = "dlg,gpi0-mode"; + char gpi_str3[] = "dlg,gpi0-polarity"; + const char *str; + u32 val; + int error; + + /* + * If there is no property, then use the mode programmed into the chip. + */ + haptics->dev_type = DA7280_DEV_MAX; + error = device_property_read_string(dev, "dlg,actuator-type", &str); + if (!error) + haptics->dev_type = da7280_haptic_of_mode_str(dev, str); + + haptics->const_op_mode = DA7280_DRO_MODE; + error = device_property_read_u32(dev, "dlg,const-op-mode", &val); + if (!error && val == DA7280_FF_PERIODIC_PWM) + haptics->const_op_mode = DA7280_PWM_MODE; + + haptics->periodic_op_mode = DA7280_RTWM_MODE; + error = device_property_read_u32(dev, "dlg,periodic-op-mode", &val); + if (!error && val == DA7280_FF_PERIODIC_ETWM) + haptics->periodic_op_mode = DA7280_ETWM_MODE; + + haptics->nommax = DA7280_SKIP_INIT; + error = device_property_read_u32(dev, "dlg,nom-microvolt", &val); + if (!error && val < DA7280_VOLTAGE_RATE_MAX) + haptics->nommax = da7280_haptic_of_volt_rating_set(val); + + haptics->absmax = DA7280_SKIP_INIT; + error = device_property_read_u32(dev, "dlg,abs-max-microvolt", &val); + if (!error && val < DA7280_VOLTAGE_RATE_MAX) + haptics->absmax = da7280_haptic_of_volt_rating_set(val); + + haptics->imax = DA7280_IMAX_DEFAULT; + error = device_property_read_u32(dev, "dlg,imax-microamp", &val); + if (!error && val < DA7280_IMAX_LIMIT) + haptics->imax = (val - 28600) / DA7280_IMAX_STEP + 1; + + haptics->impd = DA7280_IMPD_DEFAULT; + error = device_property_read_u32(dev, "dlg,impd-micro-ohms", &val); + if (!error && val <= DA7280_IMPD_MAX) + haptics->impd = val; + + haptics->resonant_freq_h = DA7280_SKIP_INIT; + haptics->resonant_freq_l = DA7280_SKIP_INIT; + error = device_property_read_u32(dev, "dlg,resonant-freq-hz", &val); + if (!error) { + if (val < DA7280_MAX_RESONAT_FREQ_HZ && + val > DA7280_MIN_RESONAT_FREQ_HZ) { + haptics->resonant_freq_h = + ((1000000000 / (val * 1333)) >> 7) & 0xFF; + haptics->resonant_freq_l = + (1000000000 / (val * 1333)) & 0x7F; + } else { + haptics->resonant_freq_h = DA7280_RESONT_FREQH_DFT; + haptics->resonant_freq_l = DA7280_RESONT_FREQL_DFT; + } + } + + /* If no property, set to zero as default is to do nothing. */ + haptics->ps_seq_id = 0; + error = device_property_read_u32(dev, "dlg,ps-seq-id", &val); + if (!error && val <= DA7280_SEQ_ID_MAX) + haptics->ps_seq_id = val; + + haptics->ps_seq_loop = 0; + error = device_property_read_u32(dev, "dlg,ps-seq-loop", &val); + if (!error && val <= DA7280_SEQ_LOOP_MAX) + haptics->ps_seq_loop = val; + + /* GPI0~2 Control */ + for (i = 0; i <= DA7280_GPI_SEQ_ID_MAX; i++) { + gpi_str1[7] = '0' + i; + haptics->gpi_ctl[i].seq_id = DA7280_GPI_SEQ_ID_DFT + i; + error = device_property_read_u32 (dev, gpi_str1, &val); + if (!error && val <= DA7280_SEQ_ID_MAX) + haptics->gpi_ctl[i].seq_id = val; + + gpi_str2[7] = '0' + i; + haptics->gpi_ctl[i].mode = 0; + error = device_property_read_string(dev, gpi_str2, &str); + if (!error) + haptics->gpi_ctl[i].mode = + da7280_haptic_of_gpi_mode_str(dev, str); + + gpi_str3[7] = '0' + i; + haptics->gpi_ctl[i].polarity = 0; + error = device_property_read_string(dev, gpi_str3, &str); + haptics->gpi_ctl[i].polarity = + da7280_haptic_of_gpi_pol_str(dev, str); + } + + haptics->bemf_sense_en = + device_property_read_bool(dev, "dlg,bemf-sens-enable"); + haptics->freq_track_en = + device_property_read_bool(dev, "dlg,freq-track-enable"); + haptics->acc_en = + device_property_read_bool(dev, "dlg,acc-enable"); + haptics->rapid_stop_en = + device_property_read_bool(dev, "dlg,rapid-stop-enable"); + haptics->amp_pid_en = + device_property_read_bool(dev, "dlg,amp-pid-enable"); + + haptics->mem_update = false; + error = device_property_read_u32_array(dev, "dlg,mem-array", + &mem[0], DA7280_SNP_MEM_SIZE); + if (!error) { + haptics->mem_update = true; + memset(haptics->snp_mem, 0, DA7280_SNP_MEM_SIZE); + for (i = 0; i < DA7280_SNP_MEM_SIZE; i++) { + if (mem[i] <= 0xff) { + haptics->snp_mem[i] = (u8)mem[i]; + } else { + dev_err(haptics->dev, + "Invalid data in mem-array at %d: %x\n", + i, mem[i]); + haptics->mem_update = false; + break; + } + } + } +} + +static irqreturn_t da7280_irq_handler(int irq, void *data) +{ + struct da7280_haptic *haptics = data; + struct device *dev = haptics->dev; + u8 events[DA7280_IRQ_NUM]; + int error; + + /* Check what events have happened */ + error = regmap_bulk_read(haptics->regmap, DA7280_IRQ_EVENT1, + events, sizeof(events)); + if (error) { + dev_err(dev, "failed to read interrupt data: %d\n", error); + goto out; + } + + /* Clear events */ + error = regmap_write(haptics->regmap, DA7280_IRQ_EVENT1, events[0]); + if (error) { + dev_err(dev, "failed to clear interrupts: %d\n", error); + goto out; + } + + if (events[0] & DA7280_E_SEQ_FAULT_MASK) { + /* + * Stop first if haptic is active, otherwise, the fault may + * happen continually even though the bit is cleared. + */ + error = regmap_update_bits(haptics->regmap, DA7280_TOP_CTL1, + DA7280_OPERATION_MODE_MASK, 0); + if (error) + dev_err(dev, "failed to clear op mode on fault: %d\n", + error); + } + + if (events[0] & DA7280_E_SEQ_DONE_MASK) + haptics->active = false; + + if (events[0] & DA7280_E_WARNING_MASK) { + if (events[1] & DA7280_E_LIM_DRIVE_MASK || + events[1] & DA7280_E_LIM_DRIVE_ACC_MASK) + dev_warn(dev, "Please reduce the driver level\n"); + if (events[1] & DA7280_E_MEM_TYPE_MASK) + dev_warn(dev, "Please check the mem data format\n"); + if (events[1] & DA7280_E_OVERTEMP_WARN_MASK) + dev_warn(dev, "Over-temperature warning\n"); + } + + if (events[0] & DA7280_E_SEQ_FAULT_MASK) { + if (events[2] & DA7280_E_SEQ_ID_FAULT_MASK) + dev_info(dev, "Please reload PS_SEQ_ID & mem data\n"); + if (events[2] & DA7280_E_MEM_FAULT_MASK) + dev_info(dev, "Please reload the mem data\n"); + if (events[2] & DA7280_E_PWM_FAULT_MASK) + dev_info(dev, "Please restart PWM interface\n"); + } + +out: + return IRQ_HANDLED; +} + +static int da7280_init(struct da7280_haptic *haptics) +{ + unsigned int val = 0; + u32 v2i_factor; + int error, i; + u8 mask = 0; + + /* + * If device type is DA7280_DEV_MAX then simply use currently + * programmed mode. + */ + if (haptics->dev_type == DA7280_DEV_MAX) { + error = regmap_read(haptics->regmap, DA7280_TOP_CFG1, &val); + if (error) + goto out_err; + + haptics->dev_type = val & DA7280_ACTUATOR_TYPE_MASK ? + DA7280_ERM_COIN : DA7280_LRA; + } + + /* Apply user settings */ + if (haptics->dev_type == DA7280_LRA && + haptics->resonant_freq_l != DA7280_SKIP_INIT) { + error = regmap_write(haptics->regmap, DA7280_FRQ_LRA_PER_H, + haptics->resonant_freq_h); + if (error) + goto out_err; + error = regmap_write(haptics->regmap, DA7280_FRQ_LRA_PER_L, + haptics->resonant_freq_l); + if (error) + goto out_err; + } else if (haptics->dev_type == DA7280_ERM_COIN) { + error = regmap_update_bits(haptics->regmap, DA7280_TOP_INT_CFG1, + DA7280_BEMF_FAULT_LIM_MASK, 0); + if (error) + goto out_err; + + mask = DA7280_TST_CALIB_IMPEDANCE_DIS_MASK | + DA7280_V2I_FACTOR_FREEZE_MASK; + val = DA7280_TST_CALIB_IMPEDANCE_DIS_MASK | + DA7280_V2I_FACTOR_FREEZE_MASK; + error = regmap_update_bits(haptics->regmap, DA7280_TOP_CFG4, + mask, val); + if (error) + goto out_err; + + haptics->acc_en = false; + haptics->rapid_stop_en = false; + haptics->amp_pid_en = false; + } + + mask = DA7280_ACTUATOR_TYPE_MASK | + DA7280_BEMF_SENSE_EN_MASK | + DA7280_FREQ_TRACK_EN_MASK | + DA7280_ACCELERATION_EN_MASK | + DA7280_RAPID_STOP_EN_MASK | + DA7280_AMP_PID_EN_MASK; + val = FIELD_PREP(DA7280_ACTUATOR_TYPE_MASK, + (haptics->dev_type ? 1 : 0)) | + FIELD_PREP(DA7280_BEMF_SENSE_EN_MASK, + (haptics->bemf_sense_en ? 1 : 0)) | + FIELD_PREP(DA7280_FREQ_TRACK_EN_MASK, + (haptics->freq_track_en ? 1 : 0)) | + FIELD_PREP(DA7280_ACCELERATION_EN_MASK, + (haptics->acc_en ? 1 : 0)) | + FIELD_PREP(DA7280_RAPID_STOP_EN_MASK, + (haptics->rapid_stop_en ? 1 : 0)) | + FIELD_PREP(DA7280_AMP_PID_EN_MASK, + (haptics->amp_pid_en ? 1 : 0)); + + error = regmap_update_bits(haptics->regmap, DA7280_TOP_CFG1, mask, val); + if (error) + goto out_err; + + error = regmap_update_bits(haptics->regmap, DA7280_TOP_CFG5, + DA7280_V2I_FACTOR_OFFSET_EN_MASK, + haptics->acc_en ? + DA7280_V2I_FACTOR_OFFSET_EN_MASK : 0); + if (error) + goto out_err; + + error = regmap_update_bits(haptics->regmap, + DA7280_TOP_CFG2, + DA7280_MEM_DATA_SIGNED_MASK, + haptics->acc_en ? + 0 : DA7280_MEM_DATA_SIGNED_MASK); + if (error) + goto out_err; + + if (haptics->nommax != DA7280_SKIP_INIT) { + error = regmap_write(haptics->regmap, DA7280_ACTUATOR1, + haptics->nommax); + if (error) + goto out_err; + } + + if (haptics->absmax != DA7280_SKIP_INIT) { + error = regmap_write(haptics->regmap, DA7280_ACTUATOR2, + haptics->absmax); + if (error) + goto out_err; + } + + error = regmap_update_bits(haptics->regmap, DA7280_ACTUATOR3, + DA7280_IMAX_MASK, haptics->imax); + if (error) + goto out_err; + + v2i_factor = haptics->impd * (haptics->imax + 4) / 1610400; + error = regmap_write(haptics->regmap, DA7280_CALIB_V2I_L, + v2i_factor & 0xff); + if (error) + goto out_err; + error = regmap_write(haptics->regmap, DA7280_CALIB_V2I_H, + v2i_factor >> 8); + if (error) + goto out_err; + + error = regmap_update_bits(haptics->regmap, + DA7280_TOP_CTL1, + DA7280_STANDBY_EN_MASK, + DA7280_STANDBY_EN_MASK); + if (error) + goto out_err; + + if (haptics->mem_update) { + error = da7280_haptic_mem_update(haptics); + if (error) + goto out_err; + } + + /* Set PS_SEQ_ID and PS_SEQ_LOOP */ + val = FIELD_PREP(DA7280_PS_SEQ_ID_MASK, haptics->ps_seq_id) | + FIELD_PREP(DA7280_PS_SEQ_LOOP_MASK, haptics->ps_seq_loop); + error = regmap_write(haptics->regmap, DA7280_SEQ_CTL2, val); + if (error) + goto out_err; + + /* GPI(N) CTL */ + for (i = 0; i < 3; i++) { + val = FIELD_PREP(DA7280_GPI0_SEQUENCE_ID_MASK, + haptics->gpi_ctl[i].seq_id) | + FIELD_PREP(DA7280_GPI0_MODE_MASK, + haptics->gpi_ctl[i].mode) | + FIELD_PREP(DA7280_GPI0_POLARITY_MASK, + haptics->gpi_ctl[i].polarity); + error = regmap_write(haptics->regmap, + DA7280_GPI_0_CTL + i, val); + if (error) + goto out_err; + } + + /* Mask ADC_SAT_M bit as default */ + error = regmap_update_bits(haptics->regmap, + DA7280_IRQ_MASK2, + DA7280_ADC_SAT_M_MASK, + DA7280_ADC_SAT_M_MASK); + if (error) + goto out_err; + + /* Clear Interrupts */ + error = regmap_write(haptics->regmap, DA7280_IRQ_EVENT1, 0xff); + if (error) + goto out_err; + + error = regmap_update_bits(haptics->regmap, + DA7280_IRQ_MASK1, + DA7280_SEQ_FAULT_M_MASK | + DA7280_SEQ_DONE_M_MASK, + 0); + if (error) + goto out_err; + + haptics->active = false; + return 0; + +out_err: + dev_err(haptics->dev, "chip initialization error: %d\n", error); + return error; +} + +static int da7280_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct da7280_haptic *haptics; + struct input_dev *input_dev; + struct pwm_state state; + struct ff_device *ff; + int error; + + if (!client->irq) { + dev_err(dev, "No IRQ configured\n"); + return -EINVAL; + } + + haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL); + if (!haptics) + return -ENOMEM; + + haptics->dev = dev; + + da7280_parse_properties(dev, haptics); + + if (haptics->const_op_mode == DA7280_PWM_MODE) { + haptics->pwm_dev = devm_pwm_get(dev, NULL); + error = PTR_ERR_OR_ZERO(haptics->pwm_dev); + if (error) { + if (error != -EPROBE_DEFER) + dev_err(dev, "Unable to request PWM: %d\n", + error); + return error; + } + + /* Sync up PWM state and ensure it is off. */ + pwm_init_state(haptics->pwm_dev, &state); + state.enabled = false; + error = pwm_apply_state(haptics->pwm_dev, &state); + if (error) { + dev_err(dev, "Failed to apply PWM state: %d\n", error); + return error; + } + + /* + * Check PWM period, PWM freq = 1000000 / state.period. + * The valid PWM freq range: 10k ~ 250kHz. + */ + if (state.period > 100000 || state.period < 4000) { + dev_err(dev, "Unsupported PWM period: %lld\n", + state.period); + return -EINVAL; + } + } + + INIT_WORK(&haptics->work, da7280_haptic_work); + + haptics->client = client; + i2c_set_clientdata(client, haptics); + + haptics->regmap = devm_regmap_init_i2c(client, + &da7280_haptic_regmap_config); + error = PTR_ERR_OR_ZERO(haptics->regmap); + if (error) { + dev_err(dev, "Failed to allocate register map: %d\n", error); + return error; + } + + error = da7280_init(haptics); + if (error) { + dev_err(dev, "Failed to initialize device: %d\n", error); + return error; + } + + /* Initialize input device for haptic device */ + input_dev = devm_input_allocate_device(dev); + if (!input_dev) { + dev_err(dev, "Failed to allocate input device\n"); + return -ENOMEM; + } + + input_dev->name = "da7280-haptic"; + input_dev->dev.parent = client->dev.parent; + input_dev->open = da7280_haptic_open; + input_dev->close = da7280_haptic_close; + input_set_drvdata(input_dev, haptics); + haptics->input_dev = input_dev; + + input_set_capability(haptics->input_dev, EV_FF, FF_PERIODIC); + input_set_capability(haptics->input_dev, EV_FF, FF_CUSTOM); + input_set_capability(haptics->input_dev, EV_FF, FF_CONSTANT); + input_set_capability(haptics->input_dev, EV_FF, FF_GAIN); + + error = input_ff_create(haptics->input_dev, + DA7280_FF_EFFECT_COUNT_MAX); + if (error) { + dev_err(dev, "Failed to create FF input device: %d\n", error); + return error; + } + + ff = input_dev->ff; + ff->upload = da7280_haptics_upload_effect; + ff->playback = da7280_haptics_playback; + + error = input_register_device(input_dev); + if (error) { + dev_err(dev, "Failed to register input device: %d\n", error); + return error; + } + + error = devm_request_threaded_irq(dev, client->irq, + NULL, da7280_irq_handler, + IRQF_ONESHOT, + "da7280-haptics", haptics); + if (error) { + dev_err(dev, "Failed to request IRQ %d: %d\n", + client->irq, error); + return error; + } + + return 0; +} + +static int __maybe_unused da7280_suspend(struct device *dev) +{ + struct da7280_haptic *haptics = dev_get_drvdata(dev); + + mutex_lock(&haptics->input_dev->mutex); + + /* + * Make sure no new requests will be submitted while device is + * suspended. + */ + spin_lock_irq(&haptics->input_dev->event_lock); + haptics->suspended = true; + spin_unlock_irq(&haptics->input_dev->event_lock); + + da7280_haptic_stop(haptics); + + mutex_unlock(&haptics->input_dev->mutex); + + return 0; +} + +static int __maybe_unused da7280_resume(struct device *dev) +{ + struct da7280_haptic *haptics = dev_get_drvdata(dev); + int retval; + + mutex_lock(&haptics->input_dev->mutex); + + retval = da7280_haptic_start(haptics); + if (!retval) { + spin_lock_irq(&haptics->input_dev->event_lock); + haptics->suspended = false; + spin_unlock_irq(&haptics->input_dev->event_lock); + } + + mutex_unlock(&haptics->input_dev->mutex); + return retval; +} + +static const struct of_device_id da7280_of_match[] = { + { .compatible = "dlg,da7280", }, + { } +}; +MODULE_DEVICE_TABLE(of, da7280_of_match); + +static const struct i2c_device_id da7280_i2c_id[] = { + { "da7280", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, da7280_i2c_id); + +static SIMPLE_DEV_PM_OPS(da7280_pm_ops, da7280_suspend, da7280_resume); + +static struct i2c_driver da7280_driver = { + .driver = { + .name = "da7280", + .of_match_table = of_match_ptr(da7280_of_match), + .pm = &da7280_pm_ops, + }, + .probe = da7280_probe, + .id_table = da7280_i2c_id, +}; +module_i2c_driver(da7280_driver); + +MODULE_DESCRIPTION("DA7280 haptics driver"); +MODULE_AUTHOR("Roy Im "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 70a62fac8ffde9be8330a7b0494df34465bc091f Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Fri, 11 Dec 2020 12:58:58 -0800 Subject: Input: parkbd - convert comma to semicolon Replace a comma between expression statements by a semicolon. Signed-off-by: Zheng Yongjun Link: https://lore.kernel.org/r/20201211084957.2540-1-zhengyongjun3@huawei.com Signed-off-by: Dmitry Torokhov --- drivers/input/serio/parkbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c index ddbbd4afb4a2..3ac57a91ede4 100644 --- a/drivers/input/serio/parkbd.c +++ b/drivers/input/serio/parkbd.c @@ -168,7 +168,7 @@ static struct serio *parkbd_allocate_serio(void) serio = kzalloc(sizeof(struct serio), GFP_KERNEL); if (serio) { serio->id.type = parkbd_mode; - serio->write = parkbd_write, + serio->write = parkbd_write; strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name)); snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", parkbd_dev->port->name); } -- cgit v1.2.3 From 94ddf7a371ff5d06281825bb63cf0ac61ca1928d Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Fri, 11 Dec 2020 13:00:14 -0800 Subject: Input: ipx4xx-beeper - convert comma to semicolon Replace a comma between expression statements by a semicolon. Signed-off-by: Zheng Yongjun Link: https://lore.kernel.org/r/20201211085032.2598-1-zhengyongjun3@huawei.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/ixp4xx-beeper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c index 794ecc9a552d..05018d0c97c7 100644 --- a/drivers/input/misc/ixp4xx-beeper.c +++ b/drivers/input/misc/ixp4xx-beeper.c @@ -97,7 +97,7 @@ static int ixp4xx_spkr_probe(struct platform_device *dev) input_set_drvdata(input_dev, (void *) dev->id); - input_dev->name = "ixp4xx beeper", + input_dev->name = "ixp4xx beeper"; input_dev->phys = "ixp4xx/gpio"; input_dev->id.bustype = BUS_HOST; input_dev->id.vendor = 0x001f; -- cgit v1.2.3 From 3e35c1946805b3ecc7967e0df2bd95a7d0e0bff1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 11 Dec 2020 13:13:25 -0800 Subject: Input: adp5589-keys - do not unconditionally configure as wakeup source We should not be configuring the controller as a wakeup source in the driver, but rather rely on I2C core to mark it as such by either instantiating as I2C_CLIENT_WAKEUP or specifying "wakeup-source" device property. Link: https://lore.kernel.org/r/20201120073920.3214492-1-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5589-keys.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index e2cdf14d90cd..d76b0e4e67c4 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -930,8 +930,6 @@ static int adp5589_keypad_add(struct adp5589_kpad *kpad, unsigned int revid) return error; } - device_init_wakeup(&client->dev, 1); - return 0; } -- cgit v1.2.3 From 51a224eaf8512bc8c355e71a88b4554fda9cdeba Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 11 Dec 2020 13:14:00 -0800 Subject: Input: adp5589-keys - do not explicitly control IRQ for wakeup If device is set up as a wakeup source, I2C core configures the interrupt line as wake IRQ and PM core automatically configures it for waking up the system on system suspend transition, so we do not have to explicitly call enable_irq_wake() and disable_irq_wake() in suspend/resume. Link: https://lore.kernel.org/r/20201120073920.3214492-2-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5589-keys.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index d76b0e4e67c4..654e0476406b 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1017,32 +1018,22 @@ static int adp5589_probe(struct i2c_client *client, static int __maybe_unused adp5589_suspend(struct device *dev) { - struct adp5589_kpad *kpad = dev_get_drvdata(dev); - struct i2c_client *client = kpad->client; - - if (!kpad->input) - return 0; - - disable_irq(client->irq); + struct i2c_client *client = to_i2c_client(dev); + struct adp5589_kpad *kpad = i2c_get_clientdata(client); - if (device_may_wakeup(&client->dev)) - enable_irq_wake(client->irq); + if (kpad->input) + disable_irq(client->irq); return 0; } static int __maybe_unused adp5589_resume(struct device *dev) { - struct adp5589_kpad *kpad = dev_get_drvdata(dev); - struct i2c_client *client = kpad->client; - - if (!kpad->input) - return 0; - - if (device_may_wakeup(&client->dev)) - disable_irq_wake(client->irq); + struct i2c_client *client = to_i2c_client(dev); + struct adp5589_kpad *kpad = i2c_get_clientdata(client); - enable_irq(client->irq); + if (kpad->input) + enable_irq(client->irq); return 0; } -- cgit v1.2.3 From 888e5fad9b78a0eaf34854f6f6a122d2d18f9c6e Mon Sep 17 00:00:00 2001 From: Stefan Riedmueller Date: Sun, 4 Oct 2020 21:12:31 -0700 Subject: Input: stmpe - add axis inversion and swapping capability Make use of generic touchscreen_properties structure to add axis inversion and swapping capabilities. It's configurable via devicetree properties: touchscreen-inverted-x touchscreen-inverted-y touchscreen-swapped-x-y Signed-off-by: Stefan Riedmueller Link: https://lore.kernel.org/r/20200922093903.157232-1-s.riedmueller@phytec.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/stmpe-ts.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index 7e16fcfe3b95..cd747725589b 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +73,7 @@ struct stmpe_touch { struct input_dev *idev; struct delayed_work work; struct device *dev; + struct touchscreen_properties prop; u8 ave_ctrl; u8 touch_det_delay; u8 settling; @@ -150,8 +152,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data) y = ((data_set[1] & 0xf) << 8) | data_set[2]; z = data_set[3]; - input_report_abs(ts->idev, ABS_X, x); - input_report_abs(ts->idev, ABS_Y, y); + touchscreen_report_pos(ts->idev, &ts->prop, x, y, false); input_report_abs(ts->idev, ABS_PRESSURE, z); input_report_key(ts->idev, BTN_TOUCH, 1); input_sync(ts->idev); @@ -337,6 +338,8 @@ static int stmpe_input_probe(struct platform_device *pdev) input_set_abs_params(idev, ABS_Y, 0, XY_MASK, 0, 0); input_set_abs_params(idev, ABS_PRESSURE, 0x0, 0xff, 0, 0); + touchscreen_parse_properties(idev, false, &ts->prop); + error = input_register_device(idev); if (error) { dev_err(&pdev->dev, "Could not register input device\n"); -- cgit v1.2.3 From 5f23e464a29f7e74c24687837071912538105469 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Fri, 11 Dec 2020 18:44:14 -0800 Subject: dt-bindings: input: Convert sc27xx-vibra.txt to json-schema Convert the sprd sc27xx vibrator binding to DT schema using json-schema. Signed-off-by: Chunyan Zhang Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201117034949.47877-3-zhang.lyra@gmail.com Signed-off-by: Dmitry Torokhov --- .../bindings/input/sprd,sc27xx-vibra.txt | 23 ----------- .../bindings/input/sprd,sc27xx-vibrator.yaml | 46 ++++++++++++++++++++++ 2 files changed, 46 insertions(+), 23 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/sprd,sc27xx-vibra.txt create mode 100644 Documentation/devicetree/bindings/input/sprd,sc27xx-vibrator.yaml diff --git a/Documentation/devicetree/bindings/input/sprd,sc27xx-vibra.txt b/Documentation/devicetree/bindings/input/sprd,sc27xx-vibra.txt deleted file mode 100644 index f2ec0d4f2dff..000000000000 --- a/Documentation/devicetree/bindings/input/sprd,sc27xx-vibra.txt +++ /dev/null @@ -1,23 +0,0 @@ -Spreadtrum SC27xx PMIC Vibrator - -Required properties: -- compatible: should be "sprd,sc2731-vibrator". -- reg: address of vibrator control register. - -Example : - - sc2731_pmic: pmic@0 { - compatible = "sprd,sc2731"; - reg = <0>; - spi-max-frequency = <26000000>; - interrupts = ; - interrupt-controller; - #interrupt-cells = <2>; - #address-cells = <1>; - #size-cells = <0>; - - vibrator@eb4 { - compatible = "sprd,sc2731-vibrator"; - reg = <0xeb4>; - }; - }; diff --git a/Documentation/devicetree/bindings/input/sprd,sc27xx-vibrator.yaml b/Documentation/devicetree/bindings/input/sprd,sc27xx-vibrator.yaml new file mode 100644 index 000000000000..b8a3f23ee3dd --- /dev/null +++ b/Documentation/devicetree/bindings/input/sprd,sc27xx-vibrator.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright 2020 Unisoc Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/sprd,sc27xx-vibrator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Spreadtrum SC27xx PMIC Vibrator Device Tree Bindings + +maintainers: + - Orson Zhai + - Baolin Wang + - Chunyan Zhang + +properties: + compatible: + enum: + - sprd,sc2731-vibrator + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + sc2731_pmic: pmic@0 { + compatible = "sprd,sc2731"; + reg = <0 0>; + spi-max-frequency = <26000000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + + vibrator@eb4 { + compatible = "sprd,sc2731-vibrator"; + reg = <0xeb4>; + }; + }; -- cgit v1.2.3 From 0010d7bbf5f58e9529ecf52bc45f9b3fcff24dad Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Fri, 11 Dec 2020 18:44:30 -0800 Subject: dt-bindings: input: Add compatible string for SC2721 and SC2730 Add new compatible strings to support sc2730 and sc2721 which are two varieties of SC27XX family. Signed-off-by: Chunyan Zhang Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201117034949.47877-4-zhang.lyra@gmail.com Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/sprd,sc27xx-vibrator.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/input/sprd,sc27xx-vibrator.yaml b/Documentation/devicetree/bindings/input/sprd,sc27xx-vibrator.yaml index b8a3f23ee3dd..5d67fc8ebc18 100644 --- a/Documentation/devicetree/bindings/input/sprd,sc27xx-vibrator.yaml +++ b/Documentation/devicetree/bindings/input/sprd,sc27xx-vibrator.yaml @@ -15,6 +15,8 @@ maintainers: properties: compatible: enum: + - sprd,sc2721-vibrator + - sprd,sc2730-vibrator - sprd,sc2731-vibrator reg: -- cgit v1.2.3 From 3993a1a951feba40c0fbc87c0d3a888dbb0f768f Mon Sep 17 00:00:00 2001 From: Nemo Han Date: Fri, 11 Dec 2020 18:44:50 -0800 Subject: Input: sc27xx - add support for sc2730 and sc2721 Add new compatible strings and match data to support sc2730 and sc2721 which are two varieties of SC27XX family. Signed-off-by: Nemo Han Signed-off-by: Chunyan Zhang Link: https://lore.kernel.org/r/20201117034949.47877-2-zhang.lyra@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/sc27xx-vibra.c | 71 ++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/drivers/input/misc/sc27xx-vibra.c b/drivers/input/misc/sc27xx-vibra.c index 295251abbdac..1478017f0968 100644 --- a/drivers/input/misc/sc27xx-vibra.c +++ b/drivers/input/misc/sc27xx-vibra.c @@ -3,45 +3,82 @@ * Copyright (C) 2018 Spreadtrum Communications Inc. */ +#include +#include +#include #include -#include #include +#include #include -#include #include -#define CUR_DRV_CAL_SEL GENMASK(13, 12) -#define SLP_LDOVIBR_PD_EN BIT(9) -#define LDO_VIBR_PD BIT(8) +#define CUR_DRV_CAL_SEL GENMASK(13, 12) +#define SLP_LDOVIBR_PD_EN BIT(9) +#define LDO_VIBR_PD BIT(8) +#define SC2730_CUR_DRV_CAL_SEL 0 +#define SC2730_SLP_LDOVIBR_PD_EN BIT(14) +#define SC2730_LDO_VIBR_PD BIT(13) + +struct sc27xx_vibra_data { + u32 cur_drv_cal_sel; + u32 slp_pd_en; + u32 ldo_pd; +}; struct vibra_info { struct input_dev *input_dev; struct work_struct play_work; struct regmap *regmap; + const struct sc27xx_vibra_data *data; u32 base; u32 strength; bool enabled; }; +static const struct sc27xx_vibra_data sc2731_data = { + .cur_drv_cal_sel = CUR_DRV_CAL_SEL, + .slp_pd_en = SLP_LDOVIBR_PD_EN, + .ldo_pd = LDO_VIBR_PD, +}; + +static const struct sc27xx_vibra_data sc2730_data = { + .cur_drv_cal_sel = SC2730_CUR_DRV_CAL_SEL, + .slp_pd_en = SC2730_SLP_LDOVIBR_PD_EN, + .ldo_pd = SC2730_LDO_VIBR_PD, +}; + +static const struct sc27xx_vibra_data sc2721_data = { + .cur_drv_cal_sel = CUR_DRV_CAL_SEL, + .slp_pd_en = SLP_LDOVIBR_PD_EN, + .ldo_pd = LDO_VIBR_PD, +}; + static void sc27xx_vibra_set(struct vibra_info *info, bool on) { + const struct sc27xx_vibra_data *data = info->data; if (on) { - regmap_update_bits(info->regmap, info->base, LDO_VIBR_PD, 0); + regmap_update_bits(info->regmap, info->base, data->ldo_pd, 0); regmap_update_bits(info->regmap, info->base, - SLP_LDOVIBR_PD_EN, 0); + data->slp_pd_en, 0); info->enabled = true; } else { - regmap_update_bits(info->regmap, info->base, LDO_VIBR_PD, - LDO_VIBR_PD); + regmap_update_bits(info->regmap, info->base, data->ldo_pd, + data->ldo_pd); regmap_update_bits(info->regmap, info->base, - SLP_LDOVIBR_PD_EN, SLP_LDOVIBR_PD_EN); + data->slp_pd_en, data->slp_pd_en); info->enabled = false; } } static int sc27xx_vibra_hw_init(struct vibra_info *info) { - return regmap_update_bits(info->regmap, info->base, CUR_DRV_CAL_SEL, 0); + const struct sc27xx_vibra_data *data = info->data; + + if (!data->cur_drv_cal_sel) + return 0; + + return regmap_update_bits(info->regmap, info->base, + data->cur_drv_cal_sel, 0); } static void sc27xx_vibra_play_work(struct work_struct *work) @@ -78,8 +115,15 @@ static void sc27xx_vibra_close(struct input_dev *input) static int sc27xx_vibra_probe(struct platform_device *pdev) { struct vibra_info *info; + const struct sc27xx_vibra_data *data; int error; + data = device_get_match_data(&pdev->dev); + if (!data) { + dev_err(&pdev->dev, "no matching driver data found\n"); + return -EINVAL; + } + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; @@ -105,6 +149,7 @@ static int sc27xx_vibra_probe(struct platform_device *pdev) info->input_dev->name = "sc27xx:vibrator"; info->input_dev->id.version = 0; info->input_dev->close = sc27xx_vibra_close; + info->data = data; input_set_drvdata(info->input_dev, info); input_set_capability(info->input_dev, EV_FF, FF_RUMBLE); @@ -134,7 +179,9 @@ static int sc27xx_vibra_probe(struct platform_device *pdev) } static const struct of_device_id sc27xx_vibra_of_match[] = { - { .compatible = "sprd,sc2731-vibrator", }, + { .compatible = "sprd,sc2721-vibrator", .data = &sc2721_data }, + { .compatible = "sprd,sc2730-vibrator", .data = &sc2730_data }, + { .compatible = "sprd,sc2731-vibrator", .data = &sc2731_data }, {} }; MODULE_DEVICE_TABLE(of, sc27xx_vibra_of_match); -- cgit v1.2.3 From f051ae4f6c732c231046945b36234e977f8467c6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 14 Dec 2020 13:37:46 -0800 Subject: Input: cyapa_gen6 - fix out-of-bounds stack access gcc -Warray-bounds warns about a serious bug in cyapa_pip_retrieve_data_structure: drivers/input/mouse/cyapa_gen6.c: In function 'cyapa_pip_retrieve_data_structure.constprop': include/linux/unaligned/access_ok.h:40:17: warning: array subscript -1 is outside array bounds of 'struct retrieve_data_struct_cmd[1]' [-Warray-bounds] 40 | *((__le16 *)p) = cpu_to_le16(val); drivers/input/mouse/cyapa_gen6.c:569:13: note: while referencing 'cmd' 569 | } __packed cmd; | ^~~ Apparently the '-2' was added to the pointer instead of the value, writing garbage into the stack next to this variable. Fixes: c2c06c41f700 ("Input: cyapa - add gen6 device module support") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20201026161332.3708389-1-arnd@kernel.org Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa_gen6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/cyapa_gen6.c b/drivers/input/mouse/cyapa_gen6.c index 7eba66fbef58..812edfced86e 100644 --- a/drivers/input/mouse/cyapa_gen6.c +++ b/drivers/input/mouse/cyapa_gen6.c @@ -573,7 +573,7 @@ static int cyapa_pip_retrieve_data_structure(struct cyapa *cyapa, memset(&cmd, 0, sizeof(cmd)); put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &cmd.head.addr); - put_unaligned_le16(sizeof(cmd), &cmd.head.length - 2); + put_unaligned_le16(sizeof(cmd) - 2, &cmd.head.length); cmd.head.report_id = PIP_APP_CMD_REPORT_ID; cmd.head.cmd_code = PIP_RETRIEVE_DATA_STRUCTURE; put_unaligned_le16(read_offset, &cmd.read_offset); -- cgit v1.2.3 From 92f0a3a22c7a4c936277ece3a0215955a2d52238 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 14 Dec 2020 14:59:44 -0800 Subject: Input: da7280 - fix spelling mistake "sequemce" -> "sequence" There is a spelling mistake in a dev_err message. Fix it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20201214223109.82924-1-colin.king@canonical.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/da7280.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c index 9fdbae2edffe..37568b00873d 100644 --- a/drivers/input/misc/da7280.c +++ b/drivers/input/misc/da7280.c @@ -642,7 +642,7 @@ set_gpix_seq_id: val); if (error) { dev_err(haptics->dev, - "Failed to update GPI sequemce: %d\n", error); + "Failed to update GPI sequence: %d\n", error); return error; } break; -- cgit v1.2.3