109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 25c6a7a62SOlivier Sobrie #include <linux/module.h> 35c6a7a62SOlivier Sobrie #include <linux/i2c.h> 45c6a7a62SOlivier Sobrie #include <linux/interrupt.h> 55c6a7a62SOlivier Sobrie #include <linux/slab.h> 65c6a7a62SOlivier Sobrie #include <linux/input.h> 75c6a7a62SOlivier Sobrie #include <linux/input/mt.h> 8f67cc3e9SMarek Vasut #include <linux/input/touchscreen.h> 95c6a7a62SOlivier Sobrie #include <linux/delay.h> 105c6a7a62SOlivier Sobrie #include <linux/workqueue.h> 11201f3c80SMarek Vasut #include <linux/gpio/consumer.h> 1249588917SMarek Vasut #include <linux/of_device.h> 13e3559442SMarek Vasut #include <asm/unaligned.h> 145c6a7a62SOlivier Sobrie 1549588917SMarek Vasut #define ILI210X_TOUCHES 2 16*eb91ecc9SMarek Vasut #define ILI211X_TOUCHES 10 1749588917SMarek Vasut #define ILI251X_TOUCHES 10 185c6a7a62SOlivier Sobrie #define DEFAULT_POLL_PERIOD 20 195c6a7a62SOlivier Sobrie 205c6a7a62SOlivier Sobrie /* Touchscreen commands */ 215c6a7a62SOlivier Sobrie #define REG_TOUCHDATA 0x10 225c6a7a62SOlivier Sobrie #define REG_PANEL_INFO 0x20 235c6a7a62SOlivier Sobrie #define REG_FIRMWARE_VERSION 0x40 245c6a7a62SOlivier Sobrie #define REG_CALIBRATE 0xcc 255c6a7a62SOlivier Sobrie 265c6a7a62SOlivier Sobrie struct firmware_version { 275c6a7a62SOlivier Sobrie u8 id; 285c6a7a62SOlivier Sobrie u8 major; 295c6a7a62SOlivier Sobrie u8 minor; 305c6a7a62SOlivier Sobrie } __packed; 315c6a7a62SOlivier Sobrie 3249588917SMarek Vasut enum ili2xxx_model { 3349588917SMarek Vasut MODEL_ILI210X, 34*eb91ecc9SMarek Vasut MODEL_ILI211X, 3549588917SMarek Vasut MODEL_ILI251X, 3649588917SMarek Vasut }; 3749588917SMarek Vasut 385c6a7a62SOlivier Sobrie struct ili210x { 395c6a7a62SOlivier Sobrie struct i2c_client *client; 405c6a7a62SOlivier Sobrie struct input_dev *input; 415c6a7a62SOlivier Sobrie unsigned int poll_period; 425c6a7a62SOlivier Sobrie struct delayed_work dwork; 43201f3c80SMarek Vasut struct gpio_desc *reset_gpio; 44f67cc3e9SMarek Vasut struct touchscreen_properties prop; 4549588917SMarek Vasut enum ili2xxx_model model; 4649588917SMarek Vasut unsigned int max_touches; 475c6a7a62SOlivier Sobrie }; 485c6a7a62SOlivier Sobrie 495c6a7a62SOlivier Sobrie static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf, 505c6a7a62SOlivier Sobrie size_t len) 515c6a7a62SOlivier Sobrie { 5249588917SMarek Vasut struct ili210x *priv = i2c_get_clientdata(client); 535c6a7a62SOlivier Sobrie struct i2c_msg msg[2] = { 545c6a7a62SOlivier Sobrie { 555c6a7a62SOlivier Sobrie .addr = client->addr, 565c6a7a62SOlivier Sobrie .flags = 0, 575c6a7a62SOlivier Sobrie .len = 1, 585c6a7a62SOlivier Sobrie .buf = ®, 595c6a7a62SOlivier Sobrie }, 605c6a7a62SOlivier Sobrie { 615c6a7a62SOlivier Sobrie .addr = client->addr, 625c6a7a62SOlivier Sobrie .flags = I2C_M_RD, 635c6a7a62SOlivier Sobrie .len = len, 645c6a7a62SOlivier Sobrie .buf = buf, 655c6a7a62SOlivier Sobrie } 665c6a7a62SOlivier Sobrie }; 675c6a7a62SOlivier Sobrie 6849588917SMarek Vasut if (priv->model == MODEL_ILI251X) { 6949588917SMarek Vasut if (i2c_transfer(client->adapter, msg, 1) != 1) { 7049588917SMarek Vasut dev_err(&client->dev, "i2c transfer failed\n"); 7149588917SMarek Vasut return -EIO; 7249588917SMarek Vasut } 7349588917SMarek Vasut 7449588917SMarek Vasut usleep_range(5000, 5500); 7549588917SMarek Vasut 7649588917SMarek Vasut if (i2c_transfer(client->adapter, msg + 1, 1) != 1) { 7749588917SMarek Vasut dev_err(&client->dev, "i2c transfer failed\n"); 7849588917SMarek Vasut return -EIO; 7949588917SMarek Vasut } 8049588917SMarek Vasut } else { 815c6a7a62SOlivier Sobrie if (i2c_transfer(client->adapter, msg, 2) != 2) { 825c6a7a62SOlivier Sobrie dev_err(&client->dev, "i2c transfer failed\n"); 835c6a7a62SOlivier Sobrie return -EIO; 845c6a7a62SOlivier Sobrie } 8549588917SMarek Vasut } 8649588917SMarek Vasut 8749588917SMarek Vasut return 0; 8849588917SMarek Vasut } 8949588917SMarek Vasut 9049588917SMarek Vasut static int ili210x_read(struct i2c_client *client, void *buf, size_t len) 9149588917SMarek Vasut { 9249588917SMarek Vasut struct i2c_msg msg = { 9349588917SMarek Vasut .addr = client->addr, 9449588917SMarek Vasut .flags = I2C_M_RD, 9549588917SMarek Vasut .len = len, 9649588917SMarek Vasut .buf = buf, 9749588917SMarek Vasut }; 9849588917SMarek Vasut 9949588917SMarek Vasut if (i2c_transfer(client->adapter, &msg, 1) != 1) { 10049588917SMarek Vasut dev_err(&client->dev, "i2c transfer failed\n"); 10149588917SMarek Vasut return -EIO; 10249588917SMarek Vasut } 1035c6a7a62SOlivier Sobrie 1045c6a7a62SOlivier Sobrie return 0; 1055c6a7a62SOlivier Sobrie } 1065c6a7a62SOlivier Sobrie 107e3559442SMarek Vasut static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, 108e3559442SMarek Vasut unsigned int finger, 109e3559442SMarek Vasut unsigned int *x, unsigned int *y) 1105c6a7a62SOlivier Sobrie { 11149588917SMarek Vasut if (finger >= ILI210X_TOUCHES) 112e3559442SMarek Vasut return false; 113e3559442SMarek Vasut 114e3559442SMarek Vasut if (touchdata[0] & BIT(finger)) 115e3559442SMarek Vasut return false; 116e3559442SMarek Vasut 117e3559442SMarek Vasut *x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0); 118e3559442SMarek Vasut *y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2); 119e3559442SMarek Vasut 120e3559442SMarek Vasut return true; 121e3559442SMarek Vasut } 122e3559442SMarek Vasut 123*eb91ecc9SMarek Vasut static bool ili211x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, 124*eb91ecc9SMarek Vasut unsigned int finger, 125*eb91ecc9SMarek Vasut unsigned int *x, unsigned int *y) 126*eb91ecc9SMarek Vasut { 127*eb91ecc9SMarek Vasut u32 data; 128*eb91ecc9SMarek Vasut 129*eb91ecc9SMarek Vasut if (finger >= ILI211X_TOUCHES) 130*eb91ecc9SMarek Vasut return false; 131*eb91ecc9SMarek Vasut 132*eb91ecc9SMarek Vasut data = get_unaligned_be32(touchdata + 1 + (finger * 4) + 0); 133*eb91ecc9SMarek Vasut if (data == 0xffffffff) /* Finger up */ 134*eb91ecc9SMarek Vasut return false; 135*eb91ecc9SMarek Vasut 136*eb91ecc9SMarek Vasut *x = ((touchdata[1 + (finger * 4) + 0] & 0xf0) << 4) | 137*eb91ecc9SMarek Vasut touchdata[1 + (finger * 4) + 1]; 138*eb91ecc9SMarek Vasut *y = ((touchdata[1 + (finger * 4) + 0] & 0x0f) << 8) | 139*eb91ecc9SMarek Vasut touchdata[1 + (finger * 4) + 2]; 140*eb91ecc9SMarek Vasut 141*eb91ecc9SMarek Vasut return true; 142*eb91ecc9SMarek Vasut } 143*eb91ecc9SMarek Vasut 14449588917SMarek Vasut static bool ili251x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, 14549588917SMarek Vasut unsigned int finger, 14649588917SMarek Vasut unsigned int *x, unsigned int *y) 14749588917SMarek Vasut { 14849588917SMarek Vasut if (finger >= ILI251X_TOUCHES) 14949588917SMarek Vasut return false; 15049588917SMarek Vasut 15149588917SMarek Vasut *x = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0); 15249588917SMarek Vasut if (!(*x & BIT(15))) /* Touch indication */ 15349588917SMarek Vasut return false; 15449588917SMarek Vasut 15549588917SMarek Vasut *x &= 0x3fff; 15649588917SMarek Vasut *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2); 15749588917SMarek Vasut 15849588917SMarek Vasut return true; 15949588917SMarek Vasut } 16049588917SMarek Vasut 161e3559442SMarek Vasut static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) 162e3559442SMarek Vasut { 163e3559442SMarek Vasut struct input_dev *input = priv->input; 1645c6a7a62SOlivier Sobrie int i; 16549588917SMarek Vasut bool contact = false, touch = false; 16649588917SMarek Vasut unsigned int x = 0, y = 0; 1675c6a7a62SOlivier Sobrie 16849588917SMarek Vasut for (i = 0; i < priv->max_touches; i++) { 16949588917SMarek Vasut if (priv->model == MODEL_ILI210X) { 17049588917SMarek Vasut touch = ili210x_touchdata_to_coords(priv, touchdata, 17149588917SMarek Vasut i, &x, &y); 172*eb91ecc9SMarek Vasut } else if (priv->model == MODEL_ILI211X) { 173*eb91ecc9SMarek Vasut touch = ili211x_touchdata_to_coords(priv, touchdata, 174*eb91ecc9SMarek Vasut i, &x, &y); 17549588917SMarek Vasut } else if (priv->model == MODEL_ILI251X) { 17649588917SMarek Vasut touch = ili251x_touchdata_to_coords(priv, touchdata, 17749588917SMarek Vasut i, &x, &y); 17849588917SMarek Vasut if (touch) 17949588917SMarek Vasut contact = true; 18049588917SMarek Vasut } 18149588917SMarek Vasut 182f67cc3e9SMarek Vasut input_mt_slot(input, i); 1835c6a7a62SOlivier Sobrie input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); 184f67cc3e9SMarek Vasut if (!touch) 185f67cc3e9SMarek Vasut continue; 186f67cc3e9SMarek Vasut touchscreen_report_pos(input, &priv->prop, x, y, 187f67cc3e9SMarek Vasut true); 1885c6a7a62SOlivier Sobrie } 1895c6a7a62SOlivier Sobrie 1905c6a7a62SOlivier Sobrie input_mt_report_pointer_emulation(input, false); 1915c6a7a62SOlivier Sobrie input_sync(input); 192e3559442SMarek Vasut 19349588917SMarek Vasut if (priv->model == MODEL_ILI210X) 19449588917SMarek Vasut contact = touchdata[0] & 0xf3; 19549588917SMarek Vasut 19649588917SMarek Vasut return contact; 1975c6a7a62SOlivier Sobrie } 1985c6a7a62SOlivier Sobrie 1995c6a7a62SOlivier Sobrie static void ili210x_work(struct work_struct *work) 2005c6a7a62SOlivier Sobrie { 2015c6a7a62SOlivier Sobrie struct ili210x *priv = container_of(work, struct ili210x, 2025c6a7a62SOlivier Sobrie dwork.work); 2035c6a7a62SOlivier Sobrie struct i2c_client *client = priv->client; 20449588917SMarek Vasut u8 touchdata[64] = { 0 }; 205*eb91ecc9SMarek Vasut s16 sum = 0; 206e3559442SMarek Vasut bool touch; 207*eb91ecc9SMarek Vasut int i, error = -EINVAL; 2085c6a7a62SOlivier Sobrie 20949588917SMarek Vasut if (priv->model == MODEL_ILI210X) { 2105c6a7a62SOlivier Sobrie error = ili210x_read_reg(client, REG_TOUCHDATA, 211e3559442SMarek Vasut touchdata, sizeof(touchdata)); 212*eb91ecc9SMarek Vasut } else if (priv->model == MODEL_ILI211X) { 213*eb91ecc9SMarek Vasut error = ili210x_read(client, touchdata, 43); 214*eb91ecc9SMarek Vasut if (!error) { 215*eb91ecc9SMarek Vasut /* This chip uses custom checksum at the end of data */ 216*eb91ecc9SMarek Vasut for (i = 0; i <= 41; i++) 217*eb91ecc9SMarek Vasut sum = (sum + touchdata[i]) & 0xff; 218*eb91ecc9SMarek Vasut if ((-sum & 0xff) != touchdata[42]) { 219*eb91ecc9SMarek Vasut dev_err(&client->dev, 220*eb91ecc9SMarek Vasut "CRC error (crc=0x%02x expected=0x%02x)\n", 221*eb91ecc9SMarek Vasut sum, touchdata[42]); 222*eb91ecc9SMarek Vasut return; 223*eb91ecc9SMarek Vasut } 224*eb91ecc9SMarek Vasut } 22549588917SMarek Vasut } else if (priv->model == MODEL_ILI251X) { 22649588917SMarek Vasut error = ili210x_read_reg(client, REG_TOUCHDATA, 22749588917SMarek Vasut touchdata, 31); 22849588917SMarek Vasut if (!error && touchdata[0] == 2) 22949588917SMarek Vasut error = ili210x_read(client, &touchdata[31], 20); 23049588917SMarek Vasut } 23149588917SMarek Vasut 2325c6a7a62SOlivier Sobrie if (error) { 2335c6a7a62SOlivier Sobrie dev_err(&client->dev, 2345c6a7a62SOlivier Sobrie "Unable to get touchdata, err = %d\n", error); 2355c6a7a62SOlivier Sobrie return; 2365c6a7a62SOlivier Sobrie } 2375c6a7a62SOlivier Sobrie 238e3559442SMarek Vasut touch = ili210x_report_events(priv, touchdata); 2395c6a7a62SOlivier Sobrie 240e3559442SMarek Vasut if (touch) 2415c6a7a62SOlivier Sobrie schedule_delayed_work(&priv->dwork, 2425c6a7a62SOlivier Sobrie msecs_to_jiffies(priv->poll_period)); 2435c6a7a62SOlivier Sobrie } 2445c6a7a62SOlivier Sobrie 2455c6a7a62SOlivier Sobrie static irqreturn_t ili210x_irq(int irq, void *irq_data) 2465c6a7a62SOlivier Sobrie { 2475c6a7a62SOlivier Sobrie struct ili210x *priv = irq_data; 2485c6a7a62SOlivier Sobrie 2495c6a7a62SOlivier Sobrie schedule_delayed_work(&priv->dwork, 0); 2505c6a7a62SOlivier Sobrie 2515c6a7a62SOlivier Sobrie return IRQ_HANDLED; 2525c6a7a62SOlivier Sobrie } 2535c6a7a62SOlivier Sobrie 2545c6a7a62SOlivier Sobrie static ssize_t ili210x_calibrate(struct device *dev, 2555c6a7a62SOlivier Sobrie struct device_attribute *attr, 2565c6a7a62SOlivier Sobrie const char *buf, size_t count) 2575c6a7a62SOlivier Sobrie { 2585c6a7a62SOlivier Sobrie struct i2c_client *client = to_i2c_client(dev); 2595c6a7a62SOlivier Sobrie struct ili210x *priv = i2c_get_clientdata(client); 2605c6a7a62SOlivier Sobrie unsigned long calibrate; 2615c6a7a62SOlivier Sobrie int rc; 2625c6a7a62SOlivier Sobrie u8 cmd = REG_CALIBRATE; 2635c6a7a62SOlivier Sobrie 2645c6a7a62SOlivier Sobrie if (kstrtoul(buf, 10, &calibrate)) 2655c6a7a62SOlivier Sobrie return -EINVAL; 2665c6a7a62SOlivier Sobrie 2675c6a7a62SOlivier Sobrie if (calibrate > 1) 2685c6a7a62SOlivier Sobrie return -EINVAL; 2695c6a7a62SOlivier Sobrie 2705c6a7a62SOlivier Sobrie if (calibrate) { 2715c6a7a62SOlivier Sobrie rc = i2c_master_send(priv->client, &cmd, sizeof(cmd)); 2725c6a7a62SOlivier Sobrie if (rc != sizeof(cmd)) 2735c6a7a62SOlivier Sobrie return -EIO; 2745c6a7a62SOlivier Sobrie } 2755c6a7a62SOlivier Sobrie 2765c6a7a62SOlivier Sobrie return count; 2775c6a7a62SOlivier Sobrie } 278b27c0d0cSDmitry Torokhov static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate); 2795c6a7a62SOlivier Sobrie 2805c6a7a62SOlivier Sobrie static struct attribute *ili210x_attributes[] = { 2815c6a7a62SOlivier Sobrie &dev_attr_calibrate.attr, 2825c6a7a62SOlivier Sobrie NULL, 2835c6a7a62SOlivier Sobrie }; 2845c6a7a62SOlivier Sobrie 2855c6a7a62SOlivier Sobrie static const struct attribute_group ili210x_attr_group = { 2865c6a7a62SOlivier Sobrie .attrs = ili210x_attributes, 2875c6a7a62SOlivier Sobrie }; 2885c6a7a62SOlivier Sobrie 289201f3c80SMarek Vasut static void ili210x_power_down(void *data) 290201f3c80SMarek Vasut { 291201f3c80SMarek Vasut struct gpio_desc *reset_gpio = data; 292201f3c80SMarek Vasut 293201f3c80SMarek Vasut gpiod_set_value_cansleep(reset_gpio, 1); 294201f3c80SMarek Vasut } 295201f3c80SMarek Vasut 2961bdec5d9SMarek Vasut static void ili210x_cancel_work(void *data) 2971bdec5d9SMarek Vasut { 2981bdec5d9SMarek Vasut struct ili210x *priv = data; 2991bdec5d9SMarek Vasut 3001bdec5d9SMarek Vasut cancel_delayed_work_sync(&priv->dwork); 3011bdec5d9SMarek Vasut } 3021bdec5d9SMarek Vasut 3035298cc4cSBill Pemberton static int ili210x_i2c_probe(struct i2c_client *client, 3045c6a7a62SOlivier Sobrie const struct i2c_device_id *id) 3055c6a7a62SOlivier Sobrie { 3065c6a7a62SOlivier Sobrie struct device *dev = &client->dev; 3075c6a7a62SOlivier Sobrie struct ili210x *priv; 308201f3c80SMarek Vasut struct gpio_desc *reset_gpio; 3095c6a7a62SOlivier Sobrie struct input_dev *input; 3105c6a7a62SOlivier Sobrie struct firmware_version firmware; 31149588917SMarek Vasut enum ili2xxx_model model; 3125c6a7a62SOlivier Sobrie int error; 3135c6a7a62SOlivier Sobrie 31449588917SMarek Vasut model = (enum ili2xxx_model)id->driver_data; 31549588917SMarek Vasut 3165c6a7a62SOlivier Sobrie dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver"); 3175c6a7a62SOlivier Sobrie 3185c6a7a62SOlivier Sobrie if (client->irq <= 0) { 3195c6a7a62SOlivier Sobrie dev_err(dev, "No IRQ!\n"); 3205c6a7a62SOlivier Sobrie return -EINVAL; 3215c6a7a62SOlivier Sobrie } 3225c6a7a62SOlivier Sobrie 323201f3c80SMarek Vasut reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 324201f3c80SMarek Vasut if (IS_ERR(reset_gpio)) 325201f3c80SMarek Vasut return PTR_ERR(reset_gpio); 326201f3c80SMarek Vasut 327201f3c80SMarek Vasut if (reset_gpio) { 328201f3c80SMarek Vasut error = devm_add_action_or_reset(dev, ili210x_power_down, 329201f3c80SMarek Vasut reset_gpio); 330201f3c80SMarek Vasut if (error) 331201f3c80SMarek Vasut return error; 332201f3c80SMarek Vasut 333201f3c80SMarek Vasut usleep_range(50, 100); 334201f3c80SMarek Vasut gpiod_set_value_cansleep(reset_gpio, 0); 335201f3c80SMarek Vasut msleep(100); 336201f3c80SMarek Vasut } 337201f3c80SMarek Vasut 33812294577SMarek Vasut priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 33912294577SMarek Vasut if (!priv) 34012294577SMarek Vasut return -ENOMEM; 34112294577SMarek Vasut 34212294577SMarek Vasut input = devm_input_allocate_device(dev); 34312294577SMarek Vasut if (!input) 34412294577SMarek Vasut return -ENOMEM; 34512294577SMarek Vasut 34612294577SMarek Vasut priv->client = client; 34712294577SMarek Vasut priv->input = input; 34812294577SMarek Vasut priv->poll_period = DEFAULT_POLL_PERIOD; 34912294577SMarek Vasut INIT_DELAYED_WORK(&priv->dwork, ili210x_work); 35012294577SMarek Vasut priv->reset_gpio = reset_gpio; 35149588917SMarek Vasut priv->model = model; 35249588917SMarek Vasut if (model == MODEL_ILI210X) 35349588917SMarek Vasut priv->max_touches = ILI210X_TOUCHES; 354*eb91ecc9SMarek Vasut if (model == MODEL_ILI211X) 355*eb91ecc9SMarek Vasut priv->max_touches = ILI211X_TOUCHES; 35649588917SMarek Vasut if (model == MODEL_ILI251X) 35749588917SMarek Vasut priv->max_touches = ILI251X_TOUCHES; 35812294577SMarek Vasut 35912294577SMarek Vasut i2c_set_clientdata(client, priv); 36012294577SMarek Vasut 3615c6a7a62SOlivier Sobrie /* Get firmware version */ 3625c6a7a62SOlivier Sobrie error = ili210x_read_reg(client, REG_FIRMWARE_VERSION, 3635c6a7a62SOlivier Sobrie &firmware, sizeof(firmware)); 3645c6a7a62SOlivier Sobrie if (error) { 3655c6a7a62SOlivier Sobrie dev_err(dev, "Failed to get firmware version, err: %d\n", 3665c6a7a62SOlivier Sobrie error); 3675c6a7a62SOlivier Sobrie return error; 3685c6a7a62SOlivier Sobrie } 3695c6a7a62SOlivier Sobrie 3705c6a7a62SOlivier Sobrie /* Setup input device */ 3715c6a7a62SOlivier Sobrie input->name = "ILI210x Touchscreen"; 3725c6a7a62SOlivier Sobrie input->id.bustype = BUS_I2C; 3735c6a7a62SOlivier Sobrie input->dev.parent = dev; 3745c6a7a62SOlivier Sobrie 3755c6a7a62SOlivier Sobrie /* Multi touch */ 376f67cc3e9SMarek Vasut input_set_abs_params(input, ABS_MT_POSITION_X, 0, 0xffff, 0, 0); 377f67cc3e9SMarek Vasut input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 0xffff, 0, 0); 378f67cc3e9SMarek Vasut touchscreen_parse_properties(input, true, &priv->prop); 379f67cc3e9SMarek Vasut input_mt_init_slots(input, priv->max_touches, INPUT_MT_DIRECT); 3805c6a7a62SOlivier Sobrie 3811bdec5d9SMarek Vasut error = devm_add_action(dev, ili210x_cancel_work, priv); 3821bdec5d9SMarek Vasut if (error) 3831bdec5d9SMarek Vasut return error; 3841bdec5d9SMarek Vasut 3851bdec5d9SMarek Vasut error = devm_request_irq(dev, client->irq, ili210x_irq, 0, 3865c6a7a62SOlivier Sobrie client->name, priv); 3875c6a7a62SOlivier Sobrie if (error) { 3885c6a7a62SOlivier Sobrie dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n", 3895c6a7a62SOlivier Sobrie error); 3901bdec5d9SMarek Vasut return error; 3915c6a7a62SOlivier Sobrie } 3925c6a7a62SOlivier Sobrie 393576057bfSDmitry Torokhov error = devm_device_add_group(dev, &ili210x_attr_group); 3945c6a7a62SOlivier Sobrie if (error) { 3955c6a7a62SOlivier Sobrie dev_err(dev, "Unable to create sysfs attributes, err: %d\n", 3965c6a7a62SOlivier Sobrie error); 3971bdec5d9SMarek Vasut return error; 3985c6a7a62SOlivier Sobrie } 3995c6a7a62SOlivier Sobrie 4005c6a7a62SOlivier Sobrie error = input_register_device(priv->input); 4015c6a7a62SOlivier Sobrie if (error) { 402971bd8faSMasanari Iida dev_err(dev, "Cannot register input device, err: %d\n", error); 403576057bfSDmitry Torokhov return error; 4045c6a7a62SOlivier Sobrie } 4055c6a7a62SOlivier Sobrie 406d7ddf154SGuenter Roeck device_init_wakeup(dev, 1); 4075c6a7a62SOlivier Sobrie 4085c6a7a62SOlivier Sobrie dev_dbg(dev, 4095c6a7a62SOlivier Sobrie "ILI210x initialized (IRQ: %d), firmware version %d.%d.%d", 4105c6a7a62SOlivier Sobrie client->irq, firmware.id, firmware.major, firmware.minor); 4115c6a7a62SOlivier Sobrie 4125c6a7a62SOlivier Sobrie return 0; 4135c6a7a62SOlivier Sobrie } 4145c6a7a62SOlivier Sobrie 41502b6a58bSJingoo Han static int __maybe_unused ili210x_i2c_suspend(struct device *dev) 4165c6a7a62SOlivier Sobrie { 4175c6a7a62SOlivier Sobrie struct i2c_client *client = to_i2c_client(dev); 4185c6a7a62SOlivier Sobrie 4195c6a7a62SOlivier Sobrie if (device_may_wakeup(&client->dev)) 4205c6a7a62SOlivier Sobrie enable_irq_wake(client->irq); 4215c6a7a62SOlivier Sobrie 4225c6a7a62SOlivier Sobrie return 0; 4235c6a7a62SOlivier Sobrie } 4245c6a7a62SOlivier Sobrie 42502b6a58bSJingoo Han static int __maybe_unused ili210x_i2c_resume(struct device *dev) 4265c6a7a62SOlivier Sobrie { 4275c6a7a62SOlivier Sobrie struct i2c_client *client = to_i2c_client(dev); 4285c6a7a62SOlivier Sobrie 4295c6a7a62SOlivier Sobrie if (device_may_wakeup(&client->dev)) 4305c6a7a62SOlivier Sobrie disable_irq_wake(client->irq); 4315c6a7a62SOlivier Sobrie 4325c6a7a62SOlivier Sobrie return 0; 4335c6a7a62SOlivier Sobrie } 4345c6a7a62SOlivier Sobrie 4355c6a7a62SOlivier Sobrie static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm, 4365c6a7a62SOlivier Sobrie ili210x_i2c_suspend, ili210x_i2c_resume); 4375c6a7a62SOlivier Sobrie 4385c6a7a62SOlivier Sobrie static const struct i2c_device_id ili210x_i2c_id[] = { 43949588917SMarek Vasut { "ili210x", MODEL_ILI210X }, 440*eb91ecc9SMarek Vasut { "ili2117", MODEL_ILI211X }, 44149588917SMarek Vasut { "ili251x", MODEL_ILI251X }, 4425c6a7a62SOlivier Sobrie { } 4435c6a7a62SOlivier Sobrie }; 4445c6a7a62SOlivier Sobrie MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); 4455c6a7a62SOlivier Sobrie 446c5d0e4b5SMarek Vasut static const struct of_device_id ili210x_dt_ids[] = { 44749588917SMarek Vasut { .compatible = "ilitek,ili210x", .data = (void *)MODEL_ILI210X }, 448*eb91ecc9SMarek Vasut { .compatible = "ilitek,ili2117", .data = (void *)MODEL_ILI211X }, 44949588917SMarek Vasut { .compatible = "ilitek,ili251x", .data = (void *)MODEL_ILI251X }, 450c5d0e4b5SMarek Vasut { }, 451c5d0e4b5SMarek Vasut }; 452c5d0e4b5SMarek Vasut MODULE_DEVICE_TABLE(of, ili210x_dt_ids); 453c5d0e4b5SMarek Vasut 4545c6a7a62SOlivier Sobrie static struct i2c_driver ili210x_ts_driver = { 4555c6a7a62SOlivier Sobrie .driver = { 4565c6a7a62SOlivier Sobrie .name = "ili210x_i2c", 4575c6a7a62SOlivier Sobrie .pm = &ili210x_i2c_pm, 458c5d0e4b5SMarek Vasut .of_match_table = ili210x_dt_ids, 4595c6a7a62SOlivier Sobrie }, 4605c6a7a62SOlivier Sobrie .id_table = ili210x_i2c_id, 4615c6a7a62SOlivier Sobrie .probe = ili210x_i2c_probe, 4625c6a7a62SOlivier Sobrie }; 4635c6a7a62SOlivier Sobrie 4645c6a7a62SOlivier Sobrie module_i2c_driver(ili210x_ts_driver); 4655c6a7a62SOlivier Sobrie 4665c6a7a62SOlivier Sobrie MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>"); 4675c6a7a62SOlivier Sobrie MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver"); 4685c6a7a62SOlivier Sobrie MODULE_LICENSE("GPL"); 469