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