diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2022-12-12 10:47:03 -0800 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2022-12-12 10:47:03 -0800 |
commit | e291c116f60f3c1ca98090f0f8e7c77e658562fb (patch) | |
tree | 2fbe810f2a6f8b29f1cdaefd87b24debbfa0ec07 /drivers/input/touchscreen | |
parent | 8c9a59939deb4bfafdc451100c03d1e848b4169b (diff) | |
parent | c3991107a28a5ad0bd90660ca3bbf8c2c220ea98 (diff) | |
download | linux-stable-e291c116f60f3c1ca98090f0f8e7c77e658562fb.tar.gz linux-stable-e291c116f60f3c1ca98090f0f8e7c77e658562fb.tar.bz2 linux-stable-e291c116f60f3c1ca98090f0f8e7c77e658562fb.zip |
Merge branch 'next' into for-linus
Prepare input updates for 6.2 merge window.
Diffstat (limited to 'drivers/input/touchscreen')
50 files changed, 2111 insertions, 199 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index dc90a3ea51ee..68d99a112e14 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -284,6 +284,22 @@ config TOUCHSCREEN_CYTTSP4_SPI To compile this driver as a module, choose M here: the module will be called cyttsp4_spi. +config TOUCHSCREEN_CYTTSP5 + tristate "Cypress TrueTouch Gen5 Touchscreen Driver" + depends on I2C + select REGMAP_I2C + select CRC_ITU_T + help + Driver for Parade TrueTouch Standard Product Generation 5 + touchscreen controllers. I2C bus interface support only. + + Say Y here if you have a Cypress Gen5 touchscreen. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called cyttsp5. + config TOUCHSCREEN_DA9034 tristate "Touchscreen support for Dialog Semiconductor DA9034" depends on PMIC_DA903X @@ -422,6 +438,18 @@ config TOUCHSCREEN_HYCON_HY46XX To compile this driver as a module, choose M here: the module will be called hycon-hy46xx. +config TOUCHSCREEN_HYNITRON_CSTXXX + tristate "Hynitron touchscreen support" + depends on I2C + help + Say Y here if you have a touchscreen using a Hynitron + touchscreen controller. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called hynitron-cstxxx. + config TOUCHSCREEN_ILI210X tristate "Ilitek ILI210X based touchscreen" depends on I2C @@ -1241,7 +1269,7 @@ config TOUCHSCREEN_STMFTS config TOUCHSCREEN_STMPE tristate "STMicroelectronics STMPE touchscreens" depends on MFD_STMPE - depends on (OF || COMPILE_TEST) + depends on OF help Say Y here if you want support for STMicroelectronics STMPE touchscreen controllers. @@ -1379,4 +1407,16 @@ config TOUCHSCREEN_ZINITIX To compile this driver as a module, choose M here: the module will be called zinitix. +config TOUCHSCREEN_HIMAX_HX83112B + tristate "Himax hx83112b touchscreen driver" + depends on I2C + select REGMAP_I2C + help + Say Y here to enable support for Himax hx83112b touchscreens. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called himax_hx83112b. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 557f84fd2075..4968c370479a 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_CORE) += cyttsp4_core.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_I2C) += cyttsp4_i2c.o cyttsp_i2c_common.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_SPI) += cyttsp4_spi.o +obj-$(CONFIG_TOUCHSCREEN_CYTTSP5) += cyttsp5.o obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o @@ -47,6 +48,7 @@ obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o +obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o obj-$(CONFIG_TOUCHSCREEN_IMAGIS) += imagis.o @@ -116,3 +118,4 @@ obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o obj-$(CONFIG_TOUCHSCREEN_ZINITIX) += zinitix.o +obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX83112B) += himax_hx83112b.o diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index 0f20a1fdcdba..dd8f31737bb8 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -23,8 +23,7 @@ static const struct regmap_config ad7879_i2c_regmap_config = { .max_register = 15, }; -static int ad7879_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ad7879_i2c_probe(struct i2c_client *client) { struct regmap *regmap; @@ -63,7 +62,7 @@ static struct i2c_driver ad7879_i2c_driver = { .pm = &ad7879_pm_ops, .of_match_table = of_match_ptr(ad7879_i2c_dt_ids), }, - .probe = ad7879_i2c_probe, + .probe_new = ad7879_i2c_probe, .id_table = ad7879_id, }; diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index dc6a85362a40..25bcc677e98b 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -87,8 +87,7 @@ static void ar1021_i2c_close(struct input_dev *dev) disable_irq(client->irq); } -static int ar1021_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ar1021_i2c_probe(struct i2c_client *client) { struct ar1021_i2c *ar1021; struct input_dev *input; @@ -182,7 +181,7 @@ static struct i2c_driver ar1021_i2c_driver = { .of_match_table = ar1021_i2c_of_match, }, - .probe = ar1021_i2c_probe, + .probe_new = ar1021_i2c_probe, .id_table = ar1021_i2c_id, }; module_i2c_driver(ar1021_i2c_driver); diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index ccecd1441f0b..39ef2664b852 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -3129,7 +3129,7 @@ static const struct dmi_system_id chromebook_T9_suspend_dmi[] = { { } }; -static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int mxt_probe(struct i2c_client *client) { struct mxt_data *data; int error; @@ -3377,7 +3377,7 @@ static struct i2c_driver mxt_driver = { .acpi_match_table = ACPI_PTR(mxt_acpi_id), .pm = &mxt_pm_ops, }, - .probe = mxt_probe, + .probe_new = mxt_probe, .remove = mxt_remove, .id_table = mxt_id, }; diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index 2deae5a6823a..a4a1d58aeeac 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -482,8 +482,7 @@ static void auo_pixcir_reset(void *data) gpiod_set_value_cansleep(ts->gpio_rst, 1); } -static int auo_pixcir_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int auo_pixcir_probe(struct i2c_client *client) { struct auo_pixcir_ts *ts; struct input_dev *input_dev; @@ -637,7 +636,7 @@ static struct i2c_driver auo_pixcir_driver = { .pm = &auo_pixcir_pm_ops, .of_match_table = of_match_ptr(auo_pixcir_ts_dt_idtable), }, - .probe = auo_pixcir_probe, + .probe_new = auo_pixcir_probe, .id_table = auo_pixcir_idtable, }; diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index 34f422e246ef..5a4dbd39a372 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -404,8 +404,7 @@ static void bu21013_disable_chip(void *_ts) gpiod_set_value(ts->cs_gpiod, 0); } -static int bu21013_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int bu21013_probe(struct i2c_client *client) { struct bu21013_ts *ts; struct input_dev *in_dev; @@ -618,7 +617,7 @@ static struct i2c_driver bu21013_driver = { .name = DRIVER_TP, .pm = &bu21013_dev_pm_ops, }, - .probe = bu21013_probe, + .probe_new = bu21013_probe, .remove = bu21013_remove, .id_table = bu21013_id, }; diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c index 392950aa7856..215f4dc5105d 100644 --- a/drivers/input/touchscreen/bu21029_ts.c +++ b/drivers/input/touchscreen/bu21029_ts.c @@ -331,8 +331,7 @@ static void bu21029_stop_chip(struct input_dev *dev) regulator_disable(bu21029->vdd); } -static int bu21029_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int bu21029_probe(struct i2c_client *client) { struct bu21029_ts_data *bu21029; struct input_dev *in_dev; @@ -475,7 +474,7 @@ static struct i2c_driver bu21029_driver = { .pm = &bu21029_pm_ops, }, .id_table = bu21029_ids, - .probe = bu21029_probe, + .probe_new = bu21029_probe, }; module_i2c_driver(bu21029_driver); diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c index f2fb41fb031e..f6769e4bd4f2 100644 --- a/drivers/input/touchscreen/chipone_icn8318.c +++ b/drivers/input/touchscreen/chipone_icn8318.c @@ -176,8 +176,7 @@ static int icn8318_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(icn8318_pm_ops, icn8318_suspend, icn8318_resume); -static int icn8318_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int icn8318_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct icn8318_data *data; @@ -267,7 +266,7 @@ static struct i2c_driver icn8318_driver = { .pm = &icn8318_pm_ops, .of_match_table = icn8318_of_match, }, - .probe = icn8318_probe, + .probe_new = icn8318_probe, .id_table = icn8318_i2c_id, }; diff --git a/drivers/input/touchscreen/cy8ctma140.c b/drivers/input/touchscreen/cy8ctma140.c index a9be29139cbf..3a91d948b7f6 100644 --- a/drivers/input/touchscreen/cy8ctma140.c +++ b/drivers/input/touchscreen/cy8ctma140.c @@ -198,8 +198,7 @@ static void cy8ctma140_power_off_action(void *d) cy8ctma140_power_down(ts); } -static int cy8ctma140_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cy8ctma140_probe(struct i2c_client *client) { struct cy8ctma140 *ts; struct input_dev *input; @@ -344,7 +343,7 @@ static struct i2c_driver cy8ctma140_driver = { .of_match_table = cy8ctma140_of_match, }, .id_table = cy8ctma140_idtable, - .probe = cy8ctma140_probe, + .probe_new = cy8ctma140_probe, }; module_i2c_driver(cy8ctma140_driver); diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index 495ef156cf43..7c2b7309dbaf 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -168,8 +168,7 @@ static void cy8ctmg110_shut_off(void *_ts) cy8ctmg110_power(ts, false); } -static int cy8ctmg110_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cy8ctmg110_probe(struct i2c_client *client) { struct cy8ctmg110 *ts; struct input_dev *input_dev; @@ -279,7 +278,7 @@ static struct i2c_driver cy8ctmg110_driver = { .pm = &cy8ctmg110_pm, }, .id_table = cy8ctmg110_idtable, - .probe = cy8ctmg110_probe, + .probe_new = cy8ctmg110_probe, }; module_i2c_driver(cy8ctmg110_driver); diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c index 28ae7c15397a..c260bab0c62c 100644 --- a/drivers/input/touchscreen/cyttsp4_i2c.c +++ b/drivers/input/touchscreen/cyttsp4_i2c.c @@ -27,8 +27,7 @@ static const struct cyttsp4_bus_ops cyttsp4_i2c_bus_ops = { .read = cyttsp_i2c_read_block_data, }; -static int cyttsp4_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cyttsp4_i2c_probe(struct i2c_client *client) { struct cyttsp4 *ts; @@ -61,7 +60,7 @@ static struct i2c_driver cyttsp4_i2c_driver = { .name = CYTTSP4_I2C_NAME, .pm = &cyttsp4_pm_ops, }, - .probe = cyttsp4_i2c_probe, + .probe_new = cyttsp4_i2c_probe, .remove = cyttsp4_i2c_remove, .id_table = cyttsp4_i2c_id, }; diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c new file mode 100644 index 000000000000..4a23d6231382 --- /dev/null +++ b/drivers/input/touchscreen/cyttsp5.c @@ -0,0 +1,900 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Parade TrueTouch(TM) Standard Product V5 Module. + * + * Copyright (C) 2015 Parade Technologies + * Copyright (C) 2012-2015 Cypress Semiconductor + * Copyright (C) 2018 Bootlin + * + * Authors: Mylène Josserand <mylene.josserand@bootlin.com> + * Alistair Francis <alistair@alistair23.me> + */ + +#include <linux/crc-itu-t.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/input/mt.h> +#include <linux/input/touchscreen.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <asm/unaligned.h> + +#define CYTTSP5_NAME "cyttsp5" +#define CY_I2C_DATA_SIZE (2 * 256) +#define HID_VERSION 0x0100 +#define CY_MAX_INPUT 512 +#define CYTTSP5_PREALLOCATED_CMD_BUFFER 32 +#define CY_BITS_PER_BTN 1 +#define CY_NUM_BTN_EVENT_ID GENMASK(CY_BITS_PER_BTN, 0) + +#define MAX_AREA 255 +#define HID_OUTPUT_BL_SOP 0x1 +#define HID_OUTPUT_BL_EOP 0x17 +#define HID_OUTPUT_BL_LAUNCH_APP 0x3B +#define HID_OUTPUT_BL_LAUNCH_APP_SIZE 11 +#define HID_OUTPUT_GET_SYSINFO 0x2 +#define HID_OUTPUT_GET_SYSINFO_SIZE 5 +#define HID_OUTPUT_MAX_CMD_SIZE 12 + +#define HID_DESC_REG 0x1 +#define HID_INPUT_REG 0x3 +#define HID_OUTPUT_REG 0x4 + +#define REPORT_ID_TOUCH 0x1 +#define REPORT_ID_BTN 0x3 +#define REPORT_SIZE_5 5 +#define REPORT_SIZE_8 8 +#define REPORT_SIZE_16 16 + +/* Touch reports offsets */ +/* Header offsets */ +#define TOUCH_REPORT_DESC_HDR_CONTACTCOUNT 16 +/* Record offsets */ +#define TOUCH_REPORT_DESC_CONTACTID 8 +#define TOUCH_REPORT_DESC_X 16 +#define TOUCH_REPORT_DESC_Y 32 +#define TOUCH_REPORT_DESC_P 48 +#define TOUCH_REPORT_DESC_MAJ 56 +#define TOUCH_REPORT_DESC_MIN 64 + +/* HID */ +#define HID_TOUCH_REPORT_ID 0x1 +#define HID_BTN_REPORT_ID 0x3 +#define HID_APP_RESPONSE_REPORT_ID 0x1F +#define HID_APP_OUTPUT_REPORT_ID 0x2F +#define HID_BL_RESPONSE_REPORT_ID 0x30 +#define HID_BL_OUTPUT_REPORT_ID 0x40 + +#define HID_OUTPUT_RESPONSE_REPORT_OFFSET 2 +#define HID_OUTPUT_RESPONSE_CMD_OFFSET 4 +#define HID_OUTPUT_RESPONSE_CMD_MASK GENMASK(6, 0) + +#define HID_SYSINFO_SENSING_OFFSET 33 +#define HID_SYSINFO_BTN_OFFSET 48 +#define HID_SYSINFO_BTN_MASK GENMASK(7, 0) +#define HID_SYSINFO_MAX_BTN 8 + +#define CY_HID_OUTPUT_TIMEOUT_MS 200 +#define CY_HID_OUTPUT_GET_SYSINFO_TIMEOUT_MS 3000 +#define CY_HID_GET_HID_DESCRIPTOR_TIMEOUT_MS 4000 + +/* maximum number of concurrent tracks */ +#define TOUCH_REPORT_SIZE 10 +#define TOUCH_INPUT_HEADER_SIZE 7 +#define BTN_REPORT_SIZE 9 +#define BTN_INPUT_HEADER_SIZE 5 + +#define MAX_CY_TCH_T_IDS 32 + +/* All usage pages for Touch Report */ +#define TOUCH_REPORT_USAGE_PG_X 0x00010030 +#define TOUCH_REPORT_USAGE_PG_Y 0x00010031 +#define TOUCH_REPORT_USAGE_PG_P 0x000D0030 +#define TOUCH_REPORT_USAGE_PG_CONTACTID 0x000D0051 +#define TOUCH_REPORT_USAGE_PG_CONTACTCOUNT 0x000D0054 +#define TOUCH_REPORT_USAGE_PG_MAJ 0xFF010062 +#define TOUCH_REPORT_USAGE_PG_MIN 0xFF010063 +#define TOUCH_COL_USAGE_PG 0x000D0022 + +/* System Information interface definitions */ +struct cyttsp5_sensing_conf_data_dev { + u8 electrodes_x; + u8 electrodes_y; + __le16 len_x; + __le16 len_y; + __le16 res_x; + __le16 res_y; + __le16 max_z; + u8 origin_x; + u8 origin_y; + u8 btn; + u8 scan_mode; + u8 max_num_of_tch_per_refresh_cycle; +} __packed; + +struct cyttsp5_sensing_conf_data { + u16 res_x; + u16 res_y; + u16 max_z; + u16 len_x; + u16 len_y; + u8 origin_x; + u8 origin_y; + u8 max_tch; +}; + +enum cyttsp5_tch_abs { /* for ordering within the extracted touch data array */ + CY_TCH_X, /* X */ + CY_TCH_Y, /* Y */ + CY_TCH_P, /* P (Z) */ + CY_TCH_T, /* TOUCH ID */ + CY_TCH_MAJ, /* TOUCH_MAJOR */ + CY_TCH_MIN, /* TOUCH_MINOR */ + CY_TCH_NUM_ABS +}; + +struct cyttsp5_tch_abs_params { + size_t ofs; /* abs byte offset */ + size_t size; /* size in bits */ + size_t min; /* min value */ + size_t max; /* max value */ + size_t bofs; /* bit offset */ +}; + +struct cyttsp5_touch { + int abs[CY_TCH_NUM_ABS]; +}; + +struct cyttsp5_sysinfo { + struct cyttsp5_sensing_conf_data sensing_conf_data; + int num_btns; + struct cyttsp5_tch_abs_params tch_hdr; + struct cyttsp5_tch_abs_params tch_abs[CY_TCH_NUM_ABS]; + u32 key_code[HID_SYSINFO_MAX_BTN]; +}; + +struct cyttsp5_hid_desc { + __le16 hid_desc_len; + u8 packet_id; + u8 reserved_byte; + __le16 bcd_version; + __le16 report_desc_len; + __le16 report_desc_register; + __le16 input_register; + __le16 max_input_len; + __le16 output_register; + __le16 max_output_len; + __le16 command_register; + __le16 data_register; + __le16 vendor_id; + __le16 product_id; + __le16 version_id; + u8 reserved[4]; +} __packed; + +struct cyttsp5 { + struct device *dev; + struct completion cmd_done; + struct cyttsp5_sysinfo sysinfo; + struct cyttsp5_hid_desc hid_desc; + u8 cmd_buf[CYTTSP5_PREALLOCATED_CMD_BUFFER]; + u8 input_buf[CY_MAX_INPUT]; + u8 response_buf[CY_MAX_INPUT]; + struct gpio_desc *reset_gpio; + struct input_dev *input; + char phys[NAME_MAX]; + int num_prv_rec; + struct regmap *regmap; + struct touchscreen_properties prop; + struct regulator *vdd; +}; + +/* + * For what is understood in the datasheet, the register does not + * matter. For consistency, use the Input Register address + * but it does mean anything to the device. The important data + * to send is the I2C address + */ +static int cyttsp5_read(struct cyttsp5 *ts, u8 *buf, u32 max) +{ + int error; + u32 size; + u8 temp[2]; + + /* Read the frame to retrieve the size */ + error = regmap_bulk_read(ts->regmap, HID_INPUT_REG, temp, sizeof(temp)); + if (error) + return error; + + size = get_unaligned_le16(temp); + if (!size || size == 2) + return 0; + + if (size > max) + return -EINVAL; + + /* Get the real value */ + return regmap_bulk_read(ts->regmap, HID_INPUT_REG, buf, size); +} + +static int cyttsp5_write(struct cyttsp5 *ts, unsigned int reg, u8 *data, + size_t size) +{ + u8 cmd[HID_OUTPUT_MAX_CMD_SIZE]; + + if (size + 1 > HID_OUTPUT_MAX_CMD_SIZE) + return -E2BIG; + + /* High bytes of register address needed as first byte of cmd */ + cmd[0] = (reg >> 8) & 0xFF; + + /* Copy the rest of the data */ + if (data) + memcpy(&cmd[1], data, size); + + /* + * The hardware wants to receive a frame with the address register + * contained in the first two bytes. As the regmap_write function + * add the register adresse in the frame, we use the low byte as + * first frame byte for the address register and the first + * data byte is the high register + left of the cmd to send + */ + return regmap_bulk_write(ts->regmap, reg & 0xFF, cmd, size + 1); +} + +static void cyttsp5_get_touch_axis(int *axis, int size, int max, u8 *xy_data, + int bofs) +{ + int nbyte; + + for (nbyte = 0, *axis = 0; nbyte < size; nbyte++) + *axis += ((xy_data[nbyte] >> bofs) << (nbyte * 8)); + + *axis &= max - 1; +} + +static void cyttsp5_get_touch_record(struct cyttsp5 *ts, + struct cyttsp5_touch *touch, u8 *xy_data) +{ + struct cyttsp5_sysinfo *si = &ts->sysinfo; + enum cyttsp5_tch_abs abs; + + for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) + cyttsp5_get_touch_axis(&touch->abs[abs], + si->tch_abs[abs].size, + si->tch_abs[abs].max, + xy_data + si->tch_abs[abs].ofs, + si->tch_abs[abs].bofs); +} + +static void cyttsp5_get_mt_touches(struct cyttsp5 *ts, + struct cyttsp5_touch *tch, int num_cur_tch) +{ + struct cyttsp5_sysinfo *si = &ts->sysinfo; + int i, t = 0, offset = 0; + DECLARE_BITMAP(ids, MAX_CY_TCH_T_IDS); + u8 *tch_addr; + int tmp; + + bitmap_zero(ids, MAX_CY_TCH_T_IDS); + memset(tch->abs, 0, sizeof(tch->abs)); + + switch (ts->input_buf[2]) { + case HID_TOUCH_REPORT_ID: + offset = TOUCH_INPUT_HEADER_SIZE; + break; + case HID_BTN_REPORT_ID: + offset = BTN_INPUT_HEADER_SIZE; + break; + } + + for (i = 0; i < num_cur_tch; i++) { + tch_addr = ts->input_buf + offset + (i * TOUCH_REPORT_SIZE); + cyttsp5_get_touch_record(ts, tch, tch_addr); + + /* Convert MAJOR/MINOR from mm to resolution */ + tmp = tch->abs[CY_TCH_MAJ] * 100 * si->sensing_conf_data.res_x; + tch->abs[CY_TCH_MAJ] = tmp / si->sensing_conf_data.len_x; + tmp = tch->abs[CY_TCH_MIN] * 100 * si->sensing_conf_data.res_x; + tch->abs[CY_TCH_MIN] = tmp / si->sensing_conf_data.len_x; + + t = tch->abs[CY_TCH_T]; + input_mt_slot(ts->input, t); + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true); + __set_bit(t, ids); + + /* position and pressure fields */ + touchscreen_report_pos(ts->input, &ts->prop, + tch->abs[CY_TCH_X], tch->abs[CY_TCH_Y], + true); + input_report_abs(ts->input, ABS_MT_PRESSURE, + tch->abs[CY_TCH_P]); + + /* Get the extended touch fields */ + input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, + tch->abs[CY_TCH_MAJ]); + input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, + tch->abs[CY_TCH_MIN]); + } + + ts->num_prv_rec = num_cur_tch; +} + +static int cyttsp5_mt_attention(struct device *dev) +{ + struct cyttsp5 *ts = dev_get_drvdata(dev); + struct cyttsp5_sysinfo *si = &ts->sysinfo; + int max_tch = si->sensing_conf_data.max_tch; + struct cyttsp5_touch tch; + int num_cur_tch; + + cyttsp5_get_touch_axis(&num_cur_tch, si->tch_hdr.size, + si->tch_hdr.max, + ts->input_buf + 3 + si->tch_hdr.ofs, + si->tch_hdr.bofs); + + if (num_cur_tch > max_tch) { + dev_err(dev, "Num touch err detected (n=%d)\n", num_cur_tch); + num_cur_tch = max_tch; + } + + if (num_cur_tch == 0 && ts->num_prv_rec == 0) + return 0; + + /* extract xy_data for all currently reported touches */ + if (num_cur_tch) + cyttsp5_get_mt_touches(ts, &tch, num_cur_tch); + + input_mt_sync_frame(ts->input); + input_sync(ts->input); + + return 0; +} + +static int cyttsp5_setup_input_device(struct device *dev) +{ + struct cyttsp5 *ts = dev_get_drvdata(dev); + struct cyttsp5_sysinfo *si = &ts->sysinfo; + int max_x, max_y, max_p; + int max_x_tmp, max_y_tmp; + int error; + + max_x_tmp = si->sensing_conf_data.res_x; + max_y_tmp = si->sensing_conf_data.res_y; + max_x = max_x_tmp - 1; + max_y = max_y_tmp - 1; + max_p = si->sensing_conf_data.max_z; + + input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, max_x, 0, 0); + input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, max_y, 0, 0); + input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, max_p, 0, 0); + + input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, MAX_AREA, 0, 0); + input_set_abs_params(ts->input, ABS_MT_TOUCH_MINOR, 0, MAX_AREA, 0, 0); + + error = input_mt_init_slots(ts->input, si->tch_abs[CY_TCH_T].max, + INPUT_MT_DROP_UNUSED | INPUT_MT_DIRECT); + if (error) + return error; + + error = input_register_device(ts->input); + if (error) { + dev_err(dev, "failed to register input device: %d\n", error); + return error; + } + + return error; +} + +static int cyttsp5_parse_dt_key_code(struct device *dev) +{ + struct cyttsp5 *ts = dev_get_drvdata(dev); + struct cyttsp5_sysinfo *si = &ts->sysinfo; + + if (!si->num_btns) + return 0; + + /* Initialize the button to RESERVED */ + memset32(si->key_code, KEY_RESERVED, si->num_btns); + + return device_property_read_u32_array(dev, "linux,keycodes", + si->key_code, si->num_btns); +} + +static int cyttsp5_btn_attention(struct device *dev) +{ + struct cyttsp5 *ts = dev_get_drvdata(dev); + struct cyttsp5_sysinfo *si = &ts->sysinfo; + int cur_btn, offset = 0; + int cur_btn_state; + + switch (ts->input_buf[2]) { + case HID_TOUCH_REPORT_ID: + offset = TOUCH_INPUT_HEADER_SIZE; + break; + case HID_BTN_REPORT_ID: + offset = BTN_INPUT_HEADER_SIZE; + break; + } + + if (ts->input_buf[2] != HID_BTN_REPORT_ID) + return 0; + + /* extract button press/release touch information */ + for (cur_btn = 0; cur_btn < si->num_btns; cur_btn++) { + /* Get current button state */ + cur_btn_state = (ts->input_buf[offset] >> (cur_btn * CY_BITS_PER_BTN)) + & CY_NUM_BTN_EVENT_ID; + + input_report_key(ts->input, si->key_code[cur_btn], + cur_btn_state); + input_sync(ts->input); + } + + return 0; +} + +static int cyttsp5_validate_cmd_response(struct cyttsp5 *ts, u8 code) +{ + u16 size, crc; + u8 status, report_id; + int command_code; + + size = get_unaligned_le16(&ts->response_buf[0]); + if (!size) + return 0; + + report_id = ts->response_buf[HID_OUTPUT_RESPONSE_REPORT_OFFSET]; + + switch (report_id) { + case HID_BL_RESPONSE_REPORT_ID: + if (ts->response_buf[4] != HID_OUTPUT_BL_SOP) { + dev_err(ts->dev, "HID output response, wrong SOP\n"); + return -EPROTO; + } + + if (ts->response_buf[size - 1] != HID_OUTPUT_BL_EOP) { + dev_err(ts->dev, "HID output response, wrong EOP\n"); + return -EPROTO; + } + + crc = crc_itu_t(0xFFFF, &ts->response_buf[4], size - 7); + if (get_unaligned_le16(&ts->response_buf[size - 3]) != crc) { + dev_err(ts->dev, + "HID output response, wrong CRC 0x%X\n", + crc); + return -EPROTO; + } + + status = ts->response_buf[5]; + if (status) { + dev_err(ts->dev, "HID output response, ERROR:%d\n", + status); + return -EPROTO; + } + break; + + case HID_APP_RESPONSE_REPORT_ID: + command_code = ts->response_buf[HID_OUTPUT_RESPONSE_CMD_OFFSET] + & HID_OUTPUT_RESPONSE_CMD_MASK; + if (command_code != code) { + dev_err(ts->dev, + "HID output response, wrong command_code:%X\n", + command_code); + return -EPROTO; + } + break; + } + + return 0; +} + +static void cyttsp5_si_get_btn_data(struct cyttsp5 *ts) +{ + struct cyttsp5_sysinfo *si = &ts->sysinfo; + unsigned int btns = ts->response_buf[HID_SYSINFO_BTN_OFFSET] & + HID_SYSINFO_BTN_MASK; + + si->num_btns = hweight8(btns); +} + +static int cyttsp5_get_sysinfo_regs(struct cyttsp5 *ts) +{ + struct cyttsp5_sensing_conf_data *scd = &ts->sysinfo.sensing_conf_data; + struct cyttsp5_sensing_conf_data_dev *scd_dev = + (struct cyttsp5_sensing_conf_data_dev *) + &ts->response_buf[HID_SYSINFO_SENSING_OFFSET]; + + cyttsp5_si_get_btn_data(ts); + + scd->max_tch = scd_dev->max_num_of_tch_per_refresh_cycle; + scd->res_x = get_unaligned_le16(&scd_dev->res_x); + scd->res_y = get_unaligned_le16(&scd_dev->res_y); + scd->max_z = get_unaligned_le16(&scd_dev->max_z); + scd->len_x = get_unaligned_le16(&scd_dev->len_x); + scd->len_y = get_unaligned_le16(&scd_dev->len_y); + + return 0; +} + +static int cyttsp5_hid_output_get_sysinfo(struct cyttsp5 *ts) +{ + int rc; + u8 cmd[HID_OUTPUT_GET_SYSINFO_SIZE]; + + /* HI bytes of Output register address */ + put_unaligned_le16(HID_OUTPUT_GET_SYSINFO_SIZE, cmd); + cmd[2] = HID_APP_OUTPUT_REPORT_ID; + cmd[3] = 0x0; /* Reserved */ + cmd[4] = HID_OUTPUT_GET_SYSINFO; + + rc = cyttsp5_write(ts, HID_OUTPUT_REG, cmd, + HID_OUTPUT_GET_SYSINFO_SIZE); + if (rc) { + dev_err(ts->dev, "Failed to write command %d", rc); + return rc; + } + + rc = wait_for_completion_interruptible_timeout(&ts->cmd_done, + msecs_to_jiffies(CY_HID_OUTPUT_GET_SYSINFO_TIMEOUT_MS)); + if (rc <= 0) { + dev_err(ts->dev, "HID output cmd execution timed out\n"); + rc = -ETIMEDOUT; + return rc; + } + + rc = cyttsp5_validate_cmd_response(ts, HID_OUTPUT_GET_SYSINFO); + if (rc) { + dev_err(ts->dev, "Validation of the response failed\n"); + return rc; + } + + return cyttsp5_get_sysinfo_regs(ts); +} + +static int cyttsp5_hid_output_bl_launch_app(struct cyttsp5 *ts) +{ + int rc; + u8 cmd[HID_OUTPUT_BL_LAUNCH_APP]; + u16 crc; + + put_unaligned_le16(HID_OUTPUT_BL_LAUNCH_APP_SIZE, cmd); + cmd[2] = HID_BL_OUTPUT_REPORT_ID; + cmd[3] = 0x0; /* Reserved */ + cmd[4] = HID_OUTPUT_BL_SOP; + cmd[5] = HID_OUTPUT_BL_LAUNCH_APP; + put_unaligned_le16(0x00, &cmd[6]); + crc = crc_itu_t(0xFFFF, &cmd[4], 4); + put_unaligned_le16(crc, &cmd[8]); + cmd[10] = HID_OUTPUT_BL_EOP; + + rc = cyttsp5_write(ts, HID_OUTPUT_REG, cmd, + HID_OUTPUT_BL_LAUNCH_APP_SIZE); + if (rc) { + dev_err(ts->dev, "Failed to write command %d", rc); + return rc; + } + + rc = wait_for_completion_interruptible_timeout(&ts->cmd_done, + msecs_to_jiffies(CY_HID_OUTPUT_TIMEOUT_MS)); + if (rc <= 0) { + dev_err(ts->dev, "HID output cmd execution timed out\n"); + rc = -ETIMEDOUT; + return rc; + } + + rc = cyttsp5_validate_cmd_response(ts, HID_OUTPUT_BL_LAUNCH_APP); + if (rc) { + dev_err(ts->dev, "Validation of the response failed\n"); + return rc; + } + + return 0; +} + +static int cyttsp5_get_hid_descriptor(struct cyttsp5 *ts, + struct cyttsp5_hid_desc *desc) +{ + struct device *dev = ts->dev; + __le16 hid_desc_register = cpu_to_le16(HID_DESC_REG); + int rc; + u8 cmd[2]; + + /* Set HID descriptor register */ + memcpy(cmd, &hid_desc_register, sizeof(hid_desc_register)); + + rc = cyttsp5_write(ts, HID_DESC_REG, NULL, 0); + if (rc) { + dev_err(dev, "Failed to get HID descriptor, rc=%d\n", rc); + return rc; + } + + rc = wait_for_completion_interruptible_timeout(&ts->cmd_done, + msecs_to_jiffies(CY_HID_GET_HID_DESCRIPTOR_TIMEOUT_MS)); + if (rc <= 0) { + dev_err(ts->dev, "HID get descriptor timed out\n"); + rc = -ETIMEDOUT; + return rc; + } + + memcpy(desc, ts->response_buf, sizeof(*desc)); + + /* Check HID descriptor length and version */ + if (le16_to_cpu(desc->hid_desc_len) != sizeof(*desc) || + le16_to_cpu(desc->bcd_version) != HID_VERSION) { + dev_err(dev, "Unsupported HID version\n"); + return -ENODEV; + } + + return 0; +} + +static int fill_tch_abs(struct cyttsp5_tch_abs_params *tch_abs, int report_size, + int offset) +{ + tch_abs->ofs = offset / 8; + tch_abs->size = report_size / 8; + if (report_size % 8) + tch_abs->size += 1; + tch_abs->min = 0; + tch_abs->max = 1 << report_size; + tch_abs->bofs = offset - (tch_abs->ofs << 3); + + return 0; +} + +static irqreturn_t cyttsp5_handle_irq(int irq, void *handle) +{ + struct cyttsp5 *ts = handle; + int report_id; + int size; + int error; + + error = cyttsp5_read(ts, ts->input_buf, CY_MAX_INPUT); + if (error) + return IRQ_HANDLED; + + size = get_unaligned_le16(&ts->input_buf[0]); + if (size == 0) { + /* reset */ + report_id = 0; + size = 2; + } else { + report_id = ts->input_buf[2]; + } + + switch (report_id) { + case HID_TOUCH_REPORT_ID: + cyttsp5_mt_attention(ts->dev); + break; + case HID_BTN_REPORT_ID: + cyttsp5_btn_attention(ts->dev); + break; + default: + /* It is not an input but a command response */ + memcpy(ts->response_buf, ts->input_buf, size); + complete(&ts->cmd_done); + } + + return IRQ_HANDLED; +} + +static int cyttsp5_deassert_int(struct cyttsp5 *ts) +{ + u16 size; + u8 buf[2]; + int error; + + error = regmap_bulk_read(ts->regmap, HID_INPUT_REG, buf, sizeof(buf)); + if (error < 0) + return error; + + size = get_unaligned_le16(&buf[0]); + if (size == 2 || size == 0) + return 0; + + return -EINVAL; +} + +static int cyttsp5_fill_all_touch(struct cyttsp5 *ts) +{ + struct cyttsp5_sysinfo *si = &ts->sysinfo; + + fill_tch_abs(&si->tch_abs[CY_TCH_X], REPORT_SIZE_16, + TOUCH_REPORT_DESC_X); + fill_tch_abs(&si->tch_abs[CY_TCH_Y], REPORT_SIZE_16, + TOUCH_REPORT_DESC_Y); + fill_tch_abs(&si->tch_abs[CY_TCH_P], REPORT_SIZE_8, + TOUCH_REPORT_DESC_P); + fill_tch_abs(&si->tch_abs[CY_TCH_T], REPORT_SIZE_5, + TOUCH_REPORT_DESC_CONTACTID); + fill_tch_abs(&si->tch_hdr, REPORT_SIZE_5, + TOUCH_REPORT_DESC_HDR_CONTACTCOUNT); + fill_tch_abs(&si->tch_abs[CY_TCH_MAJ], REPORT_SIZE_8, + TOUCH_REPORT_DESC_MAJ); + fill_tch_abs(&si->tch_abs[CY_TCH_MIN], REPORT_SIZE_8, + TOUCH_REPORT_DESC_MIN); + + return 0; +} + +static int cyttsp5_startup(struct cyttsp5 *ts) +{ + int error; + + error = cyttsp5_deassert_int(ts); + if (error) { + dev_err(ts->dev, "Error on deassert int r=%d\n", error); + return -ENODEV; + } + + /* + * Launch the application as the device starts in bootloader mode + * because of a power-on-reset + */ + error = cyttsp5_hid_output_bl_launch_app(ts); + if (error < 0) { + dev_err(ts->dev, "Error on launch app r=%d\n", error); + return error; + } + + error = cyttsp5_get_hid_descriptor(ts, &ts->hid_desc); + if (error < 0) { + dev_err(ts->dev, "Error on getting HID descriptor r=%d\n", error); + return error; + } + + error = cyttsp5_fill_all_touch(ts); + if (error < 0) { + dev_err(ts->dev, "Error on report descriptor r=%d\n", error); + return error; + } + + error = cyttsp5_hid_output_get_sysinfo(ts); + if (error) { + dev_err(ts->dev, "Error on getting sysinfo r=%d\n", error); + return error; + } + + return error; +} + +static void cyttsp5_cleanup(void *data) +{ + struct cyttsp5 *ts = data; + + regulator_disable(ts->vdd); +} + +static int cyttsp5_probe(struct device *dev, struct regmap *regmap, int irq, + const char *name) +{ + struct cyttsp5 *ts; + struct cyttsp5_sysinfo *si; + int error, i; + + ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + /* Initialize device info */ + ts->regmap = regmap; + ts->dev = dev; + si = &ts->sysinfo; + dev_set_drvdata(dev, ts); + + init_completion(&ts->cmd_done); + + /* Power up the device */ + ts->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(ts->vdd)) { + error = PTR_ERR(ts->vdd); + return error; + } + + error = devm_add_action_or_reset(dev, cyttsp5_cleanup, ts); + if (error) + return error; + + error = regulator_enable(ts->vdd); + if (error) + return error; + + ts->input = devm_input_allocate_device(dev); + if (!ts->input) { + dev_err(dev, "Error, failed to allocate input device\n"); + return -ENODEV; + } + + ts->input->name = "cyttsp5"; + scnprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev)); + ts->input->phys = ts->phys; + input_set_drvdata(ts->input, ts); + + /* Reset the gpio to be in a reset state */ + ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ts->reset_gpio)) { + error = PTR_ERR(ts->reset_gpio); + dev_err(dev, "Failed to request reset gpio, error %d\n", error); + return error; + } + gpiod_set_value_cansleep(ts->reset_gpio, 0); + + /* Need a delay to have device up */ + msleep(20); + + error = devm_request_threaded_irq(dev, irq, NULL, cyttsp5_handle_irq, + IRQF_ONESHOT, name, ts); + if (error) { + dev_err(dev, "unable to request IRQ\n"); + return error; + } + + error = cyttsp5_startup(ts); + if (error) { + dev_err(ts->dev, "Fail initial startup r=%d\n", error); + return error; + } + + error = cyttsp5_parse_dt_key_code(dev); + if (error < 0) { + dev_err(ts->dev, "Error while parsing dts %d\n", error); + return error; + } + + touchscreen_parse_properties(ts->input, true, &ts->prop); + + __set_bit(EV_KEY, ts->input->evbit); + for (i = 0; i < si->num_btns; i++) + __set_bit(si->key_code[i], ts->input->keybit); + + return cyttsp5_setup_input_device(dev); +} + +static int cyttsp5_i2c_probe(struct i2c_client *client) +{ + struct regmap *regmap; + static const struct regmap_config config = { + .reg_bits = 8, + .val_bits = 8, + }; + + regmap = devm_regmap_init_i2c(client, &config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "regmap allocation failed: %ld\n", + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return cyttsp5_probe(&client->dev, regmap, client->irq, client->name); +} + +static const struct of_device_id cyttsp5_of_match[] = { + { .compatible = "cypress,tt21000", }, + { } +}; +MODULE_DEVICE_TABLE(of, cyttsp5_of_match); + +static const struct i2c_device_id cyttsp5_i2c_id[] = { + { CYTTSP5_NAME, 0, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id); + +static struct i2c_driver cyttsp5_i2c_driver = { + .driver = { + .name = CYTTSP5_NAME, + .of_match_table = cyttsp5_of_match, + }, + .probe_new = cyttsp5_i2c_probe, + .id_table = cyttsp5_i2c_id, +}; +module_i2c_driver(cyttsp5_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Touchscreen driver for Cypress TrueTouch Gen 5 Product"); +MODULE_AUTHOR("Mylène Josserand <mylene.josserand@bootlin.com>"); diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index 4c8473d327ab..0155a1626adf 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c @@ -28,8 +28,7 @@ static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = { .read = cyttsp_i2c_read_block_data, }; -static int cyttsp_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cyttsp_i2c_probe(struct i2c_client *client) { struct cyttsp *ts; @@ -67,7 +66,7 @@ static struct i2c_driver cyttsp_i2c_driver = { .pm = &cyttsp_pm_ops, .of_match_table = cyttsp_of_i2c_match, }, - .probe = cyttsp_i2c_probe, + .probe_new = cyttsp_i2c_probe, .id_table = cyttsp_i2c_id, }; diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 9ac1378610bc..ddd0f1f62458 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1131,9 +1131,9 @@ static void edt_ft5x06_disable_regulators(void *arg) regulator_disable(data->iovcc); } -static int edt_ft5x06_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int edt_ft5x06_ts_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct edt_i2c_chip_data *chip_data; struct edt_ft5x06_ts_data *tsdata; u8 buf[2] = { 0xfc, 0x00 }; @@ -1504,7 +1504,7 @@ static struct i2c_driver edt_ft5x06_ts_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .id_table = edt_ft5x06_ts_id, - .probe = edt_ft5x06_ts_probe, + .probe_new = edt_ft5x06_ts_probe, .remove = edt_ft5x06_ts_remove, }; diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index a639ba7e56ea..c8ab03f49227 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -158,8 +158,7 @@ static void eeti_ts_close(struct input_dev *dev) eeti_ts_stop(eeti); } -static int eeti_ts_probe(struct i2c_client *client, - const struct i2c_device_id *idp) +static int eeti_ts_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct eeti_ts *eeti; @@ -292,7 +291,7 @@ static struct i2c_driver eeti_ts_driver = { .pm = &eeti_ts_pm, .of_match_table = of_match_ptr(of_eeti_ts_match), }, - .probe = eeti_ts_probe, + .probe_new = eeti_ts_probe, .id_table = eeti_ts_id, }; diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index 83ac8c128192..742d47a75ac1 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -14,17 +14,17 @@ - auto idle mode support */ +#include <linux/err.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/input.h> #include <linux/irq.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/bitops.h> #include <linux/input/mt.h> -#include <linux/of_gpio.h> /* * Mouse Mode: some panel may configure the controller to mouse mode, @@ -119,32 +119,26 @@ static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id) /* wake up controller by an falling edge of interrupt gpio. */ static int egalax_wake_up_device(struct i2c_client *client) { - struct device_node *np = client->dev.of_node; - int gpio; + struct gpio_desc *gpio; int ret; - if (!np) - return -ENODEV; - - gpio = of_get_named_gpio(np, "wakeup-gpios", 0); - if (!gpio_is_valid(gpio)) - return -ENODEV; - - ret = gpio_request(gpio, "egalax_irq"); - if (ret < 0) { - dev_err(&client->dev, - "request gpio failed, cannot wake up controller: %d\n", - ret); + /* wake up controller via an falling edge on IRQ gpio. */ + gpio = gpiod_get(&client->dev, "wakeup", GPIOD_OUT_HIGH); + ret = PTR_ERR_OR_ZERO(gpio); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(&client->dev, + "failed to request wakeup gpio, cannot wake up controller: %d\n", + ret); return ret; } - /* wake up controller via an falling edge on IRQ gpio. */ - gpio_direction_output(gpio, 0); - gpio_set_value(gpio, 1); + /* release the line */ + gpiod_set_value_cansleep(gpio, 0); - /* controller should be waken up, return irq. */ - gpio_direction_input(gpio); - gpio_free(gpio); + /* controller should be woken up, return irq. */ + gpiod_direction_input(gpio); + gpiod_put(gpio); return 0; } @@ -161,8 +155,7 @@ static int egalax_firmware_version(struct i2c_client *client) return 0; } -static int egalax_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int egalax_ts_probe(struct i2c_client *client) { struct egalax_ts *ts; struct input_dev *input_dev; @@ -185,10 +178,8 @@ static int egalax_ts_probe(struct i2c_client *client, /* controller may be in sleep, wake it up. */ error = egalax_wake_up_device(client); - if (error) { - dev_err(&client->dev, "Failed to wake up the controller\n"); + if (error) return error; - } error = egalax_firmware_version(client); if (error < 0) { @@ -211,10 +202,9 @@ static int egalax_ts_probe(struct i2c_client *client, ABS_MT_POSITION_Y, 0, EGALAX_MAX_Y, 0, 0); input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS, 0); - error = devm_request_threaded_irq(&client->dev, client->irq, NULL, - egalax_ts_interrupt, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "egalax_ts", ts); + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, egalax_ts_interrupt, + IRQF_ONESHOT, "egalax_ts", ts); if (error < 0) { dev_err(&client->dev, "Failed to register interrupt\n"); return error; @@ -273,7 +263,7 @@ static struct i2c_driver egalax_ts_driver = { .of_match_table = egalax_ts_dt_ids, }, .id_table = egalax_ts_id, - .probe = egalax_ts_probe, + .probe_new = egalax_ts_probe, }; module_i2c_driver(egalax_ts_driver); diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c index 2d01a8cbfcc6..328841eaa1b7 100644 --- a/drivers/input/touchscreen/ektf2127.c +++ b/drivers/input/touchscreen/ektf2127.c @@ -244,8 +244,7 @@ static int ektf2127_query_dimension(struct i2c_client *client, bool width) return (((buf[3] & 0xf0) << 4) | buf[2]) - 1; } -static int ektf2127_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ektf2127_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ektf2127_ts *ts; @@ -352,7 +351,7 @@ static struct i2c_driver ektf2127_driver = { .pm = &ektf2127_pm_ops, .of_match_table = of_match_ptr(ektf2127_of_match), }, - .probe = ektf2127_probe, + .probe_new = ektf2127_probe, .id_table = ektf2127_i2c_id, }; module_i2c_driver(ektf2127_driver); diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 879a4d984c90..5452b50f8a77 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -36,6 +36,7 @@ #include <linux/input/touchscreen.h> #include <linux/acpi.h> #include <linux/of.h> +#include <linux/pm_wakeirq.h> #include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> #include <linux/uuid.h> @@ -114,7 +115,7 @@ /* calibration timeout definition */ #define ELAN_CALI_TIMEOUT_MSEC 12000 -#define ELAN_POWERON_DELAY_USEC 500 +#define ELAN_POWERON_DELAY_USEC 5000 #define ELAN_RESET_DELAY_MSEC 20 /* FW boot code version */ @@ -180,7 +181,6 @@ struct elants_data { u8 cmd_resp[HEADER_SIZE]; struct completion cmd_done; - bool wake_irq_enabled; bool keep_power_in_suspend; /* Must be last to be used for DMA operations */ @@ -1329,14 +1329,12 @@ static int elants_i2c_power_on(struct elants_data *ts) if (IS_ERR_OR_NULL(ts->reset_gpio)) return 0; - gpiod_set_value_cansleep(ts->reset_gpio, 1); - error = regulator_enable(ts->vcc33); if (error) { dev_err(&ts->client->dev, "failed to enable vcc33 regulator: %d\n", error); - goto release_reset_gpio; + return error; } error = regulator_enable(ts->vccio); @@ -1345,19 +1343,16 @@ static int elants_i2c_power_on(struct elants_data *ts) "failed to enable vccio regulator: %d\n", error); regulator_disable(ts->vcc33); - goto release_reset_gpio; + return error; } /* * We need to wait a bit after powering on controller before * we are allowed to release reset GPIO. */ - udelay(ELAN_POWERON_DELAY_USEC); + usleep_range(ELAN_POWERON_DELAY_USEC, ELAN_POWERON_DELAY_USEC + 100); -release_reset_gpio: gpiod_set_value_cansleep(ts->reset_gpio, 0); - if (error) - return error; msleep(ELAN_RESET_DELAY_MSEC); @@ -1462,7 +1457,7 @@ static int elants_i2c_probe(struct i2c_client *client) return error; } - ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_LOW); + ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ts->reset_gpio)) { error = PTR_ERR(ts->reset_gpio); @@ -1567,13 +1562,6 @@ static int elants_i2c_probe(struct i2c_client *client) return error; } - /* - * Systems using device tree should set up wakeup via DTS, - * the rest will configure device as wakeup source by default. - */ - if (!client->dev.of_node) - device_init_wakeup(&client->dev, true); - error = devm_device_add_group(&client->dev, &elants_attribute_group); if (error) { dev_err(&client->dev, "failed to create sysfs attributes: %d\n", @@ -1605,7 +1593,7 @@ static int __maybe_unused elants_i2c_suspend(struct device *dev) * The device will automatically enter idle mode * that has reduced power consumption. */ - ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); + return 0; } else if (ts->keep_power_in_suspend) { for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { error = elants_i2c_send(client, set_sleep_cmd, @@ -1634,8 +1622,6 @@ static int __maybe_unused elants_i2c_resume(struct device *dev) int error; if (device_may_wakeup(dev)) { - if (ts->wake_irq_enabled) - disable_irq_wake(client->irq); elants_i2c_sw_reset(client); } else if (ts->keep_power_in_suspend) { for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index c281e49826c2..8a0a8078de8f 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -1282,8 +1282,7 @@ static void goodix_disable_regulators(void *arg) regulator_disable(ts->avdd28); } -static int goodix_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int goodix_ts_probe(struct i2c_client *client) { struct goodix_ts_data *ts; const char *cfg_name; @@ -1537,7 +1536,7 @@ MODULE_DEVICE_TABLE(of, goodix_of_match); #endif static struct i2c_driver goodix_ts_driver = { - .probe = goodix_ts_probe, + .probe_new = goodix_ts_probe, .remove = goodix_ts_remove, .id_table = goodix_ts_id, .driver = { diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c index e9547ee29756..ff4bb4c14898 100644 --- a/drivers/input/touchscreen/hideep.c +++ b/drivers/input/touchscreen/hideep.c @@ -997,8 +997,7 @@ static const struct regmap_config hideep_regmap_config = { .max_register = 0xffff, }; -static int hideep_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int hideep_probe(struct i2c_client *client) { struct hideep_ts *ts; int error; @@ -1112,7 +1111,7 @@ static struct i2c_driver hideep_driver = { .pm = &hideep_pm_ops, }, .id_table = hideep_i2c_id, - .probe = hideep_probe, + .probe_new = hideep_probe, }; module_i2c_driver(hideep_driver); diff --git a/drivers/input/touchscreen/himax_hx83112b.c b/drivers/input/touchscreen/himax_hx83112b.c new file mode 100644 index 000000000000..e96150d80a48 --- /dev/null +++ b/drivers/input/touchscreen/himax_hx83112b.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for Himax hx83112b touchscreens + * + * Copyright (C) 2022 Job Noorman <job@noorman.info> + * + * This code is based on "Himax Android Driver Sample Code for QCT platform": + * + * Copyright (C) 2017 Himax Corporation. + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/input/touchscreen.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/regmap.h> + +#define HIMAX_ID_83112B 0x83112b + +#define HIMAX_MAX_POINTS 10 + +#define HIMAX_REG_CFG_SET_ADDR 0x00 +#define HIMAX_REG_CFG_INIT_READ 0x0c +#define HIMAX_REG_CFG_READ_VALUE 0x08 +#define HIMAX_REG_READ_EVENT 0x30 + +#define HIMAX_CFG_PRODUCT_ID 0x900000d0 + +#define HIMAX_INVALID_COORD 0xffff + +struct himax_event_point { + __be16 x; + __be16 y; +} __packed; + +struct himax_event { + struct himax_event_point points[HIMAX_MAX_POINTS]; + u8 majors[HIMAX_MAX_POINTS]; + u8 pad0[2]; + u8 num_points; + u8 pad1[2]; + u8 checksum_fix; +} __packed; + +static_assert(sizeof(struct himax_event) == 56); + +struct himax_ts_data { + struct gpio_desc *gpiod_rst; + struct input_dev *input_dev; + struct i2c_client *client; + struct regmap *regmap; + struct touchscreen_properties props; +}; + +static const struct regmap_config himax_regmap_config = { + .reg_bits = 8, + .val_bits = 32, + .val_format_endian = REGMAP_ENDIAN_LITTLE, +}; + +static int himax_read_config(struct himax_ts_data *ts, u32 address, u32 *dst) +{ + int error; + + error = regmap_write(ts->regmap, HIMAX_REG_CFG_SET_ADDR, address); + if (error) + return error; + + error = regmap_write(ts->regmap, HIMAX_REG_CFG_INIT_READ, 0x0); + if (error) + return error; + + error = regmap_read(ts->regmap, HIMAX_REG_CFG_READ_VALUE, dst); + if (error) + return error; + + return 0; +} + +static void himax_reset(struct himax_ts_data *ts) +{ + gpiod_set_value_cansleep(ts->gpiod_rst, 1); + + /* Delay copied from downstream driver */ + msleep(20); + gpiod_set_value_cansleep(ts->gpiod_rst, 0); + + /* + * The downstream driver doesn't contain this delay but is seems safer + * to include it. The range is just a guess that seems to work well. + */ + usleep_range(1000, 1100); +} + +static int himax_read_product_id(struct himax_ts_data *ts, u32 *product_id) +{ + int error; + + error = himax_read_config(ts, HIMAX_CFG_PRODUCT_ID, product_id); + if (error) + return error; + + *product_id >>= 8; + return 0; +} + +static int himax_check_product_id(struct himax_ts_data *ts) +{ + int error; + u32 product_id; + + error = himax_read_product_id(ts, &product_id); + if (error) + return error; + + dev_dbg(&ts->client->dev, "Product id: %x\n", product_id); + + switch (product_id) { + case HIMAX_ID_83112B: + return 0; + + default: + dev_err(&ts->client->dev, + "Unknown product id: %x\n", product_id); + return -EINVAL; + } +} + +static int himax_input_register(struct himax_ts_data *ts) +{ + int error; + + ts->input_dev = devm_input_allocate_device(&ts->client->dev); + if (!ts->input_dev) { + dev_err(&ts->client->dev, "Failed to allocate input device\n"); + return -ENOMEM; + } + + ts->input_dev->name = "Himax Touchscreen"; + + input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_X); + input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_Y); + input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 200, 0, 0); + + touchscreen_parse_properties(ts->input_dev, true, &ts->props); + + error = input_mt_init_slots(ts->input_dev, HIMAX_MAX_POINTS, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) { + dev_err(&ts->client->dev, + "Failed to initialize MT slots: %d\n", error); + return error; + } + + error = input_register_device(ts->input_dev); + if (error) { + dev_err(&ts->client->dev, + "Failed to register input device: %d\n", error); + return error; + } + + return 0; +} + +static u8 himax_event_get_num_points(const struct himax_event *event) +{ + if (event->num_points == 0xff) + return 0; + else + return event->num_points & 0x0f; +} + +static bool himax_process_event_point(struct himax_ts_data *ts, + const struct himax_event *event, + int point_index) +{ + const struct himax_event_point *point = &event->points[point_index]; + u16 x = be16_to_cpu(point->x); + u16 y = be16_to_cpu(point->y); + u8 w = event->majors[point_index]; + + if (x == HIMAX_INVALID_COORD || y == HIMAX_INVALID_COORD) + return false; + + input_mt_slot(ts->input_dev, point_index); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); + touchscreen_report_pos(ts->input_dev, &ts->props, x, y, true); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); + return true; +} + +static void himax_process_event(struct himax_ts_data *ts, + const struct himax_event *event) +{ + int i; + int num_points_left = himax_event_get_num_points(event); + + for (i = 0; i < HIMAX_MAX_POINTS && num_points_left > 0; i++) { + if (himax_process_event_point(ts, event, i)) + num_points_left--; + } + + input_mt_sync_frame(ts->input_dev); + input_sync(ts->input_dev); +} + +static bool himax_verify_checksum(struct himax_ts_data *ts, + const struct himax_event *event) +{ + u8 *data = (u8 *)event; + int i; + u16 checksum = 0; + + for (i = 0; i < sizeof(*event); i++) + checksum += data[i]; + + if ((checksum & 0x00ff) != 0) { + dev_err(&ts->client->dev, "Wrong event checksum: %04x\n", + checksum); + return false; + } + + return true; +} + +static int himax_handle_input(struct himax_ts_data *ts) +{ + int error; + struct himax_event event; + + error = regmap_raw_read(ts->regmap, HIMAX_REG_READ_EVENT, &event, + sizeof(event)); + if (error) { + dev_err(&ts->client->dev, "Failed to read input event: %d\n", + error); + return error; + } + + /* + * Only process the current event when it has a valid checksum but + * don't consider it a fatal error when it doesn't. + */ + if (himax_verify_checksum(ts, &event)) + himax_process_event(ts, &event); + + return 0; +} + +static irqreturn_t himax_irq_handler(int irq, void *dev_id) +{ + int error; + struct himax_ts_data *ts = dev_id; + + error = himax_handle_input(ts); + if (error) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +static int himax_probe(struct i2c_client *client) +{ + int error; + struct device *dev = &client->dev; + struct himax_ts_data *ts; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(dev, "I2C check functionality failed\n"); + return -ENXIO; + } + + ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + i2c_set_clientdata(client, ts); + ts->client = client; + + ts->regmap = devm_regmap_init_i2c(client, &himax_regmap_config); + error = PTR_ERR_OR_ZERO(ts->regmap); + if (error) { + dev_err(dev, "Failed to initialize regmap: %d\n", error); + return error; + } + + ts->gpiod_rst = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + error = PTR_ERR_OR_ZERO(ts->gpiod_rst); + if (error) { + dev_err(dev, "Failed to get reset GPIO: %d\n", error); + return error; + } + + himax_reset(ts); + + error = himax_check_product_id(ts); + if (error) + return error; + + error = himax_input_register(ts); + if (error) + return error; + + error = devm_request_threaded_irq(dev, client->irq, NULL, + himax_irq_handler, IRQF_ONESHOT, + client->name, ts); + if (error) + return error; + + return 0; +} + +static int himax_suspend(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + disable_irq(ts->client->irq); + return 0; +} + +static int himax_resume(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + enable_irq(ts->client->irq); + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(himax_pm_ops, himax_suspend, himax_resume); + +static const struct i2c_device_id himax_ts_id[] = { + { "hx83112b", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, himax_ts_id); + +#ifdef CONFIG_OF +static const struct of_device_id himax_of_match[] = { + { .compatible = "himax,hx83112b" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, himax_of_match); +#endif + +static struct i2c_driver himax_ts_driver = { + .probe_new = himax_probe, + .id_table = himax_ts_id, + .driver = { + .name = "Himax-hx83112b-TS", + .of_match_table = of_match_ptr(himax_of_match), + .pm = pm_sleep_ptr(&himax_pm_ops), + }, +}; +module_i2c_driver(himax_ts_driver); + +MODULE_AUTHOR("Job Noorman <job@noorman.info>"); +MODULE_DESCRIPTION("Himax hx83112b touchscreen driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/hycon-hy46xx.c b/drivers/input/touchscreen/hycon-hy46xx.c index 891d0430083e..8f4989aba9a4 100644 --- a/drivers/input/touchscreen/hycon-hy46xx.c +++ b/drivers/input/touchscreen/hycon-hy46xx.c @@ -439,8 +439,7 @@ static void hycon_hy46xx_disable_regulator(void *arg) regulator_disable(data->vcc); } -static int hycon_hy46xx_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int hycon_hy46xx_probe(struct i2c_client *client) { struct hycon_hy46xx_data *tsdata; struct input_dev *input; @@ -581,7 +580,7 @@ static struct i2c_driver hycon_hy46xx_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .id_table = hycon_hy46xx_id, - .probe = hycon_hy46xx_probe, + .probe_new = hycon_hy46xx_probe, }; module_i2c_driver(hycon_hy46xx_driver); diff --git a/drivers/input/touchscreen/hynitron_cstxxx.c b/drivers/input/touchscreen/hynitron_cstxxx.c new file mode 100644 index 000000000000..e86c85addb38 --- /dev/null +++ b/drivers/input/touchscreen/hynitron_cstxxx.c @@ -0,0 +1,498 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for Hynitron cstxxx Touchscreen + * + * Copyright (c) 2022 Chris Morgan <macromorgan@hotmail.com> + * + * This code is based on hynitron_core.c authored by Hynitron. + * Note that no datasheet was available, so much of these registers + * are undocumented. This is essentially a cleaned-up version of the + * vendor driver with support removed for hardware I cannot test and + * device-specific functions replated with generic functions wherever + * possible. + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/input/touchscreen.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/property.h> +#include <asm/unaligned.h> + +/* Per chip data */ +struct hynitron_ts_chip_data { + unsigned int max_touch_num; + u32 ic_chkcode; + int (*firmware_info)(struct i2c_client *client); + int (*bootloader_enter)(struct i2c_client *client); + int (*init_input)(struct i2c_client *client); + void (*report_touch)(struct i2c_client *client); +}; + +/* Data generic to all (supported and non-supported) controllers. */ +struct hynitron_ts_data { + const struct hynitron_ts_chip_data *chip; + struct i2c_client *client; + struct input_dev *input_dev; + struct touchscreen_properties prop; + struct gpio_desc *reset_gpio; +}; + +/* + * Since I have no datasheet, these values are guessed and/or assumed + * based on observation and testing. + */ +#define CST3XX_FIRMWARE_INFO_START_CMD 0x01d1 +#define CST3XX_FIRMWARE_INFO_END_CMD 0x09d1 +#define CST3XX_FIRMWARE_CHK_CODE_REG 0xfcd1 +#define CST3XX_FIRMWARE_VERSION_REG 0x08d2 +#define CST3XX_FIRMWARE_VER_INVALID_VAL 0xa5a5a5a5 + +#define CST3XX_BOOTLDR_PROG_CMD 0xaa01a0 +#define CST3XX_BOOTLDR_PROG_CHK_REG 0x02a0 +#define CST3XX_BOOTLDR_CHK_VAL 0xac + +#define CST3XX_TOUCH_DATA_PART_REG 0x00d0 +#define CST3XX_TOUCH_DATA_FULL_REG 0x07d0 +#define CST3XX_TOUCH_DATA_CHK_VAL 0xab +#define CST3XX_TOUCH_DATA_TOUCH_VAL 0x03 +#define CST3XX_TOUCH_DATA_STOP_CMD 0xab00d0 +#define CST3XX_TOUCH_COUNT_MASK GENMASK(6, 0) + + +/* + * Hard coded reset delay value of 20ms not IC dependent in + * vendor driver. + */ +static void hyn_reset_proc(struct i2c_client *client, int delay) +{ + struct hynitron_ts_data *ts_data = i2c_get_clientdata(client); + + gpiod_set_value_cansleep(ts_data->reset_gpio, 1); + msleep(20); + gpiod_set_value_cansleep(ts_data->reset_gpio, 0); + if (delay) + fsleep(delay * 1000); +} + +static irqreturn_t hyn_interrupt_handler(int irq, void *dev_id) +{ + struct i2c_client *client = dev_id; + struct hynitron_ts_data *ts_data = i2c_get_clientdata(client); + + ts_data->chip->report_touch(client); + + return IRQ_HANDLED; +} + +/* + * The vendor driver would retry twice before failing to read or write + * to the i2c device. + */ + +static int cst3xx_i2c_write(struct i2c_client *client, + unsigned char *buf, int len) +{ + int ret; + int retries = 0; + + while (retries < 2) { + ret = i2c_master_send(client, buf, len); + if (ret == len) + return 0; + if (ret <= 0) + retries++; + else + break; + } + + return ret < 0 ? ret : -EIO; +} + +static int cst3xx_i2c_read_register(struct i2c_client *client, u16 reg, + u8 *val, u16 len) +{ + __le16 buf = cpu_to_le16(reg); + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = (u8 *)&buf, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = val, + } + }; + int err; + int ret; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret == ARRAY_SIZE(msgs)) + return 0; + + err = ret < 0 ? ret : -EIO; + dev_err(&client->dev, "Error reading %d bytes from 0x%04x: %d (%d)\n", + len, reg, err, ret); + + return err; +} + +static int cst3xx_firmware_info(struct i2c_client *client) +{ + struct hynitron_ts_data *ts_data = i2c_get_clientdata(client); + int err; + u32 tmp; + unsigned char buf[4]; + + /* + * Tests suggest this command needed to read firmware regs. + */ + put_unaligned_le16(CST3XX_FIRMWARE_INFO_START_CMD, buf); + err = cst3xx_i2c_write(client, buf, 2); + if (err) + return err; + + usleep_range(10000, 11000); + + /* + * Read register for check-code to determine if device detected + * correctly. + */ + err = cst3xx_i2c_read_register(client, CST3XX_FIRMWARE_CHK_CODE_REG, + buf, 4); + if (err) + return err; + + tmp = get_unaligned_le32(buf); + if ((tmp & 0xffff0000) != ts_data->chip->ic_chkcode) { + dev_err(&client->dev, "%s ic mismatch, chkcode is %u\n", + __func__, tmp); + return -ENODEV; + } + + usleep_range(10000, 11000); + + /* Read firmware version and test if firmware missing. */ + err = cst3xx_i2c_read_register(client, CST3XX_FIRMWARE_VERSION_REG, + buf, 4); + if (err) + return err; + + tmp = get_unaligned_le32(buf); + if (tmp == CST3XX_FIRMWARE_VER_INVALID_VAL) { + dev_err(&client->dev, "Device firmware missing\n"); + return -ENODEV; + } + + /* + * Tests suggest cmd required to exit reading firmware regs. + */ + put_unaligned_le16(CST3XX_FIRMWARE_INFO_END_CMD, buf); + err = cst3xx_i2c_write(client, buf, 2); + if (err) + return err; + + usleep_range(5000, 6000); + + return 0; +} + +static int cst3xx_bootloader_enter(struct i2c_client *client) +{ + int err; + u8 retry; + u32 tmp = 0; + unsigned char buf[3]; + + for (retry = 0; retry < 5; retry++) { + hyn_reset_proc(client, (7 + retry)); + /* set cmd to enter program mode */ + put_unaligned_le24(CST3XX_BOOTLDR_PROG_CMD, buf); + err = cst3xx_i2c_write(client, buf, 3); + if (err) + continue; + + usleep_range(2000, 2500); + + /* check whether in program mode */ + err = cst3xx_i2c_read_register(client, + CST3XX_BOOTLDR_PROG_CHK_REG, + buf, 1); + if (err) + continue; + + tmp = get_unaligned(buf); + if (tmp == CST3XX_BOOTLDR_CHK_VAL) + break; + } + + if (tmp != CST3XX_BOOTLDR_CHK_VAL) { + dev_err(&client->dev, "%s unable to enter bootloader mode\n", + __func__); + return -ENODEV; + } + + hyn_reset_proc(client, 40); + + return 0; +} + +static void cst3xx_report_contact(struct hynitron_ts_data *ts_data, + u8 id, unsigned int x, unsigned int y, u8 w) +{ + input_mt_slot(ts_data->input_dev, id); + input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, 1); + touchscreen_report_pos(ts_data->input_dev, &ts_data->prop, x, y, true); + input_report_abs(ts_data->input_dev, ABS_MT_TOUCH_MAJOR, w); +} + +static int cst3xx_finish_touch_read(struct i2c_client *client) +{ + unsigned char buf[3]; + int err; + + put_unaligned_le24(CST3XX_TOUCH_DATA_STOP_CMD, buf); + err = cst3xx_i2c_write(client, buf, 3); + if (err) { + dev_err(&client->dev, + "send read touch info ending failed: %d\n", err); + return err; + } + + return 0; +} + +/* + * Handle events from IRQ. Note that for cst3xx it appears that IRQ + * fires continuously while touched, otherwise once every 1500ms + * when not touched (assume touchscreen waking up periodically). + * Note buffer is sized for 5 fingers, if more needed buffer must + * be increased. The buffer contains 5 bytes for each touch point, + * a touch count byte, a check byte, and then a second check byte after + * all other touch points. + * + * For example 1 touch would look like this: + * touch1[5]:touch_count[1]:chk_byte[1] + * + * 3 touches would look like this: + * touch1[5]:touch_count[1]:chk_byte[1]:touch2[5]:touch3[5]:chk_byte[1] + */ +static void cst3xx_touch_report(struct i2c_client *client) +{ + struct hynitron_ts_data *ts_data = i2c_get_clientdata(client); + u8 buf[28]; + u8 finger_id, sw, w; + unsigned int x, y; + unsigned int touch_cnt, end_byte; + unsigned int idx = 0; + unsigned int i; + int err; + + /* Read and validate the first bits of input data. */ + err = cst3xx_i2c_read_register(client, CST3XX_TOUCH_DATA_PART_REG, + buf, 28); + if (err || + buf[6] != CST3XX_TOUCH_DATA_CHK_VAL || + buf[0] == CST3XX_TOUCH_DATA_CHK_VAL) { + dev_err(&client->dev, "cst3xx touch read failure\n"); + return; + } + + /* Report to the device we're done reading the touch data. */ + err = cst3xx_finish_touch_read(client); + if (err) + return; + + touch_cnt = buf[5] & CST3XX_TOUCH_COUNT_MASK; + /* + * Check the check bit of the last touch slot. The check bit is + * always present after touch point 1 for valid data, and then + * appears as the last byte after all other touch data. + */ + if (touch_cnt > 1) { + end_byte = touch_cnt * 5 + 2; + if (buf[end_byte] != CST3XX_TOUCH_DATA_CHK_VAL) { + dev_err(&client->dev, "cst3xx touch read failure\n"); + return; + } + } + + /* Parse through the buffer to capture touch data. */ + for (i = 0; i < touch_cnt; i++) { + x = ((buf[idx + 1] << 4) | ((buf[idx + 3] >> 4) & 0x0f)); + y = ((buf[idx + 2] << 4) | (buf[idx + 3] & 0x0f)); + w = (buf[idx + 4] >> 3); + sw = (buf[idx] & 0x0f) >> 1; + finger_id = (buf[idx] >> 4) & 0x0f; + + /* Sanity check we don't have more fingers than we expect */ + if (ts_data->chip->max_touch_num < finger_id) { + dev_err(&client->dev, "cst3xx touch read failure\n"); + break; + } + + /* sw value of 0 means no touch, 0x03 means touch */ + if (sw == CST3XX_TOUCH_DATA_TOUCH_VAL) + cst3xx_report_contact(ts_data, finger_id, x, y, w); + + idx += 5; + + /* Skip the 2 bytes between point 1 and point 2 */ + if (i == 0) + idx += 2; + } + + input_mt_sync_frame(ts_data->input_dev); + input_sync(ts_data->input_dev); +} + +static int cst3xx_input_dev_int(struct i2c_client *client) +{ + struct hynitron_ts_data *ts_data = i2c_get_clientdata(client); + int err; + + ts_data->input_dev = devm_input_allocate_device(&client->dev); + if (!ts_data->input_dev) { + dev_err(&client->dev, "Failed to allocate input device\n"); + return -ENOMEM; + } + + ts_data->input_dev->name = "Hynitron cst3xx Touchscreen"; + ts_data->input_dev->phys = "input/ts"; + ts_data->input_dev->id.bustype = BUS_I2C; + + input_set_drvdata(ts_data->input_dev, ts_data); + + input_set_capability(ts_data->input_dev, EV_ABS, ABS_MT_POSITION_X); + input_set_capability(ts_data->input_dev, EV_ABS, ABS_MT_POSITION_Y); + input_set_abs_params(ts_data->input_dev, ABS_MT_TOUCH_MAJOR, + 0, 255, 0, 0); + + touchscreen_parse_properties(ts_data->input_dev, true, &ts_data->prop); + + if (!ts_data->prop.max_x || !ts_data->prop.max_y) { + dev_err(&client->dev, + "Invalid x/y (%d, %d), using defaults\n", + ts_data->prop.max_x, ts_data->prop.max_y); + ts_data->prop.max_x = 1152; + ts_data->prop.max_y = 1920; + input_abs_set_max(ts_data->input_dev, + ABS_MT_POSITION_X, ts_data->prop.max_x); + input_abs_set_max(ts_data->input_dev, + ABS_MT_POSITION_Y, ts_data->prop.max_y); + } + + err = input_mt_init_slots(ts_data->input_dev, + ts_data->chip->max_touch_num, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (err) { + dev_err(&client->dev, + "Failed to initialize input slots: %d\n", err); + return err; + } + + err = input_register_device(ts_data->input_dev); + if (err) { + dev_err(&client->dev, + "Input device registration failed: %d\n", err); + return err; + } + + return 0; +} + +static int hyn_probe(struct i2c_client *client) +{ + struct hynitron_ts_data *ts_data; + int err; + + ts_data = devm_kzalloc(&client->dev, sizeof(*ts_data), GFP_KERNEL); + if (!ts_data) + return -ENOMEM; + + ts_data->client = client; + i2c_set_clientdata(client, ts_data); + + ts_data->chip = device_get_match_data(&client->dev); + if (!ts_data->chip) + return -EINVAL; + + ts_data->reset_gpio = devm_gpiod_get(&client->dev, + "reset", GPIOD_OUT_LOW); + err = PTR_ERR_OR_ZERO(ts_data->reset_gpio); + if (err) { + dev_err(&client->dev, "request reset gpio failed: %d\n", err); + return err; + } + + hyn_reset_proc(client, 60); + + err = ts_data->chip->bootloader_enter(client); + if (err < 0) + return err; + + err = ts_data->chip->init_input(client); + if (err < 0) + return err; + + err = ts_data->chip->firmware_info(client); + if (err < 0) + return err; + + err = devm_request_threaded_irq(&client->dev, client->irq, + NULL, hyn_interrupt_handler, + IRQF_ONESHOT, + "Hynitron Touch Int", client); + if (err) { + dev_err(&client->dev, "failed to request IRQ: %d\n", err); + return err; + } + + return 0; +} + +static const struct hynitron_ts_chip_data cst3xx_data = { + .max_touch_num = 5, + .ic_chkcode = 0xcaca0000, + .firmware_info = &cst3xx_firmware_info, + .bootloader_enter = &cst3xx_bootloader_enter, + .init_input = &cst3xx_input_dev_int, + .report_touch = &cst3xx_touch_report, +}; + +static const struct i2c_device_id hyn_tpd_id[] = { + { .name = "hynitron_ts", 0 }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i2c, hyn_tpd_id); + +static const struct of_device_id hyn_dt_match[] = { + { .compatible = "hynitron,cst340", .data = &cst3xx_data }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, hyn_dt_match); + +static struct i2c_driver hynitron_i2c_driver = { + .driver = { + .name = "Hynitron-TS", + .of_match_table = hyn_dt_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .id_table = hyn_tpd_id, + .probe_new = hyn_probe, +}; + +module_i2c_driver(hynitron_i2c_driver); + +MODULE_AUTHOR("Chris Morgan"); +MODULE_DESCRIPTION("Hynitron Touchscreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index e9bd36adbe47..4897fafa4204 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -913,9 +913,9 @@ static void ili210x_stop(void *data) priv->stop = true; } -static int ili210x_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ili210x_i2c_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device *dev = &client->dev; const struct ili2xxx_chip *chip; struct ili210x *priv; @@ -1043,7 +1043,7 @@ static struct i2c_driver ili210x_ts_driver = { .of_match_table = ili210x_dt_ids, }, .id_table = ili210x_i2c_id, - .probe = ili210x_i2c_probe, + .probe_new = ili210x_i2c_probe, }; module_i2c_driver(ili210x_ts_driver); diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c index c5d259c76adc..e6ade3775a8a 100644 --- a/drivers/input/touchscreen/ilitek_ts_i2c.c +++ b/drivers/input/touchscreen/ilitek_ts_i2c.c @@ -542,8 +542,7 @@ static struct attribute_group ilitek_attrs_group = { .attrs = ilitek_sysfs_attrs, }; -static int ilitek_ts_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ilitek_ts_i2c_probe(struct i2c_client *client) { struct ilitek_ts_data *ts; struct device *dev = &client->dev; @@ -680,7 +679,7 @@ static struct i2c_driver ilitek_ts_i2c_driver = { .of_match_table = of_match_ptr(ilitek_ts_i2c_match), .acpi_match_table = ACPI_PTR(ilitekts_acpi_id), }, - .probe = ilitek_ts_i2c_probe, + .probe_new = ilitek_ts_i2c_probe, .id_table = ilitek_ts_i2c_id, }; module_i2c_driver(ilitek_ts_i2c_driver); diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index 34c4cca57d13..dc3137a34f35 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -1019,8 +1019,7 @@ static int __maybe_unused iqs5xx_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(iqs5xx_pm, iqs5xx_suspend, iqs5xx_resume); -static int iqs5xx_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int iqs5xx_probe(struct i2c_client *client) { struct iqs5xx_private *iqs5xx; int error; @@ -1094,7 +1093,7 @@ static struct i2c_driver iqs5xx_i2c_driver = { .pm = &iqs5xx_pm, }, .id_table = iqs5xx_id, - .probe = iqs5xx_probe, + .probe_new = iqs5xx_probe, }; module_i2c_driver(iqs5xx_i2c_driver); diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index f15713aaebc2..461023fd6a09 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -168,8 +168,7 @@ static void max11801_ts_phy_init(struct max11801_data *data) max11801_write_reg(client, OP_MODE_CONF_REG, 0x36); } -static int max11801_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max11801_ts_probe(struct i2c_client *client) { struct max11801_data *data; struct input_dev *input_dev; @@ -231,7 +230,7 @@ static struct i2c_driver max11801_ts_driver = { .of_match_table = max11801_ts_dt_ids, }, .id_table = max11801_ts_id, - .probe = max11801_ts_probe, + .probe_new = max11801_ts_probe, }; module_i2c_driver(max11801_ts_driver); diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c index 5376d8f740ab..ea9517cad695 100644 --- a/drivers/input/touchscreen/mcs5000_ts.c +++ b/drivers/input/touchscreen/mcs5000_ts.c @@ -180,8 +180,7 @@ static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data, OP_MODE_ACTIVE | REPORT_RATE_80); } -static int mcs5000_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int mcs5000_ts_probe(struct i2c_client *client) { const struct mcs_platform_data *pdata; struct mcs5000_ts_data *data; @@ -272,7 +271,7 @@ static const struct i2c_device_id mcs5000_ts_id[] = { MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id); static struct i2c_driver mcs5000_ts_driver = { - .probe = mcs5000_ts_probe, + .probe_new = mcs5000_ts_probe, .driver = { .name = "mcs5000_ts", .pm = &mcs5000_ts_pm, diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index 83f4be05e27b..4ee8ed4c930c 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -1424,7 +1424,7 @@ static const struct attribute_group mip4_attr_group = { .attrs = mip4_attrs, }; -static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int mip4_probe(struct i2c_client *client) { struct mip4_ts *ts; struct input_dev *input; @@ -1590,7 +1590,7 @@ MODULE_DEVICE_TABLE(i2c, mip4_i2c_ids); static struct i2c_driver mip4_driver = { .id_table = mip4_i2c_ids, - .probe = mip4_probe, + .probe_new = mip4_probe, .driver = { .name = MIP4_DEVICE_NAME, .of_match_table = of_match_ptr(mip4_of_match), diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c index 79cd660d879e..ff0f605f3a3a 100644 --- a/drivers/input/touchscreen/migor_ts.c +++ b/drivers/input/touchscreen/migor_ts.c @@ -116,8 +116,7 @@ static void migor_ts_close(struct input_dev *dev) enable_irq(priv->irq); } -static int migor_ts_probe(struct i2c_client *client, - const struct i2c_device_id *idp) +static int migor_ts_probe(struct i2c_client *client) { struct migor_ts_priv *priv; struct input_dev *input; @@ -222,7 +221,7 @@ static struct i2c_driver migor_ts_driver = { .name = "migor_ts", .pm = &migor_ts_pm, }, - .probe = migor_ts_probe, + .probe_new = migor_ts_probe, .remove = migor_ts_remove, .id_table = migor_ts_id, }; diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 9fa3b0e421be..758b669391a7 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -440,8 +440,7 @@ static int mms114_parse_legacy_bindings(struct mms114_data *data) return 0; } -static int mms114_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int mms114_probe(struct i2c_client *client) { struct mms114_data *data; struct input_dev *input_dev; @@ -639,7 +638,7 @@ static struct i2c_driver mms114_driver = { .pm = &mms114_pm_ops, .of_match_table = of_match_ptr(mms114_dt_match), }, - .probe = mms114_probe, + .probe_new = mms114_probe, .id_table = mms114_id, }; diff --git a/drivers/input/touchscreen/msg2638.c b/drivers/input/touchscreen/msg2638.c index 75536bc88969..4c0816b09d33 100644 --- a/drivers/input/touchscreen/msg2638.c +++ b/drivers/input/touchscreen/msg2638.c @@ -21,28 +21,49 @@ #include <linux/kernel.h> #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/property.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #define MODE_DATA_RAW 0x5A -#define MAX_SUPPORTED_FINGER_NUM 5 +#define MSG2138_MAX_FINGERS 2 +#define MSG2638_MAX_FINGERS 5 + +#define MAX_BUTTONS 4 #define CHIP_ON_DELAY_MS 15 #define FIRMWARE_ON_DELAY_MS 50 #define RESET_DELAY_MIN_US 10000 #define RESET_DELAY_MAX_US 11000 -struct packet { +struct msg_chip_data { + irq_handler_t irq_handler; + unsigned int max_fingers; +}; + +struct msg2138_packet { + u8 xy_hi; /* higher bits of x and y coordinates */ + u8 x_low; + u8 y_low; +}; + +struct msg2138_touch_event { + u8 magic; + struct msg2138_packet pkt[MSG2138_MAX_FINGERS]; + u8 checksum; +}; + +struct msg2638_packet { u8 xy_hi; /* higher bits of x and y coordinates */ u8 x_low; u8 y_low; u8 pressure; }; -struct touch_event { +struct msg2638_touch_event { u8 mode; - struct packet pkt[MAX_SUPPORTED_FINGER_NUM]; + struct msg2638_packet pkt[MSG2638_MAX_FINGERS]; u8 proximity; u8 checksum; }; @@ -53,6 +74,9 @@ struct msg2638_ts_data { struct touchscreen_properties prop; struct regulator_bulk_data supplies[2]; struct gpio_desc *reset_gpiod; + int max_fingers; + u32 keycodes[MAX_BUTTONS]; + int num_keycodes; }; static u8 msg2638_checksum(u8 *data, u32 length) @@ -66,12 +90,102 @@ static u8 msg2638_checksum(u8 *data, u32 length) return (u8)((-sum) & 0xFF); } +static void msg2138_report_keys(struct msg2638_ts_data *msg2638, u8 keys) +{ + int i; + + /* keys can be 0x00 or 0xff when all keys have been released */ + if (keys == 0xff) + keys = 0; + + for (i = 0; i < msg2638->num_keycodes; ++i) + input_report_key(msg2638->input_dev, msg2638->keycodes[i], + keys & BIT(i)); +} + +static irqreturn_t msg2138_ts_irq_handler(int irq, void *msg2638_handler) +{ + struct msg2638_ts_data *msg2638 = msg2638_handler; + struct i2c_client *client = msg2638->client; + struct input_dev *input = msg2638->input_dev; + struct msg2138_touch_event touch_event; + u32 len = sizeof(touch_event); + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = sizeof(touch_event), + .buf = (u8 *)&touch_event, + }, + }; + struct msg2138_packet *p0, *p1; + u16 x, y, delta_x, delta_y; + int ret; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + dev_err(&client->dev, + "Failed I2C transfer in irq handler: %d\n", + ret < 0 ? ret : -EIO); + goto out; + } + + if (msg2638_checksum((u8 *)&touch_event, len - 1) != + touch_event.checksum) { + dev_err(&client->dev, "Failed checksum!\n"); + goto out; + } + + p0 = &touch_event.pkt[0]; + p1 = &touch_event.pkt[1]; + + /* Ignore non-pressed finger data, but check for key code */ + if (p0->xy_hi == 0xFF && p0->x_low == 0xFF && p0->y_low == 0xFF) { + if (p1->xy_hi == 0xFF && p1->y_low == 0xFF) + msg2138_report_keys(msg2638, p1->x_low); + goto report; + } + + x = ((p0->xy_hi & 0xF0) << 4) | p0->x_low; + y = ((p0->xy_hi & 0x0F) << 8) | p0->y_low; + + input_mt_slot(input, 0); + input_mt_report_slot_state(input, MT_TOOL_FINGER, true); + touchscreen_report_pos(input, &msg2638->prop, x, y, true); + + /* Ignore non-pressed finger data */ + if (p1->xy_hi == 0xFF && p1->x_low == 0xFF && p1->y_low == 0xFF) + goto report; + + /* Second finger is reported as a delta position */ + delta_x = ((p1->xy_hi & 0xF0) << 4) | p1->x_low; + delta_y = ((p1->xy_hi & 0x0F) << 8) | p1->y_low; + + /* Ignore second finger if both deltas equal 0 */ + if (delta_x == 0 && delta_y == 0) + goto report; + + x += delta_x; + y += delta_y; + + input_mt_slot(input, 1); + input_mt_report_slot_state(input, MT_TOOL_FINGER, true); + touchscreen_report_pos(input, &msg2638->prop, x, y, true); + +report: + input_mt_sync_frame(msg2638->input_dev); + input_sync(msg2638->input_dev); + +out: + return IRQ_HANDLED; +} + static irqreturn_t msg2638_ts_irq_handler(int irq, void *msg2638_handler) { struct msg2638_ts_data *msg2638 = msg2638_handler; struct i2c_client *client = msg2638->client; struct input_dev *input = msg2638->input_dev; - struct touch_event touch_event; + struct msg2638_touch_event touch_event; u32 len = sizeof(touch_event); struct i2c_msg msg[] = { { @@ -81,7 +195,7 @@ static irqreturn_t msg2638_ts_irq_handler(int irq, void *msg2638_handler) .buf = (u8 *)&touch_event, }, }; - struct packet *p; + struct msg2638_packet *p; u16 x, y; int ret; int i; @@ -103,7 +217,7 @@ static irqreturn_t msg2638_ts_irq_handler(int irq, void *msg2638_handler) goto out; } - for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++) { + for (i = 0; i < msg2638->max_fingers; i++) { p = &touch_event.pkt[i]; /* Ignore non-pressed finger data */ @@ -190,6 +304,7 @@ static int msg2638_init_input_dev(struct msg2638_ts_data *msg2638) struct device *dev = &msg2638->client->dev; struct input_dev *input_dev; int error; + int i; input_dev = devm_input_allocate_device(dev); if (!input_dev) { @@ -206,6 +321,15 @@ static int msg2638_init_input_dev(struct msg2638_ts_data *msg2638) input_dev->open = msg2638_input_open; input_dev->close = msg2638_input_close; + if (msg2638->num_keycodes) { + input_dev->keycode = msg2638->keycodes; + input_dev->keycodemax = msg2638->num_keycodes; + input_dev->keycodesize = sizeof(msg2638->keycodes[0]); + for (i = 0; i < msg2638->num_keycodes; i++) + input_set_capability(input_dev, + EV_KEY, msg2638->keycodes[i]); + } + input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X); input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y); @@ -215,7 +339,7 @@ static int msg2638_init_input_dev(struct msg2638_ts_data *msg2638) return -EINVAL; } - error = input_mt_init_slots(input_dev, MAX_SUPPORTED_FINGER_NUM, + error = input_mt_init_slots(input_dev, msg2638->max_fingers, INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); if (error) { dev_err(dev, "Failed to initialize MT slots: %d\n", error); @@ -233,6 +357,7 @@ static int msg2638_init_input_dev(struct msg2638_ts_data *msg2638) static int msg2638_ts_probe(struct i2c_client *client) { + const struct msg_chip_data *chip_data; struct device *dev = &client->dev; struct msg2638_ts_data *msg2638; int error; @@ -249,6 +374,14 @@ static int msg2638_ts_probe(struct i2c_client *client) msg2638->client = client; i2c_set_clientdata(client, msg2638); + chip_data = device_get_match_data(&client->dev); + if (!chip_data || !chip_data->max_fingers) { + dev_err(dev, "Invalid or missing chip data\n"); + return -EINVAL; + } + + msg2638->max_fingers = chip_data->max_fingers; + msg2638->supplies[0].supply = "vdd"; msg2638->supplies[1].supply = "vddio"; error = devm_regulator_bulk_get(dev, ARRAY_SIZE(msg2638->supplies), @@ -265,14 +398,33 @@ static int msg2638_ts_probe(struct i2c_client *client) return error; } - error = msg2638_init_input_dev(msg2638); - if (error) { - dev_err(dev, "Failed to initialize input device: %d\n", error); - return error; + msg2638->num_keycodes = device_property_count_u32(dev, + "linux,keycodes"); + if (msg2638->num_keycodes == -EINVAL) { + msg2638->num_keycodes = 0; + } else if (msg2638->num_keycodes < 0) { + dev_err(dev, "Unable to parse linux,keycodes property: %d\n", + msg2638->num_keycodes); + return msg2638->num_keycodes; + } else if (msg2638->num_keycodes > ARRAY_SIZE(msg2638->keycodes)) { + dev_warn(dev, "Found %d linux,keycodes but max is %zd, ignoring the rest\n", + msg2638->num_keycodes, ARRAY_SIZE(msg2638->keycodes)); + msg2638->num_keycodes = ARRAY_SIZE(msg2638->keycodes); + } + + if (msg2638->num_keycodes > 0) { + error = device_property_read_u32_array(dev, "linux,keycodes", + msg2638->keycodes, + msg2638->num_keycodes); + if (error) { + dev_err(dev, "Unable to read linux,keycodes values: %d\n", + error); + return error; + } } error = devm_request_threaded_irq(dev, client->irq, - NULL, msg2638_ts_irq_handler, + NULL, chip_data->irq_handler, IRQF_ONESHOT | IRQF_NO_AUTOEN, client->name, msg2638); if (error) { @@ -280,6 +432,12 @@ static int msg2638_ts_probe(struct i2c_client *client) return error; } + error = msg2638_init_input_dev(msg2638); + if (error) { + dev_err(dev, "Failed to initialize input device: %d\n", error); + return error; + } + return 0; } @@ -316,8 +474,19 @@ static int __maybe_unused msg2638_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(msg2638_pm_ops, msg2638_suspend, msg2638_resume); +static const struct msg_chip_data msg2138_data = { + .irq_handler = msg2138_ts_irq_handler, + .max_fingers = MSG2138_MAX_FINGERS, +}; + +static const struct msg_chip_data msg2638_data = { + .irq_handler = msg2638_ts_irq_handler, + .max_fingers = MSG2638_MAX_FINGERS, +}; + static const struct of_device_id msg2638_of_match[] = { - { .compatible = "mstar,msg2638" }, + { .compatible = "mstar,msg2138", .data = &msg2138_data }, + { .compatible = "mstar,msg2638", .data = &msg2638_data }, { } }; MODULE_DEVICE_TABLE(of, msg2638_of_match); diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index dc148b4bed74..7959947a3458 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -462,9 +462,9 @@ unlock: static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops, pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume); -static int pixcir_i2c_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pixcir_i2c_ts_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device *dev = &client->dev; struct pixcir_i2c_ts_data *tsdata; struct input_dev *input; @@ -617,7 +617,7 @@ static struct i2c_driver pixcir_i2c_ts_driver = { .pm = &pixcir_dev_pm_ops, .of_match_table = of_match_ptr(pixcir_of_match), }, - .probe = pixcir_i2c_ts_probe, + .probe_new = pixcir_i2c_ts_probe, .id_table = pixcir_i2c_ts_id, }; diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index 3d9c5758d8a4..d690a17240c2 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -21,6 +21,7 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/pm_wakeirq.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <asm/unaligned.h> @@ -134,8 +135,6 @@ struct raydium_data { u8 pkg_size; enum raydium_boot_mode boot_mode; - - bool wake_irq_enabled; }; /* @@ -1066,8 +1065,7 @@ static void raydium_i2c_power_off(void *_data) } } -static int raydium_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int raydium_i2c_probe(struct i2c_client *client) { union i2c_smbus_data dummy; struct raydium_data *ts; @@ -1224,8 +1222,6 @@ static int __maybe_unused raydium_i2c_suspend(struct device *dev) if (device_may_wakeup(dev)) { raydium_enter_sleep(client); - - ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); } else { raydium_i2c_power_off(ts); } @@ -1239,8 +1235,6 @@ static int __maybe_unused raydium_i2c_resume(struct device *dev) struct raydium_data *ts = i2c_get_clientdata(client); if (device_may_wakeup(dev)) { - if (ts->wake_irq_enabled) - disable_irq_wake(client->irq); raydium_i2c_sw_reset(client); } else { raydium_i2c_power_on(ts); @@ -1279,7 +1273,7 @@ MODULE_DEVICE_TABLE(of, raydium_of_match); #endif static struct i2c_driver raydium_i2c_driver = { - .probe = raydium_i2c_probe, + .probe_new = raydium_i2c_probe, .id_table = raydium_i2c_id, .driver = { .name = "raydium_ts", diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c index 730596d599d8..833422e5fd6d 100644 --- a/drivers/input/touchscreen/rohm_bu21023.c +++ b/drivers/input/touchscreen/rohm_bu21023.c @@ -1095,8 +1095,7 @@ static void rohm_ts_close(struct input_dev *input_dev) ts->initialized = false; } -static int rohm_bu21023_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int rohm_bu21023_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct rohm_ts_data *ts; @@ -1184,7 +1183,7 @@ static struct i2c_driver rohm_bu21023_i2c_driver = { .driver = { .name = BU21023_NAME, }, - .probe = rohm_bu21023_i2c_probe, + .probe_new = rohm_bu21023_i2c_probe, .id_table = rohm_bu21023_i2c_id, }; module_i2c_driver(rohm_bu21023_i2c_driver); diff --git a/drivers/input/touchscreen/s6sy761.c b/drivers/input/touchscreen/s6sy761.c index 1a7d00289b4c..cc417c03aaca 100644 --- a/drivers/input/touchscreen/s6sy761.c +++ b/drivers/input/touchscreen/s6sy761.c @@ -389,8 +389,7 @@ static void s6sy761_power_off(void *data) sdata->regulators); } -static int s6sy761_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int s6sy761_probe(struct i2c_client *client) { struct s6sy761_data *sdata; unsigned int max_x, max_y; @@ -540,7 +539,7 @@ static struct i2c_driver s6sy761_driver = { .of_match_table = of_match_ptr(s6sy761_of_match), .pm = &s6sy761_pm_ops, }, - .probe = s6sy761_probe, + .probe_new = s6sy761_probe, .remove = s6sy761_remove, .id_table = s6sy761_id, }; diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c index 3eef8c01090f..8a7351c4414c 100644 --- a/drivers/input/touchscreen/silead.c +++ b/drivers/input/touchscreen/silead.c @@ -652,9 +652,9 @@ static void silead_disable_regulator(void *arg) regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); } -static int silead_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int silead_ts_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct silead_ts_data *data; struct device *dev = &client->dev; int error; @@ -826,7 +826,7 @@ MODULE_DEVICE_TABLE(of, silead_ts_of_match); #endif static struct i2c_driver silead_ts_driver = { - .probe = silead_ts_probe, + .probe_new = silead_ts_probe, .id_table = silead_ts_id, .driver = { .name = SILEAD_TS_NAME, diff --git a/drivers/input/touchscreen/sis_i2c.c b/drivers/input/touchscreen/sis_i2c.c index 6274555f1673..5a493b15b25d 100644 --- a/drivers/input/touchscreen/sis_i2c.c +++ b/drivers/input/touchscreen/sis_i2c.c @@ -296,8 +296,7 @@ static void sis_ts_reset(struct sis_ts_data *ts) } } -static int sis_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sis_ts_probe(struct i2c_client *client) { struct sis_ts_data *ts; struct input_dev *input; @@ -394,7 +393,7 @@ static struct i2c_driver sis_ts_driver = { .name = SIS_I2C_NAME, .of_match_table = of_match_ptr(sis_ts_dt_ids), }, - .probe = sis_ts_probe, + .probe_new = sis_ts_probe, .id_table = sis_ts_id, }; module_i2c_driver(sis_ts_driver); diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index e38ba3e4f183..bd68633dc6c0 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -220,9 +220,9 @@ static const struct st_chip_info st1633_chip_info = { .max_fingers = 5, }; -static int st1232_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int st1232_ts_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct st_chip_info *match; struct st1232_ts_data *ts; struct input_dev *input_dev; @@ -384,7 +384,7 @@ static const struct of_device_id st1232_ts_dt_ids[] = { MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids); static struct i2c_driver st1232_ts_driver = { - .probe = st1232_ts_probe, + .probe_new = st1232_ts_probe, .id_table = st1232_ts_id, .driver = { .name = ST1232_TS_NAME, diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c index d5bd170808fb..d092e89d40e8 100644 --- a/drivers/input/touchscreen/stmfts.c +++ b/drivers/input/touchscreen/stmfts.c @@ -624,8 +624,7 @@ static int stmfts_enable_led(struct stmfts_data *sdata) return 0; } -static int stmfts_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int stmfts_probe(struct i2c_client *client) { int err; struct stmfts_data *sdata; @@ -809,7 +808,7 @@ static struct i2c_driver stmfts_driver = { .pm = &stmfts_pm_ops, .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, - .probe = stmfts_probe, + .probe_new = stmfts_probe, .remove = stmfts_remove, .id_table = stmfts_id, }; diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index 742a7e96c1b5..73eb8f80be6e 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -192,12 +192,12 @@ static int sun4i_get_temp(const struct sun4i_ts_data *ts, int *temp) return 0; } -static int sun4i_get_tz_temp(void *data, int *temp) +static int sun4i_get_tz_temp(struct thermal_zone_device *tz, int *temp) { - return sun4i_get_temp(data, temp); + return sun4i_get_temp(tz->devdata, temp); } -static const struct thermal_zone_of_device_ops sun4i_ts_tz_ops = { +static const struct thermal_zone_device_ops sun4i_ts_tz_ops = { .get_temp = sun4i_get_tz_temp, }; @@ -356,8 +356,8 @@ static int sun4i_ts_probe(struct platform_device *pdev) if (IS_ERR(hwmon)) return PTR_ERR(hwmon); - thermal = devm_thermal_zone_of_sensor_register(ts->dev, 0, ts, - &sun4i_ts_tz_ops); + thermal = devm_thermal_of_zone_register(ts->dev, 0, ts, + &sun4i_ts_tz_ops); if (IS_ERR(thermal)) return PTR_ERR(thermal); diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c index de85e57b2486..52ae73035830 100644 --- a/drivers/input/touchscreen/sx8654.c +++ b/drivers/input/touchscreen/sx8654.c @@ -306,9 +306,9 @@ static void sx8654_close(struct input_dev *dev) } } -static int sx8654_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sx8654_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct sx8654 *sx8654; struct input_dev *input; int error; @@ -470,7 +470,7 @@ static struct i2c_driver sx8654_driver = { .of_match_table = of_match_ptr(sx8654_of_match), }, .id_table = sx8654_id_table, - .probe = sx8654_probe, + .probe_new = sx8654_probe, }; module_i2c_driver(sx8654_driver); diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c index 357a3108f2e5..f48871767763 100644 --- a/drivers/input/touchscreen/tps6507x-ts.c +++ b/drivers/input/touchscreen/tps6507x-ts.c @@ -119,7 +119,6 @@ err: static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc) { s32 ret; - s32 loops = 0; u8 val; ret = tps6507x_write_u8(tsc, TPS6507X_REG_ADCONFIG, @@ -141,7 +140,6 @@ static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc) ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val); if (ret) return ret; - loops++; } return ret; diff --git a/drivers/input/touchscreen/tsc2004.c b/drivers/input/touchscreen/tsc2004.c index a9565353ee98..575768b587bb 100644 --- a/drivers/input/touchscreen/tsc2004.c +++ b/drivers/input/touchscreen/tsc2004.c @@ -34,8 +34,7 @@ static int tsc2004_cmd(struct device *dev, u8 cmd) return 0; } -static int tsc2004_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int tsc2004_probe(struct i2c_client *i2c) { return tsc200x_probe(&i2c->dev, i2c->irq, &tsc2004_input_id, @@ -69,7 +68,7 @@ static struct i2c_driver tsc2004_driver = { .pm = &tsc200x_pm_ops, }, .id_table = tsc2004_idtable, - .probe = tsc2004_probe, + .probe_new = tsc2004_probe, .remove = tsc2004_remove, }; module_i2c_driver(tsc2004_driver); diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 3e871d182c40..3c793fb70a0e 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -302,9 +302,9 @@ static void tsc2007_call_exit_platform_hw(void *data) pdata->exit_platform_hw(); } -static int tsc2007_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tsc2007_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct tsc2007_platform_data *pdata = dev_get_platdata(&client->dev); struct tsc2007 *ts; @@ -431,7 +431,7 @@ static struct i2c_driver tsc2007_driver = { .of_match_table = tsc2007_of_match, }, .id_table = tsc2007_idtable, - .probe = tsc2007_probe, + .probe_new = tsc2007_probe, }; module_i2c_driver(tsc2007_driver); diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index 141754b2764c..c9188ee00c62 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -162,8 +162,7 @@ static void wacom_i2c_close(struct input_dev *dev) disable_irq(client->irq); } -static int wacom_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int wacom_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct wacom_i2c *wac_i2c; @@ -265,7 +264,7 @@ static struct i2c_driver wacom_i2c_driver = { .pm = &wacom_i2c_pm, }, - .probe = wacom_i2c_probe, + .probe_new = wacom_i2c_probe, .id_table = wacom_i2c_id, }; module_i2c_driver(wacom_i2c_driver); diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index 166edeb77776..3f87db5cdca4 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -1064,8 +1064,7 @@ static int wdt87xx_ts_create_input_device(struct wdt87xx_data *wdt) return 0; } -static int wdt87xx_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int wdt87xx_ts_probe(struct i2c_client *client) { struct wdt87xx_data *wdt; int error; @@ -1170,7 +1169,7 @@ static const struct acpi_device_id wdt87xx_acpi_id[] = { MODULE_DEVICE_TABLE(acpi, wdt87xx_acpi_id); static struct i2c_driver wdt87xx_driver = { - .probe = wdt87xx_ts_probe, + .probe_new = wdt87xx_ts_probe, .id_table = wdt87xx_dev_id, .driver = { .name = WDT87XX_NAME, diff --git a/drivers/input/touchscreen/zet6223.c b/drivers/input/touchscreen/zet6223.c index 3b6f7ee1e38f..bfa0c637d569 100644 --- a/drivers/input/touchscreen/zet6223.c +++ b/drivers/input/touchscreen/zet6223.c @@ -167,8 +167,7 @@ static int zet6223_query_device(struct zet6223_ts *ts) return 0; } -static int zet6223_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int zet6223_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct zet6223_ts *ts; @@ -249,7 +248,7 @@ static struct i2c_driver zet6223_driver = { .name = "zet6223", .of_match_table = zet6223_of_match, }, - .probe = zet6223_probe, + .probe_new = zet6223_probe, .id_table = zet6223_id }; module_i2c_driver(zet6223_driver); diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 495629628af6..24e78ca83fa3 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -732,8 +732,7 @@ static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev) return pdata; } -static int zforce_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int zforce_probe(struct i2c_client *client) { const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev); struct zforce_ts *ts; @@ -945,7 +944,7 @@ static struct i2c_driver zforce_driver = { .pm = &zforce_pm_ops, .of_match_table = of_match_ptr(zforce_dt_idtable), }, - .probe = zforce_probe, + .probe_new = zforce_probe, .id_table = zforce_idtable, }; |