1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2f1c0a02fSMark Brown /*
3f1c0a02fSMark Brown * wm8903.c -- WM8903 ALSA SoC Audio driver
4f1c0a02fSMark Brown *
520c5fd39SMark Brown * Copyright 2008-12 Wolfson Microelectronics
60bf79ef2SStephen Warren * Copyright 2011-2012 NVIDIA, Inc.
7f1c0a02fSMark Brown *
8f1c0a02fSMark Brown * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
9f1c0a02fSMark Brown *
10f1c0a02fSMark Brown * TODO:
11f1c0a02fSMark Brown * - TDM mode configuration.
12f1c0a02fSMark Brown */
13f1c0a02fSMark Brown
14f1c0a02fSMark Brown #include <linux/module.h>
15f1c0a02fSMark Brown #include <linux/moduleparam.h>
16f1c0a02fSMark Brown #include <linux/init.h>
178abd16a6SMark Brown #include <linux/completion.h>
18f1c0a02fSMark Brown #include <linux/delay.h>
198f416066SLinus Walleij #include <linux/gpio/driver.h>
20f1c0a02fSMark Brown #include <linux/pm.h>
21f1c0a02fSMark Brown #include <linux/i2c.h>
22ee244ce4SMark Brown #include <linux/regmap.h>
23b3bbef45SLinus Walleij #include <linux/regulator/consumer.h>
245a0e3ad6STejun Heo #include <linux/slab.h>
259d35f3e1SStephen Warren #include <linux/irq.h>
2678660af7SLars-Peter Clausen #include <linux/mutex.h>
27f1c0a02fSMark Brown #include <sound/core.h>
287245387eSMark Brown #include <sound/jack.h>
29f1c0a02fSMark Brown #include <sound/pcm.h>
30f1c0a02fSMark Brown #include <sound/pcm_params.h>
31f1c0a02fSMark Brown #include <sound/tlv.h>
32f1c0a02fSMark Brown #include <sound/soc.h>
33f1c0a02fSMark Brown #include <sound/initval.h>
348abd16a6SMark Brown #include <sound/wm8903.h>
352bbb5d66SMark Brown #include <trace/events/asoc.h>
36f1c0a02fSMark Brown
37f1c0a02fSMark Brown #include "wm8903.h"
38f1c0a02fSMark Brown
39f1c0a02fSMark Brown /* Register defaults at reset */
40ee244ce4SMark Brown static const struct reg_default wm8903_reg_defaults[] = {
41ee244ce4SMark Brown { 4, 0x0018 }, /* R4 - Bias Control 0 */
42ee244ce4SMark Brown { 5, 0x0000 }, /* R5 - VMID Control 0 */
43ee244ce4SMark Brown { 6, 0x0000 }, /* R6 - Mic Bias Control 0 */
44ee244ce4SMark Brown { 8, 0x0001 }, /* R8 - Analogue DAC 0 */
45ee244ce4SMark Brown { 10, 0x0001 }, /* R10 - Analogue ADC 0 */
46ee244ce4SMark Brown { 12, 0x0000 }, /* R12 - Power Management 0 */
47ee244ce4SMark Brown { 13, 0x0000 }, /* R13 - Power Management 1 */
48ee244ce4SMark Brown { 14, 0x0000 }, /* R14 - Power Management 2 */
49ee244ce4SMark Brown { 15, 0x0000 }, /* R15 - Power Management 3 */
50ee244ce4SMark Brown { 16, 0x0000 }, /* R16 - Power Management 4 */
51ee244ce4SMark Brown { 17, 0x0000 }, /* R17 - Power Management 5 */
52ee244ce4SMark Brown { 18, 0x0000 }, /* R18 - Power Management 6 */
53ee244ce4SMark Brown { 20, 0x0400 }, /* R20 - Clock Rates 0 */
54ee244ce4SMark Brown { 21, 0x0D07 }, /* R21 - Clock Rates 1 */
55ee244ce4SMark Brown { 22, 0x0000 }, /* R22 - Clock Rates 2 */
56ee244ce4SMark Brown { 24, 0x0050 }, /* R24 - Audio Interface 0 */
57ee244ce4SMark Brown { 25, 0x0242 }, /* R25 - Audio Interface 1 */
58ee244ce4SMark Brown { 26, 0x0008 }, /* R26 - Audio Interface 2 */
59ee244ce4SMark Brown { 27, 0x0022 }, /* R27 - Audio Interface 3 */
60ee244ce4SMark Brown { 30, 0x00C0 }, /* R30 - DAC Digital Volume Left */
61ee244ce4SMark Brown { 31, 0x00C0 }, /* R31 - DAC Digital Volume Right */
62ee244ce4SMark Brown { 32, 0x0000 }, /* R32 - DAC Digital 0 */
63ee244ce4SMark Brown { 33, 0x0000 }, /* R33 - DAC Digital 1 */
64ee244ce4SMark Brown { 36, 0x00C0 }, /* R36 - ADC Digital Volume Left */
65ee244ce4SMark Brown { 37, 0x00C0 }, /* R37 - ADC Digital Volume Right */
66ee244ce4SMark Brown { 38, 0x0000 }, /* R38 - ADC Digital 0 */
67ee244ce4SMark Brown { 39, 0x0073 }, /* R39 - Digital Microphone 0 */
68ee244ce4SMark Brown { 40, 0x09BF }, /* R40 - DRC 0 */
69ee244ce4SMark Brown { 41, 0x3241 }, /* R41 - DRC 1 */
70ee244ce4SMark Brown { 42, 0x0020 }, /* R42 - DRC 2 */
71ee244ce4SMark Brown { 43, 0x0000 }, /* R43 - DRC 3 */
72ee244ce4SMark Brown { 44, 0x0085 }, /* R44 - Analogue Left Input 0 */
73ee244ce4SMark Brown { 45, 0x0085 }, /* R45 - Analogue Right Input 0 */
74ee244ce4SMark Brown { 46, 0x0044 }, /* R46 - Analogue Left Input 1 */
75ee244ce4SMark Brown { 47, 0x0044 }, /* R47 - Analogue Right Input 1 */
76ee244ce4SMark Brown { 50, 0x0008 }, /* R50 - Analogue Left Mix 0 */
77ee244ce4SMark Brown { 51, 0x0004 }, /* R51 - Analogue Right Mix 0 */
78ee244ce4SMark Brown { 52, 0x0000 }, /* R52 - Analogue Spk Mix Left 0 */
79ee244ce4SMark Brown { 53, 0x0000 }, /* R53 - Analogue Spk Mix Left 1 */
80ee244ce4SMark Brown { 54, 0x0000 }, /* R54 - Analogue Spk Mix Right 0 */
81ee244ce4SMark Brown { 55, 0x0000 }, /* R55 - Analogue Spk Mix Right 1 */
82ee244ce4SMark Brown { 57, 0x002D }, /* R57 - Analogue OUT1 Left */
83ee244ce4SMark Brown { 58, 0x002D }, /* R58 - Analogue OUT1 Right */
84ee244ce4SMark Brown { 59, 0x0039 }, /* R59 - Analogue OUT2 Left */
85ee244ce4SMark Brown { 60, 0x0039 }, /* R60 - Analogue OUT2 Right */
86ee244ce4SMark Brown { 62, 0x0139 }, /* R62 - Analogue OUT3 Left */
87ee244ce4SMark Brown { 63, 0x0139 }, /* R63 - Analogue OUT3 Right */
88ee244ce4SMark Brown { 64, 0x0000 }, /* R65 - Analogue SPK Output Control 0 */
89ee244ce4SMark Brown { 67, 0x0010 }, /* R67 - DC Servo 0 */
90ee244ce4SMark Brown { 69, 0x00A4 }, /* R69 - DC Servo 2 */
91ee244ce4SMark Brown { 90, 0x0000 }, /* R90 - Analogue HP 0 */
92ee244ce4SMark Brown { 94, 0x0000 }, /* R94 - Analogue Lineout 0 */
93ee244ce4SMark Brown { 98, 0x0000 }, /* R98 - Charge Pump 0 */
94ee244ce4SMark Brown { 104, 0x0000 }, /* R104 - Class W 0 */
95ee244ce4SMark Brown { 108, 0x0000 }, /* R108 - Write Sequencer 0 */
96ee244ce4SMark Brown { 109, 0x0000 }, /* R109 - Write Sequencer 1 */
97ee244ce4SMark Brown { 110, 0x0000 }, /* R110 - Write Sequencer 2 */
98ee244ce4SMark Brown { 111, 0x0000 }, /* R111 - Write Sequencer 3 */
99ee244ce4SMark Brown { 112, 0x0000 }, /* R112 - Write Sequencer 4 */
100ee244ce4SMark Brown { 114, 0x0000 }, /* R114 - Control Interface */
101ee244ce4SMark Brown { 116, 0x00A8 }, /* R116 - GPIO Control 1 */
102ee244ce4SMark Brown { 117, 0x00A8 }, /* R117 - GPIO Control 2 */
103ee244ce4SMark Brown { 118, 0x00A8 }, /* R118 - GPIO Control 3 */
104ee244ce4SMark Brown { 119, 0x0220 }, /* R119 - GPIO Control 4 */
105ee244ce4SMark Brown { 120, 0x01A0 }, /* R120 - GPIO Control 5 */
106ee244ce4SMark Brown { 122, 0xFFFF }, /* R122 - Interrupt Status 1 Mask */
107ee244ce4SMark Brown { 123, 0x0000 }, /* R123 - Interrupt Polarity 1 */
108ee244ce4SMark Brown { 126, 0x0000 }, /* R126 - Interrupt Control */
109ee244ce4SMark Brown { 129, 0x0000 }, /* R129 - Control Interface Test 1 */
110ee244ce4SMark Brown { 149, 0x6810 }, /* R149 - Charge Pump Test 1 */
111ee244ce4SMark Brown { 164, 0x0028 }, /* R164 - Clock Rate Test 4 */
112ee244ce4SMark Brown { 172, 0x0000 }, /* R172 - Analogue Output Bias 0 */
113f1c0a02fSMark Brown };
114f1c0a02fSMark Brown
115b3bbef45SLinus Walleij #define WM8903_NUM_SUPPLIES 4
116b3bbef45SLinus Walleij static const char *wm8903_supply_names[WM8903_NUM_SUPPLIES] = {
117b3bbef45SLinus Walleij "AVDD",
118b3bbef45SLinus Walleij "CPVDD",
119b3bbef45SLinus Walleij "DBVDD",
120b3bbef45SLinus Walleij "DCVDD",
121b3bbef45SLinus Walleij };
122b3bbef45SLinus Walleij
123d58d5d55SMark Brown struct wm8903_priv {
124c0eb27cfSStephen Warren struct wm8903_platform_data *pdata;
1250bf79ef2SStephen Warren struct device *dev;
126ee244ce4SMark Brown struct regmap *regmap;
127b3bbef45SLinus Walleij struct regulator_bulk_data supplies[WM8903_NUM_SUPPLIES];
128f0fba2adSLiam Girdwood
129d58d5d55SMark Brown int sysclk;
130f0fba2adSLiam Girdwood int irq;
131d58d5d55SMark Brown
13278660af7SLars-Peter Clausen struct mutex lock;
13369fff9bbSMark Brown int fs;
13469fff9bbSMark Brown int deemph;
13569fff9bbSMark Brown
136c5b6a9feSMark Brown int dcs_pending;
137c5b6a9feSMark Brown int dcs_cache[4];
138c5b6a9feSMark Brown
139f2c1fe09SMark Brown /* Reference count */
140d58d5d55SMark Brown int class_w_users;
141d58d5d55SMark Brown
1427245387eSMark Brown struct snd_soc_jack *mic_jack;
1437245387eSMark Brown int mic_det;
1447245387eSMark Brown int mic_short;
1457245387eSMark Brown int mic_last_report;
1467245387eSMark Brown int mic_delay;
1477cfe5617SStephen Warren
1487cfe5617SStephen Warren #ifdef CONFIG_GPIOLIB
1497cfe5617SStephen Warren struct gpio_chip gpio_chip;
1507cfe5617SStephen Warren #endif
151d58d5d55SMark Brown };
152d58d5d55SMark Brown
wm8903_readable_register(struct device * dev,unsigned int reg)153ee244ce4SMark Brown static bool wm8903_readable_register(struct device *dev, unsigned int reg)
154ee244ce4SMark Brown {
155ee244ce4SMark Brown switch (reg) {
156ee244ce4SMark Brown case WM8903_SW_RESET_AND_ID:
157ee244ce4SMark Brown case WM8903_REVISION_NUMBER:
158ee244ce4SMark Brown case WM8903_BIAS_CONTROL_0:
159ee244ce4SMark Brown case WM8903_VMID_CONTROL_0:
160ee244ce4SMark Brown case WM8903_MIC_BIAS_CONTROL_0:
161ee244ce4SMark Brown case WM8903_ANALOGUE_DAC_0:
162ee244ce4SMark Brown case WM8903_ANALOGUE_ADC_0:
163ee244ce4SMark Brown case WM8903_POWER_MANAGEMENT_0:
164ee244ce4SMark Brown case WM8903_POWER_MANAGEMENT_1:
165ee244ce4SMark Brown case WM8903_POWER_MANAGEMENT_2:
166ee244ce4SMark Brown case WM8903_POWER_MANAGEMENT_3:
167ee244ce4SMark Brown case WM8903_POWER_MANAGEMENT_4:
168ee244ce4SMark Brown case WM8903_POWER_MANAGEMENT_5:
169ee244ce4SMark Brown case WM8903_POWER_MANAGEMENT_6:
170ee244ce4SMark Brown case WM8903_CLOCK_RATES_0:
171ee244ce4SMark Brown case WM8903_CLOCK_RATES_1:
172ee244ce4SMark Brown case WM8903_CLOCK_RATES_2:
173ee244ce4SMark Brown case WM8903_AUDIO_INTERFACE_0:
174ee244ce4SMark Brown case WM8903_AUDIO_INTERFACE_1:
175ee244ce4SMark Brown case WM8903_AUDIO_INTERFACE_2:
176ee244ce4SMark Brown case WM8903_AUDIO_INTERFACE_3:
177ee244ce4SMark Brown case WM8903_DAC_DIGITAL_VOLUME_LEFT:
178ee244ce4SMark Brown case WM8903_DAC_DIGITAL_VOLUME_RIGHT:
179ee244ce4SMark Brown case WM8903_DAC_DIGITAL_0:
180ee244ce4SMark Brown case WM8903_DAC_DIGITAL_1:
181ee244ce4SMark Brown case WM8903_ADC_DIGITAL_VOLUME_LEFT:
182ee244ce4SMark Brown case WM8903_ADC_DIGITAL_VOLUME_RIGHT:
183ee244ce4SMark Brown case WM8903_ADC_DIGITAL_0:
184ee244ce4SMark Brown case WM8903_DIGITAL_MICROPHONE_0:
185ee244ce4SMark Brown case WM8903_DRC_0:
186ee244ce4SMark Brown case WM8903_DRC_1:
187ee244ce4SMark Brown case WM8903_DRC_2:
188ee244ce4SMark Brown case WM8903_DRC_3:
189ee244ce4SMark Brown case WM8903_ANALOGUE_LEFT_INPUT_0:
190ee244ce4SMark Brown case WM8903_ANALOGUE_RIGHT_INPUT_0:
191ee244ce4SMark Brown case WM8903_ANALOGUE_LEFT_INPUT_1:
192ee244ce4SMark Brown case WM8903_ANALOGUE_RIGHT_INPUT_1:
193ee244ce4SMark Brown case WM8903_ANALOGUE_LEFT_MIX_0:
194ee244ce4SMark Brown case WM8903_ANALOGUE_RIGHT_MIX_0:
195ee244ce4SMark Brown case WM8903_ANALOGUE_SPK_MIX_LEFT_0:
196ee244ce4SMark Brown case WM8903_ANALOGUE_SPK_MIX_LEFT_1:
197ee244ce4SMark Brown case WM8903_ANALOGUE_SPK_MIX_RIGHT_0:
198ee244ce4SMark Brown case WM8903_ANALOGUE_SPK_MIX_RIGHT_1:
199ee244ce4SMark Brown case WM8903_ANALOGUE_OUT1_LEFT:
200ee244ce4SMark Brown case WM8903_ANALOGUE_OUT1_RIGHT:
201ee244ce4SMark Brown case WM8903_ANALOGUE_OUT2_LEFT:
202ee244ce4SMark Brown case WM8903_ANALOGUE_OUT2_RIGHT:
203ee244ce4SMark Brown case WM8903_ANALOGUE_OUT3_LEFT:
204ee244ce4SMark Brown case WM8903_ANALOGUE_OUT3_RIGHT:
205ee244ce4SMark Brown case WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0:
206ee244ce4SMark Brown case WM8903_DC_SERVO_0:
207ee244ce4SMark Brown case WM8903_DC_SERVO_2:
208ee244ce4SMark Brown case WM8903_DC_SERVO_READBACK_1:
209ee244ce4SMark Brown case WM8903_DC_SERVO_READBACK_2:
210ee244ce4SMark Brown case WM8903_DC_SERVO_READBACK_3:
211ee244ce4SMark Brown case WM8903_DC_SERVO_READBACK_4:
212ee244ce4SMark Brown case WM8903_ANALOGUE_HP_0:
213ee244ce4SMark Brown case WM8903_ANALOGUE_LINEOUT_0:
214ee244ce4SMark Brown case WM8903_CHARGE_PUMP_0:
215ee244ce4SMark Brown case WM8903_CLASS_W_0:
216ee244ce4SMark Brown case WM8903_WRITE_SEQUENCER_0:
217ee244ce4SMark Brown case WM8903_WRITE_SEQUENCER_1:
218ee244ce4SMark Brown case WM8903_WRITE_SEQUENCER_2:
219ee244ce4SMark Brown case WM8903_WRITE_SEQUENCER_3:
220ee244ce4SMark Brown case WM8903_WRITE_SEQUENCER_4:
221ee244ce4SMark Brown case WM8903_CONTROL_INTERFACE:
222ee244ce4SMark Brown case WM8903_GPIO_CONTROL_1:
223ee244ce4SMark Brown case WM8903_GPIO_CONTROL_2:
224ee244ce4SMark Brown case WM8903_GPIO_CONTROL_3:
225ee244ce4SMark Brown case WM8903_GPIO_CONTROL_4:
226ee244ce4SMark Brown case WM8903_GPIO_CONTROL_5:
227ee244ce4SMark Brown case WM8903_INTERRUPT_STATUS_1:
228ee244ce4SMark Brown case WM8903_INTERRUPT_STATUS_1_MASK:
229ee244ce4SMark Brown case WM8903_INTERRUPT_POLARITY_1:
230ee244ce4SMark Brown case WM8903_INTERRUPT_CONTROL:
231ee244ce4SMark Brown case WM8903_CLOCK_RATE_TEST_4:
232ee244ce4SMark Brown case WM8903_ANALOGUE_OUTPUT_BIAS_0:
233ee244ce4SMark Brown return true;
234ee244ce4SMark Brown default:
235ee244ce4SMark Brown return false;
236ee244ce4SMark Brown }
237ee244ce4SMark Brown }
238ee244ce4SMark Brown
wm8903_volatile_register(struct device * dev,unsigned int reg)239ee244ce4SMark Brown static bool wm8903_volatile_register(struct device *dev, unsigned int reg)
240f1c0a02fSMark Brown {
241f1c0a02fSMark Brown switch (reg) {
242f1c0a02fSMark Brown case WM8903_SW_RESET_AND_ID:
243f1c0a02fSMark Brown case WM8903_REVISION_NUMBER:
244f1c0a02fSMark Brown case WM8903_INTERRUPT_STATUS_1:
245f1c0a02fSMark Brown case WM8903_WRITE_SEQUENCER_4:
246c5b6a9feSMark Brown case WM8903_DC_SERVO_READBACK_1:
247c5b6a9feSMark Brown case WM8903_DC_SERVO_READBACK_2:
248c5b6a9feSMark Brown case WM8903_DC_SERVO_READBACK_3:
249c5b6a9feSMark Brown case WM8903_DC_SERVO_READBACK_4:
250bee7d3c9SGustavo A. R. Silva return true;
251f1c0a02fSMark Brown
252f1c0a02fSMark Brown default:
253bee7d3c9SGustavo A. R. Silva return false;
2548d50e447SMark Brown }
255f1c0a02fSMark Brown }
256f1c0a02fSMark Brown
wm8903_cp_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)25742768a12SMark Brown static int wm8903_cp_event(struct snd_soc_dapm_widget *w,
25842768a12SMark Brown struct snd_kcontrol *kcontrol, int event)
25942768a12SMark Brown {
26042768a12SMark Brown WARN_ON(event != SND_SOC_DAPM_POST_PMU);
26142768a12SMark Brown mdelay(4);
26242768a12SMark Brown
26342768a12SMark Brown return 0;
26442768a12SMark Brown }
26542768a12SMark Brown
wm8903_dcs_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)266c5b6a9feSMark Brown static int wm8903_dcs_event(struct snd_soc_dapm_widget *w,
267c5b6a9feSMark Brown struct snd_kcontrol *kcontrol, int event)
268c5b6a9feSMark Brown {
26958bd2934SKuninori Morimoto struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
27058bd2934SKuninori Morimoto struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
271c5b6a9feSMark Brown
272c5b6a9feSMark Brown switch (event) {
273c5b6a9feSMark Brown case SND_SOC_DAPM_POST_PMU:
274c5b6a9feSMark Brown wm8903->dcs_pending |= 1 << w->shift;
275c5b6a9feSMark Brown break;
276c5b6a9feSMark Brown case SND_SOC_DAPM_PRE_PMD:
27758bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_DC_SERVO_0,
278c5b6a9feSMark Brown 1 << w->shift, 0);
279c5b6a9feSMark Brown break;
280c5b6a9feSMark Brown }
281c5b6a9feSMark Brown
282c5b6a9feSMark Brown return 0;
283c5b6a9feSMark Brown }
284c5b6a9feSMark Brown
285c5b6a9feSMark Brown #define WM8903_DCS_MODE_WRITE_STOP 0
286c5b6a9feSMark Brown #define WM8903_DCS_MODE_START_STOP 2
287c5b6a9feSMark Brown
wm8903_seq_notifier(struct snd_soc_component * component,enum snd_soc_dapm_type event,int subseq)28858bd2934SKuninori Morimoto static void wm8903_seq_notifier(struct snd_soc_component *component,
289c5b6a9feSMark Brown enum snd_soc_dapm_type event, int subseq)
290c5b6a9feSMark Brown {
29158bd2934SKuninori Morimoto struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
292c5b6a9feSMark Brown int dcs_mode = WM8903_DCS_MODE_WRITE_STOP;
293c5b6a9feSMark Brown int i, val;
294c5b6a9feSMark Brown
295c5b6a9feSMark Brown /* Complete any pending DC servo starts */
296c5b6a9feSMark Brown if (wm8903->dcs_pending) {
29758bd2934SKuninori Morimoto dev_dbg(component->dev, "Starting DC servo for %x\n",
298c5b6a9feSMark Brown wm8903->dcs_pending);
299c5b6a9feSMark Brown
300c5b6a9feSMark Brown /* If we've no cached values then we need to do startup */
301c5b6a9feSMark Brown for (i = 0; i < ARRAY_SIZE(wm8903->dcs_cache); i++) {
302c5b6a9feSMark Brown if (!(wm8903->dcs_pending & (1 << i)))
303c5b6a9feSMark Brown continue;
304c5b6a9feSMark Brown
305c5b6a9feSMark Brown if (wm8903->dcs_cache[i]) {
30658bd2934SKuninori Morimoto dev_dbg(component->dev,
307c5b6a9feSMark Brown "Restore DC servo %d value %x\n",
308c5b6a9feSMark Brown 3 - i, wm8903->dcs_cache[i]);
309c5b6a9feSMark Brown
31058bd2934SKuninori Morimoto snd_soc_component_write(component, WM8903_DC_SERVO_4 + i,
311c5b6a9feSMark Brown wm8903->dcs_cache[i] & 0xff);
312c5b6a9feSMark Brown } else {
31358bd2934SKuninori Morimoto dev_dbg(component->dev,
314c5b6a9feSMark Brown "Calibrate DC servo %d\n", 3 - i);
315c5b6a9feSMark Brown dcs_mode = WM8903_DCS_MODE_START_STOP;
316c5b6a9feSMark Brown }
317c5b6a9feSMark Brown }
318c5b6a9feSMark Brown
319c5b6a9feSMark Brown /* Don't trust the cache for analogue */
320c5b6a9feSMark Brown if (wm8903->class_w_users)
321c5b6a9feSMark Brown dcs_mode = WM8903_DCS_MODE_START_STOP;
322c5b6a9feSMark Brown
32358bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_DC_SERVO_2,
324c5b6a9feSMark Brown WM8903_DCS_MODE_MASK, dcs_mode);
325c5b6a9feSMark Brown
32658bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_DC_SERVO_0,
327c5b6a9feSMark Brown WM8903_DCS_ENA_MASK, wm8903->dcs_pending);
328c5b6a9feSMark Brown
329c5b6a9feSMark Brown switch (dcs_mode) {
330c5b6a9feSMark Brown case WM8903_DCS_MODE_WRITE_STOP:
331c5b6a9feSMark Brown break;
332c5b6a9feSMark Brown
333c5b6a9feSMark Brown case WM8903_DCS_MODE_START_STOP:
334c5b6a9feSMark Brown msleep(270);
335c5b6a9feSMark Brown
336c5b6a9feSMark Brown /* Cache the measured offsets for digital */
337c5b6a9feSMark Brown if (wm8903->class_w_users)
338c5b6a9feSMark Brown break;
339c5b6a9feSMark Brown
340c5b6a9feSMark Brown for (i = 0; i < ARRAY_SIZE(wm8903->dcs_cache); i++) {
341c5b6a9feSMark Brown if (!(wm8903->dcs_pending & (1 << i)))
342c5b6a9feSMark Brown continue;
343c5b6a9feSMark Brown
3446d75dfc3SKuninori Morimoto val = snd_soc_component_read(component,
345c5b6a9feSMark Brown WM8903_DC_SERVO_READBACK_1 + i);
34658bd2934SKuninori Morimoto dev_dbg(component->dev, "DC servo %d: %x\n",
347c5b6a9feSMark Brown 3 - i, val);
348c5b6a9feSMark Brown wm8903->dcs_cache[i] = val;
349c5b6a9feSMark Brown }
350c5b6a9feSMark Brown break;
351c5b6a9feSMark Brown
352c5b6a9feSMark Brown default:
353c5b6a9feSMark Brown pr_warn("DCS mode %d delay not set\n", dcs_mode);
354c5b6a9feSMark Brown break;
355c5b6a9feSMark Brown }
356c5b6a9feSMark Brown
357c5b6a9feSMark Brown wm8903->dcs_pending = 0;
358c5b6a9feSMark Brown }
359c5b6a9feSMark Brown }
360c5b6a9feSMark Brown
361f1c0a02fSMark Brown /*
362f1c0a02fSMark Brown * When used with DAC outputs only the WM8903 charge pump supports
363f1c0a02fSMark Brown * operation in class W mode, providing very low power consumption
364f1c0a02fSMark Brown * when used with digital sources. Enable and disable this mode
365f1c0a02fSMark Brown * automatically depending on the mixer configuration.
366f1c0a02fSMark Brown *
367f1c0a02fSMark Brown * All the relevant controls are simple switches.
368f1c0a02fSMark Brown */
wm8903_class_w_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)369f1c0a02fSMark Brown static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
370f1c0a02fSMark Brown struct snd_ctl_elem_value *ucontrol)
371f1c0a02fSMark Brown {
37258bd2934SKuninori Morimoto struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
37358bd2934SKuninori Morimoto struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
374f1c0a02fSMark Brown u16 reg;
375f1c0a02fSMark Brown int ret;
376f1c0a02fSMark Brown
3776d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8903_CLASS_W_0);
378f1c0a02fSMark Brown
379f1c0a02fSMark Brown /* Turn it off if we're about to enable bypass */
380f1c0a02fSMark Brown if (ucontrol->value.integer.value[0]) {
381f1c0a02fSMark Brown if (wm8903->class_w_users == 0) {
38258bd2934SKuninori Morimoto dev_dbg(component->dev, "Disabling Class W\n");
38358bd2934SKuninori Morimoto snd_soc_component_write(component, WM8903_CLASS_W_0, reg &
384f1c0a02fSMark Brown ~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V));
385f1c0a02fSMark Brown }
386f1c0a02fSMark Brown wm8903->class_w_users++;
387f1c0a02fSMark Brown }
388f1c0a02fSMark Brown
389f1c0a02fSMark Brown /* Implement the change */
390f1c0a02fSMark Brown ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
391f1c0a02fSMark Brown
392f1c0a02fSMark Brown /* If we've just disabled the last bypass path turn Class W on */
393f1c0a02fSMark Brown if (!ucontrol->value.integer.value[0]) {
394f1c0a02fSMark Brown if (wm8903->class_w_users == 1) {
39558bd2934SKuninori Morimoto dev_dbg(component->dev, "Enabling Class W\n");
39658bd2934SKuninori Morimoto snd_soc_component_write(component, WM8903_CLASS_W_0, reg |
397f1c0a02fSMark Brown WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
398f1c0a02fSMark Brown }
399f1c0a02fSMark Brown wm8903->class_w_users--;
400f1c0a02fSMark Brown }
401f1c0a02fSMark Brown
40258bd2934SKuninori Morimoto dev_dbg(component->dev, "Bypass use count now %d\n",
403f1c0a02fSMark Brown wm8903->class_w_users);
404f1c0a02fSMark Brown
405f1c0a02fSMark Brown return ret;
406f1c0a02fSMark Brown }
407f1c0a02fSMark Brown
408f1c0a02fSMark Brown #define SOC_DAPM_SINGLE_W(xname, reg, shift, max, invert) \
409ea3583d0SLars-Peter Clausen SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
410ea3583d0SLars-Peter Clausen snd_soc_dapm_get_volsw, wm8903_class_w_put)
411f1c0a02fSMark Brown
412f1c0a02fSMark Brown
41369fff9bbSMark Brown static int wm8903_deemph[] = { 0, 32000, 44100, 48000 };
41469fff9bbSMark Brown
wm8903_set_deemph(struct snd_soc_component * component)41558bd2934SKuninori Morimoto static int wm8903_set_deemph(struct snd_soc_component *component)
41669fff9bbSMark Brown {
41758bd2934SKuninori Morimoto struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
41869fff9bbSMark Brown int val, i, best;
41969fff9bbSMark Brown
42069fff9bbSMark Brown /* If we're using deemphasis select the nearest available sample
42169fff9bbSMark Brown * rate.
42269fff9bbSMark Brown */
42369fff9bbSMark Brown if (wm8903->deemph) {
42469fff9bbSMark Brown best = 1;
42569fff9bbSMark Brown for (i = 2; i < ARRAY_SIZE(wm8903_deemph); i++) {
42669fff9bbSMark Brown if (abs(wm8903_deemph[i] - wm8903->fs) <
42769fff9bbSMark Brown abs(wm8903_deemph[best] - wm8903->fs))
42869fff9bbSMark Brown best = i;
42969fff9bbSMark Brown }
43069fff9bbSMark Brown
43169fff9bbSMark Brown val = best << WM8903_DEEMPH_SHIFT;
43269fff9bbSMark Brown } else {
43369fff9bbSMark Brown best = 0;
43469fff9bbSMark Brown val = 0;
43569fff9bbSMark Brown }
43669fff9bbSMark Brown
43758bd2934SKuninori Morimoto dev_dbg(component->dev, "Set deemphasis %d (%dHz)\n",
43869fff9bbSMark Brown best, wm8903_deemph[best]);
43969fff9bbSMark Brown
44058bd2934SKuninori Morimoto return snd_soc_component_update_bits(component, WM8903_DAC_DIGITAL_1,
44169fff9bbSMark Brown WM8903_DEEMPH_MASK, val);
44269fff9bbSMark Brown }
44369fff9bbSMark Brown
wm8903_get_deemph(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)44469fff9bbSMark Brown static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
44569fff9bbSMark Brown struct snd_ctl_elem_value *ucontrol)
44669fff9bbSMark Brown {
44758bd2934SKuninori Morimoto struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
44858bd2934SKuninori Morimoto struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
44969fff9bbSMark Brown
45024cc883cSTakashi Iwai ucontrol->value.integer.value[0] = wm8903->deemph;
45169fff9bbSMark Brown
45269fff9bbSMark Brown return 0;
45369fff9bbSMark Brown }
45469fff9bbSMark Brown
wm8903_put_deemph(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)45569fff9bbSMark Brown static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
45669fff9bbSMark Brown struct snd_ctl_elem_value *ucontrol)
45769fff9bbSMark Brown {
45858bd2934SKuninori Morimoto struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
45958bd2934SKuninori Morimoto struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
4604d0197a5SDan Carpenter unsigned int deemph = ucontrol->value.integer.value[0];
46169fff9bbSMark Brown int ret = 0;
46269fff9bbSMark Brown
46369fff9bbSMark Brown if (deemph > 1)
46469fff9bbSMark Brown return -EINVAL;
46569fff9bbSMark Brown
46678660af7SLars-Peter Clausen mutex_lock(&wm8903->lock);
46769fff9bbSMark Brown if (wm8903->deemph != deemph) {
46869fff9bbSMark Brown wm8903->deemph = deemph;
46969fff9bbSMark Brown
47058bd2934SKuninori Morimoto wm8903_set_deemph(component);
47169fff9bbSMark Brown
47269fff9bbSMark Brown ret = 1;
47369fff9bbSMark Brown }
47478660af7SLars-Peter Clausen mutex_unlock(&wm8903->lock);
47569fff9bbSMark Brown
47669fff9bbSMark Brown return ret;
47769fff9bbSMark Brown }
47869fff9bbSMark Brown
479f1c0a02fSMark Brown /* ALSA can only do steps of .01dB */
480f1c0a02fSMark Brown static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
481f1c0a02fSMark Brown
48200aa0facSAlban Bedel static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
48300aa0facSAlban Bedel
484291ce18cSMark Brown static const DECLARE_TLV_DB_SCALE(digital_sidetone_tlv, -3600, 300, 0);
485f1c0a02fSMark Brown static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
486f1c0a02fSMark Brown
487f1c0a02fSMark Brown static const DECLARE_TLV_DB_SCALE(drc_tlv_thresh, 0, 75, 0);
488f1c0a02fSMark Brown static const DECLARE_TLV_DB_SCALE(drc_tlv_amp, -2250, 75, 0);
489f1c0a02fSMark Brown static const DECLARE_TLV_DB_SCALE(drc_tlv_min, 0, 600, 0);
490f1c0a02fSMark Brown static const DECLARE_TLV_DB_SCALE(drc_tlv_max, 1200, 600, 0);
491f1c0a02fSMark Brown static const DECLARE_TLV_DB_SCALE(drc_tlv_startup, -300, 50, 0);
492f1c0a02fSMark Brown
493460f4aaeSMark Brown static const char *hpf_mode_text[] = {
494460f4aaeSMark Brown "Hi-fi", "Voice 1", "Voice 2", "Voice 3"
495460f4aaeSMark Brown };
496460f4aaeSMark Brown
497a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(hpf_mode,
498a21bc5c5STakashi Iwai WM8903_ADC_DIGITAL_0, 5, hpf_mode_text);
499460f4aaeSMark Brown
500dcf9ada3SMark Brown static const char *osr_text[] = {
501dcf9ada3SMark Brown "Low power", "High performance"
502dcf9ada3SMark Brown };
503dcf9ada3SMark Brown
504a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(adc_osr,
505a21bc5c5STakashi Iwai WM8903_ANALOGUE_ADC_0, 0, osr_text);
506dcf9ada3SMark Brown
507a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(dac_osr,
508a21bc5c5STakashi Iwai WM8903_DAC_DIGITAL_1, 0, osr_text);
509dcf9ada3SMark Brown
510f1c0a02fSMark Brown static const char *drc_slope_text[] = {
511f1c0a02fSMark Brown "1", "1/2", "1/4", "1/8", "1/16", "0"
512f1c0a02fSMark Brown };
513f1c0a02fSMark Brown
514a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_slope_r0,
515a21bc5c5STakashi Iwai WM8903_DRC_2, 3, drc_slope_text);
516f1c0a02fSMark Brown
517a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_slope_r1,
518a21bc5c5STakashi Iwai WM8903_DRC_2, 0, drc_slope_text);
519f1c0a02fSMark Brown
520f1c0a02fSMark Brown static const char *drc_attack_text[] = {
521f1c0a02fSMark Brown "instantaneous",
522f1c0a02fSMark Brown "363us", "762us", "1.45ms", "2.9ms", "5.8ms", "11.6ms", "23.2ms",
523f1c0a02fSMark Brown "46.4ms", "92.8ms", "185.6ms"
524f1c0a02fSMark Brown };
525f1c0a02fSMark Brown
526a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_attack,
527a21bc5c5STakashi Iwai WM8903_DRC_1, 12, drc_attack_text);
528f1c0a02fSMark Brown
529f1c0a02fSMark Brown static const char *drc_decay_text[] = {
530f1c0a02fSMark Brown "186ms", "372ms", "743ms", "1.49s", "2.97s", "5.94s", "11.89s",
531f1c0a02fSMark Brown "23.87s", "47.56s"
532f1c0a02fSMark Brown };
533f1c0a02fSMark Brown
534a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_decay,
535a21bc5c5STakashi Iwai WM8903_DRC_1, 8, drc_decay_text);
536f1c0a02fSMark Brown
537f1c0a02fSMark Brown static const char *drc_ff_delay_text[] = {
538f1c0a02fSMark Brown "5 samples", "9 samples"
539f1c0a02fSMark Brown };
540f1c0a02fSMark Brown
541a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_ff_delay,
542a21bc5c5STakashi Iwai WM8903_DRC_0, 5, drc_ff_delay_text);
543f1c0a02fSMark Brown
544f1c0a02fSMark Brown static const char *drc_qr_decay_text[] = {
545f1c0a02fSMark Brown "0.725ms", "1.45ms", "5.8ms"
546f1c0a02fSMark Brown };
547f1c0a02fSMark Brown
548a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_qr_decay,
549a21bc5c5STakashi Iwai WM8903_DRC_1, 4, drc_qr_decay_text);
550f1c0a02fSMark Brown
551f1c0a02fSMark Brown static const char *drc_smoothing_text[] = {
552f1c0a02fSMark Brown "Low", "Medium", "High"
553f1c0a02fSMark Brown };
554f1c0a02fSMark Brown
555a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_smoothing,
556a21bc5c5STakashi Iwai WM8903_DRC_0, 11, drc_smoothing_text);
557f1c0a02fSMark Brown
558f1c0a02fSMark Brown static const char *soft_mute_text[] = {
559f1c0a02fSMark Brown "Fast (fs/2)", "Slow (fs/32)"
560f1c0a02fSMark Brown };
561f1c0a02fSMark Brown
562a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(soft_mute,
563a21bc5c5STakashi Iwai WM8903_DAC_DIGITAL_1, 10, soft_mute_text);
564f1c0a02fSMark Brown
565f1c0a02fSMark Brown static const char *mute_mode_text[] = {
566f1c0a02fSMark Brown "Hard", "Soft"
567f1c0a02fSMark Brown };
568f1c0a02fSMark Brown
569a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(mute_mode,
570a21bc5c5STakashi Iwai WM8903_DAC_DIGITAL_1, 9, mute_mode_text);
571f1c0a02fSMark Brown
572f1c0a02fSMark Brown static const char *companding_text[] = {
573f1c0a02fSMark Brown "ulaw", "alaw"
574f1c0a02fSMark Brown };
575f1c0a02fSMark Brown
576a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(dac_companding,
577a21bc5c5STakashi Iwai WM8903_AUDIO_INTERFACE_0, 0, companding_text);
578f1c0a02fSMark Brown
579a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(adc_companding,
580a21bc5c5STakashi Iwai WM8903_AUDIO_INTERFACE_0, 2, companding_text);
581f1c0a02fSMark Brown
582f1c0a02fSMark Brown static const char *input_mode_text[] = {
583f1c0a02fSMark Brown "Single-Ended", "Differential Line", "Differential Mic"
584f1c0a02fSMark Brown };
585f1c0a02fSMark Brown
586a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(linput_mode_enum,
587a21bc5c5STakashi Iwai WM8903_ANALOGUE_LEFT_INPUT_1, 0, input_mode_text);
588f1c0a02fSMark Brown
589a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(rinput_mode_enum,
590a21bc5c5STakashi Iwai WM8903_ANALOGUE_RIGHT_INPUT_1, 0, input_mode_text);
591f1c0a02fSMark Brown
592f1c0a02fSMark Brown static const char *linput_mux_text[] = {
593f1c0a02fSMark Brown "IN1L", "IN2L", "IN3L"
594f1c0a02fSMark Brown };
595f1c0a02fSMark Brown
596a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(linput_enum,
597a21bc5c5STakashi Iwai WM8903_ANALOGUE_LEFT_INPUT_1, 2, linput_mux_text);
598f1c0a02fSMark Brown
599a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(linput_inv_enum,
600a21bc5c5STakashi Iwai WM8903_ANALOGUE_LEFT_INPUT_1, 4, linput_mux_text);
601f1c0a02fSMark Brown
602f1c0a02fSMark Brown static const char *rinput_mux_text[] = {
603f1c0a02fSMark Brown "IN1R", "IN2R", "IN3R"
604f1c0a02fSMark Brown };
605f1c0a02fSMark Brown
606a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(rinput_enum,
607a21bc5c5STakashi Iwai WM8903_ANALOGUE_RIGHT_INPUT_1, 2, rinput_mux_text);
608f1c0a02fSMark Brown
609a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(rinput_inv_enum,
610a21bc5c5STakashi Iwai WM8903_ANALOGUE_RIGHT_INPUT_1, 4, rinput_mux_text);
611f1c0a02fSMark Brown
612f1c0a02fSMark Brown
613291ce18cSMark Brown static const char *sidetone_text[] = {
614291ce18cSMark Brown "None", "Left", "Right"
615291ce18cSMark Brown };
616291ce18cSMark Brown
617a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(lsidetone_enum,
618a21bc5c5STakashi Iwai WM8903_DAC_DIGITAL_0, 2, sidetone_text);
619291ce18cSMark Brown
620a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(rsidetone_enum,
621a21bc5c5STakashi Iwai WM8903_DAC_DIGITAL_0, 0, sidetone_text);
622291ce18cSMark Brown
62397945c46SStephen Warren static const char *adcinput_text[] = {
62497945c46SStephen Warren "ADC", "DMIC"
62597945c46SStephen Warren };
62697945c46SStephen Warren
627a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(adcinput_enum,
628a21bc5c5STakashi Iwai WM8903_CLOCK_RATE_TEST_4, 9, adcinput_text);
62997945c46SStephen Warren
6301e113bf9SMark Brown static const char *aif_text[] = {
6311e113bf9SMark Brown "Left", "Right"
6321e113bf9SMark Brown };
6331e113bf9SMark Brown
634a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(lcapture_enum,
635a21bc5c5STakashi Iwai WM8903_AUDIO_INTERFACE_0, 7, aif_text);
6361e113bf9SMark Brown
637a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(rcapture_enum,
638a21bc5c5STakashi Iwai WM8903_AUDIO_INTERFACE_0, 6, aif_text);
6391e113bf9SMark Brown
640a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(lplay_enum,
641a21bc5c5STakashi Iwai WM8903_AUDIO_INTERFACE_0, 5, aif_text);
6421e113bf9SMark Brown
643a21bc5c5STakashi Iwai static SOC_ENUM_SINGLE_DECL(rplay_enum,
644a21bc5c5STakashi Iwai WM8903_AUDIO_INTERFACE_0, 4, aif_text);
6451e113bf9SMark Brown
646f1c0a02fSMark Brown static const struct snd_kcontrol_new wm8903_snd_controls[] = {
647f1c0a02fSMark Brown
648f1c0a02fSMark Brown /* Input PGAs - No TLV since the scale depends on PGA mode */
649f1c0a02fSMark Brown SOC_SINGLE("Left Input PGA Switch", WM8903_ANALOGUE_LEFT_INPUT_0,
6505715952bSMark Brown 7, 1, 1),
651f1c0a02fSMark Brown SOC_SINGLE("Left Input PGA Volume", WM8903_ANALOGUE_LEFT_INPUT_0,
652f1c0a02fSMark Brown 0, 31, 0),
653f1c0a02fSMark Brown SOC_SINGLE("Left Input PGA Common Mode Switch", WM8903_ANALOGUE_LEFT_INPUT_1,
654f1c0a02fSMark Brown 6, 1, 0),
655f1c0a02fSMark Brown
656f1c0a02fSMark Brown SOC_SINGLE("Right Input PGA Switch", WM8903_ANALOGUE_RIGHT_INPUT_0,
6575715952bSMark Brown 7, 1, 1),
658f1c0a02fSMark Brown SOC_SINGLE("Right Input PGA Volume", WM8903_ANALOGUE_RIGHT_INPUT_0,
659f1c0a02fSMark Brown 0, 31, 0),
660f1c0a02fSMark Brown SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1,
661f1c0a02fSMark Brown 6, 1, 0),
662f1c0a02fSMark Brown
663f1c0a02fSMark Brown /* ADCs */
664dcf9ada3SMark Brown SOC_ENUM("ADC OSR", adc_osr),
665460f4aaeSMark Brown SOC_SINGLE("HPF Switch", WM8903_ADC_DIGITAL_0, 4, 1, 0),
666460f4aaeSMark Brown SOC_ENUM("HPF Mode", hpf_mode),
667f1c0a02fSMark Brown SOC_SINGLE("DRC Switch", WM8903_DRC_0, 15, 1, 0),
668f1c0a02fSMark Brown SOC_ENUM("DRC Compressor Slope R0", drc_slope_r0),
669f1c0a02fSMark Brown SOC_ENUM("DRC Compressor Slope R1", drc_slope_r1),
670af901ca1SAndré Goddard Rosa SOC_SINGLE_TLV("DRC Compressor Threshold Volume", WM8903_DRC_3, 5, 124, 1,
671f1c0a02fSMark Brown drc_tlv_thresh),
672f1c0a02fSMark Brown SOC_SINGLE_TLV("DRC Volume", WM8903_DRC_3, 0, 30, 1, drc_tlv_amp),
673f1c0a02fSMark Brown SOC_SINGLE_TLV("DRC Minimum Gain Volume", WM8903_DRC_1, 2, 3, 1, drc_tlv_min),
674f1c0a02fSMark Brown SOC_SINGLE_TLV("DRC Maximum Gain Volume", WM8903_DRC_1, 0, 3, 0, drc_tlv_max),
675f1c0a02fSMark Brown SOC_ENUM("DRC Attack Rate", drc_attack),
676f1c0a02fSMark Brown SOC_ENUM("DRC Decay Rate", drc_decay),
677f1c0a02fSMark Brown SOC_ENUM("DRC FF Delay", drc_ff_delay),
678f1c0a02fSMark Brown SOC_SINGLE("DRC Anticlip Switch", WM8903_DRC_0, 1, 1, 0),
679f1c0a02fSMark Brown SOC_SINGLE("DRC QR Switch", WM8903_DRC_0, 2, 1, 0),
680af901ca1SAndré Goddard Rosa SOC_SINGLE_TLV("DRC QR Threshold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max),
681f1c0a02fSMark Brown SOC_ENUM("DRC QR Decay Rate", drc_qr_decay),
682f1c0a02fSMark Brown SOC_SINGLE("DRC Smoothing Switch", WM8903_DRC_0, 3, 1, 0),
683f1c0a02fSMark Brown SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8903_DRC_0, 0, 1, 0),
684af901ca1SAndré Goddard Rosa SOC_ENUM("DRC Smoothing Threshold", drc_smoothing),
685f1c0a02fSMark Brown SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup),
686f1c0a02fSMark Brown
687f1c0a02fSMark Brown SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT,
68861bf35b9SStephen Warren WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
689f1c0a02fSMark Brown SOC_ENUM("ADC Companding Mode", adc_companding),
690f1c0a02fSMark Brown SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0),
691f1c0a02fSMark Brown
692291ce18cSMark Brown SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8903_DAC_DIGITAL_0, 4, 8,
693291ce18cSMark Brown 12, 0, digital_sidetone_tlv),
694291ce18cSMark Brown
695f1c0a02fSMark Brown /* DAC */
696dcf9ada3SMark Brown SOC_ENUM("DAC OSR", dac_osr),
697f1c0a02fSMark Brown SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT,
698f1c0a02fSMark Brown WM8903_DAC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
699f1c0a02fSMark Brown SOC_ENUM("DAC Soft Mute Rate", soft_mute),
700f1c0a02fSMark Brown SOC_ENUM("DAC Mute Mode", mute_mode),
701f1c0a02fSMark Brown SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0),
702f1c0a02fSMark Brown SOC_ENUM("DAC Companding Mode", dac_companding),
703f1c0a02fSMark Brown SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0),
70400aa0facSAlban Bedel SOC_SINGLE_TLV("DAC Boost Volume", WM8903_AUDIO_INTERFACE_0, 9, 3, 0,
70500aa0facSAlban Bedel dac_boost_tlv),
70669fff9bbSMark Brown SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
70769fff9bbSMark Brown wm8903_get_deemph, wm8903_put_deemph),
708f1c0a02fSMark Brown
709f1c0a02fSMark Brown /* Headphones */
710f1c0a02fSMark Brown SOC_DOUBLE_R("Headphone Switch",
711f1c0a02fSMark Brown WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT,
712f1c0a02fSMark Brown 8, 1, 1),
713f1c0a02fSMark Brown SOC_DOUBLE_R("Headphone ZC Switch",
714f1c0a02fSMark Brown WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT,
715f1c0a02fSMark Brown 6, 1, 0),
716f1c0a02fSMark Brown SOC_DOUBLE_R_TLV("Headphone Volume",
717f1c0a02fSMark Brown WM8903_ANALOGUE_OUT1_LEFT, WM8903_ANALOGUE_OUT1_RIGHT,
718f1c0a02fSMark Brown 0, 63, 0, out_tlv),
719f1c0a02fSMark Brown
720f1c0a02fSMark Brown /* Line out */
721f1c0a02fSMark Brown SOC_DOUBLE_R("Line Out Switch",
722f1c0a02fSMark Brown WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT,
723f1c0a02fSMark Brown 8, 1, 1),
724f1c0a02fSMark Brown SOC_DOUBLE_R("Line Out ZC Switch",
725f1c0a02fSMark Brown WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT,
726f1c0a02fSMark Brown 6, 1, 0),
727f1c0a02fSMark Brown SOC_DOUBLE_R_TLV("Line Out Volume",
728f1c0a02fSMark Brown WM8903_ANALOGUE_OUT2_LEFT, WM8903_ANALOGUE_OUT2_RIGHT,
729f1c0a02fSMark Brown 0, 63, 0, out_tlv),
730f1c0a02fSMark Brown
731f1c0a02fSMark Brown /* Speaker */
732f1c0a02fSMark Brown SOC_DOUBLE_R("Speaker Switch",
733f1c0a02fSMark Brown WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, 8, 1, 1),
734f1c0a02fSMark Brown SOC_DOUBLE_R("Speaker ZC Switch",
735f1c0a02fSMark Brown WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT, 6, 1, 0),
736f1c0a02fSMark Brown SOC_DOUBLE_R_TLV("Speaker Volume",
737f1c0a02fSMark Brown WM8903_ANALOGUE_OUT3_LEFT, WM8903_ANALOGUE_OUT3_RIGHT,
738f1c0a02fSMark Brown 0, 63, 0, out_tlv),
739f1c0a02fSMark Brown };
740f1c0a02fSMark Brown
741f1c0a02fSMark Brown static const struct snd_kcontrol_new linput_mode_mux =
742f1c0a02fSMark Brown SOC_DAPM_ENUM("Left Input Mode Mux", linput_mode_enum);
743f1c0a02fSMark Brown
744f1c0a02fSMark Brown static const struct snd_kcontrol_new rinput_mode_mux =
745f1c0a02fSMark Brown SOC_DAPM_ENUM("Right Input Mode Mux", rinput_mode_enum);
746f1c0a02fSMark Brown
747f1c0a02fSMark Brown static const struct snd_kcontrol_new linput_mux =
748f1c0a02fSMark Brown SOC_DAPM_ENUM("Left Input Mux", linput_enum);
749f1c0a02fSMark Brown
750f1c0a02fSMark Brown static const struct snd_kcontrol_new linput_inv_mux =
751f1c0a02fSMark Brown SOC_DAPM_ENUM("Left Inverting Input Mux", linput_inv_enum);
752f1c0a02fSMark Brown
753f1c0a02fSMark Brown static const struct snd_kcontrol_new rinput_mux =
754f1c0a02fSMark Brown SOC_DAPM_ENUM("Right Input Mux", rinput_enum);
755f1c0a02fSMark Brown
756f1c0a02fSMark Brown static const struct snd_kcontrol_new rinput_inv_mux =
757f1c0a02fSMark Brown SOC_DAPM_ENUM("Right Inverting Input Mux", rinput_inv_enum);
758f1c0a02fSMark Brown
759291ce18cSMark Brown static const struct snd_kcontrol_new lsidetone_mux =
760291ce18cSMark Brown SOC_DAPM_ENUM("DACL Sidetone Mux", lsidetone_enum);
761291ce18cSMark Brown
762291ce18cSMark Brown static const struct snd_kcontrol_new rsidetone_mux =
763291ce18cSMark Brown SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum);
764291ce18cSMark Brown
76597945c46SStephen Warren static const struct snd_kcontrol_new adcinput_mux =
76697945c46SStephen Warren SOC_DAPM_ENUM("ADC Input", adcinput_enum);
76797945c46SStephen Warren
7681e113bf9SMark Brown static const struct snd_kcontrol_new lcapture_mux =
7691e113bf9SMark Brown SOC_DAPM_ENUM("Left Capture Mux", lcapture_enum);
7701e113bf9SMark Brown
7711e113bf9SMark Brown static const struct snd_kcontrol_new rcapture_mux =
7721e113bf9SMark Brown SOC_DAPM_ENUM("Right Capture Mux", rcapture_enum);
7731e113bf9SMark Brown
7741e113bf9SMark Brown static const struct snd_kcontrol_new lplay_mux =
7751e113bf9SMark Brown SOC_DAPM_ENUM("Left Playback Mux", lplay_enum);
7761e113bf9SMark Brown
7771e113bf9SMark Brown static const struct snd_kcontrol_new rplay_mux =
7781e113bf9SMark Brown SOC_DAPM_ENUM("Right Playback Mux", rplay_enum);
7791e113bf9SMark Brown
780f1c0a02fSMark Brown static const struct snd_kcontrol_new left_output_mixer[] = {
781f1c0a02fSMark Brown SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0),
782f1c0a02fSMark Brown SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0),
783f1c0a02fSMark Brown SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0),
7844b4fffddSMark Brown SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 0, 1, 0),
785f1c0a02fSMark Brown };
786f1c0a02fSMark Brown
787f1c0a02fSMark Brown static const struct snd_kcontrol_new right_output_mixer[] = {
788f1c0a02fSMark Brown SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 3, 1, 0),
789f1c0a02fSMark Brown SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 2, 1, 0),
790f1c0a02fSMark Brown SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0),
7914b4fffddSMark Brown SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 0, 1, 0),
792f1c0a02fSMark Brown };
793f1c0a02fSMark Brown
794f1c0a02fSMark Brown static const struct snd_kcontrol_new left_speaker_mixer[] = {
795f1c0a02fSMark Brown SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 3, 1, 0),
796f1c0a02fSMark Brown SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 2, 1, 0),
797f1c0a02fSMark Brown SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 1, 1, 0),
798f1c0a02fSMark Brown SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0,
7994b4fffddSMark Brown 0, 1, 0),
800f1c0a02fSMark Brown };
801f1c0a02fSMark Brown
802f1c0a02fSMark Brown static const struct snd_kcontrol_new right_speaker_mixer[] = {
803f1c0a02fSMark Brown SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 3, 1, 0),
804f1c0a02fSMark Brown SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 2, 1, 0),
805f1c0a02fSMark Brown SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0,
806f1c0a02fSMark Brown 1, 1, 0),
807f1c0a02fSMark Brown SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0,
8084b4fffddSMark Brown 0, 1, 0),
809f1c0a02fSMark Brown };
810f1c0a02fSMark Brown
811f1c0a02fSMark Brown static const struct snd_soc_dapm_widget wm8903_dapm_widgets[] = {
812f1c0a02fSMark Brown SND_SOC_DAPM_INPUT("IN1L"),
813f1c0a02fSMark Brown SND_SOC_DAPM_INPUT("IN1R"),
814f1c0a02fSMark Brown SND_SOC_DAPM_INPUT("IN2L"),
815f1c0a02fSMark Brown SND_SOC_DAPM_INPUT("IN2R"),
816f1c0a02fSMark Brown SND_SOC_DAPM_INPUT("IN3L"),
817f1c0a02fSMark Brown SND_SOC_DAPM_INPUT("IN3R"),
81897945c46SStephen Warren SND_SOC_DAPM_INPUT("DMICDAT"),
819f1c0a02fSMark Brown
820f1c0a02fSMark Brown SND_SOC_DAPM_OUTPUT("HPOUTL"),
821f1c0a02fSMark Brown SND_SOC_DAPM_OUTPUT("HPOUTR"),
822f1c0a02fSMark Brown SND_SOC_DAPM_OUTPUT("LINEOUTL"),
823f1c0a02fSMark Brown SND_SOC_DAPM_OUTPUT("LINEOUTR"),
824f1c0a02fSMark Brown SND_SOC_DAPM_OUTPUT("LOP"),
825f1c0a02fSMark Brown SND_SOC_DAPM_OUTPUT("LON"),
826f1c0a02fSMark Brown SND_SOC_DAPM_OUTPUT("ROP"),
827f1c0a02fSMark Brown SND_SOC_DAPM_OUTPUT("RON"),
828f1c0a02fSMark Brown
8295032dc34SMark Brown SND_SOC_DAPM_SUPPLY("MICBIAS", WM8903_MIC_BIAS_CONTROL_0, 0, 0, NULL, 0),
830f1c0a02fSMark Brown
831f1c0a02fSMark Brown SND_SOC_DAPM_MUX("Left Input Mux", SND_SOC_NOPM, 0, 0, &linput_mux),
832f1c0a02fSMark Brown SND_SOC_DAPM_MUX("Left Input Inverting Mux", SND_SOC_NOPM, 0, 0,
833f1c0a02fSMark Brown &linput_inv_mux),
834f1c0a02fSMark Brown SND_SOC_DAPM_MUX("Left Input Mode Mux", SND_SOC_NOPM, 0, 0, &linput_mode_mux),
835f1c0a02fSMark Brown
836f1c0a02fSMark Brown SND_SOC_DAPM_MUX("Right Input Mux", SND_SOC_NOPM, 0, 0, &rinput_mux),
837f1c0a02fSMark Brown SND_SOC_DAPM_MUX("Right Input Inverting Mux", SND_SOC_NOPM, 0, 0,
838f1c0a02fSMark Brown &rinput_inv_mux),
839f1c0a02fSMark Brown SND_SOC_DAPM_MUX("Right Input Mode Mux", SND_SOC_NOPM, 0, 0, &rinput_mode_mux),
840f1c0a02fSMark Brown
841f1c0a02fSMark Brown SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0),
842f1c0a02fSMark Brown SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0),
843f1c0a02fSMark Brown
84497945c46SStephen Warren SND_SOC_DAPM_MUX("Left ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
84597945c46SStephen Warren SND_SOC_DAPM_MUX("Right ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
84697945c46SStephen Warren
8471e113bf9SMark Brown SND_SOC_DAPM_ADC("ADCL", NULL, WM8903_POWER_MANAGEMENT_6, 1, 0),
8481e113bf9SMark Brown SND_SOC_DAPM_ADC("ADCR", NULL, WM8903_POWER_MANAGEMENT_6, 0, 0),
8491e113bf9SMark Brown
8501e113bf9SMark Brown SND_SOC_DAPM_MUX("Left Capture Mux", SND_SOC_NOPM, 0, 0, &lcapture_mux),
8511e113bf9SMark Brown SND_SOC_DAPM_MUX("Right Capture Mux", SND_SOC_NOPM, 0, 0, &rcapture_mux),
8521e113bf9SMark Brown
8531e113bf9SMark Brown SND_SOC_DAPM_AIF_OUT("AIFTXL", "Left HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
8541e113bf9SMark Brown SND_SOC_DAPM_AIF_OUT("AIFTXR", "Right HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
855f1c0a02fSMark Brown
856291ce18cSMark Brown SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &lsidetone_mux),
857291ce18cSMark Brown SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &rsidetone_mux),
858291ce18cSMark Brown
8591e113bf9SMark Brown SND_SOC_DAPM_AIF_IN("AIFRXL", "Left Playback", 0, SND_SOC_NOPM, 0, 0),
8601e113bf9SMark Brown SND_SOC_DAPM_AIF_IN("AIFRXR", "Right Playback", 0, SND_SOC_NOPM, 0, 0),
8611e113bf9SMark Brown
8621e113bf9SMark Brown SND_SOC_DAPM_MUX("Left Playback Mux", SND_SOC_NOPM, 0, 0, &lplay_mux),
8631e113bf9SMark Brown SND_SOC_DAPM_MUX("Right Playback Mux", SND_SOC_NOPM, 0, 0, &rplay_mux),
8641e113bf9SMark Brown
8651e113bf9SMark Brown SND_SOC_DAPM_DAC("DACL", NULL, WM8903_POWER_MANAGEMENT_6, 3, 0),
8661e113bf9SMark Brown SND_SOC_DAPM_DAC("DACR", NULL, WM8903_POWER_MANAGEMENT_6, 2, 0),
867f1c0a02fSMark Brown
868f1c0a02fSMark Brown SND_SOC_DAPM_MIXER("Left Output Mixer", WM8903_POWER_MANAGEMENT_1, 1, 0,
869f1c0a02fSMark Brown left_output_mixer, ARRAY_SIZE(left_output_mixer)),
870f1c0a02fSMark Brown SND_SOC_DAPM_MIXER("Right Output Mixer", WM8903_POWER_MANAGEMENT_1, 0, 0,
871f1c0a02fSMark Brown right_output_mixer, ARRAY_SIZE(right_output_mixer)),
872f1c0a02fSMark Brown
873f1c0a02fSMark Brown SND_SOC_DAPM_MIXER("Left Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 1, 0,
874f1c0a02fSMark Brown left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
875f1c0a02fSMark Brown SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0,
876f1c0a02fSMark Brown right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
877f1c0a02fSMark Brown
8781b877cb5SDilan Lee SND_SOC_DAPM_PGA_S("Left Headphone Output PGA", 0, WM8903_POWER_MANAGEMENT_2,
8791b877cb5SDilan Lee 1, 0, NULL, 0),
8801b877cb5SDilan Lee SND_SOC_DAPM_PGA_S("Right Headphone Output PGA", 0, WM8903_POWER_MANAGEMENT_2,
88113a9983eSMark Brown 0, 0, NULL, 0),
882f1c0a02fSMark Brown
8831b877cb5SDilan Lee SND_SOC_DAPM_PGA_S("Left Line Output PGA", 0, WM8903_POWER_MANAGEMENT_3, 1, 0,
88413a9983eSMark Brown NULL, 0),
8851b877cb5SDilan Lee SND_SOC_DAPM_PGA_S("Right Line Output PGA", 0, WM8903_POWER_MANAGEMENT_3, 0, 0,
88613a9983eSMark Brown NULL, 0),
88713a9983eSMark Brown
88813a9983eSMark Brown SND_SOC_DAPM_PGA_S("HPL_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 7, 0, NULL, 0),
88913a9983eSMark Brown SND_SOC_DAPM_PGA_S("HPL_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 6, 0, NULL, 0),
8901b877cb5SDilan Lee SND_SOC_DAPM_PGA_S("HPL_ENA_DLY", 2, WM8903_ANALOGUE_HP_0, 5, 0, NULL, 0),
8911b877cb5SDilan Lee SND_SOC_DAPM_PGA_S("HPL_ENA", 1, WM8903_ANALOGUE_HP_0, 4, 0, NULL, 0),
89213a9983eSMark Brown SND_SOC_DAPM_PGA_S("HPR_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 3, 0, NULL, 0),
89313a9983eSMark Brown SND_SOC_DAPM_PGA_S("HPR_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 2, 0, NULL, 0),
8941b877cb5SDilan Lee SND_SOC_DAPM_PGA_S("HPR_ENA_DLY", 2, WM8903_ANALOGUE_HP_0, 1, 0, NULL, 0),
8951b877cb5SDilan Lee SND_SOC_DAPM_PGA_S("HPR_ENA", 1, WM8903_ANALOGUE_HP_0, 0, 0, NULL, 0),
89613a9983eSMark Brown
89713a9983eSMark Brown SND_SOC_DAPM_PGA_S("LINEOUTL_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 7, 0,
89813a9983eSMark Brown NULL, 0),
89913a9983eSMark Brown SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 6, 0,
90013a9983eSMark Brown NULL, 0),
9011b877cb5SDilan Lee SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_DLY", 2, WM8903_ANALOGUE_LINEOUT_0, 5, 0,
9021b877cb5SDilan Lee NULL, 0),
9031b877cb5SDilan Lee SND_SOC_DAPM_PGA_S("LINEOUTL_ENA", 1, WM8903_ANALOGUE_LINEOUT_0, 4, 0,
90413a9983eSMark Brown NULL, 0),
90513a9983eSMark Brown SND_SOC_DAPM_PGA_S("LINEOUTR_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 3, 0,
90613a9983eSMark Brown NULL, 0),
90713a9983eSMark Brown SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 2, 0,
90813a9983eSMark Brown NULL, 0),
9091b877cb5SDilan Lee SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_DLY", 2, WM8903_ANALOGUE_LINEOUT_0, 1, 0,
9101b877cb5SDilan Lee NULL, 0),
9111b877cb5SDilan Lee SND_SOC_DAPM_PGA_S("LINEOUTR_ENA", 1, WM8903_ANALOGUE_LINEOUT_0, 0, 0,
91213a9983eSMark Brown NULL, 0),
91313a9983eSMark Brown
914c5b6a9feSMark Brown SND_SOC_DAPM_SUPPLY("DCS Master", WM8903_DC_SERVO_0, 4, 0, NULL, 0),
915c5b6a9feSMark Brown SND_SOC_DAPM_PGA_S("HPL_DCS", 3, SND_SOC_NOPM, 3, 0, wm8903_dcs_event,
916c5b6a9feSMark Brown SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
917c5b6a9feSMark Brown SND_SOC_DAPM_PGA_S("HPR_DCS", 3, SND_SOC_NOPM, 2, 0, wm8903_dcs_event,
918c5b6a9feSMark Brown SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
919c5b6a9feSMark Brown SND_SOC_DAPM_PGA_S("LINEOUTL_DCS", 3, SND_SOC_NOPM, 1, 0, wm8903_dcs_event,
920c5b6a9feSMark Brown SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
921c5b6a9feSMark Brown SND_SOC_DAPM_PGA_S("LINEOUTR_DCS", 3, SND_SOC_NOPM, 0, 0, wm8903_dcs_event,
922c5b6a9feSMark Brown SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
923f1c0a02fSMark Brown
924f1c0a02fSMark Brown SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0,
925f1c0a02fSMark Brown NULL, 0),
926f1c0a02fSMark Brown SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0,
927f1c0a02fSMark Brown NULL, 0),
928f1c0a02fSMark Brown
92942768a12SMark Brown SND_SOC_DAPM_SUPPLY("Charge Pump", WM8903_CHARGE_PUMP_0, 0, 0,
93042768a12SMark Brown wm8903_cp_event, SND_SOC_DAPM_POST_PMU),
931c2aef4ffSMark Brown SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0),
9322c8be5a2SMark Brown SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8903_CLOCK_RATES_2, 2, 0, NULL, 0),
933f1c0a02fSMark Brown };
934f1c0a02fSMark Brown
935ecd01512SMark Brown static const struct snd_soc_dapm_route wm8903_intercon[] = {
936f1c0a02fSMark Brown
9372c8be5a2SMark Brown { "CLK_DSP", NULL, "CLK_SYS" },
9385032dc34SMark Brown { "MICBIAS", NULL, "CLK_SYS" },
9392c8be5a2SMark Brown { "HPL_DCS", NULL, "CLK_SYS" },
9402c8be5a2SMark Brown { "HPR_DCS", NULL, "CLK_SYS" },
9412c8be5a2SMark Brown { "LINEOUTL_DCS", NULL, "CLK_SYS" },
9422c8be5a2SMark Brown { "LINEOUTR_DCS", NULL, "CLK_SYS" },
9432c8be5a2SMark Brown
944f1c0a02fSMark Brown { "Left Input Mux", "IN1L", "IN1L" },
945f1c0a02fSMark Brown { "Left Input Mux", "IN2L", "IN2L" },
946f1c0a02fSMark Brown { "Left Input Mux", "IN3L", "IN3L" },
947f1c0a02fSMark Brown
948f1c0a02fSMark Brown { "Left Input Inverting Mux", "IN1L", "IN1L" },
949f1c0a02fSMark Brown { "Left Input Inverting Mux", "IN2L", "IN2L" },
950f1c0a02fSMark Brown { "Left Input Inverting Mux", "IN3L", "IN3L" },
951f1c0a02fSMark Brown
952f1c0a02fSMark Brown { "Right Input Mux", "IN1R", "IN1R" },
953f1c0a02fSMark Brown { "Right Input Mux", "IN2R", "IN2R" },
954f1c0a02fSMark Brown { "Right Input Mux", "IN3R", "IN3R" },
955f1c0a02fSMark Brown
956f1c0a02fSMark Brown { "Right Input Inverting Mux", "IN1R", "IN1R" },
957f1c0a02fSMark Brown { "Right Input Inverting Mux", "IN2R", "IN2R" },
958f1c0a02fSMark Brown { "Right Input Inverting Mux", "IN3R", "IN3R" },
959f1c0a02fSMark Brown
960f1c0a02fSMark Brown { "Left Input Mode Mux", "Single-Ended", "Left Input Inverting Mux" },
961f1c0a02fSMark Brown { "Left Input Mode Mux", "Differential Line",
962f1c0a02fSMark Brown "Left Input Mux" },
963f1c0a02fSMark Brown { "Left Input Mode Mux", "Differential Line",
964f1c0a02fSMark Brown "Left Input Inverting Mux" },
965f1c0a02fSMark Brown { "Left Input Mode Mux", "Differential Mic",
966f1c0a02fSMark Brown "Left Input Mux" },
967f1c0a02fSMark Brown { "Left Input Mode Mux", "Differential Mic",
968f1c0a02fSMark Brown "Left Input Inverting Mux" },
969f1c0a02fSMark Brown
970f1c0a02fSMark Brown { "Right Input Mode Mux", "Single-Ended",
971f1c0a02fSMark Brown "Right Input Inverting Mux" },
972f1c0a02fSMark Brown { "Right Input Mode Mux", "Differential Line",
973f1c0a02fSMark Brown "Right Input Mux" },
974f1c0a02fSMark Brown { "Right Input Mode Mux", "Differential Line",
975f1c0a02fSMark Brown "Right Input Inverting Mux" },
976f1c0a02fSMark Brown { "Right Input Mode Mux", "Differential Mic",
977f1c0a02fSMark Brown "Right Input Mux" },
978f1c0a02fSMark Brown { "Right Input Mode Mux", "Differential Mic",
979f1c0a02fSMark Brown "Right Input Inverting Mux" },
980f1c0a02fSMark Brown
981f1c0a02fSMark Brown { "Left Input PGA", NULL, "Left Input Mode Mux" },
982f1c0a02fSMark Brown { "Right Input PGA", NULL, "Right Input Mode Mux" },
983f1c0a02fSMark Brown
98497945c46SStephen Warren { "Left ADC Input", "ADC", "Left Input PGA" },
98597945c46SStephen Warren { "Left ADC Input", "DMIC", "DMICDAT" },
98697945c46SStephen Warren { "Right ADC Input", "ADC", "Right Input PGA" },
98797945c46SStephen Warren { "Right ADC Input", "DMIC", "DMICDAT" },
98897945c46SStephen Warren
9891e113bf9SMark Brown { "Left Capture Mux", "Left", "ADCL" },
9901e113bf9SMark Brown { "Left Capture Mux", "Right", "ADCR" },
9911e113bf9SMark Brown
9921e113bf9SMark Brown { "Right Capture Mux", "Left", "ADCL" },
9931e113bf9SMark Brown { "Right Capture Mux", "Right", "ADCR" },
9941e113bf9SMark Brown
9951e113bf9SMark Brown { "AIFTXL", NULL, "Left Capture Mux" },
9961e113bf9SMark Brown { "AIFTXR", NULL, "Right Capture Mux" },
9971e113bf9SMark Brown
99897945c46SStephen Warren { "ADCL", NULL, "Left ADC Input" },
999c2aef4ffSMark Brown { "ADCL", NULL, "CLK_DSP" },
100097945c46SStephen Warren { "ADCR", NULL, "Right ADC Input" },
1001c2aef4ffSMark Brown { "ADCR", NULL, "CLK_DSP" },
1002c2aef4ffSMark Brown
10031e113bf9SMark Brown { "Left Playback Mux", "Left", "AIFRXL" },
10041e113bf9SMark Brown { "Left Playback Mux", "Right", "AIFRXR" },
10051e113bf9SMark Brown
10061e113bf9SMark Brown { "Right Playback Mux", "Left", "AIFRXL" },
10071e113bf9SMark Brown { "Right Playback Mux", "Right", "AIFRXR" },
10081e113bf9SMark Brown
1009291ce18cSMark Brown { "DACL Sidetone", "Left", "ADCL" },
1010291ce18cSMark Brown { "DACL Sidetone", "Right", "ADCR" },
1011291ce18cSMark Brown { "DACR Sidetone", "Left", "ADCL" },
1012291ce18cSMark Brown { "DACR Sidetone", "Right", "ADCR" },
1013291ce18cSMark Brown
10141e113bf9SMark Brown { "DACL", NULL, "Left Playback Mux" },
1015291ce18cSMark Brown { "DACL", NULL, "DACL Sidetone" },
1016c2aef4ffSMark Brown { "DACL", NULL, "CLK_DSP" },
10171e113bf9SMark Brown
10181e113bf9SMark Brown { "DACR", NULL, "Right Playback Mux" },
1019291ce18cSMark Brown { "DACR", NULL, "DACR Sidetone" },
1020c2aef4ffSMark Brown { "DACR", NULL, "CLK_DSP" },
1021f1c0a02fSMark Brown
1022f1c0a02fSMark Brown { "Left Output Mixer", "Left Bypass Switch", "Left Input PGA" },
1023f1c0a02fSMark Brown { "Left Output Mixer", "Right Bypass Switch", "Right Input PGA" },
1024f1c0a02fSMark Brown { "Left Output Mixer", "DACL Switch", "DACL" },
1025f1c0a02fSMark Brown { "Left Output Mixer", "DACR Switch", "DACR" },
1026f1c0a02fSMark Brown
1027f1c0a02fSMark Brown { "Right Output Mixer", "Left Bypass Switch", "Left Input PGA" },
1028f1c0a02fSMark Brown { "Right Output Mixer", "Right Bypass Switch", "Right Input PGA" },
1029f1c0a02fSMark Brown { "Right Output Mixer", "DACL Switch", "DACL" },
1030f1c0a02fSMark Brown { "Right Output Mixer", "DACR Switch", "DACR" },
1031f1c0a02fSMark Brown
1032f1c0a02fSMark Brown { "Left Speaker Mixer", "Left Bypass Switch", "Left Input PGA" },
1033f1c0a02fSMark Brown { "Left Speaker Mixer", "Right Bypass Switch", "Right Input PGA" },
1034f1c0a02fSMark Brown { "Left Speaker Mixer", "DACL Switch", "DACL" },
1035f1c0a02fSMark Brown { "Left Speaker Mixer", "DACR Switch", "DACR" },
1036f1c0a02fSMark Brown
1037f1c0a02fSMark Brown { "Right Speaker Mixer", "Left Bypass Switch", "Left Input PGA" },
1038f1c0a02fSMark Brown { "Right Speaker Mixer", "Right Bypass Switch", "Right Input PGA" },
1039f1c0a02fSMark Brown { "Right Speaker Mixer", "DACL Switch", "DACL" },
1040f1c0a02fSMark Brown { "Right Speaker Mixer", "DACR Switch", "DACR" },
1041f1c0a02fSMark Brown
1042f1c0a02fSMark Brown { "Left Line Output PGA", NULL, "Left Output Mixer" },
1043f1c0a02fSMark Brown { "Right Line Output PGA", NULL, "Right Output Mixer" },
1044f1c0a02fSMark Brown
1045f1c0a02fSMark Brown { "Left Headphone Output PGA", NULL, "Left Output Mixer" },
1046f1c0a02fSMark Brown { "Right Headphone Output PGA", NULL, "Right Output Mixer" },
1047f1c0a02fSMark Brown
1048f1c0a02fSMark Brown { "Left Speaker PGA", NULL, "Left Speaker Mixer" },
1049f1c0a02fSMark Brown { "Right Speaker PGA", NULL, "Right Speaker Mixer" },
1050f1c0a02fSMark Brown
10511b877cb5SDilan Lee { "HPL_ENA", NULL, "Left Headphone Output PGA" },
10521b877cb5SDilan Lee { "HPR_ENA", NULL, "Right Headphone Output PGA" },
10531b877cb5SDilan Lee { "HPL_ENA_DLY", NULL, "HPL_ENA" },
10541b877cb5SDilan Lee { "HPR_ENA_DLY", NULL, "HPR_ENA" },
10551b877cb5SDilan Lee { "LINEOUTL_ENA", NULL, "Left Line Output PGA" },
10561b877cb5SDilan Lee { "LINEOUTR_ENA", NULL, "Right Line Output PGA" },
10571b877cb5SDilan Lee { "LINEOUTL_ENA_DLY", NULL, "LINEOUTL_ENA" },
10581b877cb5SDilan Lee { "LINEOUTR_ENA_DLY", NULL, "LINEOUTR_ENA" },
1059f1c0a02fSMark Brown
1060c5b6a9feSMark Brown { "HPL_DCS", NULL, "DCS Master" },
1061c5b6a9feSMark Brown { "HPR_DCS", NULL, "DCS Master" },
1062c5b6a9feSMark Brown { "LINEOUTL_DCS", NULL, "DCS Master" },
1063c5b6a9feSMark Brown { "LINEOUTR_DCS", NULL, "DCS Master" },
1064c5b6a9feSMark Brown
106513a9983eSMark Brown { "HPL_DCS", NULL, "HPL_ENA_DLY" },
106613a9983eSMark Brown { "HPR_DCS", NULL, "HPR_ENA_DLY" },
106713a9983eSMark Brown { "LINEOUTL_DCS", NULL, "LINEOUTL_ENA_DLY" },
106813a9983eSMark Brown { "LINEOUTR_DCS", NULL, "LINEOUTR_ENA_DLY" },
106913a9983eSMark Brown
107013a9983eSMark Brown { "HPL_ENA_OUTP", NULL, "HPL_DCS" },
107113a9983eSMark Brown { "HPR_ENA_OUTP", NULL, "HPR_DCS" },
107213a9983eSMark Brown { "LINEOUTL_ENA_OUTP", NULL, "LINEOUTL_DCS" },
107313a9983eSMark Brown { "LINEOUTR_ENA_OUTP", NULL, "LINEOUTR_DCS" },
107413a9983eSMark Brown
107513a9983eSMark Brown { "HPL_RMV_SHORT", NULL, "HPL_ENA_OUTP" },
107613a9983eSMark Brown { "HPR_RMV_SHORT", NULL, "HPR_ENA_OUTP" },
107713a9983eSMark Brown { "LINEOUTL_RMV_SHORT", NULL, "LINEOUTL_ENA_OUTP" },
107813a9983eSMark Brown { "LINEOUTR_RMV_SHORT", NULL, "LINEOUTR_ENA_OUTP" },
107913a9983eSMark Brown
108013a9983eSMark Brown { "HPOUTL", NULL, "HPL_RMV_SHORT" },
108113a9983eSMark Brown { "HPOUTR", NULL, "HPR_RMV_SHORT" },
108213a9983eSMark Brown { "LINEOUTL", NULL, "LINEOUTL_RMV_SHORT" },
108313a9983eSMark Brown { "LINEOUTR", NULL, "LINEOUTR_RMV_SHORT" },
1084f1c0a02fSMark Brown
1085f1c0a02fSMark Brown { "LOP", NULL, "Left Speaker PGA" },
1086f1c0a02fSMark Brown { "LON", NULL, "Left Speaker PGA" },
1087f1c0a02fSMark Brown
1088f1c0a02fSMark Brown { "ROP", NULL, "Right Speaker PGA" },
1089f1c0a02fSMark Brown { "RON", NULL, "Right Speaker PGA" },
109042768a12SMark Brown
1091f1ca493bSAlban Bedel { "Charge Pump", NULL, "CLK_DSP" },
1092f1ca493bSAlban Bedel
109342768a12SMark Brown { "Left Headphone Output PGA", NULL, "Charge Pump" },
109442768a12SMark Brown { "Right Headphone Output PGA", NULL, "Charge Pump" },
109542768a12SMark Brown { "Left Line Output PGA", NULL, "Charge Pump" },
109642768a12SMark Brown { "Right Line Output PGA", NULL, "Charge Pump" },
1097f1c0a02fSMark Brown };
1098f1c0a02fSMark Brown
wm8903_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)109958bd2934SKuninori Morimoto static int wm8903_set_bias_level(struct snd_soc_component *component,
1100f1c0a02fSMark Brown enum snd_soc_bias_level level)
1101f1c0a02fSMark Brown {
1102f1c0a02fSMark Brown switch (level) {
1103f1c0a02fSMark Brown case SND_SOC_BIAS_ON:
110466daaa59SMark Brown break;
110522f226ddSMark Brown
1106f1c0a02fSMark Brown case SND_SOC_BIAS_PREPARE:
110758bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
110866daaa59SMark Brown WM8903_VMID_RES_MASK,
110966daaa59SMark Brown WM8903_VMID_RES_50K);
1110f1c0a02fSMark Brown break;
1111f1c0a02fSMark Brown
1112f1c0a02fSMark Brown case SND_SOC_BIAS_STANDBY:
111358bd2934SKuninori Morimoto if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
111458bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_BIAS_CONTROL_0,
111522f226ddSMark Brown WM8903_POBCTRL | WM8903_ISEL_MASK |
111622f226ddSMark Brown WM8903_STARTUP_BIAS_ENA |
111722f226ddSMark Brown WM8903_BIAS_ENA,
111822f226ddSMark Brown WM8903_POBCTRL |
111922f226ddSMark Brown (2 << WM8903_ISEL_SHIFT) |
112022f226ddSMark Brown WM8903_STARTUP_BIAS_ENA);
11213b1228abSMark Brown
112258bd2934SKuninori Morimoto snd_soc_component_update_bits(component,
112322f226ddSMark Brown WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0,
112422f226ddSMark Brown WM8903_SPK_DISCHARGE,
112522f226ddSMark Brown WM8903_SPK_DISCHARGE);
11264dbfe809SMark Brown
112722f226ddSMark Brown msleep(33);
112822f226ddSMark Brown
112958bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_POWER_MANAGEMENT_5,
113022f226ddSMark Brown WM8903_SPKL_ENA | WM8903_SPKR_ENA,
113122f226ddSMark Brown WM8903_SPKL_ENA | WM8903_SPKR_ENA);
113222f226ddSMark Brown
113358bd2934SKuninori Morimoto snd_soc_component_update_bits(component,
113422f226ddSMark Brown WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0,
113522f226ddSMark Brown WM8903_SPK_DISCHARGE, 0);
113622f226ddSMark Brown
113758bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
113822f226ddSMark Brown WM8903_VMID_TIE_ENA |
113922f226ddSMark Brown WM8903_BUFIO_ENA |
114022f226ddSMark Brown WM8903_VMID_IO_ENA |
114122f226ddSMark Brown WM8903_VMID_SOFT_MASK |
114222f226ddSMark Brown WM8903_VMID_RES_MASK |
114322f226ddSMark Brown WM8903_VMID_BUF_ENA,
114422f226ddSMark Brown WM8903_VMID_TIE_ENA |
114522f226ddSMark Brown WM8903_BUFIO_ENA |
114622f226ddSMark Brown WM8903_VMID_IO_ENA |
114722f226ddSMark Brown (2 << WM8903_VMID_SOFT_SHIFT) |
114822f226ddSMark Brown WM8903_VMID_RES_250K |
114922f226ddSMark Brown WM8903_VMID_BUF_ENA);
115022f226ddSMark Brown
115122f226ddSMark Brown msleep(129);
115222f226ddSMark Brown
115358bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_POWER_MANAGEMENT_5,
115422f226ddSMark Brown WM8903_SPKL_ENA | WM8903_SPKR_ENA,
115522f226ddSMark Brown 0);
115622f226ddSMark Brown
115758bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
115822f226ddSMark Brown WM8903_VMID_SOFT_MASK, 0);
115922f226ddSMark Brown
116058bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
116122f226ddSMark Brown WM8903_VMID_RES_MASK,
116222f226ddSMark Brown WM8903_VMID_RES_50K);
116322f226ddSMark Brown
116458bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_BIAS_CONTROL_0,
116522f226ddSMark Brown WM8903_BIAS_ENA | WM8903_POBCTRL,
116622f226ddSMark Brown WM8903_BIAS_ENA);
1167f1c0a02fSMark Brown
1168f1c0a02fSMark Brown /* By default no bypass paths are enabled so
1169f1c0a02fSMark Brown * enable Class W support.
1170f1c0a02fSMark Brown */
117158bd2934SKuninori Morimoto dev_dbg(component->dev, "Enabling Class W\n");
117258bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_CLASS_W_0,
1173524d7692SMark Brown WM8903_CP_DYN_FREQ |
1174524d7692SMark Brown WM8903_CP_DYN_V,
1175524d7692SMark Brown WM8903_CP_DYN_FREQ |
1176524d7692SMark Brown WM8903_CP_DYN_V);
1177f1c0a02fSMark Brown }
1178f1c0a02fSMark Brown
117958bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
118066daaa59SMark Brown WM8903_VMID_RES_MASK,
118166daaa59SMark Brown WM8903_VMID_RES_250K);
1182f1c0a02fSMark Brown break;
1183f1c0a02fSMark Brown
1184f1c0a02fSMark Brown case SND_SOC_BIAS_OFF:
118558bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_BIAS_CONTROL_0,
1186b4d06f45SMark Brown WM8903_BIAS_ENA, 0);
1187b4d06f45SMark Brown
118858bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
1189b4d06f45SMark Brown WM8903_VMID_SOFT_MASK,
1190b4d06f45SMark Brown 2 << WM8903_VMID_SOFT_SHIFT);
1191b4d06f45SMark Brown
119258bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
1193b4d06f45SMark Brown WM8903_VMID_BUF_ENA, 0);
1194b4d06f45SMark Brown
1195b4d06f45SMark Brown msleep(290);
1196b4d06f45SMark Brown
119758bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_VMID_CONTROL_0,
1198b4d06f45SMark Brown WM8903_VMID_TIE_ENA | WM8903_BUFIO_ENA |
1199b4d06f45SMark Brown WM8903_VMID_IO_ENA | WM8903_VMID_RES_MASK |
1200b4d06f45SMark Brown WM8903_VMID_SOFT_MASK |
1201b4d06f45SMark Brown WM8903_VMID_BUF_ENA, 0);
1202b4d06f45SMark Brown
120358bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_BIAS_CONTROL_0,
1204b4d06f45SMark Brown WM8903_STARTUP_BIAS_ENA, 0);
1205f1c0a02fSMark Brown break;
1206f1c0a02fSMark Brown }
1207f1c0a02fSMark Brown
1208f1c0a02fSMark Brown return 0;
1209f1c0a02fSMark Brown }
1210f1c0a02fSMark Brown
wm8903_set_dai_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)1211f1c0a02fSMark Brown static int wm8903_set_dai_sysclk(struct snd_soc_dai *codec_dai,
1212f1c0a02fSMark Brown int clk_id, unsigned int freq, int dir)
1213f1c0a02fSMark Brown {
121458bd2934SKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
121558bd2934SKuninori Morimoto struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
1216f1c0a02fSMark Brown
1217f1c0a02fSMark Brown wm8903->sysclk = freq;
1218f1c0a02fSMark Brown
1219f1c0a02fSMark Brown return 0;
1220f1c0a02fSMark Brown }
1221f1c0a02fSMark Brown
wm8903_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)1222f1c0a02fSMark Brown static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai,
1223f1c0a02fSMark Brown unsigned int fmt)
1224f1c0a02fSMark Brown {
122558bd2934SKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
12266d75dfc3SKuninori Morimoto u16 aif1 = snd_soc_component_read(component, WM8903_AUDIO_INTERFACE_1);
1227f1c0a02fSMark Brown
1228f1c0a02fSMark Brown aif1 &= ~(WM8903_LRCLK_DIR | WM8903_BCLK_DIR | WM8903_AIF_FMT_MASK |
1229f1c0a02fSMark Brown WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV);
1230f1c0a02fSMark Brown
1231f1c0a02fSMark Brown switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1232f1c0a02fSMark Brown case SND_SOC_DAIFMT_CBS_CFS:
1233f1c0a02fSMark Brown break;
1234f1c0a02fSMark Brown case SND_SOC_DAIFMT_CBS_CFM:
1235f1c0a02fSMark Brown aif1 |= WM8903_LRCLK_DIR;
1236f1c0a02fSMark Brown break;
1237f1c0a02fSMark Brown case SND_SOC_DAIFMT_CBM_CFM:
1238f1c0a02fSMark Brown aif1 |= WM8903_LRCLK_DIR | WM8903_BCLK_DIR;
1239f1c0a02fSMark Brown break;
1240f1c0a02fSMark Brown case SND_SOC_DAIFMT_CBM_CFS:
1241f1c0a02fSMark Brown aif1 |= WM8903_BCLK_DIR;
1242f1c0a02fSMark Brown break;
1243f1c0a02fSMark Brown default:
1244f1c0a02fSMark Brown return -EINVAL;
1245f1c0a02fSMark Brown }
1246f1c0a02fSMark Brown
1247f1c0a02fSMark Brown switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1248f1c0a02fSMark Brown case SND_SOC_DAIFMT_DSP_A:
1249f1c0a02fSMark Brown aif1 |= 0x3;
1250f1c0a02fSMark Brown break;
1251f1c0a02fSMark Brown case SND_SOC_DAIFMT_DSP_B:
1252f1c0a02fSMark Brown aif1 |= 0x3 | WM8903_AIF_LRCLK_INV;
1253f1c0a02fSMark Brown break;
1254f1c0a02fSMark Brown case SND_SOC_DAIFMT_I2S:
1255f1c0a02fSMark Brown aif1 |= 0x2;
1256f1c0a02fSMark Brown break;
1257f1c0a02fSMark Brown case SND_SOC_DAIFMT_RIGHT_J:
1258f1c0a02fSMark Brown aif1 |= 0x1;
1259f1c0a02fSMark Brown break;
1260f1c0a02fSMark Brown case SND_SOC_DAIFMT_LEFT_J:
1261f1c0a02fSMark Brown break;
1262f1c0a02fSMark Brown default:
1263f1c0a02fSMark Brown return -EINVAL;
1264f1c0a02fSMark Brown }
1265f1c0a02fSMark Brown
1266f1c0a02fSMark Brown /* Clock inversion */
1267f1c0a02fSMark Brown switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1268f1c0a02fSMark Brown case SND_SOC_DAIFMT_DSP_A:
1269f1c0a02fSMark Brown case SND_SOC_DAIFMT_DSP_B:
1270f1c0a02fSMark Brown /* frame inversion not valid for DSP modes */
1271f1c0a02fSMark Brown switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1272f1c0a02fSMark Brown case SND_SOC_DAIFMT_NB_NF:
1273f1c0a02fSMark Brown break;
1274f1c0a02fSMark Brown case SND_SOC_DAIFMT_IB_NF:
1275f1c0a02fSMark Brown aif1 |= WM8903_AIF_BCLK_INV;
1276f1c0a02fSMark Brown break;
1277f1c0a02fSMark Brown default:
1278f1c0a02fSMark Brown return -EINVAL;
1279f1c0a02fSMark Brown }
1280f1c0a02fSMark Brown break;
1281f1c0a02fSMark Brown case SND_SOC_DAIFMT_I2S:
1282f1c0a02fSMark Brown case SND_SOC_DAIFMT_RIGHT_J:
1283f1c0a02fSMark Brown case SND_SOC_DAIFMT_LEFT_J:
1284f1c0a02fSMark Brown switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1285f1c0a02fSMark Brown case SND_SOC_DAIFMT_NB_NF:
1286f1c0a02fSMark Brown break;
1287f1c0a02fSMark Brown case SND_SOC_DAIFMT_IB_IF:
1288f1c0a02fSMark Brown aif1 |= WM8903_AIF_BCLK_INV | WM8903_AIF_LRCLK_INV;
1289f1c0a02fSMark Brown break;
1290f1c0a02fSMark Brown case SND_SOC_DAIFMT_IB_NF:
1291f1c0a02fSMark Brown aif1 |= WM8903_AIF_BCLK_INV;
1292f1c0a02fSMark Brown break;
1293f1c0a02fSMark Brown case SND_SOC_DAIFMT_NB_IF:
1294f1c0a02fSMark Brown aif1 |= WM8903_AIF_LRCLK_INV;
1295f1c0a02fSMark Brown break;
1296f1c0a02fSMark Brown default:
1297f1c0a02fSMark Brown return -EINVAL;
1298f1c0a02fSMark Brown }
1299f1c0a02fSMark Brown break;
1300f1c0a02fSMark Brown default:
1301f1c0a02fSMark Brown return -EINVAL;
1302f1c0a02fSMark Brown }
1303f1c0a02fSMark Brown
130458bd2934SKuninori Morimoto snd_soc_component_write(component, WM8903_AUDIO_INTERFACE_1, aif1);
1305f1c0a02fSMark Brown
1306f1c0a02fSMark Brown return 0;
1307f1c0a02fSMark Brown }
1308f1c0a02fSMark Brown
wm8903_mute(struct snd_soc_dai * codec_dai,int mute,int direction)130926d3c16eSKuninori Morimoto static int wm8903_mute(struct snd_soc_dai *codec_dai, int mute, int direction)
1310f1c0a02fSMark Brown {
131158bd2934SKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
1312f1c0a02fSMark Brown u16 reg;
1313f1c0a02fSMark Brown
13146d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8903_DAC_DIGITAL_1);
1315f1c0a02fSMark Brown
1316f1c0a02fSMark Brown if (mute)
1317f1c0a02fSMark Brown reg |= WM8903_DAC_MUTE;
1318f1c0a02fSMark Brown else
1319f1c0a02fSMark Brown reg &= ~WM8903_DAC_MUTE;
1320f1c0a02fSMark Brown
132158bd2934SKuninori Morimoto snd_soc_component_write(component, WM8903_DAC_DIGITAL_1, reg);
1322f1c0a02fSMark Brown
1323f1c0a02fSMark Brown return 0;
1324f1c0a02fSMark Brown }
1325f1c0a02fSMark Brown
1326f1c0a02fSMark Brown /* Lookup table for CLK_SYS/fs ratio. 256fs or more is recommended
1327f1c0a02fSMark Brown * for optimal performance so we list the lower rates first and match
1328f1c0a02fSMark Brown * on the last match we find. */
1329f1c0a02fSMark Brown static struct {
1330f1c0a02fSMark Brown int div;
1331f1c0a02fSMark Brown int rate;
1332f1c0a02fSMark Brown int mode;
1333f1c0a02fSMark Brown int mclk_div;
1334f1c0a02fSMark Brown } clk_sys_ratios[] = {
1335f1c0a02fSMark Brown { 64, 0x0, 0x0, 1 },
1336f1c0a02fSMark Brown { 68, 0x0, 0x1, 1 },
1337f1c0a02fSMark Brown { 125, 0x0, 0x2, 1 },
1338f1c0a02fSMark Brown { 128, 0x1, 0x0, 1 },
1339f1c0a02fSMark Brown { 136, 0x1, 0x1, 1 },
1340f1c0a02fSMark Brown { 192, 0x2, 0x0, 1 },
1341f1c0a02fSMark Brown { 204, 0x2, 0x1, 1 },
1342f1c0a02fSMark Brown
1343f1c0a02fSMark Brown { 64, 0x0, 0x0, 2 },
1344f1c0a02fSMark Brown { 68, 0x0, 0x1, 2 },
1345f1c0a02fSMark Brown { 125, 0x0, 0x2, 2 },
1346f1c0a02fSMark Brown { 128, 0x1, 0x0, 2 },
1347f1c0a02fSMark Brown { 136, 0x1, 0x1, 2 },
1348f1c0a02fSMark Brown { 192, 0x2, 0x0, 2 },
1349f1c0a02fSMark Brown { 204, 0x2, 0x1, 2 },
1350f1c0a02fSMark Brown
1351f1c0a02fSMark Brown { 250, 0x2, 0x2, 1 },
1352f1c0a02fSMark Brown { 256, 0x3, 0x0, 1 },
1353f1c0a02fSMark Brown { 272, 0x3, 0x1, 1 },
1354f1c0a02fSMark Brown { 384, 0x4, 0x0, 1 },
1355f1c0a02fSMark Brown { 408, 0x4, 0x1, 1 },
1356f1c0a02fSMark Brown { 375, 0x4, 0x2, 1 },
1357f1c0a02fSMark Brown { 512, 0x5, 0x0, 1 },
1358f1c0a02fSMark Brown { 544, 0x5, 0x1, 1 },
1359f1c0a02fSMark Brown { 500, 0x5, 0x2, 1 },
1360f1c0a02fSMark Brown { 768, 0x6, 0x0, 1 },
1361f1c0a02fSMark Brown { 816, 0x6, 0x1, 1 },
1362f1c0a02fSMark Brown { 750, 0x6, 0x2, 1 },
1363f1c0a02fSMark Brown { 1024, 0x7, 0x0, 1 },
1364f1c0a02fSMark Brown { 1088, 0x7, 0x1, 1 },
1365f1c0a02fSMark Brown { 1000, 0x7, 0x2, 1 },
1366f1c0a02fSMark Brown { 1408, 0x8, 0x0, 1 },
1367f1c0a02fSMark Brown { 1496, 0x8, 0x1, 1 },
1368f1c0a02fSMark Brown { 1536, 0x9, 0x0, 1 },
1369f1c0a02fSMark Brown { 1632, 0x9, 0x1, 1 },
1370f1c0a02fSMark Brown { 1500, 0x9, 0x2, 1 },
1371f1c0a02fSMark Brown
1372f1c0a02fSMark Brown { 250, 0x2, 0x2, 2 },
1373f1c0a02fSMark Brown { 256, 0x3, 0x0, 2 },
1374f1c0a02fSMark Brown { 272, 0x3, 0x1, 2 },
1375f1c0a02fSMark Brown { 384, 0x4, 0x0, 2 },
1376f1c0a02fSMark Brown { 408, 0x4, 0x1, 2 },
1377f1c0a02fSMark Brown { 375, 0x4, 0x2, 2 },
1378f1c0a02fSMark Brown { 512, 0x5, 0x0, 2 },
1379f1c0a02fSMark Brown { 544, 0x5, 0x1, 2 },
1380f1c0a02fSMark Brown { 500, 0x5, 0x2, 2 },
1381f1c0a02fSMark Brown { 768, 0x6, 0x0, 2 },
1382f1c0a02fSMark Brown { 816, 0x6, 0x1, 2 },
1383f1c0a02fSMark Brown { 750, 0x6, 0x2, 2 },
1384f1c0a02fSMark Brown { 1024, 0x7, 0x0, 2 },
1385f1c0a02fSMark Brown { 1088, 0x7, 0x1, 2 },
1386f1c0a02fSMark Brown { 1000, 0x7, 0x2, 2 },
1387f1c0a02fSMark Brown { 1408, 0x8, 0x0, 2 },
1388f1c0a02fSMark Brown { 1496, 0x8, 0x1, 2 },
1389f1c0a02fSMark Brown { 1536, 0x9, 0x0, 2 },
1390f1c0a02fSMark Brown { 1632, 0x9, 0x1, 2 },
1391f1c0a02fSMark Brown { 1500, 0x9, 0x2, 2 },
1392f1c0a02fSMark Brown };
1393f1c0a02fSMark Brown
1394f1c0a02fSMark Brown /* CLK_SYS/BCLK ratios - multiplied by 10 due to .5s */
1395f1c0a02fSMark Brown static struct {
1396f1c0a02fSMark Brown int ratio;
1397f1c0a02fSMark Brown int div;
1398f1c0a02fSMark Brown } bclk_divs[] = {
1399f1c0a02fSMark Brown { 10, 0 },
1400f1c0a02fSMark Brown { 20, 2 },
1401f1c0a02fSMark Brown { 30, 3 },
1402f1c0a02fSMark Brown { 40, 4 },
1403f1c0a02fSMark Brown { 50, 5 },
1404f1c0a02fSMark Brown { 60, 7 },
1405f1c0a02fSMark Brown { 80, 8 },
1406f1c0a02fSMark Brown { 100, 9 },
1407f1c0a02fSMark Brown { 120, 11 },
1408f1c0a02fSMark Brown { 160, 12 },
1409f1c0a02fSMark Brown { 200, 13 },
1410f1c0a02fSMark Brown { 220, 14 },
1411f1c0a02fSMark Brown { 240, 15 },
1412f1c0a02fSMark Brown { 300, 17 },
1413f1c0a02fSMark Brown { 320, 18 },
1414f1c0a02fSMark Brown { 440, 19 },
1415f1c0a02fSMark Brown { 480, 20 },
1416f1c0a02fSMark Brown };
1417f1c0a02fSMark Brown
1418f1c0a02fSMark Brown /* Sample rates for DSP */
1419f1c0a02fSMark Brown static struct {
1420f1c0a02fSMark Brown int rate;
1421f1c0a02fSMark Brown int value;
1422f1c0a02fSMark Brown } sample_rates[] = {
1423f1c0a02fSMark Brown { 8000, 0 },
1424f1c0a02fSMark Brown { 11025, 1 },
1425f1c0a02fSMark Brown { 12000, 2 },
1426f1c0a02fSMark Brown { 16000, 3 },
1427f1c0a02fSMark Brown { 22050, 4 },
1428f1c0a02fSMark Brown { 24000, 5 },
1429f1c0a02fSMark Brown { 32000, 6 },
1430f1c0a02fSMark Brown { 44100, 7 },
1431f1c0a02fSMark Brown { 48000, 8 },
1432f1c0a02fSMark Brown { 88200, 9 },
1433f1c0a02fSMark Brown { 96000, 10 },
1434f1c0a02fSMark Brown { 0, 0 },
1435f1c0a02fSMark Brown };
1436f1c0a02fSMark Brown
wm8903_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)1437f1c0a02fSMark Brown static int wm8903_hw_params(struct snd_pcm_substream *substream,
1438dee89c4dSMark Brown struct snd_pcm_hw_params *params,
1439dee89c4dSMark Brown struct snd_soc_dai *dai)
1440f1c0a02fSMark Brown {
144158bd2934SKuninori Morimoto struct snd_soc_component *component = dai->component;
144258bd2934SKuninori Morimoto struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
1443f1c0a02fSMark Brown int fs = params_rate(params);
1444f1c0a02fSMark Brown int bclk;
1445f1c0a02fSMark Brown int bclk_div;
1446f1c0a02fSMark Brown int i;
1447f1c0a02fSMark Brown int dsp_config;
1448f1c0a02fSMark Brown int clk_config;
1449f1c0a02fSMark Brown int best_val;
1450f1c0a02fSMark Brown int cur_val;
1451f1c0a02fSMark Brown int clk_sys;
1452f1c0a02fSMark Brown
14536d75dfc3SKuninori Morimoto u16 aif1 = snd_soc_component_read(component, WM8903_AUDIO_INTERFACE_1);
14546d75dfc3SKuninori Morimoto u16 aif2 = snd_soc_component_read(component, WM8903_AUDIO_INTERFACE_2);
14556d75dfc3SKuninori Morimoto u16 aif3 = snd_soc_component_read(component, WM8903_AUDIO_INTERFACE_3);
14566d75dfc3SKuninori Morimoto u16 clock0 = snd_soc_component_read(component, WM8903_CLOCK_RATES_0);
14576d75dfc3SKuninori Morimoto u16 clock1 = snd_soc_component_read(component, WM8903_CLOCK_RATES_1);
14586d75dfc3SKuninori Morimoto u16 dac_digital1 = snd_soc_component_read(component, WM8903_DAC_DIGITAL_1);
1459f1c0a02fSMark Brown
14609e79261fSMark Brown /* Enable sloping stopband filter for low sample rates */
14619e79261fSMark Brown if (fs <= 24000)
14629e79261fSMark Brown dac_digital1 |= WM8903_DAC_SB_FILT;
14639e79261fSMark Brown else
14649e79261fSMark Brown dac_digital1 &= ~WM8903_DAC_SB_FILT;
14659e79261fSMark Brown
1466f1c0a02fSMark Brown /* Configure sample rate logic for DSP - choose nearest rate */
1467f1c0a02fSMark Brown dsp_config = 0;
1468f1c0a02fSMark Brown best_val = abs(sample_rates[dsp_config].rate - fs);
1469f1c0a02fSMark Brown for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
1470f1c0a02fSMark Brown cur_val = abs(sample_rates[i].rate - fs);
1471f1c0a02fSMark Brown if (cur_val <= best_val) {
1472f1c0a02fSMark Brown dsp_config = i;
1473f1c0a02fSMark Brown best_val = cur_val;
1474f1c0a02fSMark Brown }
1475f1c0a02fSMark Brown }
1476f1c0a02fSMark Brown
147758bd2934SKuninori Morimoto dev_dbg(component->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
1478f1c0a02fSMark Brown clock1 &= ~WM8903_SAMPLE_RATE_MASK;
1479f1c0a02fSMark Brown clock1 |= sample_rates[dsp_config].value;
1480f1c0a02fSMark Brown
1481f1c0a02fSMark Brown aif1 &= ~WM8903_AIF_WL_MASK;
1482f1c0a02fSMark Brown bclk = 2 * fs;
14836139ea27SMark Brown switch (params_width(params)) {
14846139ea27SMark Brown case 16:
1485f1c0a02fSMark Brown bclk *= 16;
1486f1c0a02fSMark Brown break;
14876139ea27SMark Brown case 20:
1488f1c0a02fSMark Brown bclk *= 20;
1489f1c0a02fSMark Brown aif1 |= 0x4;
1490f1c0a02fSMark Brown break;
14916139ea27SMark Brown case 24:
1492f1c0a02fSMark Brown bclk *= 24;
1493f1c0a02fSMark Brown aif1 |= 0x8;
1494f1c0a02fSMark Brown break;
14956139ea27SMark Brown case 32:
1496f1c0a02fSMark Brown bclk *= 32;
1497f1c0a02fSMark Brown aif1 |= 0xc;
1498f1c0a02fSMark Brown break;
1499f1c0a02fSMark Brown default:
1500f1c0a02fSMark Brown return -EINVAL;
1501f1c0a02fSMark Brown }
1502f1c0a02fSMark Brown
150358bd2934SKuninori Morimoto dev_dbg(component->dev, "MCLK = %dHz, target sample rate = %dHz\n",
1504f1c0a02fSMark Brown wm8903->sysclk, fs);
1505f1c0a02fSMark Brown
1506f1c0a02fSMark Brown /* We may not have an MCLK which allows us to generate exactly
1507f1c0a02fSMark Brown * the clock we want, particularly with USB derived inputs, so
1508f1c0a02fSMark Brown * approximate.
1509f1c0a02fSMark Brown */
1510f1c0a02fSMark Brown clk_config = 0;
1511f1c0a02fSMark Brown best_val = abs((wm8903->sysclk /
1512f1c0a02fSMark Brown (clk_sys_ratios[0].mclk_div *
1513f1c0a02fSMark Brown clk_sys_ratios[0].div)) - fs);
1514f1c0a02fSMark Brown for (i = 1; i < ARRAY_SIZE(clk_sys_ratios); i++) {
1515f1c0a02fSMark Brown cur_val = abs((wm8903->sysclk /
1516f1c0a02fSMark Brown (clk_sys_ratios[i].mclk_div *
1517f1c0a02fSMark Brown clk_sys_ratios[i].div)) - fs);
1518f1c0a02fSMark Brown
1519f1c0a02fSMark Brown if (cur_val <= best_val) {
1520f1c0a02fSMark Brown clk_config = i;
1521f1c0a02fSMark Brown best_val = cur_val;
1522f1c0a02fSMark Brown }
1523f1c0a02fSMark Brown }
1524f1c0a02fSMark Brown
1525f1c0a02fSMark Brown if (clk_sys_ratios[clk_config].mclk_div == 2) {
1526f1c0a02fSMark Brown clock0 |= WM8903_MCLKDIV2;
1527f1c0a02fSMark Brown clk_sys = wm8903->sysclk / 2;
1528f1c0a02fSMark Brown } else {
1529f1c0a02fSMark Brown clock0 &= ~WM8903_MCLKDIV2;
1530f1c0a02fSMark Brown clk_sys = wm8903->sysclk;
1531f1c0a02fSMark Brown }
1532f1c0a02fSMark Brown
1533f1c0a02fSMark Brown clock1 &= ~(WM8903_CLK_SYS_RATE_MASK |
1534f1c0a02fSMark Brown WM8903_CLK_SYS_MODE_MASK);
1535f1c0a02fSMark Brown clock1 |= clk_sys_ratios[clk_config].rate << WM8903_CLK_SYS_RATE_SHIFT;
1536f1c0a02fSMark Brown clock1 |= clk_sys_ratios[clk_config].mode << WM8903_CLK_SYS_MODE_SHIFT;
1537f1c0a02fSMark Brown
153858bd2934SKuninori Morimoto dev_dbg(component->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
1539f1c0a02fSMark Brown clk_sys_ratios[clk_config].rate,
1540f1c0a02fSMark Brown clk_sys_ratios[clk_config].mode,
1541f1c0a02fSMark Brown clk_sys_ratios[clk_config].div);
1542f1c0a02fSMark Brown
154358bd2934SKuninori Morimoto dev_dbg(component->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
1544f1c0a02fSMark Brown
1545f1c0a02fSMark Brown /* We may not get quite the right frequency if using
1546f1c0a02fSMark Brown * approximate clocks so look for the closest match that is
1547f1c0a02fSMark Brown * higher than the target (we need to ensure that there enough
1548f1c0a02fSMark Brown * BCLKs to clock out the samples).
1549f1c0a02fSMark Brown */
1550f1c0a02fSMark Brown bclk_div = 0;
1551f1c0a02fSMark Brown i = 1;
1552f1c0a02fSMark Brown while (i < ARRAY_SIZE(bclk_divs)) {
1553f1c0a02fSMark Brown cur_val = ((clk_sys * 10) / bclk_divs[i].ratio) - bclk;
1554f1c0a02fSMark Brown if (cur_val < 0) /* BCLK table is sorted */
1555f1c0a02fSMark Brown break;
1556f1c0a02fSMark Brown bclk_div = i;
1557f1c0a02fSMark Brown i++;
1558f1c0a02fSMark Brown }
1559f1c0a02fSMark Brown
1560f1c0a02fSMark Brown aif2 &= ~WM8903_BCLK_DIV_MASK;
1561f1c0a02fSMark Brown aif3 &= ~WM8903_LRCLK_RATE_MASK;
1562f1c0a02fSMark Brown
156358bd2934SKuninori Morimoto dev_dbg(component->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
1564f1c0a02fSMark Brown bclk_divs[bclk_div].ratio / 10, bclk,
1565f1c0a02fSMark Brown (clk_sys * 10) / bclk_divs[bclk_div].ratio);
1566f1c0a02fSMark Brown
1567f1c0a02fSMark Brown aif2 |= bclk_divs[bclk_div].div;
1568f1c0a02fSMark Brown aif3 |= bclk / fs;
1569f1c0a02fSMark Brown
157069fff9bbSMark Brown wm8903->fs = params_rate(params);
157158bd2934SKuninori Morimoto wm8903_set_deemph(component);
157269fff9bbSMark Brown
157358bd2934SKuninori Morimoto snd_soc_component_write(component, WM8903_CLOCK_RATES_0, clock0);
157458bd2934SKuninori Morimoto snd_soc_component_write(component, WM8903_CLOCK_RATES_1, clock1);
157558bd2934SKuninori Morimoto snd_soc_component_write(component, WM8903_AUDIO_INTERFACE_1, aif1);
157658bd2934SKuninori Morimoto snd_soc_component_write(component, WM8903_AUDIO_INTERFACE_2, aif2);
157758bd2934SKuninori Morimoto snd_soc_component_write(component, WM8903_AUDIO_INTERFACE_3, aif3);
157858bd2934SKuninori Morimoto snd_soc_component_write(component, WM8903_DAC_DIGITAL_1, dac_digital1);
1579f1c0a02fSMark Brown
1580f1c0a02fSMark Brown return 0;
1581f1c0a02fSMark Brown }
1582f1c0a02fSMark Brown
15837245387eSMark Brown /**
15847245387eSMark Brown * wm8903_mic_detect - Enable microphone detection via the WM8903 IRQ
15857245387eSMark Brown *
158658bd2934SKuninori Morimoto * @component: WM8903 component
15877245387eSMark Brown * @jack: jack to report detection events on
15887245387eSMark Brown * @det: value to report for presence detection
15897245387eSMark Brown * @shrt: value to report for short detection
15907245387eSMark Brown *
15917245387eSMark Brown * Enable microphone detection via IRQ on the WM8903. If GPIOs are
15927245387eSMark Brown * being used to bring out signals to the processor then only platform
15937245387eSMark Brown * data configuration is needed for WM8903 and processor GPIOs should
15947245387eSMark Brown * be configured using snd_soc_jack_add_gpios() instead.
15957245387eSMark Brown *
15967245387eSMark Brown * The current threasholds for detection should be configured using
15977245387eSMark Brown * micdet_cfg in the platform data. Using this function will force on
15987245387eSMark Brown * the microphone bias for the device.
15997245387eSMark Brown */
wm8903_mic_detect(struct snd_soc_component * component,struct snd_soc_jack * jack,int det,int shrt)160058bd2934SKuninori Morimoto int wm8903_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack,
16017245387eSMark Brown int det, int shrt)
16027245387eSMark Brown {
160358bd2934SKuninori Morimoto struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
160469266866SMark Brown int irq_mask = WM8903_MICDET_EINT | WM8903_MICSHRT_EINT;
16057245387eSMark Brown
160658bd2934SKuninori Morimoto dev_dbg(component->dev, "Enabling microphone detection: %x %x\n",
16077245387eSMark Brown det, shrt);
16087245387eSMark Brown
16097245387eSMark Brown /* Store the configuration */
16107245387eSMark Brown wm8903->mic_jack = jack;
16117245387eSMark Brown wm8903->mic_det = det;
16127245387eSMark Brown wm8903->mic_short = shrt;
16137245387eSMark Brown
16147245387eSMark Brown /* Enable interrupts we've got a report configured for */
16157245387eSMark Brown if (det)
16167245387eSMark Brown irq_mask &= ~WM8903_MICDET_EINT;
16177245387eSMark Brown if (shrt)
16187245387eSMark Brown irq_mask &= ~WM8903_MICSHRT_EINT;
16197245387eSMark Brown
162058bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_INTERRUPT_STATUS_1_MASK,
16217245387eSMark Brown WM8903_MICDET_EINT | WM8903_MICSHRT_EINT,
16227245387eSMark Brown irq_mask);
16237245387eSMark Brown
16243088e3b4SStephen Warren if (det || shrt) {
16257245387eSMark Brown /* Enable mic detection, this may not have been set through
16267245387eSMark Brown * platform data (eg, if the defaults are OK). */
162758bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_WRITE_SEQUENCER_0,
16287245387eSMark Brown WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
162958bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_MIC_BIAS_CONTROL_0,
16307245387eSMark Brown WM8903_MICDET_ENA, WM8903_MICDET_ENA);
163169266866SMark Brown } else {
163258bd2934SKuninori Morimoto snd_soc_component_update_bits(component, WM8903_MIC_BIAS_CONTROL_0,
163369266866SMark Brown WM8903_MICDET_ENA, 0);
163469266866SMark Brown }
16357245387eSMark Brown
16367245387eSMark Brown return 0;
16377245387eSMark Brown }
16387245387eSMark Brown EXPORT_SYMBOL_GPL(wm8903_mic_detect);
16397245387eSMark Brown
wm8903_irq(int irq,void * data)16408abd16a6SMark Brown static irqreturn_t wm8903_irq(int irq, void *data)
16418abd16a6SMark Brown {
1642e373cbfbSMark Brown struct wm8903_priv *wm8903 = data;
1643e373cbfbSMark Brown int mic_report, ret;
1644e373cbfbSMark Brown unsigned int int_val, mask, int_pol;
16458abd16a6SMark Brown
1646e373cbfbSMark Brown ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1_MASK,
1647e373cbfbSMark Brown &mask);
1648e373cbfbSMark Brown if (ret != 0) {
1649e373cbfbSMark Brown dev_err(wm8903->dev, "Failed to read IRQ mask: %d\n", ret);
1650e373cbfbSMark Brown return IRQ_NONE;
1651e373cbfbSMark Brown }
1652e373cbfbSMark Brown
1653e373cbfbSMark Brown ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1, &int_val);
1654e373cbfbSMark Brown if (ret != 0) {
1655e373cbfbSMark Brown dev_err(wm8903->dev, "Failed to read IRQ status: %d\n", ret);
1656e373cbfbSMark Brown return IRQ_NONE;
1657e373cbfbSMark Brown }
1658e373cbfbSMark Brown
1659e373cbfbSMark Brown int_val &= ~mask;
16608abd16a6SMark Brown
16617245387eSMark Brown if (int_val & WM8903_WSEQ_BUSY_EINT) {
1662e373cbfbSMark Brown dev_warn(wm8903->dev, "Write sequencer done\n");
16638abd16a6SMark Brown }
16648abd16a6SMark Brown
16657245387eSMark Brown /*
16667245387eSMark Brown * The rest is microphone jack detection. We need to manually
16677245387eSMark Brown * invert the polarity of the interrupt after each event - to
16687245387eSMark Brown * simplify the code keep track of the last state we reported
16697245387eSMark Brown * and just invert the relevant bits in both the report and
16707245387eSMark Brown * the polarity register.
16717245387eSMark Brown */
16727245387eSMark Brown mic_report = wm8903->mic_last_report;
1673e373cbfbSMark Brown ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1,
1674e373cbfbSMark Brown &int_pol);
1675e373cbfbSMark Brown if (ret != 0) {
1676e373cbfbSMark Brown dev_err(wm8903->dev, "Failed to read interrupt polarity: %d\n",
1677e373cbfbSMark Brown ret);
1678e373cbfbSMark Brown return IRQ_HANDLED;
1679e373cbfbSMark Brown }
16807245387eSMark Brown
16811435b940SMark Brown #ifndef CONFIG_SND_SOC_WM8903_MODULE
16822bbb5d66SMark Brown if (int_val & (WM8903_MICSHRT_EINT | WM8903_MICDET_EINT))
1683e373cbfbSMark Brown trace_snd_soc_jack_irq(dev_name(wm8903->dev));
16841435b940SMark Brown #endif
16852bbb5d66SMark Brown
16867245387eSMark Brown if (int_val & WM8903_MICSHRT_EINT) {
1687e373cbfbSMark Brown dev_dbg(wm8903->dev, "Microphone short (pol=%x)\n", int_pol);
16887245387eSMark Brown
16897245387eSMark Brown mic_report ^= wm8903->mic_short;
16907245387eSMark Brown int_pol ^= WM8903_MICSHRT_INV;
16917245387eSMark Brown }
16927245387eSMark Brown
16937245387eSMark Brown if (int_val & WM8903_MICDET_EINT) {
1694e373cbfbSMark Brown dev_dbg(wm8903->dev, "Microphone detect (pol=%x)\n", int_pol);
16957245387eSMark Brown
16967245387eSMark Brown mic_report ^= wm8903->mic_det;
16977245387eSMark Brown int_pol ^= WM8903_MICDET_INV;
16987245387eSMark Brown
16997245387eSMark Brown msleep(wm8903->mic_delay);
17007245387eSMark Brown }
17017245387eSMark Brown
1702e373cbfbSMark Brown regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1,
17037245387eSMark Brown WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol);
17047245387eSMark Brown
17057245387eSMark Brown snd_soc_jack_report(wm8903->mic_jack, mic_report,
17067245387eSMark Brown wm8903->mic_short | wm8903->mic_det);
17077245387eSMark Brown
17087245387eSMark Brown wm8903->mic_last_report = mic_report;
17097245387eSMark Brown
17108abd16a6SMark Brown return IRQ_HANDLED;
17118abd16a6SMark Brown }
17128abd16a6SMark Brown
1713f1c0a02fSMark Brown #define WM8903_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\
1714f1c0a02fSMark Brown SNDRV_PCM_RATE_11025 | \
1715f1c0a02fSMark Brown SNDRV_PCM_RATE_16000 | \
1716f1c0a02fSMark Brown SNDRV_PCM_RATE_22050 | \
1717f1c0a02fSMark Brown SNDRV_PCM_RATE_32000 | \
1718f1c0a02fSMark Brown SNDRV_PCM_RATE_44100 | \
1719f1c0a02fSMark Brown SNDRV_PCM_RATE_48000 | \
1720f1c0a02fSMark Brown SNDRV_PCM_RATE_88200 | \
1721f1c0a02fSMark Brown SNDRV_PCM_RATE_96000)
1722f1c0a02fSMark Brown
1723f1c0a02fSMark Brown #define WM8903_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
1724f1c0a02fSMark Brown SNDRV_PCM_RATE_11025 | \
1725f1c0a02fSMark Brown SNDRV_PCM_RATE_16000 | \
1726f1c0a02fSMark Brown SNDRV_PCM_RATE_22050 | \
1727f1c0a02fSMark Brown SNDRV_PCM_RATE_32000 | \
1728f1c0a02fSMark Brown SNDRV_PCM_RATE_44100 | \
1729f1c0a02fSMark Brown SNDRV_PCM_RATE_48000)
1730f1c0a02fSMark Brown
1731f1c0a02fSMark Brown #define WM8903_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
1732f1c0a02fSMark Brown SNDRV_PCM_FMTBIT_S20_3LE |\
1733f1c0a02fSMark Brown SNDRV_PCM_FMTBIT_S24_LE)
1734f1c0a02fSMark Brown
173585e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops wm8903_dai_ops = {
17366335d055SEric Miao .hw_params = wm8903_hw_params,
173726d3c16eSKuninori Morimoto .mute_stream = wm8903_mute,
17386335d055SEric Miao .set_fmt = wm8903_set_dai_fmt,
17396335d055SEric Miao .set_sysclk = wm8903_set_dai_sysclk,
174026d3c16eSKuninori Morimoto .no_capture_mute = 1,
17416335d055SEric Miao };
17426335d055SEric Miao
1743f0fba2adSLiam Girdwood static struct snd_soc_dai_driver wm8903_dai = {
1744f0fba2adSLiam Girdwood .name = "wm8903-hifi",
1745f1c0a02fSMark Brown .playback = {
1746f1c0a02fSMark Brown .stream_name = "Playback",
1747f1c0a02fSMark Brown .channels_min = 2,
1748f1c0a02fSMark Brown .channels_max = 2,
1749f1c0a02fSMark Brown .rates = WM8903_PLAYBACK_RATES,
1750f1c0a02fSMark Brown .formats = WM8903_FORMATS,
1751f1c0a02fSMark Brown },
1752f1c0a02fSMark Brown .capture = {
1753f1c0a02fSMark Brown .stream_name = "Capture",
1754f1c0a02fSMark Brown .channels_min = 2,
1755f1c0a02fSMark Brown .channels_max = 2,
1756f1c0a02fSMark Brown .rates = WM8903_CAPTURE_RATES,
1757f1c0a02fSMark Brown .formats = WM8903_FORMATS,
1758f1c0a02fSMark Brown },
17596335d055SEric Miao .ops = &wm8903_dai_ops,
176007695752SKuninori Morimoto .symmetric_rate = 1,
1761f1c0a02fSMark Brown };
1762f1c0a02fSMark Brown
wm8903_resume(struct snd_soc_component * component)176358bd2934SKuninori Morimoto static int wm8903_resume(struct snd_soc_component *component)
1764f1c0a02fSMark Brown {
176558bd2934SKuninori Morimoto struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
1766f1c0a02fSMark Brown
1767ee244ce4SMark Brown regcache_sync(wm8903->regmap);
176845e96755SMark Brown
1769f1c0a02fSMark Brown return 0;
1770f1c0a02fSMark Brown }
1771f1c0a02fSMark Brown
17727cfe5617SStephen Warren #ifdef CONFIG_GPIOLIB
wm8903_gpio_request(struct gpio_chip * chip,unsigned offset)17737cfe5617SStephen Warren static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset)
17747cfe5617SStephen Warren {
17757cfe5617SStephen Warren if (offset >= WM8903_NUM_GPIO)
17767cfe5617SStephen Warren return -EINVAL;
17777cfe5617SStephen Warren
17787cfe5617SStephen Warren return 0;
17797cfe5617SStephen Warren }
17807cfe5617SStephen Warren
wm8903_gpio_direction_in(struct gpio_chip * chip,unsigned offset)17817cfe5617SStephen Warren static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
17827cfe5617SStephen Warren {
17838f416066SLinus Walleij struct wm8903_priv *wm8903 = gpiochip_get_data(chip);
17847cfe5617SStephen Warren unsigned int mask, val;
1785385bd937SAxel Lin int ret;
17867cfe5617SStephen Warren
17877cfe5617SStephen Warren mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK;
17887cfe5617SStephen Warren val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) |
17897cfe5617SStephen Warren WM8903_GP1_DIR;
17907cfe5617SStephen Warren
17910bf79ef2SStephen Warren ret = regmap_update_bits(wm8903->regmap,
17920bf79ef2SStephen Warren WM8903_GPIO_CONTROL_1 + offset, mask, val);
1793385bd937SAxel Lin if (ret < 0)
1794385bd937SAxel Lin return ret;
1795385bd937SAxel Lin
1796385bd937SAxel Lin return 0;
17977cfe5617SStephen Warren }
17987cfe5617SStephen Warren
wm8903_gpio_get(struct gpio_chip * chip,unsigned offset)17997cfe5617SStephen Warren static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset)
18007cfe5617SStephen Warren {
18018f416066SLinus Walleij struct wm8903_priv *wm8903 = gpiochip_get_data(chip);
18020bf79ef2SStephen Warren unsigned int reg;
18037cfe5617SStephen Warren
18040bf79ef2SStephen Warren regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, ®);
18057cfe5617SStephen Warren
1806b70381c3SLinus Walleij return !!((reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT);
18077cfe5617SStephen Warren }
18087cfe5617SStephen Warren
wm8903_gpio_direction_out(struct gpio_chip * chip,unsigned offset,int value)18097cfe5617SStephen Warren static int wm8903_gpio_direction_out(struct gpio_chip *chip,
18107cfe5617SStephen Warren unsigned offset, int value)
18117cfe5617SStephen Warren {
18128f416066SLinus Walleij struct wm8903_priv *wm8903 = gpiochip_get_data(chip);
18137cfe5617SStephen Warren unsigned int mask, val;
1814385bd937SAxel Lin int ret;
18157cfe5617SStephen Warren
18167cfe5617SStephen Warren mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK | WM8903_GP1_LVL_MASK;
18177cfe5617SStephen Warren val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) |
18187cfe5617SStephen Warren (value << WM8903_GP2_LVL_SHIFT);
18197cfe5617SStephen Warren
18200bf79ef2SStephen Warren ret = regmap_update_bits(wm8903->regmap,
18210bf79ef2SStephen Warren WM8903_GPIO_CONTROL_1 + offset, mask, val);
1822385bd937SAxel Lin if (ret < 0)
1823385bd937SAxel Lin return ret;
1824385bd937SAxel Lin
1825385bd937SAxel Lin return 0;
18267cfe5617SStephen Warren }
18277cfe5617SStephen Warren
wm8903_gpio_set(struct gpio_chip * chip,unsigned offset,int value)18287cfe5617SStephen Warren static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
18297cfe5617SStephen Warren {
18308f416066SLinus Walleij struct wm8903_priv *wm8903 = gpiochip_get_data(chip);
18317cfe5617SStephen Warren
18320bf79ef2SStephen Warren regmap_update_bits(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset,
1833c8059930SMark Brown WM8903_GP1_LVL_MASK,
1834c8059930SMark Brown !!value << WM8903_GP1_LVL_SHIFT);
18357cfe5617SStephen Warren }
18367cfe5617SStephen Warren
1837c59b24f8SJulia Lawall static const struct gpio_chip wm8903_template_chip = {
18387cfe5617SStephen Warren .label = "wm8903",
18397cfe5617SStephen Warren .owner = THIS_MODULE,
18407cfe5617SStephen Warren .request = wm8903_gpio_request,
18417cfe5617SStephen Warren .direction_input = wm8903_gpio_direction_in,
18427cfe5617SStephen Warren .get = wm8903_gpio_get,
18437cfe5617SStephen Warren .direction_output = wm8903_gpio_direction_out,
18447cfe5617SStephen Warren .set = wm8903_gpio_set,
18457cfe5617SStephen Warren .can_sleep = 1,
18467cfe5617SStephen Warren };
18477cfe5617SStephen Warren
wm8903_init_gpio(struct wm8903_priv * wm8903)18480bf79ef2SStephen Warren static void wm8903_init_gpio(struct wm8903_priv *wm8903)
18497cfe5617SStephen Warren {
1850c0eb27cfSStephen Warren struct wm8903_platform_data *pdata = wm8903->pdata;
18517cfe5617SStephen Warren int ret;
18527cfe5617SStephen Warren
18537cfe5617SStephen Warren wm8903->gpio_chip = wm8903_template_chip;
18547cfe5617SStephen Warren wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO;
185558383c78SLinus Walleij wm8903->gpio_chip.parent = wm8903->dev;
18567cfe5617SStephen Warren
1857db817784SStephen Warren if (pdata->gpio_base)
18587cfe5617SStephen Warren wm8903->gpio_chip.base = pdata->gpio_base;
18597cfe5617SStephen Warren else
18607cfe5617SStephen Warren wm8903->gpio_chip.base = -1;
18617cfe5617SStephen Warren
18628f416066SLinus Walleij ret = gpiochip_add_data(&wm8903->gpio_chip, wm8903);
18637cfe5617SStephen Warren if (ret != 0)
18640bf79ef2SStephen Warren dev_err(wm8903->dev, "Failed to add GPIOs: %d\n", ret);
18657cfe5617SStephen Warren }
18667cfe5617SStephen Warren
wm8903_free_gpio(struct wm8903_priv * wm8903)18670bf79ef2SStephen Warren static void wm8903_free_gpio(struct wm8903_priv *wm8903)
18687cfe5617SStephen Warren {
186988d5e520Sabdoulaye berthe gpiochip_remove(&wm8903->gpio_chip);
18707cfe5617SStephen Warren }
18717cfe5617SStephen Warren #else
wm8903_init_gpio(struct wm8903_priv * wm8903)18720bf79ef2SStephen Warren static void wm8903_init_gpio(struct wm8903_priv *wm8903)
18737cfe5617SStephen Warren {
18747cfe5617SStephen Warren }
18757cfe5617SStephen Warren
wm8903_free_gpio(struct wm8903_priv * wm8903)18760bf79ef2SStephen Warren static void wm8903_free_gpio(struct wm8903_priv *wm8903)
18777cfe5617SStephen Warren {
18787cfe5617SStephen Warren }
18797cfe5617SStephen Warren #endif
18807cfe5617SStephen Warren
188158bd2934SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_wm8903 = {
1882f0fba2adSLiam Girdwood .resume = wm8903_resume,
1883f0fba2adSLiam Girdwood .set_bias_level = wm8903_set_bias_level,
1884c5b6a9feSMark Brown .seq_notifier = wm8903_seq_notifier,
1885f4a10837SMark Brown .controls = wm8903_snd_controls,
1886f4a10837SMark Brown .num_controls = ARRAY_SIZE(wm8903_snd_controls),
1887ecd01512SMark Brown .dapm_widgets = wm8903_dapm_widgets,
1888ecd01512SMark Brown .num_dapm_widgets = ARRAY_SIZE(wm8903_dapm_widgets),
1889ecd01512SMark Brown .dapm_routes = wm8903_intercon,
1890ecd01512SMark Brown .num_dapm_routes = ARRAY_SIZE(wm8903_intercon),
189158bd2934SKuninori Morimoto .suspend_bias_off = 1,
189258bd2934SKuninori Morimoto .idle_bias_on = 1,
189358bd2934SKuninori Morimoto .use_pmdown_time = 1,
189458bd2934SKuninori Morimoto .endianness = 1,
1895f0fba2adSLiam Girdwood };
1896f0fba2adSLiam Girdwood
1897ee244ce4SMark Brown static const struct regmap_config wm8903_regmap = {
1898ee244ce4SMark Brown .reg_bits = 8,
1899ee244ce4SMark Brown .val_bits = 16,
1900ee244ce4SMark Brown
1901ee244ce4SMark Brown .max_register = WM8903_MAX_REGISTER,
1902ee244ce4SMark Brown .volatile_reg = wm8903_volatile_register,
1903ee244ce4SMark Brown .readable_reg = wm8903_readable_register,
1904ee244ce4SMark Brown
1905*7de380eeSMark Brown .cache_type = REGCACHE_MAPLE,
1906ee244ce4SMark Brown .reg_defaults = wm8903_reg_defaults,
1907ee244ce4SMark Brown .num_reg_defaults = ARRAY_SIZE(wm8903_reg_defaults),
1908ee244ce4SMark Brown };
1909ee244ce4SMark Brown
wm8903_set_pdata_irq_trigger(struct i2c_client * i2c,struct wm8903_platform_data * pdata)19109d35f3e1SStephen Warren static int wm8903_set_pdata_irq_trigger(struct i2c_client *i2c,
19119d35f3e1SStephen Warren struct wm8903_platform_data *pdata)
19129d35f3e1SStephen Warren {
19139d35f3e1SStephen Warren struct irq_data *irq_data = irq_get_irq_data(i2c->irq);
19149d35f3e1SStephen Warren if (!irq_data) {
19159d35f3e1SStephen Warren dev_err(&i2c->dev, "Invalid IRQ: %d\n",
19169d35f3e1SStephen Warren i2c->irq);
19179d35f3e1SStephen Warren return -EINVAL;
19189d35f3e1SStephen Warren }
19199d35f3e1SStephen Warren
19209d35f3e1SStephen Warren switch (irqd_get_trigger_type(irq_data)) {
19219d35f3e1SStephen Warren case IRQ_TYPE_NONE:
19226664ee11SMark Brown default:
19239d35f3e1SStephen Warren /*
19249d35f3e1SStephen Warren * We assume the controller imposes no restrictions,
19259d35f3e1SStephen Warren * so we are able to select active-high
19269d35f3e1SStephen Warren */
19273e146b55SGustavo A. R. Silva fallthrough;
19289d35f3e1SStephen Warren case IRQ_TYPE_LEVEL_HIGH:
19299d35f3e1SStephen Warren pdata->irq_active_low = false;
19309d35f3e1SStephen Warren break;
19319d35f3e1SStephen Warren case IRQ_TYPE_LEVEL_LOW:
19329d35f3e1SStephen Warren pdata->irq_active_low = true;
19339d35f3e1SStephen Warren break;
19349d35f3e1SStephen Warren }
19359d35f3e1SStephen Warren
19369d35f3e1SStephen Warren return 0;
19379d35f3e1SStephen Warren }
19389d35f3e1SStephen Warren
wm8903_set_pdata_from_of(struct i2c_client * i2c,struct wm8903_platform_data * pdata)19395d680b3aSStephen Warren static int wm8903_set_pdata_from_of(struct i2c_client *i2c,
19405d680b3aSStephen Warren struct wm8903_platform_data *pdata)
19415d680b3aSStephen Warren {
19425d680b3aSStephen Warren const struct device_node *np = i2c->dev.of_node;
19435d680b3aSStephen Warren u32 val32;
19445d680b3aSStephen Warren int i;
19455d680b3aSStephen Warren
19465d680b3aSStephen Warren if (of_property_read_u32(np, "micdet-cfg", &val32) >= 0)
19475d680b3aSStephen Warren pdata->micdet_cfg = val32;
19485d680b3aSStephen Warren
19495d680b3aSStephen Warren if (of_property_read_u32(np, "micdet-delay", &val32) >= 0)
19505d680b3aSStephen Warren pdata->micdet_delay = val32;
19515d680b3aSStephen Warren
19525d680b3aSStephen Warren if (of_property_read_u32_array(np, "gpio-cfg", pdata->gpio_cfg,
19535d680b3aSStephen Warren ARRAY_SIZE(pdata->gpio_cfg)) >= 0) {
19545d680b3aSStephen Warren /*
19555d680b3aSStephen Warren * In device tree: 0 means "write 0",
19565d680b3aSStephen Warren * 0xffffffff means "don't touch".
19575d680b3aSStephen Warren *
19585d680b3aSStephen Warren * In platform data: 0 means "don't touch",
19595d680b3aSStephen Warren * 0x8000 means "write 0".
19605d680b3aSStephen Warren *
19615d680b3aSStephen Warren * Note: WM8903_GPIO_CONFIG_ZERO == 0x8000.
19625d680b3aSStephen Warren *
19635d680b3aSStephen Warren * Convert from DT to pdata representation here,
19645d680b3aSStephen Warren * so no other code needs to change.
19655d680b3aSStephen Warren */
19665d680b3aSStephen Warren for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
19675d680b3aSStephen Warren if (pdata->gpio_cfg[i] == 0) {
19685d680b3aSStephen Warren pdata->gpio_cfg[i] = WM8903_GPIO_CONFIG_ZERO;
19695d680b3aSStephen Warren } else if (pdata->gpio_cfg[i] == 0xffffffff) {
19705d680b3aSStephen Warren pdata->gpio_cfg[i] = 0;
19715d680b3aSStephen Warren } else if (pdata->gpio_cfg[i] > 0x7fff) {
19725d680b3aSStephen Warren dev_err(&i2c->dev, "Invalid gpio-cfg[%d] %x\n",
19735d680b3aSStephen Warren i, pdata->gpio_cfg[i]);
19745d680b3aSStephen Warren return -EINVAL;
19755d680b3aSStephen Warren }
19765d680b3aSStephen Warren }
19775d680b3aSStephen Warren }
19785d680b3aSStephen Warren
19795d680b3aSStephen Warren return 0;
19805d680b3aSStephen Warren }
19815d680b3aSStephen Warren
wm8903_i2c_probe(struct i2c_client * i2c)198297b0b6e3SStephen Kitt static int wm8903_i2c_probe(struct i2c_client *i2c)
1983f0fba2adSLiam Girdwood {
1984c0eb27cfSStephen Warren struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev);
1985f0fba2adSLiam Girdwood struct wm8903_priv *wm8903;
1986b7c95d91SMark Brown int trigger;
198720c5fd39SMark Brown bool mic_gpio = false;
1988b7c95d91SMark Brown unsigned int val, irq_pol;
198920c5fd39SMark Brown int ret, i;
1990f0fba2adSLiam Girdwood
1991017b9b35SMarkus Elfring wm8903 = devm_kzalloc(&i2c->dev, sizeof(*wm8903), GFP_KERNEL);
1992f0fba2adSLiam Girdwood if (wm8903 == NULL)
1993f0fba2adSLiam Girdwood return -ENOMEM;
199478660af7SLars-Peter Clausen
199578660af7SLars-Peter Clausen mutex_init(&wm8903->lock);
19960bf79ef2SStephen Warren wm8903->dev = &i2c->dev;
1997f0fba2adSLiam Girdwood
19987d116684SMark Brown wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap);
1999ee244ce4SMark Brown if (IS_ERR(wm8903->regmap)) {
2000ee244ce4SMark Brown ret = PTR_ERR(wm8903->regmap);
2001ee244ce4SMark Brown dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
2002ee244ce4SMark Brown ret);
2003ee244ce4SMark Brown return ret;
2004ee244ce4SMark Brown }
2005ee244ce4SMark Brown
2006f0fba2adSLiam Girdwood i2c_set_clientdata(i2c, wm8903);
2007f0fba2adSLiam Girdwood
2008c0eb27cfSStephen Warren /* If no platform data was supplied, create storage for defaults */
2009c0eb27cfSStephen Warren if (pdata) {
2010c0eb27cfSStephen Warren wm8903->pdata = pdata;
2011c0eb27cfSStephen Warren } else {
2012017b9b35SMarkus Elfring wm8903->pdata = devm_kzalloc(&i2c->dev, sizeof(*wm8903->pdata),
2013c0eb27cfSStephen Warren GFP_KERNEL);
2014cce7c0acSMarkus Elfring if (!wm8903->pdata)
2015c0eb27cfSStephen Warren return -ENOMEM;
20169d35f3e1SStephen Warren
20179d35f3e1SStephen Warren if (i2c->irq) {
20189d35f3e1SStephen Warren ret = wm8903_set_pdata_irq_trigger(i2c, wm8903->pdata);
20199d35f3e1SStephen Warren if (ret != 0)
20209d35f3e1SStephen Warren return ret;
20219d35f3e1SStephen Warren }
20225d680b3aSStephen Warren
20235d680b3aSStephen Warren if (i2c->dev.of_node) {
20245d680b3aSStephen Warren ret = wm8903_set_pdata_from_of(i2c, wm8903->pdata);
20255d680b3aSStephen Warren if (ret != 0)
20265d680b3aSStephen Warren return ret;
20275d680b3aSStephen Warren }
2028c0eb27cfSStephen Warren }
2029c0eb27cfSStephen Warren
203020c5fd39SMark Brown pdata = wm8903->pdata;
203120c5fd39SMark Brown
2032b3bbef45SLinus Walleij for (i = 0; i < ARRAY_SIZE(wm8903->supplies); i++)
2033b3bbef45SLinus Walleij wm8903->supplies[i].supply = wm8903_supply_names[i];
2034b3bbef45SLinus Walleij
2035b3bbef45SLinus Walleij ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8903->supplies),
2036b3bbef45SLinus Walleij wm8903->supplies);
2037b3bbef45SLinus Walleij if (ret != 0) {
2038b3bbef45SLinus Walleij dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
2039b3bbef45SLinus Walleij return ret;
2040b3bbef45SLinus Walleij }
2041b3bbef45SLinus Walleij
2042b3bbef45SLinus Walleij ret = regulator_bulk_enable(ARRAY_SIZE(wm8903->supplies),
2043b3bbef45SLinus Walleij wm8903->supplies);
2044b3bbef45SLinus Walleij if (ret != 0) {
2045b3bbef45SLinus Walleij dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
2046b3bbef45SLinus Walleij return ret;
2047b3bbef45SLinus Walleij }
2048b3bbef45SLinus Walleij
20497d46a528SMark Brown ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val);
20507d46a528SMark Brown if (ret != 0) {
20517d46a528SMark Brown dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
20527d46a528SMark Brown goto err;
20537d46a528SMark Brown }
20547d46a528SMark Brown if (val != 0x8903) {
20557d46a528SMark Brown dev_err(&i2c->dev, "Device with ID %x is not a WM8903\n", val);
20567d46a528SMark Brown ret = -ENODEV;
20577d46a528SMark Brown goto err;
20587d46a528SMark Brown }
20597d46a528SMark Brown
20607d46a528SMark Brown ret = regmap_read(wm8903->regmap, WM8903_REVISION_NUMBER, &val);
20617d46a528SMark Brown if (ret != 0) {
20627d46a528SMark Brown dev_err(&i2c->dev, "Failed to read chip revision: %d\n", ret);
20637d46a528SMark Brown goto err;
20647d46a528SMark Brown }
20657d46a528SMark Brown dev_info(&i2c->dev, "WM8903 revision %c\n",
20667d46a528SMark Brown (val & WM8903_CHIP_REV_MASK) + 'A');
20677d46a528SMark Brown
20687d46a528SMark Brown /* Reset the device */
20697d46a528SMark Brown regmap_write(wm8903->regmap, WM8903_SW_RESET_AND_ID, 0x8903);
20707d46a528SMark Brown
20710bf79ef2SStephen Warren wm8903_init_gpio(wm8903);
20720bf79ef2SStephen Warren
207320c5fd39SMark Brown /* Set up GPIO pin state, detect if any are MIC detect outputs */
207420c5fd39SMark Brown for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
207520c5fd39SMark Brown if ((!pdata->gpio_cfg[i]) ||
207620c5fd39SMark Brown (pdata->gpio_cfg[i] > WM8903_GPIO_CONFIG_ZERO))
207720c5fd39SMark Brown continue;
207820c5fd39SMark Brown
207920c5fd39SMark Brown regmap_write(wm8903->regmap, WM8903_GPIO_CONTROL_1 + i,
208020c5fd39SMark Brown pdata->gpio_cfg[i] & 0x7fff);
208120c5fd39SMark Brown
208220c5fd39SMark Brown val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK)
208320c5fd39SMark Brown >> WM8903_GP1_FN_SHIFT;
208420c5fd39SMark Brown
208520c5fd39SMark Brown switch (val) {
208620c5fd39SMark Brown case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT:
208720c5fd39SMark Brown case WM8903_GPn_FN_MICBIAS_SHORT_DETECT:
208820c5fd39SMark Brown mic_gpio = true;
208920c5fd39SMark Brown break;
209020c5fd39SMark Brown default:
209120c5fd39SMark Brown break;
209220c5fd39SMark Brown }
209320c5fd39SMark Brown }
209420c5fd39SMark Brown
209520c5fd39SMark Brown /* Set up microphone detection */
209620c5fd39SMark Brown regmap_write(wm8903->regmap, WM8903_MIC_BIAS_CONTROL_0,
209720c5fd39SMark Brown pdata->micdet_cfg);
209820c5fd39SMark Brown
209920c5fd39SMark Brown /* Microphone detection needs the WSEQ clock */
210020c5fd39SMark Brown if (pdata->micdet_cfg)
210120c5fd39SMark Brown regmap_update_bits(wm8903->regmap, WM8903_WRITE_SEQUENCER_0,
210220c5fd39SMark Brown WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
210320c5fd39SMark Brown
210420c5fd39SMark Brown /* If microphone detection is enabled by pdata but
210520c5fd39SMark Brown * detected via IRQ then interrupts can be lost before
210620c5fd39SMark Brown * the machine driver has set up microphone detection
210720c5fd39SMark Brown * IRQs as the IRQs are clear on read. The detection
210820c5fd39SMark Brown * will be enabled when the machine driver configures.
210920c5fd39SMark Brown */
211020c5fd39SMark Brown WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA));
211120c5fd39SMark Brown
211220c5fd39SMark Brown wm8903->mic_delay = pdata->micdet_delay;
211320c5fd39SMark Brown
2114b7c95d91SMark Brown if (i2c->irq) {
2115b7c95d91SMark Brown if (pdata->irq_active_low) {
2116b7c95d91SMark Brown trigger = IRQF_TRIGGER_LOW;
2117b7c95d91SMark Brown irq_pol = WM8903_IRQ_POL;
2118b7c95d91SMark Brown } else {
2119b7c95d91SMark Brown trigger = IRQF_TRIGGER_HIGH;
2120b7c95d91SMark Brown irq_pol = 0;
2121b7c95d91SMark Brown }
2122b7c95d91SMark Brown
2123b7c95d91SMark Brown regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_CONTROL,
2124b7c95d91SMark Brown WM8903_IRQ_POL, irq_pol);
2125b7c95d91SMark Brown
2126b7c95d91SMark Brown ret = request_threaded_irq(i2c->irq, NULL, wm8903_irq,
2127b7c95d91SMark Brown trigger | IRQF_ONESHOT,
2128b7c95d91SMark Brown "wm8903", wm8903);
2129b7c95d91SMark Brown if (ret != 0) {
2130b7c95d91SMark Brown dev_err(wm8903->dev, "Failed to request IRQ: %d\n",
2131b7c95d91SMark Brown ret);
213283d1b65dSZheyu Ma goto err;
2133b7c95d91SMark Brown }
2134b7c95d91SMark Brown
2135b7c95d91SMark Brown /* Enable write sequencer interrupts */
2136b7c95d91SMark Brown regmap_update_bits(wm8903->regmap,
2137b7c95d91SMark Brown WM8903_INTERRUPT_STATUS_1_MASK,
2138b7c95d91SMark Brown WM8903_IM_WSEQ_BUSY_EINT, 0);
2139b7c95d91SMark Brown }
2140b7c95d91SMark Brown
2141a89c3e95SMark Brown /* Latch volume update bits */
2142a89c3e95SMark Brown regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_LEFT,
2143a89c3e95SMark Brown WM8903_ADCVU, WM8903_ADCVU);
2144a89c3e95SMark Brown regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_RIGHT,
2145a89c3e95SMark Brown WM8903_ADCVU, WM8903_ADCVU);
2146a89c3e95SMark Brown
2147a89c3e95SMark Brown regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_LEFT,
2148a89c3e95SMark Brown WM8903_DACVU, WM8903_DACVU);
2149a89c3e95SMark Brown regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_RIGHT,
2150a89c3e95SMark Brown WM8903_DACVU, WM8903_DACVU);
2151a89c3e95SMark Brown
2152a89c3e95SMark Brown regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_LEFT,
2153a89c3e95SMark Brown WM8903_HPOUTVU, WM8903_HPOUTVU);
2154a89c3e95SMark Brown regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_RIGHT,
2155a89c3e95SMark Brown WM8903_HPOUTVU, WM8903_HPOUTVU);
2156a89c3e95SMark Brown
2157a89c3e95SMark Brown regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_LEFT,
2158a89c3e95SMark Brown WM8903_LINEOUTVU, WM8903_LINEOUTVU);
2159a89c3e95SMark Brown regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_RIGHT,
2160a89c3e95SMark Brown WM8903_LINEOUTVU, WM8903_LINEOUTVU);
2161a89c3e95SMark Brown
2162a89c3e95SMark Brown regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_LEFT,
2163a89c3e95SMark Brown WM8903_SPKVU, WM8903_SPKVU);
2164a89c3e95SMark Brown regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_RIGHT,
2165a89c3e95SMark Brown WM8903_SPKVU, WM8903_SPKVU);
2166a89c3e95SMark Brown
2167a89c3e95SMark Brown /* Enable DAC soft mute by default */
2168a89c3e95SMark Brown regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_1,
2169a89c3e95SMark Brown WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE,
2170a89c3e95SMark Brown WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE);
2171a89c3e95SMark Brown
217258bd2934SKuninori Morimoto ret = devm_snd_soc_register_component(&i2c->dev,
217358bd2934SKuninori Morimoto &soc_component_dev_wm8903, &wm8903_dai, 1);
2174ee244ce4SMark Brown if (ret != 0)
2175ee244ce4SMark Brown goto err;
21762950cd22SMark Brown
2177ee244ce4SMark Brown return 0;
2178ee244ce4SMark Brown err:
2179b3bbef45SLinus Walleij regulator_bulk_disable(ARRAY_SIZE(wm8903->supplies),
2180b3bbef45SLinus Walleij wm8903->supplies);
2181f1c0a02fSMark Brown return ret;
2182f1c0a02fSMark Brown }
2183f1c0a02fSMark Brown
wm8903_i2c_remove(struct i2c_client * client)2184ed5c2f5fSUwe Kleine-König static void wm8903_i2c_remove(struct i2c_client *client)
2185f1c0a02fSMark Brown {
2186ee244ce4SMark Brown struct wm8903_priv *wm8903 = i2c_get_clientdata(client);
2187ee244ce4SMark Brown
2188b3bbef45SLinus Walleij regulator_bulk_disable(ARRAY_SIZE(wm8903->supplies),
2189b3bbef45SLinus Walleij wm8903->supplies);
2190b7c95d91SMark Brown if (client->irq)
2191b7c95d91SMark Brown free_irq(client->irq, wm8903);
21920bf79ef2SStephen Warren wm8903_free_gpio(wm8903);
2193f1c0a02fSMark Brown }
2194f1c0a02fSMark Brown
2195f18b4e2eSStephen Warren static const struct of_device_id wm8903_of_match[] = {
2196f18b4e2eSStephen Warren { .compatible = "wlf,wm8903", },
2197f18b4e2eSStephen Warren {},
2198f18b4e2eSStephen Warren };
2199f18b4e2eSStephen Warren MODULE_DEVICE_TABLE(of, wm8903_of_match);
2200f18b4e2eSStephen Warren
2201f1c0a02fSMark Brown static const struct i2c_device_id wm8903_i2c_id[] = {
2202f1c0a02fSMark Brown { "wm8903", 0 },
2203f1c0a02fSMark Brown { }
2204f1c0a02fSMark Brown };
2205f1c0a02fSMark Brown MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id);
2206f1c0a02fSMark Brown
2207f1c0a02fSMark Brown static struct i2c_driver wm8903_i2c_driver = {
2208f1c0a02fSMark Brown .driver = {
22094b592c91SMark Brown .name = "wm8903",
2210f18b4e2eSStephen Warren .of_match_table = wm8903_of_match,
2211f1c0a02fSMark Brown },
22129abcd240SUwe Kleine-König .probe = wm8903_i2c_probe,
22137a79e94eSBill Pemberton .remove = wm8903_i2c_remove,
2214f1c0a02fSMark Brown .id_table = wm8903_i2c_id,
2215f1c0a02fSMark Brown };
2216f1c0a02fSMark Brown
22175c86ea44SSachin Kamat module_i2c_driver(wm8903_i2c_driver);
221864089b84SMark Brown
2219f1c0a02fSMark Brown MODULE_DESCRIPTION("ASoC WM8903 driver");
2220f1c0a02fSMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>");
2221f1c0a02fSMark Brown MODULE_LICENSE("GPL");
2222