xref: /OK3568_Linux_fs/kernel/sound/soc/codecs/wm8753.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * wm8753.c  --  WM8753 ALSA Soc Audio driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2003-11 Wolfson Microelectronics PLC.
6*4882a593Smuzhiyun  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Notes:
9*4882a593Smuzhiyun  *  The WM8753 is a low power, high quality stereo codec with integrated PCM
10*4882a593Smuzhiyun  *  codec designed for portable digital telephony applications.
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * Dual DAI:-
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * This driver support 2 DAI PCM's. This makes the default PCM available for
15*4882a593Smuzhiyun  * HiFi audio (e.g. MP3, ogg) playback/capture and the other PCM available for
16*4882a593Smuzhiyun  * voice.
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  * Please note that the voice PCM can be connected directly to a Bluetooth
19*4882a593Smuzhiyun  * codec or GSM modem and thus cannot be read or written to, although it is
20*4882a593Smuzhiyun  * available to be configured with snd_hw_params(), etc and kcontrols in the
21*4882a593Smuzhiyun  * normal alsa manner.
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * Fast DAI switching:-
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  * The driver can now fast switch between the DAI configurations via a
26*4882a593Smuzhiyun  * an alsa kcontrol. This allows the PCM to remain open.
27*4882a593Smuzhiyun  */
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #include <linux/module.h>
30*4882a593Smuzhiyun #include <linux/kernel.h>
31*4882a593Smuzhiyun #include <linux/init.h>
32*4882a593Smuzhiyun #include <linux/delay.h>
33*4882a593Smuzhiyun #include <linux/pm.h>
34*4882a593Smuzhiyun #include <linux/i2c.h>
35*4882a593Smuzhiyun #include <linux/of_device.h>
36*4882a593Smuzhiyun #include <linux/regmap.h>
37*4882a593Smuzhiyun #include <linux/spi/spi.h>
38*4882a593Smuzhiyun #include <linux/slab.h>
39*4882a593Smuzhiyun #include <sound/core.h>
40*4882a593Smuzhiyun #include <sound/pcm.h>
41*4882a593Smuzhiyun #include <sound/pcm_params.h>
42*4882a593Smuzhiyun #include <sound/soc.h>
43*4882a593Smuzhiyun #include <sound/initval.h>
44*4882a593Smuzhiyun #include <sound/tlv.h>
45*4882a593Smuzhiyun #include <asm/div64.h>
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #include "wm8753.h"
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun static int caps_charge = 2000;
50*4882a593Smuzhiyun module_param(caps_charge, int, 0);
51*4882a593Smuzhiyun MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun static int wm8753_hifi_write_dai_fmt(struct snd_soc_component *component,
54*4882a593Smuzhiyun 		unsigned int fmt);
55*4882a593Smuzhiyun static int wm8753_voice_write_dai_fmt(struct snd_soc_component *component,
56*4882a593Smuzhiyun 		unsigned int fmt);
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /*
59*4882a593Smuzhiyun  * wm8753 register cache
60*4882a593Smuzhiyun  * We can't read the WM8753 register space when we
61*4882a593Smuzhiyun  * are using 2 wire for device control, so we cache them instead.
62*4882a593Smuzhiyun  */
63*4882a593Smuzhiyun static const struct reg_default wm8753_reg_defaults[] = {
64*4882a593Smuzhiyun 	{ 0x00, 0x0000 },
65*4882a593Smuzhiyun 	{ 0x01, 0x0008 },
66*4882a593Smuzhiyun 	{ 0x02, 0x0000 },
67*4882a593Smuzhiyun 	{ 0x03, 0x000a },
68*4882a593Smuzhiyun 	{ 0x04, 0x000a },
69*4882a593Smuzhiyun 	{ 0x05, 0x0033 },
70*4882a593Smuzhiyun 	{ 0x06, 0x0000 },
71*4882a593Smuzhiyun 	{ 0x07, 0x0007 },
72*4882a593Smuzhiyun 	{ 0x08, 0x00ff },
73*4882a593Smuzhiyun 	{ 0x09, 0x00ff },
74*4882a593Smuzhiyun 	{ 0x0a, 0x000f },
75*4882a593Smuzhiyun 	{ 0x0b, 0x000f },
76*4882a593Smuzhiyun 	{ 0x0c, 0x007b },
77*4882a593Smuzhiyun 	{ 0x0d, 0x0000 },
78*4882a593Smuzhiyun 	{ 0x0e, 0x0032 },
79*4882a593Smuzhiyun 	{ 0x0f, 0x0000 },
80*4882a593Smuzhiyun 	{ 0x10, 0x00c3 },
81*4882a593Smuzhiyun 	{ 0x11, 0x00c3 },
82*4882a593Smuzhiyun 	{ 0x12, 0x00c0 },
83*4882a593Smuzhiyun 	{ 0x13, 0x0000 },
84*4882a593Smuzhiyun 	{ 0x14, 0x0000 },
85*4882a593Smuzhiyun 	{ 0x15, 0x0000 },
86*4882a593Smuzhiyun 	{ 0x16, 0x0000 },
87*4882a593Smuzhiyun 	{ 0x17, 0x0000 },
88*4882a593Smuzhiyun 	{ 0x18, 0x0000 },
89*4882a593Smuzhiyun 	{ 0x19, 0x0000 },
90*4882a593Smuzhiyun 	{ 0x1a, 0x0000 },
91*4882a593Smuzhiyun 	{ 0x1b, 0x0000 },
92*4882a593Smuzhiyun 	{ 0x1c, 0x0000 },
93*4882a593Smuzhiyun 	{ 0x1d, 0x0000 },
94*4882a593Smuzhiyun 	{ 0x1e, 0x0000 },
95*4882a593Smuzhiyun 	{ 0x1f, 0x0000 },
96*4882a593Smuzhiyun 	{ 0x20, 0x0055 },
97*4882a593Smuzhiyun 	{ 0x21, 0x0005 },
98*4882a593Smuzhiyun 	{ 0x22, 0x0050 },
99*4882a593Smuzhiyun 	{ 0x23, 0x0055 },
100*4882a593Smuzhiyun 	{ 0x24, 0x0050 },
101*4882a593Smuzhiyun 	{ 0x25, 0x0055 },
102*4882a593Smuzhiyun 	{ 0x26, 0x0050 },
103*4882a593Smuzhiyun 	{ 0x27, 0x0055 },
104*4882a593Smuzhiyun 	{ 0x28, 0x0079 },
105*4882a593Smuzhiyun 	{ 0x29, 0x0079 },
106*4882a593Smuzhiyun 	{ 0x2a, 0x0079 },
107*4882a593Smuzhiyun 	{ 0x2b, 0x0079 },
108*4882a593Smuzhiyun 	{ 0x2c, 0x0079 },
109*4882a593Smuzhiyun 	{ 0x2d, 0x0000 },
110*4882a593Smuzhiyun 	{ 0x2e, 0x0000 },
111*4882a593Smuzhiyun 	{ 0x2f, 0x0000 },
112*4882a593Smuzhiyun 	{ 0x30, 0x0000 },
113*4882a593Smuzhiyun 	{ 0x31, 0x0097 },
114*4882a593Smuzhiyun 	{ 0x32, 0x0097 },
115*4882a593Smuzhiyun 	{ 0x33, 0x0000 },
116*4882a593Smuzhiyun 	{ 0x34, 0x0004 },
117*4882a593Smuzhiyun 	{ 0x35, 0x0000 },
118*4882a593Smuzhiyun 	{ 0x36, 0x0083 },
119*4882a593Smuzhiyun 	{ 0x37, 0x0024 },
120*4882a593Smuzhiyun 	{ 0x38, 0x01ba },
121*4882a593Smuzhiyun 	{ 0x39, 0x0000 },
122*4882a593Smuzhiyun 	{ 0x3a, 0x0083 },
123*4882a593Smuzhiyun 	{ 0x3b, 0x0024 },
124*4882a593Smuzhiyun 	{ 0x3c, 0x01ba },
125*4882a593Smuzhiyun 	{ 0x3d, 0x0000 },
126*4882a593Smuzhiyun 	{ 0x3e, 0x0000 },
127*4882a593Smuzhiyun 	{ 0x3f, 0x0000 },
128*4882a593Smuzhiyun };
129*4882a593Smuzhiyun 
wm8753_volatile(struct device * dev,unsigned int reg)130*4882a593Smuzhiyun static bool wm8753_volatile(struct device *dev, unsigned int reg)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	return reg == WM8753_RESET;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun /* codec private data */
136*4882a593Smuzhiyun struct wm8753_priv {
137*4882a593Smuzhiyun 	struct regmap *regmap;
138*4882a593Smuzhiyun 	unsigned int sysclk;
139*4882a593Smuzhiyun 	unsigned int pcmclk;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	unsigned int voice_fmt;
142*4882a593Smuzhiyun 	unsigned int hifi_fmt;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	int dai_func;
145*4882a593Smuzhiyun 	struct delayed_work charge_work;
146*4882a593Smuzhiyun };
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun #define wm8753_reset(c) snd_soc_component_write(c, WM8753_RESET, 0)
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun /*
151*4882a593Smuzhiyun  * WM8753 Controls
152*4882a593Smuzhiyun  */
153*4882a593Smuzhiyun static const char *wm8753_base[] = {"Linear Control", "Adaptive Boost"};
154*4882a593Smuzhiyun static const char *wm8753_base_filter[] =
155*4882a593Smuzhiyun 	{"130Hz @ 48kHz", "200Hz @ 48kHz", "100Hz @ 16kHz", "400Hz @ 48kHz",
156*4882a593Smuzhiyun 	"100Hz @ 8kHz", "200Hz @ 8kHz"};
157*4882a593Smuzhiyun static const char *wm8753_treble[] = {"8kHz", "4kHz"};
158*4882a593Smuzhiyun static const char *wm8753_alc_func[] = {"Off", "Right", "Left", "Stereo"};
159*4882a593Smuzhiyun static const char *wm8753_ng_type[] = {"Constant PGA Gain", "Mute ADC Output"};
160*4882a593Smuzhiyun static const char *wm8753_3d_func[] = {"Capture", "Playback"};
161*4882a593Smuzhiyun static const char *wm8753_3d_uc[] = {"2.2kHz", "1.5kHz"};
162*4882a593Smuzhiyun static const char *wm8753_3d_lc[] = {"200Hz", "500Hz"};
163*4882a593Smuzhiyun static const char *wm8753_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz"};
164*4882a593Smuzhiyun static const char *wm8753_mono_mix[] = {"Stereo", "Left", "Right", "Mono"};
165*4882a593Smuzhiyun static const char *wm8753_dac_phase[] = {"Non Inverted", "Inverted"};
166*4882a593Smuzhiyun static const char *wm8753_line_mix[] = {"Line 1 + 2", "Line 1 - 2",
167*4882a593Smuzhiyun 	"Line 1", "Line 2"};
168*4882a593Smuzhiyun static const char *wm8753_mono_mux[] = {"Line Mix", "Rx Mix"};
169*4882a593Smuzhiyun static const char *wm8753_right_mux[] = {"Line 2", "Rx Mix"};
170*4882a593Smuzhiyun static const char *wm8753_left_mux[] = {"Line 1", "Rx Mix"};
171*4882a593Smuzhiyun static const char *wm8753_rxmsel[] = {"RXP - RXN", "RXP + RXN", "RXP", "RXN"};
172*4882a593Smuzhiyun static const char *wm8753_sidetone_mux[] = {"Left PGA", "Mic 1", "Mic 2",
173*4882a593Smuzhiyun 	"Right PGA"};
174*4882a593Smuzhiyun static const char *wm8753_mono2_src[] = {"Inverted Mono 1", "Left", "Right",
175*4882a593Smuzhiyun 	"Left + Right"};
176*4882a593Smuzhiyun static const char *wm8753_out3[] = {"VREF", "ROUT2", "Left + Right"};
177*4882a593Smuzhiyun static const char *wm8753_out4[] = {"VREF", "Capture ST", "LOUT2"};
178*4882a593Smuzhiyun static const char *wm8753_radcsel[] = {"PGA", "Line or RXP-RXN", "Sidetone"};
179*4882a593Smuzhiyun static const char *wm8753_ladcsel[] = {"PGA", "Line or RXP-RXN", "Line"};
180*4882a593Smuzhiyun static const char *wm8753_mono_adc[] = {"Stereo", "Analogue Mix Left",
181*4882a593Smuzhiyun 	"Analogue Mix Right", "Digital Mono Mix"};
182*4882a593Smuzhiyun static const char *wm8753_adc_hp[] = {"3.4Hz @ 48kHz", "82Hz @ 16k",
183*4882a593Smuzhiyun 	"82Hz @ 8kHz", "170Hz @ 8kHz"};
184*4882a593Smuzhiyun static const char *wm8753_adc_filter[] = {"HiFi", "Voice"};
185*4882a593Smuzhiyun static const char *wm8753_mic_sel[] = {"Mic 1", "Mic 2", "Mic 3"};
186*4882a593Smuzhiyun static const char *wm8753_dai_mode[] = {"DAI 0", "DAI 1", "DAI 2", "DAI 3"};
187*4882a593Smuzhiyun static const char *wm8753_dat_sel[] = {"Stereo", "Left ADC", "Right ADC",
188*4882a593Smuzhiyun 	"Channel Swap"};
189*4882a593Smuzhiyun static const char *wm8753_rout2_phase[] = {"Non Inverted", "Inverted"};
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun static const struct soc_enum wm8753_enum[] = {
192*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_BASS, 7, 2, wm8753_base),
193*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_BASS, 4, 6, wm8753_base_filter),
194*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_TREBLE, 6, 2, wm8753_treble),
195*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_ALC1, 7, 4, wm8753_alc_func),
196*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_NGATE, 1, 2, wm8753_ng_type),
197*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_3D, 7, 2, wm8753_3d_func),
198*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_3D, 6, 2, wm8753_3d_uc),
199*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_3D, 5, 2, wm8753_3d_lc),
200*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_DAC, 1, 4, wm8753_deemp),
201*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_DAC, 4, 4, wm8753_mono_mix),
202*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_DAC, 6, 2, wm8753_dac_phase),
203*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_INCTL1, 3, 4, wm8753_line_mix),
204*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_INCTL1, 2, 2, wm8753_mono_mux),
205*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_INCTL1, 1, 2, wm8753_right_mux),
206*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_INCTL1, 0, 2, wm8753_left_mux),
207*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_INCTL2, 6, 4, wm8753_rxmsel),
208*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_INCTL2, 4, 4, wm8753_sidetone_mux),
209*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_OUTCTL, 7, 4, wm8753_mono2_src),
210*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_OUTCTL, 0, 3, wm8753_out3),
211*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_ADCTL2, 7, 3, wm8753_out4),
212*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_ADCIN, 2, 3, wm8753_radcsel),
213*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_ADCIN, 0, 3, wm8753_ladcsel),
214*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_ADCIN, 4, 4, wm8753_mono_adc),
215*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_ADC, 2, 4, wm8753_adc_hp),
216*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_ADC, 4, 2, wm8753_adc_filter),
217*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_MICBIAS, 6, 3, wm8753_mic_sel),
218*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_IOCTL, 2, 4, wm8753_dai_mode),
219*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_ADC, 7, 4, wm8753_dat_sel),
220*4882a593Smuzhiyun SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase),
221*4882a593Smuzhiyun };
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 
wm8753_get_dai(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)224*4882a593Smuzhiyun static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
225*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
228*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = wm8753->dai_func;
231*4882a593Smuzhiyun 	return 0;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
wm8753_set_dai(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)234*4882a593Smuzhiyun static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
235*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
238*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
239*4882a593Smuzhiyun 	u16 ioctl;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	if (wm8753->dai_func == ucontrol->value.enumerated.item[0])
242*4882a593Smuzhiyun 		return 0;
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	if (snd_soc_component_active(component))
245*4882a593Smuzhiyun 		return -EBUSY;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	ioctl = snd_soc_component_read(component, WM8753_IOCTL);
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	wm8753->dai_func = ucontrol->value.enumerated.item[0];
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	if (((ioctl >> 2) & 0x3) == wm8753->dai_func)
252*4882a593Smuzhiyun 		return 1;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	ioctl = (ioctl & 0x1f3) | (wm8753->dai_func << 2);
255*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_IOCTL, ioctl);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	wm8753_hifi_write_dai_fmt(component, wm8753->hifi_fmt);
259*4882a593Smuzhiyun 	wm8753_voice_write_dai_fmt(component, wm8753->voice_fmt);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	return 1;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0);
265*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0);
266*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
267*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
268*4882a593Smuzhiyun static const DECLARE_TLV_DB_RANGE(out_tlv,
269*4882a593Smuzhiyun 	/* 0000000 - 0101111 = "Analogue mute" */
270*4882a593Smuzhiyun 	0, 48, TLV_DB_SCALE_ITEM(-25500, 0, 0),
271*4882a593Smuzhiyun 	48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0)
272*4882a593Smuzhiyun );
273*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(mix_tlv, -1500, 300, 0);
274*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(voice_mix_tlv, -1200, 300, 0);
275*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_snd_controls[] = {
278*4882a593Smuzhiyun SOC_SINGLE("Hi-Fi DAC Left/Right channel Swap", WM8753_HIFI, 5, 1, 0),
279*4882a593Smuzhiyun SOC_DOUBLE_R_TLV("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0, dac_tlv),
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun SOC_DOUBLE_R_TLV("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0,
282*4882a593Smuzhiyun 		 adc_tlv),
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V,
285*4882a593Smuzhiyun 		 0, 127, 0, out_tlv),
286*4882a593Smuzhiyun SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0,
287*4882a593Smuzhiyun 		 127, 0, out_tlv),
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun SOC_SINGLE_TLV("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0, out_tlv),
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun SOC_DOUBLE_R_TLV("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7,
292*4882a593Smuzhiyun 		 1, mix_tlv),
293*4882a593Smuzhiyun SOC_DOUBLE_R_TLV("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4,
294*4882a593Smuzhiyun 		 7, 1, mix_tlv),
295*4882a593Smuzhiyun SOC_DOUBLE_R_TLV("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7,
296*4882a593Smuzhiyun 		 1, voice_mix_tlv),
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7,
299*4882a593Smuzhiyun 	     1, 0),
300*4882a593Smuzhiyun SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7,
301*4882a593Smuzhiyun 	     1, 0),
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun SOC_SINGLE_TLV("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1, mix_tlv),
304*4882a593Smuzhiyun SOC_SINGLE_TLV("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1,
305*4882a593Smuzhiyun 	       mix_tlv),
306*4882a593Smuzhiyun SOC_SINGLE_TLV("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1,
307*4882a593Smuzhiyun 	       voice_mix_tlv),
308*4882a593Smuzhiyun SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0),
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun SOC_ENUM("Bass Boost", wm8753_enum[0]),
311*4882a593Smuzhiyun SOC_ENUM("Bass Filter", wm8753_enum[1]),
312*4882a593Smuzhiyun SOC_SINGLE("Bass Volume", WM8753_BASS, 0, 15, 1),
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1),
315*4882a593Smuzhiyun SOC_ENUM("Treble Cut-off", wm8753_enum[2]),
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1,
318*4882a593Smuzhiyun 	       rec_mix_tlv),
319*4882a593Smuzhiyun SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1,
320*4882a593Smuzhiyun 	       rec_mix_tlv),
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun SOC_DOUBLE_R_TLV("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0,
323*4882a593Smuzhiyun 		 pga_tlv),
324*4882a593Smuzhiyun SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0),
325*4882a593Smuzhiyun SOC_DOUBLE_R("Capture Switch", WM8753_LINVOL, WM8753_RINVOL, 7, 1, 1),
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun SOC_ENUM("Capture Filter Select", wm8753_enum[23]),
328*4882a593Smuzhiyun SOC_ENUM("Capture Filter Cut-off", wm8753_enum[24]),
329*4882a593Smuzhiyun SOC_SINGLE("Capture Filter Switch", WM8753_ADC, 0, 1, 1),
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun SOC_SINGLE("ALC Capture Target Volume", WM8753_ALC1, 0, 7, 0),
332*4882a593Smuzhiyun SOC_SINGLE("ALC Capture Max Volume", WM8753_ALC1, 4, 7, 0),
333*4882a593Smuzhiyun SOC_ENUM("ALC Capture Function", wm8753_enum[3]),
334*4882a593Smuzhiyun SOC_SINGLE("ALC Capture ZC Switch", WM8753_ALC2, 8, 1, 0),
335*4882a593Smuzhiyun SOC_SINGLE("ALC Capture Hold Time", WM8753_ALC2, 0, 15, 1),
336*4882a593Smuzhiyun SOC_SINGLE("ALC Capture Decay Time", WM8753_ALC3, 4, 15, 1),
337*4882a593Smuzhiyun SOC_SINGLE("ALC Capture Attack Time", WM8753_ALC3, 0, 15, 0),
338*4882a593Smuzhiyun SOC_SINGLE("ALC Capture NG Threshold", WM8753_NGATE, 3, 31, 0),
339*4882a593Smuzhiyun SOC_ENUM("ALC Capture NG Type", wm8753_enum[4]),
340*4882a593Smuzhiyun SOC_SINGLE("ALC Capture NG Switch", WM8753_NGATE, 0, 1, 0),
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun SOC_ENUM("3D Function", wm8753_enum[5]),
343*4882a593Smuzhiyun SOC_ENUM("3D Upper Cut-off", wm8753_enum[6]),
344*4882a593Smuzhiyun SOC_ENUM("3D Lower Cut-off", wm8753_enum[7]),
345*4882a593Smuzhiyun SOC_SINGLE("3D Volume", WM8753_3D, 1, 15, 0),
346*4882a593Smuzhiyun SOC_SINGLE("3D Switch", WM8753_3D, 0, 1, 0),
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun SOC_SINGLE("Capture 6dB Attenuate", WM8753_ADCTL1, 2, 1, 0),
349*4882a593Smuzhiyun SOC_SINGLE("Playback 6dB Attenuate", WM8753_ADCTL1, 1, 1, 0),
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun SOC_ENUM("De-emphasis", wm8753_enum[8]),
352*4882a593Smuzhiyun SOC_ENUM("Playback Mono Mix", wm8753_enum[9]),
353*4882a593Smuzhiyun SOC_ENUM("Playback Phase", wm8753_enum[10]),
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun SOC_SINGLE_TLV("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0, mic_preamp_tlv),
356*4882a593Smuzhiyun SOC_SINGLE_TLV("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0, mic_preamp_tlv),
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai),
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun SOC_ENUM("ADC Data Select", wm8753_enum[27]),
361*4882a593Smuzhiyun SOC_ENUM("ROUT2 Phase", wm8753_enum[28]),
362*4882a593Smuzhiyun };
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun /*
365*4882a593Smuzhiyun  * _DAPM_ Controls
366*4882a593Smuzhiyun  */
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun /* Left Mixer */
369*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_left_mixer_controls[] = {
370*4882a593Smuzhiyun SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_LOUTM2, 8, 1, 0),
371*4882a593Smuzhiyun SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_LOUTM2, 7, 1, 0),
372*4882a593Smuzhiyun SOC_DAPM_SINGLE("Left Playback Switch", WM8753_LOUTM1, 8, 1, 0),
373*4882a593Smuzhiyun SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_LOUTM1, 7, 1, 0),
374*4882a593Smuzhiyun };
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun /* Right mixer */
377*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_right_mixer_controls[] = {
378*4882a593Smuzhiyun SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_ROUTM2, 8, 1, 0),
379*4882a593Smuzhiyun SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_ROUTM2, 7, 1, 0),
380*4882a593Smuzhiyun SOC_DAPM_SINGLE("Right Playback Switch", WM8753_ROUTM1, 8, 1, 0),
381*4882a593Smuzhiyun SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_ROUTM1, 7, 1, 0),
382*4882a593Smuzhiyun };
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun /* Mono mixer */
385*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_mono_mixer_controls[] = {
386*4882a593Smuzhiyun SOC_DAPM_SINGLE("Left Playback Switch", WM8753_MOUTM1, 8, 1, 0),
387*4882a593Smuzhiyun SOC_DAPM_SINGLE("Right Playback Switch", WM8753_MOUTM2, 8, 1, 0),
388*4882a593Smuzhiyun SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_MOUTM2, 3, 1, 0),
389*4882a593Smuzhiyun SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_MOUTM2, 7, 1, 0),
390*4882a593Smuzhiyun SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_MOUTM1, 7, 1, 0),
391*4882a593Smuzhiyun };
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun /* Mono 2 Mux */
394*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_mono2_controls =
395*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8753_enum[17]);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun /* Out 3 Mux */
398*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_out3_controls =
399*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8753_enum[18]);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun /* Out 4 Mux */
402*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_out4_controls =
403*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8753_enum[19]);
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun /* ADC Mono Mix */
406*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_adc_mono_controls =
407*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8753_enum[22]);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun /* Record mixer */
410*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_record_mixer_controls[] = {
411*4882a593Smuzhiyun SOC_DAPM_SINGLE("Voice Capture Switch", WM8753_RECMIX2, 3, 1, 0),
412*4882a593Smuzhiyun SOC_DAPM_SINGLE("Left Capture Switch", WM8753_RECMIX1, 3, 1, 0),
413*4882a593Smuzhiyun SOC_DAPM_SINGLE("Right Capture Switch", WM8753_RECMIX1, 7, 1, 0),
414*4882a593Smuzhiyun };
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun /* Left ADC mux */
417*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_adc_left_controls =
418*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8753_enum[21]);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun /* Right ADC mux */
421*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_adc_right_controls =
422*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8753_enum[20]);
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun /* MIC mux */
425*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_mic_mux_controls =
426*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8753_enum[16]);
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun /* ALC mixer */
429*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_alc_mixer_controls[] = {
430*4882a593Smuzhiyun SOC_DAPM_SINGLE("Line Capture Switch", WM8753_INCTL2, 3, 1, 0),
431*4882a593Smuzhiyun SOC_DAPM_SINGLE("Mic2 Capture Switch", WM8753_INCTL2, 2, 1, 0),
432*4882a593Smuzhiyun SOC_DAPM_SINGLE("Mic1 Capture Switch", WM8753_INCTL2, 1, 1, 0),
433*4882a593Smuzhiyun SOC_DAPM_SINGLE("Rx Capture Switch", WM8753_INCTL2, 0, 1, 0),
434*4882a593Smuzhiyun };
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun /* Left Line mux */
437*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_line_left_controls =
438*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8753_enum[14]);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun /* Right Line mux */
441*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_line_right_controls =
442*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8753_enum[13]);
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun /* Mono Line mux */
445*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_line_mono_controls =
446*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8753_enum[12]);
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun /* Line mux and mixer */
449*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_line_mux_mix_controls =
450*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8753_enum[11]);
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun /* Rx mux and mixer */
453*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_rx_mux_mix_controls =
454*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8753_enum[15]);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun /* Mic Selector Mux */
457*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8753_mic_sel_mux_controls =
458*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", wm8753_enum[25]);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
461*4882a593Smuzhiyun SND_SOC_DAPM_MICBIAS("Mic Bias", WM8753_PWR1, 5, 0),
462*4882a593Smuzhiyun SND_SOC_DAPM_MIXER("Left Mixer", WM8753_PWR4, 0, 0,
463*4882a593Smuzhiyun 	&wm8753_left_mixer_controls[0], ARRAY_SIZE(wm8753_left_mixer_controls)),
464*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Left Out 1", WM8753_PWR3, 8, 0, NULL, 0),
465*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Left Out 2", WM8753_PWR3, 6, 0, NULL, 0),
466*4882a593Smuzhiyun SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", WM8753_PWR1, 3, 0),
467*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("LOUT1"),
468*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("LOUT2"),
469*4882a593Smuzhiyun SND_SOC_DAPM_MIXER("Right Mixer", WM8753_PWR4, 1, 0,
470*4882a593Smuzhiyun 	&wm8753_right_mixer_controls[0], ARRAY_SIZE(wm8753_right_mixer_controls)),
471*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Right Out 1", WM8753_PWR3, 7, 0, NULL, 0),
472*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Right Out 2", WM8753_PWR3, 5, 0, NULL, 0),
473*4882a593Smuzhiyun SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", WM8753_PWR1, 2, 0),
474*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("ROUT1"),
475*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("ROUT2"),
476*4882a593Smuzhiyun SND_SOC_DAPM_MIXER("Mono Mixer", WM8753_PWR4, 2, 0,
477*4882a593Smuzhiyun 	&wm8753_mono_mixer_controls[0], ARRAY_SIZE(wm8753_mono_mixer_controls)),
478*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Mono Out 1", WM8753_PWR3, 2, 0, NULL, 0),
479*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Mono Out 2", WM8753_PWR3, 1, 0, NULL, 0),
480*4882a593Smuzhiyun SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", WM8753_PWR1, 4, 0),
481*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("MONO1"),
482*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Mono 2 Mux", SND_SOC_NOPM, 0, 0, &wm8753_mono2_controls),
483*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("MONO2"),
484*4882a593Smuzhiyun SND_SOC_DAPM_MIXER("Out3 Left + Right", SND_SOC_NOPM, 0, 0, NULL, 0),
485*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out3_controls),
486*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Out 3", WM8753_PWR3, 4, 0, NULL, 0),
487*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("OUT3"),
488*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Out4 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out4_controls),
489*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Out 4", WM8753_PWR3, 3, 0, NULL, 0),
490*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("OUT4"),
491*4882a593Smuzhiyun SND_SOC_DAPM_MIXER("Playback Mixer", WM8753_PWR4, 3, 0,
492*4882a593Smuzhiyun 	&wm8753_record_mixer_controls[0],
493*4882a593Smuzhiyun 	ARRAY_SIZE(wm8753_record_mixer_controls)),
494*4882a593Smuzhiyun SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8753_PWR2, 3, 0),
495*4882a593Smuzhiyun SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8753_PWR2, 2, 0),
496*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Capture Left Mixer", SND_SOC_NOPM, 0, 0,
497*4882a593Smuzhiyun 	&wm8753_adc_mono_controls),
498*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Capture Right Mixer", SND_SOC_NOPM, 0, 0,
499*4882a593Smuzhiyun 	&wm8753_adc_mono_controls),
500*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Capture Left Mux", SND_SOC_NOPM, 0, 0,
501*4882a593Smuzhiyun 	&wm8753_adc_left_controls),
502*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Capture Right Mux", SND_SOC_NOPM, 0, 0,
503*4882a593Smuzhiyun 	&wm8753_adc_right_controls),
504*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Mic Sidetone Mux", SND_SOC_NOPM, 0, 0,
505*4882a593Smuzhiyun 	&wm8753_mic_mux_controls),
506*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Left Capture Volume", WM8753_PWR2, 5, 0, NULL, 0),
507*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Right Capture Volume", WM8753_PWR2, 4, 0, NULL, 0),
508*4882a593Smuzhiyun SND_SOC_DAPM_MIXER("ALC Mixer", WM8753_PWR2, 6, 0,
509*4882a593Smuzhiyun 	&wm8753_alc_mixer_controls[0], ARRAY_SIZE(wm8753_alc_mixer_controls)),
510*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Line Left Mux", SND_SOC_NOPM, 0, 0,
511*4882a593Smuzhiyun 	&wm8753_line_left_controls),
512*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Line Right Mux", SND_SOC_NOPM, 0, 0,
513*4882a593Smuzhiyun 	&wm8753_line_right_controls),
514*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Line Mono Mux", SND_SOC_NOPM, 0, 0,
515*4882a593Smuzhiyun 	&wm8753_line_mono_controls),
516*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Line Mixer", WM8753_PWR2, 0, 0,
517*4882a593Smuzhiyun 	&wm8753_line_mux_mix_controls),
518*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Rx Mixer", WM8753_PWR2, 1, 0,
519*4882a593Smuzhiyun 	&wm8753_rx_mux_mix_controls),
520*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Mic 1 Volume", WM8753_PWR2, 8, 0, NULL, 0),
521*4882a593Smuzhiyun SND_SOC_DAPM_PGA("Mic 2 Volume", WM8753_PWR2, 7, 0, NULL, 0),
522*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Mic Selection Mux", SND_SOC_NOPM, 0, 0,
523*4882a593Smuzhiyun 	&wm8753_mic_sel_mux_controls),
524*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("LINE1"),
525*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("LINE2"),
526*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("RXP"),
527*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("RXN"),
528*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("ACIN"),
529*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("ACOP"),
530*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("MIC1N"),
531*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("MIC1"),
532*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("MIC2N"),
533*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("MIC2"),
534*4882a593Smuzhiyun SND_SOC_DAPM_VMID("VREF"),
535*4882a593Smuzhiyun };
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun static const struct snd_soc_dapm_route wm8753_dapm_routes[] = {
538*4882a593Smuzhiyun 	/* left mixer */
539*4882a593Smuzhiyun 	{"Left Mixer", "Left Playback Switch", "Left DAC"},
540*4882a593Smuzhiyun 	{"Left Mixer", "Voice Playback Switch", "Voice DAC"},
541*4882a593Smuzhiyun 	{"Left Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},
542*4882a593Smuzhiyun 	{"Left Mixer", "Bypass Playback Switch", "Line Left Mux"},
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	/* right mixer */
545*4882a593Smuzhiyun 	{"Right Mixer", "Right Playback Switch", "Right DAC"},
546*4882a593Smuzhiyun 	{"Right Mixer", "Voice Playback Switch", "Voice DAC"},
547*4882a593Smuzhiyun 	{"Right Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},
548*4882a593Smuzhiyun 	{"Right Mixer", "Bypass Playback Switch", "Line Right Mux"},
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	/* mono mixer */
551*4882a593Smuzhiyun 	{"Mono Mixer", "Voice Playback Switch", "Voice DAC"},
552*4882a593Smuzhiyun 	{"Mono Mixer", "Left Playback Switch", "Left DAC"},
553*4882a593Smuzhiyun 	{"Mono Mixer", "Right Playback Switch", "Right DAC"},
554*4882a593Smuzhiyun 	{"Mono Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},
555*4882a593Smuzhiyun 	{"Mono Mixer", "Bypass Playback Switch", "Line Mono Mux"},
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	/* left out */
558*4882a593Smuzhiyun 	{"Left Out 1", NULL, "Left Mixer"},
559*4882a593Smuzhiyun 	{"Left Out 2", NULL, "Left Mixer"},
560*4882a593Smuzhiyun 	{"LOUT1", NULL, "Left Out 1"},
561*4882a593Smuzhiyun 	{"LOUT2", NULL, "Left Out 2"},
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	/* right out */
564*4882a593Smuzhiyun 	{"Right Out 1", NULL, "Right Mixer"},
565*4882a593Smuzhiyun 	{"Right Out 2", NULL, "Right Mixer"},
566*4882a593Smuzhiyun 	{"ROUT1", NULL, "Right Out 1"},
567*4882a593Smuzhiyun 	{"ROUT2", NULL, "Right Out 2"},
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	/* mono 1 out */
570*4882a593Smuzhiyun 	{"Mono Out 1", NULL, "Mono Mixer"},
571*4882a593Smuzhiyun 	{"MONO1", NULL, "Mono Out 1"},
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	/* mono 2 out */
574*4882a593Smuzhiyun 	{"Mono 2 Mux", "Left + Right", "Out3 Left + Right"},
575*4882a593Smuzhiyun 	{"Mono 2 Mux", "Inverted Mono 1", "MONO1"},
576*4882a593Smuzhiyun 	{"Mono 2 Mux", "Left", "Left Mixer"},
577*4882a593Smuzhiyun 	{"Mono 2 Mux", "Right", "Right Mixer"},
578*4882a593Smuzhiyun 	{"Mono Out 2", NULL, "Mono 2 Mux"},
579*4882a593Smuzhiyun 	{"MONO2", NULL, "Mono Out 2"},
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	/* out 3 */
582*4882a593Smuzhiyun 	{"Out3 Left + Right", NULL, "Left Mixer"},
583*4882a593Smuzhiyun 	{"Out3 Left + Right", NULL, "Right Mixer"},
584*4882a593Smuzhiyun 	{"Out3 Mux", "VREF", "VREF"},
585*4882a593Smuzhiyun 	{"Out3 Mux", "Left + Right", "Out3 Left + Right"},
586*4882a593Smuzhiyun 	{"Out3 Mux", "ROUT2", "ROUT2"},
587*4882a593Smuzhiyun 	{"Out 3", NULL, "Out3 Mux"},
588*4882a593Smuzhiyun 	{"OUT3", NULL, "Out 3"},
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	/* out 4 */
591*4882a593Smuzhiyun 	{"Out4 Mux", "VREF", "VREF"},
592*4882a593Smuzhiyun 	{"Out4 Mux", "Capture ST", "Playback Mixer"},
593*4882a593Smuzhiyun 	{"Out4 Mux", "LOUT2", "LOUT2"},
594*4882a593Smuzhiyun 	{"Out 4", NULL, "Out4 Mux"},
595*4882a593Smuzhiyun 	{"OUT4", NULL, "Out 4"},
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	/* record mixer  */
598*4882a593Smuzhiyun 	{"Playback Mixer", "Left Capture Switch", "Left Mixer"},
599*4882a593Smuzhiyun 	{"Playback Mixer", "Voice Capture Switch", "Mono Mixer"},
600*4882a593Smuzhiyun 	{"Playback Mixer", "Right Capture Switch", "Right Mixer"},
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	/* Mic/SideTone Mux */
603*4882a593Smuzhiyun 	{"Mic Sidetone Mux", "Left PGA", "Left Capture Volume"},
604*4882a593Smuzhiyun 	{"Mic Sidetone Mux", "Right PGA", "Right Capture Volume"},
605*4882a593Smuzhiyun 	{"Mic Sidetone Mux", "Mic 1", "Mic 1 Volume"},
606*4882a593Smuzhiyun 	{"Mic Sidetone Mux", "Mic 2", "Mic 2 Volume"},
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	/* Capture Left Mux */
609*4882a593Smuzhiyun 	{"Capture Left Mux", "PGA", "Left Capture Volume"},
610*4882a593Smuzhiyun 	{"Capture Left Mux", "Line or RXP-RXN", "Line Left Mux"},
611*4882a593Smuzhiyun 	{"Capture Left Mux", "Line", "LINE1"},
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	/* Capture Right Mux */
614*4882a593Smuzhiyun 	{"Capture Right Mux", "PGA", "Right Capture Volume"},
615*4882a593Smuzhiyun 	{"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"},
616*4882a593Smuzhiyun 	{"Capture Right Mux", "Sidetone", "Playback Mixer"},
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	/* Mono Capture mixer-mux */
619*4882a593Smuzhiyun 	{"Capture Right Mixer", "Stereo", "Capture Right Mux"},
620*4882a593Smuzhiyun 	{"Capture Left Mixer", "Stereo", "Capture Left Mux"},
621*4882a593Smuzhiyun 	{"Capture Left Mixer", "Analogue Mix Left", "Capture Left Mux"},
622*4882a593Smuzhiyun 	{"Capture Left Mixer", "Analogue Mix Left", "Capture Right Mux"},
623*4882a593Smuzhiyun 	{"Capture Right Mixer", "Analogue Mix Right", "Capture Left Mux"},
624*4882a593Smuzhiyun 	{"Capture Right Mixer", "Analogue Mix Right", "Capture Right Mux"},
625*4882a593Smuzhiyun 	{"Capture Left Mixer", "Digital Mono Mix", "Capture Left Mux"},
626*4882a593Smuzhiyun 	{"Capture Left Mixer", "Digital Mono Mix", "Capture Right Mux"},
627*4882a593Smuzhiyun 	{"Capture Right Mixer", "Digital Mono Mix", "Capture Left Mux"},
628*4882a593Smuzhiyun 	{"Capture Right Mixer", "Digital Mono Mix", "Capture Right Mux"},
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	/* ADC */
631*4882a593Smuzhiyun 	{"Left ADC", NULL, "Capture Left Mixer"},
632*4882a593Smuzhiyun 	{"Right ADC", NULL, "Capture Right Mixer"},
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	/* Left Capture Volume */
635*4882a593Smuzhiyun 	{"Left Capture Volume", NULL, "ACIN"},
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	/* Right Capture Volume */
638*4882a593Smuzhiyun 	{"Right Capture Volume", NULL, "Mic 2 Volume"},
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	/* ALC Mixer */
641*4882a593Smuzhiyun 	{"ALC Mixer", "Line Capture Switch", "Line Mixer"},
642*4882a593Smuzhiyun 	{"ALC Mixer", "Mic2 Capture Switch", "Mic 2 Volume"},
643*4882a593Smuzhiyun 	{"ALC Mixer", "Mic1 Capture Switch", "Mic 1 Volume"},
644*4882a593Smuzhiyun 	{"ALC Mixer", "Rx Capture Switch", "Rx Mixer"},
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	/* Line Left Mux */
647*4882a593Smuzhiyun 	{"Line Left Mux", "Line 1", "LINE1"},
648*4882a593Smuzhiyun 	{"Line Left Mux", "Rx Mix", "Rx Mixer"},
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	/* Line Right Mux */
651*4882a593Smuzhiyun 	{"Line Right Mux", "Line 2", "LINE2"},
652*4882a593Smuzhiyun 	{"Line Right Mux", "Rx Mix", "Rx Mixer"},
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	/* Line Mono Mux */
655*4882a593Smuzhiyun 	{"Line Mono Mux", "Line Mix", "Line Mixer"},
656*4882a593Smuzhiyun 	{"Line Mono Mux", "Rx Mix", "Rx Mixer"},
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	/* Line Mixer/Mux */
659*4882a593Smuzhiyun 	{"Line Mixer", "Line 1 + 2", "LINE1"},
660*4882a593Smuzhiyun 	{"Line Mixer", "Line 1 - 2", "LINE1"},
661*4882a593Smuzhiyun 	{"Line Mixer", "Line 1 + 2", "LINE2"},
662*4882a593Smuzhiyun 	{"Line Mixer", "Line 1 - 2", "LINE2"},
663*4882a593Smuzhiyun 	{"Line Mixer", "Line 1", "LINE1"},
664*4882a593Smuzhiyun 	{"Line Mixer", "Line 2", "LINE2"},
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	/* Rx Mixer/Mux */
667*4882a593Smuzhiyun 	{"Rx Mixer", "RXP - RXN", "RXP"},
668*4882a593Smuzhiyun 	{"Rx Mixer", "RXP + RXN", "RXP"},
669*4882a593Smuzhiyun 	{"Rx Mixer", "RXP - RXN", "RXN"},
670*4882a593Smuzhiyun 	{"Rx Mixer", "RXP + RXN", "RXN"},
671*4882a593Smuzhiyun 	{"Rx Mixer", "RXP", "RXP"},
672*4882a593Smuzhiyun 	{"Rx Mixer", "RXN", "RXN"},
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	/* Mic 1 Volume */
675*4882a593Smuzhiyun 	{"Mic 1 Volume", NULL, "MIC1N"},
676*4882a593Smuzhiyun 	{"Mic 1 Volume", NULL, "Mic Selection Mux"},
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	/* Mic 2 Volume */
679*4882a593Smuzhiyun 	{"Mic 2 Volume", NULL, "MIC2N"},
680*4882a593Smuzhiyun 	{"Mic 2 Volume", NULL, "MIC2"},
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	/* Mic Selector Mux */
683*4882a593Smuzhiyun 	{"Mic Selection Mux", "Mic 1", "MIC1"},
684*4882a593Smuzhiyun 	{"Mic Selection Mux", "Mic 2", "MIC2N"},
685*4882a593Smuzhiyun 	{"Mic Selection Mux", "Mic 3", "MIC2"},
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	/* ACOP */
688*4882a593Smuzhiyun 	{"ACOP", NULL, "ALC Mixer"},
689*4882a593Smuzhiyun };
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun /* PLL divisors */
692*4882a593Smuzhiyun struct _pll_div {
693*4882a593Smuzhiyun 	u32 div2:1;
694*4882a593Smuzhiyun 	u32 n:4;
695*4882a593Smuzhiyun 	u32 k:24;
696*4882a593Smuzhiyun };
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun /* The size in bits of the pll divide multiplied by 10
699*4882a593Smuzhiyun  * to allow rounding later */
700*4882a593Smuzhiyun #define FIXED_PLL_SIZE ((1 << 22) * 10)
701*4882a593Smuzhiyun 
pll_factors(struct _pll_div * pll_div,unsigned int target,unsigned int source)702*4882a593Smuzhiyun static void pll_factors(struct _pll_div *pll_div, unsigned int target,
703*4882a593Smuzhiyun 	unsigned int source)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun 	u64 Kpart;
706*4882a593Smuzhiyun 	unsigned int K, Ndiv, Nmod;
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	Ndiv = target / source;
709*4882a593Smuzhiyun 	if (Ndiv < 6) {
710*4882a593Smuzhiyun 		source >>= 1;
711*4882a593Smuzhiyun 		pll_div->div2 = 1;
712*4882a593Smuzhiyun 		Ndiv = target / source;
713*4882a593Smuzhiyun 	} else
714*4882a593Smuzhiyun 		pll_div->div2 = 0;
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	if ((Ndiv < 6) || (Ndiv > 12))
717*4882a593Smuzhiyun 		printk(KERN_WARNING
718*4882a593Smuzhiyun 			"wm8753: unsupported N = %u\n", Ndiv);
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	pll_div->n = Ndiv;
721*4882a593Smuzhiyun 	Nmod = target % source;
722*4882a593Smuzhiyun 	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	do_div(Kpart, source);
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	K = Kpart & 0xFFFFFFFF;
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	/* Check if we need to round */
729*4882a593Smuzhiyun 	if ((K % 10) >= 5)
730*4882a593Smuzhiyun 		K += 5;
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	/* Move down to proper range now rounding is done */
733*4882a593Smuzhiyun 	K /= 10;
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 	pll_div->k = K;
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun 
wm8753_set_dai_pll(struct snd_soc_dai * codec_dai,int pll_id,int source,unsigned int freq_in,unsigned int freq_out)738*4882a593Smuzhiyun static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
739*4882a593Smuzhiyun 		int source, unsigned int freq_in, unsigned int freq_out)
740*4882a593Smuzhiyun {
741*4882a593Smuzhiyun 	u16 reg, enable;
742*4882a593Smuzhiyun 	int offset;
743*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun 	if (pll_id < WM8753_PLL1 || pll_id > WM8753_PLL2)
746*4882a593Smuzhiyun 		return -ENODEV;
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	if (pll_id == WM8753_PLL1) {
749*4882a593Smuzhiyun 		offset = 0;
750*4882a593Smuzhiyun 		enable = 0x10;
751*4882a593Smuzhiyun 		reg = snd_soc_component_read(component, WM8753_CLOCK) & 0xffef;
752*4882a593Smuzhiyun 	} else {
753*4882a593Smuzhiyun 		offset = 4;
754*4882a593Smuzhiyun 		enable = 0x8;
755*4882a593Smuzhiyun 		reg = snd_soc_component_read(component, WM8753_CLOCK) & 0xfff7;
756*4882a593Smuzhiyun 	}
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	if (!freq_in || !freq_out) {
759*4882a593Smuzhiyun 		/* disable PLL  */
760*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8753_PLL1CTL1 + offset, 0x0026);
761*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8753_CLOCK, reg);
762*4882a593Smuzhiyun 		return 0;
763*4882a593Smuzhiyun 	} else {
764*4882a593Smuzhiyun 		u16 value = 0;
765*4882a593Smuzhiyun 		struct _pll_div pll_div;
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 		pll_factors(&pll_div, freq_out * 8, freq_in);
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 		/* set up N and K PLL divisor ratios */
770*4882a593Smuzhiyun 		/* bits 8:5 = PLL_N, bits 3:0 = PLL_K[21:18] */
771*4882a593Smuzhiyun 		value = (pll_div.n << 5) + ((pll_div.k & 0x3c0000) >> 18);
772*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8753_PLL1CTL2 + offset, value);
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 		/* bits 8:0 = PLL_K[17:9] */
775*4882a593Smuzhiyun 		value = (pll_div.k & 0x03fe00) >> 9;
776*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8753_PLL1CTL3 + offset, value);
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 		/* bits 8:0 = PLL_K[8:0] */
779*4882a593Smuzhiyun 		value = pll_div.k & 0x0001ff;
780*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8753_PLL1CTL4 + offset, value);
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 		/* set PLL as input and enable */
783*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8753_PLL1CTL1 + offset, 0x0027 |
784*4882a593Smuzhiyun 			(pll_div.div2 << 3));
785*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8753_CLOCK, reg | enable);
786*4882a593Smuzhiyun 	}
787*4882a593Smuzhiyun 	return 0;
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun struct _coeff_div {
791*4882a593Smuzhiyun 	u32 mclk;
792*4882a593Smuzhiyun 	u32 rate;
793*4882a593Smuzhiyun 	u8 sr:5;
794*4882a593Smuzhiyun 	u8 usb:1;
795*4882a593Smuzhiyun };
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun /* codec hifi mclk (after PLL) clock divider coefficients */
798*4882a593Smuzhiyun static const struct _coeff_div coeff_div[] = {
799*4882a593Smuzhiyun 	/* 8k */
800*4882a593Smuzhiyun 	{12288000, 8000, 0x6, 0x0},
801*4882a593Smuzhiyun 	{11289600, 8000, 0x16, 0x0},
802*4882a593Smuzhiyun 	{18432000, 8000, 0x7, 0x0},
803*4882a593Smuzhiyun 	{16934400, 8000, 0x17, 0x0},
804*4882a593Smuzhiyun 	{12000000, 8000, 0x6, 0x1},
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	/* 11.025k */
807*4882a593Smuzhiyun 	{11289600, 11025, 0x18, 0x0},
808*4882a593Smuzhiyun 	{16934400, 11025, 0x19, 0x0},
809*4882a593Smuzhiyun 	{12000000, 11025, 0x19, 0x1},
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 	/* 16k */
812*4882a593Smuzhiyun 	{12288000, 16000, 0xa, 0x0},
813*4882a593Smuzhiyun 	{18432000, 16000, 0xb, 0x0},
814*4882a593Smuzhiyun 	{12000000, 16000, 0xa, 0x1},
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 	/* 22.05k */
817*4882a593Smuzhiyun 	{11289600, 22050, 0x1a, 0x0},
818*4882a593Smuzhiyun 	{16934400, 22050, 0x1b, 0x0},
819*4882a593Smuzhiyun 	{12000000, 22050, 0x1b, 0x1},
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 	/* 32k */
822*4882a593Smuzhiyun 	{12288000, 32000, 0xc, 0x0},
823*4882a593Smuzhiyun 	{18432000, 32000, 0xd, 0x0},
824*4882a593Smuzhiyun 	{12000000, 32000, 0xa, 0x1},
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 	/* 44.1k */
827*4882a593Smuzhiyun 	{11289600, 44100, 0x10, 0x0},
828*4882a593Smuzhiyun 	{16934400, 44100, 0x11, 0x0},
829*4882a593Smuzhiyun 	{12000000, 44100, 0x11, 0x1},
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	/* 48k */
832*4882a593Smuzhiyun 	{12288000, 48000, 0x0, 0x0},
833*4882a593Smuzhiyun 	{18432000, 48000, 0x1, 0x0},
834*4882a593Smuzhiyun 	{12000000, 48000, 0x0, 0x1},
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 	/* 88.2k */
837*4882a593Smuzhiyun 	{11289600, 88200, 0x1e, 0x0},
838*4882a593Smuzhiyun 	{16934400, 88200, 0x1f, 0x0},
839*4882a593Smuzhiyun 	{12000000, 88200, 0x1f, 0x1},
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	/* 96k */
842*4882a593Smuzhiyun 	{12288000, 96000, 0xe, 0x0},
843*4882a593Smuzhiyun 	{18432000, 96000, 0xf, 0x0},
844*4882a593Smuzhiyun 	{12000000, 96000, 0xe, 0x1},
845*4882a593Smuzhiyun };
846*4882a593Smuzhiyun 
get_coeff(int mclk,int rate)847*4882a593Smuzhiyun static int get_coeff(int mclk, int rate)
848*4882a593Smuzhiyun {
849*4882a593Smuzhiyun 	int i;
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
852*4882a593Smuzhiyun 		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
853*4882a593Smuzhiyun 			return i;
854*4882a593Smuzhiyun 	}
855*4882a593Smuzhiyun 	return -EINVAL;
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun /*
859*4882a593Smuzhiyun  * Clock after PLL and dividers
860*4882a593Smuzhiyun  */
wm8753_set_dai_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)861*4882a593Smuzhiyun static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai,
862*4882a593Smuzhiyun 		int clk_id, unsigned int freq, int dir)
863*4882a593Smuzhiyun {
864*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
865*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	switch (freq) {
868*4882a593Smuzhiyun 	case 11289600:
869*4882a593Smuzhiyun 	case 12000000:
870*4882a593Smuzhiyun 	case 12288000:
871*4882a593Smuzhiyun 	case 16934400:
872*4882a593Smuzhiyun 	case 18432000:
873*4882a593Smuzhiyun 		if (clk_id == WM8753_MCLK) {
874*4882a593Smuzhiyun 			wm8753->sysclk = freq;
875*4882a593Smuzhiyun 			return 0;
876*4882a593Smuzhiyun 		} else if (clk_id == WM8753_PCMCLK) {
877*4882a593Smuzhiyun 			wm8753->pcmclk = freq;
878*4882a593Smuzhiyun 			return 0;
879*4882a593Smuzhiyun 		}
880*4882a593Smuzhiyun 		break;
881*4882a593Smuzhiyun 	}
882*4882a593Smuzhiyun 	return -EINVAL;
883*4882a593Smuzhiyun }
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun /*
886*4882a593Smuzhiyun  * Set's ADC and Voice DAC format.
887*4882a593Smuzhiyun  */
wm8753_vdac_adc_set_dai_fmt(struct snd_soc_component * component,unsigned int fmt)888*4882a593Smuzhiyun static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_component *component,
889*4882a593Smuzhiyun 		unsigned int fmt)
890*4882a593Smuzhiyun {
891*4882a593Smuzhiyun 	u16 voice = snd_soc_component_read(component, WM8753_PCM) & 0x01ec;
892*4882a593Smuzhiyun 
893*4882a593Smuzhiyun 	/* interface format */
894*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
895*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
896*4882a593Smuzhiyun 		voice |= 0x0002;
897*4882a593Smuzhiyun 		break;
898*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_RIGHT_J:
899*4882a593Smuzhiyun 		break;
900*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_LEFT_J:
901*4882a593Smuzhiyun 		voice |= 0x0001;
902*4882a593Smuzhiyun 		break;
903*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A:
904*4882a593Smuzhiyun 		voice |= 0x0003;
905*4882a593Smuzhiyun 		break;
906*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B:
907*4882a593Smuzhiyun 		voice |= 0x0013;
908*4882a593Smuzhiyun 		break;
909*4882a593Smuzhiyun 	default:
910*4882a593Smuzhiyun 		return -EINVAL;
911*4882a593Smuzhiyun 	}
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_PCM, voice);
914*4882a593Smuzhiyun 	return 0;
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun /*
918*4882a593Smuzhiyun  * Set PCM DAI bit size and sample rate.
919*4882a593Smuzhiyun  */
wm8753_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)920*4882a593Smuzhiyun static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
921*4882a593Smuzhiyun 				struct snd_pcm_hw_params *params,
922*4882a593Smuzhiyun 				struct snd_soc_dai *dai)
923*4882a593Smuzhiyun {
924*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
925*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
926*4882a593Smuzhiyun 	u16 voice = snd_soc_component_read(component, WM8753_PCM) & 0x01f3;
927*4882a593Smuzhiyun 	u16 srate = snd_soc_component_read(component, WM8753_SRATE1) & 0x017f;
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	/* bit size */
930*4882a593Smuzhiyun 	switch (params_width(params)) {
931*4882a593Smuzhiyun 	case 16:
932*4882a593Smuzhiyun 		break;
933*4882a593Smuzhiyun 	case 20:
934*4882a593Smuzhiyun 		voice |= 0x0004;
935*4882a593Smuzhiyun 		break;
936*4882a593Smuzhiyun 	case 24:
937*4882a593Smuzhiyun 		voice |= 0x0008;
938*4882a593Smuzhiyun 		break;
939*4882a593Smuzhiyun 	case 32:
940*4882a593Smuzhiyun 		voice |= 0x000c;
941*4882a593Smuzhiyun 		break;
942*4882a593Smuzhiyun 	}
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	/* sample rate */
945*4882a593Smuzhiyun 	if (params_rate(params) * 384 == wm8753->pcmclk)
946*4882a593Smuzhiyun 		srate |= 0x80;
947*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_SRATE1, srate);
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_PCM, voice);
950*4882a593Smuzhiyun 	return 0;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun /*
954*4882a593Smuzhiyun  * Set's PCM dai fmt and BCLK.
955*4882a593Smuzhiyun  */
wm8753_pcm_set_dai_fmt(struct snd_soc_component * component,unsigned int fmt)956*4882a593Smuzhiyun static int wm8753_pcm_set_dai_fmt(struct snd_soc_component *component,
957*4882a593Smuzhiyun 		unsigned int fmt)
958*4882a593Smuzhiyun {
959*4882a593Smuzhiyun 	u16 voice, ioctl;
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun 	voice = snd_soc_component_read(component, WM8753_PCM) & 0x011f;
962*4882a593Smuzhiyun 	ioctl = snd_soc_component_read(component, WM8753_IOCTL) & 0x015d;
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 	/* set master/slave audio interface */
965*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
966*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBS_CFS:
967*4882a593Smuzhiyun 		break;
968*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFM:
969*4882a593Smuzhiyun 		ioctl |= 0x2;
970*4882a593Smuzhiyun 		fallthrough;
971*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFS:
972*4882a593Smuzhiyun 		voice |= 0x0040;
973*4882a593Smuzhiyun 		break;
974*4882a593Smuzhiyun 	default:
975*4882a593Smuzhiyun 		return -EINVAL;
976*4882a593Smuzhiyun 	}
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 	/* clock inversion */
979*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
980*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A:
981*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B:
982*4882a593Smuzhiyun 		/* frame inversion not valid for DSP modes */
983*4882a593Smuzhiyun 		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
984*4882a593Smuzhiyun 		case SND_SOC_DAIFMT_NB_NF:
985*4882a593Smuzhiyun 			break;
986*4882a593Smuzhiyun 		case SND_SOC_DAIFMT_IB_NF:
987*4882a593Smuzhiyun 			voice |= 0x0080;
988*4882a593Smuzhiyun 			break;
989*4882a593Smuzhiyun 		default:
990*4882a593Smuzhiyun 			return -EINVAL;
991*4882a593Smuzhiyun 		}
992*4882a593Smuzhiyun 		break;
993*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
994*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_RIGHT_J:
995*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_LEFT_J:
996*4882a593Smuzhiyun 		voice &= ~0x0010;
997*4882a593Smuzhiyun 		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
998*4882a593Smuzhiyun 		case SND_SOC_DAIFMT_NB_NF:
999*4882a593Smuzhiyun 			break;
1000*4882a593Smuzhiyun 		case SND_SOC_DAIFMT_IB_IF:
1001*4882a593Smuzhiyun 			voice |= 0x0090;
1002*4882a593Smuzhiyun 			break;
1003*4882a593Smuzhiyun 		case SND_SOC_DAIFMT_IB_NF:
1004*4882a593Smuzhiyun 			voice |= 0x0080;
1005*4882a593Smuzhiyun 			break;
1006*4882a593Smuzhiyun 		case SND_SOC_DAIFMT_NB_IF:
1007*4882a593Smuzhiyun 			voice |= 0x0010;
1008*4882a593Smuzhiyun 			break;
1009*4882a593Smuzhiyun 		default:
1010*4882a593Smuzhiyun 			return -EINVAL;
1011*4882a593Smuzhiyun 		}
1012*4882a593Smuzhiyun 		break;
1013*4882a593Smuzhiyun 	default:
1014*4882a593Smuzhiyun 		return -EINVAL;
1015*4882a593Smuzhiyun 	}
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_PCM, voice);
1018*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_IOCTL, ioctl);
1019*4882a593Smuzhiyun 	return 0;
1020*4882a593Smuzhiyun }
1021*4882a593Smuzhiyun 
wm8753_set_dai_clkdiv(struct snd_soc_dai * codec_dai,int div_id,int div)1022*4882a593Smuzhiyun static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
1023*4882a593Smuzhiyun 		int div_id, int div)
1024*4882a593Smuzhiyun {
1025*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
1026*4882a593Smuzhiyun 	u16 reg;
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	switch (div_id) {
1029*4882a593Smuzhiyun 	case WM8753_PCMDIV:
1030*4882a593Smuzhiyun 		reg = snd_soc_component_read(component, WM8753_CLOCK) & 0x003f;
1031*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8753_CLOCK, reg | div);
1032*4882a593Smuzhiyun 		break;
1033*4882a593Smuzhiyun 	case WM8753_BCLKDIV:
1034*4882a593Smuzhiyun 		reg = snd_soc_component_read(component, WM8753_SRATE2) & 0x01c7;
1035*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8753_SRATE2, reg | div);
1036*4882a593Smuzhiyun 		break;
1037*4882a593Smuzhiyun 	case WM8753_VXCLKDIV:
1038*4882a593Smuzhiyun 		reg = snd_soc_component_read(component, WM8753_SRATE2) & 0x003f;
1039*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8753_SRATE2, reg | div);
1040*4882a593Smuzhiyun 		break;
1041*4882a593Smuzhiyun 	default:
1042*4882a593Smuzhiyun 		return -EINVAL;
1043*4882a593Smuzhiyun 	}
1044*4882a593Smuzhiyun 	return 0;
1045*4882a593Smuzhiyun }
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun /*
1048*4882a593Smuzhiyun  * Set's HiFi DAC format.
1049*4882a593Smuzhiyun  */
wm8753_hdac_set_dai_fmt(struct snd_soc_component * component,unsigned int fmt)1050*4882a593Smuzhiyun static int wm8753_hdac_set_dai_fmt(struct snd_soc_component *component,
1051*4882a593Smuzhiyun 		unsigned int fmt)
1052*4882a593Smuzhiyun {
1053*4882a593Smuzhiyun 	u16 hifi = snd_soc_component_read(component, WM8753_HIFI) & 0x01e0;
1054*4882a593Smuzhiyun 
1055*4882a593Smuzhiyun 	/* interface format */
1056*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1057*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
1058*4882a593Smuzhiyun 		hifi |= 0x0002;
1059*4882a593Smuzhiyun 		break;
1060*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_RIGHT_J:
1061*4882a593Smuzhiyun 		break;
1062*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_LEFT_J:
1063*4882a593Smuzhiyun 		hifi |= 0x0001;
1064*4882a593Smuzhiyun 		break;
1065*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A:
1066*4882a593Smuzhiyun 		hifi |= 0x0003;
1067*4882a593Smuzhiyun 		break;
1068*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B:
1069*4882a593Smuzhiyun 		hifi |= 0x0013;
1070*4882a593Smuzhiyun 		break;
1071*4882a593Smuzhiyun 	default:
1072*4882a593Smuzhiyun 		return -EINVAL;
1073*4882a593Smuzhiyun 	}
1074*4882a593Smuzhiyun 
1075*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_HIFI, hifi);
1076*4882a593Smuzhiyun 	return 0;
1077*4882a593Smuzhiyun }
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun /*
1080*4882a593Smuzhiyun  * Set's I2S DAI format.
1081*4882a593Smuzhiyun  */
wm8753_i2s_set_dai_fmt(struct snd_soc_component * component,unsigned int fmt)1082*4882a593Smuzhiyun static int wm8753_i2s_set_dai_fmt(struct snd_soc_component *component,
1083*4882a593Smuzhiyun 		unsigned int fmt)
1084*4882a593Smuzhiyun {
1085*4882a593Smuzhiyun 	u16 ioctl, hifi;
1086*4882a593Smuzhiyun 
1087*4882a593Smuzhiyun 	hifi = snd_soc_component_read(component, WM8753_HIFI) & 0x013f;
1088*4882a593Smuzhiyun 	ioctl = snd_soc_component_read(component, WM8753_IOCTL) & 0x00ae;
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun 	/* set master/slave audio interface */
1091*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1092*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBS_CFS:
1093*4882a593Smuzhiyun 		break;
1094*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFM:
1095*4882a593Smuzhiyun 		ioctl |= 0x1;
1096*4882a593Smuzhiyun 		fallthrough;
1097*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFS:
1098*4882a593Smuzhiyun 		hifi |= 0x0040;
1099*4882a593Smuzhiyun 		break;
1100*4882a593Smuzhiyun 	default:
1101*4882a593Smuzhiyun 		return -EINVAL;
1102*4882a593Smuzhiyun 	}
1103*4882a593Smuzhiyun 
1104*4882a593Smuzhiyun 	/* clock inversion */
1105*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1106*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A:
1107*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B:
1108*4882a593Smuzhiyun 		/* frame inversion not valid for DSP modes */
1109*4882a593Smuzhiyun 		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1110*4882a593Smuzhiyun 		case SND_SOC_DAIFMT_NB_NF:
1111*4882a593Smuzhiyun 			break;
1112*4882a593Smuzhiyun 		case SND_SOC_DAIFMT_IB_NF:
1113*4882a593Smuzhiyun 			hifi |= 0x0080;
1114*4882a593Smuzhiyun 			break;
1115*4882a593Smuzhiyun 		default:
1116*4882a593Smuzhiyun 			return -EINVAL;
1117*4882a593Smuzhiyun 		}
1118*4882a593Smuzhiyun 		break;
1119*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
1120*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_RIGHT_J:
1121*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_LEFT_J:
1122*4882a593Smuzhiyun 		hifi &= ~0x0010;
1123*4882a593Smuzhiyun 		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1124*4882a593Smuzhiyun 		case SND_SOC_DAIFMT_NB_NF:
1125*4882a593Smuzhiyun 			break;
1126*4882a593Smuzhiyun 		case SND_SOC_DAIFMT_IB_IF:
1127*4882a593Smuzhiyun 			hifi |= 0x0090;
1128*4882a593Smuzhiyun 			break;
1129*4882a593Smuzhiyun 		case SND_SOC_DAIFMT_IB_NF:
1130*4882a593Smuzhiyun 			hifi |= 0x0080;
1131*4882a593Smuzhiyun 			break;
1132*4882a593Smuzhiyun 		case SND_SOC_DAIFMT_NB_IF:
1133*4882a593Smuzhiyun 			hifi |= 0x0010;
1134*4882a593Smuzhiyun 			break;
1135*4882a593Smuzhiyun 		default:
1136*4882a593Smuzhiyun 			return -EINVAL;
1137*4882a593Smuzhiyun 		}
1138*4882a593Smuzhiyun 		break;
1139*4882a593Smuzhiyun 	default:
1140*4882a593Smuzhiyun 		return -EINVAL;
1141*4882a593Smuzhiyun 	}
1142*4882a593Smuzhiyun 
1143*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_HIFI, hifi);
1144*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_IOCTL, ioctl);
1145*4882a593Smuzhiyun 	return 0;
1146*4882a593Smuzhiyun }
1147*4882a593Smuzhiyun 
1148*4882a593Smuzhiyun /*
1149*4882a593Smuzhiyun  * Set PCM DAI bit size and sample rate.
1150*4882a593Smuzhiyun  */
wm8753_i2s_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)1151*4882a593Smuzhiyun static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
1152*4882a593Smuzhiyun 				struct snd_pcm_hw_params *params,
1153*4882a593Smuzhiyun 				struct snd_soc_dai *dai)
1154*4882a593Smuzhiyun {
1155*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1156*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
1157*4882a593Smuzhiyun 	u16 srate = snd_soc_component_read(component, WM8753_SRATE1) & 0x01c0;
1158*4882a593Smuzhiyun 	u16 hifi = snd_soc_component_read(component, WM8753_HIFI) & 0x01f3;
1159*4882a593Smuzhiyun 	int coeff;
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun 	/* is digital filter coefficient valid ? */
1162*4882a593Smuzhiyun 	coeff = get_coeff(wm8753->sysclk, params_rate(params));
1163*4882a593Smuzhiyun 	if (coeff < 0) {
1164*4882a593Smuzhiyun 		printk(KERN_ERR "wm8753 invalid MCLK or rate\n");
1165*4882a593Smuzhiyun 		return coeff;
1166*4882a593Smuzhiyun 	}
1167*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) |
1168*4882a593Smuzhiyun 		coeff_div[coeff].usb);
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 	/* bit size */
1171*4882a593Smuzhiyun 	switch (params_width(params)) {
1172*4882a593Smuzhiyun 	case 16:
1173*4882a593Smuzhiyun 		break;
1174*4882a593Smuzhiyun 	case 20:
1175*4882a593Smuzhiyun 		hifi |= 0x0004;
1176*4882a593Smuzhiyun 		break;
1177*4882a593Smuzhiyun 	case 24:
1178*4882a593Smuzhiyun 		hifi |= 0x0008;
1179*4882a593Smuzhiyun 		break;
1180*4882a593Smuzhiyun 	case 32:
1181*4882a593Smuzhiyun 		hifi |= 0x000c;
1182*4882a593Smuzhiyun 		break;
1183*4882a593Smuzhiyun 	}
1184*4882a593Smuzhiyun 
1185*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_HIFI, hifi);
1186*4882a593Smuzhiyun 	return 0;
1187*4882a593Smuzhiyun }
1188*4882a593Smuzhiyun 
wm8753_mode1v_set_dai_fmt(struct snd_soc_component * component,unsigned int fmt)1189*4882a593Smuzhiyun static int wm8753_mode1v_set_dai_fmt(struct snd_soc_component *component,
1190*4882a593Smuzhiyun 		unsigned int fmt)
1191*4882a593Smuzhiyun {
1192*4882a593Smuzhiyun 	u16 clock;
1193*4882a593Smuzhiyun 
1194*4882a593Smuzhiyun 	/* set clk source as pcmclk */
1195*4882a593Smuzhiyun 	clock = snd_soc_component_read(component, WM8753_CLOCK) & 0xfffb;
1196*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_CLOCK, clock);
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun 	return wm8753_vdac_adc_set_dai_fmt(component, fmt);
1199*4882a593Smuzhiyun }
1200*4882a593Smuzhiyun 
wm8753_mode1h_set_dai_fmt(struct snd_soc_component * component,unsigned int fmt)1201*4882a593Smuzhiyun static int wm8753_mode1h_set_dai_fmt(struct snd_soc_component *component,
1202*4882a593Smuzhiyun 		unsigned int fmt)
1203*4882a593Smuzhiyun {
1204*4882a593Smuzhiyun 	return wm8753_hdac_set_dai_fmt(component, fmt);
1205*4882a593Smuzhiyun }
1206*4882a593Smuzhiyun 
wm8753_mode2_set_dai_fmt(struct snd_soc_component * component,unsigned int fmt)1207*4882a593Smuzhiyun static int wm8753_mode2_set_dai_fmt(struct snd_soc_component *component,
1208*4882a593Smuzhiyun 		unsigned int fmt)
1209*4882a593Smuzhiyun {
1210*4882a593Smuzhiyun 	u16 clock;
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun 	/* set clk source as pcmclk */
1213*4882a593Smuzhiyun 	clock = snd_soc_component_read(component, WM8753_CLOCK) & 0xfffb;
1214*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_CLOCK, clock);
1215*4882a593Smuzhiyun 
1216*4882a593Smuzhiyun 	return wm8753_vdac_adc_set_dai_fmt(component, fmt);
1217*4882a593Smuzhiyun }
1218*4882a593Smuzhiyun 
wm8753_mode3_4_set_dai_fmt(struct snd_soc_component * component,unsigned int fmt)1219*4882a593Smuzhiyun static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_component *component,
1220*4882a593Smuzhiyun 		unsigned int fmt)
1221*4882a593Smuzhiyun {
1222*4882a593Smuzhiyun 	u16 clock;
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun 	/* set clk source as mclk */
1225*4882a593Smuzhiyun 	clock = snd_soc_component_read(component, WM8753_CLOCK) & 0xfffb;
1226*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8753_CLOCK, clock | 0x4);
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 	if (wm8753_hdac_set_dai_fmt(component, fmt) < 0)
1229*4882a593Smuzhiyun 		return -EINVAL;
1230*4882a593Smuzhiyun 	return wm8753_vdac_adc_set_dai_fmt(component, fmt);
1231*4882a593Smuzhiyun }
1232*4882a593Smuzhiyun 
wm8753_hifi_write_dai_fmt(struct snd_soc_component * component,unsigned int fmt)1233*4882a593Smuzhiyun static int wm8753_hifi_write_dai_fmt(struct snd_soc_component *component,
1234*4882a593Smuzhiyun 		unsigned int fmt)
1235*4882a593Smuzhiyun {
1236*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
1237*4882a593Smuzhiyun 	int ret = 0;
1238*4882a593Smuzhiyun 
1239*4882a593Smuzhiyun 	switch (wm8753->dai_func) {
1240*4882a593Smuzhiyun 	case 0:
1241*4882a593Smuzhiyun 		ret = wm8753_mode1h_set_dai_fmt(component, fmt);
1242*4882a593Smuzhiyun 		break;
1243*4882a593Smuzhiyun 	case 1:
1244*4882a593Smuzhiyun 		ret = wm8753_mode2_set_dai_fmt(component, fmt);
1245*4882a593Smuzhiyun 		break;
1246*4882a593Smuzhiyun 	case 2:
1247*4882a593Smuzhiyun 	case 3:
1248*4882a593Smuzhiyun 		ret = wm8753_mode3_4_set_dai_fmt(component, fmt);
1249*4882a593Smuzhiyun 		break;
1250*4882a593Smuzhiyun 	default:
1251*4882a593Smuzhiyun 		 break;
1252*4882a593Smuzhiyun 	}
1253*4882a593Smuzhiyun 	if (ret)
1254*4882a593Smuzhiyun 		return ret;
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun 	return wm8753_i2s_set_dai_fmt(component, fmt);
1257*4882a593Smuzhiyun }
1258*4882a593Smuzhiyun 
wm8753_hifi_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)1259*4882a593Smuzhiyun static int wm8753_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai,
1260*4882a593Smuzhiyun 		unsigned int fmt)
1261*4882a593Smuzhiyun {
1262*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
1263*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun 	wm8753->hifi_fmt = fmt;
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun 	return wm8753_hifi_write_dai_fmt(component, fmt);
1268*4882a593Smuzhiyun };
1269*4882a593Smuzhiyun 
wm8753_voice_write_dai_fmt(struct snd_soc_component * component,unsigned int fmt)1270*4882a593Smuzhiyun static int wm8753_voice_write_dai_fmt(struct snd_soc_component *component,
1271*4882a593Smuzhiyun 		unsigned int fmt)
1272*4882a593Smuzhiyun {
1273*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
1274*4882a593Smuzhiyun 	int ret = 0;
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun 	if (wm8753->dai_func != 0)
1277*4882a593Smuzhiyun 		return 0;
1278*4882a593Smuzhiyun 
1279*4882a593Smuzhiyun 	ret = wm8753_mode1v_set_dai_fmt(component, fmt);
1280*4882a593Smuzhiyun 	if (ret)
1281*4882a593Smuzhiyun 		return ret;
1282*4882a593Smuzhiyun 	ret = wm8753_pcm_set_dai_fmt(component, fmt);
1283*4882a593Smuzhiyun 	if (ret)
1284*4882a593Smuzhiyun 		return ret;
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 	return 0;
1287*4882a593Smuzhiyun };
1288*4882a593Smuzhiyun 
wm8753_voice_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)1289*4882a593Smuzhiyun static int wm8753_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
1290*4882a593Smuzhiyun 		unsigned int fmt)
1291*4882a593Smuzhiyun {
1292*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
1293*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 	wm8753->voice_fmt = fmt;
1296*4882a593Smuzhiyun 
1297*4882a593Smuzhiyun 	return wm8753_voice_write_dai_fmt(component, fmt);
1298*4882a593Smuzhiyun };
1299*4882a593Smuzhiyun 
wm8753_mute(struct snd_soc_dai * dai,int mute,int direction)1300*4882a593Smuzhiyun static int wm8753_mute(struct snd_soc_dai *dai, int mute, int direction)
1301*4882a593Smuzhiyun {
1302*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1303*4882a593Smuzhiyun 	u16 mute_reg = snd_soc_component_read(component, WM8753_DAC) & 0xfff7;
1304*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 	/* the digital mute covers the HiFi and Voice DAC's on the WM8753.
1307*4882a593Smuzhiyun 	 * make sure we check if they are not both active when we mute */
1308*4882a593Smuzhiyun 	if (mute && wm8753->dai_func == 1) {
1309*4882a593Smuzhiyun 		if (!snd_soc_component_active(component))
1310*4882a593Smuzhiyun 			snd_soc_component_write(component, WM8753_DAC, mute_reg | 0x8);
1311*4882a593Smuzhiyun 	} else {
1312*4882a593Smuzhiyun 		if (mute)
1313*4882a593Smuzhiyun 			snd_soc_component_write(component, WM8753_DAC, mute_reg | 0x8);
1314*4882a593Smuzhiyun 		else
1315*4882a593Smuzhiyun 			snd_soc_component_write(component, WM8753_DAC, mute_reg);
1316*4882a593Smuzhiyun 	}
1317*4882a593Smuzhiyun 
1318*4882a593Smuzhiyun 	return 0;
1319*4882a593Smuzhiyun }
1320*4882a593Smuzhiyun 
wm8753_charge_work(struct work_struct * work)1321*4882a593Smuzhiyun static void wm8753_charge_work(struct work_struct *work)
1322*4882a593Smuzhiyun {
1323*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 =
1324*4882a593Smuzhiyun 		container_of(work, struct wm8753_priv, charge_work.work);
1325*4882a593Smuzhiyun 
1326*4882a593Smuzhiyun 	/* Set to 500k */
1327*4882a593Smuzhiyun 	regmap_update_bits(wm8753->regmap, WM8753_PWR1, 0x0180, 0x0100);
1328*4882a593Smuzhiyun }
1329*4882a593Smuzhiyun 
wm8753_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)1330*4882a593Smuzhiyun static int wm8753_set_bias_level(struct snd_soc_component *component,
1331*4882a593Smuzhiyun 				 enum snd_soc_bias_level level)
1332*4882a593Smuzhiyun {
1333*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
1334*4882a593Smuzhiyun 	u16 pwr_reg = snd_soc_component_read(component, WM8753_PWR1) & 0xfe3e;
1335*4882a593Smuzhiyun 
1336*4882a593Smuzhiyun 	switch (level) {
1337*4882a593Smuzhiyun 	case SND_SOC_BIAS_ON:
1338*4882a593Smuzhiyun 		/* set vmid to 50k and unmute dac */
1339*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8753_PWR1, pwr_reg | 0x00c0);
1340*4882a593Smuzhiyun 		break;
1341*4882a593Smuzhiyun 	case SND_SOC_BIAS_PREPARE:
1342*4882a593Smuzhiyun 		/* Wait until fully charged */
1343*4882a593Smuzhiyun 		flush_delayed_work(&wm8753->charge_work);
1344*4882a593Smuzhiyun 		break;
1345*4882a593Smuzhiyun 	case SND_SOC_BIAS_STANDBY:
1346*4882a593Smuzhiyun 		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
1347*4882a593Smuzhiyun 			/* set vmid to 5k for quick power up */
1348*4882a593Smuzhiyun 			snd_soc_component_write(component, WM8753_PWR1, pwr_reg | 0x01c1);
1349*4882a593Smuzhiyun 			schedule_delayed_work(&wm8753->charge_work,
1350*4882a593Smuzhiyun 				msecs_to_jiffies(caps_charge));
1351*4882a593Smuzhiyun 		} else {
1352*4882a593Smuzhiyun 			/* mute dac and set vmid to 500k, enable VREF */
1353*4882a593Smuzhiyun 			snd_soc_component_write(component, WM8753_PWR1, pwr_reg | 0x0141);
1354*4882a593Smuzhiyun 		}
1355*4882a593Smuzhiyun 		break;
1356*4882a593Smuzhiyun 	case SND_SOC_BIAS_OFF:
1357*4882a593Smuzhiyun 		cancel_delayed_work_sync(&wm8753->charge_work);
1358*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8753_PWR1, 0x0001);
1359*4882a593Smuzhiyun 		break;
1360*4882a593Smuzhiyun 	}
1361*4882a593Smuzhiyun 	return 0;
1362*4882a593Smuzhiyun }
1363*4882a593Smuzhiyun 
1364*4882a593Smuzhiyun #define WM8753_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
1365*4882a593Smuzhiyun 		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
1366*4882a593Smuzhiyun 		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
1367*4882a593Smuzhiyun 		SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun #define WM8753_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
1370*4882a593Smuzhiyun 	SNDRV_PCM_FMTBIT_S24_LE)
1371*4882a593Smuzhiyun 
1372*4882a593Smuzhiyun /*
1373*4882a593Smuzhiyun  * The WM8753 supports up to 4 different and mutually exclusive DAI
1374*4882a593Smuzhiyun  * configurations. This gives 2 PCM's available for use, hifi and voice.
1375*4882a593Smuzhiyun  * NOTE: The Voice PCM cannot play or capture audio to the CPU as it's DAI
1376*4882a593Smuzhiyun  * is connected between the wm8753 and a BT codec or GSM modem.
1377*4882a593Smuzhiyun  *
1378*4882a593Smuzhiyun  * 1. Voice over PCM DAI - HIFI DAC over HIFI DAI
1379*4882a593Smuzhiyun  * 2. Voice over HIFI DAI - HIFI disabled
1380*4882a593Smuzhiyun  * 3. Voice disabled - HIFI over HIFI
1381*4882a593Smuzhiyun  * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
1382*4882a593Smuzhiyun  */
1383*4882a593Smuzhiyun static const struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode = {
1384*4882a593Smuzhiyun 	.hw_params	= wm8753_i2s_hw_params,
1385*4882a593Smuzhiyun 	.mute_stream	= wm8753_mute,
1386*4882a593Smuzhiyun 	.set_fmt	= wm8753_hifi_set_dai_fmt,
1387*4882a593Smuzhiyun 	.set_clkdiv	= wm8753_set_dai_clkdiv,
1388*4882a593Smuzhiyun 	.set_pll	= wm8753_set_dai_pll,
1389*4882a593Smuzhiyun 	.set_sysclk	= wm8753_set_dai_sysclk,
1390*4882a593Smuzhiyun 	.no_capture_mute = 1,
1391*4882a593Smuzhiyun };
1392*4882a593Smuzhiyun 
1393*4882a593Smuzhiyun static const struct snd_soc_dai_ops wm8753_dai_ops_voice_mode = {
1394*4882a593Smuzhiyun 	.hw_params	= wm8753_pcm_hw_params,
1395*4882a593Smuzhiyun 	.mute_stream	= wm8753_mute,
1396*4882a593Smuzhiyun 	.set_fmt	= wm8753_voice_set_dai_fmt,
1397*4882a593Smuzhiyun 	.set_clkdiv	= wm8753_set_dai_clkdiv,
1398*4882a593Smuzhiyun 	.set_pll	= wm8753_set_dai_pll,
1399*4882a593Smuzhiyun 	.set_sysclk	= wm8753_set_dai_sysclk,
1400*4882a593Smuzhiyun 	.no_capture_mute = 1,
1401*4882a593Smuzhiyun };
1402*4882a593Smuzhiyun 
1403*4882a593Smuzhiyun static struct snd_soc_dai_driver wm8753_dai[] = {
1404*4882a593Smuzhiyun /* DAI HiFi mode 1 */
1405*4882a593Smuzhiyun {	.name = "wm8753-hifi",
1406*4882a593Smuzhiyun 	.playback = {
1407*4882a593Smuzhiyun 		.stream_name = "HiFi Playback",
1408*4882a593Smuzhiyun 		.channels_min = 1,
1409*4882a593Smuzhiyun 		.channels_max = 2,
1410*4882a593Smuzhiyun 		.rates = WM8753_RATES,
1411*4882a593Smuzhiyun 		.formats = WM8753_FORMATS
1412*4882a593Smuzhiyun 	},
1413*4882a593Smuzhiyun 	.capture = { /* dummy for fast DAI switching */
1414*4882a593Smuzhiyun 		.stream_name = "Capture",
1415*4882a593Smuzhiyun 		.channels_min = 1,
1416*4882a593Smuzhiyun 		.channels_max = 2,
1417*4882a593Smuzhiyun 		.rates = WM8753_RATES,
1418*4882a593Smuzhiyun 		.formats = WM8753_FORMATS
1419*4882a593Smuzhiyun 	},
1420*4882a593Smuzhiyun 	.ops = &wm8753_dai_ops_hifi_mode,
1421*4882a593Smuzhiyun },
1422*4882a593Smuzhiyun /* DAI Voice mode 1 */
1423*4882a593Smuzhiyun {	.name = "wm8753-voice",
1424*4882a593Smuzhiyun 	.playback = {
1425*4882a593Smuzhiyun 		.stream_name = "Voice Playback",
1426*4882a593Smuzhiyun 		.channels_min = 1,
1427*4882a593Smuzhiyun 		.channels_max = 1,
1428*4882a593Smuzhiyun 		.rates = WM8753_RATES,
1429*4882a593Smuzhiyun 		.formats = WM8753_FORMATS,
1430*4882a593Smuzhiyun 	},
1431*4882a593Smuzhiyun 	.capture = {
1432*4882a593Smuzhiyun 		.stream_name = "Capture",
1433*4882a593Smuzhiyun 		.channels_min = 1,
1434*4882a593Smuzhiyun 		.channels_max = 2,
1435*4882a593Smuzhiyun 		.rates = WM8753_RATES,
1436*4882a593Smuzhiyun 		.formats = WM8753_FORMATS,
1437*4882a593Smuzhiyun 	},
1438*4882a593Smuzhiyun 	.ops = &wm8753_dai_ops_voice_mode,
1439*4882a593Smuzhiyun },
1440*4882a593Smuzhiyun };
1441*4882a593Smuzhiyun 
wm8753_resume(struct snd_soc_component * component)1442*4882a593Smuzhiyun static int wm8753_resume(struct snd_soc_component *component)
1443*4882a593Smuzhiyun {
1444*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
1445*4882a593Smuzhiyun 
1446*4882a593Smuzhiyun 	regcache_sync(wm8753->regmap);
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun 	return 0;
1449*4882a593Smuzhiyun }
1450*4882a593Smuzhiyun 
wm8753_probe(struct snd_soc_component * component)1451*4882a593Smuzhiyun static int wm8753_probe(struct snd_soc_component *component)
1452*4882a593Smuzhiyun {
1453*4882a593Smuzhiyun 	struct wm8753_priv *wm8753 = snd_soc_component_get_drvdata(component);
1454*4882a593Smuzhiyun 	int ret;
1455*4882a593Smuzhiyun 
1456*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&wm8753->charge_work, wm8753_charge_work);
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun 	ret = wm8753_reset(component);
1459*4882a593Smuzhiyun 	if (ret < 0) {
1460*4882a593Smuzhiyun 		dev_err(component->dev, "Failed to issue reset: %d\n", ret);
1461*4882a593Smuzhiyun 		return ret;
1462*4882a593Smuzhiyun 	}
1463*4882a593Smuzhiyun 
1464*4882a593Smuzhiyun 	wm8753->dai_func = 0;
1465*4882a593Smuzhiyun 
1466*4882a593Smuzhiyun 	/* set the update bits */
1467*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8753_LDAC, 0x0100, 0x0100);
1468*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8753_RDAC, 0x0100, 0x0100);
1469*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8753_LADC, 0x0100, 0x0100);
1470*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8753_RADC, 0x0100, 0x0100);
1471*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8753_LOUT1V, 0x0100, 0x0100);
1472*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8753_ROUT1V, 0x0100, 0x0100);
1473*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8753_LOUT2V, 0x0100, 0x0100);
1474*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8753_ROUT2V, 0x0100, 0x0100);
1475*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8753_LINVOL, 0x0100, 0x0100);
1476*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8753_RINVOL, 0x0100, 0x0100);
1477*4882a593Smuzhiyun 
1478*4882a593Smuzhiyun 	return 0;
1479*4882a593Smuzhiyun }
1480*4882a593Smuzhiyun 
1481*4882a593Smuzhiyun static const struct snd_soc_component_driver soc_component_dev_wm8753 = {
1482*4882a593Smuzhiyun 	.probe			= wm8753_probe,
1483*4882a593Smuzhiyun 	.resume			= wm8753_resume,
1484*4882a593Smuzhiyun 	.set_bias_level		= wm8753_set_bias_level,
1485*4882a593Smuzhiyun 	.controls		= wm8753_snd_controls,
1486*4882a593Smuzhiyun 	.num_controls		= ARRAY_SIZE(wm8753_snd_controls),
1487*4882a593Smuzhiyun 	.dapm_widgets		= wm8753_dapm_widgets,
1488*4882a593Smuzhiyun 	.num_dapm_widgets	= ARRAY_SIZE(wm8753_dapm_widgets),
1489*4882a593Smuzhiyun 	.dapm_routes		= wm8753_dapm_routes,
1490*4882a593Smuzhiyun 	.num_dapm_routes	= ARRAY_SIZE(wm8753_dapm_routes),
1491*4882a593Smuzhiyun 	.suspend_bias_off	= 1,
1492*4882a593Smuzhiyun 	.idle_bias_on		= 1,
1493*4882a593Smuzhiyun 	.use_pmdown_time	= 1,
1494*4882a593Smuzhiyun 	.endianness		= 1,
1495*4882a593Smuzhiyun 	.non_legacy_dai_naming	= 1,
1496*4882a593Smuzhiyun };
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun static const struct of_device_id wm8753_of_match[] = {
1499*4882a593Smuzhiyun 	{ .compatible = "wlf,wm8753", },
1500*4882a593Smuzhiyun 	{ }
1501*4882a593Smuzhiyun };
1502*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, wm8753_of_match);
1503*4882a593Smuzhiyun 
1504*4882a593Smuzhiyun static const struct regmap_config wm8753_regmap = {
1505*4882a593Smuzhiyun 	.reg_bits = 7,
1506*4882a593Smuzhiyun 	.val_bits = 9,
1507*4882a593Smuzhiyun 
1508*4882a593Smuzhiyun 	.max_register = WM8753_ADCTL2,
1509*4882a593Smuzhiyun 	.volatile_reg = wm8753_volatile,
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun 	.cache_type = REGCACHE_RBTREE,
1512*4882a593Smuzhiyun 	.reg_defaults = wm8753_reg_defaults,
1513*4882a593Smuzhiyun 	.num_reg_defaults = ARRAY_SIZE(wm8753_reg_defaults),
1514*4882a593Smuzhiyun };
1515*4882a593Smuzhiyun 
1516*4882a593Smuzhiyun #if defined(CONFIG_SPI_MASTER)
wm8753_spi_probe(struct spi_device * spi)1517*4882a593Smuzhiyun static int wm8753_spi_probe(struct spi_device *spi)
1518*4882a593Smuzhiyun {
1519*4882a593Smuzhiyun 	struct wm8753_priv *wm8753;
1520*4882a593Smuzhiyun 	int ret;
1521*4882a593Smuzhiyun 
1522*4882a593Smuzhiyun 	wm8753 = devm_kzalloc(&spi->dev, sizeof(struct wm8753_priv),
1523*4882a593Smuzhiyun 			      GFP_KERNEL);
1524*4882a593Smuzhiyun 	if (wm8753 == NULL)
1525*4882a593Smuzhiyun 		return -ENOMEM;
1526*4882a593Smuzhiyun 
1527*4882a593Smuzhiyun 	spi_set_drvdata(spi, wm8753);
1528*4882a593Smuzhiyun 
1529*4882a593Smuzhiyun 	wm8753->regmap = devm_regmap_init_spi(spi, &wm8753_regmap);
1530*4882a593Smuzhiyun 	if (IS_ERR(wm8753->regmap)) {
1531*4882a593Smuzhiyun 		ret = PTR_ERR(wm8753->regmap);
1532*4882a593Smuzhiyun 		dev_err(&spi->dev, "Failed to allocate register map: %d\n",
1533*4882a593Smuzhiyun 			ret);
1534*4882a593Smuzhiyun 		return ret;
1535*4882a593Smuzhiyun 	}
1536*4882a593Smuzhiyun 
1537*4882a593Smuzhiyun 	ret = devm_snd_soc_register_component(&spi->dev, &soc_component_dev_wm8753,
1538*4882a593Smuzhiyun 				     wm8753_dai, ARRAY_SIZE(wm8753_dai));
1539*4882a593Smuzhiyun 	if (ret != 0)
1540*4882a593Smuzhiyun 		dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret);
1541*4882a593Smuzhiyun 
1542*4882a593Smuzhiyun 	return ret;
1543*4882a593Smuzhiyun }
1544*4882a593Smuzhiyun 
1545*4882a593Smuzhiyun static struct spi_driver wm8753_spi_driver = {
1546*4882a593Smuzhiyun 	.driver = {
1547*4882a593Smuzhiyun 		.name	= "wm8753",
1548*4882a593Smuzhiyun 		.of_match_table = wm8753_of_match,
1549*4882a593Smuzhiyun 	},
1550*4882a593Smuzhiyun 	.probe		= wm8753_spi_probe,
1551*4882a593Smuzhiyun };
1552*4882a593Smuzhiyun #endif /* CONFIG_SPI_MASTER */
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_I2C)
wm8753_i2c_probe(struct i2c_client * i2c,const struct i2c_device_id * id)1555*4882a593Smuzhiyun static int wm8753_i2c_probe(struct i2c_client *i2c,
1556*4882a593Smuzhiyun 			    const struct i2c_device_id *id)
1557*4882a593Smuzhiyun {
1558*4882a593Smuzhiyun 	struct wm8753_priv *wm8753;
1559*4882a593Smuzhiyun 	int ret;
1560*4882a593Smuzhiyun 
1561*4882a593Smuzhiyun 	wm8753 = devm_kzalloc(&i2c->dev, sizeof(struct wm8753_priv),
1562*4882a593Smuzhiyun 			      GFP_KERNEL);
1563*4882a593Smuzhiyun 	if (wm8753 == NULL)
1564*4882a593Smuzhiyun 		return -ENOMEM;
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun 	i2c_set_clientdata(i2c, wm8753);
1567*4882a593Smuzhiyun 
1568*4882a593Smuzhiyun 	wm8753->regmap = devm_regmap_init_i2c(i2c, &wm8753_regmap);
1569*4882a593Smuzhiyun 	if (IS_ERR(wm8753->regmap)) {
1570*4882a593Smuzhiyun 		ret = PTR_ERR(wm8753->regmap);
1571*4882a593Smuzhiyun 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
1572*4882a593Smuzhiyun 			ret);
1573*4882a593Smuzhiyun 		return ret;
1574*4882a593Smuzhiyun 	}
1575*4882a593Smuzhiyun 
1576*4882a593Smuzhiyun 	ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_wm8753,
1577*4882a593Smuzhiyun 				     wm8753_dai, ARRAY_SIZE(wm8753_dai));
1578*4882a593Smuzhiyun 	if (ret != 0)
1579*4882a593Smuzhiyun 		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
1580*4882a593Smuzhiyun 
1581*4882a593Smuzhiyun 	return ret;
1582*4882a593Smuzhiyun }
1583*4882a593Smuzhiyun 
1584*4882a593Smuzhiyun static const struct i2c_device_id wm8753_i2c_id[] = {
1585*4882a593Smuzhiyun 	{ "wm8753", 0 },
1586*4882a593Smuzhiyun 	{ }
1587*4882a593Smuzhiyun };
1588*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
1589*4882a593Smuzhiyun 
1590*4882a593Smuzhiyun static struct i2c_driver wm8753_i2c_driver = {
1591*4882a593Smuzhiyun 	.driver = {
1592*4882a593Smuzhiyun 		.name = "wm8753",
1593*4882a593Smuzhiyun 		.of_match_table = wm8753_of_match,
1594*4882a593Smuzhiyun 	},
1595*4882a593Smuzhiyun 	.probe =    wm8753_i2c_probe,
1596*4882a593Smuzhiyun 	.id_table = wm8753_i2c_id,
1597*4882a593Smuzhiyun };
1598*4882a593Smuzhiyun #endif
1599*4882a593Smuzhiyun 
wm8753_modinit(void)1600*4882a593Smuzhiyun static int __init wm8753_modinit(void)
1601*4882a593Smuzhiyun {
1602*4882a593Smuzhiyun 	int ret = 0;
1603*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_I2C)
1604*4882a593Smuzhiyun 	ret = i2c_add_driver(&wm8753_i2c_driver);
1605*4882a593Smuzhiyun 	if (ret != 0) {
1606*4882a593Smuzhiyun 		printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n",
1607*4882a593Smuzhiyun 		       ret);
1608*4882a593Smuzhiyun 	}
1609*4882a593Smuzhiyun #endif
1610*4882a593Smuzhiyun #if defined(CONFIG_SPI_MASTER)
1611*4882a593Smuzhiyun 	ret = spi_register_driver(&wm8753_spi_driver);
1612*4882a593Smuzhiyun 	if (ret != 0) {
1613*4882a593Smuzhiyun 		printk(KERN_ERR "Failed to register wm8753 SPI driver: %d\n",
1614*4882a593Smuzhiyun 		       ret);
1615*4882a593Smuzhiyun 	}
1616*4882a593Smuzhiyun #endif
1617*4882a593Smuzhiyun 	return ret;
1618*4882a593Smuzhiyun }
1619*4882a593Smuzhiyun module_init(wm8753_modinit);
1620*4882a593Smuzhiyun 
wm8753_exit(void)1621*4882a593Smuzhiyun static void __exit wm8753_exit(void)
1622*4882a593Smuzhiyun {
1623*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_I2C)
1624*4882a593Smuzhiyun 	i2c_del_driver(&wm8753_i2c_driver);
1625*4882a593Smuzhiyun #endif
1626*4882a593Smuzhiyun #if defined(CONFIG_SPI_MASTER)
1627*4882a593Smuzhiyun 	spi_unregister_driver(&wm8753_spi_driver);
1628*4882a593Smuzhiyun #endif
1629*4882a593Smuzhiyun }
1630*4882a593Smuzhiyun module_exit(wm8753_exit);
1631*4882a593Smuzhiyun 
1632*4882a593Smuzhiyun MODULE_DESCRIPTION("ASoC WM8753 driver");
1633*4882a593Smuzhiyun MODULE_AUTHOR("Liam Girdwood");
1634*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1635