blob: ac4138e4d17c86095e6085e6e526eef8b32a07b1 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Source for:
2 * Cypress CY8CTMA300 Prototype touchscreen driver.
3 * drivers/input/touchscreen/cy8c_ts.c
4 *
5 * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
6 * Copyright (c) 2010, 2011 Code Aurora Forum. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2, and only version 2, as published by the
11 * Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 *
22 * Cypress reserves the right to make changes without further notice
23 * to the materials described herein. Cypress does not assume any
24 * liability arising out of the application described herein.
25 *
26 * Contact Cypress Semiconductor at www.cypress.com
27 *
28 * History:
29 * (C) 2010 Cypress - Update for GPL distribution
30 * (C) 2009 Cypress - Assume maintenance ownership
31 * (C) 2009 Enea - Original prototype
32 *
33 */
34
35#include <linux/init.h>
36#include <linux/module.h>
37#include <linux/i2c.h>
38#include <linux/input.h>
39#include <linux/slab.h>
40#include <linux/interrupt.h>
41#include <linux/irq.h>
42#include <linux/gpio.h>
43#include <linux/workqueue.h>
44#include <linux/mutex.h>
45#include <linux/delay.h>
46#include <linux/input/cy8c_ts.h>
47#include <linux/pm.h>
48#include <linux/pm_runtime.h>
49
50#if defined(CONFIG_HAS_EARLYSUSPEND)
51#include <linux/earlysuspend.h>
52
53/* Early-suspend level */
54#define CY8C_TS_SUSPEND_LEVEL 1
55#endif
56
57#define CY8CTMA300 0x0
58#define CY8CTMG200 0x1
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -040059#define CY8CTMA340 0x2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060
61#define INVALID_DATA 0xff
62
63#define TOUCHSCREEN_TIMEOUT (msecs_to_jiffies(10))
64#define INITIAL_DELAY (msecs_to_jiffies(25000))
65
66struct cy8c_ts_data {
67 u8 x_index;
68 u8 y_index;
69 u8 z_index;
70 u8 id_index;
71 u8 touch_index;
72 u8 data_reg;
73 u8 status_reg;
74 u8 data_size;
75 u8 touch_bytes;
76 u8 update_data;
77 u8 touch_meta_data;
78 u8 finger_size;
79};
80
81static struct cy8c_ts_data devices[] = {
82 [0] = {
83 .x_index = 6,
84 .y_index = 4,
85 .z_index = 3,
86 .id_index = 0,
87 .data_reg = 0x3,
88 .status_reg = 0x1,
89 .update_data = 0x4,
90 .touch_bytes = 8,
91 .touch_meta_data = 3,
92 .finger_size = 70,
93 },
94 [1] = {
95 .x_index = 2,
96 .y_index = 4,
97 .id_index = 6,
98 .data_reg = 0x6,
99 .status_reg = 0x5,
100 .update_data = 0x1,
101 .touch_bytes = 12,
102 .finger_size = 70,
103 },
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400104 [2] = {
105 .x_index = 1,
106 .y_index = 3,
107 .z_index = 5,
108 .id_index = 6,
109 .data_reg = 0x2,
110 .status_reg = 0,
111 .update_data = 0x4,
112 .touch_bytes = 6,
113 .touch_meta_data = 3,
114 .finger_size = 70,
115 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116};
117
118struct cy8c_ts {
119 struct i2c_client *client;
120 struct input_dev *input;
121 struct delayed_work work;
122 struct workqueue_struct *wq;
123 struct cy8c_ts_platform_data *pdata;
124 struct cy8c_ts_data *dd;
125 u8 *touch_data;
126 u8 device_id;
127 u8 prev_touches;
128 bool is_suspended;
129 bool int_pending;
130 struct mutex sus_lock;
131 u32 pen_irq;
132#if defined(CONFIG_HAS_EARLYSUSPEND)
133 struct early_suspend early_suspend;
134#endif
135};
136
137static inline u16 join_bytes(u8 a, u8 b)
138{
139 u16 ab = 0;
140 ab = ab | a;
141 ab = ab << 8 | b;
142 return ab;
143}
144
145static s32 cy8c_ts_write_reg_u8(struct i2c_client *client, u8 reg, u8 val)
146{
147 s32 data;
148
149 data = i2c_smbus_write_byte_data(client, reg, val);
150 if (data < 0)
151 dev_err(&client->dev, "error %d in writing reg 0x%x\n",
152 data, reg);
153
154 return data;
155}
156
157static s32 cy8c_ts_read_reg_u8(struct i2c_client *client, u8 reg)
158{
159 s32 data;
160
161 data = i2c_smbus_read_byte_data(client, reg);
162 if (data < 0)
163 dev_err(&client->dev, "error %d in reading reg 0x%x\n",
164 data, reg);
165
166 return data;
167}
168
169static int cy8c_ts_read(struct i2c_client *client, u8 reg, u8 *buf, int num)
170{
171 struct i2c_msg xfer_msg[2];
172
173 xfer_msg[0].addr = client->addr;
174 xfer_msg[0].len = 1;
175 xfer_msg[0].flags = 0;
176 xfer_msg[0].buf = &reg;
177
178 xfer_msg[1].addr = client->addr;
179 xfer_msg[1].len = num;
180 xfer_msg[1].flags = I2C_M_RD;
181 xfer_msg[1].buf = buf;
182
183 return i2c_transfer(client->adapter, xfer_msg, 2);
184}
185
186static void report_data(struct cy8c_ts *ts, u16 x, u16 y, u8 pressure, u8 id)
187{
188 if (ts->pdata->swap_xy)
189 swap(x, y);
190
191 /* handle inverting coordinates */
192 if (ts->pdata->invert_x)
193 x = ts->pdata->res_x - x;
194 if (ts->pdata->invert_y)
195 y = ts->pdata->res_y - y;
196
197 input_report_abs(ts->input, ABS_MT_TRACKING_ID, id);
198 input_report_abs(ts->input, ABS_MT_POSITION_X, x);
199 input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
200 input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, pressure);
201 input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, ts->dd->finger_size);
202 input_mt_sync(ts->input);
203}
204
205static void process_tma300_data(struct cy8c_ts *ts)
206{
207 u8 id, pressure, touches, i;
208 u16 x, y;
209
210 touches = ts->touch_data[ts->dd->touch_index];
211
212 for (i = 0; i < touches; i++) {
213 id = ts->touch_data[i * ts->dd->touch_bytes +
214 ts->dd->id_index];
215 pressure = ts->touch_data[i * ts->dd->touch_bytes +
216 ts->dd->z_index];
217 x = join_bytes(ts->touch_data[i * ts->dd->touch_bytes +
218 ts->dd->x_index],
219 ts->touch_data[i * ts->dd->touch_bytes +
220 ts->dd->x_index + 1]);
221 y = join_bytes(ts->touch_data[i * ts->dd->touch_bytes +
222 ts->dd->y_index],
223 ts->touch_data[i * ts->dd->touch_bytes +
224 ts->dd->y_index + 1]);
225
226 report_data(ts, x, y, pressure, id);
227 }
228
229 for (i = 0; i < ts->prev_touches - touches; i++) {
230 input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 0);
231 input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 0);
232 input_mt_sync(ts->input);
233 }
234
235 ts->prev_touches = touches;
236 input_sync(ts->input);
237}
238
239static void process_tmg200_data(struct cy8c_ts *ts)
240{
241 u8 id, touches, i;
242 u16 x, y;
243
244 touches = ts->touch_data[ts->dd->touch_index];
245
246 if (touches > 0) {
247 x = join_bytes(ts->touch_data[ts->dd->x_index],
248 ts->touch_data[ts->dd->x_index+1]);
249 y = join_bytes(ts->touch_data[ts->dd->y_index],
250 ts->touch_data[ts->dd->y_index+1]);
251 id = ts->touch_data[ts->dd->id_index];
252
253 report_data(ts, x, y, 255, id - 1);
254
255 if (touches == 2) {
256 x = join_bytes(ts->touch_data[ts->dd->x_index+5],
257 ts->touch_data[ts->dd->x_index+6]);
258 y = join_bytes(ts->touch_data[ts->dd->y_index+5],
259 ts->touch_data[ts->dd->y_index+6]);
260 id = ts->touch_data[ts->dd->id_index+5];
261
262 report_data(ts, x, y, 255, id - 1);
263 }
264 } else {
265 for (i = 0; i < ts->prev_touches; i++) {
266 input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 0);
267 input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 0);
268 input_mt_sync(ts->input);
269 }
270 }
271
272 input_sync(ts->input);
273 ts->prev_touches = touches;
274}
275
276static void cy8c_ts_xy_worker(struct work_struct *work)
277{
278 int rc;
279 struct cy8c_ts *ts = container_of(work, struct cy8c_ts,
280 work.work);
281
282 mutex_lock(&ts->sus_lock);
283 if (ts->is_suspended == true) {
284 dev_dbg(&ts->client->dev, "TS is supended\n");
285 ts->int_pending = true;
286 mutex_unlock(&ts->sus_lock);
287 return;
288 }
289 mutex_unlock(&ts->sus_lock);
290
291 /* read data from DATA_REG */
292 rc = cy8c_ts_read(ts->client, ts->dd->data_reg, ts->touch_data,
293 ts->dd->data_size);
294 if (rc < 0) {
295 dev_err(&ts->client->dev, "read failed\n");
296 goto schedule;
297 }
298
299 if (ts->touch_data[ts->dd->touch_index] == INVALID_DATA)
300 goto schedule;
301
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400302 if ((ts->device_id == CY8CTMA300) || (ts->device_id == CY8CTMA340))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303 process_tma300_data(ts);
304 else
305 process_tmg200_data(ts);
306
307schedule:
308 enable_irq(ts->pen_irq);
309
310 /* write to STATUS_REG to update coordinates*/
311 rc = cy8c_ts_write_reg_u8(ts->client, ts->dd->status_reg,
312 ts->dd->update_data);
313 if (rc < 0) {
314 dev_err(&ts->client->dev, "write failed, try once more\n");
315
316 rc = cy8c_ts_write_reg_u8(ts->client, ts->dd->status_reg,
317 ts->dd->update_data);
318 if (rc < 0)
319 dev_err(&ts->client->dev, "write failed, exiting\n");
320 }
321}
322
323static irqreturn_t cy8c_ts_irq(int irq, void *dev_id)
324{
325 struct cy8c_ts *ts = dev_id;
326
327 disable_irq_nosync(irq);
328
329 queue_delayed_work(ts->wq, &ts->work, 0);
330
331 return IRQ_HANDLED;
332}
333
334static int cy8c_ts_init_ts(struct i2c_client *client, struct cy8c_ts *ts)
335{
336 struct input_dev *input_device;
337 int rc = 0;
338
339 ts->dd = &devices[ts->device_id];
340
341 if (!ts->pdata->nfingers) {
342 dev_err(&client->dev, "Touches information not specified\n");
343 return -EINVAL;
344 }
345
346 if (ts->device_id == CY8CTMA300) {
347 if (ts->pdata->nfingers > 10) {
348 dev_err(&client->dev, "Touches >=1 & <= 10\n");
349 return -EINVAL;
350 }
351 ts->dd->data_size = ts->pdata->nfingers * ts->dd->touch_bytes +
352 ts->dd->touch_meta_data;
353 ts->dd->touch_index = ts->pdata->nfingers *
354 ts->dd->touch_bytes;
355 } else if (ts->device_id == CY8CTMG200) {
356 if (ts->pdata->nfingers > 2) {
357 dev_err(&client->dev, "Touches >=1 & <= 2\n");
358 return -EINVAL;
359 }
360 ts->dd->data_size = ts->dd->touch_bytes;
361 ts->dd->touch_index = 0x0;
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400362 } else if (ts->device_id == CY8CTMA340) {
363 if (ts->pdata->nfingers > 10) {
364 dev_err(&client->dev, "Touches >=1 & <= 10\n");
365 return -EINVAL;
366 }
367 ts->dd->data_size = ts->pdata->nfingers * ts->dd->touch_bytes +
368 ts->dd->touch_meta_data;
369 ts->dd->touch_index = 0x0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 }
371
372 ts->touch_data = kzalloc(ts->dd->data_size, GFP_KERNEL);
373 if (!ts->touch_data) {
374 pr_err("%s: Unable to allocate memory\n", __func__);
375 return -ENOMEM;
376 }
377
378 ts->prev_touches = 0;
379
380 input_device = input_allocate_device();
381 if (!input_device) {
382 rc = -ENOMEM;
383 goto error_alloc_dev;
384 }
385
386 ts->input = input_device;
387 input_device->name = ts->pdata->ts_name;
388 input_device->id.bustype = BUS_I2C;
389 input_device->dev.parent = &client->dev;
390 input_set_drvdata(input_device, ts);
391
392 __set_bit(EV_ABS, input_device->evbit);
393
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400394 if (ts->device_id == CY8CTMA340) {
395 /* set up virtual key */
396 __set_bit(EV_KEY, input_device->evbit);
397 /* set dummy key to make driver work with virtual keys */
398 input_set_capability(input_device, EV_KEY, KEY_PROG1);
399 }
400
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401 input_set_abs_params(input_device, ABS_MT_POSITION_X,
402 ts->pdata->dis_min_x, ts->pdata->dis_max_x, 0, 0);
403 input_set_abs_params(input_device, ABS_MT_POSITION_Y,
404 ts->pdata->dis_min_y, ts->pdata->dis_max_y, 0, 0);
405 input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
406 ts->pdata->min_touch, ts->pdata->max_touch, 0, 0);
407 input_set_abs_params(input_device, ABS_MT_WIDTH_MAJOR,
408 ts->pdata->min_width, ts->pdata->max_width, 0, 0);
409 input_set_abs_params(input_device, ABS_MT_TRACKING_ID,
410 ts->pdata->min_tid, ts->pdata->max_tid, 0, 0);
411
412 ts->wq = create_singlethread_workqueue("kworkqueue_ts");
413 if (!ts->wq) {
414 dev_err(&client->dev, "Could not create workqueue\n");
415 goto error_wq_create;
416 }
417
418 INIT_DELAYED_WORK(&ts->work, cy8c_ts_xy_worker);
419
420 rc = input_register_device(input_device);
421 if (rc)
422 goto error_unreg_device;
423
424 return 0;
425
426error_unreg_device:
427 destroy_workqueue(ts->wq);
428error_wq_create:
429 input_free_device(input_device);
430error_alloc_dev:
431 kfree(ts->touch_data);
432 return rc;
433}
434
435#ifdef CONFIG_PM
436static int cy8c_ts_suspend(struct device *dev)
437{
438 struct cy8c_ts *ts = dev_get_drvdata(dev);
439 int rc = 0;
440
441 if (device_may_wakeup(dev)) {
442 /* mark suspend flag */
443 mutex_lock(&ts->sus_lock);
444 ts->is_suspended = true;
445 mutex_unlock(&ts->sus_lock);
446
447 enable_irq_wake(ts->pen_irq);
448 } else {
449 disable_irq_nosync(ts->pen_irq);
450
451 rc = cancel_delayed_work_sync(&ts->work);
452
453 if (rc) {
454 /* missed the worker, write to STATUS_REG to
455 acknowledge interrupt */
456 rc = cy8c_ts_write_reg_u8(ts->client,
457 ts->dd->status_reg, ts->dd->update_data);
458 if (rc < 0) {
459 dev_err(&ts->client->dev,
460 "write failed, try once more\n");
461
462 rc = cy8c_ts_write_reg_u8(ts->client,
463 ts->dd->status_reg,
464 ts->dd->update_data);
465 if (rc < 0)
466 dev_err(&ts->client->dev,
467 "write failed, exiting\n");
468 }
469
470 enable_irq(ts->pen_irq);
471 }
472
473 gpio_free(ts->pdata->irq_gpio);
474
475 if (ts->pdata->power_on) {
476 rc = ts->pdata->power_on(0);
477 if (rc) {
478 dev_err(dev, "unable to goto suspend\n");
479 return rc;
480 }
481 }
482 }
483 return 0;
484}
485
486static int cy8c_ts_resume(struct device *dev)
487{
488 struct cy8c_ts *ts = dev_get_drvdata(dev);
489 int rc = 0;
490
491 if (device_may_wakeup(dev)) {
492 disable_irq_wake(ts->pen_irq);
493
494 mutex_lock(&ts->sus_lock);
495 ts->is_suspended = false;
496
497 if (ts->int_pending == true) {
498 ts->int_pending = false;
499
500 /* start a delayed work */
501 queue_delayed_work(ts->wq, &ts->work, 0);
502 }
503 mutex_unlock(&ts->sus_lock);
504
505 } else {
506 if (ts->pdata->power_on) {
507 rc = ts->pdata->power_on(1);
508 if (rc) {
509 dev_err(dev, "unable to resume\n");
510 return rc;
511 }
512 }
513
514 /* configure touchscreen interrupt gpio */
515 rc = gpio_request(ts->pdata->irq_gpio, "cy8c_irq_gpio");
516 if (rc) {
517 pr_err("%s: unable to request gpio %d\n",
518 __func__, ts->pdata->irq_gpio);
519 goto err_power_off;
520 }
521
522 rc = gpio_direction_input(ts->pdata->irq_gpio);
523 if (rc) {
524 pr_err("%s: unable to set direction for gpio %d\n",
525 __func__, ts->pdata->irq_gpio);
526 goto err_gpio_free;
527 }
528
529 enable_irq(ts->pen_irq);
Mohan Pallakadf53bc32011-08-09 15:37:33 +0530530
531 /* Clear the status register of the TS controller */
532 rc = cy8c_ts_write_reg_u8(ts->client,
533 ts->dd->status_reg, ts->dd->update_data);
534 if (rc < 0) {
535 dev_err(&ts->client->dev,
536 "write failed, try once more\n");
537
538 rc = cy8c_ts_write_reg_u8(ts->client,
539 ts->dd->status_reg,
540 ts->dd->update_data);
541 if (rc < 0)
542 dev_err(&ts->client->dev,
543 "write failed, exiting\n");
544 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 }
546 return 0;
547err_gpio_free:
548 gpio_free(ts->pdata->irq_gpio);
549err_power_off:
550 if (ts->pdata->power_on)
551 rc = ts->pdata->power_on(0);
552 return rc;
553}
554
555#ifdef CONFIG_HAS_EARLYSUSPEND
556static void cy8c_ts_early_suspend(struct early_suspend *h)
557{
558 struct cy8c_ts *ts = container_of(h, struct cy8c_ts, early_suspend);
559
560 cy8c_ts_suspend(&ts->client->dev);
561}
562
563static void cy8c_ts_late_resume(struct early_suspend *h)
564{
565 struct cy8c_ts *ts = container_of(h, struct cy8c_ts, early_suspend);
566
567 cy8c_ts_resume(&ts->client->dev);
568}
569#endif
570
571static struct dev_pm_ops cy8c_ts_pm_ops = {
572#ifndef CONFIG_HAS_EARLYSUSPEND
573 .suspend = cy8c_ts_suspend,
574 .resume = cy8c_ts_resume,
575#endif
576};
577#endif
578
579static int __devinit cy8c_ts_probe(struct i2c_client *client,
580 const struct i2c_device_id *id)
581{
582 struct cy8c_ts *ts;
583 struct cy8c_ts_platform_data *pdata = client->dev.platform_data;
584 int rc, temp_reg;
585
586 if (!pdata) {
587 dev_err(&client->dev, "platform data is required!\n");
588 return -EINVAL;
589 }
590
591 if (!i2c_check_functionality(client->adapter,
592 I2C_FUNC_SMBUS_READ_WORD_DATA)) {
593 dev_err(&client->dev, "I2C functionality not supported\n");
594 return -EIO;
595 }
596
597 ts = kzalloc(sizeof(*ts), GFP_KERNEL);
598 if (!ts)
599 return -ENOMEM;
600
601 /* Enable runtime PM ops, start in ACTIVE mode */
602 rc = pm_runtime_set_active(&client->dev);
603 if (rc < 0)
604 dev_dbg(&client->dev, "unable to set runtime pm state\n");
605 pm_runtime_enable(&client->dev);
606
607 ts->client = client;
608 ts->pdata = pdata;
609 i2c_set_clientdata(client, ts);
610 ts->device_id = id->driver_data;
611
612 if (ts->pdata->dev_setup) {
613 rc = ts->pdata->dev_setup(1);
614 if (rc < 0) {
615 dev_err(&client->dev, "dev setup failed\n");
616 goto error_touch_data_alloc;
617 }
618 }
619
620 /* power on the device */
621 if (ts->pdata->power_on) {
622 rc = ts->pdata->power_on(1);
623 if (rc) {
624 pr_err("%s: Unable to power on the device\n", __func__);
625 goto error_dev_setup;
626 }
627 }
628
629 /* read one byte to make sure i2c device exists */
630 if (id->driver_data == CY8CTMA300)
631 temp_reg = 0x01;
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400632 else if (id->driver_data == CY8CTMA340)
633 temp_reg = 0x00;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634 else
635 temp_reg = 0x05;
636
637 rc = cy8c_ts_read_reg_u8(client, temp_reg);
638 if (rc < 0) {
639 dev_err(&client->dev, "i2c sanity check failed\n");
640 goto error_power_on;
641 }
642
643 ts->is_suspended = false;
644 ts->int_pending = false;
645 mutex_init(&ts->sus_lock);
646
647 rc = cy8c_ts_init_ts(client, ts);
648 if (rc < 0) {
649 dev_err(&client->dev, "CY8CTMG200-TMA300 init failed\n");
650 goto error_mutex_destroy;
651 }
652
653 if (ts->pdata->resout_gpio < 0)
654 goto config_irq_gpio;
655
656 /* configure touchscreen reset out gpio */
657 rc = gpio_request(ts->pdata->resout_gpio, "cy8c_resout_gpio");
658 if (rc) {
659 pr_err("%s: unable to request gpio %d\n",
660 __func__, ts->pdata->resout_gpio);
661 goto error_uninit_ts;
662 }
663
664 rc = gpio_direction_output(ts->pdata->resout_gpio, 0);
665 if (rc) {
666 pr_err("%s: unable to set direction for gpio %d\n",
667 __func__, ts->pdata->resout_gpio);
668 goto error_resout_gpio_dir;
669 }
670 /* reset gpio stabilization time */
671 msleep(20);
672
673config_irq_gpio:
674 /* configure touchscreen interrupt gpio */
675 rc = gpio_request(ts->pdata->irq_gpio, "cy8c_irq_gpio");
676 if (rc) {
677 pr_err("%s: unable to request gpio %d\n",
678 __func__, ts->pdata->irq_gpio);
679 goto error_irq_gpio_req;
680 }
681
682 rc = gpio_direction_input(ts->pdata->irq_gpio);
683 if (rc) {
684 pr_err("%s: unable to set direction for gpio %d\n",
685 __func__, ts->pdata->irq_gpio);
686 goto error_irq_gpio_dir;
687 }
688
689 ts->pen_irq = gpio_to_irq(ts->pdata->irq_gpio);
690 rc = request_irq(ts->pen_irq, cy8c_ts_irq,
691 IRQF_TRIGGER_FALLING,
692 ts->client->dev.driver->name, ts);
693 if (rc) {
694 dev_err(&ts->client->dev, "could not request irq\n");
695 goto error_req_irq_fail;
696 }
697
698 /* Clear the status register of the TS controller */
699 rc = cy8c_ts_write_reg_u8(ts->client, ts->dd->status_reg,
700 ts->dd->update_data);
701 if (rc < 0) {
702 /* Do multiple writes in case of failure */
703 dev_err(&ts->client->dev, "%s: write failed %d"
704 "trying again\n", __func__, rc);
705 rc = cy8c_ts_write_reg_u8(ts->client,
706 ts->dd->status_reg, ts->dd->update_data);
707 if (rc < 0) {
708 dev_err(&ts->client->dev, "%s: write failed"
709 "second time(%d)\n", __func__, rc);
710 }
711 }
712
713 device_init_wakeup(&client->dev, ts->pdata->wakeup);
714
715#ifdef CONFIG_HAS_EARLYSUSPEND
716 ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN +
717 CY8C_TS_SUSPEND_LEVEL;
718 ts->early_suspend.suspend = cy8c_ts_early_suspend;
719 ts->early_suspend.resume = cy8c_ts_late_resume;
720 register_early_suspend(&ts->early_suspend);
721#endif
722
723 return 0;
724error_req_irq_fail:
725error_irq_gpio_dir:
726 gpio_free(ts->pdata->irq_gpio);
727error_irq_gpio_req:
728error_resout_gpio_dir:
729 if (ts->pdata->resout_gpio >= 0)
730 gpio_free(ts->pdata->resout_gpio);
731error_uninit_ts:
732 destroy_workqueue(ts->wq);
733 input_unregister_device(ts->input);
734 kfree(ts->touch_data);
735error_mutex_destroy:
736 mutex_destroy(&ts->sus_lock);
737error_power_on:
738 if (ts->pdata->power_on)
739 ts->pdata->power_on(0);
740error_dev_setup:
741 if (ts->pdata->dev_setup)
742 ts->pdata->dev_setup(0);
743error_touch_data_alloc:
744 pm_runtime_set_suspended(&client->dev);
745 pm_runtime_disable(&client->dev);
746 kfree(ts);
747 return rc;
748}
749
750static int __devexit cy8c_ts_remove(struct i2c_client *client)
751{
752 struct cy8c_ts *ts = i2c_get_clientdata(client);
753
754#if defined(CONFIG_HAS_EARLYSUSPEND)
755 unregister_early_suspend(&ts->early_suspend);
756#endif
757 pm_runtime_set_suspended(&client->dev);
758 pm_runtime_disable(&client->dev);
759
760 device_init_wakeup(&client->dev, 0);
761
762 cancel_delayed_work_sync(&ts->work);
763
764 free_irq(ts->pen_irq, ts);
765
766 gpio_free(ts->pdata->irq_gpio);
767
768 if (ts->pdata->resout_gpio >= 0)
769 gpio_free(ts->pdata->resout_gpio);
770
771 destroy_workqueue(ts->wq);
772
773 input_unregister_device(ts->input);
774
775 mutex_destroy(&ts->sus_lock);
776
777 if (ts->pdata->power_on)
778 ts->pdata->power_on(0);
779
780 if (ts->pdata->dev_setup)
781 ts->pdata->dev_setup(0);
782
783 kfree(ts->touch_data);
784 kfree(ts);
785
786 return 0;
787}
788
789static const struct i2c_device_id cy8c_ts_id[] = {
790 {"cy8ctma300", CY8CTMA300},
791 {"cy8ctmg200", CY8CTMG200},
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400792 {"cy8ctma340", CY8CTMA340},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700793 {}
794};
795MODULE_DEVICE_TABLE(i2c, cy8c_ts_id);
796
797
798static struct i2c_driver cy8c_ts_driver = {
799 .driver = {
800 .name = "cy8c_ts",
801 .owner = THIS_MODULE,
802#ifdef CONFIG_PM
803 .pm = &cy8c_ts_pm_ops,
804#endif
805 },
806 .probe = cy8c_ts_probe,
807 .remove = __devexit_p(cy8c_ts_remove),
808 .id_table = cy8c_ts_id,
809};
810
811static int __init cy8c_ts_init(void)
812{
813 return i2c_add_driver(&cy8c_ts_driver);
814}
815/* Making this as late init to avoid power fluctuations
816 * during LCD initialization.
817 */
818late_initcall(cy8c_ts_init);
819
820static void __exit cy8c_ts_exit(void)
821{
822 return i2c_del_driver(&cy8c_ts_driver);
823}
824module_exit(cy8c_ts_exit);
825
826MODULE_LICENSE("GPL");
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400827MODULE_DESCRIPTION("CY8CTMA340-CY8CTMG200 touchscreen controller driver");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700828MODULE_AUTHOR("Cypress");
829MODULE_ALIAS("platform:cy8c_ts");