aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2009-12-15 11:48:57 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-12-15 11:54:51 -0500
commitd201fd5dfb22801b6b012bb9f58cd186e4690d98 (patch)
tree54224db95f01d41674f2ccc9b87cecbcdf151ce3 /drivers/input
parent60214f058f44cfaa38db2abf0b42d4436c31aa58 (diff)
Input: add mc13783 touchscreen driver
This driver provides support for the touchscreen interface integrated into the Freescale MC13783. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Acked-by: Luotao Fu <l.fu@pengutronix.de> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/touchscreen/Kconfig12
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/mc13783_ts.c258
3 files changed, 271 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 32fc8ba039aa..dfafc76da4fb 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -450,6 +450,18 @@ config TOUCHSCREEN_USB_COMPOSITE
450 To compile this driver as a module, choose M here: the 450 To compile this driver as a module, choose M here: the
451 module will be called usbtouchscreen. 451 module will be called usbtouchscreen.
452 452
453config TOUCHSCREEN_MC13783
454 tristate "Freescale MC13783 touchscreen input driver"
455 depends on MFD_MC13783
456 help
457 Say Y here if you have an Freescale MC13783 PMIC on your
458 board and want to use its touchscreen
459
460 If unsure, say N.
461
462 To compile this driver as a module, choose M here: the
463 module will be called mc13783_ts.
464
453config TOUCHSCREEN_USB_EGALAX 465config TOUCHSCREEN_USB_EGALAX
454 default y 466 default y
455 bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED 467 bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index f1f59c9e1211..d61a3b4def9a 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
18obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o 18obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
19obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o 19obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
20obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o 20obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
21obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
21obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o 22obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
22obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o 23obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
23obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o 24obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c
new file mode 100644
index 000000000000..be115b3b65eb
--- /dev/null
+++ b/drivers/input/touchscreen/mc13783_ts.c
@@ -0,0 +1,258 @@
1/*
2 * Driver for the Freescale Semiconductor MC13783 touchscreen.
3 *
4 * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
5 * Copyright (C) 2009 Sascha Hauer, Pengutronix
6 *
7 * Initial development of this code was funded by
8 * Phytec Messtechnik GmbH, http://www.phytec.de/
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 */
14#include <linux/platform_device.h>
15#include <linux/mfd/mc13783.h>
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/input.h>
19#include <linux/sched.h>
20#include <linux/init.h>
21
22#define MC13783_TS_NAME "mc13783-ts"
23
24#define DEFAULT_SAMPLE_TOLERANCE 300
25
26static unsigned int sample_tolerance = DEFAULT_SAMPLE_TOLERANCE;
27module_param(sample_tolerance, uint, S_IRUGO | S_IWUSR);
28MODULE_PARM_DESC(sample_tolerance,
29 "If the minimal and maximal value read out for one axis (out "
30 "of three) differ by this value (default: "
31 __stringify(DEFAULT_SAMPLE_TOLERANCE) ") or more, the reading "
32 "is supposed to be wrong and is discarded. Set to 0 to "
33 "disable this check.");
34
35struct mc13783_ts_priv {
36 struct input_dev *idev;
37 struct mc13783 *mc13783;
38 struct delayed_work work;
39 struct workqueue_struct *workq;
40 unsigned int sample[4];
41};
42
43static irqreturn_t mc13783_ts_handler(int irq, void *data)
44{
45 struct mc13783_ts_priv *priv = data;
46
47 mc13783_ackirq(priv->mc13783, irq);
48
49 /*
50 * Kick off reading coordinates. Note that if work happens already
51 * be queued for future execution (it rearms itself) it will not
52 * be rescheduled for immediate execution here. However the rearm
53 * delay is HZ / 50 which is acceptable.
54 */
55 queue_delayed_work(priv->workq, &priv->work, 0);
56
57 return IRQ_HANDLED;
58}
59
60#define sort3(a0, a1, a2) ({ \
61 if (a0 > a1) \
62 swap(a0, a1); \
63 if (a1 > a2) \
64 swap(a1, a2); \
65 if (a0 > a1) \
66 swap(a0, a1); \
67 })
68
69static void mc13783_ts_report_sample(struct mc13783_ts_priv *priv)
70{
71 struct input_dev *idev = priv->idev;
72 int x0, x1, x2, y0, y1, y2;
73 int cr0, cr1;
74
75 /*
76 * the values are 10-bit wide only, but the two least significant
77 * bits are for future 12 bit use and reading yields 0
78 */
79 x0 = priv->sample[0] & 0xfff;
80 x1 = priv->sample[1] & 0xfff;
81 x2 = priv->sample[2] & 0xfff;
82 y0 = priv->sample[3] & 0xfff;
83 y1 = (priv->sample[0] >> 12) & 0xfff;
84 y2 = (priv->sample[1] >> 12) & 0xfff;
85 cr0 = (priv->sample[2] >> 12) & 0xfff;
86 cr1 = (priv->sample[3] >> 12) & 0xfff;
87
88 dev_dbg(&idev->dev,
89 "x: (% 4d,% 4d,% 4d) y: (% 4d, % 4d,% 4d) cr: (% 4d, % 4d)\n",
90 x0, x1, x2, y0, y1, y2, cr0, cr1);
91
92 sort3(x0, x1, x2);
93 sort3(y0, y1, y2);
94
95 cr0 = (cr0 + cr1) / 2;
96
97 if (!cr0 || !sample_tolerance ||
98 (x2 - x0 < sample_tolerance &&
99 y2 - y0 < sample_tolerance)) {
100 /* report the median coordinate and average pressure */
101 if (cr0) {
102 input_report_abs(idev, ABS_X, x1);
103 input_report_abs(idev, ABS_Y, y1);
104
105 dev_dbg(&idev->dev, "report (%d, %d, %d)\n",
106 x1, y1, 0x1000 - cr0);
107 queue_delayed_work(priv->workq, &priv->work, HZ / 50);
108 } else
109 dev_dbg(&idev->dev, "report release\n");
110
111 input_report_abs(idev, ABS_PRESSURE,
112 cr0 ? 0x1000 - cr0 : cr0);
113 input_report_key(idev, BTN_TOUCH, cr0);
114 input_sync(idev);
115 } else
116 dev_dbg(&idev->dev, "discard event\n");
117}
118
119static void mc13783_ts_work(struct work_struct *work)
120{
121 struct mc13783_ts_priv *priv =
122 container_of(work, struct mc13783_ts_priv, work.work);
123 unsigned int mode = MC13783_ADC_MODE_TS;
124 unsigned int channel = 12;
125
126 if (mc13783_adc_do_conversion(priv->mc13783,
127 mode, channel, priv->sample) == 0)
128 mc13783_ts_report_sample(priv);
129}
130
131static int mc13783_ts_open(struct input_dev *dev)
132{
133 struct mc13783_ts_priv *priv = input_get_drvdata(dev);
134 int ret;
135
136 mc13783_lock(priv->mc13783);
137
138 mc13783_ackirq(priv->mc13783, MC13783_IRQ_TS);
139
140 ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_TS,
141 mc13783_ts_handler, MC13783_TS_NAME, priv);
142 if (ret)
143 goto out;
144
145 ret = mc13783_reg_rmw(priv->mc13783, MC13783_ADC0,
146 MC13783_ADC0_TSMOD_MASK, MC13783_ADC0_TSMOD0);
147 if (ret)
148 mc13783_irq_free(priv->mc13783, MC13783_IRQ_TS, priv);
149out:
150 mc13783_unlock(priv->mc13783);
151 return ret;
152}
153
154static void mc13783_ts_close(struct input_dev *dev)
155{
156 struct mc13783_ts_priv *priv = input_get_drvdata(dev);
157
158 mc13783_lock(priv->mc13783);
159 mc13783_reg_rmw(priv->mc13783, MC13783_ADC0,
160 MC13783_ADC0_TSMOD_MASK, 0);
161 mc13783_irq_free(priv->mc13783, MC13783_IRQ_TS, priv);
162 mc13783_unlock(priv->mc13783);
163
164 cancel_delayed_work_sync(&priv->work);
165}
166
167static int __init mc13783_ts_probe(struct platform_device *pdev)
168{
169 struct mc13783_ts_priv *priv;
170 struct input_dev *idev;
171 int ret = -ENOMEM;
172
173 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
174 idev = input_allocate_device();
175 if (!priv || !idev)
176 goto err_free_mem;
177
178 INIT_DELAYED_WORK(&priv->work, mc13783_ts_work);
179 priv->mc13783 = dev_get_drvdata(pdev->dev.parent);
180 priv->idev = idev;
181
182 /*
183 * We need separate workqueue because mc13783_adc_do_conversion
184 * uses keventd and thus would deadlock.
185 */
186 priv->workq = create_singlethread_workqueue("mc13783_ts");
187 if (!priv->workq)
188 goto err_free_mem;
189
190 idev->name = MC13783_TS_NAME;
191 idev->dev.parent = &pdev->dev;
192
193 idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
194 idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
195 input_set_abs_params(idev, ABS_X, 0, 0xfff, 0, 0);
196 input_set_abs_params(idev, ABS_Y, 0, 0xfff, 0, 0);
197 input_set_abs_params(idev, ABS_PRESSURE, 0, 0xfff, 0, 0);
198
199 idev->open = mc13783_ts_open;
200 idev->close = mc13783_ts_close;
201
202 input_set_drvdata(idev, priv);
203
204 ret = input_register_device(priv->idev);
205 if (ret) {
206 dev_err(&pdev->dev,
207 "register input device failed with %d\n", ret);
208 goto err_destroy_wq;
209 }
210
211 platform_set_drvdata(pdev, priv);
212 return 0;
213
214err_destroy_wq:
215 destroy_workqueue(priv->workq);
216err_free_mem:
217 input_free_device(idev);
218 kfree(priv);
219 return ret;
220}
221
222static int __devexit mc13783_ts_remove(struct platform_device *pdev)
223{
224 struct mc13783_ts_priv *priv = platform_get_drvdata(pdev);
225
226 platform_set_drvdata(pdev, NULL);
227
228 destroy_workqueue(priv->workq);
229 input_unregister_device(priv->idev);
230 kfree(priv);
231
232 return 0;
233}
234
235static struct platform_driver mc13783_ts_driver = {
236 .remove = __devexit_p(mc13783_ts_remove),
237 .driver = {
238 .owner = THIS_MODULE,
239 .name = MC13783_TS_NAME,
240 },
241};
242
243static int __init mc13783_ts_init(void)
244{
245 return platform_driver_probe(&mc13783_ts_driver, &mc13783_ts_probe);
246}
247module_init(mc13783_ts_init);
248
249static void __exit mc13783_ts_exit(void)
250{
251 platform_driver_unregister(&mc13783_ts_driver);
252}
253module_exit(mc13783_ts_exit);
254
255MODULE_DESCRIPTION("MC13783 input touchscreen driver");
256MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
257MODULE_LICENSE("GPL v2");
258MODULE_ALIAS("platform:" MC13783_TS_NAME);