root/drivers/input/touchscreen/cy8ctmg110_ts.c

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

DEFINITIONS

This source file includes following definitions.
  1. cy8ctmg110_power
  2. cy8ctmg110_write_regs
  3. cy8ctmg110_read_regs
  4. cy8ctmg110_touch_pos
  5. cy8ctmg110_set_sleepmode
  6. cy8ctmg110_irq_thread
  7. cy8ctmg110_probe
  8. cy8ctmg110_suspend
  9. cy8ctmg110_resume
  10. cy8ctmg110_remove

   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  */
  44 struct 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  */
  56 static 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 
  62 static 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 
  83 static 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 
 111 static 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 
 140 static 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 
 157 static 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 
 166 static 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 
 267 err_free_irq:
 268         free_irq(client->irq, ts);
 269 err_free_irq_gpio:
 270         gpio_free(ts->irq_pin);
 271 err_shutoff_device:
 272         cy8ctmg110_set_sleepmode(ts, true);
 273         cy8ctmg110_power(ts, false);
 274         if (ts->reset_pin)
 275                 gpio_free(ts->reset_pin);
 276 err_free_mem:
 277         input_free_device(input_dev);
 278         kfree(ts);
 279         return err;
 280 }
 281 
 282 static 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 
 296 static 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 
 310 static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
 311 
 312 static 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 
 329 static const struct i2c_device_id cy8ctmg110_idtable[] = {
 330         { CY8CTMG110_DRIVER_NAME, 1 },
 331         { }
 332 };
 333 
 334 MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
 335 
 336 static 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 
 346 module_i2c_driver(cy8ctmg110_driver);
 347 
 348 MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>");
 349 MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
 350 MODULE_LICENSE("GPL v2");

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