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