2 * Touchscreen driver for Sharp Corgi models (SL-C7xx)
4 * Copyright (c) 2004-2005 Richard Purdie
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.
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>
22 #include <asm/arch/corgi.h>
23 #include <asm/arch/hardware.h>
24 #include <asm/arch/pxa-regs.h>
27 #define PWR_MODE_ACTIVE 0
28 #define PWR_MODE_SUSPEND 1
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
45 struct input_dev input
;
46 struct timer_list timer
;
52 #define STATUS_HSYNC (GPLR(CORGI_GPIO_HSYNC) & GPIO_bit(CORGI_GPIO_HSYNC))
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 CCNT_ON() {int pmnc = 1; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
57 #define CCNT_OFF() {int pmnc = 0; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));}
59 #define WAIT_HS_400_VGA 7013U // 17.615us
60 #define WAIT_HS_400_QVGA 16622U // 41.750us
63 /* ADS7846 Touch Screen Controller bit definitions */
64 #define ADSCTRL_PD0 (1u << 0) /* PD0 */
65 #define ADSCTRL_PD1 (1u << 1) /* PD1 */
66 #define ADSCTRL_DFR (1u << 2) /* SER/DFR */
67 #define ADSCTRL_MOD (1u << 3) /* Mode */
68 #define ADSCTRL_ADR_SH 4 /* Address setting */
69 #define ADSCTRL_STS (1u << 7) /* Start Bit */
71 /* External Functions */
72 extern int w100fb_get_xres(void);
73 extern int w100fb_get_blanking(void);
74 extern int w100fb_get_fastsysclk(void);
75 extern unsigned int get_clk_frequency_khz(int info
);
77 static unsigned long calc_waittime(void)
79 int w100fb_xres
= w100fb_get_xres();
80 unsigned int waittime
= 0;
82 if (w100fb_xres
== 480 || w100fb_xres
== 640) {
83 waittime
= WAIT_HS_400_VGA
* get_clk_frequency_khz(0) / 398131U;
85 if (w100fb_get_fastsysclk() == 100)
86 waittime
= waittime
* 75 / 100;
88 if (w100fb_xres
== 640)
94 return WAIT_HS_400_QVGA
* get_clk_frequency_khz(0) / 398131U;
97 static int sync_receive_data_send_cmd(int doRecive
, int doSend
, unsigned int address
, unsigned long wait_time
)
100 unsigned long timer1
= 0, timer2
;
103 dosleep
= !w100fb_get_blanking();
105 if (dosleep
&& doSend
) {
114 pos
= corgi_ssp_ads7846_get();
117 int cmd
= ADSCTRL_PD0
| ADSCTRL_PD1
| (address
<< ADSCTRL_ADR_SH
) | ADSCTRL_STS
;
119 corgi_ssp_ads7846_put(cmd
);
120 corgi_ssp_ads7846_get();
123 /* Wait after HSync */
125 if (timer2
-timer1
> wait_time
) {
130 /* Wait after HSync */
133 while (timer2
- timer1
< wait_time
)
136 corgi_ssp_ads7846_put(cmd
);
143 static int read_xydata(struct corgi_ts
*corgi_ts
)
145 unsigned int x
, y
, z1
, z2
;
146 unsigned long flags
, wait_time
;
148 /* critical section */
149 local_irq_save(flags
);
150 corgi_ssp_ads7846_lock();
151 wait_time
=calc_waittime();
154 sync_receive_data_send_cmd(0, 1, 1u, wait_time
);
157 sync_receive_data_send_cmd(1, 1, 1u, wait_time
);
160 y
= sync_receive_data_send_cmd(1, 1, 5u, wait_time
);
163 x
= sync_receive_data_send_cmd(1, 1, 3u, wait_time
);
166 z1
= sync_receive_data_send_cmd(1, 1, 4u, wait_time
);
167 z2
= sync_receive_data_send_cmd(1, 0, 4u, wait_time
);
169 /* Power-Down Enable */
170 corgi_ssp_ads7846_put((1u << ADSCTRL_ADR_SH
) | ADSCTRL_STS
);
171 corgi_ssp_ads7846_get();
173 corgi_ssp_ads7846_unlock();
174 local_irq_restore(flags
);
176 if (x
== 0 || y
== 0 || z1
== 0 || (x
* (z2
- z1
) / z1
) >= 15000) {
177 corgi_ts
->tc
.pressure
= 0;
183 corgi_ts
->tc
.pressure
= (x
* (z2
- z1
)) / z1
;
187 static void new_data(struct corgi_ts
*corgi_ts
, struct pt_regs
*regs
)
189 if (corgi_ts
->power_mode
!= PWR_MODE_ACTIVE
)
192 if (!corgi_ts
->tc
.pressure
&& corgi_ts
->pendown
== 0)
196 input_regs(&corgi_ts
->input
, regs
);
198 input_report_abs(&corgi_ts
->input
, ABS_X
, corgi_ts
->tc
.x
);
199 input_report_abs(&corgi_ts
->input
, ABS_Y
, corgi_ts
->tc
.y
);
200 input_report_abs(&corgi_ts
->input
, ABS_PRESSURE
, corgi_ts
->tc
.pressure
);
201 input_report_key(&corgi_ts
->input
, BTN_TOUCH
, (corgi_ts
->pendown
!= 0));
202 input_sync(&corgi_ts
->input
);
205 static void ts_interrupt_main(struct corgi_ts
*corgi_ts
, int isTimer
, struct pt_regs
*regs
)
207 if ((GPLR(CORGI_GPIO_TP_INT
) & GPIO_bit(CORGI_GPIO_TP_INT
)) == 0) {
208 /* Disable Interrupt */
209 set_irq_type(CORGI_IRQ_GPIO_TP_INT
, IRQT_NOEDGE
);
210 if (read_xydata(corgi_ts
)) {
211 corgi_ts
->pendown
= 1;
212 new_data(corgi_ts
, regs
);
214 mod_timer(&corgi_ts
->timer
, jiffies
+ HZ
/ 100);
216 if (corgi_ts
->pendown
== 1 || corgi_ts
->pendown
== 2) {
217 mod_timer(&corgi_ts
->timer
, jiffies
+ HZ
/ 100);
222 if (corgi_ts
->pendown
) {
223 corgi_ts
->tc
.pressure
= 0;
224 new_data(corgi_ts
, regs
);
227 /* Enable Falling Edge */
228 set_irq_type(CORGI_IRQ_GPIO_TP_INT
, IRQT_FALLING
);
229 corgi_ts
->pendown
= 0;
233 static void corgi_ts_timer(unsigned long data
)
235 struct corgi_ts
*corgits_data
= (struct corgi_ts
*) data
;
236 ts_interrupt_main(corgits_data
, 1, NULL
);
239 static irqreturn_t
ts_interrupt(int irq
, void *dev_id
, struct pt_regs
*regs
)
241 struct corgi_ts
*corgits_data
= dev_id
;
242 ts_interrupt_main(corgits_data
, 0, regs
);
247 static int corgits_suspend(struct device
*dev
, uint32_t state
, uint32_t level
)
249 if (level
== SUSPEND_POWER_DOWN
) {
250 struct corgi_ts
*corgi_ts
= dev_get_drvdata(dev
);
252 if (corgi_ts
->pendown
) {
253 del_timer_sync(&corgi_ts
->timer
);
254 corgi_ts
->tc
.pressure
= 0;
255 new_data(corgi_ts
, NULL
);
256 corgi_ts
->pendown
= 0;
258 corgi_ts
->power_mode
= PWR_MODE_SUSPEND
;
260 corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH
) | ADSCTRL_STS
);
265 static int corgits_resume(struct device
*dev
, uint32_t level
)
267 if (level
== RESUME_POWER_ON
) {
268 struct corgi_ts
*corgi_ts
= dev_get_drvdata(dev
);
270 corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH
) | ADSCTRL_STS
);
271 /* Enable Falling Edge */
272 set_irq_type(CORGI_IRQ_GPIO_TP_INT
, IRQT_FALLING
);
273 corgi_ts
->power_mode
= PWR_MODE_ACTIVE
;
278 #define corgits_suspend NULL
279 #define corgits_resume NULL
282 static int __init
corgits_probe(struct device
*dev
)
284 struct corgi_ts
*corgi_ts
;
286 if (!(corgi_ts
= kmalloc(sizeof(struct corgi_ts
), GFP_KERNEL
)))
289 dev_set_drvdata(dev
, corgi_ts
);
291 memset(corgi_ts
, 0, sizeof(struct corgi_ts
));
293 init_input_dev(&corgi_ts
->input
);
294 corgi_ts
->input
.evbit
[0] = BIT(EV_KEY
) | BIT(EV_ABS
);
295 corgi_ts
->input
.keybit
[LONG(BTN_TOUCH
)] = BIT(BTN_TOUCH
);
296 input_set_abs_params(&corgi_ts
->input
, ABS_X
, X_AXIS_MIN
, X_AXIS_MAX
, 0, 0);
297 input_set_abs_params(&corgi_ts
->input
, ABS_Y
, Y_AXIS_MIN
, Y_AXIS_MAX
, 0, 0);
298 input_set_abs_params(&corgi_ts
->input
, ABS_PRESSURE
, PRESSURE_MIN
, PRESSURE_MAX
, 0, 0);
300 strcpy(corgi_ts
->phys
, "corgits/input0");
302 corgi_ts
->input
.private = corgi_ts
;
303 corgi_ts
->input
.name
= "Corgi Touchscreen";
304 corgi_ts
->input
.dev
= dev
;
305 corgi_ts
->input
.phys
= corgi_ts
->phys
;
306 corgi_ts
->input
.id
.bustype
= BUS_HOST
;
307 corgi_ts
->input
.id
.vendor
= 0x0001;
308 corgi_ts
->input
.id
.product
= 0x0002;
309 corgi_ts
->input
.id
.version
= 0x0100;
311 pxa_gpio_mode(CORGI_GPIO_TP_INT
| GPIO_IN
);
312 pxa_gpio_mode(CORGI_GPIO_HSYNC
| GPIO_IN
);
314 /* Initiaize ADS7846 Difference Reference mode */
315 corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH
) | ADSCTRL_STS
);
317 corgi_ssp_ads7846_putget((3u << ADSCTRL_ADR_SH
) | ADSCTRL_STS
);
319 corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH
) | ADSCTRL_STS
);
321 corgi_ssp_ads7846_putget((5u << ADSCTRL_ADR_SH
) | ADSCTRL_STS
);
324 init_timer(&corgi_ts
->timer
);
325 corgi_ts
->timer
.data
= (unsigned long) corgi_ts
;
326 corgi_ts
->timer
.function
= corgi_ts_timer
;
328 input_register_device(&corgi_ts
->input
);
329 corgi_ts
->power_mode
= PWR_MODE_ACTIVE
;
331 if (request_irq(CORGI_IRQ_GPIO_TP_INT
, ts_interrupt
, SA_INTERRUPT
, "ts", corgi_ts
)) {
332 input_unregister_device(&corgi_ts
->input
);
337 /* Enable Falling Edge */
338 set_irq_type(CORGI_IRQ_GPIO_TP_INT
, IRQT_FALLING
);
340 printk(KERN_INFO
"input: Corgi Touchscreen Registered\n");
345 static int corgits_remove(struct device
*dev
)
347 struct corgi_ts
*corgi_ts
= dev_get_drvdata(dev
);
349 free_irq(CORGI_IRQ_GPIO_TP_INT
, NULL
);
350 del_timer_sync(&corgi_ts
->timer
);
351 input_unregister_device(&corgi_ts
->input
);
356 static struct device_driver corgits_driver
= {
358 .bus
= &platform_bus_type
,
359 .probe
= corgits_probe
,
360 .remove
= corgits_remove
,
361 .suspend
= corgits_suspend
,
362 .resume
= corgits_resume
,
365 static int __devinit
corgits_init(void)
367 return driver_register(&corgits_driver
);
370 static void __exit
corgits_exit(void)
372 driver_unregister(&corgits_driver
);
375 module_init(corgits_init
);
376 module_exit(corgits_exit
);
378 MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
379 MODULE_DESCRIPTION("Corgi TouchScreen Driver");
380 MODULE_LICENSE("GPL");