blob: f70858251c81aa5a7a46d6ea2425477da1b0d4a2 [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);
Praveena Pachipulusu0106ea62011-11-16 15:40:07 +0530200 input_report_abs(ts->input, ABS_MT_PRESSURE, pressure);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201 input_mt_sync(ts->input);
202}
203
204static void process_tma300_data(struct cy8c_ts *ts)
205{
206 u8 id, pressure, touches, i;
207 u16 x, y;
208
209 touches = ts->touch_data[ts->dd->touch_index];
210
211 for (i = 0; i < touches; i++) {
212 id = ts->touch_data[i * ts->dd->touch_bytes +
213 ts->dd->id_index];
214 pressure = ts->touch_data[i * ts->dd->touch_bytes +
215 ts->dd->z_index];
216 x = join_bytes(ts->touch_data[i * ts->dd->touch_bytes +
217 ts->dd->x_index],
218 ts->touch_data[i * ts->dd->touch_bytes +
219 ts->dd->x_index + 1]);
220 y = join_bytes(ts->touch_data[i * ts->dd->touch_bytes +
221 ts->dd->y_index],
222 ts->touch_data[i * ts->dd->touch_bytes +
223 ts->dd->y_index + 1]);
224
225 report_data(ts, x, y, pressure, id);
226 }
227
228 for (i = 0; i < ts->prev_touches - touches; i++) {
Praveena Pachipulusu0106ea62011-11-16 15:40:07 +0530229 input_report_abs(ts->input, ABS_MT_PRESSURE, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 input_mt_sync(ts->input);
231 }
232
233 ts->prev_touches = touches;
234 input_sync(ts->input);
235}
236
237static void process_tmg200_data(struct cy8c_ts *ts)
238{
239 u8 id, touches, i;
240 u16 x, y;
241
242 touches = ts->touch_data[ts->dd->touch_index];
243
244 if (touches > 0) {
245 x = join_bytes(ts->touch_data[ts->dd->x_index],
246 ts->touch_data[ts->dd->x_index+1]);
247 y = join_bytes(ts->touch_data[ts->dd->y_index],
248 ts->touch_data[ts->dd->y_index+1]);
249 id = ts->touch_data[ts->dd->id_index];
250
251 report_data(ts, x, y, 255, id - 1);
252
253 if (touches == 2) {
254 x = join_bytes(ts->touch_data[ts->dd->x_index+5],
255 ts->touch_data[ts->dd->x_index+6]);
256 y = join_bytes(ts->touch_data[ts->dd->y_index+5],
257 ts->touch_data[ts->dd->y_index+6]);
258 id = ts->touch_data[ts->dd->id_index+5];
259
260 report_data(ts, x, y, 255, id - 1);
261 }
262 } else {
263 for (i = 0; i < ts->prev_touches; i++) {
Praveena Pachipulusu0106ea62011-11-16 15:40:07 +0530264 input_report_abs(ts->input, ABS_MT_PRESSURE, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 input_mt_sync(ts->input);
266 }
267 }
268
269 input_sync(ts->input);
270 ts->prev_touches = touches;
271}
272
273static void cy8c_ts_xy_worker(struct work_struct *work)
274{
275 int rc;
276 struct cy8c_ts *ts = container_of(work, struct cy8c_ts,
277 work.work);
278
279 mutex_lock(&ts->sus_lock);
280 if (ts->is_suspended == true) {
281 dev_dbg(&ts->client->dev, "TS is supended\n");
282 ts->int_pending = true;
283 mutex_unlock(&ts->sus_lock);
284 return;
285 }
286 mutex_unlock(&ts->sus_lock);
287
288 /* read data from DATA_REG */
289 rc = cy8c_ts_read(ts->client, ts->dd->data_reg, ts->touch_data,
290 ts->dd->data_size);
291 if (rc < 0) {
292 dev_err(&ts->client->dev, "read failed\n");
293 goto schedule;
294 }
295
296 if (ts->touch_data[ts->dd->touch_index] == INVALID_DATA)
297 goto schedule;
298
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400299 if ((ts->device_id == CY8CTMA300) || (ts->device_id == CY8CTMA340))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 process_tma300_data(ts);
301 else
302 process_tmg200_data(ts);
303
304schedule:
305 enable_irq(ts->pen_irq);
306
307 /* write to STATUS_REG to update coordinates*/
308 rc = cy8c_ts_write_reg_u8(ts->client, ts->dd->status_reg,
309 ts->dd->update_data);
310 if (rc < 0) {
311 dev_err(&ts->client->dev, "write failed, try once more\n");
312
313 rc = cy8c_ts_write_reg_u8(ts->client, ts->dd->status_reg,
314 ts->dd->update_data);
315 if (rc < 0)
316 dev_err(&ts->client->dev, "write failed, exiting\n");
317 }
318}
319
320static irqreturn_t cy8c_ts_irq(int irq, void *dev_id)
321{
322 struct cy8c_ts *ts = dev_id;
323
324 disable_irq_nosync(irq);
325
326 queue_delayed_work(ts->wq, &ts->work, 0);
327
328 return IRQ_HANDLED;
329}
330
331static int cy8c_ts_init_ts(struct i2c_client *client, struct cy8c_ts *ts)
332{
333 struct input_dev *input_device;
334 int rc = 0;
335
336 ts->dd = &devices[ts->device_id];
337
338 if (!ts->pdata->nfingers) {
339 dev_err(&client->dev, "Touches information not specified\n");
340 return -EINVAL;
341 }
342
343 if (ts->device_id == CY8CTMA300) {
344 if (ts->pdata->nfingers > 10) {
345 dev_err(&client->dev, "Touches >=1 & <= 10\n");
346 return -EINVAL;
347 }
348 ts->dd->data_size = ts->pdata->nfingers * ts->dd->touch_bytes +
349 ts->dd->touch_meta_data;
350 ts->dd->touch_index = ts->pdata->nfingers *
351 ts->dd->touch_bytes;
352 } else if (ts->device_id == CY8CTMG200) {
353 if (ts->pdata->nfingers > 2) {
354 dev_err(&client->dev, "Touches >=1 & <= 2\n");
355 return -EINVAL;
356 }
357 ts->dd->data_size = ts->dd->touch_bytes;
358 ts->dd->touch_index = 0x0;
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400359 } else if (ts->device_id == CY8CTMA340) {
360 if (ts->pdata->nfingers > 10) {
361 dev_err(&client->dev, "Touches >=1 & <= 10\n");
362 return -EINVAL;
363 }
364 ts->dd->data_size = ts->pdata->nfingers * ts->dd->touch_bytes +
365 ts->dd->touch_meta_data;
366 ts->dd->touch_index = 0x0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367 }
368
369 ts->touch_data = kzalloc(ts->dd->data_size, GFP_KERNEL);
370 if (!ts->touch_data) {
371 pr_err("%s: Unable to allocate memory\n", __func__);
372 return -ENOMEM;
373 }
374
375 ts->prev_touches = 0;
376
377 input_device = input_allocate_device();
378 if (!input_device) {
379 rc = -ENOMEM;
380 goto error_alloc_dev;
381 }
382
383 ts->input = input_device;
384 input_device->name = ts->pdata->ts_name;
385 input_device->id.bustype = BUS_I2C;
386 input_device->dev.parent = &client->dev;
387 input_set_drvdata(input_device, ts);
388
389 __set_bit(EV_ABS, input_device->evbit);
390
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400391 if (ts->device_id == CY8CTMA340) {
392 /* set up virtual key */
393 __set_bit(EV_KEY, input_device->evbit);
394 /* set dummy key to make driver work with virtual keys */
395 input_set_capability(input_device, EV_KEY, KEY_PROG1);
396 }
397
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700398 input_set_abs_params(input_device, ABS_MT_POSITION_X,
399 ts->pdata->dis_min_x, ts->pdata->dis_max_x, 0, 0);
400 input_set_abs_params(input_device, ABS_MT_POSITION_Y,
401 ts->pdata->dis_min_y, ts->pdata->dis_max_y, 0, 0);
Praveena Pachipulusu0106ea62011-11-16 15:40:07 +0530402 input_set_abs_params(input_device, ABS_MT_PRESSURE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403 ts->pdata->min_touch, ts->pdata->max_touch, 0, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404 input_set_abs_params(input_device, ABS_MT_TRACKING_ID,
405 ts->pdata->min_tid, ts->pdata->max_tid, 0, 0);
406
407 ts->wq = create_singlethread_workqueue("kworkqueue_ts");
408 if (!ts->wq) {
409 dev_err(&client->dev, "Could not create workqueue\n");
410 goto error_wq_create;
411 }
412
413 INIT_DELAYED_WORK(&ts->work, cy8c_ts_xy_worker);
414
415 rc = input_register_device(input_device);
416 if (rc)
417 goto error_unreg_device;
418
419 return 0;
420
421error_unreg_device:
422 destroy_workqueue(ts->wq);
423error_wq_create:
424 input_free_device(input_device);
425error_alloc_dev:
426 kfree(ts->touch_data);
427 return rc;
428}
429
430#ifdef CONFIG_PM
431static int cy8c_ts_suspend(struct device *dev)
432{
433 struct cy8c_ts *ts = dev_get_drvdata(dev);
434 int rc = 0;
435
436 if (device_may_wakeup(dev)) {
437 /* mark suspend flag */
438 mutex_lock(&ts->sus_lock);
439 ts->is_suspended = true;
440 mutex_unlock(&ts->sus_lock);
441
442 enable_irq_wake(ts->pen_irq);
443 } else {
444 disable_irq_nosync(ts->pen_irq);
445
446 rc = cancel_delayed_work_sync(&ts->work);
447
448 if (rc) {
449 /* missed the worker, write to STATUS_REG to
450 acknowledge interrupt */
451 rc = cy8c_ts_write_reg_u8(ts->client,
452 ts->dd->status_reg, ts->dd->update_data);
453 if (rc < 0) {
454 dev_err(&ts->client->dev,
455 "write failed, try once more\n");
456
457 rc = cy8c_ts_write_reg_u8(ts->client,
458 ts->dd->status_reg,
459 ts->dd->update_data);
460 if (rc < 0)
461 dev_err(&ts->client->dev,
462 "write failed, exiting\n");
463 }
464
465 enable_irq(ts->pen_irq);
466 }
467
468 gpio_free(ts->pdata->irq_gpio);
469
470 if (ts->pdata->power_on) {
471 rc = ts->pdata->power_on(0);
472 if (rc) {
473 dev_err(dev, "unable to goto suspend\n");
474 return rc;
475 }
476 }
477 }
478 return 0;
479}
480
481static int cy8c_ts_resume(struct device *dev)
482{
483 struct cy8c_ts *ts = dev_get_drvdata(dev);
484 int rc = 0;
485
486 if (device_may_wakeup(dev)) {
487 disable_irq_wake(ts->pen_irq);
488
489 mutex_lock(&ts->sus_lock);
490 ts->is_suspended = false;
491
492 if (ts->int_pending == true) {
493 ts->int_pending = false;
494
495 /* start a delayed work */
496 queue_delayed_work(ts->wq, &ts->work, 0);
497 }
498 mutex_unlock(&ts->sus_lock);
499
500 } else {
501 if (ts->pdata->power_on) {
502 rc = ts->pdata->power_on(1);
503 if (rc) {
504 dev_err(dev, "unable to resume\n");
505 return rc;
506 }
507 }
508
509 /* configure touchscreen interrupt gpio */
510 rc = gpio_request(ts->pdata->irq_gpio, "cy8c_irq_gpio");
511 if (rc) {
512 pr_err("%s: unable to request gpio %d\n",
513 __func__, ts->pdata->irq_gpio);
514 goto err_power_off;
515 }
516
517 rc = gpio_direction_input(ts->pdata->irq_gpio);
518 if (rc) {
519 pr_err("%s: unable to set direction for gpio %d\n",
520 __func__, ts->pdata->irq_gpio);
521 goto err_gpio_free;
522 }
523
524 enable_irq(ts->pen_irq);
Mohan Pallakadf53bc32011-08-09 15:37:33 +0530525
526 /* Clear the status register of the TS controller */
527 rc = cy8c_ts_write_reg_u8(ts->client,
528 ts->dd->status_reg, ts->dd->update_data);
529 if (rc < 0) {
530 dev_err(&ts->client->dev,
531 "write failed, try once more\n");
532
533 rc = cy8c_ts_write_reg_u8(ts->client,
534 ts->dd->status_reg,
535 ts->dd->update_data);
536 if (rc < 0)
537 dev_err(&ts->client->dev,
538 "write failed, exiting\n");
539 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700540 }
541 return 0;
542err_gpio_free:
543 gpio_free(ts->pdata->irq_gpio);
544err_power_off:
545 if (ts->pdata->power_on)
546 rc = ts->pdata->power_on(0);
547 return rc;
548}
549
550#ifdef CONFIG_HAS_EARLYSUSPEND
551static void cy8c_ts_early_suspend(struct early_suspend *h)
552{
553 struct cy8c_ts *ts = container_of(h, struct cy8c_ts, early_suspend);
554
555 cy8c_ts_suspend(&ts->client->dev);
556}
557
558static void cy8c_ts_late_resume(struct early_suspend *h)
559{
560 struct cy8c_ts *ts = container_of(h, struct cy8c_ts, early_suspend);
561
562 cy8c_ts_resume(&ts->client->dev);
563}
564#endif
565
566static struct dev_pm_ops cy8c_ts_pm_ops = {
567#ifndef CONFIG_HAS_EARLYSUSPEND
568 .suspend = cy8c_ts_suspend,
569 .resume = cy8c_ts_resume,
570#endif
571};
572#endif
573
574static int __devinit cy8c_ts_probe(struct i2c_client *client,
575 const struct i2c_device_id *id)
576{
577 struct cy8c_ts *ts;
578 struct cy8c_ts_platform_data *pdata = client->dev.platform_data;
579 int rc, temp_reg;
580
581 if (!pdata) {
582 dev_err(&client->dev, "platform data is required!\n");
583 return -EINVAL;
584 }
585
586 if (!i2c_check_functionality(client->adapter,
587 I2C_FUNC_SMBUS_READ_WORD_DATA)) {
588 dev_err(&client->dev, "I2C functionality not supported\n");
589 return -EIO;
590 }
591
592 ts = kzalloc(sizeof(*ts), GFP_KERNEL);
593 if (!ts)
594 return -ENOMEM;
595
596 /* Enable runtime PM ops, start in ACTIVE mode */
597 rc = pm_runtime_set_active(&client->dev);
598 if (rc < 0)
599 dev_dbg(&client->dev, "unable to set runtime pm state\n");
600 pm_runtime_enable(&client->dev);
601
602 ts->client = client;
603 ts->pdata = pdata;
604 i2c_set_clientdata(client, ts);
605 ts->device_id = id->driver_data;
606
607 if (ts->pdata->dev_setup) {
608 rc = ts->pdata->dev_setup(1);
609 if (rc < 0) {
610 dev_err(&client->dev, "dev setup failed\n");
611 goto error_touch_data_alloc;
612 }
613 }
614
615 /* power on the device */
616 if (ts->pdata->power_on) {
617 rc = ts->pdata->power_on(1);
618 if (rc) {
619 pr_err("%s: Unable to power on the device\n", __func__);
620 goto error_dev_setup;
621 }
622 }
623
624 /* read one byte to make sure i2c device exists */
625 if (id->driver_data == CY8CTMA300)
626 temp_reg = 0x01;
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400627 else if (id->driver_data == CY8CTMA340)
628 temp_reg = 0x00;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700629 else
630 temp_reg = 0x05;
631
632 rc = cy8c_ts_read_reg_u8(client, temp_reg);
633 if (rc < 0) {
634 dev_err(&client->dev, "i2c sanity check failed\n");
635 goto error_power_on;
636 }
637
638 ts->is_suspended = false;
639 ts->int_pending = false;
640 mutex_init(&ts->sus_lock);
641
642 rc = cy8c_ts_init_ts(client, ts);
643 if (rc < 0) {
644 dev_err(&client->dev, "CY8CTMG200-TMA300 init failed\n");
645 goto error_mutex_destroy;
646 }
647
648 if (ts->pdata->resout_gpio < 0)
649 goto config_irq_gpio;
650
651 /* configure touchscreen reset out gpio */
652 rc = gpio_request(ts->pdata->resout_gpio, "cy8c_resout_gpio");
653 if (rc) {
654 pr_err("%s: unable to request gpio %d\n",
655 __func__, ts->pdata->resout_gpio);
656 goto error_uninit_ts;
657 }
658
659 rc = gpio_direction_output(ts->pdata->resout_gpio, 0);
660 if (rc) {
661 pr_err("%s: unable to set direction for gpio %d\n",
662 __func__, ts->pdata->resout_gpio);
663 goto error_resout_gpio_dir;
664 }
665 /* reset gpio stabilization time */
666 msleep(20);
667
668config_irq_gpio:
669 /* configure touchscreen interrupt gpio */
670 rc = gpio_request(ts->pdata->irq_gpio, "cy8c_irq_gpio");
671 if (rc) {
672 pr_err("%s: unable to request gpio %d\n",
673 __func__, ts->pdata->irq_gpio);
674 goto error_irq_gpio_req;
675 }
676
677 rc = gpio_direction_input(ts->pdata->irq_gpio);
678 if (rc) {
679 pr_err("%s: unable to set direction for gpio %d\n",
680 __func__, ts->pdata->irq_gpio);
681 goto error_irq_gpio_dir;
682 }
683
684 ts->pen_irq = gpio_to_irq(ts->pdata->irq_gpio);
685 rc = request_irq(ts->pen_irq, cy8c_ts_irq,
686 IRQF_TRIGGER_FALLING,
687 ts->client->dev.driver->name, ts);
688 if (rc) {
689 dev_err(&ts->client->dev, "could not request irq\n");
690 goto error_req_irq_fail;
691 }
692
693 /* Clear the status register of the TS controller */
694 rc = cy8c_ts_write_reg_u8(ts->client, ts->dd->status_reg,
695 ts->dd->update_data);
696 if (rc < 0) {
697 /* Do multiple writes in case of failure */
698 dev_err(&ts->client->dev, "%s: write failed %d"
699 "trying again\n", __func__, rc);
700 rc = cy8c_ts_write_reg_u8(ts->client,
701 ts->dd->status_reg, ts->dd->update_data);
702 if (rc < 0) {
703 dev_err(&ts->client->dev, "%s: write failed"
704 "second time(%d)\n", __func__, rc);
705 }
706 }
707
708 device_init_wakeup(&client->dev, ts->pdata->wakeup);
709
710#ifdef CONFIG_HAS_EARLYSUSPEND
711 ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN +
712 CY8C_TS_SUSPEND_LEVEL;
713 ts->early_suspend.suspend = cy8c_ts_early_suspend;
714 ts->early_suspend.resume = cy8c_ts_late_resume;
715 register_early_suspend(&ts->early_suspend);
716#endif
717
718 return 0;
719error_req_irq_fail:
720error_irq_gpio_dir:
721 gpio_free(ts->pdata->irq_gpio);
722error_irq_gpio_req:
723error_resout_gpio_dir:
724 if (ts->pdata->resout_gpio >= 0)
725 gpio_free(ts->pdata->resout_gpio);
726error_uninit_ts:
727 destroy_workqueue(ts->wq);
728 input_unregister_device(ts->input);
729 kfree(ts->touch_data);
730error_mutex_destroy:
731 mutex_destroy(&ts->sus_lock);
732error_power_on:
733 if (ts->pdata->power_on)
734 ts->pdata->power_on(0);
735error_dev_setup:
736 if (ts->pdata->dev_setup)
737 ts->pdata->dev_setup(0);
738error_touch_data_alloc:
739 pm_runtime_set_suspended(&client->dev);
740 pm_runtime_disable(&client->dev);
741 kfree(ts);
742 return rc;
743}
744
745static int __devexit cy8c_ts_remove(struct i2c_client *client)
746{
747 struct cy8c_ts *ts = i2c_get_clientdata(client);
748
749#if defined(CONFIG_HAS_EARLYSUSPEND)
750 unregister_early_suspend(&ts->early_suspend);
751#endif
752 pm_runtime_set_suspended(&client->dev);
753 pm_runtime_disable(&client->dev);
754
755 device_init_wakeup(&client->dev, 0);
756
757 cancel_delayed_work_sync(&ts->work);
758
759 free_irq(ts->pen_irq, ts);
760
761 gpio_free(ts->pdata->irq_gpio);
762
763 if (ts->pdata->resout_gpio >= 0)
764 gpio_free(ts->pdata->resout_gpio);
765
766 destroy_workqueue(ts->wq);
767
768 input_unregister_device(ts->input);
769
770 mutex_destroy(&ts->sus_lock);
771
772 if (ts->pdata->power_on)
773 ts->pdata->power_on(0);
774
775 if (ts->pdata->dev_setup)
776 ts->pdata->dev_setup(0);
777
778 kfree(ts->touch_data);
779 kfree(ts);
780
781 return 0;
782}
783
784static const struct i2c_device_id cy8c_ts_id[] = {
785 {"cy8ctma300", CY8CTMA300},
786 {"cy8ctmg200", CY8CTMG200},
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400787 {"cy8ctma340", CY8CTMA340},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700788 {}
789};
790MODULE_DEVICE_TABLE(i2c, cy8c_ts_id);
791
792
793static struct i2c_driver cy8c_ts_driver = {
794 .driver = {
795 .name = "cy8c_ts",
796 .owner = THIS_MODULE,
797#ifdef CONFIG_PM
798 .pm = &cy8c_ts_pm_ops,
799#endif
800 },
801 .probe = cy8c_ts_probe,
802 .remove = __devexit_p(cy8c_ts_remove),
803 .id_table = cy8c_ts_id,
804};
805
806static int __init cy8c_ts_init(void)
807{
808 return i2c_add_driver(&cy8c_ts_driver);
809}
810/* Making this as late init to avoid power fluctuations
811 * during LCD initialization.
812 */
813late_initcall(cy8c_ts_init);
814
815static void __exit cy8c_ts_exit(void)
816{
817 return i2c_del_driver(&cy8c_ts_driver);
818}
819module_exit(cy8c_ts_exit);
820
821MODULE_LICENSE("GPL");
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400822MODULE_DESCRIPTION("CY8CTMA340-CY8CTMG200 touchscreen controller driver");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823MODULE_AUTHOR("Cypress");
824MODULE_ALIAS("platform:cy8c_ts");