1 // SPDX-License-Identifier: GPL-2.0-only
3 * Touchscreen driver for Dialog Semiconductor DA9034
5 * Copyright (C) 2006-2008 Marvell International Ltd.
6 * Fengwei Yin <fengwei.yin@marvell.com>
7 * Bin Yang <bin.yang@marvell.com>
8 * Eric Miao <eric.miao@marvell.com>
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/delay.h>
14 #include <linux/platform_device.h>
15 #include <linux/input.h>
16 #include <linux/workqueue.h>
17 #include <linux/mfd/da903x.h>
18 #include <linux/slab.h>
20 #define DA9034_MANUAL_CTRL 0x50
21 #define DA9034_LDO_ADC_EN (1 << 4)
23 #define DA9034_AUTO_CTRL1 0x51
25 #define DA9034_AUTO_CTRL2 0x52
26 #define DA9034_AUTO_TSI_EN (1 << 3)
27 #define DA9034_PEN_DETECT (1 << 4)
29 #define DA9034_TSI_CTRL1 0x53
30 #define DA9034_TSI_CTRL2 0x54
31 #define DA9034_TSI_X_MSB 0x6c
32 #define DA9034_TSI_Y_MSB 0x6d
33 #define DA9034_TSI_XY_LSB 0x6e
36 STATE_IDLE
, /* wait for pendown */
37 STATE_BUSY
, /* TSI busy sampling */
38 STATE_STOP
, /* sample available */
39 STATE_WAIT
, /* Wait to start next sample */
50 struct device
*da9034_dev
;
51 struct input_dev
*input_dev
;
53 struct delayed_work tsi_work
;
54 struct notifier_block notifier
;
66 static inline int is_pen_down(struct da9034_touch
*touch
)
68 return da903x_query_status(touch
->da9034_dev
, DA9034_STATUS_PEN_DOWN
);
71 static inline int detect_pen_down(struct da9034_touch
*touch
, int on
)
74 return da903x_set_bits(touch
->da9034_dev
,
75 DA9034_AUTO_CTRL2
, DA9034_PEN_DETECT
);
77 return da903x_clr_bits(touch
->da9034_dev
,
78 DA9034_AUTO_CTRL2
, DA9034_PEN_DETECT
);
81 static int read_tsi(struct da9034_touch
*touch
)
86 ret
= da903x_read(touch
->da9034_dev
, DA9034_TSI_X_MSB
, &_x
);
90 ret
= da903x_read(touch
->da9034_dev
, DA9034_TSI_Y_MSB
, &_y
);
94 ret
= da903x_read(touch
->da9034_dev
, DA9034_TSI_XY_LSB
, &_v
);
98 touch
->last_x
= ((_x
<< 2) & 0x3fc) | (_v
& 0x3);
99 touch
->last_y
= ((_y
<< 2) & 0x3fc) | ((_v
& 0xc) >> 2);
104 static inline int start_tsi(struct da9034_touch
*touch
)
106 return da903x_set_bits(touch
->da9034_dev
,
107 DA9034_AUTO_CTRL2
, DA9034_AUTO_TSI_EN
);
110 static inline int stop_tsi(struct da9034_touch
*touch
)
112 return da903x_clr_bits(touch
->da9034_dev
,
113 DA9034_AUTO_CTRL2
, DA9034_AUTO_TSI_EN
);
116 static inline void report_pen_down(struct da9034_touch
*touch
)
118 int x
= touch
->last_x
;
119 int y
= touch
->last_y
;
122 if (touch
->x_inverted
)
125 if (touch
->y_inverted
)
128 input_report_abs(touch
->input_dev
, ABS_X
, x
);
129 input_report_abs(touch
->input_dev
, ABS_Y
, y
);
130 input_report_key(touch
->input_dev
, BTN_TOUCH
, 1);
132 input_sync(touch
->input_dev
);
135 static inline void report_pen_up(struct da9034_touch
*touch
)
137 input_report_key(touch
->input_dev
, BTN_TOUCH
, 0);
138 input_sync(touch
->input_dev
);
141 static void da9034_event_handler(struct da9034_touch
*touch
, int event
)
145 switch (touch
->state
) {
147 if (event
!= EVENT_PEN_DOWN
)
150 /* Enable auto measurement of the TSI, this will
151 * automatically disable pen down detection
153 err
= start_tsi(touch
);
157 touch
->state
= STATE_BUSY
;
161 if (event
!= EVENT_TSI_READY
)
164 err
= read_tsi(touch
);
168 /* Disable auto measurement of the TSI, so that
169 * pen down status will be available
171 err
= stop_tsi(touch
);
175 touch
->state
= STATE_STOP
;
177 /* FIXME: PEN_{UP/DOWN} events are expected to be
178 * available by stopping TSI, but this is found not
179 * always true, delay and simulate such an event
180 * here is more reliable
183 da9034_event_handler(touch
,
184 is_pen_down(touch
) ? EVENT_PEN_DOWN
:
189 if (event
== EVENT_PEN_DOWN
) {
190 report_pen_down(touch
);
191 schedule_delayed_work(&touch
->tsi_work
,
192 msecs_to_jiffies(touch
->interval_ms
));
193 touch
->state
= STATE_WAIT
;
196 if (event
== EVENT_PEN_UP
) {
197 report_pen_up(touch
);
198 touch
->state
= STATE_IDLE
;
203 if (event
!= EVENT_TIMEDOUT
)
206 if (is_pen_down(touch
)) {
208 touch
->state
= STATE_BUSY
;
210 report_pen_up(touch
);
211 touch
->state
= STATE_IDLE
;
218 touch
->state
= STATE_IDLE
;
220 detect_pen_down(touch
, 1);
223 static void da9034_tsi_work(struct work_struct
*work
)
225 struct da9034_touch
*touch
=
226 container_of(work
, struct da9034_touch
, tsi_work
.work
);
228 da9034_event_handler(touch
, EVENT_TIMEDOUT
);
231 static int da9034_touch_notifier(struct notifier_block
*nb
,
232 unsigned long event
, void *data
)
234 struct da9034_touch
*touch
=
235 container_of(nb
, struct da9034_touch
, notifier
);
237 if (event
& DA9034_EVENT_TSI_READY
)
238 da9034_event_handler(touch
, EVENT_TSI_READY
);
240 if ((event
& DA9034_EVENT_PEN_DOWN
) && touch
->state
== STATE_IDLE
)
241 da9034_event_handler(touch
, EVENT_PEN_DOWN
);
246 static int da9034_touch_open(struct input_dev
*dev
)
248 struct da9034_touch
*touch
= input_get_drvdata(dev
);
251 ret
= da903x_register_notifier(touch
->da9034_dev
, &touch
->notifier
,
252 DA9034_EVENT_PEN_DOWN
| DA9034_EVENT_TSI_READY
);
257 ret
= da903x_set_bits(touch
->da9034_dev
,
258 DA9034_MANUAL_CTRL
, DA9034_LDO_ADC_EN
);
262 /* TSI_DELAY: 3 slots, TSI_SKIP: 3 slots */
263 ret
= da903x_write(touch
->da9034_dev
, DA9034_TSI_CTRL1
, 0x1b);
267 ret
= da903x_write(touch
->da9034_dev
, DA9034_TSI_CTRL2
, 0x00);
271 touch
->state
= STATE_IDLE
;
272 detect_pen_down(touch
, 1);
277 static void da9034_touch_close(struct input_dev
*dev
)
279 struct da9034_touch
*touch
= input_get_drvdata(dev
);
281 da903x_unregister_notifier(touch
->da9034_dev
, &touch
->notifier
,
282 DA9034_EVENT_PEN_DOWN
| DA9034_EVENT_TSI_READY
);
284 cancel_delayed_work_sync(&touch
->tsi_work
);
286 touch
->state
= STATE_IDLE
;
288 detect_pen_down(touch
, 0);
290 /* Disable ADC LDO */
291 da903x_clr_bits(touch
->da9034_dev
,
292 DA9034_MANUAL_CTRL
, DA9034_LDO_ADC_EN
);
296 static int da9034_touch_probe(struct platform_device
*pdev
)
298 struct da9034_touch_pdata
*pdata
= dev_get_platdata(&pdev
->dev
);
299 struct da9034_touch
*touch
;
300 struct input_dev
*input_dev
;
303 touch
= devm_kzalloc(&pdev
->dev
, sizeof(struct da9034_touch
),
306 dev_err(&pdev
->dev
, "failed to allocate driver data\n");
310 touch
->da9034_dev
= pdev
->dev
.parent
;
313 touch
->interval_ms
= pdata
->interval_ms
;
314 touch
->x_inverted
= pdata
->x_inverted
;
315 touch
->y_inverted
= pdata
->y_inverted
;
317 /* fallback into default */
318 touch
->interval_ms
= 10;
321 INIT_DELAYED_WORK(&touch
->tsi_work
, da9034_tsi_work
);
322 touch
->notifier
.notifier_call
= da9034_touch_notifier
;
324 input_dev
= devm_input_allocate_device(&pdev
->dev
);
326 dev_err(&pdev
->dev
, "failed to allocate input device\n");
330 input_dev
->name
= pdev
->name
;
331 input_dev
->open
= da9034_touch_open
;
332 input_dev
->close
= da9034_touch_close
;
333 input_dev
->dev
.parent
= &pdev
->dev
;
335 __set_bit(EV_ABS
, input_dev
->evbit
);
336 __set_bit(ABS_X
, input_dev
->absbit
);
337 __set_bit(ABS_Y
, input_dev
->absbit
);
338 input_set_abs_params(input_dev
, ABS_X
, 0, 1023, 0, 0);
339 input_set_abs_params(input_dev
, ABS_Y
, 0, 1023, 0, 0);
341 __set_bit(EV_KEY
, input_dev
->evbit
);
342 __set_bit(BTN_TOUCH
, input_dev
->keybit
);
344 touch
->input_dev
= input_dev
;
345 input_set_drvdata(input_dev
, touch
);
347 error
= input_register_device(input_dev
);
354 static struct platform_driver da9034_touch_driver
= {
356 .name
= "da9034-touch",
358 .probe
= da9034_touch_probe
,
360 module_platform_driver(da9034_touch_driver
);
362 MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9034");
363 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>, Bin Yang <bin.yang@marvell.com>");
364 MODULE_LICENSE("GPL");
365 MODULE_ALIAS("platform:da9034-touch");