diff options
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 6 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 2 | ||||
-rw-r--r-- | drivers/input/touchscreen/da9052_tsi.c | 59 | ||||
-rw-r--r-- | drivers/input/touchscreen/ti_am335x_tsc.c | 398 | ||||
-rw-r--r-- | drivers/input/touchscreen/ti_tscadc.c | 486 |
5 files changed, 422 insertions, 529 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index f7668b24c37..0c45caddd41 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -529,9 +529,9 @@ config TOUCHSCREEN_TOUCHWIN | |||
529 | To compile this driver as a module, choose M here: the | 529 | To compile this driver as a module, choose M here: the |
530 | module will be called touchwin. | 530 | module will be called touchwin. |
531 | 531 | ||
532 | config TOUCHSCREEN_TI_TSCADC | 532 | config TOUCHSCREEN_TI_AM335X_TSC |
533 | tristate "TI Touchscreen Interface" | 533 | tristate "TI Touchscreen Interface" |
534 | depends on ARCH_OMAP2PLUS | 534 | depends on MFD_TI_AM335X_TSCADC |
535 | help | 535 | help |
536 | Say Y here if you have 4/5/8 wire touchscreen controller | 536 | Say Y here if you have 4/5/8 wire touchscreen controller |
537 | to be connected to the ADC controller on your TI AM335x SoC. | 537 | to be connected to the ADC controller on your TI AM335x SoC. |
@@ -539,7 +539,7 @@ config TOUCHSCREEN_TI_TSCADC | |||
539 | If unsure, say N. | 539 | If unsure, say N. |
540 | 540 | ||
541 | To compile this driver as a module, choose M here: the | 541 | To compile this driver as a module, choose M here: the |
542 | module will be called ti_tscadc. | 542 | module will be called ti_am335x_tsc. |
543 | 543 | ||
544 | config TOUCHSCREEN_ATMEL_TSADCC | 544 | config TOUCHSCREEN_ATMEL_TSADCC |
545 | tristate "Atmel Touchscreen Interface" | 545 | tristate "Atmel Touchscreen Interface" |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 178eb128d90..7c4c78ebe49 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -52,7 +52,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o | |||
52 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o | 52 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o |
53 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o | 53 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o |
54 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o | 54 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o |
55 | obj-$(CONFIG_TOUCHSCREEN_TI_TSCADC) += ti_tscadc.o | 55 | obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o |
56 | obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o | 56 | obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o |
57 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o | 57 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o |
58 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o | 58 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o |
diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c index e8df341090c..53133efe041 100644 --- a/drivers/input/touchscreen/da9052_tsi.c +++ b/drivers/input/touchscreen/da9052_tsi.c | |||
@@ -27,8 +27,6 @@ struct da9052_tsi { | |||
27 | struct input_dev *dev; | 27 | struct input_dev *dev; |
28 | struct delayed_work ts_pen_work; | 28 | struct delayed_work ts_pen_work; |
29 | struct mutex mutex; | 29 | struct mutex mutex; |
30 | unsigned int irq_pendwn; | ||
31 | unsigned int irq_datardy; | ||
32 | bool stopped; | 30 | bool stopped; |
33 | bool adc_on; | 31 | bool adc_on; |
34 | }; | 32 | }; |
@@ -45,8 +43,8 @@ static irqreturn_t da9052_ts_pendwn_irq(int irq, void *data) | |||
45 | 43 | ||
46 | if (!tsi->stopped) { | 44 | if (!tsi->stopped) { |
47 | /* Mask PEN_DOWN event and unmask TSI_READY event */ | 45 | /* Mask PEN_DOWN event and unmask TSI_READY event */ |
48 | disable_irq_nosync(tsi->irq_pendwn); | 46 | da9052_disable_irq_nosync(tsi->da9052, DA9052_IRQ_PENDOWN); |
49 | enable_irq(tsi->irq_datardy); | 47 | da9052_enable_irq(tsi->da9052, DA9052_IRQ_TSIREADY); |
50 | 48 | ||
51 | da9052_ts_adc_toggle(tsi, true); | 49 | da9052_ts_adc_toggle(tsi, true); |
52 | 50 | ||
@@ -137,8 +135,8 @@ static void da9052_ts_pen_work(struct work_struct *work) | |||
137 | return; | 135 | return; |
138 | 136 | ||
139 | /* Mask TSI_READY event and unmask PEN_DOWN event */ | 137 | /* Mask TSI_READY event and unmask PEN_DOWN event */ |
140 | disable_irq(tsi->irq_datardy); | 138 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY); |
141 | enable_irq(tsi->irq_pendwn); | 139 | da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
142 | } | 140 | } |
143 | } | 141 | } |
144 | } | 142 | } |
@@ -197,7 +195,7 @@ static int da9052_ts_input_open(struct input_dev *input_dev) | |||
197 | mb(); | 195 | mb(); |
198 | 196 | ||
199 | /* Unmask PEN_DOWN event */ | 197 | /* Unmask PEN_DOWN event */ |
200 | enable_irq(tsi->irq_pendwn); | 198 | da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
201 | 199 | ||
202 | /* Enable Pen Detect Circuit */ | 200 | /* Enable Pen Detect Circuit */ |
203 | return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, | 201 | return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, |
@@ -210,11 +208,11 @@ static void da9052_ts_input_close(struct input_dev *input_dev) | |||
210 | 208 | ||
211 | tsi->stopped = true; | 209 | tsi->stopped = true; |
212 | mb(); | 210 | mb(); |
213 | disable_irq(tsi->irq_pendwn); | 211 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
214 | cancel_delayed_work_sync(&tsi->ts_pen_work); | 212 | cancel_delayed_work_sync(&tsi->ts_pen_work); |
215 | 213 | ||
216 | if (tsi->adc_on) { | 214 | if (tsi->adc_on) { |
217 | disable_irq(tsi->irq_datardy); | 215 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY); |
218 | da9052_ts_adc_toggle(tsi, false); | 216 | da9052_ts_adc_toggle(tsi, false); |
219 | 217 | ||
220 | /* | 218 | /* |
@@ -222,7 +220,7 @@ static void da9052_ts_input_close(struct input_dev *input_dev) | |||
222 | * twice and we need to enable it to keep enable/disable | 220 | * twice and we need to enable it to keep enable/disable |
223 | * counter balanced. IRQ is still off though. | 221 | * counter balanced. IRQ is still off though. |
224 | */ | 222 | */ |
225 | enable_irq(tsi->irq_pendwn); | 223 | da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
226 | } | 224 | } |
227 | 225 | ||
228 | /* Disable Pen Detect Circuit */ | 226 | /* Disable Pen Detect Circuit */ |
@@ -234,21 +232,12 @@ static int __devinit da9052_ts_probe(struct platform_device *pdev) | |||
234 | struct da9052 *da9052; | 232 | struct da9052 *da9052; |
235 | struct da9052_tsi *tsi; | 233 | struct da9052_tsi *tsi; |
236 | struct input_dev *input_dev; | 234 | struct input_dev *input_dev; |
237 | int irq_pendwn; | ||
238 | int irq_datardy; | ||
239 | int error; | 235 | int error; |
240 | 236 | ||
241 | da9052 = dev_get_drvdata(pdev->dev.parent); | 237 | da9052 = dev_get_drvdata(pdev->dev.parent); |
242 | if (!da9052) | 238 | if (!da9052) |
243 | return -EINVAL; | 239 | return -EINVAL; |
244 | 240 | ||
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"); | ||
249 | return -ENXIO; | ||
250 | } | ||
251 | |||
252 | tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL); | 241 | tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL); |
253 | input_dev = input_allocate_device(); | 242 | input_dev = input_allocate_device(); |
254 | if (!tsi || !input_dev) { | 243 | if (!tsi || !input_dev) { |
@@ -258,8 +247,6 @@ static int __devinit da9052_ts_probe(struct platform_device *pdev) | |||
258 | 247 | ||
259 | tsi->da9052 = da9052; | 248 | tsi->da9052 = da9052; |
260 | tsi->dev = input_dev; | 249 | tsi->dev = input_dev; |
261 | tsi->irq_pendwn = da9052->irq_base + irq_pendwn; | ||
262 | tsi->irq_datardy = da9052->irq_base + irq_datardy; | ||
263 | tsi->stopped = true; | 250 | tsi->stopped = true; |
264 | INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work); | 251 | INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work); |
265 | 252 | ||
@@ -287,31 +274,25 @@ static int __devinit da9052_ts_probe(struct platform_device *pdev) | |||
287 | /* Disable ADC */ | 274 | /* Disable ADC */ |
288 | da9052_ts_adc_toggle(tsi, false); | 275 | da9052_ts_adc_toggle(tsi, false); |
289 | 276 | ||
290 | error = request_threaded_irq(tsi->irq_pendwn, | 277 | error = da9052_request_irq(tsi->da9052, DA9052_IRQ_PENDOWN, |
291 | NULL, da9052_ts_pendwn_irq, | 278 | "pendown-irq", da9052_ts_pendwn_irq, tsi); |
292 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
293 | "PENDWN", tsi); | ||
294 | if (error) { | 279 | if (error) { |
295 | dev_err(tsi->da9052->dev, | 280 | dev_err(tsi->da9052->dev, |
296 | "Failed to register PENDWN IRQ %d, error = %d\n", | 281 | "Failed to register PENDWN IRQ: %d\n", error); |
297 | tsi->irq_pendwn, error); | ||
298 | goto err_free_mem; | 282 | goto err_free_mem; |
299 | } | 283 | } |
300 | 284 | ||
301 | error = request_threaded_irq(tsi->irq_datardy, | 285 | error = da9052_request_irq(tsi->da9052, DA9052_IRQ_TSIREADY, |
302 | NULL, da9052_ts_datardy_irq, | 286 | "tsiready-irq", da9052_ts_datardy_irq, tsi); |
303 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
304 | "TSIRDY", tsi); | ||
305 | if (error) { | 287 | if (error) { |
306 | dev_err(tsi->da9052->dev, | 288 | dev_err(tsi->da9052->dev, |
307 | "Failed to register TSIRDY IRQ %d, error = %d\n", | 289 | "Failed to register TSIRDY IRQ :%d\n", error); |
308 | tsi->irq_datardy, error); | ||
309 | goto err_free_pendwn_irq; | 290 | goto err_free_pendwn_irq; |
310 | } | 291 | } |
311 | 292 | ||
312 | /* Mask PEN_DOWN and TSI_READY events */ | 293 | /* Mask PEN_DOWN and TSI_READY events */ |
313 | disable_irq(tsi->irq_pendwn); | 294 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
314 | disable_irq(tsi->irq_datardy); | 295 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY); |
315 | 296 | ||
316 | error = da9052_configure_tsi(tsi); | 297 | error = da9052_configure_tsi(tsi); |
317 | if (error) | 298 | if (error) |
@@ -326,9 +307,9 @@ static int __devinit da9052_ts_probe(struct platform_device *pdev) | |||
326 | return 0; | 307 | return 0; |
327 | 308 | ||
328 | err_free_datardy_irq: | 309 | err_free_datardy_irq: |
329 | free_irq(tsi->irq_datardy, tsi); | 310 | da9052_free_irq(tsi->da9052, DA9052_IRQ_TSIREADY, tsi); |
330 | err_free_pendwn_irq: | 311 | err_free_pendwn_irq: |
331 | free_irq(tsi->irq_pendwn, tsi); | 312 | da9052_free_irq(tsi->da9052, DA9052_IRQ_PENDOWN, tsi); |
332 | err_free_mem: | 313 | err_free_mem: |
333 | kfree(tsi); | 314 | kfree(tsi); |
334 | input_free_device(input_dev); | 315 | input_free_device(input_dev); |
@@ -342,8 +323,8 @@ static int __devexit da9052_ts_remove(struct platform_device *pdev) | |||
342 | 323 | ||
343 | da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19); | 324 | da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19); |
344 | 325 | ||
345 | free_irq(tsi->irq_pendwn, tsi); | 326 | da9052_free_irq(tsi->da9052, DA9052_IRQ_TSIREADY, tsi); |
346 | free_irq(tsi->irq_datardy, tsi); | 327 | da9052_free_irq(tsi->da9052, DA9052_IRQ_PENDOWN, tsi); |
347 | 328 | ||
348 | input_unregister_device(tsi->dev); | 329 | input_unregister_device(tsi->dev); |
349 | kfree(tsi); | 330 | kfree(tsi); |
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c new file mode 100644 index 00000000000..7a18a8a1522 --- /dev/null +++ b/drivers/input/touchscreen/ti_am335x_tsc.c | |||
@@ -0,0 +1,398 @@ | |||
1 | /* | ||
2 | * TI Touch Screen driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation version 2. | ||
9 | * | ||
10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
11 | * kind, whether express or implied; without even the implied warranty | ||
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/input.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/input/ti_am335x_tsc.h> | ||
28 | #include <linux/delay.h> | ||
29 | |||
30 | #include <linux/mfd/ti_am335x_tscadc.h> | ||
31 | |||
32 | #define ADCFSM_STEPID 0x10 | ||
33 | #define SEQ_SETTLE 275 | ||
34 | #define MAX_12BIT ((1 << 12) - 1) | ||
35 | |||
36 | struct titsc { | ||
37 | struct input_dev *input; | ||
38 | struct ti_tscadc_dev *mfd_tscadc; | ||
39 | unsigned int irq; | ||
40 | unsigned int wires; | ||
41 | unsigned int x_plate_resistance; | ||
42 | bool pen_down; | ||
43 | int steps_to_configure; | ||
44 | }; | ||
45 | |||
46 | static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) | ||
47 | { | ||
48 | return readl(ts->mfd_tscadc->tscadc_base + reg); | ||
49 | } | ||
50 | |||
51 | static void titsc_writel(struct titsc *tsc, unsigned int reg, | ||
52 | unsigned int val) | ||
53 | { | ||
54 | writel(val, tsc->mfd_tscadc->tscadc_base + reg); | ||
55 | } | ||
56 | |||
57 | static void titsc_step_config(struct titsc *ts_dev) | ||
58 | { | ||
59 | unsigned int config; | ||
60 | int i, total_steps; | ||
61 | |||
62 | /* Configure the Step registers */ | ||
63 | total_steps = 2 * ts_dev->steps_to_configure; | ||
64 | |||
65 | config = STEPCONFIG_MODE_HWSYNC | | ||
66 | STEPCONFIG_AVG_16 | STEPCONFIG_XPP; | ||
67 | switch (ts_dev->wires) { | ||
68 | case 4: | ||
69 | config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; | ||
70 | break; | ||
71 | case 5: | ||
72 | config |= STEPCONFIG_YNN | | ||
73 | STEPCONFIG_INP_AN4 | STEPCONFIG_XNN | | ||
74 | STEPCONFIG_YPP; | ||
75 | break; | ||
76 | case 8: | ||
77 | config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; | ||
78 | break; | ||
79 | } | ||
80 | |||
81 | for (i = 1; i <= ts_dev->steps_to_configure; i++) { | ||
82 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
83 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
84 | } | ||
85 | |||
86 | config = 0; | ||
87 | config = STEPCONFIG_MODE_HWSYNC | | ||
88 | STEPCONFIG_AVG_16 | STEPCONFIG_YNN | | ||
89 | STEPCONFIG_INM_ADCREFM | STEPCONFIG_FIFO1; | ||
90 | switch (ts_dev->wires) { | ||
91 | case 4: | ||
92 | config |= STEPCONFIG_YPP; | ||
93 | break; | ||
94 | case 5: | ||
95 | config |= STEPCONFIG_XPP | STEPCONFIG_INP_AN4 | | ||
96 | STEPCONFIG_XNP | STEPCONFIG_YPN; | ||
97 | break; | ||
98 | case 8: | ||
99 | config |= STEPCONFIG_YPP; | ||
100 | break; | ||
101 | } | ||
102 | |||
103 | for (i = (ts_dev->steps_to_configure + 1); i <= total_steps; i++) { | ||
104 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
105 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
106 | } | ||
107 | |||
108 | config = 0; | ||
109 | /* Charge step configuration */ | ||
110 | config = STEPCONFIG_XPP | STEPCONFIG_YNN | | ||
111 | STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR | | ||
112 | STEPCHARGE_INM_AN1 | STEPCHARGE_INP_AN1; | ||
113 | |||
114 | titsc_writel(ts_dev, REG_CHARGECONFIG, config); | ||
115 | titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY); | ||
116 | |||
117 | config = 0; | ||
118 | /* Configure to calculate pressure */ | ||
119 | config = STEPCONFIG_MODE_HWSYNC | | ||
120 | STEPCONFIG_AVG_16 | STEPCONFIG_YPP | | ||
121 | STEPCONFIG_XNN | STEPCONFIG_INM_ADCREFM; | ||
122 | titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 1), config); | ||
123 | titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 1), | ||
124 | STEPCONFIG_OPENDLY); | ||
125 | |||
126 | config |= STEPCONFIG_INP_AN3 | STEPCONFIG_FIFO1; | ||
127 | titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 2), config); | ||
128 | titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2), | ||
129 | STEPCONFIG_OPENDLY); | ||
130 | |||
131 | titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC); | ||
132 | } | ||
133 | |||
134 | static void titsc_read_coordinates(struct titsc *ts_dev, | ||
135 | unsigned int *x, unsigned int *y) | ||
136 | { | ||
137 | unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT); | ||
138 | unsigned int prev_val_x = ~0, prev_val_y = ~0; | ||
139 | unsigned int prev_diff_x = ~0, prev_diff_y = ~0; | ||
140 | unsigned int read, diff; | ||
141 | unsigned int i, channel; | ||
142 | |||
143 | /* | ||
144 | * Delta filter is used to remove large variations in sampled | ||
145 | * values from ADC. The filter tries to predict where the next | ||
146 | * coordinate could be. This is done by taking a previous | ||
147 | * coordinate and subtracting it form current one. Further the | ||
148 | * algorithm compares the difference with that of a present value, | ||
149 | * if true the value is reported to the sub system. | ||
150 | */ | ||
151 | for (i = 0; i < fifocount - 1; i++) { | ||
152 | read = titsc_readl(ts_dev, REG_FIFO0); | ||
153 | channel = read & 0xf0000; | ||
154 | channel = channel >> 0x10; | ||
155 | if ((channel >= 0) && (channel < ts_dev->steps_to_configure)) { | ||
156 | read &= 0xfff; | ||
157 | diff = abs(read - prev_val_x); | ||
158 | if (diff < prev_diff_x) { | ||
159 | prev_diff_x = diff; | ||
160 | *x = read; | ||
161 | } | ||
162 | prev_val_x = read; | ||
163 | } | ||
164 | |||
165 | read = titsc_readl(ts_dev, REG_FIFO1); | ||
166 | channel = read & 0xf0000; | ||
167 | channel = channel >> 0x10; | ||
168 | if ((channel >= ts_dev->steps_to_configure) && | ||
169 | (channel < (2 * ts_dev->steps_to_configure - 1))) { | ||
170 | read &= 0xfff; | ||
171 | diff = abs(read - prev_val_y); | ||
172 | if (diff < prev_diff_y) { | ||
173 | prev_diff_y = diff; | ||
174 | *y = read; | ||
175 | } | ||
176 | prev_val_y = read; | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | |||
181 | static irqreturn_t titsc_irq(int irq, void *dev) | ||
182 | { | ||
183 | struct titsc *ts_dev = dev; | ||
184 | struct input_dev *input_dev = ts_dev->input; | ||
185 | unsigned int status, irqclr = 0; | ||
186 | unsigned int x = 0, y = 0; | ||
187 | unsigned int z1, z2, z; | ||
188 | unsigned int fsm; | ||
189 | unsigned int fifo1count, fifo0count; | ||
190 | int i; | ||
191 | |||
192 | status = titsc_readl(ts_dev, REG_IRQSTATUS); | ||
193 | if (status & IRQENB_FIFO0THRES) { | ||
194 | titsc_read_coordinates(ts_dev, &x, &y); | ||
195 | |||
196 | z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff; | ||
197 | z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff; | ||
198 | |||
199 | fifo1count = titsc_readl(ts_dev, REG_FIFO1CNT); | ||
200 | for (i = 0; i < fifo1count; i++) | ||
201 | titsc_readl(ts_dev, REG_FIFO1); | ||
202 | |||
203 | fifo0count = titsc_readl(ts_dev, REG_FIFO0CNT); | ||
204 | for (i = 0; i < fifo0count; i++) | ||
205 | titsc_readl(ts_dev, REG_FIFO0); | ||
206 | |||
207 | if (ts_dev->pen_down && z1 != 0 && z2 != 0) { | ||
208 | /* | ||
209 | * Calculate pressure using formula | ||
210 | * Resistance(touch) = x plate resistance * | ||
211 | * x postion/4096 * ((z2 / z1) - 1) | ||
212 | */ | ||
213 | z = z2 - z1; | ||
214 | z *= x; | ||
215 | z *= ts_dev->x_plate_resistance; | ||
216 | z /= z1; | ||
217 | z = (z + 2047) >> 12; | ||
218 | |||
219 | if (z <= MAX_12BIT) { | ||
220 | input_report_abs(input_dev, ABS_X, x); | ||
221 | input_report_abs(input_dev, ABS_Y, y); | ||
222 | input_report_abs(input_dev, ABS_PRESSURE, z); | ||
223 | input_report_key(input_dev, BTN_TOUCH, 1); | ||
224 | input_sync(input_dev); | ||
225 | } | ||
226 | } | ||
227 | irqclr |= IRQENB_FIFO0THRES; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Time for sequencer to settle, to read | ||
232 | * correct state of the sequencer. | ||
233 | */ | ||
234 | udelay(SEQ_SETTLE); | ||
235 | |||
236 | status = titsc_readl(ts_dev, REG_RAWIRQSTATUS); | ||
237 | if (status & IRQENB_PENUP) { | ||
238 | /* Pen up event */ | ||
239 | fsm = titsc_readl(ts_dev, REG_ADCFSM); | ||
240 | if (fsm == ADCFSM_STEPID) { | ||
241 | ts_dev->pen_down = false; | ||
242 | input_report_key(input_dev, BTN_TOUCH, 0); | ||
243 | input_report_abs(input_dev, ABS_PRESSURE, 0); | ||
244 | input_sync(input_dev); | ||
245 | } else { | ||
246 | ts_dev->pen_down = true; | ||
247 | } | ||
248 | irqclr |= IRQENB_PENUP; | ||
249 | } | ||
250 | |||
251 | titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); | ||
252 | |||
253 | titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC); | ||
254 | return IRQ_HANDLED; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * The functions for inserting/removing driver as a module. | ||
259 | */ | ||
260 | |||
261 | static int __devinit titsc_probe(struct platform_device *pdev) | ||
262 | { | ||
263 | struct titsc *ts_dev; | ||
264 | struct input_dev *input_dev; | ||
265 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; | ||
266 | struct mfd_tscadc_board *pdata; | ||
267 | int err; | ||
268 | |||
269 | pdata = tscadc_dev->dev->platform_data; | ||
270 | |||
271 | if (!pdata) { | ||
272 | dev_err(&pdev->dev, "Could not find platform data\n"); | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | |||
276 | /* Allocate memory for device */ | ||
277 | ts_dev = kzalloc(sizeof(struct titsc), GFP_KERNEL); | ||
278 | input_dev = input_allocate_device(); | ||
279 | if (!ts_dev || !input_dev) { | ||
280 | dev_err(&pdev->dev, "failed to allocate memory.\n"); | ||
281 | err = -ENOMEM; | ||
282 | goto err_free_mem; | ||
283 | } | ||
284 | |||
285 | tscadc_dev->tsc = ts_dev; | ||
286 | ts_dev->mfd_tscadc = tscadc_dev; | ||
287 | ts_dev->input = input_dev; | ||
288 | ts_dev->irq = tscadc_dev->irq; | ||
289 | ts_dev->wires = pdata->tsc_init->wires; | ||
290 | ts_dev->x_plate_resistance = pdata->tsc_init->x_plate_resistance; | ||
291 | ts_dev->steps_to_configure = pdata->tsc_init->steps_to_configure; | ||
292 | |||
293 | err = request_irq(ts_dev->irq, titsc_irq, | ||
294 | 0, pdev->dev.driver->name, ts_dev); | ||
295 | if (err) { | ||
296 | dev_err(&pdev->dev, "failed to allocate irq.\n"); | ||
297 | goto err_free_mem; | ||
298 | } | ||
299 | |||
300 | titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); | ||
301 | titsc_step_config(ts_dev); | ||
302 | titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure); | ||
303 | |||
304 | input_dev->name = "ti-tsc"; | ||
305 | input_dev->dev.parent = &pdev->dev; | ||
306 | |||
307 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
308 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | ||
309 | |||
310 | input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); | ||
311 | input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); | ||
312 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); | ||
313 | |||
314 | /* register to the input system */ | ||
315 | err = input_register_device(input_dev); | ||
316 | if (err) | ||
317 | goto err_free_irq; | ||
318 | |||
319 | platform_set_drvdata(pdev, ts_dev); | ||
320 | return 0; | ||
321 | |||
322 | err_free_irq: | ||
323 | free_irq(ts_dev->irq, ts_dev); | ||
324 | err_free_mem: | ||
325 | input_free_device(input_dev); | ||
326 | kfree(ts_dev); | ||
327 | return err; | ||
328 | } | ||
329 | |||
330 | static int __devexit titsc_remove(struct platform_device *pdev) | ||
331 | { | ||
332 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; | ||
333 | struct titsc *ts_dev = tscadc_dev->tsc; | ||
334 | |||
335 | free_irq(ts_dev->irq, ts_dev); | ||
336 | |||
337 | input_unregister_device(ts_dev->input); | ||
338 | |||
339 | platform_set_drvdata(pdev, NULL); | ||
340 | kfree(ts_dev); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | #ifdef CONFIG_PM | ||
345 | static int titsc_suspend(struct device *dev) | ||
346 | { | ||
347 | struct ti_tscadc_dev *tscadc_dev = dev->platform_data; | ||
348 | struct titsc *ts_dev = tscadc_dev->tsc; | ||
349 | unsigned int idle; | ||
350 | |||
351 | if (device_may_wakeup(tscadc_dev->dev)) { | ||
352 | idle = titsc_readl(ts_dev, REG_IRQENABLE); | ||
353 | titsc_writel(ts_dev, REG_IRQENABLE, | ||
354 | (idle | IRQENB_HW_PEN)); | ||
355 | titsc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); | ||
356 | } | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int titsc_resume(struct device *dev) | ||
361 | { | ||
362 | struct ti_tscadc_dev *tscadc_dev = dev->platform_data; | ||
363 | struct titsc *ts_dev = tscadc_dev->tsc; | ||
364 | |||
365 | if (device_may_wakeup(tscadc_dev->dev)) { | ||
366 | titsc_writel(ts_dev, REG_IRQWAKEUP, | ||
367 | 0x00); | ||
368 | titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); | ||
369 | } | ||
370 | titsc_step_config(ts_dev); | ||
371 | titsc_writel(ts_dev, REG_FIFO0THR, | ||
372 | ts_dev->steps_to_configure); | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static const struct dev_pm_ops titsc_pm_ops = { | ||
377 | .suspend = titsc_suspend, | ||
378 | .resume = titsc_resume, | ||
379 | }; | ||
380 | #define TITSC_PM_OPS (&titsc_pm_ops) | ||
381 | #else | ||
382 | #define TITSC_PM_OPS NULL | ||
383 | #endif | ||
384 | |||
385 | static struct platform_driver ti_tsc_driver = { | ||
386 | .probe = titsc_probe, | ||
387 | .remove = __devexit_p(titsc_remove), | ||
388 | .driver = { | ||
389 | .name = "tsc", | ||
390 | .owner = THIS_MODULE, | ||
391 | .pm = TITSC_PM_OPS, | ||
392 | }, | ||
393 | }; | ||
394 | module_platform_driver(ti_tsc_driver); | ||
395 | |||
396 | MODULE_DESCRIPTION("TI touchscreen controller driver"); | ||
397 | MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); | ||
398 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c deleted file mode 100644 index d229c741d54..00000000000 --- a/drivers/input/touchscreen/ti_tscadc.c +++ /dev/null | |||
@@ -1,486 +0,0 @@ | |||
1 | /* | ||
2 | * TI Touch Screen driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation version 2. | ||
9 | * | ||
10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
11 | * kind, whether express or implied; without even the implied warranty | ||
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/input.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/input/ti_tscadc.h> | ||
28 | #include <linux/delay.h> | ||
29 | |||
30 | #define REG_IRQEOI 0x020 | ||
31 | #define REG_RAWIRQSTATUS 0x024 | ||
32 | #define REG_IRQSTATUS 0x028 | ||
33 | #define REG_IRQENABLE 0x02C | ||
34 | #define REG_IRQWAKEUP 0x034 | ||
35 | #define REG_CTRL 0x040 | ||
36 | #define REG_ADCFSM 0x044 | ||
37 | #define REG_CLKDIV 0x04C | ||
38 | #define REG_SE 0x054 | ||
39 | #define REG_IDLECONFIG 0x058 | ||
40 | #define REG_CHARGECONFIG 0x05C | ||
41 | #define REG_CHARGEDELAY 0x060 | ||
42 | #define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8)) | ||
43 | #define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8)) | ||
44 | #define REG_STEPCONFIG13 0x0C4 | ||
45 | #define REG_STEPDELAY13 0x0C8 | ||
46 | #define REG_STEPCONFIG14 0x0CC | ||
47 | #define REG_STEPDELAY14 0x0D0 | ||
48 | #define REG_FIFO0CNT 0xE4 | ||
49 | #define REG_FIFO1THR 0xF4 | ||
50 | #define REG_FIFO0 0x100 | ||
51 | #define REG_FIFO1 0x200 | ||
52 | |||
53 | /* Register Bitfields */ | ||
54 | #define IRQWKUP_ENB BIT(0) | ||
55 | #define STPENB_STEPENB 0x7FFF | ||
56 | #define IRQENB_FIFO1THRES BIT(5) | ||
57 | #define IRQENB_PENUP BIT(9) | ||
58 | #define STEPCONFIG_MODE_HWSYNC 0x2 | ||
59 | #define STEPCONFIG_SAMPLES_AVG (1 << 4) | ||
60 | #define STEPCONFIG_XPP (1 << 5) | ||
61 | #define STEPCONFIG_XNN (1 << 6) | ||
62 | #define STEPCONFIG_YPP (1 << 7) | ||
63 | #define STEPCONFIG_YNN (1 << 8) | ||
64 | #define STEPCONFIG_XNP (1 << 9) | ||
65 | #define STEPCONFIG_YPN (1 << 10) | ||
66 | #define STEPCONFIG_INM (1 << 18) | ||
67 | #define STEPCONFIG_INP (1 << 20) | ||
68 | #define STEPCONFIG_INP_5 (1 << 21) | ||
69 | #define STEPCONFIG_FIFO1 (1 << 26) | ||
70 | #define STEPCONFIG_OPENDLY 0xff | ||
71 | #define STEPCONFIG_Z1 (3 << 19) | ||
72 | #define STEPIDLE_INP (1 << 22) | ||
73 | #define STEPCHARGE_RFP (1 << 12) | ||
74 | #define STEPCHARGE_INM (1 << 15) | ||
75 | #define STEPCHARGE_INP (1 << 19) | ||
76 | #define STEPCHARGE_RFM (1 << 23) | ||
77 | #define STEPCHARGE_DELAY 0x1 | ||
78 | #define CNTRLREG_TSCSSENB (1 << 0) | ||
79 | #define CNTRLREG_STEPID (1 << 1) | ||
80 | #define CNTRLREG_STEPCONFIGWRT (1 << 2) | ||
81 | #define CNTRLREG_4WIRE (1 << 5) | ||
82 | #define CNTRLREG_5WIRE (1 << 6) | ||
83 | #define CNTRLREG_8WIRE (3 << 5) | ||
84 | #define CNTRLREG_TSCENB (1 << 7) | ||
85 | #define ADCFSM_STEPID 0x10 | ||
86 | |||
87 | #define SEQ_SETTLE 275 | ||
88 | #define ADC_CLK 3000000 | ||
89 | #define MAX_12BIT ((1 << 12) - 1) | ||
90 | #define TSCADC_DELTA_X 15 | ||
91 | #define TSCADC_DELTA_Y 15 | ||
92 | |||
93 | struct tscadc { | ||
94 | struct input_dev *input; | ||
95 | struct clk *tsc_ick; | ||
96 | void __iomem *tsc_base; | ||
97 | unsigned int irq; | ||
98 | unsigned int wires; | ||
99 | unsigned int x_plate_resistance; | ||
100 | bool pen_down; | ||
101 | }; | ||
102 | |||
103 | static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg) | ||
104 | { | ||
105 | return readl(ts->tsc_base + reg); | ||
106 | } | ||
107 | |||
108 | static void tscadc_writel(struct tscadc *tsc, unsigned int reg, | ||
109 | unsigned int val) | ||
110 | { | ||
111 | writel(val, tsc->tsc_base + reg); | ||
112 | } | ||
113 | |||
114 | static void tscadc_step_config(struct tscadc *ts_dev) | ||
115 | { | ||
116 | unsigned int config; | ||
117 | int i; | ||
118 | |||
119 | /* Configure the Step registers */ | ||
120 | |||
121 | config = STEPCONFIG_MODE_HWSYNC | | ||
122 | STEPCONFIG_SAMPLES_AVG | STEPCONFIG_XPP; | ||
123 | switch (ts_dev->wires) { | ||
124 | case 4: | ||
125 | config |= STEPCONFIG_INP | STEPCONFIG_XNN; | ||
126 | break; | ||
127 | case 5: | ||
128 | config |= STEPCONFIG_YNN | | ||
129 | STEPCONFIG_INP_5 | STEPCONFIG_XNN | | ||
130 | STEPCONFIG_YPP; | ||
131 | break; | ||
132 | case 8: | ||
133 | config |= STEPCONFIG_INP | STEPCONFIG_XNN; | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | for (i = 1; i < 7; i++) { | ||
138 | tscadc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
139 | tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
140 | } | ||
141 | |||
142 | config = 0; | ||
143 | config = STEPCONFIG_MODE_HWSYNC | | ||
144 | STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YNN | | ||
145 | STEPCONFIG_INM | STEPCONFIG_FIFO1; | ||
146 | switch (ts_dev->wires) { | ||
147 | case 4: | ||
148 | config |= STEPCONFIG_YPP; | ||
149 | break; | ||
150 | case 5: | ||
151 | config |= STEPCONFIG_XPP | STEPCONFIG_INP_5 | | ||
152 | STEPCONFIG_XNP | STEPCONFIG_YPN; | ||
153 | break; | ||
154 | case 8: | ||
155 | config |= STEPCONFIG_YPP; | ||
156 | break; | ||
157 | } | ||
158 | |||
159 | for (i = 7; i < 13; i++) { | ||
160 | tscadc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
161 | tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
162 | } | ||
163 | |||
164 | config = 0; | ||
165 | /* Charge step configuration */ | ||
166 | config = STEPCONFIG_XPP | STEPCONFIG_YNN | | ||
167 | STEPCHARGE_RFP | STEPCHARGE_RFM | | ||
168 | STEPCHARGE_INM | STEPCHARGE_INP; | ||
169 | |||
170 | tscadc_writel(ts_dev, REG_CHARGECONFIG, config); | ||
171 | tscadc_writel(ts_dev, REG_CHARGEDELAY, STEPCHARGE_DELAY); | ||
172 | |||
173 | config = 0; | ||
174 | /* Configure to calculate pressure */ | ||
175 | config = STEPCONFIG_MODE_HWSYNC | | ||
176 | STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YPP | | ||
177 | STEPCONFIG_XNN | STEPCONFIG_INM; | ||
178 | tscadc_writel(ts_dev, REG_STEPCONFIG13, config); | ||
179 | tscadc_writel(ts_dev, REG_STEPDELAY13, STEPCONFIG_OPENDLY); | ||
180 | |||
181 | config |= STEPCONFIG_Z1 | STEPCONFIG_FIFO1; | ||
182 | tscadc_writel(ts_dev, REG_STEPCONFIG14, config); | ||
183 | tscadc_writel(ts_dev, REG_STEPDELAY14, STEPCONFIG_OPENDLY); | ||
184 | |||
185 | tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB); | ||
186 | } | ||
187 | |||
188 | static void tscadc_idle_config(struct tscadc *ts_config) | ||
189 | { | ||
190 | unsigned int idleconfig; | ||
191 | |||
192 | idleconfig = STEPCONFIG_YNN | | ||
193 | STEPCONFIG_INM | | ||
194 | STEPCONFIG_YPN | STEPIDLE_INP; | ||
195 | tscadc_writel(ts_config, REG_IDLECONFIG, idleconfig); | ||
196 | } | ||
197 | |||
198 | static void tscadc_read_coordinates(struct tscadc *ts_dev, | ||
199 | unsigned int *x, unsigned int *y) | ||
200 | { | ||
201 | unsigned int fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT); | ||
202 | unsigned int prev_val_x = ~0, prev_val_y = ~0; | ||
203 | unsigned int prev_diff_x = ~0, prev_diff_y = ~0; | ||
204 | unsigned int read, diff; | ||
205 | unsigned int i; | ||
206 | |||
207 | /* | ||
208 | * Delta filter is used to remove large variations in sampled | ||
209 | * values from ADC. The filter tries to predict where the next | ||
210 | * coordinate could be. This is done by taking a previous | ||
211 | * coordinate and subtracting it form current one. Further the | ||
212 | * algorithm compares the difference with that of a present value, | ||
213 | * if true the value is reported to the sub system. | ||
214 | */ | ||
215 | for (i = 0; i < fifocount - 1; i++) { | ||
216 | read = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff; | ||
217 | diff = abs(read - prev_val_x); | ||
218 | if (diff < prev_diff_x) { | ||
219 | prev_diff_x = diff; | ||
220 | *x = read; | ||
221 | } | ||
222 | prev_val_x = read; | ||
223 | |||
224 | read = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff; | ||
225 | diff = abs(read - prev_val_y); | ||
226 | if (diff < prev_diff_y) { | ||
227 | prev_diff_y = diff; | ||
228 | *y = read; | ||
229 | } | ||
230 | prev_val_y = read; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | static irqreturn_t tscadc_irq(int irq, void *dev) | ||
235 | { | ||
236 | struct tscadc *ts_dev = dev; | ||
237 | struct input_dev *input_dev = ts_dev->input; | ||
238 | unsigned int status, irqclr = 0; | ||
239 | unsigned int x = 0, y = 0; | ||
240 | unsigned int z1, z2, z; | ||
241 | unsigned int fsm; | ||
242 | |||
243 | status = tscadc_readl(ts_dev, REG_IRQSTATUS); | ||
244 | if (status & IRQENB_FIFO1THRES) { | ||
245 | tscadc_read_coordinates(ts_dev, &x, &y); | ||
246 | |||
247 | z1 = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff; | ||
248 | z2 = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff; | ||
249 | |||
250 | if (ts_dev->pen_down && z1 != 0 && z2 != 0) { | ||
251 | /* | ||
252 | * Calculate pressure using formula | ||
253 | * Resistance(touch) = x plate resistance * | ||
254 | * x postion/4096 * ((z2 / z1) - 1) | ||
255 | */ | ||
256 | z = z2 - z1; | ||
257 | z *= x; | ||
258 | z *= ts_dev->x_plate_resistance; | ||
259 | z /= z1; | ||
260 | z = (z + 2047) >> 12; | ||
261 | |||
262 | if (z <= MAX_12BIT) { | ||
263 | input_report_abs(input_dev, ABS_X, x); | ||
264 | input_report_abs(input_dev, ABS_Y, y); | ||
265 | input_report_abs(input_dev, ABS_PRESSURE, z); | ||
266 | input_report_key(input_dev, BTN_TOUCH, 1); | ||
267 | input_sync(input_dev); | ||
268 | } | ||
269 | } | ||
270 | irqclr |= IRQENB_FIFO1THRES; | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * Time for sequencer to settle, to read | ||
275 | * correct state of the sequencer. | ||
276 | */ | ||
277 | udelay(SEQ_SETTLE); | ||
278 | |||
279 | status = tscadc_readl(ts_dev, REG_RAWIRQSTATUS); | ||
280 | if (status & IRQENB_PENUP) { | ||
281 | /* Pen up event */ | ||
282 | fsm = tscadc_readl(ts_dev, REG_ADCFSM); | ||
283 | if (fsm == ADCFSM_STEPID) { | ||
284 | ts_dev->pen_down = false; | ||
285 | input_report_key(input_dev, BTN_TOUCH, 0); | ||
286 | input_report_abs(input_dev, ABS_PRESSURE, 0); | ||
287 | input_sync(input_dev); | ||
288 | } else { | ||
289 | ts_dev->pen_down = true; | ||
290 | } | ||
291 | irqclr |= IRQENB_PENUP; | ||
292 | } | ||
293 | |||
294 | tscadc_writel(ts_dev, REG_IRQSTATUS, irqclr); | ||
295 | /* check pending interrupts */ | ||
296 | tscadc_writel(ts_dev, REG_IRQEOI, 0x0); | ||
297 | |||
298 | tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB); | ||
299 | return IRQ_HANDLED; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * The functions for inserting/removing driver as a module. | ||
304 | */ | ||
305 | |||
306 | static int __devinit tscadc_probe(struct platform_device *pdev) | ||
307 | { | ||
308 | const struct tsc_data *pdata = pdev->dev.platform_data; | ||
309 | struct resource *res; | ||
310 | struct tscadc *ts_dev; | ||
311 | struct input_dev *input_dev; | ||
312 | struct clk *clk; | ||
313 | int err; | ||
314 | int clk_value, ctrl, irq; | ||
315 | |||
316 | if (!pdata) { | ||
317 | dev_err(&pdev->dev, "missing platform data.\n"); | ||
318 | return -EINVAL; | ||
319 | } | ||
320 | |||
321 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
322 | if (!res) { | ||
323 | dev_err(&pdev->dev, "no memory resource defined.\n"); | ||
324 | return -EINVAL; | ||
325 | } | ||
326 | |||
327 | irq = platform_get_irq(pdev, 0); | ||
328 | if (irq < 0) { | ||
329 | dev_err(&pdev->dev, "no irq ID is specified.\n"); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | |||
333 | /* Allocate memory for device */ | ||
334 | ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL); | ||
335 | input_dev = input_allocate_device(); | ||
336 | if (!ts_dev || !input_dev) { | ||
337 | dev_err(&pdev->dev, "failed to allocate memory.\n"); | ||
338 | err = -ENOMEM; | ||
339 | goto err_free_mem; | ||
340 | } | ||
341 | |||
342 | ts_dev->input = input_dev; | ||
343 | ts_dev->irq = irq; | ||
344 | ts_dev->wires = pdata->wires; | ||
345 | ts_dev->x_plate_resistance = pdata->x_plate_resistance; | ||
346 | |||
347 | res = request_mem_region(res->start, resource_size(res), pdev->name); | ||
348 | if (!res) { | ||
349 | dev_err(&pdev->dev, "failed to reserve registers.\n"); | ||
350 | err = -EBUSY; | ||
351 | goto err_free_mem; | ||
352 | } | ||
353 | |||
354 | ts_dev->tsc_base = ioremap(res->start, resource_size(res)); | ||
355 | if (!ts_dev->tsc_base) { | ||
356 | dev_err(&pdev->dev, "failed to map registers.\n"); | ||
357 | err = -ENOMEM; | ||
358 | goto err_release_mem_region; | ||
359 | } | ||
360 | |||
361 | err = request_irq(ts_dev->irq, tscadc_irq, | ||
362 | 0, pdev->dev.driver->name, ts_dev); | ||
363 | if (err) { | ||
364 | dev_err(&pdev->dev, "failed to allocate irq.\n"); | ||
365 | goto err_unmap_regs; | ||
366 | } | ||
367 | |||
368 | ts_dev->tsc_ick = clk_get(&pdev->dev, "adc_tsc_ick"); | ||
369 | if (IS_ERR(ts_dev->tsc_ick)) { | ||
370 | dev_err(&pdev->dev, "failed to get TSC ick\n"); | ||
371 | goto err_free_irq; | ||
372 | } | ||
373 | clk_enable(ts_dev->tsc_ick); | ||
374 | |||
375 | clk = clk_get(&pdev->dev, "adc_tsc_fck"); | ||
376 | if (IS_ERR(clk)) { | ||
377 | dev_err(&pdev->dev, "failed to get TSC fck\n"); | ||
378 | err = PTR_ERR(clk); | ||
379 | goto err_disable_clk; | ||
380 | } | ||
381 | |||
382 | clk_value = clk_get_rate(clk) / ADC_CLK; | ||
383 | clk_put(clk); | ||
384 | |||
385 | if (clk_value < 7) { | ||
386 | dev_err(&pdev->dev, "clock input less than min clock requirement\n"); | ||
387 | goto err_disable_clk; | ||
388 | } | ||
389 | /* CLKDIV needs to be configured to the value minus 1 */ | ||
390 | tscadc_writel(ts_dev, REG_CLKDIV, clk_value - 1); | ||
391 | |||
392 | /* Enable wake-up of the SoC using touchscreen */ | ||
393 | tscadc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); | ||
394 | |||
395 | ctrl = CNTRLREG_STEPCONFIGWRT | | ||
396 | CNTRLREG_TSCENB | | ||
397 | CNTRLREG_STEPID; | ||
398 | switch (ts_dev->wires) { | ||
399 | case 4: | ||
400 | ctrl |= CNTRLREG_4WIRE; | ||
401 | break; | ||
402 | case 5: | ||
403 | ctrl |= CNTRLREG_5WIRE; | ||
404 | break; | ||
405 | case 8: | ||
406 | ctrl |= CNTRLREG_8WIRE; | ||
407 | break; | ||
408 | } | ||
409 | tscadc_writel(ts_dev, REG_CTRL, ctrl); | ||
410 | |||
411 | tscadc_idle_config(ts_dev); | ||
412 | tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO1THRES); | ||
413 | tscadc_step_config(ts_dev); | ||
414 | tscadc_writel(ts_dev, REG_FIFO1THR, 6); | ||
415 | |||
416 | ctrl |= CNTRLREG_TSCSSENB; | ||
417 | tscadc_writel(ts_dev, REG_CTRL, ctrl); | ||
418 | |||
419 | input_dev->name = "ti-tsc-adc"; | ||
420 | input_dev->dev.parent = &pdev->dev; | ||
421 | |||
422 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
423 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | ||
424 | |||
425 | input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); | ||
426 | input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); | ||
427 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); | ||
428 | |||
429 | /* register to the input system */ | ||
430 | err = input_register_device(input_dev); | ||
431 | if (err) | ||
432 | goto err_disable_clk; | ||
433 | |||
434 | platform_set_drvdata(pdev, ts_dev); | ||
435 | return 0; | ||
436 | |||
437 | err_disable_clk: | ||
438 | clk_disable(ts_dev->tsc_ick); | ||
439 | clk_put(ts_dev->tsc_ick); | ||
440 | err_free_irq: | ||
441 | free_irq(ts_dev->irq, ts_dev); | ||
442 | err_unmap_regs: | ||
443 | iounmap(ts_dev->tsc_base); | ||
444 | err_release_mem_region: | ||
445 | release_mem_region(res->start, resource_size(res)); | ||
446 | err_free_mem: | ||
447 | input_free_device(input_dev); | ||
448 | kfree(ts_dev); | ||
449 | return err; | ||
450 | } | ||
451 | |||
452 | static int __devexit tscadc_remove(struct platform_device *pdev) | ||
453 | { | ||
454 | struct tscadc *ts_dev = platform_get_drvdata(pdev); | ||
455 | struct resource *res; | ||
456 | |||
457 | free_irq(ts_dev->irq, ts_dev); | ||
458 | |||
459 | input_unregister_device(ts_dev->input); | ||
460 | |||
461 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
462 | iounmap(ts_dev->tsc_base); | ||
463 | release_mem_region(res->start, resource_size(res)); | ||
464 | |||
465 | clk_disable(ts_dev->tsc_ick); | ||
466 | clk_put(ts_dev->tsc_ick); | ||
467 | |||
468 | kfree(ts_dev); | ||
469 | |||
470 | platform_set_drvdata(pdev, NULL); | ||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static struct platform_driver ti_tsc_driver = { | ||
475 | .probe = tscadc_probe, | ||
476 | .remove = __devexit_p(tscadc_remove), | ||
477 | .driver = { | ||
478 | .name = "tsc", | ||
479 | .owner = THIS_MODULE, | ||
480 | }, | ||
481 | }; | ||
482 | module_platform_driver(ti_tsc_driver); | ||
483 | |||
484 | MODULE_DESCRIPTION("TI touchscreen controller driver"); | ||
485 | MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); | ||
486 | MODULE_LICENSE("GPL"); | ||