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