xref: /openbmc/linux/sound/soc/codecs/wm8903.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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, &reg);
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