Linux Audio

Check our new training course

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