summaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2022-12-12 10:47:03 -0800
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2022-12-12 10:47:03 -0800
commite291c116f60f3c1ca98090f0f8e7c77e658562fb (patch)
tree2fbe810f2a6f8b29f1cdaefd87b24debbfa0ec07 /drivers/input/touchscreen
parent8c9a59939deb4bfafdc451100c03d1e848b4169b (diff)
parentc3991107a28a5ad0bd90660ca3bbf8c2c220ea98 (diff)
downloadlinux-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')
-rw-r--r--drivers/input/touchscreen/Kconfig42
-rw-r--r--drivers/input/touchscreen/Makefile3
-rw-r--r--drivers/input/touchscreen/ad7879-i2c.c5
-rw-r--r--drivers/input/touchscreen/ar1021_i2c.c5
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c4
-rw-r--r--drivers/input/touchscreen/auo-pixcir-ts.c5
-rw-r--r--drivers/input/touchscreen/bu21013_ts.c5
-rw-r--r--drivers/input/touchscreen/bu21029_ts.c5
-rw-r--r--drivers/input/touchscreen/chipone_icn8318.c5
-rw-r--r--drivers/input/touchscreen/cy8ctma140.c5
-rw-r--r--drivers/input/touchscreen/cy8ctmg110_ts.c5
-rw-r--r--drivers/input/touchscreen/cyttsp4_i2c.c5
-rw-r--r--drivers/input/touchscreen/cyttsp5.c900
-rw-r--r--drivers/input/touchscreen/cyttsp_i2c.c5
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c6
-rw-r--r--drivers/input/touchscreen/eeti_ts.c5
-rw-r--r--drivers/input/touchscreen/egalax_ts.c54
-rw-r--r--drivers/input/touchscreen/ektf2127.c5
-rw-r--r--drivers/input/touchscreen/elants_i2c.c28
-rw-r--r--drivers/input/touchscreen/goodix.c5
-rw-r--r--drivers/input/touchscreen/hideep.c5
-rw-r--r--drivers/input/touchscreen/himax_hx83112b.c364
-rw-r--r--drivers/input/touchscreen/hycon-hy46xx.c5
-rw-r--r--drivers/input/touchscreen/hynitron_cstxxx.c498
-rw-r--r--drivers/input/touchscreen/ili210x.c6
-rw-r--r--drivers/input/touchscreen/ilitek_ts_i2c.c5
-rw-r--r--drivers/input/touchscreen/iqs5xx.c5
-rw-r--r--drivers/input/touchscreen/max11801_ts.c5
-rw-r--r--drivers/input/touchscreen/mcs5000_ts.c5
-rw-r--r--drivers/input/touchscreen/melfas_mip4.c4
-rw-r--r--drivers/input/touchscreen/migor_ts.c5
-rw-r--r--drivers/input/touchscreen/mms114.c5
-rw-r--r--drivers/input/touchscreen/msg2638.c197
-rw-r--r--drivers/input/touchscreen/pixcir_i2c_ts.c6
-rw-r--r--drivers/input/touchscreen/raydium_i2c_ts.c12
-rw-r--r--drivers/input/touchscreen/rohm_bu21023.c5
-rw-r--r--drivers/input/touchscreen/s6sy761.c5
-rw-r--r--drivers/input/touchscreen/silead.c6
-rw-r--r--drivers/input/touchscreen/sis_i2c.c5
-rw-r--r--drivers/input/touchscreen/st1232.c6
-rw-r--r--drivers/input/touchscreen/stmfts.c5
-rw-r--r--drivers/input/touchscreen/sun4i-ts.c10
-rw-r--r--drivers/input/touchscreen/sx8654.c6
-rw-r--r--drivers/input/touchscreen/tps6507x-ts.c2
-rw-r--r--drivers/input/touchscreen/tsc2004.c5
-rw-r--r--drivers/input/touchscreen/tsc2007_core.c6
-rw-r--r--drivers/input/touchscreen/wacom_i2c.c5
-rw-r--r--drivers/input/touchscreen/wdt87xx_i2c.c5
-rw-r--r--drivers/input/touchscreen/zet6223.c5
-rw-r--r--drivers/input/touchscreen/zforce_ts.c5
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,
};