1*febf1dffSMark Brown /* 2*febf1dffSMark Brown * wm97xx-core.c -- Touch screen driver core for Wolfson WM9705, WM9712 3*febf1dffSMark Brown * and WM9713 AC97 Codecs. 4*febf1dffSMark Brown * 5*febf1dffSMark Brown * Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC. 6*febf1dffSMark Brown * Author: Liam Girdwood 7*febf1dffSMark Brown * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com 8*febf1dffSMark Brown * Parts Copyright : Ian Molton <spyro@f2s.com> 9*febf1dffSMark Brown * Andrew Zabolotny <zap@homelink.ru> 10*febf1dffSMark Brown * Russell King <rmk@arm.linux.org.uk> 11*febf1dffSMark Brown * 12*febf1dffSMark Brown * This program is free software; you can redistribute it and/or modify it 13*febf1dffSMark Brown * under the terms of the GNU General Public License as published by the 14*febf1dffSMark Brown * Free Software Foundation; either version 2 of the License, or (at your 15*febf1dffSMark Brown * option) any later version. 16*febf1dffSMark Brown * 17*febf1dffSMark Brown * Notes: 18*febf1dffSMark Brown * 19*febf1dffSMark Brown * Features: 20*febf1dffSMark Brown * - supports WM9705, WM9712, WM9713 21*febf1dffSMark Brown * - polling mode 22*febf1dffSMark Brown * - continuous mode (arch-dependent) 23*febf1dffSMark Brown * - adjustable rpu/dpp settings 24*febf1dffSMark Brown * - adjustable pressure current 25*febf1dffSMark Brown * - adjustable sample settle delay 26*febf1dffSMark Brown * - 4 and 5 wire touchscreens (5 wire is WM9712 only) 27*febf1dffSMark Brown * - pen down detection 28*febf1dffSMark Brown * - battery monitor 29*febf1dffSMark Brown * - sample AUX adcs 30*febf1dffSMark Brown * - power management 31*febf1dffSMark Brown * - codec GPIO 32*febf1dffSMark Brown * - codec event notification 33*febf1dffSMark Brown * Todo 34*febf1dffSMark Brown * - Support for async sampling control for noisy LCDs. 35*febf1dffSMark Brown * 36*febf1dffSMark Brown */ 37*febf1dffSMark Brown 38*febf1dffSMark Brown #include <linux/module.h> 39*febf1dffSMark Brown #include <linux/moduleparam.h> 40*febf1dffSMark Brown #include <linux/version.h> 41*febf1dffSMark Brown #include <linux/kernel.h> 42*febf1dffSMark Brown #include <linux/init.h> 43*febf1dffSMark Brown #include <linux/delay.h> 44*febf1dffSMark Brown #include <linux/string.h> 45*febf1dffSMark Brown #include <linux/proc_fs.h> 46*febf1dffSMark Brown #include <linux/pm.h> 47*febf1dffSMark Brown #include <linux/interrupt.h> 48*febf1dffSMark Brown #include <linux/bitops.h> 49*febf1dffSMark Brown #include <linux/workqueue.h> 50*febf1dffSMark Brown #include <linux/wm97xx.h> 51*febf1dffSMark Brown #include <linux/uaccess.h> 52*febf1dffSMark Brown #include <linux/io.h> 53*febf1dffSMark Brown 54*febf1dffSMark Brown #define TS_NAME "wm97xx" 55*febf1dffSMark Brown #define WM_CORE_VERSION "1.00" 56*febf1dffSMark Brown #define DEFAULT_PRESSURE 0xb0c0 57*febf1dffSMark Brown 58*febf1dffSMark Brown 59*febf1dffSMark Brown /* 60*febf1dffSMark Brown * Touchscreen absolute values 61*febf1dffSMark Brown * 62*febf1dffSMark Brown * These parameters are used to help the input layer discard out of 63*febf1dffSMark Brown * range readings and reduce jitter etc. 64*febf1dffSMark Brown * 65*febf1dffSMark Brown * o min, max:- indicate the min and max values your touch screen returns 66*febf1dffSMark Brown * o fuzz:- use a higher number to reduce jitter 67*febf1dffSMark Brown * 68*febf1dffSMark Brown * The default values correspond to Mainstone II in QVGA mode 69*febf1dffSMark Brown * 70*febf1dffSMark Brown * Please read 71*febf1dffSMark Brown * Documentation/input/input-programming.txt for more details. 72*febf1dffSMark Brown */ 73*febf1dffSMark Brown 74*febf1dffSMark Brown static int abs_x[3] = {350, 3900, 5}; 75*febf1dffSMark Brown module_param_array(abs_x, int, NULL, 0); 76*febf1dffSMark Brown MODULE_PARM_DESC(abs_x, "Touchscreen absolute X min, max, fuzz"); 77*febf1dffSMark Brown 78*febf1dffSMark Brown static int abs_y[3] = {320, 3750, 40}; 79*febf1dffSMark Brown module_param_array(abs_y, int, NULL, 0); 80*febf1dffSMark Brown MODULE_PARM_DESC(abs_y, "Touchscreen absolute Y min, max, fuzz"); 81*febf1dffSMark Brown 82*febf1dffSMark Brown static int abs_p[3] = {0, 150, 4}; 83*febf1dffSMark Brown module_param_array(abs_p, int, NULL, 0); 84*febf1dffSMark Brown MODULE_PARM_DESC(abs_p, "Touchscreen absolute Pressure min, max, fuzz"); 85*febf1dffSMark Brown 86*febf1dffSMark Brown /* 87*febf1dffSMark Brown * wm97xx IO access, all IO locking done by AC97 layer 88*febf1dffSMark Brown */ 89*febf1dffSMark Brown int wm97xx_reg_read(struct wm97xx *wm, u16 reg) 90*febf1dffSMark Brown { 91*febf1dffSMark Brown if (wm->ac97) 92*febf1dffSMark Brown return wm->ac97->bus->ops->read(wm->ac97, reg); 93*febf1dffSMark Brown else 94*febf1dffSMark Brown return -1; 95*febf1dffSMark Brown } 96*febf1dffSMark Brown EXPORT_SYMBOL_GPL(wm97xx_reg_read); 97*febf1dffSMark Brown 98*febf1dffSMark Brown void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val) 99*febf1dffSMark Brown { 100*febf1dffSMark Brown /* cache digitiser registers */ 101*febf1dffSMark Brown if (reg >= AC97_WM9713_DIG1 && reg <= AC97_WM9713_DIG3) 102*febf1dffSMark Brown wm->dig[(reg - AC97_WM9713_DIG1) >> 1] = val; 103*febf1dffSMark Brown 104*febf1dffSMark Brown /* cache gpio regs */ 105*febf1dffSMark Brown if (reg >= AC97_GPIO_CFG && reg <= AC97_MISC_AFE) 106*febf1dffSMark Brown wm->gpio[(reg - AC97_GPIO_CFG) >> 1] = val; 107*febf1dffSMark Brown 108*febf1dffSMark Brown /* wm9713 irq reg */ 109*febf1dffSMark Brown if (reg == 0x5a) 110*febf1dffSMark Brown wm->misc = val; 111*febf1dffSMark Brown 112*febf1dffSMark Brown if (wm->ac97) 113*febf1dffSMark Brown wm->ac97->bus->ops->write(wm->ac97, reg, val); 114*febf1dffSMark Brown } 115*febf1dffSMark Brown EXPORT_SYMBOL_GPL(wm97xx_reg_write); 116*febf1dffSMark Brown 117*febf1dffSMark Brown /** 118*febf1dffSMark Brown * wm97xx_read_aux_adc - Read the aux adc. 119*febf1dffSMark Brown * @wm: wm97xx device. 120*febf1dffSMark Brown * @adcsel: codec ADC to be read 121*febf1dffSMark Brown * 122*febf1dffSMark Brown * Reads the selected AUX ADC. 123*febf1dffSMark Brown */ 124*febf1dffSMark Brown 125*febf1dffSMark Brown int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel) 126*febf1dffSMark Brown { 127*febf1dffSMark Brown int power_adc = 0, auxval; 128*febf1dffSMark Brown u16 power = 0; 129*febf1dffSMark Brown 130*febf1dffSMark Brown /* get codec */ 131*febf1dffSMark Brown mutex_lock(&wm->codec_mutex); 132*febf1dffSMark Brown 133*febf1dffSMark Brown /* When the touchscreen is not in use, we may have to power up 134*febf1dffSMark Brown * the AUX ADC before we can use sample the AUX inputs-> 135*febf1dffSMark Brown */ 136*febf1dffSMark Brown if (wm->id == WM9713_ID2 && 137*febf1dffSMark Brown (power = wm97xx_reg_read(wm, AC97_EXTENDED_MID)) & 0x8000) { 138*febf1dffSMark Brown power_adc = 1; 139*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_EXTENDED_MID, power & 0x7fff); 140*febf1dffSMark Brown } 141*febf1dffSMark Brown 142*febf1dffSMark Brown /* Prepare the codec for AUX reading */ 143*febf1dffSMark Brown wm->codec->aux_prepare(wm); 144*febf1dffSMark Brown 145*febf1dffSMark Brown /* Turn polling mode on to read AUX ADC */ 146*febf1dffSMark Brown wm->pen_probably_down = 1; 147*febf1dffSMark Brown wm->codec->poll_sample(wm, adcsel, &auxval); 148*febf1dffSMark Brown 149*febf1dffSMark Brown if (power_adc) 150*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_EXTENDED_MID, power | 0x8000); 151*febf1dffSMark Brown 152*febf1dffSMark Brown wm->codec->dig_restore(wm); 153*febf1dffSMark Brown 154*febf1dffSMark Brown wm->pen_probably_down = 0; 155*febf1dffSMark Brown 156*febf1dffSMark Brown mutex_unlock(&wm->codec_mutex); 157*febf1dffSMark Brown return auxval & 0xfff; 158*febf1dffSMark Brown } 159*febf1dffSMark Brown EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc); 160*febf1dffSMark Brown 161*febf1dffSMark Brown /** 162*febf1dffSMark Brown * wm97xx_get_gpio - Get the status of a codec GPIO. 163*febf1dffSMark Brown * @wm: wm97xx device. 164*febf1dffSMark Brown * @gpio: gpio 165*febf1dffSMark Brown * 166*febf1dffSMark Brown * Get the status of a codec GPIO pin 167*febf1dffSMark Brown */ 168*febf1dffSMark Brown 169*febf1dffSMark Brown enum wm97xx_gpio_status wm97xx_get_gpio(struct wm97xx *wm, u32 gpio) 170*febf1dffSMark Brown { 171*febf1dffSMark Brown u16 status; 172*febf1dffSMark Brown enum wm97xx_gpio_status ret; 173*febf1dffSMark Brown 174*febf1dffSMark Brown mutex_lock(&wm->codec_mutex); 175*febf1dffSMark Brown status = wm97xx_reg_read(wm, AC97_GPIO_STATUS); 176*febf1dffSMark Brown 177*febf1dffSMark Brown if (status & gpio) 178*febf1dffSMark Brown ret = WM97XX_GPIO_HIGH; 179*febf1dffSMark Brown else 180*febf1dffSMark Brown ret = WM97XX_GPIO_LOW; 181*febf1dffSMark Brown 182*febf1dffSMark Brown mutex_unlock(&wm->codec_mutex); 183*febf1dffSMark Brown return ret; 184*febf1dffSMark Brown } 185*febf1dffSMark Brown EXPORT_SYMBOL_GPL(wm97xx_get_gpio); 186*febf1dffSMark Brown 187*febf1dffSMark Brown /** 188*febf1dffSMark Brown * wm97xx_set_gpio - Set the status of a codec GPIO. 189*febf1dffSMark Brown * @wm: wm97xx device. 190*febf1dffSMark Brown * @gpio: gpio 191*febf1dffSMark Brown * 192*febf1dffSMark Brown * 193*febf1dffSMark Brown * Set the status of a codec GPIO pin 194*febf1dffSMark Brown */ 195*febf1dffSMark Brown 196*febf1dffSMark Brown void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio, 197*febf1dffSMark Brown enum wm97xx_gpio_status status) 198*febf1dffSMark Brown { 199*febf1dffSMark Brown u16 reg; 200*febf1dffSMark Brown 201*febf1dffSMark Brown mutex_lock(&wm->codec_mutex); 202*febf1dffSMark Brown reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS); 203*febf1dffSMark Brown 204*febf1dffSMark Brown if (status & WM97XX_GPIO_HIGH) 205*febf1dffSMark Brown reg |= gpio; 206*febf1dffSMark Brown else 207*febf1dffSMark Brown reg &= ~gpio; 208*febf1dffSMark Brown 209*febf1dffSMark Brown if (wm->id == WM9712_ID2) 210*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1); 211*febf1dffSMark Brown else 212*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg); 213*febf1dffSMark Brown mutex_unlock(&wm->codec_mutex); 214*febf1dffSMark Brown } 215*febf1dffSMark Brown EXPORT_SYMBOL_GPL(wm97xx_set_gpio); 216*febf1dffSMark Brown 217*febf1dffSMark Brown /* 218*febf1dffSMark Brown * Codec GPIO pin configuration, this sets pin direction, polarity, 219*febf1dffSMark Brown * stickyness and wake up. 220*febf1dffSMark Brown */ 221*febf1dffSMark Brown void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, enum wm97xx_gpio_dir dir, 222*febf1dffSMark Brown enum wm97xx_gpio_pol pol, enum wm97xx_gpio_sticky sticky, 223*febf1dffSMark Brown enum wm97xx_gpio_wake wake) 224*febf1dffSMark Brown { 225*febf1dffSMark Brown u16 reg; 226*febf1dffSMark Brown 227*febf1dffSMark Brown mutex_lock(&wm->codec_mutex); 228*febf1dffSMark Brown reg = wm97xx_reg_read(wm, AC97_GPIO_POLARITY); 229*febf1dffSMark Brown 230*febf1dffSMark Brown if (pol == WM97XX_GPIO_POL_HIGH) 231*febf1dffSMark Brown reg |= gpio; 232*febf1dffSMark Brown else 233*febf1dffSMark Brown reg &= ~gpio; 234*febf1dffSMark Brown 235*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_POLARITY, reg); 236*febf1dffSMark Brown reg = wm97xx_reg_read(wm, AC97_GPIO_STICKY); 237*febf1dffSMark Brown 238*febf1dffSMark Brown if (sticky == WM97XX_GPIO_STICKY) 239*febf1dffSMark Brown reg |= gpio; 240*febf1dffSMark Brown else 241*febf1dffSMark Brown reg &= ~gpio; 242*febf1dffSMark Brown 243*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_STICKY, reg); 244*febf1dffSMark Brown reg = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP); 245*febf1dffSMark Brown 246*febf1dffSMark Brown if (wake == WM97XX_GPIO_WAKE) 247*febf1dffSMark Brown reg |= gpio; 248*febf1dffSMark Brown else 249*febf1dffSMark Brown reg &= ~gpio; 250*febf1dffSMark Brown 251*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, reg); 252*febf1dffSMark Brown reg = wm97xx_reg_read(wm, AC97_GPIO_CFG); 253*febf1dffSMark Brown 254*febf1dffSMark Brown if (dir == WM97XX_GPIO_IN) 255*febf1dffSMark Brown reg |= gpio; 256*febf1dffSMark Brown else 257*febf1dffSMark Brown reg &= ~gpio; 258*febf1dffSMark Brown 259*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_CFG, reg); 260*febf1dffSMark Brown mutex_unlock(&wm->codec_mutex); 261*febf1dffSMark Brown } 262*febf1dffSMark Brown EXPORT_SYMBOL_GPL(wm97xx_config_gpio); 263*febf1dffSMark Brown 264*febf1dffSMark Brown /* 265*febf1dffSMark Brown * Handle a pen down interrupt. 266*febf1dffSMark Brown */ 267*febf1dffSMark Brown static void wm97xx_pen_irq_worker(struct work_struct *work) 268*febf1dffSMark Brown { 269*febf1dffSMark Brown struct wm97xx *wm = container_of(work, struct wm97xx, pen_event_work); 270*febf1dffSMark Brown int pen_was_down = wm->pen_is_down; 271*febf1dffSMark Brown 272*febf1dffSMark Brown /* do we need to enable the touch panel reader */ 273*febf1dffSMark Brown if (wm->id == WM9705_ID2) { 274*febf1dffSMark Brown if (wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD) & 275*febf1dffSMark Brown WM97XX_PEN_DOWN) 276*febf1dffSMark Brown wm->pen_is_down = 1; 277*febf1dffSMark Brown else 278*febf1dffSMark Brown wm->pen_is_down = 0; 279*febf1dffSMark Brown } else { 280*febf1dffSMark Brown u16 status, pol; 281*febf1dffSMark Brown mutex_lock(&wm->codec_mutex); 282*febf1dffSMark Brown status = wm97xx_reg_read(wm, AC97_GPIO_STATUS); 283*febf1dffSMark Brown pol = wm97xx_reg_read(wm, AC97_GPIO_POLARITY); 284*febf1dffSMark Brown 285*febf1dffSMark Brown if (WM97XX_GPIO_13 & pol & status) { 286*febf1dffSMark Brown wm->pen_is_down = 1; 287*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol & 288*febf1dffSMark Brown ~WM97XX_GPIO_13); 289*febf1dffSMark Brown } else { 290*febf1dffSMark Brown wm->pen_is_down = 0; 291*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol | 292*febf1dffSMark Brown WM97XX_GPIO_13); 293*febf1dffSMark Brown } 294*febf1dffSMark Brown 295*febf1dffSMark Brown if (wm->id == WM9712_ID2) 296*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status & 297*febf1dffSMark Brown ~WM97XX_GPIO_13) << 1); 298*febf1dffSMark Brown else 299*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_STATUS, status & 300*febf1dffSMark Brown ~WM97XX_GPIO_13); 301*febf1dffSMark Brown mutex_unlock(&wm->codec_mutex); 302*febf1dffSMark Brown } 303*febf1dffSMark Brown 304*febf1dffSMark Brown /* If the system is not using continuous mode or it provides a 305*febf1dffSMark Brown * pen down operation then we need to schedule polls while the 306*febf1dffSMark Brown * pen is down. Otherwise the machine driver is responsible 307*febf1dffSMark Brown * for scheduling reads. 308*febf1dffSMark Brown */ 309*febf1dffSMark Brown if (!wm->mach_ops->acc_enabled || wm->mach_ops->acc_pen_down) { 310*febf1dffSMark Brown if (wm->pen_is_down && !pen_was_down) { 311*febf1dffSMark Brown /* Data is not availiable immediately on pen down */ 312*febf1dffSMark Brown queue_delayed_work(wm->ts_workq, &wm->ts_reader, 1); 313*febf1dffSMark Brown } 314*febf1dffSMark Brown 315*febf1dffSMark Brown /* Let ts_reader report the pen up for debounce. */ 316*febf1dffSMark Brown if (!wm->pen_is_down && pen_was_down) 317*febf1dffSMark Brown wm->pen_is_down = 1; 318*febf1dffSMark Brown } 319*febf1dffSMark Brown 320*febf1dffSMark Brown if (!wm->pen_is_down && wm->mach_ops->acc_enabled) 321*febf1dffSMark Brown wm->mach_ops->acc_pen_up(wm); 322*febf1dffSMark Brown 323*febf1dffSMark Brown wm->mach_ops->irq_enable(wm, 1); 324*febf1dffSMark Brown } 325*febf1dffSMark Brown 326*febf1dffSMark Brown /* 327*febf1dffSMark Brown * Codec PENDOWN irq handler 328*febf1dffSMark Brown * 329*febf1dffSMark Brown * We have to disable the codec interrupt in the handler because it 330*febf1dffSMark Brown * can take upto 1ms to clear the interrupt source. We schedule a task 331*febf1dffSMark Brown * in a work queue to do the actual interaction with the chip (it 332*febf1dffSMark Brown * doesn't matter if we end up reenqueing it before it is executed 333*febf1dffSMark Brown * since we don't touch the chip until it has run). The interrupt is 334*febf1dffSMark Brown * then enabled again in the slow handler when the source has been 335*febf1dffSMark Brown * cleared. 336*febf1dffSMark Brown */ 337*febf1dffSMark Brown static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id) 338*febf1dffSMark Brown { 339*febf1dffSMark Brown struct wm97xx *wm = dev_id; 340*febf1dffSMark Brown 341*febf1dffSMark Brown wm->mach_ops->irq_enable(wm, 0); 342*febf1dffSMark Brown queue_work(wm->ts_workq, &wm->pen_event_work); 343*febf1dffSMark Brown 344*febf1dffSMark Brown return IRQ_HANDLED; 345*febf1dffSMark Brown } 346*febf1dffSMark Brown 347*febf1dffSMark Brown /* 348*febf1dffSMark Brown * initialise pen IRQ handler and workqueue 349*febf1dffSMark Brown */ 350*febf1dffSMark Brown static int wm97xx_init_pen_irq(struct wm97xx *wm) 351*febf1dffSMark Brown { 352*febf1dffSMark Brown u16 reg; 353*febf1dffSMark Brown 354*febf1dffSMark Brown /* If an interrupt is supplied an IRQ enable operation must also be 355*febf1dffSMark Brown * provided. */ 356*febf1dffSMark Brown BUG_ON(!wm->mach_ops->irq_enable); 357*febf1dffSMark Brown 358*febf1dffSMark Brown if (request_irq(wm->pen_irq, wm97xx_pen_interrupt, IRQF_SHARED, 359*febf1dffSMark Brown "wm97xx-pen", wm)) { 360*febf1dffSMark Brown dev_err(wm->dev, 361*febf1dffSMark Brown "Failed to register pen down interrupt, polling"); 362*febf1dffSMark Brown wm->pen_irq = 0; 363*febf1dffSMark Brown return -EINVAL; 364*febf1dffSMark Brown } 365*febf1dffSMark Brown 366*febf1dffSMark Brown /* Configure GPIO as interrupt source on WM971x */ 367*febf1dffSMark Brown if (wm->id != WM9705_ID2) { 368*febf1dffSMark Brown BUG_ON(!wm->mach_ops->irq_gpio); 369*febf1dffSMark Brown reg = wm97xx_reg_read(wm, AC97_MISC_AFE); 370*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_MISC_AFE, 371*febf1dffSMark Brown reg & ~(wm->mach_ops->irq_gpio)); 372*febf1dffSMark Brown reg = wm97xx_reg_read(wm, 0x5a); 373*febf1dffSMark Brown wm97xx_reg_write(wm, 0x5a, reg & ~0x0001); 374*febf1dffSMark Brown } 375*febf1dffSMark Brown 376*febf1dffSMark Brown return 0; 377*febf1dffSMark Brown } 378*febf1dffSMark Brown 379*febf1dffSMark Brown static int wm97xx_read_samples(struct wm97xx *wm) 380*febf1dffSMark Brown { 381*febf1dffSMark Brown struct wm97xx_data data; 382*febf1dffSMark Brown int rc; 383*febf1dffSMark Brown 384*febf1dffSMark Brown mutex_lock(&wm->codec_mutex); 385*febf1dffSMark Brown 386*febf1dffSMark Brown if (wm->mach_ops && wm->mach_ops->acc_enabled) 387*febf1dffSMark Brown rc = wm->mach_ops->acc_pen_down(wm); 388*febf1dffSMark Brown else 389*febf1dffSMark Brown rc = wm->codec->poll_touch(wm, &data); 390*febf1dffSMark Brown 391*febf1dffSMark Brown if (rc & RC_PENUP) { 392*febf1dffSMark Brown if (wm->pen_is_down) { 393*febf1dffSMark Brown wm->pen_is_down = 0; 394*febf1dffSMark Brown dev_dbg(wm->dev, "pen up\n"); 395*febf1dffSMark Brown input_report_abs(wm->input_dev, ABS_PRESSURE, 0); 396*febf1dffSMark Brown input_sync(wm->input_dev); 397*febf1dffSMark Brown } else if (!(rc & RC_AGAIN)) { 398*febf1dffSMark Brown /* We need high frequency updates only while 399*febf1dffSMark Brown * pen is down, the user never will be able to 400*febf1dffSMark Brown * touch screen faster than a few times per 401*febf1dffSMark Brown * second... On the other hand, when the user 402*febf1dffSMark Brown * is actively working with the touchscreen we 403*febf1dffSMark Brown * don't want to lose the quick response. So we 404*febf1dffSMark Brown * will slowly increase sleep time after the 405*febf1dffSMark Brown * pen is up and quicky restore it to ~one task 406*febf1dffSMark Brown * switch when pen is down again. 407*febf1dffSMark Brown */ 408*febf1dffSMark Brown if (wm->ts_reader_interval < HZ / 10) 409*febf1dffSMark Brown wm->ts_reader_interval++; 410*febf1dffSMark Brown } 411*febf1dffSMark Brown 412*febf1dffSMark Brown } else if (rc & RC_VALID) { 413*febf1dffSMark Brown dev_dbg(wm->dev, 414*febf1dffSMark Brown "pen down: x=%x:%d, y=%x:%d, pressure=%x:%d\n", 415*febf1dffSMark Brown data.x >> 12, data.x & 0xfff, data.y >> 12, 416*febf1dffSMark Brown data.y & 0xfff, data.p >> 12, data.p & 0xfff); 417*febf1dffSMark Brown input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff); 418*febf1dffSMark Brown input_report_abs(wm->input_dev, ABS_Y, data.y & 0xfff); 419*febf1dffSMark Brown input_report_abs(wm->input_dev, ABS_PRESSURE, data.p & 0xfff); 420*febf1dffSMark Brown input_sync(wm->input_dev); 421*febf1dffSMark Brown wm->pen_is_down = 1; 422*febf1dffSMark Brown wm->ts_reader_interval = wm->ts_reader_min_interval; 423*febf1dffSMark Brown } else if (rc & RC_PENDOWN) { 424*febf1dffSMark Brown dev_dbg(wm->dev, "pen down\n"); 425*febf1dffSMark Brown wm->pen_is_down = 1; 426*febf1dffSMark Brown wm->ts_reader_interval = wm->ts_reader_min_interval; 427*febf1dffSMark Brown } 428*febf1dffSMark Brown 429*febf1dffSMark Brown mutex_unlock(&wm->codec_mutex); 430*febf1dffSMark Brown return rc; 431*febf1dffSMark Brown } 432*febf1dffSMark Brown 433*febf1dffSMark Brown /* 434*febf1dffSMark Brown * The touchscreen sample reader. 435*febf1dffSMark Brown */ 436*febf1dffSMark Brown static void wm97xx_ts_reader(struct work_struct *work) 437*febf1dffSMark Brown { 438*febf1dffSMark Brown int rc; 439*febf1dffSMark Brown struct wm97xx *wm = container_of(work, struct wm97xx, ts_reader.work); 440*febf1dffSMark Brown 441*febf1dffSMark Brown BUG_ON(!wm->codec); 442*febf1dffSMark Brown 443*febf1dffSMark Brown do { 444*febf1dffSMark Brown rc = wm97xx_read_samples(wm); 445*febf1dffSMark Brown } while (rc & RC_AGAIN); 446*febf1dffSMark Brown 447*febf1dffSMark Brown if (wm->pen_is_down || !wm->pen_irq) 448*febf1dffSMark Brown queue_delayed_work(wm->ts_workq, &wm->ts_reader, 449*febf1dffSMark Brown wm->ts_reader_interval); 450*febf1dffSMark Brown } 451*febf1dffSMark Brown 452*febf1dffSMark Brown /** 453*febf1dffSMark Brown * wm97xx_ts_input_open - Open the touch screen input device. 454*febf1dffSMark Brown * @idev: Input device to be opened. 455*febf1dffSMark Brown * 456*febf1dffSMark Brown * Called by the input sub system to open a wm97xx touchscreen device. 457*febf1dffSMark Brown * Starts the touchscreen thread and touch digitiser. 458*febf1dffSMark Brown */ 459*febf1dffSMark Brown static int wm97xx_ts_input_open(struct input_dev *idev) 460*febf1dffSMark Brown { 461*febf1dffSMark Brown struct wm97xx *wm = input_get_drvdata(idev); 462*febf1dffSMark Brown 463*febf1dffSMark Brown wm->ts_workq = create_singlethread_workqueue("kwm97xx"); 464*febf1dffSMark Brown if (wm->ts_workq == NULL) { 465*febf1dffSMark Brown dev_err(wm->dev, 466*febf1dffSMark Brown "Failed to create workqueue\n"); 467*febf1dffSMark Brown return -EINVAL; 468*febf1dffSMark Brown } 469*febf1dffSMark Brown 470*febf1dffSMark Brown /* start digitiser */ 471*febf1dffSMark Brown if (wm->mach_ops && wm->mach_ops->acc_enabled) 472*febf1dffSMark Brown wm->codec->acc_enable(wm, 1); 473*febf1dffSMark Brown wm->codec->dig_enable(wm, 1); 474*febf1dffSMark Brown 475*febf1dffSMark Brown INIT_DELAYED_WORK(&wm->ts_reader, wm97xx_ts_reader); 476*febf1dffSMark Brown INIT_WORK(&wm->pen_event_work, wm97xx_pen_irq_worker); 477*febf1dffSMark Brown 478*febf1dffSMark Brown wm->ts_reader_min_interval = HZ >= 100 ? HZ / 100 : 1; 479*febf1dffSMark Brown if (wm->ts_reader_min_interval < 1) 480*febf1dffSMark Brown wm->ts_reader_min_interval = 1; 481*febf1dffSMark Brown wm->ts_reader_interval = wm->ts_reader_min_interval; 482*febf1dffSMark Brown 483*febf1dffSMark Brown wm->pen_is_down = 0; 484*febf1dffSMark Brown if (wm->pen_irq) 485*febf1dffSMark Brown wm97xx_init_pen_irq(wm); 486*febf1dffSMark Brown else 487*febf1dffSMark Brown dev_err(wm->dev, "No IRQ specified\n"); 488*febf1dffSMark Brown 489*febf1dffSMark Brown /* If we either don't have an interrupt for pen down events or 490*febf1dffSMark Brown * failed to acquire it then we need to poll. 491*febf1dffSMark Brown */ 492*febf1dffSMark Brown if (wm->pen_irq == 0) 493*febf1dffSMark Brown queue_delayed_work(wm->ts_workq, &wm->ts_reader, 494*febf1dffSMark Brown wm->ts_reader_interval); 495*febf1dffSMark Brown 496*febf1dffSMark Brown return 0; 497*febf1dffSMark Brown } 498*febf1dffSMark Brown 499*febf1dffSMark Brown /** 500*febf1dffSMark Brown * wm97xx_ts_input_close - Close the touch screen input device. 501*febf1dffSMark Brown * @idev: Input device to be closed. 502*febf1dffSMark Brown * 503*febf1dffSMark Brown * Called by the input sub system to close a wm97xx touchscreen 504*febf1dffSMark Brown * device. Kills the touchscreen thread and stops the touch 505*febf1dffSMark Brown * digitiser. 506*febf1dffSMark Brown */ 507*febf1dffSMark Brown 508*febf1dffSMark Brown static void wm97xx_ts_input_close(struct input_dev *idev) 509*febf1dffSMark Brown { 510*febf1dffSMark Brown struct wm97xx *wm = input_get_drvdata(idev); 511*febf1dffSMark Brown u16 reg; 512*febf1dffSMark Brown 513*febf1dffSMark Brown if (wm->pen_irq) { 514*febf1dffSMark Brown /* Return the interrupt to GPIO usage (disabling it) */ 515*febf1dffSMark Brown if (wm->id != WM9705_ID2) { 516*febf1dffSMark Brown BUG_ON(!wm->mach_ops->irq_gpio); 517*febf1dffSMark Brown reg = wm97xx_reg_read(wm, AC97_MISC_AFE); 518*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_MISC_AFE, 519*febf1dffSMark Brown reg | wm->mach_ops->irq_gpio); 520*febf1dffSMark Brown } 521*febf1dffSMark Brown 522*febf1dffSMark Brown free_irq(wm->pen_irq, wm); 523*febf1dffSMark Brown } 524*febf1dffSMark Brown 525*febf1dffSMark Brown wm->pen_is_down = 0; 526*febf1dffSMark Brown 527*febf1dffSMark Brown /* Balance out interrupt disables/enables */ 528*febf1dffSMark Brown if (cancel_work_sync(&wm->pen_event_work)) 529*febf1dffSMark Brown wm->mach_ops->irq_enable(wm, 1); 530*febf1dffSMark Brown 531*febf1dffSMark Brown /* ts_reader rearms itself so we need to explicitly stop it 532*febf1dffSMark Brown * before we destroy the workqueue. 533*febf1dffSMark Brown */ 534*febf1dffSMark Brown cancel_delayed_work_sync(&wm->ts_reader); 535*febf1dffSMark Brown 536*febf1dffSMark Brown destroy_workqueue(wm->ts_workq); 537*febf1dffSMark Brown 538*febf1dffSMark Brown /* stop digitiser */ 539*febf1dffSMark Brown wm->codec->dig_enable(wm, 0); 540*febf1dffSMark Brown if (wm->mach_ops && wm->mach_ops->acc_enabled) 541*febf1dffSMark Brown wm->codec->acc_enable(wm, 0); 542*febf1dffSMark Brown } 543*febf1dffSMark Brown 544*febf1dffSMark Brown static int wm97xx_probe(struct device *dev) 545*febf1dffSMark Brown { 546*febf1dffSMark Brown struct wm97xx *wm; 547*febf1dffSMark Brown int ret = 0, id = 0; 548*febf1dffSMark Brown 549*febf1dffSMark Brown wm = kzalloc(sizeof(struct wm97xx), GFP_KERNEL); 550*febf1dffSMark Brown if (!wm) 551*febf1dffSMark Brown return -ENOMEM; 552*febf1dffSMark Brown mutex_init(&wm->codec_mutex); 553*febf1dffSMark Brown 554*febf1dffSMark Brown wm->dev = dev; 555*febf1dffSMark Brown dev->driver_data = wm; 556*febf1dffSMark Brown wm->ac97 = to_ac97_t(dev); 557*febf1dffSMark Brown 558*febf1dffSMark Brown /* check that we have a supported codec */ 559*febf1dffSMark Brown id = wm97xx_reg_read(wm, AC97_VENDOR_ID1); 560*febf1dffSMark Brown if (id != WM97XX_ID1) { 561*febf1dffSMark Brown dev_err(dev, "Device with vendor %04x is not a wm97xx\n", id); 562*febf1dffSMark Brown ret = -ENODEV; 563*febf1dffSMark Brown goto alloc_err; 564*febf1dffSMark Brown } 565*febf1dffSMark Brown 566*febf1dffSMark Brown wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2); 567*febf1dffSMark Brown 568*febf1dffSMark Brown dev_info(wm->dev, "detected a wm97%02x codec\n", wm->id & 0xff); 569*febf1dffSMark Brown 570*febf1dffSMark Brown switch (wm->id & 0xff) { 571*febf1dffSMark Brown #ifdef CONFIG_TOUCHSCREEN_WM9705 572*febf1dffSMark Brown case 0x05: 573*febf1dffSMark Brown wm->codec = &wm9705_codec; 574*febf1dffSMark Brown break; 575*febf1dffSMark Brown #endif 576*febf1dffSMark Brown #ifdef CONFIG_TOUCHSCREEN_WM9712 577*febf1dffSMark Brown case 0x12: 578*febf1dffSMark Brown wm->codec = &wm9712_codec; 579*febf1dffSMark Brown break; 580*febf1dffSMark Brown #endif 581*febf1dffSMark Brown #ifdef CONFIG_TOUCHSCREEN_WM9713 582*febf1dffSMark Brown case 0x13: 583*febf1dffSMark Brown wm->codec = &wm9713_codec; 584*febf1dffSMark Brown break; 585*febf1dffSMark Brown #endif 586*febf1dffSMark Brown default: 587*febf1dffSMark Brown dev_err(wm->dev, "Support for wm97%02x not compiled in.\n", 588*febf1dffSMark Brown wm->id & 0xff); 589*febf1dffSMark Brown ret = -ENODEV; 590*febf1dffSMark Brown goto alloc_err; 591*febf1dffSMark Brown } 592*febf1dffSMark Brown 593*febf1dffSMark Brown wm->input_dev = input_allocate_device(); 594*febf1dffSMark Brown if (wm->input_dev == NULL) { 595*febf1dffSMark Brown ret = -ENOMEM; 596*febf1dffSMark Brown goto alloc_err; 597*febf1dffSMark Brown } 598*febf1dffSMark Brown 599*febf1dffSMark Brown /* set up touch configuration */ 600*febf1dffSMark Brown wm->input_dev->name = "wm97xx touchscreen"; 601*febf1dffSMark Brown wm->input_dev->open = wm97xx_ts_input_open; 602*febf1dffSMark Brown wm->input_dev->close = wm97xx_ts_input_close; 603*febf1dffSMark Brown set_bit(EV_ABS, wm->input_dev->evbit); 604*febf1dffSMark Brown set_bit(ABS_X, wm->input_dev->absbit); 605*febf1dffSMark Brown set_bit(ABS_Y, wm->input_dev->absbit); 606*febf1dffSMark Brown set_bit(ABS_PRESSURE, wm->input_dev->absbit); 607*febf1dffSMark Brown input_set_abs_params(wm->input_dev, ABS_X, abs_x[0], abs_x[1], 608*febf1dffSMark Brown abs_x[2], 0); 609*febf1dffSMark Brown input_set_abs_params(wm->input_dev, ABS_Y, abs_y[0], abs_y[1], 610*febf1dffSMark Brown abs_y[2], 0); 611*febf1dffSMark Brown input_set_abs_params(wm->input_dev, ABS_PRESSURE, abs_p[0], abs_p[1], 612*febf1dffSMark Brown abs_p[2], 0); 613*febf1dffSMark Brown input_set_drvdata(wm->input_dev, wm); 614*febf1dffSMark Brown wm->input_dev->dev.parent = dev; 615*febf1dffSMark Brown ret = input_register_device(wm->input_dev); 616*febf1dffSMark Brown if (ret < 0) 617*febf1dffSMark Brown goto dev_alloc_err; 618*febf1dffSMark Brown 619*febf1dffSMark Brown /* set up physical characteristics */ 620*febf1dffSMark Brown wm->codec->phy_init(wm); 621*febf1dffSMark Brown 622*febf1dffSMark Brown /* load gpio cache */ 623*febf1dffSMark Brown wm->gpio[0] = wm97xx_reg_read(wm, AC97_GPIO_CFG); 624*febf1dffSMark Brown wm->gpio[1] = wm97xx_reg_read(wm, AC97_GPIO_POLARITY); 625*febf1dffSMark Brown wm->gpio[2] = wm97xx_reg_read(wm, AC97_GPIO_STICKY); 626*febf1dffSMark Brown wm->gpio[3] = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP); 627*febf1dffSMark Brown wm->gpio[4] = wm97xx_reg_read(wm, AC97_GPIO_STATUS); 628*febf1dffSMark Brown wm->gpio[5] = wm97xx_reg_read(wm, AC97_MISC_AFE); 629*febf1dffSMark Brown 630*febf1dffSMark Brown /* register our battery device */ 631*febf1dffSMark Brown wm->battery_dev = platform_device_alloc("wm97xx-battery", -1); 632*febf1dffSMark Brown if (!wm->battery_dev) { 633*febf1dffSMark Brown ret = -ENOMEM; 634*febf1dffSMark Brown goto batt_err; 635*febf1dffSMark Brown } 636*febf1dffSMark Brown platform_set_drvdata(wm->battery_dev, wm); 637*febf1dffSMark Brown wm->battery_dev->dev.parent = dev; 638*febf1dffSMark Brown ret = platform_device_add(wm->battery_dev); 639*febf1dffSMark Brown if (ret < 0) 640*febf1dffSMark Brown goto batt_reg_err; 641*febf1dffSMark Brown 642*febf1dffSMark Brown /* register our extended touch device (for machine specific 643*febf1dffSMark Brown * extensions) */ 644*febf1dffSMark Brown wm->touch_dev = platform_device_alloc("wm97xx-touch", -1); 645*febf1dffSMark Brown if (!wm->touch_dev) { 646*febf1dffSMark Brown ret = -ENOMEM; 647*febf1dffSMark Brown goto touch_err; 648*febf1dffSMark Brown } 649*febf1dffSMark Brown platform_set_drvdata(wm->touch_dev, wm); 650*febf1dffSMark Brown wm->touch_dev->dev.parent = dev; 651*febf1dffSMark Brown ret = platform_device_add(wm->touch_dev); 652*febf1dffSMark Brown if (ret < 0) 653*febf1dffSMark Brown goto touch_reg_err; 654*febf1dffSMark Brown 655*febf1dffSMark Brown return ret; 656*febf1dffSMark Brown 657*febf1dffSMark Brown touch_reg_err: 658*febf1dffSMark Brown platform_device_put(wm->touch_dev); 659*febf1dffSMark Brown touch_err: 660*febf1dffSMark Brown platform_device_unregister(wm->battery_dev); 661*febf1dffSMark Brown wm->battery_dev = NULL; 662*febf1dffSMark Brown batt_reg_err: 663*febf1dffSMark Brown platform_device_put(wm->battery_dev); 664*febf1dffSMark Brown batt_err: 665*febf1dffSMark Brown input_unregister_device(wm->input_dev); 666*febf1dffSMark Brown wm->input_dev = NULL; 667*febf1dffSMark Brown dev_alloc_err: 668*febf1dffSMark Brown input_free_device(wm->input_dev); 669*febf1dffSMark Brown alloc_err: 670*febf1dffSMark Brown kfree(wm); 671*febf1dffSMark Brown 672*febf1dffSMark Brown return ret; 673*febf1dffSMark Brown } 674*febf1dffSMark Brown 675*febf1dffSMark Brown static int wm97xx_remove(struct device *dev) 676*febf1dffSMark Brown { 677*febf1dffSMark Brown struct wm97xx *wm = dev_get_drvdata(dev); 678*febf1dffSMark Brown 679*febf1dffSMark Brown platform_device_unregister(wm->battery_dev); 680*febf1dffSMark Brown platform_device_unregister(wm->touch_dev); 681*febf1dffSMark Brown input_unregister_device(wm->input_dev); 682*febf1dffSMark Brown kfree(wm); 683*febf1dffSMark Brown 684*febf1dffSMark Brown return 0; 685*febf1dffSMark Brown } 686*febf1dffSMark Brown 687*febf1dffSMark Brown #ifdef CONFIG_PM 688*febf1dffSMark Brown static int wm97xx_suspend(struct device *dev, pm_message_t state) 689*febf1dffSMark Brown { 690*febf1dffSMark Brown struct wm97xx *wm = dev_get_drvdata(dev); 691*febf1dffSMark Brown 692*febf1dffSMark Brown if (wm->input_dev->users) 693*febf1dffSMark Brown cancel_delayed_work_sync(&wm->ts_reader); 694*febf1dffSMark Brown 695*febf1dffSMark Brown return 0; 696*febf1dffSMark Brown } 697*febf1dffSMark Brown 698*febf1dffSMark Brown static int wm97xx_resume(struct device *dev) 699*febf1dffSMark Brown { 700*febf1dffSMark Brown struct wm97xx *wm = dev_get_drvdata(dev); 701*febf1dffSMark Brown 702*febf1dffSMark Brown /* restore digitiser and gpios */ 703*febf1dffSMark Brown if (wm->id == WM9713_ID2) { 704*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig[0]); 705*febf1dffSMark Brown wm97xx_reg_write(wm, 0x5a, wm->misc); 706*febf1dffSMark Brown if (wm->input_dev->users) { 707*febf1dffSMark Brown u16 reg; 708*febf1dffSMark Brown reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) & 0x7fff; 709*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg); 710*febf1dffSMark Brown } 711*febf1dffSMark Brown } 712*febf1dffSMark Brown 713*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig[1]); 714*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2]); 715*febf1dffSMark Brown 716*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_CFG, wm->gpio[0]); 717*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_POLARITY, wm->gpio[1]); 718*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_STICKY, wm->gpio[2]); 719*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, wm->gpio[3]); 720*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_GPIO_STATUS, wm->gpio[4]); 721*febf1dffSMark Brown wm97xx_reg_write(wm, AC97_MISC_AFE, wm->gpio[5]); 722*febf1dffSMark Brown 723*febf1dffSMark Brown if (wm->input_dev->users && !wm->pen_irq) { 724*febf1dffSMark Brown wm->ts_reader_interval = wm->ts_reader_min_interval; 725*febf1dffSMark Brown queue_delayed_work(wm->ts_workq, &wm->ts_reader, 726*febf1dffSMark Brown wm->ts_reader_interval); 727*febf1dffSMark Brown } 728*febf1dffSMark Brown 729*febf1dffSMark Brown return 0; 730*febf1dffSMark Brown } 731*febf1dffSMark Brown 732*febf1dffSMark Brown #else 733*febf1dffSMark Brown #define wm97xx_suspend NULL 734*febf1dffSMark Brown #define wm97xx_resume NULL 735*febf1dffSMark Brown #endif 736*febf1dffSMark Brown 737*febf1dffSMark Brown /* 738*febf1dffSMark Brown * Machine specific operations 739*febf1dffSMark Brown */ 740*febf1dffSMark Brown int wm97xx_register_mach_ops(struct wm97xx *wm, 741*febf1dffSMark Brown struct wm97xx_mach_ops *mach_ops) 742*febf1dffSMark Brown { 743*febf1dffSMark Brown mutex_lock(&wm->codec_mutex); 744*febf1dffSMark Brown if (wm->mach_ops) { 745*febf1dffSMark Brown mutex_unlock(&wm->codec_mutex); 746*febf1dffSMark Brown return -EINVAL; 747*febf1dffSMark Brown } 748*febf1dffSMark Brown wm->mach_ops = mach_ops; 749*febf1dffSMark Brown mutex_unlock(&wm->codec_mutex); 750*febf1dffSMark Brown 751*febf1dffSMark Brown return 0; 752*febf1dffSMark Brown } 753*febf1dffSMark Brown EXPORT_SYMBOL_GPL(wm97xx_register_mach_ops); 754*febf1dffSMark Brown 755*febf1dffSMark Brown void wm97xx_unregister_mach_ops(struct wm97xx *wm) 756*febf1dffSMark Brown { 757*febf1dffSMark Brown mutex_lock(&wm->codec_mutex); 758*febf1dffSMark Brown wm->mach_ops = NULL; 759*febf1dffSMark Brown mutex_unlock(&wm->codec_mutex); 760*febf1dffSMark Brown } 761*febf1dffSMark Brown EXPORT_SYMBOL_GPL(wm97xx_unregister_mach_ops); 762*febf1dffSMark Brown 763*febf1dffSMark Brown static struct device_driver wm97xx_driver = { 764*febf1dffSMark Brown .name = "ac97", 765*febf1dffSMark Brown .bus = &ac97_bus_type, 766*febf1dffSMark Brown .owner = THIS_MODULE, 767*febf1dffSMark Brown .probe = wm97xx_probe, 768*febf1dffSMark Brown .remove = wm97xx_remove, 769*febf1dffSMark Brown .suspend = wm97xx_suspend, 770*febf1dffSMark Brown .resume = wm97xx_resume, 771*febf1dffSMark Brown }; 772*febf1dffSMark Brown 773*febf1dffSMark Brown static int __init wm97xx_init(void) 774*febf1dffSMark Brown { 775*febf1dffSMark Brown return driver_register(&wm97xx_driver); 776*febf1dffSMark Brown } 777*febf1dffSMark Brown 778*febf1dffSMark Brown static void __exit wm97xx_exit(void) 779*febf1dffSMark Brown { 780*febf1dffSMark Brown driver_unregister(&wm97xx_driver); 781*febf1dffSMark Brown } 782*febf1dffSMark Brown 783*febf1dffSMark Brown module_init(wm97xx_init); 784*febf1dffSMark Brown module_exit(wm97xx_exit); 785*febf1dffSMark Brown 786*febf1dffSMark Brown /* Module information */ 787*febf1dffSMark Brown MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>"); 788*febf1dffSMark Brown MODULE_DESCRIPTION("WM97xx Core - Touch Screen / AUX ADC / GPIO Driver"); 789*febf1dffSMark Brown MODULE_LICENSE("GPL"); 790