1/* 2 * wm9705.c -- Codec driver for Wolfson WM9705 AC97 Codec. 3 * 4 * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC. 5 * Author: Liam Girdwood <lrg@slimlogic.co.uk> 6 * Parts Copyright : Ian Molton <spyro@f2s.com> 7 * Andrew Zabolotny <zap@homelink.ru> 8 * Russell King <rmk@arm.linux.org.uk> 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 * 15 */ 16 17#include <linux/module.h> 18#include <linux/moduleparam.h> 19#include <linux/kernel.h> 20#include <linux/input.h> 21#include <linux/delay.h> 22#include <linux/bitops.h> 23#include <linux/wm97xx.h> 24 25#define TS_NAME "wm97xx" 26#define WM9705_VERSION "1.00" 27#define DEFAULT_PRESSURE 0xb0c0 28 29/* 30 * Module parameters 31 */ 32 33/* 34 * Set current used for pressure measurement. 35 * 36 * Set pil = 2 to use 400uA 37 * pil = 1 to use 200uA and 38 * pil = 0 to disable pressure measurement. 39 * 40 * This is used to increase the range of values returned by the adc 41 * when measureing touchpanel pressure. 42 */ 43static int pil; 44module_param(pil, int, 0); 45MODULE_PARM_DESC(pil, "Set current used for pressure measurement."); 46 47/* 48 * Set threshold for pressure measurement. 49 * 50 * Pen down pressure below threshold is ignored. 51 */ 52static int pressure = DEFAULT_PRESSURE & 0xfff; 53module_param(pressure, int, 0); 54MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement."); 55 56/* 57 * Set adc sample delay. 58 * 59 * For accurate touchpanel measurements, some settling time may be 60 * required between the switch matrix applying a voltage across the 61 * touchpanel plate and the ADC sampling the signal. 62 * 63 * This delay can be set by setting delay = n, where n is the array 64 * position of the delay in the array delay_table below. 65 * Long delays > 1ms are supported for completeness, but are not 66 * recommended. 67 */ 68static int delay = 4; 69module_param(delay, int, 0); 70MODULE_PARM_DESC(delay, "Set adc sample delay."); 71 72/* 73 * Pen detect comparator threshold. 74 * 75 * 0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold 76 * i.e. 1 = Vmid/15 threshold 77 * 15 = Vmid/1 threshold 78 * 79 * Adjust this value if you are having problems with pen detect not 80 * detecting any down events. 81 */ 82static int pdd = 8; 83module_param(pdd, int, 0); 84MODULE_PARM_DESC(pdd, "Set pen detect comparator threshold"); 85 86/* 87 * Set adc mask function. 88 * 89 * Sources of glitch noise, such as signals driving an LCD display, may feed 90 * through to the touch screen plates and affect measurement accuracy. In 91 * order to minimise this, a signal may be applied to the MASK pin to delay or 92 * synchronise the sampling. 93 * 94 * 0 = No delay or sync 95 * 1 = High on pin stops conversions 96 * 2 = Edge triggered, edge on pin delays conversion by delay param (above) 97 * 3 = Edge triggered, edge on pin starts conversion after delay param 98 */ 99static int mask; 100module_param(mask, int, 0); 101MODULE_PARM_DESC(mask, "Set adc mask function."); 102 103/* 104 * ADC sample delay times in uS 105 */ 106static const int delay_table[] = { 107 21, /* 1 AC97 Link frames */ 108 42, /* 2 */ 109 84, /* 4 */ 110 167, /* 8 */ 111 333, /* 16 */ 112 667, /* 32 */ 113 1000, /* 48 */ 114 1333, /* 64 */ 115 2000, /* 96 */ 116 2667, /* 128 */ 117 3333, /* 160 */ 118 4000, /* 192 */ 119 4667, /* 224 */ 120 5333, /* 256 */ 121 6000, /* 288 */ 122 0 /* No delay, switch matrix always on */ 123}; 124 125/* 126 * Delay after issuing a POLL command. 127 * 128 * The delay is 3 AC97 link frames + the touchpanel settling delay 129 */ 130static inline void poll_delay(int d) 131{ 132 udelay(3 * AC97_LINK_FRAME + delay_table[d]); 133} 134 135/* 136 * set up the physical settings of the WM9705 137 */ 138static void wm9705_phy_init(struct wm97xx *wm) 139{ 140 u16 dig1 = 0, dig2 = WM97XX_RPR; 141 142 /* 143 * mute VIDEO and AUX as they share X and Y touchscreen 144 * inputs on the WM9705 145 */ 146 wm97xx_reg_write(wm, AC97_AUX, 0x8000); 147 wm97xx_reg_write(wm, AC97_VIDEO, 0x8000); 148 149 /* touchpanel pressure current*/ 150 if (pil == 2) { 151 dig2 |= WM9705_PIL; 152 dev_dbg(wm->dev, 153 "setting pressure measurement current to 400uA."); 154 } else if (pil) 155 dev_dbg(wm->dev, 156 "setting pressure measurement current to 200uA."); 157 if (!pil) 158 pressure = 0; 159 160 /* polling mode sample settling delay */ 161 if (delay != 4) { 162 if (delay < 0 || delay > 15) { 163 dev_dbg(wm->dev, "supplied delay out of range."); 164 delay = 4; 165 } 166 } 167 dig1 &= 0xff0f; 168 dig1 |= WM97XX_DELAY(delay); 169 dev_dbg(wm->dev, "setting adc sample delay to %d u Secs.", 170 delay_table[delay]); 171 172 /* WM9705 pdd */ 173 dig2 |= (pdd & 0x000f); 174 dev_dbg(wm->dev, "setting pdd to Vmid/%d", 1 - (pdd & 0x000f)); 175 176 /* mask */ 177 dig2 |= ((mask & 0x3) << 4); 178 179 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1); 180 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2); 181} 182 183static void wm9705_dig_enable(struct wm97xx *wm, int enable) 184{ 185 if (enable) { 186 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, 187 wm->dig[2] | WM97XX_PRP_DET_DIG); 188 wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */ 189 } else 190 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, 191 wm->dig[2] & ~WM97XX_PRP_DET_DIG); 192} 193 194static void wm9705_aux_prepare(struct wm97xx *wm) 195{ 196 memcpy(wm->dig_save, wm->dig, sizeof(wm->dig)); 197 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0); 198 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG); 199} 200 201static void wm9705_dig_restore(struct wm97xx *wm) 202{ 203 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]); 204 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]); 205} 206 207static inline int is_pden(struct wm97xx *wm) 208{ 209 return wm->dig[2] & WM9705_PDEN; 210} 211 212/* 213 * Read a sample from the WM9705 adc in polling mode. 214 */ 215static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample) 216{ 217 int timeout = 5 * delay; 218 bool wants_pen = adcsel & WM97XX_PEN_DOWN; 219 220 if (wants_pen && !wm->pen_probably_down) { 221 u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); 222 if (!(data & WM97XX_PEN_DOWN)) 223 return RC_PENUP; 224 wm->pen_probably_down = 1; 225 } 226 227 /* set up digitiser */ 228 if (wm->mach_ops && wm->mach_ops->pre_sample) 229 wm->mach_ops->pre_sample(adcsel); 230 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, (adcsel & WM97XX_ADCSEL_MASK) 231 | WM97XX_POLL | WM97XX_DELAY(delay)); 232 233 /* wait 3 AC97 time slots + delay for conversion */ 234 poll_delay(delay); 235 236 /* wait for POLL to go low */ 237 while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL) 238 && timeout) { 239 udelay(AC97_LINK_FRAME); 240 timeout--; 241 } 242 243 if (timeout == 0) { 244 /* If PDEN is set, we can get a timeout when pen goes up */ 245 if (is_pden(wm)) 246 wm->pen_probably_down = 0; 247 else 248 dev_dbg(wm->dev, "adc sample timeout"); 249 return RC_PENUP; 250 } 251 252 *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); 253 if (wm->mach_ops && wm->mach_ops->post_sample) 254 wm->mach_ops->post_sample(adcsel); 255 256 /* check we have correct sample */ 257 if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) { 258 dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x", 259 adcsel & WM97XX_ADCSEL_MASK, 260 *sample & WM97XX_ADCSEL_MASK); 261 return RC_PENUP; 262 } 263 264 if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) { 265 wm->pen_probably_down = 0; 266 return RC_PENUP; 267 } 268 269 return RC_VALID; 270} 271 272/* 273 * Sample the WM9705 touchscreen in polling mode 274 */ 275static int wm9705_poll_touch(struct wm97xx *wm, struct wm97xx_data *data) 276{ 277 int rc; 278 279 rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x); 280 if (rc != RC_VALID) 281 return rc; 282 rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y); 283 if (rc != RC_VALID) 284 return rc; 285 if (pil) { 286 rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN, &data->p); 287 if (rc != RC_VALID) 288 return rc; 289 } else 290 data->p = DEFAULT_PRESSURE; 291 292 return RC_VALID; 293} 294 295/* 296 * Enable WM9705 continuous mode, i.e. touch data is streamed across 297 * an AC97 slot 298 */ 299static int wm9705_acc_enable(struct wm97xx *wm, int enable) 300{ 301 u16 dig1, dig2; 302 int ret = 0; 303 304 dig1 = wm->dig[1]; 305 dig2 = wm->dig[2]; 306 307 if (enable) { 308 /* continuous mode */ 309 if (wm->mach_ops->acc_startup && 310 (ret = wm->mach_ops->acc_startup(wm)) < 0) 311 return ret; 312 dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK | 313 WM97XX_DELAY_MASK | WM97XX_SLT_MASK); 314 dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN | 315 WM97XX_DELAY(delay) | 316 WM97XX_SLT(wm->acc_slot) | 317 WM97XX_RATE(wm->acc_rate); 318 if (pil) 319 dig1 |= WM97XX_ADCSEL_PRES; 320 dig2 |= WM9705_PDEN; 321 } else { 322 dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN); 323 dig2 &= ~WM9705_PDEN; 324 if (wm->mach_ops->acc_shutdown) 325 wm->mach_ops->acc_shutdown(wm); 326 } 327 328 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1); 329 wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2); 330 331 return ret; 332} 333 334struct wm97xx_codec_drv wm9705_codec = { 335 .id = WM9705_ID2, 336 .name = "wm9705", 337 .poll_sample = wm9705_poll_sample, 338 .poll_touch = wm9705_poll_touch, 339 .acc_enable = wm9705_acc_enable, 340 .phy_init = wm9705_phy_init, 341 .dig_enable = wm9705_dig_enable, 342 .dig_restore = wm9705_dig_restore, 343 .aux_prepare = wm9705_aux_prepare, 344}; 345EXPORT_SYMBOL_GPL(wm9705_codec); 346 347/* Module information */ 348MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>"); 349MODULE_DESCRIPTION("WM9705 Touch Screen Driver"); 350MODULE_LICENSE("GPL"); 351