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
adau7118_set_channel_map(struct snd_soc_dai * dai,unsigned int tx_num,const unsigned int * tx_slot,unsigned int rx_num,const unsigned int * rx_slot)123 static int adau7118_set_channel_map(struct snd_soc_dai *dai,
124 unsigned int tx_num,
125 const unsigned int *tx_slot,
126 unsigned int rx_num,
127 const unsigned int *rx_slot)
128 {
129 struct adau7118_data *st =
130 snd_soc_component_get_drvdata(dai->component);
131 int chan, ret;
132
133 dev_dbg(st->dev, "Set channel map, %d", tx_num);
134
135 for (chan = 0; chan < tx_num; chan++) {
136 ret = snd_soc_component_update_bits(dai->component,
137 ADAU7118_REG_SPT_CX(chan),
138 ADAU7118_SPT_SLOT_MASK,
139 ADAU7118_SPT_SLOT(tx_slot[chan]));
140 if (ret < 0)
141 return ret;
142 }
143
144 return 0;
145 }
146
adau7118_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)147 static int adau7118_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
148 {
149 struct adau7118_data *st =
150 snd_soc_component_get_drvdata(dai->component);
151 int ret = 0;
152 u32 regval;
153
154 dev_dbg(st->dev, "Set format, fmt:%d\n", fmt);
155
156 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
157 case SND_SOC_DAIFMT_I2S:
158 ret = snd_soc_component_update_bits(dai->component,
159 ADAU7118_REG_SPT_CTRL1,
160 ADAU7118_DATA_FMT_MASK,
161 ADAU7118_DATA_FMT(0));
162 break;
163 case SND_SOC_DAIFMT_LEFT_J:
164 ret = snd_soc_component_update_bits(dai->component,
165 ADAU7118_REG_SPT_CTRL1,
166 ADAU7118_DATA_FMT_MASK,
167 ADAU7118_DATA_FMT(1));
168 break;
169 case SND_SOC_DAIFMT_RIGHT_J:
170 st->right_j = true;
171 break;
172 case SND_SOC_DAIFMT_DSP_A:
173 ret = snd_soc_component_update_bits(dai->component,
174 ADAU7118_REG_SPT_CTRL1,
175 ADAU7118_DATA_FMT_MASK,
176 ADAU7118_DATA_FMT(1));
177 break;
178 default:
179 dev_err(st->dev, "Invalid format %d",
180 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
181 return -EINVAL;
182 }
183
184 if (ret < 0)
185 return ret;
186
187 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
188 case SND_SOC_DAIFMT_NB_NF:
189 regval = ADAU7118_LRCLK_BCLK_POL(0);
190 break;
191 case SND_SOC_DAIFMT_NB_IF:
192 regval = ADAU7118_LRCLK_BCLK_POL(2);
193 break;
194 case SND_SOC_DAIFMT_IB_NF:
195 regval = ADAU7118_LRCLK_BCLK_POL(1);
196 break;
197 case SND_SOC_DAIFMT_IB_IF:
198 regval = ADAU7118_LRCLK_BCLK_POL(3);
199 break;
200 default:
201 dev_err(st->dev, "Invalid Inv mask %d",
202 fmt & SND_SOC_DAIFMT_INV_MASK);
203 return -EINVAL;
204 }
205
206 ret = snd_soc_component_update_bits(dai->component,
207 ADAU7118_REG_SPT_CTRL2,
208 ADAU7118_LRCLK_BCLK_POL_MASK,
209 regval);
210 if (ret < 0)
211 return ret;
212
213 return 0;
214 }
215
adau7118_set_tristate(struct snd_soc_dai * dai,int tristate)216 static int adau7118_set_tristate(struct snd_soc_dai *dai, int tristate)
217 {
218 struct adau7118_data *st =
219 snd_soc_component_get_drvdata(dai->component);
220 int ret;
221
222 dev_dbg(st->dev, "Set tristate, %d\n", tristate);
223
224 ret = snd_soc_component_update_bits(dai->component,
225 ADAU7118_REG_SPT_CTRL1,
226 ADAU7118_TRISTATE_MASK,
227 ADAU7118_TRISTATE(tristate));
228 if (ret < 0)
229 return ret;
230
231 return 0;
232 }
233
adau7118_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)234 static int adau7118_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
235 unsigned int rx_mask, int slots,
236 int slot_width)
237 {
238 struct adau7118_data *st =
239 snd_soc_component_get_drvdata(dai->component);
240 int ret = 0;
241 u32 regval;
242
243 dev_dbg(st->dev, "Set tdm, slots:%d width:%d\n", slots, slot_width);
244
245 switch (slot_width) {
246 case 32:
247 regval = ADAU7118_SLOT_WIDTH(0);
248 break;
249 case 24:
250 regval = ADAU7118_SLOT_WIDTH(2);
251 break;
252 case 16:
253 regval = ADAU7118_SLOT_WIDTH(1);
254 break;
255 default:
256 dev_err(st->dev, "Invalid slot width:%d\n", slot_width);
257 return -EINVAL;
258 }
259
260 ret = snd_soc_component_update_bits(dai->component,
261 ADAU7118_REG_SPT_CTRL1,
262 ADAU7118_SLOT_WIDTH_MASK, regval);
263 if (ret < 0)
264 return ret;
265
266 st->slot_width = slot_width;
267 st->slots = slots;
268
269 return 0;
270 }
271
adau7118_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)272 static int adau7118_hw_params(struct snd_pcm_substream *substream,
273 struct snd_pcm_hw_params *params,
274 struct snd_soc_dai *dai)
275 {
276 struct adau7118_data *st =
277 snd_soc_component_get_drvdata(dai->component);
278 u32 data_width = params_width(params), slots_width;
279 int ret;
280 u32 regval;
281
282 if (!st->slots) {
283 /* set stereo mode */
284 ret = snd_soc_component_update_bits(dai->component,
285 ADAU7118_REG_SPT_CTRL1,
286 ADAU7118_SAI_MODE_MASK,
287 ADAU7118_SAI_MODE(0));
288 if (ret < 0)
289 return ret;
290
291 slots_width = 32;
292 } else {
293 slots_width = st->slot_width;
294 }
295
296 if (data_width > slots_width) {
297 dev_err(st->dev, "Invalid data_width:%d, slots_width:%d",
298 data_width, slots_width);
299 return -EINVAL;
300 }
301
302 if (st->right_j) {
303 switch (slots_width - data_width) {
304 case 8:
305 /* delay bclck by 8 */
306 regval = ADAU7118_DATA_FMT(2);
307 break;
308 case 12:
309 /* delay bclck by 12 */
310 regval = ADAU7118_DATA_FMT(3);
311 break;
312 case 16:
313 /* delay bclck by 16 */
314 regval = ADAU7118_DATA_FMT(4);
315 break;
316 default:
317 dev_err(st->dev,
318 "Cannot set right_j setting, slot_w:%d, data_w:%d\n",
319 slots_width, data_width);
320 return -EINVAL;
321 }
322
323 ret = snd_soc_component_update_bits(dai->component,
324 ADAU7118_REG_SPT_CTRL1,
325 ADAU7118_DATA_FMT_MASK,
326 regval);
327 if (ret < 0)
328 return ret;
329 }
330
331 return 0;
332 }
333
adau7118_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)334 static int adau7118_set_bias_level(struct snd_soc_component *component,
335 enum snd_soc_bias_level level)
336 {
337 struct adau7118_data *st = snd_soc_component_get_drvdata(component);
338 int ret = 0;
339
340 dev_dbg(st->dev, "Set bias level %d\n", level);
341
342 switch (level) {
343 case SND_SOC_BIAS_ON:
344 case SND_SOC_BIAS_PREPARE:
345 break;
346
347 case SND_SOC_BIAS_STANDBY:
348 if (snd_soc_component_get_bias_level(component) ==
349 SND_SOC_BIAS_OFF) {
350 /* power on */
351 ret = regulator_enable(st->iovdd);
352 if (ret)
353 return ret;
354
355 /* there's no timing constraints before enabling dvdd */
356 ret = regulator_enable(st->dvdd);
357 if (ret) {
358 regulator_disable(st->iovdd);
359 return ret;
360 }
361
362 if (st->hw_mode)
363 return 0;
364
365 regcache_cache_only(st->map, false);
366 /* sync cache */
367 ret = snd_soc_component_cache_sync(component);
368 }
369 break;
370 case SND_SOC_BIAS_OFF:
371 /* power off */
372 ret = regulator_disable(st->dvdd);
373 if (ret)
374 return ret;
375
376 ret = regulator_disable(st->iovdd);
377 if (ret)
378 return ret;
379
380 if (st->hw_mode)
381 return 0;
382
383 /* cache only */
384 regcache_mark_dirty(st->map);
385 regcache_cache_only(st->map, true);
386
387 break;
388 }
389
390 return ret;
391 }
392
adau7118_component_probe(struct snd_soc_component * component)393 static int adau7118_component_probe(struct snd_soc_component *component)
394 {
395 struct adau7118_data *st = snd_soc_component_get_drvdata(component);
396 struct snd_soc_dapm_context *dapm =
397 snd_soc_component_get_dapm(component);
398 int ret = 0;
399
400 if (st->hw_mode) {
401 ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_hw,
402 ARRAY_SIZE(adau7118_widgets_hw));
403 if (ret)
404 return ret;
405
406 ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_hw,
407 ARRAY_SIZE(adau7118_routes_hw));
408 } else {
409 snd_soc_component_init_regmap(component, st->map);
410 ret = snd_soc_dapm_new_controls(dapm, adau7118_widgets_sw,
411 ARRAY_SIZE(adau7118_widgets_sw));
412 if (ret)
413 return ret;
414
415 ret = snd_soc_dapm_add_routes(dapm, adau7118_routes_sw,
416 ARRAY_SIZE(adau7118_routes_sw));
417 }
418
419 return ret;
420 }
421
422 static const struct snd_soc_dai_ops adau7118_ops = {
423 .hw_params = adau7118_hw_params,
424 .set_channel_map = adau7118_set_channel_map,
425 .set_fmt = adau7118_set_fmt,
426 .set_tdm_slot = adau7118_set_tdm_slot,
427 .set_tristate = adau7118_set_tristate,
428 };
429
430 static struct snd_soc_dai_driver adau7118_dai = {
431 .name = "adau7118-hifi-capture",
432 .capture = {
433 .stream_name = "Capture",
434 .channels_min = 1,
435 .channels_max = 8,
436 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |
437 SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE |
438 SNDRV_PCM_FMTBIT_S24_3LE,
439 .rates = SNDRV_PCM_RATE_CONTINUOUS,
440 .rate_min = 4000,
441 .rate_max = 192000,
442 .sig_bits = 24,
443 },
444 };
445
446 static const struct snd_soc_component_driver adau7118_component_driver = {
447 .probe = adau7118_component_probe,
448 .set_bias_level = adau7118_set_bias_level,
449 .dapm_widgets = adau7118_widgets,
450 .num_dapm_widgets = ARRAY_SIZE(adau7118_widgets),
451 .use_pmdown_time = 1,
452 .endianness = 1,
453 };
454
adau7118_regulator_setup(struct adau7118_data * st)455 static int adau7118_regulator_setup(struct adau7118_data *st)
456 {
457 st->iovdd = devm_regulator_get(st->dev, "iovdd");
458 if (IS_ERR(st->iovdd)) {
459 dev_err(st->dev, "Could not get iovdd: %ld\n",
460 PTR_ERR(st->iovdd));
461 return PTR_ERR(st->iovdd);
462 }
463
464 st->dvdd = devm_regulator_get(st->dev, "dvdd");
465 if (IS_ERR(st->dvdd)) {
466 dev_err(st->dev, "Could not get dvdd: %ld\n",
467 PTR_ERR(st->dvdd));
468 return PTR_ERR(st->dvdd);
469 }
470 /* just assume the device is in reset */
471 if (!st->hw_mode) {
472 regcache_mark_dirty(st->map);
473 regcache_cache_only(st->map, true);
474 }
475
476 return 0;
477 }
478
adau7118_parset_dt(const struct adau7118_data * st)479 static int adau7118_parset_dt(const struct adau7118_data *st)
480 {
481 int ret;
482 u32 dec_ratio = 0;
483 /* 4 inputs */
484 u32 clk_map[4], regval;
485
486 if (st->hw_mode)
487 return 0;
488
489 ret = device_property_read_u32(st->dev, "adi,decimation-ratio",
490 &dec_ratio);
491 if (!ret) {
492 switch (dec_ratio) {
493 case 64:
494 regval = ADAU7118_DEC_RATIO(0);
495 break;
496 case 32:
497 regval = ADAU7118_DEC_RATIO(1);
498 break;
499 case 16:
500 regval = ADAU7118_DEC_RATIO(2);
501 break;
502 default:
503 dev_err(st->dev, "Invalid dec ratio: %u", dec_ratio);
504 return -EINVAL;
505 }
506
507 ret = regmap_update_bits(st->map,
508 ADAU7118_REG_DEC_RATIO_CLK_MAP,
509 ADAU7118_DEC_RATIO_MASK, regval);
510 if (ret)
511 return ret;
512 }
513
514 ret = device_property_read_u32_array(st->dev, "adi,pdm-clk-map",
515 clk_map, ARRAY_SIZE(clk_map));
516 if (!ret) {
517 int pdm;
518 u32 _clk_map = 0;
519
520 for (pdm = 0; pdm < ARRAY_SIZE(clk_map); pdm++)
521 _clk_map |= (clk_map[pdm] << (pdm + 4));
522
523 ret = regmap_update_bits(st->map,
524 ADAU7118_REG_DEC_RATIO_CLK_MAP,
525 ADAU7118_CLK_MAP_MASK, _clk_map);
526 if (ret)
527 return ret;
528 }
529
530 return 0;
531 }
532
adau7118_probe(struct device * dev,struct regmap * map,bool hw_mode)533 int adau7118_probe(struct device *dev, struct regmap *map, bool hw_mode)
534 {
535 struct adau7118_data *st;
536 int ret;
537
538 st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
539 if (!st)
540 return -ENOMEM;
541
542 st->dev = dev;
543 st->hw_mode = hw_mode;
544 dev_set_drvdata(dev, st);
545
546 if (!hw_mode) {
547 st->map = map;
548 adau7118_dai.ops = &adau7118_ops;
549 /*
550 * Perform a full soft reset. This will set all register's
551 * with their reset values.
552 */
553 ret = regmap_update_bits(map, ADAU7118_REG_RESET,
554 ADAU7118_FULL_SOFT_R_MASK,
555 ADAU7118_FULL_SOFT_R(1));
556 if (ret)
557 return ret;
558 }
559
560 ret = adau7118_parset_dt(st);
561 if (ret)
562 return ret;
563
564 ret = adau7118_regulator_setup(st);
565 if (ret)
566 return ret;
567
568 return devm_snd_soc_register_component(dev,
569 &adau7118_component_driver,
570 &adau7118_dai, 1);
571 }
572 EXPORT_SYMBOL_GPL(adau7118_probe);
573
574 MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
575 MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver");
576 MODULE_LICENSE("GPL");
577