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> 1171f8e38aSDmitry Torokhov #include <linux/slab.h> 12e3559442SMarek Vasut #include <asm/unaligned.h> 135c6a7a62SOlivier Sobrie 1471f8e38aSDmitry Torokhov #define ILI2XXX_POLL_PERIOD 20 155c6a7a62SOlivier Sobrie 16*ef536abdSDmitry Torokhov #define ILI210X_DATA_SIZE 64 17*ef536abdSDmitry Torokhov #define ILI211X_DATA_SIZE 43 18*ef536abdSDmitry Torokhov #define ILI251X_DATA_SIZE1 31 19*ef536abdSDmitry Torokhov #define ILI251X_DATA_SIZE2 20 20*ef536abdSDmitry Torokhov 215c6a7a62SOlivier Sobrie /* Touchscreen commands */ 225c6a7a62SOlivier Sobrie #define REG_TOUCHDATA 0x10 235c6a7a62SOlivier Sobrie #define REG_PANEL_INFO 0x20 245c6a7a62SOlivier Sobrie #define REG_FIRMWARE_VERSION 0x40 255c6a7a62SOlivier Sobrie #define REG_CALIBRATE 0xcc 265c6a7a62SOlivier Sobrie 275c6a7a62SOlivier Sobrie struct firmware_version { 285c6a7a62SOlivier Sobrie u8 id; 295c6a7a62SOlivier Sobrie u8 major; 305c6a7a62SOlivier Sobrie u8 minor; 315c6a7a62SOlivier Sobrie } __packed; 325c6a7a62SOlivier Sobrie 33*ef536abdSDmitry Torokhov struct ili2xxx_chip { 34*ef536abdSDmitry Torokhov int (*read_reg)(struct i2c_client *client, u8 reg, 35*ef536abdSDmitry Torokhov void *buf, size_t len); 36*ef536abdSDmitry Torokhov int (*get_touch_data)(struct i2c_client *client, u8 *data); 37*ef536abdSDmitry Torokhov bool (*parse_touch_data)(const u8 *data, unsigned int finger, 38*ef536abdSDmitry Torokhov unsigned int *x, unsigned int *y); 39*ef536abdSDmitry Torokhov bool (*continue_polling)(const u8 *data, bool touch); 40*ef536abdSDmitry Torokhov unsigned int max_touches; 4149588917SMarek Vasut }; 4249588917SMarek Vasut 435c6a7a62SOlivier Sobrie struct ili210x { 445c6a7a62SOlivier Sobrie struct i2c_client *client; 455c6a7a62SOlivier Sobrie struct input_dev *input; 46201f3c80SMarek Vasut struct gpio_desc *reset_gpio; 47f67cc3e9SMarek Vasut struct touchscreen_properties prop; 48*ef536abdSDmitry Torokhov const struct ili2xxx_chip *chip; 4971f8e38aSDmitry Torokhov bool stop; 505c6a7a62SOlivier Sobrie }; 515c6a7a62SOlivier Sobrie 52*ef536abdSDmitry Torokhov static int ili210x_read_reg(struct i2c_client *client, 53*ef536abdSDmitry Torokhov u8 reg, void *buf, size_t len) 545c6a7a62SOlivier Sobrie { 55*ef536abdSDmitry Torokhov struct i2c_msg msg[] = { 565c6a7a62SOlivier Sobrie { 575c6a7a62SOlivier Sobrie .addr = client->addr, 585c6a7a62SOlivier Sobrie .flags = 0, 595c6a7a62SOlivier Sobrie .len = 1, 605c6a7a62SOlivier Sobrie .buf = ®, 615c6a7a62SOlivier Sobrie }, 625c6a7a62SOlivier Sobrie { 635c6a7a62SOlivier Sobrie .addr = client->addr, 645c6a7a62SOlivier Sobrie .flags = I2C_M_RD, 655c6a7a62SOlivier Sobrie .len = len, 665c6a7a62SOlivier Sobrie .buf = buf, 675c6a7a62SOlivier Sobrie } 685c6a7a62SOlivier Sobrie }; 69*ef536abdSDmitry Torokhov int error, ret; 705c6a7a62SOlivier Sobrie 71*ef536abdSDmitry Torokhov ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); 72*ef536abdSDmitry Torokhov if (ret != ARRAY_SIZE(msg)) { 73*ef536abdSDmitry Torokhov error = ret < 0 ? ret : -EIO; 74*ef536abdSDmitry Torokhov dev_err(&client->dev, "%s failed: %d\n", __func__, error); 75*ef536abdSDmitry Torokhov return error; 7649588917SMarek Vasut } 7749588917SMarek Vasut 7849588917SMarek Vasut return 0; 7949588917SMarek Vasut } 8049588917SMarek Vasut 81*ef536abdSDmitry Torokhov static int ili210x_read_touch_data(struct i2c_client *client, u8 *data) 8249588917SMarek Vasut { 83*ef536abdSDmitry Torokhov return ili210x_read_reg(client, REG_TOUCHDATA, 84*ef536abdSDmitry Torokhov data, ILI210X_DATA_SIZE); 8549588917SMarek Vasut } 865c6a7a62SOlivier Sobrie 87*ef536abdSDmitry Torokhov static bool ili210x_touchdata_to_coords(const u8 *touchdata, 88e3559442SMarek Vasut unsigned int finger, 89e3559442SMarek Vasut unsigned int *x, unsigned int *y) 905c6a7a62SOlivier Sobrie { 91e3559442SMarek Vasut 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 100*ef536abdSDmitry Torokhov static bool ili210x_check_continue_polling(const u8 *data, bool touch) 101*ef536abdSDmitry Torokhov { 102*ef536abdSDmitry Torokhov return data[0] & 0xf3; 103*ef536abdSDmitry Torokhov } 104*ef536abdSDmitry Torokhov 105*ef536abdSDmitry Torokhov static const struct ili2xxx_chip ili210x_chip = { 106*ef536abdSDmitry Torokhov .read_reg = ili210x_read_reg, 107*ef536abdSDmitry Torokhov .get_touch_data = ili210x_read_touch_data, 108*ef536abdSDmitry Torokhov .parse_touch_data = ili210x_touchdata_to_coords, 109*ef536abdSDmitry Torokhov .continue_polling = ili210x_check_continue_polling, 110*ef536abdSDmitry Torokhov .max_touches = 2, 111*ef536abdSDmitry Torokhov }; 112*ef536abdSDmitry Torokhov 113*ef536abdSDmitry Torokhov static int ili211x_read_touch_data(struct i2c_client *client, u8 *data) 114*ef536abdSDmitry Torokhov { 115*ef536abdSDmitry Torokhov s16 sum = 0; 116*ef536abdSDmitry Torokhov int error; 117*ef536abdSDmitry Torokhov int ret; 118*ef536abdSDmitry Torokhov int i; 119*ef536abdSDmitry Torokhov 120*ef536abdSDmitry Torokhov ret = i2c_master_recv(client, data, ILI211X_DATA_SIZE); 121*ef536abdSDmitry Torokhov if (ret != ILI211X_DATA_SIZE) { 122*ef536abdSDmitry Torokhov error = ret < 0 ? ret : -EIO; 123*ef536abdSDmitry Torokhov dev_err(&client->dev, "%s failed: %d\n", __func__, error); 124*ef536abdSDmitry Torokhov return error; 125*ef536abdSDmitry Torokhov } 126*ef536abdSDmitry Torokhov 127*ef536abdSDmitry Torokhov /* This chip uses custom checksum at the end of data */ 128*ef536abdSDmitry Torokhov for (i = 0; i < ILI211X_DATA_SIZE - 1; i++) 129*ef536abdSDmitry Torokhov sum = (sum + data[i]) & 0xff; 130*ef536abdSDmitry Torokhov 131*ef536abdSDmitry Torokhov if ((-sum & 0xff) != data[ILI211X_DATA_SIZE - 1]) { 132*ef536abdSDmitry Torokhov dev_err(&client->dev, 133*ef536abdSDmitry Torokhov "CRC error (crc=0x%02x expected=0x%02x)\n", 134*ef536abdSDmitry Torokhov sum, data[ILI211X_DATA_SIZE - 1]); 135*ef536abdSDmitry Torokhov return -EIO; 136*ef536abdSDmitry Torokhov } 137*ef536abdSDmitry Torokhov 138*ef536abdSDmitry Torokhov return 0; 139*ef536abdSDmitry Torokhov } 140*ef536abdSDmitry Torokhov 141*ef536abdSDmitry Torokhov static bool ili211x_touchdata_to_coords(const u8 *touchdata, 142eb91ecc9SMarek Vasut unsigned int finger, 143eb91ecc9SMarek Vasut unsigned int *x, unsigned int *y) 144eb91ecc9SMarek Vasut { 145eb91ecc9SMarek Vasut u32 data; 146eb91ecc9SMarek Vasut 147eb91ecc9SMarek Vasut data = get_unaligned_be32(touchdata + 1 + (finger * 4) + 0); 148eb91ecc9SMarek Vasut if (data == 0xffffffff) /* Finger up */ 149eb91ecc9SMarek Vasut return false; 150eb91ecc9SMarek Vasut 151eb91ecc9SMarek Vasut *x = ((touchdata[1 + (finger * 4) + 0] & 0xf0) << 4) | 152eb91ecc9SMarek Vasut touchdata[1 + (finger * 4) + 1]; 153eb91ecc9SMarek Vasut *y = ((touchdata[1 + (finger * 4) + 0] & 0x0f) << 8) | 154eb91ecc9SMarek Vasut touchdata[1 + (finger * 4) + 2]; 155eb91ecc9SMarek Vasut 156eb91ecc9SMarek Vasut return true; 157eb91ecc9SMarek Vasut } 158eb91ecc9SMarek Vasut 159*ef536abdSDmitry Torokhov static bool ili211x_decline_polling(const u8 *data, bool touch) 160*ef536abdSDmitry Torokhov { 161*ef536abdSDmitry Torokhov return false; 162*ef536abdSDmitry Torokhov } 163*ef536abdSDmitry Torokhov 164*ef536abdSDmitry Torokhov static const struct ili2xxx_chip ili211x_chip = { 165*ef536abdSDmitry Torokhov .read_reg = ili210x_read_reg, 166*ef536abdSDmitry Torokhov .get_touch_data = ili211x_read_touch_data, 167*ef536abdSDmitry Torokhov .parse_touch_data = ili211x_touchdata_to_coords, 168*ef536abdSDmitry Torokhov .continue_polling = ili211x_decline_polling, 169*ef536abdSDmitry Torokhov .max_touches = 10, 170*ef536abdSDmitry Torokhov }; 171*ef536abdSDmitry Torokhov 172*ef536abdSDmitry Torokhov static int ili251x_read_reg(struct i2c_client *client, 173*ef536abdSDmitry Torokhov u8 reg, void *buf, size_t len) 174*ef536abdSDmitry Torokhov { 175*ef536abdSDmitry Torokhov int error; 176*ef536abdSDmitry Torokhov int ret; 177*ef536abdSDmitry Torokhov 178*ef536abdSDmitry Torokhov ret = i2c_master_send(client, ®, 1); 179*ef536abdSDmitry Torokhov if (ret == 1) { 180*ef536abdSDmitry Torokhov usleep_range(5000, 5500); 181*ef536abdSDmitry Torokhov 182*ef536abdSDmitry Torokhov ret = i2c_master_recv(client, buf, len); 183*ef536abdSDmitry Torokhov if (ret == len) 184*ef536abdSDmitry Torokhov return 0; 185*ef536abdSDmitry Torokhov } 186*ef536abdSDmitry Torokhov 187*ef536abdSDmitry Torokhov error = ret < 0 ? ret : -EIO; 188*ef536abdSDmitry Torokhov dev_err(&client->dev, "%s failed: %d\n", __func__, error); 189*ef536abdSDmitry Torokhov return ret; 190*ef536abdSDmitry Torokhov } 191*ef536abdSDmitry Torokhov 192*ef536abdSDmitry Torokhov static int ili251x_read_touch_data(struct i2c_client *client, u8 *data) 193*ef536abdSDmitry Torokhov { 194*ef536abdSDmitry Torokhov int error; 195*ef536abdSDmitry Torokhov 196*ef536abdSDmitry Torokhov error = ili251x_read_reg(client, REG_TOUCHDATA, 197*ef536abdSDmitry Torokhov data, ILI251X_DATA_SIZE1); 198*ef536abdSDmitry Torokhov if (!error && data[0] == 2) { 199*ef536abdSDmitry Torokhov error = i2c_master_recv(client, data + ILI251X_DATA_SIZE1, 200*ef536abdSDmitry Torokhov ILI251X_DATA_SIZE2); 201*ef536abdSDmitry Torokhov if (error >= 0 && error != ILI251X_DATA_SIZE2) 202*ef536abdSDmitry Torokhov error = -EIO; 203*ef536abdSDmitry Torokhov } 204*ef536abdSDmitry Torokhov 205*ef536abdSDmitry Torokhov return error; 206*ef536abdSDmitry Torokhov } 207*ef536abdSDmitry Torokhov 208*ef536abdSDmitry Torokhov static bool ili251x_touchdata_to_coords(const u8 *touchdata, 20949588917SMarek Vasut unsigned int finger, 21049588917SMarek Vasut unsigned int *x, unsigned int *y) 21149588917SMarek Vasut { 212*ef536abdSDmitry Torokhov u16 val; 213*ef536abdSDmitry Torokhov 214*ef536abdSDmitry Torokhov val = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0); 215*ef536abdSDmitry Torokhov if (!(val & BIT(15))) /* Touch indication */ 21649588917SMarek Vasut return false; 21749588917SMarek Vasut 218*ef536abdSDmitry Torokhov *x = val & 0x3fff; 21949588917SMarek Vasut *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2); 22049588917SMarek Vasut 22149588917SMarek Vasut return true; 22249588917SMarek Vasut } 22349588917SMarek Vasut 224*ef536abdSDmitry Torokhov static bool ili251x_check_continue_polling(const u8 *data, bool touch) 225*ef536abdSDmitry Torokhov { 226*ef536abdSDmitry Torokhov return touch; 227*ef536abdSDmitry Torokhov } 228*ef536abdSDmitry Torokhov 229*ef536abdSDmitry Torokhov static const struct ili2xxx_chip ili251x_chip = { 230*ef536abdSDmitry Torokhov .read_reg = ili251x_read_reg, 231*ef536abdSDmitry Torokhov .get_touch_data = ili251x_read_touch_data, 232*ef536abdSDmitry Torokhov .parse_touch_data = ili251x_touchdata_to_coords, 233*ef536abdSDmitry Torokhov .continue_polling = ili251x_check_continue_polling, 234*ef536abdSDmitry Torokhov .max_touches = 10, 235*ef536abdSDmitry Torokhov }; 236*ef536abdSDmitry Torokhov 237e3559442SMarek Vasut static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) 238e3559442SMarek Vasut { 239e3559442SMarek Vasut struct input_dev *input = priv->input; 2405c6a7a62SOlivier Sobrie int i; 241*ef536abdSDmitry Torokhov bool contact = false, touch; 24249588917SMarek Vasut unsigned int x = 0, y = 0; 2435c6a7a62SOlivier Sobrie 244*ef536abdSDmitry Torokhov for (i = 0; i < priv->chip->max_touches; i++) { 245*ef536abdSDmitry Torokhov touch = priv->chip->parse_touch_data(touchdata, i, &x, &y); 24649588917SMarek Vasut 247f67cc3e9SMarek Vasut input_mt_slot(input, i); 248*ef536abdSDmitry Torokhov if (input_mt_report_slot_state(input, MT_TOOL_FINGER, touch)) { 249*ef536abdSDmitry Torokhov touchscreen_report_pos(input, &priv->prop, x, y, true); 250*ef536abdSDmitry Torokhov contact = true; 251*ef536abdSDmitry Torokhov } 2525c6a7a62SOlivier Sobrie } 2535c6a7a62SOlivier Sobrie 2545c6a7a62SOlivier Sobrie input_mt_report_pointer_emulation(input, false); 2555c6a7a62SOlivier Sobrie input_sync(input); 256e3559442SMarek Vasut 25749588917SMarek Vasut return contact; 2585c6a7a62SOlivier Sobrie } 2595c6a7a62SOlivier Sobrie 26071f8e38aSDmitry Torokhov static irqreturn_t ili210x_irq(int irq, void *irq_data) 2615c6a7a62SOlivier Sobrie { 26271f8e38aSDmitry Torokhov struct ili210x *priv = irq_data; 2635c6a7a62SOlivier Sobrie struct i2c_client *client = priv->client; 264*ef536abdSDmitry Torokhov const struct ili2xxx_chip *chip = priv->chip; 265*ef536abdSDmitry Torokhov u8 touchdata[ILI210X_DATA_SIZE] = { 0 }; 266*ef536abdSDmitry Torokhov bool keep_polling; 267e3559442SMarek Vasut bool touch; 26871f8e38aSDmitry Torokhov int error; 2695c6a7a62SOlivier Sobrie 27071f8e38aSDmitry Torokhov do { 271*ef536abdSDmitry Torokhov error = chip->get_touch_data(client, touchdata); 2725c6a7a62SOlivier Sobrie if (error) { 2735c6a7a62SOlivier Sobrie dev_err(&client->dev, 274*ef536abdSDmitry Torokhov "Unable to get touch data: %d\n", error); 27571f8e38aSDmitry Torokhov break; 2765c6a7a62SOlivier Sobrie } 2775c6a7a62SOlivier Sobrie 278e3559442SMarek Vasut touch = ili210x_report_events(priv, touchdata); 279*ef536abdSDmitry Torokhov keep_polling = chip->continue_polling(touchdata, touch); 280*ef536abdSDmitry Torokhov if (keep_polling) 28171f8e38aSDmitry Torokhov msleep(ILI2XXX_POLL_PERIOD); 282*ef536abdSDmitry Torokhov } while (!priv->stop && keep_polling); 2835c6a7a62SOlivier Sobrie 2845c6a7a62SOlivier Sobrie return IRQ_HANDLED; 2855c6a7a62SOlivier Sobrie } 2865c6a7a62SOlivier Sobrie 2875c6a7a62SOlivier Sobrie static ssize_t ili210x_calibrate(struct device *dev, 2885c6a7a62SOlivier Sobrie struct device_attribute *attr, 2895c6a7a62SOlivier Sobrie const char *buf, size_t count) 2905c6a7a62SOlivier Sobrie { 2915c6a7a62SOlivier Sobrie struct i2c_client *client = to_i2c_client(dev); 2925c6a7a62SOlivier Sobrie struct ili210x *priv = i2c_get_clientdata(client); 2935c6a7a62SOlivier Sobrie unsigned long calibrate; 2945c6a7a62SOlivier Sobrie int rc; 2955c6a7a62SOlivier Sobrie u8 cmd = REG_CALIBRATE; 2965c6a7a62SOlivier Sobrie 2975c6a7a62SOlivier Sobrie if (kstrtoul(buf, 10, &calibrate)) 2985c6a7a62SOlivier Sobrie return -EINVAL; 2995c6a7a62SOlivier Sobrie 3005c6a7a62SOlivier Sobrie if (calibrate > 1) 3015c6a7a62SOlivier Sobrie return -EINVAL; 3025c6a7a62SOlivier Sobrie 3035c6a7a62SOlivier Sobrie if (calibrate) { 3045c6a7a62SOlivier Sobrie rc = i2c_master_send(priv->client, &cmd, sizeof(cmd)); 3055c6a7a62SOlivier Sobrie if (rc != sizeof(cmd)) 3065c6a7a62SOlivier Sobrie return -EIO; 3075c6a7a62SOlivier Sobrie } 3085c6a7a62SOlivier Sobrie 3095c6a7a62SOlivier Sobrie return count; 3105c6a7a62SOlivier Sobrie } 311b27c0d0cSDmitry Torokhov static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate); 3125c6a7a62SOlivier Sobrie 3135c6a7a62SOlivier Sobrie static struct attribute *ili210x_attributes[] = { 3145c6a7a62SOlivier Sobrie &dev_attr_calibrate.attr, 3155c6a7a62SOlivier Sobrie NULL, 3165c6a7a62SOlivier Sobrie }; 3175c6a7a62SOlivier Sobrie 3185c6a7a62SOlivier Sobrie static const struct attribute_group ili210x_attr_group = { 3195c6a7a62SOlivier Sobrie .attrs = ili210x_attributes, 3205c6a7a62SOlivier Sobrie }; 3215c6a7a62SOlivier Sobrie 322201f3c80SMarek Vasut static void ili210x_power_down(void *data) 323201f3c80SMarek Vasut { 324201f3c80SMarek Vasut struct gpio_desc *reset_gpio = data; 325201f3c80SMarek Vasut 326201f3c80SMarek Vasut gpiod_set_value_cansleep(reset_gpio, 1); 327201f3c80SMarek Vasut } 328201f3c80SMarek Vasut 32971f8e38aSDmitry Torokhov static void ili210x_stop(void *data) 3301bdec5d9SMarek Vasut { 3311bdec5d9SMarek Vasut struct ili210x *priv = data; 3321bdec5d9SMarek Vasut 33371f8e38aSDmitry Torokhov /* Tell ISR to quit even if there is a contact. */ 33471f8e38aSDmitry Torokhov priv->stop = true; 3351bdec5d9SMarek Vasut } 3361bdec5d9SMarek Vasut 3375298cc4cSBill Pemberton static int ili210x_i2c_probe(struct i2c_client *client, 3385c6a7a62SOlivier Sobrie const struct i2c_device_id *id) 3395c6a7a62SOlivier Sobrie { 3405c6a7a62SOlivier Sobrie struct device *dev = &client->dev; 341*ef536abdSDmitry Torokhov const struct ili2xxx_chip *chip; 3425c6a7a62SOlivier Sobrie struct ili210x *priv; 343201f3c80SMarek Vasut struct gpio_desc *reset_gpio; 3445c6a7a62SOlivier Sobrie struct input_dev *input; 3455c6a7a62SOlivier Sobrie struct firmware_version firmware; 3465c6a7a62SOlivier Sobrie int error; 3475c6a7a62SOlivier Sobrie 3485c6a7a62SOlivier Sobrie dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver"); 3495c6a7a62SOlivier Sobrie 350*ef536abdSDmitry Torokhov chip = device_get_match_data(dev); 351*ef536abdSDmitry Torokhov if (!chip && id) 352*ef536abdSDmitry Torokhov chip = (const struct ili2xxx_chip *)id->driver_data; 353*ef536abdSDmitry Torokhov if (!chip) { 354*ef536abdSDmitry Torokhov dev_err(&client->dev, "unknown device model\n"); 355*ef536abdSDmitry Torokhov return -ENODEV; 356*ef536abdSDmitry Torokhov } 357*ef536abdSDmitry Torokhov 3585c6a7a62SOlivier Sobrie if (client->irq <= 0) { 3595c6a7a62SOlivier Sobrie dev_err(dev, "No IRQ!\n"); 3605c6a7a62SOlivier Sobrie return -EINVAL; 3615c6a7a62SOlivier Sobrie } 3625c6a7a62SOlivier Sobrie 363201f3c80SMarek Vasut reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 364201f3c80SMarek Vasut if (IS_ERR(reset_gpio)) 365201f3c80SMarek Vasut return PTR_ERR(reset_gpio); 366201f3c80SMarek Vasut 367201f3c80SMarek Vasut if (reset_gpio) { 368201f3c80SMarek Vasut error = devm_add_action_or_reset(dev, ili210x_power_down, 369201f3c80SMarek Vasut reset_gpio); 370201f3c80SMarek Vasut if (error) 371201f3c80SMarek Vasut return error; 372201f3c80SMarek Vasut 373201f3c80SMarek Vasut usleep_range(50, 100); 374201f3c80SMarek Vasut gpiod_set_value_cansleep(reset_gpio, 0); 375201f3c80SMarek Vasut msleep(100); 376201f3c80SMarek Vasut } 377201f3c80SMarek Vasut 37812294577SMarek Vasut priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 37912294577SMarek Vasut if (!priv) 38012294577SMarek Vasut return -ENOMEM; 38112294577SMarek Vasut 38212294577SMarek Vasut input = devm_input_allocate_device(dev); 38312294577SMarek Vasut if (!input) 38412294577SMarek Vasut return -ENOMEM; 38512294577SMarek Vasut 38612294577SMarek Vasut priv->client = client; 38712294577SMarek Vasut priv->input = input; 38812294577SMarek Vasut priv->reset_gpio = reset_gpio; 389*ef536abdSDmitry Torokhov priv->chip = chip; 39012294577SMarek Vasut i2c_set_clientdata(client, priv); 39112294577SMarek Vasut 3925c6a7a62SOlivier Sobrie /* Get firmware version */ 393*ef536abdSDmitry Torokhov error = chip->read_reg(client, REG_FIRMWARE_VERSION, 3945c6a7a62SOlivier Sobrie &firmware, sizeof(firmware)); 3955c6a7a62SOlivier Sobrie if (error) { 3965c6a7a62SOlivier Sobrie dev_err(dev, "Failed to get firmware version, err: %d\n", 3975c6a7a62SOlivier Sobrie error); 3985c6a7a62SOlivier Sobrie return error; 3995c6a7a62SOlivier Sobrie } 4005c6a7a62SOlivier Sobrie 4015c6a7a62SOlivier Sobrie /* Setup input device */ 4025c6a7a62SOlivier Sobrie input->name = "ILI210x Touchscreen"; 4035c6a7a62SOlivier Sobrie input->id.bustype = BUS_I2C; 4045c6a7a62SOlivier Sobrie 4055c6a7a62SOlivier Sobrie /* Multi touch */ 406f67cc3e9SMarek Vasut input_set_abs_params(input, ABS_MT_POSITION_X, 0, 0xffff, 0, 0); 407f67cc3e9SMarek Vasut input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 0xffff, 0, 0); 408f67cc3e9SMarek Vasut touchscreen_parse_properties(input, true, &priv->prop); 40943f06a4cSDmitry Torokhov 410*ef536abdSDmitry Torokhov error = input_mt_init_slots(input, priv->chip->max_touches, 411*ef536abdSDmitry Torokhov INPUT_MT_DIRECT); 41243f06a4cSDmitry Torokhov if (error) { 41343f06a4cSDmitry Torokhov dev_err(dev, "Unable to set up slots, err: %d\n", error); 41443f06a4cSDmitry Torokhov return error; 41543f06a4cSDmitry Torokhov } 4165c6a7a62SOlivier Sobrie 41771f8e38aSDmitry Torokhov error = devm_request_threaded_irq(dev, client->irq, NULL, ili210x_irq, 41871f8e38aSDmitry Torokhov IRQF_ONESHOT, client->name, priv); 4195c6a7a62SOlivier Sobrie if (error) { 4205c6a7a62SOlivier Sobrie dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n", 4215c6a7a62SOlivier Sobrie error); 4221bdec5d9SMarek Vasut return error; 4235c6a7a62SOlivier Sobrie } 4245c6a7a62SOlivier Sobrie 42571f8e38aSDmitry Torokhov error = devm_add_action_or_reset(dev, ili210x_stop, priv); 42671f8e38aSDmitry Torokhov if (error) 42771f8e38aSDmitry Torokhov return error; 42871f8e38aSDmitry Torokhov 429576057bfSDmitry Torokhov error = devm_device_add_group(dev, &ili210x_attr_group); 4305c6a7a62SOlivier Sobrie if (error) { 4315c6a7a62SOlivier Sobrie dev_err(dev, "Unable to create sysfs attributes, err: %d\n", 4325c6a7a62SOlivier Sobrie error); 4331bdec5d9SMarek Vasut return error; 4345c6a7a62SOlivier Sobrie } 4355c6a7a62SOlivier Sobrie 4365c6a7a62SOlivier Sobrie error = input_register_device(priv->input); 4375c6a7a62SOlivier Sobrie if (error) { 438971bd8faSMasanari Iida dev_err(dev, "Cannot register input device, err: %d\n", error); 439576057bfSDmitry Torokhov return error; 4405c6a7a62SOlivier Sobrie } 4415c6a7a62SOlivier Sobrie 442d7ddf154SGuenter Roeck device_init_wakeup(dev, 1); 4435c6a7a62SOlivier Sobrie 4445c6a7a62SOlivier Sobrie dev_dbg(dev, 4455c6a7a62SOlivier Sobrie "ILI210x initialized (IRQ: %d), firmware version %d.%d.%d", 4465c6a7a62SOlivier Sobrie client->irq, firmware.id, firmware.major, firmware.minor); 4475c6a7a62SOlivier Sobrie 4485c6a7a62SOlivier Sobrie return 0; 4495c6a7a62SOlivier Sobrie } 4505c6a7a62SOlivier Sobrie 45102b6a58bSJingoo Han static int __maybe_unused ili210x_i2c_suspend(struct device *dev) 4525c6a7a62SOlivier Sobrie { 4535c6a7a62SOlivier Sobrie struct i2c_client *client = to_i2c_client(dev); 4545c6a7a62SOlivier Sobrie 4555c6a7a62SOlivier Sobrie if (device_may_wakeup(&client->dev)) 4565c6a7a62SOlivier Sobrie enable_irq_wake(client->irq); 4575c6a7a62SOlivier Sobrie 4585c6a7a62SOlivier Sobrie return 0; 4595c6a7a62SOlivier Sobrie } 4605c6a7a62SOlivier Sobrie 46102b6a58bSJingoo Han static int __maybe_unused ili210x_i2c_resume(struct device *dev) 4625c6a7a62SOlivier Sobrie { 4635c6a7a62SOlivier Sobrie struct i2c_client *client = to_i2c_client(dev); 4645c6a7a62SOlivier Sobrie 4655c6a7a62SOlivier Sobrie if (device_may_wakeup(&client->dev)) 4665c6a7a62SOlivier Sobrie disable_irq_wake(client->irq); 4675c6a7a62SOlivier Sobrie 4685c6a7a62SOlivier Sobrie return 0; 4695c6a7a62SOlivier Sobrie } 4705c6a7a62SOlivier Sobrie 4715c6a7a62SOlivier Sobrie static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm, 4725c6a7a62SOlivier Sobrie ili210x_i2c_suspend, ili210x_i2c_resume); 4735c6a7a62SOlivier Sobrie 4745c6a7a62SOlivier Sobrie static const struct i2c_device_id ili210x_i2c_id[] = { 475*ef536abdSDmitry Torokhov { "ili210x", (long)&ili210x_chip }, 476*ef536abdSDmitry Torokhov { "ili2117", (long)&ili211x_chip }, 477*ef536abdSDmitry Torokhov { "ili251x", (long)&ili251x_chip }, 4785c6a7a62SOlivier Sobrie { } 4795c6a7a62SOlivier Sobrie }; 4805c6a7a62SOlivier Sobrie MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); 4815c6a7a62SOlivier Sobrie 482c5d0e4b5SMarek Vasut static const struct of_device_id ili210x_dt_ids[] = { 483*ef536abdSDmitry Torokhov { .compatible = "ilitek,ili210x", .data = &ili210x_chip }, 484*ef536abdSDmitry Torokhov { .compatible = "ilitek,ili2117", .data = &ili211x_chip }, 485*ef536abdSDmitry Torokhov { .compatible = "ilitek,ili251x", .data = &ili251x_chip }, 486*ef536abdSDmitry Torokhov { } 487c5d0e4b5SMarek Vasut }; 488c5d0e4b5SMarek Vasut MODULE_DEVICE_TABLE(of, ili210x_dt_ids); 489c5d0e4b5SMarek Vasut 4905c6a7a62SOlivier Sobrie static struct i2c_driver ili210x_ts_driver = { 4915c6a7a62SOlivier Sobrie .driver = { 4925c6a7a62SOlivier Sobrie .name = "ili210x_i2c", 4935c6a7a62SOlivier Sobrie .pm = &ili210x_i2c_pm, 494c5d0e4b5SMarek Vasut .of_match_table = ili210x_dt_ids, 4955c6a7a62SOlivier Sobrie }, 4965c6a7a62SOlivier Sobrie .id_table = ili210x_i2c_id, 4975c6a7a62SOlivier Sobrie .probe = ili210x_i2c_probe, 4985c6a7a62SOlivier Sobrie }; 4995c6a7a62SOlivier Sobrie 5005c6a7a62SOlivier Sobrie module_i2c_driver(ili210x_ts_driver); 5015c6a7a62SOlivier Sobrie 5025c6a7a62SOlivier Sobrie MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>"); 5035c6a7a62SOlivier Sobrie MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver"); 5045c6a7a62SOlivier Sobrie MODULE_LICENSE("GPL"); 505