2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 * Copyright (c) 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
17 * iPAQ H1940 touchscreen support
21 * 2004-09-05: Herbert Pƶtzl <herbert@13thfloor.at>
22 * - added clock (de-)allocation code
24 * 2005-03-06: Arnaud Patard <arnaud.patard@rtp-net.org>
25 * - h1940_ -> s3c2410 (this driver is now also used on the n30
27 * - Debug messages are now enabled with the config option
28 * TOUCHSCREEN_S3C2410_DEBUG
29 * - Changed the way the value are read
30 * - Input subsystem should now work
31 * - Use ioremap and readl/writel
33 * 2005-03-23: Arnaud Patard <arnaud.patard@rtp-net.org>
34 * - Make use of some undocumented features of the touchscreen
37 * 2007-05-23: Harald Welte <laforge@openmoko.org>
38 * - Add proper support for S32440
40 * 2008-06-18: Andy Green <andy@openmoko.com>
44 #include <linux/errno.h>
45 #include <linux/kernel.h>
46 #include <linux/module.h>
47 #include <linux/slab.h>
48 #include <linux/input.h>
49 #include <linux/init.h>
50 #include <linux/serio.h>
51 #include <linux/delay.h>
52 #include <linux/platform_device.h>
53 #include <linux/clk.h>
57 #include <asm/arch/regs-gpio.h>
58 #include <asm/arch/ts.h>
60 #include <asm/plat-s3c/regs-adc.h>
62 /* For ts.dev.id.version */
63 #define S3C2410TSVERSION 0x0101
65 #define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0))
67 #define WAIT4INT(x) (((x)<<8) | \
68 S3C2410_ADCTSC_YM_SEN | \
69 S3C2410_ADCTSC_YP_SEN | \
70 S3C2410_ADCTSC_XP_SEN | \
71 S3C2410_ADCTSC_XY_PST(3))
73 #define AUTOPST (S3C2410_ADCTSC_YM_SEN | \
74 S3C2410_ADCTSC_YP_SEN | \
75 S3C2410_ADCTSC_XP_SEN | \
76 S3C2410_ADCTSC_AUTO_PST | \
77 S3C2410_ADCTSC_XY_PST(0))
79 #define DEBUG_LVL KERN_DEBUG
81 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
82 MODULE_DESCRIPTION("s3c2410 touchscreen driver");
83 MODULE_LICENSE("GPL");
86 * Definitions & global arrays.
90 static char *s3c2410ts_name
= "s3c2410 TouchScreen";
93 * Per-touchscreen data.
96 struct s3c2410ts_sample
{
102 struct input_dev
*dev
;
107 int extent
; /* 1 << shift */
109 /* the raw sample fifo is a lightweight way to track a running average
110 * of all taken samples. "running average" here means that it gives
111 * correct average for each sample, not only at the end of block of
114 int excursion_filter_len
;
115 struct s3c2410ts_sample
*raw_sample_fifo
;
118 struct s3c2410ts_sample raw_running_avg
;
119 int reject_threshold_vs_avg
;
120 int flag_previous_exceeded_threshold
;
123 static struct s3c2410ts ts
;
124 static void __iomem
*base_addr
;
126 static void clear_raw_fifo(void)
128 ts
.head_raw_fifo
= 0;
129 ts
.tail_raw_fifo
= 0;
130 ts
.raw_running_avg
.x
= 0;
131 ts
.raw_running_avg
.y
= 0;
132 ts
.flag_previous_exceeded_threshold
= 0;
136 static inline void s3c2410_ts_connect(void)
138 s3c2410_gpio_cfgpin(S3C2410_GPG12
, S3C2410_GPG12_XMON
);
139 s3c2410_gpio_cfgpin(S3C2410_GPG13
, S3C2410_GPG13_nXPON
);
140 s3c2410_gpio_cfgpin(S3C2410_GPG14
, S3C2410_GPG14_YMON
);
141 s3c2410_gpio_cfgpin(S3C2410_GPG15
, S3C2410_GPG15_nYPON
);
144 static void touch_timer_fire(unsigned long data
)
150 data0
= readl(base_addr
+ S3C2410_ADCDAT0
);
151 data1
= readl(base_addr
+ S3C2410_ADCDAT1
);
153 updown
= (!(data0
& S3C2410_ADCDAT0_UPDOWN
)) &&
154 (!(data1
& S3C2410_ADCDAT0_UPDOWN
));
161 #ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
165 do_gettimeofday(&tv
);
166 printk(DEBUG_LVL
"T:%06d, X:%03ld, Y:%03ld\n",
167 (int)tv
.tv_usec
, ts
.xp
, ts
.yp
);
171 input_report_abs(ts
.dev
, ABS_X
, ts
.xp
);
172 input_report_abs(ts
.dev
, ABS_Y
, ts
.yp
);
174 input_report_key(ts
.dev
, BTN_TOUCH
, 1);
175 input_report_abs(ts
.dev
, ABS_PRESSURE
, 1);
183 writel(S3C2410_ADCTSC_PULL_UP_DISABLE
| AUTOPST
,
184 base_addr
+S3C2410_ADCTSC
);
185 writel(readl(base_addr
+S3C2410_ADCCON
) |
186 S3C2410_ADCCON_ENABLE_START
, base_addr
+S3C2410_ADCCON
);
190 input_report_key(ts
.dev
, BTN_TOUCH
, 0);
191 input_report_abs(ts
.dev
, ABS_PRESSURE
, 0);
194 writel(WAIT4INT(0), base_addr
+S3C2410_ADCTSC
);
198 static struct timer_list touch_timer
=
199 TIMER_INITIALIZER(touch_timer_fire
, 0, 0);
201 static irqreturn_t
stylus_updown(int irq
, void *dev_id
)
207 data0
= readl(base_addr
+S3C2410_ADCDAT0
);
208 data1
= readl(base_addr
+S3C2410_ADCDAT1
);
210 updown
= (!(data0
& S3C2410_ADCDAT0_UPDOWN
)) &&
211 (!(data1
& S3C2410_ADCDAT0_UPDOWN
));
213 /* TODO we should never get an interrupt with updown set while
214 * the timer is running, but maybe we ought to verify that the
215 * timer isn't running anyways. */
224 static irqreturn_t
stylus_action(int irq
, void *dev_id
)
228 int length
= (ts
.head_raw_fifo
- ts
.tail_raw_fifo
) & (ts
.extent
- 1);
229 int scaled_avg_x
= ts
.raw_running_avg
.x
/ length
;
230 int scaled_avg_y
= ts
.raw_running_avg
.y
/ length
;
232 x
= readl(base_addr
+ S3C2410_ADCDAT0
) & S3C2410_ADCDAT0_XPDATA_MASK
;
233 y
= readl(base_addr
+ S3C2410_ADCDAT1
) & S3C2410_ADCDAT1_YPDATA_MASK
;
235 /* we appear to accept every sample into both the running average FIFO
236 * and the summing average. BUT, if the last sample crossed a
237 * machine-set threshold, each time we do a beauty contest
238 * on the new sample comparing if it is closer to the running
239 * average and the previous sample. If it is closer to the previous
240 * suspicious sample, we assume the change is real and accept both
241 * if the new sample has returned to being closer to the average than
242 * the previous sample, we take the previous sample as an excursion
243 * and overwrite it in both the running average and summing average.
246 if (ts
.flag_previous_exceeded_threshold
)
247 /* new one closer to "nonconformist" previous, or average?
248 * Pythagoras? Who? Don't need it because large excursion
249 * will be accounted for correctly this way
251 if ((abs(x
- scaled_avg_x
) + abs(y
- scaled_avg_y
)) <
252 (abs(x
- ts
.raw_sample_fifo
[(ts
.head_raw_fifo
- 1) &
253 (ts
.extent
- 1)].x
) +
254 abs(y
- ts
.raw_sample_fifo
[(ts
.head_raw_fifo
- 1) &
255 (ts
.extent
- 1)].y
))) {
256 /* it's closer to average, reject previous as a one-
257 * shot excursion, by overwriting it
259 ts
.xp
+= x
- ts
.raw_sample_fifo
[(ts
.head_raw_fifo
- 1) &
261 ts
.yp
+= y
- ts
.raw_sample_fifo
[(ts
.head_raw_fifo
- 1) &
263 ts
.raw_sample_fifo
[(ts
.head_raw_fifo
- 1) &
264 (ts
.extent
- 1)].x
= x
;
265 ts
.raw_sample_fifo
[(ts
.head_raw_fifo
- 1) &
266 (ts
.extent
- 1)].y
= y
;
267 /* no new sample: replaced previous, so we are done */
270 /* else it was closer to nonconformist previous: it's likely
271 * a genuine consistent move then.
272 * Keep previous and add new guy.
275 if ((x
>= scaled_avg_x
- ts
.reject_threshold_vs_avg
) &&
276 (x
<= scaled_avg_x
+ ts
.reject_threshold_vs_avg
) &&
277 (y
>= scaled_avg_y
- ts
.reject_threshold_vs_avg
) &&
278 (y
<= scaled_avg_y
+ ts
.reject_threshold_vs_avg
))
279 ts
.flag_previous_exceeded_threshold
= 0;
281 ts
.flag_previous_exceeded_threshold
= 1;
288 /* remove oldest sample from avg when we have full pipeline */
289 if (((ts
.head_raw_fifo
+ 1) & (ts
.extent
- 1)) == ts
.tail_raw_fifo
) {
290 ts
.raw_running_avg
.x
-= ts
.raw_sample_fifo
[ts
.tail_raw_fifo
].x
;
291 ts
.raw_running_avg
.y
-= ts
.raw_sample_fifo
[ts
.tail_raw_fifo
].y
;
292 ts
.tail_raw_fifo
= (ts
.tail_raw_fifo
+ 1) & (ts
.extent
- 1);
294 /* always add current sample to fifo and average */
295 ts
.raw_sample_fifo
[ts
.head_raw_fifo
].x
= x
;
296 ts
.raw_sample_fifo
[ts
.head_raw_fifo
].y
= y
;
297 ts
.raw_running_avg
.x
+= x
;
298 ts
.raw_running_avg
.y
+= y
;
299 ts
.head_raw_fifo
= (ts
.head_raw_fifo
+ 1) & (ts
.extent
- 1);
302 if (ts
.count
>= (1 << ts
.shift
)) {
303 mod_timer(&touch_timer
, jiffies
+ 1);
304 writel(WAIT4INT(1), base_addr
+S3C2410_ADCTSC
);
308 writel(S3C2410_ADCTSC_PULL_UP_DISABLE
| AUTOPST
,
309 base_addr
+S3C2410_ADCTSC
);
310 writel(readl(base_addr
+S3C2410_ADCCON
) |
311 S3C2410_ADCCON_ENABLE_START
, base_addr
+S3C2410_ADCCON
);
317 static struct clk
*adc_clock
;
320 * The functions for inserting/removing us as a module.
323 static int __init
s3c2410ts_probe(struct platform_device
*pdev
)
326 struct s3c2410_ts_mach_info
*info
;
327 struct input_dev
*input_dev
;
329 info
= (struct s3c2410_ts_mach_info
*)pdev
->dev
.platform_data
;
333 dev_err(&pdev
->dev
, "Hm... too bad: no platform data for ts\n");
337 #ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
338 printk(DEBUG_LVL
"Entering s3c2410ts_init\n");
341 adc_clock
= clk_get(NULL
, "adc");
343 dev_err(&pdev
->dev
, "failed to get adc clock source\n");
346 clk_enable(adc_clock
);
348 #ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
349 printk(DEBUG_LVL
"got and enabled clock\n");
352 base_addr
= ioremap(S3C2410_PA_ADC
,0x20);
353 if (base_addr
== NULL
) {
354 dev_err(&pdev
->dev
, "Failed to remap register block\n");
359 /* If we acutally are a S3C2410: Configure GPIOs */
360 if (!strcmp(pdev
->name
, "s3c2410-ts"))
361 s3c2410_ts_connect();
363 if ((info
->presc
& 0xff) > 0)
364 writel(S3C2410_ADCCON_PRSCEN
|
365 S3C2410_ADCCON_PRSCVL(info
->presc
&0xFF),
366 base_addr
+ S3C2410_ADCCON
);
368 writel(0, base_addr
+S3C2410_ADCCON
);
371 /* Initialise registers */
372 if ((info
->delay
& 0xffff) > 0)
373 writel(info
->delay
& 0xffff, base_addr
+ S3C2410_ADCDLY
);
375 writel(WAIT4INT(0), base_addr
+ S3C2410_ADCTSC
);
377 /* Initialise input stuff */
378 memset(&ts
, 0, sizeof(struct s3c2410ts
));
379 input_dev
= input_allocate_device();
382 dev_err(&pdev
->dev
, "Unable to allocate the input device\n");
387 ts
.dev
->evbit
[0] = BIT_MASK(EV_SYN
) | BIT_MASK(EV_KEY
) |
389 ts
.dev
->keybit
[BIT_WORD(BTN_TOUCH
)] = BIT_MASK(BTN_TOUCH
);
390 input_set_abs_params(ts
.dev
, ABS_X
, 0, 0x3FF, 0, 0);
391 input_set_abs_params(ts
.dev
, ABS_Y
, 0, 0x3FF, 0, 0);
392 input_set_abs_params(ts
.dev
, ABS_PRESSURE
, 0, 1, 0, 0);
394 ts
.dev
->private = &ts
;
395 ts
.dev
->name
= s3c2410ts_name
;
396 ts
.dev
->id
.bustype
= BUS_RS232
;
397 ts
.dev
->id
.vendor
= 0xDEAD;
398 ts
.dev
->id
.product
= 0xBEEF;
399 ts
.dev
->id
.version
= S3C2410TSVERSION
;
401 ts
.shift
= info
->oversampling_shift
;
402 ts
.extent
= 1 << info
->oversampling_shift
;
403 ts
.reject_threshold_vs_avg
= info
->reject_threshold_vs_avg
;
404 ts
.excursion_filter_len
= 1 << info
->excursion_filter_len_bits
;
406 ts
.raw_sample_fifo
= kmalloc(sizeof(struct s3c2410ts_sample
) *
407 ts
.excursion_filter_len
, GFP_KERNEL
);
411 if (request_irq(IRQ_ADC
, stylus_action
, IRQF_SAMPLE_RANDOM
,
412 "s3c2410_action", ts
.dev
)) {
413 dev_err(&pdev
->dev
, "Could not allocate ts IRQ_ADC !\n");
417 if (request_irq(IRQ_TC
, stylus_updown
, IRQF_SAMPLE_RANDOM
,
418 "s3c2410_action", ts
.dev
)) {
419 dev_err(&pdev
->dev
, "Could not allocate ts IRQ_TC !\n");
420 free_irq(IRQ_ADC
, ts
.dev
);
425 dev_info(&pdev
->dev
, "successfully loaded\n");
427 /* All went ok, so register to the input system */
428 rc
= input_register_device(ts
.dev
);
430 free_irq(IRQ_TC
, ts
.dev
);
431 free_irq(IRQ_ADC
, ts
.dev
);
432 clk_disable(adc_clock
);
440 static int s3c2410ts_remove(struct platform_device
*pdev
)
442 disable_irq(IRQ_ADC
);
444 free_irq(IRQ_TC
,ts
.dev
);
445 free_irq(IRQ_ADC
,ts
.dev
);
448 clk_disable(adc_clock
);
453 kfree(ts
.raw_sample_fifo
);
455 input_unregister_device(ts
.dev
);
462 static int s3c2410ts_suspend(struct platform_device
*pdev
, pm_message_t state
)
464 writel(TSC_SLEEP
, base_addr
+S3C2410_ADCTSC
);
465 writel(readl(base_addr
+S3C2410_ADCCON
) | S3C2410_ADCCON_STDBM
,
466 base_addr
+S3C2410_ADCCON
);
468 disable_irq(IRQ_ADC
);
471 clk_disable(adc_clock
);
476 static int s3c2410ts_resume(struct platform_device
*pdev
)
478 struct s3c2410_ts_mach_info
*info
=
479 ( struct s3c2410_ts_mach_info
*)pdev
->dev
.platform_data
;
481 clk_enable(adc_clock
);
489 if ((info
->presc
&0xff) > 0)
490 writel(S3C2410_ADCCON_PRSCEN
|
491 S3C2410_ADCCON_PRSCVL(info
->presc
&0xFF),
492 base_addr
+S3C2410_ADCCON
);
494 writel(0,base_addr
+S3C2410_ADCCON
);
496 /* Initialise registers */
497 if ((info
->delay
& 0xffff) > 0)
498 writel(info
->delay
& 0xffff, base_addr
+S3C2410_ADCDLY
);
500 writel(WAIT4INT(0), base_addr
+S3C2410_ADCTSC
);
506 #define s3c2410ts_suspend NULL
507 #define s3c2410ts_resume NULL
510 static struct platform_driver s3c2410ts_driver
= {
512 .name
= "s3c2410-ts",
513 .owner
= THIS_MODULE
,
515 .probe
= s3c2410ts_probe
,
516 .remove
= s3c2410ts_remove
,
517 .suspend
= s3c2410ts_suspend
,
518 .resume
= s3c2410ts_resume
,
522 static struct platform_driver s3c2440ts_driver
= {
524 .name
= "s3c2440-ts",
525 .owner
= THIS_MODULE
,
527 .probe
= s3c2410ts_probe
,
528 .remove
= s3c2410ts_remove
,
529 .suspend
= s3c2410ts_suspend
,
530 .resume
= s3c2410ts_resume
,
534 static int __init
s3c2410ts_init(void)
538 rc
= platform_driver_register(&s3c2410ts_driver
);
542 rc
= platform_driver_register(&s3c2440ts_driver
);
544 platform_driver_unregister(&s3c2410ts_driver
);
549 static void __exit
s3c2410ts_exit(void)
551 platform_driver_unregister(&s3c2440ts_driver
);
552 platform_driver_unregister(&s3c2410ts_driver
);
555 module_init(s3c2410ts_init
);
556 module_exit(s3c2410ts_exit
);
560 compile-command: "make ARCH=arm CROSS_COMPILE=/usr/local/arm/3.3.2/bin/arm-linux- -k -C ../../.."