hh.org updates
[hh.org.git] / arch / arm / mach-pxa / h1900 / h1900_ssp.c
blobecff66712b3bf6276a17e368126f140ef6ced467
1 /*
2 * Touchscreen and battery driver for iPAQ h1910/h1915
4 * Copyright (C) 2005-2006 Pawel Kolodziejski
5 * Copyright (c) 2002,2003 SHARP Corporation
6 * Copyright (C) 2003 Joshua Wise
8 * Use consistent with the GNU GPL is permitted,
9 * provided that this copyright notice is
10 * preserved in its entirety in all copies and derived works.
14 #include <linux/module.h>
15 #include <linux/version.h>
16 #include <linux/config.h>
17 #include <linux/init.h>
18 #include <linux/fs.h>
19 #include <linux/interrupt.h>
20 #include <linux/sched.h>
21 #include <linux/pm.h>
22 #include <linux/device.h>
23 #include <linux/sysctl.h>
24 #include <linux/proc_fs.h>
25 #include <linux/delay.h>
26 #include <linux/input.h>
27 #include <linux/soc/asic3_base.h>
28 #include <linux/platform_device.h>
30 #include <asm/mach/map.h>
31 #include <asm/mach-types.h>
32 #include <asm/arch/hardware.h>
33 #include <asm/irq.h>
34 #include <asm/mach/irq.h>
35 #include <asm/arch/pxa-regs.h>
36 #include <asm/arch/ssp.h>
37 #include <asm/arch-pxa/h1900-gpio.h>
38 #include <asm/arch-pxa/h1900-asic.h>
39 #include <asm/hardware/ipaq-asic3.h>
41 static spinlock_t h1900_ssp_lock = SPIN_LOCK_UNLOCKED;
42 static struct ssp_dev h1900_ssp_dev;
43 static struct ssp_state h1900_ssp_state;
45 unsigned long h1900_ssp_putget(ulong data)
47 unsigned long flag;
48 u32 ret;
50 spin_lock_irqsave(&h1900_ssp_lock, flag);
52 ssp_write_word(&h1900_ssp_dev, data);
53 ssp_read_word(&h1900_ssp_dev, &ret);
55 spin_unlock_irqrestore(&h1900_ssp_lock, flag);
57 return ret;
60 #define SAMPLE_TIMEOUT 20
62 static struct timer_list timer_pen;
63 static struct input_dev *idev;
65 static int touch_pressed;
66 static int irq_disable;
68 static void report_touchpanel(int x, int y, int pressure)
70 input_report_key(idev, BTN_TOUCH, pressure != 0);
71 input_report_abs(idev, ABS_PRESSURE, pressure);
72 input_report_abs(idev, ABS_X, x);
73 input_report_abs(idev, ABS_Y, y);
74 input_sync(idev);
77 #define CTRL_START 0x80
78 #define CTRL_YPOS 0x10
79 #define CTRL_Z1POS 0x30
80 #define CTRL_Z2POS 0x40
81 #define CTRL_XPOS 0x50
82 #define CTRL_TEMP0 0x04
83 #define CTRL_TEMP1 0x74
84 #define CTRL_VBAT 0x24
85 #define CTRL_AUX 0x64
86 #define CTRL_PD0 0x01
87 #define CTRL_PD1 0x02
89 #define ADSCTRL_ADR_SH 4
91 typedef struct ts_pos_s {
92 unsigned long xd;
93 unsigned long yd;
94 } ts_pos_t;
96 void read_xydata(ts_pos_t *tp)
98 #define abscmpmin(x,y,d) ( ((int)((x) - (y)) < (int)(d)) && ((int)((y) - (x)) < (int)(d)) )
99 unsigned long cmd;
100 unsigned int t, x, y, z[2];
101 unsigned long pressure;
102 int i, j, k;
103 int d = 8, c = 10;
104 int err = 0;
106 for (i = j = k = 0, x = y = 0;; i = 1) {
107 // Pressure
108 cmd = CTRL_PD0 | CTRL_PD1 | CTRL_START | CTRL_Z1POS;
109 t = h1900_ssp_putget(cmd);
110 z[i] = h1900_ssp_putget(cmd);
112 if (i)
113 break;
115 // X-axis
116 cmd = CTRL_PD0 | CTRL_PD1 | CTRL_START | CTRL_XPOS;
117 x = h1900_ssp_putget(cmd);
118 for (j = 0; !err; j++) {
119 t = x;
120 x = h1900_ssp_putget(cmd);
121 if (abscmpmin(t, x, d))
122 break;
123 if (j > c) {
124 err = 1;
125 //printk("ts: x(%d,%d,%d)\n", t, x, t - x);
129 // Y-axis
130 cmd = CTRL_PD0 | CTRL_PD1 | CTRL_START | CTRL_YPOS;
131 y = h1900_ssp_putget(cmd);
132 for (k = 0; !err; k++) {
133 t = y;
134 y = h1900_ssp_putget(cmd);
135 if (abscmpmin(t ,y , d))
136 break;
137 if (k > c) {
138 err = 1;
139 //printk("ts: y(%d,%d,%d)\n", t, y, t - y);
143 pressure = 1;
144 for (i = 0; i < 2; i++) {
145 if (!z[i])
146 pressure = 0;
148 if (pressure) {
149 for (i = 0; i < 2; i++){
150 if (z[i] < 10)
151 err = 1;
153 if (x >= 4095)
154 err = 1;
157 cmd &= ~(CTRL_PD0 | CTRL_PD1);
158 t = h1900_ssp_putget(cmd);
160 if (err == 0 && pressure != 0) {
161 //printk("ts: pxyp=%d(%d/%d,%d/%d)%d\n", z[0], x, j, y, k, z[1]);
162 } else {
163 //printk("pxype=%d,%d,%d,%d\n", z[0], x, y, z[1]);
164 x = 0; y = 0;
166 tp->xd = x;
167 tp->yd = y;
170 static irqreturn_t h1900_stylus(int irq, void *data, struct pt_regs *regs)
172 ts_pos_t ts_pos;
174 if (irq == IRQ_GPIO(GPIO_NR_H1900_PEN_IRQ_N) && irq_disable == 0) {
175 //printk("IRQ\n");
176 irq_disable = 1;
177 disable_irq(IRQ_GPIO(GPIO_NR_H1900_PEN_IRQ_N));
180 read_xydata(&ts_pos);
182 if (ts_pos.xd == 0 || ts_pos.yd == 0) {
183 report_touchpanel(0, 0, 0);
184 //printk("touch released\n");
185 if (irq_disable == 1) {
186 request_irq(IRQ_GPIO(GPIO_NR_H1900_PEN_IRQ_N), h1900_stylus, SA_SAMPLE_RANDOM, "ads7876 stylus", NULL);
187 set_irq_type(IRQ_GPIO(GPIO_NR_H1900_PEN_IRQ_N), IRQT_FALLING);
188 enable_irq(IRQ_GPIO(GPIO_NR_H1900_PEN_IRQ_N));
189 irq_disable = 0;
191 return IRQ_HANDLED;
194 //printk("%04d %04d\n", (int)ts_pos.xd, (int)ts_pos.yd);
195 //printk("touch pressed\n");
196 report_touchpanel(ts_pos.xd, ts_pos.yd, 1);
198 mod_timer(&timer_pen, jiffies + (SAMPLE_TIMEOUT * HZ) / 1000);
200 //printk("callback\n");
201 return IRQ_HANDLED;
204 static void h1900_ts_timer(unsigned long nr)
206 h1900_stylus(-1, NULL, NULL);
209 static int __init h1900_ssp_probe(struct device *dev)
211 int ret;
213 if (!machine_is_h1900()) {
214 return -ENODEV;
217 ret = ssp_init(&h1900_ssp_dev, 1, 0);
219 if (ret) {
220 printk(KERN_ERR "Unable to register SSP handler!\n");
221 return ret;
222 } else {
223 ssp_disable(&h1900_ssp_dev);
224 ssp_config(&h1900_ssp_dev, (SSCR0_National | 0x0b), 0, 0, SSCR0_SerClkDiv(36));
225 ssp_enable(&h1900_ssp_dev);
228 h1900_ssp_putget(CTRL_YPOS | CTRL_START);
229 mdelay(1);
230 h1900_ssp_putget(CTRL_Z1POS | CTRL_START);
231 mdelay(1);
232 h1900_ssp_putget(CTRL_Z2POS | CTRL_START);
233 mdelay(1);
234 h1900_ssp_putget(CTRL_XPOS | CTRL_START);
236 init_timer(&timer_pen);
237 timer_pen.function = h1900_ts_timer;
238 timer_pen.data = (unsigned long)NULL;
240 idev = input_allocate_device();
241 if (!idev)
242 return -ENOMEM;
244 idev->name = "ads7876";
245 idev->phys = "touchscreen/ads7876";
247 set_bit(EV_ABS, idev->evbit);
248 set_bit(EV_KEY, idev->evbit);
249 set_bit(ABS_X, idev->absbit);
250 set_bit(ABS_Y, idev->absbit);
251 set_bit(ABS_PRESSURE, idev->absbit);
252 set_bit(BTN_TOUCH, idev->keybit);
253 idev->absmax[ABS_PRESSURE] = 1;
254 idev->absmin[ABS_X] = 190;
255 idev->absmax[ABS_X] = 1860;
256 idev->absmin[ABS_Y] = 150;
257 idev->absmax[ABS_Y] = 1880;
259 input_register_device(idev);
261 touch_pressed = 0;
262 irq_disable = 0;
264 set_irq_type(IRQ_GPIO(GPIO_NR_H1900_PEN_IRQ_N), IRQT_FALLING);
265 request_irq(IRQ_GPIO(GPIO_NR_H1900_PEN_IRQ_N), h1900_stylus, SA_SAMPLE_RANDOM, "ads7876 stylus", NULL);
267 return 0;
270 #ifdef CONFIG_PM
271 static int h1900_ssp_suspend(struct device *dev, pm_message_t state)
273 del_timer_sync(&timer_pen);
275 disable_irq(IRQ_GPIO(GPIO_NR_H1900_PEN_IRQ_N));
277 ssp_flush(&h1900_ssp_dev);
278 ssp_save_state(&h1900_ssp_dev, &h1900_ssp_state);
280 return 0;
283 static int h1900_ssp_resume(struct device *dev)
285 ssp_restore_state(&h1900_ssp_dev, &h1900_ssp_state);
286 ssp_enable(&h1900_ssp_dev);
288 irq_disable = 0;
289 touch_pressed = 0;
290 enable_irq(IRQ_GPIO(GPIO_NR_H1900_PEN_IRQ_N));
292 return 0;
295 static int h1900_ssp_remove(struct device *dev)
297 del_timer_sync(&timer_pen);
299 free_irq(IRQ_GPIO(GPIO_NR_H1900_PEN_IRQ_N), NULL);
301 ssp_exit(&h1900_ssp_dev);
303 input_unregister_device(idev);
304 input_free_device(idev);
306 return 0;
308 #endif
310 static struct device_driver h1900_ssp_driver = {
311 .name = "h1900-ssp",
312 .bus = &platform_bus_type,
313 .probe = h1900_ssp_probe,
314 .remove = h1900_ssp_remove,
315 #ifdef CONFIG_PM
316 .suspend = h1900_ssp_suspend,
317 .resume = h1900_ssp_resume,
318 #endif
321 static int __init h1900_ssp_init(void)
323 if (!machine_is_h1900())
324 return -ENODEV;
326 return driver_register(&h1900_ssp_driver);
329 static void __exit h1900_ssp_exit(void)
331 driver_unregister(&h1900_ssp_driver);
334 module_init(h1900_ssp_init)
335 module_exit(h1900_ssp_exit)
337 MODULE_AUTHOR("Joshua Wise, Pawel Kolodziejski");
338 MODULE_DESCRIPTION("SSP touchscreen support for the iPAQ h1910/h1915");
339 MODULE_LICENSE("GPL");