2 * Touchscreen driver for Dialog Semiconductor DA9034
4 * Copyright (C) 2006-2008 Marvell International Ltd.
5 * Fengwei Yin <fengwei.yin@marvell.com>
6 * Eric Miao <eric.miao@marvell.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/delay.h>
17 #include <linux/platform_device.h>
18 #include <linux/input.h>
19 #include <linux/workqueue.h>
20 #include <linux/mfd/da903x.h>
22 #define DA9034_MANUAL_CTRL 0x50
23 #define DA9034_LDO_ADC_EN (1 << 4)
25 #define DA9034_AUTO_CTRL1 0x51
27 #define DA9034_AUTO_CTRL2 0x52
28 #define DA9034_AUTO_TSI_EN (1 << 3)
29 #define DA9034_PEN_DETECT (1 << 4)
31 #define DA9034_TSI_CTRL1 0x53
32 #define DA9034_TSI_CTRL2 0x54
33 #define DA9034_TSI_X_MSB 0x6c
34 #define DA9034_TSI_Y_MSB 0x6d
35 #define DA9034_TSI_XY_LSB 0x6e
38 STATE_IDLE
, /* wait for pendown */
39 STATE_BUSY
, /* TSI busy sampling */
40 STATE_STOP
, /* sample available */
41 STATE_WAIT
, /* Wait to start next sample */
52 struct device
*da9034_dev
;
53 struct input_dev
*input_dev
;
55 struct delayed_work tsi_work
;
56 struct notifier_block notifier
;
68 static inline int is_pen_down(struct da9034_touch
*touch
)
70 return da903x_query_status(touch
->da9034_dev
, DA9034_STATUS_PEN_DOWN
);
73 static inline int detect_pen_down(struct da9034_touch
*touch
, int on
)
76 return da903x_set_bits(touch
->da9034_dev
,
77 DA9034_AUTO_CTRL2
, DA9034_PEN_DETECT
);
79 return da903x_clr_bits(touch
->da9034_dev
,
80 DA9034_AUTO_CTRL2
, DA9034_PEN_DETECT
);
83 static int read_tsi(struct da9034_touch
*touch
)
88 ret
= da903x_read(touch
->da9034_dev
, DA9034_TSI_X_MSB
, &_x
);
92 ret
= da903x_read(touch
->da9034_dev
, DA9034_TSI_Y_MSB
, &_y
);
96 ret
= da903x_read(touch
->da9034_dev
, DA9034_TSI_XY_LSB
, &_v
);
100 touch
->last_x
= ((_x
<< 2) & 0x3fc) | (_v
& 0x3);
101 touch
->last_y
= ((_y
<< 2) & 0x3fc) | ((_v
& 0xc) >> 2);
106 static inline int start_tsi(struct da9034_touch
*touch
)
108 return da903x_set_bits(touch
->da9034_dev
,
109 DA9034_AUTO_CTRL2
, DA9034_AUTO_TSI_EN
);
112 static inline int stop_tsi(struct da9034_touch
*touch
)
114 return da903x_clr_bits(touch
->da9034_dev
,
115 DA9034_AUTO_CTRL2
, DA9034_AUTO_TSI_EN
);
118 static inline void report_pen_down(struct da9034_touch
*touch
)
120 int x
= touch
->last_x
;
121 int y
= touch
->last_y
;
124 if (touch
->x_inverted
)
127 if (touch
->y_inverted
)
130 input_report_abs(touch
->input_dev
, ABS_X
, x
);
131 input_report_abs(touch
->input_dev
, ABS_Y
, y
);
132 input_report_key(touch
->input_dev
, BTN_TOUCH
, 1);
134 input_sync(touch
->input_dev
);
137 static inline void report_pen_up(struct da9034_touch
*touch
)
139 input_report_key(touch
->input_dev
, BTN_TOUCH
, 0);
140 input_sync(touch
->input_dev
);
143 static void da9034_event_handler(struct da9034_touch
*touch
, int event
)
147 switch (touch
->state
) {
149 if (event
!= EVENT_PEN_DOWN
)
152 /* Enable auto measurement of the TSI, this will
153 * automatically disable pen down detection
155 err
= start_tsi(touch
);
159 touch
->state
= STATE_BUSY
;
163 if (event
!= EVENT_TSI_READY
)
166 err
= read_tsi(touch
);
170 /* Disable auto measurement of the TSI, so that
171 * pen down status will be available
173 err
= stop_tsi(touch
);
177 touch
->state
= STATE_STOP
;
181 if (event
== EVENT_PEN_DOWN
) {
182 report_pen_down(touch
);
183 schedule_delayed_work(&touch
->tsi_work
,
184 msecs_to_jiffies(touch
->interval_ms
));
185 touch
->state
= STATE_WAIT
;
188 if (event
== EVENT_PEN_UP
) {
189 report_pen_up(touch
);
190 touch
->state
= STATE_IDLE
;
193 input_sync(touch
->input_dev
);
197 if (event
!= EVENT_TIMEDOUT
)
200 if (is_pen_down(touch
)) {
202 touch
->state
= STATE_BUSY
;
204 touch
->state
= STATE_IDLE
;
210 touch
->state
= STATE_IDLE
;
212 detect_pen_down(touch
, 1);
215 static void da9034_tsi_work(struct work_struct
*work
)
217 struct da9034_touch
*touch
=
218 container_of(work
, struct da9034_touch
, tsi_work
.work
);
220 da9034_event_handler(touch
, EVENT_TIMEDOUT
);
223 static int da9034_touch_notifier(struct notifier_block
*nb
,
224 unsigned long event
, void *data
)
226 struct da9034_touch
*touch
=
227 container_of(nb
, struct da9034_touch
, notifier
);
229 if (event
& DA9034_EVENT_PEN_DOWN
) {
230 if (is_pen_down(touch
))
231 da9034_event_handler(touch
, EVENT_PEN_DOWN
);
233 da9034_event_handler(touch
, EVENT_PEN_UP
);
236 if (event
& DA9034_EVENT_TSI_READY
)
237 da9034_event_handler(touch
, EVENT_TSI_READY
);
242 static int da9034_touch_open(struct input_dev
*dev
)
244 struct da9034_touch
*touch
= input_get_drvdata(dev
);
247 ret
= da903x_register_notifier(touch
->da9034_dev
, &touch
->notifier
,
248 DA9034_EVENT_PEN_DOWN
| DA9034_EVENT_TSI_READY
);
253 ret
= da903x_set_bits(touch
->da9034_dev
,
254 DA9034_MANUAL_CTRL
, DA9034_LDO_ADC_EN
);
258 /* TSI_DELAY: 3 slots, TSI_SKIP: 3 slots */
259 ret
= da903x_write(touch
->da9034_dev
, DA9034_TSI_CTRL1
, 0x1b);
263 ret
= da903x_write(touch
->da9034_dev
, DA9034_TSI_CTRL2
, 0x00);
267 touch
->state
= STATE_IDLE
;
268 detect_pen_down(touch
, 1);
273 static void da9034_touch_close(struct input_dev
*dev
)
275 struct da9034_touch
*touch
= input_get_drvdata(dev
);
277 da903x_unregister_notifier(touch
->da9034_dev
, &touch
->notifier
,
278 DA9034_EVENT_PEN_DOWN
| DA9034_EVENT_TSI_READY
);
280 cancel_delayed_work_sync(&touch
->tsi_work
);
282 touch
->state
= STATE_IDLE
;
284 detect_pen_down(touch
, 0);
286 /* Disable ADC LDO */
287 da903x_clr_bits(touch
->da9034_dev
,
288 DA9034_MANUAL_CTRL
, DA9034_LDO_ADC_EN
);
292 static int __devinit
da9034_touch_probe(struct platform_device
*pdev
)
294 struct da9034_touch_pdata
*pdata
= pdev
->dev
.platform_data
;
295 struct da9034_touch
*touch
;
296 struct input_dev
*input_dev
;
299 touch
= kzalloc(sizeof(struct da9034_touch
), GFP_KERNEL
);
301 dev_err(&pdev
->dev
, "failed to allocate driver data\n");
305 touch
->da9034_dev
= pdev
->dev
.parent
;
308 touch
->interval_ms
= pdata
->interval_ms
;
309 touch
->x_inverted
= pdata
->x_inverted
;
310 touch
->y_inverted
= pdata
->y_inverted
;
312 /* fallback into default */
313 touch
->interval_ms
= 10;
315 INIT_DELAYED_WORK(&touch
->tsi_work
, da9034_tsi_work
);
316 touch
->notifier
.notifier_call
= da9034_touch_notifier
;
318 input_dev
= input_allocate_device();
320 dev_err(&pdev
->dev
, "failed to allocate input device\n");
325 input_dev
->name
= pdev
->name
;
326 input_dev
->open
= da9034_touch_open
;
327 input_dev
->close
= da9034_touch_close
;
328 input_dev
->dev
.parent
= &pdev
->dev
;
330 __set_bit(EV_ABS
, input_dev
->evbit
);
331 __set_bit(ABS_X
, input_dev
->absbit
);
332 __set_bit(ABS_Y
, input_dev
->absbit
);
333 input_set_abs_params(input_dev
, ABS_X
, 0, 1023, 0, 0);
334 input_set_abs_params(input_dev
, ABS_Y
, 0, 1023, 0, 0);
336 __set_bit(EV_KEY
, input_dev
->evbit
);
337 __set_bit(BTN_TOUCH
, input_dev
->keybit
);
339 touch
->input_dev
= input_dev
;
340 input_set_drvdata(input_dev
, touch
);
342 ret
= input_register_device(input_dev
);
346 platform_set_drvdata(pdev
, touch
);
350 input_free_device(input_dev
);
356 static int __devexit
da9034_touch_remove(struct platform_device
*pdev
)
358 struct da9034_touch
*touch
= platform_get_drvdata(pdev
);
360 input_unregister_device(touch
->input_dev
);
366 static struct platform_driver da9034_touch_driver
= {
368 .name
= "da9034-touch",
369 .owner
= THIS_MODULE
,
371 .probe
= da9034_touch_probe
,
372 .remove
= __devexit_p(da9034_touch_remove
),
375 static int __init
da9034_touch_init(void)
377 return platform_driver_register(&da9034_touch_driver
);
379 module_init(da9034_touch_init
);
381 static void __exit
da9034_touch_exit(void)
383 platform_driver_unregister(&da9034_touch_driver
);
385 module_exit(da9034_touch_exit
);
387 MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9034");
388 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
389 MODULE_LICENSE("GPL");
390 MODULE_ALIAS("platform:da9034-touch");