Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/input/touchscreen/cy8ctmg110_ts.c
15111 views
1
/*
2
* Driver for cypress touch screen controller
3
*
4
* Copyright (c) 2009 Aava Mobile
5
*
6
* Some cleanups by Alan Cox <[email protected]>
7
*
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License version 2 as
10
* published by the Free Software Foundation.
11
*
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
16
*
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
*/
21
22
#include <linux/module.h>
23
#include <linux/kernel.h>
24
#include <linux/input.h>
25
#include <linux/slab.h>
26
#include <linux/interrupt.h>
27
#include <linux/io.h>
28
#include <linux/i2c.h>
29
#include <linux/gpio.h>
30
#include <linux/input/cy8ctmg110_pdata.h>
31
32
#define CY8CTMG110_DRIVER_NAME "cy8ctmg110"
33
34
/* Touch coordinates */
35
#define CY8CTMG110_X_MIN 0
36
#define CY8CTMG110_Y_MIN 0
37
#define CY8CTMG110_X_MAX 759
38
#define CY8CTMG110_Y_MAX 465
39
40
41
/* cy8ctmg110 register definitions */
42
#define CY8CTMG110_TOUCH_WAKEUP_TIME 0
43
#define CY8CTMG110_TOUCH_SLEEP_TIME 2
44
#define CY8CTMG110_TOUCH_X1 3
45
#define CY8CTMG110_TOUCH_Y1 5
46
#define CY8CTMG110_TOUCH_X2 7
47
#define CY8CTMG110_TOUCH_Y2 9
48
#define CY8CTMG110_FINGERS 11
49
#define CY8CTMG110_GESTURE 12
50
#define CY8CTMG110_REG_MAX 13
51
52
53
/*
54
* The touch driver structure.
55
*/
56
struct cy8ctmg110 {
57
struct input_dev *input;
58
char phys[32];
59
struct i2c_client *client;
60
int reset_pin;
61
int irq_pin;
62
};
63
64
/*
65
* cy8ctmg110_power is the routine that is called when touch hardware
66
* will powered off or on.
67
*/
68
static void cy8ctmg110_power(struct cy8ctmg110 *ts, bool poweron)
69
{
70
if (ts->reset_pin)
71
gpio_direction_output(ts->reset_pin, 1 - poweron);
72
}
73
74
static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg,
75
unsigned char len, unsigned char *value)
76
{
77
struct i2c_client *client = tsc->client;
78
int ret;
79
unsigned char i2c_data[6];
80
81
BUG_ON(len > 5);
82
83
i2c_data[0] = reg;
84
memcpy(i2c_data + 1, value, len);
85
86
ret = i2c_master_send(client, i2c_data, len + 1);
87
if (ret != 1) {
88
dev_err(&client->dev, "i2c write data cmd failed\n");
89
return ret ? ret : -EIO;
90
}
91
92
return 0;
93
}
94
95
static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc,
96
unsigned char *data, unsigned char len, unsigned char cmd)
97
{
98
struct i2c_client *client = tsc->client;
99
int ret;
100
struct i2c_msg msg[2] = {
101
/* first write slave position to i2c devices */
102
{ client->addr, 0, 1, &cmd },
103
/* Second read data from position */
104
{ client->addr, I2C_M_RD, len, data }
105
};
106
107
ret = i2c_transfer(client->adapter, msg, 2);
108
if (ret < 0)
109
return ret;
110
111
return 0;
112
}
113
114
static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc)
115
{
116
struct input_dev *input = tsc->input;
117
unsigned char reg_p[CY8CTMG110_REG_MAX];
118
int x, y;
119
120
memset(reg_p, 0, CY8CTMG110_REG_MAX);
121
122
/* Reading coordinates */
123
if (cy8ctmg110_read_regs(tsc, reg_p, 9, CY8CTMG110_TOUCH_X1) != 0)
124
return -EIO;
125
126
y = reg_p[2] << 8 | reg_p[3];
127
x = reg_p[0] << 8 | reg_p[1];
128
129
/* Number of touch */
130
if (reg_p[8] == 0) {
131
input_report_key(input, BTN_TOUCH, 0);
132
} else {
133
input_report_key(input, BTN_TOUCH, 1);
134
input_report_abs(input, ABS_X, x);
135
input_report_abs(input, ABS_Y, y);
136
}
137
138
input_sync(input);
139
140
return 0;
141
}
142
143
static int cy8ctmg110_set_sleepmode(struct cy8ctmg110 *ts, bool sleep)
144
{
145
unsigned char reg_p[3];
146
147
if (sleep) {
148
reg_p[0] = 0x00;
149
reg_p[1] = 0xff;
150
reg_p[2] = 5;
151
} else {
152
reg_p[0] = 0x10;
153
reg_p[1] = 0xff;
154
reg_p[2] = 0;
155
}
156
157
return cy8ctmg110_write_regs(ts, CY8CTMG110_TOUCH_WAKEUP_TIME, 3, reg_p);
158
}
159
160
static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)
161
{
162
struct cy8ctmg110 *tsc = dev_id;
163
164
cy8ctmg110_touch_pos(tsc);
165
166
return IRQ_HANDLED;
167
}
168
169
static int __devinit cy8ctmg110_probe(struct i2c_client *client,
170
const struct i2c_device_id *id)
171
{
172
const struct cy8ctmg110_pdata *pdata = client->dev.platform_data;
173
struct cy8ctmg110 *ts;
174
struct input_dev *input_dev;
175
int err;
176
177
/* No pdata no way forward */
178
if (pdata == NULL) {
179
dev_err(&client->dev, "no pdata\n");
180
return -ENODEV;
181
}
182
183
if (!i2c_check_functionality(client->adapter,
184
I2C_FUNC_SMBUS_READ_WORD_DATA))
185
return -EIO;
186
187
ts = kzalloc(sizeof(struct cy8ctmg110), GFP_KERNEL);
188
input_dev = input_allocate_device();
189
if (!ts || !input_dev) {
190
err = -ENOMEM;
191
goto err_free_mem;
192
}
193
194
ts->client = client;
195
ts->input = input_dev;
196
197
snprintf(ts->phys, sizeof(ts->phys),
198
"%s/input0", dev_name(&client->dev));
199
200
input_dev->name = CY8CTMG110_DRIVER_NAME " Touchscreen";
201
input_dev->phys = ts->phys;
202
input_dev->id.bustype = BUS_I2C;
203
input_dev->dev.parent = &client->dev;
204
205
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
206
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
207
208
input_set_abs_params(input_dev, ABS_X,
209
CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 4, 0);
210
input_set_abs_params(input_dev, ABS_Y,
211
CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 4, 0);
212
213
if (ts->reset_pin) {
214
err = gpio_request(ts->reset_pin, NULL);
215
if (err) {
216
dev_err(&client->dev,
217
"Unable to request GPIO pin %d.\n",
218
ts->reset_pin);
219
goto err_free_mem;
220
}
221
}
222
223
cy8ctmg110_power(ts, true);
224
cy8ctmg110_set_sleepmode(ts, false);
225
226
err = gpio_request(ts->irq_pin, "touch_irq_key");
227
if (err < 0) {
228
dev_err(&client->dev,
229
"Failed to request GPIO %d, error %d\n",
230
ts->irq_pin, err);
231
goto err_shutoff_device;
232
}
233
234
err = gpio_direction_input(ts->irq_pin);
235
if (err < 0) {
236
dev_err(&client->dev,
237
"Failed to configure input direction for GPIO %d, error %d\n",
238
ts->irq_pin, err);
239
goto err_free_irq_gpio;
240
}
241
242
client->irq = gpio_to_irq(ts->irq_pin);
243
if (client->irq < 0) {
244
err = client->irq;
245
dev_err(&client->dev,
246
"Unable to get irq number for GPIO %d, error %d\n",
247
ts->irq_pin, err);
248
goto err_free_irq_gpio;
249
}
250
251
err = request_threaded_irq(client->irq, NULL, cy8ctmg110_irq_thread,
252
IRQF_TRIGGER_RISING, "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
#ifdef CONFIG_PM
283
static int cy8ctmg110_suspend(struct device *dev)
284
{
285
struct i2c_client *client = to_i2c_client(dev);
286
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
287
288
if (device_may_wakeup(&client->dev))
289
enable_irq_wake(client->irq);
290
else {
291
cy8ctmg110_set_sleepmode(ts, true);
292
cy8ctmg110_power(ts, false);
293
}
294
return 0;
295
}
296
297
static int cy8ctmg110_resume(struct device *dev)
298
{
299
struct i2c_client *client = to_i2c_client(dev);
300
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
301
302
if (device_may_wakeup(&client->dev))
303
disable_irq_wake(client->irq);
304
else {
305
cy8ctmg110_power(ts, true);
306
cy8ctmg110_set_sleepmode(ts, false);
307
}
308
return 0;
309
}
310
311
static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
312
#endif
313
314
static int __devexit cy8ctmg110_remove(struct i2c_client *client)
315
{
316
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
317
318
cy8ctmg110_set_sleepmode(ts, true);
319
cy8ctmg110_power(ts, false);
320
321
free_irq(client->irq, ts);
322
input_unregister_device(ts->input);
323
gpio_free(ts->irq_pin);
324
if (ts->reset_pin)
325
gpio_free(ts->reset_pin);
326
kfree(ts);
327
328
return 0;
329
}
330
331
static struct i2c_device_id cy8ctmg110_idtable[] = {
332
{ CY8CTMG110_DRIVER_NAME, 1 },
333
{ }
334
};
335
336
MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
337
338
static struct i2c_driver cy8ctmg110_driver = {
339
.driver = {
340
.owner = THIS_MODULE,
341
.name = CY8CTMG110_DRIVER_NAME,
342
#ifdef CONFIG_PM
343
.pm = &cy8ctmg110_pm,
344
#endif
345
},
346
.id_table = cy8ctmg110_idtable,
347
.probe = cy8ctmg110_probe,
348
.remove = __devexit_p(cy8ctmg110_remove),
349
};
350
351
static int __init cy8ctmg110_init(void)
352
{
353
return i2c_add_driver(&cy8ctmg110_driver);
354
}
355
356
static void __exit cy8ctmg110_exit(void)
357
{
358
i2c_del_driver(&cy8ctmg110_driver);
359
}
360
361
module_init(cy8ctmg110_init);
362
module_exit(cy8ctmg110_exit);
363
364
MODULE_AUTHOR("Samuli Konttila <[email protected]>");
365
MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
366
MODULE_LICENSE("GPL v2");
367
368