xref: /linux/sound/soc/meson/aiu-formatter-i2s.c (revision e5c91aac491def6ab3f90c4cc246e3fcb0f8f058)
12cbb32d8SValerio Setti // SPDX-License-Identifier: GPL-2.0
22cbb32d8SValerio Setti //
32cbb32d8SValerio Setti // Copyright (c) 2026 BayLibre, SAS.
42cbb32d8SValerio Setti // Author: Valerio Setti <vsetti@baylibre.com>
52cbb32d8SValerio Setti 
62cbb32d8SValerio Setti #include <sound/pcm_params.h>
72cbb32d8SValerio Setti #include <sound/soc.h>
82cbb32d8SValerio Setti #include <sound/soc-dai.h>
92cbb32d8SValerio Setti 
102cbb32d8SValerio Setti #include "aiu.h"
112cbb32d8SValerio Setti #include "gx-formatter.h"
122cbb32d8SValerio Setti 
132cbb32d8SValerio Setti #define AIU_I2S_SOURCE_DESC_MODE_8CH	BIT(0)
142cbb32d8SValerio Setti #define AIU_I2S_SOURCE_DESC_MODE_24BIT	BIT(5)
152cbb32d8SValerio Setti #define AIU_I2S_SOURCE_DESC_MODE_32BIT	BIT(9)
162cbb32d8SValerio Setti 
172cbb32d8SValerio Setti #define AIU_I2S_DAC_CFG_MSB_FIRST	BIT(2)
182cbb32d8SValerio Setti 
192cbb32d8SValerio Setti static struct snd_soc_dai *
202cbb32d8SValerio Setti aiu_formatter_i2s_get_be(struct snd_soc_dapm_widget *w)
212cbb32d8SValerio Setti {
222cbb32d8SValerio Setti 	struct snd_soc_dapm_path *p;
232cbb32d8SValerio Setti 	struct snd_soc_dai *be;
242cbb32d8SValerio Setti 
252cbb32d8SValerio Setti 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
262cbb32d8SValerio Setti 		if (!p->connect)
272cbb32d8SValerio Setti 			continue;
282cbb32d8SValerio Setti 
292cbb32d8SValerio Setti 		if (p->sink->id == snd_soc_dapm_dai_in)
302cbb32d8SValerio Setti 			return (struct snd_soc_dai *)p->sink->priv;
312cbb32d8SValerio Setti 
322cbb32d8SValerio Setti 		be = aiu_formatter_i2s_get_be(p->sink);
332cbb32d8SValerio Setti 		if (be)
342cbb32d8SValerio Setti 			return be;
352cbb32d8SValerio Setti 	}
362cbb32d8SValerio Setti 
372cbb32d8SValerio Setti 	return NULL;
382cbb32d8SValerio Setti }
392cbb32d8SValerio Setti 
402cbb32d8SValerio Setti static struct gx_stream *
412cbb32d8SValerio Setti aiu_formatter_i2s_get_stream(struct snd_soc_dapm_widget *w)
422cbb32d8SValerio Setti {
432cbb32d8SValerio Setti 	struct snd_soc_dai *be = aiu_formatter_i2s_get_be(w);
442cbb32d8SValerio Setti 
452cbb32d8SValerio Setti 	if (!be)
462cbb32d8SValerio Setti 		return NULL;
472cbb32d8SValerio Setti 
482cbb32d8SValerio Setti 	return snd_soc_dai_dma_data_get_playback(be);
492cbb32d8SValerio Setti }
502cbb32d8SValerio Setti 
512cbb32d8SValerio Setti static int aiu_formatter_i2s_prepare(struct regmap *map,
522cbb32d8SValerio Setti 				 const struct gx_formatter_hw *quirks,
532cbb32d8SValerio Setti 				 struct gx_stream *ts)
542cbb32d8SValerio Setti {
552cbb32d8SValerio Setti 	/* Always operate in split (classic interleaved) mode */
562cbb32d8SValerio Setti 	unsigned int desc = 0;
572cbb32d8SValerio Setti 
58*72fe2ef1SValerio Setti 	/*
59*72fe2ef1SValerio Setti 	 * Pipeline reset is already implemented in aiu_fifo_i2s_trigger() at
60*72fe2ef1SValerio Setti 	 * trigger time.
61*72fe2ef1SValerio Setti 	 */
622cbb32d8SValerio Setti 
632cbb32d8SValerio Setti 	switch (ts->physical_width) {
642cbb32d8SValerio Setti 	case 16: /* Nothing to do */
652cbb32d8SValerio Setti 		break;
662cbb32d8SValerio Setti 
672cbb32d8SValerio Setti 	case 32:
682cbb32d8SValerio Setti 		desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT |
692cbb32d8SValerio Setti 			 AIU_I2S_SOURCE_DESC_MODE_32BIT);
702cbb32d8SValerio Setti 		break;
712cbb32d8SValerio Setti 
722cbb32d8SValerio Setti 	default:
732cbb32d8SValerio Setti 		return -EINVAL;
742cbb32d8SValerio Setti 	}
752cbb32d8SValerio Setti 
762cbb32d8SValerio Setti 	switch (ts->channels) {
772cbb32d8SValerio Setti 	case 2: /* Nothing to do */
782cbb32d8SValerio Setti 		break;
792cbb32d8SValerio Setti 	case 8:
802cbb32d8SValerio Setti 		desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
812cbb32d8SValerio Setti 		break;
822cbb32d8SValerio Setti 	default:
832cbb32d8SValerio Setti 		return -EINVAL;
842cbb32d8SValerio Setti 	}
852cbb32d8SValerio Setti 
862cbb32d8SValerio Setti 	regmap_update_bits(map, AIU_I2S_SOURCE_DESC,
872cbb32d8SValerio Setti 				AIU_I2S_SOURCE_DESC_MODE_8CH |
882cbb32d8SValerio Setti 				AIU_I2S_SOURCE_DESC_MODE_24BIT |
892cbb32d8SValerio Setti 				AIU_I2S_SOURCE_DESC_MODE_32BIT,
902cbb32d8SValerio Setti 				desc);
912cbb32d8SValerio Setti 
922cbb32d8SValerio Setti 	/* Send data MSB first */
932cbb32d8SValerio Setti 	regmap_update_bits(map, AIU_I2S_DAC_CFG,
942cbb32d8SValerio Setti 				AIU_I2S_DAC_CFG_MSB_FIRST,
952cbb32d8SValerio Setti 				AIU_I2S_DAC_CFG_MSB_FIRST);
962cbb32d8SValerio Setti 
972cbb32d8SValerio Setti 	return 0;
982cbb32d8SValerio Setti }
992cbb32d8SValerio Setti 
1002cbb32d8SValerio Setti const struct gx_formatter_ops aiu_formatter_i2s_ops = {
1012cbb32d8SValerio Setti 	.get_stream	= aiu_formatter_i2s_get_stream,
1022cbb32d8SValerio Setti 	.prepare	= aiu_formatter_i2s_prepare,
1032cbb32d8SValerio Setti };
104