hh.org updates
[hh.org.git] / arch / arm / mach-pxa / h4000 / h4000_ts.c
blob10df3a0a4b3a56ef2f48e8e755cb447ae0479994
1 /*
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>
14 * June 2003
18 #include <linux/module.h>
19 #include <linux/version.h>
20 #include <linux/init.h>
21 #include <linux/fs.h>
22 #include <linux/interrupt.h>
23 #include <linux/sched.h>
24 #include <linux/pm.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>
35 #include <asm/irq.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);
60 input_sync(idev);
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
72 #define CTRL_PD0 0x01
73 #define CTRL_PD1 0x02
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;
81 int timeout;
83 spin_lock_irqsave(&ts_lock, flags);
85 SSDR = data;
87 timeout = 100000;
88 while ((SSSR & SSSR_TNF_MSK) != SSSR_TNF_MSK && --timeout);
89 if (timeout == 0) {
90 printk("%s: warning: timeout while waiting for SSSR_TNF_MSK\n", __FUNCTION__);
93 udelay(1);
95 timeout = 100000;
96 while ((SSSR & SSSR_RNE_MSK) != SSSR_RNE_MSK && --timeout);
97 if (timeout == 0) {
98 printk("%s: warning: timeout while waiting for SSSR_RNE_MSK\n", __FUNCTION__);
101 ret = (SSDR);
102 spin_unlock_irqrestore(&ts_lock, flags);
103 return ret;
106 #define ADSCTRL_ADR_SH 4 // Address setting
108 typedef struct ts_pos_s {
109 unsigned long xd;
110 unsigned long yd;
111 } ts_pos_t;
113 void read_xydata(ts_pos_t *tp)
115 #define abscmpmin(x,y,d) ( ((int)((x) - (y)) < (int)(d)) && ((int)((y) - (x)) < (int)(d)) )
116 unsigned long cmd;
117 unsigned int t, x, y, z[2];
118 unsigned long pressure;
119 int i,j,k;
120 int d = 8, c = 10;
121 int err = 0;
123 for(i = j = k = 0, x = y = 0;; i = 1) {
124 /* Pressure */
125 cmd = CTRL_PD0 | CTRL_PD1 | CTRL_START | CTRL_Z1POS;
126 t = h4000_spi_putget(cmd);
127 z[i] = h4000_spi_putget(cmd);
129 if (i)
130 break;
132 /* X-axis */
133 cmd = CTRL_PD0 | CTRL_PD1 | CTRL_START | CTRL_XPOS;
134 x = h4000_spi_putget(cmd);
135 for(j = 0; !err; j++) {
136 t = x;
137 x = h4000_spi_putget(cmd);
138 if (abscmpmin(t, x, d))
139 break;
140 if (j > c) {
141 err = 1;
142 //printk("ts: x(%d,%d,%d)\n", t, x, t - x);
146 /* Y-axis */
147 cmd = CTRL_PD0 | CTRL_PD1 | CTRL_START | CTRL_YPOS;
148 y = h4000_spi_putget(cmd);
149 for (k = 0; !err; k++) {
150 t = y;
151 y = h4000_spi_putget(cmd);
152 if (abscmpmin(t ,y , d))
153 break;
154 if (k > c) {
155 err = 1;
156 //printk("ts: y(%d,%d,%d)\n", t, y, t - y);
160 pressure = 1;
161 for (i = 0; i < 2; i++) {
162 if (!z[i])
163 pressure = 0;
165 if (pressure) {
166 for (i = 0; i < 2; i++){
167 if (z[i] < 10)
168 err = 1;
170 if (x >= 4095)
171 err = 1;
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]);
179 } else {
180 //printk("pxype=%d,%d,%d,%d\n", z[0], x, y, z[1]);
181 x = 0; y = 0;
183 tp->xd = x;
184 tp->yd = y;
187 static irqreturn_t h4000_stylus(int irq, void* data)
189 ts_pos_t ts_pos;
191 if (irq == IRQ_GPIO(GPIO_NR_H4000_PEN_IRQ_N) && irq_disable == 0) {
192 //printk("IRQ\n");
193 irq_disable = 1;
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));
204 irq_disable = 0;
206 return IRQ_HANDLED;
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");
216 return IRQ_HANDLED;
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);
236 SSCR0 = 0;
237 SSCR0 |= 0xB; /* 12 bits */
238 SSCR0 |= SSCR0_National;
239 SSCR0 |= 0x1100; /* 100 mhz */
241 SSCR1 = 0;
243 SSCR0 |= SSCR0_SSE;
245 h4000_spi_putget(CTRL_YPOS | CTRL_START);
246 mdelay(5);
247 h4000_spi_putget(CTRL_Z1POS | CTRL_START);
248 mdelay(5);
249 h4000_spi_putget(CTRL_Z2POS | CTRL_START);
250 mdelay(5);
251 h4000_spi_putget(CTRL_XPOS | CTRL_START);
252 mdelay(5);
255 int h4000_spi_init(void)
257 if (!machine_is_h4000()) {
258 return -ENODEV;
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();
268 if (!idev)
269 return -ENOMEM;
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);
291 touch_pressed = 0;
292 irq_disable = 0;
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);
296 return 0;
299 static int h4000_ts_probe(struct platform_device *dev)
301 h4000_spi_init();
303 return 0;
306 #ifdef CONFIG_PM
307 static int h4000_ts_resume(struct platform_device *dev)
309 h4000_ts_init_chip();
311 return 0;
313 #else
314 #define h4000_ts_resume NULL
315 #endif
317 static struct platform_driver h4000_ts_driver = {
318 .driver = {
319 .name = "h4000_ts",
321 .probe = h4000_ts_probe,
322 #ifdef CONFIG_PM
323 .suspend = NULL,
324 .resume = h4000_ts_resume,
325 #endif
328 static int __init h4000_ts_init(void)
330 if (!machine_is_h4000())
331 return -ENODEV;
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);
342 SSCR0 &= ~SSCR0_SSE;
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");