[PATCH v2 4/4] ASoC: meson: aiu: use aiu-formatter-i2s to format I2S output data
Valerio Setti
vsetti at baylibre.com
Wed Jun 10 14:29:28 PDT 2026
Create a new DAPM widget for "I2S formatter" and place it on the path
between FIFO and output DAI interface. Remove I2S output formatting code
from aiu-encoder-i2s since it's now implemented from aiu-formatter-i2s.
Signed-off-by: Valerio Setti <vsetti at baylibre.com>
---
sound/soc/meson/aiu-encoder-i2s.c | 78 ++++++++++-----------------------------
sound/soc/meson/aiu.c | 32 ++++++++++++++--
sound/soc/meson/aiu.h | 1 +
3 files changed, 48 insertions(+), 63 deletions(-)
diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c
index f50b03824ad280afabb31eecc20ccb855defa11e..83b579e98f1c75ce03fea1c6ff4e99b2fedebe0c 100644
--- a/sound/soc/meson/aiu-encoder-i2s.c
+++ b/sound/soc/meson/aiu-encoder-i2s.c
@@ -13,13 +13,8 @@
#include "gx-formatter.h"
#include "gx-interface.h"
-#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0)
-#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5)
-#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9)
#define AIU_I2S_SOURCE_DESC_MODE_SPLIT BIT(11)
-#define AIU_RST_SOFT_I2S_FAST BIT(0)
-#define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2)
#define AIU_CLK_CTRL_I2S_DIV_EN BIT(0)
#define AIU_CLK_CTRL_I2S_DIV GENMASK(3, 2)
#define AIU_CLK_CTRL_AOCLK_INVERT BIT(6)
@@ -37,49 +32,6 @@ static void aiu_encoder_i2s_divider_enable(struct snd_soc_component *component,
enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0);
}
-static int aiu_encoder_i2s_setup_desc(struct snd_soc_component *component,
- struct snd_pcm_hw_params *params)
-{
- /* Always operate in split (classic interleaved) mode */
- unsigned int desc = AIU_I2S_SOURCE_DESC_MODE_SPLIT;
-
- /* Reset required to update the pipeline */
- snd_soc_component_write(component, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST);
- snd_soc_component_read(component, AIU_I2S_SYNC);
-
- switch (params_physical_width(params)) {
- case 16: /* Nothing to do */
- break;
-
- case 32:
- desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT |
- AIU_I2S_SOURCE_DESC_MODE_32BIT);
- break;
-
- default:
- return -EINVAL;
- }
-
- switch (params_channels(params)) {
- case 2: /* Nothing to do */
- break;
- case 8:
- desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
- break;
- default:
- return -EINVAL;
- }
-
- snd_soc_component_update_bits(component, AIU_I2S_SOURCE_DESC,
- AIU_I2S_SOURCE_DESC_MODE_8CH |
- AIU_I2S_SOURCE_DESC_MODE_24BIT |
- AIU_I2S_SOURCE_DESC_MODE_32BIT |
- AIU_I2S_SOURCE_DESC_MODE_SPLIT,
- desc);
-
- return 0;
-}
-
static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component,
struct snd_pcm_hw_params *params,
unsigned int bs)
@@ -173,11 +125,6 @@ static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component,
if ((fs % 64) || (fs == 0))
return -EINVAL;
- /* Send data MSB first */
- snd_soc_component_update_bits(component, AIU_I2S_DAC_CFG,
- AIU_I2S_DAC_CFG_MSB_FIRST,
- AIU_I2S_DAC_CFG_MSB_FIRST);
-
/* Set bclk to lrlck ratio */
snd_soc_component_update_bits(component, AIU_CODEC_DAC_LRCLK_CTRL,
AIU_CODEC_DAC_LRCLK_CTRL_DIV,
@@ -223,12 +170,6 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream,
}
}
- ret = aiu_encoder_i2s_setup_desc(component, params);
- if (ret) {
- dev_err(dai->dev, "setting i2s desc failed: %d\n", ret);
- return ret;
- }
-
ret = aiu_encoder_i2s_set_clocks(component, params);
if (ret) {
dev_err(dai->dev, "setting i2s clocks failed: %d\n", ret);
@@ -411,6 +352,25 @@ static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream,
return ret;
}
+ /*
+ * We're always operating in split mode for the playback stream.
+ *
+ * This setting arguably belong to the 'aiu-formatter', but it's kept
+ * here for backward compatibility reason. At reset the I2S encoder
+ * operates in normal mode which would only support 8ch, but by default
+ * only 2ch are enabled. If a playback stream is started without
+ * changing to split mode, then the I2S encoder doesn't consume audio
+ * samples and the playback fails.
+ * Moving this to 'aiu-formatter' would cause the split mode to be set
+ * only when the formatter is enabled, which doesn't happen at boot as
+ * the default value for "HDMI CTRL SRC" is "DISABLED".
+ */
+ ret = snd_soc_component_update_bits(dai->component, AIU_I2S_SOURCE_DESC,
+ AIU_I2S_SOURCE_DESC_MODE_SPLIT,
+ AIU_I2S_SOURCE_DESC_MODE_SPLIT);
+ if (ret < 0)
+ dev_err(dai->dev, "failed to update AIU_I2S_SOURCE_DESC: %d", ret);
+
return 0;
}
diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c
index f2890111c1d2cfa2213bf01849957a796744b9ae..64ace4d25d92cbe137066359a839e1b11bf140f8 100644
--- a/sound/soc/meson/aiu.c
+++ b/sound/soc/meson/aiu.c
@@ -29,13 +29,22 @@ static SOC_ENUM_SINGLE_DECL(aiu_spdif_encode_sel_enum, AIU_I2S_MISC,
static const struct snd_kcontrol_new aiu_spdif_encode_mux =
SOC_DAPM_ENUM("SPDIF Buffer Src", aiu_spdif_encode_sel_enum);
-static const struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = {
- SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0,
- &aiu_spdif_encode_mux),
+#define AIU_WIDGET_SPDIF_SRC_SEL 0
+#define AIU_WIDGET_I2S_FORMATTER 1
+
+static struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = {
+ [AIU_WIDGET_SPDIF_SRC_SEL] =
+ SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0,
+ &aiu_spdif_encode_mux),
+ [AIU_WIDGET_I2S_FORMATTER] =
+ SND_SOC_DAPM_PGA_E("I2S Formatter", SND_SOC_NOPM, 0, 0, NULL, 0,
+ gx_formatter_event,
+ (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)),
};
static const struct snd_soc_dapm_route aiu_cpu_dapm_routes[] = {
- { "I2S Encoder Playback", NULL, "I2S FIFO Playback" },
+ { "I2S Formatter", NULL, "I2S FIFO Playback" },
+ { "I2S Encoder Playback", NULL, "I2S Formatter" },
{ "SPDIF SRC SEL", "SPDIF", "SPDIF FIFO Playback" },
{ "SPDIF SRC SEL", "I2S", "I2S FIFO Playback" },
{ "SPDIF Encoder Playback", NULL, "SPDIF SRC SEL" },
@@ -172,6 +181,11 @@ static const struct regmap_config aiu_regmap_cfg = {
.max_register = 0x2ac,
};
+const struct gx_formatter_driver aiu_formatter_i2s_drv = {
+ .regmap_cfg = &aiu_regmap_cfg,
+ .ops = &aiu_formatter_i2s_ops,
+};
+
static int aiu_clk_bulk_get(struct device *dev,
const char * const *ids,
unsigned int num,
@@ -282,6 +296,14 @@ static int aiu_probe(struct platform_device *pdev)
if (ret)
return ret;
+ /* Allocate the aiu-formatter into its widget */
+ ret = gx_formatter_create(dev, &aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER],
+ &aiu_formatter_i2s_drv, map);
+ if (ret) {
+ dev_err(dev, "Failed to allocate aiu formatter\n");
+ goto err;
+ }
+
/* Register the cpu component of the aiu */
ret = snd_soc_register_component(dev, &aiu_cpu_component,
aiu_cpu_dai_drv,
@@ -310,12 +332,14 @@ static int aiu_probe(struct platform_device *pdev)
return 0;
err:
+ gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]);
snd_soc_unregister_component(dev);
return ret;
}
static void aiu_remove(struct platform_device *pdev)
{
+ gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]);
snd_soc_unregister_component(&pdev->dev);
}
diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h
index 68310de0bdf7a97d8de2ff306c159248ee9b0ede..7d0b98c1f351b3c526ca06c43a4c04ee5f4b6dfa 100644
--- a/sound/soc/meson/aiu.h
+++ b/sound/soc/meson/aiu.h
@@ -61,6 +61,7 @@ extern const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops;
extern const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops;
extern const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops;
extern const struct snd_soc_dai_ops aiu_encoder_spdif_dai_ops;
+extern const struct gx_formatter_ops aiu_formatter_i2s_ops;
#define AIU_IEC958_BPF 0x000
#define AIU_958_MISC 0x010
--
2.39.5
More information about the linux-arm-kernel
mailing list