1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * wm9705.c -- Codec driver for Wolfson WM9705 AC97 Codec.
5 * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
6 * Author: Liam Girdwood <lrg@slimlogic.co.uk>
7 * Parts Copyright : Ian Molton <spyro@f2s.com>
8 * Andrew Zabolotny <zap@homelink.ru>
9 * Russell King <rmk@arm.linux.org.uk>
12 #include <linux/module.h>
13 #include <linux/moduleparam.h>
14 #include <linux/kernel.h>
15 #include <linux/input.h>
16 #include <linux/delay.h>
17 #include <linux/bitops.h>
18 #include <linux/wm97xx.h>
20 #define TS_NAME "wm97xx"
21 #define WM9705_VERSION "1.00"
22 #define DEFAULT_PRESSURE 0xb0c0
29 * Set current used for pressure measurement.
31 * Set pil = 2 to use 400uA
32 * pil = 1 to use 200uA and
33 * pil = 0 to disable pressure measurement.
35 * This is used to increase the range of values returned by the adc
36 * when measureing touchpanel pressure.
39 module_param(pil
, int, 0);
40 MODULE_PARM_DESC(pil
, "Set current used for pressure measurement.");
43 * Set threshold for pressure measurement.
45 * Pen down pressure below threshold is ignored.
47 static int pressure
= DEFAULT_PRESSURE
& 0xfff;
48 module_param(pressure
, int, 0);
49 MODULE_PARM_DESC(pressure
, "Set threshold for pressure measurement.");
52 * Set adc sample delay.
54 * For accurate touchpanel measurements, some settling time may be
55 * required between the switch matrix applying a voltage across the
56 * touchpanel plate and the ADC sampling the signal.
58 * This delay can be set by setting delay = n, where n is the array
59 * position of the delay in the array delay_table below.
60 * Long delays > 1ms are supported for completeness, but are not
64 module_param(delay
, int, 0);
65 MODULE_PARM_DESC(delay
, "Set adc sample delay.");
68 * Pen detect comparator threshold.
70 * 0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold
71 * i.e. 1 = Vmid/15 threshold
72 * 15 = Vmid/1 threshold
74 * Adjust this value if you are having problems with pen detect not
75 * detecting any down events.
78 module_param(pdd
, int, 0);
79 MODULE_PARM_DESC(pdd
, "Set pen detect comparator threshold");
82 * Set adc mask function.
84 * Sources of glitch noise, such as signals driving an LCD display, may feed
85 * through to the touch screen plates and affect measurement accuracy. In
86 * order to minimise this, a signal may be applied to the MASK pin to delay or
87 * synchronise the sampling.
89 * 0 = No delay or sync
90 * 1 = High on pin stops conversions
91 * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
92 * 3 = Edge triggered, edge on pin starts conversion after delay param
95 module_param(mask
, int, 0);
96 MODULE_PARM_DESC(mask
, "Set adc mask function.");
99 * ADC sample delay times in uS
101 static const int delay_table
[] = {
102 21, /* 1 AC97 Link frames */
117 0 /* No delay, switch matrix always on */
121 * Delay after issuing a POLL command.
123 * The delay is 3 AC97 link frames + the touchpanel settling delay
125 static inline void poll_delay(int d
)
127 udelay(3 * AC97_LINK_FRAME
+ delay_table
[d
]);
131 * set up the physical settings of the WM9705
133 static void wm9705_phy_init(struct wm97xx
*wm
)
135 u16 dig1
= 0, dig2
= WM97XX_RPR
;
138 * mute VIDEO and AUX as they share X and Y touchscreen
139 * inputs on the WM9705
141 wm97xx_reg_write(wm
, AC97_AUX
, 0x8000);
142 wm97xx_reg_write(wm
, AC97_VIDEO
, 0x8000);
144 /* touchpanel pressure current*/
148 "setting pressure measurement current to 400uA.");
151 "setting pressure measurement current to 200uA.");
155 /* polling mode sample settling delay */
157 if (delay
< 0 || delay
> 15) {
158 dev_dbg(wm
->dev
, "supplied delay out of range.");
163 dig1
|= WM97XX_DELAY(delay
);
164 dev_dbg(wm
->dev
, "setting adc sample delay to %d u Secs.",
168 dig2
|= (pdd
& 0x000f);
169 dev_dbg(wm
->dev
, "setting pdd to Vmid/%d", 1 - (pdd
& 0x000f));
172 dig2
|= ((mask
& 0x3) << 4);
174 wm97xx_reg_write(wm
, AC97_WM97XX_DIGITISER1
, dig1
);
175 wm97xx_reg_write(wm
, AC97_WM97XX_DIGITISER2
, dig2
);
178 static void wm9705_dig_enable(struct wm97xx
*wm
, int enable
)
181 wm97xx_reg_write(wm
, AC97_WM97XX_DIGITISER2
,
182 wm
->dig
[2] | WM97XX_PRP_DET_DIG
);
183 wm97xx_reg_read(wm
, AC97_WM97XX_DIGITISER_RD
); /* dummy read */
185 wm97xx_reg_write(wm
, AC97_WM97XX_DIGITISER2
,
186 wm
->dig
[2] & ~WM97XX_PRP_DET_DIG
);
189 static void wm9705_aux_prepare(struct wm97xx
*wm
)
191 memcpy(wm
->dig_save
, wm
->dig
, sizeof(wm
->dig
));
192 wm97xx_reg_write(wm
, AC97_WM97XX_DIGITISER1
, 0);
193 wm97xx_reg_write(wm
, AC97_WM97XX_DIGITISER2
, WM97XX_PRP_DET_DIG
);
196 static void wm9705_dig_restore(struct wm97xx
*wm
)
198 wm97xx_reg_write(wm
, AC97_WM97XX_DIGITISER1
, wm
->dig_save
[1]);
199 wm97xx_reg_write(wm
, AC97_WM97XX_DIGITISER2
, wm
->dig_save
[2]);
202 static inline int is_pden(struct wm97xx
*wm
)
204 return wm
->dig
[2] & WM9705_PDEN
;
208 * Read a sample from the WM9705 adc in polling mode.
210 static int wm9705_poll_sample(struct wm97xx
*wm
, int adcsel
, int *sample
)
212 int timeout
= 5 * delay
;
213 bool wants_pen
= adcsel
& WM97XX_PEN_DOWN
;
215 if (wants_pen
&& !wm
->pen_probably_down
) {
216 u16 data
= wm97xx_reg_read(wm
, AC97_WM97XX_DIGITISER_RD
);
217 if (!(data
& WM97XX_PEN_DOWN
))
219 wm
->pen_probably_down
= 1;
222 /* set up digitiser */
223 if (wm
->mach_ops
&& wm
->mach_ops
->pre_sample
)
224 wm
->mach_ops
->pre_sample(adcsel
);
225 wm97xx_reg_write(wm
, AC97_WM97XX_DIGITISER1
, (adcsel
& WM97XX_ADCSEL_MASK
)
226 | WM97XX_POLL
| WM97XX_DELAY(delay
));
228 /* wait 3 AC97 time slots + delay for conversion */
231 /* wait for POLL to go low */
232 while ((wm97xx_reg_read(wm
, AC97_WM97XX_DIGITISER1
) & WM97XX_POLL
)
234 udelay(AC97_LINK_FRAME
);
239 /* If PDEN is set, we can get a timeout when pen goes up */
241 wm
->pen_probably_down
= 0;
243 dev_dbg(wm
->dev
, "adc sample timeout");
247 *sample
= wm97xx_reg_read(wm
, AC97_WM97XX_DIGITISER_RD
);
248 if (wm
->mach_ops
&& wm
->mach_ops
->post_sample
)
249 wm
->mach_ops
->post_sample(adcsel
);
251 /* check we have correct sample */
252 if ((*sample
^ adcsel
) & WM97XX_ADCSEL_MASK
) {
253 dev_dbg(wm
->dev
, "adc wrong sample, wanted %x got %x",
254 adcsel
& WM97XX_ADCSEL_MASK
,
255 *sample
& WM97XX_ADCSEL_MASK
);
259 if (wants_pen
&& !(*sample
& WM97XX_PEN_DOWN
)) {
260 wm
->pen_probably_down
= 0;
268 * Sample the WM9705 touchscreen in polling mode
270 static int wm9705_poll_touch(struct wm97xx
*wm
, struct wm97xx_data
*data
)
274 rc
= wm9705_poll_sample(wm
, WM97XX_ADCSEL_X
| WM97XX_PEN_DOWN
, &data
->x
);
277 rc
= wm9705_poll_sample(wm
, WM97XX_ADCSEL_Y
| WM97XX_PEN_DOWN
, &data
->y
);
281 rc
= wm9705_poll_sample(wm
, WM97XX_ADCSEL_PRES
| WM97XX_PEN_DOWN
, &data
->p
);
285 data
->p
= DEFAULT_PRESSURE
;
291 * Enable WM9705 continuous mode, i.e. touch data is streamed across
294 static int wm9705_acc_enable(struct wm97xx
*wm
, int enable
)
303 /* continuous mode */
304 if (wm
->mach_ops
->acc_startup
&&
305 (ret
= wm
->mach_ops
->acc_startup(wm
)) < 0)
307 dig1
&= ~(WM97XX_CM_RATE_MASK
| WM97XX_ADCSEL_MASK
|
308 WM97XX_DELAY_MASK
| WM97XX_SLT_MASK
);
309 dig1
|= WM97XX_CTC
| WM97XX_COO
| WM97XX_SLEN
|
310 WM97XX_DELAY(delay
) |
311 WM97XX_SLT(wm
->acc_slot
) |
312 WM97XX_RATE(wm
->acc_rate
);
314 dig1
|= WM97XX_ADCSEL_PRES
;
317 dig1
&= ~(WM97XX_CTC
| WM97XX_COO
| WM97XX_SLEN
);
318 dig2
&= ~WM9705_PDEN
;
319 if (wm
->mach_ops
->acc_shutdown
)
320 wm
->mach_ops
->acc_shutdown(wm
);
323 wm97xx_reg_write(wm
, AC97_WM97XX_DIGITISER1
, dig1
);
324 wm97xx_reg_write(wm
, AC97_WM97XX_DIGITISER2
, dig2
);
329 struct wm97xx_codec_drv wm9705_codec
= {
332 .poll_sample
= wm9705_poll_sample
,
333 .poll_touch
= wm9705_poll_touch
,
334 .acc_enable
= wm9705_acc_enable
,
335 .phy_init
= wm9705_phy_init
,
336 .dig_enable
= wm9705_dig_enable
,
337 .dig_restore
= wm9705_dig_restore
,
338 .aux_prepare
= wm9705_aux_prepare
,
340 EXPORT_SYMBOL_GPL(wm9705_codec
);
342 /* Module information */
343 MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
344 MODULE_DESCRIPTION("WM9705 Touch Screen Driver");
345 MODULE_LICENSE("GPL");