2 * TSI driver for Dialog DA9052
4 * Copyright(c) 2012 Dialog Semiconductor Ltd.
6 * Author: David Dajun Chen <dchen@diasemi.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
14 #include <linux/module.h>
15 #include <linux/input.h>
16 #include <linux/delay.h>
17 #include <linux/platform_device.h>
18 #include <linux/interrupt.h>
20 #include <linux/mfd/da9052/reg.h>
21 #include <linux/mfd/da9052/da9052.h>
23 #define TSI_PEN_DOWN_STATUS 0x40
26 struct da9052 *da9052;
27 struct input_dev *dev;
28 struct delayed_work ts_pen_work;
30 unsigned int irq_pendwn;
31 unsigned int irq_datardy;
36 static void da9052_ts_adc_toggle(struct da9052_tsi *tsi, bool on)
38 da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 0, on);
42 static irqreturn_t da9052_ts_pendwn_irq(int irq, void *data)
44 struct da9052_tsi *tsi = data;
47 /* Mask PEN_DOWN event and unmask TSI_READY event */
48 disable_irq_nosync(tsi->irq_pendwn);
49 enable_irq(tsi->irq_datardy);
51 da9052_ts_adc_toggle(tsi, true);
53 schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
59 static void da9052_ts_read(struct da9052_tsi *tsi)
61 struct input_dev *input = tsi->dev;
66 ret = da9052_reg_read(tsi->da9052, DA9052_TSI_X_MSB_REG);
72 ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Y_MSB_REG);
78 ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Z_MSB_REG);
84 ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
90 x = ((x << 2) & 0x3fc) | (v & 0x3);
91 y = ((y << 2) & 0x3fc) | ((v & 0xc) >> 2);
92 z = ((z << 2) & 0x3fc) | ((v & 0x30) >> 4);
94 input_report_key(input, BTN_TOUCH, 1);
95 input_report_abs(input, ABS_X, x);
96 input_report_abs(input, ABS_Y, y);
97 input_report_abs(input, ABS_PRESSURE, z);
101 static irqreturn_t da9052_ts_datardy_irq(int irq, void *data)
103 struct da9052_tsi *tsi = data;
110 static void da9052_ts_pen_work(struct work_struct *work)
112 struct da9052_tsi *tsi = container_of(work, struct da9052_tsi,
115 int ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
116 if (ret < 0 || (ret & TSI_PEN_DOWN_STATUS)) {
117 /* Pen is still DOWN (or read error) */
118 schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
120 struct input_dev *input = tsi->dev;
123 da9052_ts_adc_toggle(tsi, false);
126 input_report_key(input, BTN_TOUCH, 0);
127 input_report_abs(input, ABS_PRESSURE, 0);
131 * FIXME: Fixes the unhandled irq issue when quick
132 * pen down and pen up events occurs
134 ret = da9052_reg_update(tsi->da9052,
135 DA9052_EVENT_B_REG, 0xC0, 0xC0);
139 /* Mask TSI_READY event and unmask PEN_DOWN event */
140 disable_irq(tsi->irq_datardy);
141 enable_irq(tsi->irq_pendwn);
146 static int __devinit da9052_ts_configure_gpio(struct da9052 *da9052)
150 error = da9052_reg_update(da9052, DA9052_GPIO_2_3_REG, 0x30, 0);
154 error = da9052_reg_update(da9052, DA9052_GPIO_4_5_REG, 0x33, 0);
158 error = da9052_reg_update(da9052, DA9052_GPIO_6_7_REG, 0x33, 0);
165 static int __devinit da9052_configure_tsi(struct da9052_tsi *tsi)
169 error = da9052_ts_configure_gpio(tsi->da9052);
173 /* Measure TSI sample every 1ms */
174 error = da9052_reg_update(tsi->da9052, DA9052_ADC_CONT_REG,
179 /* TSI_DELAY: 3 slots, TSI_SKIP: 0 slots, TSI_MODE: XYZP */
180 error = da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 0xFC, 0xC0);
184 /* Supply TSIRef through LD09 */
185 error = da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x59);
192 static int da9052_ts_input_open(struct input_dev *input_dev)
194 struct da9052_tsi *tsi = input_get_drvdata(input_dev);
196 tsi->stopped = false;
199 /* Unmask PEN_DOWN event */
200 enable_irq(tsi->irq_pendwn);
202 /* Enable Pen Detect Circuit */
203 return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG,
207 static void da9052_ts_input_close(struct input_dev *input_dev)
209 struct da9052_tsi *tsi = input_get_drvdata(input_dev);
213 disable_irq(tsi->irq_pendwn);
214 cancel_delayed_work_sync(&tsi->ts_pen_work);
217 disable_irq(tsi->irq_datardy);
218 da9052_ts_adc_toggle(tsi, false);
221 * If ADC was on that means that pendwn IRQ was disabled
222 * twice and we need to enable it to keep enable/disable
223 * counter balanced. IRQ is still off though.
225 enable_irq(tsi->irq_pendwn);
228 /* Disable Pen Detect Circuit */
229 da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
232 static int __devinit da9052_ts_probe(struct platform_device *pdev)
234 struct da9052 *da9052;
235 struct da9052_tsi *tsi;
236 struct input_dev *input_dev;
241 da9052 = dev_get_drvdata(pdev->dev.parent);
245 irq_pendwn = platform_get_irq_byname(pdev, "PENDWN");
246 irq_datardy = platform_get_irq_byname(pdev, "TSIRDY");
247 if (irq_pendwn < 0 || irq_datardy < 0) {
248 dev_err(da9052->dev, "Unable to determine device interrupts\n");
252 tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL);
253 input_dev = input_allocate_device();
254 if (!tsi || !input_dev) {
259 tsi->da9052 = da9052;
260 tsi->dev = input_dev;
261 tsi->irq_pendwn = da9052->irq_base + irq_pendwn;
262 tsi->irq_datardy = da9052->irq_base + irq_datardy;
264 INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work);
266 input_dev->id.version = 0x0101;
267 input_dev->id.vendor = 0x15B6;
268 input_dev->id.product = 0x9052;
269 input_dev->name = "Dialog DA9052 TouchScreen Driver";
270 input_dev->dev.parent = &pdev->dev;
271 input_dev->open = da9052_ts_input_open;
272 input_dev->close = da9052_ts_input_close;
274 __set_bit(EV_ABS, input_dev->evbit);
275 __set_bit(EV_KEY, input_dev->evbit);
276 __set_bit(BTN_TOUCH, input_dev->keybit);
278 input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
279 input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
280 input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1023, 0, 0);
282 input_set_drvdata(input_dev, tsi);
284 /* Disable Pen Detect Circuit */
285 da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
288 da9052_ts_adc_toggle(tsi, false);
290 error = request_threaded_irq(tsi->irq_pendwn,
291 NULL, da9052_ts_pendwn_irq,
292 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
295 dev_err(tsi->da9052->dev,
296 "Failed to register PENDWN IRQ %d, error = %d\n",
297 tsi->irq_pendwn, error);
301 error = request_threaded_irq(tsi->irq_datardy,
302 NULL, da9052_ts_datardy_irq,
303 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
306 dev_err(tsi->da9052->dev,
307 "Failed to register TSIRDY IRQ %d, error = %d\n",
308 tsi->irq_datardy, error);
309 goto err_free_pendwn_irq;
312 /* Mask PEN_DOWN and TSI_READY events */
313 disable_irq(tsi->irq_pendwn);
314 disable_irq(tsi->irq_datardy);
316 error = da9052_configure_tsi(tsi);
318 goto err_free_datardy_irq;
320 error = input_register_device(tsi->dev);
322 goto err_free_datardy_irq;
324 platform_set_drvdata(pdev, tsi);
328 err_free_datardy_irq:
329 free_irq(tsi->irq_datardy, tsi);
331 free_irq(tsi->irq_pendwn, tsi);
334 input_free_device(input_dev);
339 static int __devexit da9052_ts_remove(struct platform_device *pdev)
341 struct da9052_tsi *tsi = platform_get_drvdata(pdev);
343 da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19);
345 free_irq(tsi->irq_pendwn, tsi);
346 free_irq(tsi->irq_datardy, tsi);
348 input_unregister_device(tsi->dev);
351 platform_set_drvdata(pdev, NULL);
356 static struct platform_driver da9052_tsi_driver = {
357 .probe = da9052_ts_probe,
358 .remove = __devexit_p(da9052_ts_remove),
360 .name = "da9052-tsi",
361 .owner = THIS_MODULE,
365 module_platform_driver(da9052_tsi_driver);
367 MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9052");
368 MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");
369 MODULE_LICENSE("GPL");
370 MODULE_ALIAS("platform:da9052-tsi");