Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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