From d18716542d137beafef2859bdf90d4e0c9a25523 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 4 Aug 2016 08:21:19 -0700 Subject: [PATCH 01/26] Input: remove duplicate ft6236 driver The new(ish) ft6236 simply re-implements the M09 protocol of the (much) older edt-ft5x06.c driver. This commit removes this duplicate driver and adds the i2c ids and dt compatible string to the edt-ft5x06.c driver to keep compatibility. This commit also adds the standard touchscreen properties as optional properties to the edt,ft5x06 binding, these were documented in the focaltech,ft6236 bindingi, but were missing from the edt,ft5x06 doc. Signed-off-by: Hans de Goede Acked-by: Rob Herring Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/edt-ft5x06.txt | 8 + .../input/touchscreen/focaltech-ft6236.txt | 35 -- drivers/input/touchscreen/Kconfig | 13 - drivers/input/touchscreen/Makefile | 1 - drivers/input/touchscreen/edt-ft5x06.c | 8 + drivers/input/touchscreen/ft6236.c | 326 ------------------ 6 files changed, 16 insertions(+), 375 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt delete mode 100644 drivers/input/touchscreen/ft6236.c diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt index f99528da1b1d..6db22103e2dd 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt @@ -19,6 +19,7 @@ Required properties: or: "edt,edt-ft5306" or: "edt,edt-ft5406" or: "edt,edt-ft5506" + or: "focaltech,ft6236" - reg: I2C slave address of the chip (0x38) - interrupt-parent: a phandle pointing to the interrupt controller @@ -43,6 +44,13 @@ Optional properties: - offset: allows setting the edge compensation in the range from 0 to 31. + - touchscreen-size-x : See touchscreen.txt + - touchscreen-size-y : See touchscreen.txt + - touchscreen-fuzz-x : See touchscreen.txt + - touchscreen-fuzz-y : See touchscreen.txt + - touchscreen-inverted-x : See touchscreen.txt + - touchscreen-inverted-y : See touchscreen.txt + - touchscreen-swapped-x-y : See touchscreen.txt Example: polytouch: edt-ft5x06@38 { diff --git a/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt b/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt deleted file mode 100644 index 777521da3da5..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/focaltech-ft6236.txt +++ /dev/null @@ -1,35 +0,0 @@ -* FocalTech FT6236 I2C touchscreen controller - -Required properties: - - compatible : "focaltech,ft6236" - - reg : I2C slave address of the chip (0x38) - - interrupt-parent : a phandle pointing to the interrupt controller - serving the interrupt for this chip - - interrupts : interrupt specification for the touch controller - interrupt - - reset-gpios : GPIO specification for the RSTN input - - touchscreen-size-x : horizontal resolution of touchscreen (in pixels) - - touchscreen-size-y : vertical resolution of touchscreen (in pixels) - -Optional properties: - - touchscreen-fuzz-x : horizontal noise value of the absolute input - device (in pixels) - - touchscreen-fuzz-y : vertical noise value of the absolute input - device (in pixels) - - touchscreen-inverted-x : X axis is inverted (boolean) - - touchscreen-inverted-y : Y axis is inverted (boolean) - - touchscreen-swapped-x-y: X and Y axis are swapped (boolean) - Swapping is done after inverting the axis - -Example: - - ft6x06@38 { - compatible = "focaltech,ft6236"; - reg = <0x38>; - interrupt-parent = <&gpio>; - interrupts = <23 2>; - touchscreen-size-x = <320>; - touchscreen-size-y = <480>; - touchscreen-inverted-x; - touchscreen-swapped-x-y; - }; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 8d893cefb0e3..c3e20e5357d4 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -305,19 +305,6 @@ config TOUCHSCREEN_EGALAX_SERIAL To compile this driver as a module, choose M here: the module will be called egalax_ts_serial. -config TOUCHSCREEN_FT6236 - tristate "FT6236 I2C touchscreen" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - help - Say Y here to enable support for the I2C connected FT6x06 and - FT6x36 family of capacitive touchscreen drivers. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called ft6236. - config TOUCHSCREEN_FUJITSU tristate "Fujitsu serial touchscreen" select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index b4373d6be402..57a1c099bc0d 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -36,7 +36,6 @@ obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o -obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 703e295a37ed..28466e358fee 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1063,9 +1063,15 @@ static const struct edt_i2c_chip_data edt_ft5506_data = { .max_support_points = 10, }; +static const struct edt_i2c_chip_data edt_ft6236_data = { + .max_support_points = 2, +}; + static const struct i2c_device_id edt_ft5x06_ts_id[] = { { .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data }, { .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data }, + /* Note no edt- prefix for compatibility with the ft6236.c driver */ + { .name = "ft6236", .driver_data = (long)&edt_ft6236_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); @@ -1076,6 +1082,8 @@ static const struct of_device_id edt_ft5x06_of_match[] = { { .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data }, { .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data }, { .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data }, + /* Note focaltech vendor prefix for compatibility with ft6236.c */ + { .compatible = "focaltech,ft6236", .data = &edt_ft6236_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); diff --git a/drivers/input/touchscreen/ft6236.c b/drivers/input/touchscreen/ft6236.c deleted file mode 100644 index d240d2e212bd..000000000000 --- a/drivers/input/touchscreen/ft6236.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * FocalTech FT6236 TouchScreen driver. - * - * Copyright (c) 2010 Focal tech Ltd. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define FT6236_MAX_TOUCH_POINTS 2 - -#define FT6236_REG_TH_GROUP 0x80 -#define FT6236_REG_PERIODACTIVE 0x88 -#define FT6236_REG_LIB_VER_H 0xa1 -#define FT6236_REG_LIB_VER_L 0xa2 -#define FT6236_REG_CIPHER 0xa3 -#define FT6236_REG_FIRMID 0xa6 -#define FT6236_REG_FOCALTECH_ID 0xa8 -#define FT6236_REG_RELEASE_CODE_ID 0xaf - -#define FT6236_EVENT_PRESS_DOWN 0 -#define FT6236_EVENT_LIFT_UP 1 -#define FT6236_EVENT_CONTACT 2 -#define FT6236_EVENT_NO_EVENT 3 - -struct ft6236_data { - struct i2c_client *client; - struct input_dev *input; - struct gpio_desc *reset_gpio; - u32 max_x; - u32 max_y; - bool invert_x; - bool invert_y; - bool swap_xy; -}; - -/* - * This struct is a touchpoint as stored in hardware. Note that the id, - * as well as the event, are stored in the upper nybble of the hi byte. - */ -struct ft6236_touchpoint { - union { - u8 xhi; - u8 event; - }; - u8 xlo; - union { - u8 yhi; - u8 id; - }; - u8 ylo; - u8 weight; - u8 misc; -} __packed; - -/* This packet represents the register map as read from offset 0 */ -struct ft6236_packet { - u8 dev_mode; - u8 gest_id; - u8 touches; - struct ft6236_touchpoint points[FT6236_MAX_TOUCH_POINTS]; -} __packed; - -static int ft6236_read(struct i2c_client *client, u8 reg, u8 len, void *data) -{ - int error; - - error = i2c_smbus_read_i2c_block_data(client, reg, len, data); - if (error < 0) - return error; - - if (error != len) - return -EIO; - - return 0; -} - -static irqreturn_t ft6236_interrupt(int irq, void *dev_id) -{ - struct ft6236_data *ft6236 = dev_id; - struct device *dev = &ft6236->client->dev; - struct input_dev *input = ft6236->input; - struct ft6236_packet buf; - u8 touches; - int i, error; - - error = ft6236_read(ft6236->client, 0, sizeof(buf), &buf); - if (error) { - dev_err(dev, "read touchdata failed %d\n", error); - return IRQ_HANDLED; - } - - touches = buf.touches & 0xf; - if (touches > FT6236_MAX_TOUCH_POINTS) { - dev_dbg(dev, - "%d touch points reported, only %d are supported\n", - touches, FT6236_MAX_TOUCH_POINTS); - touches = FT6236_MAX_TOUCH_POINTS; - } - - for (i = 0; i < touches; i++) { - struct ft6236_touchpoint *point = &buf.points[i]; - u16 x = ((point->xhi & 0xf) << 8) | buf.points[i].xlo; - u16 y = ((point->yhi & 0xf) << 8) | buf.points[i].ylo; - u8 event = point->event >> 6; - u8 id = point->id >> 4; - bool act = (event == FT6236_EVENT_PRESS_DOWN || - event == FT6236_EVENT_CONTACT); - - input_mt_slot(input, id); - input_mt_report_slot_state(input, MT_TOOL_FINGER, act); - if (!act) - continue; - - if (ft6236->invert_x) - x = ft6236->max_x - x; - - if (ft6236->invert_y) - y = ft6236->max_y - y; - - if (ft6236->swap_xy) { - input_report_abs(input, ABS_MT_POSITION_X, y); - input_report_abs(input, ABS_MT_POSITION_Y, x); - } else { - input_report_abs(input, ABS_MT_POSITION_X, x); - input_report_abs(input, ABS_MT_POSITION_Y, y); - } - } - - input_mt_sync_frame(input); - input_sync(input); - - return IRQ_HANDLED; -} - -static u8 ft6236_debug_read_byte(struct ft6236_data *ft6236, u8 reg) -{ - struct i2c_client *client = ft6236->client; - u8 val = 0; - int error; - - error = ft6236_read(client, reg, 1, &val); - if (error) - dev_dbg(&client->dev, - "error reading register 0x%02x: %d\n", reg, error); - - return val; -} - -static void ft6236_debug_info(struct ft6236_data *ft6236) -{ - struct device *dev = &ft6236->client->dev; - - dev_dbg(dev, "Touch threshold is %d\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_TH_GROUP) * 4); - dev_dbg(dev, "Report rate is %dHz\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_PERIODACTIVE) * 10); - dev_dbg(dev, "Firmware library version 0x%02x%02x\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_H), - ft6236_debug_read_byte(ft6236, FT6236_REG_LIB_VER_L)); - dev_dbg(dev, "Firmware version 0x%02x\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_FIRMID)); - dev_dbg(dev, "Chip vendor ID 0x%02x\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_CIPHER)); - dev_dbg(dev, "CTPM vendor ID 0x%02x\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_FOCALTECH_ID)); - dev_dbg(dev, "Release code version 0x%02x\n", - ft6236_debug_read_byte(ft6236, FT6236_REG_RELEASE_CODE_ID)); -} - -static void ft6236_reset(struct ft6236_data *ft6236) -{ - if (!ft6236->reset_gpio) - return; - - gpiod_set_value_cansleep(ft6236->reset_gpio, 1); - usleep_range(5000, 20000); - gpiod_set_value_cansleep(ft6236->reset_gpio, 0); - msleep(300); -} - -static int ft6236_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct device *dev = &client->dev; - struct ft6236_data *ft6236; - struct input_dev *input; - u32 fuzz_x = 0, fuzz_y = 0; - u8 val; - int error; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - return -ENXIO; - - if (!client->irq) { - dev_err(dev, "irq is missing\n"); - return -EINVAL; - } - - ft6236 = devm_kzalloc(dev, sizeof(*ft6236), GFP_KERNEL); - if (!ft6236) - return -ENOMEM; - - ft6236->client = client; - ft6236->reset_gpio = devm_gpiod_get_optional(dev, "reset", - GPIOD_OUT_LOW); - if (IS_ERR(ft6236->reset_gpio)) { - error = PTR_ERR(ft6236->reset_gpio); - if (error != -EPROBE_DEFER) - dev_err(dev, "error getting reset gpio: %d\n", error); - return error; - } - - ft6236_reset(ft6236); - - /* verify that the controller is present */ - error = ft6236_read(client, 0x00, 1, &val); - if (error) { - dev_err(dev, "failed to read from controller: %d\n", error); - return error; - } - - ft6236_debug_info(ft6236); - - input = devm_input_allocate_device(dev); - if (!input) - return -ENOMEM; - - ft6236->input = input; - input->name = client->name; - input->id.bustype = BUS_I2C; - - if (device_property_read_u32(dev, "touchscreen-size-x", - &ft6236->max_x) || - device_property_read_u32(dev, "touchscreen-size-y", - &ft6236->max_y)) { - dev_err(dev, "touchscreen-size-x and/or -y missing\n"); - return -EINVAL; - } - - device_property_read_u32(dev, "touchscreen-fuzz-x", &fuzz_x); - device_property_read_u32(dev, "touchscreen-fuzz-y", &fuzz_y); - ft6236->invert_x = device_property_read_bool(dev, - "touchscreen-inverted-x"); - ft6236->invert_y = device_property_read_bool(dev, - "touchscreen-inverted-y"); - ft6236->swap_xy = device_property_read_bool(dev, - "touchscreen-swapped-x-y"); - - if (ft6236->swap_xy) { - input_set_abs_params(input, ABS_MT_POSITION_X, 0, - ft6236->max_y, fuzz_y, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, - ft6236->max_x, fuzz_x, 0); - } else { - input_set_abs_params(input, ABS_MT_POSITION_X, 0, - ft6236->max_x, fuzz_x, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, - ft6236->max_y, fuzz_y, 0); - } - - error = input_mt_init_slots(input, FT6236_MAX_TOUCH_POINTS, - INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); - if (error) - return error; - - error = devm_request_threaded_irq(dev, client->irq, NULL, - ft6236_interrupt, IRQF_ONESHOT, - client->name, ft6236); - if (error) { - dev_err(dev, "request irq %d failed: %d\n", client->irq, error); - return error; - } - - error = input_register_device(input); - if (error) { - dev_err(dev, "failed to register input device: %d\n", error); - return error; - } - - return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id ft6236_of_match[] = { - { .compatible = "focaltech,ft6236", }, - { } -}; -MODULE_DEVICE_TABLE(of, ft6236_of_match); -#endif - -static const struct i2c_device_id ft6236_id[] = { - { "ft6236", }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ft6236_id); - -static struct i2c_driver ft6236_driver = { - .driver = { - .name = "ft6236", - .of_match_table = of_match_ptr(ft6236_of_match), - }, - .probe = ft6236_probe, - .id_table = ft6236_id, -}; -module_i2c_driver(ft6236_driver); - -MODULE_AUTHOR("Sean Cross "); -MODULE_AUTHOR("Noralf Trønnes "); -MODULE_DESCRIPTION("FocalTech FT6236 TouchScreen driver"); -MODULE_LICENSE("GPL v2"); From 8ffef3cc696e9eff67ec79be349407895bffdfc1 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Fri, 19 Aug 2016 10:16:51 -0700 Subject: [PATCH 02/26] Input: pixcir_i2c_ts - simplify code with of_device_get_match_data The usage of of_device_get_match_data reduce the code size a bit. Furthermore, it is better to use a standard function for getting the match data. Signed-off-by: LABBE Corentin Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index d159e14f4d20..b0a2dc2fbe08 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -431,13 +431,7 @@ static const struct of_device_id pixcir_of_match[]; static int pixcir_parse_dt(struct device *dev, struct pixcir_i2c_ts_data *tsdata) { - const struct of_device_id *match; - - match = of_match_device(of_match_ptr(pixcir_of_match), dev); - if (!match) - return -EINVAL; - - tsdata->chip = (const struct pixcir_i2c_chip_data *)match->data; + tsdata->chip = of_device_get_match_data(dev); if (!tsdata->chip) return -EINVAL; From 5ac82f081ac08c5ca551aa6cfc5d81ff26efdf4e Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Fri, 19 Aug 2016 10:17:18 -0700 Subject: [PATCH 03/26] Input: pixcir_i2c_ts - remove text about writing to Free Software Foundation Checkpatch complains about the text suggesting writing to Free Software Foundation for GPLv2 license copy. This patch remove that text. Signed-off-by: LABBE Corentin Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index b0a2dc2fbe08..d8b8889fd858 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -11,10 +11,6 @@ * 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 library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include From e9bf4529d3db9e6291ebfe41be08e6bb76bdf49d Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Fri, 19 Aug 2016 10:18:32 -0700 Subject: [PATCH 04/26] Input: pixcir_i2c_ts - remove a useless blank line This patch fix the following checkpatch report: Blank lines aren't necessary after an open brace Signed-off-by: LABBE Corentin Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index d8b8889fd858..3bb0637d832e 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -400,7 +400,6 @@ static int __maybe_unused pixcir_i2c_ts_resume(struct device *dev) mutex_lock(&input->mutex); if (device_may_wakeup(&client->dev)) { - if (!input->users) { ret = pixcir_stop(ts); if (ret) { From 3f5c5920e627b602db4e13b9010f76ed1d078c54 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 19 Aug 2016 10:15:46 -0700 Subject: [PATCH 05/26] Input: max77693-haptic - change Krzysztof Kozlowski's email to kernel.org Change my email address to kernel.org instead of Samsung one for the purpose of any future contact. The copyrights remain untouched and are attributed to Samsung. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Dmitry Torokhov --- drivers/input/misc/max77693-haptic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c index 6d96bff32a0e..08d5394dd981 100644 --- a/drivers/input/misc/max77693-haptic.c +++ b/drivers/input/misc/max77693-haptic.c @@ -3,7 +3,7 @@ * * Copyright (C) 2014,2015 Samsung Electronics * Jaewon Kim - * Krzysztof Kozlowski + * Krzysztof Kozlowski * * This program is not provided / owned by Maxim Integrated Products. * @@ -415,7 +415,7 @@ static struct platform_driver max77693_haptic_driver = { module_platform_driver(max77693_haptic_driver); MODULE_AUTHOR("Jaewon Kim "); -MODULE_AUTHOR("Krzysztof Kozlowski "); +MODULE_AUTHOR("Krzysztof Kozlowski "); MODULE_DESCRIPTION("MAXIM 77693/77843 Haptic driver"); MODULE_ALIAS("platform:max77693-haptic"); MODULE_LICENSE("GPL"); From a8a7bdc598ec0c355491bc1cac75f8f6b8a1740d Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 19 Aug 2016 09:40:58 -0700 Subject: [PATCH 06/26] Input: jornada720_kbd - switch to devm_* APIs Switch the jornada720_kbd driver to use the devm_* APIs. This is in preparation to removing the mach/irqs.h include from this driver. Signed-off-by: Russell King Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/jornada720_kbd.c | 43 +++++-------------------- 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 421d9c55b0e8..0a7832e0e05a 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -99,12 +99,10 @@ static int jornada720_kbd_probe(struct platform_device *pdev) struct input_dev *input_dev; int i, err; - jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!jornadakbd || !input_dev) { - err = -ENOMEM; - goto fail1; - } + jornadakbd = devm_kzalloc(&pdev->dev, sizeof(*jornadakbd), GFP_KERNEL); + input_dev = devm_input_allocate_device(&pdev->dev); + if (!jornadakbd || !input_dev) + return -ENOMEM; platform_set_drvdata(pdev, jornadakbd); @@ -127,40 +125,16 @@ static int jornada720_kbd_probe(struct platform_device *pdev) input_set_capability(input_dev, EV_MSC, MSC_SCAN); - err = request_irq(IRQ_GPIO0, - jornada720_kbd_interrupt, - IRQF_TRIGGER_FALLING, - "jornadakbd", pdev); + err = devm_request_irq(&pdev->dev, IRQ_GPIO0, jornada720_kbd_interrupt, + IRQF_TRIGGER_FALLING, "jornadakbd", pdev); if (err) { printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n"); - goto fail1; + return err; } - err = input_register_device(jornadakbd->input); - if (err) - goto fail2; - - return 0; - - fail2: /* IRQ, DEVICE, MEMORY */ - free_irq(IRQ_GPIO0, pdev); - fail1: /* DEVICE, MEMORY */ - input_free_device(input_dev); - kfree(jornadakbd); - return err; + return input_register_device(jornadakbd->input); }; -static int jornada720_kbd_remove(struct platform_device *pdev) -{ - struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); - - free_irq(IRQ_GPIO0, pdev); - input_unregister_device(jornadakbd->input); - kfree(jornadakbd); - - return 0; -} - /* work with hotplug and coldplug */ MODULE_ALIAS("platform:jornada720_kbd"); @@ -169,6 +143,5 @@ static struct platform_driver jornada720_kbd_driver = { .name = "jornada720_kbd", }, .probe = jornada720_kbd_probe, - .remove = jornada720_kbd_remove, }; module_platform_driver(jornada720_kbd_driver); From 0f631d87d9a5e3f5f22908b102c8eaad944f390e Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 19 Aug 2016 09:41:47 -0700 Subject: [PATCH 07/26] Input: jornada720_kbd - get rid of mach/irqs.h include Switch the jornada720 keyboard driver to obtain its interrupt from the platform device, rather than via a hard-coded interrupt number obtained from the mach/irqs.h header. Signed-off-by: Russell King Signed-off-by: Dmitry Torokhov --- arch/arm/mach-sa1100/jornada720.c | 6 ++++++ drivers/input/keyboard/jornada720_kbd.c | 11 +++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c index c0b1f5bafae4..2b96f7bc16bd 100644 --- a/arch/arm/mach-sa1100/jornada720.c +++ b/arch/arm/mach-sa1100/jornada720.c @@ -217,9 +217,15 @@ static struct platform_device jornada_ssp_device = { .id = -1, }; +static struct resource jornada_kbd_resources[] = { + DEFINE_RES_IRQ(IRQ_GPIO0), +}; + static struct platform_device jornada_kbd_device = { .name = "jornada720_kbd", .id = -1, + .num_resources = ARRAY_SIZE(jornada_kbd_resources), + .resource = jornada_kbd_resources, }; static struct platform_device jornada_ts_device = { diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 0a7832e0e05a..648340439d5f 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -26,7 +26,6 @@ #include #include -#include MODULE_AUTHOR("Kristoffer Ericson "); MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver"); @@ -97,7 +96,11 @@ static int jornada720_kbd_probe(struct platform_device *pdev) { struct jornadakbd *jornadakbd; struct input_dev *input_dev; - int i, err; + int i, err, irq; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) + return irq < 0 ? irq : -EINVAL; jornadakbd = devm_kzalloc(&pdev->dev, sizeof(*jornadakbd), GFP_KERNEL); input_dev = devm_input_allocate_device(&pdev->dev); @@ -125,10 +128,10 @@ static int jornada720_kbd_probe(struct platform_device *pdev) input_set_capability(input_dev, EV_MSC, MSC_SCAN); - err = devm_request_irq(&pdev->dev, IRQ_GPIO0, jornada720_kbd_interrupt, + err = devm_request_irq(&pdev->dev, irq, jornada720_kbd_interrupt, IRQF_TRIGGER_FALLING, "jornadakbd", pdev); if (err) { - printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n"); + dev_err(&pdev->dev, "unable to grab IRQ%d: %d\n", irq, err); return err; } From 99ff4d3af80caa91eef5a4b709def6b8b362ce8c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 19 Aug 2016 10:03:59 -0700 Subject: [PATCH 08/26] Input: jornada720_kbd - switch to using dev_dbg Switch to using dev_dbg instead of naked printk so that output is uniform with the other driver messages in the kernel. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/jornada720_kbd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 648340439d5f..fd8e15ea9149 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -65,10 +65,8 @@ static irqreturn_t jornada720_kbd_interrupt(int irq, void *dev_id) jornada_ssp_start(); if (jornada_ssp_inout(GETSCANKEYCODE) != TXDUMMY) { - printk(KERN_DEBUG - "jornada720_kbd: " - "GetKeycode command failed with ETIMEDOUT, " - "flushed bus\n"); + dev_dbg(&pdev->dev, + "GetKeycode command failed with ETIMEDOUT, flushed bus\n"); } else { /* How many keycodes are waiting for us? */ count = jornada_ssp_byte(TXDUMMY); From 24dde60f564b1e2eb588761ba797c7b99a374860 Mon Sep 17 00:00:00 2001 From: Bhaktipriya Shridhar Date: Tue, 23 Aug 2016 13:46:22 -0700 Subject: [PATCH 09/26] Input: psmouse - remove deprecated create_singletheread_workqueue alloc_ordered_workqueue() replaces the deprecated create_singlethread_workqueue(). There are multiple work items on the work queue viz &priv->dev3_register_work, &priv->recalib_wq, &psmouse->resync_work, which require execution ordering. Hence, an ordered workqueue has been used. The workqueue is not being used on a memory reclaim path. Hence, WQ_MEM_RECLAIM has not been set. Signed-off-by: Bhaktipriya Shridhar Acked-by: Tejun Heo Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 5784e20542a4..fb4b185dea96 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -1916,7 +1916,7 @@ static int __init psmouse_init(void) synaptics_module_init(); hgpk_module_init(); - kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); + kpsmoused_wq = alloc_ordered_workqueue("kpsmoused", 0); if (!kpsmoused_wq) { pr_err("failed to create kpsmoused workqueue\n"); return -ENOMEM; From 62e5147568968e0679ab413c7cb2ef35c8a0a4e3 Mon Sep 17 00:00:00 2001 From: Bhaktipriya Shridhar Date: Tue, 23 Aug 2016 13:47:03 -0700 Subject: [PATCH 10/26] Input: mc13783_ts - remove deprecated create_singletheread_workqueue The workqueue "workqueue" has a single workitem(&priv->work) and hence doesn't require ordering. Also, it is not being used on a memory reclaim path. Hence, the singlethreaded workqueue has been replaced with the use of system_wq. System workqueues have been able to handle high level of concurrency for a long time now and hence it's not required to have a singlethreaded workqueue just to gain concurrency. Unlike a dedicated per-cpu workqueue created with create_singlethread_workqueue(), system_wq allows multiple work items to overlap executions even on the same CPU; however, a per-cpu workqueue doesn't have any CPU locality or global ordering guarantee unless the target CPU is explicitly specified and thus the increase of local concurrency shouldn't make any difference. Workitem is sync cancelled in mc13783_ts_remove() to ensure that there are no workitems pending when the driver is disconnected. Signed-off-by: Bhaktipriya Shridhar Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/mc13783_ts.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c index 913e25a994b4..ef64f36c5ffc 100644 --- a/drivers/input/touchscreen/mc13783_ts.c +++ b/drivers/input/touchscreen/mc13783_ts.c @@ -37,7 +37,6 @@ struct mc13783_ts_priv { struct input_dev *idev; struct mc13xxx *mc13xxx; struct delayed_work work; - struct workqueue_struct *workq; unsigned int sample[4]; struct mc13xxx_ts_platform_data *touch; }; @@ -54,7 +53,7 @@ static irqreturn_t mc13783_ts_handler(int irq, void *data) * be rescheduled for immediate execution here. However the rearm * delay is HZ / 50 which is acceptable. */ - queue_delayed_work(priv->workq, &priv->work, 0); + schedule_delayed_work(&priv->work, 0); return IRQ_HANDLED; } @@ -106,16 +105,18 @@ static void mc13783_ts_report_sample(struct mc13783_ts_priv *priv) dev_dbg(&idev->dev, "report (%d, %d, %d)\n", x1, y1, 0x1000 - cr0); - queue_delayed_work(priv->workq, &priv->work, HZ / 50); - } else + schedule_delayed_work(&priv->work, HZ / 50); + } else { dev_dbg(&idev->dev, "report release\n"); + } input_report_abs(idev, ABS_PRESSURE, cr0 ? 0x1000 - cr0 : cr0); input_report_key(idev, BTN_TOUCH, cr0); input_sync(idev); - } else + } else { dev_dbg(&idev->dev, "discard event\n"); + } } static void mc13783_ts_work(struct work_struct *work) @@ -189,14 +190,6 @@ static int __init mc13783_ts_probe(struct platform_device *pdev) goto err_free_mem; } - /* - * We need separate workqueue because mc13783_adc_do_conversion - * uses keventd and thus would deadlock. - */ - priv->workq = create_singlethread_workqueue("mc13783_ts"); - if (!priv->workq) - goto err_free_mem; - idev->name = MC13783_TS_NAME; idev->dev.parent = &pdev->dev; @@ -215,14 +208,12 @@ static int __init mc13783_ts_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "register input device failed with %d\n", ret); - goto err_destroy_wq; + goto err_free_mem; } platform_set_drvdata(pdev, priv); return 0; -err_destroy_wq: - destroy_workqueue(priv->workq); err_free_mem: input_free_device(idev); kfree(priv); @@ -233,7 +224,6 @@ static int mc13783_ts_remove(struct platform_device *pdev) { struct mc13783_ts_priv *priv = platform_get_drvdata(pdev); - destroy_workqueue(priv->workq); input_unregister_device(priv->idev); kfree(priv); From c9a3a7cf95d8429c5db0fc98758c21f8fefb38fa Mon Sep 17 00:00:00 2001 From: Bhaktipriya Shridhar Date: Tue, 23 Aug 2016 14:03:03 -0700 Subject: [PATCH 11/26] Input: wm97xx - remove deprecated create_singletheread_workqueue alloc_ordered_workqueue() replaces deprecated create_singlethread_workqueue(). It queues work items via &wm->ts_reader and &wm->pen_event_work which map to wm97xx_pen_irq_worker (handles a pen down interrupt) and wm97xx_ts_reader (the touchscreen sample reader) respectively. Hence, an ordered dedicated workqueue has been used. Signed-off-by: Bhaktipriya Shridhar Acked-by: Charles Keepax 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 1534e9b0788c..90d6be3c26cc 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -500,7 +500,7 @@ static int wm97xx_ts_input_open(struct input_dev *idev) { struct wm97xx *wm = input_get_drvdata(idev); - wm->ts_workq = create_singlethread_workqueue("kwm97xx"); + wm->ts_workq = alloc_ordered_workqueue("kwm97xx", 0); if (wm->ts_workq == NULL) { dev_err(wm->dev, "Failed to create workqueue\n"); From bc1d57fe5ff7574e6cf1d53bd88edbd87e127420 Mon Sep 17 00:00:00 2001 From: Johnny Chuang Date: Thu, 25 Aug 2016 09:26:53 -0700 Subject: [PATCH 12/26] Input: elants_i2c - get product id on recovery mode for FW update We use hw version to construct name of file holding touchscreen firmware, so let's try reading it even if touchscreen initialization fails (the firmware supports reading product/hardware id even when device is in recovery/boot mode). Signed-off-by: Johnny Chuang Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/elants_i2c.c | 31 +++++++++++++++++--------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index ac09855fa435..02aec284deca 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -298,7 +298,7 @@ static u16 elants_i2c_parse_version(u8 *buf) return get_unaligned_be32(buf) >> 4; } -static int elants_i2c_query_fw_id(struct elants_data *ts) +static int elants_i2c_query_hw_version(struct elants_data *ts) { struct i2c_client *client = ts->client; int error, retry_cnt; @@ -318,8 +318,13 @@ static int elants_i2c_query_fw_id(struct elants_data *ts) error, (int)sizeof(resp), resp); } - dev_err(&client->dev, - "Failed to read fw id or fw id is invalid\n"); + if (error) { + dev_err(&client->dev, + "Failed to read fw id: %d\n", error); + return error; + } + + dev_err(&client->dev, "Invalid fw id: %#04x\n", ts->hw_version); return -EINVAL; } @@ -508,7 +513,7 @@ static int elants_i2c_fastboot(struct i2c_client *client) static int elants_i2c_initialize(struct elants_data *ts) { struct i2c_client *client = ts->client; - int error, retry_cnt; + int error, error2, retry_cnt; const u8 hello_packet[] = { 0x55, 0x55, 0x55, 0x55 }; const u8 recov_packet[] = { 0x55, 0x55, 0x80, 0x80 }; u8 buf[HEADER_SIZE]; @@ -553,18 +558,22 @@ static int elants_i2c_initialize(struct elants_data *ts) } } + /* hw version is available even if device in recovery state */ + error2 = elants_i2c_query_hw_version(ts); if (!error) - error = elants_i2c_query_fw_id(ts); + error = error2; + if (!error) error = elants_i2c_query_fw_version(ts); + if (!error) + error = elants_i2c_query_test_version(ts); + if (!error) + error = elants_i2c_query_bc_version(ts); + if (!error) + error = elants_i2c_query_ts_info(ts); - if (error) { + if (error) ts->iap_mode = ELAN_IAP_RECOVERY; - } else { - elants_i2c_query_test_version(ts); - elants_i2c_query_bc_version(ts); - elants_i2c_query_ts_info(ts); - } return 0; } From f959cd8c0eafe2bdaa9d0ec3e3da3b9451ad38aa Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Thu, 25 Aug 2016 09:41:38 -0700 Subject: [PATCH 13/26] Input: pegasus_notetaker - directly include workqueue header According to the kernel's guidelines, let's directly include the workqueue functions we use. Signed-off-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/pegasus_notetaker.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/tablet/pegasus_notetaker.c b/drivers/input/tablet/pegasus_notetaker.c index 949dacc78664..47de5a81172f 100644 --- a/drivers/input/tablet/pegasus_notetaker.c +++ b/drivers/input/tablet/pegasus_notetaker.c @@ -40,6 +40,7 @@ #include #include #include +#include /* USB HID defines */ #define USB_REQ_GET_REPORT 0x01 From 680772647d96ed853d20f837a2726151f24d8b20 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 29 Aug 2016 19:57:06 -0700 Subject: [PATCH 14/26] Input: add ADC resistor ladder driver A common way of multiplexing buttons on a single input in cheap devices is to use a resistor ladder on an ADC. This driver supports that configuration by polling an ADC channel provided by IIO. Acked-by: Jonathan Cameron Signed-off-by: Alexandre Belloni Acked-by: Rob Herring Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/adc-keys.txt | 49 ++++ drivers/input/keyboard/Kconfig | 15 ++ drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/adc-keys.c | 210 ++++++++++++++++++ 4 files changed, 275 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/adc-keys.txt create mode 100644 drivers/input/keyboard/adc-keys.c diff --git a/Documentation/devicetree/bindings/input/adc-keys.txt b/Documentation/devicetree/bindings/input/adc-keys.txt new file mode 100644 index 000000000000..e551814629b4 --- /dev/null +++ b/Documentation/devicetree/bindings/input/adc-keys.txt @@ -0,0 +1,49 @@ +ADC attached resistor ladder buttons +------------------------------------ + +Required properties: + - compatible: "adc-keys" + - io-channels: Phandle to an ADC channel + - io-channel-names = "buttons"; + - keyup-threshold-microvolt: Voltage at which all the keys are considered up. + +Optional properties: + - poll-interval: Poll interval time in milliseconds + - autorepeat: Boolean, Enable auto repeat feature of Linux input + subsystem. + +Each button (key) is represented as a sub-node of "adc-keys": + +Required subnode-properties: + - label: Descriptive name of the key. + - linux,code: Keycode to emit. + - press-threshold-microvolt: Voltage ADC input when this key is pressed. + +Example: + +#include + + adc-keys { + compatible = "adc-keys"; + io-channels = <&lradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <2000000>; + + button-up { + label = "Volume Up"; + linux,code = ; + press-threshold-microvolt = <1500000>; + }; + + button-down { + label = "Volume Down"; + linux,code = ; + press-threshold-microvolt = <1000000>; + }; + + button-enter { + label = "Enter"; + linux,code = ; + press-threshold-microvolt = <500000>; + }; + }; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 509608c95994..cbd75cf44739 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -12,6 +12,21 @@ menuconfig INPUT_KEYBOARD if INPUT_KEYBOARD +config KEYBOARD_ADC + tristate "ADC Ladder Buttons" + depends on IIO + select INPUT_POLLDEV + help + This driver implements support for buttons connected + to an ADC using a resistor ladder. + + Say Y here if your device has such buttons connected to an ADC. Your + board-specific setup logic must also provide a configuration data + for mapping voltages to buttons. + + To compile this driver as a module, choose M here: the + module will be called adc_keys. + config KEYBOARD_ADP5520 tristate "Keypad Support for ADP5520 PMIC" depends on PMIC_ADP5520 diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 1d416ddf84e4..d9f4cfcf3410 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -4,6 +4,7 @@ # Each configuration option enables a list of files. +obj-$(CONFIG_KEYBOARD_ADC) += adc-keys.o obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c new file mode 100644 index 000000000000..f8cf2ccacefd --- /dev/null +++ b/drivers/input/keyboard/adc-keys.c @@ -0,0 +1,210 @@ +/* + * Input driver for resistor ladder connected on ADC + * + * Copyright (c) 2016 Alexandre Belloni + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct adc_keys_button { + u32 voltage; + u32 keycode; +}; + +struct adc_keys_state { + struct iio_channel *channel; + u32 num_keys; + u32 last_key; + u32 keyup_voltage; + const struct adc_keys_button *map; +}; + +static void adc_keys_poll(struct input_polled_dev *dev) +{ + struct adc_keys_state *st = dev->private; + int i, value, ret; + u32 diff, closest = 0xffffffff; + int keycode = 0; + + ret = iio_read_channel_processed(st->channel, &value); + if (unlikely(ret < 0)) { + /* Forcibly release key if any was pressed */ + value = st->keyup_voltage; + } else { + for (i = 0; i < st->num_keys; i++) { + diff = abs(st->map[i].voltage - value); + if (diff < closest) { + closest = diff; + keycode = st->map[i].keycode; + } + } + } + + if (abs(st->keyup_voltage - value) < closest) + keycode = 0; + + if (st->last_key && st->last_key != keycode) + input_report_key(dev->input, st->last_key, 0); + + if (keycode) + input_report_key(dev->input, keycode, 1); + + input_sync(dev->input); + st->last_key = keycode; +} + +static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st) +{ + struct adc_keys_button *map; + struct fwnode_handle *child; + int i; + + st->num_keys = device_get_child_node_count(dev); + if (st->num_keys == 0) { + dev_err(dev, "keymap is missing\n"); + return -EINVAL; + } + + map = devm_kmalloc_array(dev, st->num_keys, sizeof(*map), GFP_KERNEL); + if (!map) + return -ENOMEM; + + i = 0; + device_for_each_child_node(dev, child) { + if (fwnode_property_read_u32(child, "press-threshold-microvolt", + &map[i].voltage)) { + dev_err(dev, "Key with invalid or missing voltage\n"); + fwnode_handle_put(child); + return -EINVAL; + } + map[i].voltage /= 1000; + + if (fwnode_property_read_u32(child, "linux,code", + &map[i].keycode)) { + dev_err(dev, "Key with invalid or missing linux,code\n"); + fwnode_handle_put(child); + return -EINVAL; + } + + i++; + } + + st->map = map; + return 0; +} + +static int adc_keys_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct adc_keys_state *st; + struct input_polled_dev *poll_dev; + struct input_dev *input; + enum iio_chan_type type; + int i, value; + int error; + + st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + st->channel = devm_iio_channel_get(dev, "buttons"); + if (IS_ERR(st->channel)) + return PTR_ERR(st->channel); + + if (!st->channel->indio_dev) + return -ENXIO; + + error = iio_get_channel_type(st->channel, &type); + if (error < 0) + return error; + + if (type != IIO_VOLTAGE) { + dev_err(dev, "Incompatible channel type %d\n", type); + return -EINVAL; + } + + if (device_property_read_u32(dev, "keyup-threshold-microvolt", + &st->keyup_voltage)) { + dev_err(dev, "Invalid or missing keyup voltage\n"); + return -EINVAL; + } + st->keyup_voltage /= 1000; + + error = adc_keys_load_keymap(dev, st); + if (error) + return error; + + platform_set_drvdata(pdev, st); + + poll_dev = devm_input_allocate_polled_device(dev); + if (!poll_dev) { + dev_err(dev, "failed to allocate input device\n"); + return -ENOMEM; + } + + if (!device_property_read_u32(dev, "poll-interval", &value)) + poll_dev->poll_interval = value; + + poll_dev->poll = adc_keys_poll; + poll_dev->private = st; + + input = poll_dev->input; + + input->name = pdev->name; + input->phys = "adc-keys/input0"; + + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + + __set_bit(EV_KEY, input->evbit); + for (i = 0; i < st->num_keys; i++) + __set_bit(st->map[i].keycode, input->keybit); + + if (device_property_read_bool(dev, "autorepeat")) + __set_bit(EV_REP, input->evbit); + + error = input_register_polled_device(poll_dev); + if (error) { + dev_err(dev, "Unable to register input device: %d\n", error); + return error; + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id adc_keys_of_match[] = { + { .compatible = "adc-keys", }, + { } +}; +MODULE_DEVICE_TABLE(of, adc_keys_of_match); +#endif + +static struct platform_driver __refdata adc_keys_driver = { + .driver = { + .name = "adc_keys", + .of_match_table = of_match_ptr(adc_keys_of_match), + }, + .probe = adc_keys_probe, +}; +module_platform_driver(adc_keys_driver); + +MODULE_AUTHOR("Alexandre Belloni "); +MODULE_DESCRIPTION("Input driver for resistor ladder connected on ADC"); +MODULE_LICENSE("GPL v2"); From 694641616448a9c5b30b3a5e5f51da73cb3a0016 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Thu, 25 Aug 2016 09:46:41 -0700 Subject: [PATCH 15/26] Input: add generic input driver to read encoded GPIO lines Add a driver to read group of GPIO lines and provide its status as a numerical value as input event to the system. This will help in interfacing devices, that can be connected over GPIOs, that provide input to the system by driving GPIO lines connected to them like a rotary dial or a switch. For example, a rotary switch can be connected to four GPIO lines. The status of the GPIO lines reflect the actual position of the rotary switch dial. For example, if dial points to 9, then the four GPIO lines connected to the switch will read HLLH(0b'1001 = 9). This value can be reported as an ABS_* event to the input subsystem. Signed-off-by: Vignesh R Acked-by: Rob Herring Signed-off-by: Dmitry Torokhov --- .../bindings/input/gpio-decoder.txt | 23 +++ drivers/input/misc/Kconfig | 12 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/gpio_decoder.c | 137 ++++++++++++++++++ 4 files changed, 173 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/gpio-decoder.txt create mode 100644 drivers/input/misc/gpio_decoder.c diff --git a/Documentation/devicetree/bindings/input/gpio-decoder.txt b/Documentation/devicetree/bindings/input/gpio-decoder.txt new file mode 100644 index 000000000000..14a77fb96cf0 --- /dev/null +++ b/Documentation/devicetree/bindings/input/gpio-decoder.txt @@ -0,0 +1,23 @@ +* GPIO Decoder DT bindings + +Required Properties: +- compatible: should be "gpio-decoder" +- gpios: a spec of gpios (at least two) to be decoded to a number with + first entry representing the MSB. + +Optional Properties: +- decoder-max-value: Maximum possible value that can be reported by + the gpios. +- linux,axis: the input subsystem axis to map to (ABS_X/ABS_Y). + Defaults to 0 (ABS_X). + +Example: + gpio-decoder0 { + compatible = "gpio-decoder"; + gpios = <&pca9536 3 GPIO_ACTIVE_HIGH>, + <&pca9536 2 GPIO_ACTIVE_HIGH>, + <&pca9536 1 GPIO_ACTIVE_HIGH>, + <&pca9536 0 GPIO_ACTIVE_HIGH>; + linux,axis = <0>; /* ABS_X */ + decoder-max-value = <9>; + }; diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index efb0ca871327..7cdb89397d18 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -292,6 +292,18 @@ config INPUT_GPIO_TILT_POLLED To compile this driver as a module, choose M here: the module will be called gpio_tilt_polled. +config INPUT_GPIO_DECODER + tristate "Polled GPIO Decoder Input driver" + depends on GPIOLIB || COMPILE_TEST + select INPUT_POLLDEV + help + Say Y here if you want driver to read status of multiple GPIO + lines and report the encoded value as an absolute integer to + input subsystem. + + To compile this driver as a module, choose M here: the module + will be called gpio_decoder. + config INPUT_IXP4XX_BEEPER tristate "IXP4XX Beeper support" depends on ARCH_IXP4XX diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 6a1e5e20fc1c..0b6d025f0487 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o +obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o diff --git a/drivers/input/misc/gpio_decoder.c b/drivers/input/misc/gpio_decoder.c new file mode 100644 index 000000000000..ca7e0bacb2d8 --- /dev/null +++ b/drivers/input/misc/gpio_decoder.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * A generic driver to read multiple gpio lines and translate the + * encoded numeric value into an input event. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct gpio_decoder { + struct input_polled_dev *poll_dev; + struct gpio_descs *input_gpios; + struct device *dev; + u32 axis; + u32 last_stable; +}; + +static int gpio_decoder_get_gpios_state(struct gpio_decoder *decoder) +{ + struct gpio_descs *gpios = decoder->input_gpios; + unsigned int ret = 0; + int i, val; + + for (i = 0; i < gpios->ndescs; i++) { + val = gpiod_get_value_cansleep(gpios->desc[i]); + if (val < 0) { + dev_err(decoder->dev, + "Error reading gpio %d: %d\n", + desc_to_gpio(gpios->desc[i]), val); + return val; + } + + val = !!val; + ret = (ret << 1) | val; + } + + return ret; +} + +static void gpio_decoder_poll_gpios(struct input_polled_dev *poll_dev) +{ + struct gpio_decoder *decoder = poll_dev->private; + int state; + + state = gpio_decoder_get_gpios_state(decoder); + if (state >= 0 && state != decoder->last_stable) { + input_report_abs(poll_dev->input, decoder->axis, state); + input_sync(poll_dev->input); + decoder->last_stable = state; + } +} + +static int gpio_decoder_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct gpio_decoder *decoder; + struct input_polled_dev *poll_dev; + u32 max; + int err; + + decoder = devm_kzalloc(dev, sizeof(struct gpio_decoder), GFP_KERNEL); + if (!decoder) + return -ENOMEM; + + device_property_read_u32(dev, "linux,axis", &decoder->axis); + decoder->input_gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN); + if (IS_ERR(decoder->input_gpios)) { + dev_err(dev, "unable to acquire input gpios\n"); + return PTR_ERR(decoder->input_gpios); + } + if (decoder->input_gpios->ndescs < 2) { + dev_err(dev, "not enough gpios found\n"); + return -EINVAL; + } + + if (device_property_read_u32(dev, "decoder-max-value", &max)) + max = (1U << decoder->input_gpios->ndescs) - 1; + + decoder->dev = dev; + poll_dev = devm_input_allocate_polled_device(decoder->dev); + if (!poll_dev) + return -ENOMEM; + + poll_dev->private = decoder; + poll_dev->poll = gpio_decoder_poll_gpios; + decoder->poll_dev = poll_dev; + + poll_dev->input->name = pdev->name; + poll_dev->input->id.bustype = BUS_HOST; + input_set_abs_params(poll_dev->input, decoder->axis, 0, max, 0, 0); + + err = input_register_polled_device(poll_dev); + if (err) { + dev_err(dev, "failed to register polled device\n"); + return err; + } + platform_set_drvdata(pdev, decoder); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id gpio_decoder_of_match[] = { + { .compatible = "gpio-decoder", }, + { }, +}; +MODULE_DEVICE_TABLE(of, gpio_decoder_of_match); +#endif + +static struct platform_driver gpio_decoder_driver = { + .probe = gpio_decoder_probe, + .driver = { + .name = "gpio-decoder", + .of_match_table = of_match_ptr(gpio_decoder_of_match), + } +}; +module_platform_driver(gpio_decoder_driver); + +MODULE_DESCRIPTION("GPIO decoder input driver"); +MODULE_AUTHOR("Vignesh R "); +MODULE_LICENSE("GPL v2"); From de56bea05b09aa1f3498ee12df8f995aaf259dd7 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Sat, 3 Sep 2016 10:39:07 -0700 Subject: [PATCH 16/26] Input: gpio-keys-polled - don't use unit-address with button nodes The change corrects an example in device tree documentation section, because button/key device nodes don't contain reg property there is no need to declare unit-address, and address and size cell properties are also redundant. At the moment a compilation of the hypothetical original example should produce W=1 level warnings, and it is better to stop spreading misusage of the polled gpio keys device tree binding through this example. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/gpio-keys-polled.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt index 95d0fb11a787..4d9a3717eaaf 100644 --- a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt +++ b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt @@ -34,11 +34,10 @@ Example nodes: gpio_keys_polled { compatible = "gpio-keys-polled"; - #address-cells = <1>; - #size-cells = <0>; poll-interval = <100>; autorepeat; - button@21 { + + button21 { label = "GPIO Key UP"; linux,code = <103>; gpios = <&gpio1 0 1>; From 4e7482332236d9f0c8f6df2e80fd73ad68363c35 Mon Sep 17 00:00:00 2001 From: HungNien Chen Date: Mon, 5 Sep 2016 10:25:36 -0700 Subject: [PATCH 17/26] Input: wdt87xx_i2c - fix the flash erase issue The spec says that flash erase time is 30ms typical/200ms max, so let's replace current 50ms wait with 200ms to avoid potential failures. Signed-off-by: HungNien Chen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wdt87xx_i2c.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index 73861ad22df4..a9132603ab34 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -23,7 +23,7 @@ #include #define WDT87XX_NAME "wdt87xx_i2c" -#define WDT87XX_DRV_VER "0.9.7" +#define WDT87XX_DRV_VER "0.9.8" #define WDT87XX_FW_NAME "wdt87xx_fw.bin" #define WDT87XX_CFG_NAME "wdt87xx_cfg.bin" @@ -157,6 +157,7 @@ /* Controller requires minimum 300us between commands */ #define WDT_COMMAND_DELAY_MS 2 #define WDT_FLASH_WRITE_DELAY_MS 4 +#define WDT_FLASH_ERASE_DELAY_MS 200 #define WDT_FW_RESET_TIME 2500 struct wdt87xx_sys_param { @@ -726,7 +727,7 @@ static int wdt87xx_write_firmware(struct i2c_client *client, const void *chunk) break; } - msleep(50); + msleep(WDT_FLASH_ERASE_DELAY_MS); error = wdt87xx_write_data(client, data, start_addr, page_size); From db808498ae2c922c9bd3eaf39a7526581468a79b Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Mon, 5 Sep 2016 10:33:28 -0700 Subject: [PATCH 18/26] Input: focaltech - mark focaltech_set_resolution() static We get 1 warning when building kernel with W=1: drivers/input/mouse/focaltech.c:393:6: warning: no previous prototype for 'focaltech_set_resolution' [-Wmissing-prototypes] In fact, this function is only used in the file in which it is declared and don't need a declaration, but can be made static. So this patch marks it 'static'. Signed-off-by: Baoyou Xie Acked-by: Arnd Bergmann Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/focaltech.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c index c8c6a8cc329d..54eceb30ede5 100644 --- a/drivers/input/mouse/focaltech.c +++ b/drivers/input/mouse/focaltech.c @@ -390,7 +390,8 @@ static int focaltech_read_size(struct psmouse *psmouse) return 0; } -void focaltech_set_resolution(struct psmouse *psmouse, unsigned int resolution) +static void focaltech_set_resolution(struct psmouse *psmouse, + unsigned int resolution) { /* not supported yet */ } From 72f6d0b9eaee7e00ffab57b49d8543cc35a7d894 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 7 Sep 2016 19:21:06 -0700 Subject: [PATCH 19/26] Input: jornada720_kbd - remove unneeded mach/hardware.h include The Jornada720 keyboard driver does not make use of anything from the mach/hardware.h header, so this header can be removed. Tested-by: Adam Wysocki Signed-off-by: Russell King Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/jornada720_kbd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index fd8e15ea9149..1277c39f9482 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -25,7 +25,6 @@ #include #include -#include MODULE_AUTHOR("Kristoffer Ericson "); MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver"); From 3521a0f05d28e75612bbe1ee014bdfedf831b23f Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 7 Sep 2016 19:22:01 -0700 Subject: [PATCH 20/26] Input: jornada720_ts - get rid of mach/irqs.h and mach/hardware.h includes Switch the jornada720 touchscreen driver to obtain its gpio from the platform device via gpiolib and derive the interrupt from the GPIO, rather than via a hard-coded interrupt number obtained from the mach/irqs.h and mach/hardware.h headers. Tested-by: Adam Wysocki Signed-off-by: Russell King Signed-off-by: Dmitry Torokhov --- arch/arm/mach-sa1100/jornada720.c | 10 ++++++++++ drivers/input/touchscreen/jornada720_ts.c | 21 ++++++++++++++------- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c index 2b96f7bc16bd..0a2ca9be00e6 100644 --- a/arch/arm/mach-sa1100/jornada720.c +++ b/arch/arm/mach-sa1100/jornada720.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -228,6 +229,13 @@ static struct platform_device jornada_kbd_device = { .resource = jornada_kbd_resources, }; +static struct gpiod_lookup_table jornada_ts_gpiod_table = { + .dev_id = "jornada_ts", + .table = { + GPIO_LOOKUP("gpio", 9, "penup", GPIO_ACTIVE_HIGH), + }, +}; + static struct platform_device jornada_ts_device = { .name = "jornada_ts", .id = -1, @@ -256,6 +264,8 @@ static int __init jornada720_init(void) GPSR = GPIO_GPIO20; /* restart gpio20 */ udelay(20); /* give it some time to restart */ + gpiod_add_lookup_table(&jornada_ts_gpiod_table); + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index ea3b6a5b83e6..729b3c89324c 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -13,6 +13,7 @@ * HP Jornada 710/720/729 Touchscreen Driver */ +#include #include #include #include @@ -20,9 +21,7 @@ #include #include -#include #include -#include MODULE_AUTHOR("Kristoffer Ericson "); MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver"); @@ -30,6 +29,7 @@ MODULE_LICENSE("GPL v2"); struct jornada_ts { struct input_dev *dev; + struct gpio_desc *gpio; int x_data[4]; /* X sample values */ int y_data[4]; /* Y sample values */ }; @@ -71,8 +71,8 @@ static irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id) struct input_dev *input = jornada_ts->dev; int x, y; - /* If GPIO_GPIO9 is set to high then report pen up */ - if (GPLR & GPIO_GPIO(9)) { + /* If gpio is high then report pen up */ + if (gpiod_get_value(jornada_ts->gpio)) { input_report_key(input, BTN_TOUCH, 0); input_sync(input); } else { @@ -101,7 +101,7 @@ static int jornada720_ts_probe(struct platform_device *pdev) { struct jornada_ts *jornada_ts; struct input_dev *input_dev; - int error; + int error, irq; jornada_ts = devm_kzalloc(&pdev->dev, sizeof(*jornada_ts), GFP_KERNEL); if (!jornada_ts) @@ -113,6 +113,14 @@ static int jornada720_ts_probe(struct platform_device *pdev) platform_set_drvdata(pdev, jornada_ts); + jornada_ts->gpio = devm_gpiod_get(&pdev->dev, "penup", GPIOD_IN); + if (IS_ERR(jornada_ts->gpio)) + return PTR_ERR(jornada_ts->gpio); + + irq = gpiod_to_irq(jornada_ts->gpio); + if (irq <= 0) + return irq < 0 ? irq : -EINVAL; + jornada_ts->dev = input_dev; input_dev->name = "HP Jornada 7xx Touchscreen"; @@ -125,8 +133,7 @@ static int jornada720_ts_probe(struct platform_device *pdev) input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0); input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0); - error = devm_request_irq(&pdev->dev, IRQ_GPIO9, - jornada720_ts_interrupt, + error = devm_request_irq(&pdev->dev, irq, jornada720_ts_interrupt, IRQF_TRIGGER_RISING, "HP7XX Touchscreen driver", pdev); if (error) { From 722dc54628ca5cffd3b4581b523775aa422b55df Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Sat, 10 Sep 2016 10:42:53 -0700 Subject: [PATCH 21/26] Input: tps65218-pwrbutton - add support for tps65217 variant The power button found in tps65217 device is very similar to the tps65218, so let's enhance the driver to support both variants. This driver enables us to use tps65217's power button as KEY_POWER on am335x boards (directly connected button in chiliboard, accessible pin via expansion header in beaglebone). This patch has been tested with chiliboard. Signed-off-by: Marcin Niestroj Signed-off-by: Dmitry Torokhov --- .../bindings/input/tps65218-pwrbutton.txt | 17 +++- drivers/input/misc/Kconfig | 4 +- drivers/input/misc/tps65218-pwrbutton.c | 96 +++++++++++++------ 3 files changed, 83 insertions(+), 34 deletions(-) diff --git a/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt index e30e0b93f2b3..3e5b9793341f 100644 --- a/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt +++ b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt @@ -1,13 +1,24 @@ -Texas Instruments TPS65218 power button +Texas Instruments TPS65217 and TPS65218 power button + +This module is part of the TPS65217/TPS65218. For more details about the whole +TPS65217 chip see Documentation/devicetree/bindings/regulator/tps65217.txt. This driver provides a simple power button event via an Interrupt. Required properties: -- compatible: should be "ti,tps65218-pwrbutton" +- compatible: should be "ti,tps65217-pwrbutton" or "ti,tps65218-pwrbutton" + +Required properties for TPS65218: - interrupts: should be one of the following - <3 IRQ_TYPE_EDGE_BOTH>: For controllers compatible with tps65218 -Example: +Examples: + +&tps { + tps65217-pwrbutton { + compatible = "ti,tps65217-pwrbutton"; + }; +}; &tps { power-button { diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 7cdb89397d18..7ffb614ce566 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -466,10 +466,10 @@ config INPUT_RETU_PWRBUTTON config INPUT_TPS65218_PWRBUTTON tristate "TPS65218 Power button driver" - depends on MFD_TPS65218 + depends on (MFD_TPS65217 || MFD_TPS65218) help Say Y here if you want to enable power buttong reporting for - the TPS65218 Power Management IC device. + TPS65217 and TPS65218 Power Management IC devices. To compile this driver as a module, choose M here. The module will be called tps65218-pwrbutton. diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c index a39b62651a4b..3273217ce80c 100644 --- a/drivers/input/misc/tps65218-pwrbutton.c +++ b/drivers/input/misc/tps65218-pwrbutton.c @@ -1,8 +1,9 @@ /* - * Texas Instruments' TPS65218 Power Button Input Driver + * Texas Instruments' TPS65217 and TPS65218 Power Button Input Driver * * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ * Author: Felipe Balbi + * Author: Marcin Niestroj * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -18,31 +19,61 @@ #include #include #include +#include #include #include #include #include +#include #include -struct tps65218_pwrbutton { - struct device *dev; - struct tps65218 *tps; - struct input_dev *idev; +struct tps6521x_data { + unsigned int reg_status; + unsigned int pb_mask; + const char *name; }; -static irqreturn_t tps65218_pwr_irq(int irq, void *_pwr) +static const struct tps6521x_data tps65217_data = { + .reg_status = TPS65217_REG_STATUS, + .pb_mask = TPS65217_STATUS_PB, + .name = "tps65217_pwrbutton", +}; + +static const struct tps6521x_data tps65218_data = { + .reg_status = TPS65218_REG_STATUS, + .pb_mask = TPS65218_STATUS_PB_STATE, + .name = "tps65218_pwrbutton", +}; + +struct tps6521x_pwrbutton { + struct device *dev; + struct regmap *regmap; + struct input_dev *idev; + const struct tps6521x_data *data; + char phys[32]; +}; + +static const struct of_device_id of_tps6521x_pb_match[] = { + { .compatible = "ti,tps65217-pwrbutton", .data = &tps65217_data }, + { .compatible = "ti,tps65218-pwrbutton", .data = &tps65218_data }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_tps6521x_pb_match); + +static irqreturn_t tps6521x_pb_irq(int irq, void *_pwr) { - struct tps65218_pwrbutton *pwr = _pwr; + struct tps6521x_pwrbutton *pwr = _pwr; + const struct tps6521x_data *tps_data = pwr->data; unsigned int reg; int error; - error = tps65218_reg_read(pwr->tps, TPS65218_REG_STATUS, ®); + error = regmap_read(pwr->regmap, tps_data->reg_status, ®); if (error) { dev_err(pwr->dev, "can't read register: %d\n", error); goto out; } - if (reg & TPS65218_STATUS_PB_STATE) { + if (reg & tps_data->pb_mask) { input_report_key(pwr->idev, KEY_POWER, 1); pm_wakeup_event(pwr->dev, 0); } else { @@ -55,42 +86,55 @@ out: return IRQ_HANDLED; } -static int tps65218_pwron_probe(struct platform_device *pdev) +static int tps6521x_pb_probe(struct platform_device *pdev) { - struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent); struct device *dev = &pdev->dev; - struct tps65218_pwrbutton *pwr; + struct tps6521x_pwrbutton *pwr; struct input_dev *idev; + const struct of_device_id *match; int error; int irq; + match = of_match_node(of_tps6521x_pb_match, pdev->dev.of_node); + if (!match) + return -ENXIO; + pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL); if (!pwr) return -ENOMEM; + pwr->data = match->data; + idev = devm_input_allocate_device(dev); if (!idev) return -ENOMEM; - idev->name = "tps65218_pwrbutton"; - idev->phys = "tps65218_pwrbutton/input0"; + idev->name = pwr->data->name; + snprintf(pwr->phys, sizeof(pwr->phys), "%s/input0", + pwr->data->name); + idev->phys = pwr->phys; idev->dev.parent = dev; idev->id.bustype = BUS_I2C; input_set_capability(idev, EV_KEY, KEY_POWER); - pwr->tps = tps; + pwr->regmap = dev_get_regmap(pdev->dev.parent, NULL); pwr->dev = dev; pwr->idev = idev; platform_set_drvdata(pdev, pwr); device_init_wakeup(dev, true); irq = platform_get_irq(pdev, 0); - error = devm_request_threaded_irq(dev, irq, NULL, tps65218_pwr_irq, + if (irq < 0) { + dev_err(dev, "No IRQ resource!\n"); + return -EINVAL; + } + + error = devm_request_threaded_irq(dev, irq, NULL, tps6521x_pb_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "tps65218-pwrbutton", pwr); + pwr->data->name, pwr); if (error) { dev_err(dev, "failed to request IRQ #%d: %d\n", irq, error); @@ -106,21 +150,15 @@ static int tps65218_pwron_probe(struct platform_device *pdev) return 0; } -static const struct of_device_id of_tps65218_pwr_match[] = { - { .compatible = "ti,tps65218-pwrbutton" }, - { }, -}; -MODULE_DEVICE_TABLE(of, of_tps65218_pwr_match); - -static struct platform_driver tps65218_pwron_driver = { - .probe = tps65218_pwron_probe, +static struct platform_driver tps6521x_pb_driver = { + .probe = tps6521x_pb_probe, .driver = { - .name = "tps65218_pwrbutton", - .of_match_table = of_tps65218_pwr_match, + .name = "tps6521x_pwrbutton", + .of_match_table = of_tps6521x_pb_match, }, }; -module_platform_driver(tps65218_pwron_driver); +module_platform_driver(tps6521x_pb_driver); -MODULE_DESCRIPTION("TPS65218 Power Button"); +MODULE_DESCRIPTION("TPS6521X Power Button"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Felipe Balbi "); From 51db013767c46dc0243a8945085b5a229d9bd281 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 4 Aug 2016 11:16:23 -0700 Subject: [PATCH 22/26] Input: serio - add hangup support The Pulse-Eight USB CEC adapter is a usb device that shows up as a ttyACM0 device. It requires that you run inputattach in order to communicate with it via serio. This all works well, but it would be nice to have a udev rule to automatically start inputattach. That too works OK, but the problem comes when the USB device is unplugged: the tty hangup is never handled by the serio framework so the inputattach utility never exits and you have to kill it manually. By adding this hangup callback the inputattach utility now properly exits as soon as the USB device is unplugged. The udev rule I used on my Debian sid system is: SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", ATTRS{idVendor}=="2548", ATTRS{idProduct}=="1002", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}+="pulse8-cec-inputattach@%k.service" And /etc/systemd/system/pulse8-cec-inputattach@.service is as follows: =============================================================== [Unit] Description=inputattach for pulse8-cec device on %I [Service] Type=simple ExecStart=/usr/local/bin/inputattach --pulse8-cec /dev/%I KillMode=process =============================================================== Signed-off-by: Hans Verkuil Tested-by: Hans Verkuil Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serport.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 9c927d35c1f5..d189843f3727 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -71,10 +71,7 @@ static void serport_serio_close(struct serio *serio) spin_lock_irqsave(&serport->lock, flags); clear_bit(SERPORT_ACTIVE, &serport->flags); - set_bit(SERPORT_DEAD, &serport->flags); spin_unlock_irqrestore(&serport->lock, flags); - - wake_up_interruptible(&serport->wait); } /* @@ -248,6 +245,19 @@ static long serport_ldisc_compat_ioctl(struct tty_struct *tty, } #endif +static int serport_ldisc_hangup(struct tty_struct *tty) +{ + struct serport *serport = (struct serport *) tty->disc_data; + unsigned long flags; + + spin_lock_irqsave(&serport->lock, flags); + set_bit(SERPORT_DEAD, &serport->flags); + spin_unlock_irqrestore(&serport->lock, flags); + + wake_up_interruptible(&serport->wait); + return 0; +} + static void serport_ldisc_write_wakeup(struct tty_struct * tty) { struct serport *serport = (struct serport *) tty->disc_data; @@ -274,6 +284,7 @@ static struct tty_ldisc_ops serport_ldisc = { .compat_ioctl = serport_ldisc_compat_ioctl, #endif .receive_buf = serport_ldisc_receive, + .hangup = serport_ldisc_hangup, .write_wakeup = serport_ldisc_write_wakeup }; From 9ca5bf5029b6c17ce50b34581242f71f9b777ae7 Mon Sep 17 00:00:00 2001 From: Siebren Vroegindeweij Date: Thu, 15 Sep 2016 15:38:02 -0700 Subject: [PATCH 23/26] Input: add support for Elan eKTF2127 touchscreen controller This adds a driver for the Elan eKTF2127 touchscreen controller, which speaks an i2c protocol which is distinctly different from the already supported eKTH controllers. Signed-off-by: Michel Verlaan Signed-off-by: Siebren Vroegindeweij Signed-off-by: Hans de Goede Acked-by: Rob Herring Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/ektf2127.txt | 27 ++ drivers/input/touchscreen/Kconfig | 12 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/ektf2127.c | 336 ++++++++++++++++++ 4 files changed, 376 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt create mode 100644 drivers/input/touchscreen/ektf2127.c diff --git a/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt b/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt new file mode 100644 index 000000000000..5a19f4c3e9d7 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt @@ -0,0 +1,27 @@ +* Elan eKTF2127 I2C touchscreen controller + +Required properties: + - compatible : "elan,ektf2127" + - reg : I2C slave address of the chip (0x40) + - interrupt-parent : a phandle pointing to the interrupt controller + serving the interrupt for this chip + - interrupts : interrupt specification for the ektf2127 interrupt + - power-gpios : GPIO specification for the pin connected to the + ektf2127's wake input. This needs to be driven high + to take ektf2127 out of it's low power state + +For additional optional properties see: touchscreen.txt + +Example: + +i2c@00000000 { + ektf2127: touchscreen@15 { + compatible = "elan,ektf2127"; + reg = <0x15>; + interrupt-parent = <&pio>; + interrupts = <6 11 IRQ_TYPE_EDGE_FALLING> + power-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; + touchscreen-inverted-x; + touchscreen-swapped-x-y; + }; +}; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index c3e20e5357d4..17f75a67cc46 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -384,6 +384,18 @@ config TOUCHSCREEN_GUNZE To compile this driver as a module, choose M here: the module will be called gunze. +config TOUCHSCREEN_EKTF2127 + tristate "Elan eKTF2127 I2C touchscreen" + depends on I2C + help + Say Y here if you have an Elan eKTF2127 touchscreen + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called ektf2127. + config TOUCHSCREEN_ELAN tristate "Elan eKTH I2C touchscreen" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 57a1c099bc0d..81b86451782d 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06) += edt-ft5x06.o obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o +obj-$(CONFIG_TOUCHSCREEN_EKTF2127) += ektf2127.o obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c new file mode 100644 index 000000000000..31a2dd7f38aa --- /dev/null +++ b/drivers/input/touchscreen/ektf2127.c @@ -0,0 +1,336 @@ +/* + * Driver for ELAN eKTF2127 i2c touchscreen controller + * + * For this driver the layout of the Chipone icn8318 i2c + * touchscreencontroller is used. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: + * Michel Verlaan + * Siebren Vroegindeweij + * + * Original chipone_icn8318 driver: + * Hans de Goede + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Packet header defines (first byte of data send / received) */ +#define EKTF2127_NOISE 0x40 +#define EKTF2127_RESPONSE 0x52 +#define EKTF2127_REQUEST 0x53 +#define EKTF2127_HELLO 0x55 +#define EKTF2127_REPORT 0x5d +#define EKTF2127_CALIB_DONE 0x66 + +/* Register defines (second byte of data send / received) */ +#define EKTF2127_ENV_NOISY 0x41 +#define EKTF2127_HEIGHT 0x60 +#define EKTF2127_WIDTH 0x63 + +/* 2 bytes header + 5 * 3 bytes coordinates + 3 bytes pressure info + footer */ +#define EKTF2127_TOUCH_REPORT_SIZE 21 +#define EKTF2127_MAX_TOUCHES 5 + +struct ektf2127_ts { + struct i2c_client *client; + struct input_dev *input; + struct gpio_desc *power_gpios; + struct touchscreen_properties prop; +}; + +static void ektf2127_parse_coordinates(const u8* buf, unsigned int touch_count, + struct input_mt_pos *touches) +{ + int index = 0; + int i; + + for (i = 0; i < touch_count; i++) { + index = 2 + i * 3; + + touches[i].x = (buf[index] & 0x0f); + touches[i].x <<= 8; + touches[i].x |= buf[index + 2]; + + touches[i].y = (buf[index] & 0xf0); + touches[i].y <<= 4; + touches[i].y |= buf[index + 1]; + } +} + +static void ektf2127_report_event(struct ektf2127_ts *ts, const u8 *buf) +{ + struct input_mt_pos touches[EKTF2127_MAX_TOUCHES]; + int slots[EKTF2127_MAX_TOUCHES]; + unsigned int touch_count, i; + + touch_count = buf[1] & 0x07; + if (touch_count > EKTF2127_MAX_TOUCHES) { + dev_err(&ts->client->dev, + "Too many touches %d > %d\n", + touch_count, EKTF2127_MAX_TOUCHES); + touch_count = EKTF2127_MAX_TOUCHES; + } + + ektf2127_parse_coordinates(buf, touch_count, touches); + input_mt_assign_slots(ts->input, slots, touches, + touch_count, 0); + + for (i = 0; i < touch_count; i++) { + input_mt_slot(ts->input, slots[i]); + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true); + touchscreen_report_pos(ts->input, &ts->prop, + touches[i].x, touches[i].y, true); + } + + 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; + struct device *dev = &ts->client->dev; + char buf[EKTF2127_TOUCH_REPORT_SIZE]; + int ret; + + ret = i2c_master_recv(ts->client, buf, EKTF2127_TOUCH_REPORT_SIZE); + if (ret != EKTF2127_TOUCH_REPORT_SIZE) { + dev_err(dev, "Error reading touch data: %d\n", ret); + goto out; + } + + switch (buf[0]) { + case EKTF2127_REPORT: + ektf2127_report_event(ts, buf); + break; + + case EKTF2127_NOISE: + if (buf[1] == EKTF2127_ENV_NOISY) + dev_dbg(dev, "Environment is electrically noisy\n"); + break; + + case EKTF2127_HELLO: + case EKTF2127_CALIB_DONE: + break; + + default: + dev_err(dev, "Unexpected packet header byte %#02x\n", buf[0]); + break; + } + +out: + return IRQ_HANDLED; +} + +static int ektf2127_start(struct input_dev *dev) +{ + struct ektf2127_ts *ts = input_get_drvdata(dev); + + enable_irq(ts->client->irq); + gpiod_set_value_cansleep(ts->power_gpios, 1); + + return 0; +} + +static void ektf2127_stop(struct input_dev *dev) +{ + struct ektf2127_ts *ts = input_get_drvdata(dev); + + disable_irq(ts->client->irq); + gpiod_set_value_cansleep(ts->power_gpios, 0); +} + +static int 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) + ektf2127_stop(ts->input); + mutex_unlock(&ts->input->mutex); + + return 0; +} + +static int 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) + ektf2127_start(ts->input); + mutex_unlock(&ts->input->mutex); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(ektf2127_pm_ops, ektf2127_suspend, + ektf2127_resume); + +static int ektf2127_query_dimension(struct i2c_client *client, bool width) +{ + struct device *dev = &client->dev; + const char *what = width ? "width" : "height"; + u8 what_code = width ? EKTF2127_WIDTH : EKTF2127_HEIGHT; + u8 buf[4]; + int ret; + int error; + + /* Request dimension */ + buf[0] = EKTF2127_REQUEST; + buf[1] = width ? EKTF2127_WIDTH : EKTF2127_HEIGHT; + buf[2] = 0x00; + buf[3] = 0x00; + ret = i2c_master_send(client, buf, sizeof(buf)); + if (ret != sizeof(buf)) { + error = ret < 0 ? ret : -EIO; + dev_err(dev, "Failed to request %s: %d\n", what, error); + return error; + } + + msleep(20); + + /* Read response */ + ret = i2c_master_recv(client, buf, sizeof(buf)); + if (ret != sizeof(buf)) { + error = ret < 0 ? ret : -EIO; + dev_err(dev, "Failed to receive %s data: %d\n", what, error); + return error; + } + + if (buf[0] != EKTF2127_RESPONSE || buf[1] != what_code) { + dev_err(dev, "Unexpected %s data: %#02x %#02x\n", + what, buf[0], buf[1]); + return -EIO; + } + + return (((buf[3] & 0xf0) << 4) | buf[2]) - 1; +} + +static int ektf2127_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct ektf2127_ts *ts; + struct input_dev *input; + u8 buf[4]; + int max_x, max_y; + int error; + + if (!client->irq) { + dev_err(dev, "Error no irq specified\n"); + return -EINVAL; + } + + ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + /* This requests the gpio *and* turns on the touchscreen controller */ + ts->power_gpios = devm_gpiod_get(dev, "power", GPIOD_OUT_HIGH); + if (IS_ERR(ts->power_gpios)) { + error = PTR_ERR(ts->power_gpios); + if (error != -EPROBE_DEFER) + dev_err(dev, "Error getting power gpio: %d\n", error); + return error; + } + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + input->name = client->name; + input->id.bustype = BUS_I2C; + input->open = ektf2127_start; + input->close = ektf2127_stop; + + ts->client = client; + + /* Read hello (ignore result, depends on initial power state) */ + msleep(20); + i2c_master_recv(ts->client, buf, sizeof(buf)); + + /* Read resolution from chip */ + max_x = ektf2127_query_dimension(client, true); + if (max_x < 0) + return max_x; + + max_y = ektf2127_query_dimension(client, false); + if (max_y < 0) + return max_y; + + input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_x, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_y, 0, 0); + touchscreen_parse_properties(input, true, &ts->prop); + + error = input_mt_init_slots(input, EKTF2127_MAX_TOUCHES, + INPUT_MT_DIRECT | + INPUT_MT_DROP_UNUSED | + INPUT_MT_TRACK); + if (error) + return error; + + ts->input = input; + input_set_drvdata(input, ts); + + error = devm_request_threaded_irq(dev, client->irq, + NULL, ektf2127_irq, + IRQF_ONESHOT, client->name, ts); + if (error) { + dev_err(dev, "Error requesting irq: %d\n", error); + return error; + } + + /* Stop device till opened */ + ektf2127_stop(ts->input); + + error = input_register_device(input); + if (error) + return error; + + i2c_set_clientdata(client, ts); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id ektf2127_of_match[] = { + { .compatible = "elan,ektf2127" }, + {} +}; +MODULE_DEVICE_TABLE(of, ektf2127_of_match); +#endif + +static const struct i2c_device_id ektf2127_i2c_id[] = { + { "ektf2127", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ektf2127_i2c_id); + +static struct i2c_driver ektf2127_driver = { + .driver = { + .name = "elan_ektf2127", + .pm = &ektf2127_pm_ops, + .of_match_table = of_match_ptr(ektf2127_of_match), + }, + .probe = ektf2127_probe, + .id_table = ektf2127_i2c_id, +}; +module_i2c_driver(ektf2127_driver); + +MODULE_DESCRIPTION("ELAN eKTF2127 I2C Touchscreen Driver"); +MODULE_AUTHOR("Michel Verlaan, Siebren Vroegindeweij"); +MODULE_LICENSE("GPL"); From d095c500fd79421f915cea26925677cd16ecd623 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 23 Sep 2016 15:01:07 -0700 Subject: [PATCH 24/26] Input: snvs_pwrkey - drop input_free_device call if input_register_device fails Current code uses devm_input_allocate_device() so don't explicitly call input_free_device if input_register_device fails. Signed-off-by: Axel Lin Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/snvs_pwrkey.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c index 24a9f599082f..7544888c4749 100644 --- a/drivers/input/keyboard/snvs_pwrkey.c +++ b/drivers/input/keyboard/snvs_pwrkey.c @@ -168,7 +168,6 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) error = input_register_device(input); if (error < 0) { dev_err(&pdev->dev, "failed to register input device\n"); - input_free_device(input); return error; } From 979987ded3a5ae1fb60ef751bdf185c502d70590 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 30 Sep 2016 15:36:54 -0700 Subject: [PATCH 25/26] Input: ektf2127 - mark PM functions as __maybe_unused The newly added ektf2127 driver uses the SIMPLE_DEV_PM_OPS macro to conditionally refer to the resume/suspend functions, which causes a warning when CONFIG_PM_SLEEP is disabled: drivers/input/touchscreen/ektf2127.c:168:12: error: 'ektf2127_resume' defined but not used [-Werror=unused-function] drivers/input/touchscreen/ektf2127.c:156:12: error: 'ektf2127_suspend' defined but not used [-Werror=unused-function] We could either put these functions inside of an #ifdef or add __maybe_unused annotations. This uses the second approach, which is generally more foolproof. Fixes: 9ca5bf5029b6 ("Input: add support for Elan eKTF2127 touchscreen controller") Signed-off-by: Arnd Bergmann Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ektf2127.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c index 31a2dd7f38aa..0ed34ff787ce 100644 --- a/drivers/input/touchscreen/ektf2127.c +++ b/drivers/input/touchscreen/ektf2127.c @@ -153,7 +153,7 @@ static void ektf2127_stop(struct input_dev *dev) gpiod_set_value_cansleep(ts->power_gpios, 0); } -static int ektf2127_suspend(struct device *dev) +static int __maybe_unused ektf2127_suspend(struct device *dev) { struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev)); @@ -165,7 +165,7 @@ static int ektf2127_suspend(struct device *dev) return 0; } -static int ektf2127_resume(struct device *dev) +static int __maybe_unused ektf2127_resume(struct device *dev) { struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev)); From 265d426d7470d53e900379960eef5b4482125089 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 30 Sep 2016 16:42:19 -0700 Subject: [PATCH 26/26] Input: elan_i2c - fix return tests of i2c_smbus_read_block_data() i2c_smbus_read_block_data() returns negative errno else the number of data bytes in the slave's response. Checking for error not null means the function always fails if the device answers properly. So given that we read 3 bytes and access those, better check that we actually read those 3 bytes. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_smbus.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index cb6aecbc1dc2..e23b2495d52e 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -222,11 +222,13 @@ static int elan_smbus_get_checksum(struct i2c_client *client, static int elan_smbus_get_max(struct i2c_client *client, unsigned int *max_x, unsigned int *max_y) { + int ret; int error; u8 val[3]; - error = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val); - if (error) { + ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val); + if (ret != 3) { + error = ret < 0 ? ret : -EIO; dev_err(&client->dev, "failed to get dimensions: %d\n", error); return error; } @@ -240,12 +242,13 @@ static int elan_smbus_get_max(struct i2c_client *client, static int elan_smbus_get_resolution(struct i2c_client *client, u8 *hw_res_x, u8 *hw_res_y) { + int ret; int error; u8 val[3]; - error = i2c_smbus_read_block_data(client, - ETP_SMBUS_RESOLUTION_CMD, val); - if (error) { + ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RESOLUTION_CMD, val); + if (ret != 3) { + error = ret < 0 ? ret : -EIO; dev_err(&client->dev, "failed to get resolution: %d\n", error); return error; } @@ -260,12 +263,13 @@ static int elan_smbus_get_num_traces(struct i2c_client *client, unsigned int *x_traces, unsigned int *y_traces) { + int ret; int error; u8 val[3]; - error = i2c_smbus_read_block_data(client, - ETP_SMBUS_XY_TRACENUM_CMD, val); - if (error) { + ret = i2c_smbus_read_block_data(client, ETP_SMBUS_XY_TRACENUM_CMD, val); + if (ret != 3) { + error = ret < 0 ? ret : -EIO; dev_err(&client->dev, "failed to get trace info: %d\n", error); return error; }