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