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