xref: /OK3568_Linux_fs/kernel/sound/soc/codecs/wm8580.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * wm8580.c  --  WM8580 and WM8581 ALSA Soc Audio driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2008-12 Wolfson Microelectronics PLC.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Notes:
8*4882a593Smuzhiyun  *  The WM8580 is a multichannel codec with S/PDIF support, featuring six
9*4882a593Smuzhiyun  *  DAC channels and two ADC channels.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  *  The WM8581 is a multichannel codec with S/PDIF support, featuring eight
12*4882a593Smuzhiyun  *  DAC channels and two ADC channels.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  *  Currently only the primary audio interface is supported - S/PDIF and
15*4882a593Smuzhiyun  *  the secondary audio interfaces are not.
16*4882a593Smuzhiyun  */
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <linux/module.h>
19*4882a593Smuzhiyun #include <linux/moduleparam.h>
20*4882a593Smuzhiyun #include <linux/kernel.h>
21*4882a593Smuzhiyun #include <linux/init.h>
22*4882a593Smuzhiyun #include <linux/delay.h>
23*4882a593Smuzhiyun #include <linux/pm.h>
24*4882a593Smuzhiyun #include <linux/i2c.h>
25*4882a593Smuzhiyun #include <linux/regmap.h>
26*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
27*4882a593Smuzhiyun #include <linux/slab.h>
28*4882a593Smuzhiyun #include <linux/of_device.h>
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #include <sound/core.h>
31*4882a593Smuzhiyun #include <sound/pcm.h>
32*4882a593Smuzhiyun #include <sound/pcm_params.h>
33*4882a593Smuzhiyun #include <sound/soc.h>
34*4882a593Smuzhiyun #include <sound/tlv.h>
35*4882a593Smuzhiyun #include <sound/initval.h>
36*4882a593Smuzhiyun #include <asm/div64.h>
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #include "wm8580.h"
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /* WM8580 register space */
41*4882a593Smuzhiyun #define WM8580_PLLA1                         0x00
42*4882a593Smuzhiyun #define WM8580_PLLA2                         0x01
43*4882a593Smuzhiyun #define WM8580_PLLA3                         0x02
44*4882a593Smuzhiyun #define WM8580_PLLA4                         0x03
45*4882a593Smuzhiyun #define WM8580_PLLB1                         0x04
46*4882a593Smuzhiyun #define WM8580_PLLB2                         0x05
47*4882a593Smuzhiyun #define WM8580_PLLB3                         0x06
48*4882a593Smuzhiyun #define WM8580_PLLB4                         0x07
49*4882a593Smuzhiyun #define WM8580_CLKSEL                        0x08
50*4882a593Smuzhiyun #define WM8580_PAIF1                         0x09
51*4882a593Smuzhiyun #define WM8580_PAIF2                         0x0A
52*4882a593Smuzhiyun #define WM8580_SAIF1                         0x0B
53*4882a593Smuzhiyun #define WM8580_PAIF3                         0x0C
54*4882a593Smuzhiyun #define WM8580_PAIF4                         0x0D
55*4882a593Smuzhiyun #define WM8580_SAIF2                         0x0E
56*4882a593Smuzhiyun #define WM8580_DAC_CONTROL1                  0x0F
57*4882a593Smuzhiyun #define WM8580_DAC_CONTROL2                  0x10
58*4882a593Smuzhiyun #define WM8580_DAC_CONTROL3                  0x11
59*4882a593Smuzhiyun #define WM8580_DAC_CONTROL4                  0x12
60*4882a593Smuzhiyun #define WM8580_DAC_CONTROL5                  0x13
61*4882a593Smuzhiyun #define WM8580_DIGITAL_ATTENUATION_DACL1     0x14
62*4882a593Smuzhiyun #define WM8580_DIGITAL_ATTENUATION_DACR1     0x15
63*4882a593Smuzhiyun #define WM8580_DIGITAL_ATTENUATION_DACL2     0x16
64*4882a593Smuzhiyun #define WM8580_DIGITAL_ATTENUATION_DACR2     0x17
65*4882a593Smuzhiyun #define WM8580_DIGITAL_ATTENUATION_DACL3     0x18
66*4882a593Smuzhiyun #define WM8580_DIGITAL_ATTENUATION_DACR3     0x19
67*4882a593Smuzhiyun #define WM8581_DIGITAL_ATTENUATION_DACL4     0x1A
68*4882a593Smuzhiyun #define WM8581_DIGITAL_ATTENUATION_DACR4     0x1B
69*4882a593Smuzhiyun #define WM8580_MASTER_DIGITAL_ATTENUATION    0x1C
70*4882a593Smuzhiyun #define WM8580_ADC_CONTROL1                  0x1D
71*4882a593Smuzhiyun #define WM8580_SPDTXCHAN0                    0x1E
72*4882a593Smuzhiyun #define WM8580_SPDTXCHAN1                    0x1F
73*4882a593Smuzhiyun #define WM8580_SPDTXCHAN2                    0x20
74*4882a593Smuzhiyun #define WM8580_SPDTXCHAN3                    0x21
75*4882a593Smuzhiyun #define WM8580_SPDTXCHAN4                    0x22
76*4882a593Smuzhiyun #define WM8580_SPDTXCHAN5                    0x23
77*4882a593Smuzhiyun #define WM8580_SPDMODE                       0x24
78*4882a593Smuzhiyun #define WM8580_INTMASK                       0x25
79*4882a593Smuzhiyun #define WM8580_GPO1                          0x26
80*4882a593Smuzhiyun #define WM8580_GPO2                          0x27
81*4882a593Smuzhiyun #define WM8580_GPO3                          0x28
82*4882a593Smuzhiyun #define WM8580_GPO4                          0x29
83*4882a593Smuzhiyun #define WM8580_GPO5                          0x2A
84*4882a593Smuzhiyun #define WM8580_INTSTAT                       0x2B
85*4882a593Smuzhiyun #define WM8580_SPDRXCHAN1                    0x2C
86*4882a593Smuzhiyun #define WM8580_SPDRXCHAN2                    0x2D
87*4882a593Smuzhiyun #define WM8580_SPDRXCHAN3                    0x2E
88*4882a593Smuzhiyun #define WM8580_SPDRXCHAN4                    0x2F
89*4882a593Smuzhiyun #define WM8580_SPDRXCHAN5                    0x30
90*4882a593Smuzhiyun #define WM8580_SPDSTAT                       0x31
91*4882a593Smuzhiyun #define WM8580_PWRDN1                        0x32
92*4882a593Smuzhiyun #define WM8580_PWRDN2                        0x33
93*4882a593Smuzhiyun #define WM8580_READBACK                      0x34
94*4882a593Smuzhiyun #define WM8580_RESET                         0x35
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun #define WM8580_MAX_REGISTER                  0x35
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun #define WM8580_DACOSR 0x40
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun /* PLLB4 (register 7h) */
101*4882a593Smuzhiyun #define WM8580_PLLB4_MCLKOUTSRC_MASK   0x60
102*4882a593Smuzhiyun #define WM8580_PLLB4_MCLKOUTSRC_PLLA   0x20
103*4882a593Smuzhiyun #define WM8580_PLLB4_MCLKOUTSRC_PLLB   0x40
104*4882a593Smuzhiyun #define WM8580_PLLB4_MCLKOUTSRC_OSC    0x60
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun #define WM8580_PLLB4_CLKOUTSRC_MASK    0x180
107*4882a593Smuzhiyun #define WM8580_PLLB4_CLKOUTSRC_PLLACLK 0x080
108*4882a593Smuzhiyun #define WM8580_PLLB4_CLKOUTSRC_PLLBCLK 0x100
109*4882a593Smuzhiyun #define WM8580_PLLB4_CLKOUTSRC_OSCCLK  0x180
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun /* CLKSEL (register 8h) */
112*4882a593Smuzhiyun #define WM8580_CLKSEL_DAC_CLKSEL_MASK 0x03
113*4882a593Smuzhiyun #define WM8580_CLKSEL_DAC_CLKSEL_PLLA 0x01
114*4882a593Smuzhiyun #define WM8580_CLKSEL_DAC_CLKSEL_PLLB 0x02
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun /* AIF control 1 (registers 9h-bh) */
117*4882a593Smuzhiyun #define WM8580_AIF_RATE_MASK       0x7
118*4882a593Smuzhiyun #define WM8580_AIF_BCLKSEL_MASK   0x18
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun #define WM8580_AIF_MS             0x20
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun #define WM8580_AIF_CLKSRC_MASK    0xc0
123*4882a593Smuzhiyun #define WM8580_AIF_CLKSRC_PLLA    0x40
124*4882a593Smuzhiyun #define WM8580_AIF_CLKSRC_PLLB    0x40
125*4882a593Smuzhiyun #define WM8580_AIF_CLKSRC_MCLK    0xc0
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun /* AIF control 2 (registers ch-eh) */
128*4882a593Smuzhiyun #define WM8580_AIF_FMT_MASK    0x03
129*4882a593Smuzhiyun #define WM8580_AIF_FMT_RIGHTJ  0x00
130*4882a593Smuzhiyun #define WM8580_AIF_FMT_LEFTJ   0x01
131*4882a593Smuzhiyun #define WM8580_AIF_FMT_I2S     0x02
132*4882a593Smuzhiyun #define WM8580_AIF_FMT_DSP     0x03
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun #define WM8580_AIF_LENGTH_MASK   0x0c
135*4882a593Smuzhiyun #define WM8580_AIF_LENGTH_16     0x00
136*4882a593Smuzhiyun #define WM8580_AIF_LENGTH_20     0x04
137*4882a593Smuzhiyun #define WM8580_AIF_LENGTH_24     0x08
138*4882a593Smuzhiyun #define WM8580_AIF_LENGTH_32     0x0c
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun #define WM8580_AIF_LRP         0x10
141*4882a593Smuzhiyun #define WM8580_AIF_BCP         0x20
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun /* Powerdown Register 1 (register 32h) */
144*4882a593Smuzhiyun #define WM8580_PWRDN1_PWDN     0x001
145*4882a593Smuzhiyun #define WM8580_PWRDN1_ALLDACPD 0x040
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun /* Powerdown Register 2 (register 33h) */
148*4882a593Smuzhiyun #define WM8580_PWRDN2_OSSCPD   0x001
149*4882a593Smuzhiyun #define WM8580_PWRDN2_PLLAPD   0x002
150*4882a593Smuzhiyun #define WM8580_PWRDN2_PLLBPD   0x004
151*4882a593Smuzhiyun #define WM8580_PWRDN2_SPDIFPD  0x008
152*4882a593Smuzhiyun #define WM8580_PWRDN2_SPDIFTXD 0x010
153*4882a593Smuzhiyun #define WM8580_PWRDN2_SPDIFRXD 0x020
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun #define WM8580_DAC_CONTROL5_MUTEALL 0x10
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun /*
158*4882a593Smuzhiyun  * wm8580 register cache
159*4882a593Smuzhiyun  * We can't read the WM8580 register space when we
160*4882a593Smuzhiyun  * are using 2 wire for device control, so we cache them instead.
161*4882a593Smuzhiyun  */
162*4882a593Smuzhiyun static const struct reg_default wm8580_reg_defaults[] = {
163*4882a593Smuzhiyun 	{  0, 0x0121 },
164*4882a593Smuzhiyun 	{  1, 0x017e },
165*4882a593Smuzhiyun 	{  2, 0x007d },
166*4882a593Smuzhiyun 	{  3, 0x0014 },
167*4882a593Smuzhiyun 	{  4, 0x0121 },
168*4882a593Smuzhiyun 	{  5, 0x017e },
169*4882a593Smuzhiyun 	{  6, 0x007d },
170*4882a593Smuzhiyun 	{  7, 0x0194 },
171*4882a593Smuzhiyun 	{  8, 0x0010 },
172*4882a593Smuzhiyun 	{  9, 0x0002 },
173*4882a593Smuzhiyun 	{ 10, 0x0002 },
174*4882a593Smuzhiyun 	{ 11, 0x00c2 },
175*4882a593Smuzhiyun 	{ 12, 0x0182 },
176*4882a593Smuzhiyun 	{ 13, 0x0082 },
177*4882a593Smuzhiyun 	{ 14, 0x000a },
178*4882a593Smuzhiyun 	{ 15, 0x0024 },
179*4882a593Smuzhiyun 	{ 16, 0x0009 },
180*4882a593Smuzhiyun 	{ 17, 0x0000 },
181*4882a593Smuzhiyun 	{ 18, 0x00ff },
182*4882a593Smuzhiyun 	{ 19, 0x0000 },
183*4882a593Smuzhiyun 	{ 20, 0x00ff },
184*4882a593Smuzhiyun 	{ 21, 0x00ff },
185*4882a593Smuzhiyun 	{ 22, 0x00ff },
186*4882a593Smuzhiyun 	{ 23, 0x00ff },
187*4882a593Smuzhiyun 	{ 24, 0x00ff },
188*4882a593Smuzhiyun 	{ 25, 0x00ff },
189*4882a593Smuzhiyun 	{ 26, 0x00ff },
190*4882a593Smuzhiyun 	{ 27, 0x00ff },
191*4882a593Smuzhiyun 	{ 28, 0x01f0 },
192*4882a593Smuzhiyun 	{ 29, 0x0040 },
193*4882a593Smuzhiyun 	{ 30, 0x0000 },
194*4882a593Smuzhiyun 	{ 31, 0x0000 },
195*4882a593Smuzhiyun 	{ 32, 0x0000 },
196*4882a593Smuzhiyun 	{ 33, 0x0000 },
197*4882a593Smuzhiyun 	{ 34, 0x0031 },
198*4882a593Smuzhiyun 	{ 35, 0x000b },
199*4882a593Smuzhiyun 	{ 36, 0x0039 },
200*4882a593Smuzhiyun 	{ 37, 0x0000 },
201*4882a593Smuzhiyun 	{ 38, 0x0010 },
202*4882a593Smuzhiyun 	{ 39, 0x0032 },
203*4882a593Smuzhiyun 	{ 40, 0x0054 },
204*4882a593Smuzhiyun 	{ 41, 0x0076 },
205*4882a593Smuzhiyun 	{ 42, 0x0098 },
206*4882a593Smuzhiyun 	{ 43, 0x0000 },
207*4882a593Smuzhiyun 	{ 44, 0x0000 },
208*4882a593Smuzhiyun 	{ 45, 0x0000 },
209*4882a593Smuzhiyun 	{ 46, 0x0000 },
210*4882a593Smuzhiyun 	{ 47, 0x0000 },
211*4882a593Smuzhiyun 	{ 48, 0x0000 },
212*4882a593Smuzhiyun 	{ 49, 0x0000 },
213*4882a593Smuzhiyun 	{ 50, 0x005e },
214*4882a593Smuzhiyun 	{ 51, 0x003e },
215*4882a593Smuzhiyun 	{ 52, 0x0000 },
216*4882a593Smuzhiyun };
217*4882a593Smuzhiyun 
wm8580_volatile(struct device * dev,unsigned int reg)218*4882a593Smuzhiyun static bool wm8580_volatile(struct device *dev, unsigned int reg)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	switch (reg) {
221*4882a593Smuzhiyun 	case WM8580_RESET:
222*4882a593Smuzhiyun 		return true;
223*4882a593Smuzhiyun 	default:
224*4882a593Smuzhiyun 		return false;
225*4882a593Smuzhiyun 	}
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun struct pll_state {
229*4882a593Smuzhiyun 	unsigned int in;
230*4882a593Smuzhiyun 	unsigned int out;
231*4882a593Smuzhiyun };
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun #define WM8580_NUM_SUPPLIES 3
234*4882a593Smuzhiyun static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {
235*4882a593Smuzhiyun 	"AVDD",
236*4882a593Smuzhiyun 	"DVDD",
237*4882a593Smuzhiyun 	"PVDD",
238*4882a593Smuzhiyun };
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun struct wm8580_driver_data {
241*4882a593Smuzhiyun 	int num_dacs;
242*4882a593Smuzhiyun };
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun /* codec private data */
245*4882a593Smuzhiyun struct wm8580_priv {
246*4882a593Smuzhiyun 	struct regmap *regmap;
247*4882a593Smuzhiyun 	struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES];
248*4882a593Smuzhiyun 	struct pll_state a;
249*4882a593Smuzhiyun 	struct pll_state b;
250*4882a593Smuzhiyun 	const struct wm8580_driver_data *drvdata;
251*4882a593Smuzhiyun 	int sysclk[2];
252*4882a593Smuzhiyun };
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
255*4882a593Smuzhiyun 
wm8580_out_vu(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)256*4882a593Smuzhiyun static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
257*4882a593Smuzhiyun 			 struct snd_ctl_elem_value *ucontrol)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	struct soc_mixer_control *mc =
260*4882a593Smuzhiyun 		(struct soc_mixer_control *)kcontrol->private_value;
261*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
262*4882a593Smuzhiyun 	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
263*4882a593Smuzhiyun 	unsigned int reg = mc->reg;
264*4882a593Smuzhiyun 	unsigned int reg2 = mc->rreg;
265*4882a593Smuzhiyun 	int ret;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	/* Clear the register cache VU so we write without VU set */
268*4882a593Smuzhiyun 	regcache_cache_only(wm8580->regmap, true);
269*4882a593Smuzhiyun 	regmap_update_bits(wm8580->regmap, reg, 0x100, 0x000);
270*4882a593Smuzhiyun 	regmap_update_bits(wm8580->regmap, reg2, 0x100, 0x000);
271*4882a593Smuzhiyun 	regcache_cache_only(wm8580->regmap, false);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	ret = snd_soc_put_volsw(kcontrol, ucontrol);
274*4882a593Smuzhiyun 	if (ret < 0)
275*4882a593Smuzhiyun 		return ret;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	/* Now write again with the volume update bit set */
278*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, reg, 0x100, 0x100);
279*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, reg2, 0x100, 0x100);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	return 0;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8580_snd_controls[] = {
285*4882a593Smuzhiyun SOC_DOUBLE_R_EXT_TLV("DAC1 Playback Volume",
286*4882a593Smuzhiyun 		     WM8580_DIGITAL_ATTENUATION_DACL1,
287*4882a593Smuzhiyun 		     WM8580_DIGITAL_ATTENUATION_DACR1,
288*4882a593Smuzhiyun 		     0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
289*4882a593Smuzhiyun SOC_DOUBLE_R_EXT_TLV("DAC2 Playback Volume",
290*4882a593Smuzhiyun 		     WM8580_DIGITAL_ATTENUATION_DACL2,
291*4882a593Smuzhiyun 		     WM8580_DIGITAL_ATTENUATION_DACR2,
292*4882a593Smuzhiyun 		     0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
293*4882a593Smuzhiyun SOC_DOUBLE_R_EXT_TLV("DAC3 Playback Volume",
294*4882a593Smuzhiyun 		     WM8580_DIGITAL_ATTENUATION_DACL3,
295*4882a593Smuzhiyun 		     WM8580_DIGITAL_ATTENUATION_DACR3,
296*4882a593Smuzhiyun 		     0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun SOC_SINGLE("DAC1 Deemphasis Switch", WM8580_DAC_CONTROL3, 0, 1, 0),
299*4882a593Smuzhiyun SOC_SINGLE("DAC2 Deemphasis Switch", WM8580_DAC_CONTROL3, 1, 1, 0),
300*4882a593Smuzhiyun SOC_SINGLE("DAC3 Deemphasis Switch", WM8580_DAC_CONTROL3, 2, 1, 0),
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun SOC_DOUBLE("DAC1 Invert Switch", WM8580_DAC_CONTROL4,  0, 1, 1, 0),
303*4882a593Smuzhiyun SOC_DOUBLE("DAC2 Invert Switch", WM8580_DAC_CONTROL4,  2, 3, 1, 0),
304*4882a593Smuzhiyun SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4,  4, 5, 1, 0),
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0),
307*4882a593Smuzhiyun SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 1),
308*4882a593Smuzhiyun SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 1),
309*4882a593Smuzhiyun SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 1),
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun SOC_DOUBLE("Capture Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 1),
312*4882a593Smuzhiyun SOC_SINGLE("Capture High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
313*4882a593Smuzhiyun };
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8581_snd_controls[] = {
316*4882a593Smuzhiyun SOC_DOUBLE_R_EXT_TLV("DAC4 Playback Volume",
317*4882a593Smuzhiyun 		     WM8581_DIGITAL_ATTENUATION_DACL4,
318*4882a593Smuzhiyun 		     WM8581_DIGITAL_ATTENUATION_DACR4,
319*4882a593Smuzhiyun 		     0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun SOC_SINGLE("DAC4 Deemphasis Switch", WM8580_DAC_CONTROL3, 3, 1, 0),
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun SOC_DOUBLE("DAC4 Invert Switch", WM8580_DAC_CONTROL4,  8, 7, 1, 0),
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun SOC_SINGLE("DAC4 Switch", WM8580_DAC_CONTROL5, 3, 1, 1),
326*4882a593Smuzhiyun };
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = {
329*4882a593Smuzhiyun SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1),
330*4882a593Smuzhiyun SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1),
331*4882a593Smuzhiyun SND_SOC_DAPM_DAC("DAC3", "Playback", WM8580_PWRDN1, 4, 1),
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("VOUT1L"),
334*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("VOUT1R"),
335*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("VOUT2L"),
336*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("VOUT2R"),
337*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("VOUT3L"),
338*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("VOUT3R"),
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun SND_SOC_DAPM_ADC("ADC", "Capture", WM8580_PWRDN1, 1, 1),
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("AINL"),
343*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("AINR"),
344*4882a593Smuzhiyun };
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun static const struct snd_soc_dapm_widget wm8581_dapm_widgets[] = {
347*4882a593Smuzhiyun SND_SOC_DAPM_DAC("DAC4", "Playback", WM8580_PWRDN1, 5, 1),
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("VOUT4L"),
350*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("VOUT4R"),
351*4882a593Smuzhiyun };
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun static const struct snd_soc_dapm_route wm8580_dapm_routes[] = {
354*4882a593Smuzhiyun 	{ "VOUT1L", NULL, "DAC1" },
355*4882a593Smuzhiyun 	{ "VOUT1R", NULL, "DAC1" },
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	{ "VOUT2L", NULL, "DAC2" },
358*4882a593Smuzhiyun 	{ "VOUT2R", NULL, "DAC2" },
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	{ "VOUT3L", NULL, "DAC3" },
361*4882a593Smuzhiyun 	{ "VOUT3R", NULL, "DAC3" },
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	{ "ADC", NULL, "AINL" },
364*4882a593Smuzhiyun 	{ "ADC", NULL, "AINR" },
365*4882a593Smuzhiyun };
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun static const struct snd_soc_dapm_route wm8581_dapm_routes[] = {
368*4882a593Smuzhiyun 	{ "VOUT4L", NULL, "DAC4" },
369*4882a593Smuzhiyun 	{ "VOUT4R", NULL, "DAC4" },
370*4882a593Smuzhiyun };
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun /* PLL divisors */
373*4882a593Smuzhiyun struct _pll_div {
374*4882a593Smuzhiyun 	u32 prescale:1;
375*4882a593Smuzhiyun 	u32 postscale:1;
376*4882a593Smuzhiyun 	u32 freqmode:2;
377*4882a593Smuzhiyun 	u32 n:4;
378*4882a593Smuzhiyun 	u32 k:24;
379*4882a593Smuzhiyun };
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun /* The size in bits of the pll divide */
382*4882a593Smuzhiyun #define FIXED_PLL_SIZE (1 << 22)
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun /* PLL rate to output rate divisions */
385*4882a593Smuzhiyun static struct {
386*4882a593Smuzhiyun 	unsigned int div;
387*4882a593Smuzhiyun 	unsigned int freqmode;
388*4882a593Smuzhiyun 	unsigned int postscale;
389*4882a593Smuzhiyun } post_table[] = {
390*4882a593Smuzhiyun 	{  2,  0, 0 },
391*4882a593Smuzhiyun 	{  4,  0, 1 },
392*4882a593Smuzhiyun 	{  4,  1, 0 },
393*4882a593Smuzhiyun 	{  8,  1, 1 },
394*4882a593Smuzhiyun 	{  8,  2, 0 },
395*4882a593Smuzhiyun 	{ 16,  2, 1 },
396*4882a593Smuzhiyun 	{ 12,  3, 0 },
397*4882a593Smuzhiyun 	{ 24,  3, 1 }
398*4882a593Smuzhiyun };
399*4882a593Smuzhiyun 
pll_factors(struct _pll_div * pll_div,unsigned int target,unsigned int source)400*4882a593Smuzhiyun static int pll_factors(struct _pll_div *pll_div, unsigned int target,
401*4882a593Smuzhiyun 		       unsigned int source)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun 	u64 Kpart;
404*4882a593Smuzhiyun 	unsigned int K, Ndiv, Nmod;
405*4882a593Smuzhiyun 	int i;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	pr_debug("wm8580: PLL %uHz->%uHz\n", source, target);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	/* Scale the output frequency up; the PLL should run in the
410*4882a593Smuzhiyun 	 * region of 90-100MHz.
411*4882a593Smuzhiyun 	 */
412*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(post_table); i++) {
413*4882a593Smuzhiyun 		if (target * post_table[i].div >=  90000000 &&
414*4882a593Smuzhiyun 		    target * post_table[i].div <= 100000000) {
415*4882a593Smuzhiyun 			pll_div->freqmode = post_table[i].freqmode;
416*4882a593Smuzhiyun 			pll_div->postscale = post_table[i].postscale;
417*4882a593Smuzhiyun 			target *= post_table[i].div;
418*4882a593Smuzhiyun 			break;
419*4882a593Smuzhiyun 		}
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	if (i == ARRAY_SIZE(post_table)) {
423*4882a593Smuzhiyun 		printk(KERN_ERR "wm8580: Unable to scale output frequency "
424*4882a593Smuzhiyun 		       "%u\n", target);
425*4882a593Smuzhiyun 		return -EINVAL;
426*4882a593Smuzhiyun 	}
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	Ndiv = target / source;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	if (Ndiv < 5) {
431*4882a593Smuzhiyun 		source /= 2;
432*4882a593Smuzhiyun 		pll_div->prescale = 1;
433*4882a593Smuzhiyun 		Ndiv = target / source;
434*4882a593Smuzhiyun 	} else
435*4882a593Smuzhiyun 		pll_div->prescale = 0;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	if ((Ndiv < 5) || (Ndiv > 13)) {
438*4882a593Smuzhiyun 		printk(KERN_ERR
439*4882a593Smuzhiyun 			"WM8580 N=%u outside supported range\n", Ndiv);
440*4882a593Smuzhiyun 		return -EINVAL;
441*4882a593Smuzhiyun 	}
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	pll_div->n = Ndiv;
444*4882a593Smuzhiyun 	Nmod = target % source;
445*4882a593Smuzhiyun 	Kpart = FIXED_PLL_SIZE * (long long)Nmod;
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	do_div(Kpart, source);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	K = Kpart & 0xFFFFFFFF;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	pll_div->k = K;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	pr_debug("PLL %x.%x prescale %d freqmode %d postscale %d\n",
454*4882a593Smuzhiyun 		 pll_div->n, pll_div->k, pll_div->prescale, pll_div->freqmode,
455*4882a593Smuzhiyun 		 pll_div->postscale);
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	return 0;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun 
wm8580_set_dai_pll(struct snd_soc_dai * codec_dai,int pll_id,int source,unsigned int freq_in,unsigned int freq_out)460*4882a593Smuzhiyun static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
461*4882a593Smuzhiyun 		int source, unsigned int freq_in, unsigned int freq_out)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun 	int offset;
464*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
465*4882a593Smuzhiyun 	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
466*4882a593Smuzhiyun 	struct pll_state *state;
467*4882a593Smuzhiyun 	struct _pll_div pll_div;
468*4882a593Smuzhiyun 	unsigned int reg;
469*4882a593Smuzhiyun 	unsigned int pwr_mask;
470*4882a593Smuzhiyun 	int ret;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	/* GCC isn't able to work out the ifs below for initialising/using
473*4882a593Smuzhiyun 	 * pll_div so suppress warnings.
474*4882a593Smuzhiyun 	 */
475*4882a593Smuzhiyun 	memset(&pll_div, 0, sizeof(pll_div));
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	switch (pll_id) {
478*4882a593Smuzhiyun 	case WM8580_PLLA:
479*4882a593Smuzhiyun 		state = &wm8580->a;
480*4882a593Smuzhiyun 		offset = 0;
481*4882a593Smuzhiyun 		pwr_mask = WM8580_PWRDN2_PLLAPD;
482*4882a593Smuzhiyun 		break;
483*4882a593Smuzhiyun 	case WM8580_PLLB:
484*4882a593Smuzhiyun 		state = &wm8580->b;
485*4882a593Smuzhiyun 		offset = 4;
486*4882a593Smuzhiyun 		pwr_mask = WM8580_PWRDN2_PLLBPD;
487*4882a593Smuzhiyun 		break;
488*4882a593Smuzhiyun 	default:
489*4882a593Smuzhiyun 		return -ENODEV;
490*4882a593Smuzhiyun 	}
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	if (freq_in && freq_out) {
493*4882a593Smuzhiyun 		ret = pll_factors(&pll_div, freq_out, freq_in);
494*4882a593Smuzhiyun 		if (ret != 0)
495*4882a593Smuzhiyun 			return ret;
496*4882a593Smuzhiyun 	}
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	state->in = freq_in;
499*4882a593Smuzhiyun 	state->out = freq_out;
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	/* Always disable the PLL - it is not safe to leave it running
502*4882a593Smuzhiyun 	 * while reprogramming it.
503*4882a593Smuzhiyun 	 */
504*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8580_PWRDN2, pwr_mask, pwr_mask);
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	if (!freq_in || !freq_out)
507*4882a593Smuzhiyun 		return 0;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8580_PLLA1 + offset, pll_div.k & 0x1ff);
510*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0x1ff);
511*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8580_PLLA3 + offset,
512*4882a593Smuzhiyun 		     (pll_div.k >> 18 & 0xf) | (pll_div.n << 4));
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	reg = snd_soc_component_read(component, WM8580_PLLA4 + offset);
515*4882a593Smuzhiyun 	reg &= ~0x1b;
516*4882a593Smuzhiyun 	reg |= pll_div.prescale | pll_div.postscale << 1 |
517*4882a593Smuzhiyun 		pll_div.freqmode << 3;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8580_PLLA4 + offset, reg);
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	/* All done, turn it on */
522*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8580_PWRDN2, pwr_mask, 0);
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	return 0;
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun static const int wm8580_sysclk_ratios[] = {
528*4882a593Smuzhiyun 	128, 192, 256, 384, 512, 768, 1152,
529*4882a593Smuzhiyun };
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun /*
532*4882a593Smuzhiyun  * Set PCM DAI bit size and sample rate.
533*4882a593Smuzhiyun  */
wm8580_paif_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)534*4882a593Smuzhiyun static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
535*4882a593Smuzhiyun 				 struct snd_pcm_hw_params *params,
536*4882a593Smuzhiyun 				 struct snd_soc_dai *dai)
537*4882a593Smuzhiyun {
538*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
539*4882a593Smuzhiyun 	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
540*4882a593Smuzhiyun 	u16 paifa = 0;
541*4882a593Smuzhiyun 	u16 paifb = 0;
542*4882a593Smuzhiyun 	int i, ratio, osr;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	/* bit size */
545*4882a593Smuzhiyun 	switch (params_width(params)) {
546*4882a593Smuzhiyun 	case 16:
547*4882a593Smuzhiyun 		paifa |= 0x8;
548*4882a593Smuzhiyun 		break;
549*4882a593Smuzhiyun 	case 20:
550*4882a593Smuzhiyun 		paifa |= 0x0;
551*4882a593Smuzhiyun 		paifb |= WM8580_AIF_LENGTH_20;
552*4882a593Smuzhiyun 		break;
553*4882a593Smuzhiyun 	case 24:
554*4882a593Smuzhiyun 		paifa |= 0x0;
555*4882a593Smuzhiyun 		paifb |= WM8580_AIF_LENGTH_24;
556*4882a593Smuzhiyun 		break;
557*4882a593Smuzhiyun 	case 32:
558*4882a593Smuzhiyun 		paifa |= 0x0;
559*4882a593Smuzhiyun 		paifb |= WM8580_AIF_LENGTH_32;
560*4882a593Smuzhiyun 		break;
561*4882a593Smuzhiyun 	default:
562*4882a593Smuzhiyun 		return -EINVAL;
563*4882a593Smuzhiyun 	}
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	/* Look up the SYSCLK ratio; accept only exact matches */
566*4882a593Smuzhiyun 	ratio = wm8580->sysclk[dai->driver->id] / params_rate(params);
567*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(wm8580_sysclk_ratios); i++)
568*4882a593Smuzhiyun 		if (ratio == wm8580_sysclk_ratios[i])
569*4882a593Smuzhiyun 			break;
570*4882a593Smuzhiyun 	if (i == ARRAY_SIZE(wm8580_sysclk_ratios)) {
571*4882a593Smuzhiyun 		dev_err(component->dev, "Invalid clock ratio %d/%d\n",
572*4882a593Smuzhiyun 			wm8580->sysclk[dai->driver->id], params_rate(params));
573*4882a593Smuzhiyun 		return -EINVAL;
574*4882a593Smuzhiyun 	}
575*4882a593Smuzhiyun 	paifa |= i;
576*4882a593Smuzhiyun 	dev_dbg(component->dev, "Running at %dfs with %dHz clock\n",
577*4882a593Smuzhiyun 		wm8580_sysclk_ratios[i], wm8580->sysclk[dai->driver->id]);
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
580*4882a593Smuzhiyun 		switch (ratio) {
581*4882a593Smuzhiyun 		case 128:
582*4882a593Smuzhiyun 		case 192:
583*4882a593Smuzhiyun 			osr = WM8580_DACOSR;
584*4882a593Smuzhiyun 			dev_dbg(component->dev, "Selecting 64x OSR\n");
585*4882a593Smuzhiyun 			break;
586*4882a593Smuzhiyun 		default:
587*4882a593Smuzhiyun 			osr = 0;
588*4882a593Smuzhiyun 			dev_dbg(component->dev, "Selecting 128x OSR\n");
589*4882a593Smuzhiyun 			break;
590*4882a593Smuzhiyun 		}
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 		snd_soc_component_update_bits(component, WM8580_PAIF3, WM8580_DACOSR, osr);
593*4882a593Smuzhiyun 	}
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8580_PAIF1 + dai->driver->id,
596*4882a593Smuzhiyun 			    WM8580_AIF_RATE_MASK | WM8580_AIF_BCLKSEL_MASK,
597*4882a593Smuzhiyun 			    paifa);
598*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8580_PAIF3 + dai->driver->id,
599*4882a593Smuzhiyun 			    WM8580_AIF_LENGTH_MASK, paifb);
600*4882a593Smuzhiyun 	return 0;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun 
wm8580_set_paif_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)603*4882a593Smuzhiyun static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
604*4882a593Smuzhiyun 				      unsigned int fmt)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
607*4882a593Smuzhiyun 	unsigned int aifa;
608*4882a593Smuzhiyun 	unsigned int aifb;
609*4882a593Smuzhiyun 	int can_invert_lrclk;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	aifa = snd_soc_component_read(component, WM8580_PAIF1 + codec_dai->driver->id);
612*4882a593Smuzhiyun 	aifb = snd_soc_component_read(component, WM8580_PAIF3 + codec_dai->driver->id);
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP);
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
617*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBS_CFS:
618*4882a593Smuzhiyun 		aifa &= ~WM8580_AIF_MS;
619*4882a593Smuzhiyun 		break;
620*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFM:
621*4882a593Smuzhiyun 		aifa |= WM8580_AIF_MS;
622*4882a593Smuzhiyun 		break;
623*4882a593Smuzhiyun 	default:
624*4882a593Smuzhiyun 		return -EINVAL;
625*4882a593Smuzhiyun 	}
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
628*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
629*4882a593Smuzhiyun 		can_invert_lrclk = 1;
630*4882a593Smuzhiyun 		aifb |= WM8580_AIF_FMT_I2S;
631*4882a593Smuzhiyun 		break;
632*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_RIGHT_J:
633*4882a593Smuzhiyun 		can_invert_lrclk = 1;
634*4882a593Smuzhiyun 		aifb |= WM8580_AIF_FMT_RIGHTJ;
635*4882a593Smuzhiyun 		break;
636*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_LEFT_J:
637*4882a593Smuzhiyun 		can_invert_lrclk = 1;
638*4882a593Smuzhiyun 		aifb |= WM8580_AIF_FMT_LEFTJ;
639*4882a593Smuzhiyun 		break;
640*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A:
641*4882a593Smuzhiyun 		can_invert_lrclk = 0;
642*4882a593Smuzhiyun 		aifb |= WM8580_AIF_FMT_DSP;
643*4882a593Smuzhiyun 		break;
644*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B:
645*4882a593Smuzhiyun 		can_invert_lrclk = 0;
646*4882a593Smuzhiyun 		aifb |= WM8580_AIF_FMT_DSP;
647*4882a593Smuzhiyun 		aifb |= WM8580_AIF_LRP;
648*4882a593Smuzhiyun 		break;
649*4882a593Smuzhiyun 	default:
650*4882a593Smuzhiyun 		return -EINVAL;
651*4882a593Smuzhiyun 	}
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
654*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_NF:
655*4882a593Smuzhiyun 		break;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_IF:
658*4882a593Smuzhiyun 		if (!can_invert_lrclk)
659*4882a593Smuzhiyun 			return -EINVAL;
660*4882a593Smuzhiyun 		aifb |= WM8580_AIF_BCP;
661*4882a593Smuzhiyun 		aifb |= WM8580_AIF_LRP;
662*4882a593Smuzhiyun 		break;
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_NF:
665*4882a593Smuzhiyun 		aifb |= WM8580_AIF_BCP;
666*4882a593Smuzhiyun 		break;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_IF:
669*4882a593Smuzhiyun 		if (!can_invert_lrclk)
670*4882a593Smuzhiyun 			return -EINVAL;
671*4882a593Smuzhiyun 		aifb |= WM8580_AIF_LRP;
672*4882a593Smuzhiyun 		break;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	default:
675*4882a593Smuzhiyun 		return -EINVAL;
676*4882a593Smuzhiyun 	}
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8580_PAIF1 + codec_dai->driver->id, aifa);
679*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8580_PAIF3 + codec_dai->driver->id, aifb);
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 	return 0;
682*4882a593Smuzhiyun }
683*4882a593Smuzhiyun 
wm8580_set_dai_clkdiv(struct snd_soc_dai * codec_dai,int div_id,int div)684*4882a593Smuzhiyun static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
685*4882a593Smuzhiyun 				 int div_id, int div)
686*4882a593Smuzhiyun {
687*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
688*4882a593Smuzhiyun 	unsigned int reg;
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	switch (div_id) {
691*4882a593Smuzhiyun 	case WM8580_MCLK:
692*4882a593Smuzhiyun 		reg = snd_soc_component_read(component, WM8580_PLLB4);
693*4882a593Smuzhiyun 		reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 		switch (div) {
696*4882a593Smuzhiyun 		case WM8580_CLKSRC_MCLK:
697*4882a593Smuzhiyun 			/* Input */
698*4882a593Smuzhiyun 			break;
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 		case WM8580_CLKSRC_PLLA:
701*4882a593Smuzhiyun 			reg |= WM8580_PLLB4_MCLKOUTSRC_PLLA;
702*4882a593Smuzhiyun 			break;
703*4882a593Smuzhiyun 		case WM8580_CLKSRC_PLLB:
704*4882a593Smuzhiyun 			reg |= WM8580_PLLB4_MCLKOUTSRC_PLLB;
705*4882a593Smuzhiyun 			break;
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 		case WM8580_CLKSRC_OSC:
708*4882a593Smuzhiyun 			reg |= WM8580_PLLB4_MCLKOUTSRC_OSC;
709*4882a593Smuzhiyun 			break;
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 		default:
712*4882a593Smuzhiyun 			return -EINVAL;
713*4882a593Smuzhiyun 		}
714*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8580_PLLB4, reg);
715*4882a593Smuzhiyun 		break;
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	case WM8580_CLKOUTSRC:
718*4882a593Smuzhiyun 		reg = snd_soc_component_read(component, WM8580_PLLB4);
719*4882a593Smuzhiyun 		reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK;
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 		switch (div) {
722*4882a593Smuzhiyun 		case WM8580_CLKSRC_NONE:
723*4882a593Smuzhiyun 			break;
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 		case WM8580_CLKSRC_PLLA:
726*4882a593Smuzhiyun 			reg |= WM8580_PLLB4_CLKOUTSRC_PLLACLK;
727*4882a593Smuzhiyun 			break;
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 		case WM8580_CLKSRC_PLLB:
730*4882a593Smuzhiyun 			reg |= WM8580_PLLB4_CLKOUTSRC_PLLBCLK;
731*4882a593Smuzhiyun 			break;
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 		case WM8580_CLKSRC_OSC:
734*4882a593Smuzhiyun 			reg |= WM8580_PLLB4_CLKOUTSRC_OSCCLK;
735*4882a593Smuzhiyun 			break;
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 		default:
738*4882a593Smuzhiyun 			return -EINVAL;
739*4882a593Smuzhiyun 		}
740*4882a593Smuzhiyun 		snd_soc_component_write(component, WM8580_PLLB4, reg);
741*4882a593Smuzhiyun 		break;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	default:
744*4882a593Smuzhiyun 		return -EINVAL;
745*4882a593Smuzhiyun 	}
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	return 0;
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun 
wm8580_set_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)750*4882a593Smuzhiyun static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
751*4882a593Smuzhiyun 			     unsigned int freq, int dir)
752*4882a593Smuzhiyun {
753*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
754*4882a593Smuzhiyun 	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
755*4882a593Smuzhiyun 	int ret, sel, sel_mask, sel_shift;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	switch (dai->driver->id) {
758*4882a593Smuzhiyun 	case WM8580_DAI_PAIFRX:
759*4882a593Smuzhiyun 		sel_mask = 0x3;
760*4882a593Smuzhiyun 		sel_shift = 0;
761*4882a593Smuzhiyun 		break;
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	case WM8580_DAI_PAIFTX:
764*4882a593Smuzhiyun 		sel_mask = 0xc;
765*4882a593Smuzhiyun 		sel_shift = 2;
766*4882a593Smuzhiyun 		break;
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	default:
769*4882a593Smuzhiyun 		WARN(1, "Unknown DAI driver ID\n");
770*4882a593Smuzhiyun 		return -EINVAL;
771*4882a593Smuzhiyun 	}
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	switch (clk_id) {
774*4882a593Smuzhiyun 	case WM8580_CLKSRC_ADCMCLK:
775*4882a593Smuzhiyun 		if (dai->driver->id != WM8580_DAI_PAIFTX)
776*4882a593Smuzhiyun 			return -EINVAL;
777*4882a593Smuzhiyun 		sel = 0 << sel_shift;
778*4882a593Smuzhiyun 		break;
779*4882a593Smuzhiyun 	case WM8580_CLKSRC_PLLA:
780*4882a593Smuzhiyun 		sel = 1 << sel_shift;
781*4882a593Smuzhiyun 		break;
782*4882a593Smuzhiyun 	case WM8580_CLKSRC_PLLB:
783*4882a593Smuzhiyun 		sel = 2 << sel_shift;
784*4882a593Smuzhiyun 		break;
785*4882a593Smuzhiyun 	case WM8580_CLKSRC_MCLK:
786*4882a593Smuzhiyun 		sel = 3 << sel_shift;
787*4882a593Smuzhiyun 		break;
788*4882a593Smuzhiyun 	default:
789*4882a593Smuzhiyun 		dev_err(component->dev, "Unknown clock %d\n", clk_id);
790*4882a593Smuzhiyun 		return -EINVAL;
791*4882a593Smuzhiyun 	}
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	/* We really should validate PLL settings but not yet */
794*4882a593Smuzhiyun 	wm8580->sysclk[dai->driver->id] = freq;
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 	ret = snd_soc_component_update_bits(component, WM8580_CLKSEL, sel_mask, sel);
797*4882a593Smuzhiyun 	if (ret < 0)
798*4882a593Smuzhiyun 		return ret;
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	return 0;
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun 
wm8580_mute(struct snd_soc_dai * codec_dai,int mute,int direction)803*4882a593Smuzhiyun static int wm8580_mute(struct snd_soc_dai *codec_dai, int mute, int direction)
804*4882a593Smuzhiyun {
805*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
806*4882a593Smuzhiyun 	unsigned int reg;
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun 	reg = snd_soc_component_read(component, WM8580_DAC_CONTROL5);
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	if (mute)
811*4882a593Smuzhiyun 		reg |= WM8580_DAC_CONTROL5_MUTEALL;
812*4882a593Smuzhiyun 	else
813*4882a593Smuzhiyun 		reg &= ~WM8580_DAC_CONTROL5_MUTEALL;
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8580_DAC_CONTROL5, reg);
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	return 0;
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun 
wm8580_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)820*4882a593Smuzhiyun static int wm8580_set_bias_level(struct snd_soc_component *component,
821*4882a593Smuzhiyun 	enum snd_soc_bias_level level)
822*4882a593Smuzhiyun {
823*4882a593Smuzhiyun 	switch (level) {
824*4882a593Smuzhiyun 	case SND_SOC_BIAS_ON:
825*4882a593Smuzhiyun 	case SND_SOC_BIAS_PREPARE:
826*4882a593Smuzhiyun 		break;
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	case SND_SOC_BIAS_STANDBY:
829*4882a593Smuzhiyun 		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
830*4882a593Smuzhiyun 			/* Power up and get individual control of the DACs */
831*4882a593Smuzhiyun 			snd_soc_component_update_bits(component, WM8580_PWRDN1,
832*4882a593Smuzhiyun 					    WM8580_PWRDN1_PWDN |
833*4882a593Smuzhiyun 					    WM8580_PWRDN1_ALLDACPD, 0);
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 			/* Make VMID high impedance */
836*4882a593Smuzhiyun 			snd_soc_component_update_bits(component, WM8580_ADC_CONTROL1,
837*4882a593Smuzhiyun 					    0x100, 0);
838*4882a593Smuzhiyun 		}
839*4882a593Smuzhiyun 		break;
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	case SND_SOC_BIAS_OFF:
842*4882a593Smuzhiyun 		snd_soc_component_update_bits(component, WM8580_PWRDN1,
843*4882a593Smuzhiyun 				    WM8580_PWRDN1_PWDN, WM8580_PWRDN1_PWDN);
844*4882a593Smuzhiyun 		break;
845*4882a593Smuzhiyun 	}
846*4882a593Smuzhiyun 	return 0;
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun 
wm8580_playback_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)849*4882a593Smuzhiyun static int wm8580_playback_startup(struct snd_pcm_substream *substream,
850*4882a593Smuzhiyun 			   struct snd_soc_dai *dai)
851*4882a593Smuzhiyun {
852*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
853*4882a593Smuzhiyun 	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 	return snd_pcm_hw_constraint_minmax(substream->runtime,
856*4882a593Smuzhiyun 		SNDRV_PCM_HW_PARAM_CHANNELS, 1, wm8580->drvdata->num_dacs * 2);
857*4882a593Smuzhiyun }
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
860*4882a593Smuzhiyun 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun static const struct snd_soc_dai_ops wm8580_dai_ops_playback = {
863*4882a593Smuzhiyun 	.startup	= wm8580_playback_startup,
864*4882a593Smuzhiyun 	.set_sysclk	= wm8580_set_sysclk,
865*4882a593Smuzhiyun 	.hw_params	= wm8580_paif_hw_params,
866*4882a593Smuzhiyun 	.set_fmt	= wm8580_set_paif_dai_fmt,
867*4882a593Smuzhiyun 	.set_clkdiv	= wm8580_set_dai_clkdiv,
868*4882a593Smuzhiyun 	.set_pll	= wm8580_set_dai_pll,
869*4882a593Smuzhiyun 	.mute_stream	= wm8580_mute,
870*4882a593Smuzhiyun 	.no_capture_mute = 1,
871*4882a593Smuzhiyun };
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun static const struct snd_soc_dai_ops wm8580_dai_ops_capture = {
874*4882a593Smuzhiyun 	.set_sysclk	= wm8580_set_sysclk,
875*4882a593Smuzhiyun 	.hw_params	= wm8580_paif_hw_params,
876*4882a593Smuzhiyun 	.set_fmt	= wm8580_set_paif_dai_fmt,
877*4882a593Smuzhiyun 	.set_clkdiv	= wm8580_set_dai_clkdiv,
878*4882a593Smuzhiyun 	.set_pll	= wm8580_set_dai_pll,
879*4882a593Smuzhiyun };
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun static struct snd_soc_dai_driver wm8580_dai[] = {
882*4882a593Smuzhiyun 	{
883*4882a593Smuzhiyun 		.name = "wm8580-hifi-playback",
884*4882a593Smuzhiyun 		.id	= WM8580_DAI_PAIFRX,
885*4882a593Smuzhiyun 		.playback = {
886*4882a593Smuzhiyun 			.stream_name = "Playback",
887*4882a593Smuzhiyun 			.channels_min = 1,
888*4882a593Smuzhiyun 			.rates = SNDRV_PCM_RATE_8000_192000,
889*4882a593Smuzhiyun 			.formats = WM8580_FORMATS,
890*4882a593Smuzhiyun 		},
891*4882a593Smuzhiyun 		.ops = &wm8580_dai_ops_playback,
892*4882a593Smuzhiyun 	},
893*4882a593Smuzhiyun 	{
894*4882a593Smuzhiyun 		.name = "wm8580-hifi-capture",
895*4882a593Smuzhiyun 		.id	=	WM8580_DAI_PAIFTX,
896*4882a593Smuzhiyun 		.capture = {
897*4882a593Smuzhiyun 			.stream_name = "Capture",
898*4882a593Smuzhiyun 			.channels_min = 2,
899*4882a593Smuzhiyun 			.channels_max = 2,
900*4882a593Smuzhiyun 			.rates = SNDRV_PCM_RATE_8000_192000,
901*4882a593Smuzhiyun 			.formats = WM8580_FORMATS,
902*4882a593Smuzhiyun 		},
903*4882a593Smuzhiyun 		.ops = &wm8580_dai_ops_capture,
904*4882a593Smuzhiyun 	},
905*4882a593Smuzhiyun };
906*4882a593Smuzhiyun 
wm8580_probe(struct snd_soc_component * component)907*4882a593Smuzhiyun static int wm8580_probe(struct snd_soc_component *component)
908*4882a593Smuzhiyun {
909*4882a593Smuzhiyun 	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
910*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
911*4882a593Smuzhiyun 	int ret = 0;
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 	switch (wm8580->drvdata->num_dacs) {
914*4882a593Smuzhiyun 	case 4:
915*4882a593Smuzhiyun 		snd_soc_add_component_controls(component, wm8581_snd_controls,
916*4882a593Smuzhiyun 					ARRAY_SIZE(wm8581_snd_controls));
917*4882a593Smuzhiyun 		snd_soc_dapm_new_controls(dapm, wm8581_dapm_widgets,
918*4882a593Smuzhiyun 					ARRAY_SIZE(wm8581_dapm_widgets));
919*4882a593Smuzhiyun 		snd_soc_dapm_add_routes(dapm, wm8581_dapm_routes,
920*4882a593Smuzhiyun 					ARRAY_SIZE(wm8581_dapm_routes));
921*4882a593Smuzhiyun 		break;
922*4882a593Smuzhiyun 	default:
923*4882a593Smuzhiyun 		break;
924*4882a593Smuzhiyun 	}
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),
927*4882a593Smuzhiyun 				    wm8580->supplies);
928*4882a593Smuzhiyun 	if (ret != 0) {
929*4882a593Smuzhiyun 		dev_err(component->dev, "Failed to enable supplies: %d\n", ret);
930*4882a593Smuzhiyun 		goto err_regulator_get;
931*4882a593Smuzhiyun 	}
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	/* Get the codec into a known state */
934*4882a593Smuzhiyun 	ret = snd_soc_component_write(component, WM8580_RESET, 0);
935*4882a593Smuzhiyun 	if (ret != 0) {
936*4882a593Smuzhiyun 		dev_err(component->dev, "Failed to reset component: %d\n", ret);
937*4882a593Smuzhiyun 		goto err_regulator_enable;
938*4882a593Smuzhiyun 	}
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 	return 0;
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun err_regulator_enable:
943*4882a593Smuzhiyun 	regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
944*4882a593Smuzhiyun err_regulator_get:
945*4882a593Smuzhiyun 	return ret;
946*4882a593Smuzhiyun }
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun /* power down chip */
wm8580_remove(struct snd_soc_component * component)949*4882a593Smuzhiyun static void wm8580_remove(struct snd_soc_component *component)
950*4882a593Smuzhiyun {
951*4882a593Smuzhiyun 	struct wm8580_priv *wm8580 = snd_soc_component_get_drvdata(component);
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
954*4882a593Smuzhiyun }
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun static const struct snd_soc_component_driver soc_component_dev_wm8580 = {
957*4882a593Smuzhiyun 	.probe			= wm8580_probe,
958*4882a593Smuzhiyun 	.remove			= wm8580_remove,
959*4882a593Smuzhiyun 	.set_bias_level		= wm8580_set_bias_level,
960*4882a593Smuzhiyun 	.controls		= wm8580_snd_controls,
961*4882a593Smuzhiyun 	.num_controls		= ARRAY_SIZE(wm8580_snd_controls),
962*4882a593Smuzhiyun 	.dapm_widgets		= wm8580_dapm_widgets,
963*4882a593Smuzhiyun 	.num_dapm_widgets	= ARRAY_SIZE(wm8580_dapm_widgets),
964*4882a593Smuzhiyun 	.dapm_routes		= wm8580_dapm_routes,
965*4882a593Smuzhiyun 	.num_dapm_routes	= ARRAY_SIZE(wm8580_dapm_routes),
966*4882a593Smuzhiyun 	.idle_bias_on		= 1,
967*4882a593Smuzhiyun 	.use_pmdown_time	= 1,
968*4882a593Smuzhiyun 	.endianness		= 1,
969*4882a593Smuzhiyun 	.non_legacy_dai_naming	= 1,
970*4882a593Smuzhiyun };
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun static const struct regmap_config wm8580_regmap = {
973*4882a593Smuzhiyun 	.reg_bits = 7,
974*4882a593Smuzhiyun 	.val_bits = 9,
975*4882a593Smuzhiyun 	.max_register = WM8580_MAX_REGISTER,
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun 	.reg_defaults = wm8580_reg_defaults,
978*4882a593Smuzhiyun 	.num_reg_defaults = ARRAY_SIZE(wm8580_reg_defaults),
979*4882a593Smuzhiyun 	.cache_type = REGCACHE_RBTREE,
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun 	.volatile_reg = wm8580_volatile,
982*4882a593Smuzhiyun };
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun static const struct wm8580_driver_data wm8580_data = {
985*4882a593Smuzhiyun 	.num_dacs = 3,
986*4882a593Smuzhiyun };
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun static const struct wm8580_driver_data wm8581_data = {
989*4882a593Smuzhiyun 	.num_dacs = 4,
990*4882a593Smuzhiyun };
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun static const struct of_device_id wm8580_of_match[] = {
993*4882a593Smuzhiyun 	{ .compatible = "wlf,wm8580", .data = &wm8580_data },
994*4882a593Smuzhiyun 	{ .compatible = "wlf,wm8581", .data = &wm8581_data },
995*4882a593Smuzhiyun 	{ },
996*4882a593Smuzhiyun };
997*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, wm8580_of_match);
998*4882a593Smuzhiyun 
wm8580_i2c_probe(struct i2c_client * i2c,const struct i2c_device_id * id)999*4882a593Smuzhiyun static int wm8580_i2c_probe(struct i2c_client *i2c,
1000*4882a593Smuzhiyun 			    const struct i2c_device_id *id)
1001*4882a593Smuzhiyun {
1002*4882a593Smuzhiyun 	const struct of_device_id *of_id;
1003*4882a593Smuzhiyun 	struct wm8580_priv *wm8580;
1004*4882a593Smuzhiyun 	int ret, i;
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 	wm8580 = devm_kzalloc(&i2c->dev, sizeof(struct wm8580_priv),
1007*4882a593Smuzhiyun 			      GFP_KERNEL);
1008*4882a593Smuzhiyun 	if (wm8580 == NULL)
1009*4882a593Smuzhiyun 		return -ENOMEM;
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 	wm8580->regmap = devm_regmap_init_i2c(i2c, &wm8580_regmap);
1012*4882a593Smuzhiyun 	if (IS_ERR(wm8580->regmap))
1013*4882a593Smuzhiyun 		return PTR_ERR(wm8580->regmap);
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++)
1016*4882a593Smuzhiyun 		wm8580->supplies[i].supply = wm8580_supply_names[i];
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8580->supplies),
1019*4882a593Smuzhiyun 				      wm8580->supplies);
1020*4882a593Smuzhiyun 	if (ret != 0) {
1021*4882a593Smuzhiyun 		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
1022*4882a593Smuzhiyun 		return ret;
1023*4882a593Smuzhiyun 	}
1024*4882a593Smuzhiyun 
1025*4882a593Smuzhiyun 	i2c_set_clientdata(i2c, wm8580);
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun 	of_id = of_match_device(wm8580_of_match, &i2c->dev);
1028*4882a593Smuzhiyun 	if (of_id)
1029*4882a593Smuzhiyun 		wm8580->drvdata = of_id->data;
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	if (!wm8580->drvdata) {
1032*4882a593Smuzhiyun 		dev_err(&i2c->dev, "failed to find driver data\n");
1033*4882a593Smuzhiyun 		return -EINVAL;
1034*4882a593Smuzhiyun 	}
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 	ret = devm_snd_soc_register_component(&i2c->dev,
1037*4882a593Smuzhiyun 			&soc_component_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai));
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 	return ret;
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun 
1042*4882a593Smuzhiyun static const struct i2c_device_id wm8580_i2c_id[] = {
1043*4882a593Smuzhiyun 	{ "wm8580", (kernel_ulong_t)&wm8580_data },
1044*4882a593Smuzhiyun 	{ "wm8581", (kernel_ulong_t)&wm8581_data },
1045*4882a593Smuzhiyun 	{ }
1046*4882a593Smuzhiyun };
1047*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id);
1048*4882a593Smuzhiyun 
1049*4882a593Smuzhiyun static struct i2c_driver wm8580_i2c_driver = {
1050*4882a593Smuzhiyun 	.driver = {
1051*4882a593Smuzhiyun 		.name = "wm8580",
1052*4882a593Smuzhiyun 		.of_match_table = wm8580_of_match,
1053*4882a593Smuzhiyun 	},
1054*4882a593Smuzhiyun 	.probe =    wm8580_i2c_probe,
1055*4882a593Smuzhiyun 	.id_table = wm8580_i2c_id,
1056*4882a593Smuzhiyun };
1057*4882a593Smuzhiyun 
1058*4882a593Smuzhiyun module_i2c_driver(wm8580_i2c_driver);
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun MODULE_DESCRIPTION("ASoC WM8580 driver");
1061*4882a593Smuzhiyun MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1062*4882a593Smuzhiyun MODULE_AUTHOR("Matt Flax <flatmax@flatmax.org>");
1063*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1064