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