xref: /OK3568_Linux_fs/kernel/sound/soc/codecs/wm8350.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * wm8350.c -- WM8350 ALSA SoC audio driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2007-12 Wolfson Microelectronics PLC.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/moduleparam.h>
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/delay.h>
15*4882a593Smuzhiyun #include <linux/pm.h>
16*4882a593Smuzhiyun #include <linux/platform_device.h>
17*4882a593Smuzhiyun #include <linux/mfd/wm8350/audio.h>
18*4882a593Smuzhiyun #include <linux/mfd/wm8350/core.h>
19*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
20*4882a593Smuzhiyun #include <sound/core.h>
21*4882a593Smuzhiyun #include <sound/pcm.h>
22*4882a593Smuzhiyun #include <sound/pcm_params.h>
23*4882a593Smuzhiyun #include <sound/soc.h>
24*4882a593Smuzhiyun #include <sound/initval.h>
25*4882a593Smuzhiyun #include <sound/tlv.h>
26*4882a593Smuzhiyun #include <trace/events/asoc.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include "wm8350.h"
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #define WM8350_OUTn_0dB 0x39
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #define WM8350_RAMP_NONE	0
33*4882a593Smuzhiyun #define WM8350_RAMP_UP		1
34*4882a593Smuzhiyun #define WM8350_RAMP_DOWN	2
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /* We only include the analogue supplies here; the digital supplies
37*4882a593Smuzhiyun  * need to be available well before this driver can be probed.
38*4882a593Smuzhiyun  */
39*4882a593Smuzhiyun static const char *supply_names[] = {
40*4882a593Smuzhiyun 	"AVDD",
41*4882a593Smuzhiyun 	"HPVDD",
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun struct wm8350_output {
45*4882a593Smuzhiyun 	u16 active;
46*4882a593Smuzhiyun 	u16 left_vol;
47*4882a593Smuzhiyun 	u16 right_vol;
48*4882a593Smuzhiyun 	u16 ramp;
49*4882a593Smuzhiyun 	u16 mute;
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun struct wm8350_jack_data {
53*4882a593Smuzhiyun 	struct snd_soc_jack *jack;
54*4882a593Smuzhiyun 	struct delayed_work work;
55*4882a593Smuzhiyun 	int report;
56*4882a593Smuzhiyun 	int short_report;
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun struct wm8350_data {
60*4882a593Smuzhiyun 	struct wm8350 *wm8350;
61*4882a593Smuzhiyun 	struct wm8350_output out1;
62*4882a593Smuzhiyun 	struct wm8350_output out2;
63*4882a593Smuzhiyun 	struct wm8350_jack_data hpl;
64*4882a593Smuzhiyun 	struct wm8350_jack_data hpr;
65*4882a593Smuzhiyun 	struct wm8350_jack_data mic;
66*4882a593Smuzhiyun 	struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
67*4882a593Smuzhiyun 	int fll_freq_out;
68*4882a593Smuzhiyun 	int fll_freq_in;
69*4882a593Smuzhiyun 	struct delayed_work pga_work;
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /*
73*4882a593Smuzhiyun  * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown.
74*4882a593Smuzhiyun  */
wm8350_out1_ramp_step(struct wm8350_data * wm8350_data)75*4882a593Smuzhiyun static inline int wm8350_out1_ramp_step(struct wm8350_data *wm8350_data)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	struct wm8350_output *out1 = &wm8350_data->out1;
78*4882a593Smuzhiyun 	struct wm8350 *wm8350 = wm8350_data->wm8350;
79*4882a593Smuzhiyun 	int left_complete = 0, right_complete = 0;
80*4882a593Smuzhiyun 	u16 reg, val;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	/* left channel */
83*4882a593Smuzhiyun 	reg = wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME);
84*4882a593Smuzhiyun 	val = (reg & WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	if (out1->ramp == WM8350_RAMP_UP) {
87*4882a593Smuzhiyun 		/* ramp step up */
88*4882a593Smuzhiyun 		if (val < out1->left_vol) {
89*4882a593Smuzhiyun 			val++;
90*4882a593Smuzhiyun 			reg &= ~WM8350_OUT1L_VOL_MASK;
91*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME,
92*4882a593Smuzhiyun 					 reg | (val << WM8350_OUT1L_VOL_SHIFT));
93*4882a593Smuzhiyun 		} else
94*4882a593Smuzhiyun 			left_complete = 1;
95*4882a593Smuzhiyun 	} else if (out1->ramp == WM8350_RAMP_DOWN) {
96*4882a593Smuzhiyun 		/* ramp step down */
97*4882a593Smuzhiyun 		if (val > 0) {
98*4882a593Smuzhiyun 			val--;
99*4882a593Smuzhiyun 			reg &= ~WM8350_OUT1L_VOL_MASK;
100*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME,
101*4882a593Smuzhiyun 					 reg | (val << WM8350_OUT1L_VOL_SHIFT));
102*4882a593Smuzhiyun 		} else
103*4882a593Smuzhiyun 			left_complete = 1;
104*4882a593Smuzhiyun 	} else
105*4882a593Smuzhiyun 		return 1;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	/* right channel */
108*4882a593Smuzhiyun 	reg = wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME);
109*4882a593Smuzhiyun 	val = (reg & WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
110*4882a593Smuzhiyun 	if (out1->ramp == WM8350_RAMP_UP) {
111*4882a593Smuzhiyun 		/* ramp step up */
112*4882a593Smuzhiyun 		if (val < out1->right_vol) {
113*4882a593Smuzhiyun 			val++;
114*4882a593Smuzhiyun 			reg &= ~WM8350_OUT1R_VOL_MASK;
115*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME,
116*4882a593Smuzhiyun 					 reg | (val << WM8350_OUT1R_VOL_SHIFT));
117*4882a593Smuzhiyun 		} else
118*4882a593Smuzhiyun 			right_complete = 1;
119*4882a593Smuzhiyun 	} else if (out1->ramp == WM8350_RAMP_DOWN) {
120*4882a593Smuzhiyun 		/* ramp step down */
121*4882a593Smuzhiyun 		if (val > 0) {
122*4882a593Smuzhiyun 			val--;
123*4882a593Smuzhiyun 			reg &= ~WM8350_OUT1R_VOL_MASK;
124*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME,
125*4882a593Smuzhiyun 					 reg | (val << WM8350_OUT1R_VOL_SHIFT));
126*4882a593Smuzhiyun 		} else
127*4882a593Smuzhiyun 			right_complete = 1;
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	/* only hit the update bit if either volume has changed this step */
131*4882a593Smuzhiyun 	if (!left_complete || !right_complete)
132*4882a593Smuzhiyun 		wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME, WM8350_OUT1_VU);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	return left_complete & right_complete;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun /*
138*4882a593Smuzhiyun  * Ramp OUT2 PGA volume to minimise pops at stream startup and shutdown.
139*4882a593Smuzhiyun  */
wm8350_out2_ramp_step(struct wm8350_data * wm8350_data)140*4882a593Smuzhiyun static inline int wm8350_out2_ramp_step(struct wm8350_data *wm8350_data)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	struct wm8350_output *out2 = &wm8350_data->out2;
143*4882a593Smuzhiyun 	struct wm8350 *wm8350 = wm8350_data->wm8350;
144*4882a593Smuzhiyun 	int left_complete = 0, right_complete = 0;
145*4882a593Smuzhiyun 	u16 reg, val;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	/* left channel */
148*4882a593Smuzhiyun 	reg = wm8350_reg_read(wm8350, WM8350_LOUT2_VOLUME);
149*4882a593Smuzhiyun 	val = (reg & WM8350_OUT2L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
150*4882a593Smuzhiyun 	if (out2->ramp == WM8350_RAMP_UP) {
151*4882a593Smuzhiyun 		/* ramp step up */
152*4882a593Smuzhiyun 		if (val < out2->left_vol) {
153*4882a593Smuzhiyun 			val++;
154*4882a593Smuzhiyun 			reg &= ~WM8350_OUT2L_VOL_MASK;
155*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME,
156*4882a593Smuzhiyun 					 reg | (val << WM8350_OUT1L_VOL_SHIFT));
157*4882a593Smuzhiyun 		} else
158*4882a593Smuzhiyun 			left_complete = 1;
159*4882a593Smuzhiyun 	} else if (out2->ramp == WM8350_RAMP_DOWN) {
160*4882a593Smuzhiyun 		/* ramp step down */
161*4882a593Smuzhiyun 		if (val > 0) {
162*4882a593Smuzhiyun 			val--;
163*4882a593Smuzhiyun 			reg &= ~WM8350_OUT2L_VOL_MASK;
164*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME,
165*4882a593Smuzhiyun 					 reg | (val << WM8350_OUT1L_VOL_SHIFT));
166*4882a593Smuzhiyun 		} else
167*4882a593Smuzhiyun 			left_complete = 1;
168*4882a593Smuzhiyun 	} else
169*4882a593Smuzhiyun 		return 1;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	/* right channel */
172*4882a593Smuzhiyun 	reg = wm8350_reg_read(wm8350, WM8350_ROUT2_VOLUME);
173*4882a593Smuzhiyun 	val = (reg & WM8350_OUT2R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
174*4882a593Smuzhiyun 	if (out2->ramp == WM8350_RAMP_UP) {
175*4882a593Smuzhiyun 		/* ramp step up */
176*4882a593Smuzhiyun 		if (val < out2->right_vol) {
177*4882a593Smuzhiyun 			val++;
178*4882a593Smuzhiyun 			reg &= ~WM8350_OUT2R_VOL_MASK;
179*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME,
180*4882a593Smuzhiyun 					 reg | (val << WM8350_OUT1R_VOL_SHIFT));
181*4882a593Smuzhiyun 		} else
182*4882a593Smuzhiyun 			right_complete = 1;
183*4882a593Smuzhiyun 	} else if (out2->ramp == WM8350_RAMP_DOWN) {
184*4882a593Smuzhiyun 		/* ramp step down */
185*4882a593Smuzhiyun 		if (val > 0) {
186*4882a593Smuzhiyun 			val--;
187*4882a593Smuzhiyun 			reg &= ~WM8350_OUT2R_VOL_MASK;
188*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME,
189*4882a593Smuzhiyun 					 reg | (val << WM8350_OUT1R_VOL_SHIFT));
190*4882a593Smuzhiyun 		} else
191*4882a593Smuzhiyun 			right_complete = 1;
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	/* only hit the update bit if either volume has changed this step */
195*4882a593Smuzhiyun 	if (!left_complete || !right_complete)
196*4882a593Smuzhiyun 		wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME, WM8350_OUT2_VU);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	return left_complete & right_complete;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun /*
202*4882a593Smuzhiyun  * This work ramps both output PGAs at stream start/stop time to
203*4882a593Smuzhiyun  * minimise pop associated with DAPM power switching.
204*4882a593Smuzhiyun  * It's best to enable Zero Cross when ramping occurs to minimise any
205*4882a593Smuzhiyun  * zipper noises.
206*4882a593Smuzhiyun  */
wm8350_pga_work(struct work_struct * work)207*4882a593Smuzhiyun static void wm8350_pga_work(struct work_struct *work)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun 	struct wm8350_data *wm8350_data =
210*4882a593Smuzhiyun 		container_of(work, struct wm8350_data, pga_work.work);
211*4882a593Smuzhiyun 	struct wm8350_output *out1 = &wm8350_data->out1,
212*4882a593Smuzhiyun 	    *out2 = &wm8350_data->out2;
213*4882a593Smuzhiyun 	int i, out1_complete, out2_complete;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	/* do we need to ramp at all ? */
216*4882a593Smuzhiyun 	if (out1->ramp == WM8350_RAMP_NONE && out2->ramp == WM8350_RAMP_NONE)
217*4882a593Smuzhiyun 		return;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	/* PGA volumes have 6 bits of resolution to ramp */
220*4882a593Smuzhiyun 	for (i = 0; i <= 63; i++) {
221*4882a593Smuzhiyun 		out1_complete = 1, out2_complete = 1;
222*4882a593Smuzhiyun 		if (out1->ramp != WM8350_RAMP_NONE)
223*4882a593Smuzhiyun 			out1_complete = wm8350_out1_ramp_step(wm8350_data);
224*4882a593Smuzhiyun 		if (out2->ramp != WM8350_RAMP_NONE)
225*4882a593Smuzhiyun 			out2_complete = wm8350_out2_ramp_step(wm8350_data);
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 		/* ramp finished ? */
228*4882a593Smuzhiyun 		if (out1_complete && out2_complete)
229*4882a593Smuzhiyun 			break;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 		/* we need to delay longer on the up ramp */
232*4882a593Smuzhiyun 		if (out1->ramp == WM8350_RAMP_UP ||
233*4882a593Smuzhiyun 		    out2->ramp == WM8350_RAMP_UP) {
234*4882a593Smuzhiyun 			/* delay is longer over 0dB as increases are larger */
235*4882a593Smuzhiyun 			if (i >= WM8350_OUTn_0dB)
236*4882a593Smuzhiyun 				schedule_timeout_interruptible(msecs_to_jiffies
237*4882a593Smuzhiyun 							       (2));
238*4882a593Smuzhiyun 			else
239*4882a593Smuzhiyun 				schedule_timeout_interruptible(msecs_to_jiffies
240*4882a593Smuzhiyun 							       (1));
241*4882a593Smuzhiyun 		} else
242*4882a593Smuzhiyun 			udelay(50);	/* doesn't matter if we delay longer */
243*4882a593Smuzhiyun 	}
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	out1->ramp = WM8350_RAMP_NONE;
246*4882a593Smuzhiyun 	out2->ramp = WM8350_RAMP_NONE;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun /*
250*4882a593Smuzhiyun  * WM8350 Controls
251*4882a593Smuzhiyun  */
252*4882a593Smuzhiyun 
pga_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)253*4882a593Smuzhiyun static int pga_event(struct snd_soc_dapm_widget *w,
254*4882a593Smuzhiyun 		     struct snd_kcontrol *kcontrol, int event)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
257*4882a593Smuzhiyun 	struct wm8350_data *wm8350_data = snd_soc_component_get_drvdata(component);
258*4882a593Smuzhiyun 	struct wm8350_output *out;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	switch (w->shift) {
261*4882a593Smuzhiyun 	case 0:
262*4882a593Smuzhiyun 	case 1:
263*4882a593Smuzhiyun 		out = &wm8350_data->out1;
264*4882a593Smuzhiyun 		break;
265*4882a593Smuzhiyun 	case 2:
266*4882a593Smuzhiyun 	case 3:
267*4882a593Smuzhiyun 		out = &wm8350_data->out2;
268*4882a593Smuzhiyun 		break;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	default:
271*4882a593Smuzhiyun 		WARN(1, "Invalid shift %d\n", w->shift);
272*4882a593Smuzhiyun 		return -1;
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	switch (event) {
276*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMU:
277*4882a593Smuzhiyun 		out->ramp = WM8350_RAMP_UP;
278*4882a593Smuzhiyun 		out->active = 1;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 		schedule_delayed_work(&wm8350_data->pga_work,
281*4882a593Smuzhiyun 				      msecs_to_jiffies(1));
282*4882a593Smuzhiyun 		break;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMD:
285*4882a593Smuzhiyun 		out->ramp = WM8350_RAMP_DOWN;
286*4882a593Smuzhiyun 		out->active = 0;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 		schedule_delayed_work(&wm8350_data->pga_work,
289*4882a593Smuzhiyun 				      msecs_to_jiffies(1));
290*4882a593Smuzhiyun 		break;
291*4882a593Smuzhiyun 	}
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	return 0;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
wm8350_put_volsw_2r_vu(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)296*4882a593Smuzhiyun static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
297*4882a593Smuzhiyun 				  struct snd_ctl_elem_value *ucontrol)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
300*4882a593Smuzhiyun 	struct wm8350_data *wm8350_priv = snd_soc_component_get_drvdata(component);
301*4882a593Smuzhiyun 	struct wm8350_output *out = NULL;
302*4882a593Smuzhiyun 	struct soc_mixer_control *mc =
303*4882a593Smuzhiyun 		(struct soc_mixer_control *)kcontrol->private_value;
304*4882a593Smuzhiyun 	int ret;
305*4882a593Smuzhiyun 	unsigned int reg = mc->reg;
306*4882a593Smuzhiyun 	u16 val;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	/* For OUT1 and OUT2 we shadow the values and only actually write
309*4882a593Smuzhiyun 	 * them out when active in order to ensure the amplifier comes on
310*4882a593Smuzhiyun 	 * as quietly as possible. */
311*4882a593Smuzhiyun 	switch (reg) {
312*4882a593Smuzhiyun 	case WM8350_LOUT1_VOLUME:
313*4882a593Smuzhiyun 		out = &wm8350_priv->out1;
314*4882a593Smuzhiyun 		break;
315*4882a593Smuzhiyun 	case WM8350_LOUT2_VOLUME:
316*4882a593Smuzhiyun 		out = &wm8350_priv->out2;
317*4882a593Smuzhiyun 		break;
318*4882a593Smuzhiyun 	default:
319*4882a593Smuzhiyun 		break;
320*4882a593Smuzhiyun 	}
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	if (out) {
323*4882a593Smuzhiyun 		out->left_vol = ucontrol->value.integer.value[0];
324*4882a593Smuzhiyun 		out->right_vol = ucontrol->value.integer.value[1];
325*4882a593Smuzhiyun 		if (!out->active)
326*4882a593Smuzhiyun 			return 1;
327*4882a593Smuzhiyun 	}
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	ret = snd_soc_put_volsw(kcontrol, ucontrol);
330*4882a593Smuzhiyun 	if (ret < 0)
331*4882a593Smuzhiyun 		return ret;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	/* now hit the volume update bits (always bit 8) */
334*4882a593Smuzhiyun 	val = snd_soc_component_read(component, reg);
335*4882a593Smuzhiyun 	snd_soc_component_write(component, reg, val | WM8350_OUT1_VU);
336*4882a593Smuzhiyun 	return 1;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun 
wm8350_get_volsw_2r(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)339*4882a593Smuzhiyun static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol,
340*4882a593Smuzhiyun 			       struct snd_ctl_elem_value *ucontrol)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
343*4882a593Smuzhiyun 	struct wm8350_data *wm8350_priv = snd_soc_component_get_drvdata(component);
344*4882a593Smuzhiyun 	struct wm8350_output *out1 = &wm8350_priv->out1;
345*4882a593Smuzhiyun 	struct wm8350_output *out2 = &wm8350_priv->out2;
346*4882a593Smuzhiyun 	struct soc_mixer_control *mc =
347*4882a593Smuzhiyun 		(struct soc_mixer_control *)kcontrol->private_value;
348*4882a593Smuzhiyun 	unsigned int reg = mc->reg;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	/* If these are cached registers use the cache */
351*4882a593Smuzhiyun 	switch (reg) {
352*4882a593Smuzhiyun 	case WM8350_LOUT1_VOLUME:
353*4882a593Smuzhiyun 		ucontrol->value.integer.value[0] = out1->left_vol;
354*4882a593Smuzhiyun 		ucontrol->value.integer.value[1] = out1->right_vol;
355*4882a593Smuzhiyun 		return 0;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	case WM8350_LOUT2_VOLUME:
358*4882a593Smuzhiyun 		ucontrol->value.integer.value[0] = out2->left_vol;
359*4882a593Smuzhiyun 		ucontrol->value.integer.value[1] = out2->right_vol;
360*4882a593Smuzhiyun 		return 0;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	default:
363*4882a593Smuzhiyun 		break;
364*4882a593Smuzhiyun 	}
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	return snd_soc_get_volsw(kcontrol, ucontrol);
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun static const char *wm8350_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
370*4882a593Smuzhiyun static const char *wm8350_pol[] = { "Normal", "Inv R", "Inv L", "Inv L & R" };
371*4882a593Smuzhiyun static const char *wm8350_dacmutem[] = { "Normal", "Soft" };
372*4882a593Smuzhiyun static const char *wm8350_dacmutes[] = { "Fast", "Slow" };
373*4882a593Smuzhiyun static const char *wm8350_adcfilter[] = { "None", "High Pass" };
374*4882a593Smuzhiyun static const char *wm8350_adchp[] = { "44.1kHz", "8kHz", "16kHz", "32kHz" };
375*4882a593Smuzhiyun static const char *wm8350_lr[] = { "Left", "Right" };
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun static const struct soc_enum wm8350_enum[] = {
378*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 4, 4, wm8350_deemp),
379*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 0, 4, wm8350_pol),
380*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 14, 2, wm8350_dacmutem),
381*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 13, 2, wm8350_dacmutes),
382*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 15, 2, wm8350_adcfilter),
383*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 8, 4, wm8350_adchp),
384*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 0, 4, wm8350_pol),
385*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(WM8350_INPUT_MIXER_VOLUME, 15, 2, wm8350_lr),
386*4882a593Smuzhiyun };
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun static DECLARE_TLV_DB_SCALE(pre_amp_tlv, -1200, 3525, 0);
389*4882a593Smuzhiyun static DECLARE_TLV_DB_SCALE(out_pga_tlv, -5700, 600, 0);
390*4882a593Smuzhiyun static DECLARE_TLV_DB_SCALE(dac_pcm_tlv, -7163, 36, 1);
391*4882a593Smuzhiyun static DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -12700, 50, 1);
392*4882a593Smuzhiyun static DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 1);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun static const DECLARE_TLV_DB_RANGE(capture_sd_tlv,
395*4882a593Smuzhiyun 	0, 12, TLV_DB_SCALE_ITEM(-3600, 300, 1),
396*4882a593Smuzhiyun 	13, 15, TLV_DB_SCALE_ITEM(0, 0, 0)
397*4882a593Smuzhiyun );
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8350_snd_controls[] = {
400*4882a593Smuzhiyun 	SOC_ENUM("Playback Deemphasis", wm8350_enum[0]),
401*4882a593Smuzhiyun 	SOC_ENUM("Playback DAC Inversion", wm8350_enum[1]),
402*4882a593Smuzhiyun 	SOC_DOUBLE_R_EXT_TLV("Playback PCM Volume",
403*4882a593Smuzhiyun 				WM8350_DAC_DIGITAL_VOLUME_L,
404*4882a593Smuzhiyun 				WM8350_DAC_DIGITAL_VOLUME_R,
405*4882a593Smuzhiyun 				0, 255, 0, wm8350_get_volsw_2r,
406*4882a593Smuzhiyun 				wm8350_put_volsw_2r_vu, dac_pcm_tlv),
407*4882a593Smuzhiyun 	SOC_ENUM("Playback PCM Mute Function", wm8350_enum[2]),
408*4882a593Smuzhiyun 	SOC_ENUM("Playback PCM Mute Speed", wm8350_enum[3]),
409*4882a593Smuzhiyun 	SOC_ENUM("Capture PCM Filter", wm8350_enum[4]),
410*4882a593Smuzhiyun 	SOC_ENUM("Capture PCM HP Filter", wm8350_enum[5]),
411*4882a593Smuzhiyun 	SOC_ENUM("Capture ADC Inversion", wm8350_enum[6]),
412*4882a593Smuzhiyun 	SOC_DOUBLE_R_EXT_TLV("Capture PCM Volume",
413*4882a593Smuzhiyun 				WM8350_ADC_DIGITAL_VOLUME_L,
414*4882a593Smuzhiyun 				WM8350_ADC_DIGITAL_VOLUME_R,
415*4882a593Smuzhiyun 				0, 255, 0, wm8350_get_volsw_2r,
416*4882a593Smuzhiyun 				wm8350_put_volsw_2r_vu, adc_pcm_tlv),
417*4882a593Smuzhiyun 	SOC_DOUBLE_TLV("Capture Sidetone Volume",
418*4882a593Smuzhiyun 		       WM8350_ADC_DIVIDER,
419*4882a593Smuzhiyun 		       8, 4, 15, 1, capture_sd_tlv),
420*4882a593Smuzhiyun 	SOC_DOUBLE_R_EXT_TLV("Capture Volume",
421*4882a593Smuzhiyun 				WM8350_LEFT_INPUT_VOLUME,
422*4882a593Smuzhiyun 				WM8350_RIGHT_INPUT_VOLUME,
423*4882a593Smuzhiyun 				2, 63, 0, wm8350_get_volsw_2r,
424*4882a593Smuzhiyun 				wm8350_put_volsw_2r_vu, pre_amp_tlv),
425*4882a593Smuzhiyun 	SOC_DOUBLE_R("Capture ZC Switch",
426*4882a593Smuzhiyun 		     WM8350_LEFT_INPUT_VOLUME,
427*4882a593Smuzhiyun 		     WM8350_RIGHT_INPUT_VOLUME, 13, 1, 0),
428*4882a593Smuzhiyun 	SOC_SINGLE_TLV("Left Input Left Sidetone Volume",
429*4882a593Smuzhiyun 		       WM8350_OUTPUT_LEFT_MIXER_VOLUME, 1, 7, 0, out_mix_tlv),
430*4882a593Smuzhiyun 	SOC_SINGLE_TLV("Left Input Right Sidetone Volume",
431*4882a593Smuzhiyun 		       WM8350_OUTPUT_LEFT_MIXER_VOLUME,
432*4882a593Smuzhiyun 		       5, 7, 0, out_mix_tlv),
433*4882a593Smuzhiyun 	SOC_SINGLE_TLV("Left Input Bypass Volume",
434*4882a593Smuzhiyun 		       WM8350_OUTPUT_LEFT_MIXER_VOLUME,
435*4882a593Smuzhiyun 		       9, 7, 0, out_mix_tlv),
436*4882a593Smuzhiyun 	SOC_SINGLE_TLV("Right Input Left Sidetone Volume",
437*4882a593Smuzhiyun 		       WM8350_OUTPUT_RIGHT_MIXER_VOLUME,
438*4882a593Smuzhiyun 		       1, 7, 0, out_mix_tlv),
439*4882a593Smuzhiyun 	SOC_SINGLE_TLV("Right Input Right Sidetone Volume",
440*4882a593Smuzhiyun 		       WM8350_OUTPUT_RIGHT_MIXER_VOLUME,
441*4882a593Smuzhiyun 		       5, 7, 0, out_mix_tlv),
442*4882a593Smuzhiyun 	SOC_SINGLE_TLV("Right Input Bypass Volume",
443*4882a593Smuzhiyun 		       WM8350_OUTPUT_RIGHT_MIXER_VOLUME,
444*4882a593Smuzhiyun 		       13, 7, 0, out_mix_tlv),
445*4882a593Smuzhiyun 	SOC_SINGLE("Left Input Mixer +20dB Switch",
446*4882a593Smuzhiyun 		   WM8350_INPUT_MIXER_VOLUME_L, 0, 1, 0),
447*4882a593Smuzhiyun 	SOC_SINGLE("Right Input Mixer +20dB Switch",
448*4882a593Smuzhiyun 		   WM8350_INPUT_MIXER_VOLUME_R, 0, 1, 0),
449*4882a593Smuzhiyun 	SOC_SINGLE_TLV("Out4 Capture Volume",
450*4882a593Smuzhiyun 		       WM8350_INPUT_MIXER_VOLUME,
451*4882a593Smuzhiyun 		       1, 7, 0, out_mix_tlv),
452*4882a593Smuzhiyun 	SOC_DOUBLE_R_EXT_TLV("Out1 Playback Volume",
453*4882a593Smuzhiyun 				WM8350_LOUT1_VOLUME,
454*4882a593Smuzhiyun 				WM8350_ROUT1_VOLUME,
455*4882a593Smuzhiyun 				2, 63, 0, wm8350_get_volsw_2r,
456*4882a593Smuzhiyun 				wm8350_put_volsw_2r_vu, out_pga_tlv),
457*4882a593Smuzhiyun 	SOC_DOUBLE_R("Out1 Playback ZC Switch",
458*4882a593Smuzhiyun 		     WM8350_LOUT1_VOLUME,
459*4882a593Smuzhiyun 		     WM8350_ROUT1_VOLUME, 13, 1, 0),
460*4882a593Smuzhiyun 	SOC_DOUBLE_R_EXT_TLV("Out2 Playback Volume",
461*4882a593Smuzhiyun 				WM8350_LOUT2_VOLUME,
462*4882a593Smuzhiyun 				WM8350_ROUT2_VOLUME,
463*4882a593Smuzhiyun 				2, 63, 0, wm8350_get_volsw_2r,
464*4882a593Smuzhiyun 				wm8350_put_volsw_2r_vu, out_pga_tlv),
465*4882a593Smuzhiyun 	SOC_DOUBLE_R("Out2 Playback ZC Switch", WM8350_LOUT2_VOLUME,
466*4882a593Smuzhiyun 		     WM8350_ROUT2_VOLUME, 13, 1, 0),
467*4882a593Smuzhiyun 	SOC_SINGLE("Out2 Right Invert Switch", WM8350_ROUT2_VOLUME, 10, 1, 0),
468*4882a593Smuzhiyun 	SOC_SINGLE_TLV("Out2 Beep Volume", WM8350_BEEP_VOLUME,
469*4882a593Smuzhiyun 		       5, 7, 0, out_mix_tlv),
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	SOC_DOUBLE_R("Out1 Playback Switch",
472*4882a593Smuzhiyun 		     WM8350_LOUT1_VOLUME,
473*4882a593Smuzhiyun 		     WM8350_ROUT1_VOLUME,
474*4882a593Smuzhiyun 		     14, 1, 1),
475*4882a593Smuzhiyun 	SOC_DOUBLE_R("Out2 Playback Switch",
476*4882a593Smuzhiyun 		     WM8350_LOUT2_VOLUME,
477*4882a593Smuzhiyun 		     WM8350_ROUT2_VOLUME,
478*4882a593Smuzhiyun 		     14, 1, 1),
479*4882a593Smuzhiyun };
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun /*
482*4882a593Smuzhiyun  * DAPM Controls
483*4882a593Smuzhiyun  */
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun /* Left Playback Mixer */
486*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8350_left_play_mixer_controls[] = {
487*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Playback Switch",
488*4882a593Smuzhiyun 			WM8350_LEFT_MIXER_CONTROL, 11, 1, 0),
489*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Left Bypass Switch",
490*4882a593Smuzhiyun 			WM8350_LEFT_MIXER_CONTROL, 2, 1, 0),
491*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Right Playback Switch",
492*4882a593Smuzhiyun 			WM8350_LEFT_MIXER_CONTROL, 12, 1, 0),
493*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Left Sidetone Switch",
494*4882a593Smuzhiyun 			WM8350_LEFT_MIXER_CONTROL, 0, 1, 0),
495*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Right Sidetone Switch",
496*4882a593Smuzhiyun 			WM8350_LEFT_MIXER_CONTROL, 1, 1, 0),
497*4882a593Smuzhiyun };
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun /* Right Playback Mixer */
500*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8350_right_play_mixer_controls[] = {
501*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Playback Switch",
502*4882a593Smuzhiyun 			WM8350_RIGHT_MIXER_CONTROL, 12, 1, 0),
503*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Right Bypass Switch",
504*4882a593Smuzhiyun 			WM8350_RIGHT_MIXER_CONTROL, 3, 1, 0),
505*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Left Playback Switch",
506*4882a593Smuzhiyun 			WM8350_RIGHT_MIXER_CONTROL, 11, 1, 0),
507*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Left Sidetone Switch",
508*4882a593Smuzhiyun 			WM8350_RIGHT_MIXER_CONTROL, 0, 1, 0),
509*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Right Sidetone Switch",
510*4882a593Smuzhiyun 			WM8350_RIGHT_MIXER_CONTROL, 1, 1, 0),
511*4882a593Smuzhiyun };
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun /* Out4 Mixer */
514*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8350_out4_mixer_controls[] = {
515*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Right Playback Switch",
516*4882a593Smuzhiyun 			WM8350_OUT4_MIXER_CONTROL, 12, 1, 0),
517*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Left Playback Switch",
518*4882a593Smuzhiyun 			WM8350_OUT4_MIXER_CONTROL, 11, 1, 0),
519*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Right Capture Switch",
520*4882a593Smuzhiyun 			WM8350_OUT4_MIXER_CONTROL, 9, 1, 0),
521*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Out3 Playback Switch",
522*4882a593Smuzhiyun 			WM8350_OUT4_MIXER_CONTROL, 2, 1, 0),
523*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Right Mixer Switch",
524*4882a593Smuzhiyun 			WM8350_OUT4_MIXER_CONTROL, 1, 1, 0),
525*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Left Mixer Switch",
526*4882a593Smuzhiyun 			WM8350_OUT4_MIXER_CONTROL, 0, 1, 0),
527*4882a593Smuzhiyun };
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun /* Out3 Mixer */
530*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8350_out3_mixer_controls[] = {
531*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Left Playback Switch",
532*4882a593Smuzhiyun 			WM8350_OUT3_MIXER_CONTROL, 11, 1, 0),
533*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Left Capture Switch",
534*4882a593Smuzhiyun 			WM8350_OUT3_MIXER_CONTROL, 8, 1, 0),
535*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Out4 Playback Switch",
536*4882a593Smuzhiyun 			WM8350_OUT3_MIXER_CONTROL, 3, 1, 0),
537*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Left Mixer Switch",
538*4882a593Smuzhiyun 			WM8350_OUT3_MIXER_CONTROL, 0, 1, 0),
539*4882a593Smuzhiyun };
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun /* Left Input Mixer */
542*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8350_left_capt_mixer_controls[] = {
543*4882a593Smuzhiyun 	SOC_DAPM_SINGLE_TLV("L2 Capture Volume",
544*4882a593Smuzhiyun 			    WM8350_INPUT_MIXER_VOLUME_L, 1, 7, 0, out_mix_tlv),
545*4882a593Smuzhiyun 	SOC_DAPM_SINGLE_TLV("L3 Capture Volume",
546*4882a593Smuzhiyun 			    WM8350_INPUT_MIXER_VOLUME_L, 9, 7, 0, out_mix_tlv),
547*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("PGA Capture Switch",
548*4882a593Smuzhiyun 			WM8350_LEFT_INPUT_VOLUME, 14, 1, 1),
549*4882a593Smuzhiyun };
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun /* Right Input Mixer */
552*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8350_right_capt_mixer_controls[] = {
553*4882a593Smuzhiyun 	SOC_DAPM_SINGLE_TLV("L2 Capture Volume",
554*4882a593Smuzhiyun 			    WM8350_INPUT_MIXER_VOLUME_R, 5, 7, 0, out_mix_tlv),
555*4882a593Smuzhiyun 	SOC_DAPM_SINGLE_TLV("L3 Capture Volume",
556*4882a593Smuzhiyun 			    WM8350_INPUT_MIXER_VOLUME_R, 13, 7, 0, out_mix_tlv),
557*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("PGA Capture Switch",
558*4882a593Smuzhiyun 			WM8350_RIGHT_INPUT_VOLUME, 14, 1, 1),
559*4882a593Smuzhiyun };
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun /* Left Mic Mixer */
562*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8350_left_mic_mixer_controls[] = {
563*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("INN Capture Switch", WM8350_INPUT_CONTROL, 1, 1, 0),
564*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("INP Capture Switch", WM8350_INPUT_CONTROL, 0, 1, 0),
565*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("IN2 Capture Switch", WM8350_INPUT_CONTROL, 2, 1, 0),
566*4882a593Smuzhiyun };
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun /* Right Mic Mixer */
569*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8350_right_mic_mixer_controls[] = {
570*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("INN Capture Switch", WM8350_INPUT_CONTROL, 9, 1, 0),
571*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("INP Capture Switch", WM8350_INPUT_CONTROL, 8, 1, 0),
572*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("IN2 Capture Switch", WM8350_INPUT_CONTROL, 10, 1, 0),
573*4882a593Smuzhiyun };
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun /* Beep Switch */
576*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8350_beep_switch_controls =
577*4882a593Smuzhiyun SOC_DAPM_SINGLE("Switch", WM8350_BEEP_VOLUME, 15, 1, 1);
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun /* Out4 Capture Mux */
580*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8350_out4_capture_controls =
581*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8350_enum[7]);
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun static const struct snd_soc_dapm_widget wm8350_dapm_widgets[] = {
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("IN3R PGA", WM8350_POWER_MGMT_2, 11, 0, NULL, 0),
586*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("IN3L PGA", WM8350_POWER_MGMT_2, 10, 0, NULL, 0),
587*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA_E("Right Out2 PGA", WM8350_POWER_MGMT_3, 3, 0, NULL,
588*4882a593Smuzhiyun 			   0, pga_event,
589*4882a593Smuzhiyun 			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
590*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA_E("Left Out2 PGA", WM8350_POWER_MGMT_3, 2, 0, NULL, 0,
591*4882a593Smuzhiyun 			   pga_event,
592*4882a593Smuzhiyun 			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
593*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA_E("Right Out1 PGA", WM8350_POWER_MGMT_3, 1, 0, NULL,
594*4882a593Smuzhiyun 			   0, pga_event,
595*4882a593Smuzhiyun 			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
596*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA_E("Left Out1 PGA", WM8350_POWER_MGMT_3, 0, 0, NULL, 0,
597*4882a593Smuzhiyun 			   pga_event,
598*4882a593Smuzhiyun 			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	SND_SOC_DAPM_MIXER("Right Capture Mixer", WM8350_POWER_MGMT_2,
601*4882a593Smuzhiyun 			   7, 0, &wm8350_right_capt_mixer_controls[0],
602*4882a593Smuzhiyun 			   ARRAY_SIZE(wm8350_right_capt_mixer_controls)),
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	SND_SOC_DAPM_MIXER("Left Capture Mixer", WM8350_POWER_MGMT_2,
605*4882a593Smuzhiyun 			   6, 0, &wm8350_left_capt_mixer_controls[0],
606*4882a593Smuzhiyun 			   ARRAY_SIZE(wm8350_left_capt_mixer_controls)),
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	SND_SOC_DAPM_MIXER("Out4 Mixer", WM8350_POWER_MGMT_2, 5, 0,
609*4882a593Smuzhiyun 			   &wm8350_out4_mixer_controls[0],
610*4882a593Smuzhiyun 			   ARRAY_SIZE(wm8350_out4_mixer_controls)),
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	SND_SOC_DAPM_MIXER("Out3 Mixer", WM8350_POWER_MGMT_2, 4, 0,
613*4882a593Smuzhiyun 			   &wm8350_out3_mixer_controls[0],
614*4882a593Smuzhiyun 			   ARRAY_SIZE(wm8350_out3_mixer_controls)),
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	SND_SOC_DAPM_MIXER("Right Playback Mixer", WM8350_POWER_MGMT_2, 1, 0,
617*4882a593Smuzhiyun 			   &wm8350_right_play_mixer_controls[0],
618*4882a593Smuzhiyun 			   ARRAY_SIZE(wm8350_right_play_mixer_controls)),
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	SND_SOC_DAPM_MIXER("Left Playback Mixer", WM8350_POWER_MGMT_2, 0, 0,
621*4882a593Smuzhiyun 			   &wm8350_left_play_mixer_controls[0],
622*4882a593Smuzhiyun 			   ARRAY_SIZE(wm8350_left_play_mixer_controls)),
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	SND_SOC_DAPM_MIXER("Left Mic Mixer", WM8350_POWER_MGMT_2, 8, 0,
625*4882a593Smuzhiyun 			   &wm8350_left_mic_mixer_controls[0],
626*4882a593Smuzhiyun 			   ARRAY_SIZE(wm8350_left_mic_mixer_controls)),
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	SND_SOC_DAPM_MIXER("Right Mic Mixer", WM8350_POWER_MGMT_2, 9, 0,
629*4882a593Smuzhiyun 			   &wm8350_right_mic_mixer_controls[0],
630*4882a593Smuzhiyun 			   ARRAY_SIZE(wm8350_right_mic_mixer_controls)),
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	/* virtual mixer for Beep and Out2R */
633*4882a593Smuzhiyun 	SND_SOC_DAPM_MIXER("Out2 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	SND_SOC_DAPM_SWITCH("Beep", WM8350_POWER_MGMT_3, 7, 0,
636*4882a593Smuzhiyun 			    &wm8350_beep_switch_controls),
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	SND_SOC_DAPM_ADC("Right ADC", "Right Capture",
639*4882a593Smuzhiyun 			 WM8350_POWER_MGMT_4, 3, 0),
640*4882a593Smuzhiyun 	SND_SOC_DAPM_ADC("Left ADC", "Left Capture",
641*4882a593Smuzhiyun 			 WM8350_POWER_MGMT_4, 2, 0),
642*4882a593Smuzhiyun 	SND_SOC_DAPM_DAC("Right DAC", "Right Playback",
643*4882a593Smuzhiyun 			 WM8350_POWER_MGMT_4, 5, 0),
644*4882a593Smuzhiyun 	SND_SOC_DAPM_DAC("Left DAC", "Left Playback",
645*4882a593Smuzhiyun 			 WM8350_POWER_MGMT_4, 4, 0),
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8350_POWER_MGMT_1, 4, 0),
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("Out4 Capture Channel", SND_SOC_NOPM, 0, 0,
650*4882a593Smuzhiyun 			 &wm8350_out4_capture_controls),
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("OUT1R"),
653*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("OUT1L"),
654*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("OUT2R"),
655*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("OUT2L"),
656*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("OUT3"),
657*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("OUT4"),
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("IN1RN"),
660*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("IN1RP"),
661*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("IN2R"),
662*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("IN1LP"),
663*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("IN1LN"),
664*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("IN2L"),
665*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("IN3R"),
666*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("IN3L"),
667*4882a593Smuzhiyun };
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun static const struct snd_soc_dapm_route wm8350_dapm_routes[] = {
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	/* left playback mixer */
672*4882a593Smuzhiyun 	{"Left Playback Mixer", "Playback Switch", "Left DAC"},
673*4882a593Smuzhiyun 	{"Left Playback Mixer", "Left Bypass Switch", "IN3L PGA"},
674*4882a593Smuzhiyun 	{"Left Playback Mixer", "Right Playback Switch", "Right DAC"},
675*4882a593Smuzhiyun 	{"Left Playback Mixer", "Left Sidetone Switch", "Left Mic Mixer"},
676*4882a593Smuzhiyun 	{"Left Playback Mixer", "Right Sidetone Switch", "Right Mic Mixer"},
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	/* right playback mixer */
679*4882a593Smuzhiyun 	{"Right Playback Mixer", "Playback Switch", "Right DAC"},
680*4882a593Smuzhiyun 	{"Right Playback Mixer", "Right Bypass Switch", "IN3R PGA"},
681*4882a593Smuzhiyun 	{"Right Playback Mixer", "Left Playback Switch", "Left DAC"},
682*4882a593Smuzhiyun 	{"Right Playback Mixer", "Left Sidetone Switch", "Left Mic Mixer"},
683*4882a593Smuzhiyun 	{"Right Playback Mixer", "Right Sidetone Switch", "Right Mic Mixer"},
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	/* out4 playback mixer */
686*4882a593Smuzhiyun 	{"Out4 Mixer", "Right Playback Switch", "Right DAC"},
687*4882a593Smuzhiyun 	{"Out4 Mixer", "Left Playback Switch", "Left DAC"},
688*4882a593Smuzhiyun 	{"Out4 Mixer", "Right Capture Switch", "Right Capture Mixer"},
689*4882a593Smuzhiyun 	{"Out4 Mixer", "Out3 Playback Switch", "Out3 Mixer"},
690*4882a593Smuzhiyun 	{"Out4 Mixer", "Right Mixer Switch", "Right Playback Mixer"},
691*4882a593Smuzhiyun 	{"Out4 Mixer", "Left Mixer Switch", "Left Playback Mixer"},
692*4882a593Smuzhiyun 	{"OUT4", NULL, "Out4 Mixer"},
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	/* out3 playback mixer */
695*4882a593Smuzhiyun 	{"Out3 Mixer", "Left Playback Switch", "Left DAC"},
696*4882a593Smuzhiyun 	{"Out3 Mixer", "Left Capture Switch", "Left Capture Mixer"},
697*4882a593Smuzhiyun 	{"Out3 Mixer", "Left Mixer Switch", "Left Playback Mixer"},
698*4882a593Smuzhiyun 	{"Out3 Mixer", "Out4 Playback Switch", "Out4 Mixer"},
699*4882a593Smuzhiyun 	{"OUT3", NULL, "Out3 Mixer"},
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	/* out2 */
702*4882a593Smuzhiyun 	{"Right Out2 PGA", NULL, "Right Playback Mixer"},
703*4882a593Smuzhiyun 	{"Left Out2 PGA", NULL, "Left Playback Mixer"},
704*4882a593Smuzhiyun 	{"OUT2L", NULL, "Left Out2 PGA"},
705*4882a593Smuzhiyun 	{"OUT2R", NULL, "Right Out2 PGA"},
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	/* out1 */
708*4882a593Smuzhiyun 	{"Right Out1 PGA", NULL, "Right Playback Mixer"},
709*4882a593Smuzhiyun 	{"Left Out1 PGA", NULL, "Left Playback Mixer"},
710*4882a593Smuzhiyun 	{"OUT1L", NULL, "Left Out1 PGA"},
711*4882a593Smuzhiyun 	{"OUT1R", NULL, "Right Out1 PGA"},
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	/* ADCs */
714*4882a593Smuzhiyun 	{"Left ADC", NULL, "Left Capture Mixer"},
715*4882a593Smuzhiyun 	{"Right ADC", NULL, "Right Capture Mixer"},
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	/* Left capture mixer */
718*4882a593Smuzhiyun 	{"Left Capture Mixer", "L2 Capture Volume", "IN2L"},
719*4882a593Smuzhiyun 	{"Left Capture Mixer", "L3 Capture Volume", "IN3L PGA"},
720*4882a593Smuzhiyun 	{"Left Capture Mixer", "PGA Capture Switch", "Left Mic Mixer"},
721*4882a593Smuzhiyun 	{"Left Capture Mixer", NULL, "Out4 Capture Channel"},
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	/* Right capture mixer */
724*4882a593Smuzhiyun 	{"Right Capture Mixer", "L2 Capture Volume", "IN2R"},
725*4882a593Smuzhiyun 	{"Right Capture Mixer", "L3 Capture Volume", "IN3R PGA"},
726*4882a593Smuzhiyun 	{"Right Capture Mixer", "PGA Capture Switch", "Right Mic Mixer"},
727*4882a593Smuzhiyun 	{"Right Capture Mixer", NULL, "Out4 Capture Channel"},
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 	/* L3 Inputs */
730*4882a593Smuzhiyun 	{"IN3L PGA", NULL, "IN3L"},
731*4882a593Smuzhiyun 	{"IN3R PGA", NULL, "IN3R"},
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	/* Left Mic mixer */
734*4882a593Smuzhiyun 	{"Left Mic Mixer", "INN Capture Switch", "IN1LN"},
735*4882a593Smuzhiyun 	{"Left Mic Mixer", "INP Capture Switch", "IN1LP"},
736*4882a593Smuzhiyun 	{"Left Mic Mixer", "IN2 Capture Switch", "IN2L"},
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	/* Right Mic mixer */
739*4882a593Smuzhiyun 	{"Right Mic Mixer", "INN Capture Switch", "IN1RN"},
740*4882a593Smuzhiyun 	{"Right Mic Mixer", "INP Capture Switch", "IN1RP"},
741*4882a593Smuzhiyun 	{"Right Mic Mixer", "IN2 Capture Switch", "IN2R"},
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	/* out 4 capture */
744*4882a593Smuzhiyun 	{"Out4 Capture Channel", NULL, "Out4 Mixer"},
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	/* Beep */
747*4882a593Smuzhiyun 	{"Beep", NULL, "IN3R PGA"},
748*4882a593Smuzhiyun };
749*4882a593Smuzhiyun 
wm8350_set_dai_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)750*4882a593Smuzhiyun static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
751*4882a593Smuzhiyun 				 int clk_id, unsigned int freq, int dir)
752*4882a593Smuzhiyun {
753*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
754*4882a593Smuzhiyun 	struct wm8350_data *wm8350_data = snd_soc_component_get_drvdata(component);
755*4882a593Smuzhiyun 	struct wm8350 *wm8350 = wm8350_data->wm8350;
756*4882a593Smuzhiyun 	u16 fll_4;
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	switch (clk_id) {
759*4882a593Smuzhiyun 	case WM8350_MCLK_SEL_MCLK:
760*4882a593Smuzhiyun 		wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_1,
761*4882a593Smuzhiyun 				  WM8350_MCLK_SEL);
762*4882a593Smuzhiyun 		break;
763*4882a593Smuzhiyun 	case WM8350_MCLK_SEL_PLL_MCLK:
764*4882a593Smuzhiyun 	case WM8350_MCLK_SEL_PLL_DAC:
765*4882a593Smuzhiyun 	case WM8350_MCLK_SEL_PLL_ADC:
766*4882a593Smuzhiyun 	case WM8350_MCLK_SEL_PLL_32K:
767*4882a593Smuzhiyun 		wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_1,
768*4882a593Smuzhiyun 				WM8350_MCLK_SEL);
769*4882a593Smuzhiyun 		fll_4 = snd_soc_component_read(component, WM8350_FLL_CONTROL_4) &
770*4882a593Smuzhiyun 		    ~WM8350_FLL_CLK_SRC_MASK;
771*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8350_FLL_CONTROL_4, fll_4 | clk_id);
772*4882a593Smuzhiyun 		break;
773*4882a593Smuzhiyun 	}
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	/* MCLK direction */
776*4882a593Smuzhiyun 	if (dir == SND_SOC_CLOCK_OUT)
777*4882a593Smuzhiyun 		wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2,
778*4882a593Smuzhiyun 				WM8350_MCLK_DIR);
779*4882a593Smuzhiyun 	else
780*4882a593Smuzhiyun 		wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_2,
781*4882a593Smuzhiyun 				  WM8350_MCLK_DIR);
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	return 0;
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun 
wm8350_set_clkdiv(struct snd_soc_dai * codec_dai,int div_id,int div)786*4882a593Smuzhiyun static int wm8350_set_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div)
787*4882a593Smuzhiyun {
788*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
789*4882a593Smuzhiyun 	u16 val;
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	switch (div_id) {
792*4882a593Smuzhiyun 	case WM8350_ADC_CLKDIV:
793*4882a593Smuzhiyun 		val = snd_soc_component_read(component, WM8350_ADC_DIVIDER) &
794*4882a593Smuzhiyun 		    ~WM8350_ADC_CLKDIV_MASK;
795*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8350_ADC_DIVIDER, val | div);
796*4882a593Smuzhiyun 		break;
797*4882a593Smuzhiyun 	case WM8350_DAC_CLKDIV:
798*4882a593Smuzhiyun 		val = snd_soc_component_read(component, WM8350_DAC_CLOCK_CONTROL) &
799*4882a593Smuzhiyun 		    ~WM8350_DAC_CLKDIV_MASK;
800*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8350_DAC_CLOCK_CONTROL, val | div);
801*4882a593Smuzhiyun 		break;
802*4882a593Smuzhiyun 	case WM8350_BCLK_CLKDIV:
803*4882a593Smuzhiyun 		val = snd_soc_component_read(component, WM8350_CLOCK_CONTROL_1) &
804*4882a593Smuzhiyun 		    ~WM8350_BCLK_DIV_MASK;
805*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8350_CLOCK_CONTROL_1, val | div);
806*4882a593Smuzhiyun 		break;
807*4882a593Smuzhiyun 	case WM8350_OPCLK_CLKDIV:
808*4882a593Smuzhiyun 		val = snd_soc_component_read(component, WM8350_CLOCK_CONTROL_1) &
809*4882a593Smuzhiyun 		    ~WM8350_OPCLK_DIV_MASK;
810*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8350_CLOCK_CONTROL_1, val | div);
811*4882a593Smuzhiyun 		break;
812*4882a593Smuzhiyun 	case WM8350_SYS_CLKDIV:
813*4882a593Smuzhiyun 		val = snd_soc_component_read(component, WM8350_CLOCK_CONTROL_1) &
814*4882a593Smuzhiyun 		    ~WM8350_MCLK_DIV_MASK;
815*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8350_CLOCK_CONTROL_1, val | div);
816*4882a593Smuzhiyun 		break;
817*4882a593Smuzhiyun 	case WM8350_DACLR_CLKDIV:
818*4882a593Smuzhiyun 		val = snd_soc_component_read(component, WM8350_DAC_LR_RATE) &
819*4882a593Smuzhiyun 		    ~WM8350_DACLRC_RATE_MASK;
820*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8350_DAC_LR_RATE, val | div);
821*4882a593Smuzhiyun 		break;
822*4882a593Smuzhiyun 	case WM8350_ADCLR_CLKDIV:
823*4882a593Smuzhiyun 		val = snd_soc_component_read(component, WM8350_ADC_LR_RATE) &
824*4882a593Smuzhiyun 		    ~WM8350_ADCLRC_RATE_MASK;
825*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8350_ADC_LR_RATE, val | div);
826*4882a593Smuzhiyun 		break;
827*4882a593Smuzhiyun 	default:
828*4882a593Smuzhiyun 		return -EINVAL;
829*4882a593Smuzhiyun 	}
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	return 0;
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun 
wm8350_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)834*4882a593Smuzhiyun static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
835*4882a593Smuzhiyun {
836*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
837*4882a593Smuzhiyun 	u16 iface = snd_soc_component_read(component, WM8350_AI_FORMATING) &
838*4882a593Smuzhiyun 	    ~(WM8350_AIF_BCLK_INV | WM8350_AIF_LRCLK_INV | WM8350_AIF_FMT_MASK);
839*4882a593Smuzhiyun 	u16 master = snd_soc_component_read(component, WM8350_AI_DAC_CONTROL) &
840*4882a593Smuzhiyun 	    ~WM8350_BCLK_MSTR;
841*4882a593Smuzhiyun 	u16 dac_lrc = snd_soc_component_read(component, WM8350_DAC_LR_RATE) &
842*4882a593Smuzhiyun 	    ~WM8350_DACLRC_ENA;
843*4882a593Smuzhiyun 	u16 adc_lrc = snd_soc_component_read(component, WM8350_ADC_LR_RATE) &
844*4882a593Smuzhiyun 	    ~WM8350_ADCLRC_ENA;
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	/* set master/slave audio interface */
847*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
848*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFM:
849*4882a593Smuzhiyun 		master |= WM8350_BCLK_MSTR;
850*4882a593Smuzhiyun 		dac_lrc |= WM8350_DACLRC_ENA;
851*4882a593Smuzhiyun 		adc_lrc |= WM8350_ADCLRC_ENA;
852*4882a593Smuzhiyun 		break;
853*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBS_CFS:
854*4882a593Smuzhiyun 		break;
855*4882a593Smuzhiyun 	default:
856*4882a593Smuzhiyun 		return -EINVAL;
857*4882a593Smuzhiyun 	}
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 	/* interface format */
860*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
861*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
862*4882a593Smuzhiyun 		iface |= 0x2 << 8;
863*4882a593Smuzhiyun 		break;
864*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_RIGHT_J:
865*4882a593Smuzhiyun 		break;
866*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_LEFT_J:
867*4882a593Smuzhiyun 		iface |= 0x1 << 8;
868*4882a593Smuzhiyun 		break;
869*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A:
870*4882a593Smuzhiyun 		iface |= 0x3 << 8;
871*4882a593Smuzhiyun 		break;
872*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B:
873*4882a593Smuzhiyun 		iface |= 0x3 << 8 | WM8350_AIF_LRCLK_INV;
874*4882a593Smuzhiyun 		break;
875*4882a593Smuzhiyun 	default:
876*4882a593Smuzhiyun 		return -EINVAL;
877*4882a593Smuzhiyun 	}
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun 	/* clock inversion */
880*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
881*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_NF:
882*4882a593Smuzhiyun 		break;
883*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_IF:
884*4882a593Smuzhiyun 		iface |= WM8350_AIF_LRCLK_INV | WM8350_AIF_BCLK_INV;
885*4882a593Smuzhiyun 		break;
886*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_NF:
887*4882a593Smuzhiyun 		iface |= WM8350_AIF_BCLK_INV;
888*4882a593Smuzhiyun 		break;
889*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_IF:
890*4882a593Smuzhiyun 		iface |= WM8350_AIF_LRCLK_INV;
891*4882a593Smuzhiyun 		break;
892*4882a593Smuzhiyun 	default:
893*4882a593Smuzhiyun 		return -EINVAL;
894*4882a593Smuzhiyun 	}
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8350_AI_FORMATING, iface);
897*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8350_AI_DAC_CONTROL, master);
898*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8350_DAC_LR_RATE, dac_lrc);
899*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8350_ADC_LR_RATE, adc_lrc);
900*4882a593Smuzhiyun 	return 0;
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun 
wm8350_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * codec_dai)903*4882a593Smuzhiyun static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
904*4882a593Smuzhiyun 				struct snd_pcm_hw_params *params,
905*4882a593Smuzhiyun 				struct snd_soc_dai *codec_dai)
906*4882a593Smuzhiyun {
907*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
908*4882a593Smuzhiyun 	struct wm8350_data *wm8350_data = snd_soc_component_get_drvdata(component);
909*4882a593Smuzhiyun 	struct wm8350 *wm8350 = wm8350_data->wm8350;
910*4882a593Smuzhiyun 	u16 iface = snd_soc_component_read(component, WM8350_AI_FORMATING) &
911*4882a593Smuzhiyun 	    ~WM8350_AIF_WL_MASK;
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 	/* bit size */
914*4882a593Smuzhiyun 	switch (params_width(params)) {
915*4882a593Smuzhiyun 	case 16:
916*4882a593Smuzhiyun 		break;
917*4882a593Smuzhiyun 	case 20:
918*4882a593Smuzhiyun 		iface |= 0x1 << 10;
919*4882a593Smuzhiyun 		break;
920*4882a593Smuzhiyun 	case 24:
921*4882a593Smuzhiyun 		iface |= 0x2 << 10;
922*4882a593Smuzhiyun 		break;
923*4882a593Smuzhiyun 	case 32:
924*4882a593Smuzhiyun 		iface |= 0x3 << 10;
925*4882a593Smuzhiyun 		break;
926*4882a593Smuzhiyun 	}
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8350_AI_FORMATING, iface);
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	/* The sloping stopband filter is recommended for use with
931*4882a593Smuzhiyun 	 * lower sample rates to improve performance.
932*4882a593Smuzhiyun 	 */
933*4882a593Smuzhiyun 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
934*4882a593Smuzhiyun 		if (params_rate(params) < 24000)
935*4882a593Smuzhiyun 			wm8350_set_bits(wm8350, WM8350_DAC_MUTE_VOLUME,
936*4882a593Smuzhiyun 					WM8350_DAC_SB_FILT);
937*4882a593Smuzhiyun 		else
938*4882a593Smuzhiyun 			wm8350_clear_bits(wm8350, WM8350_DAC_MUTE_VOLUME,
939*4882a593Smuzhiyun 					  WM8350_DAC_SB_FILT);
940*4882a593Smuzhiyun 	}
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 	return 0;
943*4882a593Smuzhiyun }
944*4882a593Smuzhiyun 
wm8350_mute(struct snd_soc_dai * dai,int mute,int direction)945*4882a593Smuzhiyun static int wm8350_mute(struct snd_soc_dai *dai, int mute, int direction)
946*4882a593Smuzhiyun {
947*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
948*4882a593Smuzhiyun 	unsigned int val;
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun 	if (mute)
951*4882a593Smuzhiyun 		val = WM8350_DAC_MUTE_ENA;
952*4882a593Smuzhiyun 	else
953*4882a593Smuzhiyun 		val = 0;
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA, val);
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 	return 0;
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun /* FLL divisors */
961*4882a593Smuzhiyun struct _fll_div {
962*4882a593Smuzhiyun 	int div;		/* FLL_OUTDIV */
963*4882a593Smuzhiyun 	int n;
964*4882a593Smuzhiyun 	int k;
965*4882a593Smuzhiyun 	int ratio;		/* FLL_FRATIO */
966*4882a593Smuzhiyun };
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun /* The size in bits of the fll divide multiplied by 10
969*4882a593Smuzhiyun  * to allow rounding later */
970*4882a593Smuzhiyun #define FIXED_FLL_SIZE ((1 << 16) * 10)
971*4882a593Smuzhiyun 
fll_factors(struct _fll_div * fll_div,unsigned int input,unsigned int output)972*4882a593Smuzhiyun static inline int fll_factors(struct _fll_div *fll_div, unsigned int input,
973*4882a593Smuzhiyun 			      unsigned int output)
974*4882a593Smuzhiyun {
975*4882a593Smuzhiyun 	u64 Kpart;
976*4882a593Smuzhiyun 	unsigned int t1, t2, K, Nmod;
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 	if (output >= 2815250 && output <= 3125000)
979*4882a593Smuzhiyun 		fll_div->div = 0x4;
980*4882a593Smuzhiyun 	else if (output >= 5625000 && output <= 6250000)
981*4882a593Smuzhiyun 		fll_div->div = 0x3;
982*4882a593Smuzhiyun 	else if (output >= 11250000 && output <= 12500000)
983*4882a593Smuzhiyun 		fll_div->div = 0x2;
984*4882a593Smuzhiyun 	else if (output >= 22500000 && output <= 25000000)
985*4882a593Smuzhiyun 		fll_div->div = 0x1;
986*4882a593Smuzhiyun 	else {
987*4882a593Smuzhiyun 		printk(KERN_ERR "wm8350: fll freq %d out of range\n", output);
988*4882a593Smuzhiyun 		return -EINVAL;
989*4882a593Smuzhiyun 	}
990*4882a593Smuzhiyun 
991*4882a593Smuzhiyun 	if (input > 48000)
992*4882a593Smuzhiyun 		fll_div->ratio = 1;
993*4882a593Smuzhiyun 	else
994*4882a593Smuzhiyun 		fll_div->ratio = 8;
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 	t1 = output * (1 << (fll_div->div + 1));
997*4882a593Smuzhiyun 	t2 = input * fll_div->ratio;
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 	fll_div->n = t1 / t2;
1000*4882a593Smuzhiyun 	Nmod = t1 % t2;
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 	if (Nmod) {
1003*4882a593Smuzhiyun 		Kpart = FIXED_FLL_SIZE * (long long)Nmod;
1004*4882a593Smuzhiyun 		do_div(Kpart, t2);
1005*4882a593Smuzhiyun 		K = Kpart & 0xFFFFFFFF;
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 		/* Check if we need to round */
1008*4882a593Smuzhiyun 		if ((K % 10) >= 5)
1009*4882a593Smuzhiyun 			K += 5;
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 		/* Move down to proper range now rounding is done */
1012*4882a593Smuzhiyun 		K /= 10;
1013*4882a593Smuzhiyun 		fll_div->k = K;
1014*4882a593Smuzhiyun 	} else
1015*4882a593Smuzhiyun 		fll_div->k = 0;
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 	return 0;
1018*4882a593Smuzhiyun }
1019*4882a593Smuzhiyun 
wm8350_set_fll(struct snd_soc_dai * codec_dai,int pll_id,int source,unsigned int freq_in,unsigned int freq_out)1020*4882a593Smuzhiyun static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
1021*4882a593Smuzhiyun 			  int pll_id, int source, unsigned int freq_in,
1022*4882a593Smuzhiyun 			  unsigned int freq_out)
1023*4882a593Smuzhiyun {
1024*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
1025*4882a593Smuzhiyun 	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
1026*4882a593Smuzhiyun 	struct wm8350 *wm8350 = priv->wm8350;
1027*4882a593Smuzhiyun 	struct _fll_div fll_div;
1028*4882a593Smuzhiyun 	int ret = 0;
1029*4882a593Smuzhiyun 	u16 fll_1, fll_4;
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	if (freq_in == priv->fll_freq_in && freq_out == priv->fll_freq_out)
1032*4882a593Smuzhiyun 		return 0;
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun 	/* power down FLL - we need to do this for reconfiguration */
1035*4882a593Smuzhiyun 	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4,
1036*4882a593Smuzhiyun 			  WM8350_FLL_ENA | WM8350_FLL_OSC_ENA);
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun 	if (freq_out == 0 || freq_in == 0)
1039*4882a593Smuzhiyun 		return ret;
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun 	ret = fll_factors(&fll_div, freq_in, freq_out);
1042*4882a593Smuzhiyun 	if (ret < 0)
1043*4882a593Smuzhiyun 		return ret;
1044*4882a593Smuzhiyun 	dev_dbg(wm8350->dev,
1045*4882a593Smuzhiyun 		"FLL in %u FLL out %u N 0x%x K 0x%x div %d ratio %d",
1046*4882a593Smuzhiyun 		freq_in, freq_out, fll_div.n, fll_div.k, fll_div.div,
1047*4882a593Smuzhiyun 		fll_div.ratio);
1048*4882a593Smuzhiyun 
1049*4882a593Smuzhiyun 	/* set up N.K & dividers */
1050*4882a593Smuzhiyun 	fll_1 = snd_soc_component_read(component, WM8350_FLL_CONTROL_1) &
1051*4882a593Smuzhiyun 	    ~(WM8350_FLL_OUTDIV_MASK | WM8350_FLL_RSP_RATE_MASK | 0xc000);
1052*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8350_FLL_CONTROL_1,
1053*4882a593Smuzhiyun 			   fll_1 | (fll_div.div << 8) | 0x50);
1054*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8350_FLL_CONTROL_2,
1055*4882a593Smuzhiyun 			   (fll_div.ratio << 11) | (fll_div.
1056*4882a593Smuzhiyun 						    n & WM8350_FLL_N_MASK));
1057*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8350_FLL_CONTROL_3, fll_div.k);
1058*4882a593Smuzhiyun 	fll_4 = snd_soc_component_read(component, WM8350_FLL_CONTROL_4) &
1059*4882a593Smuzhiyun 	    ~(WM8350_FLL_FRAC | WM8350_FLL_SLOW_LOCK_REF);
1060*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8350_FLL_CONTROL_4,
1061*4882a593Smuzhiyun 			   fll_4 | (fll_div.k ? WM8350_FLL_FRAC : 0) |
1062*4882a593Smuzhiyun 			   (fll_div.ratio == 8 ? WM8350_FLL_SLOW_LOCK_REF : 0));
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun 	/* power FLL on */
1065*4882a593Smuzhiyun 	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_OSC_ENA);
1066*4882a593Smuzhiyun 	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA);
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 	priv->fll_freq_out = freq_out;
1069*4882a593Smuzhiyun 	priv->fll_freq_in = freq_in;
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun 	return 0;
1072*4882a593Smuzhiyun }
1073*4882a593Smuzhiyun 
wm8350_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)1074*4882a593Smuzhiyun static int wm8350_set_bias_level(struct snd_soc_component *component,
1075*4882a593Smuzhiyun 				 enum snd_soc_bias_level level)
1076*4882a593Smuzhiyun {
1077*4882a593Smuzhiyun 	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
1078*4882a593Smuzhiyun 	struct wm8350 *wm8350 = priv->wm8350;
1079*4882a593Smuzhiyun 	struct wm8350_audio_platform_data *platform =
1080*4882a593Smuzhiyun 		wm8350->codec.platform_data;
1081*4882a593Smuzhiyun 	u16 pm1;
1082*4882a593Smuzhiyun 	int ret;
1083*4882a593Smuzhiyun 
1084*4882a593Smuzhiyun 	switch (level) {
1085*4882a593Smuzhiyun 	case SND_SOC_BIAS_ON:
1086*4882a593Smuzhiyun 		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
1087*4882a593Smuzhiyun 		    ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK);
1088*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
1089*4882a593Smuzhiyun 				 pm1 | WM8350_VMID_50K |
1090*4882a593Smuzhiyun 				 platform->codec_current_on << 14);
1091*4882a593Smuzhiyun 		break;
1092*4882a593Smuzhiyun 
1093*4882a593Smuzhiyun 	case SND_SOC_BIAS_PREPARE:
1094*4882a593Smuzhiyun 		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1);
1095*4882a593Smuzhiyun 		pm1 &= ~WM8350_VMID_MASK;
1096*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
1097*4882a593Smuzhiyun 				 pm1 | WM8350_VMID_50K);
1098*4882a593Smuzhiyun 		break;
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	case SND_SOC_BIAS_STANDBY:
1101*4882a593Smuzhiyun 		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
1102*4882a593Smuzhiyun 			ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
1103*4882a593Smuzhiyun 						    priv->supplies);
1104*4882a593Smuzhiyun 			if (ret != 0)
1105*4882a593Smuzhiyun 				return ret;
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun 			/* Enable the system clock */
1108*4882a593Smuzhiyun 			wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4,
1109*4882a593Smuzhiyun 					WM8350_SYSCLK_ENA);
1110*4882a593Smuzhiyun 
1111*4882a593Smuzhiyun 			/* mute DAC & outputs */
1112*4882a593Smuzhiyun 			wm8350_set_bits(wm8350, WM8350_DAC_MUTE,
1113*4882a593Smuzhiyun 					WM8350_DAC_MUTE_ENA);
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 			/* discharge cap memory */
1116*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
1117*4882a593Smuzhiyun 					 platform->dis_out1 |
1118*4882a593Smuzhiyun 					 (platform->dis_out2 << 2) |
1119*4882a593Smuzhiyun 					 (platform->dis_out3 << 4) |
1120*4882a593Smuzhiyun 					 (platform->dis_out4 << 6));
1121*4882a593Smuzhiyun 
1122*4882a593Smuzhiyun 			/* wait for discharge */
1123*4882a593Smuzhiyun 			schedule_timeout_interruptible(msecs_to_jiffies
1124*4882a593Smuzhiyun 						       (platform->
1125*4882a593Smuzhiyun 							cap_discharge_msecs));
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun 			/* enable antipop */
1128*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
1129*4882a593Smuzhiyun 					 (platform->vmid_s_curve << 8));
1130*4882a593Smuzhiyun 
1131*4882a593Smuzhiyun 			/* ramp up vmid */
1132*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
1133*4882a593Smuzhiyun 					 (platform->
1134*4882a593Smuzhiyun 					  codec_current_charge << 14) |
1135*4882a593Smuzhiyun 					 WM8350_VMID_5K | WM8350_VMIDEN |
1136*4882a593Smuzhiyun 					 WM8350_VBUFEN);
1137*4882a593Smuzhiyun 
1138*4882a593Smuzhiyun 			/* wait for vmid */
1139*4882a593Smuzhiyun 			schedule_timeout_interruptible(msecs_to_jiffies
1140*4882a593Smuzhiyun 						       (platform->
1141*4882a593Smuzhiyun 							vmid_charge_msecs));
1142*4882a593Smuzhiyun 
1143*4882a593Smuzhiyun 			/* turn on vmid 300k  */
1144*4882a593Smuzhiyun 			pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
1145*4882a593Smuzhiyun 			    ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK);
1146*4882a593Smuzhiyun 			pm1 |= WM8350_VMID_300K |
1147*4882a593Smuzhiyun 				(platform->codec_current_standby << 14);
1148*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
1149*4882a593Smuzhiyun 					 pm1);
1150*4882a593Smuzhiyun 
1151*4882a593Smuzhiyun 
1152*4882a593Smuzhiyun 			/* enable analogue bias */
1153*4882a593Smuzhiyun 			pm1 |= WM8350_BIASEN;
1154*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 			/* disable antipop */
1157*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 0);
1158*4882a593Smuzhiyun 
1159*4882a593Smuzhiyun 		} else {
1160*4882a593Smuzhiyun 			/* turn on vmid 300k and reduce current */
1161*4882a593Smuzhiyun 			pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
1162*4882a593Smuzhiyun 			    ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK);
1163*4882a593Smuzhiyun 			wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
1164*4882a593Smuzhiyun 					 pm1 | WM8350_VMID_300K |
1165*4882a593Smuzhiyun 					 (platform->
1166*4882a593Smuzhiyun 					  codec_current_standby << 14));
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun 		}
1169*4882a593Smuzhiyun 		break;
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 	case SND_SOC_BIAS_OFF:
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun 		/* mute DAC & enable outputs */
1174*4882a593Smuzhiyun 		wm8350_set_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA);
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_3,
1177*4882a593Smuzhiyun 				WM8350_OUT1L_ENA | WM8350_OUT1R_ENA |
1178*4882a593Smuzhiyun 				WM8350_OUT2L_ENA | WM8350_OUT2R_ENA);
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 		/* enable anti pop S curve */
1181*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
1182*4882a593Smuzhiyun 				 (platform->vmid_s_curve << 8));
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 		/* turn off vmid  */
1185*4882a593Smuzhiyun 		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
1186*4882a593Smuzhiyun 		    ~WM8350_VMIDEN;
1187*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);
1188*4882a593Smuzhiyun 
1189*4882a593Smuzhiyun 		/* wait */
1190*4882a593Smuzhiyun 		schedule_timeout_interruptible(msecs_to_jiffies
1191*4882a593Smuzhiyun 					       (platform->
1192*4882a593Smuzhiyun 						vmid_discharge_msecs));
1193*4882a593Smuzhiyun 
1194*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL,
1195*4882a593Smuzhiyun 				 (platform->vmid_s_curve << 8) |
1196*4882a593Smuzhiyun 				 platform->dis_out1 |
1197*4882a593Smuzhiyun 				 (platform->dis_out2 << 2) |
1198*4882a593Smuzhiyun 				 (platform->dis_out3 << 4) |
1199*4882a593Smuzhiyun 				 (platform->dis_out4 << 6));
1200*4882a593Smuzhiyun 
1201*4882a593Smuzhiyun 		/* turn off VBuf and drain */
1202*4882a593Smuzhiyun 		pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) &
1203*4882a593Smuzhiyun 		    ~(WM8350_VBUFEN | WM8350_VMID_MASK);
1204*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1,
1205*4882a593Smuzhiyun 				 pm1 | WM8350_OUTPUT_DRAIN_EN);
1206*4882a593Smuzhiyun 
1207*4882a593Smuzhiyun 		/* wait */
1208*4882a593Smuzhiyun 		schedule_timeout_interruptible(msecs_to_jiffies
1209*4882a593Smuzhiyun 					       (platform->drain_msecs));
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 		pm1 &= ~WM8350_BIASEN;
1212*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1);
1213*4882a593Smuzhiyun 
1214*4882a593Smuzhiyun 		/* disable anti-pop */
1215*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 0);
1216*4882a593Smuzhiyun 
1217*4882a593Smuzhiyun 		wm8350_clear_bits(wm8350, WM8350_LOUT1_VOLUME,
1218*4882a593Smuzhiyun 				  WM8350_OUT1L_ENA);
1219*4882a593Smuzhiyun 		wm8350_clear_bits(wm8350, WM8350_ROUT1_VOLUME,
1220*4882a593Smuzhiyun 				  WM8350_OUT1R_ENA);
1221*4882a593Smuzhiyun 		wm8350_clear_bits(wm8350, WM8350_LOUT2_VOLUME,
1222*4882a593Smuzhiyun 				  WM8350_OUT2L_ENA);
1223*4882a593Smuzhiyun 		wm8350_clear_bits(wm8350, WM8350_ROUT2_VOLUME,
1224*4882a593Smuzhiyun 				  WM8350_OUT2R_ENA);
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 		/* disable clock gen */
1227*4882a593Smuzhiyun 		wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4,
1228*4882a593Smuzhiyun 				  WM8350_SYSCLK_ENA);
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 		regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
1231*4882a593Smuzhiyun 				       priv->supplies);
1232*4882a593Smuzhiyun 		break;
1233*4882a593Smuzhiyun 	}
1234*4882a593Smuzhiyun 	return 0;
1235*4882a593Smuzhiyun }
1236*4882a593Smuzhiyun 
wm8350_hp_work(struct wm8350_data * priv,struct wm8350_jack_data * jack,u16 mask)1237*4882a593Smuzhiyun static void wm8350_hp_work(struct wm8350_data *priv,
1238*4882a593Smuzhiyun 			   struct wm8350_jack_data *jack,
1239*4882a593Smuzhiyun 			   u16 mask)
1240*4882a593Smuzhiyun {
1241*4882a593Smuzhiyun 	struct wm8350 *wm8350 = priv->wm8350;
1242*4882a593Smuzhiyun 	u16 reg;
1243*4882a593Smuzhiyun 	int report;
1244*4882a593Smuzhiyun 
1245*4882a593Smuzhiyun 	reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
1246*4882a593Smuzhiyun 	if (reg & mask)
1247*4882a593Smuzhiyun 		report = jack->report;
1248*4882a593Smuzhiyun 	else
1249*4882a593Smuzhiyun 		report = 0;
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun 	snd_soc_jack_report(jack->jack, report, jack->report);
1252*4882a593Smuzhiyun 
1253*4882a593Smuzhiyun }
1254*4882a593Smuzhiyun 
wm8350_hpl_work(struct work_struct * work)1255*4882a593Smuzhiyun static void wm8350_hpl_work(struct work_struct *work)
1256*4882a593Smuzhiyun {
1257*4882a593Smuzhiyun 	struct wm8350_data *priv =
1258*4882a593Smuzhiyun 	    container_of(work, struct wm8350_data, hpl.work.work);
1259*4882a593Smuzhiyun 
1260*4882a593Smuzhiyun 	wm8350_hp_work(priv, &priv->hpl, WM8350_JACK_L_LVL);
1261*4882a593Smuzhiyun }
1262*4882a593Smuzhiyun 
wm8350_hpr_work(struct work_struct * work)1263*4882a593Smuzhiyun static void wm8350_hpr_work(struct work_struct *work)
1264*4882a593Smuzhiyun {
1265*4882a593Smuzhiyun 	struct wm8350_data *priv =
1266*4882a593Smuzhiyun 	    container_of(work, struct wm8350_data, hpr.work.work);
1267*4882a593Smuzhiyun 
1268*4882a593Smuzhiyun 	wm8350_hp_work(priv, &priv->hpr, WM8350_JACK_R_LVL);
1269*4882a593Smuzhiyun }
1270*4882a593Smuzhiyun 
wm8350_hpl_jack_handler(int irq,void * data)1271*4882a593Smuzhiyun static irqreturn_t wm8350_hpl_jack_handler(int irq, void *data)
1272*4882a593Smuzhiyun {
1273*4882a593Smuzhiyun 	struct wm8350_data *priv = data;
1274*4882a593Smuzhiyun 	struct wm8350 *wm8350 = priv->wm8350;
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun #ifndef CONFIG_SND_SOC_WM8350_MODULE
1277*4882a593Smuzhiyun 	trace_snd_soc_jack_irq("WM8350 HPL");
1278*4882a593Smuzhiyun #endif
1279*4882a593Smuzhiyun 
1280*4882a593Smuzhiyun 	if (device_may_wakeup(wm8350->dev))
1281*4882a593Smuzhiyun 		pm_wakeup_event(wm8350->dev, 250);
1282*4882a593Smuzhiyun 
1283*4882a593Smuzhiyun 	queue_delayed_work(system_power_efficient_wq,
1284*4882a593Smuzhiyun 			   &priv->hpl.work, msecs_to_jiffies(200));
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 	return IRQ_HANDLED;
1287*4882a593Smuzhiyun }
1288*4882a593Smuzhiyun 
wm8350_hpr_jack_handler(int irq,void * data)1289*4882a593Smuzhiyun static irqreturn_t wm8350_hpr_jack_handler(int irq, void *data)
1290*4882a593Smuzhiyun {
1291*4882a593Smuzhiyun 	struct wm8350_data *priv = data;
1292*4882a593Smuzhiyun 	struct wm8350 *wm8350 = priv->wm8350;
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun #ifndef CONFIG_SND_SOC_WM8350_MODULE
1295*4882a593Smuzhiyun 	trace_snd_soc_jack_irq("WM8350 HPR");
1296*4882a593Smuzhiyun #endif
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun 	if (device_may_wakeup(wm8350->dev))
1299*4882a593Smuzhiyun 		pm_wakeup_event(wm8350->dev, 250);
1300*4882a593Smuzhiyun 
1301*4882a593Smuzhiyun 	queue_delayed_work(system_power_efficient_wq,
1302*4882a593Smuzhiyun 			   &priv->hpr.work, msecs_to_jiffies(200));
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun 	return IRQ_HANDLED;
1305*4882a593Smuzhiyun }
1306*4882a593Smuzhiyun 
1307*4882a593Smuzhiyun /**
1308*4882a593Smuzhiyun  * wm8350_hp_jack_detect - Enable headphone jack detection.
1309*4882a593Smuzhiyun  *
1310*4882a593Smuzhiyun  * @component:  WM8350 component
1311*4882a593Smuzhiyun  * @which:  left or right jack detect signal
1312*4882a593Smuzhiyun  * @jack:   jack to report detection events on
1313*4882a593Smuzhiyun  * @report: value to report
1314*4882a593Smuzhiyun  *
1315*4882a593Smuzhiyun  * Enables the headphone jack detection of the WM8350.  If no report
1316*4882a593Smuzhiyun  * is specified then detection is disabled.
1317*4882a593Smuzhiyun  */
wm8350_hp_jack_detect(struct snd_soc_component * component,enum wm8350_jack which,struct snd_soc_jack * jack,int report)1318*4882a593Smuzhiyun int wm8350_hp_jack_detect(struct snd_soc_component *component, enum wm8350_jack which,
1319*4882a593Smuzhiyun 			  struct snd_soc_jack *jack, int report)
1320*4882a593Smuzhiyun {
1321*4882a593Smuzhiyun 	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
1322*4882a593Smuzhiyun 	struct wm8350 *wm8350 = priv->wm8350;
1323*4882a593Smuzhiyun 	int ena;
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 	switch (which) {
1326*4882a593Smuzhiyun 	case WM8350_JDL:
1327*4882a593Smuzhiyun 		priv->hpl.jack = jack;
1328*4882a593Smuzhiyun 		priv->hpl.report = report;
1329*4882a593Smuzhiyun 		ena = WM8350_JDL_ENA;
1330*4882a593Smuzhiyun 		break;
1331*4882a593Smuzhiyun 
1332*4882a593Smuzhiyun 	case WM8350_JDR:
1333*4882a593Smuzhiyun 		priv->hpr.jack = jack;
1334*4882a593Smuzhiyun 		priv->hpr.report = report;
1335*4882a593Smuzhiyun 		ena = WM8350_JDR_ENA;
1336*4882a593Smuzhiyun 		break;
1337*4882a593Smuzhiyun 
1338*4882a593Smuzhiyun 	default:
1339*4882a593Smuzhiyun 		return -EINVAL;
1340*4882a593Smuzhiyun 	}
1341*4882a593Smuzhiyun 
1342*4882a593Smuzhiyun 	if (report) {
1343*4882a593Smuzhiyun 		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
1344*4882a593Smuzhiyun 		wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena);
1345*4882a593Smuzhiyun 	} else {
1346*4882a593Smuzhiyun 		wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, ena);
1347*4882a593Smuzhiyun 	}
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun 	/* Sync status */
1350*4882a593Smuzhiyun 	switch (which) {
1351*4882a593Smuzhiyun 	case WM8350_JDL:
1352*4882a593Smuzhiyun 		wm8350_hpl_jack_handler(0, priv);
1353*4882a593Smuzhiyun 		break;
1354*4882a593Smuzhiyun 	case WM8350_JDR:
1355*4882a593Smuzhiyun 		wm8350_hpr_jack_handler(0, priv);
1356*4882a593Smuzhiyun 		break;
1357*4882a593Smuzhiyun 	}
1358*4882a593Smuzhiyun 
1359*4882a593Smuzhiyun 	return 0;
1360*4882a593Smuzhiyun }
1361*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(wm8350_hp_jack_detect);
1362*4882a593Smuzhiyun 
wm8350_mic_handler(int irq,void * data)1363*4882a593Smuzhiyun static irqreturn_t wm8350_mic_handler(int irq, void *data)
1364*4882a593Smuzhiyun {
1365*4882a593Smuzhiyun 	struct wm8350_data *priv = data;
1366*4882a593Smuzhiyun 	struct wm8350 *wm8350 = priv->wm8350;
1367*4882a593Smuzhiyun 	u16 reg;
1368*4882a593Smuzhiyun 	int report = 0;
1369*4882a593Smuzhiyun 
1370*4882a593Smuzhiyun #ifndef CONFIG_SND_SOC_WM8350_MODULE
1371*4882a593Smuzhiyun 	trace_snd_soc_jack_irq("WM8350 mic");
1372*4882a593Smuzhiyun #endif
1373*4882a593Smuzhiyun 
1374*4882a593Smuzhiyun 	reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
1375*4882a593Smuzhiyun 	if (reg & WM8350_JACK_MICSCD_LVL)
1376*4882a593Smuzhiyun 		report |= priv->mic.short_report;
1377*4882a593Smuzhiyun 	if (reg & WM8350_JACK_MICSD_LVL)
1378*4882a593Smuzhiyun 		report |= priv->mic.report;
1379*4882a593Smuzhiyun 
1380*4882a593Smuzhiyun 	snd_soc_jack_report(priv->mic.jack, report,
1381*4882a593Smuzhiyun 			    priv->mic.report | priv->mic.short_report);
1382*4882a593Smuzhiyun 
1383*4882a593Smuzhiyun 	return IRQ_HANDLED;
1384*4882a593Smuzhiyun }
1385*4882a593Smuzhiyun 
1386*4882a593Smuzhiyun /**
1387*4882a593Smuzhiyun  * wm8350_mic_jack_detect - Enable microphone jack detection.
1388*4882a593Smuzhiyun  *
1389*4882a593Smuzhiyun  * @component:         WM8350 component
1390*4882a593Smuzhiyun  * @jack:          jack to report detection events on
1391*4882a593Smuzhiyun  * @detect_report: value to report when presence detected
1392*4882a593Smuzhiyun  * @short_report:  value to report when microphone short detected
1393*4882a593Smuzhiyun  *
1394*4882a593Smuzhiyun  * Enables the microphone jack detection of the WM8350.  If both reports
1395*4882a593Smuzhiyun  * are specified as zero then detection is disabled.
1396*4882a593Smuzhiyun  */
wm8350_mic_jack_detect(struct snd_soc_component * component,struct snd_soc_jack * jack,int detect_report,int short_report)1397*4882a593Smuzhiyun int wm8350_mic_jack_detect(struct snd_soc_component *component,
1398*4882a593Smuzhiyun 			   struct snd_soc_jack *jack,
1399*4882a593Smuzhiyun 			   int detect_report, int short_report)
1400*4882a593Smuzhiyun {
1401*4882a593Smuzhiyun 	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
1402*4882a593Smuzhiyun 	struct wm8350 *wm8350 = priv->wm8350;
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 	priv->mic.jack = jack;
1405*4882a593Smuzhiyun 	priv->mic.report = detect_report;
1406*4882a593Smuzhiyun 	priv->mic.short_report = short_report;
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun 	if (detect_report || short_report) {
1409*4882a593Smuzhiyun 		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
1410*4882a593Smuzhiyun 		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_1,
1411*4882a593Smuzhiyun 				WM8350_MIC_DET_ENA);
1412*4882a593Smuzhiyun 	} else {
1413*4882a593Smuzhiyun 		wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_1,
1414*4882a593Smuzhiyun 				  WM8350_MIC_DET_ENA);
1415*4882a593Smuzhiyun 	}
1416*4882a593Smuzhiyun 
1417*4882a593Smuzhiyun 	return 0;
1418*4882a593Smuzhiyun }
1419*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect);
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun #define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
1422*4882a593Smuzhiyun 
1423*4882a593Smuzhiyun #define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
1424*4882a593Smuzhiyun 			SNDRV_PCM_FMTBIT_S20_3LE |\
1425*4882a593Smuzhiyun 			SNDRV_PCM_FMTBIT_S24_LE)
1426*4882a593Smuzhiyun 
1427*4882a593Smuzhiyun static const struct snd_soc_dai_ops wm8350_dai_ops = {
1428*4882a593Smuzhiyun 	 .hw_params	= wm8350_pcm_hw_params,
1429*4882a593Smuzhiyun 	 .mute_stream	= wm8350_mute,
1430*4882a593Smuzhiyun 	 .set_fmt	= wm8350_set_dai_fmt,
1431*4882a593Smuzhiyun 	 .set_sysclk	= wm8350_set_dai_sysclk,
1432*4882a593Smuzhiyun 	 .set_pll	= wm8350_set_fll,
1433*4882a593Smuzhiyun 	 .set_clkdiv	= wm8350_set_clkdiv,
1434*4882a593Smuzhiyun 	 .no_capture_mute = 1,
1435*4882a593Smuzhiyun };
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun static struct snd_soc_dai_driver wm8350_dai = {
1438*4882a593Smuzhiyun 	.name = "wm8350-hifi",
1439*4882a593Smuzhiyun 	.playback = {
1440*4882a593Smuzhiyun 		.stream_name = "Playback",
1441*4882a593Smuzhiyun 		.channels_min = 1,
1442*4882a593Smuzhiyun 		.channels_max = 2,
1443*4882a593Smuzhiyun 		.rates = WM8350_RATES,
1444*4882a593Smuzhiyun 		.formats = WM8350_FORMATS,
1445*4882a593Smuzhiyun 	},
1446*4882a593Smuzhiyun 	.capture = {
1447*4882a593Smuzhiyun 		 .stream_name = "Capture",
1448*4882a593Smuzhiyun 		 .channels_min = 1,
1449*4882a593Smuzhiyun 		 .channels_max = 2,
1450*4882a593Smuzhiyun 		 .rates = WM8350_RATES,
1451*4882a593Smuzhiyun 		 .formats = WM8350_FORMATS,
1452*4882a593Smuzhiyun 	 },
1453*4882a593Smuzhiyun 	.ops = &wm8350_dai_ops,
1454*4882a593Smuzhiyun };
1455*4882a593Smuzhiyun 
wm8350_component_probe(struct snd_soc_component * component)1456*4882a593Smuzhiyun static  int wm8350_component_probe(struct snd_soc_component *component)
1457*4882a593Smuzhiyun {
1458*4882a593Smuzhiyun 	struct wm8350 *wm8350 = dev_get_platdata(component->dev);
1459*4882a593Smuzhiyun 	struct wm8350_data *priv;
1460*4882a593Smuzhiyun 	struct wm8350_output *out1;
1461*4882a593Smuzhiyun 	struct wm8350_output *out2;
1462*4882a593Smuzhiyun 	int ret, i;
1463*4882a593Smuzhiyun 
1464*4882a593Smuzhiyun 	if (wm8350->codec.platform_data == NULL) {
1465*4882a593Smuzhiyun 		dev_err(component->dev, "No audio platform data supplied\n");
1466*4882a593Smuzhiyun 		return -EINVAL;
1467*4882a593Smuzhiyun 	}
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun 	priv = devm_kzalloc(component->dev, sizeof(struct wm8350_data),
1470*4882a593Smuzhiyun 			    GFP_KERNEL);
1471*4882a593Smuzhiyun 	if (priv == NULL)
1472*4882a593Smuzhiyun 		return -ENOMEM;
1473*4882a593Smuzhiyun 
1474*4882a593Smuzhiyun 	snd_soc_component_init_regmap(component, wm8350->regmap);
1475*4882a593Smuzhiyun 	snd_soc_component_set_drvdata(component, priv);
1476*4882a593Smuzhiyun 
1477*4882a593Smuzhiyun 	priv->wm8350 = wm8350;
1478*4882a593Smuzhiyun 
1479*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
1480*4882a593Smuzhiyun 		priv->supplies[i].supply = supply_names[i];
1481*4882a593Smuzhiyun 
1482*4882a593Smuzhiyun 	ret = devm_regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
1483*4882a593Smuzhiyun 				 priv->supplies);
1484*4882a593Smuzhiyun 	if (ret != 0)
1485*4882a593Smuzhiyun 		return ret;
1486*4882a593Smuzhiyun 
1487*4882a593Smuzhiyun 	/* Put the codec into reset if it wasn't already */
1488*4882a593Smuzhiyun 	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
1489*4882a593Smuzhiyun 
1490*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&priv->pga_work, wm8350_pga_work);
1491*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&priv->hpl.work, wm8350_hpl_work);
1492*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&priv->hpr.work, wm8350_hpr_work);
1493*4882a593Smuzhiyun 
1494*4882a593Smuzhiyun 	/* Enable the codec */
1495*4882a593Smuzhiyun 	wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
1496*4882a593Smuzhiyun 
1497*4882a593Smuzhiyun 	/* Enable robust clocking mode in ADC */
1498*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8350_SECURITY, 0xa7);
1499*4882a593Smuzhiyun 	snd_soc_component_write(component, 0xde, 0x13);
1500*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8350_SECURITY, 0);
1501*4882a593Smuzhiyun 
1502*4882a593Smuzhiyun 	/* read OUT1 & OUT2 volumes */
1503*4882a593Smuzhiyun 	out1 = &priv->out1;
1504*4882a593Smuzhiyun 	out2 = &priv->out2;
1505*4882a593Smuzhiyun 	out1->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME) &
1506*4882a593Smuzhiyun 			  WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
1507*4882a593Smuzhiyun 	out1->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME) &
1508*4882a593Smuzhiyun 			   WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
1509*4882a593Smuzhiyun 	out2->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT2_VOLUME) &
1510*4882a593Smuzhiyun 			  WM8350_OUT2L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT;
1511*4882a593Smuzhiyun 	out2->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT2_VOLUME) &
1512*4882a593Smuzhiyun 			   WM8350_OUT2R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT;
1513*4882a593Smuzhiyun 	wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, 0);
1514*4882a593Smuzhiyun 	wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, 0);
1515*4882a593Smuzhiyun 	wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME, 0);
1516*4882a593Smuzhiyun 	wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, 0);
1517*4882a593Smuzhiyun 
1518*4882a593Smuzhiyun 	/* Latch VU bits & mute */
1519*4882a593Smuzhiyun 	wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME,
1520*4882a593Smuzhiyun 			WM8350_OUT1_VU | WM8350_OUT1L_MUTE);
1521*4882a593Smuzhiyun 	wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME,
1522*4882a593Smuzhiyun 			WM8350_OUT2_VU | WM8350_OUT2L_MUTE);
1523*4882a593Smuzhiyun 	wm8350_set_bits(wm8350, WM8350_ROUT1_VOLUME,
1524*4882a593Smuzhiyun 			WM8350_OUT1_VU | WM8350_OUT1R_MUTE);
1525*4882a593Smuzhiyun 	wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME,
1526*4882a593Smuzhiyun 			WM8350_OUT2_VU | WM8350_OUT2R_MUTE);
1527*4882a593Smuzhiyun 
1528*4882a593Smuzhiyun 	/* Make sure AIF tristating is disabled by default */
1529*4882a593Smuzhiyun 	wm8350_clear_bits(wm8350, WM8350_AI_FORMATING, WM8350_AIF_TRI);
1530*4882a593Smuzhiyun 
1531*4882a593Smuzhiyun 	/* Make sure we've got a sane companding setup too */
1532*4882a593Smuzhiyun 	wm8350_clear_bits(wm8350, WM8350_ADC_DAC_COMP,
1533*4882a593Smuzhiyun 			  WM8350_DAC_COMP | WM8350_LOOPBACK);
1534*4882a593Smuzhiyun 
1535*4882a593Smuzhiyun 	/* Make sure jack detect is disabled to start off with */
1536*4882a593Smuzhiyun 	wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
1537*4882a593Smuzhiyun 			  WM8350_JDL_ENA | WM8350_JDR_ENA);
1538*4882a593Smuzhiyun 
1539*4882a593Smuzhiyun 	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L,
1540*4882a593Smuzhiyun 			    wm8350_hpl_jack_handler, 0, "Left jack detect",
1541*4882a593Smuzhiyun 			    priv);
1542*4882a593Smuzhiyun 	if (ret != 0)
1543*4882a593Smuzhiyun 		goto err;
1544*4882a593Smuzhiyun 
1545*4882a593Smuzhiyun 	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R,
1546*4882a593Smuzhiyun 			    wm8350_hpr_jack_handler, 0, "Right jack detect",
1547*4882a593Smuzhiyun 			    priv);
1548*4882a593Smuzhiyun 	if (ret != 0)
1549*4882a593Smuzhiyun 		goto free_jck_det_l;
1550*4882a593Smuzhiyun 
1551*4882a593Smuzhiyun 	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD,
1552*4882a593Smuzhiyun 			    wm8350_mic_handler, 0, "Microphone short", priv);
1553*4882a593Smuzhiyun 	if (ret != 0)
1554*4882a593Smuzhiyun 		goto free_jck_det_r;
1555*4882a593Smuzhiyun 
1556*4882a593Smuzhiyun 	ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD,
1557*4882a593Smuzhiyun 			    wm8350_mic_handler, 0, "Microphone detect", priv);
1558*4882a593Smuzhiyun 	if (ret != 0)
1559*4882a593Smuzhiyun 		goto free_micscd;
1560*4882a593Smuzhiyun 
1561*4882a593Smuzhiyun 	return 0;
1562*4882a593Smuzhiyun 
1563*4882a593Smuzhiyun free_micscd:
1564*4882a593Smuzhiyun 	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, priv);
1565*4882a593Smuzhiyun free_jck_det_r:
1566*4882a593Smuzhiyun 	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv);
1567*4882a593Smuzhiyun free_jck_det_l:
1568*4882a593Smuzhiyun 	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv);
1569*4882a593Smuzhiyun err:
1570*4882a593Smuzhiyun 	return ret;
1571*4882a593Smuzhiyun }
1572*4882a593Smuzhiyun 
wm8350_component_remove(struct snd_soc_component * component)1573*4882a593Smuzhiyun static void wm8350_component_remove(struct snd_soc_component *component)
1574*4882a593Smuzhiyun {
1575*4882a593Smuzhiyun 	struct wm8350_data *priv = snd_soc_component_get_drvdata(component);
1576*4882a593Smuzhiyun 	struct wm8350 *wm8350 = dev_get_platdata(component->dev);
1577*4882a593Smuzhiyun 
1578*4882a593Smuzhiyun 	wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
1579*4882a593Smuzhiyun 			  WM8350_JDL_ENA | WM8350_JDR_ENA);
1580*4882a593Smuzhiyun 	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
1581*4882a593Smuzhiyun 
1582*4882a593Smuzhiyun 	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICD, priv);
1583*4882a593Smuzhiyun 	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, priv);
1584*4882a593Smuzhiyun 	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv);
1585*4882a593Smuzhiyun 	wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv);
1586*4882a593Smuzhiyun 
1587*4882a593Smuzhiyun 	priv->hpl.jack = NULL;
1588*4882a593Smuzhiyun 	priv->hpr.jack = NULL;
1589*4882a593Smuzhiyun 	priv->mic.jack = NULL;
1590*4882a593Smuzhiyun 
1591*4882a593Smuzhiyun 	cancel_delayed_work_sync(&priv->hpl.work);
1592*4882a593Smuzhiyun 	cancel_delayed_work_sync(&priv->hpr.work);
1593*4882a593Smuzhiyun 
1594*4882a593Smuzhiyun 	/* if there was any work waiting then we run it now and
1595*4882a593Smuzhiyun 	 * wait for its completion */
1596*4882a593Smuzhiyun 	flush_delayed_work(&priv->pga_work);
1597*4882a593Smuzhiyun 
1598*4882a593Smuzhiyun 	wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
1599*4882a593Smuzhiyun }
1600*4882a593Smuzhiyun 
1601*4882a593Smuzhiyun static const struct snd_soc_component_driver soc_component_dev_wm8350 = {
1602*4882a593Smuzhiyun 	.probe			= wm8350_component_probe,
1603*4882a593Smuzhiyun 	.remove			= wm8350_component_remove,
1604*4882a593Smuzhiyun 	.set_bias_level		= wm8350_set_bias_level,
1605*4882a593Smuzhiyun 	.controls		= wm8350_snd_controls,
1606*4882a593Smuzhiyun 	.num_controls		= ARRAY_SIZE(wm8350_snd_controls),
1607*4882a593Smuzhiyun 	.dapm_widgets		= wm8350_dapm_widgets,
1608*4882a593Smuzhiyun 	.num_dapm_widgets	= ARRAY_SIZE(wm8350_dapm_widgets),
1609*4882a593Smuzhiyun 	.dapm_routes		= wm8350_dapm_routes,
1610*4882a593Smuzhiyun 	.num_dapm_routes	= ARRAY_SIZE(wm8350_dapm_routes),
1611*4882a593Smuzhiyun 	.suspend_bias_off	= 1,
1612*4882a593Smuzhiyun 	.idle_bias_on		= 1,
1613*4882a593Smuzhiyun 	.use_pmdown_time	= 1,
1614*4882a593Smuzhiyun 	.endianness		= 1,
1615*4882a593Smuzhiyun 	.non_legacy_dai_naming	= 1,
1616*4882a593Smuzhiyun };
1617*4882a593Smuzhiyun 
wm8350_probe(struct platform_device * pdev)1618*4882a593Smuzhiyun static int wm8350_probe(struct platform_device *pdev)
1619*4882a593Smuzhiyun {
1620*4882a593Smuzhiyun 	return devm_snd_soc_register_component(&pdev->dev,
1621*4882a593Smuzhiyun 			&soc_component_dev_wm8350,
1622*4882a593Smuzhiyun 			&wm8350_dai, 1);
1623*4882a593Smuzhiyun }
1624*4882a593Smuzhiyun 
1625*4882a593Smuzhiyun static struct platform_driver wm8350_codec_driver = {
1626*4882a593Smuzhiyun 	.driver = {
1627*4882a593Smuzhiyun 		   .name = "wm8350-codec",
1628*4882a593Smuzhiyun 		   },
1629*4882a593Smuzhiyun 	.probe = wm8350_probe,
1630*4882a593Smuzhiyun };
1631*4882a593Smuzhiyun 
1632*4882a593Smuzhiyun module_platform_driver(wm8350_codec_driver);
1633*4882a593Smuzhiyun 
1634*4882a593Smuzhiyun MODULE_DESCRIPTION("ASoC WM8350 driver");
1635*4882a593Smuzhiyun MODULE_AUTHOR("Liam Girdwood");
1636*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1637*4882a593Smuzhiyun MODULE_ALIAS("platform:wm8350-codec");
1638