linux/drivers/input/touchscreen/sx8654.c
<<
>>
Prefs
   1/*
   2 * Driver for Semtech SX8654 I2C touchscreen controller.
   3 *
   4 * Copyright (c) 2015 Armadeus Systems
   5 *      Sébastien Szymanski <sebastien.szymanski@armadeus.com>
   6 *
   7 * Using code from:
   8 *  - sx865x.c
   9 *      Copyright (c) 2013 U-MoBo Srl
  10 *      Pierluigi Passaro <p.passaro@u-mobo.com>
  11 *  - sx8650.c
  12 *      Copyright (c) 2009 Wayne Roberts
  13 *  - tsc2007.c
  14 *      Copyright (c) 2008 Kwangwoo Lee
  15 *  - ads7846.c
  16 *      Copyright (c) 2005 David Brownell
  17 *      Copyright (c) 2006 Nokia Corporation
  18 *  - corgi_ts.c
  19 *      Copyright (C) 2004-2005 Richard Purdie
  20 *  - omap_ts.[hc], ads7846.h, ts_osk.c
  21 *      Copyright (C) 2002 MontaVista Software
  22 *      Copyright (C) 2004 Texas Instruments
  23 *      Copyright (C) 2005 Dirk Behme
  24 *
  25 *  This program is free software; you can redistribute it and/or modify
  26 *  it under the terms of the GNU General Public License version 2 as
  27 *  published by the Free Software Foundation.
  28 */
  29
  30#include <linux/input.h>
  31#include <linux/module.h>
  32#include <linux/of.h>
  33#include <linux/i2c.h>
  34#include <linux/interrupt.h>
  35#include <linux/irq.h>
  36
  37/* register addresses */
  38#define I2C_REG_TOUCH0                  0x00
  39#define I2C_REG_TOUCH1                  0x01
  40#define I2C_REG_CHANMASK                0x04
  41#define I2C_REG_IRQMASK                 0x22
  42#define I2C_REG_IRQSRC                  0x23
  43#define I2C_REG_SOFTRESET               0x3f
  44
  45/* commands */
  46#define CMD_READ_REGISTER               0x40
  47#define CMD_MANUAL                      0xc0
  48#define CMD_PENTRG                      0xe0
  49
  50/* value for I2C_REG_SOFTRESET */
  51#define SOFTRESET_VALUE                 0xde
  52
  53/* bits for I2C_REG_IRQSRC */
  54#define IRQ_PENTOUCH_TOUCHCONVDONE      0x08
  55#define IRQ_PENRELEASE                  0x04
  56
  57/* bits for RegTouch1 */
  58#define CONDIRQ                         0x20
  59#define FILT_7SA                        0x03
  60
  61/* bits for I2C_REG_CHANMASK */
  62#define CONV_X                          0x80
  63#define CONV_Y                          0x40
  64
  65/* coordinates rate: higher nibble of CTRL0 register */
  66#define RATE_MANUAL                     0x00
  67#define RATE_5000CPS                    0xf0
  68
  69/* power delay: lower nibble of CTRL0 register */
  70#define POWDLY_1_1MS                    0x0b
  71
  72#define MAX_12BIT                       ((1 << 12) - 1)
  73
  74struct sx8654 {
  75        struct input_dev *input;
  76        struct i2c_client *client;
  77};
  78
  79static irqreturn_t sx8654_irq(int irq, void *handle)
  80{
  81        struct sx8654 *sx8654 = handle;
  82        int irqsrc;
  83        u8 data[4];
  84        unsigned int x, y;
  85        int retval;
  86
  87        irqsrc = i2c_smbus_read_byte_data(sx8654->client,
  88                                          CMD_READ_REGISTER | I2C_REG_IRQSRC);
  89        dev_dbg(&sx8654->client->dev, "irqsrc = 0x%x", irqsrc);
  90
  91        if (irqsrc < 0)
  92                goto out;
  93
  94        if (irqsrc & IRQ_PENRELEASE) {
  95                dev_dbg(&sx8654->client->dev, "pen release interrupt");
  96
  97                input_report_key(sx8654->input, BTN_TOUCH, 0);
  98                input_sync(sx8654->input);
  99        }
 100
 101        if (irqsrc & IRQ_PENTOUCH_TOUCHCONVDONE) {
 102                dev_dbg(&sx8654->client->dev, "pen touch interrupt");
 103
 104                retval = i2c_master_recv(sx8654->client, data, sizeof(data));
 105                if (retval != sizeof(data))
 106                        goto out;
 107
 108                /* invalid data */
 109                if (unlikely(data[0] & 0x80 || data[2] & 0x80))
 110                        goto out;
 111
 112                x = ((data[0] & 0xf) << 8) | (data[1]);
 113                y = ((data[2] & 0xf) << 8) | (data[3]);
 114
 115                input_report_abs(sx8654->input, ABS_X, x);
 116                input_report_abs(sx8654->input, ABS_Y, y);
 117                input_report_key(sx8654->input, BTN_TOUCH, 1);
 118                input_sync(sx8654->input);
 119
 120                dev_dbg(&sx8654->client->dev, "point(%4d,%4d)\n", x, y);
 121        }
 122
 123out:
 124        return IRQ_HANDLED;
 125}
 126
 127static int sx8654_open(struct input_dev *dev)
 128{
 129        struct sx8654 *sx8654 = input_get_drvdata(dev);
 130        struct i2c_client *client = sx8654->client;
 131        int error;
 132
 133        /* enable pen trigger mode */
 134        error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0,
 135                                          RATE_5000CPS | POWDLY_1_1MS);
 136        if (error) {
 137                dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
 138                return error;
 139        }
 140
 141        error = i2c_smbus_write_byte(client, CMD_PENTRG);
 142        if (error) {
 143                dev_err(&client->dev, "writing command CMD_PENTRG failed");
 144                return error;
 145        }
 146
 147        enable_irq(client->irq);
 148
 149        return 0;
 150}
 151
 152static void sx8654_close(struct input_dev *dev)
 153{
 154        struct sx8654 *sx8654 = input_get_drvdata(dev);
 155        struct i2c_client *client = sx8654->client;
 156        int error;
 157
 158        disable_irq(client->irq);
 159
 160        /* enable manual mode mode */
 161        error = i2c_smbus_write_byte(client, CMD_MANUAL);
 162        if (error) {
 163                dev_err(&client->dev, "writing command CMD_MANUAL failed");
 164                return;
 165        }
 166
 167        error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, 0);
 168        if (error) {
 169                dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
 170                return;
 171        }
 172}
 173
 174static int sx8654_probe(struct i2c_client *client,
 175                        const struct i2c_device_id *id)
 176{
 177        struct sx8654 *sx8654;
 178        struct input_dev *input;
 179        int error;
 180
 181        if (!i2c_check_functionality(client->adapter,
 182                                     I2C_FUNC_SMBUS_READ_WORD_DATA))
 183                return -ENXIO;
 184
 185        sx8654 = devm_kzalloc(&client->dev, sizeof(*sx8654), GFP_KERNEL);
 186        if (!sx8654)
 187                return -ENOMEM;
 188
 189        input = devm_input_allocate_device(&client->dev);
 190        if (!input)
 191                return -ENOMEM;
 192
 193        input->name = "SX8654 I2C Touchscreen";
 194        input->id.bustype = BUS_I2C;
 195        input->dev.parent = &client->dev;
 196        input->open = sx8654_open;
 197        input->close = sx8654_close;
 198
 199        __set_bit(INPUT_PROP_DIRECT, input->propbit);
 200        input_set_capability(input, EV_KEY, BTN_TOUCH);
 201        input_set_abs_params(input, ABS_X, 0, MAX_12BIT, 0, 0);
 202        input_set_abs_params(input, ABS_Y, 0, MAX_12BIT, 0, 0);
 203
 204        sx8654->client = client;
 205        sx8654->input = input;
 206
 207        input_set_drvdata(sx8654->input, sx8654);
 208
 209        error = i2c_smbus_write_byte_data(client, I2C_REG_SOFTRESET,
 210                                          SOFTRESET_VALUE);
 211        if (error) {
 212                dev_err(&client->dev, "writing softreset value failed");
 213                return error;
 214        }
 215
 216        error = i2c_smbus_write_byte_data(client, I2C_REG_CHANMASK,
 217                                          CONV_X | CONV_Y);
 218        if (error) {
 219                dev_err(&client->dev, "writing to I2C_REG_CHANMASK failed");
 220                return error;
 221        }
 222
 223        error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK,
 224                                          IRQ_PENTOUCH_TOUCHCONVDONE |
 225                                                IRQ_PENRELEASE);
 226        if (error) {
 227                dev_err(&client->dev, "writing to I2C_REG_IRQMASK failed");
 228                return error;
 229        }
 230
 231        error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH1,
 232                                          CONDIRQ | FILT_7SA);
 233        if (error) {
 234                dev_err(&client->dev, "writing to I2C_REG_TOUCH1 failed");
 235                return error;
 236        }
 237
 238        error = devm_request_threaded_irq(&client->dev, client->irq,
 239                                          NULL, sx8654_irq,
 240                                          IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 241                                          client->name, sx8654);
 242        if (error) {
 243                dev_err(&client->dev,
 244                        "Failed to enable IRQ %d, error: %d\n",
 245                        client->irq, error);
 246                return error;
 247        }
 248
 249        /* Disable the IRQ, we'll enable it in sx8654_open() */
 250        disable_irq(client->irq);
 251
 252        error = input_register_device(sx8654->input);
 253        if (error)
 254                return error;
 255
 256        return 0;
 257}
 258
 259#ifdef CONFIG_OF
 260static const struct of_device_id sx8654_of_match[] = {
 261        { .compatible = "semtech,sx8654", },
 262        { },
 263};
 264MODULE_DEVICE_TABLE(of, sx8654_of_match);
 265#endif
 266
 267static const struct i2c_device_id sx8654_id_table[] = {
 268        { "semtech_sx8654", 0 },
 269        { },
 270};
 271MODULE_DEVICE_TABLE(i2c, sx8654_id_table);
 272
 273static struct i2c_driver sx8654_driver = {
 274        .driver = {
 275                .name = "sx8654",
 276                .of_match_table = of_match_ptr(sx8654_of_match),
 277        },
 278        .id_table = sx8654_id_table,
 279        .probe = sx8654_probe,
 280};
 281module_i2c_driver(sx8654_driver);
 282
 283MODULE_AUTHOR("Sébastien Szymanski <sebastien.szymanski@armadeus.com>");
 284MODULE_DESCRIPTION("Semtech SX8654 I2C Touchscreen Driver");
 285MODULE_LICENSE("GPL");
 286