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