From e85bb0beb6498c0dffe18a2f1f16d575bc175c32 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Mon, 7 Jan 2019 11:53:59 -0800 Subject: Input: ad7879 - add check for read errors in interrupt regmap_bulk_read() can return a non zero value on failure. The fix checks if the function call succeeded before calling mod_timer. The issue was identified by a static analysis tool. Signed-off-by: Aditya Pakki Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 6fa714c587b4..3a016f43fb85 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -246,11 +246,14 @@ static void ad7879_timer(struct timer_list *t) static irqreturn_t ad7879_irq(int irq, void *handle) { struct ad7879 *ts = handle; + int error; - regmap_bulk_read(ts->regmap, AD7879_REG_XPLUS, - ts->conversion_data, AD7879_NR_SENSE); - - if (!ad7879_report(ts)) + error = regmap_bulk_read(ts->regmap, AD7879_REG_XPLUS, + ts->conversion_data, AD7879_NR_SENSE); + if (error) + dev_err_ratelimited(ts->dev, "failed to read %#02x: %d\n", + AD7879_REG_XPLUS, error); + else if (!ad7879_report(ts)) mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT); return IRQ_HANDLED; -- cgit v1.2.3-55-g7522 From a2f39dac0decd9943ba14e14fb58535bb149fd4e Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Sun, 13 Jan 2019 23:08:32 -0800 Subject: Input: edt-ft5x06 - add support for Evervision FT5726 Evervision displays are using different Focaltech touchscreen controllers. This commit adds the initial support for the ones using the FT5726 controller. Receiving the touch data is the same as for the GENERIC_FT but the x and y cooridnates are swapped. The main differences are the register addresses where the GAIN and THRESHOLD parameters are stored. Signed-off-by: Marco Felsch Reviewed-by: Rob Herring Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/edt-ft5x06.txt | 4 +- drivers/input/touchscreen/edt-ft5x06.c | 44 ++++++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt index da2dc5d6c98b..179e434f5619 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt @@ -1,11 +1,12 @@ FocalTech EDT-FT5x06 Polytouch driver ===================================== -There are 3 variants of the chip for various touch panel sizes +There are 5 variants of the chip for various touch panel sizes FT5206GE1 2.8" .. 3.8" FT5306DE4 4.3" .. 7" FT5406EE8 7" .. 8.9" FT5506EEG 7" .. 8.9" +FT5726NEI 5.7” .. 11.6" The software interface is identical for all those chips, so that currently there is no need for the driver to distinguish between the @@ -19,6 +20,7 @@ Required properties: or: "edt,edt-ft5306" or: "edt,edt-ft5406" or: "edt,edt-ft5506" + or: "evervision,ev-ft5726" or: "focaltech,ft6236" - reg: I2C slave address of the chip (0x38) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 1e18ca0d1b4e..1cd5b804a456 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,9 @@ #define M09_REGISTER_NUM_X 0x94 #define M09_REGISTER_NUM_Y 0x95 +#define EV_REGISTER_THRESHOLD 0x40 +#define EV_REGISTER_GAIN 0x41 + #define NO_REGISTER 0xff #define WORK_REGISTER_OPMODE 0x3c @@ -73,6 +77,7 @@ enum edt_ver { EDT_M06, EDT_M09, EDT_M12, + EV_FT, GENERIC_FT, }; @@ -190,6 +195,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) case EDT_M09: case EDT_M12: + case EV_FT: case GENERIC_FT: cmd = 0x0; offset = 3; @@ -242,6 +248,10 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) x = ((buf[0] << 8) | buf[1]) & 0x0fff; y = ((buf[2] << 8) | buf[3]) & 0x0fff; + /* The FT5x26 send the y coordinate first */ + if (tsdata->version == EV_FT) + swap(x, y); + id = (buf[2] >> 4) & 0x0f; down = type != TOUCH_EVENT_UP; @@ -275,8 +285,10 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL); + /* fallthrough */ case EDT_M09: case EDT_M12: + case EV_FT: case GENERIC_FT: wrbuf[0] = addr; wrbuf[1] = value; @@ -315,8 +327,10 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, } break; + /* fallthrough */ case EDT_M09: case EDT_M12: + case EV_FT: case GENERIC_FT: wrbuf[0] = addr; error = edt_ft5x06_ts_readwrite(tsdata->client, 1, @@ -605,8 +619,9 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) tsdata->threshold); edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, tsdata->gain); - edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, - tsdata->offset); + if (reg_addr->reg_offset != NO_REGISTER) + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, + tsdata->offset); if (reg_addr->reg_report_rate != NO_REGISTER) edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate, tsdata->report_rate); @@ -867,6 +882,16 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, case 0x5a: /* Solomon Goldentek Display */ snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0"); break; + case 0x59: /* Evervision Display with FT5xx6 TS */ + tsdata->version = EV_FT; + error = edt_ft5x06_ts_readwrite(client, 1, "\x53", + 1, rdbuf); + if (error) + return error; + strlcpy(fw_version, rdbuf, 1); + snprintf(model_name, EDT_NAME_LEN, + "EVERVISION-FT5726NEi"); + break; default: snprintf(model_name, EDT_NAME_LEN, "generic ft5x06 (%02x)", @@ -912,7 +937,9 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) tsdata->threshold = edt_ft5x06_register_read(tsdata, reg_addr->reg_threshold); tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain); - tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); + if (reg_addr->reg_offset != NO_REGISTER) + tsdata->offset = + edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); if (reg_addr->reg_report_rate != NO_REGISTER) tsdata->report_rate = edt_ft5x06_register_read(tsdata, reg_addr->reg_report_rate); @@ -954,6 +981,15 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_num_y = M09_REGISTER_NUM_Y; break; + case EV_FT: + reg_addr->reg_threshold = EV_REGISTER_THRESHOLD; + reg_addr->reg_gain = EV_REGISTER_GAIN; + reg_addr->reg_offset = NO_REGISTER; + reg_addr->reg_num_x = NO_REGISTER; + reg_addr->reg_num_y = NO_REGISTER; + reg_addr->reg_report_rate = NO_REGISTER; + break; + case GENERIC_FT: /* this is a guesswork */ reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; @@ -1155,6 +1191,7 @@ static const struct edt_i2c_chip_data edt_ft6236_data = { 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 }, /* Note no edt- prefix for compatibility with the ft6236.c driver */ { .name = "ft6236", .driver_data = (long)&edt_ft6236_data }, { /* sentinel */ } @@ -1167,6 +1204,7 @@ static const struct of_device_id edt_ft5x06_of_match[] = { { .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data }, { .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data }, { .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data }, + { .compatible = "evervision,ev-ft5726", .data = &edt_ft5506_data }, /* Note focaltech vendor prefix for compatibility with ft6236.c */ { .compatible = "focaltech,ft6236", .data = &edt_ft6236_data }, { /* sentinel */ } -- cgit v1.2.3-55-g7522 From 2ebc1919e9a9812903ab684cc53862015987e7a0 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Sun, 13 Jan 2019 23:10:22 -0800 Subject: Input: edt-ft5x06 - add support to update ev-ft5726 registers Currently only the threshold and gain parameters can be read. Signed-off-by: Marco Felsch Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 1cd5b804a456..a67915535b47 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -353,9 +353,10 @@ struct edt_ft5x06_attribute { u8 limit_high; u8 addr_m06; u8 addr_m09; + u8 addr_ev; }; -#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, \ +#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, _addr_ev, \ _limit_low, _limit_high) \ struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \ .dattr = __ATTR(_field, _mode, \ @@ -364,6 +365,7 @@ struct edt_ft5x06_attribute { .field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \ .addr_m06 = _addr_m06, \ .addr_m09 = _addr_m09, \ + .addr_ev = _addr_ev, \ .limit_low = _limit_low, \ .limit_high = _limit_high, \ } @@ -400,6 +402,10 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, addr = attr->addr_m09; break; + case EV_FT: + addr = attr->addr_ev; + break; + default: error = -ENODEV; goto out; @@ -471,6 +477,10 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, addr = attr->addr_m09; break; + case EV_FT: + addr = attr->addr_ev; + break; + default: error = -ENODEV; goto out; @@ -494,16 +504,16 @@ out: /* m06, m09: range 0-31, m12: range 0-5 */ static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, - M09_REGISTER_GAIN, 0, 31); + M09_REGISTER_GAIN, EV_REGISTER_GAIN, 0, 31); /* m06, m09: range 0-31, m12: range 0-16 */ static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, - M09_REGISTER_OFFSET, 0, 31); + M09_REGISTER_OFFSET, NO_REGISTER, 0, 31); /* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */ static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, - M09_REGISTER_THRESHOLD, 0, 255); + M09_REGISTER_THRESHOLD, EV_REGISTER_THRESHOLD, 0, 255); /* m06: range 3 to 14, m12: (0x64: 100Hz) */ static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, - NO_REGISTER, 0, 255); + NO_REGISTER, NO_REGISTER, 0, 255); static struct attribute *edt_ft5x06_attrs[] = { &edt_ft5x06_attr_gain.dattr.attr, -- cgit v1.2.3-55-g7522 From b6eba86030bf2fa3abcf9a0e3fb04527330da52e Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Sun, 13 Jan 2019 23:10:50 -0800 Subject: Input: edt-ft5x06 - add offset support for ev-ft5726 Unfortunately the evervision focaltech implementation uses two offset registers, one for the x coordinate and one for y. This patch extends the driver to handle those offset registers only for devices that support these. Signed-off-by: Marco Felsch Reviewed-by: Rob Herring Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/edt-ft5x06.txt | 9 +++++ drivers/input/touchscreen/edt-ft5x06.c | 46 ++++++++++++++++++++++ 2 files changed, 55 insertions(+) (limited to 'drivers/input/touchscreen') diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt index 179e434f5619..870b8c5cce9b 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt @@ -44,6 +44,15 @@ Optional properties: - offset: allows setting the edge compensation in the range from 0 to 31. + + - offset-x: Same as offset, but applies only to the horizontal position. + Range from 0 to 80, only supported by evervision,ev-ft5726 + devices. + + - offset-y: Same as offset, but applies only to the vertical position. + Range from 0 to 80, only supported by evervision,ev-ft5726 + devices. + - touchscreen-size-x : See touchscreen.txt - touchscreen-size-y : See touchscreen.txt - touchscreen-fuzz-x : See touchscreen.txt diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index a67915535b47..702bfda7ee77 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -56,6 +56,8 @@ #define EV_REGISTER_THRESHOLD 0x40 #define EV_REGISTER_GAIN 0x41 +#define EV_REGISTER_OFFSET_Y 0x45 +#define EV_REGISTER_OFFSET_X 0x46 #define NO_REGISTER 0xff @@ -86,6 +88,8 @@ struct edt_reg_addr { int reg_report_rate; int reg_gain; int reg_offset; + int reg_offset_x; + int reg_offset_y; int reg_num_x; int reg_num_y; }; @@ -111,6 +115,8 @@ struct edt_ft5x06_ts_data { int threshold; int gain; int offset; + int offset_x; + int offset_y; int report_rate; int max_support_points; @@ -508,6 +514,12 @@ static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, /* m06, m09: range 0-31, m12: range 0-16 */ static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, M09_REGISTER_OFFSET, NO_REGISTER, 0, 31); +/* m06, m09, m12: no supported, ev_ft: range 0-80 */ +static EDT_ATTR(offset_x, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER, + EV_REGISTER_OFFSET_X, 0, 80); +/* m06, m09, m12: no supported, ev_ft: range 0-80 */ +static EDT_ATTR(offset_y, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER, + EV_REGISTER_OFFSET_Y, 0, 80); /* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */ static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, M09_REGISTER_THRESHOLD, EV_REGISTER_THRESHOLD, 0, 255); @@ -518,6 +530,8 @@ static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, static struct attribute *edt_ft5x06_attrs[] = { &edt_ft5x06_attr_gain.dattr.attr, &edt_ft5x06_attr_offset.dattr.attr, + &edt_ft5x06_attr_offset_x.dattr.attr, + &edt_ft5x06_attr_offset_y.dattr.attr, &edt_ft5x06_attr_threshold.dattr.attr, &edt_ft5x06_attr_report_rate.dattr.attr, NULL @@ -632,6 +646,12 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) if (reg_addr->reg_offset != NO_REGISTER) edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, tsdata->offset); + if (reg_addr->reg_offset_x != NO_REGISTER) + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x, + tsdata->offset_x); + if (reg_addr->reg_offset_y != NO_REGISTER) + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y, + tsdata->offset_y); if (reg_addr->reg_report_rate != NO_REGISTER) edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate, tsdata->report_rate); @@ -937,6 +957,18 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev, edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, val); tsdata->offset = val; } + + error = device_property_read_u32(dev, "offset-x", &val); + if (!error) { + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x, val); + tsdata->offset_x = val; + } + + error = device_property_read_u32(dev, "offset-y", &val); + if (!error) { + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y, val); + tsdata->offset_y = val; + } } static void @@ -950,6 +982,12 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) if (reg_addr->reg_offset != NO_REGISTER) tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); + if (reg_addr->reg_offset_x != NO_REGISTER) + tsdata->offset_x = edt_ft5x06_register_read(tsdata, + reg_addr->reg_offset_x); + if (reg_addr->reg_offset_y != NO_REGISTER) + tsdata->offset_y = edt_ft5x06_register_read(tsdata, + reg_addr->reg_offset_y); if (reg_addr->reg_report_rate != NO_REGISTER) tsdata->report_rate = edt_ft5x06_register_read(tsdata, reg_addr->reg_report_rate); @@ -977,6 +1015,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; reg_addr->reg_gain = WORK_REGISTER_GAIN; reg_addr->reg_offset = WORK_REGISTER_OFFSET; + reg_addr->reg_offset_x = NO_REGISTER; + reg_addr->reg_offset_y = NO_REGISTER; reg_addr->reg_num_x = WORK_REGISTER_NUM_X; reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; break; @@ -987,6 +1027,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_report_rate = NO_REGISTER; reg_addr->reg_gain = M09_REGISTER_GAIN; reg_addr->reg_offset = M09_REGISTER_OFFSET; + reg_addr->reg_offset_x = NO_REGISTER; + reg_addr->reg_offset_y = NO_REGISTER; reg_addr->reg_num_x = M09_REGISTER_NUM_X; reg_addr->reg_num_y = M09_REGISTER_NUM_Y; break; @@ -995,6 +1037,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_threshold = EV_REGISTER_THRESHOLD; reg_addr->reg_gain = EV_REGISTER_GAIN; reg_addr->reg_offset = NO_REGISTER; + reg_addr->reg_offset_x = EV_REGISTER_OFFSET_X; + reg_addr->reg_offset_y = EV_REGISTER_OFFSET_Y; reg_addr->reg_num_x = NO_REGISTER; reg_addr->reg_num_y = NO_REGISTER; reg_addr->reg_report_rate = NO_REGISTER; @@ -1005,6 +1049,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; reg_addr->reg_gain = M09_REGISTER_GAIN; reg_addr->reg_offset = M09_REGISTER_OFFSET; + reg_addr->reg_offset_x = NO_REGISTER; + reg_addr->reg_offset_y = NO_REGISTER; break; } } -- cgit v1.2.3-55-g7522 From 351e0592bfeae58c76a11bdcec59eb78b2937593 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 28 Jan 2019 10:38:10 -0800 Subject: Input: st1232 - add support for st1633 Add support for the Sitronix ST1633 touchscreen controller to the st1232 driver. A protocol spec can be found here: www.ampdisplay.com/documents/pdf/AM-320480B6TZQW-TC0H.pdf Signed-off-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/sitronix-st1232.txt | 6 +- drivers/input/touchscreen/Kconfig | 6 +- drivers/input/touchscreen/st1232.c | 120 +++++++++++++++------ 3 files changed, 93 insertions(+), 39 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt b/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt index 64ad48b824a2..e73e826e0f2a 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt @@ -1,7 +1,9 @@ -* Sitronix st1232 touchscreen controller +* Sitronix st1232 or st1633 touchscreen controller Required properties: -- compatible: must be "sitronix,st1232" +- compatible: must contain one of + * "sitronix,st1232" + * "sitronix,st1633" - reg: I2C address of the chip - interrupts: interrupt to which the chip is connected diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index af6027cc7bbf..6c16aaeb4191 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1168,11 +1168,11 @@ config TOUCHSCREEN_SIS_I2C module will be called sis_i2c. config TOUCHSCREEN_ST1232 - tristate "Sitronix ST1232 touchscreen controllers" + tristate "Sitronix ST1232 or ST1633 touchscreen controllers" depends on I2C help - Say Y here if you want to support Sitronix ST1232 - touchscreen controller. + Say Y here if you want to support the Sitronix ST1232 + or ST1633 touchscreen controller. If unsure, say N. diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 11ff32c68025..777df903605d 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -23,13 +23,7 @@ #include #define ST1232_TS_NAME "st1232-ts" - -#define MIN_X 0x00 -#define MIN_Y 0x00 -#define MAX_X 0x31f /* (800 - 1) */ -#define MAX_Y 0x1df /* (480 - 1) */ -#define MAX_AREA 0xff -#define MAX_FINGERS 2 +#define ST1633_TS_NAME "st1633-ts" struct st1232_ts_finger { u16 x; @@ -38,12 +32,24 @@ struct st1232_ts_finger { bool is_valid; }; +struct st_chip_info { + bool have_z; + u16 max_x; + u16 max_y; + u16 max_area; + u16 max_fingers; + u8 start_reg; +}; + struct st1232_ts_data { struct i2c_client *client; struct input_dev *input_dev; - struct st1232_ts_finger finger[MAX_FINGERS]; struct dev_pm_qos_request low_latency_req; int reset_gpio; + const struct st_chip_info *chip_info; + int read_buf_len; + u8 *read_buf; + struct st1232_ts_finger *finger; }; static int st1232_ts_read_data(struct st1232_ts_data *ts) @@ -52,40 +58,35 @@ static int st1232_ts_read_data(struct st1232_ts_data *ts) struct i2c_client *client = ts->client; struct i2c_msg msg[2]; int error; - u8 start_reg; - u8 buf[10]; + int i, y; + u8 start_reg = ts->chip_info->start_reg; + u8 *buf = ts->read_buf; - /* read touchscreen data from ST1232 */ + /* read touchscreen data */ msg[0].addr = client->addr; msg[0].flags = 0; msg[0].len = 1; msg[0].buf = &start_reg; - start_reg = 0x10; msg[1].addr = ts->client->addr; msg[1].flags = I2C_M_RD; - msg[1].len = sizeof(buf); + msg[1].len = ts->read_buf_len; msg[1].buf = buf; error = i2c_transfer(client->adapter, msg, 2); if (error < 0) return error; - /* get "valid" bits */ - finger[0].is_valid = buf[2] >> 7; - finger[1].is_valid = buf[5] >> 7; - - /* get xy coordinate */ - if (finger[0].is_valid) { - finger[0].x = ((buf[2] & 0x0070) << 4) | buf[3]; - finger[0].y = ((buf[2] & 0x0007) << 8) | buf[4]; - finger[0].t = buf[8]; - } + for (i = 0, y = 0; i < ts->chip_info->max_fingers; i++, y += 3) { + finger[i].is_valid = buf[i + y] >> 7; + if (finger[i].is_valid) { + finger[i].x = ((buf[i + y] & 0x0070) << 4) | buf[i + 1]; + finger[i].y = ((buf[i + y] & 0x0007) << 8) | buf[i + 2]; - if (finger[1].is_valid) { - finger[1].x = ((buf[5] & 0x0070) << 4) | buf[6]; - finger[1].y = ((buf[5] & 0x0007) << 8) | buf[7]; - finger[1].t = buf[9]; + /* st1232 includes a z-axis / touch strength */ + if (ts->chip_info->have_z) + finger[i].t = buf[i + 6]; + } } return 0; @@ -104,11 +105,14 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id) goto end; /* multi touch protocol */ - for (i = 0; i < MAX_FINGERS; i++) { + for (i = 0; i < ts->chip_info->max_fingers; i++) { if (!finger[i].is_valid) continue; - input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t); + if (ts->chip_info->have_z) + input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, + finger[i].t); + input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x); input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y); input_mt_sync(input_dev); @@ -142,13 +146,41 @@ static void st1232_ts_power(struct st1232_ts_data *ts, bool poweron) gpio_direction_output(ts->reset_gpio, poweron); } +static const struct st_chip_info st1232_chip_info = { + .have_z = true, + .max_x = 0x31f, /* 800 - 1 */ + .max_y = 0x1df, /* 480 -1 */ + .max_area = 0xff, + .max_fingers = 2, + .start_reg = 0x12, +}; + +static const struct st_chip_info st1633_chip_info = { + .have_z = false, + .max_x = 0x13f, /* 320 - 1 */ + .max_y = 0x1df, /* 480 -1 */ + .max_area = 0x00, + .max_fingers = 5, + .start_reg = 0x12, +}; + static int st1232_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { + const struct st_chip_info *match; struct st1232_ts_data *ts; + struct st1232_ts_finger *finger; struct input_dev *input_dev; int error; + match = device_get_match_data(&client->dev); + if (!match && id) + match = (const void *)id->driver_data; + if (!match) { + dev_err(&client->dev, "unknown device model\n"); + return -ENODEV; + } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "need I2C_FUNC_I2C\n"); return -EIO; @@ -163,6 +195,19 @@ static int st1232_ts_probe(struct i2c_client *client, if (!ts) return -ENOMEM; + ts->chip_info = match; + ts->finger = devm_kcalloc(&client->dev, + ts->chip_info->max_fingers, sizeof(*finger), + GFP_KERNEL); + if (!ts->finger) + return -ENOMEM; + + /* allocate a buffer according to the number of registers to read */ + ts->read_buf_len = ts->chip_info->max_fingers * 4; + ts->read_buf = devm_kzalloc(&client->dev, ts->read_buf_len, GFP_KERNEL); + if (!ts->read_buf) + return -ENOMEM; + input_dev = devm_input_allocate_device(&client->dev); if (!input_dev) return -ENOMEM; @@ -192,9 +237,14 @@ static int st1232_ts_probe(struct i2c_client *client, __set_bit(EV_KEY, input_dev->evbit); __set_bit(EV_ABS, input_dev->evbit); - input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_AREA, 0, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_X, MIN_X, MAX_X, 0, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_Y, MIN_Y, MAX_Y, 0, 0); + if (ts->chip_info->have_z) + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, + ts->chip_info->max_area, 0, 0); + + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, ts->chip_info->max_x, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, ts->chip_info->max_y, 0, 0); error = devm_request_threaded_irq(&client->dev, client->irq, NULL, st1232_ts_irq_handler, @@ -261,13 +311,15 @@ static SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops, st1232_ts_suspend, st1232_ts_resume); static const struct i2c_device_id st1232_ts_id[] = { - { ST1232_TS_NAME, 0 }, + { ST1232_TS_NAME, (unsigned long)&st1232_chip_info }, + { ST1633_TS_NAME, (unsigned long)&st1633_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, st1232_ts_id); static const struct of_device_id st1232_ts_dt_ids[] = { - { .compatible = "sitronix,st1232", }, + { .compatible = "sitronix,st1232", .data = &st1232_chip_info }, + { .compatible = "sitronix,st1633", .data = &st1633_chip_info }, { } }; MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids); -- cgit v1.2.3-55-g7522 From 4dbb71195b34232d9ecc12c4cfbee6871688a0e3 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 28 Jan 2019 11:04:08 -0800 Subject: Input: st1232 - add Martin as module author This adds myself as an author of the st1232 driver module as Tony's email address doesn't seem to work anymore. Signed-off-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/st1232.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 777df903605d..634d6c243845 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -338,5 +338,6 @@ static struct i2c_driver st1232_ts_driver = { module_i2c_driver(st1232_ts_driver); MODULE_AUTHOR("Tony SIM "); +MODULE_AUTHOR("Martin Kepplinger "); MODULE_DESCRIPTION("SITRONIX ST1232 Touchscreen Controller Driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-55-g7522 From c3a39380a39df3750149a2f4699c1c241a0e6ea2 Mon Sep 17 00:00:00 2001 From: Richard Leitner Date: Mon, 28 Jan 2019 14:49:37 -0800 Subject: Input: sx8654 - add reset-gpio support The sx8654 features a NRST input which may be connected to a GPIO. Therefore add support for hard-resetting the sx8654 via this NRST. If the reset-gpio property is provided the sx8654 is resetted via NRST instead of the soft-reset via I2C. Signed-off-by: Richard Leitner Reviewed-by: Rob Herring Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/sx8654.txt | 4 ++ drivers/input/touchscreen/sx8654.c | 44 +++++++++++++++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt index 4886c4aa2906..ca521d8f7d65 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt @@ -5,6 +5,9 @@ Required properties: - reg: i2c slave address - interrupts: touch controller interrupt +Optional properties: + - reset-gpios: GPIO specification for the NRST input + Example: sx8654@48 { @@ -12,4 +15,5 @@ Example: reg = <0x48>; interrupt-parent = <&gpio6>; interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>; }; diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c index ed29db3ec731..ab5cbf7e0879 100644 --- a/drivers/input/touchscreen/sx8654.c +++ b/drivers/input/touchscreen/sx8654.c @@ -27,12 +27,14 @@ * published by the Free Software Foundation. */ -#include -#include -#include +#include +#include #include +#include #include #include +#include +#include /* register addresses */ #define I2C_REG_TOUCH0 0x00 @@ -74,6 +76,7 @@ struct sx8654 { struct input_dev *input; struct i2c_client *client; + struct gpio_desc *gpio_reset; }; static irqreturn_t sx8654_irq(int irq, void *handle) @@ -124,6 +127,25 @@ out: return IRQ_HANDLED; } +static int sx8654_reset(struct sx8654 *ts) +{ + int err; + + if (ts->gpio_reset) { + gpiod_set_value_cansleep(ts->gpio_reset, 1); + udelay(2); /* Tpulse > 1µs */ + gpiod_set_value_cansleep(ts->gpio_reset, 0); + } else { + dev_dbg(&ts->client->dev, "NRST unavailable, try softreset\n"); + err = i2c_smbus_write_byte_data(ts->client, I2C_REG_SOFTRESET, + SOFTRESET_VALUE); + if (err) + return err; + } + + return 0; +} + static int sx8654_open(struct input_dev *dev) { struct sx8654 *sx8654 = input_get_drvdata(dev); @@ -186,6 +208,17 @@ static int sx8654_probe(struct i2c_client *client, if (!sx8654) return -ENOMEM; + sx8654->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(sx8654->gpio_reset)) { + error = PTR_ERR(sx8654->gpio_reset); + if (error != -EPROBE_DEFER) + dev_err(&client->dev, "unable to get reset-gpio: %d\n", + error); + return error; + } + dev_dbg(&client->dev, "got GPIO reset pin\n"); + input = devm_input_allocate_device(&client->dev); if (!input) return -ENOMEM; @@ -206,10 +239,9 @@ static int sx8654_probe(struct i2c_client *client, input_set_drvdata(sx8654->input, sx8654); - error = i2c_smbus_write_byte_data(client, I2C_REG_SOFTRESET, - SOFTRESET_VALUE); + error = sx8654_reset(sx8654); if (error) { - dev_err(&client->dev, "writing softreset value failed"); + dev_err(&client->dev, "reset failed"); return error; } -- cgit v1.2.3-55-g7522 From 5896756a70b2f1d476d5cf2e174c1675ff0d9e8b Mon Sep 17 00:00:00 2001 From: Richard Leitner Date: Mon, 28 Jan 2019 14:54:04 -0800 Subject: Input: sx8654 - add sx8655 and sx8656 to compatibles As the sx865[456] share the same datasheet and differ only in the presence of a "capacitive proximity detection circuit" and a "haptics motor driver for LRA/ERM" add them to the compatbiles. As the driver doesn't implement these features it should be no problem. Signed-off-by: Richard Leitner Reviewed-by: Rob Herring Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/touchscreen/sx8654.txt | 5 ++++- drivers/input/touchscreen/sx8654.c | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/input/touchscreen') diff --git a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt index ca521d8f7d65..a538678424dd 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt @@ -1,7 +1,10 @@ * Semtech SX8654 I2C Touchscreen Controller Required properties: -- compatible: must be "semtech,sx8654" +- compatible: must be one of the following, depending on the model: + "semtech,sx8654" + "semtech,sx8655" + "semtech,sx8656" - reg: i2c slave address - interrupts: touch controller interrupt diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c index ab5cbf7e0879..9e1777ed93a7 100644 --- a/drivers/input/touchscreen/sx8654.c +++ b/drivers/input/touchscreen/sx8654.c @@ -291,6 +291,8 @@ static int sx8654_probe(struct i2c_client *client, #ifdef CONFIG_OF static const struct of_device_id sx8654_of_match[] = { { .compatible = "semtech,sx8654", }, + { .compatible = "semtech,sx8655", }, + { .compatible = "semtech,sx8656", }, { }, }; MODULE_DEVICE_TABLE(of, sx8654_of_match); @@ -298,6 +300,8 @@ MODULE_DEVICE_TABLE(of, sx8654_of_match); static const struct i2c_device_id sx8654_id_table[] = { { "semtech_sx8654", 0 }, + { "semtech_sx8655", 0 }, + { "semtech_sx8656", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, sx8654_id_table); -- cgit v1.2.3-55-g7522 From 43df039c6d92266d6e023f7eb23aeb6511934f20 Mon Sep 17 00:00:00 2001 From: Richard Leitner Date: Mon, 28 Jan 2019 14:58:27 -0800 Subject: Input: sx8654 - add sx8650 support The sx8654 and sx8650 are quite similar, therefore add support for the sx8650 within the sx8654 driver. Signed-off-by: Richard Leitner Reviewed-by: Rob Herring [dtor: use __be16 in sx8650_irq, add missing del_timer_sync] Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/sx8654.txt | 1 + drivers/input/touchscreen/sx8654.c | 196 ++++++++++++++++++--- 2 files changed, 177 insertions(+), 20 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt index a538678424dd..0ebe6dd043c7 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt @@ -2,6 +2,7 @@ Required properties: - compatible: must be one of the following, depending on the model: + "semtech,sx8650" "semtech,sx8654" "semtech,sx8655" "semtech,sx8656" diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c index 9e1777ed93a7..5f5af8eaecea 100644 --- a/drivers/input/touchscreen/sx8654.c +++ b/drivers/input/touchscreen/sx8654.c @@ -44,9 +44,11 @@ #define I2C_REG_IRQSRC 0x23 #define I2C_REG_SOFTRESET 0x3f +#define I2C_REG_SX8650_STAT 0x05 +#define SX8650_STAT_CONVIRQ 0x80 + /* commands */ #define CMD_READ_REGISTER 0x40 -#define CMD_MANUAL 0xc0 #define CMD_PENTRG 0xe0 /* value for I2C_REG_SOFTRESET */ @@ -58,6 +60,7 @@ /* bits for RegTouch1 */ #define CONDIRQ 0x20 +#define RPDNT_100K 0x00 #define FILT_7SA 0x03 /* bits for I2C_REG_CHANMASK */ @@ -71,14 +74,121 @@ /* power delay: lower nibble of CTRL0 register */ #define POWDLY_1_1MS 0x0b +/* for sx8650, as we have no pen release IRQ there: timeout in ns following the + * last PENIRQ after which we assume the pen is lifted. + */ +#define SX8650_PENIRQ_TIMEOUT msecs_to_jiffies(10) + #define MAX_12BIT ((1 << 12) - 1) +#define MAX_I2C_READ_LEN 10 /* see datasheet section 5.1.5 */ + +/* channel definition */ +#define CH_X 0x00 +#define CH_Y 0x01 + +struct sx865x_data { + u8 cmd_manual; + u8 chan_mask; + bool has_irq_penrelease; + bool has_reg_irqmask; + irq_handler_t irqh; +}; struct sx8654 { struct input_dev *input; struct i2c_client *client; struct gpio_desc *gpio_reset; + + spinlock_t lock; /* for input reporting from irq/timer */ + struct timer_list timer; + + const struct sx865x_data *data; }; +static inline void sx865x_penrelease(struct sx8654 *ts) +{ + struct input_dev *input_dev = ts->input; + + input_report_key(input_dev, BTN_TOUCH, 0); + input_sync(input_dev); +} + +static void sx865x_penrelease_timer_handler(struct timer_list *t) +{ + struct sx8654 *ts = from_timer(ts, t, timer); + unsigned long flags; + + spin_lock_irqsave(&ts->lock, flags); + sx865x_penrelease(ts); + spin_unlock_irqrestore(&ts->lock, flags); + dev_dbg(&ts->client->dev, "penrelease by timer\n"); +} + +static irqreturn_t sx8650_irq(int irq, void *handle) +{ + struct sx8654 *ts = handle; + struct device *dev = &ts->client->dev; + int len, i; + unsigned long flags; + u8 stat; + u16 x, y; + u16 ch; + u16 chdata; + __be16 data[MAX_I2C_READ_LEN / sizeof(__be16)]; + u8 nchan = hweight32(ts->data->chan_mask); + u8 readlen = nchan * sizeof(*data); + + stat = i2c_smbus_read_byte_data(ts->client, CMD_READ_REGISTER + | I2C_REG_SX8650_STAT); + + if (!(stat & SX8650_STAT_CONVIRQ)) { + dev_dbg(dev, "%s ignore stat [0x%02x]", __func__, stat); + return IRQ_HANDLED; + } + + len = i2c_master_recv(ts->client, (u8 *)data, readlen); + if (len != readlen) { + dev_dbg(dev, "ignore short recv (%d)\n", len); + return IRQ_HANDLED; + } + + spin_lock_irqsave(&ts->lock, flags); + + x = 0; + y = 0; + for (i = 0; i < nchan; i++) { + chdata = be16_to_cpu(data[i]); + + if (unlikely(chdata == 0xFFFF)) { + dev_dbg(dev, "invalid qualified data @ %d\n", i); + continue; + } else if (unlikely(chdata & 0x8000)) { + dev_warn(dev, "hibit @ %d [0x%04x]\n", i, chdata); + continue; + } + + ch = chdata >> 12; + if (ch == CH_X) + x = chdata & MAX_12BIT; + else if (ch == CH_Y) + y = chdata & MAX_12BIT; + else + dev_warn(dev, "unknown channel %d [0x%04x]\n", ch, + chdata); + } + + input_report_abs(ts->input, ABS_X, x); + input_report_abs(ts->input, ABS_Y, y); + input_report_key(ts->input, BTN_TOUCH, 1); + input_sync(ts->input); + dev_dbg(dev, "point(%4d,%4d)\n", x, y); + + mod_timer(&ts->timer, jiffies + SX8650_PENIRQ_TIMEOUT); + spin_unlock_irqrestore(&ts->lock, flags); + + return IRQ_HANDLED; +} + static irqreturn_t sx8654_irq(int irq, void *handle) { struct sx8654 *sx8654 = handle; @@ -179,14 +289,17 @@ static void sx8654_close(struct input_dev *dev) disable_irq(client->irq); + if (!sx8654->data->has_irq_penrelease) + del_timer_sync(&sx8654->timer); + /* enable manual mode mode */ - error = i2c_smbus_write_byte(client, CMD_MANUAL); + error = i2c_smbus_write_byte(client, sx8654->data->cmd_manual); if (error) { dev_err(&client->dev, "writing command CMD_MANUAL failed"); return; } - error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, 0); + error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, RATE_MANUAL); if (error) { dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed"); return; @@ -219,6 +332,20 @@ static int sx8654_probe(struct i2c_client *client, } dev_dbg(&client->dev, "got GPIO reset pin\n"); + sx8654->data = device_get_match_data(&client->dev); + if (!sx8654->data) + sx8654->data = (const struct sx865x_data *)id->driver_data; + if (!sx8654->data) { + dev_err(&client->dev, "invalid or missing device data\n"); + return -EINVAL; + } + + if (!sx8654->data->has_irq_penrelease) { + dev_dbg(&client->dev, "use timer for penrelease\n"); + timer_setup(&sx8654->timer, sx865x_penrelease_timer_handler, 0); + spin_lock_init(&sx8654->lock); + } + input = devm_input_allocate_device(&client->dev); if (!input) return -ENOMEM; @@ -246,29 +373,31 @@ static int sx8654_probe(struct i2c_client *client, } error = i2c_smbus_write_byte_data(client, I2C_REG_CHANMASK, - CONV_X | CONV_Y); + sx8654->data->chan_mask); if (error) { dev_err(&client->dev, "writing to I2C_REG_CHANMASK failed"); return error; } - error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK, - IRQ_PENTOUCH_TOUCHCONVDONE | - IRQ_PENRELEASE); - if (error) { - dev_err(&client->dev, "writing to I2C_REG_IRQMASK failed"); - return error; + if (sx8654->data->has_reg_irqmask) { + error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK, + IRQ_PENTOUCH_TOUCHCONVDONE | + IRQ_PENRELEASE); + if (error) { + dev_err(&client->dev, "writing I2C_REG_IRQMASK failed"); + return error; + } } error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH1, - CONDIRQ | FILT_7SA); + CONDIRQ | RPDNT_100K | FILT_7SA); if (error) { dev_err(&client->dev, "writing to I2C_REG_TOUCH1 failed"); return error; } error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, sx8654_irq, + NULL, sx8654->data->irqh, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, sx8654); if (error) { @@ -288,21 +417,48 @@ static int sx8654_probe(struct i2c_client *client, return 0; } +static const struct sx865x_data sx8650_data = { + .cmd_manual = 0xb0, + .has_irq_penrelease = false, + .has_reg_irqmask = false, + .chan_mask = (CONV_X | CONV_Y), + .irqh = sx8650_irq, +}; + +static const struct sx865x_data sx8654_data = { + .cmd_manual = 0xc0, + .has_irq_penrelease = true, + .has_reg_irqmask = true, + .chan_mask = (CONV_X | CONV_Y), + .irqh = sx8654_irq, +}; + #ifdef CONFIG_OF static const struct of_device_id sx8654_of_match[] = { - { .compatible = "semtech,sx8654", }, - { .compatible = "semtech,sx8655", }, - { .compatible = "semtech,sx8656", }, - { }, + { + .compatible = "semtech,sx8650", + .data = &sx8650_data, + }, { + .compatible = "semtech,sx8654", + .data = &sx8654_data, + }, { + .compatible = "semtech,sx8655", + .data = &sx8654_data, + }, { + .compatible = "semtech,sx8656", + .data = &sx8654_data, + }, + { } }; MODULE_DEVICE_TABLE(of, sx8654_of_match); #endif static const struct i2c_device_id sx8654_id_table[] = { - { "semtech_sx8654", 0 }, - { "semtech_sx8655", 0 }, - { "semtech_sx8656", 0 }, - { }, + { .name = "semtech_sx8650", .driver_data = (long)&sx8650_data }, + { .name = "semtech_sx8654", .driver_data = (long)&sx8654_data }, + { .name = "semtech_sx8655", .driver_data = (long)&sx8654_data }, + { .name = "semtech_sx8656", .driver_data = (long)&sx8654_data }, + { } }; MODULE_DEVICE_TABLE(i2c, sx8654_id_table); -- cgit v1.2.3-55-g7522 From 4ec90ac5047e33f5d64e21c31046be2ff8aaaf4b Mon Sep 17 00:00:00 2001 From: Richard Leitner Date: Mon, 28 Jan 2019 16:14:16 -0800 Subject: Input: sx8654 - use common of_touchscreen functions of_touchscreen.c provides a common interface for a axis inversion and swapping of touchscreens. Therefore use it in the sx8654 driver. Signed-off-by: Richard Leitner Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/sx8654.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c index 5f5af8eaecea..de83ed1da36e 100644 --- a/drivers/input/touchscreen/sx8654.c +++ b/drivers/input/touchscreen/sx8654.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -102,6 +103,8 @@ struct sx8654 { spinlock_t lock; /* for input reporting from irq/timer */ struct timer_list timer; + struct touchscreen_properties props; + const struct sx865x_data *data; }; @@ -177,8 +180,7 @@ static irqreturn_t sx8650_irq(int irq, void *handle) chdata); } - input_report_abs(ts->input, ABS_X, x); - input_report_abs(ts->input, ABS_Y, y); + touchscreen_report_pos(ts->input, &ts->props, x, y, false); input_report_key(ts->input, BTN_TOUCH, 1); input_sync(ts->input); dev_dbg(dev, "point(%4d,%4d)\n", x, y); @@ -225,8 +227,8 @@ static irqreturn_t sx8654_irq(int irq, void *handle) x = ((data[0] & 0xf) << 8) | (data[1]); y = ((data[2] & 0xf) << 8) | (data[3]); - input_report_abs(sx8654->input, ABS_X, x); - input_report_abs(sx8654->input, ABS_Y, y); + touchscreen_report_pos(sx8654->input, &sx8654->props, x, y, + false); input_report_key(sx8654->input, BTN_TOUCH, 1); input_sync(sx8654->input); @@ -361,6 +363,8 @@ static int sx8654_probe(struct i2c_client *client, input_set_abs_params(input, ABS_X, 0, MAX_12BIT, 0, 0); input_set_abs_params(input, ABS_Y, 0, MAX_12BIT, 0, 0); + touchscreen_parse_properties(input, false, &sx8654->props); + sx8654->client = client; sx8654->input = input; -- cgit v1.2.3-55-g7522 From e47ff893bc674c32ac21094d623533ac6e585ca7 Mon Sep 17 00:00:00 2001 From: Richard Leitner Date: Mon, 28 Jan 2019 16:17:58 -0800 Subject: Input: sx8654 - convert #defined flags to BIT(x) Some of the #defined register values are one-bit flags. Convert them to use the BIT(x) macro instead of 1 byte hexadecimal values. This improves readability and clarifies the intent. Signed-off-by: Richard Leitner Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/sx8654.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c index de83ed1da36e..477533cd40ab 100644 --- a/drivers/input/touchscreen/sx8654.c +++ b/drivers/input/touchscreen/sx8654.c @@ -27,6 +27,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -46,7 +47,7 @@ #define I2C_REG_SOFTRESET 0x3f #define I2C_REG_SX8650_STAT 0x05 -#define SX8650_STAT_CONVIRQ 0x80 +#define SX8650_STAT_CONVIRQ BIT(7) /* commands */ #define CMD_READ_REGISTER 0x40 @@ -56,8 +57,8 @@ #define SOFTRESET_VALUE 0xde /* bits for I2C_REG_IRQSRC */ -#define IRQ_PENTOUCH_TOUCHCONVDONE 0x08 -#define IRQ_PENRELEASE 0x04 +#define IRQ_PENTOUCH_TOUCHCONVDONE BIT(3) +#define IRQ_PENRELEASE BIT(2) /* bits for RegTouch1 */ #define CONDIRQ 0x20 @@ -65,8 +66,8 @@ #define FILT_7SA 0x03 /* bits for I2C_REG_CHANMASK */ -#define CONV_X 0x80 -#define CONV_Y 0x40 +#define CONV_X BIT(7) +#define CONV_Y BIT(6) /* coordinates rate: higher nibble of CTRL0 register */ #define RATE_MANUAL 0x00 -- cgit v1.2.3-55-g7522 From 3c1697e6bc5cbe51e8e86446ab0482318a762637 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 28 Jan 2019 16:34:37 -0800 Subject: Input: sx8654 - do not override interrupt trigger We should rely on the interrupt trigger (level vs edge) set up by the firmware or board code instead of forcing what we consider appropriate. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/sx8654.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c index 477533cd40ab..dbdf4898aa17 100644 --- a/drivers/input/touchscreen/sx8654.c +++ b/drivers/input/touchscreen/sx8654.c @@ -403,7 +403,7 @@ static int sx8654_probe(struct i2c_client *client, error = devm_request_threaded_irq(&client->dev, client->irq, NULL, sx8654->data->irqh, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + IRQF_ONESHOT, client->name, sx8654); if (error) { dev_err(&client->dev, -- cgit v1.2.3-55-g7522 From 626feb863274da93e44d644a9fd4a59b46851794 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Feb 2019 21:53:48 -0800 Subject: Input: ili210x - drop platform data support There is not a single user of the ili210x platform data in the kernel, just drop it. Signed-off-by: Marek Vasut Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ili210x.c | 12 ++---------- include/linux/input/ili210x.h | 11 ----------- 2 files changed, 2 insertions(+), 21 deletions(-) delete mode 100644 include/linux/input/ili210x.h (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 6f76eeedf465..25b0ca6c07d9 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -6,7 +6,6 @@ #include #include #include -#include #define MAX_TOUCHES 2 #define DEFAULT_POLL_PERIOD 20 @@ -184,7 +183,6 @@ static int ili210x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; - const struct ili210x_platform_data *pdata = dev_get_platdata(dev); struct ili210x *priv; struct input_dev *input; struct panel_info panel; @@ -194,11 +192,6 @@ static int ili210x_i2c_probe(struct i2c_client *client, dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver"); - if (!pdata) { - dev_err(dev, "No platform data!\n"); - return -EINVAL; - } - if (client->irq <= 0) { dev_err(dev, "No IRQ!\n"); return -EINVAL; @@ -233,8 +226,7 @@ static int ili210x_i2c_probe(struct i2c_client *client, priv->client = client; priv->input = input; - priv->get_pendown_state = pdata->get_pendown_state; - priv->poll_period = pdata->poll_period ? : DEFAULT_POLL_PERIOD; + priv->poll_period = DEFAULT_POLL_PERIOD; INIT_DELAYED_WORK(&priv->dwork, ili210x_work); /* Setup input device */ @@ -258,7 +250,7 @@ static int ili210x_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, priv); - error = request_irq(client->irq, ili210x_irq, pdata->irq_flags, + error = request_irq(client->irq, ili210x_irq, 0, client->name, priv); if (error) { dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n", diff --git a/include/linux/input/ili210x.h b/include/linux/input/ili210x.h deleted file mode 100644 index b76e7c1404cd..000000000000 --- a/include/linux/input/ili210x.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ILI210X_H -#define _ILI210X_H - -struct ili210x_platform_data { - unsigned long irq_flags; - unsigned int poll_period; - bool (*get_pendown_state)(void); -}; - -#endif -- cgit v1.2.3-55-g7522 From 2fa928390f3f04fbb29267b29ca09d980b17f9d1 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Feb 2019 21:54:37 -0800 Subject: Input: ili210x - drop get_pendown_state The .get_pendown_state callback is set only by the platform data code, which was just removed. Thus, get_pendown_state() always returns false, so drop that altogether. Signed-off-by: Marek Vasut Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ili210x.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 25b0ca6c07d9..11007bf8113c 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -43,7 +43,6 @@ struct firmware_version { struct ili210x { struct i2c_client *client; struct input_dev *input; - bool (*get_pendown_state)(void); unsigned int poll_period; struct delayed_work dwork; }; @@ -102,16 +101,6 @@ static void ili210x_report_events(struct input_dev *input, input_sync(input); } -static bool get_pendown_state(const struct ili210x *priv) -{ - bool state = false; - - if (priv->get_pendown_state) - state = priv->get_pendown_state(); - - return state; -} - static void ili210x_work(struct work_struct *work) { struct ili210x *priv = container_of(work, struct ili210x, @@ -130,7 +119,7 @@ static void ili210x_work(struct work_struct *work) ili210x_report_events(priv->input, &touchdata); - if ((touchdata.status & 0xf3) || get_pendown_state(priv)) + if (touchdata.status & 0xf3) schedule_delayed_work(&priv->dwork, msecs_to_jiffies(priv->poll_period)); } -- cgit v1.2.3-55-g7522 From 63083fd582b9eb46a67fff6d4077a931d986d066 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Feb 2019 21:54:59 -0800 Subject: Input: ili210x - convert to devm_ functions Convert the driver to dev-managed allocations. Signed-off-by: Marek Vasut Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ili210x.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 11007bf8113c..788f4140e302 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -206,12 +206,13 @@ static int ili210x_i2c_probe(struct i2c_client *client, xmax = panel.finger_max.x_low | (panel.finger_max.x_high << 8); ymax = panel.finger_max.y_low | (panel.finger_max.y_high << 8); - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - input = input_allocate_device(); - if (!priv || !input) { - error = -ENOMEM; - goto err_free_mem; - } + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; priv->client = client; priv->input = input; @@ -273,8 +274,6 @@ err_remove_sysfs: err_free_irq: free_irq(client->irq, priv); err_free_mem: - input_free_device(input); - kfree(priv); return error; } @@ -285,8 +284,6 @@ static int ili210x_i2c_remove(struct i2c_client *client) sysfs_remove_group(&client->dev.kobj, &ili210x_attr_group); free_irq(priv->client->irq, priv); cancel_delayed_work_sync(&priv->dwork); - input_unregister_device(priv->input); - kfree(priv); return 0; } -- cgit v1.2.3-55-g7522 From 201f3c803544c052aa1bab9e562e0ada4aefe03d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Feb 2019 21:55:26 -0800 Subject: Input: ili210x - add reset GPIO support The touchscreen can have a reset GPIO connected to it, add support for such an arrangement. Signed-off-by: Marek Vasut Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ili210x.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 788f4140e302..f8b20d302384 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -6,6 +6,7 @@ #include #include #include +#include #define MAX_TOUCHES 2 #define DEFAULT_POLL_PERIOD 20 @@ -45,6 +46,7 @@ struct ili210x { struct input_dev *input; unsigned int poll_period; struct delayed_work dwork; + struct gpio_desc *reset_gpio; }; static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf, @@ -168,11 +170,19 @@ static const struct attribute_group ili210x_attr_group = { .attrs = ili210x_attributes, }; +static void ili210x_power_down(void *data) +{ + struct gpio_desc *reset_gpio = data; + + gpiod_set_value_cansleep(reset_gpio, 1); +} + static int ili210x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; struct ili210x *priv; + struct gpio_desc *reset_gpio; struct input_dev *input; struct panel_info panel; struct firmware_version firmware; @@ -186,6 +196,21 @@ static int ili210x_i2c_probe(struct i2c_client *client, return -EINVAL; } + reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpio)) + return PTR_ERR(reset_gpio); + + if (reset_gpio) { + error = devm_add_action_or_reset(dev, ili210x_power_down, + reset_gpio); + if (error) + return error; + + usleep_range(50, 100); + gpiod_set_value_cansleep(reset_gpio, 0); + msleep(100); + } + /* Get firmware version */ error = ili210x_read_reg(client, REG_FIRMWARE_VERSION, &firmware, sizeof(firmware)); @@ -218,6 +243,7 @@ static int ili210x_i2c_probe(struct i2c_client *client, priv->input = input; priv->poll_period = DEFAULT_POLL_PERIOD; INIT_DELAYED_WORK(&priv->dwork, ili210x_work); + priv->reset_gpio = reset_gpio; /* Setup input device */ input->name = "ILI210x Touchscreen"; -- cgit v1.2.3-55-g7522 From 1bdec5d9818c47e080c19784dfd25d1d9c20807e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Feb 2019 22:00:44 -0800 Subject: Input: ili210x - convert to devm IRQ Convert the driver to devm_request_irq(), drop the related unmanaged deregistration code and add ili210x_irq_teardown() to tear the IRQ down and cancel possible touchscreen pending work. Signed-off-by: Marek Vasut Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ili210x.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index f8b20d302384..bc674ece61f3 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -177,6 +177,13 @@ static void ili210x_power_down(void *data) gpiod_set_value_cansleep(reset_gpio, 1); } +static void ili210x_cancel_work(void *data) +{ + struct ili210x *priv = data; + + cancel_delayed_work_sync(&priv->dwork); +} + static int ili210x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -266,19 +273,23 @@ static int ili210x_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, priv); - error = request_irq(client->irq, ili210x_irq, 0, - client->name, priv); + error = devm_add_action(dev, ili210x_cancel_work, priv); + if (error) + return error; + + error = devm_request_irq(dev, client->irq, ili210x_irq, 0, + client->name, priv); if (error) { dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n", error); - goto err_free_mem; + return error; } error = sysfs_create_group(&dev->kobj, &ili210x_attr_group); if (error) { dev_err(dev, "Unable to create sysfs attributes, err: %d\n", error); - goto err_free_irq; + return error; } error = input_register_device(priv->input); @@ -297,19 +308,12 @@ static int ili210x_i2c_probe(struct i2c_client *client, err_remove_sysfs: sysfs_remove_group(&dev->kobj, &ili210x_attr_group); -err_free_irq: - free_irq(client->irq, priv); -err_free_mem: return error; } static int ili210x_i2c_remove(struct i2c_client *client) { - struct ili210x *priv = i2c_get_clientdata(client); - sysfs_remove_group(&client->dev.kobj, &ili210x_attr_group); - free_irq(priv->client->irq, priv); - cancel_delayed_work_sync(&priv->dwork); return 0; } -- cgit v1.2.3-55-g7522 From e3559442afd2a3d9b09eedc236f19698c515472e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Feb 2019 22:01:07 -0800 Subject: Input: ili210x - rework the touchscreen sample processing Get rid of the packed structures for representing data as that does not apply to other similar Ilitek touchscreens. Instead, implement a function which parses the data and reports touch events and coordinates. Signed-off-by: Marek Vasut Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ili210x.c | 55 ++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 25 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index bc674ece61f3..c345d6df783f 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -7,6 +7,7 @@ #include #include #include +#include #define MAX_TOUCHES 2 #define DEFAULT_POLL_PERIOD 20 @@ -17,20 +18,11 @@ #define REG_FIRMWARE_VERSION 0x40 #define REG_CALIBRATE 0xcc -struct finger { +struct panel_info { u8 x_low; u8 x_high; u8 y_low; u8 y_high; -} __packed; - -struct touchdata { - u8 status; - struct finger finger[MAX_TOUCHES]; -} __packed; - -struct panel_info { - struct finger finger_max; u8 xchannel_num; u8 ychannel_num; } __packed; @@ -75,25 +67,35 @@ static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf, return 0; } -static void ili210x_report_events(struct input_dev *input, - const struct touchdata *touchdata) +static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, + unsigned int finger, + unsigned int *x, unsigned int *y) +{ + if (finger >= MAX_TOUCHES) + return false; + + if (touchdata[0] & BIT(finger)) + return false; + + *x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0); + *y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2); + + return true; +} + +static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) { + struct input_dev *input = priv->input; int i; bool touch; unsigned int x, y; - const struct finger *finger; for (i = 0; i < MAX_TOUCHES; i++) { input_mt_slot(input, i); - finger = &touchdata->finger[i]; - - touch = touchdata->status & (1 << i); + touch = ili210x_touchdata_to_coords(priv, touchdata, i, &x, &y); input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); if (touch) { - x = finger->x_low | (finger->x_high << 8); - y = finger->y_low | (finger->y_high << 8); - input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); } @@ -101,6 +103,8 @@ static void ili210x_report_events(struct input_dev *input, input_mt_report_pointer_emulation(input, false); input_sync(input); + + return touchdata[0] & 0xf3; } static void ili210x_work(struct work_struct *work) @@ -108,20 +112,21 @@ static void ili210x_work(struct work_struct *work) struct ili210x *priv = container_of(work, struct ili210x, dwork.work); struct i2c_client *client = priv->client; - struct touchdata touchdata; + u8 touchdata[1 + 4 * MAX_TOUCHES]; + bool touch; int error; error = ili210x_read_reg(client, REG_TOUCHDATA, - &touchdata, sizeof(touchdata)); + touchdata, sizeof(touchdata)); if (error) { dev_err(&client->dev, "Unable to get touchdata, err = %d\n", error); return; } - ili210x_report_events(priv->input, &touchdata); + touch = ili210x_report_events(priv, touchdata); - if (touchdata.status & 0xf3) + if (touch) schedule_delayed_work(&priv->dwork, msecs_to_jiffies(priv->poll_period)); } @@ -235,8 +240,8 @@ static int ili210x_i2c_probe(struct i2c_client *client, return error; } - xmax = panel.finger_max.x_low | (panel.finger_max.x_high << 8); - ymax = panel.finger_max.y_low | (panel.finger_max.y_high << 8); + xmax = panel.x_low | (panel.x_high << 8); + ymax = panel.y_low | (panel.y_high << 8); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) -- cgit v1.2.3-55-g7522 From 122945776271efee91012c2a345b720d39b15b7c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Feb 2019 22:01:30 -0800 Subject: Input: ili210x - reorder probe Perform the register access only after the I2C client data are set, this is only done in preparation for the subsequent patch which uses the I2C client data in the register IO function. Signed-off-by: Marek Vasut Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ili210x.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index c345d6df783f..ba2634582364 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -223,6 +223,22 @@ static int ili210x_i2c_probe(struct i2c_client *client, msleep(100); } + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + priv->client = client; + priv->input = input; + priv->poll_period = DEFAULT_POLL_PERIOD; + INIT_DELAYED_WORK(&priv->dwork, ili210x_work); + priv->reset_gpio = reset_gpio; + + i2c_set_clientdata(client, priv); + /* Get firmware version */ error = ili210x_read_reg(client, REG_FIRMWARE_VERSION, &firmware, sizeof(firmware)); @@ -243,20 +259,6 @@ static int ili210x_i2c_probe(struct i2c_client *client, xmax = panel.x_low | (panel.x_high << 8); ymax = panel.y_low | (panel.y_high << 8); - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - input = devm_input_allocate_device(dev); - if (!input) - return -ENOMEM; - - priv->client = client; - priv->input = input; - priv->poll_period = DEFAULT_POLL_PERIOD; - INIT_DELAYED_WORK(&priv->dwork, ili210x_work); - priv->reset_gpio = reset_gpio; - /* Setup input device */ input->name = "ILI210x Touchscreen"; input->id.bustype = BUS_I2C; @@ -276,8 +278,6 @@ static int ili210x_i2c_probe(struct i2c_client *client, input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0); - i2c_set_clientdata(client, priv); - error = devm_add_action(dev, ili210x_cancel_work, priv); if (error) return error; -- cgit v1.2.3-55-g7522 From c5d0e4b5154ac81cffdf6472d5f5e1408faa8ccd Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Feb 2019 22:01:51 -0800 Subject: Input: ili210x - add OF match table Add OF match table for the ili210x touchscreen. Signed-off-by: Marek Vasut Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ili210x.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index ba2634582364..4e550fe0cb15 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -352,10 +352,17 @@ static const struct i2c_device_id ili210x_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); +static const struct of_device_id ili210x_dt_ids[] = { + { .compatible = "ilitek,ili210x", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ili210x_dt_ids); + static struct i2c_driver ili210x_ts_driver = { .driver = { .name = "ili210x_i2c", .pm = &ili210x_i2c_pm, + .of_match_table = ili210x_dt_ids, }, .id_table = ili210x_i2c_id, .probe = ili210x_i2c_probe, -- cgit v1.2.3-55-g7522 From 4958891764749304ac1511f6140ae3888c088e23 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Feb 2019 22:02:02 -0800 Subject: Input: ili210x - add ILI251X support Add support for ILI251x touch controller. This controller is similar to the ILI210x, except for the following differences: - Does not support I2C R-W transfer, Read must be followed by an obscenely long delay, and then followed by Write - Does support 10 simultaneous touch inputs. - Touch data format is slightly different, pressure reporting does not work although the touch data contain such information. Signed-off-by: Marek Vasut Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ili210x.c | 118 +++++++++++++++++++++++++++++++----- 1 file changed, 103 insertions(+), 15 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 4e550fe0cb15..6cfe463ac118 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -7,9 +7,11 @@ #include #include #include +#include #include -#define MAX_TOUCHES 2 +#define ILI210X_TOUCHES 2 +#define ILI251X_TOUCHES 10 #define DEFAULT_POLL_PERIOD 20 /* Touchscreen commands */ @@ -33,17 +35,25 @@ struct firmware_version { u8 minor; } __packed; +enum ili2xxx_model { + MODEL_ILI210X, + MODEL_ILI251X, +}; + struct ili210x { struct i2c_client *client; struct input_dev *input; unsigned int poll_period; struct delayed_work dwork; struct gpio_desc *reset_gpio; + enum ili2xxx_model model; + unsigned int max_touches; }; static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf, size_t len) { + struct ili210x *priv = i2c_get_clientdata(client); struct i2c_msg msg[2] = { { .addr = client->addr, @@ -59,7 +69,38 @@ static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf, } }; - if (i2c_transfer(client->adapter, msg, 2) != 2) { + if (priv->model == MODEL_ILI251X) { + if (i2c_transfer(client->adapter, msg, 1) != 1) { + dev_err(&client->dev, "i2c transfer failed\n"); + return -EIO; + } + + usleep_range(5000, 5500); + + if (i2c_transfer(client->adapter, msg + 1, 1) != 1) { + dev_err(&client->dev, "i2c transfer failed\n"); + return -EIO; + } + } else { + if (i2c_transfer(client->adapter, msg, 2) != 2) { + dev_err(&client->dev, "i2c transfer failed\n"); + return -EIO; + } + } + + return 0; +} + +static int ili210x_read(struct i2c_client *client, void *buf, size_t len) +{ + struct i2c_msg msg = { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = buf, + }; + + if (i2c_transfer(client->adapter, &msg, 1) != 1) { dev_err(&client->dev, "i2c transfer failed\n"); return -EIO; } @@ -71,7 +112,7 @@ static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, unsigned int finger, unsigned int *x, unsigned int *y) { - if (finger >= MAX_TOUCHES) + if (finger >= ILI210X_TOUCHES) return false; if (touchdata[0] & BIT(finger)) @@ -83,17 +124,43 @@ static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, return true; } +static bool ili251x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, + unsigned int finger, + unsigned int *x, unsigned int *y) +{ + if (finger >= ILI251X_TOUCHES) + return false; + + *x = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0); + if (!(*x & BIT(15))) /* Touch indication */ + return false; + + *x &= 0x3fff; + *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2); + + return true; +} + static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) { struct input_dev *input = priv->input; int i; - bool touch; - unsigned int x, y; + bool contact = false, touch = false; + unsigned int x = 0, y = 0; - for (i = 0; i < MAX_TOUCHES; i++) { + for (i = 0; i < priv->max_touches; i++) { input_mt_slot(input, i); - touch = ili210x_touchdata_to_coords(priv, touchdata, i, &x, &y); + if (priv->model == MODEL_ILI210X) { + touch = ili210x_touchdata_to_coords(priv, touchdata, + i, &x, &y); + } else if (priv->model == MODEL_ILI251X) { + touch = ili251x_touchdata_to_coords(priv, touchdata, + i, &x, &y); + if (touch) + contact = true; + } + input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); if (touch) { input_report_abs(input, ABS_MT_POSITION_X, x); @@ -104,7 +171,10 @@ static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) input_mt_report_pointer_emulation(input, false); input_sync(input); - return touchdata[0] & 0xf3; + if (priv->model == MODEL_ILI210X) + contact = touchdata[0] & 0xf3; + + return contact; } static void ili210x_work(struct work_struct *work) @@ -112,12 +182,20 @@ static void ili210x_work(struct work_struct *work) struct ili210x *priv = container_of(work, struct ili210x, dwork.work); struct i2c_client *client = priv->client; - u8 touchdata[1 + 4 * MAX_TOUCHES]; + u8 touchdata[64] = { 0 }; bool touch; - int error; + int error = -EINVAL; + + if (priv->model == MODEL_ILI210X) { + error = ili210x_read_reg(client, REG_TOUCHDATA, + touchdata, sizeof(touchdata)); + } else if (priv->model == MODEL_ILI251X) { + error = ili210x_read_reg(client, REG_TOUCHDATA, + touchdata, 31); + if (!error && touchdata[0] == 2) + error = ili210x_read(client, &touchdata[31], 20); + } - error = ili210x_read_reg(client, REG_TOUCHDATA, - touchdata, sizeof(touchdata)); if (error) { dev_err(&client->dev, "Unable to get touchdata, err = %d\n", error); @@ -198,9 +276,12 @@ static int ili210x_i2c_probe(struct i2c_client *client, struct input_dev *input; struct panel_info panel; struct firmware_version firmware; + enum ili2xxx_model model; int xmax, ymax; int error; + model = (enum ili2xxx_model)id->driver_data; + dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver"); if (client->irq <= 0) { @@ -236,6 +317,11 @@ static int ili210x_i2c_probe(struct i2c_client *client, priv->poll_period = DEFAULT_POLL_PERIOD; INIT_DELAYED_WORK(&priv->dwork, ili210x_work); priv->reset_gpio = reset_gpio; + priv->model = model; + if (model == MODEL_ILI210X) + priv->max_touches = ILI210X_TOUCHES; + if (model == MODEL_ILI251X) + priv->max_touches = ILI251X_TOUCHES; i2c_set_clientdata(client, priv); @@ -274,7 +360,7 @@ static int ili210x_i2c_probe(struct i2c_client *client, input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0); /* Multi touch */ - input_mt_init_slots(input, MAX_TOUCHES, 0); + input_mt_init_slots(input, priv->max_touches, 0); input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0); @@ -347,13 +433,15 @@ static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm, ili210x_i2c_suspend, ili210x_i2c_resume); static const struct i2c_device_id ili210x_i2c_id[] = { - { "ili210x", 0 }, + { "ili210x", MODEL_ILI210X }, + { "ili251x", MODEL_ILI251X }, { } }; MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); static const struct of_device_id ili210x_dt_ids[] = { - { .compatible = "ilitek,ili210x", }, + { .compatible = "ilitek,ili210x", .data = (void *)MODEL_ILI210X }, + { .compatible = "ilitek,ili251x", .data = (void *)MODEL_ILI251X }, { }, }; MODULE_DEVICE_TABLE(of, ili210x_dt_ids); -- cgit v1.2.3-55-g7522 From 576057bf75cb3e40ff81bb01f021d76b764fdc92 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 6 Feb 2019 22:19:42 -0800 Subject: Input: ili210x - switch to using devm_device_add_group() By switching to devm_device_add_group() we can complete driver conversion to using managed resources and get rid of ili210x_i2c_remove(). Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ili210x.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 6cfe463ac118..af1dd9cff12a 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -376,7 +376,7 @@ static int ili210x_i2c_probe(struct i2c_client *client, return error; } - error = sysfs_create_group(&dev->kobj, &ili210x_attr_group); + error = devm_device_add_group(dev, &ili210x_attr_group); if (error) { dev_err(dev, "Unable to create sysfs attributes, err: %d\n", error); @@ -386,7 +386,7 @@ static int ili210x_i2c_probe(struct i2c_client *client, error = input_register_device(priv->input); if (error) { dev_err(dev, "Cannot register input device, err: %d\n", error); - goto err_remove_sysfs; + return error; } device_init_wakeup(dev, 1); @@ -396,17 +396,6 @@ static int ili210x_i2c_probe(struct i2c_client *client, client->irq, firmware.id, firmware.major, firmware.minor); return 0; - -err_remove_sysfs: - sysfs_remove_group(&dev->kobj, &ili210x_attr_group); - return error; -} - -static int ili210x_i2c_remove(struct i2c_client *client) -{ - sysfs_remove_group(&client->dev.kobj, &ili210x_attr_group); - - return 0; } static int __maybe_unused ili210x_i2c_suspend(struct device *dev) @@ -454,7 +443,6 @@ static struct i2c_driver ili210x_ts_driver = { }, .id_table = ili210x_i2c_id, .probe = ili210x_i2c_probe, - .remove = ili210x_i2c_remove, }; module_i2c_driver(ili210x_ts_driver); -- cgit v1.2.3-55-g7522 From 937c4e552fd1174784045684740edfcea536159d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 5 Feb 2019 14:40:40 -0800 Subject: Input: stmfts - acknowledge that setting brightness is a blocking call We need to turn regulators on and off when switching brightness, and that may block, therefore we have to set stmfts_brightness_set() as LED's brightness_set_blocking() method. Fixes: 78bcac7b2ae1 ("Input: add support for the STMicroelectronics FingerTip touchscreen") Acked-by: Andi Shyti Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/stmfts.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c index 704e99046916..b6f95f20f924 100644 --- a/drivers/input/touchscreen/stmfts.c +++ b/drivers/input/touchscreen/stmfts.c @@ -106,27 +106,29 @@ struct stmfts_data { bool running; }; -static void stmfts_brightness_set(struct led_classdev *led_cdev, +static int stmfts_brightness_set(struct led_classdev *led_cdev, enum led_brightness value) { struct stmfts_data *sdata = container_of(led_cdev, struct stmfts_data, led_cdev); int err; - if (value == sdata->led_status || !sdata->ledvdd) - return; - - if (!value) { - regulator_disable(sdata->ledvdd); - } else { - err = regulator_enable(sdata->ledvdd); - if (err) - dev_warn(&sdata->client->dev, - "failed to disable ledvdd regulator: %d\n", - err); + if (value != sdata->led_status && sdata->ledvdd) { + if (!value) { + regulator_disable(sdata->ledvdd); + } else { + err = regulator_enable(sdata->ledvdd); + if (err) { + dev_warn(&sdata->client->dev, + "failed to disable ledvdd regulator: %d\n", + err); + return err; + } + } + sdata->led_status = value; } - sdata->led_status = value; + return 0; } static enum led_brightness stmfts_brightness_get(struct led_classdev *led_cdev) @@ -608,7 +610,7 @@ static int stmfts_enable_led(struct stmfts_data *sdata) sdata->led_cdev.name = STMFTS_DEV_NAME; sdata->led_cdev.max_brightness = LED_ON; sdata->led_cdev.brightness = LED_OFF; - sdata->led_cdev.brightness_set = stmfts_brightness_set; + sdata->led_cdev.brightness_set_blocking = stmfts_brightness_set; sdata->led_cdev.brightness_get = stmfts_brightness_get; err = devm_led_classdev_register(&sdata->client->dev, &sdata->led_cdev); -- cgit v1.2.3-55-g7522 From f67cc3e927d8414ad3872e046764534ea1f5db0d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 9 Feb 2019 08:49:38 -0800 Subject: Input: ili210x - fetch touchscreen geometry from DT Fetching the geometry from the ILI251x registers seems unreliable and sometimes returns all zeroes. Add support for fetching the geometry and axis inversion from DT instead. Signed-off-by: Marek Vasut Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ili210x.c | 51 ++++++++----------------------------- 1 file changed, 11 insertions(+), 40 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index af1dd9cff12a..9169aa03958a 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -20,15 +21,6 @@ #define REG_FIRMWARE_VERSION 0x40 #define REG_CALIBRATE 0xcc -struct panel_info { - u8 x_low; - u8 x_high; - u8 y_low; - u8 y_high; - u8 xchannel_num; - u8 ychannel_num; -} __packed; - struct firmware_version { u8 id; u8 major; @@ -46,6 +38,7 @@ struct ili210x { unsigned int poll_period; struct delayed_work dwork; struct gpio_desc *reset_gpio; + struct touchscreen_properties prop; enum ili2xxx_model model; unsigned int max_touches; }; @@ -149,8 +142,6 @@ static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) unsigned int x = 0, y = 0; for (i = 0; i < priv->max_touches; i++) { - input_mt_slot(input, i); - if (priv->model == MODEL_ILI210X) { touch = ili210x_touchdata_to_coords(priv, touchdata, i, &x, &y); @@ -161,11 +152,12 @@ static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) contact = true; } + input_mt_slot(input, i); input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); - if (touch) { - input_report_abs(input, ABS_MT_POSITION_X, x); - input_report_abs(input, ABS_MT_POSITION_Y, y); - } + if (!touch) + continue; + touchscreen_report_pos(input, &priv->prop, x, y, + true); } input_mt_report_pointer_emulation(input, false); @@ -274,10 +266,8 @@ static int ili210x_i2c_probe(struct i2c_client *client, struct ili210x *priv; struct gpio_desc *reset_gpio; struct input_dev *input; - struct panel_info panel; struct firmware_version firmware; enum ili2xxx_model model; - int xmax, ymax; int error; model = (enum ili2xxx_model)id->driver_data; @@ -334,35 +324,16 @@ static int ili210x_i2c_probe(struct i2c_client *client, return error; } - /* get panel info */ - error = ili210x_read_reg(client, REG_PANEL_INFO, &panel, sizeof(panel)); - if (error) { - dev_err(dev, "Failed to get panel information, err: %d\n", - error); - return error; - } - - xmax = panel.x_low | (panel.x_high << 8); - ymax = panel.y_low | (panel.y_high << 8); - /* Setup input device */ input->name = "ILI210x Touchscreen"; input->id.bustype = BUS_I2C; input->dev.parent = dev; - __set_bit(EV_SYN, input->evbit); - __set_bit(EV_KEY, input->evbit); - __set_bit(EV_ABS, input->evbit); - __set_bit(BTN_TOUCH, input->keybit); - - /* Single touch */ - input_set_abs_params(input, ABS_X, 0, xmax, 0, 0); - input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0); - /* Multi touch */ - input_mt_init_slots(input, priv->max_touches, 0); - input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_X, 0, 0xffff, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 0xffff, 0, 0); + touchscreen_parse_properties(input, true, &priv->prop); + input_mt_init_slots(input, priv->max_touches, INPUT_MT_DIRECT); error = devm_add_action(dev, ili210x_cancel_work, priv); if (error) -- cgit v1.2.3-55-g7522 From e3dd12f0eacc52ddf5cd4e6651e09daebcb25f0e Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Sat, 9 Feb 2019 08:53:13 -0800 Subject: Input: st1232 - switch to gpiod API Use devm_gpiod_get_optional() and gpiod_set_value_cansleep() instead of the old API. The st1232_ts_power() now passes on the inverted "poweron" value to reflect the correct logical value. Signed-off-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/st1232.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 634d6c243845..32819ee6ec4b 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -11,13 +11,12 @@ */ #include -#include +#include #include #include #include #include #include -#include #include #include #include @@ -45,7 +44,7 @@ struct st1232_ts_data { struct i2c_client *client; struct input_dev *input_dev; struct dev_pm_qos_request low_latency_req; - int reset_gpio; + struct gpio_desc *reset_gpio; const struct st_chip_info *chip_info; int read_buf_len; u8 *read_buf; @@ -142,8 +141,8 @@ end: static void st1232_ts_power(struct st1232_ts_data *ts, bool poweron) { - if (gpio_is_valid(ts->reset_gpio)) - gpio_direction_output(ts->reset_gpio, poweron); + if (ts->reset_gpio) + gpiod_set_value_cansleep(ts->reset_gpio, !poweron); } static const struct st_chip_info st1232_chip_info = { @@ -215,15 +214,13 @@ static int st1232_ts_probe(struct i2c_client *client, ts->client = client; ts->input_dev = input_dev; - ts->reset_gpio = of_get_gpio(client->dev.of_node, 0); - if (gpio_is_valid(ts->reset_gpio)) { - error = devm_gpio_request(&client->dev, ts->reset_gpio, NULL); - if (error) { - dev_err(&client->dev, - "Unable to request GPIO pin %d.\n", - ts->reset_gpio); - return error; - } + ts->reset_gpio = devm_gpiod_get_optional(&client->dev, NULL, + GPIOD_OUT_HIGH); + if (IS_ERR(ts->reset_gpio)) { + error = PTR_ERR(ts->reset_gpio); + dev_err(&client->dev, "Unable to request GPIO pin: %d.\n", + error); + return error; } st1232_ts_power(ts, true); -- cgit v1.2.3-55-g7522 From 16ab4f43eb953277e915115c1d811d2a518d6bf2 Mon Sep 17 00:00:00 2001 From: Matthias Fend Date: Mon, 11 Feb 2019 00:30:26 -0800 Subject: Input: st1232 - handle common DT bindings This is required to specify generic touchscreen properties via DT. Signed-off-by: Matthias Fend Reviewed-by: Rob Herring Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/touchscreen/sitronix-st1232.txt | 2 ++ drivers/input/touchscreen/st1232.c | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt b/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt index e73e826e0f2a..019373253b28 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt @@ -10,6 +10,8 @@ Required properties: Optional properties: - gpios: a phandle to the reset GPIO +For additional optional properties see: touchscreen.txt + Example: i2c@00000000 { diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 32819ee6ec4b..34923399ece4 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -20,6 +20,7 @@ #include #include #include +#include #define ST1232_TS_NAME "st1232-ts" #define ST1633_TS_NAME "st1633-ts" @@ -43,6 +44,7 @@ struct st_chip_info { struct st1232_ts_data { struct i2c_client *client; struct input_dev *input_dev; + struct touchscreen_properties prop; struct dev_pm_qos_request low_latency_req; struct gpio_desc *reset_gpio; const struct st_chip_info *chip_info; @@ -112,8 +114,8 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id) input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t); - input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y); + touchscreen_report_pos(input_dev, &ts->prop, + finger[i].x, finger[i].y, true); input_mt_sync(input_dev); count++; } @@ -243,6 +245,8 @@ static int st1232_ts_probe(struct i2c_client *client, input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, ts->chip_info->max_y, 0, 0); + touchscreen_parse_properties(input_dev, true, &ts->prop); + error = devm_request_threaded_irq(&client->dev, client->irq, NULL, st1232_ts_irq_handler, IRQF_ONESHOT, -- cgit v1.2.3-55-g7522 From 84ef1b339c2fa27e664657d2493601cc025cc9fa Mon Sep 17 00:00:00 2001 From: Guido Günther Date: Sat, 16 Feb 2019 23:03:13 -0800 Subject: Input: goodix - support Goodix gt5688 From what I've seen in vendor trees it's fine to treat this as gt1x¹. Tested on the Purism Librem 5 Devkit (Rocktech JH057N00900 panel). [1]: https://github.com/TadiT7/android_kernel_mtk-4.4/tree/master/drivers/input/touchscreen/mediatek/GT5688 Signed-off-by: Guido Günther Reviewed-by: Bastien Nocera Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/touchscreen/goodix.txt | 1 + drivers/input/touchscreen/goodix.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers/input/touchscreen') diff --git a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt index f7e95c52f3c7..57d3d8870a09 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt @@ -3,6 +3,7 @@ Device tree bindings for Goodix GT9xx series touchscreen controller Required properties: - compatible : Should be "goodix,gt1151" + or "goodix,gt5688" or "goodix,gt911" or "goodix,gt9110" or "goodix,gt912" diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index f2d9c2c41885..47b1ced41576 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -216,6 +216,7 @@ static const struct goodix_chip_data *goodix_get_chip_data(u16 id) { switch (id) { case 1151: + case 5688: return >1x_chip_data; case 911: @@ -942,6 +943,7 @@ MODULE_DEVICE_TABLE(acpi, goodix_acpi_match); #ifdef CONFIG_OF static const struct of_device_id goodix_of_match[] = { { .compatible = "goodix,gt1151" }, + { .compatible = "goodix,gt5688" }, { .compatible = "goodix,gt911" }, { .compatible = "goodix,gt9110" }, { .compatible = "goodix,gt912" }, -- cgit v1.2.3-55-g7522 From c1c00aa53a636d635d9bfad15652fa0694b54f9d Mon Sep 17 00:00:00 2001 From: Guido Günther Date: Sat, 16 Feb 2019 23:04:43 -0800 Subject: Input: goodix - print values in case of inconsistencies "Invalid config" gives little idea what's wrong. Print the values that must not be 0 so we know which ones are off. Signed-off-by: Guido Günther Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/goodix.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 47b1ced41576..f57d82220a88 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -693,7 +693,9 @@ static int goodix_configure_dev(struct goodix_ts_data *ts) touchscreen_parse_properties(ts->input_dev, true, &ts->prop); if (!ts->prop.max_x || !ts->prop.max_y || !ts->max_touch_num) { - dev_err(&ts->client->dev, "Invalid config, using defaults\n"); + dev_err(&ts->client->dev, + "Invalid config (%d, %d, %d), using defaults\n", + ts->prop.max_x, ts->prop.max_y, ts->max_touch_num); ts->prop.max_x = GOODIX_MAX_WIDTH - 1; ts->prop.max_y = GOODIX_MAX_HEIGHT - 1; ts->max_touch_num = GOODIX_MAX_CONTACTS; -- cgit v1.2.3-55-g7522 From 44466306ebecc73c68835f5fe27d119591a1ab5c Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 18 Feb 2019 12:17:39 -0800 Subject: Input: ti_am335x_tsc - remove set but not used variable 'tscadc_dev' Fixes gcc '-Wunused-but-set-variable' warning: drivers/input/touchscreen/ti_am335x_tsc.c: In function 'titsc_suspend': drivers/input/touchscreen/ti_am335x_tsc.c:510:24: warning: variable 'tscadc_dev' set but not used [-Wunused-but-set-variable] drivers/input/touchscreen/ti_am335x_tsc.c: In function 'titsc_resume': drivers/input/touchscreen/ti_am335x_tsc.c:527:24: warning: variable 'tscadc_dev' set but not used [-Wunused-but-set-variable] It's not used any more after 333e07ec4b33 ("Input: ti_am335x_tsc: Mark TSC device as wakeup source") Signed-off-by: YueHaibing Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ti_am335x_tsc.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/input/touchscreen') diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 9e8684ab48f4..83e685557a19 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -507,10 +507,8 @@ static int titsc_remove(struct platform_device *pdev) static int __maybe_unused titsc_suspend(struct device *dev) { struct titsc *ts_dev = dev_get_drvdata(dev); - struct ti_tscadc_dev *tscadc_dev; unsigned int idle; - tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); if (device_may_wakeup(dev)) { titsc_writel(ts_dev, REG_IRQSTATUS, TSC_IRQENB_MASK); idle = titsc_readl(ts_dev, REG_IRQENABLE); @@ -524,9 +522,7 @@ static int __maybe_unused titsc_suspend(struct device *dev) static int __maybe_unused titsc_resume(struct device *dev) { struct titsc *ts_dev = dev_get_drvdata(dev); - struct ti_tscadc_dev *tscadc_dev; - tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); if (device_may_wakeup(dev)) { titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00); -- cgit v1.2.3-55-g7522