xref: /linux/sound/soc/meson/aiu-formatter-i2s.c (revision e5c91aac491def6ab3f90c4cc246e3fcb0f8f058)
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Copyright (c) 2026 BayLibre, SAS.
4 // Author: Valerio Setti <vsetti@baylibre.com>
5 
6 #include <sound/pcm_params.h>
7 #include <sound/soc.h>
8 #include <sound/soc-dai.h>
9 
10 #include "aiu.h"
11 #include "gx-formatter.h"
12 
13 #define AIU_I2S_SOURCE_DESC_MODE_8CH	BIT(0)
14 #define AIU_I2S_SOURCE_DESC_MODE_24BIT	BIT(5)
15 #define AIU_I2S_SOURCE_DESC_MODE_32BIT	BIT(9)
16 
17 #define AIU_I2S_DAC_CFG_MSB_FIRST	BIT(2)
18 
19 static struct snd_soc_dai *
20 aiu_formatter_i2s_get_be(struct snd_soc_dapm_widget *w)
21 {
22 	struct snd_soc_dapm_path *p;
23 	struct snd_soc_dai *be;
24 
25 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
26 		if (!p->connect)
27 			continue;
28 
29 		if (p->sink->id == snd_soc_dapm_dai_in)
30 			return (struct snd_soc_dai *)p->sink->priv;
31 
32 		be = aiu_formatter_i2s_get_be(p->sink);
33 		if (be)
34 			return be;
35 	}
36 
37 	return NULL;
38 }
39 
40 static struct gx_stream *
41 aiu_formatter_i2s_get_stream(struct snd_soc_dapm_widget *w)
42 {
43 	struct snd_soc_dai *be = aiu_formatter_i2s_get_be(w);
44 
45 	if (!be)
46 		return NULL;
47 
48 	return snd_soc_dai_dma_data_get_playback(be);
49 }
50 
51 static int aiu_formatter_i2s_prepare(struct regmap *map,
52 				 const struct gx_formatter_hw *quirks,
53 				 struct gx_stream *ts)
54 {
55 	/* Always operate in split (classic interleaved) mode */
56 	unsigned int desc = 0;
57 
58 	/*
59 	 * Pipeline reset is already implemented in aiu_fifo_i2s_trigger() at
60 	 * trigger time.
61 	 */
62 
63 	switch (ts->physical_width) {
64 	case 16: /* Nothing to do */
65 		break;
66 
67 	case 32:
68 		desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT |
69 			 AIU_I2S_SOURCE_DESC_MODE_32BIT);
70 		break;
71 
72 	default:
73 		return -EINVAL;
74 	}
75 
76 	switch (ts->channels) {
77 	case 2: /* Nothing to do */
78 		break;
79 	case 8:
80 		desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
81 		break;
82 	default:
83 		return -EINVAL;
84 	}
85 
86 	regmap_update_bits(map, AIU_I2S_SOURCE_DESC,
87 				AIU_I2S_SOURCE_DESC_MODE_8CH |
88 				AIU_I2S_SOURCE_DESC_MODE_24BIT |
89 				AIU_I2S_SOURCE_DESC_MODE_32BIT,
90 				desc);
91 
92 	/* Send data MSB first */
93 	regmap_update_bits(map, AIU_I2S_DAC_CFG,
94 				AIU_I2S_DAC_CFG_MSB_FIRST,
95 				AIU_I2S_DAC_CFG_MSB_FIRST);
96 
97 	return 0;
98 }
99 
100 const struct gx_formatter_ops aiu_formatter_i2s_ops = {
101 	.get_stream	= aiu_formatter_i2s_get_stream,
102 	.prepare	= aiu_formatter_i2s_prepare,
103 };
104