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