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

Input: add accelerated touchscreen support for Marvell Zylonite

This patch implements accelerated touchscreen support for the Marvell
Zylonite development platform, supporting pen down interrupts and
continuous mode data transfers.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

Mark Brown and committed by
Dmitry Torokhov
22e39d34 cd2d64b1

+254
+13
drivers/input/touchscreen/Kconfig
··· 308 308 To compile this driver as a module, choose M here: the 309 309 module will be called mainstone-wm97xx. 310 310 311 + config TOUCHSCREEN_WM97XX_ZYLONITE 312 + tristate "Zylonite accelerated touch" 313 + depends on TOUCHSCREEN_WM97XX && MACH_ZYLONITE 314 + select TOUCHSCREEN_WM9713 315 + help 316 + Say Y here for support for streaming mode with the touchscreen 317 + on Zylonite systems. 318 + 319 + If unsure, say N. 320 + 321 + To compile this driver as a module, choose M here: the 322 + module will be called zylonite-wm97xx. 323 + 311 324 config TOUCHSCREEN_USB_COMPOSITE 312 325 tristate "USB Touchscreen Driver" 313 326 depends on USB_ARCH_HAS_HCD
+1
drivers/input/touchscreen/Makefile
··· 34 34 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o 35 35 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o 36 36 obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o 37 + obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
+240
drivers/input/touchscreen/zylonite-wm97xx.c
··· 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 + 34 + struct 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 + 43 + static 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 */ 51 + static int sp_idx; 52 + 53 + /* 54 + * Pen sampling frequency (Hz) in continuous mode. 55 + */ 56 + static int cont_rate = 200; 57 + module_param(cont_rate, int, 0); 58 + MODULE_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 + */ 65 + static int pressure; 66 + module_param(pressure, int, 0); 67 + MODULE_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 + */ 74 + static int ac97_touch_slot = 5; 75 + module_param(ac97_touch_slot, int, 0); 76 + MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number"); 77 + 78 + 79 + /* flush AC97 slot 5 FIFO machines */ 80 + static 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 + 90 + static 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); 136 + up: 137 + return RC_PENDOWN | RC_AGAIN; 138 + } 139 + 140 + static 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 + 165 + static 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 + 173 + static 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 + 182 + static 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 + 207 + static 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 + 216 + static 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 + 224 + static int __init zylonite_wm97xx_init(void) 225 + { 226 + return platform_driver_register(&zylonite_wm97xx_driver); 227 + } 228 + 229 + static void __exit zylonite_wm97xx_exit(void) 230 + { 231 + platform_driver_unregister(&zylonite_wm97xx_driver); 232 + } 233 + 234 + module_init(zylonite_wm97xx_init); 235 + module_exit(zylonite_wm97xx_exit); 236 + 237 + /* Module information */ 238 + MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 239 + MODULE_DESCRIPTION("wm97xx continuous touch driver for Zylonite"); 240 + MODULE_LICENSE("GPL");