1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter driver
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright 2019 Analog Devices Inc.
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/bitfield.h>
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/regmap.h>
10*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
11*4882a593Smuzhiyun #include <sound/pcm_params.h>
12*4882a593Smuzhiyun #include <sound/soc.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include "adau7118.h"
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #define ADAU7118_DEC_RATIO_MASK GENMASK(1, 0)
17*4882a593Smuzhiyun #define ADAU7118_DEC_RATIO(x) FIELD_PREP(ADAU7118_DEC_RATIO_MASK, x)
18*4882a593Smuzhiyun #define ADAU7118_CLK_MAP_MASK GENMASK(7, 4)
19*4882a593Smuzhiyun #define ADAU7118_SLOT_WIDTH_MASK GENMASK(5, 4)
20*4882a593Smuzhiyun #define ADAU7118_SLOT_WIDTH(x) FIELD_PREP(ADAU7118_SLOT_WIDTH_MASK, x)
21*4882a593Smuzhiyun #define ADAU7118_TRISTATE_MASK BIT(6)
22*4882a593Smuzhiyun #define ADAU7118_TRISTATE(x) FIELD_PREP(ADAU7118_TRISTATE_MASK, x)
23*4882a593Smuzhiyun #define ADAU7118_DATA_FMT_MASK GENMASK(3, 1)
24*4882a593Smuzhiyun #define ADAU7118_DATA_FMT(x) FIELD_PREP(ADAU7118_DATA_FMT_MASK, x)
25*4882a593Smuzhiyun #define ADAU7118_SAI_MODE_MASK BIT(0)
26*4882a593Smuzhiyun #define ADAU7118_SAI_MODE(x) FIELD_PREP(ADAU7118_SAI_MODE_MASK, x)
27*4882a593Smuzhiyun #define ADAU7118_LRCLK_BCLK_POL_MASK GENMASK(1, 0)
28*4882a593Smuzhiyun #define ADAU7118_LRCLK_BCLK_POL(x) \
29*4882a593Smuzhiyun FIELD_PREP(ADAU7118_LRCLK_BCLK_POL_MASK, x)
30*4882a593Smuzhiyun #define ADAU7118_SPT_SLOT_MASK GENMASK(7, 4)
31*4882a593Smuzhiyun #define ADAU7118_SPT_SLOT(x) FIELD_PREP(ADAU7118_SPT_SLOT_MASK, x)
32*4882a593Smuzhiyun #define ADAU7118_FULL_SOFT_R_MASK BIT(1)
33*4882a593Smuzhiyun #define ADAU7118_FULL_SOFT_R(x) FIELD_PREP(ADAU7118_FULL_SOFT_R_MASK, x)
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun struct adau7118_data {
36*4882a593Smuzhiyun struct regmap *map;
37*4882a593Smuzhiyun struct device *dev;
38*4882a593Smuzhiyun struct regulator *iovdd;
39*4882a593Smuzhiyun struct regulator *dvdd;
40*4882a593Smuzhiyun u32 slot_width;
41*4882a593Smuzhiyun u32 slots;
42*4882a593Smuzhiyun bool hw_mode;
43*4882a593Smuzhiyun bool right_j;
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /* Input Enable */
47*4882a593Smuzhiyun static const struct snd_kcontrol_new adau7118_dapm_pdm_control[4] = {
48*4882a593Smuzhiyun SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 0, 1, 0),
49*4882a593Smuzhiyun SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 1, 1, 0),
50*4882a593Smuzhiyun SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 2, 1, 0),
51*4882a593Smuzhiyun SOC_DAPM_SINGLE("Capture Switch", ADAU7118_REG_ENABLES, 3, 1, 0),
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun static const struct snd_soc_dapm_widget adau7118_widgets_sw[] = {
55*4882a593Smuzhiyun /* Input Enable Switches */
56*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("PDM0", SND_SOC_NOPM, 0, 0,
57*4882a593Smuzhiyun &adau7118_dapm_pdm_control[0]),
58*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("PDM1", SND_SOC_NOPM, 0, 0,
59*4882a593Smuzhiyun &adau7118_dapm_pdm_control[1]),
60*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("PDM2", SND_SOC_NOPM, 0, 0,
61*4882a593Smuzhiyun &adau7118_dapm_pdm_control[2]),
62*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("PDM3", SND_SOC_NOPM, 0, 0,
63*4882a593Smuzhiyun &adau7118_dapm_pdm_control[3]),
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /* PDM Clocks */
66*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("PDM_CLK0", ADAU7118_REG_ENABLES, 4, 0, NULL, 0),
67*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("PDM_CLK1", ADAU7118_REG_ENABLES, 5, 0, NULL, 0),
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* Output channels */
70*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, ADAU7118_REG_SPT_CX(0),
71*4882a593Smuzhiyun 0, 0),
72*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 0, ADAU7118_REG_SPT_CX(1),
73*4882a593Smuzhiyun 0, 0),
74*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 0, ADAU7118_REG_SPT_CX(2),
75*4882a593Smuzhiyun 0, 0),
76*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 0, ADAU7118_REG_SPT_CX(3),
77*4882a593Smuzhiyun 0, 0),
78*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 0, ADAU7118_REG_SPT_CX(4),
79*4882a593Smuzhiyun 0, 0),
80*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 0, ADAU7118_REG_SPT_CX(5),
81*4882a593Smuzhiyun 0, 0),
82*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("AIF1TX7", "Capture", 0, ADAU7118_REG_SPT_CX(6),
83*4882a593Smuzhiyun 0, 0),
84*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("AIF1TX8", "Capture", 0, ADAU7118_REG_SPT_CX(7),
85*4882a593Smuzhiyun 0, 0),
86*4882a593Smuzhiyun };
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun static const struct snd_soc_dapm_route adau7118_routes_sw[] = {
89*4882a593Smuzhiyun { "PDM0", "Capture Switch", "PDM_DAT0" },
90*4882a593Smuzhiyun { "PDM1", "Capture Switch", "PDM_DAT1" },
91*4882a593Smuzhiyun { "PDM2", "Capture Switch", "PDM_DAT2" },
92*4882a593Smuzhiyun { "PDM3", "Capture Switch", "PDM_DAT3" },
93*4882a593Smuzhiyun { "AIF1TX1", NULL, "PDM0" },
94*4882a593Smuzhiyun { "AIF1TX2", NULL, "PDM0" },
95*4882a593Smuzhiyun { "AIF1TX3", NULL, "PDM1" },
96*4882a593Smuzhiyun { "AIF1TX4", NULL, "PDM1" },
97*4882a593Smuzhiyun { "AIF1TX5", NULL, "PDM2" },
98*4882a593Smuzhiyun { "AIF1TX6", NULL, "PDM2" },
99*4882a593Smuzhiyun { "AIF1TX7", NULL, "PDM3" },
100*4882a593Smuzhiyun { "AIF1TX8", NULL, "PDM3" },
101*4882a593Smuzhiyun { "Capture", NULL, "PDM_CLK0" },
102*4882a593Smuzhiyun { "Capture", NULL, "PDM_CLK1" },
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun static const struct snd_soc_dapm_widget adau7118_widgets_hw[] = {
106*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("AIF1TX", "Capture", 0, SND_SOC_NOPM, 0, 0),
107*4882a593Smuzhiyun };
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun static const struct snd_soc_dapm_route adau7118_routes_hw[] = {
110*4882a593Smuzhiyun { "AIF1TX", NULL, "PDM_DAT0" },
111*4882a593Smuzhiyun { "AIF1TX", NULL, "PDM_DAT1" },
112*4882a593Smuzhiyun { "AIF1TX", NULL, "PDM_DAT2" },
113*4882a593Smuzhiyun { "AIF1TX", NULL, "PDM_DAT3" },
114*4882a593Smuzhiyun };
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun static const struct snd_soc_dapm_widget adau7118_widgets[] = {
117*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("PDM_DAT0"),
118*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("PDM_DAT1"),
119*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("PDM_DAT2"),
120*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("PDM_DAT3"),
121*4882a593Smuzhiyun };
122*4882a593Smuzhiyun
adau7118_set_channel_map(struct snd_soc_dai * dai,unsigned int tx_num,unsigned int * tx_slot,unsigned int rx_num,unsigned int * rx_slot)123*4882a593Smuzhiyun static int adau7118_set_channel_map(struct snd_soc_dai *dai,
124*4882a593Smuzhiyun unsigned int tx_num, unsigned int *tx_slot,
125*4882a593Smuzhiyun unsigned int rx_num, unsigned int *rx_slot)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun struct adau7118_data *st =
128*4882a593Smuzhiyun snd_soc_component_get_drvdata(dai->component);
129*4882a593Smuzhiyun int chan, ret;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun dev_dbg(st->dev, "Set channel map, %d", tx_num);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun for (chan = 0; chan < tx_num; chan++) {
134*4882a593Smuzhiyun ret = snd_soc_component_update_bits(dai->component,
135*4882a593Smuzhiyun ADAU7118_REG_SPT_CX(chan),
136*4882a593Smuzhiyun ADAU7118_SPT_SLOT_MASK,
137*4882a593Smuzhiyun ADAU7118_SPT_SLOT(tx_slot[chan]));
138*4882a593Smuzhiyun if (ret < 0)
139*4882a593Smuzhiyun return ret;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun return 0;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
adau7118_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)145*4882a593Smuzhiyun static int adau7118_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun struct adau7118_data *st =
148*4882a593Smuzhiyun snd_soc_component_get_drvdata(dai->component);
149*4882a593Smuzhiyun int ret = 0;
150*4882a593Smuzhiyun u32 regval;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun dev_dbg(st->dev, "Set format, fmt:%d\n", fmt);
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
155*4882a593Smuzhiyun case SND_SOC_DAIFMT_I2S:
156*4882a593Smuzhiyun ret = snd_soc_component_update_bits(dai->component,
157*4882a593Smuzhiyun ADAU7118_REG_SPT_CTRL1,
158*4882a593Smuzhiyun ADAU7118_DATA_FMT_MASK,
159*4882a593Smuzhiyun ADAU7118_DATA_FMT(0));
160*4882a593Smuzhiyun break;
161*4882a593Smuzhiyun case SND_SOC_DAIFMT_LEFT_J:
162*4882a593Smuzhiyun ret = snd_soc_component_update_bits(dai->component,
163*4882a593Smuzhiyun ADAU7118_REG_SPT_CTRL1,
164*4882a593Smuzhiyun ADAU7118_DATA_FMT_MASK,
165*4882a593Smuzhiyun ADAU7118_DATA_FMT(1));
166*4882a593Smuzhiyun break;
167*4882a593Smuzhiyun case SND_SOC_DAIFMT_RIGHT_J:
168*4882a593Smuzhiyun st->right_j = true;
169*4882a593Smuzhiyun break;
170*4882a593Smuzhiyun default:
171*4882a593Smuzhiyun dev_err(st->dev, "Invalid format %d",
172*4882a593Smuzhiyun fmt & SND_SOC_DAIFMT_FORMAT_MASK);
173*4882a593Smuzhiyun return -EINVAL;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun if (ret < 0)
177*4882a593Smuzhiyun return ret;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
180*4882a593Smuzhiyun case SND_SOC_DAIFMT_NB_NF:
181*4882a593Smuzhiyun regval = ADAU7118_LRCLK_BCLK_POL(0);
182*4882a593Smuzhiyun break;
183*4882a593Smuzhiyun case SND_SOC_DAIFMT_NB_IF:
184*4882a593Smuzhiyun regval = ADAU7118_LRCLK_BCLK_POL(2);
185*4882a593Smuzhiyun break;
186*4882a593Smuzhiyun case SND_SOC_DAIFMT_IB_NF:
187*4882a593Smuzhiyun regval = ADAU7118_LRCLK_BCLK_POL(1);
188*4882a593Smuzhiyun break;
189*4882a593Smuzhiyun case SND_SOC_DAIFMT_IB_IF:
190*4882a593Smuzhiyun regval = ADAU7118_LRCLK_BCLK_POL(3);
191*4882a593Smuzhiyun break;
192*4882a593Smuzhiyun default:
193*4882a593Smuzhiyun dev_err(st->dev, "Invalid Inv mask %d",
194*4882a593Smuzhiyun fmt & SND_SOC_DAIFMT_INV_MASK);
195*4882a593Smuzhiyun return -EINVAL;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun ret = snd_soc_component_update_bits(dai->component,
199*4882a593Smuzhiyun ADAU7118_REG_SPT_CTRL2,
200*4882a593Smuzhiyun ADAU7118_LRCLK_BCLK_POL_MASK,
201*4882a593Smuzhiyun regval);
202*4882a593Smuzhiyun if (ret < 0)
203*4882a593Smuzhiyun return ret;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun return 0;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
adau7118_set_tristate(struct snd_soc_dai * dai,int tristate)208*4882a593Smuzhiyun static int adau7118_set_tristate(struct snd_soc_dai *dai, int tristate)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun struct adau7118_data *st =
211*4882a593Smuzhiyun snd_soc_component_get_drvdata(dai->component);
212*4882a593Smuzhiyun int ret;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun dev_dbg(st->dev, "Set tristate, %d\n", tristate);
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun ret = snd_soc_component_update_bits(dai->component,
217*4882a593Smuzhiyun ADAU7118_REG_SPT_CTRL1,
218*4882a593Smuzhiyun ADAU7118_TRISTATE_MASK,
219*4882a593Smuzhiyun ADAU7118_TRISTATE(tristate));
220*4882a593Smuzhiyun if (ret < 0)
221*4882a593Smuzhiyun return ret;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun return 0;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
adau7118_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)226*4882a593Smuzhiyun static int adau7118_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
227*4882a593Smuzhiyun unsigned int rx_mask, int slots,
228*4882a593Smuzhiyun int slot_width)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun struct adau7118_data *st =
231*4882a593Smuzhiyun snd_soc_component_get_drvdata(dai->component);
232*4882a593Smuzhiyun int ret = 0;
233*4882a593Smuzhiyun u32 regval;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun dev_dbg(st->dev, "Set tdm, slots:%d width:%d\n", slots, slot_width);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun switch (slot_width) {
238*4882a593Smuzhiyun case 32:
239*4882a593Smuzhiyun regval = ADAU7118_SLOT_WIDTH(0);
240*4882a593Smuzhiyun break;
241*4882a593Smuzhiyun case 24:
242*4882a593Smuzhiyun regval = ADAU7118_SLOT_WIDTH(2);
243*4882a593Smuzhiyun break;
244*4882a593Smuzhiyun case 16:
245*4882a593Smuzhiyun regval = ADAU7118_SLOT_WIDTH(1);
246*4882a593Smuzhiyun break;
247*4882a593Smuzhiyun default:
248*4882a593Smuzhiyun dev_err(st->dev, "Invalid slot width:%d\n", slot_width);
249*4882a593Smuzhiyun return -EINVAL;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun ret = snd_soc_component_update_bits(dai->component,
253*4882a593Smuzhiyun ADAU7118_REG_SPT_CTRL1,
254*4882a593Smuzhiyun ADAU7118_SLOT_WIDTH_MASK, regval);
255*4882a593Smuzhiyun if (ret < 0)
256*4882a593Smuzhiyun return ret;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun st->slot_width = slot_width;
259*4882a593Smuzhiyun st->slots = slots;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun return 0;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
adau7118_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)264*4882a593Smuzhiyun static int adau7118_hw_params(struct snd_pcm_substream *substream,
265*4882a593Smuzhiyun struct snd_pcm_hw_params *params,
266*4882a593Smuzhiyun struct snd_soc_dai *dai)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun struct adau7118_data *st =
269*4882a593Smuzhiyun snd_soc_component_get_drvdata(dai->component);
270*4882a593Smuzhiyun u32 data_width = params_width(params), slots_width;
271*4882a593Smuzhiyun int ret;
272*4882a593Smuzhiyun u32 regval;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun if (!st->slots) {
275*4882a593Smuzhiyun /* set stereo mode */
276*4882a593Smuzhiyun ret = snd_soc_component_update_bits(dai->component,
277*4882a593Smuzhiyun ADAU7118_REG_SPT_CTRL1,
278*4882a593Smuzhiyun ADAU7118_SAI_MODE_MASK,
279*4882a593Smuzhiyun ADAU7118_SAI_MODE(0));
280*4882a593Smuzhiyun if (ret < 0)
281*4882a593Smuzhiyun return ret;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun slots_width = 32;
284*4882a593Smuzhiyun } else {
285*4882a593Smuzhiyun slots_width = st->slot_width;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun if (data_width > slots_width) {
289*4882a593Smuzhiyun dev_err(st->dev, "Invalid data_width:%d, slots_width:%d",
290*4882a593Smuzhiyun data_width, slots_width);
291*4882a593Smuzhiyun return -EINVAL;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun if (st->right_j) {
295*4882a593Smuzhiyun switch (slots_width - data_width) {
296*4882a593Smuzhiyun case 8:
297*4882a593Smuzhiyun /* delay bclck by 8 */
298*4882a593Smuzhiyun regval = ADAU7118_DATA_FMT(2);
299*4882a593Smuzhiyun break;
300*4882a593Smuzhiyun case 12:
301*4882a593Smuzhiyun /* delay bclck by 12 */
302*4882a593Smuzhiyun regval = ADAU7118_DATA_FMT(3);
303*4882a593Smuzhiyun break;
304*4882a593Smuzhiyun case 16:
305*4882a593Smuzhiyun /* delay bclck by 16 */
306*4882a593Smuzhiyun regval = ADAU7118_DATA_FMT(4);
307*4882a593Smuzhiyun break;
308*4882a593Smuzhiyun default:
309*4882a593Smuzhiyun dev_err(st->dev,
310*4882a593Smuzhiyun "Cannot set right_j setting, slot_w:%d, data_w:%d\n",
311*4882a593Smuzhiyun slots_width, data_width);
312*4882a593Smuzhiyun return -EINVAL;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun ret = snd_soc_component_update_bits(dai->component,
316*4882a593Smuzhiyun ADAU7118_REG_SPT_CTRL1,
317*4882a593Smuzhiyun ADAU7118_DATA_FMT_MASK,
318*4882a593Smuzhiyun regval);
319*4882a593Smuzhiyun if (ret < 0)
320*4882a593Smuzhiyun return ret;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun return 0;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
adau7118_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)326*4882a593Smuzhiyun static int adau7118_set_bias_level(struct snd_soc_component *component,
327*4882a593Smuzhiyun enum snd_soc_bias_level level)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun struct adau7118_data *st = snd_soc_component_get_drvdata(component);
330*4882a593Smuzhiyun int ret = 0;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun dev_dbg(st->dev, "Set bias level %d\n", level);
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun switch (level) {
335*4882a593Smuzhiyun case SND_SOC_BIAS_ON:
336*4882a593Smuzhiyun case SND_SOC_BIAS_PREPARE:
337*4882a593Smuzhiyun break;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun case SND_SOC_BIAS_STANDBY:
340*4882a593Smuzhiyun if (snd_soc_component_get_bias_level(component) ==
341*4882a593Smuzhiyun SND_SOC_BIAS_OFF) {
342*4882a593Smuzhiyun /* power on */
343*4882a593Smuzhiyun ret = regulator_enable(st->iovdd);
344*4882a593Smuzhiyun if (ret)
345*4882a593Smuzhiyun return ret;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun /* there's no timing constraints before enabling dvdd */
348*4882a593Smuzhiyun ret = regulator_enable(st->dvdd);
349*4882a593Smuzhiyun if (ret) {
350*4882a593Smuzhiyun regulator_disable(st->iovdd);
351*4882a593Smuzhiyun return ret;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun if (st->hw_mode)
355*4882a593Smuzhiyun return 0;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun regcache_cache_only(st->map, false);
358*4882a593Smuzhiyun /* sync cache */
359*4882a593Smuzhiyun ret = snd_soc_component_cache_sync(component);
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun break;
362*4882a593Smuzhiyun case SND_SOC_BIAS_OFF:
363*4882a593Smuzhiyun /* power off */
364*4882a593Smuzhiyun ret = regulator_disable(st->dvdd);
365*4882a593Smuzhiyun if (ret)
366*4882a593Smuzhiyun return ret;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun ret = regulator_disable(st->iovdd);
369*4882a593Smuzhiyun if (ret)
370*4882a593Smuzhiyun return ret;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun if (st->hw_mode)
373*4882a593Smuzhiyun return 0;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun /* cache only */
376*4882a593Smuzhiyun regcache_mark_dirty(st->map);
377*4882a593Smuzhiyun regcache_cache_only(st->map, true);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun break;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun return ret;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
adau7118_component_probe(struct snd_soc_component * component)385*4882a593Smuzhiyun static int adau7118_component_probe(struct snd_soc_component *component)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun struct adau7118_data *st = snd_soc_component_get_drvdata(component);
388*4882a593Smuzhiyun struct snd_soc_dapm_context *dapm =
389*4882a593Smuzhiyun snd_soc_component_get_dapm(component);
390*4882a593Smuzhiyun int ret = 0;
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun if (st->hw_mode) {
393*4882a593Smuzhiyun ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_hw,
394*4882a593Smuzhiyun ARRAY_SIZE(adau7118_widgets_hw));
395*4882a593Smuzhiyun if (ret)
396*4882a593Smuzhiyun return ret;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_hw,
399*4882a593Smuzhiyun ARRAY_SIZE(adau7118_routes_hw));
400*4882a593Smuzhiyun } else {
401*4882a593Smuzhiyun snd_soc_component_init_regmap(component, st->map);
402*4882a593Smuzhiyun ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_sw,
403*4882a593Smuzhiyun ARRAY_SIZE(adau7118_widgets_sw));
404*4882a593Smuzhiyun if (ret)
405*4882a593Smuzhiyun return ret;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_sw,
408*4882a593Smuzhiyun ARRAY_SIZE(adau7118_routes_sw));
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun return ret;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun static const struct snd_soc_dai_ops adau7118_ops = {
415*4882a593Smuzhiyun .hw_params = adau7118_hw_params,
416*4882a593Smuzhiyun .set_channel_map = adau7118_set_channel_map,
417*4882a593Smuzhiyun .set_fmt = adau7118_set_fmt,
418*4882a593Smuzhiyun .set_tdm_slot = adau7118_set_tdm_slot,
419*4882a593Smuzhiyun .set_tristate = adau7118_set_tristate,
420*4882a593Smuzhiyun };
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun static struct snd_soc_dai_driver adau7118_dai = {
423*4882a593Smuzhiyun .name = "adau7118-hifi-capture",
424*4882a593Smuzhiyun .capture = {
425*4882a593Smuzhiyun .stream_name = "Capture",
426*4882a593Smuzhiyun .channels_min = 1,
427*4882a593Smuzhiyun .channels_max = 8,
428*4882a593Smuzhiyun .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |
429*4882a593Smuzhiyun SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE |
430*4882a593Smuzhiyun SNDRV_PCM_FMTBIT_S24_3LE,
431*4882a593Smuzhiyun .rates = SNDRV_PCM_RATE_CONTINUOUS,
432*4882a593Smuzhiyun .rate_min = 4000,
433*4882a593Smuzhiyun .rate_max = 192000,
434*4882a593Smuzhiyun .sig_bits = 24,
435*4882a593Smuzhiyun },
436*4882a593Smuzhiyun };
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun static const struct snd_soc_component_driver adau7118_component_driver = {
439*4882a593Smuzhiyun .probe = adau7118_component_probe,
440*4882a593Smuzhiyun .set_bias_level = adau7118_set_bias_level,
441*4882a593Smuzhiyun .dapm_widgets = adau7118_widgets,
442*4882a593Smuzhiyun .num_dapm_widgets = ARRAY_SIZE(adau7118_widgets),
443*4882a593Smuzhiyun .use_pmdown_time = 1,
444*4882a593Smuzhiyun .endianness = 1,
445*4882a593Smuzhiyun .non_legacy_dai_naming = 1,
446*4882a593Smuzhiyun };
447*4882a593Smuzhiyun
adau7118_regulator_disable(void * data)448*4882a593Smuzhiyun static void adau7118_regulator_disable(void *data)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun struct adau7118_data *st = data;
451*4882a593Smuzhiyun int ret;
452*4882a593Smuzhiyun /*
453*4882a593Smuzhiyun * If we fail to disable DVDD, don't bother in trying IOVDD. We
454*4882a593Smuzhiyun * actually don't want to be left in the situation where DVDD
455*4882a593Smuzhiyun * is enabled and IOVDD is disabled.
456*4882a593Smuzhiyun */
457*4882a593Smuzhiyun ret = regulator_disable(st->dvdd);
458*4882a593Smuzhiyun if (ret)
459*4882a593Smuzhiyun return;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun regulator_disable(st->iovdd);
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
adau7118_regulator_setup(struct adau7118_data * st)464*4882a593Smuzhiyun static int adau7118_regulator_setup(struct adau7118_data *st)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun st->iovdd = devm_regulator_get(st->dev, "iovdd");
467*4882a593Smuzhiyun if (IS_ERR(st->iovdd)) {
468*4882a593Smuzhiyun dev_err(st->dev, "Could not get iovdd: %ld\n",
469*4882a593Smuzhiyun PTR_ERR(st->iovdd));
470*4882a593Smuzhiyun return PTR_ERR(st->iovdd);
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun st->dvdd = devm_regulator_get(st->dev, "dvdd");
474*4882a593Smuzhiyun if (IS_ERR(st->dvdd)) {
475*4882a593Smuzhiyun dev_err(st->dev, "Could not get dvdd: %ld\n",
476*4882a593Smuzhiyun PTR_ERR(st->dvdd));
477*4882a593Smuzhiyun return PTR_ERR(st->dvdd);
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun /* just assume the device is in reset */
480*4882a593Smuzhiyun if (!st->hw_mode) {
481*4882a593Smuzhiyun regcache_mark_dirty(st->map);
482*4882a593Smuzhiyun regcache_cache_only(st->map, true);
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun return devm_add_action_or_reset(st->dev, adau7118_regulator_disable,
486*4882a593Smuzhiyun st);
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
adau7118_parset_dt(const struct adau7118_data * st)489*4882a593Smuzhiyun static int adau7118_parset_dt(const struct adau7118_data *st)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun int ret;
492*4882a593Smuzhiyun u32 dec_ratio = 0;
493*4882a593Smuzhiyun /* 4 inputs */
494*4882a593Smuzhiyun u32 clk_map[4], regval;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun if (st->hw_mode)
497*4882a593Smuzhiyun return 0;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun ret = device_property_read_u32(st->dev, "adi,decimation-ratio",
500*4882a593Smuzhiyun &dec_ratio);
501*4882a593Smuzhiyun if (!ret) {
502*4882a593Smuzhiyun switch (dec_ratio) {
503*4882a593Smuzhiyun case 64:
504*4882a593Smuzhiyun regval = ADAU7118_DEC_RATIO(0);
505*4882a593Smuzhiyun break;
506*4882a593Smuzhiyun case 32:
507*4882a593Smuzhiyun regval = ADAU7118_DEC_RATIO(1);
508*4882a593Smuzhiyun break;
509*4882a593Smuzhiyun case 16:
510*4882a593Smuzhiyun regval = ADAU7118_DEC_RATIO(2);
511*4882a593Smuzhiyun break;
512*4882a593Smuzhiyun default:
513*4882a593Smuzhiyun dev_err(st->dev, "Invalid dec ratio: %u", dec_ratio);
514*4882a593Smuzhiyun return -EINVAL;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun ret = regmap_update_bits(st->map,
518*4882a593Smuzhiyun ADAU7118_REG_DEC_RATIO_CLK_MAP,
519*4882a593Smuzhiyun ADAU7118_DEC_RATIO_MASK, regval);
520*4882a593Smuzhiyun if (ret)
521*4882a593Smuzhiyun return ret;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun ret = device_property_read_u32_array(st->dev, "adi,pdm-clk-map",
525*4882a593Smuzhiyun clk_map, ARRAY_SIZE(clk_map));
526*4882a593Smuzhiyun if (!ret) {
527*4882a593Smuzhiyun int pdm;
528*4882a593Smuzhiyun u32 _clk_map = 0;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun for (pdm = 0; pdm < ARRAY_SIZE(clk_map); pdm++)
531*4882a593Smuzhiyun _clk_map |= (clk_map[pdm] << (pdm + 4));
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun ret = regmap_update_bits(st->map,
534*4882a593Smuzhiyun ADAU7118_REG_DEC_RATIO_CLK_MAP,
535*4882a593Smuzhiyun ADAU7118_CLK_MAP_MASK, _clk_map);
536*4882a593Smuzhiyun if (ret)
537*4882a593Smuzhiyun return ret;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun return 0;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun
adau7118_probe(struct device * dev,struct regmap * map,bool hw_mode)543*4882a593Smuzhiyun int adau7118_probe(struct device *dev, struct regmap *map, bool hw_mode)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun struct adau7118_data *st;
546*4882a593Smuzhiyun int ret;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
549*4882a593Smuzhiyun if (!st)
550*4882a593Smuzhiyun return -ENOMEM;
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun st->dev = dev;
553*4882a593Smuzhiyun st->hw_mode = hw_mode;
554*4882a593Smuzhiyun dev_set_drvdata(dev, st);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun if (!hw_mode) {
557*4882a593Smuzhiyun st->map = map;
558*4882a593Smuzhiyun adau7118_dai.ops = &adau7118_ops;
559*4882a593Smuzhiyun /*
560*4882a593Smuzhiyun * Perform a full soft reset. This will set all register's
561*4882a593Smuzhiyun * with their reset values.
562*4882a593Smuzhiyun */
563*4882a593Smuzhiyun ret = regmap_update_bits(map, ADAU7118_REG_RESET,
564*4882a593Smuzhiyun ADAU7118_FULL_SOFT_R_MASK,
565*4882a593Smuzhiyun ADAU7118_FULL_SOFT_R(1));
566*4882a593Smuzhiyun if (ret)
567*4882a593Smuzhiyun return ret;
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun ret = adau7118_parset_dt(st);
571*4882a593Smuzhiyun if (ret)
572*4882a593Smuzhiyun return ret;
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun ret = adau7118_regulator_setup(st);
575*4882a593Smuzhiyun if (ret)
576*4882a593Smuzhiyun return ret;
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun return devm_snd_soc_register_component(dev,
579*4882a593Smuzhiyun &adau7118_component_driver,
580*4882a593Smuzhiyun &adau7118_dai, 1);
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(adau7118_probe);
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
585*4882a593Smuzhiyun MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver");
586*4882a593Smuzhiyun MODULE_LICENSE("GPL");
587