1 // SPDX-License-Identifier: GPL-2.0
3 // Analog Devices ADAU7118 8 channel PDM-to-I2S/TDM Converter driver
5 // Copyright 2019 Analog Devices Inc.
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>
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)
35 struct adau7118_data
{
38 struct regulator
*iovdd
;
39 struct regulator
*dvdd
;
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),
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]),
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),
70 SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0, ADAU7118_REG_SPT_CX(0),
72 SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 0, ADAU7118_REG_SPT_CX(1),
74 SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 0, ADAU7118_REG_SPT_CX(2),
76 SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 0, ADAU7118_REG_SPT_CX(3),
78 SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 0, ADAU7118_REG_SPT_CX(4),
80 SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 0, ADAU7118_REG_SPT_CX(5),
82 SND_SOC_DAPM_AIF_OUT("AIF1TX7", "Capture", 0, ADAU7118_REG_SPT_CX(6),
84 SND_SOC_DAPM_AIF_OUT("AIF1TX8", "Capture", 0, ADAU7118_REG_SPT_CX(7),
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" },
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),
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" },
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"),
123 static int adau7118_set_channel_map(struct snd_soc_dai
*dai
,
125 const unsigned int *tx_slot
,
127 const unsigned int *rx_slot
)
129 struct adau7118_data
*st
=
130 snd_soc_component_get_drvdata(dai
->component
);
133 dev_dbg(st
->dev
, "Set channel map, %d", tx_num
);
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
]));
147 static int adau7118_set_fmt(struct snd_soc_dai
*dai
, unsigned int fmt
)
149 struct adau7118_data
*st
=
150 snd_soc_component_get_drvdata(dai
->component
);
154 dev_dbg(st
->dev
, "Set format, fmt:%d\n", fmt
);
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));
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));
169 case SND_SOC_DAIFMT_RIGHT_J
:
173 dev_err(st
->dev
, "Invalid format %d",
174 fmt
& SND_SOC_DAIFMT_FORMAT_MASK
);
181 switch (fmt
& SND_SOC_DAIFMT_INV_MASK
) {
182 case SND_SOC_DAIFMT_NB_NF
:
183 regval
= ADAU7118_LRCLK_BCLK_POL(0);
185 case SND_SOC_DAIFMT_NB_IF
:
186 regval
= ADAU7118_LRCLK_BCLK_POL(2);
188 case SND_SOC_DAIFMT_IB_NF
:
189 regval
= ADAU7118_LRCLK_BCLK_POL(1);
191 case SND_SOC_DAIFMT_IB_IF
:
192 regval
= ADAU7118_LRCLK_BCLK_POL(3);
195 dev_err(st
->dev
, "Invalid Inv mask %d",
196 fmt
& SND_SOC_DAIFMT_INV_MASK
);
200 ret
= snd_soc_component_update_bits(dai
->component
,
201 ADAU7118_REG_SPT_CTRL2
,
202 ADAU7118_LRCLK_BCLK_POL_MASK
,
210 static int adau7118_set_tristate(struct snd_soc_dai
*dai
, int tristate
)
212 struct adau7118_data
*st
=
213 snd_soc_component_get_drvdata(dai
->component
);
216 dev_dbg(st
->dev
, "Set tristate, %d\n", tristate
);
218 ret
= snd_soc_component_update_bits(dai
->component
,
219 ADAU7118_REG_SPT_CTRL1
,
220 ADAU7118_TRISTATE_MASK
,
221 ADAU7118_TRISTATE(tristate
));
228 static int adau7118_set_tdm_slot(struct snd_soc_dai
*dai
, unsigned int tx_mask
,
229 unsigned int rx_mask
, int slots
,
232 struct adau7118_data
*st
=
233 snd_soc_component_get_drvdata(dai
->component
);
237 dev_dbg(st
->dev
, "Set tdm, slots:%d width:%d\n", slots
, slot_width
);
239 switch (slot_width
) {
241 regval
= ADAU7118_SLOT_WIDTH(0);
244 regval
= ADAU7118_SLOT_WIDTH(2);
247 regval
= ADAU7118_SLOT_WIDTH(1);
250 dev_err(st
->dev
, "Invalid slot width:%d\n", slot_width
);
254 ret
= snd_soc_component_update_bits(dai
->component
,
255 ADAU7118_REG_SPT_CTRL1
,
256 ADAU7118_SLOT_WIDTH_MASK
, regval
);
260 st
->slot_width
= slot_width
;
266 static int adau7118_hw_params(struct snd_pcm_substream
*substream
,
267 struct snd_pcm_hw_params
*params
,
268 struct snd_soc_dai
*dai
)
270 struct adau7118_data
*st
=
271 snd_soc_component_get_drvdata(dai
->component
);
272 u32 data_width
= params_width(params
), slots_width
;
277 /* set stereo mode */
278 ret
= snd_soc_component_update_bits(dai
->component
,
279 ADAU7118_REG_SPT_CTRL1
,
280 ADAU7118_SAI_MODE_MASK
,
281 ADAU7118_SAI_MODE(0));
287 slots_width
= st
->slot_width
;
290 if (data_width
> slots_width
) {
291 dev_err(st
->dev
, "Invalid data_width:%d, slots_width:%d",
292 data_width
, slots_width
);
297 switch (slots_width
- data_width
) {
299 /* delay bclck by 8 */
300 regval
= ADAU7118_DATA_FMT(2);
303 /* delay bclck by 12 */
304 regval
= ADAU7118_DATA_FMT(3);
307 /* delay bclck by 16 */
308 regval
= ADAU7118_DATA_FMT(4);
312 "Cannot set right_j setting, slot_w:%d, data_w:%d\n",
313 slots_width
, data_width
);
317 ret
= snd_soc_component_update_bits(dai
->component
,
318 ADAU7118_REG_SPT_CTRL1
,
319 ADAU7118_DATA_FMT_MASK
,
328 static int adau7118_set_bias_level(struct snd_soc_component
*component
,
329 enum snd_soc_bias_level level
)
331 struct adau7118_data
*st
= snd_soc_component_get_drvdata(component
);
334 dev_dbg(st
->dev
, "Set bias level %d\n", level
);
337 case SND_SOC_BIAS_ON
:
338 case SND_SOC_BIAS_PREPARE
:
341 case SND_SOC_BIAS_STANDBY
:
342 if (snd_soc_component_get_bias_level(component
) ==
345 ret
= regulator_enable(st
->iovdd
);
349 /* there's no timing constraints before enabling dvdd */
350 ret
= regulator_enable(st
->dvdd
);
352 regulator_disable(st
->iovdd
);
359 regcache_cache_only(st
->map
, false);
361 ret
= snd_soc_component_cache_sync(component
);
364 case SND_SOC_BIAS_OFF
:
366 ret
= regulator_disable(st
->dvdd
);
370 ret
= regulator_disable(st
->iovdd
);
378 regcache_mark_dirty(st
->map
);
379 regcache_cache_only(st
->map
, true);
387 static int adau7118_component_probe(struct snd_soc_component
*component
)
389 struct adau7118_data
*st
= snd_soc_component_get_drvdata(component
);
390 struct snd_soc_dapm_context
*dapm
=
391 snd_soc_component_get_dapm(component
);
395 ret
= snd_soc_dapm_new_controls(dapm
, adau7118_widgets_hw
,
396 ARRAY_SIZE(adau7118_widgets_hw
));
400 ret
= snd_soc_dapm_add_routes(dapm
, adau7118_routes_hw
,
401 ARRAY_SIZE(adau7118_routes_hw
));
403 snd_soc_component_init_regmap(component
, st
->map
);
404 ret
= snd_soc_dapm_new_controls(dapm
, adau7118_widgets_sw
,
405 ARRAY_SIZE(adau7118_widgets_sw
));
409 ret
= snd_soc_dapm_add_routes(dapm
, adau7118_routes_sw
,
410 ARRAY_SIZE(adau7118_routes_sw
));
416 static const struct snd_soc_dai_ops adau7118_ops
= {
417 .hw_params
= adau7118_hw_params
,
418 .set_channel_map
= adau7118_set_channel_map
,
419 .set_fmt
= adau7118_set_fmt
,
420 .set_tdm_slot
= adau7118_set_tdm_slot
,
421 .set_tristate
= adau7118_set_tristate
,
424 static struct snd_soc_dai_driver adau7118_dai
= {
425 .name
= "adau7118-hifi-capture",
427 .stream_name
= "Capture",
430 .formats
= SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S20_3LE
|
431 SNDRV_PCM_FMTBIT_S20_LE
| SNDRV_PCM_FMTBIT_S24_LE
|
432 SNDRV_PCM_FMTBIT_S24_3LE
,
433 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
440 static const struct snd_soc_component_driver adau7118_component_driver
= {
441 .probe
= adau7118_component_probe
,
442 .set_bias_level
= adau7118_set_bias_level
,
443 .dapm_widgets
= adau7118_widgets
,
444 .num_dapm_widgets
= ARRAY_SIZE(adau7118_widgets
),
445 .use_pmdown_time
= 1,
449 static int adau7118_regulator_setup(struct adau7118_data
*st
)
451 st
->iovdd
= devm_regulator_get(st
->dev
, "iovdd");
452 if (IS_ERR(st
->iovdd
)) {
453 dev_err(st
->dev
, "Could not get iovdd: %ld\n",
455 return PTR_ERR(st
->iovdd
);
458 st
->dvdd
= devm_regulator_get(st
->dev
, "dvdd");
459 if (IS_ERR(st
->dvdd
)) {
460 dev_err(st
->dev
, "Could not get dvdd: %ld\n",
462 return PTR_ERR(st
->dvdd
);
464 /* just assume the device is in reset */
466 regcache_mark_dirty(st
->map
);
467 regcache_cache_only(st
->map
, true);
473 static int adau7118_parset_dt(const struct adau7118_data
*st
)
478 u32 clk_map
[4], regval
;
483 ret
= device_property_read_u32(st
->dev
, "adi,decimation-ratio",
488 regval
= ADAU7118_DEC_RATIO(0);
491 regval
= ADAU7118_DEC_RATIO(1);
494 regval
= ADAU7118_DEC_RATIO(2);
497 dev_err(st
->dev
, "Invalid dec ratio: %u", dec_ratio
);
501 ret
= regmap_update_bits(st
->map
,
502 ADAU7118_REG_DEC_RATIO_CLK_MAP
,
503 ADAU7118_DEC_RATIO_MASK
, regval
);
508 ret
= device_property_read_u32_array(st
->dev
, "adi,pdm-clk-map",
509 clk_map
, ARRAY_SIZE(clk_map
));
514 for (pdm
= 0; pdm
< ARRAY_SIZE(clk_map
); pdm
++)
515 _clk_map
|= (clk_map
[pdm
] << (pdm
+ 4));
517 ret
= regmap_update_bits(st
->map
,
518 ADAU7118_REG_DEC_RATIO_CLK_MAP
,
519 ADAU7118_CLK_MAP_MASK
, _clk_map
);
527 int adau7118_probe(struct device
*dev
, struct regmap
*map
, bool hw_mode
)
529 struct adau7118_data
*st
;
532 st
= devm_kzalloc(dev
, sizeof(*st
), GFP_KERNEL
);
537 st
->hw_mode
= hw_mode
;
538 dev_set_drvdata(dev
, st
);
542 adau7118_dai
.ops
= &adau7118_ops
;
544 * Perform a full soft reset. This will set all register's
545 * with their reset values.
547 ret
= regmap_update_bits(map
, ADAU7118_REG_RESET
,
548 ADAU7118_FULL_SOFT_R_MASK
,
549 ADAU7118_FULL_SOFT_R(1));
554 ret
= adau7118_parset_dt(st
);
558 ret
= adau7118_regulator_setup(st
);
562 return devm_snd_soc_register_component(dev
,
563 &adau7118_component_driver
,
566 EXPORT_SYMBOL_GPL(adau7118_probe
);
568 MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
569 MODULE_DESCRIPTION("ADAU7118 8 channel PDM-to-I2S/TDM Converter driver");
570 MODULE_LICENSE("GPL");