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