ASoC: meson: aiu: use aiu-formatter-i2s to format I2S output data

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@baylibre.com>
Reviewed-by: Jerome Brunet <jbrunet@baylibre.com>
Link: https://patch.msgid.link/20260610-reshape-aiu-as-axg-v2-4-cac3663a8b51@baylibre.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Valerio Setti 2026-06-10 23:29:28 +02:00 committed by Mark Brown
parent 2cbb32d8dc
commit 83b83024cd
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
3 changed files with 48 additions and 63 deletions

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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