2 * Copyright (C) 2003 Joshua Wise
3 * Copyright (c) 2002,2003 SHARP Corporation
4 * Copyright (C) 2005 Pawel Kolodziejski
6 * Use consistent with the GNU GPL is permitted,
7 * provided that this copyright notice is
8 * preserved in its entirety in all copies and derived works.
10 * HAL code based on h5400_asic_io.c, which is
11 * Copyright (C) 2003 Compaq Computer Corporation.
13 * Author: Joshua Wise <joshua at joshuawise.com>
18 #include <linux/module.h>
19 #include <linux/version.h>
20 #include <linux/init.h>
22 #include <linux/interrupt.h>
23 #include <linux/sched.h>
25 #include <linux/device.h>
26 #include <linux/sysctl.h>
27 #include <linux/delay.h>
28 #include <linux/input.h>
29 #include <linux/soc/asic3_base.h>
30 #include <linux/platform_device.h>
32 #include <asm/mach/map.h>
33 #include <asm/mach-types.h>
34 #include <asm/arch/hardware.h>
36 #include <asm/mach/irq.h>
37 #include <asm/arch/pxa-regs.h>
38 #include <asm/arch-pxa/h4000-gpio.h>
39 #include <asm/arch-pxa/h4000-asic.h>
40 #include <asm/hardware/ipaq-asic3.h>
42 #define SAMPLE_TIMEOUT 20 /* sample every 20ms */
44 extern struct platform_device h4000_asic3
;
45 #define asic3 &h4000_asic3.dev
47 static struct timer_list timer_pen
;
48 static struct input_dev
*idev
;
50 static spinlock_t ts_lock
;
51 static int irq_disable
;
52 static int touch_pressed
;
54 static void report_touchpanel(int x
, int y
, int pressure
)
56 input_report_key(idev
, BTN_TOUCH
, pressure
!= 0);
57 input_report_abs(idev
, ABS_PRESSURE
, pressure
);
58 input_report_abs(idev
, ABS_X
, x
);
59 input_report_abs(idev
, ABS_Y
, y
);
63 #define CTRL_START 0x80
64 #define CTRL_YPOS 0x10
65 #define CTRL_Z1POS 0x30
66 #define CTRL_Z2POS 0x40
67 #define CTRL_XPOS 0x50
68 #define CTRL_TEMP0 0x04
69 #define CTRL_TEMP1 0x74
70 #define CTRL_VBAT 0x24
71 #define CTRL_AUX_N 0x64
75 #define SSSR_TNF_MSK (1u << 2)
76 #define SSSR_RNE_MSK (1u << 3)
78 unsigned long h4000_spi_putget(ulong data
)
80 unsigned long ret
, flags
;
83 spin_lock_irqsave(&ts_lock
, flags
);
88 while ((SSSR
& SSSR_TNF_MSK
) != SSSR_TNF_MSK
&& --timeout
);
90 printk("%s: warning: timeout while waiting for SSSR_TNF_MSK\n", __FUNCTION__
);
96 while ((SSSR
& SSSR_RNE_MSK
) != SSSR_RNE_MSK
&& --timeout
);
98 printk("%s: warning: timeout while waiting for SSSR_RNE_MSK\n", __FUNCTION__
);
102 spin_unlock_irqrestore(&ts_lock
, flags
);
106 #define ADSCTRL_ADR_SH 4 // Address setting
108 typedef struct ts_pos_s
{
113 void read_xydata(ts_pos_t
*tp
)
115 #define abscmpmin(x,y,d) ( ((int)((x) - (y)) < (int)(d)) && ((int)((y) - (x)) < (int)(d)) )
117 unsigned int t
, x
, y
, z
[2];
118 unsigned long pressure
;
123 for(i
= j
= k
= 0, x
= y
= 0;; i
= 1) {
125 cmd
= CTRL_PD0
| CTRL_PD1
| CTRL_START
| CTRL_Z1POS
;
126 t
= h4000_spi_putget(cmd
);
127 z
[i
] = h4000_spi_putget(cmd
);
133 cmd
= CTRL_PD0
| CTRL_PD1
| CTRL_START
| CTRL_XPOS
;
134 x
= h4000_spi_putget(cmd
);
135 for(j
= 0; !err
; j
++) {
137 x
= h4000_spi_putget(cmd
);
138 if (abscmpmin(t
, x
, d
))
142 //printk("ts: x(%d,%d,%d)\n", t, x, t - x);
147 cmd
= CTRL_PD0
| CTRL_PD1
| CTRL_START
| CTRL_YPOS
;
148 y
= h4000_spi_putget(cmd
);
149 for (k
= 0; !err
; k
++) {
151 y
= h4000_spi_putget(cmd
);
152 if (abscmpmin(t
,y
, d
))
156 //printk("ts: y(%d,%d,%d)\n", t, y, t - y);
161 for (i
= 0; i
< 2; i
++) {
166 for (i
= 0; i
< 2; i
++){
174 cmd
&= ~(CTRL_PD0
| CTRL_PD1
);
175 t
= h4000_spi_putget(cmd
);
177 if (err
== 0 && pressure
!= 0) {
178 //printk("ts: pxyp=%d(%d/%d,%d/%d)%d\n", z[0], x, j, y, k, z[1]);
180 //printk("pxype=%d,%d,%d,%d\n", z[0], x, y, z[1]);
187 static irqreturn_t
h4000_stylus(int irq
, void* data
)
191 if (irq
== IRQ_GPIO(GPIO_NR_H4000_PEN_IRQ_N
) && irq_disable
== 0) {
194 disable_irq(IRQ_GPIO(GPIO_NR_H4000_PEN_IRQ_N
));
197 read_xydata(&ts_pos
);
199 if (ts_pos
.xd
== 0 || ts_pos
.yd
== 0) {
200 report_touchpanel(0, 0, 0);
201 //printk("touch released\n");
202 if (irq_disable
== 1) {
203 enable_irq(IRQ_GPIO(GPIO_NR_H4000_PEN_IRQ_N
));
209 //printk("%04d %04d\n", (int)ts_pos.xd, (int)ts_pos.yd);
210 //printk("touch pressed\n");
211 report_touchpanel(ts_pos
.xd
, ts_pos
.yd
, 1);
213 mod_timer(&timer_pen
, jiffies
+ (SAMPLE_TIMEOUT
* HZ
) / 1000);
215 //printk("callback\n");
219 static void h4000_ts_timer(unsigned long nr
)
221 h4000_stylus(0, NULL
);
224 void h4000_ts_init_chip(void)
226 /* now to set up GPIOs... */
227 GPDR(GPIO23_SCLK
) |= GPIO_bit(GPIO23_SCLK
);
228 GPDR(GPIO24_SFRM
) |= GPIO_bit(GPIO24_SFRM
);
229 GPDR(GPIO25_STXD
) |= GPIO_bit(GPIO25_STXD
);
230 GPDR(GPIO26_SRXD
) &= ~GPIO_bit(GPIO26_SRXD
);
231 pxa_gpio_mode(GPIO23_SCLK_MD
);
232 pxa_gpio_mode(GPIO24_SFRM_MD
);
233 pxa_gpio_mode(GPIO25_STXD_MD
);
234 pxa_gpio_mode(GPIO26_SRXD_MD
);
237 SSCR0
|= 0xB; /* 12 bits */
238 SSCR0
|= SSCR0_National
;
239 SSCR0
|= 0x1100; /* 100 mhz */
245 h4000_spi_putget(CTRL_YPOS
| CTRL_START
);
247 h4000_spi_putget(CTRL_Z1POS
| CTRL_START
);
249 h4000_spi_putget(CTRL_Z2POS
| CTRL_START
);
251 h4000_spi_putget(CTRL_XPOS
| CTRL_START
);
255 int h4000_spi_init(void)
257 if (!machine_is_h4000()) {
261 h4000_ts_init_chip();
263 init_timer(&timer_pen
);
264 timer_pen
.function
= h4000_ts_timer
;
265 timer_pen
.data
= (unsigned long)NULL
;
267 idev
= input_allocate_device();
271 idev
->name
= "ads7876";
272 idev
->phys
= "touchscreen/ads7876";
274 set_bit(EV_ABS
, idev
->evbit
);
275 set_bit(EV_KEY
, idev
->evbit
);
276 set_bit(ABS_X
, idev
->absbit
);
277 set_bit(ABS_Y
, idev
->absbit
);
278 set_bit(ABS_PRESSURE
, idev
->absbit
);
279 set_bit(BTN_TOUCH
, idev
->keybit
);
280 idev
->absmin
[ABS_PRESSURE
] = 0;
281 idev
->absmax
[ABS_PRESSURE
] = 1;
282 idev
->absmin
[ABS_X
] = 190;
283 idev
->absmax
[ABS_X
] = 1860;
284 idev
->absmin
[ABS_Y
] = 150;
285 idev
->absmax
[ABS_Y
] = 1880;
287 input_register_device(idev
);
289 spin_lock_init(&ts_lock
);
293 set_irq_type(IRQ_GPIO(GPIO_NR_H4000_PEN_IRQ_N
), IRQT_FALLING
);
294 request_irq(IRQ_GPIO(GPIO_NR_H4000_PEN_IRQ_N
), h4000_stylus
, SA_SAMPLE_RANDOM
, "stylus", NULL
);
299 static int h4000_ts_probe(struct platform_device
*dev
)
307 static int h4000_ts_resume(struct platform_device
*dev
)
309 h4000_ts_init_chip();
314 #define h4000_ts_resume NULL
317 static struct platform_driver h4000_ts_driver
= {
321 .probe
= h4000_ts_probe
,
324 .resume
= h4000_ts_resume
,
328 static int __init
h4000_ts_init(void)
330 if (!machine_is_h4000())
333 return platform_driver_register(&h4000_ts_driver
);
336 static void __exit
h4000_ts_exit(void)
338 del_timer_sync(&timer_pen
);
340 free_irq(IRQ_GPIO(GPIO_NR_H4000_PEN_IRQ_N
), NULL
);
344 input_unregister_device(idev
);
346 platform_driver_unregister(&h4000_ts_driver
);
349 module_init(h4000_ts_init
)
350 module_exit(h4000_ts_exit
)
352 EXPORT_SYMBOL(h4000_spi_putget
);
354 MODULE_AUTHOR("Joshua Wise, Pawel Kolodziejski");
355 MODULE_DESCRIPTION("Touchscreen support for the iPAQ h4xxx");
356 MODULE_LICENSE("GPL");