15c6a7a62SOlivier Sobrie #include <linux/module.h> 25c6a7a62SOlivier Sobrie #include <linux/i2c.h> 35c6a7a62SOlivier Sobrie #include <linux/interrupt.h> 45c6a7a62SOlivier Sobrie #include <linux/slab.h> 55c6a7a62SOlivier Sobrie #include <linux/input.h> 65c6a7a62SOlivier Sobrie #include <linux/input/mt.h> 75c6a7a62SOlivier Sobrie #include <linux/delay.h> 85c6a7a62SOlivier Sobrie #include <linux/workqueue.h> 9201f3c80SMarek Vasut #include <linux/gpio/consumer.h> 10*49588917SMarek Vasut #include <linux/of_device.h> 11e3559442SMarek Vasut #include <asm/unaligned.h> 125c6a7a62SOlivier Sobrie 13*49588917SMarek Vasut #define ILI210X_TOUCHES 2 14*49588917SMarek Vasut #define ILI251X_TOUCHES 10 155c6a7a62SOlivier Sobrie #define DEFAULT_POLL_PERIOD 20 165c6a7a62SOlivier Sobrie 175c6a7a62SOlivier Sobrie /* Touchscreen commands */ 185c6a7a62SOlivier Sobrie #define REG_TOUCHDATA 0x10 195c6a7a62SOlivier Sobrie #define REG_PANEL_INFO 0x20 205c6a7a62SOlivier Sobrie #define REG_FIRMWARE_VERSION 0x40 215c6a7a62SOlivier Sobrie #define REG_CALIBRATE 0xcc 225c6a7a62SOlivier Sobrie 23e3559442SMarek Vasut struct panel_info { 245c6a7a62SOlivier Sobrie u8 x_low; 255c6a7a62SOlivier Sobrie u8 x_high; 265c6a7a62SOlivier Sobrie u8 y_low; 275c6a7a62SOlivier Sobrie u8 y_high; 285c6a7a62SOlivier Sobrie u8 xchannel_num; 295c6a7a62SOlivier Sobrie u8 ychannel_num; 305c6a7a62SOlivier Sobrie } __packed; 315c6a7a62SOlivier Sobrie 325c6a7a62SOlivier Sobrie struct firmware_version { 335c6a7a62SOlivier Sobrie u8 id; 345c6a7a62SOlivier Sobrie u8 major; 355c6a7a62SOlivier Sobrie u8 minor; 365c6a7a62SOlivier Sobrie } __packed; 375c6a7a62SOlivier Sobrie 38*49588917SMarek Vasut enum ili2xxx_model { 39*49588917SMarek Vasut MODEL_ILI210X, 40*49588917SMarek Vasut MODEL_ILI251X, 41*49588917SMarek Vasut }; 42*49588917SMarek Vasut 435c6a7a62SOlivier Sobrie struct ili210x { 445c6a7a62SOlivier Sobrie struct i2c_client *client; 455c6a7a62SOlivier Sobrie struct input_dev *input; 465c6a7a62SOlivier Sobrie unsigned int poll_period; 475c6a7a62SOlivier Sobrie struct delayed_work dwork; 48201f3c80SMarek Vasut struct gpio_desc *reset_gpio; 49*49588917SMarek Vasut enum ili2xxx_model model; 50*49588917SMarek Vasut unsigned int max_touches; 515c6a7a62SOlivier Sobrie }; 525c6a7a62SOlivier Sobrie 535c6a7a62SOlivier Sobrie static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf, 545c6a7a62SOlivier Sobrie size_t len) 555c6a7a62SOlivier Sobrie { 56*49588917SMarek Vasut struct ili210x *priv = i2c_get_clientdata(client); 575c6a7a62SOlivier Sobrie struct i2c_msg msg[2] = { 585c6a7a62SOlivier Sobrie { 595c6a7a62SOlivier Sobrie .addr = client->addr, 605c6a7a62SOlivier Sobrie .flags = 0, 615c6a7a62SOlivier Sobrie .len = 1, 625c6a7a62SOlivier Sobrie .buf = ®, 635c6a7a62SOlivier Sobrie }, 645c6a7a62SOlivier Sobrie { 655c6a7a62SOlivier Sobrie .addr = client->addr, 665c6a7a62SOlivier Sobrie .flags = I2C_M_RD, 675c6a7a62SOlivier Sobrie .len = len, 685c6a7a62SOlivier Sobrie .buf = buf, 695c6a7a62SOlivier Sobrie } 705c6a7a62SOlivier Sobrie }; 715c6a7a62SOlivier Sobrie 72*49588917SMarek Vasut if (priv->model == MODEL_ILI251X) { 73*49588917SMarek Vasut if (i2c_transfer(client->adapter, msg, 1) != 1) { 74*49588917SMarek Vasut dev_err(&client->dev, "i2c transfer failed\n"); 75*49588917SMarek Vasut return -EIO; 76*49588917SMarek Vasut } 77*49588917SMarek Vasut 78*49588917SMarek Vasut usleep_range(5000, 5500); 79*49588917SMarek Vasut 80*49588917SMarek Vasut if (i2c_transfer(client->adapter, msg + 1, 1) != 1) { 81*49588917SMarek Vasut dev_err(&client->dev, "i2c transfer failed\n"); 82*49588917SMarek Vasut return -EIO; 83*49588917SMarek Vasut } 84*49588917SMarek Vasut } else { 855c6a7a62SOlivier Sobrie if (i2c_transfer(client->adapter, msg, 2) != 2) { 865c6a7a62SOlivier Sobrie dev_err(&client->dev, "i2c transfer failed\n"); 875c6a7a62SOlivier Sobrie return -EIO; 885c6a7a62SOlivier Sobrie } 89*49588917SMarek Vasut } 90*49588917SMarek Vasut 91*49588917SMarek Vasut return 0; 92*49588917SMarek Vasut } 93*49588917SMarek Vasut 94*49588917SMarek Vasut static int ili210x_read(struct i2c_client *client, void *buf, size_t len) 95*49588917SMarek Vasut { 96*49588917SMarek Vasut struct i2c_msg msg = { 97*49588917SMarek Vasut .addr = client->addr, 98*49588917SMarek Vasut .flags = I2C_M_RD, 99*49588917SMarek Vasut .len = len, 100*49588917SMarek Vasut .buf = buf, 101*49588917SMarek Vasut }; 102*49588917SMarek Vasut 103*49588917SMarek Vasut if (i2c_transfer(client->adapter, &msg, 1) != 1) { 104*49588917SMarek Vasut dev_err(&client->dev, "i2c transfer failed\n"); 105*49588917SMarek Vasut return -EIO; 106*49588917SMarek Vasut } 1075c6a7a62SOlivier Sobrie 1085c6a7a62SOlivier Sobrie return 0; 1095c6a7a62SOlivier Sobrie } 1105c6a7a62SOlivier Sobrie 111e3559442SMarek Vasut static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, 112e3559442SMarek Vasut unsigned int finger, 113e3559442SMarek Vasut unsigned int *x, unsigned int *y) 1145c6a7a62SOlivier Sobrie { 115*49588917SMarek Vasut if (finger >= ILI210X_TOUCHES) 116e3559442SMarek Vasut return false; 117e3559442SMarek Vasut 118e3559442SMarek Vasut if (touchdata[0] & BIT(finger)) 119e3559442SMarek Vasut return false; 120e3559442SMarek Vasut 121e3559442SMarek Vasut *x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0); 122e3559442SMarek Vasut *y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2); 123e3559442SMarek Vasut 124e3559442SMarek Vasut return true; 125e3559442SMarek Vasut } 126e3559442SMarek Vasut 127*49588917SMarek Vasut static bool ili251x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, 128*49588917SMarek Vasut unsigned int finger, 129*49588917SMarek Vasut unsigned int *x, unsigned int *y) 130*49588917SMarek Vasut { 131*49588917SMarek Vasut if (finger >= ILI251X_TOUCHES) 132*49588917SMarek Vasut return false; 133*49588917SMarek Vasut 134*49588917SMarek Vasut *x = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0); 135*49588917SMarek Vasut if (!(*x & BIT(15))) /* Touch indication */ 136*49588917SMarek Vasut return false; 137*49588917SMarek Vasut 138*49588917SMarek Vasut *x &= 0x3fff; 139*49588917SMarek Vasut *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2); 140*49588917SMarek Vasut 141*49588917SMarek Vasut return true; 142*49588917SMarek Vasut } 143*49588917SMarek Vasut 144e3559442SMarek Vasut static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) 145e3559442SMarek Vasut { 146e3559442SMarek Vasut struct input_dev *input = priv->input; 1475c6a7a62SOlivier Sobrie int i; 148*49588917SMarek Vasut bool contact = false, touch = false; 149*49588917SMarek Vasut unsigned int x = 0, y = 0; 1505c6a7a62SOlivier Sobrie 151*49588917SMarek Vasut for (i = 0; i < priv->max_touches; i++) { 1525c6a7a62SOlivier Sobrie input_mt_slot(input, i); 1535c6a7a62SOlivier Sobrie 154*49588917SMarek Vasut if (priv->model == MODEL_ILI210X) { 155*49588917SMarek Vasut touch = ili210x_touchdata_to_coords(priv, touchdata, 156*49588917SMarek Vasut i, &x, &y); 157*49588917SMarek Vasut } else if (priv->model == MODEL_ILI251X) { 158*49588917SMarek Vasut touch = ili251x_touchdata_to_coords(priv, touchdata, 159*49588917SMarek Vasut i, &x, &y); 160*49588917SMarek Vasut if (touch) 161*49588917SMarek Vasut contact = true; 162*49588917SMarek Vasut } 163*49588917SMarek Vasut 1645c6a7a62SOlivier Sobrie input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); 1655c6a7a62SOlivier Sobrie if (touch) { 1665c6a7a62SOlivier Sobrie input_report_abs(input, ABS_MT_POSITION_X, x); 1675c6a7a62SOlivier Sobrie input_report_abs(input, ABS_MT_POSITION_Y, y); 1685c6a7a62SOlivier Sobrie } 1695c6a7a62SOlivier Sobrie } 1705c6a7a62SOlivier Sobrie 1715c6a7a62SOlivier Sobrie input_mt_report_pointer_emulation(input, false); 1725c6a7a62SOlivier Sobrie input_sync(input); 173e3559442SMarek Vasut 174*49588917SMarek Vasut if (priv->model == MODEL_ILI210X) 175*49588917SMarek Vasut contact = touchdata[0] & 0xf3; 176*49588917SMarek Vasut 177*49588917SMarek Vasut return contact; 1785c6a7a62SOlivier Sobrie } 1795c6a7a62SOlivier Sobrie 1805c6a7a62SOlivier Sobrie static void ili210x_work(struct work_struct *work) 1815c6a7a62SOlivier Sobrie { 1825c6a7a62SOlivier Sobrie struct ili210x *priv = container_of(work, struct ili210x, 1835c6a7a62SOlivier Sobrie dwork.work); 1845c6a7a62SOlivier Sobrie struct i2c_client *client = priv->client; 185*49588917SMarek Vasut u8 touchdata[64] = { 0 }; 186e3559442SMarek Vasut bool touch; 187*49588917SMarek Vasut int error = -EINVAL; 1885c6a7a62SOlivier Sobrie 189*49588917SMarek Vasut if (priv->model == MODEL_ILI210X) { 1905c6a7a62SOlivier Sobrie error = ili210x_read_reg(client, REG_TOUCHDATA, 191e3559442SMarek Vasut touchdata, sizeof(touchdata)); 192*49588917SMarek Vasut } else if (priv->model == MODEL_ILI251X) { 193*49588917SMarek Vasut error = ili210x_read_reg(client, REG_TOUCHDATA, 194*49588917SMarek Vasut touchdata, 31); 195*49588917SMarek Vasut if (!error && touchdata[0] == 2) 196*49588917SMarek Vasut error = ili210x_read(client, &touchdata[31], 20); 197*49588917SMarek Vasut } 198*49588917SMarek Vasut 1995c6a7a62SOlivier Sobrie if (error) { 2005c6a7a62SOlivier Sobrie dev_err(&client->dev, 2015c6a7a62SOlivier Sobrie "Unable to get touchdata, err = %d\n", error); 2025c6a7a62SOlivier Sobrie return; 2035c6a7a62SOlivier Sobrie } 2045c6a7a62SOlivier Sobrie 205e3559442SMarek Vasut touch = ili210x_report_events(priv, touchdata); 2065c6a7a62SOlivier Sobrie 207e3559442SMarek Vasut if (touch) 2085c6a7a62SOlivier Sobrie schedule_delayed_work(&priv->dwork, 2095c6a7a62SOlivier Sobrie msecs_to_jiffies(priv->poll_period)); 2105c6a7a62SOlivier Sobrie } 2115c6a7a62SOlivier Sobrie 2125c6a7a62SOlivier Sobrie static irqreturn_t ili210x_irq(int irq, void *irq_data) 2135c6a7a62SOlivier Sobrie { 2145c6a7a62SOlivier Sobrie struct ili210x *priv = irq_data; 2155c6a7a62SOlivier Sobrie 2165c6a7a62SOlivier Sobrie schedule_delayed_work(&priv->dwork, 0); 2175c6a7a62SOlivier Sobrie 2185c6a7a62SOlivier Sobrie return IRQ_HANDLED; 2195c6a7a62SOlivier Sobrie } 2205c6a7a62SOlivier Sobrie 2215c6a7a62SOlivier Sobrie static ssize_t ili210x_calibrate(struct device *dev, 2225c6a7a62SOlivier Sobrie struct device_attribute *attr, 2235c6a7a62SOlivier Sobrie const char *buf, size_t count) 2245c6a7a62SOlivier Sobrie { 2255c6a7a62SOlivier Sobrie struct i2c_client *client = to_i2c_client(dev); 2265c6a7a62SOlivier Sobrie struct ili210x *priv = i2c_get_clientdata(client); 2275c6a7a62SOlivier Sobrie unsigned long calibrate; 2285c6a7a62SOlivier Sobrie int rc; 2295c6a7a62SOlivier Sobrie u8 cmd = REG_CALIBRATE; 2305c6a7a62SOlivier Sobrie 2315c6a7a62SOlivier Sobrie if (kstrtoul(buf, 10, &calibrate)) 2325c6a7a62SOlivier Sobrie return -EINVAL; 2335c6a7a62SOlivier Sobrie 2345c6a7a62SOlivier Sobrie if (calibrate > 1) 2355c6a7a62SOlivier Sobrie return -EINVAL; 2365c6a7a62SOlivier Sobrie 2375c6a7a62SOlivier Sobrie if (calibrate) { 2385c6a7a62SOlivier Sobrie rc = i2c_master_send(priv->client, &cmd, sizeof(cmd)); 2395c6a7a62SOlivier Sobrie if (rc != sizeof(cmd)) 2405c6a7a62SOlivier Sobrie return -EIO; 2415c6a7a62SOlivier Sobrie } 2425c6a7a62SOlivier Sobrie 2435c6a7a62SOlivier Sobrie return count; 2445c6a7a62SOlivier Sobrie } 245b27c0d0cSDmitry Torokhov static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate); 2465c6a7a62SOlivier Sobrie 2475c6a7a62SOlivier Sobrie static struct attribute *ili210x_attributes[] = { 2485c6a7a62SOlivier Sobrie &dev_attr_calibrate.attr, 2495c6a7a62SOlivier Sobrie NULL, 2505c6a7a62SOlivier Sobrie }; 2515c6a7a62SOlivier Sobrie 2525c6a7a62SOlivier Sobrie static const struct attribute_group ili210x_attr_group = { 2535c6a7a62SOlivier Sobrie .attrs = ili210x_attributes, 2545c6a7a62SOlivier Sobrie }; 2555c6a7a62SOlivier Sobrie 256201f3c80SMarek Vasut static void ili210x_power_down(void *data) 257201f3c80SMarek Vasut { 258201f3c80SMarek Vasut struct gpio_desc *reset_gpio = data; 259201f3c80SMarek Vasut 260201f3c80SMarek Vasut gpiod_set_value_cansleep(reset_gpio, 1); 261201f3c80SMarek Vasut } 262201f3c80SMarek Vasut 2631bdec5d9SMarek Vasut static void ili210x_cancel_work(void *data) 2641bdec5d9SMarek Vasut { 2651bdec5d9SMarek Vasut struct ili210x *priv = data; 2661bdec5d9SMarek Vasut 2671bdec5d9SMarek Vasut cancel_delayed_work_sync(&priv->dwork); 2681bdec5d9SMarek Vasut } 2691bdec5d9SMarek Vasut 2705298cc4cSBill Pemberton static int ili210x_i2c_probe(struct i2c_client *client, 2715c6a7a62SOlivier Sobrie const struct i2c_device_id *id) 2725c6a7a62SOlivier Sobrie { 2735c6a7a62SOlivier Sobrie struct device *dev = &client->dev; 2745c6a7a62SOlivier Sobrie struct ili210x *priv; 275201f3c80SMarek Vasut struct gpio_desc *reset_gpio; 2765c6a7a62SOlivier Sobrie struct input_dev *input; 2775c6a7a62SOlivier Sobrie struct panel_info panel; 2785c6a7a62SOlivier Sobrie struct firmware_version firmware; 279*49588917SMarek Vasut enum ili2xxx_model model; 2805c6a7a62SOlivier Sobrie int xmax, ymax; 2815c6a7a62SOlivier Sobrie int error; 2825c6a7a62SOlivier Sobrie 283*49588917SMarek Vasut model = (enum ili2xxx_model)id->driver_data; 284*49588917SMarek Vasut 2855c6a7a62SOlivier Sobrie dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver"); 2865c6a7a62SOlivier Sobrie 2875c6a7a62SOlivier Sobrie if (client->irq <= 0) { 2885c6a7a62SOlivier Sobrie dev_err(dev, "No IRQ!\n"); 2895c6a7a62SOlivier Sobrie return -EINVAL; 2905c6a7a62SOlivier Sobrie } 2915c6a7a62SOlivier Sobrie 292201f3c80SMarek Vasut reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 293201f3c80SMarek Vasut if (IS_ERR(reset_gpio)) 294201f3c80SMarek Vasut return PTR_ERR(reset_gpio); 295201f3c80SMarek Vasut 296201f3c80SMarek Vasut if (reset_gpio) { 297201f3c80SMarek Vasut error = devm_add_action_or_reset(dev, ili210x_power_down, 298201f3c80SMarek Vasut reset_gpio); 299201f3c80SMarek Vasut if (error) 300201f3c80SMarek Vasut return error; 301201f3c80SMarek Vasut 302201f3c80SMarek Vasut usleep_range(50, 100); 303201f3c80SMarek Vasut gpiod_set_value_cansleep(reset_gpio, 0); 304201f3c80SMarek Vasut msleep(100); 305201f3c80SMarek Vasut } 306201f3c80SMarek Vasut 30712294577SMarek Vasut priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 30812294577SMarek Vasut if (!priv) 30912294577SMarek Vasut return -ENOMEM; 31012294577SMarek Vasut 31112294577SMarek Vasut input = devm_input_allocate_device(dev); 31212294577SMarek Vasut if (!input) 31312294577SMarek Vasut return -ENOMEM; 31412294577SMarek Vasut 31512294577SMarek Vasut priv->client = client; 31612294577SMarek Vasut priv->input = input; 31712294577SMarek Vasut priv->poll_period = DEFAULT_POLL_PERIOD; 31812294577SMarek Vasut INIT_DELAYED_WORK(&priv->dwork, ili210x_work); 31912294577SMarek Vasut priv->reset_gpio = reset_gpio; 320*49588917SMarek Vasut priv->model = model; 321*49588917SMarek Vasut if (model == MODEL_ILI210X) 322*49588917SMarek Vasut priv->max_touches = ILI210X_TOUCHES; 323*49588917SMarek Vasut if (model == MODEL_ILI251X) 324*49588917SMarek Vasut priv->max_touches = ILI251X_TOUCHES; 32512294577SMarek Vasut 32612294577SMarek Vasut i2c_set_clientdata(client, priv); 32712294577SMarek Vasut 3285c6a7a62SOlivier Sobrie /* Get firmware version */ 3295c6a7a62SOlivier Sobrie error = ili210x_read_reg(client, REG_FIRMWARE_VERSION, 3305c6a7a62SOlivier Sobrie &firmware, sizeof(firmware)); 3315c6a7a62SOlivier Sobrie if (error) { 3325c6a7a62SOlivier Sobrie dev_err(dev, "Failed to get firmware version, err: %d\n", 3335c6a7a62SOlivier Sobrie error); 3345c6a7a62SOlivier Sobrie return error; 3355c6a7a62SOlivier Sobrie } 3365c6a7a62SOlivier Sobrie 3375c6a7a62SOlivier Sobrie /* get panel info */ 3385c6a7a62SOlivier Sobrie error = ili210x_read_reg(client, REG_PANEL_INFO, &panel, sizeof(panel)); 3395c6a7a62SOlivier Sobrie if (error) { 340971bd8faSMasanari Iida dev_err(dev, "Failed to get panel information, err: %d\n", 3415c6a7a62SOlivier Sobrie error); 3425c6a7a62SOlivier Sobrie return error; 3435c6a7a62SOlivier Sobrie } 3445c6a7a62SOlivier Sobrie 345e3559442SMarek Vasut xmax = panel.x_low | (panel.x_high << 8); 346e3559442SMarek Vasut ymax = panel.y_low | (panel.y_high << 8); 3475c6a7a62SOlivier Sobrie 3485c6a7a62SOlivier Sobrie /* Setup input device */ 3495c6a7a62SOlivier Sobrie input->name = "ILI210x Touchscreen"; 3505c6a7a62SOlivier Sobrie input->id.bustype = BUS_I2C; 3515c6a7a62SOlivier Sobrie input->dev.parent = dev; 3525c6a7a62SOlivier Sobrie 3535c6a7a62SOlivier Sobrie __set_bit(EV_SYN, input->evbit); 3545c6a7a62SOlivier Sobrie __set_bit(EV_KEY, input->evbit); 3555c6a7a62SOlivier Sobrie __set_bit(EV_ABS, input->evbit); 3565c6a7a62SOlivier Sobrie __set_bit(BTN_TOUCH, input->keybit); 3575c6a7a62SOlivier Sobrie 3585c6a7a62SOlivier Sobrie /* Single touch */ 3595c6a7a62SOlivier Sobrie input_set_abs_params(input, ABS_X, 0, xmax, 0, 0); 3605c6a7a62SOlivier Sobrie input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0); 3615c6a7a62SOlivier Sobrie 3625c6a7a62SOlivier Sobrie /* Multi touch */ 363*49588917SMarek Vasut input_mt_init_slots(input, priv->max_touches, 0); 3645c6a7a62SOlivier Sobrie input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0); 3655c6a7a62SOlivier Sobrie input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0); 3665c6a7a62SOlivier Sobrie 3671bdec5d9SMarek Vasut error = devm_add_action(dev, ili210x_cancel_work, priv); 3681bdec5d9SMarek Vasut if (error) 3691bdec5d9SMarek Vasut return error; 3701bdec5d9SMarek Vasut 3711bdec5d9SMarek Vasut error = devm_request_irq(dev, client->irq, ili210x_irq, 0, 3725c6a7a62SOlivier Sobrie client->name, priv); 3735c6a7a62SOlivier Sobrie if (error) { 3745c6a7a62SOlivier Sobrie dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n", 3755c6a7a62SOlivier Sobrie error); 3761bdec5d9SMarek Vasut return error; 3775c6a7a62SOlivier Sobrie } 3785c6a7a62SOlivier Sobrie 3795c6a7a62SOlivier Sobrie error = sysfs_create_group(&dev->kobj, &ili210x_attr_group); 3805c6a7a62SOlivier Sobrie if (error) { 3815c6a7a62SOlivier Sobrie dev_err(dev, "Unable to create sysfs attributes, err: %d\n", 3825c6a7a62SOlivier Sobrie error); 3831bdec5d9SMarek Vasut return error; 3845c6a7a62SOlivier Sobrie } 3855c6a7a62SOlivier Sobrie 3865c6a7a62SOlivier Sobrie error = input_register_device(priv->input); 3875c6a7a62SOlivier Sobrie if (error) { 388971bd8faSMasanari Iida dev_err(dev, "Cannot register input device, err: %d\n", error); 3895c6a7a62SOlivier Sobrie goto err_remove_sysfs; 3905c6a7a62SOlivier Sobrie } 3915c6a7a62SOlivier Sobrie 392d7ddf154SGuenter Roeck device_init_wakeup(dev, 1); 3935c6a7a62SOlivier Sobrie 3945c6a7a62SOlivier Sobrie dev_dbg(dev, 3955c6a7a62SOlivier Sobrie "ILI210x initialized (IRQ: %d), firmware version %d.%d.%d", 3965c6a7a62SOlivier Sobrie client->irq, firmware.id, firmware.major, firmware.minor); 3975c6a7a62SOlivier Sobrie 3985c6a7a62SOlivier Sobrie return 0; 3995c6a7a62SOlivier Sobrie 4005c6a7a62SOlivier Sobrie err_remove_sysfs: 4015c6a7a62SOlivier Sobrie sysfs_remove_group(&dev->kobj, &ili210x_attr_group); 4025c6a7a62SOlivier Sobrie return error; 4035c6a7a62SOlivier Sobrie } 4045c6a7a62SOlivier Sobrie 405e2619cf7SBill Pemberton static int ili210x_i2c_remove(struct i2c_client *client) 4065c6a7a62SOlivier Sobrie { 4075c6a7a62SOlivier Sobrie sysfs_remove_group(&client->dev.kobj, &ili210x_attr_group); 4085c6a7a62SOlivier Sobrie 4095c6a7a62SOlivier Sobrie return 0; 4105c6a7a62SOlivier Sobrie } 4115c6a7a62SOlivier Sobrie 41202b6a58bSJingoo Han static int __maybe_unused ili210x_i2c_suspend(struct device *dev) 4135c6a7a62SOlivier Sobrie { 4145c6a7a62SOlivier Sobrie struct i2c_client *client = to_i2c_client(dev); 4155c6a7a62SOlivier Sobrie 4165c6a7a62SOlivier Sobrie if (device_may_wakeup(&client->dev)) 4175c6a7a62SOlivier Sobrie enable_irq_wake(client->irq); 4185c6a7a62SOlivier Sobrie 4195c6a7a62SOlivier Sobrie return 0; 4205c6a7a62SOlivier Sobrie } 4215c6a7a62SOlivier Sobrie 42202b6a58bSJingoo Han static int __maybe_unused ili210x_i2c_resume(struct device *dev) 4235c6a7a62SOlivier Sobrie { 4245c6a7a62SOlivier Sobrie struct i2c_client *client = to_i2c_client(dev); 4255c6a7a62SOlivier Sobrie 4265c6a7a62SOlivier Sobrie if (device_may_wakeup(&client->dev)) 4275c6a7a62SOlivier Sobrie disable_irq_wake(client->irq); 4285c6a7a62SOlivier Sobrie 4295c6a7a62SOlivier Sobrie return 0; 4305c6a7a62SOlivier Sobrie } 4315c6a7a62SOlivier Sobrie 4325c6a7a62SOlivier Sobrie static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm, 4335c6a7a62SOlivier Sobrie ili210x_i2c_suspend, ili210x_i2c_resume); 4345c6a7a62SOlivier Sobrie 4355c6a7a62SOlivier Sobrie static const struct i2c_device_id ili210x_i2c_id[] = { 436*49588917SMarek Vasut { "ili210x", MODEL_ILI210X }, 437*49588917SMarek Vasut { "ili251x", MODEL_ILI251X }, 4385c6a7a62SOlivier Sobrie { } 4395c6a7a62SOlivier Sobrie }; 4405c6a7a62SOlivier Sobrie MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); 4415c6a7a62SOlivier Sobrie 442c5d0e4b5SMarek Vasut static const struct of_device_id ili210x_dt_ids[] = { 443*49588917SMarek Vasut { .compatible = "ilitek,ili210x", .data = (void *)MODEL_ILI210X }, 444*49588917SMarek Vasut { .compatible = "ilitek,ili251x", .data = (void *)MODEL_ILI251X }, 445c5d0e4b5SMarek Vasut { }, 446c5d0e4b5SMarek Vasut }; 447c5d0e4b5SMarek Vasut MODULE_DEVICE_TABLE(of, ili210x_dt_ids); 448c5d0e4b5SMarek Vasut 4495c6a7a62SOlivier Sobrie static struct i2c_driver ili210x_ts_driver = { 4505c6a7a62SOlivier Sobrie .driver = { 4515c6a7a62SOlivier Sobrie .name = "ili210x_i2c", 4525c6a7a62SOlivier Sobrie .pm = &ili210x_i2c_pm, 453c5d0e4b5SMarek Vasut .of_match_table = ili210x_dt_ids, 4545c6a7a62SOlivier Sobrie }, 4555c6a7a62SOlivier Sobrie .id_table = ili210x_i2c_id, 4565c6a7a62SOlivier Sobrie .probe = ili210x_i2c_probe, 4571cb0aa88SBill Pemberton .remove = ili210x_i2c_remove, 4585c6a7a62SOlivier Sobrie }; 4595c6a7a62SOlivier Sobrie 4605c6a7a62SOlivier Sobrie module_i2c_driver(ili210x_ts_driver); 4615c6a7a62SOlivier Sobrie 4625c6a7a62SOlivier Sobrie MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>"); 4635c6a7a62SOlivier Sobrie MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver"); 4645c6a7a62SOlivier Sobrie MODULE_LICENSE("GPL"); 465