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.31 240 lines 5.9 kB view raw
1/* 2 * zylonite-wm97xx.c -- Zylonite Continuous Touch screen driver 3 * 4 * Copyright 2004, 2007, 2008 Wolfson Microelectronics PLC. 5 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 6 * Parts Copyright : Ian Molton <spyro@f2s.com> 7 * Andrew Zabolotny <zap@homelink.ru> 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 * 14 * Notes: 15 * This is a wm97xx extended touch driver supporting interrupt driven 16 * and continuous operation on Marvell Zylonite development systems 17 * (which have a WM9713 on board). 18 */ 19 20#include <linux/module.h> 21#include <linux/moduleparam.h> 22#include <linux/kernel.h> 23#include <linux/init.h> 24#include <linux/delay.h> 25#include <linux/irq.h> 26#include <linux/interrupt.h> 27#include <linux/io.h> 28#include <linux/wm97xx.h> 29 30#include <mach/hardware.h> 31#include <mach/mfp.h> 32#include <mach/regs-ac97.h> 33 34struct continuous { 35 u16 id; /* codec id */ 36 u8 code; /* continuous code */ 37 u8 reads; /* number of coord reads per read cycle */ 38 u32 speed; /* number of coords per second */ 39}; 40 41#define WM_READS(sp) ((sp / HZ) + 1) 42 43static const struct continuous cinfo[] = { 44 { WM9713_ID2, 0, WM_READS(94), 94 }, 45 { WM9713_ID2, 1, WM_READS(120), 120 }, 46 { WM9713_ID2, 2, WM_READS(154), 154 }, 47 { WM9713_ID2, 3, WM_READS(188), 188 }, 48}; 49 50/* continuous speed index */ 51static int sp_idx; 52 53/* 54 * Pen sampling frequency (Hz) in continuous mode. 55 */ 56static int cont_rate = 200; 57module_param(cont_rate, int, 0); 58MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)"); 59 60/* 61 * Pressure readback. 62 * 63 * Set to 1 to read back pen down pressure 64 */ 65static int pressure; 66module_param(pressure, int, 0); 67MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)"); 68 69/* 70 * AC97 touch data slot. 71 * 72 * Touch screen readback data ac97 slot 73 */ 74static int ac97_touch_slot = 5; 75module_param(ac97_touch_slot, int, 0); 76MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number"); 77 78 79/* flush AC97 slot 5 FIFO machines */ 80static void wm97xx_acc_pen_up(struct wm97xx *wm) 81{ 82 int i; 83 84 msleep(1); 85 86 for (i = 0; i < 16; i++) 87 MODR; 88} 89 90static int wm97xx_acc_pen_down(struct wm97xx *wm) 91{ 92 u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES; 93 int reads = 0; 94 static u16 last, tries; 95 96 /* When the AC97 queue has been drained we need to allow time 97 * to buffer up samples otherwise we end up spinning polling 98 * for samples. The controller can't have a suitably low 99 * threashold set to use the notifications it gives. 100 */ 101 msleep(1); 102 103 if (tries > 5) { 104 tries = 0; 105 return RC_PENUP; 106 } 107 108 x = MODR; 109 if (x == last) { 110 tries++; 111 return RC_AGAIN; 112 } 113 last = x; 114 do { 115 if (reads) 116 x = MODR; 117 y = MODR; 118 if (pressure) 119 p = MODR; 120 121 /* are samples valid */ 122 if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X || 123 (y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y || 124 (p & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_PRES) 125 goto up; 126 127 /* coordinate is good */ 128 tries = 0; 129 input_report_abs(wm->input_dev, ABS_X, x & 0xfff); 130 input_report_abs(wm->input_dev, ABS_Y, y & 0xfff); 131 input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff); 132 input_report_key(wm->input_dev, BTN_TOUCH, (p != 0)); 133 input_sync(wm->input_dev); 134 reads++; 135 } while (reads < cinfo[sp_idx].reads); 136up: 137 return RC_PENDOWN | RC_AGAIN; 138} 139 140static int wm97xx_acc_startup(struct wm97xx *wm) 141{ 142 int idx; 143 144 /* check we have a codec */ 145 if (wm->ac97 == NULL) 146 return -ENODEV; 147 148 /* Go you big red fire engine */ 149 for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) { 150 if (wm->id != cinfo[idx].id) 151 continue; 152 sp_idx = idx; 153 if (cont_rate <= cinfo[idx].speed) 154 break; 155 } 156 wm->acc_rate = cinfo[sp_idx].code; 157 wm->acc_slot = ac97_touch_slot; 158 dev_info(wm->dev, 159 "zylonite accelerated touchscreen driver, %d samples/sec\n", 160 cinfo[sp_idx].speed); 161 162 return 0; 163} 164 165static void wm97xx_irq_enable(struct wm97xx *wm, int enable) 166{ 167 if (enable) 168 enable_irq(wm->pen_irq); 169 else 170 disable_irq_nosync(wm->pen_irq); 171} 172 173static struct wm97xx_mach_ops zylonite_mach_ops = { 174 .acc_enabled = 1, 175 .acc_pen_up = wm97xx_acc_pen_up, 176 .acc_pen_down = wm97xx_acc_pen_down, 177 .acc_startup = wm97xx_acc_startup, 178 .irq_enable = wm97xx_irq_enable, 179 .irq_gpio = WM97XX_GPIO_2, 180}; 181 182static int zylonite_wm97xx_probe(struct platform_device *pdev) 183{ 184 struct wm97xx *wm = platform_get_drvdata(pdev); 185 int gpio_touch_irq; 186 187 if (cpu_is_pxa320()) 188 gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO15); 189 else 190 gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO26); 191 192 wm->pen_irq = IRQ_GPIO(gpio_touch_irq); 193 set_irq_type(IRQ_GPIO(gpio_touch_irq), IRQ_TYPE_EDGE_BOTH); 194 195 wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, 196 WM97XX_GPIO_POL_HIGH, 197 WM97XX_GPIO_STICKY, 198 WM97XX_GPIO_WAKE); 199 wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT, 200 WM97XX_GPIO_POL_HIGH, 201 WM97XX_GPIO_NOTSTICKY, 202 WM97XX_GPIO_NOWAKE); 203 204 return wm97xx_register_mach_ops(wm, &zylonite_mach_ops); 205} 206 207static int zylonite_wm97xx_remove(struct platform_device *pdev) 208{ 209 struct wm97xx *wm = platform_get_drvdata(pdev); 210 211 wm97xx_unregister_mach_ops(wm); 212 213 return 0; 214} 215 216static struct platform_driver zylonite_wm97xx_driver = { 217 .probe = zylonite_wm97xx_probe, 218 .remove = zylonite_wm97xx_remove, 219 .driver = { 220 .name = "wm97xx-touch", 221 }, 222}; 223 224static int __init zylonite_wm97xx_init(void) 225{ 226 return platform_driver_register(&zylonite_wm97xx_driver); 227} 228 229static void __exit zylonite_wm97xx_exit(void) 230{ 231 platform_driver_unregister(&zylonite_wm97xx_driver); 232} 233 234module_init(zylonite_wm97xx_init); 235module_exit(zylonite_wm97xx_exit); 236 237/* Module information */ 238MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 239MODULE_DESCRIPTION("wm97xx continuous touch driver for Zylonite"); 240MODULE_LICENSE("GPL");