33ccb31cad52822922d20e81fbcaf8476f06acd7
[linux-2.6-microblaze.git] / drivers / input / touchscreen / cy8ctmg110_ts.c
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 #include <asm/byteorder.h>
20
21 #define CY8CTMG110_DRIVER_NAME      "cy8ctmg110"
22
23 /* Touch coordinates */
24 #define CY8CTMG110_X_MIN                0
25 #define CY8CTMG110_Y_MIN                0
26 #define CY8CTMG110_X_MAX                759
27 #define CY8CTMG110_Y_MAX                465
28
29
30 /* cy8ctmg110 register definitions */
31 #define CY8CTMG110_TOUCH_WAKEUP_TIME    0
32 #define CY8CTMG110_TOUCH_SLEEP_TIME     2
33 #define CY8CTMG110_TOUCH_X1             3
34 #define CY8CTMG110_TOUCH_Y1             5
35 #define CY8CTMG110_TOUCH_X2             7
36 #define CY8CTMG110_TOUCH_Y2             9
37 #define CY8CTMG110_FINGERS              11
38 #define CY8CTMG110_GESTURE              12
39 #define CY8CTMG110_REG_MAX              13
40
41
42 /*
43  * The touch driver structure.
44  */
45 struct cy8ctmg110 {
46         struct input_dev *input;
47         char phys[32];
48         struct i2c_client *client;
49         int reset_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
116         memset(reg_p, 0, CY8CTMG110_REG_MAX);
117
118         /* Reading coordinates */
119         if (cy8ctmg110_read_regs(tsc, reg_p, 9, CY8CTMG110_TOUCH_X1) != 0)
120                 return -EIO;
121
122         /* Number of touch */
123         if (reg_p[8] == 0) {
124                 input_report_key(input, BTN_TOUCH, 0);
125         } else  {
126                 input_report_key(input, BTN_TOUCH, 1);
127                 input_report_abs(input, ABS_X,
128                                  be16_to_cpup((__be16 *)(reg_p + 0)));
129                 input_report_abs(input, ABS_Y,
130                                  be16_to_cpup((__be16 *)(reg_p + 2)));
131         }
132
133         input_sync(input);
134
135         return 0;
136 }
137
138 static int cy8ctmg110_set_sleepmode(struct cy8ctmg110 *ts, bool sleep)
139 {
140         unsigned char reg_p[3];
141
142         if (sleep) {
143                 reg_p[0] = 0x00;
144                 reg_p[1] = 0xff;
145                 reg_p[2] = 5;
146         } else {
147                 reg_p[0] = 0x10;
148                 reg_p[1] = 0xff;
149                 reg_p[2] = 0;
150         }
151
152         return cy8ctmg110_write_regs(ts, CY8CTMG110_TOUCH_WAKEUP_TIME, 3, reg_p);
153 }
154
155 static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)
156 {
157         struct cy8ctmg110 *tsc = dev_id;
158
159         cy8ctmg110_touch_pos(tsc);
160
161         return IRQ_HANDLED;
162 }
163
164 static void cy8ctmg110_shut_off(void *_ts)
165 {
166         struct cy8ctmg110 *ts = _ts;
167
168         cy8ctmg110_set_sleepmode(ts, true);
169         cy8ctmg110_power(ts, false);
170 }
171
172 static int cy8ctmg110_probe(struct i2c_client *client,
173                                         const struct i2c_device_id *id)
174 {
175         const struct cy8ctmg110_pdata *pdata = dev_get_platdata(&client->dev);
176         struct cy8ctmg110 *ts;
177         struct input_dev *input_dev;
178         int err;
179
180         /* No pdata no way forward */
181         if (pdata == NULL) {
182                 dev_err(&client->dev, "no pdata\n");
183                 return -ENODEV;
184         }
185
186         if (!i2c_check_functionality(client->adapter,
187                                         I2C_FUNC_SMBUS_READ_WORD_DATA))
188                 return -EIO;
189
190         ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
191         if (!ts)
192                 return -ENOMEM;
193
194         input_dev = devm_input_allocate_device(&client->dev);
195         if (!input_dev)
196                 return -ENOMEM;
197
198         ts->client = client;
199         ts->input = input_dev;
200         ts->reset_pin = pdata->reset_pin;
201
202         snprintf(ts->phys, sizeof(ts->phys),
203                  "%s/input0", dev_name(&client->dev));
204
205         input_dev->name = CY8CTMG110_DRIVER_NAME " Touchscreen";
206         input_dev->phys = ts->phys;
207         input_dev->id.bustype = BUS_I2C;
208
209         input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
210         input_set_abs_params(input_dev, ABS_X,
211                         CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 4, 0);
212         input_set_abs_params(input_dev, ABS_Y,
213                         CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 4, 0);
214
215         if (ts->reset_pin) {
216                 err = devm_gpio_request(&client->dev, ts->reset_pin, NULL);
217                 if (err) {
218                         dev_err(&client->dev,
219                                 "Unable to request GPIO pin %d.\n",
220                                 ts->reset_pin);
221                         return err;
222                 }
223         }
224
225         cy8ctmg110_power(ts, true);
226         cy8ctmg110_set_sleepmode(ts, false);
227
228         err = devm_add_action_or_reset(&client->dev, cy8ctmg110_shut_off, ts);
229         if (err)
230                 return err;
231
232         err = devm_request_threaded_irq(&client->dev, client->irq,
233                                         NULL, cy8ctmg110_irq_thread,
234                                         IRQF_ONESHOT, "touch_reset_key", ts);
235         if (err) {
236                 dev_err(&client->dev,
237                         "irq %d busy? error %d\n", client->irq, err);
238                 return err;
239         }
240
241         err = input_register_device(input_dev);
242         if (err)
243                 return err;
244
245         i2c_set_clientdata(client, ts);
246
247         return 0;
248 }
249
250 static int __maybe_unused cy8ctmg110_suspend(struct device *dev)
251 {
252         struct i2c_client *client = to_i2c_client(dev);
253         struct cy8ctmg110 *ts = i2c_get_clientdata(client);
254
255         if (!device_may_wakeup(&client->dev)) {
256                 cy8ctmg110_set_sleepmode(ts, true);
257                 cy8ctmg110_power(ts, false);
258         }
259
260         return 0;
261 }
262
263 static int __maybe_unused cy8ctmg110_resume(struct device *dev)
264 {
265         struct i2c_client *client = to_i2c_client(dev);
266         struct cy8ctmg110 *ts = i2c_get_clientdata(client);
267
268         if (!device_may_wakeup(&client->dev)) {
269                 cy8ctmg110_power(ts, true);
270                 cy8ctmg110_set_sleepmode(ts, false);
271         }
272
273         return 0;
274 }
275
276 static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
277
278 static const struct i2c_device_id cy8ctmg110_idtable[] = {
279         { CY8CTMG110_DRIVER_NAME, 1 },
280         { }
281 };
282
283 MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
284
285 static struct i2c_driver cy8ctmg110_driver = {
286         .driver         = {
287                 .name   = CY8CTMG110_DRIVER_NAME,
288                 .pm     = &cy8ctmg110_pm,
289         },
290         .id_table       = cy8ctmg110_idtable,
291         .probe          = cy8ctmg110_probe,
292 };
293
294 module_i2c_driver(cy8ctmg110_driver);
295
296 MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>");
297 MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
298 MODULE_LICENSE("GPL v2");