Root/
1 | /* |
2 | * Driver for AUO in-cell touchscreens |
3 | * |
4 | * Copyright (c) 2011 Heiko Stuebner <heiko@sntech.de> |
5 | * |
6 | * loosely based on auo_touch.c from Dell Streak vendor-kernel |
7 | * |
8 | * Copyright (c) 2008 QUALCOMM Incorporated. |
9 | * Copyright (c) 2008 QUALCOMM USA, INC. |
10 | * |
11 | * |
12 | * This software is licensed under the terms of the GNU General Public |
13 | * License version 2, as published by the Free Software Foundation, and |
14 | * may be copied, distributed, and modified under those terms. |
15 | * |
16 | * This program is distributed in the hope that it will be useful, |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | * GNU General Public License for more details. |
20 | * |
21 | */ |
22 | |
23 | #include <linux/kernel.h> |
24 | #include <linux/module.h> |
25 | #include <linux/interrupt.h> |
26 | #include <linux/slab.h> |
27 | #include <linux/input.h> |
28 | #include <linux/jiffies.h> |
29 | #include <linux/i2c.h> |
30 | #include <linux/mutex.h> |
31 | #include <linux/delay.h> |
32 | #include <linux/gpio.h> |
33 | #include <linux/input/auo-pixcir-ts.h> |
34 | |
35 | /* |
36 | * Coordinate calculation: |
37 | * X1 = X1_LSB + X1_MSB*256 |
38 | * Y1 = Y1_LSB + Y1_MSB*256 |
39 | * X2 = X2_LSB + X2_MSB*256 |
40 | * Y2 = Y2_LSB + Y2_MSB*256 |
41 | */ |
42 | #define AUO_PIXCIR_REG_X1_LSB 0x00 |
43 | #define AUO_PIXCIR_REG_X1_MSB 0x01 |
44 | #define AUO_PIXCIR_REG_Y1_LSB 0x02 |
45 | #define AUO_PIXCIR_REG_Y1_MSB 0x03 |
46 | #define AUO_PIXCIR_REG_X2_LSB 0x04 |
47 | #define AUO_PIXCIR_REG_X2_MSB 0x05 |
48 | #define AUO_PIXCIR_REG_Y2_LSB 0x06 |
49 | #define AUO_PIXCIR_REG_Y2_MSB 0x07 |
50 | |
51 | #define AUO_PIXCIR_REG_STRENGTH 0x0d |
52 | #define AUO_PIXCIR_REG_STRENGTH_X1_LSB 0x0e |
53 | #define AUO_PIXCIR_REG_STRENGTH_X1_MSB 0x0f |
54 | |
55 | #define AUO_PIXCIR_REG_RAW_DATA_X 0x2b |
56 | #define AUO_PIXCIR_REG_RAW_DATA_Y 0x4f |
57 | |
58 | #define AUO_PIXCIR_REG_X_SENSITIVITY 0x6f |
59 | #define AUO_PIXCIR_REG_Y_SENSITIVITY 0x70 |
60 | #define AUO_PIXCIR_REG_INT_SETTING 0x71 |
61 | #define AUO_PIXCIR_REG_INT_WIDTH 0x72 |
62 | #define AUO_PIXCIR_REG_POWER_MODE 0x73 |
63 | |
64 | #define AUO_PIXCIR_REG_VERSION 0x77 |
65 | #define AUO_PIXCIR_REG_CALIBRATE 0x78 |
66 | |
67 | #define AUO_PIXCIR_REG_TOUCHAREA_X1 0x1e |
68 | #define AUO_PIXCIR_REG_TOUCHAREA_Y1 0x1f |
69 | #define AUO_PIXCIR_REG_TOUCHAREA_X2 0x20 |
70 | #define AUO_PIXCIR_REG_TOUCHAREA_Y2 0x21 |
71 | |
72 | #define AUO_PIXCIR_REG_EEPROM_CALIB_X 0x42 |
73 | #define AUO_PIXCIR_REG_EEPROM_CALIB_Y 0xad |
74 | |
75 | #define AUO_PIXCIR_INT_TPNUM_MASK 0xe0 |
76 | #define AUO_PIXCIR_INT_TPNUM_SHIFT 5 |
77 | #define AUO_PIXCIR_INT_RELEASE (1 << 4) |
78 | #define AUO_PIXCIR_INT_ENABLE (1 << 3) |
79 | #define AUO_PIXCIR_INT_POL_HIGH (1 << 2) |
80 | #define AUO_PIXCIR_INT_MODE_MASK 0x03 |
81 | |
82 | /* |
83 | * Power modes: |
84 | * active: scan speed 60Hz |
85 | * sleep: scan speed 10Hz can be auto-activated, wakeup on 1st touch |
86 | * deep sleep: scan speed 1Hz can only be entered or left manually. |
87 | */ |
88 | #define AUO_PIXCIR_POWER_ACTIVE 0x00 |
89 | #define AUO_PIXCIR_POWER_SLEEP 0x01 |
90 | #define AUO_PIXCIR_POWER_DEEP_SLEEP 0x02 |
91 | #define AUO_PIXCIR_POWER_MASK 0x03 |
92 | |
93 | #define AUO_PIXCIR_POWER_ALLOW_SLEEP (1 << 2) |
94 | #define AUO_PIXCIR_POWER_IDLE_TIME(ms) ((ms & 0xf) << 4) |
95 | |
96 | #define AUO_PIXCIR_CALIBRATE 0x03 |
97 | |
98 | #define AUO_PIXCIR_EEPROM_CALIB_X_LEN 62 |
99 | #define AUO_PIXCIR_EEPROM_CALIB_Y_LEN 36 |
100 | |
101 | #define AUO_PIXCIR_RAW_DATA_X_LEN 18 |
102 | #define AUO_PIXCIR_RAW_DATA_Y_LEN 11 |
103 | |
104 | #define AUO_PIXCIR_STRENGTH_ENABLE (1 << 0) |
105 | |
106 | /* Touchscreen absolute values */ |
107 | #define AUO_PIXCIR_REPORT_POINTS 2 |
108 | #define AUO_PIXCIR_MAX_AREA 0xff |
109 | #define AUO_PIXCIR_PENUP_TIMEOUT_MS 10 |
110 | |
111 | struct auo_pixcir_ts { |
112 | struct i2c_client *client; |
113 | struct input_dev *input; |
114 | char phys[32]; |
115 | |
116 | /* special handling for touch_indicate interupt mode */ |
117 | bool touch_ind_mode; |
118 | |
119 | wait_queue_head_t wait; |
120 | bool stopped; |
121 | }; |
122 | |
123 | struct auo_point_t { |
124 | int coord_x; |
125 | int coord_y; |
126 | int area_major; |
127 | int area_minor; |
128 | int orientation; |
129 | }; |
130 | |
131 | static int auo_pixcir_collect_data(struct auo_pixcir_ts *ts, |
132 | struct auo_point_t *point) |
133 | { |
134 | struct i2c_client *client = ts->client; |
135 | const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data; |
136 | uint8_t raw_coord[8]; |
137 | uint8_t raw_area[4]; |
138 | int i, ret; |
139 | |
140 | /* touch coordinates */ |
141 | ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_X1_LSB, |
142 | 8, raw_coord); |
143 | if (ret < 0) { |
144 | dev_err(&client->dev, "failed to read coordinate, %d\n", ret); |
145 | return ret; |
146 | } |
147 | |
148 | /* touch area */ |
149 | ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_TOUCHAREA_X1, |
150 | 4, raw_area); |
151 | if (ret < 0) { |
152 | dev_err(&client->dev, "could not read touch area, %d\n", ret); |
153 | return ret; |
154 | } |
155 | |
156 | for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) { |
157 | point[i].coord_x = |
158 | raw_coord[4 * i + 1] << 8 | raw_coord[4 * i]; |
159 | point[i].coord_y = |
160 | raw_coord[4 * i + 3] << 8 | raw_coord[4 * i + 2]; |
161 | |
162 | if (point[i].coord_x > pdata->x_max || |
163 | point[i].coord_y > pdata->y_max) { |
164 | dev_warn(&client->dev, "coordinates (%d,%d) invalid\n", |
165 | point[i].coord_x, point[i].coord_y); |
166 | point[i].coord_x = point[i].coord_y = 0; |
167 | } |
168 | |
169 | /* determine touch major, minor and orientation */ |
170 | point[i].area_major = max(raw_area[2 * i], raw_area[2 * i + 1]); |
171 | point[i].area_minor = min(raw_area[2 * i], raw_area[2 * i + 1]); |
172 | point[i].orientation = raw_area[2 * i] > raw_area[2 * i + 1]; |
173 | } |
174 | |
175 | return 0; |
176 | } |
177 | |
178 | static irqreturn_t auo_pixcir_interrupt(int irq, void *dev_id) |
179 | { |
180 | struct auo_pixcir_ts *ts = dev_id; |
181 | struct i2c_client *client = ts->client; |
182 | const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data; |
183 | struct auo_point_t point[AUO_PIXCIR_REPORT_POINTS]; |
184 | int i; |
185 | int ret; |
186 | int fingers = 0; |
187 | int abs = -1; |
188 | |
189 | while (!ts->stopped) { |
190 | |
191 | /* check for up event in touch touch_ind_mode */ |
192 | if (ts->touch_ind_mode) { |
193 | if (gpio_get_value(pdata->gpio_int) == 0) { |
194 | input_mt_sync(ts->input); |
195 | input_report_key(ts->input, BTN_TOUCH, 0); |
196 | input_sync(ts->input); |
197 | break; |
198 | } |
199 | } |
200 | |
201 | ret = auo_pixcir_collect_data(ts, point); |
202 | if (ret < 0) { |
203 | /* we want to loop only in touch_ind_mode */ |
204 | if (!ts->touch_ind_mode) |
205 | break; |
206 | |
207 | wait_event_timeout(ts->wait, ts->stopped, |
208 | msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS)); |
209 | continue; |
210 | } |
211 | |
212 | for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) { |
213 | if (point[i].coord_x > 0 || point[i].coord_y > 0) { |
214 | input_report_abs(ts->input, ABS_MT_POSITION_X, |
215 | point[i].coord_x); |
216 | input_report_abs(ts->input, ABS_MT_POSITION_Y, |
217 | point[i].coord_y); |
218 | input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, |
219 | point[i].area_major); |
220 | input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, |
221 | point[i].area_minor); |
222 | input_report_abs(ts->input, ABS_MT_ORIENTATION, |
223 | point[i].orientation); |
224 | input_mt_sync(ts->input); |
225 | |
226 | /* use first finger as source for singletouch */ |
227 | if (fingers == 0) |
228 | abs = i; |
229 | |
230 | /* number of touch points could also be queried |
231 | * via i2c but would require an additional call |
232 | */ |
233 | fingers++; |
234 | } |
235 | } |
236 | |
237 | input_report_key(ts->input, BTN_TOUCH, fingers > 0); |
238 | |
239 | if (abs > -1) { |
240 | input_report_abs(ts->input, ABS_X, point[abs].coord_x); |
241 | input_report_abs(ts->input, ABS_Y, point[abs].coord_y); |
242 | } |
243 | |
244 | input_sync(ts->input); |
245 | |
246 | /* we want to loop only in touch_ind_mode */ |
247 | if (!ts->touch_ind_mode) |
248 | break; |
249 | |
250 | wait_event_timeout(ts->wait, ts->stopped, |
251 | msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS)); |
252 | } |
253 | |
254 | return IRQ_HANDLED; |
255 | } |
256 | |
257 | /* |
258 | * Set the power mode of the device. |
259 | * Valid modes are |
260 | * - AUO_PIXCIR_POWER_ACTIVE |
261 | * - AUO_PIXCIR_POWER_SLEEP - automatically left on first touch |
262 | * - AUO_PIXCIR_POWER_DEEP_SLEEP |
263 | */ |
264 | static int auo_pixcir_power_mode(struct auo_pixcir_ts *ts, int mode) |
265 | { |
266 | struct i2c_client *client = ts->client; |
267 | int ret; |
268 | |
269 | ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_POWER_MODE); |
270 | if (ret < 0) { |
271 | dev_err(&client->dev, "unable to read reg %Xh, %d\n", |
272 | AUO_PIXCIR_REG_POWER_MODE, ret); |
273 | return ret; |
274 | } |
275 | |
276 | ret &= ~AUO_PIXCIR_POWER_MASK; |
277 | ret |= mode; |
278 | |
279 | ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_POWER_MODE, ret); |
280 | if (ret) { |
281 | dev_err(&client->dev, "unable to write reg %Xh, %d\n", |
282 | AUO_PIXCIR_REG_POWER_MODE, ret); |
283 | return ret; |
284 | } |
285 | |
286 | return 0; |
287 | } |
288 | |
289 | static int auo_pixcir_int_config(struct auo_pixcir_ts *ts, |
290 | int int_setting) |
291 | { |
292 | struct i2c_client *client = ts->client; |
293 | struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data; |
294 | int ret; |
295 | |
296 | ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING); |
297 | if (ret < 0) { |
298 | dev_err(&client->dev, "unable to read reg %Xh, %d\n", |
299 | AUO_PIXCIR_REG_INT_SETTING, ret); |
300 | return ret; |
301 | } |
302 | |
303 | ret &= ~AUO_PIXCIR_INT_MODE_MASK; |
304 | ret |= int_setting; |
305 | ret |= AUO_PIXCIR_INT_POL_HIGH; /* always use high for interrupts */ |
306 | |
307 | ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING, |
308 | ret); |
309 | if (ret < 0) { |
310 | dev_err(&client->dev, "unable to write reg %Xh, %d\n", |
311 | AUO_PIXCIR_REG_INT_SETTING, ret); |
312 | return ret; |
313 | } |
314 | |
315 | ts->touch_ind_mode = pdata->int_setting == AUO_PIXCIR_INT_TOUCH_IND; |
316 | |
317 | return 0; |
318 | } |
319 | |
320 | /* control the generation of interrupts on the device side */ |
321 | static int auo_pixcir_int_toggle(struct auo_pixcir_ts *ts, bool enable) |
322 | { |
323 | struct i2c_client *client = ts->client; |
324 | int ret; |
325 | |
326 | ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING); |
327 | if (ret < 0) { |
328 | dev_err(&client->dev, "unable to read reg %Xh, %d\n", |
329 | AUO_PIXCIR_REG_INT_SETTING, ret); |
330 | return ret; |
331 | } |
332 | |
333 | if (enable) |
334 | ret |= AUO_PIXCIR_INT_ENABLE; |
335 | else |
336 | ret &= ~AUO_PIXCIR_INT_ENABLE; |
337 | |
338 | ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING, |
339 | ret); |
340 | if (ret < 0) { |
341 | dev_err(&client->dev, "unable to write reg %Xh, %d\n", |
342 | AUO_PIXCIR_REG_INT_SETTING, ret); |
343 | return ret; |
344 | } |
345 | |
346 | return 0; |
347 | } |
348 | |
349 | static int auo_pixcir_start(struct auo_pixcir_ts *ts) |
350 | { |
351 | struct i2c_client *client = ts->client; |
352 | int ret; |
353 | |
354 | ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_ACTIVE); |
355 | if (ret < 0) { |
356 | dev_err(&client->dev, "could not set power mode, %d\n", |
357 | ret); |
358 | return ret; |
359 | } |
360 | |
361 | ts->stopped = false; |
362 | mb(); |
363 | enable_irq(client->irq); |
364 | |
365 | ret = auo_pixcir_int_toggle(ts, 1); |
366 | if (ret < 0) { |
367 | dev_err(&client->dev, "could not enable interrupt, %d\n", |
368 | ret); |
369 | disable_irq(client->irq); |
370 | return ret; |
371 | } |
372 | |
373 | return 0; |
374 | } |
375 | |
376 | static int auo_pixcir_stop(struct auo_pixcir_ts *ts) |
377 | { |
378 | struct i2c_client *client = ts->client; |
379 | int ret; |
380 | |
381 | ret = auo_pixcir_int_toggle(ts, 0); |
382 | if (ret < 0) { |
383 | dev_err(&client->dev, "could not disable interrupt, %d\n", |
384 | ret); |
385 | return ret; |
386 | } |
387 | |
388 | /* disable receiving of interrupts */ |
389 | disable_irq(client->irq); |
390 | ts->stopped = true; |
391 | mb(); |
392 | wake_up(&ts->wait); |
393 | |
394 | return auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_DEEP_SLEEP); |
395 | } |
396 | |
397 | static int auo_pixcir_input_open(struct input_dev *dev) |
398 | { |
399 | struct auo_pixcir_ts *ts = input_get_drvdata(dev); |
400 | int ret; |
401 | |
402 | ret = auo_pixcir_start(ts); |
403 | if (ret) |
404 | return ret; |
405 | |
406 | return 0; |
407 | } |
408 | |
409 | static void auo_pixcir_input_close(struct input_dev *dev) |
410 | { |
411 | struct auo_pixcir_ts *ts = input_get_drvdata(dev); |
412 | |
413 | auo_pixcir_stop(ts); |
414 | |
415 | return; |
416 | } |
417 | |
418 | #ifdef CONFIG_PM_SLEEP |
419 | static int auo_pixcir_suspend(struct device *dev) |
420 | { |
421 | struct i2c_client *client = to_i2c_client(dev); |
422 | struct auo_pixcir_ts *ts = i2c_get_clientdata(client); |
423 | struct input_dev *input = ts->input; |
424 | int ret = 0; |
425 | |
426 | mutex_lock(&input->mutex); |
427 | |
428 | /* when configured as wakeup source, device should always wake system |
429 | * therefore start device if necessary |
430 | */ |
431 | if (device_may_wakeup(&client->dev)) { |
432 | /* need to start device if not open, to be wakeup source */ |
433 | if (!input->users) { |
434 | ret = auo_pixcir_start(ts); |
435 | if (ret) |
436 | goto unlock; |
437 | } |
438 | |
439 | enable_irq_wake(client->irq); |
440 | ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_SLEEP); |
441 | } else if (input->users) { |
442 | ret = auo_pixcir_stop(ts); |
443 | } |
444 | |
445 | unlock: |
446 | mutex_unlock(&input->mutex); |
447 | |
448 | return ret; |
449 | } |
450 | |
451 | static int auo_pixcir_resume(struct device *dev) |
452 | { |
453 | struct i2c_client *client = to_i2c_client(dev); |
454 | struct auo_pixcir_ts *ts = i2c_get_clientdata(client); |
455 | struct input_dev *input = ts->input; |
456 | int ret = 0; |
457 | |
458 | mutex_lock(&input->mutex); |
459 | |
460 | if (device_may_wakeup(&client->dev)) { |
461 | disable_irq_wake(client->irq); |
462 | |
463 | /* need to stop device if it was not open on suspend */ |
464 | if (!input->users) { |
465 | ret = auo_pixcir_stop(ts); |
466 | if (ret) |
467 | goto unlock; |
468 | } |
469 | |
470 | /* device wakes automatically from SLEEP */ |
471 | } else if (input->users) { |
472 | ret = auo_pixcir_start(ts); |
473 | } |
474 | |
475 | unlock: |
476 | mutex_unlock(&input->mutex); |
477 | |
478 | return ret; |
479 | } |
480 | #endif |
481 | |
482 | static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops, auo_pixcir_suspend, |
483 | auo_pixcir_resume); |
484 | |
485 | static int auo_pixcir_probe(struct i2c_client *client, |
486 | const struct i2c_device_id *id) |
487 | { |
488 | const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data; |
489 | struct auo_pixcir_ts *ts; |
490 | struct input_dev *input_dev; |
491 | int ret; |
492 | |
493 | if (!pdata) |
494 | return -EINVAL; |
495 | |
496 | ts = kzalloc(sizeof(struct auo_pixcir_ts), GFP_KERNEL); |
497 | if (!ts) |
498 | return -ENOMEM; |
499 | |
500 | ret = gpio_request(pdata->gpio_int, "auo_pixcir_ts_int"); |
501 | if (ret) { |
502 | dev_err(&client->dev, "request of gpio %d failed, %d\n", |
503 | pdata->gpio_int, ret); |
504 | goto err_gpio_int; |
505 | } |
506 | |
507 | if (pdata->init_hw) |
508 | pdata->init_hw(client); |
509 | |
510 | ts->client = client; |
511 | ts->touch_ind_mode = 0; |
512 | init_waitqueue_head(&ts->wait); |
513 | |
514 | snprintf(ts->phys, sizeof(ts->phys), |
515 | "%s/input0", dev_name(&client->dev)); |
516 | |
517 | input_dev = input_allocate_device(); |
518 | if (!input_dev) { |
519 | dev_err(&client->dev, "could not allocate input device\n"); |
520 | goto err_input_alloc; |
521 | } |
522 | |
523 | ts->input = input_dev; |
524 | |
525 | input_dev->name = "AUO-Pixcir touchscreen"; |
526 | input_dev->phys = ts->phys; |
527 | input_dev->id.bustype = BUS_I2C; |
528 | input_dev->dev.parent = &client->dev; |
529 | |
530 | input_dev->open = auo_pixcir_input_open; |
531 | input_dev->close = auo_pixcir_input_close; |
532 | |
533 | __set_bit(EV_ABS, input_dev->evbit); |
534 | __set_bit(EV_KEY, input_dev->evbit); |
535 | |
536 | __set_bit(BTN_TOUCH, input_dev->keybit); |
537 | |
538 | /* For single touch */ |
539 | input_set_abs_params(input_dev, ABS_X, 0, pdata->x_max, 0, 0); |
540 | input_set_abs_params(input_dev, ABS_Y, 0, pdata->y_max, 0, 0); |
541 | |
542 | /* For multi touch */ |
543 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, |
544 | pdata->x_max, 0, 0); |
545 | input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, |
546 | pdata->y_max, 0, 0); |
547 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, |
548 | AUO_PIXCIR_MAX_AREA, 0, 0); |
549 | input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, |
550 | AUO_PIXCIR_MAX_AREA, 0, 0); |
551 | input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); |
552 | |
553 | ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_VERSION); |
554 | if (ret < 0) |
555 | goto err_fw_vers; |
556 | dev_info(&client->dev, "firmware version 0x%X\n", ret); |
557 | |
558 | ret = auo_pixcir_int_config(ts, pdata->int_setting); |
559 | if (ret) |
560 | goto err_fw_vers; |
561 | |
562 | input_set_drvdata(ts->input, ts); |
563 | ts->stopped = true; |
564 | |
565 | ret = request_threaded_irq(client->irq, NULL, auo_pixcir_interrupt, |
566 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, |
567 | input_dev->name, ts); |
568 | if (ret) { |
569 | dev_err(&client->dev, "irq %d requested failed\n", client->irq); |
570 | goto err_fw_vers; |
571 | } |
572 | |
573 | /* stop device and put it into deep sleep until it is opened */ |
574 | ret = auo_pixcir_stop(ts); |
575 | if (ret < 0) |
576 | goto err_input_register; |
577 | |
578 | ret = input_register_device(input_dev); |
579 | if (ret) { |
580 | dev_err(&client->dev, "could not register input device\n"); |
581 | goto err_input_register; |
582 | } |
583 | |
584 | i2c_set_clientdata(client, ts); |
585 | |
586 | return 0; |
587 | |
588 | err_input_register: |
589 | free_irq(client->irq, ts); |
590 | err_fw_vers: |
591 | input_free_device(input_dev); |
592 | err_input_alloc: |
593 | if (pdata->exit_hw) |
594 | pdata->exit_hw(client); |
595 | gpio_free(pdata->gpio_int); |
596 | err_gpio_int: |
597 | kfree(ts); |
598 | |
599 | return ret; |
600 | } |
601 | |
602 | static int auo_pixcir_remove(struct i2c_client *client) |
603 | { |
604 | struct auo_pixcir_ts *ts = i2c_get_clientdata(client); |
605 | const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data; |
606 | |
607 | free_irq(client->irq, ts); |
608 | |
609 | input_unregister_device(ts->input); |
610 | |
611 | if (pdata->exit_hw) |
612 | pdata->exit_hw(client); |
613 | |
614 | gpio_free(pdata->gpio_int); |
615 | |
616 | kfree(ts); |
617 | |
618 | return 0; |
619 | } |
620 | |
621 | static const struct i2c_device_id auo_pixcir_idtable[] = { |
622 | { "auo_pixcir_ts", 0 }, |
623 | { } |
624 | }; |
625 | MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable); |
626 | |
627 | static struct i2c_driver auo_pixcir_driver = { |
628 | .driver = { |
629 | .owner = THIS_MODULE, |
630 | .name = "auo_pixcir_ts", |
631 | .pm = &auo_pixcir_pm_ops, |
632 | }, |
633 | .probe = auo_pixcir_probe, |
634 | .remove = auo_pixcir_remove, |
635 | .id_table = auo_pixcir_idtable, |
636 | }; |
637 | |
638 | module_i2c_driver(auo_pixcir_driver); |
639 | |
640 | MODULE_DESCRIPTION("AUO-PIXCIR touchscreen driver"); |
641 | MODULE_LICENSE("GPL v2"); |
642 | MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); |
643 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9