aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen/panjit_i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen/panjit_i2c.c')
-rw-r--r--drivers/input/touchscreen/panjit_i2c.c361
1 files changed, 361 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/panjit_i2c.c b/drivers/input/touchscreen/panjit_i2c.c
new file mode 100644
index 00000000000..4fccebc52ea
--- /dev/null
+++ b/drivers/input/touchscreen/panjit_i2c.c
@@ -0,0 +1,361 @@
1/*
2 * drivers/input/touchscreen/panjit_i2c.c
3 *
4 * Touchscreen class input driver for Panjit touch panel using I2C bus
5 *
6 * Copyright (c) 2010, NVIDIA Corporation.
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * 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
23#include <linux/module.h>
24#include <linux/device.h>
25#include <linux/input.h>
26#include <linux/delay.h>
27#include <linux/earlysuspend.h>
28#include <linux/i2c.h>
29#include <linux/i2c/panjit_ts.h>
30#include <linux/interrupt.h>
31#include <linux/gpio.h>
32#include <linux/slab.h>
33
34#define CSR 0x00
35 #define CSR_SCAN_EN (1 << 3)
36 #define CSR_SLEEP_EN (1 << 7)
37#define C_FLAG 0x01
38#define X1_H 0x03
39
40#define DRIVER_NAME "panjit_touch"
41
42#ifdef CONFIG_HAS_EARLYSUSPEND
43static void pj_early_suspend(struct early_suspend *h);
44static void pj_late_resume(struct early_suspend *h);
45#endif
46
47struct pj_data {
48 struct input_dev *input_dev;
49 struct i2c_client *client;
50 int gpio_reset;
51 struct early_suspend early_suspend;
52};
53
54struct pj_event {
55 __be16 coord[2][2];
56 __u8 fingers;
57 __u8 gesture;
58};
59
60union pj_buff {
61 struct pj_event data;
62 unsigned char buff[sizeof(struct pj_data)];
63};
64
65static void pj_reset(struct pj_data *touch)
66{
67 if (touch->gpio_reset < 0)
68 return;
69
70 gpio_set_value(touch->gpio_reset, 1);
71 msleep(50);
72 gpio_set_value(touch->gpio_reset, 0);
73 msleep(50);
74}
75
76static irqreturn_t pj_irq(int irq, void *dev_id)
77{
78 struct pj_data *touch = dev_id;
79 struct i2c_client *client = touch->client;
80 union pj_buff event;
81 int ret, i;
82
83 ret = i2c_smbus_read_i2c_block_data(client, X1_H,
84 sizeof(event.buff), event.buff);
85 if (WARN_ON(ret < 0)) {
86 dev_err(&client->dev, "error %d reading event data\n", ret);
87 return IRQ_NONE;
88 }
89 ret = i2c_smbus_write_byte_data(client, C_FLAG, 0);
90 if (WARN_ON(ret < 0)) {
91 dev_err(&client->dev, "error %d clearing interrupt\n", ret);
92 return IRQ_NONE;
93 }
94
95 input_report_key(touch->input_dev, BTN_TOUCH,
96 (event.data.fingers == 1 || event.data.fingers == 2));
97 input_report_key(touch->input_dev, BTN_2, (event.data.fingers == 2));
98
99 if (!event.data.fingers || (event.data.fingers > 2))
100 goto out;
101
102 for (i = 0; i < event.data.fingers; i++) {
103 input_report_abs(touch->input_dev, ABS_MT_POSITION_X,
104 __be16_to_cpu(event.data.coord[i][0]));
105 input_report_abs(touch->input_dev, ABS_MT_POSITION_Y,
106 __be16_to_cpu(event.data.coord[i][1]));
107 input_report_abs(touch->input_dev, ABS_MT_TRACKING_ID, i + 1);
108 input_mt_sync(touch->input_dev);
109 }
110
111out:
112 input_sync(touch->input_dev);
113 return IRQ_HANDLED;
114}
115
116static int pj_probe(struct i2c_client *client,
117 const struct i2c_device_id *id)
118{
119 struct panjit_i2c_ts_platform_data *pdata = client->dev.platform_data;
120 struct pj_data *touch = NULL;
121 struct input_dev *input_dev = NULL;
122 int ret = 0;
123
124 touch = kzalloc(sizeof(struct pj_data), GFP_KERNEL);
125 if (!touch) {
126 dev_err(&client->dev, "%s: no memory\n", __func__);
127 return -ENOMEM;
128 }
129
130 touch->gpio_reset = -EINVAL;
131
132 if (pdata) {
133 ret = gpio_request(pdata->gpio_reset, "panjit_reset");
134 if (!ret) {
135 ret = gpio_direction_output(pdata->gpio_reset, 1);
136 if (ret < 0)
137 gpio_free(pdata->gpio_reset);
138 }
139
140 if (!ret)
141 touch->gpio_reset = pdata->gpio_reset;
142 else
143 dev_warn(&client->dev, "unable to configure GPIO\n");
144 }
145
146 input_dev = input_allocate_device();
147 if (!input_dev) {
148 dev_err(&client->dev, "%s: no memory\n", __func__);
149 kfree(touch);
150 return -ENOMEM;
151 }
152
153 touch->client = client;
154 i2c_set_clientdata(client, touch);
155
156 pj_reset(touch);
157
158 /* clear interrupt */
159 ret = i2c_smbus_write_byte_data(touch->client, C_FLAG, 0);
160 if (ret < 0) {
161 dev_err(&client->dev, "%s: clear interrupt failed\n",
162 __func__);
163 goto fail_i2c_or_register;
164 }
165
166 /* enable scanning */
167 ret = i2c_smbus_write_byte_data(touch->client, CSR, CSR_SCAN_EN);
168 if (ret < 0) {
169 dev_err(&client->dev, "%s: enable interrupt failed\n",
170 __func__);
171 goto fail_i2c_or_register;
172 }
173
174 touch->input_dev = input_dev;
175 touch->input_dev->name = DRIVER_NAME;
176
177 set_bit(EV_SYN, touch->input_dev->evbit);
178 set_bit(EV_KEY, touch->input_dev->evbit);
179 set_bit(EV_ABS, touch->input_dev->evbit);
180 set_bit(BTN_TOUCH, touch->input_dev->keybit);
181 set_bit(BTN_2, touch->input_dev->keybit);
182
183 /* expose multi-touch capabilities */
184 set_bit(ABS_MT_POSITION_X, touch->input_dev->keybit);
185 set_bit(ABS_MT_POSITION_Y, touch->input_dev->keybit);
186 set_bit(ABS_X, touch->input_dev->keybit);
187 set_bit(ABS_Y, touch->input_dev->keybit);
188
189 /* all coordinates are reported in 0..4095 */
190 input_set_abs_params(touch->input_dev, ABS_X, 0, 4095, 0, 0);
191 input_set_abs_params(touch->input_dev, ABS_Y, 0, 4095, 0, 0);
192 input_set_abs_params(touch->input_dev, ABS_HAT0X, 0, 4095, 0, 0);
193 input_set_abs_params(touch->input_dev, ABS_HAT0Y, 0, 4095, 0, 0);
194 input_set_abs_params(touch->input_dev, ABS_HAT1X, 0, 4095, 0, 0);
195 input_set_abs_params(touch->input_dev, ABS_HAT1Y, 0, 4095, 0, 0);
196
197 input_set_abs_params(touch->input_dev, ABS_MT_POSITION_X, 0, 4095, 0, 0);
198 input_set_abs_params(touch->input_dev, ABS_MT_POSITION_Y, 0, 4095, 0, 0);
199 input_set_abs_params(touch->input_dev, ABS_MT_TRACKING_ID, 0, 2, 1, 0);
200
201 ret = input_register_device(touch->input_dev);
202 if (ret) {
203 dev_err(&client->dev, "%s: input_register_device failed\n",
204 __func__);
205 goto fail_i2c_or_register;
206 }
207
208 /* get the irq */
209 ret = request_threaded_irq(touch->client->irq, NULL, pj_irq,
210 IRQF_ONESHOT | IRQF_TRIGGER_LOW,
211 DRIVER_NAME, touch);
212 if (ret) {
213 dev_err(&client->dev, "%s: request_irq(%d) failed\n",
214 __func__, touch->client->irq);
215 goto fail_irq;
216 }
217
218#ifdef CONFIG_HAS_EARLYSUSPEND
219 touch->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
220 touch->early_suspend.suspend = pj_early_suspend;
221 touch->early_suspend.resume = pj_late_resume;
222 register_early_suspend(&touch->early_suspend);
223#endif
224 dev_info(&client->dev, "%s: initialized\n", __func__);
225 return 0;
226
227fail_irq:
228 input_unregister_device(touch->input_dev);
229
230fail_i2c_or_register:
231 if (touch->gpio_reset >= 0)
232 gpio_free(touch->gpio_reset);
233
234 input_free_device(input_dev);
235 kfree(touch);
236 return ret;
237}
238
239static int pj_suspend(struct i2c_client *client, pm_message_t state)
240{
241 struct pj_data *touch = i2c_get_clientdata(client);
242 int ret;
243
244 if (WARN_ON(!touch))
245 return -EINVAL;
246
247 disable_irq(client->irq);
248
249 /* disable scanning and enable deep sleep */
250 ret = i2c_smbus_write_byte_data(client, CSR, CSR_SLEEP_EN);
251 if (ret < 0) {
252 dev_err(&client->dev, "%s: sleep enable fail\n", __func__);
253 return ret;
254 }
255
256 return 0;
257}
258
259static int pj_resume(struct i2c_client *client)
260{
261 struct pj_data *touch = i2c_get_clientdata(client);
262 int ret = 0;
263
264 if (WARN_ON(!touch))
265 return -EINVAL;
266
267 pj_reset(touch);
268
269 /* enable scanning and disable deep sleep */
270 ret = i2c_smbus_write_byte_data(client, C_FLAG, 0);
271 if (ret >= 0)
272 ret = i2c_smbus_write_byte_data(client, CSR, CSR_SCAN_EN);
273 if (ret < 0) {
274 dev_err(&client->dev, "%s: scan enable fail\n", __func__);
275 return ret;
276 }
277
278 enable_irq(client->irq);
279
280 return 0;
281}
282
283#ifdef CONFIG_HAS_EARLYSUSPEND
284static void pj_early_suspend(struct early_suspend *es)
285{
286 struct pj_data *touch;
287 touch = container_of(es, struct pj_data, early_suspend);
288
289 if (pj_suspend(touch->client, PMSG_SUSPEND) != 0)
290 dev_err(&touch->client->dev, "%s: failed\n", __func__);
291}
292
293static void pj_late_resume(struct early_suspend *es)
294{
295 struct pj_data *touch;
296 touch = container_of(es, struct pj_data, early_suspend);
297
298 if (pj_resume(touch->client) != 0)
299 dev_err(&touch->client->dev, "%s: failed\n", __func__);
300}
301#endif
302
303static int pj_remove(struct i2c_client *client)
304{
305 struct pj_data *touch = i2c_get_clientdata(client);
306
307 if (!touch)
308 return -EINVAL;
309
310#ifdef CONFIG_HAS_EARLYSUSPEND
311 unregister_early_suspend(&touch->early_suspend);
312#endif
313 free_irq(touch->client->irq, touch);
314 if (touch->gpio_reset >= 0)
315 gpio_free(touch->gpio_reset);
316 input_unregister_device(touch->input_dev);
317 input_free_device(touch->input_dev);
318 kfree(touch);
319 return 0;
320}
321
322static const struct i2c_device_id panjit_ts_id[] = {
323 { DRIVER_NAME, 0 },
324 { }
325};
326
327static struct i2c_driver panjit_driver = {
328 .probe = pj_probe,
329 .remove = pj_remove,
330#ifndef CONFIG_HAS_EARLYSUSPEND
331 .suspend = pj_suspend,
332 .resume = pj_resume,
333#endif
334 .id_table = panjit_ts_id,
335 .driver = {
336 .name = DRIVER_NAME,
337 },
338};
339
340static int __devinit panjit_init(void)
341{
342 int e;
343
344 e = i2c_add_driver(&panjit_driver);
345 if (e != 0) {
346 pr_err("%s: failed to register with I2C bus with "
347 "error: 0x%x\n", __func__, e);
348 }
349 return e;
350}
351
352static void __exit panjit_exit(void)
353{
354 i2c_del_driver(&panjit_driver);
355}
356
357module_init(panjit_init);
358module_exit(panjit_exit);
359
360MODULE_LICENSE("GPL");
361MODULE_DESCRIPTION("Panjit I2C touch driver");