linux/drivers/input/touchscreen/cy8ctmg110_ts.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Driver for cypress touch screen controller
   4 *
   5 * Copyright (c) 2009 Aava Mobile
   6 *
   7 * Some cleanups by Alan Cox <alan@linux.intel.com>
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/kernel.h>
  12#include <linux/input.h>
  13#include <linux/slab.h>
  14#include <linux/interrupt.h>
  15#include <linux/io.h>
  16#include <linux/i2c.h>
  17#include <linux/gpio.h>
  18#include <linux/input/cy8ctmg110_pdata.h>
  19
  20#define CY8CTMG110_DRIVER_NAME      "cy8ctmg110"
  21
  22/* Touch coordinates */
  23#define CY8CTMG110_X_MIN                0
  24#define CY8CTMG110_Y_MIN                0
  25#define CY8CTMG110_X_MAX                759
  26#define CY8CTMG110_Y_MAX                465
  27
  28
  29/* cy8ctmg110 register definitions */
  30#define CY8CTMG110_TOUCH_WAKEUP_TIME    0
  31#define CY8CTMG110_TOUCH_SLEEP_TIME     2
  32#define CY8CTMG110_TOUCH_X1             3
  33#define CY8CTMG110_TOUCH_Y1             5
  34#define CY8CTMG110_TOUCH_X2             7
  35#define CY8CTMG110_TOUCH_Y2             9
  36#define CY8CTMG110_FINGERS              11
  37#define CY8CTMG110_GESTURE              12
  38#define CY8CTMG110_REG_MAX              13
  39
  40
  41/*
  42 * The touch driver structure.
  43 */
  44struct cy8ctmg110 {
  45        struct input_dev *input;
  46        char phys[32];
  47        struct i2c_client *client;
  48        int reset_pin;
  49        int irq_pin;
  50};
  51
  52/*
  53 * cy8ctmg110_power is the routine that is called when touch hardware
  54 * will powered off or on.
  55 */
  56static void cy8ctmg110_power(struct cy8ctmg110 *ts, bool poweron)
  57{
  58        if (ts->reset_pin)
  59                gpio_direction_output(ts->reset_pin, 1 - poweron);
  60}
  61
  62static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg,
  63                unsigned char len, unsigned char *value)
  64{
  65        struct i2c_client *client = tsc->client;
  66        int ret;
  67        unsigned char i2c_data[6];
  68
  69        BUG_ON(len > 5);
  70
  71        i2c_data[0] = reg;
  72        memcpy(i2c_data + 1, value, len);
  73
  74        ret = i2c_master_send(client, i2c_data, len + 1);
  75        if (ret != len + 1) {
  76                dev_err(&client->dev, "i2c write data cmd failed\n");
  77                return ret < 0 ? ret : -EIO;
  78        }
  79
  80        return 0;
  81}
  82
  83static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc,
  84                unsigned char *data, unsigned char len, unsigned char cmd)
  85{
  86        struct i2c_client *client = tsc->client;
  87        int ret;
  88        struct i2c_msg msg[2] = {
  89                /* first write slave position to i2c devices */
  90                {
  91                        .addr = client->addr,
  92                        .len = 1,
  93                        .buf = &cmd
  94                },
  95                /* Second read data from position */
  96                {
  97                        .addr = client->addr,
  98                        .flags = I2C_M_RD,
  99                        .len = len,
 100                        .buf = data
 101                }
 102        };
 103
 104        ret = i2c_transfer(client->adapter, msg, 2);
 105        if (ret < 0)
 106                return ret;
 107
 108        return 0;
 109}
 110
 111static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc)
 112{
 113        struct input_dev *input = tsc->input;
 114        unsigned char reg_p[CY8CTMG110_REG_MAX];
 115        int x, y;
 116
 117        memset(reg_p, 0, CY8CTMG110_REG_MAX);
 118
 119        /* Reading coordinates */
 120        if (cy8ctmg110_read_regs(tsc, reg_p, 9, CY8CTMG110_TOUCH_X1) != 0)
 121                return -EIO;
 122
 123        y = reg_p[2] << 8 | reg_p[3];
 124        x = reg_p[0] << 8 | reg_p[1];
 125
 126        /* Number of touch */
 127        if (reg_p[8] == 0) {
 128                input_report_key(input, BTN_TOUCH, 0);
 129        } else  {
 130                input_report_key(input, BTN_TOUCH, 1);
 131                input_report_abs(input, ABS_X, x);
 132                input_report_abs(input, ABS_Y, y);
 133        }
 134
 135        input_sync(input);
 136
 137        return 0;
 138}
 139
 140static int cy8ctmg110_set_sleepmode(struct cy8ctmg110 *ts, bool sleep)
 141{
 142        unsigned char reg_p[3];
 143
 144        if (sleep) {
 145                reg_p[0] = 0x00;
 146                reg_p[1] = 0xff;
 147                reg_p[2] = 5;
 148        } else {
 149                reg_p[0] = 0x10;
 150                reg_p[1] = 0xff;
 151                reg_p[2] = 0;
 152        }
 153
 154        return cy8ctmg110_write_regs(ts, CY8CTMG110_TOUCH_WAKEUP_TIME, 3, reg_p);
 155}
 156
 157static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)
 158{
 159        struct cy8ctmg110 *tsc = dev_id;
 160
 161        cy8ctmg110_touch_pos(tsc);
 162
 163        return IRQ_HANDLED;
 164}
 165
 166static int cy8ctmg110_probe(struct i2c_client *client,
 167                                        const struct i2c_device_id *id)
 168{
 169        const struct cy8ctmg110_pdata *pdata = dev_get_platdata(&client->dev);
 170        struct cy8ctmg110 *ts;
 171        struct input_dev *input_dev;
 172        int err;
 173
 174        /* No pdata no way forward */
 175        if (pdata == NULL) {
 176                dev_err(&client->dev, "no pdata\n");
 177                return -ENODEV;
 178        }
 179
 180        if (!i2c_check_functionality(client->adapter,
 181                                        I2C_FUNC_SMBUS_READ_WORD_DATA))
 182                return -EIO;
 183
 184        ts = kzalloc(sizeof(struct cy8ctmg110), GFP_KERNEL);
 185        input_dev = input_allocate_device();
 186        if (!ts || !input_dev) {
 187                err = -ENOMEM;
 188                goto err_free_mem;
 189        }
 190
 191        ts->client = client;
 192        ts->input = input_dev;
 193        ts->reset_pin = pdata->reset_pin;
 194        ts->irq_pin = pdata->irq_pin;
 195
 196        snprintf(ts->phys, sizeof(ts->phys),
 197                 "%s/input0", dev_name(&client->dev));
 198
 199        input_dev->name = CY8CTMG110_DRIVER_NAME " Touchscreen";
 200        input_dev->phys = ts->phys;
 201        input_dev->id.bustype = BUS_I2C;
 202        input_dev->dev.parent = &client->dev;
 203
 204        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 205        input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 206
 207        input_set_abs_params(input_dev, ABS_X,
 208                        CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 4, 0);
 209        input_set_abs_params(input_dev, ABS_Y,
 210                        CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 4, 0);
 211
 212        if (ts->reset_pin) {
 213                err = gpio_request(ts->reset_pin, NULL);
 214                if (err) {
 215                        dev_err(&client->dev,
 216                                "Unable to request GPIO pin %d.\n",
 217                                ts->reset_pin);
 218                        goto err_free_mem;
 219                }
 220        }
 221
 222        cy8ctmg110_power(ts, true);
 223        cy8ctmg110_set_sleepmode(ts, false);
 224
 225        err = gpio_request(ts->irq_pin, "touch_irq_key");
 226        if (err < 0) {
 227                dev_err(&client->dev,
 228                        "Failed to request GPIO %d, error %d\n",
 229                        ts->irq_pin, err);
 230                goto err_shutoff_device;
 231        }
 232
 233        err = gpio_direction_input(ts->irq_pin);
 234        if (err < 0) {
 235                dev_err(&client->dev,
 236                        "Failed to configure input direction for GPIO %d, error %d\n",
 237                        ts->irq_pin, err);
 238                goto err_free_irq_gpio;
 239        }
 240
 241        client->irq = gpio_to_irq(ts->irq_pin);
 242        if (client->irq < 0) {
 243                err = client->irq;
 244                dev_err(&client->dev,
 245                        "Unable to get irq number for GPIO %d, error %d\n",
 246                        ts->irq_pin, err);
 247                goto err_free_irq_gpio;
 248        }
 249
 250        err = request_threaded_irq(client->irq, NULL, cy8ctmg110_irq_thread,
 251                                   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 252                                   "touch_reset_key", ts);
 253        if (err < 0) {
 254                dev_err(&client->dev,
 255                        "irq %d busy? error %d\n", client->irq, err);
 256                goto err_free_irq_gpio;
 257        }
 258
 259        err = input_register_device(input_dev);
 260        if (err)
 261                goto err_free_irq;
 262
 263        i2c_set_clientdata(client, ts);
 264        device_init_wakeup(&client->dev, 1);
 265        return 0;
 266
 267err_free_irq:
 268        free_irq(client->irq, ts);
 269err_free_irq_gpio:
 270        gpio_free(ts->irq_pin);
 271err_shutoff_device:
 272        cy8ctmg110_set_sleepmode(ts, true);
 273        cy8ctmg110_power(ts, false);
 274        if (ts->reset_pin)
 275                gpio_free(ts->reset_pin);
 276err_free_mem:
 277        input_free_device(input_dev);
 278        kfree(ts);
 279        return err;
 280}
 281
 282static int __maybe_unused cy8ctmg110_suspend(struct device *dev)
 283{
 284        struct i2c_client *client = to_i2c_client(dev);
 285        struct cy8ctmg110 *ts = i2c_get_clientdata(client);
 286
 287        if (device_may_wakeup(&client->dev))
 288                enable_irq_wake(client->irq);
 289        else {
 290                cy8ctmg110_set_sleepmode(ts, true);
 291                cy8ctmg110_power(ts, false);
 292        }
 293        return 0;
 294}
 295
 296static int __maybe_unused cy8ctmg110_resume(struct device *dev)
 297{
 298        struct i2c_client *client = to_i2c_client(dev);
 299        struct cy8ctmg110 *ts = i2c_get_clientdata(client);
 300
 301        if (device_may_wakeup(&client->dev))
 302                disable_irq_wake(client->irq);
 303        else {
 304                cy8ctmg110_power(ts, true);
 305                cy8ctmg110_set_sleepmode(ts, false);
 306        }
 307        return 0;
 308}
 309
 310static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
 311
 312static int cy8ctmg110_remove(struct i2c_client *client)
 313{
 314        struct cy8ctmg110 *ts = i2c_get_clientdata(client);
 315
 316        cy8ctmg110_set_sleepmode(ts, true);
 317        cy8ctmg110_power(ts, false);
 318
 319        free_irq(client->irq, ts);
 320        input_unregister_device(ts->input);
 321        gpio_free(ts->irq_pin);
 322        if (ts->reset_pin)
 323                gpio_free(ts->reset_pin);
 324        kfree(ts);
 325
 326        return 0;
 327}
 328
 329static const struct i2c_device_id cy8ctmg110_idtable[] = {
 330        { CY8CTMG110_DRIVER_NAME, 1 },
 331        { }
 332};
 333
 334MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
 335
 336static struct i2c_driver cy8ctmg110_driver = {
 337        .driver         = {
 338                .name   = CY8CTMG110_DRIVER_NAME,
 339                .pm     = &cy8ctmg110_pm,
 340        },
 341        .id_table       = cy8ctmg110_idtable,
 342        .probe          = cy8ctmg110_probe,
 343        .remove         = cy8ctmg110_remove,
 344};
 345
 346module_i2c_driver(cy8ctmg110_driver);
 347
 348MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>");
 349MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
 350MODULE_LICENSE("GPL v2");
 351