From 7dbad03ebcb924cde142f7477d65a54ffb1166a3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 6 Aug 2020 20:20:39 +0200 Subject: ARM: s3c: adc: move header to linux/soc/samsung There are multiple drivers using the private adc interface. It seems unlikely that they would ever get converted to iio, so make the current state official by making the header file global. The s3c2410_ts driver needs a couple of register definitions as well. Signed-off-by: Arnd Bergmann Acked-by: Guenter Roeck Acked-by: Dmitry Torokhov Acked-by: Sebastian Reichel Link: https://lore.kernel.org/r/20200806182059.2431-22-krzk@kernel.org Signed-off-by: Krzysztof Kozlowski --- drivers/input/touchscreen/s3c2410_ts.c | 37 ++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index 82920ff46f72..2e70c0b79444 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -20,10 +20,43 @@ #include #include -#include -#include +#include #include +#define S3C2410_ADCCON (0x00) +#define S3C2410_ADCTSC (0x04) +#define S3C2410_ADCDLY (0x08) +#define S3C2410_ADCDAT0 (0x0C) +#define S3C2410_ADCDAT1 (0x10) +#define S3C64XX_ADCUPDN (0x14) +#define S3C2443_ADCMUX (0x18) +#define S3C64XX_ADCCLRINT (0x18) +#define S5P_ADCMUX (0x1C) +#define S3C64XX_ADCCLRINTPNDNUP (0x20) + +/* ADCTSC Register Bits */ +#define S3C2443_ADCTSC_UD_SEN (1 << 8) +#define S3C2410_ADCTSC_YM_SEN (1<<7) +#define S3C2410_ADCTSC_YP_SEN (1<<6) +#define S3C2410_ADCTSC_XM_SEN (1<<5) +#define S3C2410_ADCTSC_XP_SEN (1<<4) +#define S3C2410_ADCTSC_PULL_UP_DISABLE (1<<3) +#define S3C2410_ADCTSC_AUTO_PST (1<<2) +#define S3C2410_ADCTSC_XY_PST(x) (((x)&0x3)<<0) + +/* ADCDAT0 Bits */ +#define S3C2410_ADCDAT0_UPDOWN (1<<15) +#define S3C2410_ADCDAT0_AUTO_PST (1<<14) +#define S3C2410_ADCDAT0_XY_PST (0x3<<12) +#define S3C2410_ADCDAT0_XPDATA_MASK (0x03FF) + +/* ADCDAT1 Bits */ +#define S3C2410_ADCDAT1_UPDOWN (1<<15) +#define S3C2410_ADCDAT1_AUTO_PST (1<<14) +#define S3C2410_ADCDAT1_XY_PST (0x3<<12) +#define S3C2410_ADCDAT1_YPDATA_MASK (0x03FF) + + #define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0)) #define INT_DOWN (0) -- cgit v1.2.3-59-g8ed1b From 376ccca853fdb9959f7ac5185a428a9f91e71e86 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 27 Oct 2020 10:57:24 +0100 Subject: Input: ads7846: do not overwrite spi->mode flags set by spi framework Do not overwrite spi->mode flags set by spi framework, otherwise the chip select polarity will get lost. Signed-off-by: Oleksij Rempel Acked-by: Dmitry Torokhov Link: https://lore.kernel.org/r/20201027095724.18654-3-o.rempel@pengutronix.de Signed-off-by: Mark Brown --- drivers/input/touchscreen/ads7846.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 8fd7fc39c4fd..f2dc2c8ab5ec 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -1288,7 +1288,8 @@ static int ads7846_probe(struct spi_device *spi) * may not. So we stick to very-portable 8 bit words, both RX and TX. */ spi->bits_per_word = 8; - spi->mode = SPI_MODE_0; + spi->mode &= ~SPI_MODE_X_MASK; + spi->mode |= SPI_MODE_0; err = spi_setup(spi); if (err < 0) return err; -- cgit v1.2.3-59-g8ed1b From fafd320ae51b9c72d371585b2501f86640ea7b7d Mon Sep 17 00:00:00 2001 From: "jeffrey.lin" Date: Tue, 15 Dec 2020 10:50:12 -0800 Subject: Input: raydium_ts_i2c - do not send zero length Add default write command package to prevent i2c quirk error of zero data length as Raydium touch firmware update is executed. Signed-off-by: jeffrey.lin Link: https://lore.kernel.org/r/1608031217-7247-1-git-send-email-jeffrey.lin@raydium.corp-partner.google.com Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/raydium_i2c_ts.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index e694a9b2b1e5..678afac85507 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -395,6 +395,7 @@ static int raydium_i2c_write_object(struct i2c_client *client, enum raydium_bl_ack state) { int error; + static const u8 cmd[] = { 0xFF, 0x39 }; error = raydium_i2c_send(client, RM_CMD_BOOT_WRT, data, len); if (error) { @@ -403,7 +404,7 @@ static int raydium_i2c_write_object(struct i2c_client *client, return error; } - error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, NULL, 0); + error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, cmd, sizeof(cmd)); if (error) { dev_err(&client->dev, "Ack obj command failed: %d\n", error); return error; -- cgit v1.2.3-59-g8ed1b From 7c0c38402a61db1141dd5a2ae2f44d4cdc17a23a Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 19 Jan 2021 18:17:53 -0800 Subject: Input: melfas_mip4 - mark a bunch of variables as __always_unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dmitry requested to keep these around for the purposes of documentation. Fixes the following W=1 kernel build warning(s): drivers/input/touchscreen/melfas_mip4.c: In function ‘mip4_report_touch’: drivers/input/touchscreen/melfas_mip4.c:474:5: warning: variable ‘size’ set but not used [-Wunused-but-set-variable] drivers/input/touchscreen/melfas_mip4.c:472:5: warning: variable ‘pressure_stage’ set but not used [-Wunused-but-set-variable] drivers/input/touchscreen/melfas_mip4.c:469:7: warning: variable ‘palm’ set but not used [-Wunused-but-set-variable] drivers/input/touchscreen/melfas_mip4.c:468:7: warning: variable ‘hover’ set but not used [-Wunused-but-set-variable] Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20210114152323.2382283-3-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/melfas_mip4.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index c0050044a5a9..225796a3f546 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -465,13 +465,13 @@ static void mip4_report_keys(struct mip4_ts *ts, u8 *packet) static void mip4_report_touch(struct mip4_ts *ts, u8 *packet) { int id; - bool hover; - bool palm; + bool __always_unused hover; + bool __always_unused palm; bool state; u16 x, y; - u8 pressure_stage = 0; + u8 __always_unused pressure_stage = 0; u8 pressure; - u8 size; + u8 __always_unused size; u8 touch_major; u8 touch_minor; -- cgit v1.2.3-59-g8ed1b From 33f93726b7b28f0206e2dfbfa98b54f4415a47ad Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 19 Jan 2021 18:19:04 -0800 Subject: Input: usbtouchscreen - actually check return value of usb_submit_urb() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/input/touchscreen/usbtouchscreen.c: In function ‘nexio_read_data’: drivers/input/touchscreen/usbtouchscreen.c:1052:50: warning: variable ‘ret’ set but not used [-Wunused-but-set-variable] Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20210114152323.2382283-4-lee.jones@linaro.org [dtor: log error code as well] Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/usbtouchscreen.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 397cb1d3f481..c847453a03c2 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -1044,6 +1044,7 @@ static void nexio_exit(struct usbtouch_usb *usbtouch) static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt) { + struct device *dev = &usbtouch->interface->dev; struct nexio_touch_packet *packet = (void *) pkt; struct nexio_priv *priv = usbtouch->priv; unsigned int data_len = be16_to_cpu(packet->data_len); @@ -1062,6 +1063,8 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt) /* send ACK */ ret = usb_submit_urb(priv->ack, GFP_ATOMIC); + if (ret) + dev_warn(dev, "Failed to submit ACK URB: %d\n", ret); if (!usbtouch->type->max_xc) { usbtouch->type->max_xc = 2 * x_len; -- cgit v1.2.3-59-g8ed1b From e664f0021fcaf4e4e5078e00a75db0f0bfa79256 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 19 Jan 2021 18:22:29 -0800 Subject: Input: surface3_spi - remove set but unused variable 'timestamp' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/input/touchscreen/surface3_spi.c: In function ‘surface3_spi_process_touch’: drivers/input/touchscreen/surface3_spi.c:97:6: warning: variable ‘timestamp’ set but not used [-Wunused-but-set-variable] Signed-off-by: Lee Jones Reviewed-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20210114152323.2382283-5-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/surface3_spi.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c index 731454599fce..1da23e5585a0 100644 --- a/drivers/input/touchscreen/surface3_spi.c +++ b/drivers/input/touchscreen/surface3_spi.c @@ -94,9 +94,7 @@ static void surface3_spi_report_touch(struct surface3_ts_data *ts_data, static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *data) { - u16 timestamp; unsigned int i; - timestamp = get_unaligned_le16(&data[15]); for (i = 0; i < 13; i++) { struct surface3_ts_data_finger *finger; -- cgit v1.2.3-59-g8ed1b From 05b67b7a08fb64ecb80d365f5d745a473a020dba Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 19 Jan 2021 18:23:23 -0800 Subject: Input: stmpe-ts - add description for 'prop' struct member Fixes the following W=1 kernel build warning(s): drivers/input/touchscreen/stmpe-ts.c:82: warning: Function parameter or member 'prop' not described in 'stmpe_touch' Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20210114152323.2382283-6-lee.jones@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/stmpe-ts.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index cd747725589b..25c45c3a3561 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -52,6 +52,7 @@ * @idev: registered input device * @work: a work item used to scan the device * @dev: a pointer back to the MFD cell struct device* + * @prop: Touchscreen properties * @ave_ctrl: Sample average control * (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples) * @touch_det_delay: Touch detect interrupt delay -- cgit v1.2.3-59-g8ed1b From 6965eece2a89c3f1d00881c6052ee1e987870c08 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 20 Jan 2021 23:18:28 -0800 Subject: Input: ads7846 - convert to one message Convert multiple full duplex transfers in to a single transfer to reduce CPU load. Current driver version support following filtering modes: - ads7846_no_filter() - not filtered - ads7846_debounce_filter() - driver specific debounce filter - pdata->filter - platform specific debounce filter (do any platform provides such filter?) Without filter this HW is not really usable, since the physic of resistive touchscreen can provide some bounce effects. With driver internal filter, we have constant amount of retries + debounce retries if some anomaly was detected. High amount of tiny SPI transfers is the primer reason of high CPU load and interrupt frequency. This patch create one SPI transfer with all fields and not optional retires. If bounce anomaly was detected, we will make more transfer if needed. Without this patch, we will get about 10% CPU load on iMX6S on pen-down event. For example by holding stylus on the screen. With this patch, depending in the amount of retries, the CPU load will be 1% with "ti,debounce-rep = <3>". One buffer transfer allows us to use PIO FIFO or DMA engine, depending on the platform. Signed-off-by: Oleksij Rempel Link: https://lore.kernel.org/r/20201110085041.16303-3-o.rempel@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 376 ++++++++++++++++++------------------ 1 file changed, 193 insertions(+), 183 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index de058644ef8a..93fc182f5e84 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -64,24 +64,13 @@ struct ads7846_buf { u8 cmd; - /* - * This union is a temporary hack. The driver does an in-place - * endianness conversion. This will be cleaned up in the next - * patch. - */ - union { - __be16 data_be16; - u16 data; - }; + __be16 data; } __packed; - -struct ts_event { - bool ignore; - struct ads7846_buf x; - struct ads7846_buf y; - struct ads7846_buf z1; - struct ads7846_buf z2; +struct ads7846_buf_layout { + unsigned int offset; + unsigned int count; + unsigned int skip; }; /* @@ -90,12 +79,18 @@ struct ts_event { * systems where main memory is not DMA-coherent (most non-x86 boards). */ struct ads7846_packet { - struct ts_event tc; - struct ads7846_buf read_x_cmd; - struct ads7846_buf read_y_cmd; - struct ads7846_buf read_z1_cmd; - struct ads7846_buf read_z2_cmd; + unsigned int count; + unsigned int count_skip; + unsigned int cmds; + unsigned int last_cmd_idx; + struct ads7846_buf_layout l[5]; + struct ads7846_buf *rx; + struct ads7846_buf *tx; + struct ads7846_buf pwrdown_cmd; + + bool ignore; + u16 x, y, z1, z2; }; struct ads7846 { @@ -194,7 +189,6 @@ struct ads7846 { #define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref)) #define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref)) #define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref)) - #define READ_X(vref) (READ_12BIT_DFR(x, 1, vref)) #define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */ @@ -207,6 +201,21 @@ struct ads7846 { #define REF_ON (READ_12BIT_DFR(x, 1, 1)) #define REF_OFF (READ_12BIT_DFR(y, 0, 0)) +/* Order commands in the most optimal way to reduce Vref switching and + * settling time: + * Measure: X; Vref: X+, X-; IN: Y+ + * Measure: Y; Vref: Y+, Y-; IN: X+ + * Measure: Z1; Vref: Y+, X-; IN: X+ + * Measure: Z2; Vref: Y+, X-; IN: Y- + */ +enum ads7846_cmds { + ADS7846_X, + ADS7846_Y, + ADS7846_Z1, + ADS7846_Z2, + ADS7846_PWDOWN, +}; + static int get_pendown_state(struct ads7846 *ts) { if (ts->get_pendown_state) @@ -689,26 +698,109 @@ static int ads7846_no_filter(void *ads, int data_idx, int *val) return ADS7846_FILTER_OK; } -static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m) +static int ads7846_get_value(struct ads7846_buf *buf) { int value; - struct spi_transfer *t = - list_entry(m->transfers.prev, struct spi_transfer, transfer_list); - struct ads7846_buf *buf = t->rx_buf; - value = be16_to_cpup(&buf->data_be16); + value = be16_to_cpup(&buf->data); /* enforce ADC output is 12 bits width */ return (value >> 3) & 0xfff; } -static void ads7846_update_value(struct spi_message *m, int val) +static void ads7846_set_cmd_val(struct ads7846 *ts, enum ads7846_cmds cmd_idx, + u16 val) +{ + struct ads7846_packet *packet = ts->packet; + + switch (cmd_idx) { + case ADS7846_Y: + packet->y = val; + break; + case ADS7846_X: + packet->x = val; + break; + case ADS7846_Z1: + packet->z1 = val; + break; + case ADS7846_Z2: + packet->z2 = val; + break; + default: + WARN_ON_ONCE(1); + } +} + +static u8 ads7846_get_cmd(enum ads7846_cmds cmd_idx, int vref) +{ + switch (cmd_idx) { + case ADS7846_Y: + return READ_Y(vref); + case ADS7846_X: + return READ_X(vref); + + /* 7846 specific commands */ + case ADS7846_Z1: + return READ_Z1(vref); + case ADS7846_Z2: + return READ_Z2(vref); + case ADS7846_PWDOWN: + return PWRDOWN; + default: + WARN_ON_ONCE(1); + } + + return 0; +} + +static bool ads7846_cmd_need_settle(enum ads7846_cmds cmd_idx) +{ + switch (cmd_idx) { + case ADS7846_X: + case ADS7846_Y: + case ADS7846_Z1: + case ADS7846_Z2: + return true; + case ADS7846_PWDOWN: + return false; + default: + WARN_ON_ONCE(1); + } + + return false; +} + +static int ads7846_filter(struct ads7846 *ts) { - struct spi_transfer *t = - list_entry(m->transfers.prev, struct spi_transfer, transfer_list); - struct ads7846_buf *buf = t->rx_buf; + struct ads7846_packet *packet = ts->packet; + int action; + int val; + unsigned int cmd_idx, b; - buf->data = val; + packet->ignore = false; + for (cmd_idx = packet->last_cmd_idx; cmd_idx < packet->cmds - 1; cmd_idx++) { + struct ads7846_buf_layout *l = &packet->l[cmd_idx]; + + packet->last_cmd_idx = cmd_idx; + + for (b = l->skip; b < l->count; b++) { + val = ads7846_get_value(&packet->rx[l->offset + b]); + + action = ts->filter(ts->filter_data, cmd_idx, &val); + if (action == ADS7846_FILTER_REPEAT) { + if (b == l->count - 1) + return -EAGAIN; + } else if (action == ADS7846_FILTER_OK) { + ads7846_set_cmd_val(ts, cmd_idx, val); + break; + } else { + packet->ignore = true; + return 0; + } + } + } + + return 0; } static void ads7846_read_state(struct ads7846 *ts) @@ -716,52 +808,26 @@ static void ads7846_read_state(struct ads7846 *ts) struct ads7846_packet *packet = ts->packet; struct spi_message *m; int msg_idx = 0; - int val; - int action; int error; - while (msg_idx < ts->msg_count) { + packet->last_cmd_idx = 0; + while (true) { ts->wait_for_sync(); m = &ts->msg[msg_idx]; error = spi_sync(ts->spi, m); if (error) { dev_err(&ts->spi->dev, "spi_sync --> %d\n", error); - packet->tc.ignore = true; + packet->ignore = true; return; } - /* - * Last message is power down request, no need to convert - * or filter the value. - */ - if (msg_idx < ts->msg_count - 1) { - - val = ads7846_get_value(ts, m); - - action = ts->filter(ts->filter_data, msg_idx, &val); - switch (action) { - case ADS7846_FILTER_REPEAT: - continue; - - case ADS7846_FILTER_IGNORE: - packet->tc.ignore = true; - msg_idx = ts->msg_count - 1; - continue; - - case ADS7846_FILTER_OK: - ads7846_update_value(m, val); - packet->tc.ignore = false; - msg_idx++; - break; + error = ads7846_filter(ts); + if (error) + continue; - default: - BUG(); - } - } else { - msg_idx++; - } + return; } } @@ -771,19 +837,14 @@ static void ads7846_report_state(struct ads7846 *ts) unsigned int Rt; u16 x, y, z1, z2; - /* - * ads7846_get_value() does in-place conversion (including byte swap) - * from on-the-wire format as part of debouncing to get stable - * readings. - */ - x = packet->tc.x.data; - y = packet->tc.y.data; + x = packet->x; + y = packet->y; if (ts->model == 7845) { z1 = 0; z2 = 0; } else { - z1 = packet->tc.z1.data; - z2 = packet->tc.z2.data; + z1 = packet->z1; + z2 = packet->z2; } /* range filtering */ @@ -816,9 +877,9 @@ static void ads7846_report_state(struct ads7846 *ts) * the maximum. Don't report it to user space, repeat at least * once more the measurement */ - if (packet->tc.ignore || Rt > ts->pressure_max) { + if (packet->ignore || Rt > ts->pressure_max) { dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n", - packet->tc.ignore, Rt); + packet->ignore, Rt); return; } @@ -979,13 +1040,59 @@ static int ads7846_setup_pendown(struct spi_device *spi, * Set up the transfers to read touchscreen state; this assumes we * use formula #2 for pressure, not #3. */ -static void ads7846_setup_spi_msg(struct ads7846 *ts, +static int ads7846_setup_spi_msg(struct ads7846 *ts, const struct ads7846_platform_data *pdata) { struct spi_message *m = &ts->msg[0]; struct spi_transfer *x = ts->xfer; struct ads7846_packet *packet = ts->packet; int vref = pdata->keep_vref_on; + unsigned int count, offset = 0; + unsigned int cmd_idx, b; + unsigned long time; + size_t size = 0; + + /* time per bit */ + time = NSEC_PER_SEC / ts->spi->max_speed_hz; + + count = pdata->settle_delay_usecs * NSEC_PER_USEC / time; + packet->count_skip = DIV_ROUND_UP(count, 24); + + if (ts->debounce_max && ts->debounce_rep) + /* ads7846_debounce_filter() is making ts->debounce_rep + 2 + * reads. So we need to get all samples for normal case. */ + packet->count = ts->debounce_rep + 2; + else + packet->count = 1; + + if (ts->model == 7846) + packet->cmds = 5; /* x, y, z1, z2, pwdown */ + else + packet->cmds = 3; /* x, y, pwdown */ + + for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) { + struct ads7846_buf_layout *l = &packet->l[cmd_idx]; + unsigned int max_count; + + if (ads7846_cmd_need_settle(cmd_idx)) + max_count = packet->count + packet->count_skip; + else + max_count = packet->count; + + l->offset = offset; + offset += max_count; + l->count = max_count; + l->skip = packet->count_skip; + size += sizeof(*packet->tx) * max_count; + } + + packet->tx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL); + if (!packet->tx) + return -ENOMEM; + + packet->rx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL); + if (!packet->rx) + return -ENOMEM; if (ts->model == 7873) { /* @@ -1001,117 +1108,20 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, spi_message_init(m); m->context = ts; - packet->read_y_cmd.cmd = READ_Y(vref); - x->tx_buf = &packet->read_y_cmd; - x->rx_buf = &packet->tc.y; - x->len = 3; - spi_message_add_tail(x, m); + for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) { + struct ads7846_buf_layout *l = &packet->l[cmd_idx]; + u8 cmd = ads7846_get_cmd(cmd_idx, vref); - /* - * The first sample after switching drivers can be low quality; - * optionally discard it, using a second one after the signals - * have had enough time to stabilize. - */ - if (pdata->settle_delay_usecs) { - x->delay.value = pdata->settle_delay_usecs; - x->delay.unit = SPI_DELAY_UNIT_USECS; - x++; - - x->tx_buf = &packet->read_y_cmd; - x->rx_buf = &packet->tc.y; - x->len = 3; - spi_message_add_tail(x, m); + for (b = 0; b < l->count; b++) + packet->tx[l->offset + b].cmd = cmd; } - ts->msg_count++; - m++; - spi_message_init(m); - m->context = ts; - - /* turn y- off, x+ on, then leave in lowpower */ - x++; - packet->read_x_cmd.cmd = READ_X(vref); - x->tx_buf = &packet->read_x_cmd; - x->rx_buf = &packet->tc.x; - x->len = 3; + x->tx_buf = packet->tx; + x->rx_buf = packet->rx; + x->len = size; spi_message_add_tail(x, m); - /* ... maybe discard first sample ... */ - if (pdata->settle_delay_usecs) { - x->delay.value = pdata->settle_delay_usecs; - x->delay.unit = SPI_DELAY_UNIT_USECS; - - x++; - x->tx_buf = &packet->read_x_cmd; - x->rx_buf = &packet->tc.x; - x->len = 3; - spi_message_add_tail(x, m); - } - - /* turn y+ off, x- on; we'll use formula #2 */ - if (ts->model == 7846) { - ts->msg_count++; - m++; - spi_message_init(m); - m->context = ts; - - x++; - packet->read_z1_cmd.cmd = READ_Z1(vref); - x->tx_buf = &packet->read_z1_cmd; - x->rx_buf = &packet->tc.z1; - x->len = 3; - spi_message_add_tail(x, m); - - /* ... maybe discard first sample ... */ - if (pdata->settle_delay_usecs) { - x->delay.value = pdata->settle_delay_usecs; - x->delay.unit = SPI_DELAY_UNIT_USECS; - - x++; - x->tx_buf = &packet->read_z1_cmd; - x->rx_buf = &packet->tc.z1; - x->len = 3; - spi_message_add_tail(x, m); - } - - ts->msg_count++; - m++; - spi_message_init(m); - m->context = ts; - - x++; - packet->read_z2_cmd.cmd = READ_Z2(vref); - x->tx_buf = &packet->read_z2_cmd; - x->rx_buf = &packet->tc.z2; - x->len = 3; - spi_message_add_tail(x, m); - - /* ... maybe discard first sample ... */ - if (pdata->settle_delay_usecs) { - x->delay.value = pdata->settle_delay_usecs; - x->delay.unit = SPI_DELAY_UNIT_USECS; - - x++; - x->tx_buf = &packet->read_z2_cmd; - x->rx_buf = &packet->tc.z2; - x->len = 3; - spi_message_add_tail(x, m); - } - } - - /* power down */ - ts->msg_count++; - m++; - spi_message_init(m); - m->context = ts; - - x++; - packet->pwrdown_cmd.cmd = PWRDOWN; - x->tx_buf = &packet->pwrdown_cmd; - x->len = 3; - - CS_CHANGE(*x); - spi_message_add_tail(x, m); + return 0; } #ifdef CONFIG_OF -- cgit v1.2.3-59-g8ed1b From 9517b95bdc4699d94c2ffc6a520bb0ccec396f5b Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Sun, 24 Jan 2021 14:28:01 -0800 Subject: Input: elants_i2c - add support for eKTF3624 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ELAN KTF3624 touchscreen support to the elants_i2c driver. The eKTF3624 TS is found on a series of ASUS Transformer tablet devices, Nexus 7 tablet and etc. The firmware interface of eKTF3624 is nearly identical to eKTH3500, which is already supported by the driver. The minor differences of the firmware interface are now handled by the driver. The eKTF3624 support was tested on ASUS Transformer TF700T, TF300T and Nexus 7 tablets. Signed-off-by: Michał Mirosław Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210124195414.27333-1-digetx@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/elants_i2c.c | 152 +++++++++++++++++++++++++++++---- 1 file changed, 135 insertions(+), 17 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index d51cb910fba1..6f57ec579f00 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -56,6 +56,7 @@ #define QUEUE_HEADER_SINGLE 0x62 #define QUEUE_HEADER_NORMAL 0X63 #define QUEUE_HEADER_WAIT 0x64 +#define QUEUE_HEADER_NORMAL2 0x66 /* Command header definition */ #define CMD_HEADER_WRITE 0x54 @@ -69,6 +70,7 @@ #define CMD_HEADER_REK 0x66 /* FW position data */ +#define PACKET_SIZE_OLD 40 #define PACKET_SIZE 55 #define MAX_CONTACT_NUM 10 #define FW_POS_HEADER 0 @@ -90,6 +92,8 @@ /* FW read command, 0x53 0x?? 0x0, 0x01 */ #define E_ELAN_INFO_FW_VER 0x00 #define E_ELAN_INFO_BC_VER 0x10 +#define E_ELAN_INFO_X_RES 0x60 +#define E_ELAN_INFO_Y_RES 0x63 #define E_ELAN_INFO_REK 0xD0 #define E_ELAN_INFO_TEST_VER 0xE0 #define E_ELAN_INFO_FW_ID 0xF0 @@ -112,6 +116,11 @@ #define ELAN_POWERON_DELAY_USEC 500 #define ELAN_RESET_DELAY_MSEC 20 +enum elants_chip_id { + EKTH3500, + EKTF3624, +}; + enum elants_state { ELAN_STATE_NORMAL, ELAN_WAIT_QUEUE_HEADER, @@ -143,9 +152,12 @@ struct elants_data { unsigned int y_res; unsigned int x_max; unsigned int y_max; + unsigned int phy_x; + unsigned int phy_y; struct touchscreen_properties prop; enum elants_state state; + enum elants_chip_id chip_id; enum elants_iap_mode iap_mode; /* Guards against concurrent access to the device via sysfs */ @@ -433,7 +445,51 @@ static int elants_i2c_query_bc_version(struct elants_data *ts) return 0; } -static int elants_i2c_query_ts_info(struct elants_data *ts) +static int elants_i2c_query_ts_info_ektf(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error; + u8 resp[4]; + u16 phy_x, phy_y; + const u8 get_xres_cmd[] = { + CMD_HEADER_READ, E_ELAN_INFO_X_RES, 0x00, 0x00 + }; + const u8 get_yres_cmd[] = { + CMD_HEADER_READ, E_ELAN_INFO_Y_RES, 0x00, 0x00 + }; + + /* Get X/Y size in mm */ + error = elants_i2c_execute_command(client, get_xres_cmd, + sizeof(get_xres_cmd), + resp, sizeof(resp), 1, + "get X size"); + if (error) + return error; + + phy_x = resp[2] | ((resp[3] & 0xF0) << 4); + + error = elants_i2c_execute_command(client, get_yres_cmd, + sizeof(get_yres_cmd), + resp, sizeof(resp), 1, + "get Y size"); + if (error) + return error; + + phy_y = resp[2] | ((resp[3] & 0xF0) << 4); + + dev_dbg(&client->dev, "phy_x=%d, phy_y=%d\n", phy_x, phy_y); + + ts->phy_x = phy_x; + ts->phy_y = phy_y; + + /* eKTF doesn't report max size, set it to default values */ + ts->x_max = 2240 - 1; + ts->y_max = 1408 - 1; + + return 0; +} + +static int elants_i2c_query_ts_info_ekth(struct elants_data *ts) { struct i2c_client *client = ts->client; int error; @@ -508,6 +564,8 @@ static int elants_i2c_query_ts_info(struct elants_data *ts) ts->x_res = DIV_ROUND_CLOSEST(ts->x_max, phy_x); ts->y_max = ELAN_TS_RESOLUTION(cols, osr); ts->y_res = DIV_ROUND_CLOSEST(ts->y_max, phy_y); + ts->phy_x = phy_x; + ts->phy_y = phy_y; } return 0; @@ -587,8 +645,20 @@ static int elants_i2c_initialize(struct elants_data *ts) error = elants_i2c_query_fw_version(ts); if (!error) error = elants_i2c_query_test_version(ts); - if (!error) - error = elants_i2c_query_ts_info(ts); + + switch (ts->chip_id) { + case EKTH3500: + if (!error) + error = elants_i2c_query_ts_info_ekth(ts); + break; + case EKTF3624: + if (!error) + error = elants_i2c_query_ts_info_ektf(ts); + break; + default: + unreachable(); + break; + } if (error) ts->iap_mode = ELAN_IAP_RECOVERY; @@ -853,7 +923,8 @@ out: * Event reporting. */ -static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf) +static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf, + size_t packet_size) { struct input_dev *input = ts->input; unsigned int n_fingers; @@ -880,8 +951,24 @@ static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf) pos = &buf[FW_POS_XY + i * 3]; x = (((u16)pos[0] & 0xf0) << 4) | pos[1]; y = (((u16)pos[0] & 0x0f) << 8) | pos[2]; - p = buf[FW_POS_PRESSURE + i]; - w = buf[FW_POS_WIDTH + i]; + + /* + * eKTF3624 may have use "old" touch-report format, + * depending on a device and TS firmware version. + * For example, ASUS Transformer devices use the "old" + * format, while ASUS Nexus 7 uses the "new" formant. + */ + if (packet_size == PACKET_SIZE_OLD && + ts->chip_id == EKTF3624) { + w = buf[FW_POS_WIDTH + i / 2]; + w >>= 4 * (~i & 1); + w |= w << 4; + w |= !w; + p = w; + } else { + p = buf[FW_POS_PRESSURE + i]; + w = buf[FW_POS_WIDTH + i]; + } dev_dbg(&ts->client->dev, "i=%d x=%d y=%d p=%d w=%d\n", i, x, y, p, w); @@ -913,7 +1000,8 @@ static u8 elants_i2c_calculate_checksum(u8 *buf) return checksum; } -static void elants_i2c_event(struct elants_data *ts, u8 *buf) +static void elants_i2c_event(struct elants_data *ts, u8 *buf, + size_t packet_size) { u8 checksum = elants_i2c_calculate_checksum(buf); @@ -927,7 +1015,7 @@ static void elants_i2c_event(struct elants_data *ts, u8 *buf) "%s: unknown packet type: %02x\n", __func__, buf[FW_POS_HEADER]); else - elants_i2c_mt_event(ts, buf); + elants_i2c_mt_event(ts, buf, packet_size); } static irqreturn_t elants_i2c_irq(int irq, void *_dev) @@ -970,7 +1058,6 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev) switch (ts->buf[FW_HDR_TYPE]) { case CMD_HEADER_HELLO: case CMD_HEADER_RESP: - case CMD_HEADER_REK: break; case QUEUE_HEADER_WAIT: @@ -985,9 +1072,24 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev) break; case QUEUE_HEADER_SINGLE: - elants_i2c_event(ts, &ts->buf[HEADER_SIZE]); + elants_i2c_event(ts, &ts->buf[HEADER_SIZE], + ts->buf[FW_HDR_LENGTH]); break; + case QUEUE_HEADER_NORMAL2: /* CMD_HEADER_REK */ + /* + * Depending on firmware version, eKTF3624 touchscreens + * may utilize one of these opcodes for the touch events: + * 0x63 (NORMAL) and 0x66 (NORMAL2). The 0x63 is used by + * older firmware version and differs from 0x66 such that + * touch pressure value needs to be adjusted. The 0x66 + * opcode of newer firmware is equal to 0x63 of eKTH3500. + */ + if (ts->chip_id != EKTF3624) + break; + + fallthrough; + case QUEUE_HEADER_NORMAL: report_count = ts->buf[FW_HDR_COUNT]; if (report_count == 0 || report_count > 3) { @@ -998,7 +1100,12 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev) } report_len = ts->buf[FW_HDR_LENGTH] / report_count; - if (report_len != PACKET_SIZE) { + + if (report_len == PACKET_SIZE_OLD && + ts->chip_id == EKTF3624) { + dev_dbg_once(&client->dev, + "using old report format\n"); + } else if (report_len != PACKET_SIZE) { dev_err(&client->dev, "mismatching report length: %*ph\n", HEADER_SIZE, ts->buf); @@ -1007,8 +1114,8 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev) for (i = 0; i < report_count; i++) { u8 *buf = ts->buf + HEADER_SIZE + - i * PACKET_SIZE; - elants_i2c_event(ts, buf); + i * report_len; + elants_i2c_event(ts, buf, report_len); } break; @@ -1250,6 +1357,7 @@ static int elants_i2c_probe(struct i2c_client *client, init_completion(&ts->cmd_done); ts->client = client; + ts->chip_id = (enum elants_chip_id)id->driver_data; i2c_set_clientdata(client, ts); ts->vcc33 = devm_regulator_get(&client->dev, "vcc33"); @@ -1331,13 +1439,20 @@ static int elants_i2c_probe(struct i2c_client *client, input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0); input_set_abs_params(ts->input, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0); + + touchscreen_parse_properties(ts->input, true, &ts->prop); + + if (ts->chip_id == EKTF3624) { + /* calculate resolution from size */ + ts->x_res = DIV_ROUND_CLOSEST(ts->prop.max_x, ts->phy_x); + ts->y_res = DIV_ROUND_CLOSEST(ts->prop.max_y, ts->phy_y); + } + input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res); input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res); if (ts->major_res > 0) input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, ts->major_res); - touchscreen_parse_properties(ts->input, true, &ts->prop); - error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM, INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); if (error) { @@ -1466,14 +1581,16 @@ static SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops, elants_i2c_suspend, elants_i2c_resume); static const struct i2c_device_id elants_i2c_id[] = { - { DEVICE_NAME, 0 }, + { DEVICE_NAME, EKTH3500 }, + { "ekth3500", EKTH3500 }, + { "ektf3624", EKTF3624 }, { } }; MODULE_DEVICE_TABLE(i2c, elants_i2c_id); #ifdef CONFIG_ACPI static const struct acpi_device_id elants_acpi_id[] = { - { "ELAN0001", 0 }, + { "ELAN0001", EKTH3500 }, { } }; MODULE_DEVICE_TABLE(acpi, elants_acpi_id); @@ -1482,6 +1599,7 @@ MODULE_DEVICE_TABLE(acpi, elants_acpi_id); #ifdef CONFIG_OF static const struct of_device_id elants_of_match[] = { { .compatible = "elan,ekth3500" }, + { .compatible = "elan,ektf3624" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, elants_of_match); -- cgit v1.2.3-59-g8ed1b From 785a19d97cb072c748a310d558859853f8ba987b Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Sun, 24 Jan 2021 20:14:35 -0800 Subject: Input: iqs5xx - minor cosmetic improvements Copyrights are generally followed by the name of a person or a company (i.e. the copyright holder) but that was not done here. Fix this by squashing the 'copyright' and 'author' lines. Also, trim some leading whitespace ahead of the parameters for the fw_file_store() function and re-align them for readability. Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/1611002626-5889-2-git-send-email-jeff@labundy.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/iqs5xx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index 4fd21bc3ce0f..08e79d6ed9f5 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -2,8 +2,7 @@ /* * Azoteq IQS550/572/525 Trackpad/Touchscreen Controller * - * Copyright (C) 2018 - * Author: Jeff LaBundy + * Copyright (C) 2018 Jeff LaBundy * * These devices require firmware exported from a PC-based configuration tool * made available by the vendor. Firmware files may be pushed to the device's @@ -952,8 +951,9 @@ err_kfree: return error; } -static ssize_t fw_file_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t fw_file_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev); struct i2c_client *client = iqs5xx->client; -- cgit v1.2.3-59-g8ed1b From 2539da6677b6355e124b99d1dbe15eb1066f1d46 Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Sun, 24 Jan 2021 20:14:50 -0800 Subject: Input: iqs5xx - preserve bootloader errors After user space writes the fw_file attribute to push new firmware to the device, the driver calls iqs5xx_dev_init() to re-initialize the device with the updated firmware or recover the device in case the update failed. In the case of the latter, however, iqs5xx_fw_file_write() returns zero (success) so long as iqs5xx_dev_init() does not fail, and any error encountered during the update process is lost. Solve this by saving the error before calling iqs5xx_dev_init(). Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/1611002626-5889-3-git-send-email-jeff@labundy.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/iqs5xx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index 08e79d6ed9f5..ff0a0e96aa5c 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -883,7 +883,7 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client, static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file) { struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client); - int error; + int error, error_bl; u8 *pmap; if (iqs5xx->bl_status == IQS5XX_BL_STATUS_NONE) @@ -937,6 +937,7 @@ err_reset: usleep_range(10000, 10100); } + error_bl = error; error = iqs5xx_dev_init(client); if (!error && iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET) error = -EINVAL; @@ -948,6 +949,9 @@ err_reset: err_kfree: kfree(pmap); + if (error_bl) + return error_bl; + return error; } -- cgit v1.2.3-59-g8ed1b From 1302c71a30615226838f3583028d122f6792d720 Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Sun, 24 Jan 2021 20:17:08 -0800 Subject: Input: iqs5xx - accommodate bootloader latency The bootloader NAK's all I2C communication after the first 64-byte bulk write if the bus frequency is equal to 400 kHz. This prevents the platform from pushing updated firmware to the device. The vendor's USB bootloader programming dongle appears to insert a delay between the "open" command and the first 64-byte bulk write. Adding a similar delay to the driver seems to eliminate the issue. Furthermore, the dongle does not access the bootloader immediately after powering up the device. Follow suit by adding a delay before the "open" command to avoid wasted retries at 400 kHz. Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/1611002626-5889-4-git-send-email-jeff@labundy.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/iqs5xx.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index ff0a0e96aa5c..b2de8c67b541 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -336,11 +336,16 @@ static int iqs5xx_bl_open(struct i2c_client *client) */ for (i = 0; i < IQS5XX_BL_ATTEMPTS; i++) { iqs5xx_reset(client); + usleep_range(350, 400); for (j = 0; j < IQS5XX_NUM_RETRIES; j++) { error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_VER, 0); - if (!error || error == -EINVAL) - return error; + if (!error) + usleep_range(10000, 10100); + else if (error != -EINVAL) + continue; + + return error; } } -- cgit v1.2.3-59-g8ed1b From e10ba0d3c042161a26311d43bd37c3634d7bc5ca Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Sun, 24 Jan 2021 20:29:38 -0800 Subject: Input: iqs5xx - re-initialize device upon warm reset The device may be inadvertently reset during runtime in the event of ESD strike, etc. To protect against this case, acknowledge the SHOW_RESET interrupt and re-initialize the device. To facilitate this change, expand the range of registers that are read in the interrupt handler to include the system status fields. Also, update the unrelated (but nearby) SUSPEND register field to use the BIT() macro. The remaining register fields are cleaned up in another patch. Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/1611002626-5889-6-git-send-email-jeff@labundy.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/iqs5xx.c | 52 ++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 11 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index b2de8c67b541..cc84bcc3395b 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -11,6 +11,7 @@ * Link to PC-based configuration tool and data sheet: http://www.azoteq.com/ */ +#include #include #include #include @@ -40,8 +41,11 @@ #define IQS5XX_PROJ_NUM_B000 15 #define IQS5XX_MAJOR_VER_MIN 2 -#define IQS5XX_RESUME 0x00 -#define IQS5XX_SUSPEND 0x01 +#define IQS5XX_SHOW_RESET BIT(7) +#define IQS5XX_ACK_RESET BIT(7) + +#define IQS5XX_SUSPEND BIT(0) +#define IQS5XX_RESUME 0 #define IQS5XX_SW_INPUT_EVENT 0x10 #define IQS5XX_SETUP_COMPLETE 0x40 @@ -53,8 +57,8 @@ #define IQS5XX_SWITCH_XY_AXIS 0x04 #define IQS5XX_PROD_NUM 0x0000 -#define IQS5XX_ABS_X 0x0016 -#define IQS5XX_ABS_Y 0x0018 +#define IQS5XX_SYS_INFO0 0x000F +#define IQS5XX_SYS_INFO1 0x0010 #define IQS5XX_SYS_CTRL0 0x0431 #define IQS5XX_SYS_CTRL1 0x0432 #define IQS5XX_SYS_CFG0 0x058E @@ -125,6 +129,14 @@ struct iqs5xx_touch_data { u8 area; } __packed; +struct iqs5xx_status { + u8 sys_info[2]; + u8 num_active; + __be16 rel_x; + __be16 rel_y; + struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS]; +} __packed; + static int iqs5xx_read_burst(struct i2c_client *client, u16 reg, void *val, u16 len) { @@ -670,6 +682,10 @@ static int iqs5xx_dev_init(struct i2c_client *client) if (error) return error; + error = iqs5xx_write_byte(client, IQS5XX_SYS_CTRL0, IQS5XX_ACK_RESET); + if (error) + return error; + error = iqs5xx_read_byte(client, IQS5XX_SYS_CFG0, &val); if (error) return error; @@ -706,7 +722,7 @@ static int iqs5xx_dev_init(struct i2c_client *client) static irqreturn_t iqs5xx_irq(int irq, void *data) { struct iqs5xx_private *iqs5xx = data; - struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS]; + struct iqs5xx_status status; struct i2c_client *client = iqs5xx->client; struct input_dev *input = iqs5xx->input; int error, i; @@ -719,21 +735,35 @@ static irqreturn_t iqs5xx_irq(int irq, void *data) if (iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET) return IRQ_NONE; - error = iqs5xx_read_burst(client, IQS5XX_ABS_X, - touch_data, sizeof(touch_data)); + error = iqs5xx_read_burst(client, IQS5XX_SYS_INFO0, + &status, sizeof(status)); if (error) return IRQ_NONE; - for (i = 0; i < ARRAY_SIZE(touch_data); i++) { - u16 pressure = be16_to_cpu(touch_data[i].strength); + if (status.sys_info[0] & IQS5XX_SHOW_RESET) { + dev_err(&client->dev, "Unexpected device reset\n"); + + error = iqs5xx_dev_init(client); + if (error) { + dev_err(&client->dev, + "Failed to re-initialize device: %d\n", error); + return IRQ_NONE; + } + + return IRQ_HANDLED; + } + + for (i = 0; i < ARRAY_SIZE(status.touch_data); i++) { + struct iqs5xx_touch_data *touch_data = &status.touch_data[i]; + u16 pressure = be16_to_cpu(touch_data->strength); input_mt_slot(input, i); if (input_mt_report_slot_state(input, MT_TOOL_FINGER, pressure != 0)) { input_report_abs(input, ABS_MT_POSITION_X, - be16_to_cpu(touch_data[i].abs_x)); + be16_to_cpu(touch_data->abs_x)); input_report_abs(input, ABS_MT_POSITION_Y, - be16_to_cpu(touch_data[i].abs_y)); + be16_to_cpu(touch_data->abs_y)); input_report_abs(input, ABS_MT_PRESSURE, pressure); } } -- cgit v1.2.3-59-g8ed1b From 4a76d861d9182f2edfab96e7aa1f1e10f4f86bc0 Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Sun, 24 Jan 2021 20:33:37 -0800 Subject: Input: iqs5xx - simplify axis setup logic The present implementation manipulates axis swap and inversion fields in the device to more or less duplicate what touchscreen_report_pos() does. The resulting logic is convoluted and difficult to follow. Instead report the maximum X and Y coordinates in earnest as they are read from the device, then let touchscreen_parse_properties() fix the axes up as necessary. Finally, use touchscreen_report_pos() to report the transformed coordinates. Last but not least, the maximum X and Y coordinates are not functions of the number of rows/columns that comprise the touch surface. Either coordinate is simply limited to 1 below what is reported for absolute X or Y coordinates when no fingers are present (0xFFFF). Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/1611002626-5889-7-git-send-email-jeff@labundy.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/iqs5xx.c | 100 ++++++++----------------------------- 1 file changed, 21 insertions(+), 79 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index cc84bcc3395b..127687ac160e 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -30,9 +30,9 @@ #define IQS5XX_FW_FILE_LEN 64 #define IQS5XX_NUM_RETRIES 10 -#define IQS5XX_NUM_POINTS 256 #define IQS5XX_NUM_CONTACTS 5 #define IQS5XX_WR_BYTES_MAX 2 +#define IQS5XX_XY_RES_MAX 0xFFFE #define IQS5XX_PROD_NUM_IQS550 40 #define IQS5XX_PROD_NUM_IQS572 58 @@ -52,10 +52,6 @@ #define IQS5XX_EVENT_MODE 0x01 #define IQS5XX_TP_EVENT 0x04 -#define IQS5XX_FLIP_X 0x01 -#define IQS5XX_FLIP_Y 0x02 -#define IQS5XX_SWITCH_XY_AXIS 0x04 - #define IQS5XX_PROD_NUM 0x0000 #define IQS5XX_SYS_INFO0 0x000F #define IQS5XX_SYS_INFO1 0x0010 @@ -63,9 +59,6 @@ #define IQS5XX_SYS_CTRL1 0x0432 #define IQS5XX_SYS_CFG0 0x058E #define IQS5XX_SYS_CFG1 0x058F -#define IQS5XX_TOTAL_RX 0x063D -#define IQS5XX_TOTAL_TX 0x063E -#define IQS5XX_XY_CFG0 0x0669 #define IQS5XX_X_RES 0x066E #define IQS5XX_Y_RES 0x0670 #define IQS5XX_CHKSM 0x83C0 @@ -102,6 +95,7 @@ struct iqs5xx_private { struct i2c_client *client; struct input_dev *input; struct gpio_desc *reset_gpio; + struct touchscreen_properties prop; struct mutex lock; u8 bl_status; }; @@ -497,12 +491,10 @@ static void iqs5xx_close(struct input_dev *input) static int iqs5xx_axis_init(struct i2c_client *client) { struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client); - struct touchscreen_properties prop; + struct touchscreen_properties *prop = &iqs5xx->prop; struct input_dev *input; + u16 max_x, max_y; int error; - u16 max_x, max_x_hw; - u16 max_y, max_y_hw; - u8 val; if (!iqs5xx->input) { input = devm_input_allocate_device(&client->dev); @@ -522,89 +514,39 @@ static int iqs5xx_axis_init(struct i2c_client *client) iqs5xx->input = input; } - touchscreen_parse_properties(iqs5xx->input, true, &prop); - - error = iqs5xx_read_byte(client, IQS5XX_TOTAL_RX, &val); - if (error) - return error; - max_x_hw = (val - 1) * IQS5XX_NUM_POINTS; - - error = iqs5xx_read_byte(client, IQS5XX_TOTAL_TX, &val); + error = iqs5xx_read_word(client, IQS5XX_X_RES, &max_x); if (error) return error; - max_y_hw = (val - 1) * IQS5XX_NUM_POINTS; - error = iqs5xx_read_byte(client, IQS5XX_XY_CFG0, &val); + error = iqs5xx_read_word(client, IQS5XX_Y_RES, &max_y); if (error) return error; - if (val & IQS5XX_SWITCH_XY_AXIS) - swap(max_x_hw, max_y_hw); - - if (prop.swap_x_y) - val ^= IQS5XX_SWITCH_XY_AXIS; + input_abs_set_max(iqs5xx->input, ABS_MT_POSITION_X, max_x); + input_abs_set_max(iqs5xx->input, ABS_MT_POSITION_Y, max_y); - if (prop.invert_x) - val ^= prop.swap_x_y ? IQS5XX_FLIP_Y : IQS5XX_FLIP_X; + touchscreen_parse_properties(iqs5xx->input, true, prop); - if (prop.invert_y) - val ^= prop.swap_x_y ? IQS5XX_FLIP_X : IQS5XX_FLIP_Y; - - error = iqs5xx_write_byte(client, IQS5XX_XY_CFG0, val); - if (error) - return error; - - if (prop.max_x > max_x_hw) { + if (prop->max_x > IQS5XX_XY_RES_MAX) { dev_err(&client->dev, "Invalid maximum x-coordinate: %u > %u\n", - prop.max_x, max_x_hw); + prop->max_x, IQS5XX_XY_RES_MAX); return -EINVAL; - } else if (prop.max_x == 0) { - error = iqs5xx_read_word(client, IQS5XX_X_RES, &max_x); + } else if (prop->max_x != max_x) { + error = iqs5xx_write_word(client, IQS5XX_X_RES, prop->max_x); if (error) return error; - - input_abs_set_max(iqs5xx->input, - prop.swap_x_y ? ABS_MT_POSITION_Y : - ABS_MT_POSITION_X, - max_x); - } else { - max_x = (u16)prop.max_x; } - if (prop.max_y > max_y_hw) { + if (prop->max_y > IQS5XX_XY_RES_MAX) { dev_err(&client->dev, "Invalid maximum y-coordinate: %u > %u\n", - prop.max_y, max_y_hw); + prop->max_y, IQS5XX_XY_RES_MAX); return -EINVAL; - } else if (prop.max_y == 0) { - error = iqs5xx_read_word(client, IQS5XX_Y_RES, &max_y); + } else if (prop->max_y != max_y) { + error = iqs5xx_write_word(client, IQS5XX_Y_RES, prop->max_y); if (error) return error; - - input_abs_set_max(iqs5xx->input, - prop.swap_x_y ? ABS_MT_POSITION_X : - ABS_MT_POSITION_Y, - max_y); - } else { - max_y = (u16)prop.max_y; } - /* - * Write horizontal and vertical resolution to the device in case its - * original defaults were overridden or swapped as per the properties - * specified in the device tree. - */ - error = iqs5xx_write_word(client, - prop.swap_x_y ? IQS5XX_Y_RES : IQS5XX_X_RES, - max_x); - if (error) - return error; - - error = iqs5xx_write_word(client, - prop.swap_x_y ? IQS5XX_X_RES : IQS5XX_Y_RES, - max_y); - if (error) - return error; - error = input_mt_init_slots(iqs5xx->input, IQS5XX_NUM_CONTACTS, INPUT_MT_DIRECT); if (error) @@ -760,10 +702,10 @@ static irqreturn_t iqs5xx_irq(int irq, void *data) input_mt_slot(input, i); if (input_mt_report_slot_state(input, MT_TOOL_FINGER, pressure != 0)) { - input_report_abs(input, ABS_MT_POSITION_X, - be16_to_cpu(touch_data->abs_x)); - input_report_abs(input, ABS_MT_POSITION_Y, - be16_to_cpu(touch_data->abs_y)); + touchscreen_report_pos(iqs5xx->input, &iqs5xx->prop, + be16_to_cpu(touch_data->abs_x), + be16_to_cpu(touch_data->abs_y), + true); input_report_abs(input, ABS_MT_PRESSURE, pressure); } } -- cgit v1.2.3-59-g8ed1b From 050fac7f056b23764a69fb1fcf3b4e4e90eb61b0 Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Sun, 24 Jan 2021 20:40:51 -0800 Subject: Input: iqs5xx - eliminate unnecessary register read Instead of relying on firmware to enable important register fields and performing read-modify-write operations to additionally enable the fields the driver cares about, it's much simpler just to write all of the pertinent fields explicitly. This avoids an unnecessary register read operation at start-up and makes way for the iqs5xx_read_byte() helper to be dropped. Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/1611002626-5889-8-git-send-email-jeff@labundy.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/iqs5xx.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index 127687ac160e..35da66bfd87f 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -47,10 +47,13 @@ #define IQS5XX_SUSPEND BIT(0) #define IQS5XX_RESUME 0 -#define IQS5XX_SW_INPUT_EVENT 0x10 -#define IQS5XX_SETUP_COMPLETE 0x40 -#define IQS5XX_EVENT_MODE 0x01 -#define IQS5XX_TP_EVENT 0x04 +#define IQS5XX_SETUP_COMPLETE BIT(6) +#define IQS5XX_WDT BIT(5) +#define IQS5XX_ALP_REATI BIT(3) +#define IQS5XX_REATI BIT(2) + +#define IQS5XX_TP_EVENT BIT(2) +#define IQS5XX_EVENT_MODE BIT(0) #define IQS5XX_PROD_NUM 0x0000 #define IQS5XX_SYS_INFO0 0x000F @@ -187,11 +190,6 @@ static int iqs5xx_read_word(struct i2c_client *client, u16 reg, u16 *val) return 0; } -static int iqs5xx_read_byte(struct i2c_client *client, u16 reg, u8 *val) -{ - return iqs5xx_read_burst(client, reg, val, sizeof(*val)); -} - static int iqs5xx_write_burst(struct i2c_client *client, u16 reg, const void *val, u16 len) { @@ -561,7 +559,6 @@ static int iqs5xx_dev_init(struct i2c_client *client) struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client); struct iqs5xx_dev_id_info *dev_id_info; int error; - u8 val; u8 buf[sizeof(*dev_id_info) + 1]; error = iqs5xx_read_burst(client, IQS5XX_PROD_NUM, @@ -628,18 +625,14 @@ static int iqs5xx_dev_init(struct i2c_client *client) if (error) return error; - error = iqs5xx_read_byte(client, IQS5XX_SYS_CFG0, &val); - if (error) - return error; - - val |= IQS5XX_SETUP_COMPLETE; - val &= ~IQS5XX_SW_INPUT_EVENT; - error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG0, val); + error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG0, + IQS5XX_SETUP_COMPLETE | IQS5XX_WDT | + IQS5XX_ALP_REATI | IQS5XX_REATI); if (error) return error; - val = IQS5XX_TP_EVENT | IQS5XX_EVENT_MODE; - error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG1, val); + error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG1, + IQS5XX_TP_EVENT | IQS5XX_EVENT_MODE); if (error) return error; -- cgit v1.2.3-59-g8ed1b From 8e6a8b0c9fe98b905a2ae4f9f91296eb4f82b9ae Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Sun, 24 Jan 2021 20:41:38 -0800 Subject: Input: iqs5xx - allow more time for ATI to complete After the device is initialized, it runs ATI (calibration) during which it cannot readily respond to I2C communication. To keep the open and close callbacks from writing to the device too soon, the driver waits 100 ms before returning from probe. The vendor reports that ATI may actually take up to 250 ms to run (including margin), so increase the delay accordingly. Update the comments to clarify the reason for the delay as well. Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/1611002626-5889-9-git-send-email-jeff@labundy.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/iqs5xx.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index 35da66bfd87f..b5287301a293 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -643,13 +643,12 @@ static int iqs5xx_dev_init(struct i2c_client *client) iqs5xx->bl_status = dev_id_info->bl_status; /* - * Closure of the first communication window that appears following the - * release of reset appears to kick off an initialization period during - * which further communication is met with clock stretching. The return - * from this function is delayed so that further communication attempts - * avoid this period. + * The following delay allows ATI to complete before the open and close + * callbacks are free to elicit I2C communication. Any attempts to read + * from or write to the device during this time may face extended clock + * stretching and prompt the I2C controller to report an error. */ - msleep(100); + msleep(250); return 0; } -- cgit v1.2.3-59-g8ed1b From ce996aa30ef1d20bb8c84aa78087bb07b4745317 Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Sun, 24 Jan 2021 20:44:26 -0800 Subject: Input: iqs5xx - allow device to be a wake-up source Avoid placing the device in suspend mode (from which it cannot generate interrupts) if it is defined as a wake-up source. The device is still permitted to enter a low-power sensing mode on its own. Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/1611002626-5889-11-git-send-email-jeff@labundy.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/iqs5xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index b5287301a293..05e0c6ff217b 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -985,7 +985,7 @@ static int __maybe_unused iqs5xx_suspend(struct device *dev) struct input_dev *input = iqs5xx->input; int error = 0; - if (!input) + if (!input || device_may_wakeup(dev)) return error; mutex_lock(&input->mutex); @@ -1004,7 +1004,7 @@ static int __maybe_unused iqs5xx_resume(struct device *dev) struct input_dev *input = iqs5xx->input; int error = 0; - if (!input) + if (!input || device_may_wakeup(dev)) return error; mutex_lock(&input->mutex); -- cgit v1.2.3-59-g8ed1b From 7a6a53b2b1a3e68b69cd75a74783f4d8fd5b6fb5 Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Mon, 25 Jan 2021 10:13:14 -0800 Subject: Input: iqs5xx - initialize an uninitialized variable If execution jumps to the err_kfree label, error_bl is evaluated before it is initialized. Fix this by initializing it to zero. Fixes: 2539da6677b6 ("Input: iqs5xx - preserve bootloader errors") Reported-by: kernel test robot Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/1611592500-32209-1-git-send-email-jeff@labundy.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/iqs5xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index 05e0c6ff217b..54f30038dca4 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -852,7 +852,7 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client, static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file) { struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client); - int error, error_bl; + int error, error_bl = 0; u8 *pmap; if (iqs5xx->bl_status == IQS5XX_BL_STATUS_NONE) -- cgit v1.2.3-59-g8ed1b From a374c19f7f15e3b2c85b3d8753c63e16dbb22d2e Mon Sep 17 00:00:00 2001 From: Yang Li Date: Fri, 5 Feb 2021 11:50:52 -0800 Subject: Input: zinitix - remove unneeded semicolon Eliminate the following coccicheck warning: ./drivers/input/touchscreen/zinitix.c:164:31-32: Unneeded semicolon Reported-by: Abaci Robot Signed-off-by: Yang Li Link: https://lore.kernel.org/r/1612319443-115831-1-git-send-email-yang.lee@linux.alibaba.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/zinitix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c index a3e3adbabc67..f64d88170fac 100644 --- a/drivers/input/touchscreen/zinitix.c +++ b/drivers/input/touchscreen/zinitix.c @@ -161,7 +161,7 @@ static int zinitix_read_data(struct i2c_client *client, ret = i2c_master_recv(client, (u8 *)values, length); if (ret != length) - return ret < 0 ? ret : -EIO; ; + return ret < 0 ? ret : -EIO; return 0; } -- cgit v1.2.3-59-g8ed1b From ede6747c2f8975892ab98bed94357dc8c35d790c Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 11 Feb 2021 12:50:37 -0800 Subject: Input: elants_i2c - detect enum overflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If an enum value were to get added without updating this switch statement, the unreachable() annotation would trigger undefined behavior, causing execution to fall through the end of the function, into the next one. Make the error handling more robust for an unexpected enum value, by doing BUG() instead of unreachable(). Fixes the following objtool warning: drivers/input/touchscreen/elants_i2c.o: warning: objtool: elants_i2c_initialize() falls through to next function elants_i2c_resume() Reported-by: Randy Dunlap Acked-by: Randy Dunlap Signed-off-by: Josh Poimboeuf Reviewed-by: Michał Mirosław Link: https://lore.kernel.org/r/59e2e82d1e40df11ab38874c03556a31c6b2f484.1612974132.git.jpoimboe@redhat.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/elants_i2c.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 6f57ec579f00..4c2b579f6c8b 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -656,8 +656,7 @@ static int elants_i2c_initialize(struct elants_data *ts) error = elants_i2c_query_ts_info_ektf(ts); break; default: - unreachable(); - break; + BUG(); } if (error) -- cgit v1.2.3-59-g8ed1b From b0b7d2815839024e5181bd2572f5d8d4f65363b3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 16 Feb 2021 20:30:45 -0800 Subject: Input: sur40 - fix an error code in sur40_probe() If v4l2_ctrl_handler_setup() fails then probe() should return an error code instead of returning success. Fixes: cee1e3e2ef39 ("media: add video control handlers using V4L2 control framework") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YBKFkbATXa5fA3xj@mwanda Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/sur40.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index 620cdd7d214a..12f2562b0141 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -787,6 +787,7 @@ static int sur40_probe(struct usb_interface *interface, dev_err(&interface->dev, "Unable to register video controls."); v4l2_ctrl_handler_free(&sur40->hdl); + error = sur40->hdl.error; goto err_unreg_v4l2; } -- cgit v1.2.3-59-g8ed1b From 0958351e93fa0ac142f6dd8bd844441594f30a57 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 16 Feb 2021 20:29:05 -0800 Subject: Input: elo - fix an error code in elo_connect() If elo_setup_10() fails then this should return an error code instead of success. Fixes: fae3006e4b42 ("Input: elo - add support for non-pressure-sensitive touchscreens") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YBKFd5CvDu+jVmfW@mwanda Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/elo.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index e0bacd34866a..96173232e53f 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c @@ -341,8 +341,10 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) switch (elo->id) { case 0: /* 10-byte protocol */ - if (elo_setup_10(elo)) + if (elo_setup_10(elo)) { + err = -EIO; goto fail3; + } break; -- cgit v1.2.3-59-g8ed1b From b2e3543b5e193c2be802ae2db0a8ae82ec8c0f66 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 19 Feb 2021 10:39:16 -0800 Subject: Input: add missing dependencies on CONFIG_HAS_IOMEM devm_ioremap_resource() is only guaranteed to be present if CONFIG_HAS_IOMEM is set. Reported-by: kernel test robot Link: https://lore.kernel.org/r/YCyauGyqxut69JNz@google.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/Kconfig | 4 ++-- drivers/input/serio/Kconfig | 2 +- drivers/input/touchscreen/Kconfig | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 94eab82086b2..32d15809ae58 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -685,7 +685,7 @@ config KEYBOARD_OMAP config KEYBOARD_OMAP4 tristate "TI OMAP4+ keypad support" - depends on OF || ARCH_OMAP2PLUS + depends on (OF && HAS_IOMEM) || ARCH_OMAP2PLUS select INPUT_MATRIXKMAP help Say Y here if you want to use the OMAP4+ keypad. @@ -773,7 +773,7 @@ config KEYBOARD_CAP11XX config KEYBOARD_BCM tristate "Broadcom keypad driver" - depends on OF && HAVE_CLK + depends on OF && HAVE_CLK && HAS_IOMEM select INPUT_MATRIXKMAP default ARCH_BCM_CYGNUS help diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 0754744b9ce5..f39b7b3f7942 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -255,7 +255,7 @@ config SERIO_ARC_PS2 config SERIO_APBPS2 tristate "GRLIB APBPS2 PS/2 keyboard/mouse controller" - depends on OF + depends on OF && HAS_IOMEM help Say Y here if you want support for GRLIB APBPS2 peripherals used to connect to PS/2 keyboard and/or mouse. diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index f012fe746df0..d1b6ef9fd8d4 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -607,7 +607,7 @@ config TOUCHSCREEN_MTOUCH config TOUCHSCREEN_IMX6UL_TSC tristate "Freescale i.MX6UL touchscreen controller" - depends on (OF && GPIOLIB) || COMPILE_TEST + depends on ((OF && GPIOLIB) || COMPILE_TEST) && HAS_IOMEM help Say Y here if you have a Freescale i.MX6UL, and want to use the internal touchscreen controller. -- cgit v1.2.3-59-g8ed1b From 836f308cb5c72d48e2dff8d3e64c3adb94f4710d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 19 Feb 2021 10:36:48 -0800 Subject: Input: zinitix - fix return type of zinitix_init_touch() zinitix_init_touch() returns error code or 0 for success and therefore return type must be int, not bool. Fixes: 26822652c85e ("Input: add zinitix touchscreen driver") Reported-by: kernel test robot Reported-by: Jiapeng Chong Link: https://lore.kernel.org/r/YC8z2bXc3Oy8pABa@google.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/zinitix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c index f64d88170fac..3b636beb583c 100644 --- a/drivers/input/touchscreen/zinitix.c +++ b/drivers/input/touchscreen/zinitix.c @@ -190,7 +190,7 @@ static int zinitix_write_cmd(struct i2c_client *client, u16 reg) return 0; } -static bool zinitix_init_touch(struct bt541_ts_data *bt541) +static int zinitix_init_touch(struct bt541_ts_data *bt541) { struct i2c_client *client = bt541->client; int i; -- cgit v1.2.3-59-g8ed1b