1 From 04cce88d3d6753ae23ec36cf383f81aaed5fc71b Mon Sep 17 00:00:00 2001
2 From: mokopatches <mokopatches@openmoko.org>
3 Date: Fri, 4 Apr 2008 11:32:18 +0100
4 Subject: [PATCH] s3c2410_touchscreen.patch
7 arch/arm/mach-s3c2410/mach-h1940.c | 8 +
8 arch/arm/plat-s3c24xx/devs.c | 18 ++
9 arch/arm/plat-s3c24xx/s3c244x.c | 1 +
10 drivers/input/touchscreen/Kconfig | 18 ++
11 drivers/input/touchscreen/Makefile | 1 +
12 drivers/input/touchscreen/s3c2410_ts.c | 437 ++++++++++++++++++++++++++++++++
13 include/asm-arm/arch-s3c2410/ts.h | 28 ++
14 include/asm-arm/plat-s3c24xx/devs.h | 1 +
15 8 files changed, 512 insertions(+), 0 deletions(-)
16 create mode 100644 drivers/input/touchscreen/s3c2410_ts.c
17 create mode 100644 include/asm-arm/arch-s3c2410/ts.h
19 diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
20 index 7c1145e..93cd8c8 100644
21 --- a/arch/arm/mach-s3c2410/mach-h1940.c
22 +++ b/arch/arm/mach-s3c2410/mach-h1940.c
24 #include <asm/arch/h1940.h>
25 #include <asm/arch/h1940-latch.h>
26 #include <asm/arch/fb.h>
27 +#include <asm/arch/tc.h>
28 #include <asm/plat-s3c24xx/udc.h>
30 #include <asm/plat-s3c24xx/clock.h>
31 @@ -129,6 +130,11 @@ static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = {
32 .vbus_pin_inverted = 1,
35 +static struct s3c2410_ts_mach_info h1940_ts_cfg __initdata = {
38 + .oversampling_shift = 2,
43 @@ -186,6 +192,7 @@ static struct platform_device *h1940_devices[] __initdata = {
46 &s3c_device_usbgadget,
49 &s3c_device_bluetooth,
51 @@ -214,6 +221,7 @@ static void __init h1940_init(void)
54 s3c24xx_fb_set_platdata(&h1940_fb_info);
55 + set_s3c2410ts_info(&h1940_ts_cfg);
56 s3c24xx_udc_set_platdata(&h1940_udc_cfg);
58 /* Turn off suspend on both USB ports, and switch the
59 diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
60 index e546e93..c1fbe2d 100644
61 --- a/arch/arm/plat-s3c24xx/devs.c
62 +++ b/arch/arm/plat-s3c24xx/devs.c
64 #include <asm/mach/map.h>
65 #include <asm/mach/irq.h>
66 #include <asm/arch/fb.h>
67 +#include <asm/arch/ts.h>
68 #include <asm/hardware.h>
71 @@ -207,6 +208,23 @@ struct platform_device s3c_device_nand = {
73 EXPORT_SYMBOL(s3c_device_nand);
76 +struct platform_device s3c_device_ts = {
77 + .name = "s3c2410-ts",
81 +EXPORT_SYMBOL(s3c_device_ts);
83 +static struct s3c2410_ts_mach_info s3c2410ts_info;
85 +void set_s3c2410ts_info(struct s3c2410_ts_mach_info *hard_s3c2410ts_info)
87 + memcpy(&s3c2410ts_info,hard_s3c2410ts_info,sizeof(struct s3c2410_ts_mach_info));
88 + s3c_device_ts.dev.platform_data = &s3c2410ts_info;
90 +EXPORT_SYMBOL(set_s3c2410ts_info);
92 /* USB Device (Gadget)*/
94 static struct resource s3c_usbgadget_resource[] = {
95 diff --git a/arch/arm/plat-s3c24xx/s3c244x.c b/arch/arm/plat-s3c24xx/s3c244x.c
96 index 3444b13..b9389b9 100644
97 --- a/arch/arm/plat-s3c24xx/s3c244x.c
98 +++ b/arch/arm/plat-s3c24xx/s3c244x.c
99 @@ -67,6 +67,7 @@ void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
101 s3c_device_i2c.name = "s3c2440-i2c";
102 s3c_device_nand.name = "s3c2440-nand";
103 + s3c_device_ts.name = "s3c2440-ts";
104 s3c_device_usbgadget.name = "s3c2440-usbgadget";
107 diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
108 index 90e8e92..b94fa62 100644
109 --- a/drivers/input/touchscreen/Kconfig
110 +++ b/drivers/input/touchscreen/Kconfig
111 @@ -67,6 +67,24 @@ config TOUCHSCREEN_FUJITSU
112 To compile this driver as a module, choose M here: the
113 module will be called fujitsu-ts.
115 +config TOUCHSCREEN_S3C2410
116 + tristate "Samsung S3C2410 touchscreen input driver"
117 + depends on ARCH_S3C2410 && INPUT && INPUT_TOUCHSCREEN
120 + Say Y here if you have the s3c2410 touchscreen.
124 + To compile this driver as a module, choose M here: the
125 + module will be called s3c2410_ts.
127 +config TOUCHSCREEN_S3C2410_DEBUG
128 + boolean "Samsung S3C2410 touchscreen debug messages"
129 + depends on TOUCHSCREEN_S3C2410
131 + Select this if you want debug messages
133 config TOUCHSCREEN_GUNZE
134 tristate "Gunze AHL-51S touchscreen"
136 diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
137 index 35d4097..6558e63 100644
138 --- a/drivers/input/touchscreen/Makefile
139 +++ b/drivers/input/touchscreen/Makefile
140 @@ -19,3 +19,4 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
141 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
142 obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
143 obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
144 +obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
145 diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c
147 index 0000000..68071c2
149 +++ b/drivers/input/touchscreen/s3c2410_ts.c
152 + * This program is free software; you can redistribute it and/or modify
153 + * it under the terms of the GNU General Public License as published by
154 + * the Free Software Foundation; either version 2 of the License, or
155 + * (at your option) any later version.
157 + * This program is distributed in the hope that it will be useful,
158 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
159 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
160 + * GNU General Public License for more details.
162 + * You should have received a copy of the GNU General Public License
163 + * along with this program; if not, write to the Free Software
164 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
166 + * Copyright (c) 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
167 + * iPAQ H1940 touchscreen support
171 + * 2004-09-05: Herbert Pƶtzl <herbert@13thfloor.at>
172 + * - added clock (de-)allocation code
174 + * 2005-03-06: Arnaud Patard <arnaud.patard@rtp-net.org>
175 + * - h1940_ -> s3c2410 (this driver is now also used on the n30
177 + * - Debug messages are now enabled with the config option
178 + * TOUCHSCREEN_S3C2410_DEBUG
179 + * - Changed the way the value are read
180 + * - Input subsystem should now work
181 + * - Use ioremap and readl/writel
183 + * 2005-03-23: Arnaud Patard <arnaud.patard@rtp-net.org>
184 + * - Make use of some undocumented features of the touchscreen
187 + * 2007-05-23: Harald Welte <laforge@openmoko.org>
188 + * - Add proper support for S32440
191 +#include <linux/errno.h>
192 +#include <linux/kernel.h>
193 +#include <linux/module.h>
194 +#include <linux/slab.h>
195 +#include <linux/input.h>
196 +#include <linux/init.h>
197 +#include <linux/serio.h>
198 +#include <linux/delay.h>
199 +#include <linux/platform_device.h>
200 +#include <linux/clk.h>
202 +#include <asm/irq.h>
204 +#include <asm/arch/regs-gpio.h>
205 +#include <asm/arch/ts.h>
207 +#include <asm/plat-s3c/regs-adc.h>
209 +/* For ts.dev.id.version */
210 +#define S3C2410TSVERSION 0x0101
212 +#define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0))
214 +#define WAIT4INT(x) (((x)<<8) | \
215 + S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
216 + S3C2410_ADCTSC_XY_PST(3))
218 +#define AUTOPST (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
219 + S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))
221 +#define DEBUG_LVL KERN_DEBUG
223 +MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
224 +MODULE_DESCRIPTION("s3c2410 touchscreen driver");
225 +MODULE_LICENSE("GPL");
228 + * Definitions & global arrays.
232 +static char *s3c2410ts_name = "s3c2410 TouchScreen";
235 + * Per-touchscreen data.
239 + struct input_dev *dev;
246 +static struct s3c2410ts ts;
247 +static void __iomem *base_addr;
249 +static inline void s3c2410_ts_connect(void)
251 + s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);
252 + s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);
253 + s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON);
254 + s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);
257 +static void touch_timer_fire(unsigned long data)
259 + unsigned long data0;
260 + unsigned long data1;
263 + data0 = readl(base_addr+S3C2410_ADCDAT0);
264 + data1 = readl(base_addr+S3C2410_ADCDAT1);
266 + updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
269 + if (ts.count != 0) {
270 + ts.xp >>= ts.shift;
271 + ts.yp >>= ts.shift;
273 +#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
276 + do_gettimeofday(&tv);
277 + printk(DEBUG_LVL "T: %06d, X: %03ld, Y: %03ld\n", (int)tv.tv_usec, ts.xp, ts.yp);
281 + input_report_abs(ts.dev, ABS_X, ts.xp);
282 + input_report_abs(ts.dev, ABS_Y, ts.yp);
284 + input_report_key(ts.dev, BTN_TOUCH, 1);
285 + input_report_abs(ts.dev, ABS_PRESSURE, 1);
286 + input_sync(ts.dev);
293 + writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
294 + writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
298 + input_report_key(ts.dev, BTN_TOUCH, 0);
299 + input_report_abs(ts.dev, ABS_PRESSURE, 0);
300 + input_sync(ts.dev);
302 + writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
306 +static struct timer_list touch_timer =
307 + TIMER_INITIALIZER(touch_timer_fire, 0, 0);
309 +static irqreturn_t stylus_updown(int irq, void *dev_id)
311 + unsigned long data0;
312 + unsigned long data1;
315 + data0 = readl(base_addr+S3C2410_ADCDAT0);
316 + data1 = readl(base_addr+S3C2410_ADCDAT1);
318 + updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
320 + /* TODO we should never get an interrupt with updown set while
321 + * the timer is running, but maybe we ought to verify that the
322 + * timer isn't running anyways. */
325 + touch_timer_fire(0);
327 + return IRQ_HANDLED;
331 +static irqreturn_t stylus_action(int irq, void *dev_id)
333 + unsigned long data0;
334 + unsigned long data1;
336 + data0 = readl(base_addr+S3C2410_ADCDAT0);
337 + data1 = readl(base_addr+S3C2410_ADCDAT1);
339 + ts.xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;
340 + ts.yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;
343 + if (ts.count < (1<<ts.shift)) {
344 + writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
345 + writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
347 + mod_timer(&touch_timer, jiffies+1);
348 + writel(WAIT4INT(1), base_addr+S3C2410_ADCTSC);
351 + return IRQ_HANDLED;
354 +static struct clk *adc_clock;
357 + * The functions for inserting/removing us as a module.
360 +static int __init s3c2410ts_probe(struct platform_device *pdev)
363 + struct s3c2410_ts_mach_info *info;
364 + struct input_dev *input_dev;
366 + info = ( struct s3c2410_ts_mach_info *)pdev->dev.platform_data;
370 + printk(KERN_ERR "Hm... too bad : no platform data for ts\n");
374 +#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
375 + printk(DEBUG_LVL "Entering s3c2410ts_init\n");
378 + adc_clock = clk_get(NULL, "adc");
380 + printk(KERN_ERR "failed to get adc clock source\n");
383 + clk_enable(adc_clock);
385 +#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
386 + printk(DEBUG_LVL "got and enabled clock\n");
389 + base_addr = ioremap(S3C2410_PA_ADC,0x20);
390 + if (base_addr == NULL) {
391 + printk(KERN_ERR "Failed to remap register block\n");
396 + /* If we acutally are a S3C2410: Configure GPIOs */
397 + if (!strcmp(pdev->name, "s3c2410-ts"))
398 + s3c2410_ts_connect();
400 + if ((info->presc&0xff) > 0)
401 + writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(info->presc&0xFF),\
402 + base_addr+S3C2410_ADCCON);
404 + writel(0,base_addr+S3C2410_ADCCON);
407 + /* Initialise registers */
408 + if ((info->delay&0xffff) > 0)
409 + writel(info->delay & 0xffff, base_addr+S3C2410_ADCDLY);
411 + writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
413 + /* Initialise input stuff */
414 + memset(&ts, 0, sizeof(struct s3c2410ts));
415 + input_dev = input_allocate_device();
418 + printk(KERN_ERR "Unable to allocate the input device !!\n");
422 + ts.dev = input_dev;
423 + ts.dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) |
425 + ts.dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
426 + input_set_abs_params(ts.dev, ABS_X, 0, 0x3FF, 0, 0);
427 + input_set_abs_params(ts.dev, ABS_Y, 0, 0x3FF, 0, 0);
428 + input_set_abs_params(ts.dev, ABS_PRESSURE, 0, 1, 0, 0);
430 + ts.dev->private = &ts;
431 + ts.dev->name = s3c2410ts_name;
432 + ts.dev->id.bustype = BUS_RS232;
433 + ts.dev->id.vendor = 0xDEAD;
434 + ts.dev->id.product = 0xBEEF;
435 + ts.dev->id.version = S3C2410TSVERSION;
437 + ts.shift = info->oversampling_shift;
440 + if (request_irq(IRQ_ADC, stylus_action, IRQF_SAMPLE_RANDOM,
441 + "s3c2410_action", ts.dev)) {
442 + printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n");
443 + iounmap(base_addr);
446 + if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,
447 + "s3c2410_action", ts.dev)) {
448 + printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n");
449 + free_irq(IRQ_ADC, ts.dev);
450 + iounmap(base_addr);
454 + printk(KERN_INFO "%s successfully loaded\n", s3c2410ts_name);
456 + /* All went ok, so register to the input system */
457 + rc = input_register_device(ts.dev);
459 + free_irq(IRQ_TC, ts.dev);
460 + free_irq(IRQ_ADC, ts.dev);
461 + clk_disable(adc_clock);
462 + iounmap(base_addr);
469 +static int s3c2410ts_remove(struct platform_device *pdev)
471 + disable_irq(IRQ_ADC);
472 + disable_irq(IRQ_TC);
473 + free_irq(IRQ_TC,ts.dev);
474 + free_irq(IRQ_ADC,ts.dev);
477 + clk_disable(adc_clock);
478 + clk_put(adc_clock);
482 + input_unregister_device(ts.dev);
483 + iounmap(base_addr);
489 +static int s3c2410ts_suspend(struct platform_device *pdev, pm_message_t state)
491 + writel(TSC_SLEEP, base_addr+S3C2410_ADCTSC);
492 + writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_STDBM,
493 + base_addr+S3C2410_ADCCON);
495 + disable_irq(IRQ_ADC);
496 + disable_irq(IRQ_TC);
498 + clk_disable(adc_clock);
503 +static int s3c2410ts_resume(struct platform_device *pdev)
505 + struct s3c2410_ts_mach_info *info =
506 + ( struct s3c2410_ts_mach_info *)pdev->dev.platform_data;
508 + clk_enable(adc_clock);
511 + enable_irq(IRQ_ADC);
512 + enable_irq(IRQ_TC);
514 + if ((info->presc&0xff) > 0)
515 + writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(info->presc&0xFF),\
516 + base_addr+S3C2410_ADCCON);
518 + writel(0,base_addr+S3C2410_ADCCON);
520 + /* Initialise registers */
521 + if ((info->delay&0xffff) > 0)
522 + writel(info->delay & 0xffff, base_addr+S3C2410_ADCDLY);
524 + writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
530 +#define s3c2410ts_suspend NULL
531 +#define s3c2410ts_resume NULL
534 +static struct platform_driver s3c2410ts_driver = {
536 + .name = "s3c2410-ts",
537 + .owner = THIS_MODULE,
539 + .probe = s3c2410ts_probe,
540 + .remove = s3c2410ts_remove,
541 + .suspend = s3c2410ts_suspend,
542 + .resume = s3c2410ts_resume,
546 +static struct platform_driver s3c2440ts_driver = {
548 + .name = "s3c2440-ts",
549 + .owner = THIS_MODULE,
551 + .probe = s3c2410ts_probe,
552 + .remove = s3c2410ts_remove,
553 + .suspend = s3c2410ts_suspend,
554 + .resume = s3c2410ts_resume,
558 +static int __init s3c2410ts_init(void)
562 + rc = platform_driver_register(&s3c2410ts_driver);
566 + rc = platform_driver_register(&s3c2440ts_driver);
568 + platform_driver_unregister(&s3c2410ts_driver);
573 +static void __exit s3c2410ts_exit(void)
575 + platform_driver_unregister(&s3c2440ts_driver);
576 + platform_driver_unregister(&s3c2410ts_driver);
579 +module_init(s3c2410ts_init);
580 +module_exit(s3c2410ts_exit);
584 + compile-command: "make ARCH=arm CROSS_COMPILE=/usr/local/arm/3.3.2/bin/arm-linux- -k -C ../../.."
588 diff --git a/include/asm-arm/arch-s3c2410/ts.h b/include/asm-arm/arch-s3c2410/ts.h
590 index 0000000..593632a
592 +++ b/include/asm-arm/arch-s3c2410/ts.h
594 +/* linux/include/asm/arch-s3c2410/ts.h
596 + * Copyright (c) 2005 Arnaud Patard <arnaud.patard@rtp-net.org>
599 + * This program is free software; you can redistribute it and/or modify
600 + * it under the terms of the GNU General Public License version 2 as
601 + * published by the Free Software Foundation.
605 + * 24-Mar-2005 RTP Created file
606 + * 03-Aug-2005 RTP Renamed to ts.h
609 +#ifndef __ASM_ARM_TS_H
610 +#define __ASM_ARM_TS_H
612 +struct s3c2410_ts_mach_info {
615 + int oversampling_shift;
618 +void set_s3c2410ts_info(struct s3c2410_ts_mach_info *hard_s3c2410ts_info);
620 +#endif /* __ASM_ARM_TS_H */
622 diff --git a/include/asm-arm/plat-s3c24xx/devs.h b/include/asm-arm/plat-s3c24xx/devs.h
623 index f9d6f03..43de9cc 100644
624 --- a/include/asm-arm/plat-s3c24xx/devs.h
625 +++ b/include/asm-arm/plat-s3c24xx/devs.h
626 @@ -42,6 +42,7 @@ extern struct platform_device s3c_device_timer2;
627 extern struct platform_device s3c_device_timer3;
629 extern struct platform_device s3c_device_usbgadget;
630 +extern struct platform_device s3c_device_ts;
632 /* s3c2440 specific devices */