blob: 2ee479726650be831fcb7abce93008a2334292cf [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.
Duy Truong790f06d2013-02-13 16:38:12 -08006 * Copyright (c) 2010-2012 The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007 *
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);
Amy Maloche28378282012-06-20 11:10:40 -0700390 __set_bit(INPUT_PROP_DIRECT, input_device->propbit);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400392 if (ts->device_id == CY8CTMA340) {
393 /* set up virtual key */
394 __set_bit(EV_KEY, input_device->evbit);
395 /* set dummy key to make driver work with virtual keys */
396 input_set_capability(input_device, EV_KEY, KEY_PROG1);
397 }
398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399 input_set_abs_params(input_device, ABS_MT_POSITION_X,
400 ts->pdata->dis_min_x, ts->pdata->dis_max_x, 0, 0);
401 input_set_abs_params(input_device, ABS_MT_POSITION_Y,
402 ts->pdata->dis_min_y, ts->pdata->dis_max_y, 0, 0);
Praveena Pachipulusu0106ea62011-11-16 15:40:07 +0530403 input_set_abs_params(input_device, ABS_MT_PRESSURE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404 ts->pdata->min_touch, ts->pdata->max_touch, 0, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 input_set_abs_params(input_device, ABS_MT_TRACKING_ID,
406 ts->pdata->min_tid, ts->pdata->max_tid, 0, 0);
407
408 ts->wq = create_singlethread_workqueue("kworkqueue_ts");
409 if (!ts->wq) {
410 dev_err(&client->dev, "Could not create workqueue\n");
411 goto error_wq_create;
412 }
413
414 INIT_DELAYED_WORK(&ts->work, cy8c_ts_xy_worker);
415
416 rc = input_register_device(input_device);
417 if (rc)
418 goto error_unreg_device;
419
420 return 0;
421
422error_unreg_device:
423 destroy_workqueue(ts->wq);
424error_wq_create:
425 input_free_device(input_device);
426error_alloc_dev:
427 kfree(ts->touch_data);
428 return rc;
429}
430
431#ifdef CONFIG_PM
432static int cy8c_ts_suspend(struct device *dev)
433{
434 struct cy8c_ts *ts = dev_get_drvdata(dev);
435 int rc = 0;
436
437 if (device_may_wakeup(dev)) {
438 /* mark suspend flag */
439 mutex_lock(&ts->sus_lock);
440 ts->is_suspended = true;
441 mutex_unlock(&ts->sus_lock);
442
443 enable_irq_wake(ts->pen_irq);
444 } else {
445 disable_irq_nosync(ts->pen_irq);
446
447 rc = cancel_delayed_work_sync(&ts->work);
448
449 if (rc) {
450 /* missed the worker, write to STATUS_REG to
451 acknowledge interrupt */
452 rc = cy8c_ts_write_reg_u8(ts->client,
453 ts->dd->status_reg, ts->dd->update_data);
454 if (rc < 0) {
455 dev_err(&ts->client->dev,
456 "write failed, try once more\n");
457
458 rc = cy8c_ts_write_reg_u8(ts->client,
459 ts->dd->status_reg,
460 ts->dd->update_data);
461 if (rc < 0)
462 dev_err(&ts->client->dev,
463 "write failed, exiting\n");
464 }
465
466 enable_irq(ts->pen_irq);
467 }
468
469 gpio_free(ts->pdata->irq_gpio);
470
471 if (ts->pdata->power_on) {
472 rc = ts->pdata->power_on(0);
473 if (rc) {
474 dev_err(dev, "unable to goto suspend\n");
475 return rc;
476 }
477 }
478 }
479 return 0;
480}
481
482static int cy8c_ts_resume(struct device *dev)
483{
484 struct cy8c_ts *ts = dev_get_drvdata(dev);
485 int rc = 0;
486
487 if (device_may_wakeup(dev)) {
488 disable_irq_wake(ts->pen_irq);
489
490 mutex_lock(&ts->sus_lock);
491 ts->is_suspended = false;
492
493 if (ts->int_pending == true) {
494 ts->int_pending = false;
495
496 /* start a delayed work */
497 queue_delayed_work(ts->wq, &ts->work, 0);
498 }
499 mutex_unlock(&ts->sus_lock);
500
501 } else {
502 if (ts->pdata->power_on) {
503 rc = ts->pdata->power_on(1);
504 if (rc) {
505 dev_err(dev, "unable to resume\n");
506 return rc;
507 }
508 }
509
510 /* configure touchscreen interrupt gpio */
511 rc = gpio_request(ts->pdata->irq_gpio, "cy8c_irq_gpio");
512 if (rc) {
513 pr_err("%s: unable to request gpio %d\n",
514 __func__, ts->pdata->irq_gpio);
515 goto err_power_off;
516 }
517
518 rc = gpio_direction_input(ts->pdata->irq_gpio);
519 if (rc) {
520 pr_err("%s: unable to set direction for gpio %d\n",
521 __func__, ts->pdata->irq_gpio);
522 goto err_gpio_free;
523 }
524
525 enable_irq(ts->pen_irq);
Mohan Pallakadf53bc32011-08-09 15:37:33 +0530526
527 /* Clear the status register of the TS controller */
528 rc = cy8c_ts_write_reg_u8(ts->client,
529 ts->dd->status_reg, ts->dd->update_data);
530 if (rc < 0) {
531 dev_err(&ts->client->dev,
532 "write failed, try once more\n");
533
534 rc = cy8c_ts_write_reg_u8(ts->client,
535 ts->dd->status_reg,
536 ts->dd->update_data);
537 if (rc < 0)
538 dev_err(&ts->client->dev,
539 "write failed, exiting\n");
540 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541 }
542 return 0;
543err_gpio_free:
544 gpio_free(ts->pdata->irq_gpio);
545err_power_off:
546 if (ts->pdata->power_on)
547 rc = ts->pdata->power_on(0);
548 return rc;
549}
550
551#ifdef CONFIG_HAS_EARLYSUSPEND
552static void cy8c_ts_early_suspend(struct early_suspend *h)
553{
554 struct cy8c_ts *ts = container_of(h, struct cy8c_ts, early_suspend);
555
556 cy8c_ts_suspend(&ts->client->dev);
557}
558
559static void cy8c_ts_late_resume(struct early_suspend *h)
560{
561 struct cy8c_ts *ts = container_of(h, struct cy8c_ts, early_suspend);
562
563 cy8c_ts_resume(&ts->client->dev);
564}
565#endif
566
567static struct dev_pm_ops cy8c_ts_pm_ops = {
568#ifndef CONFIG_HAS_EARLYSUSPEND
569 .suspend = cy8c_ts_suspend,
570 .resume = cy8c_ts_resume,
571#endif
572};
573#endif
574
575static int __devinit cy8c_ts_probe(struct i2c_client *client,
576 const struct i2c_device_id *id)
577{
578 struct cy8c_ts *ts;
579 struct cy8c_ts_platform_data *pdata = client->dev.platform_data;
580 int rc, temp_reg;
581
582 if (!pdata) {
583 dev_err(&client->dev, "platform data is required!\n");
584 return -EINVAL;
585 }
586
587 if (!i2c_check_functionality(client->adapter,
588 I2C_FUNC_SMBUS_READ_WORD_DATA)) {
589 dev_err(&client->dev, "I2C functionality not supported\n");
590 return -EIO;
591 }
592
593 ts = kzalloc(sizeof(*ts), GFP_KERNEL);
594 if (!ts)
595 return -ENOMEM;
596
597 /* Enable runtime PM ops, start in ACTIVE mode */
598 rc = pm_runtime_set_active(&client->dev);
599 if (rc < 0)
600 dev_dbg(&client->dev, "unable to set runtime pm state\n");
601 pm_runtime_enable(&client->dev);
602
603 ts->client = client;
604 ts->pdata = pdata;
605 i2c_set_clientdata(client, ts);
606 ts->device_id = id->driver_data;
607
608 if (ts->pdata->dev_setup) {
609 rc = ts->pdata->dev_setup(1);
610 if (rc < 0) {
611 dev_err(&client->dev, "dev setup failed\n");
612 goto error_touch_data_alloc;
613 }
614 }
615
616 /* power on the device */
617 if (ts->pdata->power_on) {
618 rc = ts->pdata->power_on(1);
619 if (rc) {
620 pr_err("%s: Unable to power on the device\n", __func__);
621 goto error_dev_setup;
622 }
623 }
624
625 /* read one byte to make sure i2c device exists */
626 if (id->driver_data == CY8CTMA300)
627 temp_reg = 0x01;
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400628 else if (id->driver_data == CY8CTMA340)
629 temp_reg = 0x00;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630 else
631 temp_reg = 0x05;
632
633 rc = cy8c_ts_read_reg_u8(client, temp_reg);
634 if (rc < 0) {
635 dev_err(&client->dev, "i2c sanity check failed\n");
636 goto error_power_on;
637 }
638
639 ts->is_suspended = false;
640 ts->int_pending = false;
641 mutex_init(&ts->sus_lock);
642
643 rc = cy8c_ts_init_ts(client, ts);
644 if (rc < 0) {
645 dev_err(&client->dev, "CY8CTMG200-TMA300 init failed\n");
646 goto error_mutex_destroy;
647 }
648
649 if (ts->pdata->resout_gpio < 0)
650 goto config_irq_gpio;
651
652 /* configure touchscreen reset out gpio */
653 rc = gpio_request(ts->pdata->resout_gpio, "cy8c_resout_gpio");
654 if (rc) {
655 pr_err("%s: unable to request gpio %d\n",
656 __func__, ts->pdata->resout_gpio);
657 goto error_uninit_ts;
658 }
659
660 rc = gpio_direction_output(ts->pdata->resout_gpio, 0);
661 if (rc) {
662 pr_err("%s: unable to set direction for gpio %d\n",
663 __func__, ts->pdata->resout_gpio);
664 goto error_resout_gpio_dir;
665 }
666 /* reset gpio stabilization time */
667 msleep(20);
668
669config_irq_gpio:
670 /* configure touchscreen interrupt gpio */
671 rc = gpio_request(ts->pdata->irq_gpio, "cy8c_irq_gpio");
672 if (rc) {
673 pr_err("%s: unable to request gpio %d\n",
674 __func__, ts->pdata->irq_gpio);
675 goto error_irq_gpio_req;
676 }
677
678 rc = gpio_direction_input(ts->pdata->irq_gpio);
679 if (rc) {
680 pr_err("%s: unable to set direction for gpio %d\n",
681 __func__, ts->pdata->irq_gpio);
682 goto error_irq_gpio_dir;
683 }
684
685 ts->pen_irq = gpio_to_irq(ts->pdata->irq_gpio);
686 rc = request_irq(ts->pen_irq, cy8c_ts_irq,
687 IRQF_TRIGGER_FALLING,
688 ts->client->dev.driver->name, ts);
689 if (rc) {
690 dev_err(&ts->client->dev, "could not request irq\n");
691 goto error_req_irq_fail;
692 }
693
694 /* Clear the status register of the TS controller */
695 rc = cy8c_ts_write_reg_u8(ts->client, ts->dd->status_reg,
696 ts->dd->update_data);
697 if (rc < 0) {
698 /* Do multiple writes in case of failure */
699 dev_err(&ts->client->dev, "%s: write failed %d"
700 "trying again\n", __func__, rc);
701 rc = cy8c_ts_write_reg_u8(ts->client,
702 ts->dd->status_reg, ts->dd->update_data);
703 if (rc < 0) {
704 dev_err(&ts->client->dev, "%s: write failed"
705 "second time(%d)\n", __func__, rc);
706 }
707 }
708
709 device_init_wakeup(&client->dev, ts->pdata->wakeup);
710
711#ifdef CONFIG_HAS_EARLYSUSPEND
712 ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN +
713 CY8C_TS_SUSPEND_LEVEL;
714 ts->early_suspend.suspend = cy8c_ts_early_suspend;
715 ts->early_suspend.resume = cy8c_ts_late_resume;
716 register_early_suspend(&ts->early_suspend);
717#endif
718
719 return 0;
720error_req_irq_fail:
721error_irq_gpio_dir:
722 gpio_free(ts->pdata->irq_gpio);
723error_irq_gpio_req:
724error_resout_gpio_dir:
725 if (ts->pdata->resout_gpio >= 0)
726 gpio_free(ts->pdata->resout_gpio);
727error_uninit_ts:
728 destroy_workqueue(ts->wq);
729 input_unregister_device(ts->input);
730 kfree(ts->touch_data);
731error_mutex_destroy:
732 mutex_destroy(&ts->sus_lock);
733error_power_on:
734 if (ts->pdata->power_on)
735 ts->pdata->power_on(0);
736error_dev_setup:
737 if (ts->pdata->dev_setup)
738 ts->pdata->dev_setup(0);
739error_touch_data_alloc:
740 pm_runtime_set_suspended(&client->dev);
741 pm_runtime_disable(&client->dev);
742 kfree(ts);
743 return rc;
744}
745
746static int __devexit cy8c_ts_remove(struct i2c_client *client)
747{
748 struct cy8c_ts *ts = i2c_get_clientdata(client);
749
750#if defined(CONFIG_HAS_EARLYSUSPEND)
751 unregister_early_suspend(&ts->early_suspend);
752#endif
753 pm_runtime_set_suspended(&client->dev);
754 pm_runtime_disable(&client->dev);
755
756 device_init_wakeup(&client->dev, 0);
757
758 cancel_delayed_work_sync(&ts->work);
759
760 free_irq(ts->pen_irq, ts);
761
762 gpio_free(ts->pdata->irq_gpio);
763
764 if (ts->pdata->resout_gpio >= 0)
765 gpio_free(ts->pdata->resout_gpio);
766
767 destroy_workqueue(ts->wq);
768
769 input_unregister_device(ts->input);
770
771 mutex_destroy(&ts->sus_lock);
772
773 if (ts->pdata->power_on)
774 ts->pdata->power_on(0);
775
776 if (ts->pdata->dev_setup)
777 ts->pdata->dev_setup(0);
778
779 kfree(ts->touch_data);
780 kfree(ts);
781
782 return 0;
783}
784
785static const struct i2c_device_id cy8c_ts_id[] = {
786 {"cy8ctma300", CY8CTMA300},
787 {"cy8ctmg200", CY8CTMG200},
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400788 {"cy8ctma340", CY8CTMA340},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789 {}
790};
791MODULE_DEVICE_TABLE(i2c, cy8c_ts_id);
792
793
794static struct i2c_driver cy8c_ts_driver = {
795 .driver = {
796 .name = "cy8c_ts",
797 .owner = THIS_MODULE,
798#ifdef CONFIG_PM
799 .pm = &cy8c_ts_pm_ops,
800#endif
801 },
802 .probe = cy8c_ts_probe,
803 .remove = __devexit_p(cy8c_ts_remove),
804 .id_table = cy8c_ts_id,
805};
806
807static int __init cy8c_ts_init(void)
808{
809 return i2c_add_driver(&cy8c_ts_driver);
810}
811/* Making this as late init to avoid power fluctuations
812 * during LCD initialization.
813 */
814late_initcall(cy8c_ts_init);
815
816static void __exit cy8c_ts_exit(void)
817{
818 return i2c_del_driver(&cy8c_ts_driver);
819}
820module_exit(cy8c_ts_exit);
821
822MODULE_LICENSE("GPL");
Zhang Chang Kenf5a4bbe2011-07-05 19:16:39 -0400823MODULE_DESCRIPTION("CY8CTMA340-CY8CTMG200 touchscreen controller driver");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824MODULE_AUTHOR("Cypress");
825MODULE_ALIAS("platform:cy8c_ts");