[PATCH] SharpSL: Add cxx00 support to the Corgi LCD driver
[safe/jmp/linux-2.6] / drivers / input / touchscreen / corgi_ts.c
1 /*
2  *  Touchscreen driver for Sharp Corgi models (SL-C7xx)
3  *
4  *  Copyright (c) 2004-2005 Richard Purdie
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License version 2 as
8  *  published by the Free Software Foundation.
9  *
10  */
11
12
13 #include <linux/delay.h>
14 #include <linux/device.h>
15 #include <linux/init.h>
16 #include <linux/input.h>
17 #include <linux/interrupt.h>
18 #include <linux/module.h>
19 #include <linux/slab.h>
20 #include <asm/irq.h>
21
22 #include <asm/arch/corgi.h>
23 #include <asm/arch/hardware.h>
24 #include <asm/arch/pxa-regs.h>
25
26
27 #define PWR_MODE_ACTIVE         0
28 #define PWR_MODE_SUSPEND        1
29
30 #define X_AXIS_MAX              3830
31 #define X_AXIS_MIN              150
32 #define Y_AXIS_MAX              3830
33 #define Y_AXIS_MIN              190
34 #define PRESSURE_MIN            0
35 #define PRESSURE_MAX            15000
36
37 struct ts_event {
38         short pressure;
39         short x;
40         short y;
41 };
42
43 struct corgi_ts {
44         char phys[32];
45         struct input_dev input;
46         struct timer_list timer;
47         struct ts_event tc;
48         int pendown;
49         int power_mode;
50 };
51
52 #define STATUS_HSYNC            (GPLR(CORGI_GPIO_HSYNC) & GPIO_bit(CORGI_GPIO_HSYNC))
53
54 #define SyncHS()        while((STATUS_HSYNC) == 0); while((STATUS_HSYNC) != 0);
55 #define CCNT(a)         asm volatile ("mrc p14, 0, %0, C1, C0, 0" : "=r"(a))
56 #define PMNC_GET(x)     asm volatile ("mrc p14, 0, %0, C0, C0, 0" : "=r"(x))
57 #define PMNC_SET(x)     asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(x))
58
59
60 /* ADS7846 Touch Screen Controller bit definitions */
61 #define ADSCTRL_PD0             (1u << 0)       /* PD0 */
62 #define ADSCTRL_PD1             (1u << 1)       /* PD1 */
63 #define ADSCTRL_DFR             (1u << 2)       /* SER/DFR */
64 #define ADSCTRL_MOD             (1u << 3)       /* Mode */
65 #define ADSCTRL_ADR_SH  4       /* Address setting */
66 #define ADSCTRL_STS             (1u << 7)       /* Start Bit */
67
68 /* External Functions */
69 extern unsigned long w100fb_get_hsynclen(struct device *dev);
70 extern unsigned int get_clk_frequency_khz(int info);
71
72 static unsigned long calc_waittime(void)
73 {
74         unsigned long hsync_len = w100fb_get_hsynclen(&corgifb_device.dev);
75
76         if (hsync_len)
77                 return get_clk_frequency_khz(0)*1000/hsync_len;
78         else
79                 return 0;
80 }
81
82 static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int address, unsigned long wait_time)
83 {
84         unsigned long timer1 = 0, timer2, pmnc = 0;
85         int pos = 0;
86
87         if (wait_time && doSend) {
88                 PMNC_GET(pmnc);
89                 if (!(pmnc & 0x01))
90                         PMNC_SET(0x01);
91
92                 /* polling HSync */
93                 SyncHS();
94                 /* get CCNT */
95                 CCNT(timer1);
96         }
97
98         if (doRecive)
99                 pos = corgi_ssp_ads7846_get();
100
101         if (doSend) {
102                 int cmd = ADSCTRL_PD0 | ADSCTRL_PD1 | (address << ADSCTRL_ADR_SH) | ADSCTRL_STS;
103                 /* dummy command */
104                 corgi_ssp_ads7846_put(cmd);
105                 corgi_ssp_ads7846_get();
106
107                 if (wait_time) {
108                         /* Wait after HSync */
109                         CCNT(timer2);
110                         if (timer2-timer1 > wait_time) {
111                                 /* too slow - timeout, try again */
112                                 SyncHS();
113                                 /* get OSCR */
114                                 CCNT(timer1);
115                                 /* Wait after HSync */
116                                 CCNT(timer2);
117                         }
118                         while (timer2 - timer1 < wait_time)
119                                 CCNT(timer2);
120                 }
121                 corgi_ssp_ads7846_put(cmd);
122                 if (wait_time && !(pmnc & 0x01))
123                         PMNC_SET(pmnc);
124         }
125         return pos;
126 }
127
128 static int read_xydata(struct corgi_ts *corgi_ts)
129 {
130         unsigned int x, y, z1, z2;
131         unsigned long flags, wait_time;
132
133         /* critical section */
134         local_irq_save(flags);
135         corgi_ssp_ads7846_lock();
136         wait_time=calc_waittime();
137
138         /* Y-axis */
139         sync_receive_data_send_cmd(0, 1, 1u, wait_time);
140
141         /* Y-axis */
142         sync_receive_data_send_cmd(1, 1, 1u, wait_time);
143
144         /* X-axis */
145         y = sync_receive_data_send_cmd(1, 1, 5u, wait_time);
146
147         /* Z1 */
148         x = sync_receive_data_send_cmd(1, 1, 3u, wait_time);
149
150         /* Z2 */
151         z1 = sync_receive_data_send_cmd(1, 1, 4u, wait_time);
152         z2 = sync_receive_data_send_cmd(1, 0, 4u, wait_time);
153
154         /* Power-Down Enable */
155         corgi_ssp_ads7846_put((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
156         corgi_ssp_ads7846_get();
157
158         corgi_ssp_ads7846_unlock();
159         local_irq_restore(flags);
160
161         if (x== 0 || y == 0 || z1 == 0 || (x * (z2 - z1) / z1) >= 15000) {
162                 corgi_ts->tc.pressure = 0;
163                 return 0;
164         }
165
166         corgi_ts->tc.x = x;
167         corgi_ts->tc.y = y;
168         corgi_ts->tc.pressure = (x * (z2 - z1)) / z1;
169         return 1;
170 }
171
172 static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs)
173 {
174         if (corgi_ts->power_mode != PWR_MODE_ACTIVE)
175                 return;
176
177         if (!corgi_ts->tc.pressure && corgi_ts->pendown == 0)
178                 return;
179
180         if (regs)
181                 input_regs(&corgi_ts->input, regs);
182
183         input_report_abs(&corgi_ts->input, ABS_X, corgi_ts->tc.x);
184         input_report_abs(&corgi_ts->input, ABS_Y, corgi_ts->tc.y);
185         input_report_abs(&corgi_ts->input, ABS_PRESSURE, corgi_ts->tc.pressure);
186         input_report_key(&corgi_ts->input, BTN_TOUCH, (corgi_ts->pendown != 0));
187         input_sync(&corgi_ts->input);
188 }
189
190 static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_regs *regs)
191 {
192         if ((GPLR(CORGI_GPIO_TP_INT) & GPIO_bit(CORGI_GPIO_TP_INT)) == 0) {
193                 /* Disable Interrupt */
194                 set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_NOEDGE);
195                 if (read_xydata(corgi_ts)) {
196                         corgi_ts->pendown = 1;
197                         new_data(corgi_ts, regs);
198                 }
199                 mod_timer(&corgi_ts->timer, jiffies + HZ / 100);
200         } else {
201                 if (corgi_ts->pendown == 1 || corgi_ts->pendown == 2) {
202                         mod_timer(&corgi_ts->timer, jiffies + HZ / 100);
203                         corgi_ts->pendown++;
204                         return;
205                 }
206
207                 if (corgi_ts->pendown) {
208                         corgi_ts->tc.pressure = 0;
209                         new_data(corgi_ts, regs);
210                 }
211
212                 /* Enable Falling Edge */
213                 set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
214                 corgi_ts->pendown = 0;
215         }
216 }
217
218 static void corgi_ts_timer(unsigned long data)
219 {
220         struct corgi_ts *corgits_data = (struct corgi_ts *) data;
221         ts_interrupt_main(corgits_data, 1, NULL);
222 }
223
224 static irqreturn_t ts_interrupt(int irq, void *dev_id, struct pt_regs *regs)
225 {
226         struct corgi_ts *corgits_data = dev_id;
227         ts_interrupt_main(corgits_data, 0, regs);
228         return IRQ_HANDLED;
229 }
230
231 #ifdef CONFIG_PM
232 static int corgits_suspend(struct device *dev, pm_message_t state, uint32_t level)
233 {
234         if (level == SUSPEND_POWER_DOWN) {
235                 struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
236
237                 if (corgi_ts->pendown) {
238                         del_timer_sync(&corgi_ts->timer);
239                         corgi_ts->tc.pressure = 0;
240                         new_data(corgi_ts, NULL);
241                         corgi_ts->pendown = 0;
242                 }
243                 corgi_ts->power_mode = PWR_MODE_SUSPEND;
244
245                 corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
246         }
247         return 0;
248 }
249
250 static int corgits_resume(struct device *dev, uint32_t level)
251 {
252         if (level == RESUME_POWER_ON) {
253                 struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
254
255                 corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
256                 /* Enable Falling Edge */
257                 set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
258                 corgi_ts->power_mode = PWR_MODE_ACTIVE;
259         }
260         return 0;
261 }
262 #else
263 #define corgits_suspend         NULL
264 #define corgits_resume          NULL
265 #endif
266
267 static int __init corgits_probe(struct device *dev)
268 {
269         struct corgi_ts *corgi_ts;
270
271         if (!(corgi_ts = kmalloc(sizeof(struct corgi_ts), GFP_KERNEL)))
272                 return -ENOMEM;
273
274         dev_set_drvdata(dev, corgi_ts);
275
276         memset(corgi_ts, 0, sizeof(struct corgi_ts));
277
278         init_input_dev(&corgi_ts->input);
279         corgi_ts->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
280         corgi_ts->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
281         input_set_abs_params(&corgi_ts->input, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
282         input_set_abs_params(&corgi_ts->input, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
283         input_set_abs_params(&corgi_ts->input, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0);
284
285         strcpy(corgi_ts->phys, "corgits/input0");
286
287         corgi_ts->input.private = corgi_ts;
288         corgi_ts->input.name = "Corgi Touchscreen";
289         corgi_ts->input.dev = dev;
290         corgi_ts->input.phys = corgi_ts->phys;
291         corgi_ts->input.id.bustype = BUS_HOST;
292         corgi_ts->input.id.vendor = 0x0001;
293         corgi_ts->input.id.product = 0x0002;
294         corgi_ts->input.id.version = 0x0100;
295
296         pxa_gpio_mode(CORGI_GPIO_TP_INT | GPIO_IN);
297         pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
298
299         /* Initiaize ADS7846 Difference Reference mode */
300         corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
301         mdelay(5);
302         corgi_ssp_ads7846_putget((3u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
303         mdelay(5);
304         corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
305         mdelay(5);
306         corgi_ssp_ads7846_putget((5u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
307         mdelay(5);
308
309         init_timer(&corgi_ts->timer);
310         corgi_ts->timer.data = (unsigned long) corgi_ts;
311         corgi_ts->timer.function = corgi_ts_timer;
312
313         input_register_device(&corgi_ts->input);
314         corgi_ts->power_mode = PWR_MODE_ACTIVE;
315
316         if (request_irq(CORGI_IRQ_GPIO_TP_INT, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) {
317                 input_unregister_device(&corgi_ts->input);
318                 kfree(corgi_ts);
319                 return -EBUSY;
320         }
321
322         /* Enable Falling Edge */
323         set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
324
325         printk(KERN_INFO "input: Corgi Touchscreen Registered\n");
326
327         return 0;
328 }
329
330 static int corgits_remove(struct device *dev)
331 {
332         struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
333
334         free_irq(CORGI_IRQ_GPIO_TP_INT, NULL);
335         del_timer_sync(&corgi_ts->timer);
336         input_unregister_device(&corgi_ts->input);
337         kfree(corgi_ts);
338         return 0;
339 }
340
341 static struct device_driver corgits_driver = {
342         .name           = "corgi-ts",
343         .bus            = &platform_bus_type,
344         .probe          = corgits_probe,
345         .remove         = corgits_remove,
346         .suspend        = corgits_suspend,
347         .resume         = corgits_resume,
348 };
349
350 static int __devinit corgits_init(void)
351 {
352         return driver_register(&corgits_driver);
353 }
354
355 static void __exit corgits_exit(void)
356 {
357         driver_unregister(&corgits_driver);
358 }
359
360 module_init(corgits_init);
361 module_exit(corgits_exit);
362
363 MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
364 MODULE_DESCRIPTION("Corgi TouchScreen Driver");
365 MODULE_LICENSE("GPL");