root/drivers/input/touchscreen/ili210x.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ili210x_read_reg
  2. ili210x_read
  3. ili210x_touchdata_to_coords
  4. ili251x_touchdata_to_coords
  5. ili210x_report_events
  6. ili210x_work
  7. ili210x_irq
  8. ili210x_calibrate
  9. ili210x_power_down
  10. ili210x_cancel_work
  11. ili210x_i2c_probe
  12. ili210x_i2c_suspend
  13. ili210x_i2c_resume

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 #include <linux/module.h>
   3 #include <linux/i2c.h>
   4 #include <linux/interrupt.h>
   5 #include <linux/slab.h>
   6 #include <linux/input.h>
   7 #include <linux/input/mt.h>
   8 #include <linux/input/touchscreen.h>
   9 #include <linux/delay.h>
  10 #include <linux/workqueue.h>
  11 #include <linux/gpio/consumer.h>
  12 #include <linux/of_device.h>
  13 #include <asm/unaligned.h>
  14 
  15 #define ILI210X_TOUCHES         2
  16 #define ILI251X_TOUCHES         10
  17 #define DEFAULT_POLL_PERIOD     20
  18 
  19 /* Touchscreen commands */
  20 #define REG_TOUCHDATA           0x10
  21 #define REG_PANEL_INFO          0x20
  22 #define REG_FIRMWARE_VERSION    0x40
  23 #define REG_CALIBRATE           0xcc
  24 
  25 struct firmware_version {
  26         u8 id;
  27         u8 major;
  28         u8 minor;
  29 } __packed;
  30 
  31 enum ili2xxx_model {
  32         MODEL_ILI210X,
  33         MODEL_ILI251X,
  34 };
  35 
  36 struct ili210x {
  37         struct i2c_client *client;
  38         struct input_dev *input;
  39         unsigned int poll_period;
  40         struct delayed_work dwork;
  41         struct gpio_desc *reset_gpio;
  42         struct touchscreen_properties prop;
  43         enum ili2xxx_model model;
  44         unsigned int max_touches;
  45 };
  46 
  47 static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf,
  48                             size_t len)
  49 {
  50         struct ili210x *priv = i2c_get_clientdata(client);
  51         struct i2c_msg msg[2] = {
  52                 {
  53                         .addr   = client->addr,
  54                         .flags  = 0,
  55                         .len    = 1,
  56                         .buf    = &reg,
  57                 },
  58                 {
  59                         .addr   = client->addr,
  60                         .flags  = I2C_M_RD,
  61                         .len    = len,
  62                         .buf    = buf,
  63                 }
  64         };
  65 
  66         if (priv->model == MODEL_ILI251X) {
  67                 if (i2c_transfer(client->adapter, msg, 1) != 1) {
  68                         dev_err(&client->dev, "i2c transfer failed\n");
  69                         return -EIO;
  70                 }
  71 
  72                 usleep_range(5000, 5500);
  73 
  74                 if (i2c_transfer(client->adapter, msg + 1, 1) != 1) {
  75                         dev_err(&client->dev, "i2c transfer failed\n");
  76                         return -EIO;
  77                 }
  78         } else {
  79                 if (i2c_transfer(client->adapter, msg, 2) != 2) {
  80                         dev_err(&client->dev, "i2c transfer failed\n");
  81                         return -EIO;
  82                 }
  83         }
  84 
  85         return 0;
  86 }
  87 
  88 static int ili210x_read(struct i2c_client *client, void *buf, size_t len)
  89 {
  90         struct i2c_msg msg = {
  91                 .addr   = client->addr,
  92                 .flags  = I2C_M_RD,
  93                 .len    = len,
  94                 .buf    = buf,
  95         };
  96 
  97         if (i2c_transfer(client->adapter, &msg, 1) != 1) {
  98                 dev_err(&client->dev, "i2c transfer failed\n");
  99                 return -EIO;
 100         }
 101 
 102         return 0;
 103 }
 104 
 105 static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
 106                                         unsigned int finger,
 107                                         unsigned int *x, unsigned int *y)
 108 {
 109         if (finger >= ILI210X_TOUCHES)
 110                 return false;
 111 
 112         if (touchdata[0] & BIT(finger))
 113                 return false;
 114 
 115         *x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0);
 116         *y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2);
 117 
 118         return true;
 119 }
 120 
 121 static bool ili251x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata,
 122                                         unsigned int finger,
 123                                         unsigned int *x, unsigned int *y)
 124 {
 125         if (finger >= ILI251X_TOUCHES)
 126                 return false;
 127 
 128         *x = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0);
 129         if (!(*x & BIT(15)))    /* Touch indication */
 130                 return false;
 131 
 132         *x &= 0x3fff;
 133         *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2);
 134 
 135         return true;
 136 }
 137 
 138 static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata)
 139 {
 140         struct input_dev *input = priv->input;
 141         int i;
 142         bool contact = false, touch = false;
 143         unsigned int x = 0, y = 0;
 144 
 145         for (i = 0; i < priv->max_touches; i++) {
 146                 if (priv->model == MODEL_ILI210X) {
 147                         touch = ili210x_touchdata_to_coords(priv, touchdata,
 148                                                             i, &x, &y);
 149                 } else if (priv->model == MODEL_ILI251X) {
 150                         touch = ili251x_touchdata_to_coords(priv, touchdata,
 151                                                             i, &x, &y);
 152                         if (touch)
 153                                 contact = true;
 154                 }
 155 
 156                 input_mt_slot(input, i);
 157                 input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
 158                 if (!touch)
 159                         continue;
 160                 touchscreen_report_pos(input, &priv->prop, x, y,
 161                                        true);
 162         }
 163 
 164         input_mt_report_pointer_emulation(input, false);
 165         input_sync(input);
 166 
 167         if (priv->model == MODEL_ILI210X)
 168                 contact = touchdata[0] & 0xf3;
 169 
 170         return contact;
 171 }
 172 
 173 static void ili210x_work(struct work_struct *work)
 174 {
 175         struct ili210x *priv = container_of(work, struct ili210x,
 176                                             dwork.work);
 177         struct i2c_client *client = priv->client;
 178         u8 touchdata[64] = { 0 };
 179         bool touch;
 180         int error = -EINVAL;
 181 
 182         if (priv->model == MODEL_ILI210X) {
 183                 error = ili210x_read_reg(client, REG_TOUCHDATA,
 184                                          touchdata, sizeof(touchdata));
 185         } else if (priv->model == MODEL_ILI251X) {
 186                 error = ili210x_read_reg(client, REG_TOUCHDATA,
 187                                          touchdata, 31);
 188                 if (!error && touchdata[0] == 2)
 189                         error = ili210x_read(client, &touchdata[31], 20);
 190         }
 191 
 192         if (error) {
 193                 dev_err(&client->dev,
 194                         "Unable to get touchdata, err = %d\n", error);
 195                 return;
 196         }
 197 
 198         touch = ili210x_report_events(priv, touchdata);
 199 
 200         if (touch)
 201                 schedule_delayed_work(&priv->dwork,
 202                                       msecs_to_jiffies(priv->poll_period));
 203 }
 204 
 205 static irqreturn_t ili210x_irq(int irq, void *irq_data)
 206 {
 207         struct ili210x *priv = irq_data;
 208 
 209         schedule_delayed_work(&priv->dwork, 0);
 210 
 211         return IRQ_HANDLED;
 212 }
 213 
 214 static ssize_t ili210x_calibrate(struct device *dev,
 215                                  struct device_attribute *attr,
 216                                  const char *buf, size_t count)
 217 {
 218         struct i2c_client *client = to_i2c_client(dev);
 219         struct ili210x *priv = i2c_get_clientdata(client);
 220         unsigned long calibrate;
 221         int rc;
 222         u8 cmd = REG_CALIBRATE;
 223 
 224         if (kstrtoul(buf, 10, &calibrate))
 225                 return -EINVAL;
 226 
 227         if (calibrate > 1)
 228                 return -EINVAL;
 229 
 230         if (calibrate) {
 231                 rc = i2c_master_send(priv->client, &cmd, sizeof(cmd));
 232                 if (rc != sizeof(cmd))
 233                         return -EIO;
 234         }
 235 
 236         return count;
 237 }
 238 static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
 239 
 240 static struct attribute *ili210x_attributes[] = {
 241         &dev_attr_calibrate.attr,
 242         NULL,
 243 };
 244 
 245 static const struct attribute_group ili210x_attr_group = {
 246         .attrs = ili210x_attributes,
 247 };
 248 
 249 static void ili210x_power_down(void *data)
 250 {
 251         struct gpio_desc *reset_gpio = data;
 252 
 253         gpiod_set_value_cansleep(reset_gpio, 1);
 254 }
 255 
 256 static void ili210x_cancel_work(void *data)
 257 {
 258         struct ili210x *priv = data;
 259 
 260         cancel_delayed_work_sync(&priv->dwork);
 261 }
 262 
 263 static int ili210x_i2c_probe(struct i2c_client *client,
 264                                        const struct i2c_device_id *id)
 265 {
 266         struct device *dev = &client->dev;
 267         struct ili210x *priv;
 268         struct gpio_desc *reset_gpio;
 269         struct input_dev *input;
 270         struct firmware_version firmware;
 271         enum ili2xxx_model model;
 272         int error;
 273 
 274         model = (enum ili2xxx_model)id->driver_data;
 275 
 276         dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
 277 
 278         if (client->irq <= 0) {
 279                 dev_err(dev, "No IRQ!\n");
 280                 return -EINVAL;
 281         }
 282 
 283         reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
 284         if (IS_ERR(reset_gpio))
 285                 return PTR_ERR(reset_gpio);
 286 
 287         if (reset_gpio) {
 288                 error = devm_add_action_or_reset(dev, ili210x_power_down,
 289                                                  reset_gpio);
 290                 if (error)
 291                         return error;
 292 
 293                 usleep_range(50, 100);
 294                 gpiod_set_value_cansleep(reset_gpio, 0);
 295                 msleep(100);
 296         }
 297 
 298         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 299         if (!priv)
 300                 return -ENOMEM;
 301 
 302         input = devm_input_allocate_device(dev);
 303         if (!input)
 304                 return -ENOMEM;
 305 
 306         priv->client = client;
 307         priv->input = input;
 308         priv->poll_period = DEFAULT_POLL_PERIOD;
 309         INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
 310         priv->reset_gpio = reset_gpio;
 311         priv->model = model;
 312         if (model == MODEL_ILI210X)
 313                 priv->max_touches = ILI210X_TOUCHES;
 314         if (model == MODEL_ILI251X)
 315                 priv->max_touches = ILI251X_TOUCHES;
 316 
 317         i2c_set_clientdata(client, priv);
 318 
 319         /* Get firmware version */
 320         error = ili210x_read_reg(client, REG_FIRMWARE_VERSION,
 321                                  &firmware, sizeof(firmware));
 322         if (error) {
 323                 dev_err(dev, "Failed to get firmware version, err: %d\n",
 324                         error);
 325                 return error;
 326         }
 327 
 328         /* Setup input device */
 329         input->name = "ILI210x Touchscreen";
 330         input->id.bustype = BUS_I2C;
 331         input->dev.parent = dev;
 332 
 333         /* Multi touch */
 334         input_set_abs_params(input, ABS_MT_POSITION_X, 0, 0xffff, 0, 0);
 335         input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 0xffff, 0, 0);
 336         touchscreen_parse_properties(input, true, &priv->prop);
 337 
 338         error = input_mt_init_slots(input, priv->max_touches, INPUT_MT_DIRECT);
 339         if (error) {
 340                 dev_err(dev, "Unable to set up slots, err: %d\n", error);
 341                 return error;
 342         }
 343 
 344         error = devm_add_action(dev, ili210x_cancel_work, priv);
 345         if (error)
 346                 return error;
 347 
 348         error = devm_request_irq(dev, client->irq, ili210x_irq, 0,
 349                                  client->name, priv);
 350         if (error) {
 351                 dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
 352                         error);
 353                 return error;
 354         }
 355 
 356         error = devm_device_add_group(dev, &ili210x_attr_group);
 357         if (error) {
 358                 dev_err(dev, "Unable to create sysfs attributes, err: %d\n",
 359                         error);
 360                 return error;
 361         }
 362 
 363         error = input_register_device(priv->input);
 364         if (error) {
 365                 dev_err(dev, "Cannot register input device, err: %d\n", error);
 366                 return error;
 367         }
 368 
 369         device_init_wakeup(dev, 1);
 370 
 371         dev_dbg(dev,
 372                 "ILI210x initialized (IRQ: %d), firmware version %d.%d.%d",
 373                 client->irq, firmware.id, firmware.major, firmware.minor);
 374 
 375         return 0;
 376 }
 377 
 378 static int __maybe_unused ili210x_i2c_suspend(struct device *dev)
 379 {
 380         struct i2c_client *client = to_i2c_client(dev);
 381 
 382         if (device_may_wakeup(&client->dev))
 383                 enable_irq_wake(client->irq);
 384 
 385         return 0;
 386 }
 387 
 388 static int __maybe_unused ili210x_i2c_resume(struct device *dev)
 389 {
 390         struct i2c_client *client = to_i2c_client(dev);
 391 
 392         if (device_may_wakeup(&client->dev))
 393                 disable_irq_wake(client->irq);
 394 
 395         return 0;
 396 }
 397 
 398 static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm,
 399                          ili210x_i2c_suspend, ili210x_i2c_resume);
 400 
 401 static const struct i2c_device_id ili210x_i2c_id[] = {
 402         { "ili210x", MODEL_ILI210X },
 403         { "ili251x", MODEL_ILI251X },
 404         { }
 405 };
 406 MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
 407 
 408 static const struct of_device_id ili210x_dt_ids[] = {
 409         { .compatible = "ilitek,ili210x", .data = (void *)MODEL_ILI210X },
 410         { .compatible = "ilitek,ili251x", .data = (void *)MODEL_ILI251X },
 411         { },
 412 };
 413 MODULE_DEVICE_TABLE(of, ili210x_dt_ids);
 414 
 415 static struct i2c_driver ili210x_ts_driver = {
 416         .driver = {
 417                 .name = "ili210x_i2c",
 418                 .pm = &ili210x_i2c_pm,
 419                 .of_match_table = ili210x_dt_ids,
 420         },
 421         .id_table = ili210x_i2c_id,
 422         .probe = ili210x_i2c_probe,
 423 };
 424 
 425 module_i2c_driver(ili210x_ts_driver);
 426 
 427 MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
 428 MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver");
 429 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */