xref: /linux/drivers/input/touchscreen/wm97xx-core.c (revision febf1dff119ef27ee22a54d40f284d2454f00d8d)
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