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
35struct 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 */
47static 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
54static 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
88static 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
105static 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
109static 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
116static 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
123static 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
145static 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
208static 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
226static 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
264static 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
326static 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
385static 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
414static 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
422static 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
438static 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
447static 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
471static 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
525int 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}
564EXPORT_SYMBOL_GPL(adau7118_probe);
565
566MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
567MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver");
568MODULE_LICENSE("GPL");
569

source code of linux/sound/soc/codecs/adau7118.c