From bb546136cc0b07b3f4dc972a196650d50fe1aaaa Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 9 May 2017 17:48:45 -0700 Subject: Input: use seq_putc() in input_seq_print_bitmap() Switch to using seq_putc() when printing a single character '0'. Signed-off-by: Markus Elfring Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/input.c b/drivers/input/input.c index 067d648028a2..0d204b841575 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1126,7 +1126,7 @@ static void input_seq_print_bitmap(struct seq_file *seq, const char *name, * If no output was produced print a single 0. */ if (skip_empty) - seq_puts(seq, "0"); + seq_putc(seq, '0'); seq_putc(seq, '\n'); } -- cgit v1.3-15-g9ac1 From 63c9576544718a949460865588981b70bb717020 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 9 May 2017 17:49:59 -0700 Subject: Input: use seq_puts() in input_devices_seq_show() Use seq_puts() when printing a string which does not contain a data format specification. Signed-off-by: Markus Elfring Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/input.c b/drivers/input/input.c index 0d204b841575..067a6edd643c 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1144,7 +1144,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : ""); seq_printf(seq, "S: Sysfs=%s\n", path ? path : ""); seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : ""); - seq_printf(seq, "H: Handlers="); + seq_puts(seq, "H: Handlers="); list_for_each_entry(handle, &dev->h_list, d_node) seq_printf(seq, "%s ", handle->name); -- cgit v1.3-15-g9ac1 From c3f6f8612bdab5959950a58291bd61d1d42d996b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 9 May 2017 17:51:30 -0700 Subject: Input: switch to using sizeof(*type) when allocating memory Instead of specifying type explicitly, derive it from the type of pointer when allocating memory, which is considered safer practice. Signed-off-by: Markus Elfring Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/input.c b/drivers/input/input.c index 067a6edd643c..7e6842bd525c 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -481,7 +481,7 @@ EXPORT_SYMBOL(input_inject_event); void input_alloc_absinfo(struct input_dev *dev) { if (!dev->absinfo) - dev->absinfo = kcalloc(ABS_CNT, sizeof(struct input_absinfo), + dev->absinfo = kcalloc(ABS_CNT, sizeof(*dev->absinfo), GFP_KERNEL); WARN(!dev->absinfo, "%s(): kcalloc() failed?\n", __func__); @@ -1783,7 +1783,7 @@ struct input_dev *input_allocate_device(void) static atomic_t input_no = ATOMIC_INIT(-1); struct input_dev *dev; - dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev) { dev->dev.type = &input_dev_type; dev->dev.class = &input_class; @@ -1849,7 +1849,7 @@ struct input_dev *devm_input_allocate_device(struct device *dev) struct input_devres *devres; devres = devres_alloc(devm_input_device_release, - sizeof(struct input_devres), GFP_KERNEL); + sizeof(*devres), GFP_KERNEL); if (!devres) return NULL; @@ -2099,7 +2099,7 @@ int input_register_device(struct input_dev *dev) if (dev->devres_managed) { devres = devres_alloc(devm_input_device_unregister, - sizeof(struct input_devres), GFP_KERNEL); + sizeof(*devres), GFP_KERNEL); if (!devres) return -ENOMEM; -- cgit v1.3-15-g9ac1 From c5928551fd41b2eecdad78fa2be2a4a13ed5fde9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 19 Dec 2014 12:57:49 -0800 Subject: Input: elan_i2c - check if device is there before really probing Before trying to properly initialize the touchpad and generate bunch of errors, let's first see it there is anything at the given address. If we get error, fail silently with -ENXIO. Reviewed-by: Guenter Roeck Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index d5ab9ddef3e3..551ad2934fa7 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1077,6 +1077,13 @@ static int elan_probe(struct i2c_client *client, return error; } + /* Make sure there is something at this address */ + error = i2c_smbus_read_byte(client); + if (error < 0) { + dev_dbg(&client->dev, "nothing at this address: %d\n", error); + return -ENXIO; + } + /* Initialize the touchpad. */ error = elan_initialize(data); if (error) -- cgit v1.3-15-g9ac1 From a2eaf299d134cfe780c68c771f88d81516c1e70d Mon Sep 17 00:00:00 2001 From: KT Liao Date: Sun, 27 Nov 2016 20:59:29 -0800 Subject: Input: elan_i2c - add support for fetching chip type on newer hardware Newer Elantech hardware requires different way of fetching chip type and version data. Signed-off-by: KT Liao Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c.h | 3 +- drivers/input/mouse/elan_i2c_core.c | 33 +++++++++++++---- drivers/input/mouse/elan_i2c_i2c.c | 71 ++++++++++++++++++++++++++++++++---- drivers/input/mouse/elan_i2c_smbus.c | 9 ++++- 4 files changed, 99 insertions(+), 17 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index c0ec26118732..61c202436250 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -58,7 +58,7 @@ struct elan_transport_ops { int (*get_version)(struct i2c_client *client, bool iap, u8 *version); int (*get_sm_version)(struct i2c_client *client, - u8* ic_type, u8 *version); + u16 *ic_type, u8 *version); int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum); int (*get_product_id)(struct i2c_client *client, u16 *id); @@ -82,6 +82,7 @@ struct elan_transport_ops { int (*get_report)(struct i2c_client *client, u8 *report); int (*get_pressure_adjustment)(struct i2c_client *client, int *adjustment); + int (*get_pattern)(struct i2c_client *client, u8 *pattern); }; extern const struct elan_transport_ops elan_smbus_ops, elan_i2c_ops; diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 551ad2934fa7..3b616cb7c67f 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -5,7 +5,7 @@ * * Author: 林政維 (Duson Lin) * Author: KT Liao - * Version: 1.6.2 + * Version: 1.6.3 * * Based on cyapa driver: * copyright (c) 2011-2012 Cypress Semiconductor, Inc. @@ -41,7 +41,7 @@ #include "elan_i2c.h" #define DRIVER_NAME "elan_i2c" -#define ELAN_DRIVER_VERSION "1.6.2" +#define ELAN_DRIVER_VERSION "1.6.3" #define ELAN_VENDOR_ID 0x04f3 #define ETP_MAX_PRESSURE 255 #define ETP_FWIDTH_REDUCE 90 @@ -78,6 +78,7 @@ struct elan_tp_data { unsigned int x_res; unsigned int y_res; + u8 pattern; u16 product_id; u8 fw_version; u8 sm_version; @@ -85,7 +86,7 @@ struct elan_tp_data { u16 fw_checksum; int pressure_adjustment; u8 mode; - u8 ic_type; + u16 ic_type; u16 fw_validpage_count; u16 fw_signature_address; @@ -96,10 +97,10 @@ struct elan_tp_data { bool baseline_ready; }; -static int elan_get_fwinfo(u8 iap_version, u16 *validpage_count, +static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count, u16 *signature_address) { - switch (iap_version) { + switch (ic_type) { case 0x00: case 0x06: case 0x08: @@ -119,6 +120,9 @@ static int elan_get_fwinfo(u8 iap_version, u16 *validpage_count, case 0x0E: *validpage_count = 640; break; + case 0x10: + *validpage_count = 1024; + break; default: /* unknown ic type clear value */ *validpage_count = 0; @@ -305,6 +309,7 @@ static int elan_initialize(struct elan_tp_data *data) static int elan_query_device_info(struct elan_tp_data *data) { int error; + u16 ic_type; error = data->ops->get_version(data->client, false, &data->fw_version); if (error) @@ -324,7 +329,16 @@ static int elan_query_device_info(struct elan_tp_data *data) if (error) return error; - error = elan_get_fwinfo(data->iap_version, &data->fw_validpage_count, + error = data->ops->get_pattern(data->client, &data->pattern); + if (error) + return error; + + if (data->pattern == 0x01) + ic_type = data->ic_type; + else + ic_type = data->iap_version; + + error = elan_get_fwinfo(ic_type, &data->fw_validpage_count, &data->fw_signature_address); if (error) dev_warn(&data->client->dev, @@ -1108,10 +1122,13 @@ static int elan_probe(struct i2c_client *client, "Elan Touchpad Extra Information:\n" " Max ABS X,Y: %d,%d\n" " Width X,Y: %d,%d\n" - " Resolution X,Y: %d,%d (dots/mm)\n", + " Resolution X,Y: %d,%d (dots/mm)\n" + " ic type: 0x%x\n" + " info pattern: 0x%x\n", data->max_x, data->max_y, data->width_x, data->width_y, - data->x_res, data->y_res); + data->x_res, data->y_res, + data->ic_type, data->pattern); /* Set up input device properties based on queried parameters. */ error = elan_setup_input_device(data); diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index a679e56c44cd..3be75c6e8090 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -34,9 +34,12 @@ #define ETP_I2C_DESC_CMD 0x0001 #define ETP_I2C_REPORT_DESC_CMD 0x0002 #define ETP_I2C_STAND_CMD 0x0005 +#define ETP_I2C_PATTERN_CMD 0x0100 #define ETP_I2C_UNIQUEID_CMD 0x0101 #define ETP_I2C_FW_VERSION_CMD 0x0102 -#define ETP_I2C_SM_VERSION_CMD 0x0103 +#define ETP_I2C_IC_TYPE_CMD 0x0103 +#define ETP_I2C_OSM_VERSION_CMD 0x0103 +#define ETP_I2C_NSM_VERSION_CMD 0x0104 #define ETP_I2C_XY_TRACENUM_CMD 0x0105 #define ETP_I2C_MAX_X_AXIS_CMD 0x0106 #define ETP_I2C_MAX_Y_AXIS_CMD 0x0107 @@ -239,12 +242,34 @@ static int elan_i2c_get_baseline_data(struct i2c_client *client, return 0; } +static int elan_i2c_get_pattern(struct i2c_client *client, u8 *pattern) +{ + int error; + u8 val[3]; + + error = elan_i2c_read_cmd(client, ETP_I2C_PATTERN_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get pattern: %d\n", error); + return error; + } + *pattern = val[1]; + + return 0; +} + static int elan_i2c_get_version(struct i2c_client *client, bool iap, u8 *version) { int error; + u8 pattern_ver; u8 val[3]; + error = elan_i2c_get_pattern(client, &pattern_ver); + if (error) { + dev_err(&client->dev, "failed to get pattern version\n"); + return error; + } + error = elan_i2c_read_cmd(client, iap ? ETP_I2C_IAP_VERSION_CMD : ETP_I2C_FW_VERSION_CMD, @@ -255,24 +280,54 @@ static int elan_i2c_get_version(struct i2c_client *client, return error; } - *version = val[0]; + if (pattern_ver == 0x01) + *version = iap ? val[1] : val[0]; + else + *version = val[0]; return 0; } static int elan_i2c_get_sm_version(struct i2c_client *client, - u8 *ic_type, u8 *version) + u16 *ic_type, u8 *version) { int error; + u8 pattern_ver; u8 val[3]; - error = elan_i2c_read_cmd(client, ETP_I2C_SM_VERSION_CMD, val); + error = elan_i2c_get_pattern(client, &pattern_ver); if (error) { - dev_err(&client->dev, "failed to get SM version: %d\n", error); + dev_err(&client->dev, "failed to get pattern version\n"); return error; } - *version = val[0]; - *ic_type = val[1]; + if (pattern_ver == 0x01) { + error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get ic type: %d\n", + error); + return error; + } + *ic_type = be16_to_cpup((__be16 *)val); + + error = elan_i2c_read_cmd(client, ETP_I2C_NSM_VERSION_CMD, + val); + if (error) { + dev_err(&client->dev, "failed to get SM version: %d\n", + error); + return error; + } + *version = val[1]; + } else { + error = elan_i2c_read_cmd(client, ETP_I2C_OSM_VERSION_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get SM version: %d\n", + error); + return error; + } + *version = val[0]; + *ic_type = val[1]; + } + return 0; } @@ -639,5 +694,7 @@ const struct elan_transport_ops elan_i2c_ops = { .write_fw_block = elan_i2c_write_fw_block, .finish_fw_update = elan_i2c_finish_fw_update, + .get_pattern = elan_i2c_get_pattern, + .get_report = elan_i2c_get_report, }; diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index e23b2495d52e..df7a57ca7331 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -166,7 +166,7 @@ static int elan_smbus_get_version(struct i2c_client *client, } static int elan_smbus_get_sm_version(struct i2c_client *client, - u8 *ic_type, u8 *version) + u16 *ic_type, u8 *version) { int error; u8 val[3]; @@ -495,6 +495,12 @@ static int elan_smbus_finish_fw_update(struct i2c_client *client, return 0; } +static int elan_smbus_get_pattern(struct i2c_client *client, u8 *pattern) +{ + *pattern = 0; + return 0; +} + const struct elan_transport_ops elan_smbus_ops = { .initialize = elan_smbus_initialize, .sleep_control = elan_smbus_sleep_control, @@ -524,4 +530,5 @@ const struct elan_transport_ops elan_smbus_ops = { .finish_fw_update = elan_smbus_finish_fw_update, .get_report = elan_smbus_get_report, + .get_pattern = elan_smbus_get_pattern, }; -- cgit v1.3-15-g9ac1 From d899520b0431e70279bfb5066ecb6dc91d0b7072 Mon Sep 17 00:00:00 2001 From: KT Liao Date: Mon, 12 Dec 2016 11:03:42 -0800 Subject: Input: elantech - force relative mode on a certain module One of Elan modules with sample version is 0x74 and hw_version is 0x03 has a bug in absolute mode implementation, so let it run in default PS/2 relative mode. Signed-off-by: KT Liao Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index efc8ec342351..3dbab0727376 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1687,6 +1687,17 @@ int elantech_init(struct psmouse *psmouse) etd->samples[0], etd->samples[1], etd->samples[2]); } + if (etd->samples[1] == 0x74 && etd->hw_version == 0x03) { + /* + * This module has a bug which makes absolute mode + * unusable, so let's abort so we'll be using standard + * PS/2 protocol. + */ + psmouse_info(psmouse, + "absolute mode broken, forcing standard PS/2 protocol\n"); + goto init_fail; + } + if (elantech_set_absolute_mode(psmouse)) { psmouse_err(psmouse, "failed to put touchpad into absolute mode.\n"); -- cgit v1.3-15-g9ac1 From f81126b0b67c864b0b3d614d8adadc3a37ba5209 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 22 May 2017 16:24:22 -0700 Subject: Input: lm8323 - move header file out of I2C realm include/linux/i2c is not for client devices. Move the header file to a more appropriate location. Signed-off-by: Wolfram Sang Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/lm8323.c | 2 +- include/linux/i2c/lm8323.h | 46 ------------------------------------ include/linux/platform_data/lm8323.h | 46 ++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 47 deletions(-) delete mode 100644 include/linux/i2c/lm8323.h create mode 100644 include/linux/platform_data/lm8323.h (limited to 'drivers/input') diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 21bea52d4365..04a5d7e134d7 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -30,8 +30,8 @@ #include #include #include +#include #include -#include #include /* Commands to send to the chip. */ diff --git a/include/linux/i2c/lm8323.h b/include/linux/i2c/lm8323.h deleted file mode 100644 index 478d668bc590..000000000000 --- a/include/linux/i2c/lm8323.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * lm8323.h - Configuration for LM8323 keypad driver. - * - * 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 only). - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __LINUX_LM8323_H -#define __LINUX_LM8323_H - -#include - -/* - * Largest keycode that the chip can send, plus one, - * so keys can be mapped directly at the index of the - * LM8323 keycode instead of subtracting one. - */ -#define LM8323_KEYMAP_SIZE (0x7f + 1) - -#define LM8323_NUM_PWMS 3 - -struct lm8323_platform_data { - int debounce_time; /* Time to watch for key bouncing, in ms. */ - int active_time; /* Idle time until sleep, in ms. */ - - int size_x; - int size_y; - bool repeat; - const unsigned short *keymap; - - const char *pwm_names[LM8323_NUM_PWMS]; - - const char *name; /* Device name. */ -}; - -#endif /* __LINUX_LM8323_H */ diff --git a/include/linux/platform_data/lm8323.h b/include/linux/platform_data/lm8323.h new file mode 100644 index 000000000000..478d668bc590 --- /dev/null +++ b/include/linux/platform_data/lm8323.h @@ -0,0 +1,46 @@ +/* + * lm8323.h - Configuration for LM8323 keypad driver. + * + * 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 only). + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LINUX_LM8323_H +#define __LINUX_LM8323_H + +#include + +/* + * Largest keycode that the chip can send, plus one, + * so keys can be mapped directly at the index of the + * LM8323 keycode instead of subtracting one. + */ +#define LM8323_KEYMAP_SIZE (0x7f + 1) + +#define LM8323_NUM_PWMS 3 + +struct lm8323_platform_data { + int debounce_time; /* Time to watch for key bouncing, in ms. */ + int active_time; /* Idle time until sleep, in ms. */ + + int size_x; + int size_y; + bool repeat; + const unsigned short *keymap; + + const char *pwm_names[LM8323_NUM_PWMS]; + + const char *name; /* Device name. */ +}; + +#endif /* __LINUX_LM8323_H */ -- cgit v1.3-15-g9ac1 From 8cd9ab9e19b8cf23a7cae503af81ae70154e7956 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 22 May 2017 16:26:56 -0700 Subject: Input: mcs - move header file out of I2C realm include/linux/i2c is not for client devices. Move the header file to a more appropriate location. Signed-off-by: Wolfram Sang Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/mcs_touchkey.c | 2 +- drivers/input/touchscreen/mcs5000_ts.c | 2 +- include/linux/i2c/mcs.h | 35 ---------------------------------- include/linux/platform_data/mcs.h | 35 ++++++++++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 37 deletions(-) delete mode 100644 include/linux/i2c/mcs.h create mode 100644 include/linux/platform_data/mcs.h (limited to 'drivers/input') diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index 31090d71a685..be56d4f262a7 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -13,11 +13,11 @@ #include #include -#include #include #include #include #include +#include #include /* MCS5000 Touchkey */ diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c index 90fc07dc98a6..8868573133ab 100644 --- a/drivers/input/touchscreen/mcs5000_ts.c +++ b/drivers/input/touchscreen/mcs5000_ts.c @@ -15,10 +15,10 @@ #include #include -#include #include #include #include +#include #include /* Registers */ diff --git a/include/linux/i2c/mcs.h b/include/linux/i2c/mcs.h deleted file mode 100644 index 61bb18a4fd3c..000000000000 --- a/include/linux/i2c/mcs.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2009 - 2010 Samsung Electronics Co.Ltd - * Author: Joonyoung Shim - * Author: HeungJun Kim - * - * 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. - * - */ - -#ifndef __LINUX_MCS_H -#define __LINUX_MCS_H - -#define MCS_KEY_MAP(v, c) ((((v) & 0xff) << 16) | ((c) & 0xffff)) -#define MCS_KEY_VAL(v) (((v) >> 16) & 0xff) -#define MCS_KEY_CODE(v) ((v) & 0xffff) - -struct mcs_platform_data { - void (*poweron)(bool); - void (*cfg_pin)(void); - - /* touchscreen */ - unsigned int x_size; - unsigned int y_size; - - /* touchkey */ - const u32 *keymap; - unsigned int keymap_size; - unsigned int key_maxval; - bool no_autorepeat; -}; - -#endif /* __LINUX_MCS_H */ diff --git a/include/linux/platform_data/mcs.h b/include/linux/platform_data/mcs.h new file mode 100644 index 000000000000..61bb18a4fd3c --- /dev/null +++ b/include/linux/platform_data/mcs.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 - 2010 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim + * Author: HeungJun Kim + * + * 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. + * + */ + +#ifndef __LINUX_MCS_H +#define __LINUX_MCS_H + +#define MCS_KEY_MAP(v, c) ((((v) & 0xff) << 16) | ((c) & 0xffff)) +#define MCS_KEY_VAL(v) (((v) >> 16) & 0xff) +#define MCS_KEY_CODE(v) ((v) & 0xffff) + +struct mcs_platform_data { + void (*poweron)(bool); + void (*cfg_pin)(void); + + /* touchscreen */ + unsigned int x_size; + unsigned int y_size; + + /* touchkey */ + const u32 *keymap; + unsigned int keymap_size; + unsigned int key_maxval; + bool no_autorepeat; +}; + +#endif /* __LINUX_MCS_H */ -- cgit v1.3-15-g9ac1 From 0d846a4cbbcbf81e527542d15e165b8f774bace5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 22 May 2017 16:28:42 -0700 Subject: Input: mms114 - move header file out of I2C realm include/linux/i2c is not for client devices. Move the header file to a more appropriate location. Signed-off-by: Wolfram Sang Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/mms114.c | 2 +- include/linux/i2c/mms114.h | 24 ------------------------ include/linux/platform_data/mms114.h | 24 ++++++++++++++++++++++++ 3 files changed, 25 insertions(+), 25 deletions(-) delete mode 100644 include/linux/i2c/mms114.h create mode 100644 include/linux/platform_data/mms114.h (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 1fafc9f57af6..e5eeb6311f7d 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -11,9 +11,9 @@ #include #include #include -#include #include #include +#include #include #include diff --git a/include/linux/i2c/mms114.h b/include/linux/i2c/mms114.h deleted file mode 100644 index 5722ebfb2738..000000000000 --- a/include/linux/i2c/mms114.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics Co.Ltd - * Author: Joonyoung Shim - * - * 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 Foundationr - */ - -#ifndef __LINUX_MMS114_H -#define __LINUX_MMS114_H - -struct mms114_platform_data { - unsigned int x_size; - unsigned int y_size; - unsigned int contact_threshold; - unsigned int moving_threshold; - bool x_invert; - bool y_invert; - - void (*cfg_pin)(bool); -}; - -#endif /* __LINUX_MMS114_H */ diff --git a/include/linux/platform_data/mms114.h b/include/linux/platform_data/mms114.h new file mode 100644 index 000000000000..5722ebfb2738 --- /dev/null +++ b/include/linux/platform_data/mms114.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2012 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim + * + * 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 Foundationr + */ + +#ifndef __LINUX_MMS114_H +#define __LINUX_MMS114_H + +struct mms114_platform_data { + unsigned int x_size; + unsigned int y_size; + unsigned int contact_threshold; + unsigned int moving_threshold; + bool x_invert; + bool y_invert; + + void (*cfg_pin)(bool); +}; + +#endif /* __LINUX_MMS114_H */ -- cgit v1.3-15-g9ac1 From 8fd708157a592a376c4d0b3b2ba23b9e9f79caa5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 22 May 2017 16:30:04 -0700 Subject: Input: tsc2007 - move header file out of I2C realm include/linux/i2c is not for client devices. Move the header file to a more appropriate location. Signed-off-by: Wolfram Sang Acked-by: Lee Jones Signed-off-by: Dmitry Torokhov --- arch/sh/boards/mach-ecovec24/setup.c | 2 +- drivers/input/touchscreen/tsc2007_core.c | 2 +- drivers/mfd/timberdale.c | 2 +- include/linux/i2c/tsc2007.h | 22 ---------------------- include/linux/platform_data/tsc2007.h | 22 ++++++++++++++++++++++ 5 files changed, 25 insertions(+), 25 deletions(-) delete mode 100644 include/linux/i2c/tsc2007.h create mode 100644 include/linux/platform_data/tsc2007.h (limited to 'drivers/input') diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 6d612792f6b8..1faf6cb93dcb 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index fc7384936011..8342e0c48a53 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -25,9 +25,9 @@ #include #include #include -#include #include #include +#include #include "tsc2007.h" int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd) diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index c9339f85359b..cd4a6d7d6750 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -32,13 +32,13 @@ #include #include #include -#include #include #include #include #include +#include #include #include diff --git a/include/linux/i2c/tsc2007.h b/include/linux/i2c/tsc2007.h deleted file mode 100644 index 4f35b6ad3889..000000000000 --- a/include/linux/i2c/tsc2007.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __LINUX_I2C_TSC2007_H -#define __LINUX_I2C_TSC2007_H - -/* linux/i2c/tsc2007.h */ - -struct tsc2007_platform_data { - u16 model; /* 2007. */ - u16 x_plate_ohms; /* must be non-zero value */ - u16 max_rt; /* max. resistance above which samples are ignored */ - unsigned long poll_period; /* time (in ms) between samples */ - int fuzzx; /* fuzz factor for X, Y and pressure axes */ - int fuzzy; - int fuzzz; - - int (*get_pendown_state)(struct device *); - /* If needed, clear 2nd level interrupt source */ - void (*clear_penirq)(void); - int (*init_platform_hw)(void); - void (*exit_platform_hw)(void); -}; - -#endif diff --git a/include/linux/platform_data/tsc2007.h b/include/linux/platform_data/tsc2007.h new file mode 100644 index 000000000000..c2d3aa1dadd4 --- /dev/null +++ b/include/linux/platform_data/tsc2007.h @@ -0,0 +1,22 @@ +#ifndef __LINUX_I2C_TSC2007_H +#define __LINUX_I2C_TSC2007_H + +/* linux/platform_data/tsc2007.h */ + +struct tsc2007_platform_data { + u16 model; /* 2007. */ + u16 x_plate_ohms; /* must be non-zero value */ + u16 max_rt; /* max. resistance above which samples are ignored */ + unsigned long poll_period; /* time (in ms) between samples */ + int fuzzx; /* fuzz factor for X, Y and pressure axes */ + int fuzzy; + int fuzzz; + + int (*get_pendown_state)(struct device *); + /* If needed, clear 2nd level interrupt source */ + void (*clear_penirq)(void); + int (*init_platform_hw)(void); + void (*exit_platform_hw)(void); +}; + +#endif -- cgit v1.3-15-g9ac1 From f9f5796e7a534cc99cee577be47e109d5123baf1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 26 May 2017 23:47:39 -0400 Subject: hp_sdc: use probe_kernel_read() Signed-off-by: Al Viro --- drivers/input/serio/hp_sdc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 559c99ca6592..1bfdae4b0d99 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -1001,7 +1001,6 @@ static int __init hp_sdc_register(void) uint8_t tq_init_seq[5]; struct semaphore tq_init_sem; #if defined(__mc68000__) - mm_segment_t fs; unsigned char i; #endif @@ -1026,11 +1025,8 @@ static int __init hp_sdc_register(void) hp_sdc.base_io = (unsigned long) 0xf0428000; hp_sdc.data_io = (unsigned long) hp_sdc.base_io + 1; hp_sdc.status_io = (unsigned long) hp_sdc.base_io + 3; - fs = get_fs(); - set_fs(KERNEL_DS); - if (!get_user(i, (unsigned char *)hp_sdc.data_io)) + if (!probe_kernel_read(&i, (unsigned char *)hp_sdc.data_io, 1)) hp_sdc.dev = (void *)1; - set_fs(fs); hp_sdc.dev_err = hp_sdc_init(); #endif if (hp_sdc.dev == NULL) { -- cgit v1.3-15-g9ac1 From c1a4634013141b96324c647b45356e16f1fff781 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 21 May 2017 23:57:27 +0200 Subject: gpio: adp5588: move header file out of I2C realm include/linux/i2c is not for client devices. Move the header file to a more appropriate location. Signed-off-by: Wolfram Sang Acked-by: Dmitry Torokhov Signed-off-by: Linus Walleij --- arch/blackfin/mach-bf537/boards/stamp.c | 2 +- drivers/gpio/gpio-adp5588.c | 2 +- drivers/input/keyboard/adp5588-keys.c | 2 +- include/linux/i2c/adp5588.h | 172 -------------------------------- include/linux/platform_data/adp5588.h | 172 ++++++++++++++++++++++++++++++++ 5 files changed, 175 insertions(+), 175 deletions(-) delete mode 100644 include/linux/i2c/adp5588.h create mode 100644 include/linux/platform_data/adp5588.h (limited to 'drivers/input') diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c index eaec7b4832a2..24985e658c19 100644 --- a/arch/blackfin/mach-bf537/boards/stamp.c +++ b/arch/blackfin/mach-bf537/boards/stamp.c @@ -22,7 +22,7 @@ #include #endif #include -#include +#include #include #include #include diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index c0f718b12317..e717f8dc3966 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -16,7 +16,7 @@ #include #include -#include +#include #define DRV_NAME "adp5588-gpio" diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 53fe9a3fb620..f9d273c8b306 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -20,7 +20,7 @@ #include #include -#include +#include /* Key Event Register xy */ #define KEY_EV_PRESSED (1 << 7) diff --git a/include/linux/i2c/adp5588.h b/include/linux/i2c/adp5588.h deleted file mode 100644 index c2153049cfbd..000000000000 --- a/include/linux/i2c/adp5588.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Analog Devices ADP5588 I/O Expander and QWERTY Keypad Controller - * - * Copyright 2009-2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#ifndef _ADP5588_H -#define _ADP5588_H - -#define DEV_ID 0x00 /* Device ID */ -#define CFG 0x01 /* Configuration Register1 */ -#define INT_STAT 0x02 /* Interrupt Status Register */ -#define KEY_LCK_EC_STAT 0x03 /* Key Lock and Event Counter Register */ -#define Key_EVENTA 0x04 /* Key Event Register A */ -#define Key_EVENTB 0x05 /* Key Event Register B */ -#define Key_EVENTC 0x06 /* Key Event Register C */ -#define Key_EVENTD 0x07 /* Key Event Register D */ -#define Key_EVENTE 0x08 /* Key Event Register E */ -#define Key_EVENTF 0x09 /* Key Event Register F */ -#define Key_EVENTG 0x0A /* Key Event Register G */ -#define Key_EVENTH 0x0B /* Key Event Register H */ -#define Key_EVENTI 0x0C /* Key Event Register I */ -#define Key_EVENTJ 0x0D /* Key Event Register J */ -#define KP_LCK_TMR 0x0E /* Keypad Lock1 to Lock2 Timer */ -#define UNLOCK1 0x0F /* Unlock Key1 */ -#define UNLOCK2 0x10 /* Unlock Key2 */ -#define GPIO_INT_STAT1 0x11 /* GPIO Interrupt Status */ -#define GPIO_INT_STAT2 0x12 /* GPIO Interrupt Status */ -#define GPIO_INT_STAT3 0x13 /* GPIO Interrupt Status */ -#define GPIO_DAT_STAT1 0x14 /* GPIO Data Status, Read twice to clear */ -#define GPIO_DAT_STAT2 0x15 /* GPIO Data Status, Read twice to clear */ -#define GPIO_DAT_STAT3 0x16 /* GPIO Data Status, Read twice to clear */ -#define GPIO_DAT_OUT1 0x17 /* GPIO DATA OUT */ -#define GPIO_DAT_OUT2 0x18 /* GPIO DATA OUT */ -#define GPIO_DAT_OUT3 0x19 /* GPIO DATA OUT */ -#define GPIO_INT_EN1 0x1A /* GPIO Interrupt Enable */ -#define GPIO_INT_EN2 0x1B /* GPIO Interrupt Enable */ -#define GPIO_INT_EN3 0x1C /* GPIO Interrupt Enable */ -#define KP_GPIO1 0x1D /* Keypad or GPIO Selection */ -#define KP_GPIO2 0x1E /* Keypad or GPIO Selection */ -#define KP_GPIO3 0x1F /* Keypad or GPIO Selection */ -#define GPI_EM1 0x20 /* GPI Event Mode 1 */ -#define GPI_EM2 0x21 /* GPI Event Mode 2 */ -#define GPI_EM3 0x22 /* GPI Event Mode 3 */ -#define GPIO_DIR1 0x23 /* GPIO Data Direction */ -#define GPIO_DIR2 0x24 /* GPIO Data Direction */ -#define GPIO_DIR3 0x25 /* GPIO Data Direction */ -#define GPIO_INT_LVL1 0x26 /* GPIO Edge/Level Detect */ -#define GPIO_INT_LVL2 0x27 /* GPIO Edge/Level Detect */ -#define GPIO_INT_LVL3 0x28 /* GPIO Edge/Level Detect */ -#define Debounce_DIS1 0x29 /* Debounce Disable */ -#define Debounce_DIS2 0x2A /* Debounce Disable */ -#define Debounce_DIS3 0x2B /* Debounce Disable */ -#define GPIO_PULL1 0x2C /* GPIO Pull Disable */ -#define GPIO_PULL2 0x2D /* GPIO Pull Disable */ -#define GPIO_PULL3 0x2E /* GPIO Pull Disable */ -#define CMP_CFG_STAT 0x30 /* Comparator Configuration and Status Register */ -#define CMP_CONFG_SENS1 0x31 /* Sensor1 Comparator Configuration Register */ -#define CMP_CONFG_SENS2 0x32 /* L2 Light Sensor Reference Level, Output Falling for Sensor 1 */ -#define CMP1_LVL2_TRIP 0x33 /* L2 Light Sensor Hysteresis (Active when Output Rising) for Sensor 1 */ -#define CMP1_LVL2_HYS 0x34 /* L3 Light Sensor Reference Level, Output Falling For Sensor 1 */ -#define CMP1_LVL3_TRIP 0x35 /* L3 Light Sensor Hysteresis (Active when Output Rising) For Sensor 1 */ -#define CMP1_LVL3_HYS 0x36 /* Sensor 2 Comparator Configuration Register */ -#define CMP2_LVL2_TRIP 0x37 /* L2 Light Sensor Reference Level, Output Falling for Sensor 2 */ -#define CMP2_LVL2_HYS 0x38 /* L2 Light Sensor Hysteresis (Active when Output Rising) for Sensor 2 */ -#define CMP2_LVL3_TRIP 0x39 /* L3 Light Sensor Reference Level, Output Falling For Sensor 2 */ -#define CMP2_LVL3_HYS 0x3A /* L3 Light Sensor Hysteresis (Active when Output Rising) For Sensor 2 */ -#define CMP1_ADC_DAT_R1 0x3B /* Comparator 1 ADC data Register1 */ -#define CMP1_ADC_DAT_R2 0x3C /* Comparator 1 ADC data Register2 */ -#define CMP2_ADC_DAT_R1 0x3D /* Comparator 2 ADC data Register1 */ -#define CMP2_ADC_DAT_R2 0x3E /* Comparator 2 ADC data Register2 */ - -#define ADP5588_DEVICE_ID_MASK 0xF - - /* Configuration Register1 */ -#define ADP5588_AUTO_INC (1 << 7) -#define ADP5588_GPIEM_CFG (1 << 6) -#define ADP5588_OVR_FLOW_M (1 << 5) -#define ADP5588_INT_CFG (1 << 4) -#define ADP5588_OVR_FLOW_IEN (1 << 3) -#define ADP5588_K_LCK_IM (1 << 2) -#define ADP5588_GPI_IEN (1 << 1) -#define ADP5588_KE_IEN (1 << 0) - -/* Interrupt Status Register */ -#define ADP5588_CMP2_INT (1 << 5) -#define ADP5588_CMP1_INT (1 << 4) -#define ADP5588_OVR_FLOW_INT (1 << 3) -#define ADP5588_K_LCK_INT (1 << 2) -#define ADP5588_GPI_INT (1 << 1) -#define ADP5588_KE_INT (1 << 0) - -/* Key Lock and Event Counter Register */ -#define ADP5588_K_LCK_EN (1 << 6) -#define ADP5588_LCK21 0x30 -#define ADP5588_KEC 0xF - -#define ADP5588_MAXGPIO 18 -#define ADP5588_BANK(offs) ((offs) >> 3) -#define ADP5588_BIT(offs) (1u << ((offs) & 0x7)) - -/* Put one of these structures in i2c_board_info platform_data */ - -#define ADP5588_KEYMAPSIZE 80 - -#define GPI_PIN_ROW0 97 -#define GPI_PIN_ROW1 98 -#define GPI_PIN_ROW2 99 -#define GPI_PIN_ROW3 100 -#define GPI_PIN_ROW4 101 -#define GPI_PIN_ROW5 102 -#define GPI_PIN_ROW6 103 -#define GPI_PIN_ROW7 104 -#define GPI_PIN_COL0 105 -#define GPI_PIN_COL1 106 -#define GPI_PIN_COL2 107 -#define GPI_PIN_COL3 108 -#define GPI_PIN_COL4 109 -#define GPI_PIN_COL5 110 -#define GPI_PIN_COL6 111 -#define GPI_PIN_COL7 112 -#define GPI_PIN_COL8 113 -#define GPI_PIN_COL9 114 - -#define GPI_PIN_ROW_BASE GPI_PIN_ROW0 -#define GPI_PIN_ROW_END GPI_PIN_ROW7 -#define GPI_PIN_COL_BASE GPI_PIN_COL0 -#define GPI_PIN_COL_END GPI_PIN_COL9 - -#define GPI_PIN_BASE GPI_PIN_ROW_BASE -#define GPI_PIN_END GPI_PIN_COL_END - -#define ADP5588_GPIMAPSIZE_MAX (GPI_PIN_END - GPI_PIN_BASE + 1) - -struct adp5588_gpi_map { - unsigned short pin; - unsigned short sw_evt; -}; - -struct adp5588_kpad_platform_data { - int rows; /* Number of rows */ - int cols; /* Number of columns */ - const unsigned short *keymap; /* Pointer to keymap */ - unsigned short keymapsize; /* Keymap size */ - unsigned repeat:1; /* Enable key repeat */ - unsigned en_keylock:1; /* Enable Key Lock feature */ - unsigned short unlock_key1; /* Unlock Key 1 */ - unsigned short unlock_key2; /* Unlock Key 2 */ - const struct adp5588_gpi_map *gpimap; - unsigned short gpimapsize; - const struct adp5588_gpio_platform_data *gpio_data; -}; - -struct i2c_client; /* forward declaration */ - -struct adp5588_gpio_platform_data { - int gpio_start; /* GPIO Chip base # */ - const char *const *names; - unsigned irq_base; /* interrupt base # */ - unsigned pullup_dis_mask; /* Pull-Up Disable Mask */ - int (*setup)(struct i2c_client *client, - unsigned gpio, unsigned ngpio, - void *context); - int (*teardown)(struct i2c_client *client, - unsigned gpio, unsigned ngpio, - void *context); - void *context; -}; - -#endif diff --git a/include/linux/platform_data/adp5588.h b/include/linux/platform_data/adp5588.h new file mode 100644 index 000000000000..c2153049cfbd --- /dev/null +++ b/include/linux/platform_data/adp5588.h @@ -0,0 +1,172 @@ +/* + * Analog Devices ADP5588 I/O Expander and QWERTY Keypad Controller + * + * Copyright 2009-2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _ADP5588_H +#define _ADP5588_H + +#define DEV_ID 0x00 /* Device ID */ +#define CFG 0x01 /* Configuration Register1 */ +#define INT_STAT 0x02 /* Interrupt Status Register */ +#define KEY_LCK_EC_STAT 0x03 /* Key Lock and Event Counter Register */ +#define Key_EVENTA 0x04 /* Key Event Register A */ +#define Key_EVENTB 0x05 /* Key Event Register B */ +#define Key_EVENTC 0x06 /* Key Event Register C */ +#define Key_EVENTD 0x07 /* Key Event Register D */ +#define Key_EVENTE 0x08 /* Key Event Register E */ +#define Key_EVENTF 0x09 /* Key Event Register F */ +#define Key_EVENTG 0x0A /* Key Event Register G */ +#define Key_EVENTH 0x0B /* Key Event Register H */ +#define Key_EVENTI 0x0C /* Key Event Register I */ +#define Key_EVENTJ 0x0D /* Key Event Register J */ +#define KP_LCK_TMR 0x0E /* Keypad Lock1 to Lock2 Timer */ +#define UNLOCK1 0x0F /* Unlock Key1 */ +#define UNLOCK2 0x10 /* Unlock Key2 */ +#define GPIO_INT_STAT1 0x11 /* GPIO Interrupt Status */ +#define GPIO_INT_STAT2 0x12 /* GPIO Interrupt Status */ +#define GPIO_INT_STAT3 0x13 /* GPIO Interrupt Status */ +#define GPIO_DAT_STAT1 0x14 /* GPIO Data Status, Read twice to clear */ +#define GPIO_DAT_STAT2 0x15 /* GPIO Data Status, Read twice to clear */ +#define GPIO_DAT_STAT3 0x16 /* GPIO Data Status, Read twice to clear */ +#define GPIO_DAT_OUT1 0x17 /* GPIO DATA OUT */ +#define GPIO_DAT_OUT2 0x18 /* GPIO DATA OUT */ +#define GPIO_DAT_OUT3 0x19 /* GPIO DATA OUT */ +#define GPIO_INT_EN1 0x1A /* GPIO Interrupt Enable */ +#define GPIO_INT_EN2 0x1B /* GPIO Interrupt Enable */ +#define GPIO_INT_EN3 0x1C /* GPIO Interrupt Enable */ +#define KP_GPIO1 0x1D /* Keypad or GPIO Selection */ +#define KP_GPIO2 0x1E /* Keypad or GPIO Selection */ +#define KP_GPIO3 0x1F /* Keypad or GPIO Selection */ +#define GPI_EM1 0x20 /* GPI Event Mode 1 */ +#define GPI_EM2 0x21 /* GPI Event Mode 2 */ +#define GPI_EM3 0x22 /* GPI Event Mode 3 */ +#define GPIO_DIR1 0x23 /* GPIO Data Direction */ +#define GPIO_DIR2 0x24 /* GPIO Data Direction */ +#define GPIO_DIR3 0x25 /* GPIO Data Direction */ +#define GPIO_INT_LVL1 0x26 /* GPIO Edge/Level Detect */ +#define GPIO_INT_LVL2 0x27 /* GPIO Edge/Level Detect */ +#define GPIO_INT_LVL3 0x28 /* GPIO Edge/Level Detect */ +#define Debounce_DIS1 0x29 /* Debounce Disable */ +#define Debounce_DIS2 0x2A /* Debounce Disable */ +#define Debounce_DIS3 0x2B /* Debounce Disable */ +#define GPIO_PULL1 0x2C /* GPIO Pull Disable */ +#define GPIO_PULL2 0x2D /* GPIO Pull Disable */ +#define GPIO_PULL3 0x2E /* GPIO Pull Disable */ +#define CMP_CFG_STAT 0x30 /* Comparator Configuration and Status Register */ +#define CMP_CONFG_SENS1 0x31 /* Sensor1 Comparator Configuration Register */ +#define CMP_CONFG_SENS2 0x32 /* L2 Light Sensor Reference Level, Output Falling for Sensor 1 */ +#define CMP1_LVL2_TRIP 0x33 /* L2 Light Sensor Hysteresis (Active when Output Rising) for Sensor 1 */ +#define CMP1_LVL2_HYS 0x34 /* L3 Light Sensor Reference Level, Output Falling For Sensor 1 */ +#define CMP1_LVL3_TRIP 0x35 /* L3 Light Sensor Hysteresis (Active when Output Rising) For Sensor 1 */ +#define CMP1_LVL3_HYS 0x36 /* Sensor 2 Comparator Configuration Register */ +#define CMP2_LVL2_TRIP 0x37 /* L2 Light Sensor Reference Level, Output Falling for Sensor 2 */ +#define CMP2_LVL2_HYS 0x38 /* L2 Light Sensor Hysteresis (Active when Output Rising) for Sensor 2 */ +#define CMP2_LVL3_TRIP 0x39 /* L3 Light Sensor Reference Level, Output Falling For Sensor 2 */ +#define CMP2_LVL3_HYS 0x3A /* L3 Light Sensor Hysteresis (Active when Output Rising) For Sensor 2 */ +#define CMP1_ADC_DAT_R1 0x3B /* Comparator 1 ADC data Register1 */ +#define CMP1_ADC_DAT_R2 0x3C /* Comparator 1 ADC data Register2 */ +#define CMP2_ADC_DAT_R1 0x3D /* Comparator 2 ADC data Register1 */ +#define CMP2_ADC_DAT_R2 0x3E /* Comparator 2 ADC data Register2 */ + +#define ADP5588_DEVICE_ID_MASK 0xF + + /* Configuration Register1 */ +#define ADP5588_AUTO_INC (1 << 7) +#define ADP5588_GPIEM_CFG (1 << 6) +#define ADP5588_OVR_FLOW_M (1 << 5) +#define ADP5588_INT_CFG (1 << 4) +#define ADP5588_OVR_FLOW_IEN (1 << 3) +#define ADP5588_K_LCK_IM (1 << 2) +#define ADP5588_GPI_IEN (1 << 1) +#define ADP5588_KE_IEN (1 << 0) + +/* Interrupt Status Register */ +#define ADP5588_CMP2_INT (1 << 5) +#define ADP5588_CMP1_INT (1 << 4) +#define ADP5588_OVR_FLOW_INT (1 << 3) +#define ADP5588_K_LCK_INT (1 << 2) +#define ADP5588_GPI_INT (1 << 1) +#define ADP5588_KE_INT (1 << 0) + +/* Key Lock and Event Counter Register */ +#define ADP5588_K_LCK_EN (1 << 6) +#define ADP5588_LCK21 0x30 +#define ADP5588_KEC 0xF + +#define ADP5588_MAXGPIO 18 +#define ADP5588_BANK(offs) ((offs) >> 3) +#define ADP5588_BIT(offs) (1u << ((offs) & 0x7)) + +/* Put one of these structures in i2c_board_info platform_data */ + +#define ADP5588_KEYMAPSIZE 80 + +#define GPI_PIN_ROW0 97 +#define GPI_PIN_ROW1 98 +#define GPI_PIN_ROW2 99 +#define GPI_PIN_ROW3 100 +#define GPI_PIN_ROW4 101 +#define GPI_PIN_ROW5 102 +#define GPI_PIN_ROW6 103 +#define GPI_PIN_ROW7 104 +#define GPI_PIN_COL0 105 +#define GPI_PIN_COL1 106 +#define GPI_PIN_COL2 107 +#define GPI_PIN_COL3 108 +#define GPI_PIN_COL4 109 +#define GPI_PIN_COL5 110 +#define GPI_PIN_COL6 111 +#define GPI_PIN_COL7 112 +#define GPI_PIN_COL8 113 +#define GPI_PIN_COL9 114 + +#define GPI_PIN_ROW_BASE GPI_PIN_ROW0 +#define GPI_PIN_ROW_END GPI_PIN_ROW7 +#define GPI_PIN_COL_BASE GPI_PIN_COL0 +#define GPI_PIN_COL_END GPI_PIN_COL9 + +#define GPI_PIN_BASE GPI_PIN_ROW_BASE +#define GPI_PIN_END GPI_PIN_COL_END + +#define ADP5588_GPIMAPSIZE_MAX (GPI_PIN_END - GPI_PIN_BASE + 1) + +struct adp5588_gpi_map { + unsigned short pin; + unsigned short sw_evt; +}; + +struct adp5588_kpad_platform_data { + int rows; /* Number of rows */ + int cols; /* Number of columns */ + const unsigned short *keymap; /* Pointer to keymap */ + unsigned short keymapsize; /* Keymap size */ + unsigned repeat:1; /* Enable key repeat */ + unsigned en_keylock:1; /* Enable Key Lock feature */ + unsigned short unlock_key1; /* Unlock Key 1 */ + unsigned short unlock_key2; /* Unlock Key 2 */ + const struct adp5588_gpi_map *gpimap; + unsigned short gpimapsize; + const struct adp5588_gpio_platform_data *gpio_data; +}; + +struct i2c_client; /* forward declaration */ + +struct adp5588_gpio_platform_data { + int gpio_start; /* GPIO Chip base # */ + const char *const *names; + unsigned irq_base; /* interrupt base # */ + unsigned pullup_dis_mask; /* Pull-Up Disable Mask */ + int (*setup)(struct i2c_client *client, + unsigned gpio, unsigned ngpio, + void *context); + int (*teardown)(struct i2c_client *client, + unsigned gpio, unsigned ngpio, + void *context); + void *context; +}; + +#endif -- cgit v1.3-15-g9ac1 From 79ffd5f98c11572c004d52f7ecd270ab680a7f72 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 26 May 2017 16:55:10 -0700 Subject: Input: sparse-keymap - remove sparse_keymap_free() Now that all users of sparse_keymap_free() are gone we can remove the stub. Signed-off-by: Dmitry Torokhov --- drivers/input/sparse-keymap.c | 14 -------------- include/linux/input/sparse-keymap.h | 1 - 2 files changed, 15 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 12a3ad83296d..bb0349fa64bc 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -223,20 +223,6 @@ int sparse_keymap_setup(struct input_dev *dev, } EXPORT_SYMBOL(sparse_keymap_setup); -/** - * sparse_keymap_free - free memory allocated for sparse keymap - * @dev: Input device using sparse keymap - * - * This function used to free memory allocated by sparse keymap - * in an input device that was set up by sparse_keymap_setup(). - * Since sparse_keymap_setup() now uses a managed allocation for the - * keymap copy, use of this function is deprecated. - */ -void sparse_keymap_free(struct input_dev *dev) -{ -} -EXPORT_SYMBOL(sparse_keymap_free); - /** * sparse_keymap_report_entry - report event corresponding to given key entry * @dev: Input device for which event should be reported diff --git a/include/linux/input/sparse-keymap.h b/include/linux/input/sparse-keymap.h index 52db62064c6e..c7346e33d958 100644 --- a/include/linux/input/sparse-keymap.h +++ b/include/linux/input/sparse-keymap.h @@ -51,7 +51,6 @@ struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev, int sparse_keymap_setup(struct input_dev *dev, const struct key_entry *keymap, int (*setup)(struct input_dev *, struct key_entry *)); -void sparse_keymap_free(struct input_dev *dev); void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke, unsigned int value, bool autorelease); -- cgit v1.3-15-g9ac1 From 32a62b9441d840e676d55b45468371c252a4fa01 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 29 May 2017 20:21:52 -0700 Subject: Input: synaptics-rmi4 - change a char type to u8 Smatch doesn't like when we use "%02X" to print char types because, what about if it's a negative? Signed-off-by: Dan Carpenter Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_f34v7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c index 10c0d11b72c9..ae2db1c3aebf 100644 --- a/drivers/input/rmi4/rmi_f34v7.c +++ b/drivers/input/rmi4/rmi_f34v7.c @@ -518,7 +518,7 @@ static int rmi_f34v7_read_queries(struct f34_data *f34) query_1_7.partition_support[1] & HAS_GUEST_CODE; if (query_0 & HAS_CONFIG_ID) { - char f34_ctrl[CONFIG_ID_SIZE]; + u8 f34_ctrl[CONFIG_ID_SIZE]; int i = 0; u8 *p = f34->configuration_id; *p = '\0'; -- cgit v1.3-15-g9ac1 From 49bbbfa8d27a227521a9e07cb1612f60e8f0e8ff Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 29 May 2017 20:22:34 -0700 Subject: Input: synaptics-rmi4 - use %phN to form F34 configuration ID Instead of printing bytes one by one, let's use %phN to print the buffer in one go. Also use hweight8 to count number of partitions instead of inspecting it bit by bit. Reviewed-by: Benjamin Tissoires Tested-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_f34v7.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c index ae2db1c3aebf..3991d2943660 100644 --- a/drivers/input/rmi4/rmi_f34v7.c +++ b/drivers/input/rmi4/rmi_f34v7.c @@ -9,13 +9,14 @@ * the Free Software Foundation. */ +#include #include #include #include -#include #include #include #include +#include #include "rmi_driver.h" #include "rmi_f34.h" @@ -464,7 +465,7 @@ static int rmi_f34v7_read_queries_bl_version(struct f34_data *f34) static int rmi_f34v7_read_queries(struct f34_data *f34) { int ret; - int i, j; + int i; u8 base; int offset; u8 *ptable; @@ -519,9 +520,6 @@ static int rmi_f34v7_read_queries(struct f34_data *f34) if (query_0 & HAS_CONFIG_ID) { u8 f34_ctrl[CONFIG_ID_SIZE]; - int i = 0; - u8 *p = f34->configuration_id; - *p = '\0'; ret = rmi_read_block(f34->fn->rmi_dev, f34->fn->fd.control_base_addr, @@ -531,13 +529,11 @@ static int rmi_f34v7_read_queries(struct f34_data *f34) return ret; /* Eat leading zeros */ - while (i < sizeof(f34_ctrl) && !f34_ctrl[i]) - i++; + for (i = 0; i < sizeof(f34_ctrl) - 1 && !f34_ctrl[i]; i++) + /* Empty */; - for (; i < sizeof(f34_ctrl); i++) - p += snprintf(p, f34->configuration_id - + sizeof(f34->configuration_id) - p, - "%02X", f34_ctrl[i]); + snprintf(f34->configuration_id, sizeof(f34->configuration_id), + "%*phN", (int)sizeof(f34_ctrl) - i, f34_ctrl + i); rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Configuration ID: %s\n", f34->configuration_id); @@ -545,9 +541,7 @@ static int rmi_f34v7_read_queries(struct f34_data *f34) f34->v7.partitions = 0; for (i = 0; i < sizeof(query_1_7.partition_support); i++) - for (j = 0; j < 8; j++) - if (query_1_7.partition_support[i] & (1 << j)) - f34->v7.partitions++; + f34->v7.partitions += hweight8(query_1_7.partition_support[i]); rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: Supported partitions: %*ph\n", __func__, sizeof(query_1_7.partition_support), -- cgit v1.3-15-g9ac1 From 58be76896786b512e97cb743ec271648623a7107 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 2 Jun 2017 17:51:42 -0700 Subject: Input: axp20x-pek - add wakeup support At least on devices with the AXP288 PMIC the device is expected to wakeup from suspend when the power-button gets pressed, add support for this. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/misc/axp20x-pek.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c index f11807db6979..d3e9ce27a2be 100644 --- a/drivers/input/misc/axp20x-pek.c +++ b/drivers/input/misc/axp20x-pek.c @@ -253,6 +253,9 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek, return error; } + if (axp20x_pek->axp20x->variant == AXP288_ID) + enable_irq_wake(axp20x_pek->irq_dbr); + return 0; } @@ -301,10 +304,35 @@ static int axp20x_pek_probe(struct platform_device *pdev) return 0; } +static int __maybe_unused axp20x_pek_resume_noirq(struct device *dev) +{ + struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev); + + if (axp20x_pek->axp20x->variant != AXP288_ID) + return 0; + + /* + * Clear interrupts from button presses during suspend, to avoid + * a wakeup power-button press getting reported to userspace. + */ + regmap_write(axp20x_pek->axp20x->regmap, + AXP20X_IRQ1_STATE + AXP288_IRQ_POKN / 8, + BIT(AXP288_IRQ_POKN % 8)); + + return 0; +} + +static const struct dev_pm_ops axp20x_pek_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .resume_noirq = axp20x_pek_resume_noirq, +#endif +}; + static struct platform_driver axp20x_pek_driver = { .probe = axp20x_pek_probe, .driver = { .name = "axp20x-pek", + .pm = &axp20x_pek_pm_ops, }, }; module_platform_driver(axp20x_pek_driver); -- cgit v1.3-15-g9ac1 From 086cebfa72fa22e1e49f251d33fe1ceaab4af2d4 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 30 May 2017 09:44:28 -0700 Subject: Input: s3c2410_ts - handle return value of clk_prepare_enable clk_prepare_enable() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/s3c2410_ts.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index 41d58e88cc8a..3b3db8c868e0 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -264,7 +264,11 @@ static int s3c2410ts_probe(struct platform_device *pdev) return -ENOENT; } - clk_prepare_enable(ts.clock); + ret = clk_prepare_enable(ts.clock); + if (ret) { + dev_err(dev, "Failed! to enabled clocks\n"); + goto err_clk_get; + } dev_dbg(dev, "got and enabled clocks\n"); ts.irq_tc = ret = platform_get_irq(pdev, 0); @@ -353,7 +357,9 @@ static int s3c2410ts_probe(struct platform_device *pdev) err_iomap: iounmap(ts.io); err_clk: + clk_disable_unprepare(ts.clock); del_timer_sync(&touch_timer); + err_clk_get: clk_put(ts.clock); return ret; } -- cgit v1.3-15-g9ac1 From 131b3de7016b73fca1aba8ffb528217ac95b2505 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 5 Jun 2017 14:48:44 -0700 Subject: Input: add D-Link DIR-685 touchkeys driver This adds support for the D-Link DIR-685 touchkeys found in the router with this name. The vendor code calles this a "touchpad" but we are registering it here under its real name. Signed-off-by: Linus Walleij Acked-by: Rob Herring Signed-off-by: Dmitry Torokhov --- .../bindings/input/dlink,dir685-touchkeys.txt | 21 +++ MAINTAINERS | 6 + drivers/input/keyboard/Kconfig | 11 ++ drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/dlink-dir685-touchkeys.c | 155 +++++++++++++++++++++ 5 files changed, 194 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/dlink,dir685-touchkeys.txt create mode 100644 drivers/input/keyboard/dlink-dir685-touchkeys.c (limited to 'drivers/input') diff --git a/Documentation/devicetree/bindings/input/dlink,dir685-touchkeys.txt b/Documentation/devicetree/bindings/input/dlink,dir685-touchkeys.txt new file mode 100644 index 000000000000..10dec1c57abf --- /dev/null +++ b/Documentation/devicetree/bindings/input/dlink,dir685-touchkeys.txt @@ -0,0 +1,21 @@ +* D-Link DIR-685 Touchkeys + +This is a I2C one-off touchkey controller based on the Cypress Semiconductor +CY8C214 MCU with some firmware in its internal 8KB flash. The circuit +board inside the router is named E119921. + +The touchkey device node should be placed inside an I2C bus node. + +Required properties: +- compatible: must be "dlink,dir685-touchkeys" +- reg: the I2C address of the touchkeys +- interrupts: reference to the interrupt number + +Example: + +touchkeys@26 { + compatible = "dlink,dir685-touchkeys"; + reg = <0x26>; + interrupt-parent = <&gpio0>; + interrupts = <17 IRQ_TYPE_EDGE_FALLING>; +}; diff --git a/MAINTAINERS b/MAINTAINERS index 053c3bdd1fe5..98861181fb2a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3786,6 +3786,12 @@ S: Supported F: drivers/input/touchscreen/cyttsp* F: include/linux/input/cyttsp.h +D-LINK DIR-685 TOUCHKEYS DRIVER +M: Linus Walleij +L: linux-input@vger.kernel.org +S: Supported +F: drivers/input/dlink-dir685-touchkeys.c + DALLAS/MAXIM DS1685-FAMILY REAL TIME CLOCK M: Joshua Kinard S: Maintained diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 97acd6524ad7..4c4ab1ced235 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -178,6 +178,17 @@ config KEYBOARD_CLPS711X To compile this driver as a module, choose M here: the module will be called clps711x-keypad. +config KEYBOARD_DLINK_DIR685 + tristate "D-Link DIR-685 touchkeys support" + depends on I2C + default ARCH_GEMINI + help + If you say yes here you get support for the D-Link DIR-685 + touchkeys. + + To compile this driver as a module, choose M here: the + module will be called dlink-dir685-touchkeys. + config KEYBOARD_LKKBD tristate "DECstation/VAXstation LK201/LK401 keyboard" select SERIO diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 7d9acff819a7..d2338bacdad1 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o +obj-$(CONFIG_KEYBOARD_DLINK_DIR685) += dlink-dir685-touchkeys.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o diff --git a/drivers/input/keyboard/dlink-dir685-touchkeys.c b/drivers/input/keyboard/dlink-dir685-touchkeys.c new file mode 100644 index 000000000000..88e321b76397 --- /dev/null +++ b/drivers/input/keyboard/dlink-dir685-touchkeys.c @@ -0,0 +1,155 @@ +/* + * D-Link DIR-685 router I2C-based Touchkeys input driver + * Copyright (C) 2017 Linus Walleij + * + * This is a one-off touchkey controller based on the Cypress Semiconductor + * CY8C214 MCU with some firmware in its internal 8KB flash. The circuit + * board inside the router is named E119921 + */ + +#include +#include +#include +#include +#include +#include +#include + +struct dir685_touchkeys { + struct device *dev; + struct i2c_client *client; + struct input_dev *input; + unsigned long cur_key; + u16 codes[7]; +}; + +static irqreturn_t dir685_tk_irq_thread(int irq, void *data) +{ + struct dir685_touchkeys *tk = data; + const int num_bits = min_t(int, ARRAY_SIZE(tk->codes), 16); + unsigned long changed; + u8 buf[6]; + unsigned long key; + int i; + int err; + + memset(buf, 0, sizeof(buf)); + err = i2c_master_recv(tk->client, buf, sizeof(buf)); + if (err != sizeof(buf)) { + dev_err(tk->dev, "short read %d\n", err); + return IRQ_HANDLED; + } + + dev_dbg(tk->dev, "IN: %*ph\n", (int)sizeof(buf), buf); + key = be16_to_cpup((__be16 *) &buf[4]); + + /* Figure out if any bits went high or low since last message */ + changed = tk->cur_key ^ key; + for_each_set_bit(i, &changed, num_bits) { + dev_dbg(tk->dev, "key %d is %s\n", i, + test_bit(i, &key) ? "down" : "up"); + input_report_key(tk->input, tk->codes[i], test_bit(i, &key)); + } + + /* Store currently down keys */ + tk->cur_key = key; + input_sync(tk->input); + + return IRQ_HANDLED; +} + +static int dir685_tk_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct dir685_touchkeys *tk; + struct device *dev = &client->dev; + u8 bl_data[] = { 0xa7, 0x40 }; + int err; + int i; + + tk = devm_kzalloc(&client->dev, sizeof(*tk), GFP_KERNEL); + if (!tk) + return -ENOMEM; + + tk->input = devm_input_allocate_device(dev); + if (!tk->input) + return -ENOMEM; + + tk->client = client; + tk->dev = dev; + + tk->input->keycodesize = sizeof(u16); + tk->input->keycodemax = ARRAY_SIZE(tk->codes); + tk->input->keycode = tk->codes; + tk->codes[0] = KEY_UP; + tk->codes[1] = KEY_DOWN; + tk->codes[2] = KEY_LEFT; + tk->codes[3] = KEY_RIGHT; + tk->codes[4] = KEY_ENTER; + tk->codes[5] = KEY_WPS_BUTTON; + /* + * This key appears in the vendor driver, but I have + * not been able to activate it. + */ + tk->codes[6] = KEY_RESERVED; + + __set_bit(EV_KEY, tk->input->evbit); + for (i = 0; i < ARRAY_SIZE(tk->codes); i++) + __set_bit(tk->codes[i], tk->input->keybit); + __clear_bit(KEY_RESERVED, tk->input->keybit); + + tk->input->name = "D-Link DIR-685 touchkeys"; + tk->input->id.bustype = BUS_I2C; + + err = input_register_device(tk->input); + if (err) + return err; + + /* Set the brightness to max level */ + err = i2c_master_send(client, bl_data, sizeof(bl_data)); + if (err != sizeof(bl_data)) + dev_warn(tk->dev, "error setting brightness level\n"); + + if (!client->irq) { + dev_err(dev, "no IRQ on the I2C device\n"); + return -ENODEV; + } + err = devm_request_threaded_irq(dev, client->irq, + NULL, dir685_tk_irq_thread, + IRQF_ONESHOT, + "dir685-tk", tk); + if (err) { + dev_err(dev, "can't request IRQ\n"); + return err; + } + + return 0; +} + +static const struct i2c_device_id dir685_tk_id[] = { + { "dir685tk", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, dir685_tk_id); + +#ifdef CONFIG_OF +static const struct of_device_id dir685_tk_of_match[] = { + { .compatible = "dlink,dir685-touchkeys" }, + {}, +}; +MODULE_DEVICE_TABLE(of, dir685_tk_of_match); +#endif + +static struct i2c_driver dir685_tk_i2c_driver = { + .driver = { + .name = "dlin-dir685-touchkeys", + .of_match_table = of_match_ptr(dir685_tk_of_match), + }, + .probe = dir685_tk_probe, + .id_table = dir685_tk_id, +}; +module_i2c_driver(dir685_tk_i2c_driver); + +MODULE_AUTHOR("Linus Walleij "); +MODULE_DESCRIPTION("D-Link DIR-685 touchkeys driver"); +MODULE_LICENSE("GPL"); -- cgit v1.3-15-g9ac1 From 78bcac7b2ae1e4f6e96c68ff353c140669ea231c Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Mon, 5 Jun 2017 15:29:18 -0700 Subject: Input: add support for the STMicroelectronics FingerTip touchscreen The stmfts (ST-Microelectronics FingerTip S) touchscreen device is a capacitive multi-touch controller mainly for mobile use. It's connected through i2c bus at the address 0x49 and it interfaces with userspace through input event interface. At the current state it provides a touchscreen multitouch functionality up to 10 fingers. Each finger is enumerated with a distinctive id (from 0 to 9). If enabled the device can support single "touch" hovering, by providing three coordinates, x, y and distance. It is possible to select the touchkey functionality which provides a basic two keys interface for "home" and "back" menu, typical in mobile phones. Signed-off-by: Andi Shyti Reviewed-by: Javier Martinez Canillas Acked-by: Rob Herring Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/st,stmfts.txt | 43 ++ drivers/input/touchscreen/Kconfig | 11 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/stmfts.c | 822 +++++++++++++++++++++ 4 files changed, 877 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/st,stmfts.txt create mode 100644 drivers/input/touchscreen/stmfts.c (limited to 'drivers/input') diff --git a/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.txt b/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.txt new file mode 100644 index 000000000000..9683595cd0f5 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.txt @@ -0,0 +1,43 @@ +* ST-Microelectronics FingerTip touchscreen controller + +The ST-Microelectronics FingerTip device provides a basic touchscreen +functionality. Along with it the user can enable the touchkey which can work as +a basic HOME and BACK key for phones. + +The driver supports also hovering as an absolute single touch event with x, y, z +coordinates. + +Required properties: +- compatible : must be "st,stmfts" +- reg : I2C slave address, (e.g. 0x49) +- interrupt-parent : the phandle to the interrupt controller which provides + the interrupt +- interrupts : interrupt specification +- avdd-supply : analogic power supply +- vdd-supply : power supply +- touchscreen-size-x : see touchscreen.txt +- touchscreen-size-y : see touchscreen.txt + +Optional properties: +- touch-key-connected : specifies whether the touchkey feature is connected +- ledvdd-supply : power supply to the touch key leds + +Example: + +i2c@00000000 { + + /* ... */ + + touchscreen@49 { + compatible = "st,stmfts"; + reg = <0x49>; + interrupt-parent = <&gpa1>; + interrupts = <1 IRQ_TYPE_NONE>; + touchscreen-size-x = <1599>; + touchscreen-size-y = <2559>; + touch-key-connected; + avdd-supply = <&ldo30_reg>; + vdd-supply = <&ldo31_reg>; + ledvdd-supply = <&ldo33_reg>; + }; +}; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index cf26ca49ae6d..64b30fe273fd 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1114,6 +1114,17 @@ config TOUCHSCREEN_ST1232 To compile this driver as a module, choose M here: the module will be called st1232_ts. +config TOUCHSCREEN_STMFTS + tristate "STMicroelectronics STMFTS touchscreen" + depends on I2C + depends on LEDS_CLASS + help + Say Y here if you want support for STMicroelectronics + STMFTS touchscreen. + + To compile this driver as a module, choose M here: the + module will be called stmfts. + config TOUCHSCREEN_STMPE tristate "STMicroelectronics STMPE touchscreens" depends on MFD_STMPE diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 18e476948e44..6badce87037b 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o +obj-$(CONFIG_TOUCHSCREEN_STMFTS) += stmfts.o obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c new file mode 100644 index 000000000000..802d0e82d034 --- /dev/null +++ b/drivers/input/touchscreen/stmfts.c @@ -0,0 +1,822 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Author: Andi Shyti + * + * 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. + * + * STMicroelectronics FTS Touchscreen device driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* I2C commands */ +#define STMFTS_READ_INFO 0x80 +#define STMFTS_READ_STATUS 0x84 +#define STMFTS_READ_ONE_EVENT 0x85 +#define STMFTS_READ_ALL_EVENT 0x86 +#define STMFTS_LATEST_EVENT 0x87 +#define STMFTS_SLEEP_IN 0x90 +#define STMFTS_SLEEP_OUT 0x91 +#define STMFTS_MS_MT_SENSE_OFF 0x92 +#define STMFTS_MS_MT_SENSE_ON 0x93 +#define STMFTS_SS_HOVER_SENSE_OFF 0x94 +#define STMFTS_SS_HOVER_SENSE_ON 0x95 +#define STMFTS_MS_KEY_SENSE_OFF 0x9a +#define STMFTS_MS_KEY_SENSE_ON 0x9b +#define STMFTS_SYSTEM_RESET 0xa0 +#define STMFTS_CLEAR_EVENT_STACK 0xa1 +#define STMFTS_FULL_FORCE_CALIBRATION 0xa2 +#define STMFTS_MS_CX_TUNING 0xa3 +#define STMFTS_SS_CX_TUNING 0xa4 + +/* events */ +#define STMFTS_EV_NO_EVENT 0x00 +#define STMFTS_EV_MULTI_TOUCH_DETECTED 0x02 +#define STMFTS_EV_MULTI_TOUCH_ENTER 0x03 +#define STMFTS_EV_MULTI_TOUCH_LEAVE 0x04 +#define STMFTS_EV_MULTI_TOUCH_MOTION 0x05 +#define STMFTS_EV_HOVER_ENTER 0x07 +#define STMFTS_EV_HOVER_LEAVE 0x08 +#define STMFTS_EV_HOVER_MOTION 0x09 +#define STMFTS_EV_KEY_STATUS 0x0e +#define STMFTS_EV_ERROR 0x0f +#define STMFTS_EV_CONTROLLER_READY 0x10 +#define STMFTS_EV_SLEEP_OUT_CONTROLLER_READY 0x11 +#define STMFTS_EV_STATUS 0x16 +#define STMFTS_EV_DEBUG 0xdb + +/* multi touch related event masks */ +#define STMFTS_MASK_EVENT_ID 0x0f +#define STMFTS_MASK_TOUCH_ID 0xf0 +#define STMFTS_MASK_LEFT_EVENT 0x0f +#define STMFTS_MASK_X_MSB 0x0f +#define STMFTS_MASK_Y_LSB 0xf0 + +/* key related event masks */ +#define STMFTS_MASK_KEY_NO_TOUCH 0x00 +#define STMFTS_MASK_KEY_MENU 0x01 +#define STMFTS_MASK_KEY_BACK 0x02 + +#define STMFTS_EVENT_SIZE 8 +#define STMFTS_STACK_DEPTH 32 +#define STMFTS_DATA_MAX_SIZE (STMFTS_EVENT_SIZE * STMFTS_STACK_DEPTH) +#define STMFTS_MAX_FINGERS 10 +#define STMFTS_DEV_NAME "stmfts" + +enum stmfts_regulators { + STMFTS_REGULATOR_VDD, + STMFTS_REGULATOR_AVDD, +}; + +struct stmfts_data { + struct i2c_client *client; + struct input_dev *input; + struct led_classdev led_cdev; + struct mutex mutex; + + struct touchscreen_properties prop; + + struct regulator_bulk_data regulators[2]; + + /* + * Presence of ledvdd will be used also to check + * whether the LED is supported. + */ + struct regulator *ledvdd; + + u16 chip_id; + u8 chip_ver; + u16 fw_ver; + u8 config_id; + u8 config_ver; + + u8 data[STMFTS_DATA_MAX_SIZE]; + + struct completion cmd_done; + + bool use_key; + bool led_status; + bool hover_enabled; + bool running; +}; + +static void stmfts_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct stmfts_data *sdata = container_of(led_cdev, + struct stmfts_data, led_cdev); + int err; + + if (value == sdata->led_status || !sdata->ledvdd) + return; + + if (!value) { + regulator_disable(sdata->ledvdd); + } else { + err = regulator_enable(sdata->ledvdd); + if (err) + dev_warn(&sdata->client->dev, + "failed to disable ledvdd regulator: %d\n", + err); + } + + sdata->led_status = value; +} + +static enum led_brightness stmfts_brightness_get(struct led_classdev *led_cdev) +{ + struct stmfts_data *sdata = container_of(led_cdev, + struct stmfts_data, led_cdev); + + return !!regulator_is_enabled(sdata->ledvdd); +} + +/* + * We can't simply use i2c_smbus_read_i2c_block_data because we + * need to read more than 255 bytes ( + */ +static int stmfts_read_events(struct stmfts_data *sdata) +{ + u8 cmd = STMFTS_READ_ALL_EVENT; + struct i2c_msg msgs[2] = { + { + .addr = sdata->client->addr, + .len = 1, + .buf = &cmd, + }, + { + .addr = sdata->client->addr, + .flags = I2C_M_RD, + .len = STMFTS_DATA_MAX_SIZE, + .buf = sdata->data, + }, + }; + int ret; + + ret = i2c_transfer(sdata->client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + return ret; + + return ret == ARRAY_SIZE(msgs) ? 0 : -EIO; +} + +static void stmfts_report_contact_event(struct stmfts_data *sdata, + const u8 event[]) +{ + u8 slot_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4; + u16 x = event[1] | ((event[2] & STMFTS_MASK_X_MSB) << 8); + u16 y = (event[2] >> 4) | (event[3] << 4); + u8 maj = event[4]; + u8 min = event[5]; + u8 orientation = event[6]; + u8 area = event[7]; + + input_mt_slot(sdata->input, slot_id); + + input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, true); + input_report_abs(sdata->input, ABS_MT_POSITION_X, x); + input_report_abs(sdata->input, ABS_MT_POSITION_Y, y); + input_report_abs(sdata->input, ABS_MT_TOUCH_MAJOR, maj); + input_report_abs(sdata->input, ABS_MT_TOUCH_MINOR, min); + input_report_abs(sdata->input, ABS_MT_PRESSURE, area); + input_report_abs(sdata->input, ABS_MT_ORIENTATION, orientation); + + input_sync(sdata->input); +} + +static void stmfts_report_contact_release(struct stmfts_data *sdata, + const u8 event[]) +{ + u8 slot_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4; + + input_mt_slot(sdata->input, slot_id); + input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, false); + + input_sync(sdata->input); +} + +static void stmfts_report_hover_event(struct stmfts_data *sdata, + const u8 event[]) +{ + u16 x = (event[2] << 4) | (event[4] >> 4); + u16 y = (event[3] << 4) | (event[4] & STMFTS_MASK_Y_LSB); + u8 z = event[5]; + + input_report_abs(sdata->input, ABS_X, x); + input_report_abs(sdata->input, ABS_Y, y); + input_report_abs(sdata->input, ABS_DISTANCE, z); + + input_sync(sdata->input); +} + +static void stmfts_report_key_event(struct stmfts_data *sdata, const u8 event[]) +{ + switch (event[2]) { + case 0: + input_report_key(sdata->input, KEY_BACK, 0); + input_report_key(sdata->input, KEY_MENU, 0); + break; + + case STMFTS_MASK_KEY_BACK: + input_report_key(sdata->input, KEY_BACK, 1); + break; + + case STMFTS_MASK_KEY_MENU: + input_report_key(sdata->input, KEY_MENU, 1); + break; + + default: + dev_warn(&sdata->client->dev, + "unknown key event: %#02x\n", event[2]); + break; + } + + input_sync(sdata->input); +} + +static void stmfts_parse_events(struct stmfts_data *sdata) +{ + int i; + + for (i = 0; i < STMFTS_STACK_DEPTH; i++) { + u8 *event = &sdata->data[i * STMFTS_EVENT_SIZE]; + + switch (event[0]) { + + case STMFTS_EV_CONTROLLER_READY: + case STMFTS_EV_SLEEP_OUT_CONTROLLER_READY: + case STMFTS_EV_STATUS: + complete(&sdata->cmd_done); + /* fall through */ + + case STMFTS_EV_NO_EVENT: + case STMFTS_EV_DEBUG: + return; + } + + switch (event[0] & STMFTS_MASK_EVENT_ID) { + + case STMFTS_EV_MULTI_TOUCH_ENTER: + case STMFTS_EV_MULTI_TOUCH_MOTION: + stmfts_report_contact_event(sdata, event); + break; + + case STMFTS_EV_MULTI_TOUCH_LEAVE: + stmfts_report_contact_release(sdata, event); + break; + + case STMFTS_EV_HOVER_ENTER: + case STMFTS_EV_HOVER_LEAVE: + case STMFTS_EV_HOVER_MOTION: + stmfts_report_hover_event(sdata, event); + break; + + case STMFTS_EV_KEY_STATUS: + stmfts_report_key_event(sdata, event); + break; + + case STMFTS_EV_ERROR: + dev_warn(&sdata->client->dev, + "error code: 0x%x%x%x%x%x%x", + event[6], event[5], event[4], + event[3], event[2], event[1]); + break; + + default: + dev_err(&sdata->client->dev, + "unknown event %#02x\n", event[0]); + } + } +} + +static irqreturn_t stmfts_irq_handler(int irq, void *dev) +{ + struct stmfts_data *sdata = dev; + int err; + + mutex_lock(&sdata->mutex); + + err = stmfts_read_events(sdata); + if (unlikely(err)) + dev_err(&sdata->client->dev, + "failed to read events: %d\n", err); + else + stmfts_parse_events(sdata); + + mutex_unlock(&sdata->mutex); + return IRQ_HANDLED; +} + +static int stmfts_command(struct stmfts_data *sdata, const u8 cmd) +{ + int err; + + reinit_completion(&sdata->cmd_done); + + err = i2c_smbus_write_byte(sdata->client, cmd); + if (err) + return err; + + if (!wait_for_completion_timeout(&sdata->cmd_done, + msecs_to_jiffies(1000))) + return -ETIMEDOUT; + + return 0; +} + +static int stmfts_input_open(struct input_dev *dev) +{ + struct stmfts_data *sdata = input_get_drvdata(dev); + int err; + + err = pm_runtime_get_sync(&sdata->client->dev); + if (err < 0) + return err; + + err = i2c_smbus_write_byte(sdata->client, STMFTS_MS_MT_SENSE_ON); + if (err) + return err; + + mutex_lock(&sdata->mutex); + sdata->running = true; + + if (sdata->hover_enabled) { + err = i2c_smbus_write_byte(sdata->client, + STMFTS_SS_HOVER_SENSE_ON); + if (err) + dev_warn(&sdata->client->dev, + "failed to enable hover\n"); + } + mutex_unlock(&sdata->mutex); + + if (sdata->use_key) { + err = i2c_smbus_write_byte(sdata->client, + STMFTS_MS_KEY_SENSE_ON); + if (err) + /* I can still use only the touch screen */ + dev_warn(&sdata->client->dev, + "failed to enable touchkey\n"); + } + + return 0; +} + +static void stmfts_input_close(struct input_dev *dev) +{ + struct stmfts_data *sdata = input_get_drvdata(dev); + int err; + + err = i2c_smbus_write_byte(sdata->client, STMFTS_MS_MT_SENSE_OFF); + if (err) + dev_warn(&sdata->client->dev, + "failed to disable touchscreen: %d\n", err); + + mutex_lock(&sdata->mutex); + + sdata->running = false; + + if (sdata->hover_enabled) { + err = i2c_smbus_write_byte(sdata->client, + STMFTS_SS_HOVER_SENSE_OFF); + if (err) + dev_warn(&sdata->client->dev, + "failed to disable hover: %d\n", err); + } + mutex_unlock(&sdata->mutex); + + if (sdata->use_key) { + err = i2c_smbus_write_byte(sdata->client, + STMFTS_MS_KEY_SENSE_OFF); + if (err) + dev_warn(&sdata->client->dev, + "failed to disable touchkey: %d\n", err); + } + + pm_runtime_put_sync(&sdata->client->dev); +} + +static ssize_t stmfts_sysfs_chip_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmfts_data *sdata = dev_get_drvdata(dev); + + return sprintf(buf, "%#x\n", sdata->chip_id); +} + +static ssize_t stmfts_sysfs_chip_version(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmfts_data *sdata = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", sdata->chip_ver); +} + +static ssize_t stmfts_sysfs_fw_ver(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmfts_data *sdata = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", sdata->fw_ver); +} + +static ssize_t stmfts_sysfs_config_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmfts_data *sdata = dev_get_drvdata(dev); + + return sprintf(buf, "%#x\n", sdata->config_id); +} + +static ssize_t stmfts_sysfs_config_version(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmfts_data *sdata = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", sdata->config_ver); +} + +static ssize_t stmfts_sysfs_read_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmfts_data *sdata = dev_get_drvdata(dev); + u8 status[4]; + int err; + + err = i2c_smbus_read_i2c_block_data(sdata->client, STMFTS_READ_STATUS, + sizeof(status), status); + if (err) + return err; + + return sprintf(buf, "%#02x\n", status[0]); +} + +static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmfts_data *sdata = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", sdata->hover_enabled); +} + +static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct stmfts_data *sdata = dev_get_drvdata(dev); + unsigned long value; + int err = 0; + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + mutex_lock(&sdata->mutex); + + if (value & sdata->hover_enabled) + goto out; + + if (sdata->running) + err = i2c_smbus_write_byte(sdata->client, + value ? STMFTS_SS_HOVER_SENSE_ON : + STMFTS_SS_HOVER_SENSE_OFF); + + if (!err) + sdata->hover_enabled = !!value; + +out: + mutex_unlock(&sdata->mutex); + + return len; +} + +static DEVICE_ATTR(chip_id, 0444, stmfts_sysfs_chip_id, NULL); +static DEVICE_ATTR(chip_version, 0444, stmfts_sysfs_chip_version, NULL); +static DEVICE_ATTR(fw_ver, 0444, stmfts_sysfs_fw_ver, NULL); +static DEVICE_ATTR(config_id, 0444, stmfts_sysfs_config_id, NULL); +static DEVICE_ATTR(config_version, 0444, stmfts_sysfs_config_version, NULL); +static DEVICE_ATTR(status, 0444, stmfts_sysfs_read_status, NULL); +static DEVICE_ATTR(hover_enable, 0644, stmfts_sysfs_hover_enable_read, + stmfts_sysfs_hover_enable_write); + +static struct attribute *stmfts_sysfs_attrs[] = { + &dev_attr_chip_id.attr, + &dev_attr_chip_version.attr, + &dev_attr_fw_ver.attr, + &dev_attr_config_id.attr, + &dev_attr_config_version.attr, + &dev_attr_status.attr, + &dev_attr_hover_enable.attr, + NULL +}; + +static struct attribute_group stmfts_attribute_group = { + .attrs = stmfts_sysfs_attrs +}; + +static int stmfts_power_on(struct stmfts_data *sdata) +{ + int err; + u8 reg[8]; + + err = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators), + sdata->regulators); + if (err) + return err; + + /* + * The datasheet does not specify the power on time, but considering + * that the reset time is < 10ms, I sleep 20ms to be sure + */ + msleep(20); + + err = i2c_smbus_read_i2c_block_data(sdata->client, STMFTS_READ_INFO, + sizeof(reg), reg); + if (err < 0) + return err; + if (err != sizeof(reg)) + return -EIO; + + sdata->chip_id = be16_to_cpup((__be16 *)®[6]); + sdata->chip_ver = reg[0]; + sdata->fw_ver = be16_to_cpup((__be16 *)®[2]); + sdata->config_id = reg[4]; + sdata->config_ver = reg[5]; + + enable_irq(sdata->client->irq); + + msleep(50); + + err = stmfts_command(sdata, STMFTS_SYSTEM_RESET); + if (err) + return err; + + err = stmfts_command(sdata, STMFTS_SLEEP_OUT); + if (err) + return err; + + /* optional tuning */ + err = stmfts_command(sdata, STMFTS_MS_CX_TUNING); + if (err) + dev_warn(&sdata->client->dev, + "failed to perform mutual auto tune: %d\n", err); + + /* optional tuning */ + err = stmfts_command(sdata, STMFTS_SS_CX_TUNING); + if (err) + dev_warn(&sdata->client->dev, + "failed to perform self auto tune: %d\n", err); + + err = stmfts_command(sdata, STMFTS_FULL_FORCE_CALIBRATION); + if (err) + return err; + + /* + * At this point no one is using the touchscreen + * and I don't really care about the return value + */ + (void) i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN); + + return 0; +} + +static void stmfts_power_off(void *data) +{ + struct stmfts_data *sdata = data; + + disable_irq(sdata->client->irq); + regulator_bulk_disable(ARRAY_SIZE(sdata->regulators), + sdata->regulators); +} + +/* This function is void because I don't want to prevent using the touch key + * only because the LEDs don't get registered + */ +static int stmfts_enable_led(struct stmfts_data *sdata) +{ + int err; + + /* get the regulator for powering the leds on */ + sdata->ledvdd = devm_regulator_get(&sdata->client->dev, "ledvdd"); + if (IS_ERR(sdata->ledvdd)) + return PTR_ERR(sdata->ledvdd); + + sdata->led_cdev.name = STMFTS_DEV_NAME; + sdata->led_cdev.max_brightness = LED_ON; + sdata->led_cdev.brightness = LED_OFF; + sdata->led_cdev.brightness_set = stmfts_brightness_set; + sdata->led_cdev.brightness_get = stmfts_brightness_get; + + err = devm_led_classdev_register(&sdata->client->dev, &sdata->led_cdev); + if (err) { + devm_regulator_put(sdata->ledvdd); + return err; + } + + return 0; +} + +static int stmfts_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err; + struct stmfts_data *sdata; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) + return -ENODEV; + + sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL); + if (!sdata) + return -ENOMEM; + + i2c_set_clientdata(client, sdata); + + sdata->client = client; + mutex_init(&sdata->mutex); + init_completion(&sdata->cmd_done); + + sdata->regulators[STMFTS_REGULATOR_VDD].supply = "vdd"; + sdata->regulators[STMFTS_REGULATOR_AVDD].supply = "avdd"; + err = devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(sdata->regulators), + sdata->regulators); + if (err) + return err; + + sdata->input = devm_input_allocate_device(&client->dev); + if (!sdata->input) + return -ENOMEM; + + sdata->input->name = STMFTS_DEV_NAME; + sdata->input->id.bustype = BUS_I2C; + sdata->input->open = stmfts_input_open; + sdata->input->close = stmfts_input_close; + + touchscreen_parse_properties(sdata->input, true, &sdata->prop); + + input_set_abs_params(sdata->input, ABS_MT_POSITION_X, 0, + sdata->prop.max_x, 0, 0); + input_set_abs_params(sdata->input, ABS_MT_POSITION_Y, 0, + sdata->prop.max_y, 0, 0); + input_set_abs_params(sdata->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(sdata->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0); + input_set_abs_params(sdata->input, ABS_MT_ORIENTATION, 0, 255, 0, 0); + input_set_abs_params(sdata->input, ABS_MT_PRESSURE, 0, 255, 0, 0); + input_set_abs_params(sdata->input, ABS_DISTANCE, 0, 255, 0, 0); + + sdata->use_key = device_property_read_bool(&client->dev, + "touch-key-connected"); + if (sdata->use_key) { + input_set_capability(sdata->input, EV_KEY, KEY_MENU); + input_set_capability(sdata->input, EV_KEY, KEY_BACK); + } + + err = input_mt_init_slots(sdata->input, + STMFTS_MAX_FINGERS, INPUT_MT_DIRECT); + if (err) + return err; + + input_set_drvdata(sdata->input, sdata); + + err = devm_request_threaded_irq(&client->dev, client->irq, + NULL, stmfts_irq_handler, + IRQF_ONESHOT, + "stmfts_irq", sdata); + if (err) + return err; + + /* stmfts_power_on expects interrupt to be disabled */ + disable_irq(client->irq); + + dev_dbg(&client->dev, "initializing ST-Microelectronics FTS...\n"); + + err = stmfts_power_on(sdata); + if (err) + return err; + + err = devm_add_action_or_reset(&client->dev, stmfts_power_off, sdata); + if (err) + return err; + + err = input_register_device(sdata->input); + if (err) + return err; + + if (sdata->use_key) { + err = stmfts_enable_led(sdata); + if (err) { + /* + * Even if the LEDs have failed to be initialized and + * used in the driver, I can still use the device even + * without LEDs. The ledvdd regulator pointer will be + * used as a flag. + */ + dev_warn(&client->dev, "unable to use touchkey leds\n"); + sdata->ledvdd = NULL; + } + } + + err = sysfs_create_group(&sdata->client->dev.kobj, + &stmfts_attribute_group); + if (err) + return err; + + pm_runtime_enable(&client->dev); + + return 0; +} + +static int stmfts_remove(struct i2c_client *client) +{ + pm_runtime_disable(&client->dev); + sysfs_remove_group(&client->dev.kobj, &stmfts_attribute_group); + + return 0; +} + +static int stmfts_runtime_suspend(struct device *dev) +{ + struct stmfts_data *sdata = dev_get_drvdata(dev); + int ret; + + ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN); + if (ret) + dev_warn(dev, "failed to suspend device: %d\n", ret); + + return ret; +} + +static int stmfts_runtime_resume(struct device *dev) +{ + struct stmfts_data *sdata = dev_get_drvdata(dev); + int ret; + + ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_OUT); + if (ret) + dev_err(dev, "failed to resume device: %d\n", ret); + + return ret; +} + +static int __maybe_unused stmfts_suspend(struct device *dev) +{ + struct stmfts_data *sdata = dev_get_drvdata(dev); + + stmfts_power_off(sdata); + + return 0; +} + +static int __maybe_unused stmfts_resume(struct device *dev) +{ + struct stmfts_data *sdata = dev_get_drvdata(dev); + + return stmfts_power_on(sdata); +} + +static const struct dev_pm_ops stmfts_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(stmfts_suspend, stmfts_resume) + SET_RUNTIME_PM_OPS(stmfts_runtime_suspend, stmfts_runtime_resume, NULL) +}; + +#ifdef CONFIG_OF +static const struct of_device_id stmfts_of_match[] = { + { .compatible = "st,stmfts", }, + { }, +}; +MODULE_DEVICE_TABLE(of, stmfts_of_match); +#endif + +static const struct i2c_device_id stmfts_id[] = { + { "stmfts", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, stmfts_id); + +static struct i2c_driver stmfts_driver = { + .driver = { + .name = STMFTS_DEV_NAME, + .of_match_table = of_match_ptr(stmfts_of_match), + .pm = &stmfts_pm_ops, + }, + .probe = stmfts_probe, + .remove = stmfts_remove, + .id_table = stmfts_id, +}; + +module_i2c_driver(stmfts_driver); + +MODULE_AUTHOR("Andi Shyti "); +MODULE_DESCRIPTION("STMicroelectronics FTS Touch Screen"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-15-g9ac1 From d4c9354b4015aa8d1b032c368682dd20a00f4e1f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Jun 2017 09:54:09 -0700 Subject: Input: stmfts - mark all PM functions as __maybe_unused We get a harmless warning when CONFIG_RUNTIME_PM is disabled: drivers/input/touchscreen/stmfts.c:760:12: error: 'stmfts_runtime_resume' defined but not used [-Werror=unused-function] static int stmfts_runtime_resume(struct device *dev) drivers/input/touchscreen/stmfts.c:748:12: error: 'stmfts_runtime_suspend' defined but not used [-Werror=unused-function] static int stmfts_runtime_suspend(struct device *dev) The regular PM functions are already marked as __maybe_unused, so let's do the same for the runtime-PM as well. Fixes: 78bcac7b2ae1 ("Input: add support for the STMicroelectronics FingerTip touchscreen") Signed-off-by: Arnd Bergmann Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/stmfts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c index 802d0e82d034..157fdb4bb2e8 100644 --- a/drivers/input/touchscreen/stmfts.c +++ b/drivers/input/touchscreen/stmfts.c @@ -745,7 +745,7 @@ static int stmfts_remove(struct i2c_client *client) return 0; } -static int stmfts_runtime_suspend(struct device *dev) +static int __maybe_unused stmfts_runtime_suspend(struct device *dev) { struct stmfts_data *sdata = dev_get_drvdata(dev); int ret; @@ -757,7 +757,7 @@ static int stmfts_runtime_suspend(struct device *dev) return ret; } -static int stmfts_runtime_resume(struct device *dev) +static int __maybe_unused stmfts_runtime_resume(struct device *dev) { struct stmfts_data *sdata = dev_get_drvdata(dev); int ret; -- cgit v1.3-15-g9ac1 From ad2ee015245dfe22743a25d7245b3d6abd33c02e Mon Sep 17 00:00:00 2001 From: Oleksandr Andrushchenko Date: Sun, 28 May 2017 23:52:23 -0700 Subject: Input: xen-kbdfront - use string constants from PV protocol Xen input para-virtual protocol defines string constants used by both back and frontend. Use those instead of explicit strings in the frontend driver. Signed-off-by: Oleksandr Andrushchenko Signed-off-by: Dmitry Torokhov --- drivers/input/misc/xen-kbdfront.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 690148f9940e..eb770613a9bd 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -135,14 +135,17 @@ static int xenkbd_probe(struct xenbus_device *dev, goto error_nomem; /* Set input abs params to match backend screen res */ - abs = xenbus_read_unsigned(dev->otherend, "feature-abs-pointer", 0); - ptr_size[KPARAM_X] = xenbus_read_unsigned(dev->otherend, "width", + abs = xenbus_read_unsigned(dev->otherend, + XENKBD_FIELD_FEAT_ABS_POINTER, 0); + ptr_size[KPARAM_X] = xenbus_read_unsigned(dev->otherend, + XENKBD_FIELD_WIDTH, ptr_size[KPARAM_X]); - ptr_size[KPARAM_Y] = xenbus_read_unsigned(dev->otherend, "height", + ptr_size[KPARAM_Y] = xenbus_read_unsigned(dev->otherend, + XENKBD_FIELD_HEIGHT, ptr_size[KPARAM_Y]); if (abs) { ret = xenbus_write(XBT_NIL, dev->nodename, - "request-abs-pointer", "1"); + XENKBD_FIELD_REQ_ABS_POINTER, "1"); if (ret) { pr_warn("xenkbd: can't request abs-pointer\n"); abs = 0; @@ -271,14 +274,15 @@ static int xenkbd_connect_backend(struct xenbus_device *dev, xenbus_dev_fatal(dev, ret, "starting transaction"); goto error_irqh; } - ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + ret = xenbus_printf(xbt, dev->nodename, XENKBD_FIELD_RING_REF, "%lu", virt_to_gfn(info->page)); if (ret) goto error_xenbus; - ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref); + ret = xenbus_printf(xbt, dev->nodename, XENKBD_FIELD_RING_GREF, + "%u", info->gref); if (ret) goto error_xenbus; - ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + ret = xenbus_printf(xbt, dev->nodename, XENKBD_FIELD_EVT_CHANNEL, "%u", evtchn); if (ret) goto error_xenbus; @@ -353,7 +357,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, } static const struct xenbus_device_id xenkbd_ids[] = { - { "vkbd" }, + { XENKBD_DRIVER_NAME }, { "" } }; @@ -390,4 +394,4 @@ module_exit(xenkbd_cleanup); MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("xen:vkbd"); +MODULE_ALIAS("xen:" XENKBD_DRIVER_NAME); -- cgit v1.3-15-g9ac1 From c225370e01b87d3c4ef40d98295ac0bb1e5a3116 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 18 Jun 2017 15:40:37 -0700 Subject: Input: xpad - sync supported devices with 360Controller 360Controller [0] is an OpenSource driver for Xbox/Xbox360/XboxOne controllers on macOS. It contains a couple device IDs unknown to the Linux driver, so I wrote a small Python script [1] to extract them and feed them into my previous script [2] to compare them with the IDs known to Linux. For most devices, this information is not really needed as xpad is able to automatically detect the type of an unknown Xbox Controller at run-time. I've therefore stripped all the generic/vague entries. I've excluded the Logitech G920, it's handled by a HID driver already. I've also excluded the Scene It! Big Button IR, it's handled by an out-of-tree driver. [3] [0] https://github.com/360Controller/360Controller [1] http://codepad.org/v9GyLKMq [2] http://codepad.org/qh7jclpD [3] https://github.com/micolous/xbox360bb Reviewed-by: Cameron Gutman Signed-off-by: Benjamin Valentin Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 57 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index def96cd2479b..b8d08f2296ff 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -131,8 +131,10 @@ static const struct xpad_device { { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX }, { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX }, { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX }, + { 0x045e, 0x0288, "Microsoft Xbox Controller S v2", 0, XTYPE_XBOX }, { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX }, { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 }, + { 0x045e, 0x028f, "Microsoft X-Box 360 pad v2", 0, XTYPE_XBOX360 }, { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE }, @@ -145,6 +147,7 @@ static const struct xpad_device { { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 }, { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX }, { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX }, + { 0x046d, 0xcaa3, "Logitech DriveFx Racing Wheel", 0, XTYPE_XBOX360 }, { 0x056e, 0x2004, "Elecom JC-U3613M", 0, XTYPE_XBOX360 }, { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX }, { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX }, @@ -158,14 +161,19 @@ static const struct xpad_device { { 0x0738, 0x4718, "Mad Catz Street Fighter IV FightStick SE", 0, XTYPE_XBOX360 }, { 0x0738, 0x4726, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x0738, 0x4736, "Mad Catz MicroCon Gamepad", 0, XTYPE_XBOX360 }, { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0738, 0x4740, "Mad Catz Beat Pad", 0, XTYPE_XBOX360 }, + { 0x0738, 0x4758, "Mad Catz Arcade Game Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0738, 0x4a01, "Mad Catz FightStick TE 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, + { 0x0738, 0x9871, "Mad Catz Portable Drum", 0, XTYPE_XBOX360 }, { 0x0738, 0xb726, "Mad Catz Xbox controller - MW2", 0, XTYPE_XBOX360 }, + { 0x0738, 0xb738, "Mad Catz MVC2TE Stick 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 }, { 0x0738, 0xcb02, "Saitek Cyborg Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, { 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, + { 0x0738, 0xcb29, "Saitek Aviator Stick AV8R02", 0, XTYPE_XBOX360 }, { 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 }, { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX }, @@ -181,30 +189,52 @@ static const struct xpad_device { { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0e6f, 0x0113, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x011f, "Rock Candy Gamepad Wired Controller", 0, XTYPE_XBOX360 }, + { 0x0e6f, 0x0131, "PDP EA Sports Controller", 0, XTYPE_XBOX360 }, + { 0x0e6f, 0x0133, "Xbox 360 Wired Controller", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x0139, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x013a, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0147, "PDP Marvel Xbox One Controller", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x015c, "PDP Xbox One Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, + { 0x0e6f, 0x0161, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0162, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0163, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0164, "PDP Battlefield One", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0165, "PDP Titanfall 2", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, + { 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 }, + { 0x0e6f, 0x0346, "Rock Candy Gamepad for Xbox One 2016", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x0413, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, + { 0x0e6f, 0x0501, "PDP Xbox 360 Controller", 0, XTYPE_XBOX360 }, + { 0x0e6f, 0xf900, "PDP Afterglow AX.1", 0, XTYPE_XBOX360 }, { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX }, { 0x0e8f, 0x3008, "Generic xbox control (dealextreme)", 0, XTYPE_XBOX }, { 0x0f0d, 0x000a, "Hori Co. DOA4 FightStick", 0, XTYPE_XBOX360 }, + { 0x0f0d, 0x000c, "Hori PadEX Turbo", 0, XTYPE_XBOX360 }, { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x0f0d, 0x001b, "Hori Real Arcade Pro VX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x0f0d, 0x0063, "Hori Real Arcade Pro Hayabusa (USA) Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE }, + { 0x0f0d, 0x0078, "Hori Real Arcade Pro V Kai Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX }, + { 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 }, { 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 }, + { 0x12ab, 0x0303, "Mortal Kombat Klassic FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 }, { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, + { 0x1430, 0xf801, "RedOctane Controller", 0, XTYPE_XBOX360 }, { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 }, { 0x1532, 0x0037, "Razer Sabertooth", 0, XTYPE_XBOX360 }, + { 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE }, { 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 }, { 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, @@ -215,22 +245,42 @@ static const struct xpad_device { { 0x1689, 0xfe00, "Razer Sabertooth", 0, XTYPE_XBOX360 }, { 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 }, { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1bad, 0x0130, "Ion Drum Rocker", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf018, "Mad Catz Street Fighter IV SE Fighting Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0xf019, "Mad Catz Brawlstick for Xbox 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0xf021, "Mad Cats Ghost Recon FS GamePad", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf023, "MLG Pro Circuit Controller (Xbox)", 0, XTYPE_XBOX360 }, + { 0x1bad, 0xf025, "Mad Catz Call Of Duty", 0, XTYPE_XBOX360 }, + { 0x1bad, 0xf027, "Mad Catz FPS Pro", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf028, "Street Fighter IV FightPad", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf02e, "Mad Catz Fightpad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0xf038, "Street Fighter IV FightStick TE", 0, XTYPE_XBOX360 }, + { 0x1bad, 0xf039, "Mad Catz MvC2 TE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0xf03a, "Mad Catz SFxT Fightstick Pro", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1bad, 0xf03d, "Street Fighter IV Arcade Stick TE - Chun Li", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1bad, 0xf03e, "Mad Catz MLG FightStick TE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1bad, 0xf03f, "Mad Catz FightStick SoulCaliber", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1bad, 0xf042, "Mad Catz FightStick TES+", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1bad, 0xf080, "Mad Catz FightStick TE2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1bad, 0xf501, "HoriPad EX2 Turbo", 0, XTYPE_XBOX360 }, + { 0x1bad, 0xf502, "Hori Real Arcade Pro.VX SA", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1bad, 0xf503, "Hori Fighting Stick VX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1bad, 0xf504, "Hori Real Arcade Pro. EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1bad, 0xf505, "Hori Fighting Stick EX2B", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1bad, 0xf506, "Hori Real Arcade Pro.EX Premium VLX", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf900, "Harmonix Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 }, + { 0x1bad, 0xf904, "PDP Versus Fighting Pad", 0, XTYPE_XBOX360 }, + { 0x1bad, 0xf906, "MortalKombat FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0xfa01, "MadCatz GamePad", 0, XTYPE_XBOX360 }, + { 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 }, + { 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, + { 0x24c6, 0x530a, "Xbox 360 Pro EX Controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x531a, "PowerA Pro Ex", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5397, "FUS1ON Tournament Controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x541a, "PowerA Xbox One Mini Wired Controller", 0, XTYPE_XBOXONE }, @@ -238,12 +288,18 @@ static const struct xpad_device { { 0x24c6, 0x543a, "PowerA Xbox One wired controller", 0, XTYPE_XBOXONE }, { 0x24c6, 0x5500, "Hori XBOX 360 EX 2 with Turbo", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5501, "Hori Real Arcade Pro VX-SA", 0, XTYPE_XBOX360 }, + { 0x24c6, 0x5502, "Hori Fighting Stick VX Alt", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5503, "Hori Fighting Edge", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5506, "Hori SOULCALIBUR V Stick", 0, XTYPE_XBOX360 }, { 0x24c6, 0x550d, "Hori GEM Xbox controller", 0, XTYPE_XBOX360 }, + { 0x24c6, 0x550e, "Hori Real Arcade Pro V Kai 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x24c6, 0x551a, "PowerA FUSION Pro Controller", 0, XTYPE_XBOXONE }, + { 0x24c6, 0x561a, "PowerA FUSION Controller", 0, XTYPE_XBOXONE }, + { 0x24c6, 0x5b00, "ThrustMaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5b02, "Thrustmaster, Inc. GPX Controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5b03, "Thrustmaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 }, + { 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } }; @@ -338,6 +394,7 @@ static struct usb_device_id xpad_table[] = { XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f X-Box One controllers */ XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */ + XPAD_XBOX360_VENDOR(0x11c9), /* Nacon GC100XF */ XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */ XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */ -- cgit v1.3-15-g9ac1 From be19788c73d382f66dd3fba3c5ccef59cf12a126 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 18 Jun 2017 15:41:20 -0700 Subject: Input: xpad - sync supported devices with XBCD XBCD [0][1] is an OpenSource driver for Xbox controllers on Windows. Later it also started supporting Xbox360 controllers (presumably before the official Windows driver was released). It contains a couple device IDs unknown to the Linux driver, so I extracted those from xbcd.inf and added them to our list. It has a special type for Wheels and I have the feeling they might need some extra handling. They all have 'Wheel' in their name, so that information is available for future improvements. [0] https://www.s-config.com/xbcd-original-xbox-controllers-win10/ [1] http://www.redcl0ud.com/xbcd.html Reviewed-by: Cameron Gutman Signed-off-by: Benjamin Valentin Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index b8d08f2296ff..298a6ba51411 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -126,7 +126,10 @@ static const struct xpad_device { u8 mapping; u8 xtype; } xpad_device[] = { + { 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX }, + { 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, + { 0x044f, 0x0f10, "Thrustmaster Modena GT Wheel", 0, XTYPE_XBOX }, { 0x044f, 0xb326, "Thrustmaster Gamepad GP XID", 0, XTYPE_XBOX360 }, { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX }, { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX }, @@ -147,16 +150,30 @@ static const struct xpad_device { { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 }, { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX }, { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX }, + { 0x046d, 0xca8a, "Logitech Precision Vibration Feedback Wheel", 0, XTYPE_XBOX }, { 0x046d, 0xcaa3, "Logitech DriveFx Racing Wheel", 0, XTYPE_XBOX360 }, { 0x056e, 0x2004, "Elecom JC-U3613M", 0, XTYPE_XBOX360 }, { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX }, { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX }, + { 0x05fe, 0x3030, "Chic Controller", 0, XTYPE_XBOX }, + { 0x05fe, 0x3031, "Chic Controller", 0, XTYPE_XBOX }, + { 0x062a, 0x0020, "Logic3 Xbox GamePad", 0, XTYPE_XBOX }, + { 0x062a, 0x0033, "Competition Pro Steering Wheel", 0, XTYPE_XBOX }, + { 0x06a3, 0x0200, "Saitek Racing Wheel", 0, XTYPE_XBOX }, + { 0x06a3, 0x0201, "Saitek Adrenalin", 0, XTYPE_XBOX }, + { 0x06a3, 0xf51a, "Saitek P3600", 0, XTYPE_XBOX360 }, + { 0x0738, 0x4506, "Mad Catz 4506 Wireless Controller", 0, XTYPE_XBOX }, { 0x0738, 0x4516, "Mad Catz Control Pad", 0, XTYPE_XBOX }, + { 0x0738, 0x4520, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX }, { 0x0738, 0x4522, "Mad Catz LumiCON", 0, XTYPE_XBOX }, { 0x0738, 0x4526, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX }, + { 0x0738, 0x4530, "Mad Catz Universal MC2 Racing Wheel and Pedals", 0, XTYPE_XBOX }, { 0x0738, 0x4536, "Mad Catz MicroCON", 0, XTYPE_XBOX }, { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX }, + { 0x0738, 0x4586, "Mad Catz MicroCon Wireless Controller", 0, XTYPE_XBOX }, + { 0x0738, 0x4588, "Mad Catz Blaster", 0, XTYPE_XBOX }, + { 0x0738, 0x45ff, "Mad Catz Beat Pad (w/ Handle)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x0738, 0x4718, "Mad Catz Street Fighter IV FightStick SE", 0, XTYPE_XBOX360 }, { 0x0738, 0x4726, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 }, @@ -164,6 +181,7 @@ static const struct xpad_device { { 0x0738, 0x4736, "Mad Catz MicroCon Gamepad", 0, XTYPE_XBOX360 }, { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0738, 0x4740, "Mad Catz Beat Pad", 0, XTYPE_XBOX360 }, + { 0x0738, 0x4743, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0738, 0x4758, "Mad Catz Arcade Game Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0738, 0x4a01, "Mad Catz FightStick TE 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, @@ -175,6 +193,9 @@ static const struct xpad_device { { 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, { 0x0738, 0xcb29, "Saitek Aviator Stick AV8R02", 0, XTYPE_XBOX360 }, { 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 }, + { 0x07ff, 0xffff, "Mad Catz GamePad", 0, XTYPE_XBOX360 }, + { 0x0c12, 0x0005, "Intec wireless", 0, XTYPE_XBOX }, + { 0x0c12, 0x8801, "Nyko Xbox Controller", 0, XTYPE_XBOX }, { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX }, { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX }, @@ -182,10 +203,13 @@ static const struct xpad_device { { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX }, { 0x0d2f, 0x0002, "Andamiro Pump It Up pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX }, + { 0x0e4c, 0x1103, "Radica Gamester Reflex", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX }, { 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX }, + { 0x0e4c, 0x3510, "Radica Gamester", 0, XTYPE_XBOX }, { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX }, { 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX }, { 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX }, + { 0x0e6f, 0x0008, "After Glow Pro Controller", 0, XTYPE_XBOX }, { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0e6f, 0x0113, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x011f, "Rock Candy Gamepad Wired Controller", 0, XTYPE_XBOX360 }, @@ -221,6 +245,7 @@ static const struct xpad_device { { 0x0f0d, 0x0063, "Hori Real Arcade Pro Hayabusa (USA) Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE }, { 0x0f0d, 0x0078, "Hori Real Arcade Pro V Kai Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, + { 0x0f30, 0x010b, "Philips Recoil", 0, XTYPE_XBOX }, { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX }, @@ -255,6 +280,8 @@ static const struct xpad_device { { 0x1bad, 0xf027, "Mad Catz FPS Pro", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf028, "Street Fighter IV FightPad", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf02e, "Mad Catz Fightpad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1bad, 0xf030, "Mad Catz Xbox 360 MC2 MicroCon Racing Wheel", 0, XTYPE_XBOX360 }, + { 0x1bad, 0xf036, "Mad Catz MicroCon GamePad Pro", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf038, "Street Fighter IV FightStick TE", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf039, "Mad Catz MvC2 TE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0xf03a, "Mad Catz SFxT Fightstick Pro", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, @@ -300,6 +327,7 @@ static const struct xpad_device { { 0x24c6, 0x5b03, "Thrustmaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 }, { 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, + { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } }; @@ -387,9 +415,11 @@ static struct usb_device_id xpad_table[] = { XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft X-Box One controllers */ XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */ XPAD_XBOX360_VENDOR(0x056e), /* Elecom JC-U3613M */ + XPAD_XBOX360_VENDOR(0x06a3), /* Saitek P3600 */ XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */ { USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */ XPAD_XBOXONE_VENDOR(0x0738), /* Mad Catz FightStick TE 2 */ + XPAD_XBOX360_VENDOR(0x07ff), /* Mad Catz GamePad */ XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */ XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f X-Box One controllers */ XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ -- cgit v1.3-15-g9ac1 From 49aac8204da5f344f52ed9b3eb8736ca7a60c4a8 Mon Sep 17 00:00:00 2001 From: Oleksandr Andrushchenko Date: Thu, 29 Jun 2017 00:20:19 -0700 Subject: Input: xen-kbdfront - add multi-touch support Extend xen_kbdfront to provide multi-touch support to unprivileged domains. Signed-off-by: Oleksandr Andrushchenko [dtor: factor out various sub-protocols - multitouch, single touch, keys] Signed-off-by: Dmitry Torokhov --- drivers/input/misc/xen-kbdfront.c | 219 +++++++++++++++++++++++++++++++------- 1 file changed, 179 insertions(+), 40 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index eb770613a9bd..fa130e7b734c 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -34,11 +35,14 @@ struct xenkbd_info { struct input_dev *kbd; struct input_dev *ptr; + struct input_dev *mtouch; struct xenkbd_page *page; int gref; int irq; struct xenbus_device *xbdev; char phys[32]; + /* current MT slot/contact ID we are injecting events in */ + int mtouch_cur_contact_id; }; enum { KPARAM_X, KPARAM_Y, KPARAM_CNT }; @@ -56,6 +60,112 @@ static void xenkbd_disconnect_backend(struct xenkbd_info *); * to do that. */ +static void xenkbd_handle_motion_event(struct xenkbd_info *info, + struct xenkbd_motion *motion) +{ + input_report_rel(info->ptr, REL_X, motion->rel_x); + input_report_rel(info->ptr, REL_Y, motion->rel_y); + if (motion->rel_z) + input_report_rel(info->ptr, REL_WHEEL, -motion->rel_z); + input_sync(info->ptr); +} + +static void xenkbd_handle_position_event(struct xenkbd_info *info, + struct xenkbd_position *pos) +{ + input_report_abs(info->ptr, ABS_X, pos->abs_x); + input_report_abs(info->ptr, ABS_Y, pos->abs_y); + if (pos->rel_z) + input_report_rel(info->ptr, REL_WHEEL, -pos->rel_z); + input_sync(info->ptr); +} + +static void xenkbd_handle_key_event(struct xenkbd_info *info, + struct xenkbd_key *key) +{ + struct input_dev *dev; + + if (test_bit(key->keycode, info->ptr->keybit)) { + dev = info->ptr; + } else if (test_bit(key->keycode, info->kbd->keybit)) { + dev = info->kbd; + } else { + pr_warn("unhandled keycode 0x%x\n", key->keycode); + return; + } + + input_report_key(dev, key->keycode, key->pressed); + input_sync(dev); +} + +static void xenkbd_handle_mt_event(struct xenkbd_info *info, + struct xenkbd_mtouch *mtouch) +{ + if (unlikely(!info->mtouch)) + return; + + if (mtouch->contact_id != info->mtouch_cur_contact_id) { + info->mtouch_cur_contact_id = mtouch->contact_id; + input_mt_slot(info->mtouch, mtouch->contact_id); + } + + switch (mtouch->event_type) { + case XENKBD_MT_EV_DOWN: + input_mt_report_slot_state(info->mtouch, MT_TOOL_FINGER, true); + /* fall through */ + + case XENKBD_MT_EV_MOTION: + input_report_abs(info->mtouch, ABS_MT_POSITION_X, + mtouch->u.pos.abs_x); + input_report_abs(info->mtouch, ABS_MT_POSITION_Y, + mtouch->u.pos.abs_y); + break; + + case XENKBD_MT_EV_SHAPE: + input_report_abs(info->mtouch, ABS_MT_TOUCH_MAJOR, + mtouch->u.shape.major); + input_report_abs(info->mtouch, ABS_MT_TOUCH_MINOR, + mtouch->u.shape.minor); + break; + + case XENKBD_MT_EV_ORIENT: + input_report_abs(info->mtouch, ABS_MT_ORIENTATION, + mtouch->u.orientation); + break; + + case XENKBD_MT_EV_UP: + input_mt_report_slot_state(info->mtouch, MT_TOOL_FINGER, false); + break; + + case XENKBD_MT_EV_SYN: + input_mt_sync_frame(info->mtouch); + input_sync(info->mtouch); + break; + } +} + +static void xenkbd_handle_event(struct xenkbd_info *info, + union xenkbd_in_event *event) +{ + switch (event->type) { + case XENKBD_TYPE_MOTION: + xenkbd_handle_motion_event(info, &event->motion); + break; + + case XENKBD_TYPE_KEY: + xenkbd_handle_key_event(info, &event->key); + break; + + case XENKBD_TYPE_POS: + xenkbd_handle_position_event(info, &event->pos); + break; + + case XENKBD_TYPE_MTOUCH: + xenkbd_handle_mt_event(info, &event->mtouch); + break; + } +} + static irqreturn_t input_handler(int rq, void *dev_id) { struct xenkbd_info *info = dev_id; @@ -66,44 +176,8 @@ static irqreturn_t input_handler(int rq, void *dev_id) if (prod == page->in_cons) return IRQ_HANDLED; rmb(); /* ensure we see ring contents up to prod */ - for (cons = page->in_cons; cons != prod; cons++) { - union xenkbd_in_event *event; - struct input_dev *dev; - event = &XENKBD_IN_RING_REF(page, cons); - - dev = info->ptr; - switch (event->type) { - case XENKBD_TYPE_MOTION: - input_report_rel(dev, REL_X, event->motion.rel_x); - input_report_rel(dev, REL_Y, event->motion.rel_y); - if (event->motion.rel_z) - input_report_rel(dev, REL_WHEEL, - -event->motion.rel_z); - break; - case XENKBD_TYPE_KEY: - dev = NULL; - if (test_bit(event->key.keycode, info->kbd->keybit)) - dev = info->kbd; - if (test_bit(event->key.keycode, info->ptr->keybit)) - dev = info->ptr; - if (dev) - input_report_key(dev, event->key.keycode, - event->key.pressed); - else - pr_warn("unhandled keycode 0x%x\n", - event->key.keycode); - break; - case XENKBD_TYPE_POS: - input_report_abs(dev, ABS_X, event->pos.abs_x); - input_report_abs(dev, ABS_Y, event->pos.abs_y); - if (event->pos.rel_z) - input_report_rel(dev, REL_WHEEL, - -event->pos.rel_z); - break; - } - if (dev) - input_sync(dev); - } + for (cons = page->in_cons; cons != prod; cons++) + xenkbd_handle_event(info, &XENKBD_IN_RING_REF(page, cons)); mb(); /* ensure we got ring contents */ page->in_cons = cons; notify_remote_via_irq(info->irq); @@ -115,9 +189,9 @@ static int xenkbd_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { int ret, i; - unsigned int abs; + unsigned int abs, touch; struct xenkbd_info *info; - struct input_dev *kbd, *ptr; + struct input_dev *kbd, *ptr, *mtouch; info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) { @@ -152,6 +226,17 @@ static int xenkbd_probe(struct xenbus_device *dev, } } + touch = xenbus_read_unsigned(dev->nodename, + XENKBD_FIELD_FEAT_MTOUCH, 0); + if (touch) { + ret = xenbus_write(XBT_NIL, dev->nodename, + XENKBD_FIELD_REQ_MTOUCH, "1"); + if (ret) { + pr_warn("xenkbd: can't request multi-touch"); + touch = 0; + } + } + /* keyboard */ kbd = input_allocate_device(); if (!kbd) @@ -208,6 +293,58 @@ static int xenkbd_probe(struct xenbus_device *dev, } info->ptr = ptr; + /* multi-touch device */ + if (touch) { + int num_cont, width, height; + + mtouch = input_allocate_device(); + if (!mtouch) + goto error_nomem; + + num_cont = xenbus_read_unsigned(info->xbdev->nodename, + XENKBD_FIELD_MT_NUM_CONTACTS, + 1); + width = xenbus_read_unsigned(info->xbdev->nodename, + XENKBD_FIELD_MT_WIDTH, + XENFB_WIDTH); + height = xenbus_read_unsigned(info->xbdev->nodename, + XENKBD_FIELD_MT_HEIGHT, + XENFB_HEIGHT); + + mtouch->name = "Xen Virtual Multi-touch"; + mtouch->phys = info->phys; + mtouch->id.bustype = BUS_PCI; + mtouch->id.vendor = 0x5853; + mtouch->id.product = 0xfffd; + + input_set_abs_params(mtouch, ABS_MT_TOUCH_MAJOR, + 0, 255, 0, 0); + input_set_abs_params(mtouch, ABS_MT_POSITION_X, + 0, width, 0, 0); + input_set_abs_params(mtouch, ABS_MT_POSITION_Y, + 0, height, 0, 0); + input_set_abs_params(mtouch, ABS_MT_PRESSURE, + 0, 255, 0, 0); + + ret = input_mt_init_slots(mtouch, num_cont, INPUT_MT_DIRECT); + if (ret) { + input_free_device(mtouch); + xenbus_dev_fatal(info->xbdev, ret, + "input_mt_init_slots"); + goto error; + } + + ret = input_register_device(mtouch); + if (ret) { + input_free_device(mtouch); + xenbus_dev_fatal(info->xbdev, ret, + "input_register_device(mtouch)"); + goto error; + } + info->mtouch_cur_contact_id = -1; + info->mtouch = mtouch; + } + ret = xenkbd_connect_backend(dev, info); if (ret < 0) goto error; @@ -240,6 +377,8 @@ static int xenkbd_remove(struct xenbus_device *dev) input_unregister_device(info->kbd); if (info->ptr) input_unregister_device(info->ptr); + if (info->mtouch) + input_unregister_device(info->mtouch); free_page((unsigned long)info->page); kfree(info); return 0; -- cgit v1.3-15-g9ac1 From 0f107573da417c7f5c6d3a0160ebacc3adb019c4 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Sun, 2 Jul 2017 13:38:31 -0700 Subject: Input: gpio_keys - handle the missing key press event in resume phase The GPIO key press event might be missed in the resume phase, if the key had been released before the system had been resumed to the stage that it could capture the press event. So we simulate the wakeup key press event in case the key had been released by the time we got interrupt handler to run. Signed-off-by: Joseph Lo Signed-off-by: Enric Balletbo i Serra Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index da3d362f21b1..a047b9af8369 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -48,6 +48,7 @@ struct gpio_button_data { spinlock_t lock; bool disabled; bool key_pressed; + bool suspended; }; struct gpio_keys_drvdata { @@ -396,8 +397,20 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) BUG_ON(irq != bdata->irq); - if (bdata->button->wakeup) + if (bdata->button->wakeup) { + const struct gpio_keys_button *button = bdata->button; + pm_stay_awake(bdata->input->dev.parent); + if (bdata->suspended && + (button->type == 0 || button->type == EV_KEY)) { + /* + * Simulate wakeup key press in case the key has + * already released by the time we got interrupt + * handler to run. + */ + input_report_key(bdata->input, button->code, 1); + } + } mod_delayed_work(system_wq, &bdata->work, @@ -855,6 +868,7 @@ static int __maybe_unused gpio_keys_suspend(struct device *dev) struct gpio_button_data *bdata = &ddata->data[i]; if (bdata->button->wakeup) enable_irq_wake(bdata->irq); + bdata->suspended = true; } } else { mutex_lock(&input->mutex); @@ -878,6 +892,7 @@ static int __maybe_unused gpio_keys_resume(struct device *dev) struct gpio_button_data *bdata = &ddata->data[i]; if (bdata->button->wakeup) disable_irq_wake(bdata->irq); + bdata->suspended = false; } } else { mutex_lock(&input->mutex); -- cgit v1.3-15-g9ac1 From 340d394a789518018f834ff70f7534fc463d3226 Mon Sep 17 00:00:00 2001 From: Chen Hong Date: Sun, 2 Jul 2017 15:11:10 -0700 Subject: Input: i8042 - fix crash at boot time The driver checks port->exists twice in i8042_interrupt(), first when trying to assign temporary "serio" variable, and second time when deciding whether it should call serio_interrupt(). The value of port->exists may change between the 2 checks, and we may end up calling serio_interrupt() with a NULL pointer: BUG: unable to handle kernel NULL pointer dereference at 0000000000000050 IP: [] _spin_lock_irqsave+0x1f/0x40 PGD 0 Oops: 0002 [#1] SMP last sysfs file: CPU 0 Modules linked in: Pid: 1, comm: swapper Not tainted 2.6.32-358.el6.x86_64 #1 QEMU Standard PC (i440FX + PIIX, 1996) RIP: 0010:[] [] _spin_lock_irqsave+0x1f/0x40 RSP: 0018:ffff880028203cc0 EFLAGS: 00010082 RAX: 0000000000010000 RBX: 0000000000000000 RCX: 0000000000000000 RDX: 0000000000000282 RSI: 0000000000000098 RDI: 0000000000000050 RBP: ffff880028203cc0 R08: ffff88013e79c000 R09: ffff880028203ee0 R10: 0000000000000298 R11: 0000000000000282 R12: 0000000000000050 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000098 FS: 0000000000000000(0000) GS:ffff880028200000(0000) knlGS:0000000000000000 CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b CR2: 0000000000000050 CR3: 0000000001a85000 CR4: 00000000001407f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process swapper (pid: 1, threadinfo ffff88013e79c000, task ffff88013e79b500) Stack: ffff880028203d00 ffffffff813de186 ffffffffffffff02 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000098 ffff880028203d70 ffffffff813e0162 ffff880028203d20 ffffffff8103b8ac Call Trace: [] serio_interrupt+0x36/0xa0 [] i8042_interrupt+0x132/0x3a0 [] ? kvm_clock_read+0x1c/0x20 [] ? kvm_clock_get_cycles+0x9/0x10 [] handle_IRQ_event+0x60/0x170 [] ? kvm_guest_apic_eoi_write+0x44/0x50 [] handle_edge_irq+0xde/0x180 [] handle_irq+0x49/0xa0 [] do_IRQ+0x6c/0xf0 [] ret_from_intr+0x0/0x11 [] ? __do_softirq+0x73/0x1e0 [] ? hrtimer_interrupt+0x14b/0x260 [] ? call_softirq+0x1c/0x30 [] ? do_softirq+0x65/0xa0 [] ? irq_exit+0x85/0x90 [] ? smp_apic_timer_interrupt+0x70/0x9b [] ? apic_timer_interrupt+0x13/0x20 To avoid the issue let's change the second check to test whether serio is NULL or not. Also, let's take i8042_lock in i8042_start() and i8042_stop() instead of trying to be overly smart and using memory barriers. Signed-off-by: Chen Hong [dtor: take lock in i8042_start()/i8042_stop()] Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index c52da651269b..824f4c1c1f31 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -436,8 +436,10 @@ static int i8042_start(struct serio *serio) { struct i8042_port *port = serio->port_data; + spin_lock_irq(&i8042_lock); port->exists = true; - mb(); + spin_unlock_irq(&i8042_lock); + return 0; } @@ -450,16 +452,20 @@ static void i8042_stop(struct serio *serio) { struct i8042_port *port = serio->port_data; + spin_lock_irq(&i8042_lock); port->exists = false; + port->serio = NULL; + spin_unlock_irq(&i8042_lock); /* + * We need to make sure that interrupt handler finishes using + * our serio port before we return from this function. * We synchronize with both AUX and KBD IRQs because there is * a (very unlikely) chance that AUX IRQ is raised for KBD port * and vice versa. */ synchronize_irq(I8042_AUX_IRQ); synchronize_irq(I8042_KBD_IRQ); - port->serio = NULL; } /* @@ -576,7 +582,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) spin_unlock_irqrestore(&i8042_lock, flags); - if (likely(port->exists && !filtered)) + if (likely(serio && !filtered)) serio_interrupt(serio, data, dfl); out: -- cgit v1.3-15-g9ac1