109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 271f8e38aSDmitry Torokhov #include <linux/delay.h> 371f8e38aSDmitry Torokhov #include <linux/gpio/consumer.h> 45c6a7a62SOlivier Sobrie #include <linux/i2c.h> 55c6a7a62SOlivier Sobrie #include <linux/input.h> 65c6a7a62SOlivier Sobrie #include <linux/input/mt.h> 7f67cc3e9SMarek Vasut #include <linux/input/touchscreen.h> 871f8e38aSDmitry Torokhov #include <linux/interrupt.h> 971f8e38aSDmitry Torokhov #include <linux/module.h> 1049588917SMarek Vasut #include <linux/of_device.h> 11b32fbeaeSSven Van Asbroeck #include <linux/sizes.h> 1271f8e38aSDmitry Torokhov #include <linux/slab.h> 13e3559442SMarek Vasut #include <asm/unaligned.h> 145c6a7a62SOlivier Sobrie 1571f8e38aSDmitry Torokhov #define ILI2XXX_POLL_PERIOD 20 165c6a7a62SOlivier Sobrie 17ef536abdSDmitry Torokhov #define ILI210X_DATA_SIZE 64 18ef536abdSDmitry Torokhov #define ILI211X_DATA_SIZE 43 19ef536abdSDmitry Torokhov #define ILI251X_DATA_SIZE1 31 20ef536abdSDmitry Torokhov #define ILI251X_DATA_SIZE2 20 21ef536abdSDmitry Torokhov 225c6a7a62SOlivier Sobrie /* Touchscreen commands */ 235c6a7a62SOlivier Sobrie #define REG_TOUCHDATA 0x10 245c6a7a62SOlivier Sobrie #define REG_PANEL_INFO 0x20 255c6a7a62SOlivier Sobrie #define REG_CALIBRATE 0xcc 265c6a7a62SOlivier Sobrie 27ef536abdSDmitry Torokhov struct ili2xxx_chip { 28ef536abdSDmitry Torokhov int (*read_reg)(struct i2c_client *client, u8 reg, 29ef536abdSDmitry Torokhov void *buf, size_t len); 30ef536abdSDmitry Torokhov int (*get_touch_data)(struct i2c_client *client, u8 *data); 31ef536abdSDmitry Torokhov bool (*parse_touch_data)(const u8 *data, unsigned int finger, 3260159e9eSMarek Vasut unsigned int *x, unsigned int *y, 3360159e9eSMarek Vasut unsigned int *z); 34ef536abdSDmitry Torokhov bool (*continue_polling)(const u8 *data, bool touch); 35ef536abdSDmitry Torokhov unsigned int max_touches; 36b32fbeaeSSven Van Asbroeck unsigned int resolution; 37cc12ba18SSven Van Asbroeck bool has_calibrate_reg; 38*235300edSMarek Vasut bool has_firmware_proto; 3960159e9eSMarek Vasut bool has_pressure_reg; 4049588917SMarek Vasut }; 4149588917SMarek Vasut 425c6a7a62SOlivier Sobrie struct ili210x { 435c6a7a62SOlivier Sobrie struct i2c_client *client; 445c6a7a62SOlivier Sobrie struct input_dev *input; 45201f3c80SMarek Vasut struct gpio_desc *reset_gpio; 46f67cc3e9SMarek Vasut struct touchscreen_properties prop; 47ef536abdSDmitry Torokhov const struct ili2xxx_chip *chip; 4871f8e38aSDmitry Torokhov bool stop; 495c6a7a62SOlivier Sobrie }; 505c6a7a62SOlivier Sobrie 51ef536abdSDmitry Torokhov static int ili210x_read_reg(struct i2c_client *client, 52ef536abdSDmitry Torokhov u8 reg, void *buf, size_t len) 535c6a7a62SOlivier Sobrie { 54ef536abdSDmitry Torokhov struct i2c_msg msg[] = { 555c6a7a62SOlivier Sobrie { 565c6a7a62SOlivier Sobrie .addr = client->addr, 575c6a7a62SOlivier Sobrie .flags = 0, 585c6a7a62SOlivier Sobrie .len = 1, 595c6a7a62SOlivier Sobrie .buf = ®, 605c6a7a62SOlivier Sobrie }, 615c6a7a62SOlivier Sobrie { 625c6a7a62SOlivier Sobrie .addr = client->addr, 635c6a7a62SOlivier Sobrie .flags = I2C_M_RD, 645c6a7a62SOlivier Sobrie .len = len, 655c6a7a62SOlivier Sobrie .buf = buf, 665c6a7a62SOlivier Sobrie } 675c6a7a62SOlivier Sobrie }; 68ef536abdSDmitry Torokhov int error, ret; 695c6a7a62SOlivier Sobrie 70ef536abdSDmitry Torokhov ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); 71ef536abdSDmitry Torokhov if (ret != ARRAY_SIZE(msg)) { 72ef536abdSDmitry Torokhov error = ret < 0 ? ret : -EIO; 73ef536abdSDmitry Torokhov dev_err(&client->dev, "%s failed: %d\n", __func__, error); 74ef536abdSDmitry Torokhov return error; 7549588917SMarek Vasut } 7649588917SMarek Vasut 7749588917SMarek Vasut return 0; 7849588917SMarek Vasut } 7949588917SMarek Vasut 80ef536abdSDmitry Torokhov static int ili210x_read_touch_data(struct i2c_client *client, u8 *data) 8149588917SMarek Vasut { 82ef536abdSDmitry Torokhov return ili210x_read_reg(client, REG_TOUCHDATA, 83ef536abdSDmitry Torokhov data, ILI210X_DATA_SIZE); 8449588917SMarek Vasut } 855c6a7a62SOlivier Sobrie 86ef536abdSDmitry Torokhov static bool ili210x_touchdata_to_coords(const u8 *touchdata, 87e3559442SMarek Vasut unsigned int finger, 8860159e9eSMarek Vasut unsigned int *x, unsigned int *y, 8960159e9eSMarek Vasut unsigned int *z) 905c6a7a62SOlivier Sobrie { 91ac05a8a9SHansem Ro if (!(touchdata[0] & BIT(finger))) 92e3559442SMarek Vasut return false; 93e3559442SMarek Vasut 94e3559442SMarek Vasut *x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0); 95e3559442SMarek Vasut *y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2); 96e3559442SMarek Vasut 97e3559442SMarek Vasut return true; 98e3559442SMarek Vasut } 99e3559442SMarek Vasut 100ef536abdSDmitry Torokhov static bool ili210x_check_continue_polling(const u8 *data, bool touch) 101ef536abdSDmitry Torokhov { 102ef536abdSDmitry Torokhov return data[0] & 0xf3; 103ef536abdSDmitry Torokhov } 104ef536abdSDmitry Torokhov 105ef536abdSDmitry Torokhov static const struct ili2xxx_chip ili210x_chip = { 106ef536abdSDmitry Torokhov .read_reg = ili210x_read_reg, 107ef536abdSDmitry Torokhov .get_touch_data = ili210x_read_touch_data, 108ef536abdSDmitry Torokhov .parse_touch_data = ili210x_touchdata_to_coords, 109ef536abdSDmitry Torokhov .continue_polling = ili210x_check_continue_polling, 110ef536abdSDmitry Torokhov .max_touches = 2, 111cc12ba18SSven Van Asbroeck .has_calibrate_reg = true, 112ef536abdSDmitry Torokhov }; 113ef536abdSDmitry Torokhov 114ef536abdSDmitry Torokhov static int ili211x_read_touch_data(struct i2c_client *client, u8 *data) 115ef536abdSDmitry Torokhov { 116ef536abdSDmitry Torokhov s16 sum = 0; 117ef536abdSDmitry Torokhov int error; 118ef536abdSDmitry Torokhov int ret; 119ef536abdSDmitry Torokhov int i; 120ef536abdSDmitry Torokhov 121ef536abdSDmitry Torokhov ret = i2c_master_recv(client, data, ILI211X_DATA_SIZE); 122ef536abdSDmitry Torokhov if (ret != ILI211X_DATA_SIZE) { 123ef536abdSDmitry Torokhov error = ret < 0 ? ret : -EIO; 124ef536abdSDmitry Torokhov dev_err(&client->dev, "%s failed: %d\n", __func__, error); 125ef536abdSDmitry Torokhov return error; 126ef536abdSDmitry Torokhov } 127ef536abdSDmitry Torokhov 128ef536abdSDmitry Torokhov /* This chip uses custom checksum at the end of data */ 129ef536abdSDmitry Torokhov for (i = 0; i < ILI211X_DATA_SIZE - 1; i++) 130ef536abdSDmitry Torokhov sum = (sum + data[i]) & 0xff; 131ef536abdSDmitry Torokhov 132ef536abdSDmitry Torokhov if ((-sum & 0xff) != data[ILI211X_DATA_SIZE - 1]) { 133ef536abdSDmitry Torokhov dev_err(&client->dev, 134ef536abdSDmitry Torokhov "CRC error (crc=0x%02x expected=0x%02x)\n", 135ef536abdSDmitry Torokhov sum, data[ILI211X_DATA_SIZE - 1]); 136ef536abdSDmitry Torokhov return -EIO; 137ef536abdSDmitry Torokhov } 138ef536abdSDmitry Torokhov 139ef536abdSDmitry Torokhov return 0; 140ef536abdSDmitry Torokhov } 141ef536abdSDmitry Torokhov 142ef536abdSDmitry Torokhov static bool ili211x_touchdata_to_coords(const u8 *touchdata, 143eb91ecc9SMarek Vasut unsigned int finger, 14460159e9eSMarek Vasut unsigned int *x, unsigned int *y, 14560159e9eSMarek Vasut unsigned int *z) 146eb91ecc9SMarek Vasut { 147eb91ecc9SMarek Vasut u32 data; 148eb91ecc9SMarek Vasut 149eb91ecc9SMarek Vasut data = get_unaligned_be32(touchdata + 1 + (finger * 4) + 0); 150eb91ecc9SMarek Vasut if (data == 0xffffffff) /* Finger up */ 151eb91ecc9SMarek Vasut return false; 152eb91ecc9SMarek Vasut 153eb91ecc9SMarek Vasut *x = ((touchdata[1 + (finger * 4) + 0] & 0xf0) << 4) | 154eb91ecc9SMarek Vasut touchdata[1 + (finger * 4) + 1]; 155eb91ecc9SMarek Vasut *y = ((touchdata[1 + (finger * 4) + 0] & 0x0f) << 8) | 156eb91ecc9SMarek Vasut touchdata[1 + (finger * 4) + 2]; 157eb91ecc9SMarek Vasut 158eb91ecc9SMarek Vasut return true; 159eb91ecc9SMarek Vasut } 160eb91ecc9SMarek Vasut 161ef536abdSDmitry Torokhov static bool ili211x_decline_polling(const u8 *data, bool touch) 162ef536abdSDmitry Torokhov { 163ef536abdSDmitry Torokhov return false; 164ef536abdSDmitry Torokhov } 165ef536abdSDmitry Torokhov 166ef536abdSDmitry Torokhov static const struct ili2xxx_chip ili211x_chip = { 167ef536abdSDmitry Torokhov .read_reg = ili210x_read_reg, 168ef536abdSDmitry Torokhov .get_touch_data = ili211x_read_touch_data, 169ef536abdSDmitry Torokhov .parse_touch_data = ili211x_touchdata_to_coords, 170ef536abdSDmitry Torokhov .continue_polling = ili211x_decline_polling, 171ef536abdSDmitry Torokhov .max_touches = 10, 172b32fbeaeSSven Van Asbroeck .resolution = 2048, 173ef536abdSDmitry Torokhov }; 174ef536abdSDmitry Torokhov 175d0c5e7d4SLuca Weiss static bool ili212x_touchdata_to_coords(const u8 *touchdata, 176d0c5e7d4SLuca Weiss unsigned int finger, 17760159e9eSMarek Vasut unsigned int *x, unsigned int *y, 17860159e9eSMarek Vasut unsigned int *z) 179d0c5e7d4SLuca Weiss { 180d0c5e7d4SLuca Weiss u16 val; 181d0c5e7d4SLuca Weiss 182d0c5e7d4SLuca Weiss val = get_unaligned_be16(touchdata + 3 + (finger * 5) + 0); 183d0c5e7d4SLuca Weiss if (!(val & BIT(15))) /* Touch indication */ 184d0c5e7d4SLuca Weiss return false; 185d0c5e7d4SLuca Weiss 186d0c5e7d4SLuca Weiss *x = val & 0x3fff; 187d0c5e7d4SLuca Weiss *y = get_unaligned_be16(touchdata + 3 + (finger * 5) + 2); 188d0c5e7d4SLuca Weiss 189d0c5e7d4SLuca Weiss return true; 190d0c5e7d4SLuca Weiss } 191d0c5e7d4SLuca Weiss 192d0c5e7d4SLuca Weiss static bool ili212x_check_continue_polling(const u8 *data, bool touch) 193d0c5e7d4SLuca Weiss { 194d0c5e7d4SLuca Weiss return touch; 195d0c5e7d4SLuca Weiss } 196d0c5e7d4SLuca Weiss 197d0c5e7d4SLuca Weiss static const struct ili2xxx_chip ili212x_chip = { 198d0c5e7d4SLuca Weiss .read_reg = ili210x_read_reg, 199d0c5e7d4SLuca Weiss .get_touch_data = ili210x_read_touch_data, 200d0c5e7d4SLuca Weiss .parse_touch_data = ili212x_touchdata_to_coords, 201d0c5e7d4SLuca Weiss .continue_polling = ili212x_check_continue_polling, 202d0c5e7d4SLuca Weiss .max_touches = 10, 203d0c5e7d4SLuca Weiss .has_calibrate_reg = true, 204d0c5e7d4SLuca Weiss }; 205d0c5e7d4SLuca Weiss 206ef536abdSDmitry Torokhov static int ili251x_read_reg(struct i2c_client *client, 207ef536abdSDmitry Torokhov u8 reg, void *buf, size_t len) 208ef536abdSDmitry Torokhov { 209ef536abdSDmitry Torokhov int error; 210ef536abdSDmitry Torokhov int ret; 211ef536abdSDmitry Torokhov 212ef536abdSDmitry Torokhov ret = i2c_master_send(client, ®, 1); 213ef536abdSDmitry Torokhov if (ret == 1) { 214ef536abdSDmitry Torokhov usleep_range(5000, 5500); 215ef536abdSDmitry Torokhov 216ef536abdSDmitry Torokhov ret = i2c_master_recv(client, buf, len); 217ef536abdSDmitry Torokhov if (ret == len) 218ef536abdSDmitry Torokhov return 0; 219ef536abdSDmitry Torokhov } 220ef536abdSDmitry Torokhov 221ef536abdSDmitry Torokhov error = ret < 0 ? ret : -EIO; 222ef536abdSDmitry Torokhov dev_err(&client->dev, "%s failed: %d\n", __func__, error); 223ef536abdSDmitry Torokhov return ret; 224ef536abdSDmitry Torokhov } 225ef536abdSDmitry Torokhov 226ef536abdSDmitry Torokhov static int ili251x_read_touch_data(struct i2c_client *client, u8 *data) 227ef536abdSDmitry Torokhov { 228ef536abdSDmitry Torokhov int error; 229ef536abdSDmitry Torokhov 230ef536abdSDmitry Torokhov error = ili251x_read_reg(client, REG_TOUCHDATA, 231ef536abdSDmitry Torokhov data, ILI251X_DATA_SIZE1); 232ef536abdSDmitry Torokhov if (!error && data[0] == 2) { 233ef536abdSDmitry Torokhov error = i2c_master_recv(client, data + ILI251X_DATA_SIZE1, 234ef536abdSDmitry Torokhov ILI251X_DATA_SIZE2); 235ef536abdSDmitry Torokhov if (error >= 0 && error != ILI251X_DATA_SIZE2) 236ef536abdSDmitry Torokhov error = -EIO; 237ef536abdSDmitry Torokhov } 238ef536abdSDmitry Torokhov 239ef536abdSDmitry Torokhov return error; 240ef536abdSDmitry Torokhov } 241ef536abdSDmitry Torokhov 242ef536abdSDmitry Torokhov static bool ili251x_touchdata_to_coords(const u8 *touchdata, 24349588917SMarek Vasut unsigned int finger, 24460159e9eSMarek Vasut unsigned int *x, unsigned int *y, 24560159e9eSMarek Vasut unsigned int *z) 24649588917SMarek Vasut { 247ef536abdSDmitry Torokhov u16 val; 248ef536abdSDmitry Torokhov 249ef536abdSDmitry Torokhov val = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0); 250ef536abdSDmitry Torokhov if (!(val & BIT(15))) /* Touch indication */ 25149588917SMarek Vasut return false; 25249588917SMarek Vasut 253ef536abdSDmitry Torokhov *x = val & 0x3fff; 25449588917SMarek Vasut *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2); 25560159e9eSMarek Vasut *z = touchdata[1 + (finger * 5) + 4]; 25649588917SMarek Vasut 25749588917SMarek Vasut return true; 25849588917SMarek Vasut } 25949588917SMarek Vasut 260ef536abdSDmitry Torokhov static bool ili251x_check_continue_polling(const u8 *data, bool touch) 261ef536abdSDmitry Torokhov { 262ef536abdSDmitry Torokhov return touch; 263ef536abdSDmitry Torokhov } 264ef536abdSDmitry Torokhov 265ef536abdSDmitry Torokhov static const struct ili2xxx_chip ili251x_chip = { 266ef536abdSDmitry Torokhov .read_reg = ili251x_read_reg, 267ef536abdSDmitry Torokhov .get_touch_data = ili251x_read_touch_data, 268ef536abdSDmitry Torokhov .parse_touch_data = ili251x_touchdata_to_coords, 269ef536abdSDmitry Torokhov .continue_polling = ili251x_check_continue_polling, 270ef536abdSDmitry Torokhov .max_touches = 10, 271cc12ba18SSven Van Asbroeck .has_calibrate_reg = true, 272*235300edSMarek Vasut .has_firmware_proto = true, 27360159e9eSMarek Vasut .has_pressure_reg = true, 274ef536abdSDmitry Torokhov }; 275ef536abdSDmitry Torokhov 276e3559442SMarek Vasut static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) 277e3559442SMarek Vasut { 278e3559442SMarek Vasut struct input_dev *input = priv->input; 2795c6a7a62SOlivier Sobrie int i; 280ef536abdSDmitry Torokhov bool contact = false, touch; 28160159e9eSMarek Vasut unsigned int x = 0, y = 0, z = 0; 2825c6a7a62SOlivier Sobrie 283ef536abdSDmitry Torokhov for (i = 0; i < priv->chip->max_touches; i++) { 28460159e9eSMarek Vasut touch = priv->chip->parse_touch_data(touchdata, i, &x, &y, &z); 28549588917SMarek Vasut 286f67cc3e9SMarek Vasut input_mt_slot(input, i); 287ef536abdSDmitry Torokhov if (input_mt_report_slot_state(input, MT_TOOL_FINGER, touch)) { 288ef536abdSDmitry Torokhov touchscreen_report_pos(input, &priv->prop, x, y, true); 28960159e9eSMarek Vasut if (priv->chip->has_pressure_reg) 29060159e9eSMarek Vasut input_report_abs(input, ABS_MT_PRESSURE, z); 291ef536abdSDmitry Torokhov contact = true; 292ef536abdSDmitry Torokhov } 2935c6a7a62SOlivier Sobrie } 2945c6a7a62SOlivier Sobrie 2955c6a7a62SOlivier Sobrie input_mt_report_pointer_emulation(input, false); 2965c6a7a62SOlivier Sobrie input_sync(input); 297e3559442SMarek Vasut 29849588917SMarek Vasut return contact; 2995c6a7a62SOlivier Sobrie } 3005c6a7a62SOlivier Sobrie 30171f8e38aSDmitry Torokhov static irqreturn_t ili210x_irq(int irq, void *irq_data) 3025c6a7a62SOlivier Sobrie { 30371f8e38aSDmitry Torokhov struct ili210x *priv = irq_data; 3045c6a7a62SOlivier Sobrie struct i2c_client *client = priv->client; 305ef536abdSDmitry Torokhov const struct ili2xxx_chip *chip = priv->chip; 306ef536abdSDmitry Torokhov u8 touchdata[ILI210X_DATA_SIZE] = { 0 }; 307ef536abdSDmitry Torokhov bool keep_polling; 308e3559442SMarek Vasut bool touch; 30971f8e38aSDmitry Torokhov int error; 3105c6a7a62SOlivier Sobrie 31171f8e38aSDmitry Torokhov do { 312ef536abdSDmitry Torokhov error = chip->get_touch_data(client, touchdata); 3135c6a7a62SOlivier Sobrie if (error) { 3145c6a7a62SOlivier Sobrie dev_err(&client->dev, 315ef536abdSDmitry Torokhov "Unable to get touch data: %d\n", error); 31671f8e38aSDmitry Torokhov break; 3175c6a7a62SOlivier Sobrie } 3185c6a7a62SOlivier Sobrie 319e3559442SMarek Vasut touch = ili210x_report_events(priv, touchdata); 320ef536abdSDmitry Torokhov keep_polling = chip->continue_polling(touchdata, touch); 321ef536abdSDmitry Torokhov if (keep_polling) 32271f8e38aSDmitry Torokhov msleep(ILI2XXX_POLL_PERIOD); 323ef536abdSDmitry Torokhov } while (!priv->stop && keep_polling); 3245c6a7a62SOlivier Sobrie 3255c6a7a62SOlivier Sobrie return IRQ_HANDLED; 3265c6a7a62SOlivier Sobrie } 3275c6a7a62SOlivier Sobrie 328*235300edSMarek Vasut static int ili251x_firmware_update_resolution(struct device *dev) 329*235300edSMarek Vasut { 330*235300edSMarek Vasut struct i2c_client *client = to_i2c_client(dev); 331*235300edSMarek Vasut struct ili210x *priv = i2c_get_clientdata(client); 332*235300edSMarek Vasut u16 resx, resy; 333*235300edSMarek Vasut u8 rs[10]; 334*235300edSMarek Vasut int error; 335*235300edSMarek Vasut 336*235300edSMarek Vasut /* The firmware update blob might have changed the resolution. */ 337*235300edSMarek Vasut error = priv->chip->read_reg(client, REG_PANEL_INFO, &rs, sizeof(rs)); 338*235300edSMarek Vasut if (error) 339*235300edSMarek Vasut return error; 340*235300edSMarek Vasut 341*235300edSMarek Vasut resx = le16_to_cpup((__le16 *)rs); 342*235300edSMarek Vasut resy = le16_to_cpup((__le16 *)(rs + 2)); 343*235300edSMarek Vasut 344*235300edSMarek Vasut /* The value reported by the firmware is invalid. */ 345*235300edSMarek Vasut if (!resx || resx == 0xffff || !resy || resy == 0xffff) 346*235300edSMarek Vasut return -EINVAL; 347*235300edSMarek Vasut 348*235300edSMarek Vasut input_abs_set_max(priv->input, ABS_X, resx - 1); 349*235300edSMarek Vasut input_abs_set_max(priv->input, ABS_Y, resy - 1); 350*235300edSMarek Vasut input_abs_set_max(priv->input, ABS_MT_POSITION_X, resx - 1); 351*235300edSMarek Vasut input_abs_set_max(priv->input, ABS_MT_POSITION_Y, resy - 1); 352*235300edSMarek Vasut 353*235300edSMarek Vasut return 0; 354*235300edSMarek Vasut } 355*235300edSMarek Vasut 356*235300edSMarek Vasut static int ili251x_firmware_update_cached_state(struct device *dev) 357*235300edSMarek Vasut { 358*235300edSMarek Vasut struct i2c_client *client = to_i2c_client(dev); 359*235300edSMarek Vasut struct ili210x *priv = i2c_get_clientdata(client); 360*235300edSMarek Vasut int error; 361*235300edSMarek Vasut 362*235300edSMarek Vasut if (!priv->chip->has_firmware_proto) 363*235300edSMarek Vasut return 0; 364*235300edSMarek Vasut 365*235300edSMarek Vasut /* Wait for firmware to boot and stabilize itself. */ 366*235300edSMarek Vasut msleep(200); 367*235300edSMarek Vasut 368*235300edSMarek Vasut /* Firmware does report valid information. */ 369*235300edSMarek Vasut error = ili251x_firmware_update_resolution(dev); 370*235300edSMarek Vasut if (error) 371*235300edSMarek Vasut return error; 372*235300edSMarek Vasut 373*235300edSMarek Vasut return 0; 374*235300edSMarek Vasut } 375*235300edSMarek Vasut 3765c6a7a62SOlivier Sobrie static ssize_t ili210x_calibrate(struct device *dev, 3775c6a7a62SOlivier Sobrie struct device_attribute *attr, 3785c6a7a62SOlivier Sobrie const char *buf, size_t count) 3795c6a7a62SOlivier Sobrie { 3805c6a7a62SOlivier Sobrie struct i2c_client *client = to_i2c_client(dev); 3815c6a7a62SOlivier Sobrie struct ili210x *priv = i2c_get_clientdata(client); 3825c6a7a62SOlivier Sobrie unsigned long calibrate; 3835c6a7a62SOlivier Sobrie int rc; 3845c6a7a62SOlivier Sobrie u8 cmd = REG_CALIBRATE; 3855c6a7a62SOlivier Sobrie 3865c6a7a62SOlivier Sobrie if (kstrtoul(buf, 10, &calibrate)) 3875c6a7a62SOlivier Sobrie return -EINVAL; 3885c6a7a62SOlivier Sobrie 3895c6a7a62SOlivier Sobrie if (calibrate > 1) 3905c6a7a62SOlivier Sobrie return -EINVAL; 3915c6a7a62SOlivier Sobrie 3925c6a7a62SOlivier Sobrie if (calibrate) { 3935c6a7a62SOlivier Sobrie rc = i2c_master_send(priv->client, &cmd, sizeof(cmd)); 3945c6a7a62SOlivier Sobrie if (rc != sizeof(cmd)) 3955c6a7a62SOlivier Sobrie return -EIO; 3965c6a7a62SOlivier Sobrie } 3975c6a7a62SOlivier Sobrie 3985c6a7a62SOlivier Sobrie return count; 3995c6a7a62SOlivier Sobrie } 400b27c0d0cSDmitry Torokhov static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate); 4015c6a7a62SOlivier Sobrie 4025c6a7a62SOlivier Sobrie static struct attribute *ili210x_attributes[] = { 4035c6a7a62SOlivier Sobrie &dev_attr_calibrate.attr, 4045c6a7a62SOlivier Sobrie NULL, 4055c6a7a62SOlivier Sobrie }; 4065c6a7a62SOlivier Sobrie 407cc12ba18SSven Van Asbroeck static umode_t ili210x_calibrate_visible(struct kobject *kobj, 408cc12ba18SSven Van Asbroeck struct attribute *attr, int index) 409cc12ba18SSven Van Asbroeck { 410cc12ba18SSven Van Asbroeck struct device *dev = kobj_to_dev(kobj); 411cc12ba18SSven Van Asbroeck struct i2c_client *client = to_i2c_client(dev); 412cc12ba18SSven Van Asbroeck struct ili210x *priv = i2c_get_clientdata(client); 413cc12ba18SSven Van Asbroeck 414fbd1ec00SLuca Weiss return priv->chip->has_calibrate_reg ? attr->mode : 0; 415cc12ba18SSven Van Asbroeck } 416cc12ba18SSven Van Asbroeck 4175c6a7a62SOlivier Sobrie static const struct attribute_group ili210x_attr_group = { 4185c6a7a62SOlivier Sobrie .attrs = ili210x_attributes, 419cc12ba18SSven Van Asbroeck .is_visible = ili210x_calibrate_visible, 4205c6a7a62SOlivier Sobrie }; 4215c6a7a62SOlivier Sobrie 422201f3c80SMarek Vasut static void ili210x_power_down(void *data) 423201f3c80SMarek Vasut { 424201f3c80SMarek Vasut struct gpio_desc *reset_gpio = data; 425201f3c80SMarek Vasut 426201f3c80SMarek Vasut gpiod_set_value_cansleep(reset_gpio, 1); 427201f3c80SMarek Vasut } 428201f3c80SMarek Vasut 42971f8e38aSDmitry Torokhov static void ili210x_stop(void *data) 4301bdec5d9SMarek Vasut { 4311bdec5d9SMarek Vasut struct ili210x *priv = data; 4321bdec5d9SMarek Vasut 43371f8e38aSDmitry Torokhov /* Tell ISR to quit even if there is a contact. */ 43471f8e38aSDmitry Torokhov priv->stop = true; 4351bdec5d9SMarek Vasut } 4361bdec5d9SMarek Vasut 4375298cc4cSBill Pemberton static int ili210x_i2c_probe(struct i2c_client *client, 4385c6a7a62SOlivier Sobrie const struct i2c_device_id *id) 4395c6a7a62SOlivier Sobrie { 4405c6a7a62SOlivier Sobrie struct device *dev = &client->dev; 441ef536abdSDmitry Torokhov const struct ili2xxx_chip *chip; 4425c6a7a62SOlivier Sobrie struct ili210x *priv; 443201f3c80SMarek Vasut struct gpio_desc *reset_gpio; 4445c6a7a62SOlivier Sobrie struct input_dev *input; 4455c6a7a62SOlivier Sobrie int error; 446b32fbeaeSSven Van Asbroeck unsigned int max_xy; 4475c6a7a62SOlivier Sobrie 4485c6a7a62SOlivier Sobrie dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver"); 4495c6a7a62SOlivier Sobrie 450ef536abdSDmitry Torokhov chip = device_get_match_data(dev); 451ef536abdSDmitry Torokhov if (!chip && id) 452ef536abdSDmitry Torokhov chip = (const struct ili2xxx_chip *)id->driver_data; 453ef536abdSDmitry Torokhov if (!chip) { 454ef536abdSDmitry Torokhov dev_err(&client->dev, "unknown device model\n"); 455ef536abdSDmitry Torokhov return -ENODEV; 456ef536abdSDmitry Torokhov } 457ef536abdSDmitry Torokhov 4585c6a7a62SOlivier Sobrie if (client->irq <= 0) { 4595c6a7a62SOlivier Sobrie dev_err(dev, "No IRQ!\n"); 4605c6a7a62SOlivier Sobrie return -EINVAL; 4615c6a7a62SOlivier Sobrie } 4625c6a7a62SOlivier Sobrie 463201f3c80SMarek Vasut reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 464201f3c80SMarek Vasut if (IS_ERR(reset_gpio)) 465201f3c80SMarek Vasut return PTR_ERR(reset_gpio); 466201f3c80SMarek Vasut 467201f3c80SMarek Vasut if (reset_gpio) { 468201f3c80SMarek Vasut error = devm_add_action_or_reset(dev, ili210x_power_down, 469201f3c80SMarek Vasut reset_gpio); 470201f3c80SMarek Vasut if (error) 471201f3c80SMarek Vasut return error; 472201f3c80SMarek Vasut 473201f3c80SMarek Vasut usleep_range(50, 100); 474201f3c80SMarek Vasut gpiod_set_value_cansleep(reset_gpio, 0); 475201f3c80SMarek Vasut msleep(100); 476201f3c80SMarek Vasut } 477201f3c80SMarek Vasut 47812294577SMarek Vasut priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 47912294577SMarek Vasut if (!priv) 48012294577SMarek Vasut return -ENOMEM; 48112294577SMarek Vasut 48212294577SMarek Vasut input = devm_input_allocate_device(dev); 48312294577SMarek Vasut if (!input) 48412294577SMarek Vasut return -ENOMEM; 48512294577SMarek Vasut 48612294577SMarek Vasut priv->client = client; 48712294577SMarek Vasut priv->input = input; 48812294577SMarek Vasut priv->reset_gpio = reset_gpio; 489ef536abdSDmitry Torokhov priv->chip = chip; 49012294577SMarek Vasut i2c_set_clientdata(client, priv); 49112294577SMarek Vasut 4925c6a7a62SOlivier Sobrie /* Setup input device */ 4935c6a7a62SOlivier Sobrie input->name = "ILI210x Touchscreen"; 4945c6a7a62SOlivier Sobrie input->id.bustype = BUS_I2C; 4955c6a7a62SOlivier Sobrie 4965c6a7a62SOlivier Sobrie /* Multi touch */ 497b32fbeaeSSven Van Asbroeck max_xy = (chip->resolution ?: SZ_64K) - 1; 498b32fbeaeSSven Van Asbroeck input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_xy, 0, 0); 499b32fbeaeSSven Van Asbroeck input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_xy, 0, 0); 50060159e9eSMarek Vasut if (priv->chip->has_pressure_reg) 50160159e9eSMarek Vasut input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xa, 0, 0); 502*235300edSMarek Vasut error = ili251x_firmware_update_cached_state(dev); 503*235300edSMarek Vasut if (error) { 504*235300edSMarek Vasut dev_err(dev, "Unable to cache firmware information, err: %d\n", 505*235300edSMarek Vasut error); 506*235300edSMarek Vasut return error; 507*235300edSMarek Vasut } 508f67cc3e9SMarek Vasut touchscreen_parse_properties(input, true, &priv->prop); 50943f06a4cSDmitry Torokhov 510ef536abdSDmitry Torokhov error = input_mt_init_slots(input, priv->chip->max_touches, 511ef536abdSDmitry Torokhov INPUT_MT_DIRECT); 51243f06a4cSDmitry Torokhov if (error) { 51343f06a4cSDmitry Torokhov dev_err(dev, "Unable to set up slots, err: %d\n", error); 51443f06a4cSDmitry Torokhov return error; 51543f06a4cSDmitry Torokhov } 5165c6a7a62SOlivier Sobrie 51771f8e38aSDmitry Torokhov error = devm_request_threaded_irq(dev, client->irq, NULL, ili210x_irq, 51871f8e38aSDmitry Torokhov IRQF_ONESHOT, client->name, priv); 5195c6a7a62SOlivier Sobrie if (error) { 5205c6a7a62SOlivier Sobrie dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n", 5215c6a7a62SOlivier Sobrie error); 5221bdec5d9SMarek Vasut return error; 5235c6a7a62SOlivier Sobrie } 5245c6a7a62SOlivier Sobrie 52571f8e38aSDmitry Torokhov error = devm_add_action_or_reset(dev, ili210x_stop, priv); 52671f8e38aSDmitry Torokhov if (error) 52771f8e38aSDmitry Torokhov return error; 52871f8e38aSDmitry Torokhov 529576057bfSDmitry Torokhov error = devm_device_add_group(dev, &ili210x_attr_group); 5305c6a7a62SOlivier Sobrie if (error) { 5315c6a7a62SOlivier Sobrie dev_err(dev, "Unable to create sysfs attributes, err: %d\n", 5325c6a7a62SOlivier Sobrie error); 5331bdec5d9SMarek Vasut return error; 5345c6a7a62SOlivier Sobrie } 5355c6a7a62SOlivier Sobrie 5365c6a7a62SOlivier Sobrie error = input_register_device(priv->input); 5375c6a7a62SOlivier Sobrie if (error) { 538971bd8faSMasanari Iida dev_err(dev, "Cannot register input device, err: %d\n", error); 539576057bfSDmitry Torokhov return error; 5405c6a7a62SOlivier Sobrie } 5415c6a7a62SOlivier Sobrie 5425c6a7a62SOlivier Sobrie return 0; 5435c6a7a62SOlivier Sobrie } 5445c6a7a62SOlivier Sobrie 5455c6a7a62SOlivier Sobrie static const struct i2c_device_id ili210x_i2c_id[] = { 546ef536abdSDmitry Torokhov { "ili210x", (long)&ili210x_chip }, 547ef536abdSDmitry Torokhov { "ili2117", (long)&ili211x_chip }, 548d0c5e7d4SLuca Weiss { "ili2120", (long)&ili212x_chip }, 549ef536abdSDmitry Torokhov { "ili251x", (long)&ili251x_chip }, 5505c6a7a62SOlivier Sobrie { } 5515c6a7a62SOlivier Sobrie }; 5525c6a7a62SOlivier Sobrie MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); 5535c6a7a62SOlivier Sobrie 554c5d0e4b5SMarek Vasut static const struct of_device_id ili210x_dt_ids[] = { 555ef536abdSDmitry Torokhov { .compatible = "ilitek,ili210x", .data = &ili210x_chip }, 556ef536abdSDmitry Torokhov { .compatible = "ilitek,ili2117", .data = &ili211x_chip }, 557d0c5e7d4SLuca Weiss { .compatible = "ilitek,ili2120", .data = &ili212x_chip }, 558ef536abdSDmitry Torokhov { .compatible = "ilitek,ili251x", .data = &ili251x_chip }, 559ef536abdSDmitry Torokhov { } 560c5d0e4b5SMarek Vasut }; 561c5d0e4b5SMarek Vasut MODULE_DEVICE_TABLE(of, ili210x_dt_ids); 562c5d0e4b5SMarek Vasut 5635c6a7a62SOlivier Sobrie static struct i2c_driver ili210x_ts_driver = { 5645c6a7a62SOlivier Sobrie .driver = { 5655c6a7a62SOlivier Sobrie .name = "ili210x_i2c", 566c5d0e4b5SMarek Vasut .of_match_table = ili210x_dt_ids, 5675c6a7a62SOlivier Sobrie }, 5685c6a7a62SOlivier Sobrie .id_table = ili210x_i2c_id, 5695c6a7a62SOlivier Sobrie .probe = ili210x_i2c_probe, 5705c6a7a62SOlivier Sobrie }; 5715c6a7a62SOlivier Sobrie 5725c6a7a62SOlivier Sobrie module_i2c_driver(ili210x_ts_driver); 5735c6a7a62SOlivier Sobrie 5745c6a7a62SOlivier Sobrie MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>"); 5755c6a7a62SOlivier Sobrie MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver"); 5765c6a7a62SOlivier Sobrie MODULE_LICENSE("GPL"); 577