xref: /OK3568_Linux_fs/kernel/sound/soc/codecs/wm8523.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * wm8523.c  --  WM8523 ALSA SoC Audio driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2009 Wolfson Microelectronics plc
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/moduleparam.h>
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/delay.h>
14*4882a593Smuzhiyun #include <linux/pm.h>
15*4882a593Smuzhiyun #include <linux/i2c.h>
16*4882a593Smuzhiyun #include <linux/regmap.h>
17*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
18*4882a593Smuzhiyun #include <linux/slab.h>
19*4882a593Smuzhiyun #include <linux/of_device.h>
20*4882a593Smuzhiyun #include <sound/core.h>
21*4882a593Smuzhiyun #include <sound/pcm.h>
22*4882a593Smuzhiyun #include <sound/pcm_params.h>
23*4882a593Smuzhiyun #include <sound/soc.h>
24*4882a593Smuzhiyun #include <sound/initval.h>
25*4882a593Smuzhiyun #include <sound/tlv.h>
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include "wm8523.h"
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define WM8523_NUM_SUPPLIES 2
30*4882a593Smuzhiyun static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
31*4882a593Smuzhiyun 	"AVDD",
32*4882a593Smuzhiyun 	"LINEVDD",
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #define WM8523_NUM_RATES 7
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /* codec private data */
38*4882a593Smuzhiyun struct wm8523_priv {
39*4882a593Smuzhiyun 	struct regmap *regmap;
40*4882a593Smuzhiyun 	struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES];
41*4882a593Smuzhiyun 	unsigned int sysclk;
42*4882a593Smuzhiyun 	unsigned int rate_constraint_list[WM8523_NUM_RATES];
43*4882a593Smuzhiyun 	struct snd_pcm_hw_constraint_list rate_constraint;
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static const struct reg_default wm8523_reg_defaults[] = {
47*4882a593Smuzhiyun 	{ 2, 0x0000 },     /* R2 - PSCTRL1 */
48*4882a593Smuzhiyun 	{ 3, 0x1812 },     /* R3 - AIF_CTRL1 */
49*4882a593Smuzhiyun 	{ 4, 0x0000 },     /* R4 - AIF_CTRL2 */
50*4882a593Smuzhiyun 	{ 5, 0x0001 },     /* R5 - DAC_CTRL3 */
51*4882a593Smuzhiyun 	{ 6, 0x0190 },     /* R6 - DAC_GAINL */
52*4882a593Smuzhiyun 	{ 7, 0x0190 },     /* R7 - DAC_GAINR */
53*4882a593Smuzhiyun 	{ 8, 0x0000 },     /* R8 - ZERO_DETECT */
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun 
wm8523_volatile_register(struct device * dev,unsigned int reg)56*4882a593Smuzhiyun static bool wm8523_volatile_register(struct device *dev, unsigned int reg)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	switch (reg) {
59*4882a593Smuzhiyun 	case WM8523_DEVICE_ID:
60*4882a593Smuzhiyun 	case WM8523_REVISION:
61*4882a593Smuzhiyun 		return true;
62*4882a593Smuzhiyun 	default:
63*4882a593Smuzhiyun 		return false;
64*4882a593Smuzhiyun 	}
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 25, 0);
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun static const char *wm8523_zd_count_text[] = {
70*4882a593Smuzhiyun 	"1024",
71*4882a593Smuzhiyun 	"2048",
72*4882a593Smuzhiyun };
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(wm8523_zc_count, WM8523_ZERO_DETECT, 0,
75*4882a593Smuzhiyun 			    wm8523_zd_count_text);
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun static const struct snd_kcontrol_new wm8523_controls[] = {
78*4882a593Smuzhiyun SOC_DOUBLE_R_TLV("Playback Volume", WM8523_DAC_GAINL, WM8523_DAC_GAINR,
79*4882a593Smuzhiyun 		 0, 448, 0, dac_tlv),
80*4882a593Smuzhiyun SOC_SINGLE("ZC Switch", WM8523_DAC_CTRL3, 4, 1, 0),
81*4882a593Smuzhiyun SOC_SINGLE("Playback Deemphasis Switch", WM8523_AIF_CTRL1, 8, 1, 0),
82*4882a593Smuzhiyun SOC_DOUBLE("Playback Switch", WM8523_DAC_CTRL3, 2, 3, 1, 1),
83*4882a593Smuzhiyun SOC_SINGLE("Volume Ramp Up Switch", WM8523_DAC_CTRL3, 1, 1, 0),
84*4882a593Smuzhiyun SOC_SINGLE("Volume Ramp Down Switch", WM8523_DAC_CTRL3, 0, 1, 0),
85*4882a593Smuzhiyun SOC_ENUM("Zero Detect Count", wm8523_zc_count),
86*4882a593Smuzhiyun };
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun static const struct snd_soc_dapm_widget wm8523_dapm_widgets[] = {
89*4882a593Smuzhiyun SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
90*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("LINEVOUTL"),
91*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("LINEVOUTR"),
92*4882a593Smuzhiyun };
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun static const struct snd_soc_dapm_route wm8523_dapm_routes[] = {
95*4882a593Smuzhiyun 	{ "LINEVOUTL", NULL, "DAC" },
96*4882a593Smuzhiyun 	{ "LINEVOUTR", NULL, "DAC" },
97*4882a593Smuzhiyun };
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun static const struct {
100*4882a593Smuzhiyun 	int value;
101*4882a593Smuzhiyun 	int ratio;
102*4882a593Smuzhiyun } lrclk_ratios[WM8523_NUM_RATES] = {
103*4882a593Smuzhiyun 	{ 1, 128 },
104*4882a593Smuzhiyun 	{ 2, 192 },
105*4882a593Smuzhiyun 	{ 3, 256 },
106*4882a593Smuzhiyun 	{ 4, 384 },
107*4882a593Smuzhiyun 	{ 5, 512 },
108*4882a593Smuzhiyun 	{ 6, 768 },
109*4882a593Smuzhiyun 	{ 7, 1152 },
110*4882a593Smuzhiyun };
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun static const struct {
113*4882a593Smuzhiyun 	int value;
114*4882a593Smuzhiyun 	int ratio;
115*4882a593Smuzhiyun } bclk_ratios[] = {
116*4882a593Smuzhiyun 	{ 2, 32 },
117*4882a593Smuzhiyun 	{ 3, 64 },
118*4882a593Smuzhiyun 	{ 4, 128 },
119*4882a593Smuzhiyun };
120*4882a593Smuzhiyun 
wm8523_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)121*4882a593Smuzhiyun static int wm8523_startup(struct snd_pcm_substream *substream,
122*4882a593Smuzhiyun 			  struct snd_soc_dai *dai)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
125*4882a593Smuzhiyun 	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	/* The set of sample rates that can be supported depends on the
128*4882a593Smuzhiyun 	 * MCLK supplied to the CODEC - enforce this.
129*4882a593Smuzhiyun 	 */
130*4882a593Smuzhiyun 	if (!wm8523->sysclk) {
131*4882a593Smuzhiyun 		dev_err(component->dev,
132*4882a593Smuzhiyun 			"No MCLK configured, call set_sysclk() on init\n");
133*4882a593Smuzhiyun 		return -EINVAL;
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	snd_pcm_hw_constraint_list(substream->runtime, 0,
137*4882a593Smuzhiyun 				   SNDRV_PCM_HW_PARAM_RATE,
138*4882a593Smuzhiyun 				   &wm8523->rate_constraint);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	return 0;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
wm8523_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)143*4882a593Smuzhiyun static int wm8523_hw_params(struct snd_pcm_substream *substream,
144*4882a593Smuzhiyun 			    struct snd_pcm_hw_params *params,
145*4882a593Smuzhiyun 			    struct snd_soc_dai *dai)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
148*4882a593Smuzhiyun 	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
149*4882a593Smuzhiyun 	int i;
150*4882a593Smuzhiyun 	u16 aifctrl1 = snd_soc_component_read(component, WM8523_AIF_CTRL1);
151*4882a593Smuzhiyun 	u16 aifctrl2 = snd_soc_component_read(component, WM8523_AIF_CTRL2);
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	/* Find a supported LRCLK ratio */
154*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
155*4882a593Smuzhiyun 		if (wm8523->sysclk / params_rate(params) ==
156*4882a593Smuzhiyun 		    lrclk_ratios[i].ratio)
157*4882a593Smuzhiyun 			break;
158*4882a593Smuzhiyun 	}
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	/* Should never happen, should be handled by constraints */
161*4882a593Smuzhiyun 	if (i == ARRAY_SIZE(lrclk_ratios)) {
162*4882a593Smuzhiyun 		dev_err(component->dev, "MCLK/fs ratio %d unsupported\n",
163*4882a593Smuzhiyun 			wm8523->sysclk / params_rate(params));
164*4882a593Smuzhiyun 		return -EINVAL;
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	aifctrl2 &= ~WM8523_SR_MASK;
168*4882a593Smuzhiyun 	aifctrl2 |= lrclk_ratios[i].value;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	if (aifctrl1 & WM8523_AIF_MSTR) {
171*4882a593Smuzhiyun 		/* Find a fs->bclk ratio */
172*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(bclk_ratios); i++)
173*4882a593Smuzhiyun 			if (params_width(params) * 2 <= bclk_ratios[i].ratio)
174*4882a593Smuzhiyun 				break;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 		if (i == ARRAY_SIZE(bclk_ratios)) {
177*4882a593Smuzhiyun 			dev_err(component->dev,
178*4882a593Smuzhiyun 				"No matching BCLK/fs ratio for word length %d\n",
179*4882a593Smuzhiyun 				params_width(params));
180*4882a593Smuzhiyun 			return -EINVAL;
181*4882a593Smuzhiyun 		}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 		aifctrl2 &= ~WM8523_BCLKDIV_MASK;
184*4882a593Smuzhiyun 		aifctrl2 |= bclk_ratios[i].value << WM8523_BCLKDIV_SHIFT;
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	aifctrl1 &= ~WM8523_WL_MASK;
188*4882a593Smuzhiyun 	switch (params_width(params)) {
189*4882a593Smuzhiyun 	case 16:
190*4882a593Smuzhiyun 		break;
191*4882a593Smuzhiyun 	case 20:
192*4882a593Smuzhiyun 		aifctrl1 |= 0x8;
193*4882a593Smuzhiyun 		break;
194*4882a593Smuzhiyun 	case 24:
195*4882a593Smuzhiyun 		aifctrl1 |= 0x10;
196*4882a593Smuzhiyun 		break;
197*4882a593Smuzhiyun 	case 32:
198*4882a593Smuzhiyun 		aifctrl1 |= 0x18;
199*4882a593Smuzhiyun 		break;
200*4882a593Smuzhiyun 	}
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8523_AIF_CTRL1, aifctrl1);
203*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8523_AIF_CTRL2, aifctrl2);
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	return 0;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
wm8523_set_dai_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)208*4882a593Smuzhiyun static int wm8523_set_dai_sysclk(struct snd_soc_dai *codec_dai,
209*4882a593Smuzhiyun 		int clk_id, unsigned int freq, int dir)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
212*4882a593Smuzhiyun 	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
213*4882a593Smuzhiyun 	unsigned int val;
214*4882a593Smuzhiyun 	int i;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	wm8523->sysclk = freq;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	wm8523->rate_constraint.count = 0;
219*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
220*4882a593Smuzhiyun 		val = freq / lrclk_ratios[i].ratio;
221*4882a593Smuzhiyun 		/* Check that it's a standard rate since core can't
222*4882a593Smuzhiyun 		 * cope with others and having the odd rates confuses
223*4882a593Smuzhiyun 		 * constraint matching.
224*4882a593Smuzhiyun 		 */
225*4882a593Smuzhiyun 		switch (val) {
226*4882a593Smuzhiyun 		case 8000:
227*4882a593Smuzhiyun 		case 11025:
228*4882a593Smuzhiyun 		case 16000:
229*4882a593Smuzhiyun 		case 22050:
230*4882a593Smuzhiyun 		case 32000:
231*4882a593Smuzhiyun 		case 44100:
232*4882a593Smuzhiyun 		case 48000:
233*4882a593Smuzhiyun 		case 64000:
234*4882a593Smuzhiyun 		case 88200:
235*4882a593Smuzhiyun 		case 96000:
236*4882a593Smuzhiyun 		case 176400:
237*4882a593Smuzhiyun 		case 192000:
238*4882a593Smuzhiyun 			dev_dbg(component->dev, "Supported sample rate: %dHz\n",
239*4882a593Smuzhiyun 				val);
240*4882a593Smuzhiyun 			wm8523->rate_constraint_list[i] = val;
241*4882a593Smuzhiyun 			wm8523->rate_constraint.count++;
242*4882a593Smuzhiyun 			break;
243*4882a593Smuzhiyun 		default:
244*4882a593Smuzhiyun 			dev_dbg(component->dev, "Skipping sample rate: %dHz\n",
245*4882a593Smuzhiyun 				val);
246*4882a593Smuzhiyun 		}
247*4882a593Smuzhiyun 	}
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	/* Need at least one supported rate... */
250*4882a593Smuzhiyun 	if (wm8523->rate_constraint.count == 0)
251*4882a593Smuzhiyun 		return -EINVAL;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	return 0;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 
wm8523_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)257*4882a593Smuzhiyun static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai,
258*4882a593Smuzhiyun 		unsigned int fmt)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
261*4882a593Smuzhiyun 	u16 aifctrl1 = snd_soc_component_read(component, WM8523_AIF_CTRL1);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	aifctrl1 &= ~(WM8523_BCLK_INV_MASK | WM8523_LRCLK_INV_MASK |
264*4882a593Smuzhiyun 		      WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK);
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
267*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFM:
268*4882a593Smuzhiyun 		aifctrl1 |= WM8523_AIF_MSTR;
269*4882a593Smuzhiyun 		break;
270*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBS_CFS:
271*4882a593Smuzhiyun 		break;
272*4882a593Smuzhiyun 	default:
273*4882a593Smuzhiyun 		return -EINVAL;
274*4882a593Smuzhiyun 	}
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
277*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
278*4882a593Smuzhiyun 		aifctrl1 |= 0x0002;
279*4882a593Smuzhiyun 		break;
280*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_RIGHT_J:
281*4882a593Smuzhiyun 		break;
282*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_LEFT_J:
283*4882a593Smuzhiyun 		aifctrl1 |= 0x0001;
284*4882a593Smuzhiyun 		break;
285*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A:
286*4882a593Smuzhiyun 		aifctrl1 |= 0x0003;
287*4882a593Smuzhiyun 		break;
288*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B:
289*4882a593Smuzhiyun 		aifctrl1 |= 0x0023;
290*4882a593Smuzhiyun 		break;
291*4882a593Smuzhiyun 	default:
292*4882a593Smuzhiyun 		return -EINVAL;
293*4882a593Smuzhiyun 	}
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
296*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_NF:
297*4882a593Smuzhiyun 		break;
298*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_IF:
299*4882a593Smuzhiyun 		aifctrl1 |= WM8523_BCLK_INV | WM8523_LRCLK_INV;
300*4882a593Smuzhiyun 		break;
301*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_NF:
302*4882a593Smuzhiyun 		aifctrl1 |= WM8523_BCLK_INV;
303*4882a593Smuzhiyun 		break;
304*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_IF:
305*4882a593Smuzhiyun 		aifctrl1 |= WM8523_LRCLK_INV;
306*4882a593Smuzhiyun 		break;
307*4882a593Smuzhiyun 	default:
308*4882a593Smuzhiyun 		return -EINVAL;
309*4882a593Smuzhiyun 	}
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	snd_soc_component_write(component, WM8523_AIF_CTRL1, aifctrl1);
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	return 0;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
wm8523_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)316*4882a593Smuzhiyun static int wm8523_set_bias_level(struct snd_soc_component *component,
317*4882a593Smuzhiyun 				 enum snd_soc_bias_level level)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
320*4882a593Smuzhiyun 	int ret;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	switch (level) {
323*4882a593Smuzhiyun 	case SND_SOC_BIAS_ON:
324*4882a593Smuzhiyun 		break;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	case SND_SOC_BIAS_PREPARE:
327*4882a593Smuzhiyun 		/* Full power on */
328*4882a593Smuzhiyun 		snd_soc_component_update_bits(component, WM8523_PSCTRL1,
329*4882a593Smuzhiyun 				    WM8523_SYS_ENA_MASK, 3);
330*4882a593Smuzhiyun 		break;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	case SND_SOC_BIAS_STANDBY:
333*4882a593Smuzhiyun 		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
334*4882a593Smuzhiyun 			ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
335*4882a593Smuzhiyun 						    wm8523->supplies);
336*4882a593Smuzhiyun 			if (ret != 0) {
337*4882a593Smuzhiyun 				dev_err(component->dev,
338*4882a593Smuzhiyun 					"Failed to enable supplies: %d\n",
339*4882a593Smuzhiyun 					ret);
340*4882a593Smuzhiyun 				return ret;
341*4882a593Smuzhiyun 			}
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 			/* Sync back default/cached values */
344*4882a593Smuzhiyun 			regcache_sync(wm8523->regmap);
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 			/* Initial power up */
347*4882a593Smuzhiyun 			snd_soc_component_update_bits(component, WM8523_PSCTRL1,
348*4882a593Smuzhiyun 					    WM8523_SYS_ENA_MASK, 1);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 			msleep(100);
351*4882a593Smuzhiyun 		}
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 		/* Power up to mute */
354*4882a593Smuzhiyun 		snd_soc_component_update_bits(component, WM8523_PSCTRL1,
355*4882a593Smuzhiyun 				    WM8523_SYS_ENA_MASK, 2);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 		break;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	case SND_SOC_BIAS_OFF:
360*4882a593Smuzhiyun 		/* The chip runs through the power down sequence for us. */
361*4882a593Smuzhiyun 		snd_soc_component_update_bits(component, WM8523_PSCTRL1,
362*4882a593Smuzhiyun 				    WM8523_SYS_ENA_MASK, 0);
363*4882a593Smuzhiyun 		msleep(100);
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 		regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies),
366*4882a593Smuzhiyun 				       wm8523->supplies);
367*4882a593Smuzhiyun 		break;
368*4882a593Smuzhiyun 	}
369*4882a593Smuzhiyun 	return 0;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun #define WM8523_RATES SNDRV_PCM_RATE_8000_192000
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun #define WM8523_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
375*4882a593Smuzhiyun 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun static const struct snd_soc_dai_ops wm8523_dai_ops = {
378*4882a593Smuzhiyun 	.startup	= wm8523_startup,
379*4882a593Smuzhiyun 	.hw_params	= wm8523_hw_params,
380*4882a593Smuzhiyun 	.set_sysclk	= wm8523_set_dai_sysclk,
381*4882a593Smuzhiyun 	.set_fmt	= wm8523_set_dai_fmt,
382*4882a593Smuzhiyun };
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun static struct snd_soc_dai_driver wm8523_dai = {
385*4882a593Smuzhiyun 	.name = "wm8523-hifi",
386*4882a593Smuzhiyun 	.playback = {
387*4882a593Smuzhiyun 		.stream_name = "Playback",
388*4882a593Smuzhiyun 		.channels_min = 2,  /* Mono modes not yet supported */
389*4882a593Smuzhiyun 		.channels_max = 2,
390*4882a593Smuzhiyun 		.rates = WM8523_RATES,
391*4882a593Smuzhiyun 		.formats = WM8523_FORMATS,
392*4882a593Smuzhiyun 	},
393*4882a593Smuzhiyun 	.ops = &wm8523_dai_ops,
394*4882a593Smuzhiyun };
395*4882a593Smuzhiyun 
wm8523_probe(struct snd_soc_component * component)396*4882a593Smuzhiyun static int wm8523_probe(struct snd_soc_component *component)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	struct wm8523_priv *wm8523 = snd_soc_component_get_drvdata(component);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
401*4882a593Smuzhiyun 	wm8523->rate_constraint.count =
402*4882a593Smuzhiyun 		ARRAY_SIZE(wm8523->rate_constraint_list);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	/* Change some default settings - latch VU and enable ZC */
405*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8523_DAC_GAINR,
406*4882a593Smuzhiyun 			    WM8523_DACR_VU, WM8523_DACR_VU);
407*4882a593Smuzhiyun 	snd_soc_component_update_bits(component, WM8523_DAC_CTRL3, WM8523_ZC, WM8523_ZC);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	return 0;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun static const struct snd_soc_component_driver soc_component_dev_wm8523 = {
413*4882a593Smuzhiyun 	.probe			= wm8523_probe,
414*4882a593Smuzhiyun 	.set_bias_level		= wm8523_set_bias_level,
415*4882a593Smuzhiyun 	.controls		= wm8523_controls,
416*4882a593Smuzhiyun 	.num_controls		= ARRAY_SIZE(wm8523_controls),
417*4882a593Smuzhiyun 	.dapm_widgets		= wm8523_dapm_widgets,
418*4882a593Smuzhiyun 	.num_dapm_widgets	= ARRAY_SIZE(wm8523_dapm_widgets),
419*4882a593Smuzhiyun 	.dapm_routes		= wm8523_dapm_routes,
420*4882a593Smuzhiyun 	.num_dapm_routes	= ARRAY_SIZE(wm8523_dapm_routes),
421*4882a593Smuzhiyun 	.suspend_bias_off	= 1,
422*4882a593Smuzhiyun 	.idle_bias_on		= 1,
423*4882a593Smuzhiyun 	.use_pmdown_time	= 1,
424*4882a593Smuzhiyun 	.endianness		= 1,
425*4882a593Smuzhiyun 	.non_legacy_dai_naming	= 1,
426*4882a593Smuzhiyun };
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun static const struct of_device_id wm8523_of_match[] = {
429*4882a593Smuzhiyun 	{ .compatible = "wlf,wm8523" },
430*4882a593Smuzhiyun 	{ },
431*4882a593Smuzhiyun };
432*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, wm8523_of_match);
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun static const struct regmap_config wm8523_regmap = {
435*4882a593Smuzhiyun 	.reg_bits = 8,
436*4882a593Smuzhiyun 	.val_bits = 16,
437*4882a593Smuzhiyun 	.max_register = WM8523_ZERO_DETECT,
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	.reg_defaults = wm8523_reg_defaults,
440*4882a593Smuzhiyun 	.num_reg_defaults = ARRAY_SIZE(wm8523_reg_defaults),
441*4882a593Smuzhiyun 	.cache_type = REGCACHE_RBTREE,
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	.volatile_reg = wm8523_volatile_register,
444*4882a593Smuzhiyun };
445*4882a593Smuzhiyun 
wm8523_i2c_probe(struct i2c_client * i2c,const struct i2c_device_id * id)446*4882a593Smuzhiyun static int wm8523_i2c_probe(struct i2c_client *i2c,
447*4882a593Smuzhiyun 			    const struct i2c_device_id *id)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun 	struct wm8523_priv *wm8523;
450*4882a593Smuzhiyun 	unsigned int val;
451*4882a593Smuzhiyun 	int ret, i;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	wm8523 = devm_kzalloc(&i2c->dev, sizeof(struct wm8523_priv),
454*4882a593Smuzhiyun 			      GFP_KERNEL);
455*4882a593Smuzhiyun 	if (wm8523 == NULL)
456*4882a593Smuzhiyun 		return -ENOMEM;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	wm8523->regmap = devm_regmap_init_i2c(i2c, &wm8523_regmap);
459*4882a593Smuzhiyun 	if (IS_ERR(wm8523->regmap)) {
460*4882a593Smuzhiyun 		ret = PTR_ERR(wm8523->regmap);
461*4882a593Smuzhiyun 		dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
462*4882a593Smuzhiyun 		return ret;
463*4882a593Smuzhiyun 	}
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++)
466*4882a593Smuzhiyun 		wm8523->supplies[i].supply = wm8523_supply_names[i];
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8523->supplies),
469*4882a593Smuzhiyun 				      wm8523->supplies);
470*4882a593Smuzhiyun 	if (ret != 0) {
471*4882a593Smuzhiyun 		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
472*4882a593Smuzhiyun 		return ret;
473*4882a593Smuzhiyun 	}
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
476*4882a593Smuzhiyun 				    wm8523->supplies);
477*4882a593Smuzhiyun 	if (ret != 0) {
478*4882a593Smuzhiyun 		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
479*4882a593Smuzhiyun 		return ret;
480*4882a593Smuzhiyun 	}
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	ret = regmap_read(wm8523->regmap, WM8523_DEVICE_ID, &val);
483*4882a593Smuzhiyun 	if (ret < 0) {
484*4882a593Smuzhiyun 		dev_err(&i2c->dev, "Failed to read ID register\n");
485*4882a593Smuzhiyun 		goto err_enable;
486*4882a593Smuzhiyun 	}
487*4882a593Smuzhiyun 	if (val != 0x8523) {
488*4882a593Smuzhiyun 		dev_err(&i2c->dev, "Device is not a WM8523, ID is %x\n", ret);
489*4882a593Smuzhiyun 		ret = -EINVAL;
490*4882a593Smuzhiyun 		goto err_enable;
491*4882a593Smuzhiyun 	}
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	ret = regmap_read(wm8523->regmap, WM8523_REVISION, &val);
494*4882a593Smuzhiyun 	if (ret < 0) {
495*4882a593Smuzhiyun 		dev_err(&i2c->dev, "Failed to read revision register\n");
496*4882a593Smuzhiyun 		goto err_enable;
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun 	dev_info(&i2c->dev, "revision %c\n",
499*4882a593Smuzhiyun 		 (val & WM8523_CHIP_REV_MASK) + 'A');
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	ret = regmap_write(wm8523->regmap, WM8523_DEVICE_ID, 0x8523);
502*4882a593Smuzhiyun 	if (ret != 0) {
503*4882a593Smuzhiyun 		dev_err(&i2c->dev, "Failed to reset device: %d\n", ret);
504*4882a593Smuzhiyun 		goto err_enable;
505*4882a593Smuzhiyun 	}
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	i2c_set_clientdata(i2c, wm8523);
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	ret = devm_snd_soc_register_component(&i2c->dev,
512*4882a593Smuzhiyun 			&soc_component_dev_wm8523, &wm8523_dai, 1);
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	return ret;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun err_enable:
517*4882a593Smuzhiyun 	regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
518*4882a593Smuzhiyun 	return ret;
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun static const struct i2c_device_id wm8523_i2c_id[] = {
522*4882a593Smuzhiyun 	{ "wm8523", 0 },
523*4882a593Smuzhiyun 	{ }
524*4882a593Smuzhiyun };
525*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id);
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun static struct i2c_driver wm8523_i2c_driver = {
528*4882a593Smuzhiyun 	.driver = {
529*4882a593Smuzhiyun 		.name = "wm8523",
530*4882a593Smuzhiyun 		.of_match_table = wm8523_of_match,
531*4882a593Smuzhiyun 	},
532*4882a593Smuzhiyun 	.probe =    wm8523_i2c_probe,
533*4882a593Smuzhiyun 	.id_table = wm8523_i2c_id,
534*4882a593Smuzhiyun };
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun module_i2c_driver(wm8523_i2c_driver);
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun MODULE_DESCRIPTION("ASoC WM8523 driver");
539*4882a593Smuzhiyun MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
540*4882a593Smuzhiyun MODULE_LICENSE("GPL");
541