summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r--drivers/input/touchscreen/Kconfig34
-rw-r--r--drivers/input/touchscreen/Makefile3
-rw-r--r--drivers/input/touchscreen/ad7877.c10
-rw-r--r--drivers/input/touchscreen/ad7879.c14
-rw-r--r--drivers/input/touchscreen/ads7846.c4
-rw-r--r--drivers/input/touchscreen/apple_z2.c481
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c15
-rw-r--r--drivers/input/touchscreen/bu21029_ts.c5
-rw-r--r--drivers/input/touchscreen/cyttsp5.c11
-rw-r--r--drivers/input/touchscreen/cyttsp_core.c1
-rw-r--r--drivers/input/touchscreen/da9052_tsi.c2
-rw-r--r--drivers/input/touchscreen/dynapro.c6
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c32
-rw-r--r--drivers/input/touchscreen/egalax_ts_serial.c5
-rw-r--r--drivers/input/touchscreen/elo.c4
-rw-r--r--drivers/input/touchscreen/exc3000.c4
-rw-r--r--drivers/input/touchscreen/fsl-imx25-tcq.c1
-rw-r--r--drivers/input/touchscreen/fujitsu_ts.c5
-rw-r--r--drivers/input/touchscreen/goodix.c78
-rw-r--r--drivers/input/touchscreen/goodix.h1
-rw-r--r--drivers/input/touchscreen/goodix_berlin.h16
-rw-r--r--drivers/input/touchscreen/goodix_berlin_core.c24
-rw-r--r--drivers/input/touchscreen/goodix_berlin_i2c.c14
-rw-r--r--drivers/input/touchscreen/goodix_berlin_spi.c48
-rw-r--r--drivers/input/touchscreen/gunze.c4
-rw-r--r--drivers/input/touchscreen/hampshire.c6
-rw-r--r--drivers/input/touchscreen/himax_hx852x.c503
-rw-r--r--drivers/input/touchscreen/hynitron-cst816x.c253
-rw-r--r--drivers/input/touchscreen/ili210x.c96
-rw-r--r--drivers/input/touchscreen/ilitek_ts_i2c.c10
-rw-r--r--drivers/input/touchscreen/imx6ul_tsc.c121
-rw-r--r--drivers/input/touchscreen/inexio.c4
-rw-r--r--drivers/input/touchscreen/iqs5xx.c1
-rw-r--r--drivers/input/touchscreen/mc13783_ts.c6
-rw-r--r--drivers/input/touchscreen/melfas_mip4.c2
-rw-r--r--drivers/input/touchscreen/migor_ts.c2
-rw-r--r--drivers/input/touchscreen/mtouch.c4
-rw-r--r--drivers/input/touchscreen/novatek-nvt-ts.c5
-rw-r--r--drivers/input/touchscreen/pcap_ts.c2
-rw-r--r--drivers/input/touchscreen/penmount.c4
-rw-r--r--drivers/input/touchscreen/st1232.c35
-rw-r--r--drivers/input/touchscreen/stmfts.c21
-rw-r--r--drivers/input/touchscreen/stmpe-ts.c7
-rw-r--r--drivers/input/touchscreen/sur40.c4
-rw-r--r--drivers/input/touchscreen/sx8654.c4
-rw-r--r--drivers/input/touchscreen/ti_am335x_tsc.c8
-rw-r--r--drivers/input/touchscreen/touchit213.c6
-rw-r--r--drivers/input/touchscreen/touchright.c4
-rw-r--r--drivers/input/touchscreen/touchwin.c4
-rw-r--r--drivers/input/touchscreen/tsc2007.h2
-rw-r--r--drivers/input/touchscreen/tsc2007_core.c44
-rw-r--r--drivers/input/touchscreen/tsc200x-core.c7
-rw-r--r--drivers/input/touchscreen/tsc40.c4
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c6
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c2
-rw-r--r--drivers/input/touchscreen/wdt87xx_i2c.c14
-rw-r--r--drivers/input/touchscreen/wm9705.c1
-rw-r--r--drivers/input/touchscreen/wm9712.c1
-rw-r--r--drivers/input/touchscreen/wm9713.c1
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c1
-rw-r--r--drivers/input/touchscreen/zforce_ts.c3
61 files changed, 1719 insertions, 301 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 1a03de7fcfa6..7d5b72ee07fa 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -103,6 +103,18 @@ config TOUCHSCREEN_ADC
To compile this driver as a module, choose M here: the
module will be called resistive-adc-touch.ko.
+config TOUCHSCREEN_APPLE_Z2
+ tristate "Apple Z2 touchscreens"
+ depends on SPI && (ARCH_APPLE || COMPILE_TEST)
+ help
+ Say Y here if you have an ARM Apple device with
+ a touchscreen or a touchbar.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called apple_z2.
+
config TOUCHSCREEN_AR1021_I2C
tristate "Microchip AR1020/1021 i2c touchscreen"
depends on I2C && OF
@@ -429,6 +441,16 @@ config TOUCHSCREEN_HIDEEP
To compile this driver as a module, choose M here : the
module will be called hideep_ts.
+config TOUCHSCREEN_HIMAX_HX852X
+ tristate "Himax HX852x(ES) touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have a Himax HX852x(ES) touchscreen.
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the module
+ will be called himax_hx852x.
+
config TOUCHSCREEN_HYCON_HY46XX
tristate "Hycon hy46xx touchscreen support"
depends on I2C
@@ -453,6 +475,18 @@ config TOUCHSCREEN_HYNITRON_CSTXXX
To compile this driver as a module, choose M here: the
module will be called hynitron-cstxxx.
+config TOUCHSCREEN_HYNITRON_CST816X
+ tristate "Hynitron CST816x touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have a touchscreen using a Hynitron
+ CST816x series touchscreen controller.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hynitron-cst816x.
+
config TOUCHSCREEN_ILI210X
tristate "Ilitek ILI210X based touchscreen"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 82bc837ca01e..ab9abd151078 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADC) += resistive-adc-touch.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
+obj-$(CONFIG_TOUCHSCREEN_APPLE_Z2) += apple_z2.o
obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
@@ -48,7 +49,9 @@ obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE) += goodix_berlin_core.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C) += goodix_berlin_i2c.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI) += goodix_berlin_spi.o
obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o
+obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX852X) += himax_hx852x.o
obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o
+obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CST816X) += hynitron-cst816x.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o
obj-$(CONFIG_TOUCHSCREEN_IMAGIS) += imagis.o
diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c
index a0598e9c7aff..33c5eb522389 100644
--- a/drivers/input/touchscreen/ad7877.c
+++ b/drivers/input/touchscreen/ad7877.c
@@ -201,7 +201,7 @@ static int ad7877_read(struct spi_device *spi, u16 reg)
struct ser_req *req;
int status, ret;
- req = kzalloc(sizeof *req, GFP_KERNEL);
+ req = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
@@ -232,7 +232,7 @@ static int ad7877_write(struct spi_device *spi, u16 reg, u16 val)
struct ser_req *req;
int status;
- req = kzalloc(sizeof *req, GFP_KERNEL);
+ req = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
@@ -259,7 +259,7 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command)
int sample;
int i;
- req = kzalloc(sizeof *req, GFP_KERNEL);
+ req = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
@@ -375,7 +375,7 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts)
static void ad7877_timer(struct timer_list *t)
{
- struct ad7877 *ts = from_timer(ts, t, timer);
+ struct ad7877 *ts = timer_container_of(ts, t, timer);
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
@@ -415,7 +415,7 @@ static void ad7877_disable(void *data)
ts->disabled = true;
disable_irq(ts->spi->irq);
- if (del_timer_sync(&ts->timer))
+ if (timer_delete_sync(&ts->timer))
ad7877_ts_event_release(ts);
}
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index e5d69bf2276e..4c448f39bf57 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -22,6 +22,7 @@
#include <linux/device.h>
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -237,7 +238,7 @@ static void ad7879_ts_event_release(struct ad7879 *ts)
static void ad7879_timer(struct timer_list *t)
{
- struct ad7879 *ts = from_timer(ts, t, timer);
+ struct ad7879 *ts = timer_container_of(ts, t, timer);
ad7879_ts_event_release(ts);
}
@@ -273,7 +274,7 @@ static void __ad7879_disable(struct ad7879 *ts)
AD7879_PM(AD7879_PM_SHUTDOWN);
disable_irq(ts->irq);
- if (del_timer_sync(&ts->timer))
+ if (timer_delete_sync(&ts->timer))
ad7879_ts_event_release(ts);
ad7879_write(ts, AD7879_REG_CTRL2, reg);
@@ -444,10 +445,11 @@ static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
return !!(val & AD7879_GPIO_DATA);
}
-static void ad7879_gpio_set_value(struct gpio_chip *chip,
- unsigned gpio, int value)
+static int ad7879_gpio_set_value(struct gpio_chip *chip, unsigned int gpio,
+ int value)
{
struct ad7879 *ts = gpiochip_get_data(chip);
+ int ret;
mutex_lock(&ts->mutex);
if (value)
@@ -455,8 +457,10 @@ static void ad7879_gpio_set_value(struct gpio_chip *chip,
else
ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
- ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
+ ret = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
mutex_unlock(&ts->mutex);
+
+ return ret;
}
static int ad7879_gpio_add(struct ad7879 *ts)
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 67264c5b49cb..0963b1a78a0c 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -357,7 +357,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
struct ser_req *req;
int status;
- req = kzalloc(sizeof *req, GFP_KERNEL);
+ req = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
@@ -442,7 +442,7 @@ static int ads7845_read12_ser(struct device *dev, unsigned command)
struct ads7845_ser_req *req;
int status;
- req = kzalloc(sizeof *req, GFP_KERNEL);
+ req = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
diff --git a/drivers/input/touchscreen/apple_z2.c b/drivers/input/touchscreen/apple_z2.c
new file mode 100644
index 000000000000..271ababf0ad5
--- /dev/null
+++ b/drivers/input/touchscreen/apple_z2.c
@@ -0,0 +1,481 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Apple Z2 touchscreen driver
+ *
+ * Copyright (C) The Asahi Linux Contributors
+ */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+#include <linux/unaligned.h>
+
+#define APPLE_Z2_NUM_FINGERS_OFFSET 16
+#define APPLE_Z2_FINGERS_OFFSET 24
+#define APPLE_Z2_TOUCH_STARTED 3
+#define APPLE_Z2_TOUCH_MOVED 4
+#define APPLE_Z2_CMD_READ_INTERRUPT_DATA 0xEB
+#define APPLE_Z2_REPLY_INTERRUPT_DATA 0xE1
+#define APPLE_Z2_HBPP_CMD_BLOB 0x3001
+#define APPLE_Z2_FW_MAGIC 0x5746325A
+#define LOAD_COMMAND_INIT_PAYLOAD 0
+#define LOAD_COMMAND_SEND_BLOB 1
+#define LOAD_COMMAND_SEND_CALIBRATION 2
+#define CAL_PROP_NAME "apple,z2-cal-blob"
+
+struct apple_z2 {
+ struct spi_device *spidev;
+ struct gpio_desc *reset_gpio;
+ struct input_dev *input_dev;
+ struct completion boot_irq;
+ bool booted;
+ int index_parity;
+ struct touchscreen_properties props;
+ const char *fw_name;
+ u8 *tx_buf;
+ u8 *rx_buf;
+};
+
+struct apple_z2_finger {
+ u8 finger;
+ u8 state;
+ __le16 unknown2;
+ __le16 abs_x;
+ __le16 abs_y;
+ __le16 rel_x;
+ __le16 rel_y;
+ __le16 tool_major;
+ __le16 tool_minor;
+ __le16 orientation;
+ __le16 touch_major;
+ __le16 touch_minor;
+ __le16 unused[2];
+ __le16 pressure;
+ __le16 multi;
+} __packed;
+
+struct apple_z2_hbpp_blob_hdr {
+ __le16 cmd;
+ __le16 len;
+ __le32 addr;
+ __le16 checksum;
+};
+
+struct apple_z2_fw_hdr {
+ __le32 magic;
+ __le32 version;
+};
+
+struct apple_z2_read_interrupt_cmd {
+ u8 cmd;
+ u8 counter;
+ u8 unused[12];
+ __le16 checksum;
+};
+
+static void apple_z2_parse_touches(struct apple_z2 *z2,
+ const u8 *msg, size_t msg_len)
+{
+ int i;
+ int nfingers;
+ int slot;
+ int slot_valid;
+ struct apple_z2_finger *fingers;
+
+ if (msg_len <= APPLE_Z2_NUM_FINGERS_OFFSET)
+ return;
+ nfingers = msg[APPLE_Z2_NUM_FINGERS_OFFSET];
+ fingers = (struct apple_z2_finger *)(msg + APPLE_Z2_FINGERS_OFFSET);
+ for (i = 0; i < nfingers; i++) {
+ slot = input_mt_get_slot_by_key(z2->input_dev, fingers[i].finger);
+ if (slot < 0) {
+ dev_warn(&z2->spidev->dev, "unable to get slot for finger\n");
+ continue;
+ }
+ slot_valid = fingers[i].state == APPLE_Z2_TOUCH_STARTED ||
+ fingers[i].state == APPLE_Z2_TOUCH_MOVED;
+ input_mt_slot(z2->input_dev, slot);
+ if (!input_mt_report_slot_state(z2->input_dev, MT_TOOL_FINGER, slot_valid))
+ continue;
+ touchscreen_report_pos(z2->input_dev, &z2->props,
+ le16_to_cpu(fingers[i].abs_x),
+ le16_to_cpu(fingers[i].abs_y),
+ true);
+ input_report_abs(z2->input_dev, ABS_MT_WIDTH_MAJOR,
+ le16_to_cpu(fingers[i].tool_major));
+ input_report_abs(z2->input_dev, ABS_MT_WIDTH_MINOR,
+ le16_to_cpu(fingers[i].tool_minor));
+ input_report_abs(z2->input_dev, ABS_MT_ORIENTATION,
+ le16_to_cpu(fingers[i].orientation));
+ input_report_abs(z2->input_dev, ABS_MT_TOUCH_MAJOR,
+ le16_to_cpu(fingers[i].touch_major));
+ input_report_abs(z2->input_dev, ABS_MT_TOUCH_MINOR,
+ le16_to_cpu(fingers[i].touch_minor));
+ }
+ input_mt_sync_frame(z2->input_dev);
+ input_sync(z2->input_dev);
+}
+
+static int apple_z2_read_packet(struct apple_z2 *z2)
+{
+ struct apple_z2_read_interrupt_cmd *len_cmd = (void *)z2->tx_buf;
+ struct spi_transfer xfer;
+ int error;
+ size_t pkt_len;
+
+ memset(&xfer, 0, sizeof(xfer));
+ len_cmd->cmd = APPLE_Z2_CMD_READ_INTERRUPT_DATA;
+ len_cmd->counter = z2->index_parity + 1;
+ len_cmd->checksum =
+ cpu_to_le16(APPLE_Z2_CMD_READ_INTERRUPT_DATA + len_cmd->counter);
+ z2->index_parity = !z2->index_parity;
+ xfer.tx_buf = z2->tx_buf;
+ xfer.rx_buf = z2->rx_buf;
+ xfer.len = sizeof(*len_cmd);
+
+ error = spi_sync_transfer(z2->spidev, &xfer, 1);
+ if (error)
+ return error;
+
+ if (z2->rx_buf[0] != APPLE_Z2_REPLY_INTERRUPT_DATA)
+ return 0;
+
+ pkt_len = (get_unaligned_le16(z2->rx_buf + 1) + 8) & 0xfffffffc;
+
+ error = spi_read(z2->spidev, z2->rx_buf, pkt_len);
+ if (error)
+ return error;
+
+ apple_z2_parse_touches(z2, z2->rx_buf + 5, pkt_len - 5);
+
+ return 0;
+}
+
+static irqreturn_t apple_z2_irq(int irq, void *data)
+{
+ struct apple_z2 *z2 = data;
+
+ if (unlikely(!z2->booted))
+ complete(&z2->boot_irq);
+ else
+ apple_z2_read_packet(z2);
+
+ return IRQ_HANDLED;
+}
+
+/* Build calibration blob, caller is responsible for freeing the blob data. */
+static const u8 *apple_z2_build_cal_blob(struct apple_z2 *z2,
+ u32 address, size_t *size)
+{
+ u8 *cal_data;
+ int cal_size;
+ size_t blob_size;
+ u32 checksum;
+ u16 checksum_hdr;
+ int i;
+ struct apple_z2_hbpp_blob_hdr *hdr;
+ int error;
+
+ if (!device_property_present(&z2->spidev->dev, CAL_PROP_NAME))
+ return NULL;
+
+ cal_size = device_property_count_u8(&z2->spidev->dev, CAL_PROP_NAME);
+ if (cal_size < 0)
+ return ERR_PTR(cal_size);
+
+ blob_size = sizeof(struct apple_z2_hbpp_blob_hdr) + cal_size + sizeof(__le32);
+ u8 *blob_data __free(kfree) = kzalloc(blob_size, GFP_KERNEL);
+ if (!blob_data)
+ return ERR_PTR(-ENOMEM);
+
+ hdr = (struct apple_z2_hbpp_blob_hdr *)blob_data;
+ hdr->cmd = cpu_to_le16(APPLE_Z2_HBPP_CMD_BLOB);
+ hdr->len = cpu_to_le16(round_up(cal_size, 4) / 4);
+ hdr->addr = cpu_to_le32(address);
+
+ checksum_hdr = 0;
+ for (i = 2; i < 8; i++)
+ checksum_hdr += blob_data[i];
+ hdr->checksum = cpu_to_le16(checksum_hdr);
+
+ cal_data = blob_data + sizeof(struct apple_z2_hbpp_blob_hdr);
+ error = device_property_read_u8_array(&z2->spidev->dev, CAL_PROP_NAME,
+ cal_data, cal_size);
+ if (error)
+ return ERR_PTR(error);
+
+ checksum = 0;
+ for (i = 0; i < cal_size; i++)
+ checksum += cal_data[i];
+ put_unaligned_le32(checksum, cal_data + cal_size);
+
+ *size = blob_size;
+ return no_free_ptr(blob_data);
+}
+
+static int apple_z2_send_firmware_blob(struct apple_z2 *z2, const u8 *data,
+ u32 size, bool init)
+{
+ struct spi_message msg;
+ struct spi_transfer blob_xfer, ack_xfer;
+ int error;
+
+ z2->tx_buf[0] = 0x1a;
+ z2->tx_buf[1] = 0xa1;
+
+ spi_message_init(&msg);
+ memset(&blob_xfer, 0, sizeof(blob_xfer));
+ memset(&ack_xfer, 0, sizeof(ack_xfer));
+
+ blob_xfer.tx_buf = data;
+ blob_xfer.len = size;
+ blob_xfer.bits_per_word = init ? 8 : 16;
+ spi_message_add_tail(&blob_xfer, &msg);
+
+ ack_xfer.tx_buf = z2->tx_buf;
+ ack_xfer.len = 2;
+ spi_message_add_tail(&ack_xfer, &msg);
+
+ reinit_completion(&z2->boot_irq);
+ error = spi_sync(z2->spidev, &msg);
+ if (error)
+ return error;
+
+ /* Irq only happens sometimes, but the thing boots reliably nonetheless */
+ wait_for_completion_timeout(&z2->boot_irq, msecs_to_jiffies(20));
+
+ return 0;
+}
+
+static int apple_z2_upload_firmware(struct apple_z2 *z2)
+{
+ const struct apple_z2_fw_hdr *fw_hdr;
+ size_t fw_idx = sizeof(struct apple_z2_fw_hdr);
+ int error;
+ u32 load_cmd;
+ u32 address;
+ bool init;
+ size_t size;
+
+ const struct firmware *fw __free(firmware) = NULL;
+ error = request_firmware(&fw, z2->fw_name, &z2->spidev->dev);
+ if (error) {
+ dev_err(&z2->spidev->dev, "unable to load firmware\n");
+ return error;
+ }
+
+ fw_hdr = (const struct apple_z2_fw_hdr *)fw->data;
+ if (le32_to_cpu(fw_hdr->magic) != APPLE_Z2_FW_MAGIC || le32_to_cpu(fw_hdr->version) != 1) {
+ dev_err(&z2->spidev->dev, "invalid firmware header\n");
+ return -EINVAL;
+ }
+
+ /*
+ * This will interrupt the upload half-way if the file is malformed
+ * As the device has no non-volatile storage to corrupt, and gets reset
+ * on boot anyway, this is fine.
+ */
+ while (fw_idx < fw->size) {
+ if (fw->size - fw_idx < 8) {
+ dev_err(&z2->spidev->dev, "firmware malformed\n");
+ return -EINVAL;
+ }
+
+ load_cmd = le32_to_cpup((__force __le32 *)(fw->data + fw_idx));
+ fw_idx += sizeof(u32);
+ if (load_cmd == LOAD_COMMAND_INIT_PAYLOAD || load_cmd == LOAD_COMMAND_SEND_BLOB) {
+ size = le32_to_cpup((__force __le32 *)(fw->data + fw_idx));
+ fw_idx += sizeof(u32);
+ if (fw->size - fw_idx < size) {
+ dev_err(&z2->spidev->dev, "firmware malformed\n");
+ return -EINVAL;
+ }
+ init = load_cmd == LOAD_COMMAND_INIT_PAYLOAD;
+ error = apple_z2_send_firmware_blob(z2, fw->data + fw_idx,
+ size, init);
+ if (error)
+ return error;
+ fw_idx += size;
+ } else if (load_cmd == LOAD_COMMAND_SEND_CALIBRATION) {
+ address = le32_to_cpup((__force __le32 *)(fw->data + fw_idx));
+ fw_idx += sizeof(u32);
+
+ const u8 *data __free(kfree) =
+ apple_z2_build_cal_blob(z2, address, &size);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ if (data) {
+ error = apple_z2_send_firmware_blob(z2, data, size, false);
+ if (error)
+ return error;
+ }
+ } else {
+ dev_err(&z2->spidev->dev, "firmware malformed\n");
+ return -EINVAL;
+ }
+ fw_idx = round_up(fw_idx, 4);
+ }
+
+
+ z2->booted = true;
+ apple_z2_read_packet(z2);
+ return 0;
+}
+
+static int apple_z2_boot(struct apple_z2 *z2)
+{
+ int error;
+
+ reinit_completion(&z2->boot_irq);
+ enable_irq(z2->spidev->irq);
+ gpiod_set_value(z2->reset_gpio, 0);
+ if (!wait_for_completion_timeout(&z2->boot_irq, msecs_to_jiffies(20)))
+ return -ETIMEDOUT;
+
+ error = apple_z2_upload_firmware(z2);
+ if (error) {
+ gpiod_set_value(z2->reset_gpio, 1);
+ disable_irq(z2->spidev->irq);
+ return error;
+ }
+
+ return 0;
+}
+
+static int apple_z2_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct apple_z2 *z2;
+ int error;
+
+ z2 = devm_kzalloc(dev, sizeof(*z2), GFP_KERNEL);
+ if (!z2)
+ return -ENOMEM;
+
+ z2->tx_buf = devm_kzalloc(dev, sizeof(struct apple_z2_read_interrupt_cmd), GFP_KERNEL);
+ if (!z2->tx_buf)
+ return -ENOMEM;
+ /* 4096 will end up being rounded up to 8192 due to devres header */
+ z2->rx_buf = devm_kzalloc(dev, 4000, GFP_KERNEL);
+ if (!z2->rx_buf)
+ return -ENOMEM;
+
+ z2->spidev = spi;
+ init_completion(&z2->boot_irq);
+ spi_set_drvdata(spi, z2);
+
+ /* Reset the device on boot */
+ z2->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(z2->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(z2->reset_gpio), "unable to get reset\n");
+
+ error = devm_request_threaded_irq(dev, z2->spidev->irq, NULL, apple_z2_irq,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN,
+ "apple-z2-irq", z2);
+ if (error)
+ return dev_err_probe(dev, error, "unable to request irq\n");
+
+ error = device_property_read_string(dev, "firmware-name", &z2->fw_name);
+ if (error)
+ return dev_err_probe(dev, error, "unable to get firmware name\n");
+
+ z2->input_dev = devm_input_allocate_device(dev);
+ if (!z2->input_dev)
+ return -ENOMEM;
+
+ z2->input_dev->name = (char *)spi_get_device_id(spi)->driver_data;
+ z2->input_dev->phys = "apple_z2";
+ z2->input_dev->id.bustype = BUS_SPI;
+
+ /* Allocate the axes before setting from DT */
+ input_set_abs_params(z2->input_dev, ABS_MT_POSITION_X, 0, 0, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_POSITION_Y, 0, 0, 0, 0);
+ touchscreen_parse_properties(z2->input_dev, true, &z2->props);
+ input_abs_set_res(z2->input_dev, ABS_MT_POSITION_X, 100);
+ input_abs_set_res(z2->input_dev, ABS_MT_POSITION_Y, 100);
+ input_set_abs_params(z2->input_dev, ABS_MT_WIDTH_MAJOR, 0, 65535, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_WIDTH_MINOR, 0, 65535, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_TOUCH_MAJOR, 0, 65535, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_TOUCH_MINOR, 0, 65535, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_ORIENTATION, -32768, 32767, 0, 0);
+
+ error = input_mt_init_slots(z2->input_dev, 256, INPUT_MT_DIRECT);
+ if (error)
+ return dev_err_probe(dev, error, "unable to initialize multitouch slots\n");
+
+ error = input_register_device(z2->input_dev);
+ if (error)
+ return dev_err_probe(dev, error, "unable to register input device\n");
+
+ /* Wait for device reset to finish */
+ usleep_range(5000, 10000);
+ error = apple_z2_boot(z2);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static void apple_z2_shutdown(struct spi_device *spi)
+{
+ struct apple_z2 *z2 = spi_get_drvdata(spi);
+
+ disable_irq(z2->spidev->irq);
+ gpiod_direction_output(z2->reset_gpio, 1);
+ z2->booted = false;
+}
+
+static int apple_z2_suspend(struct device *dev)
+{
+ apple_z2_shutdown(to_spi_device(dev));
+
+ return 0;
+}
+
+static int apple_z2_resume(struct device *dev)
+{
+ struct apple_z2 *z2 = spi_get_drvdata(to_spi_device(dev));
+
+ return apple_z2_boot(z2);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(apple_z2_pm, apple_z2_suspend, apple_z2_resume);
+
+static const struct of_device_id apple_z2_of_match[] = {
+ { .compatible = "apple,j293-touchbar" },
+ { .compatible = "apple,j493-touchbar" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, apple_z2_of_match);
+
+static struct spi_device_id apple_z2_of_id[] = {
+ { .name = "j293-touchbar", .driver_data = (kernel_ulong_t)"MacBookPro17,1 Touch Bar" },
+ { .name = "j493-touchbar", .driver_data = (kernel_ulong_t)"Mac14,7 Touch Bar" },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, apple_z2_of_id);
+
+static struct spi_driver apple_z2_driver = {
+ .driver = {
+ .name = "apple-z2",
+ .pm = pm_sleep_ptr(&apple_z2_pm),
+ .of_match_table = apple_z2_of_match,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .id_table = apple_z2_of_id,
+ .probe = apple_z2_probe,
+ .remove = apple_z2_shutdown,
+};
+
+module_spi_driver(apple_z2_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("apple/dfrmtfw-*.bin");
+MODULE_DESCRIPTION("Apple Z2 touchscreens driver");
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3ddabc5a2c99..dd0544cc1bc1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -19,6 +19,7 @@
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h>
@@ -355,6 +356,8 @@ struct mxt_data {
enum mxt_suspend_mode suspend_mode;
u32 wakeup_method;
+
+ struct touchscreen_properties prop;
};
struct mxt_vb2_buffer {
@@ -888,8 +891,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
/* Touch active */
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
- input_report_abs(input_dev, ABS_MT_POSITION_X, x);
- input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ touchscreen_report_pos(input_dev, &data->prop, x, y, true);
input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
} else {
@@ -1010,8 +1012,7 @@ static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
id, type, x, y, major, pressure, orientation);
input_mt_report_slot_state(input_dev, tool, 1);
- input_report_abs(input_dev, ABS_MT_POSITION_X, x);
- input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ touchscreen_report_pos(input_dev, &data->prop, x, y, true);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, major);
input_report_abs(input_dev, ABS_MT_PRESSURE, pressure);
input_report_abs(input_dev, ABS_MT_DISTANCE, distance);
@@ -2212,6 +2213,8 @@ static int mxt_initialize_input_device(struct mxt_data *data)
0, 255, 0, 0);
}
+ touchscreen_parse_properties(input_dev, true, &data->prop);
+
/* For T15 and T97 Key Array */
if (data->T15_reportid_min || data->T97_reportid_min) {
for (i = 0; i < data->t15_num_keys; i++)
@@ -2535,8 +2538,6 @@ fault:
static const struct vb2_ops mxt_queue_ops = {
.queue_setup = mxt_queue_setup,
.buf_queue = mxt_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static const struct vb2_queue mxt_queue = {
@@ -3319,7 +3320,7 @@ static int mxt_probe(struct i2c_client *client)
if (data->reset_gpio) {
/* Wait a while and then de-assert the RESET GPIO line */
msleep(MXT_RESET_GPIO_TIME);
- gpiod_set_value(data->reset_gpio, 0);
+ gpiod_set_value_cansleep(data->reset_gpio, 0);
msleep(MXT_RESET_INVALID_CHG);
}
diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c
index 686d0a6b1570..64f474e67312 100644
--- a/drivers/input/touchscreen/bu21029_ts.c
+++ b/drivers/input/touchscreen/bu21029_ts.c
@@ -209,7 +209,8 @@ static void bu21029_touch_report(struct bu21029_ts_data *bu21029, const u8 *buf)
static void bu21029_touch_release(struct timer_list *t)
{
- struct bu21029_ts_data *bu21029 = from_timer(bu21029, t, timer);
+ struct bu21029_ts_data *bu21029 = timer_container_of(bu21029, t,
+ timer);
input_report_abs(bu21029->in_dev, ABS_PRESSURE, 0);
input_report_key(bu21029->in_dev, BTN_TOUCH, 0);
@@ -325,7 +326,7 @@ static void bu21029_stop_chip(struct input_dev *dev)
struct bu21029_ts_data *bu21029 = input_get_drvdata(dev);
disable_irq(bu21029->client->irq);
- del_timer_sync(&bu21029->timer);
+ timer_delete_sync(&bu21029->timer);
bu21029_put_chip_in_reset(bu21029);
regulator_disable(bu21029->vdd);
diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c
index eafe5a9b8964..47f4271395a6 100644
--- a/drivers/input/touchscreen/cyttsp5.c
+++ b/drivers/input/touchscreen/cyttsp5.c
@@ -580,7 +580,7 @@ static int cyttsp5_power_control(struct cyttsp5 *ts, bool on)
int rc;
SET_CMD_REPORT_TYPE(cmd[0], 0);
- SET_CMD_REPORT_ID(cmd[0], HID_POWER_SLEEP);
+ SET_CMD_REPORT_ID(cmd[0], state);
SET_CMD_OPCODE(cmd[1], HID_CMD_SET_POWER);
rc = cyttsp5_write(ts, HID_COMMAND_REG, cmd, sizeof(cmd));
@@ -870,13 +870,16 @@ static int cyttsp5_probe(struct device *dev, struct regmap *regmap, int irq,
ts->input->phys = ts->phys;
input_set_drvdata(ts->input, ts);
- /* Reset the gpio to be in a reset state */
+ /* Assert 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;
}
+
+ fsleep(10); /* Ensure long-enough reset pulse (minimum 10us). */
+
gpiod_set_value_cansleep(ts->reset_gpio, 0);
/* Need a delay to have device up */
@@ -920,8 +923,8 @@ static int cyttsp5_i2c_probe(struct i2c_client *client)
regmap = devm_regmap_init_i2c(client, &config);
if (IS_ERR(regmap)) {
- dev_err(&client->dev, "regmap allocation failed: %ld\n",
- PTR_ERR(regmap));
+ dev_err(&client->dev, "regmap allocation failed: %pe\n",
+ regmap);
return PTR_ERR(regmap);
}
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
index b8ce6012364c..9e729910fbc8 100644
--- a/drivers/input/touchscreen/cyttsp_core.c
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -14,6 +14,7 @@
*/
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c
index c2d3252f8466..a8e3d85eece7 100644
--- a/drivers/input/touchscreen/da9052_tsi.c
+++ b/drivers/input/touchscreen/da9052_tsi.c
@@ -232,7 +232,7 @@ static int da9052_ts_probe(struct platform_device *pdev)
if (!da9052)
return -EINVAL;
- tsi = kzalloc(sizeof(*tsi), GFP_KERNEL);
+ tsi = kzalloc_obj(*tsi);
input_dev = input_allocate_device();
if (!tsi || !input_dev) {
error = -ENOMEM;
diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c
index fe626a226b85..943ba8c2fb6c 100644
--- a/drivers/input/touchscreen/dynapro.c
+++ b/drivers/input/touchscreen/dynapro.c
@@ -110,7 +110,7 @@ static int dynapro_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- pdynapro = kzalloc(sizeof(*pdynapro), GFP_KERNEL);
+ pdynapro = kzalloc_obj(*pdynapro);
input_dev = input_allocate_device();
if (!pdynapro || !input_dev) {
err = -ENOMEM;
@@ -119,8 +119,8 @@ static int dynapro_connect(struct serio *serio, struct serio_driver *drv)
pdynapro->serio = serio;
pdynapro->dev = input_dev;
- snprintf(pdynapro->phys, sizeof(pdynapro->phys),
- "%s/input0", serio->phys);
+ scnprintf(pdynapro->phys, sizeof(pdynapro->phys),
+ "%s/input0", serio->phys);
input_dev->name = "Dynapro Serial TouchScreen";
input_dev->phys = pdynapro->phys;
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 0d7bf18e2508..d0ab644be006 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -120,7 +120,6 @@ struct edt_ft5x06_ts_data {
struct regmap *regmap;
#if defined(CONFIG_DEBUG_FS)
- struct dentry *debug_dir;
u8 *raw_buffer;
size_t raw_bufsize;
#endif
@@ -815,23 +814,21 @@ static const struct file_operations debugfs_raw_data_fops = {
.read = edt_ft5x06_debugfs_raw_data_read,
};
-static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
- const char *debugfs_name)
+static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata)
{
- tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL);
+ struct dentry *debug_dir = tsdata->client->debugfs;
- debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x);
- debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y);
+ debugfs_create_u16("num_x", S_IRUSR, debug_dir, &tsdata->num_x);
+ debugfs_create_u16("num_y", S_IRUSR, debug_dir, &tsdata->num_y);
debugfs_create_file("mode", S_IRUSR | S_IWUSR,
- tsdata->debug_dir, tsdata, &debugfs_mode_fops);
+ debug_dir, tsdata, &debugfs_mode_fops);
debugfs_create_file("raw_data", S_IRUSR,
- tsdata->debug_dir, tsdata, &debugfs_raw_data_fops);
+ debug_dir, tsdata, &debugfs_raw_data_fops);
}
static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
{
- debugfs_remove_recursive(tsdata->debug_dir);
kfree(tsdata->raw_buffer);
}
@@ -842,8 +839,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
return -ENOSYS;
}
-static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
- const char *debugfs_name)
+static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata)
{
}
@@ -1349,7 +1345,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
if (error)
return error;
- edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
+ edt_ft5x06_ts_prepare_debugfs(tsdata);
dev_dbg(&client->dev,
"EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
@@ -1479,6 +1475,10 @@ static const struct edt_i2c_chip_data edt_ft5x06_data = {
.max_support_points = 5,
};
+static const struct edt_i2c_chip_data edt_ft3518_data = {
+ .max_support_points = 10,
+};
+
static const struct edt_i2c_chip_data edt_ft5452_data = {
.max_support_points = 5,
};
@@ -1495,6 +1495,10 @@ static const struct edt_i2c_chip_data edt_ft8201_data = {
.max_support_points = 10,
};
+static const struct edt_i2c_chip_data edt_ft8716_data = {
+ .max_support_points = 10,
+};
+
static const struct edt_i2c_chip_data edt_ft8719_data = {
.max_support_points = 10,
};
@@ -1503,10 +1507,12 @@ static const struct i2c_device_id edt_ft5x06_ts_id[] = {
{ .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data },
{ .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data },
{ .name = "ev-ft5726", .driver_data = (long)&edt_ft5506_data },
+ { .name = "ft3518", .driver_data = (long)&edt_ft3518_data },
{ .name = "ft5452", .driver_data = (long)&edt_ft5452_data },
/* Note no edt- prefix for compatibility with the ft6236.c driver */
{ .name = "ft6236", .driver_data = (long)&edt_ft6236_data },
{ .name = "ft8201", .driver_data = (long)&edt_ft8201_data },
+ { .name = "ft8716", .driver_data = (long)&edt_ft8716_data },
{ .name = "ft8719", .driver_data = (long)&edt_ft8719_data },
{ /* sentinel */ }
};
@@ -1518,11 +1524,13 @@ static const struct of_device_id edt_ft5x06_of_match[] = {
{ .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data },
{ .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data },
{ .compatible = "evervision,ev-ft5726", .data = &edt_ft5506_data },
+ { .compatible = "focaltech,ft3518", .data = &edt_ft3518_data },
{ .compatible = "focaltech,ft5426", .data = &edt_ft5506_data },
{ .compatible = "focaltech,ft5452", .data = &edt_ft5452_data },
/* Note focaltech vendor prefix for compatibility with ft6236.c */
{ .compatible = "focaltech,ft6236", .data = &edt_ft6236_data },
{ .compatible = "focaltech,ft8201", .data = &edt_ft8201_data },
+ { .compatible = "focaltech,ft8716", .data = &edt_ft8716_data },
{ .compatible = "focaltech,ft8719", .data = &edt_ft8719_data },
{ /* sentinel */ }
};
diff --git a/drivers/input/touchscreen/egalax_ts_serial.c b/drivers/input/touchscreen/egalax_ts_serial.c
index 07a4aa1c19bb..e04ea1fea4ad 100644
--- a/drivers/input/touchscreen/egalax_ts_serial.c
+++ b/drivers/input/touchscreen/egalax_ts_serial.c
@@ -99,7 +99,7 @@ static int egalax_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int error;
- egalax = kzalloc(sizeof(*egalax), GFP_KERNEL);
+ egalax = kzalloc_obj(*egalax);
input_dev = input_allocate_device();
if (!egalax || !input_dev) {
error = -ENOMEM;
@@ -108,8 +108,7 @@ static int egalax_connect(struct serio *serio, struct serio_driver *drv)
egalax->serio = serio;
egalax->input = input_dev;
- snprintf(egalax->phys, sizeof(egalax->phys),
- "%s/input0", serio->phys);
+ scnprintf(egalax->phys, sizeof(egalax->phys), "%s/input0", serio->phys);
input_dev->name = "EETI eGalaxTouch Serial TouchScreen";
input_dev->phys = egalax->phys;
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index ad209e6e82a6..434b9b47e964 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -307,7 +307,7 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- elo = kzalloc(sizeof(*elo), GFP_KERNEL);
+ elo = kzalloc_obj(*elo);
input_dev = input_allocate_device();
if (!elo || !input_dev) {
err = -ENOMEM;
@@ -320,7 +320,7 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
elo->expected_packet = ELO10_TOUCH_PACKET;
mutex_init(&elo->cmd_mutex);
init_completion(&elo->cmd_done);
- snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys);
+ scnprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys);
input_dev->name = "Elo Serial TouchScreen";
input_dev->phys = elo->phys;
diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c
index fdda8412b164..28da7ba55a4b 100644
--- a/drivers/input/touchscreen/exc3000.c
+++ b/drivers/input/touchscreen/exc3000.c
@@ -105,7 +105,7 @@ static void exc3000_report_slots(struct input_dev *input,
static void exc3000_timer(struct timer_list *t)
{
- struct exc3000_data *data = from_timer(data, t, timer);
+ struct exc3000_data *data = timer_container_of(data, t, timer);
input_mt_sync_frame(data->input);
input_sync(data->input);
@@ -174,7 +174,7 @@ static int exc3000_handle_mt_event(struct exc3000_data *data)
/*
* We read full state successfully, no contacts will be "stuck".
*/
- del_timer_sync(&data->timer);
+ timer_delete_sync(&data->timer);
while (total_slots > 0) {
int slots = min(total_slots, EXC3000_SLOTS_PER_FRAME);
diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c
index a32708652d10..ff270b3b8572 100644
--- a/drivers/input/touchscreen/fsl-imx25-tcq.c
+++ b/drivers/input/touchscreen/fsl-imx25-tcq.c
@@ -39,7 +39,6 @@ struct mx25_tcq_priv {
};
static const struct regmap_config mx25_tcq_regconfig = {
- .fast_io = true,
.max_register = 0x5c,
.reg_bits = 32,
.val_bits = 32,
diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c
index 1a3e14ea2e08..8ed592294b17 100644
--- a/drivers/input/touchscreen/fujitsu_ts.c
+++ b/drivers/input/touchscreen/fujitsu_ts.c
@@ -99,7 +99,7 @@ static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- fujitsu = kzalloc(sizeof(*fujitsu), GFP_KERNEL);
+ fujitsu = kzalloc_obj(*fujitsu);
input_dev = input_allocate_device();
if (!fujitsu || !input_dev) {
err = -ENOMEM;
@@ -108,8 +108,7 @@ static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
fujitsu->serio = serio;
fujitsu->dev = input_dev;
- snprintf(fujitsu->phys, sizeof(fujitsu->phys),
- "%s/input0", serio->phys);
+ scnprintf(fujitsu->phys, sizeof(fujitsu->phys), "%s/input0", serio->phys);
input_dev->name = "Fujitsu Serial Touchscreen";
input_dev->phys = fujitsu->phys;
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index a3e8a51c9144..f8798d11ec03 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -44,9 +44,11 @@
#define GOODIX_HAVE_KEY BIT(4)
#define GOODIX_BUFFER_STATUS_TIMEOUT 20
-#define RESOLUTION_LOC 1
-#define MAX_CONTACTS_LOC 5
-#define TRIGGER_LOC 6
+#define RESOLUTION_LOC 1
+#define MAX_CONTACTS_LOC 5
+#define TRIGGER_LOC 6
+
+#define GOODIX_POLL_INTERVAL_MS 17 /* 17ms = 60fps */
/* Our special handling for GPIO accesses through ACPI is x86 specific */
#if defined CONFIG_X86 && defined CONFIG_ACPI
@@ -497,6 +499,14 @@ sync:
input_sync(ts->input_dev);
}
+static void goodix_ts_work_i2c_poll(struct input_dev *input)
+{
+ struct goodix_ts_data *ts = input_get_drvdata(input);
+
+ goodix_process_events(ts);
+ goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0);
+}
+
/**
* goodix_ts_irq_handler - The IRQ handler
*
@@ -513,13 +523,29 @@ static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void goodix_enable_irq(struct goodix_ts_data *ts)
+{
+ if (ts->client->irq)
+ enable_irq(ts->client->irq);
+}
+
+static void goodix_disable_irq(struct goodix_ts_data *ts)
+{
+ if (ts->client->irq)
+ disable_irq(ts->client->irq);
+}
+
static void goodix_free_irq(struct goodix_ts_data *ts)
{
- devm_free_irq(&ts->client->dev, ts->client->irq, ts);
+ if (ts->client->irq)
+ devm_free_irq(&ts->client->dev, ts->client->irq, ts);
}
static int goodix_request_irq(struct goodix_ts_data *ts)
{
+ if (!ts->client->irq)
+ return 0;
+
return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
NULL, goodix_ts_irq_handler,
ts->irq_flags, ts->client->name, ts);
@@ -770,17 +796,6 @@ int goodix_reset_no_int_sync(struct goodix_ts_data *ts)
usleep_range(6000, 10000); /* T4: > 5ms */
- /*
- * Put the reset pin back in to input / high-impedance mode to save
- * power. Only do this in the non ACPI case since some ACPI boards
- * don't have a pull-up, so there the reset pin must stay active-high.
- */
- if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_GPIO) {
- error = gpiod_direction_input(ts->gpiod_rst);
- if (error)
- goto error;
- }
-
return 0;
error:
@@ -931,14 +946,6 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
return -EINVAL;
}
- /*
- * Normally we put the reset pin in input / high-impedance mode to save
- * power. But some x86/ACPI boards don't have a pull-up, so for the ACPI
- * case, leave the pin as is. This results in the pin not being touched
- * at all on x86/ACPI boards, except when needed for error-recover.
- */
- ts->gpiod_rst_flags = GPIOD_ASIS;
-
return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping);
}
#else
@@ -963,12 +970,6 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
return -EINVAL;
dev = &ts->client->dev;
- /*
- * By default we request the reset pin as input, leaving it in
- * high-impedance when not resetting the controller to save power.
- */
- ts->gpiod_rst_flags = GPIOD_IN;
-
ts->avdd28 = devm_regulator_get(dev, "AVDD28");
if (IS_ERR(ts->avdd28))
return dev_err_probe(dev, PTR_ERR(ts->avdd28), "Failed to get AVDD28 regulator\n");
@@ -993,7 +994,7 @@ retry_get_irq_gpio:
ts->gpiod_int = gpiod;
/* Get the reset line GPIO pin number */
- gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags);
+ gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_ASIS);
if (IS_ERR(gpiod))
return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n",
GOODIX_GPIO_RST_NAME);
@@ -1219,6 +1220,18 @@ retry_read_config:
return error;
}
+ input_set_drvdata(ts->input_dev, ts);
+
+ if (!ts->client->irq) {
+ error = input_setup_polling(ts->input_dev, goodix_ts_work_i2c_poll);
+ if (error) {
+ dev_err(&ts->client->dev,
+ "could not set up polling mode, %d\n", error);
+ return error;
+ }
+ input_set_poll_interval(ts->input_dev, GOODIX_POLL_INTERVAL_MS);
+ }
+
error = input_register_device(ts->input_dev);
if (error) {
dev_err(&ts->client->dev,
@@ -1422,7 +1435,7 @@ static int goodix_suspend(struct device *dev)
/* We need gpio pins to suspend/resume */
if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
- disable_irq(client->irq);
+ goodix_disable_irq(ts);
return 0;
}
@@ -1466,7 +1479,7 @@ static int goodix_resume(struct device *dev)
int error;
if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
- enable_irq(client->irq);
+ goodix_enable_irq(ts);
return 0;
}
@@ -1519,6 +1532,7 @@ MODULE_DEVICE_TABLE(i2c, goodix_ts_id);
static const struct acpi_device_id goodix_acpi_match[] = {
{ "GDIX1001", 0 },
{ "GDIX1002", 0 },
+ { "GDIX1003", 0 },
{ "GDX9110", 0 },
{ }
};
diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h
index 87797cc88b32..0d1e8a8d2cba 100644
--- a/drivers/input/touchscreen/goodix.h
+++ b/drivers/input/touchscreen/goodix.h
@@ -88,7 +88,6 @@ struct goodix_ts_data {
struct gpio_desc *gpiod_rst;
int gpio_count;
int gpio_int_idx;
- enum gpiod_flags gpiod_rst_flags;
char id[GOODIX_ID_MAX_LEN + 1];
char cfg_name[64];
u16 version;
diff --git a/drivers/input/touchscreen/goodix_berlin.h b/drivers/input/touchscreen/goodix_berlin.h
index 38b6f9ddbdef..d8bbd4853206 100644
--- a/drivers/input/touchscreen/goodix_berlin.h
+++ b/drivers/input/touchscreen/goodix_berlin.h
@@ -12,12 +12,26 @@
#include <linux/pm.h>
+#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR_A 0x1000C
+#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D 0x10014
+
+#define GOODIX_BERLIN_IC_INFO_ADDR_A 0x10068
+#define GOODIX_BERLIN_IC_INFO_ADDR_D 0x10070
+
+struct goodix_berlin_ic_data {
+ int fw_version_info_addr;
+ int ic_info_addr;
+ ssize_t read_dummy_len;
+ ssize_t read_prefix_len;
+};
+
struct device;
struct input_id;
struct regmap;
int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
- struct regmap *regmap);
+ struct regmap *regmap,
+ const struct goodix_berlin_ic_data *ic_data);
extern const struct dev_pm_ops goodix_berlin_pm_ops;
extern const struct attribute_group *goodix_berlin_groups[];
diff --git a/drivers/input/touchscreen/goodix_berlin_core.c b/drivers/input/touchscreen/goodix_berlin_core.c
index f7ea443b152e..83f28b870531 100644
--- a/drivers/input/touchscreen/goodix_berlin_core.c
+++ b/drivers/input/touchscreen/goodix_berlin_core.c
@@ -12,7 +12,7 @@
* to the previous generations.
*
* Currently the driver only handles Multitouch events with already
- * programmed firmware and "config" for "Revision D" Berlin IC.
+ * programmed firmware and "config" for "Revision A/D" Berlin IC.
*
* Support is missing for:
* - ESD Management
@@ -20,14 +20,16 @@
* - "Config" update/flashing
* - Stylus Events
* - Gesture Events
- * - Support for older revisions (A & B)
+ * - Support for revision B
*/
#include <linux/bitfield.h>
+#include <linux/export.h>
#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/sizes.h>
@@ -53,10 +55,8 @@
#define GOODIX_BERLIN_DEV_CONFIRM_VAL 0xAA
#define GOODIX_BERLIN_BOOTOPTION_ADDR 0x10000
-#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR 0x10014
#define GOODIX_BERLIN_IC_INFO_MAX_LEN SZ_1K
-#define GOODIX_BERLIN_IC_INFO_ADDR 0x10070
#define GOODIX_BERLIN_CHECKSUM_SIZE sizeof(u16)
@@ -175,6 +175,8 @@ struct goodix_berlin_core {
/* Runtime parameters extracted from IC_INFO buffer */
u32 touch_data_addr;
+ const struct goodix_berlin_ic_data *ic_data;
+
struct goodix_berlin_event event;
};
@@ -299,7 +301,7 @@ static int goodix_berlin_read_version(struct goodix_berlin_core *cd)
{
int error;
- error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_FW_VERSION_INFO_ADDR,
+ error = regmap_raw_read(cd->regmap, cd->ic_data->fw_version_info_addr,
&cd->fw_version, sizeof(cd->fw_version));
if (error) {
dev_err(cd->dev, "error reading fw version, %d\n", error);
@@ -367,7 +369,7 @@ static int goodix_berlin_get_ic_info(struct goodix_berlin_core *cd)
if (!afe_data)
return -ENOMEM;
- error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_IC_INFO_ADDR,
+ error = regmap_raw_read(cd->regmap, cd->ic_data->ic_info_addr,
&length_raw, sizeof(length_raw));
if (error) {
dev_err(cd->dev, "failed get ic info length, %d\n", error);
@@ -380,8 +382,8 @@ static int goodix_berlin_get_ic_info(struct goodix_berlin_core *cd)
return -EINVAL;
}
- error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_IC_INFO_ADDR,
- afe_data, length);
+ error = regmap_raw_read(cd->regmap, cd->ic_data->ic_info_addr, afe_data,
+ length);
if (error) {
dev_err(cd->dev, "failed get ic info data, %d\n", error);
return error;
@@ -706,7 +708,7 @@ static const struct bin_attribute *const goodix_berlin_bin_attrs[] = {
};
static const struct attribute_group goodix_berlin_attr_group = {
- .bin_attrs_new = goodix_berlin_bin_attrs,
+ .bin_attrs = goodix_berlin_bin_attrs,
};
const struct attribute_group *goodix_berlin_groups[] = {
@@ -716,7 +718,8 @@ const struct attribute_group *goodix_berlin_groups[] = {
EXPORT_SYMBOL_GPL(goodix_berlin_groups);
int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
- struct regmap *regmap)
+ struct regmap *regmap,
+ const struct goodix_berlin_ic_data *ic_data)
{
struct goodix_berlin_core *cd;
int error;
@@ -733,6 +736,7 @@ int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
cd->dev = dev;
cd->regmap = regmap;
cd->irq = irq;
+ cd->ic_data = ic_data;
cd->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(cd->reset_gpio))
diff --git a/drivers/input/touchscreen/goodix_berlin_i2c.c b/drivers/input/touchscreen/goodix_berlin_i2c.c
index ad7a60d94338..929090a094bf 100644
--- a/drivers/input/touchscreen/goodix_berlin_i2c.c
+++ b/drivers/input/touchscreen/goodix_berlin_i2c.c
@@ -31,6 +31,8 @@ static const struct input_id goodix_berlin_i2c_input_id = {
static int goodix_berlin_i2c_probe(struct i2c_client *client)
{
+ const struct goodix_berlin_ic_data *ic_data =
+ i2c_get_match_data(client);
struct regmap *regmap;
int error;
@@ -39,22 +41,28 @@ static int goodix_berlin_i2c_probe(struct i2c_client *client)
return PTR_ERR(regmap);
error = goodix_berlin_probe(&client->dev, client->irq,
- &goodix_berlin_i2c_input_id, regmap);
+ &goodix_berlin_i2c_input_id, regmap,
+ ic_data);
if (error)
return error;
return 0;
}
+static const struct goodix_berlin_ic_data gt9916_data = {
+ .fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D,
+ .ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_D,
+};
+
static const struct i2c_device_id goodix_berlin_i2c_id[] = {
- { "gt9916" },
+ { .name = "gt9916", .driver_data = (long)&gt9916_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, goodix_berlin_i2c_id);
static const struct of_device_id goodix_berlin_i2c_of_match[] = {
- { .compatible = "goodix,gt9916", },
+ { .compatible = "goodix,gt9916", .data = &gt9916_data },
{ }
};
MODULE_DEVICE_TABLE(of, goodix_berlin_i2c_of_match);
diff --git a/drivers/input/touchscreen/goodix_berlin_spi.c b/drivers/input/touchscreen/goodix_berlin_spi.c
index 0662e87b8692..01f850f484c2 100644
--- a/drivers/input/touchscreen/goodix_berlin_spi.c
+++ b/drivers/input/touchscreen/goodix_berlin_spi.c
@@ -18,10 +18,14 @@
#define GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN 1
#define GOODIX_BERLIN_REGISTER_WIDTH 4
-#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN 3
-#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
+#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A 4
+#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D 3
+#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN_A (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
GOODIX_BERLIN_REGISTER_WIDTH + \
- GOODIX_BERLIN_SPI_READ_DUMMY_LEN)
+ GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A)
+#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN_D (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
+ GOODIX_BERLIN_REGISTER_WIDTH + \
+ GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D)
#define GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
GOODIX_BERLIN_REGISTER_WIDTH)
@@ -33,6 +37,7 @@ static int goodix_berlin_spi_read(void *context, const void *reg_buf,
size_t val_size)
{
struct spi_device *spi = context;
+ const struct goodix_berlin_ic_data *ic_data = spi_get_device_match_data(spi);
struct spi_transfer xfers;
struct spi_message spi_msg;
const u32 *reg = reg_buf; /* reg is stored as native u32 at start of buffer */
@@ -42,23 +47,22 @@ static int goodix_berlin_spi_read(void *context, const void *reg_buf,
return -EINVAL;
u8 *buf __free(kfree) =
- kzalloc(GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size,
- GFP_KERNEL);
+ kzalloc(ic_data->read_prefix_len + val_size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
spi_message_init(&spi_msg);
memset(&xfers, 0, sizeof(xfers));
- /* buffer format: 0xF1 + addr(4bytes) + dummy(3bytes) + data */
+ /* buffer format: 0xF1 + addr(4bytes) + dummy(3/4bytes) + data */
buf[0] = GOODIX_BERLIN_SPI_READ_FLAG;
put_unaligned_be32(*reg, buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN);
memset(buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + GOODIX_BERLIN_REGISTER_WIDTH,
- 0xff, GOODIX_BERLIN_SPI_READ_DUMMY_LEN);
+ 0xff, ic_data->read_dummy_len);
xfers.tx_buf = buf;
xfers.rx_buf = buf;
- xfers.len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size;
+ xfers.len = ic_data->read_prefix_len + val_size;
xfers.cs_change = 0;
spi_message_add_tail(&xfers, &spi_msg);
@@ -68,7 +72,7 @@ static int goodix_berlin_spi_read(void *context, const void *reg_buf,
return error;
}
- memcpy(val_buf, buf + GOODIX_BERLIN_SPI_READ_PREFIX_LEN, val_size);
+ memcpy(val_buf, buf + ic_data->read_prefix_len, val_size);
return error;
}
@@ -123,6 +127,7 @@ static const struct input_id goodix_berlin_spi_input_id = {
static int goodix_berlin_spi_probe(struct spi_device *spi)
{
+ const struct goodix_berlin_ic_data *ic_data = spi_get_device_match_data(spi);
struct regmap_config regmap_config;
struct regmap *regmap;
size_t max_size;
@@ -137,7 +142,7 @@ static int goodix_berlin_spi_probe(struct spi_device *spi)
max_size = spi_max_transfer_size(spi);
regmap_config = goodix_berlin_spi_regmap_conf;
- regmap_config.max_raw_read = max_size - GOODIX_BERLIN_SPI_READ_PREFIX_LEN;
+ regmap_config.max_raw_read = max_size - ic_data->read_prefix_len;
regmap_config.max_raw_write = max_size - GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN;
regmap = devm_regmap_init(&spi->dev, NULL, spi, &regmap_config);
@@ -145,21 +150,38 @@ static int goodix_berlin_spi_probe(struct spi_device *spi)
return PTR_ERR(regmap);
error = goodix_berlin_probe(&spi->dev, spi->irq,
- &goodix_berlin_spi_input_id, regmap);
+ &goodix_berlin_spi_input_id, regmap,
+ ic_data);
if (error)
return error;
return 0;
}
+static const struct goodix_berlin_ic_data gt9897_data = {
+ .fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_A,
+ .ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_A,
+ .read_dummy_len = GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A,
+ .read_prefix_len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN_A,
+};
+
+static const struct goodix_berlin_ic_data gt9916_data = {
+ .fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D,
+ .ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_D,
+ .read_dummy_len = GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D,
+ .read_prefix_len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN_D,
+};
+
static const struct spi_device_id goodix_berlin_spi_ids[] = {
- { "gt9916" },
+ { .name = "gt9897", .driver_data = (long)&gt9897_data },
+ { .name = "gt9916", .driver_data = (long)&gt9916_data },
{ },
};
MODULE_DEVICE_TABLE(spi, goodix_berlin_spi_ids);
static const struct of_device_id goodix_berlin_spi_of_match[] = {
- { .compatible = "goodix,gt9916", },
+ { .compatible = "goodix,gt9897", .data = &gt9897_data },
+ { .compatible = "goodix,gt9916", .data = &gt9916_data },
{ }
};
MODULE_DEVICE_TABLE(of, goodix_berlin_spi_of_match);
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index dbf92fb02f80..2baeb4f3b941 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -97,7 +97,7 @@ static int gunze_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- gunze = kzalloc(sizeof(*gunze), GFP_KERNEL);
+ gunze = kzalloc_obj(*gunze);
input_dev = input_allocate_device();
if (!gunze || !input_dev) {
err = -ENOMEM;
@@ -106,7 +106,7 @@ static int gunze_connect(struct serio *serio, struct serio_driver *drv)
gunze->serio = serio;
gunze->dev = input_dev;
- snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys);
+ scnprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys);
input_dev->name = "Gunze AHL-51S TouchScreen";
input_dev->phys = gunze->phys;
diff --git a/drivers/input/touchscreen/hampshire.c b/drivers/input/touchscreen/hampshire.c
index dc0a2482ddd6..394ae8c88d50 100644
--- a/drivers/input/touchscreen/hampshire.c
+++ b/drivers/input/touchscreen/hampshire.c
@@ -109,7 +109,7 @@ static int hampshire_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- phampshire = kzalloc(sizeof(*phampshire), GFP_KERNEL);
+ phampshire = kzalloc_obj(*phampshire);
input_dev = input_allocate_device();
if (!phampshire || !input_dev) {
err = -ENOMEM;
@@ -118,8 +118,8 @@ static int hampshire_connect(struct serio *serio, struct serio_driver *drv)
phampshire->serio = serio;
phampshire->dev = input_dev;
- snprintf(phampshire->phys, sizeof(phampshire->phys),
- "%s/input0", serio->phys);
+ scnprintf(phampshire->phys, sizeof(phampshire->phys),
+ "%s/input0", serio->phys);
input_dev->name = "Hampshire Serial TouchScreen";
input_dev->phys = phampshire->phys;
diff --git a/drivers/input/touchscreen/himax_hx852x.c b/drivers/input/touchscreen/himax_hx852x.c
new file mode 100644
index 000000000000..83c60e137a55
--- /dev/null
+++ b/drivers/input/touchscreen/himax_hx852x.c
@@ -0,0 +1,503 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Himax HX852x(ES) Touchscreen Driver
+ * Copyright (c) 2020-2024 Stephan Gerhold <stephan@gerhold.net>
+ * Copyright (c) 2020 Jonathan Albrieux <jonathan.albrieux@gmail.com>
+ *
+ * Based on the Himax Android Driver Sample Code Ver 0.3 for HMX852xES chipset:
+ * Copyright (c) 2014 Himax Corporation.
+ */
+
+#include <linux/delay.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/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/unaligned.h>
+
+#define HX852X_COORD_SIZE(fingers) ((fingers) * sizeof(struct hx852x_coord))
+#define HX852X_WIDTH_SIZE(fingers) ALIGN(fingers, 4)
+#define HX852X_BUF_SIZE(fingers) (HX852X_COORD_SIZE(fingers) + \
+ HX852X_WIDTH_SIZE(fingers) + \
+ sizeof(struct hx852x_touch_info))
+
+#define HX852X_MAX_FINGERS 12
+#define HX852X_MAX_KEY_COUNT 4
+#define HX852X_MAX_BUF_SIZE HX852X_BUF_SIZE(HX852X_MAX_FINGERS)
+
+#define HX852X_TS_SLEEP_IN 0x80
+#define HX852X_TS_SLEEP_OUT 0x81
+#define HX852X_TS_SENSE_OFF 0x82
+#define HX852X_TS_SENSE_ON 0x83
+#define HX852X_READ_ONE_EVENT 0x85
+#define HX852X_READ_ALL_EVENTS 0x86
+#define HX852X_READ_LATEST_EVENT 0x87
+#define HX852X_CLEAR_EVENT_STACK 0x88
+
+#define HX852X_REG_SRAM_SWITCH 0x8c
+#define HX852X_REG_SRAM_ADDR 0x8b
+#define HX852X_REG_FLASH_RPLACE 0x5a
+
+#define HX852X_SRAM_SWITCH_TEST_MODE 0x14
+#define HX852X_SRAM_ADDR_CONFIG 0x7000
+
+struct hx852x {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ struct touchscreen_properties props;
+ struct gpio_desc *reset_gpiod;
+ struct regulator_bulk_data supplies[2];
+ unsigned int max_fingers;
+ unsigned int keycount;
+ unsigned int keycodes[HX852X_MAX_KEY_COUNT];
+};
+
+struct hx852x_config {
+ u8 rx_num;
+ u8 tx_num;
+ u8 max_pt;
+ u8 padding1[3];
+ __be16 x_res;
+ __be16 y_res;
+ u8 padding2[2];
+} __packed __aligned(4);
+
+struct hx852x_coord {
+ __be16 x;
+ __be16 y;
+} __packed __aligned(4);
+
+struct hx852x_touch_info {
+ u8 finger_num;
+ __le16 finger_pressed;
+ u8 padding;
+} __packed __aligned(4);
+
+static int hx852x_i2c_read(struct hx852x *hx, u8 cmd, void *data, u16 len)
+{
+ struct i2c_client *client = hx->client;
+ int error;
+ int ret;
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &cmd,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = data,
+ },
+ };
+
+ ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (ret != ARRAY_SIZE(msg)) {
+ error = ret < 0 ? ret : -EIO;
+ dev_err(&client->dev, "failed to read %#x: %d\n", cmd, error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int hx852x_power_on(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error;
+
+ error = regulator_bulk_enable(ARRAY_SIZE(hx->supplies), hx->supplies);
+ if (error) {
+ dev_err(dev, "failed to enable regulators: %d\n", error);
+ return error;
+ }
+
+ gpiod_set_value_cansleep(hx->reset_gpiod, 1);
+ msleep(20);
+ gpiod_set_value_cansleep(hx->reset_gpiod, 0);
+ msleep(50);
+
+ return 0;
+}
+
+static int hx852x_start(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error;
+
+ error = i2c_smbus_write_byte(hx->client, HX852X_TS_SLEEP_OUT);
+ if (error) {
+ dev_err(dev, "failed to send TS_SLEEP_OUT: %d\n", error);
+ return error;
+ }
+ msleep(30);
+
+ error = i2c_smbus_write_byte(hx->client, HX852X_TS_SENSE_ON);
+ if (error) {
+ dev_err(dev, "failed to send TS_SENSE_ON: %d\n", error);
+ return error;
+ }
+ msleep(20);
+
+ return 0;
+}
+
+static int hx852x_stop(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error;
+
+ error = i2c_smbus_write_byte(hx->client, HX852X_TS_SENSE_OFF);
+ if (error) {
+ dev_err(dev, "failed to send TS_SENSE_OFF: %d\n", error);
+ return error;
+ }
+ msleep(20);
+
+ error = i2c_smbus_write_byte(hx->client, HX852X_TS_SLEEP_IN);
+ if (error) {
+ dev_err(dev, "failed to send TS_SLEEP_IN: %d\n", error);
+ return error;
+ }
+ msleep(30);
+
+ return 0;
+}
+
+static int hx852x_power_off(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error;
+
+ error = regulator_bulk_disable(ARRAY_SIZE(hx->supplies), hx->supplies);
+ if (error) {
+ dev_err(dev, "failed to disable regulators: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int hx852x_read_config(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ struct hx852x_config conf;
+ int x_res, y_res;
+ int error, error2;
+
+ error = hx852x_power_on(hx);
+ if (error)
+ return error;
+
+ /* Sensing must be turned on briefly to load the config */
+ error = hx852x_start(hx);
+ if (error)
+ goto err_power_off;
+
+ error = hx852x_stop(hx);
+ if (error)
+ goto err_power_off;
+
+ error = i2c_smbus_write_byte_data(hx->client, HX852X_REG_SRAM_SWITCH,
+ HX852X_SRAM_SWITCH_TEST_MODE);
+ if (error)
+ goto err_power_off;
+
+ error = i2c_smbus_write_word_data(hx->client, HX852X_REG_SRAM_ADDR,
+ HX852X_SRAM_ADDR_CONFIG);
+ if (error)
+ goto err_test_mode;
+
+ error = hx852x_i2c_read(hx, HX852X_REG_FLASH_RPLACE, &conf, sizeof(conf));
+ if (error)
+ goto err_test_mode;
+
+ x_res = be16_to_cpu(conf.x_res);
+ y_res = be16_to_cpu(conf.y_res);
+ hx->max_fingers = (conf.max_pt & 0xf0) >> 4;
+ dev_dbg(dev, "x res: %u, y res: %u, max fingers: %u\n",
+ x_res, y_res, hx->max_fingers);
+
+ if (hx->max_fingers > HX852X_MAX_FINGERS) {
+ dev_err(dev, "max supported fingers: %u, found: %u\n",
+ HX852X_MAX_FINGERS, hx->max_fingers);
+ error = -EINVAL;
+ goto err_test_mode;
+ }
+
+ if (x_res && y_res) {
+ input_set_abs_params(hx->input_dev, ABS_MT_POSITION_X, 0, x_res - 1, 0, 0);
+ input_set_abs_params(hx->input_dev, ABS_MT_POSITION_Y, 0, y_res - 1, 0, 0);
+ }
+
+err_test_mode:
+ error2 = i2c_smbus_write_byte_data(hx->client, HX852X_REG_SRAM_SWITCH, 0);
+ error = error ?: error2;
+err_power_off:
+ error2 = hx852x_power_off(hx);
+ return error ?: error2;
+}
+
+static int hx852x_handle_events(struct hx852x *hx)
+{
+ /*
+ * The event packets have variable size, depending on the amount of
+ * supported fingers (hx->max_fingers). They are laid out as follows:
+ * - struct hx852x_coord[hx->max_fingers]: Coordinates for each finger
+ * - u8[ALIGN(hx->max_fingers, 4)]: Touch width for each finger
+ * with padding for 32-bit alignment
+ * - struct hx852x_touch_info
+ *
+ * Load everything into a 32-bit aligned buffer so the coordinates
+ * can be assigned directly, without using get_unaligned_*().
+ */
+ u8 buf[HX852X_MAX_BUF_SIZE] __aligned(4);
+ struct hx852x_coord *coord = (struct hx852x_coord *)buf;
+ u8 *width = &buf[HX852X_COORD_SIZE(hx->max_fingers)];
+ struct hx852x_touch_info *info = (struct hx852x_touch_info *)
+ &width[HX852X_WIDTH_SIZE(hx->max_fingers)];
+ unsigned long finger_pressed, key_pressed;
+ unsigned int i, x, y, w;
+ int error;
+
+ error = hx852x_i2c_read(hx, HX852X_READ_ALL_EVENTS, buf,
+ HX852X_BUF_SIZE(hx->max_fingers));
+ if (error)
+ return error;
+
+ finger_pressed = get_unaligned_le16(&info->finger_pressed);
+ key_pressed = finger_pressed >> HX852X_MAX_FINGERS;
+
+ /* All bits are set when no touch is detected */
+ if (info->finger_num == 0xff || !(info->finger_num & 0x0f))
+ finger_pressed = 0;
+ if (key_pressed == 0xf)
+ key_pressed = 0;
+
+ for_each_set_bit(i, &finger_pressed, hx->max_fingers) {
+ x = be16_to_cpu(coord[i].x);
+ y = be16_to_cpu(coord[i].y);
+ w = width[i];
+
+ input_mt_slot(hx->input_dev, i);
+ input_mt_report_slot_state(hx->input_dev, MT_TOOL_FINGER, 1);
+ touchscreen_report_pos(hx->input_dev, &hx->props, x, y, true);
+ input_report_abs(hx->input_dev, ABS_MT_TOUCH_MAJOR, w);
+ }
+ input_mt_sync_frame(hx->input_dev);
+
+ for (i = 0; i < hx->keycount; i++)
+ input_report_key(hx->input_dev, hx->keycodes[i], key_pressed & BIT(i));
+
+ input_sync(hx->input_dev);
+ return 0;
+}
+
+static irqreturn_t hx852x_interrupt(int irq, void *ptr)
+{
+ struct hx852x *hx = ptr;
+ int error;
+
+ error = hx852x_handle_events(hx);
+ if (error) {
+ dev_err_ratelimited(&hx->client->dev,
+ "failed to handle events: %d\n", error);
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int hx852x_input_open(struct input_dev *dev)
+{
+ struct hx852x *hx = input_get_drvdata(dev);
+ int error;
+
+ error = hx852x_power_on(hx);
+ if (error)
+ return error;
+
+ error = hx852x_start(hx);
+ if (error) {
+ hx852x_power_off(hx);
+ return error;
+ }
+
+ enable_irq(hx->client->irq);
+ return 0;
+}
+
+static void hx852x_input_close(struct input_dev *dev)
+{
+ struct hx852x *hx = input_get_drvdata(dev);
+
+ hx852x_stop(hx);
+ disable_irq(hx->client->irq);
+ hx852x_power_off(hx);
+}
+
+static int hx852x_parse_properties(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error, count;
+
+ count = device_property_count_u32(dev, "linux,keycodes");
+ if (count == -EINVAL) {
+ /* Property does not exist, keycodes are optional */
+ return 0;
+ } else if (count < 0) {
+ dev_err(dev, "Failed to read linux,keycodes: %d\n", count);
+ return count;
+ } else if (count > HX852X_MAX_KEY_COUNT) {
+ dev_err(dev, "max supported keys: %u, found: %u\n",
+ HX852X_MAX_KEY_COUNT, hx->keycount);
+ return -EINVAL;
+ }
+ hx->keycount = count;
+
+ error = device_property_read_u32_array(dev, "linux,keycodes",
+ hx->keycodes, hx->keycount);
+ if (error) {
+ dev_err(dev, "failed to read linux,keycodes: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int hx852x_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct hx852x *hx;
+ int error, i;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_WORD_DATA)) {
+ dev_err(dev, "not all required i2c functionality supported\n");
+ return -ENXIO;
+ }
+
+ hx = devm_kzalloc(dev, sizeof(*hx), GFP_KERNEL);
+ if (!hx)
+ return -ENOMEM;
+
+ hx->client = client;
+ hx->input_dev = devm_input_allocate_device(dev);
+ if (!hx->input_dev)
+ return -ENOMEM;
+
+ hx->input_dev->name = "Himax HX852x";
+ hx->input_dev->id.bustype = BUS_I2C;
+ hx->input_dev->open = hx852x_input_open;
+ hx->input_dev->close = hx852x_input_close;
+
+ i2c_set_clientdata(client, hx);
+ input_set_drvdata(hx->input_dev, hx);
+
+ hx->supplies[0].supply = "vcca";
+ hx->supplies[1].supply = "vccd";
+ error = devm_regulator_bulk_get(dev, ARRAY_SIZE(hx->supplies), hx->supplies);
+ if (error)
+ return dev_err_probe(dev, error, "failed to get regulators\n");
+
+ hx->reset_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(hx->reset_gpiod))
+ return dev_err_probe(dev, PTR_ERR(hx->reset_gpiod),
+ "failed to get reset gpio\n");
+
+ error = devm_request_threaded_irq(dev, client->irq, NULL, hx852x_interrupt,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN, NULL, hx);
+ if (error)
+ return dev_err_probe(dev, error, "failed to request irq %d", client->irq);
+
+ error = hx852x_read_config(hx);
+ if (error)
+ return error;
+
+ input_set_capability(hx->input_dev, EV_ABS, ABS_MT_POSITION_X);
+ input_set_capability(hx->input_dev, EV_ABS, ABS_MT_POSITION_Y);
+ input_set_abs_params(hx->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+
+ touchscreen_parse_properties(hx->input_dev, true, &hx->props);
+ error = hx852x_parse_properties(hx);
+ if (error)
+ return error;
+
+ hx->input_dev->keycode = hx->keycodes;
+ hx->input_dev->keycodemax = hx->keycount;
+ hx->input_dev->keycodesize = sizeof(hx->keycodes[0]);
+ for (i = 0; i < hx->keycount; i++)
+ input_set_capability(hx->input_dev, EV_KEY, hx->keycodes[i]);
+
+ error = input_mt_init_slots(hx->input_dev, hx->max_fingers,
+ INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+ if (error)
+ return dev_err_probe(dev, error, "failed to init MT slots\n");
+
+ error = input_register_device(hx->input_dev);
+ if (error)
+ return dev_err_probe(dev, error, "failed to register input device\n");
+
+ return 0;
+}
+
+static int hx852x_suspend(struct device *dev)
+{
+ struct hx852x *hx = dev_get_drvdata(dev);
+
+ guard(mutex)(&hx->input_dev->mutex);
+
+ if (input_device_enabled(hx->input_dev))
+ return hx852x_stop(hx);
+
+ return 0;
+}
+
+static int hx852x_resume(struct device *dev)
+{
+ struct hx852x *hx = dev_get_drvdata(dev);
+
+ guard(mutex)(&hx->input_dev->mutex);
+
+ if (input_device_enabled(hx->input_dev))
+ return hx852x_start(hx);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(hx852x_pm_ops, hx852x_suspend, hx852x_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id hx852x_of_match[] = {
+ { .compatible = "himax,hx852es" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, hx852x_of_match);
+#endif
+
+static struct i2c_driver hx852x_driver = {
+ .probe = hx852x_probe,
+ .driver = {
+ .name = "himax_hx852x",
+ .pm = pm_sleep_ptr(&hx852x_pm_ops),
+ .of_match_table = of_match_ptr(hx852x_of_match),
+ },
+};
+module_i2c_driver(hx852x_driver);
+
+MODULE_DESCRIPTION("Himax HX852x(ES) Touchscreen Driver");
+MODULE_AUTHOR("Jonathan Albrieux <jonathan.albrieux@gmail.com>");
+MODULE_AUTHOR("Stephan Gerhold <stephan@gerhold.net>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/hynitron-cst816x.c b/drivers/input/touchscreen/hynitron-cst816x.c
new file mode 100644
index 000000000000..b64d7928e18f
--- /dev/null
+++ b/drivers/input/touchscreen/hynitron-cst816x.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for I2C connected Hynitron CST816x Series Touchscreen
+ *
+ * Copyright (C) 2025 Oleh Kuzhylnyi <kuzhylol@gmail.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/unaligned.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#define CST816X_RD_REG 0x01
+#define CST816X_NUM_KEYS 5
+
+struct cst816x_touch {
+ u8 gest;
+ u8 active;
+ u16 abs_x;
+ u16 abs_y;
+} __packed;
+
+struct cst816x_priv {
+ struct i2c_client *client;
+ struct gpio_desc *reset;
+ struct input_dev *input;
+ unsigned int keycode[CST816X_NUM_KEYS];
+ unsigned int keycodemax;
+};
+
+static int cst816x_parse_keycodes(struct device *dev, struct cst816x_priv *priv)
+{
+ int count;
+ int error;
+
+ if (device_property_present(dev, "linux,keycodes")) {
+ count = device_property_count_u32(dev, "linux,keycodes");
+ if (count < 0) {
+ error = count;
+ dev_err(dev, "failed to count keys: %d\n", error);
+ return error;
+ } else if (count > ARRAY_SIZE(priv->keycode)) {
+ dev_err(dev, "too many keys defined: %d\n", count);
+ return -EINVAL;
+ }
+ priv->keycodemax = count;
+
+ error = device_property_read_u32_array(dev, "linux,keycodes",
+ priv->keycode,
+ priv->keycodemax);
+ if (error) {
+ dev_err(dev, "failed to read keycodes: %d\n", error);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+static int cst816x_i2c_read_register(struct cst816x_priv *priv, u8 reg,
+ void *buf, size_t len)
+{
+ struct i2c_msg xfer[] = {
+ {
+ .addr = priv->client->addr,
+ .flags = 0,
+ .buf = &reg,
+ .len = sizeof(reg),
+ },
+ {
+ .addr = priv->client->addr,
+ .flags = I2C_M_RD,
+ .buf = buf,
+ .len = len,
+ },
+ };
+ int error;
+ int ret;
+
+ ret = i2c_transfer(priv->client->adapter, xfer, ARRAY_SIZE(xfer));
+ if (ret != ARRAY_SIZE(xfer)) {
+ error = ret < 0 ? ret : -EIO;
+ dev_err(&priv->client->dev, "i2c rx err: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static u8 cst816x_gest_idx(u8 gest)
+{
+ u8 index;
+
+ switch (gest) {
+ case 0x01: /* Slide up gesture */
+ case 0x02: /* Slide down gesture */
+ case 0x03: /* Slide left gesture */
+ case 0x04: /* Slide right gesture */
+ index = gest;
+ break;
+ case 0x0c: /* Long press gesture */
+ default:
+ index = CST816X_NUM_KEYS;
+ break;
+ }
+
+ return index - 1;
+}
+
+static bool cst816x_process_touch(struct cst816x_priv *priv,
+ struct cst816x_touch *tch)
+{
+ if (cst816x_i2c_read_register(priv, CST816X_RD_REG, tch, sizeof(*tch)))
+ return false;
+
+ tch->abs_x = get_unaligned_be16(&tch->abs_x) & GENMASK(11, 0);
+ tch->abs_y = get_unaligned_be16(&tch->abs_y) & GENMASK(11, 0);
+
+ dev_dbg(&priv->client->dev, "x: %u, y: %u, t: %u, g: 0x%x\n",
+ tch->abs_x, tch->abs_y, tch->active, tch->gest);
+
+ return true;
+}
+
+static int cst816x_register_input(struct cst816x_priv *priv)
+{
+ priv->input = devm_input_allocate_device(&priv->client->dev);
+ if (!priv->input)
+ return -ENOMEM;
+
+ priv->input->name = "Hynitron CST816x Series Touchscreen";
+ priv->input->phys = "input/ts";
+ priv->input->id.bustype = BUS_I2C;
+
+ input_set_drvdata(priv->input, priv);
+
+ input_set_abs_params(priv->input, ABS_X, 0, 240, 0, 0);
+ input_set_abs_params(priv->input, ABS_Y, 0, 240, 0, 0);
+ input_set_capability(priv->input, EV_KEY, BTN_TOUCH);
+
+ priv->input->keycode = priv->keycode;
+ priv->input->keycodesize = sizeof(priv->keycode[0]);
+ priv->input->keycodemax = priv->keycodemax;
+
+ for (int i = 0; i < priv->keycodemax; i++) {
+ if (priv->keycode[i] == KEY_RESERVED)
+ continue;
+
+ input_set_capability(priv->input, EV_KEY, priv->keycode[i]);
+ }
+
+ return input_register_device(priv->input);
+}
+
+static void cst816x_reset(struct cst816x_priv *priv)
+{
+ gpiod_set_value_cansleep(priv->reset, 1);
+ msleep(50);
+ gpiod_set_value_cansleep(priv->reset, 0);
+ msleep(100);
+}
+
+static irqreturn_t cst816x_irq_cb(int irq, void *cookie)
+{
+ struct cst816x_priv *priv = cookie;
+ struct cst816x_touch tch;
+
+ if (!cst816x_process_touch(priv, &tch))
+ return IRQ_HANDLED;
+
+ input_report_abs(priv->input, ABS_X, tch.abs_x);
+ input_report_abs(priv->input, ABS_Y, tch.abs_y);
+
+ if (tch.gest)
+ input_report_key(priv->input,
+ priv->keycode[cst816x_gest_idx(tch.gest)],
+ tch.active);
+
+ input_report_key(priv->input, BTN_TOUCH, tch.active);
+
+ input_sync(priv->input);
+
+ return IRQ_HANDLED;
+}
+
+static int cst816x_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct cst816x_priv *priv;
+ int error;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = client;
+
+ priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset))
+ return dev_err_probe(dev, PTR_ERR(priv->reset),
+ "gpio reset request failed\n");
+
+ if (priv->reset)
+ cst816x_reset(priv);
+
+ error = cst816x_parse_keycodes(dev, priv);
+ if (error)
+ dev_warn(dev, "no gestures found in dt\n");
+
+ error = cst816x_register_input(priv);
+ if (error)
+ return dev_err_probe(dev, error, "input register failed\n");
+
+ error = devm_request_threaded_irq(dev, client->irq,
+ NULL, cst816x_irq_cb, IRQF_ONESHOT,
+ dev_driver_string(dev), priv);
+ if (error)
+ return dev_err_probe(dev, error, "irq request failed\n");
+
+ return 0;
+}
+
+static const struct i2c_device_id cst816x_id[] = {
+ { .name = "cst816s", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cst816x_id);
+
+static const struct of_device_id cst816x_of_match[] = {
+ { .compatible = "hynitron,cst816s", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cst816x_of_match);
+
+static struct i2c_driver cst816x_driver = {
+ .driver = {
+ .name = "cst816x",
+ .of_match_table = cst816x_of_match,
+ },
+ .id_table = cst816x_id,
+ .probe = cst816x_probe,
+};
+
+module_i2c_driver(cst816x_driver);
+
+MODULE_AUTHOR("Oleh Kuzhylnyi <kuzhylol@gmail.com>");
+MODULE_DESCRIPTION("Hynitron CST816x Series Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c
index fa38d70aded7..3bf524a6ee20 100644
--- a/drivers/input/touchscreen/ili210x.c
+++ b/drivers/input/touchscreen/ili210x.c
@@ -327,9 +327,8 @@ static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata)
return contact;
}
-static irqreturn_t ili210x_irq(int irq, void *irq_data)
+static void ili210x_process_events(struct ili210x *priv)
{
- struct ili210x *priv = irq_data;
struct i2c_client *client = priv->client;
const struct ili2xxx_chip *chip = priv->chip;
u8 touchdata[ILI210X_DATA_SIZE] = { 0 };
@@ -356,8 +355,22 @@ static irqreturn_t ili210x_irq(int irq, void *irq_data)
usleep_range(time_delta, time_delta + 1000);
}
} while (!priv->stop && keep_polling);
+}
+
+static irqreturn_t ili210x_irq(int irq, void *irq_data)
+{
+ struct ili210x *priv = irq_data;
+
+ ili210x_process_events(priv);
return IRQ_HANDLED;
+};
+
+static void ili210x_work_i2c_poll(struct input_dev *input)
+{
+ struct ili210x *priv = input_get_drvdata(input);
+
+ ili210x_process_events(priv);
}
static int ili251x_firmware_update_resolution(struct device *dev)
@@ -829,12 +842,32 @@ static int ili210x_do_firmware_update(struct ili210x *priv,
return 0;
}
+static ssize_t ili210x_firmware_update(struct device *dev, const u8 *fwbuf,
+ u16 ac_end, u16 df_end)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ili210x *priv = i2c_get_clientdata(client);
+ const char *fwname = ILI251X_FW_FILENAME;
+ int error;
+
+ dev_dbg(dev, "Firmware update started, firmware=%s\n", fwname);
+
+ ili210x_hardware_reset(priv->reset_gpio);
+
+ error = ili210x_do_firmware_update(priv, fwbuf, ac_end, df_end);
+
+ ili210x_hardware_reset(priv->reset_gpio);
+
+ dev_dbg(dev, "Firmware update ended, error=%i\n", error);
+
+ return error;
+}
+
static ssize_t ili210x_firmware_update_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
- struct ili210x *priv = i2c_get_clientdata(client);
const char *fwname = ILI251X_FW_FILENAME;
u16 ac_end, df_end;
int error;
@@ -860,16 +893,11 @@ static ssize_t ili210x_firmware_update_store(struct device *dev,
* the touch controller to disable the IRQs during update, so we have
* to do it this way here.
*/
- scoped_guard(disable_irq, &client->irq) {
- dev_dbg(dev, "Firmware update started, firmware=%s\n", fwname);
-
- ili210x_hardware_reset(priv->reset_gpio);
-
- error = ili210x_do_firmware_update(priv, fwbuf, ac_end, df_end);
-
- ili210x_hardware_reset(priv->reset_gpio);
-
- dev_dbg(dev, "Firmware update ended, error=%i\n", error);
+ if (client->irq > 0) {
+ guard(disable_irq)(&client->irq);
+ error = ili210x_firmware_update(dev, fwbuf, ac_end, df_end);
+ } else {
+ error = ili210x_firmware_update(dev, fwbuf, ac_end, df_end);
}
return error ?: count;
@@ -942,15 +970,8 @@ static int ili210x_i2c_probe(struct i2c_client *client)
chip = device_get_match_data(dev);
if (!chip && id)
chip = (const struct ili2xxx_chip *)id->driver_data;
- if (!chip) {
- dev_err(&client->dev, "unknown device model\n");
- return -ENODEV;
- }
-
- if (client->irq <= 0) {
- dev_err(dev, "No IRQ!\n");
- return -EINVAL;
- }
+ if (!chip)
+ return dev_err_probe(&client->dev, -ENODEV, "unknown device model\n");
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpio))
@@ -998,17 +1019,22 @@ static int ili210x_i2c_probe(struct i2c_client *client)
error = input_mt_init_slots(input, priv->chip->max_touches,
INPUT_MT_DIRECT);
- if (error) {
- dev_err(dev, "Unable to set up slots, err: %d\n", error);
- return error;
- }
+ if (error)
+ return dev_err_probe(dev, error, "Unable to set up slots\n");
- error = devm_request_threaded_irq(dev, client->irq, NULL, ili210x_irq,
- IRQF_ONESHOT, client->name, priv);
- if (error) {
- dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
- error);
- return error;
+ input_set_drvdata(input, priv);
+
+ if (client->irq > 0) {
+ error = devm_request_threaded_irq(dev, client->irq, NULL, ili210x_irq,
+ IRQF_ONESHOT, client->name, priv);
+ if (error)
+ return dev_err_probe(dev, error, "Unable to request touchscreen IRQ\n");
+ } else {
+ error = input_setup_polling(input, ili210x_work_i2c_poll);
+ if (error)
+ return dev_err_probe(dev, error, "Could not set up polling mode\n");
+
+ input_set_poll_interval(input, ILI2XXX_POLL_PERIOD);
}
error = devm_add_action_or_reset(dev, ili210x_stop, priv);
@@ -1016,10 +1042,8 @@ static int ili210x_i2c_probe(struct i2c_client *client)
return error;
error = input_register_device(priv->input);
- if (error) {
- dev_err(dev, "Cannot register input device, err: %d\n", error);
- return error;
- }
+ if (error)
+ return dev_err_probe(dev, error, "Cannot register input device\n");
return 0;
}
diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c
index 0dd632724a00..0706443792ba 100644
--- a/drivers/input/touchscreen/ilitek_ts_i2c.c
+++ b/drivers/input/touchscreen/ilitek_ts_i2c.c
@@ -122,7 +122,7 @@ static int ilitek_i2c_write_and_read(struct ilitek_ts_data *ts,
return error;
}
if (delay > 0)
- mdelay(delay);
+ fsleep(delay * 1000);
if (read_len > 0) {
error = i2c_transfer(client->adapter, msgs + 1, 1);
@@ -396,10 +396,10 @@ static const struct ilitek_protocol_map ptl_func_map[] = {
static void ilitek_reset(struct ilitek_ts_data *ts, int delay)
{
if (ts->reset_gpio) {
- gpiod_set_value(ts->reset_gpio, 1);
- mdelay(10);
- gpiod_set_value(ts->reset_gpio, 0);
- mdelay(delay);
+ gpiod_set_value_cansleep(ts->reset_gpio, 1);
+ fsleep(10000);
+ gpiod_set_value_cansleep(ts->reset_gpio, 0);
+ fsleep(delay * 1000);
}
}
diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c
index 6ac8fa84ed9f..85f697de2b7e 100644
--- a/drivers/input/touchscreen/imx6ul_tsc.c
+++ b/drivers/input/touchscreen/imx6ul_tsc.c
@@ -7,6 +7,7 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/bitfield.h>
#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/slab.h>
@@ -20,25 +21,23 @@
#include <linux/log2.h>
/* ADC configuration registers field define */
-#define ADC_AIEN (0x1 << 7)
+#define ADC_AIEN BIT(7)
+#define ADC_ADCH_MASK GENMASK(4, 0)
#define ADC_CONV_DISABLE 0x1F
-#define ADC_AVGE (0x1 << 5)
-#define ADC_CAL (0x1 << 7)
-#define ADC_CALF 0x2
-#define ADC_12BIT_MODE (0x2 << 2)
-#define ADC_CONV_MODE_MASK (0x3 << 2)
+#define ADC_AVGE BIT(5)
+#define ADC_CAL BIT(7)
+#define ADC_CALF BIT(1)
+#define ADC_CONV_MODE_MASK GENMASK(3, 2)
+#define ADC_12BIT_MODE 0x2
#define ADC_IPG_CLK 0x00
-#define ADC_INPUT_CLK_MASK 0x3
-#define ADC_CLK_DIV_8 (0x03 << 5)
-#define ADC_CLK_DIV_MASK (0x3 << 5)
-#define ADC_SHORT_SAMPLE_MODE (0x0 << 4)
-#define ADC_SAMPLE_MODE_MASK (0x1 << 4)
-#define ADC_HARDWARE_TRIGGER (0x1 << 13)
-#define ADC_AVGS_SHIFT 14
-#define ADC_AVGS_MASK (0x3 << 14)
+#define ADC_INPUT_CLK_MASK GENMASK(1, 0)
+#define ADC_CLK_DIV_8 0x03
+#define ADC_CLK_DIV_MASK GENMASK(6, 5)
+#define ADC_SAMPLE_MODE BIT(4)
+#define ADC_HARDWARE_TRIGGER BIT(13)
+#define ADC_AVGS_MASK GENMASK(15, 14)
#define SELECT_CHANNEL_4 0x04
#define SELECT_CHANNEL_1 0x01
-#define DISABLE_CONVERSION_INT (0x0 << 7)
/* ADC registers */
#define REG_ADC_HC0 0x00
@@ -55,7 +54,7 @@
#define ADC_TIMEOUT msecs_to_jiffies(100)
/* TSC registers */
-#define REG_TSC_BASIC_SETING 0x00
+#define REG_TSC_BASIC_SETTING 0x00
#define REG_TSC_PRE_CHARGE_TIME 0x10
#define REG_TSC_FLOW_CONTROL 0x20
#define REG_TSC_MEASURE_VALUE 0x30
@@ -65,19 +64,26 @@
#define REG_TSC_DEBUG_MODE 0x70
#define REG_TSC_DEBUG_MODE2 0x80
+/* TSC_MEASURE_VALUE register field define */
+#define X_VALUE_MASK GENMASK(27, 16)
+#define Y_VALUE_MASK GENMASK(11, 0)
+
/* TSC configuration registers field define */
-#define DETECT_4_WIRE_MODE (0x0 << 4)
-#define AUTO_MEASURE 0x1
-#define MEASURE_SIGNAL 0x1
-#define DETECT_SIGNAL (0x1 << 4)
-#define VALID_SIGNAL (0x1 << 8)
-#define MEASURE_INT_EN 0x1
-#define MEASURE_SIG_EN 0x1
-#define VALID_SIG_EN (0x1 << 8)
-#define DE_GLITCH_2 (0x2 << 29)
-#define START_SENSE (0x1 << 12)
-#define TSC_DISABLE (0x1 << 16)
+#define MEASURE_DELAY_TIME_MASK GENMASK(31, 8)
+#define DETECT_5_WIRE_MODE BIT(4)
+#define AUTO_MEASURE BIT(0)
+#define MEASURE_SIGNAL BIT(0)
+#define DETECT_SIGNAL BIT(4)
+#define VALID_SIGNAL BIT(8)
+#define MEASURE_INT_EN BIT(0)
+#define MEASURE_SIG_EN BIT(0)
+#define VALID_SIG_EN BIT(8)
+#define DE_GLITCH_MASK GENMASK(30, 29)
+#define DE_GLITCH_DEF 0x02
+#define START_SENSE BIT(12)
+#define TSC_DISABLE BIT(16)
#define DETECT_MODE 0x2
+#define STATE_MACHINE_MASK GENMASK(22, 20)
struct imx6ul_tsc {
struct device *dev;
@@ -92,6 +98,7 @@ struct imx6ul_tsc {
u32 pre_charge_time;
bool average_enable;
u32 average_select;
+ u32 de_glitch;
struct completion completion;
};
@@ -112,19 +119,20 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG);
adc_cfg &= ~(ADC_CONV_MODE_MASK | ADC_INPUT_CLK_MASK);
- adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK;
- adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK);
- adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE;
+ adc_cfg |= FIELD_PREP(ADC_CONV_MODE_MASK, ADC_12BIT_MODE) |
+ FIELD_PREP(ADC_INPUT_CLK_MASK, ADC_IPG_CLK);
+ adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE);
+ adc_cfg |= FIELD_PREP(ADC_CLK_DIV_MASK, ADC_CLK_DIV_8);
if (tsc->average_enable) {
adc_cfg &= ~ADC_AVGS_MASK;
- adc_cfg |= (tsc->average_select) << ADC_AVGS_SHIFT;
+ adc_cfg |= FIELD_PREP(ADC_AVGS_MASK, tsc->average_select);
}
adc_cfg &= ~ADC_HARDWARE_TRIGGER;
writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG);
/* enable calibration interrupt */
adc_hc |= ADC_AIEN;
- adc_hc |= ADC_CONV_DISABLE;
+ adc_hc |= FIELD_PREP(ADC_ADCH_MASK, ADC_CONV_DISABLE);
writel(adc_hc, tsc->adc_regs + REG_ADC_HC0);
/* start ADC calibration */
@@ -164,19 +172,21 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
{
u32 adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4;
- adc_hc0 = DISABLE_CONVERSION_INT;
+ adc_hc0 = FIELD_PREP(ADC_AIEN, 0);
writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0);
- adc_hc1 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_4;
+ adc_hc1 = FIELD_PREP(ADC_AIEN, 0) |
+ FIELD_PREP(ADC_ADCH_MASK, SELECT_CHANNEL_4);
writel(adc_hc1, tsc->adc_regs + REG_ADC_HC1);
- adc_hc2 = DISABLE_CONVERSION_INT;
+ adc_hc2 = FIELD_PREP(ADC_AIEN, 0);
writel(adc_hc2, tsc->adc_regs + REG_ADC_HC2);
- adc_hc3 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_1;
+ adc_hc3 = FIELD_PREP(ADC_AIEN, 0) |
+ FIELD_PREP(ADC_ADCH_MASK, SELECT_CHANNEL_1);
writel(adc_hc3, tsc->adc_regs + REG_ADC_HC3);
- adc_hc4 = DISABLE_CONVERSION_INT;
+ adc_hc4 = FIELD_PREP(ADC_AIEN, 0);
writel(adc_hc4, tsc->adc_regs + REG_ADC_HC4);
}
@@ -188,13 +198,16 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
static void imx6ul_tsc_set(struct imx6ul_tsc *tsc)
{
u32 basic_setting = 0;
+ u32 debug_mode2;
u32 start;
- basic_setting |= tsc->measure_delay_time << 8;
- basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE;
- writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETING);
+ basic_setting |= FIELD_PREP(MEASURE_DELAY_TIME_MASK,
+ tsc->measure_delay_time);
+ basic_setting |= AUTO_MEASURE;
+ writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETTING);
- writel(DE_GLITCH_2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2);
+ debug_mode2 = FIELD_PREP(DE_GLITCH_MASK, tsc->de_glitch);
+ writel(debug_mode2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2);
writel(tsc->pre_charge_time, tsc->tsc_regs + REG_TSC_PRE_CHARGE_TIME);
writel(MEASURE_INT_EN, tsc->tsc_regs + REG_TSC_INT_EN);
@@ -250,7 +263,7 @@ static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc)
usleep_range(200, 400);
debug_mode2 = readl(tsc->tsc_regs + REG_TSC_DEBUG_MODE2);
- state_machine = (debug_mode2 >> 20) & 0x7;
+ state_machine = FIELD_GET(STATE_MACHINE_MASK, debug_mode2);
} while (state_machine != DETECT_MODE);
usleep_range(200, 400);
@@ -278,8 +291,8 @@ static irqreturn_t tsc_irq_fn(int irq, void *dev_id)
if (status & MEASURE_SIGNAL) {
value = readl(tsc->tsc_regs + REG_TSC_MEASURE_VALUE);
- x = (value >> 16) & 0x0fff;
- y = value & 0x0fff;
+ x = FIELD_GET(X_VALUE_MASK, value);
+ y = FIELD_GET(Y_VALUE_MASK, value);
/*
* In detect mode, we can get the xnur gpio value,
@@ -379,6 +392,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
int tsc_irq;
int adc_irq;
u32 average_samples;
+ u32 de_glitch;
tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL);
if (!tsc)
@@ -501,6 +515,25 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
return -EINVAL;
}
+ err = of_property_read_u32(np, "debounce-delay-us", &de_glitch);
+ if (err) {
+ tsc->de_glitch = DE_GLITCH_DEF;
+ } else {
+ u64 cycles;
+ unsigned long rate = clk_get_rate(tsc->tsc_clk);
+
+ cycles = DIV64_U64_ROUND_UP((u64)de_glitch * rate, USEC_PER_SEC);
+
+ if (cycles <= 0x3ff)
+ tsc->de_glitch = 3;
+ else if (cycles <= 0x7ff)
+ tsc->de_glitch = 2;
+ else if (cycles <= 0xfff)
+ tsc->de_glitch = 1;
+ else
+ tsc->de_glitch = 0;
+ }
+
err = input_register_device(tsc->input);
if (err) {
dev_err(&pdev->dev,
diff --git a/drivers/input/touchscreen/inexio.c b/drivers/input/touchscreen/inexio.c
index 82f7ac62a4f2..ac3836ff2a30 100644
--- a/drivers/input/touchscreen/inexio.c
+++ b/drivers/input/touchscreen/inexio.c
@@ -114,7 +114,7 @@ static int inexio_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- pinexio = kzalloc(sizeof(*pinexio), GFP_KERNEL);
+ pinexio = kzalloc_obj(*pinexio);
input_dev = input_allocate_device();
if (!pinexio || !input_dev) {
err = -ENOMEM;
@@ -123,7 +123,7 @@ static int inexio_connect(struct serio *serio, struct serio_driver *drv)
pinexio->serio = serio;
pinexio->dev = input_dev;
- snprintf(pinexio->phys, sizeof(pinexio->phys), "%s/input0", serio->phys);
+ scnprintf(pinexio->phys, sizeof(pinexio->phys), "%s/input0", serio->phys);
input_dev->name = "iNexio Serial TouchScreen";
input_dev->phys = pinexio->phys;
diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c
index 4ebd7565ae6e..c63819abaf9b 100644
--- a/drivers/input/touchscreen/iqs5xx.c
+++ b/drivers/input/touchscreen/iqs5xx.c
@@ -17,6 +17,7 @@
#include <linux/err.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
+#include <linux/hex.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c
index 33635da85079..4b7e70a4c6d5 100644
--- a/drivers/input/touchscreen/mc13783_ts.c
+++ b/drivers/input/touchscreen/mc13783_ts.c
@@ -42,8 +42,6 @@ static irqreturn_t mc13783_ts_handler(int irq, void *data)
{
struct mc13783_ts_priv *priv = data;
- mc13xxx_irq_ack(priv->mc13xxx, irq);
-
/*
* Kick off reading coordinates. Note that if work happens already
* be queued for future execution (it rearms itself) it will not
@@ -137,8 +135,6 @@ static int mc13783_ts_open(struct input_dev *dev)
mc13xxx_lock(priv->mc13xxx);
- mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_TS);
-
ret = mc13xxx_irq_request(priv->mc13xxx, MC13XXX_IRQ_TS,
mc13783_ts_handler, MC13783_TS_NAME, priv);
if (ret)
@@ -172,7 +168,7 @@ static int __init mc13783_ts_probe(struct platform_device *pdev)
struct input_dev *idev;
int ret = -ENOMEM;
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = kzalloc_obj(*priv);
idev = input_allocate_device();
if (!priv || !idev)
goto err_free_mem;
diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c
index a6946e3d8376..869884219908 100644
--- a/drivers/input/touchscreen/melfas_mip4.c
+++ b/drivers/input/touchscreen/melfas_mip4.c
@@ -1554,7 +1554,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mip4_pm_ops, mip4_suspend, mip4_resume);
#ifdef CONFIG_OF
static const struct of_device_id mip4_of_match[] = {
- { .compatible = "melfas,"MIP4_DEVICE_NAME, },
+ { .compatible = "melfas,mip4_ts", },
{ },
};
MODULE_DEVICE_TABLE(of, mip4_of_match);
diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c
index 7511a134e302..993d945dcd23 100644
--- a/drivers/input/touchscreen/migor_ts.c
+++ b/drivers/input/touchscreen/migor_ts.c
@@ -122,7 +122,7 @@ static int migor_ts_probe(struct i2c_client *client)
struct input_dev *input;
int error;
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = kzalloc_obj(*priv);
input = input_allocate_device();
if (!priv || !input) {
dev_err(&client->dev, "failed to allocate memory\n");
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
index eefae96a2d40..cc2d206d2f3d 100644
--- a/drivers/input/touchscreen/mtouch.c
+++ b/drivers/input/touchscreen/mtouch.c
@@ -128,7 +128,7 @@ static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- mtouch = kzalloc(sizeof(*mtouch), GFP_KERNEL);
+ mtouch = kzalloc_obj(*mtouch);
input_dev = input_allocate_device();
if (!mtouch || !input_dev) {
err = -ENOMEM;
@@ -137,7 +137,7 @@ static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
mtouch->serio = serio;
mtouch->dev = input_dev;
- snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys);
+ scnprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys);
input_dev->name = "MicroTouch Serial TouchScreen";
input_dev->phys = mtouch->phys;
diff --git a/drivers/input/touchscreen/novatek-nvt-ts.c b/drivers/input/touchscreen/novatek-nvt-ts.c
index 44b58e0dc1ad..3e6e2ee0ba8f 100644
--- a/drivers/input/touchscreen/novatek-nvt-ts.c
+++ b/drivers/input/touchscreen/novatek-nvt-ts.c
@@ -27,7 +27,6 @@
#define NVT_TS_PARAMS_MAX_TOUCH 0x09
#define NVT_TS_PARAMS_MAX_BUTTONS 0x0a
#define NVT_TS_PARAMS_IRQ_TYPE 0x0b
-#define NVT_TS_PARAMS_WAKE_TYPE 0x0c
#define NVT_TS_PARAMS_CHIP_ID 0x0e
#define NVT_TS_PARAMS_SIZE 0x0f
@@ -49,7 +48,6 @@ static const int nvt_ts_irq_type[4] = {
};
struct nvt_ts_i2c_chip_data {
- u8 wake_type;
u8 chip_id;
};
@@ -261,7 +259,6 @@ static int nvt_ts_probe(struct i2c_client *client)
if (width > NVT_TS_MAX_SIZE || height >= NVT_TS_MAX_SIZE ||
data->max_touches > NVT_TS_MAX_TOUCHES ||
irq_type >= ARRAY_SIZE(nvt_ts_irq_type) ||
- data->buf[NVT_TS_PARAMS_WAKE_TYPE] != chip->wake_type ||
data->buf[NVT_TS_PARAMS_CHIP_ID] != chip->chip_id) {
dev_err(dev, "Unsupported touchscreen parameters: %*ph\n",
NVT_TS_PARAMS_SIZE, data->buf);
@@ -314,12 +311,10 @@ static int nvt_ts_probe(struct i2c_client *client)
}
static const struct nvt_ts_i2c_chip_data nvt_nt11205_ts_data = {
- .wake_type = 0x05,
.chip_id = 0x05,
};
static const struct nvt_ts_i2c_chip_data nvt_nt36672a_ts_data = {
- .wake_type = 0x01,
.chip_id = 0x08,
};
diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c
index 083206a3457b..7b89eb74b9de 100644
--- a/drivers/input/touchscreen/pcap_ts.c
+++ b/drivers/input/touchscreen/pcap_ts.c
@@ -138,7 +138,7 @@ static int pcap_ts_probe(struct platform_device *pdev)
struct pcap_ts *pcap_ts;
int err = -ENOMEM;
- pcap_ts = kzalloc(sizeof(*pcap_ts), GFP_KERNEL);
+ pcap_ts = kzalloc_obj(*pcap_ts);
if (!pcap_ts)
return err;
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c
index 95adede26703..4b57b6664e37 100644
--- a/drivers/input/touchscreen/penmount.c
+++ b/drivers/input/touchscreen/penmount.c
@@ -199,7 +199,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
int max_x, max_y;
int err;
- pm = kzalloc(sizeof(*pm), GFP_KERNEL);
+ pm = kzalloc_obj(*pm);
input_dev = input_allocate_device();
if (!pm || !input_dev) {
err = -ENOMEM;
@@ -208,7 +208,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
pm->serio = serio;
pm->dev = input_dev;
- snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
+ scnprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
pm->maxcontacts = 1;
input_dev->name = "PenMount Serial TouchScreen";
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index 6475084aee1b..9b3901eec0a5 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -22,6 +22,7 @@
#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/input/touch-overlay.h>
#define ST1232_TS_NAME "st1232-ts"
#define ST1633_TS_NAME "st1633-ts"
@@ -57,6 +58,7 @@ struct st1232_ts_data {
struct dev_pm_qos_request low_latency_req;
struct gpio_desc *reset_gpio;
const struct st_chip_info *chip_info;
+ struct list_head touch_overlay_list;
int read_buf_len;
u8 *read_buf;
};
@@ -156,6 +158,10 @@ static int st1232_ts_parse_and_report(struct st1232_ts_data *ts)
input_mt_assign_slots(input, slots, pos, n_contacts, 0);
for (i = 0; i < n_contacts; i++) {
+ if (touch_overlay_process_contact(&ts->touch_overlay_list,
+ input, &pos[i], slots[i]))
+ continue;
+
input_mt_slot(input, slots[i]);
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
input_report_abs(input, ABS_MT_POSITION_X, pos[i].x);
@@ -164,6 +170,7 @@ static int st1232_ts_parse_and_report(struct st1232_ts_data *ts)
input_report_abs(input, ABS_MT_TOUCH_MAJOR, z[i]);
}
+ touch_overlay_sync_frame(&ts->touch_overlay_list, input);
input_mt_sync_frame(input);
input_sync(input);
@@ -292,18 +299,30 @@ static int st1232_ts_probe(struct i2c_client *client)
if (error)
return error;
- /* Read resolution from the chip */
- error = st1232_ts_read_resolution(ts, &max_x, &max_y);
- if (error) {
- dev_err(&client->dev,
- "Failed to read resolution: %d\n", error);
- return error;
- }
-
if (ts->chip_info->have_z)
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
ts->chip_info->max_area, 0, 0);
+ /* map overlay objects if defined in the device tree */
+ INIT_LIST_HEAD(&ts->touch_overlay_list);
+ error = touch_overlay_map(&ts->touch_overlay_list, input_dev);
+ if (error)
+ return error;
+
+ if (touch_overlay_mapped_touchscreen(&ts->touch_overlay_list)) {
+ /* Read resolution from the overlay touchscreen if defined */
+ touch_overlay_get_touchscreen_abs(&ts->touch_overlay_list,
+ &max_x, &max_y);
+ } else {
+ /* Read resolution from the chip */
+ error = st1232_ts_read_resolution(ts, &max_x, &max_y);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to read resolution: %d\n", error);
+ return error;
+ }
+ }
+
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, max_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index 119cd26851cf..4b166b0a9a5a 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -120,7 +120,7 @@ static int stmfts_brightness_set(struct led_classdev *led_cdev,
err = regulator_enable(sdata->ledvdd);
if (err) {
dev_warn(&sdata->client->dev,
- "failed to disable ledvdd regulator: %d\n",
+ "failed to enable ledvdd regulator: %d\n",
err);
return err;
}
@@ -141,7 +141,7 @@ static enum led_brightness stmfts_brightness_get(struct led_classdev *led_cdev)
/*
* We can't simply use i2c_smbus_read_i2c_block_data because we
- * need to read more than 255 bytes (
+ * need to read 256 bytes, which exceeds the 255-byte SMBus block limit.
*/
static int stmfts_read_events(struct stmfts_data *sdata)
{
@@ -410,7 +410,7 @@ static ssize_t stmfts_sysfs_chip_id(struct device *dev,
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
- return sprintf(buf, "%#x\n", sdata->chip_id);
+ return sysfs_emit(buf, "%#x\n", sdata->chip_id);
}
static ssize_t stmfts_sysfs_chip_version(struct device *dev,
@@ -418,7 +418,7 @@ static ssize_t stmfts_sysfs_chip_version(struct device *dev,
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", sdata->chip_ver);
+ return sysfs_emit(buf, "%u\n", sdata->chip_ver);
}
static ssize_t stmfts_sysfs_fw_ver(struct device *dev,
@@ -426,7 +426,7 @@ static ssize_t stmfts_sysfs_fw_ver(struct device *dev,
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", sdata->fw_ver);
+ return sysfs_emit(buf, "%u\n", sdata->fw_ver);
}
static ssize_t stmfts_sysfs_config_id(struct device *dev,
@@ -434,7 +434,7 @@ static ssize_t stmfts_sysfs_config_id(struct device *dev,
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
- return sprintf(buf, "%#x\n", sdata->config_id);
+ return sysfs_emit(buf, "%#x\n", sdata->config_id);
}
static ssize_t stmfts_sysfs_config_version(struct device *dev,
@@ -442,7 +442,7 @@ static ssize_t stmfts_sysfs_config_version(struct device *dev,
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", sdata->config_ver);
+ return sysfs_emit(buf, "%u\n", sdata->config_ver);
}
static ssize_t stmfts_sysfs_read_status(struct device *dev,
@@ -457,7 +457,7 @@ static ssize_t stmfts_sysfs_read_status(struct device *dev,
if (err)
return err;
- return sprintf(buf, "%#02x\n", status[0]);
+ return sysfs_emit(buf, "%#02x\n", status[0]);
}
static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev,
@@ -465,7 +465,7 @@ static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev,
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", sdata->hover_enabled);
+ return sysfs_emit(buf, "%u\n", sdata->hover_enabled);
}
static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,
@@ -594,9 +594,6 @@ static void stmfts_power_off(void *data)
sdata->regulators);
}
-/* This function is void because I don't want to prevent using the touch key
- * only because the LEDs don't get registered
- */
static int stmfts_enable_led(struct stmfts_data *sdata)
{
int err;
diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c
index a94a1997f96b..af0fb38bcfdc 100644
--- a/drivers/input/touchscreen/stmpe-ts.c
+++ b/drivers/input/touchscreen/stmpe-ts.c
@@ -366,12 +366,7 @@ static struct platform_driver stmpe_ts_driver = {
};
module_platform_driver(stmpe_ts_driver);
-static const struct of_device_id stmpe_ts_ids[] = {
- { .compatible = "st,stmpe-ts", },
- { },
-};
-MODULE_DEVICE_TABLE(of, stmpe_ts_ids);
-
+MODULE_ALIAS("platform:stmpe-ts");
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
MODULE_DESCRIPTION("STMPEXXX touchscreen driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 8365a2ac6fce..877eae34fb5a 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -672,7 +672,7 @@ static int sur40_probe(struct usb_interface *interface,
return -ENODEV;
/* Allocate memory for our device state and initialize it. */
- sur40 = kzalloc(sizeof(*sur40), GFP_KERNEL);
+ sur40 = kzalloc_obj(*sur40);
if (!sur40)
return -ENOMEM;
@@ -1108,8 +1108,6 @@ static const struct vb2_ops sur40_queue_ops = {
.buf_queue = sur40_buffer_queue,
.start_streaming = sur40_start_streaming,
.stop_streaming = sur40_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static const struct vb2_queue sur40_queue = {
diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c
index f5c5881cef6b..5fa47a1a6fdc 100644
--- a/drivers/input/touchscreen/sx8654.c
+++ b/drivers/input/touchscreen/sx8654.c
@@ -116,7 +116,7 @@ static inline void sx865x_penrelease(struct sx8654 *ts)
static void sx865x_penrelease_timer_handler(struct timer_list *t)
{
- struct sx8654 *ts = from_timer(ts, t, timer);
+ struct sx8654 *ts = timer_container_of(ts, t, timer);
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
@@ -290,7 +290,7 @@ static void sx8654_close(struct input_dev *dev)
disable_irq(client->irq);
if (!sx8654->data->has_irq_penrelease)
- del_timer_sync(&sx8654->timer);
+ timer_delete_sync(&sx8654->timer);
/* enable manual mode mode */
error = i2c_smbus_write_byte(client, sx8654->data->cmd_manual);
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index 93d659ff90aa..623546e80668 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -85,7 +85,7 @@ static int titsc_config_wires(struct titsc *ts_dev)
wire_order[i] = ts_dev->config_inp[i] & 0x0F;
if (WARN_ON(analog_line[i] > 7))
return -EINVAL;
- if (WARN_ON(wire_order[i] > ARRAY_SIZE(config_pins)))
+ if (WARN_ON(wire_order[i] >= ARRAY_SIZE(config_pins)))
return -EINVAL;
}
@@ -389,6 +389,10 @@ static int titsc_parse_dt(struct platform_device *pdev,
dev_warn(&pdev->dev,
"invalid co-ordinate readouts, resetting it to 5\n");
ts_dev->coordinate_readouts = 5;
+ } else if (ts_dev->coordinate_readouts > 6) {
+ dev_warn(&pdev->dev,
+ "co-ordinate readouts too large, limiting to 6\n");
+ ts_dev->coordinate_readouts = 6;
}
err = of_property_read_u32(node, "ti,charge-delay",
@@ -418,7 +422,7 @@ static int titsc_probe(struct platform_device *pdev)
int err;
/* Allocate memory for device */
- ts_dev = kzalloc(sizeof(*ts_dev), GFP_KERNEL);
+ ts_dev = kzalloc_obj(*ts_dev);
input_dev = input_allocate_device();
if (!ts_dev || !input_dev) {
dev_err(&pdev->dev, "failed to allocate memory.\n");
diff --git a/drivers/input/touchscreen/touchit213.c b/drivers/input/touchscreen/touchit213.c
index c2718350815c..6d4a1acf57c9 100644
--- a/drivers/input/touchscreen/touchit213.c
+++ b/drivers/input/touchscreen/touchit213.c
@@ -139,7 +139,7 @@ static int touchit213_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- touchit213 = kzalloc(sizeof(*touchit213), GFP_KERNEL);
+ touchit213 = kzalloc_obj(*touchit213);
input_dev = input_allocate_device();
if (!touchit213 || !input_dev) {
err = -ENOMEM;
@@ -148,8 +148,8 @@ static int touchit213_connect(struct serio *serio, struct serio_driver *drv)
touchit213->serio = serio;
touchit213->dev = input_dev;
- snprintf(touchit213->phys, sizeof(touchit213->phys),
- "%s/input0", serio->phys);
+ scnprintf(touchit213->phys, sizeof(touchit213->phys),
+ "%s/input0", serio->phys);
input_dev->name = "Sahara Touch-iT213 Serial TouchScreen";
input_dev->phys = touchit213->phys;
diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c
index 30ba97bd00a1..d7fdf201e4d1 100644
--- a/drivers/input/touchscreen/touchright.c
+++ b/drivers/input/touchscreen/touchright.c
@@ -102,7 +102,7 @@ static int tr_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- tr = kzalloc(sizeof(*tr), GFP_KERNEL);
+ tr = kzalloc_obj(*tr);
input_dev = input_allocate_device();
if (!tr || !input_dev) {
err = -ENOMEM;
@@ -111,7 +111,7 @@ static int tr_connect(struct serio *serio, struct serio_driver *drv)
tr->serio = serio;
tr->dev = input_dev;
- snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys);
+ scnprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys);
input_dev->name = "Touchright Serial TouchScreen";
input_dev->phys = tr->phys;
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c
index fbd72789ea80..099fd88e65d8 100644
--- a/drivers/input/touchscreen/touchwin.c
+++ b/drivers/input/touchscreen/touchwin.c
@@ -109,7 +109,7 @@ static int tw_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- tw = kzalloc(sizeof(*tw), GFP_KERNEL);
+ tw = kzalloc_obj(*tw);
input_dev = input_allocate_device();
if (!tw || !input_dev) {
err = -ENOMEM;
@@ -118,7 +118,7 @@ static int tw_connect(struct serio *serio, struct serio_driver *drv)
tw->serio = serio;
tw->dev = input_dev;
- snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys);
+ scnprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys);
input_dev->name = "Touchwindow Serial TouchScreen";
input_dev->phys = tw->phys;
diff --git a/drivers/input/touchscreen/tsc2007.h b/drivers/input/touchscreen/tsc2007.h
index 69b08dd6c8df..e346fb4f7552 100644
--- a/drivers/input/touchscreen/tsc2007.h
+++ b/drivers/input/touchscreen/tsc2007.h
@@ -19,6 +19,7 @@
#ifndef _TSC2007_H
#define _TSC2007_H
+#include <linux/input/touchscreen.h>
struct gpio_desc;
#define TSC2007_MEASURE_TEMP0 (0x0 << 4)
@@ -63,6 +64,7 @@ struct tsc2007 {
struct i2c_client *client;
+ struct touchscreen_properties prop;
u16 model;
u16 x_plate_ohms;
u16 max_rt;
diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c
index 8d832a372b89..948935de894b 100644
--- a/drivers/input/touchscreen/tsc2007_core.c
+++ b/drivers/input/touchscreen/tsc2007_core.c
@@ -23,6 +23,7 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
+#include <linux/math64.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/platform_data/tsc2007.h>
@@ -68,7 +69,7 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc)
{
- u32 rt = 0;
+ u64 rt = 0;
/* range filtering */
if (tc->x == MAX_12BIT)
@@ -79,11 +80,13 @@ u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc)
rt = tc->z2 - tc->z1;
rt *= tc->x;
rt *= tsc->x_plate_ohms;
- rt /= tc->z1;
+ rt = div_u64(rt, tc->z1);
rt = (rt + 2047) >> 12;
}
- return rt;
+ if (rt > U32_MAX)
+ return U32_MAX;
+ return (u32) rt;
}
bool tsc2007_is_pen_down(struct tsc2007 *ts)
@@ -142,8 +145,7 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
rt = ts->max_rt - rt;
input_report_key(input, BTN_TOUCH, 1);
- input_report_abs(input, ABS_X, tc.x);
- input_report_abs(input, ABS_Y, tc.y);
+ touchscreen_report_pos(input, &ts->prop, tc.x, tc.y, false);
input_report_abs(input, ABS_PRESSURE, rt);
input_sync(input);
@@ -178,7 +180,8 @@ static void tsc2007_stop(struct tsc2007 *ts)
mb();
wake_up(&ts->wait);
- disable_irq(ts->irq);
+ if (ts->irq)
+ disable_irq(ts->irq);
}
static int tsc2007_open(struct input_dev *input_dev)
@@ -189,7 +192,8 @@ static int tsc2007_open(struct input_dev *input_dev)
ts->stopped = false;
mb();
- enable_irq(ts->irq);
+ if (ts->irq)
+ enable_irq(ts->irq);
/* Prepare for touch readings - power down ADC and enable PENIRQ */
err = tsc2007_xfer(ts, PWRDOWN);
@@ -254,7 +258,7 @@ static int tsc2007_probe_properties(struct device *dev, struct tsc2007 *ts)
if (ts->gpiod)
ts->get_pendown_state = tsc2007_get_pendown_state_gpio;
else
- dev_warn(dev, "Pen down GPIO is not specified in properties\n");
+ dev_dbg(dev, "Pen down GPIO is not specified in properties\n");
return 0;
}
@@ -339,9 +343,9 @@ static int tsc2007_probe(struct i2c_client *client)
input_set_drvdata(input_dev, ts);
input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
-
input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0);
input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0);
+ touchscreen_parse_properties(input_dev, false, &ts->prop);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
ts->fuzzz, 0);
@@ -362,17 +366,19 @@ static int tsc2007_probe(struct i2c_client *client)
pdata->init_platform_hw();
}
- err = devm_request_threaded_irq(&client->dev, ts->irq,
- NULL, tsc2007_soft_irq,
- IRQF_ONESHOT,
- client->dev.driver->name, ts);
- if (err) {
- dev_err(&client->dev, "Failed to request irq %d: %d\n",
- ts->irq, err);
- return err;
- }
+ if (ts->irq) {
+ err = devm_request_threaded_irq(&client->dev, ts->irq,
+ NULL, tsc2007_soft_irq,
+ IRQF_ONESHOT,
+ client->dev.driver->name, ts);
+ if (err) {
+ dev_err(&client->dev, "Failed to request irq %d: %d\n",
+ ts->irq, err);
+ return err;
+ }
- tsc2007_stop(ts);
+ tsc2007_stop(ts);
+ }
/* power down the chip (TSC2007_SETUP does not ACK on I2C) */
err = tsc2007_xfer(ts, PWRDOWN);
diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c
index df39dee13e1c..eba53613b005 100644
--- a/drivers/input/touchscreen/tsc200x-core.c
+++ b/drivers/input/touchscreen/tsc200x-core.c
@@ -10,6 +10,7 @@
* based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.com>
*/
+#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
@@ -194,7 +195,7 @@ out:
static void tsc200x_penup_timer(struct timer_list *t)
{
- struct tsc200x *ts = from_timer(ts, t, penup_timer);
+ struct tsc200x *ts = timer_container_of(ts, t, penup_timer);
guard(spinlock_irqsave)(&ts->lock);
tsc200x_update_pen_state(ts, 0, 0, 0);
@@ -229,7 +230,7 @@ static void __tsc200x_disable(struct tsc200x *ts)
guard(disable_irq)(&ts->irq);
- del_timer_sync(&ts->penup_timer);
+ timer_delete_sync(&ts->penup_timer);
cancel_delayed_work_sync(&ts->esd_work);
}
@@ -388,7 +389,7 @@ static void tsc200x_esd_work(struct work_struct *work)
dev_info(ts->dev, "TSC200X not responding - resetting\n");
scoped_guard(disable_irq, &ts->irq) {
- del_timer_sync(&ts->penup_timer);
+ timer_delete_sync(&ts->penup_timer);
tsc200x_update_pen_state(ts, 0, 0, 0);
tsc200x_reset(ts);
}
diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c
index 9f485cf57a72..2a28a309eab5 100644
--- a/drivers/input/touchscreen/tsc40.c
+++ b/drivers/input/touchscreen/tsc40.c
@@ -83,7 +83,7 @@ static int tsc_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int error;
- ptsc = kzalloc(sizeof(*ptsc), GFP_KERNEL);
+ ptsc = kzalloc_obj(*ptsc);
input_dev = input_allocate_device();
if (!ptsc || !input_dev) {
error = -ENOMEM;
@@ -92,7 +92,7 @@ static int tsc_connect(struct serio *serio, struct serio_driver *drv)
ptsc->serio = serio;
ptsc->dev = input_dev;
- snprintf(ptsc->phys, sizeof(ptsc->phys), "%s/input0", serio->phys);
+ scnprintf(ptsc->phys, sizeof(ptsc->phys), "%s/input0", serio->phys);
input_dev->name = "TSC-10/25/40 Serial TouchScreen";
input_dev->phys = ptsc->phys;
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 7567efabe014..657555c8796c 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -378,7 +378,7 @@ static int mtouch_alloc(struct usbtouch_usb *usbtouch)
{
struct mtouch_priv *priv;
- priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+ priv = kmalloc_obj(*priv);
if (!priv)
return -ENOMEM;
@@ -938,7 +938,7 @@ static int nexio_alloc(struct usbtouch_usb *usbtouch)
struct nexio_priv *priv;
int ret = -ENOMEM;
- priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+ priv = kmalloc_obj(*priv);
if (!priv)
goto out_buf;
@@ -1458,7 +1458,7 @@ static int usbtouch_probe(struct usb_interface *intf,
if (!endpoint)
return -ENXIO;
- usbtouch = kzalloc(sizeof(*usbtouch), GFP_KERNEL);
+ usbtouch = kzalloc_obj(*usbtouch);
input_dev = input_allocate_device();
if (!usbtouch || !input_dev)
goto out_free;
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index ed2ca8a689d5..45930d731873 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -596,7 +596,7 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
char basename[64] = "Wacom Serial";
int err, err_pen, err_touch;
- w8001 = kzalloc(sizeof(*w8001), GFP_KERNEL);
+ w8001 = kzalloc_obj(*w8001);
input_dev_pen = input_allocate_device();
input_dev_touch = input_allocate_device();
if (!w8001 || !input_dev_pen || !input_dev_touch) {
diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c
index 88d376090e6e..1e2a6bbb88cb 100644
--- a/drivers/input/touchscreen/wdt87xx_i2c.c
+++ b/drivers/input/touchscreen/wdt87xx_i2c.c
@@ -1026,10 +1026,8 @@ static int wdt87xx_ts_create_input_device(struct wdt87xx_data *wdt)
int error;
input = devm_input_allocate_device(dev);
- if (!input) {
- dev_err(dev, "failed to allocate input device\n");
+ if (!input)
return -ENOMEM;
- }
wdt->input = input;
input->name = "WDT87xx Touchscreen";
@@ -1053,10 +1051,8 @@ static int wdt87xx_ts_create_input_device(struct wdt87xx_data *wdt)
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
error = input_register_device(input);
- if (error) {
- dev_err(dev, "failed to register input device: %d\n", error);
- return error;
- }
+ if (error)
+ return dev_err_probe(dev, error, "failed to register input device\n");
return 0;
}
@@ -1096,10 +1092,8 @@ static int wdt87xx_ts_probe(struct i2c_client *client)
NULL, wdt87xx_ts_interrupt,
IRQF_ONESHOT,
client->name, wdt);
- if (error) {
- dev_err(&client->dev, "request irq failed: %d\n", error);
+ if (error)
return error;
- }
return 0;
}
diff --git a/drivers/input/touchscreen/wm9705.c b/drivers/input/touchscreen/wm9705.c
index 4b55d5e1ea0f..96484aae030c 100644
--- a/drivers/input/touchscreen/wm9705.c
+++ b/drivers/input/touchscreen/wm9705.c
@@ -9,6 +9,7 @@
* Russell King <rmk@arm.linux.org.uk>
*/
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c
index 6947714dfefa..087ece57741a 100644
--- a/drivers/input/touchscreen/wm9712.c
+++ b/drivers/input/touchscreen/wm9712.c
@@ -9,6 +9,7 @@
* Russell King <rmk@arm.linux.org.uk>
*/
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c
index a67fbe304f92..6f13f46ce6e6 100644
--- a/drivers/input/touchscreen/wm9713.c
+++ b/drivers/input/touchscreen/wm9713.c
@@ -9,6 +9,7 @@
* Russell King <rmk@arm.linux.org.uk>
*/
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index b25771a8df2b..96354c44af87 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -29,6 +29,7 @@
* - Support for async sampling control for noisy LCDs.
*/
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c
index df42fdf36ae3..a360749fa076 100644
--- a/drivers/input/touchscreen/zforce_ts.c
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -747,8 +747,7 @@ static int zforce_probe(struct i2c_client *client)
input_dev = devm_input_allocate_device(&client->dev);
if (!input_dev)
- return dev_err_probe(&client->dev, -ENOMEM,
- "could not allocate input device\n");
+ return -ENOMEM;
ts->client = client;
ts->input = input_dev;