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 v2.6.26-rc5 385 lines 9.6 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/platform_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 <linux/irq.h> 21 22#include <asm/arch/sharpsl.h> 23#include <asm/arch/hardware.h> 24#include <asm/arch/pxa-regs.h> 25#include <asm/arch/pxa2xx-gpio.h> 26 27 28#define PWR_MODE_ACTIVE 0 29#define PWR_MODE_SUSPEND 1 30 31#define X_AXIS_MAX 3830 32#define X_AXIS_MIN 150 33#define Y_AXIS_MAX 3830 34#define Y_AXIS_MIN 190 35#define PRESSURE_MIN 0 36#define PRESSURE_MAX 15000 37 38struct ts_event { 39 short pressure; 40 short x; 41 short y; 42}; 43 44struct corgi_ts { 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_invperiod = corgi_ts->machinfo->get_hsync_invperiod(); 79 80 if (hsync_invperiod) 81 return get_clk_frequency_khz(0)*1000/hsync_invperiod; 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 CCNT */ 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) 178{ 179 struct input_dev *dev = corgi_ts->input; 180 181 if (corgi_ts->power_mode != PWR_MODE_ACTIVE) 182 return; 183 184 if (!corgi_ts->tc.pressure && corgi_ts->pendown == 0) 185 return; 186 187 input_report_abs(dev, ABS_X, corgi_ts->tc.x); 188 input_report_abs(dev, ABS_Y, corgi_ts->tc.y); 189 input_report_abs(dev, ABS_PRESSURE, corgi_ts->tc.pressure); 190 input_report_key(dev, BTN_TOUCH, corgi_ts->pendown); 191 input_sync(dev); 192} 193 194static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer) 195{ 196 if ((GPLR(IRQ_TO_GPIO(corgi_ts->irq_gpio)) & GPIO_bit(IRQ_TO_GPIO(corgi_ts->irq_gpio))) == 0) { 197 /* Disable Interrupt */ 198 set_irq_type(corgi_ts->irq_gpio, IRQT_NOEDGE); 199 if (read_xydata(corgi_ts)) { 200 corgi_ts->pendown = 1; 201 new_data(corgi_ts); 202 } 203 mod_timer(&corgi_ts->timer, jiffies + HZ / 100); 204 } else { 205 if (corgi_ts->pendown == 1 || corgi_ts->pendown == 2) { 206 mod_timer(&corgi_ts->timer, jiffies + HZ / 100); 207 corgi_ts->pendown++; 208 return; 209 } 210 211 if (corgi_ts->pendown) { 212 corgi_ts->tc.pressure = 0; 213 new_data(corgi_ts); 214 } 215 216 /* Enable Falling Edge */ 217 set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); 218 corgi_ts->pendown = 0; 219 } 220} 221 222static void corgi_ts_timer(unsigned long data) 223{ 224 struct corgi_ts *corgits_data = (struct corgi_ts *) data; 225 226 ts_interrupt_main(corgits_data, 1); 227} 228 229static irqreturn_t ts_interrupt(int irq, void *dev_id) 230{ 231 struct corgi_ts *corgits_data = dev_id; 232 233 ts_interrupt_main(corgits_data, 0); 234 return IRQ_HANDLED; 235} 236 237#ifdef CONFIG_PM 238static int corgits_suspend(struct platform_device *dev, pm_message_t state) 239{ 240 struct corgi_ts *corgi_ts = platform_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); 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 platform_device *dev) 256{ 257 struct corgi_ts *corgi_ts = platform_get_drvdata(dev); 258 259 corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS); 260 /* Enable Falling Edge */ 261 set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); 262 corgi_ts->power_mode = PWR_MODE_ACTIVE; 263 264 return 0; 265} 266#else 267#define corgits_suspend NULL 268#define corgits_resume NULL 269#endif 270 271static int __init corgits_probe(struct platform_device *pdev) 272{ 273 struct corgi_ts *corgi_ts; 274 struct input_dev *input_dev; 275 int err = -ENOMEM; 276 277 corgi_ts = kzalloc(sizeof(struct corgi_ts), GFP_KERNEL); 278 input_dev = input_allocate_device(); 279 if (!corgi_ts || !input_dev) 280 goto fail1; 281 282 platform_set_drvdata(pdev, corgi_ts); 283 284 corgi_ts->machinfo = pdev->dev.platform_data; 285 corgi_ts->irq_gpio = platform_get_irq(pdev, 0); 286 287 if (corgi_ts->irq_gpio < 0) { 288 err = -ENODEV; 289 goto fail1; 290 } 291 292 corgi_ts->input = input_dev; 293 294 init_timer(&corgi_ts->timer); 295 corgi_ts->timer.data = (unsigned long) corgi_ts; 296 corgi_ts->timer.function = corgi_ts_timer; 297 298 input_dev->name = "Corgi Touchscreen"; 299 input_dev->phys = "corgits/input0"; 300 input_dev->id.bustype = BUS_HOST; 301 input_dev->id.vendor = 0x0001; 302 input_dev->id.product = 0x0002; 303 input_dev->id.version = 0x0100; 304 input_dev->dev.parent = &pdev->dev; 305 306 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 307 input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 308 input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0); 309 input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0); 310 input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0); 311 312 pxa_gpio_mode(IRQ_TO_GPIO(corgi_ts->irq_gpio) | GPIO_IN); 313 314 /* Initiaize ADS7846 Difference Reference mode */ 315 corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS); 316 mdelay(5); 317 corgi_ssp_ads7846_putget((3u << ADSCTRL_ADR_SH) | ADSCTRL_STS); 318 mdelay(5); 319 corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS); 320 mdelay(5); 321 corgi_ssp_ads7846_putget((5u << ADSCTRL_ADR_SH) | ADSCTRL_STS); 322 mdelay(5); 323 324 if (request_irq(corgi_ts->irq_gpio, ts_interrupt, IRQF_DISABLED, "ts", corgi_ts)) { 325 err = -EBUSY; 326 goto fail1; 327 } 328 329 err = input_register_device(corgi_ts->input); 330 if (err) 331 goto fail2; 332 333 corgi_ts->power_mode = PWR_MODE_ACTIVE; 334 335 /* Enable Falling Edge */ 336 set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); 337 338 return 0; 339 340 fail2: free_irq(corgi_ts->irq_gpio, corgi_ts); 341 fail1: input_free_device(input_dev); 342 kfree(corgi_ts); 343 return err; 344} 345 346static int corgits_remove(struct platform_device *pdev) 347{ 348 struct corgi_ts *corgi_ts = platform_get_drvdata(pdev); 349 350 free_irq(corgi_ts->irq_gpio, corgi_ts); 351 del_timer_sync(&corgi_ts->timer); 352 corgi_ts->machinfo->put_hsync(); 353 input_unregister_device(corgi_ts->input); 354 kfree(corgi_ts); 355 return 0; 356} 357 358static struct platform_driver corgits_driver = { 359 .probe = corgits_probe, 360 .remove = corgits_remove, 361 .suspend = corgits_suspend, 362 .resume = corgits_resume, 363 .driver = { 364 .name = "corgi-ts", 365 .owner = THIS_MODULE, 366 }, 367}; 368 369static int __devinit corgits_init(void) 370{ 371 return platform_driver_register(&corgits_driver); 372} 373 374static void __exit corgits_exit(void) 375{ 376 platform_driver_unregister(&corgits_driver); 377} 378 379module_init(corgits_init); 380module_exit(corgits_exit); 381 382MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); 383MODULE_DESCRIPTION("Corgi TouchScreen Driver"); 384MODULE_LICENSE("GPL"); 385MODULE_ALIAS("platform:corgi-ts");