Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Driver for cypress touch screen controller
0004  *
0005  * Copyright (c) 2009 Aava Mobile
0006  *
0007  * Some cleanups by Alan Cox <alan@linux.intel.com>
0008  */
0009 
0010 #include <linux/i2c.h>
0011 #include <linux/input.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/gpio/consumer.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/slab.h>
0017 #include <asm/byteorder.h>
0018 
0019 #define CY8CTMG110_DRIVER_NAME      "cy8ctmg110"
0020 
0021 /* Touch coordinates */
0022 #define CY8CTMG110_X_MIN        0
0023 #define CY8CTMG110_Y_MIN        0
0024 #define CY8CTMG110_X_MAX        759
0025 #define CY8CTMG110_Y_MAX        465
0026 
0027 
0028 /* cy8ctmg110 register definitions */
0029 #define CY8CTMG110_TOUCH_WAKEUP_TIME    0
0030 #define CY8CTMG110_TOUCH_SLEEP_TIME 2
0031 #define CY8CTMG110_TOUCH_X1     3
0032 #define CY8CTMG110_TOUCH_Y1     5
0033 #define CY8CTMG110_TOUCH_X2     7
0034 #define CY8CTMG110_TOUCH_Y2     9
0035 #define CY8CTMG110_FINGERS      11
0036 #define CY8CTMG110_GESTURE      12
0037 #define CY8CTMG110_REG_MAX      13
0038 
0039 
0040 /*
0041  * The touch driver structure.
0042  */
0043 struct cy8ctmg110 {
0044     struct input_dev *input;
0045     char phys[32];
0046     struct i2c_client *client;
0047     struct gpio_desc *reset_gpio;
0048 };
0049 
0050 /*
0051  * cy8ctmg110_power is the routine that is called when touch hardware
0052  * is being powered off or on. When powering on this routine de-asserts
0053  * the RESET line, when powering off reset line is asserted.
0054  */
0055 static void cy8ctmg110_power(struct cy8ctmg110 *ts, bool poweron)
0056 {
0057     if (ts->reset_gpio)
0058         gpiod_set_value_cansleep(ts->reset_gpio, !poweron);
0059 }
0060 
0061 static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg,
0062         unsigned char len, unsigned char *value)
0063 {
0064     struct i2c_client *client = tsc->client;
0065     int ret;
0066     unsigned char i2c_data[6];
0067 
0068     BUG_ON(len > 5);
0069 
0070     i2c_data[0] = reg;
0071     memcpy(i2c_data + 1, value, len);
0072 
0073     ret = i2c_master_send(client, i2c_data, len + 1);
0074     if (ret != len + 1) {
0075         dev_err(&client->dev, "i2c write data cmd failed\n");
0076         return ret < 0 ? ret : -EIO;
0077     }
0078 
0079     return 0;
0080 }
0081 
0082 static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc,
0083         unsigned char *data, unsigned char len, unsigned char cmd)
0084 {
0085     struct i2c_client *client = tsc->client;
0086     int ret;
0087     struct i2c_msg msg[2] = {
0088         /* first write slave position to i2c devices */
0089         {
0090             .addr = client->addr,
0091             .len = 1,
0092             .buf = &cmd
0093         },
0094         /* Second read data from position */
0095         {
0096             .addr = client->addr,
0097             .flags = I2C_M_RD,
0098             .len = len,
0099             .buf = data
0100         }
0101     };
0102 
0103     ret = i2c_transfer(client->adapter, msg, 2);
0104     if (ret < 0)
0105         return ret;
0106 
0107     return 0;
0108 }
0109 
0110 static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc)
0111 {
0112     struct input_dev *input = tsc->input;
0113     unsigned char reg_p[CY8CTMG110_REG_MAX];
0114 
0115     memset(reg_p, 0, CY8CTMG110_REG_MAX);
0116 
0117     /* Reading coordinates */
0118     if (cy8ctmg110_read_regs(tsc, reg_p, 9, CY8CTMG110_TOUCH_X1) != 0)
0119         return -EIO;
0120 
0121     /* Number of touch */
0122     if (reg_p[8] == 0) {
0123         input_report_key(input, BTN_TOUCH, 0);
0124     } else  {
0125         input_report_key(input, BTN_TOUCH, 1);
0126         input_report_abs(input, ABS_X,
0127                  be16_to_cpup((__be16 *)(reg_p + 0)));
0128         input_report_abs(input, ABS_Y,
0129                  be16_to_cpup((__be16 *)(reg_p + 2)));
0130     }
0131 
0132     input_sync(input);
0133 
0134     return 0;
0135 }
0136 
0137 static int cy8ctmg110_set_sleepmode(struct cy8ctmg110 *ts, bool sleep)
0138 {
0139     unsigned char reg_p[3];
0140 
0141     if (sleep) {
0142         reg_p[0] = 0x00;
0143         reg_p[1] = 0xff;
0144         reg_p[2] = 5;
0145     } else {
0146         reg_p[0] = 0x10;
0147         reg_p[1] = 0xff;
0148         reg_p[2] = 0;
0149     }
0150 
0151     return cy8ctmg110_write_regs(ts, CY8CTMG110_TOUCH_WAKEUP_TIME, 3, reg_p);
0152 }
0153 
0154 static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)
0155 {
0156     struct cy8ctmg110 *tsc = dev_id;
0157 
0158     cy8ctmg110_touch_pos(tsc);
0159 
0160     return IRQ_HANDLED;
0161 }
0162 
0163 static void cy8ctmg110_shut_off(void *_ts)
0164 {
0165     struct cy8ctmg110 *ts = _ts;
0166 
0167     cy8ctmg110_set_sleepmode(ts, true);
0168     cy8ctmg110_power(ts, false);
0169 }
0170 
0171 static int cy8ctmg110_probe(struct i2c_client *client,
0172                     const struct i2c_device_id *id)
0173 {
0174     struct cy8ctmg110 *ts;
0175     struct input_dev *input_dev;
0176     int err;
0177 
0178     if (!i2c_check_functionality(client->adapter,
0179                     I2C_FUNC_SMBUS_READ_WORD_DATA))
0180         return -EIO;
0181 
0182     ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
0183     if (!ts)
0184         return -ENOMEM;
0185 
0186     input_dev = devm_input_allocate_device(&client->dev);
0187     if (!input_dev)
0188         return -ENOMEM;
0189 
0190     ts->client = client;
0191     ts->input = input_dev;
0192 
0193     snprintf(ts->phys, sizeof(ts->phys),
0194          "%s/input0", dev_name(&client->dev));
0195 
0196     input_dev->name = CY8CTMG110_DRIVER_NAME " Touchscreen";
0197     input_dev->phys = ts->phys;
0198     input_dev->id.bustype = BUS_I2C;
0199 
0200     input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
0201     input_set_abs_params(input_dev, ABS_X,
0202             CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 4, 0);
0203     input_set_abs_params(input_dev, ABS_Y,
0204             CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 4, 0);
0205 
0206     /* Request and assert reset line */
0207     ts->reset_gpio = devm_gpiod_get_optional(&client->dev, NULL,
0208                          GPIOD_OUT_HIGH);
0209     if (IS_ERR(ts->reset_gpio)) {
0210         err = PTR_ERR(ts->reset_gpio);
0211         dev_err(&client->dev,
0212             "Unable to request reset GPIO: %d\n", err);
0213         return err;
0214     }
0215 
0216     cy8ctmg110_power(ts, true);
0217     cy8ctmg110_set_sleepmode(ts, false);
0218 
0219     err = devm_add_action_or_reset(&client->dev, cy8ctmg110_shut_off, ts);
0220     if (err)
0221         return err;
0222 
0223     err = devm_request_threaded_irq(&client->dev, client->irq,
0224                     NULL, cy8ctmg110_irq_thread,
0225                     IRQF_ONESHOT, "touch_reset_key", ts);
0226     if (err) {
0227         dev_err(&client->dev,
0228             "irq %d busy? error %d\n", client->irq, err);
0229         return err;
0230     }
0231 
0232     err = input_register_device(input_dev);
0233     if (err)
0234         return err;
0235 
0236     i2c_set_clientdata(client, ts);
0237 
0238     return 0;
0239 }
0240 
0241 static int __maybe_unused cy8ctmg110_suspend(struct device *dev)
0242 {
0243     struct i2c_client *client = to_i2c_client(dev);
0244     struct cy8ctmg110 *ts = i2c_get_clientdata(client);
0245 
0246     if (!device_may_wakeup(&client->dev)) {
0247         cy8ctmg110_set_sleepmode(ts, true);
0248         cy8ctmg110_power(ts, false);
0249     }
0250 
0251     return 0;
0252 }
0253 
0254 static int __maybe_unused cy8ctmg110_resume(struct device *dev)
0255 {
0256     struct i2c_client *client = to_i2c_client(dev);
0257     struct cy8ctmg110 *ts = i2c_get_clientdata(client);
0258 
0259     if (!device_may_wakeup(&client->dev)) {
0260         cy8ctmg110_power(ts, true);
0261         cy8ctmg110_set_sleepmode(ts, false);
0262     }
0263 
0264     return 0;
0265 }
0266 
0267 static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
0268 
0269 static const struct i2c_device_id cy8ctmg110_idtable[] = {
0270     { CY8CTMG110_DRIVER_NAME, 1 },
0271     { }
0272 };
0273 
0274 MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
0275 
0276 static struct i2c_driver cy8ctmg110_driver = {
0277     .driver     = {
0278         .name   = CY8CTMG110_DRIVER_NAME,
0279         .pm = &cy8ctmg110_pm,
0280     },
0281     .id_table   = cy8ctmg110_idtable,
0282     .probe      = cy8ctmg110_probe,
0283 };
0284 
0285 module_i2c_driver(cy8ctmg110_driver);
0286 
0287 MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>");
0288 MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
0289 MODULE_LICENSE("GPL v2");