linux/drivers/input/touchscreen/ili210x.c
<<
>>
Prefs
   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/delay.h>
   9#include <linux/workqueue.h>
  10#include <linux/input/ili210x.h>
  11
  12#define MAX_TOUCHES             2
  13#define DEFAULT_POLL_PERIOD     20
  14
  15/* Touchscreen commands */
  16#define REG_TOUCHDATA           0x10
  17#define REG_PANEL_INFO          0x20
  18#define REG_FIRMWARE_VERSION    0x40
  19#define REG_CALIBRATE           0xcc
  20
  21struct finger {
  22        u8 x_low;
  23        u8 x_high;
  24        u8 y_low;
  25        u8 y_high;
  26} __packed;
  27
  28struct touchdata {
  29        u8 status;
  30        struct finger finger[MAX_TOUCHES];
  31} __packed;
  32
  33struct panel_info {
  34        struct finger finger_max;
  35        u8 xchannel_num;
  36        u8 ychannel_num;
  37} __packed;
  38
  39struct firmware_version {
  40        u8 id;
  41        u8 major;
  42        u8 minor;
  43} __packed;
  44
  45struct ili210x {
  46        struct i2c_client *client;
  47        struct input_dev *input;
  48        bool (*get_pendown_state)(void);
  49        unsigned int poll_period;
  50        struct delayed_work dwork;
  51};
  52
  53static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf,
  54                            size_t len)
  55{
  56        struct i2c_msg msg[2] = {
  57                {
  58                        .addr   = client->addr,
  59                        .flags  = 0,
  60                        .len    = 1,
  61                        .buf    = &reg,
  62                },
  63                {
  64                        .addr   = client->addr,
  65                        .flags  = I2C_M_RD,
  66                        .len    = len,
  67                        .buf    = buf,
  68                }
  69        };
  70
  71        if (i2c_transfer(client->adapter, msg, 2) != 2) {
  72                dev_err(&client->dev, "i2c transfer failed\n");
  73                return -EIO;
  74        }
  75
  76        return 0;
  77}
  78
  79static void ili210x_report_events(struct input_dev *input,
  80                                  const struct touchdata *touchdata)
  81{
  82        int i;
  83        bool touch;
  84        unsigned int x, y;
  85        const struct finger *finger;
  86
  87        for (i = 0; i < MAX_TOUCHES; i++) {
  88                input_mt_slot(input, i);
  89
  90                finger = &touchdata->finger[i];
  91
  92                touch = touchdata->status & (1 << i);
  93                input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
  94                if (touch) {
  95                        x = finger->x_low | (finger->x_high << 8);
  96                        y = finger->y_low | (finger->y_high << 8);
  97
  98                        input_report_abs(input, ABS_MT_POSITION_X, x);
  99                        input_report_abs(input, ABS_MT_POSITION_Y, y);
 100                }
 101        }
 102
 103        input_mt_report_pointer_emulation(input, false);
 104        input_sync(input);
 105}
 106
 107static bool get_pendown_state(const struct ili210x *priv)
 108{
 109        bool state = false;
 110
 111        if (priv->get_pendown_state)
 112                state = priv->get_pendown_state();
 113
 114        return state;
 115}
 116
 117static void ili210x_work(struct work_struct *work)
 118{
 119        struct ili210x *priv = container_of(work, struct ili210x,
 120                                            dwork.work);
 121        struct i2c_client *client = priv->client;
 122        struct touchdata touchdata;
 123        int error;
 124
 125        error = ili210x_read_reg(client, REG_TOUCHDATA,
 126                                 &touchdata, sizeof(touchdata));
 127        if (error) {
 128                dev_err(&client->dev,
 129                        "Unable to get touchdata, err = %d\n", error);
 130                return;
 131        }
 132
 133        ili210x_report_events(priv->input, &touchdata);
 134
 135        if ((touchdata.status & 0xf3) || get_pendown_state(priv))
 136                schedule_delayed_work(&priv->dwork,
 137                                      msecs_to_jiffies(priv->poll_period));
 138}
 139
 140static irqreturn_t ili210x_irq(int irq, void *irq_data)
 141{
 142        struct ili210x *priv = irq_data;
 143
 144        schedule_delayed_work(&priv->dwork, 0);
 145
 146        return IRQ_HANDLED;
 147}
 148
 149static ssize_t ili210x_calibrate(struct device *dev,
 150                                 struct device_attribute *attr,
 151                                 const char *buf, size_t count)
 152{
 153        struct i2c_client *client = to_i2c_client(dev);
 154        struct ili210x *priv = i2c_get_clientdata(client);
 155        unsigned long calibrate;
 156        int rc;
 157        u8 cmd = REG_CALIBRATE;
 158
 159        if (kstrtoul(buf, 10, &calibrate))
 160                return -EINVAL;
 161
 162        if (calibrate > 1)
 163                return -EINVAL;
 164
 165        if (calibrate) {
 166                rc = i2c_master_send(priv->client, &cmd, sizeof(cmd));
 167                if (rc != sizeof(cmd))
 168                        return -EIO;
 169        }
 170
 171        return count;
 172}
 173static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
 174
 175static struct attribute *ili210x_attributes[] = {
 176        &dev_attr_calibrate.attr,
 177        NULL,
 178};
 179
 180static const struct attribute_group ili210x_attr_group = {
 181        .attrs = ili210x_attributes,
 182};
 183
 184static int ili210x_i2c_probe(struct i2c_client *client,
 185                                       const struct i2c_device_id *id)
 186{
 187        struct device *dev = &client->dev;
 188        const struct ili210x_platform_data *pdata = dev_get_platdata(dev);
 189        struct ili210x *priv;
 190        struct input_dev *input;
 191        struct panel_info panel;
 192        struct firmware_version firmware;
 193        int xmax, ymax;
 194        int error;
 195
 196        dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
 197
 198        if (!pdata) {
 199                dev_err(dev, "No platform data!\n");
 200                return -EINVAL;
 201        }
 202
 203        if (client->irq <= 0) {
 204                dev_err(dev, "No IRQ!\n");
 205                return -EINVAL;
 206        }
 207
 208        /* Get firmware version */
 209        error = ili210x_read_reg(client, REG_FIRMWARE_VERSION,
 210                                 &firmware, sizeof(firmware));
 211        if (error) {
 212                dev_err(dev, "Failed to get firmware version, err: %d\n",
 213                        error);
 214                return error;
 215        }
 216
 217        /* get panel info */
 218        error = ili210x_read_reg(client, REG_PANEL_INFO, &panel, sizeof(panel));
 219        if (error) {
 220                dev_err(dev, "Failed to get panel information, err: %d\n",
 221                        error);
 222                return error;
 223        }
 224
 225        xmax = panel.finger_max.x_low | (panel.finger_max.x_high << 8);
 226        ymax = panel.finger_max.y_low | (panel.finger_max.y_high << 8);
 227
 228        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 229        input = input_allocate_device();
 230        if (!priv || !input) {
 231                error = -ENOMEM;
 232                goto err_free_mem;
 233        }
 234
 235        priv->client = client;
 236        priv->input = input;
 237        priv->get_pendown_state = pdata->get_pendown_state;
 238        priv->poll_period = pdata->poll_period ? : DEFAULT_POLL_PERIOD;
 239        INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
 240
 241        /* Setup input device */
 242        input->name = "ILI210x Touchscreen";
 243        input->id.bustype = BUS_I2C;
 244        input->dev.parent = dev;
 245
 246        __set_bit(EV_SYN, input->evbit);
 247        __set_bit(EV_KEY, input->evbit);
 248        __set_bit(EV_ABS, input->evbit);
 249        __set_bit(BTN_TOUCH, input->keybit);
 250
 251        /* Single touch */
 252        input_set_abs_params(input, ABS_X, 0, xmax, 0, 0);
 253        input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0);
 254
 255        /* Multi touch */
 256        input_mt_init_slots(input, MAX_TOUCHES, 0);
 257        input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0);
 258        input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0);
 259
 260        i2c_set_clientdata(client, priv);
 261
 262        error = request_irq(client->irq, ili210x_irq, pdata->irq_flags,
 263                            client->name, priv);
 264        if (error) {
 265                dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
 266                        error);
 267                goto err_free_mem;
 268        }
 269
 270        error = sysfs_create_group(&dev->kobj, &ili210x_attr_group);
 271        if (error) {
 272                dev_err(dev, "Unable to create sysfs attributes, err: %d\n",
 273                        error);
 274                goto err_free_irq;
 275        }
 276
 277        error = input_register_device(priv->input);
 278        if (error) {
 279                dev_err(dev, "Cannot register input device, err: %d\n", error);
 280                goto err_remove_sysfs;
 281        }
 282
 283        device_init_wakeup(dev, 1);
 284
 285        dev_dbg(dev,
 286                "ILI210x initialized (IRQ: %d), firmware version %d.%d.%d",
 287                client->irq, firmware.id, firmware.major, firmware.minor);
 288
 289        return 0;
 290
 291err_remove_sysfs:
 292        sysfs_remove_group(&dev->kobj, &ili210x_attr_group);
 293err_free_irq:
 294        free_irq(client->irq, priv);
 295err_free_mem:
 296        input_free_device(input);
 297        kfree(priv);
 298        return error;
 299}
 300
 301static int ili210x_i2c_remove(struct i2c_client *client)
 302{
 303        struct ili210x *priv = i2c_get_clientdata(client);
 304
 305        sysfs_remove_group(&client->dev.kobj, &ili210x_attr_group);
 306        free_irq(priv->client->irq, priv);
 307        cancel_delayed_work_sync(&priv->dwork);
 308        input_unregister_device(priv->input);
 309        kfree(priv);
 310
 311        return 0;
 312}
 313
 314static int __maybe_unused ili210x_i2c_suspend(struct device *dev)
 315{
 316        struct i2c_client *client = to_i2c_client(dev);
 317
 318        if (device_may_wakeup(&client->dev))
 319                enable_irq_wake(client->irq);
 320
 321        return 0;
 322}
 323
 324static int __maybe_unused ili210x_i2c_resume(struct device *dev)
 325{
 326        struct i2c_client *client = to_i2c_client(dev);
 327
 328        if (device_may_wakeup(&client->dev))
 329                disable_irq_wake(client->irq);
 330
 331        return 0;
 332}
 333
 334static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm,
 335                         ili210x_i2c_suspend, ili210x_i2c_resume);
 336
 337static const struct i2c_device_id ili210x_i2c_id[] = {
 338        { "ili210x", 0 },
 339        { }
 340};
 341MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
 342
 343static struct i2c_driver ili210x_ts_driver = {
 344        .driver = {
 345                .name = "ili210x_i2c",
 346                .pm = &ili210x_i2c_pm,
 347        },
 348        .id_table = ili210x_i2c_id,
 349        .probe = ili210x_i2c_probe,
 350        .remove = ili210x_i2c_remove,
 351};
 352
 353module_i2c_driver(ili210x_ts_driver);
 354
 355MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
 356MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver");
 357MODULE_LICENSE("GPL");
 358