From: Ryan Walklin <ryan@testtoast.com>
To: Liam Girdwood <lgirdwood@gmail.com>,
Mark Brown <broonie@kernel.org>, Jaroslav Kysela <perex@perex.cz>,
Takashi Iwai <tiwai@suse.com>, Chen-Yu Tsai <wens@csie.org>,
Jernej Skrabec <jernej.skrabec@gmail.com>,
Samuel Holland <samuel@sholland.org>
Cc: linux-sound@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-sunxi@lists.linux.dev, devicetree@vger.kernel.org,
linux-clk@vger.kernel.org, Ryan Walklin <ryan@testtoast.com>
Subject: [PATCH 5/6] ASoC: sun4i-codec: support allwinner H616 codec
Date: Sun, 29 Sep 2024 23:06:06 +1300 [thread overview]
Message-ID: <20240929100750.860329-6-ryan@testtoast.com> (raw)
In-Reply-To: <20240929100750.860329-1-ryan@testtoast.com>
The H616 SoC codec is playback-only with a single line-out route, and
has some register differences from prior codecs.
Add the required compatible string, registers, quirks, DAPM widgets,
codec controls and routes, based on existing devices and the H616
datasheet.
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
sound/soc/sunxi/sun4i-codec.c | 202 ++++++++++++++++++++++++++++++++++
1 file changed, 202 insertions(+)
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 312d2655c3f4e..1cdda20e8ed59 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -226,6 +226,43 @@
#define SUN8I_H3_CODEC_DAC_DBG (0x48)
#define SUN8I_H3_CODEC_ADC_DBG (0x4c)
+/* H616 specific registers */
+#define SUN50I_H616_CODEC_DAC_FIFOC (0x10)
+
+#define SUN50I_DAC_FIFO_STA (0x14)
+#define SUN50I_DAC_TXE_INT (3)
+#define SUN50I_DAC_TXU_INT (2)
+#define SUN50I_DAC_TXO_INT (1)
+
+#define SUN50I_DAC_CNT (0x24)
+#define SUN50I_DAC_DG_REG (0x28)
+#define SUN50I_DAC_DAP_CTL (0xf0)
+
+#define SUN50I_H616_DAC_AC_DAC_REG (0x310)
+#define SUN50I_H616_DAC_LEN (15)
+#define SUN50I_H616_DAC_REN (14)
+#define SUN50I_H616_LINEOUTL_EN (13)
+#define SUN50I_H616_LMUTE (12)
+#define SUN50I_H616_LINEOUTR_EN (11)
+#define SUN50I_H616_RMUTE (10)
+#define SUN50I_H616_RSWITCH (9)
+#define SUN50I_H616_RAMPEN (8)
+#define SUN50I_H616_LINEOUTL_SEL (6)
+#define SUN50I_H616_LINEOUTR_SEL (5)
+#define SUN50I_H616_LINEOUT_VOL (0)
+
+#define SUN50I_H616_DAC_AC_MIXER_REG (0x314)
+#define SUN50I_H616_LMIX_LDAC (21)
+#define SUN50I_H616_LMIX_RDAC (20)
+#define SUN50I_H616_RMIX_RDAC (17)
+#define SUN50I_H616_RMIX_LDAC (16)
+#define SUN50I_H616_LMIXEN (11)
+#define SUN50I_H616_RMIXEN (10)
+
+#define SUN50I_H616_DAC_AC_RAMP_REG (0x31c)
+#define SUN50I_H616_RAMP_STEP (4)
+#define SUN50I_H616_RDEN (0)
+
/* TODO H3 DAP (Digital Audio Processing) bits */
struct sun4i_codec {
@@ -1520,6 +1557,149 @@ static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev)
return card;
};
+static const struct snd_kcontrol_new sun50i_h616_codec_codec_controls[] = {
+ SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
+ SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
+ sun6i_codec_dvol_scale),
+ SOC_SINGLE_TLV("Line Out Playback Volume",
+ SUN50I_H616_DAC_AC_DAC_REG,
+ SUN50I_H616_LINEOUT_VOL, 0x1f, 0,
+ sun6i_codec_lineout_vol_scale),
+ SOC_DOUBLE("Line Out Playback Switch",
+ SUN50I_H616_DAC_AC_DAC_REG,
+ SUN50I_H616_LINEOUTL_EN,
+ SUN50I_H616_LINEOUTR_EN, 1, 0),
+};
+
+static const struct snd_kcontrol_new sun50i_h616_codec_mixer_controls[] = {
+ SOC_DAPM_DOUBLE("DAC Playback Switch",
+ SUN50I_H616_DAC_AC_MIXER_REG,
+ SUN50I_H616_LMIX_LDAC,
+ SUN50I_H616_RMIX_RDAC, 1, 0),
+ SOC_DAPM_DOUBLE("DAC Reversed Playback Switch",
+ SUN50I_H616_DAC_AC_MIXER_REG,
+ SUN50I_H616_LMIX_RDAC,
+ SUN50I_H616_RMIX_LDAC, 1, 0),
+};
+
+static SOC_ENUM_DOUBLE_DECL(sun50i_h616_codec_lineout_src_enum,
+ SUN50I_H616_DAC_AC_DAC_REG,
+ SUN50I_H616_LINEOUTL_SEL,
+ SUN50I_H616_LINEOUTR_SEL,
+ sun6i_codec_lineout_src_enum_text);
+
+static const struct snd_kcontrol_new sun50i_h616_codec_lineout_src[] = {
+ SOC_DAPM_ENUM("Line Out Source Playback Route",
+ sun50i_h616_codec_lineout_src_enum),
+};
+
+static const struct snd_soc_dapm_widget sun50i_h616_codec_codec_widgets[] = {
+ /* Digital parts of the DACs */
+ SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
+ SUN4I_CODEC_DAC_DPC_EN_DA, 0,
+ NULL, 0),
+
+ /* Analog parts of the DACs */
+ SND_SOC_DAPM_DAC("Left DAC", "Codec Playback",
+ SUN50I_H616_DAC_AC_DAC_REG,
+ SUN50I_H616_DAC_LEN, 0),
+ SND_SOC_DAPM_DAC("Right DAC", "Codec Playback",
+ SUN50I_H616_DAC_AC_DAC_REG,
+ SUN50I_H616_DAC_REN, 0),
+
+ /* Mixers */
+ SOC_MIXER_ARRAY("Left Mixer", SUN50I_H616_DAC_AC_MIXER_REG,
+ SUN50I_H616_LMIXEN, 0,
+ sun50i_h616_codec_mixer_controls),
+ SOC_MIXER_ARRAY("Right Mixer", SUN50I_H616_DAC_AC_MIXER_REG,
+ SUN50I_H616_RMIXEN, 0,
+ sun50i_h616_codec_mixer_controls),
+
+ /* Line Out path */
+ SND_SOC_DAPM_MUX("Line Out Source Playback Route",
+ SND_SOC_NOPM, 0, 0, sun50i_h616_codec_lineout_src),
+ SND_SOC_DAPM_OUT_DRV("Line Out Ramp Controller",
+ SUN50I_H616_DAC_AC_RAMP_REG,
+ SUN50I_H616_RDEN, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("LINEOUT"),
+};
+
+static const struct snd_soc_component_driver sun50i_h616_codec_codec = {
+ .controls = sun50i_h616_codec_codec_controls,
+ .num_controls = ARRAY_SIZE(sun50i_h616_codec_codec_controls),
+ .dapm_widgets = sun50i_h616_codec_codec_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sun50i_h616_codec_codec_widgets),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
+static const struct snd_kcontrol_new sun50i_h616_card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("LINEOUT"),
+};
+
+static const struct snd_soc_dapm_widget sun50i_h616_codec_card_dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("Line Out", NULL),
+ SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
+};
+
+/* Connect digital side enables to analog side widgets */
+static const struct snd_soc_dapm_route sun50i_h616_codec_card_routes[] = {
+ /* DAC Routes */
+ { "Left DAC", NULL, "DAC Enable" },
+ { "Right DAC", NULL, "DAC Enable" },
+
+ /* Left Mixer Routes */
+ { "Left Mixer", "DAC Playback Switch", "Left DAC" },
+ { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
+
+ /* Right Mixer Routes */
+ { "Right Mixer", "DAC Playback Switch", "Right DAC" },
+ { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
+
+ /* Line Out Routes */
+ { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
+ { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
+ { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
+ { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
+ { "Line Out Ramp Controller", NULL, "Line Out Source Playback Route" },
+ { "LINEOUT", NULL, "Line Out Ramp Controller" },
+};
+
+static struct snd_soc_card *sun50i_h616_codec_create_card(struct device *dev)
+{
+ struct snd_soc_card *card;
+ int ret;
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return ERR_PTR(-ENOMEM);
+
+ card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
+ if (!card->dai_link)
+ return ERR_PTR(-ENOMEM);
+
+ card->dai_link->playback_only = true;
+ card->dai_link->capture_only = false;
+
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->name = "H616 Audio Codec";
+ card->controls = sun50i_h616_card_controls;
+ card->num_controls = ARRAY_SIZE(sun50i_h616_card_controls);
+ card->dapm_widgets = sun50i_h616_codec_card_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(sun50i_h616_codec_card_dapm_widgets);
+ card->dapm_routes = sun50i_h616_codec_card_routes;
+ card->num_dapm_routes = ARRAY_SIZE(sun50i_h616_codec_card_routes);
+ card->fully_routed = true;
+
+ ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
+ if (ret)
+ dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
+
+ return card;
+};
+
static const struct regmap_config sun4i_codec_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -1562,6 +1742,14 @@ static const struct regmap_config sun8i_v3s_codec_regmap_config = {
.max_register = SUN8I_H3_CODEC_ADC_DBG,
};
+static const struct regmap_config sun50i_h616_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUN50I_H616_DAC_AC_RAMP_REG,
+ .cache_type = REGCACHE_NONE,
+};
+
struct sun4i_codec_quirks {
const struct regmap_config *regmap_config;
const struct snd_soc_component_driver *codec;
@@ -1647,6 +1835,15 @@ static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = {
.has_reset = true,
};
+static const struct sun4i_codec_quirks sun50i_h616_codec_quirks = {
+ .regmap_config = &sun50i_h616_codec_regmap_config,
+ .codec = &sun50i_h616_codec_codec,
+ .create_card = sun50i_h616_codec_create_card,
+ .reg_dac_fifoc = REG_FIELD(SUN50I_H616_CODEC_DAC_FIFOC, 0, 31),
+ .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
+ .has_reset = true,
+};
+
static const struct of_device_id sun4i_codec_of_match[] = {
{
.compatible = "allwinner,sun4i-a10-codec",
@@ -1672,6 +1869,10 @@ static const struct of_device_id sun4i_codec_of_match[] = {
.compatible = "allwinner,sun8i-v3s-codec",
.data = &sun8i_v3s_codec_quirks,
},
+ {
+ .compatible = "allwinner,sun50i-h616-codec",
+ .data = &sun50i_h616_codec_quirks,
+ },
{}
};
MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
@@ -1860,4 +2061,5 @@ MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>");
MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
+MODULE_AUTHOR("Ryan Walklin <ryan@testtoast.com");
MODULE_LICENSE("GPL");
--
2.46.1
next prev parent reply other threads:[~2024-09-29 10:08 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-29 10:06 [PATCH 0/6] ASoC: add Allwinner H616 audio codec support Ryan Walklin
2024-09-29 10:06 ` [PATCH 1/6] ASoC: sun4i-codec: Add support for different DAC FIFOC addresses to quirks Ryan Walklin
2024-10-08 12:22 ` Andre Przywara
2024-09-29 10:06 ` [PATCH 2/6] ASoC: sun4i-codec: Add playback only flag " Ryan Walklin
2024-10-08 12:32 ` Andre Przywara
2024-10-20 6:04 ` Ryan Walklin
2024-10-20 10:19 ` Andre Przywara
2024-09-29 10:06 ` [PATCH 3/6] clk: sunxi-ng: h616: Add sigma-delta modulation settings for audio PLL Ryan Walklin
2024-10-01 13:28 ` Andre Przywara
2024-10-18 9:29 ` Andre Przywara
2024-10-20 6:38 ` Ryan Walklin
2024-09-29 10:06 ` [PATCH 4/6] dt-bindings: allwinner: add H616 sun4i audio codec binding Ryan Walklin
2024-09-29 19:56 ` Krzysztof Kozlowski
2024-10-20 6:58 ` Ryan Walklin
2024-10-20 10:27 ` Andre Przywara
2024-09-29 10:06 ` Ryan Walklin [this message]
2024-10-18 9:55 ` [PATCH 5/6] ASoC: sun4i-codec: support allwinner H616 codec Andre Przywara
2024-09-29 10:06 ` [PATCH 6/6] arm64: dts: allwinner: h616: Add audio codec node Ryan Walklin
2024-10-08 12:37 ` Andre Przywara
2024-10-18 10:07 ` Andre Przywara
2024-10-05 18:44 ` [PATCH 0/6] ASoC: add Allwinner H616 audio codec support Philippe Simons
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240929100750.860329-6-ryan@testtoast.com \
--to=ryan@testtoast.com \
--cc=broonie@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=jernej.skrabec@gmail.com \
--cc=lgirdwood@gmail.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-clk@vger.kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=linux-sunxi@lists.linux.dev \
--cc=perex@perex.cz \
--cc=samuel@sholland.org \
--cc=tiwai@suse.com \
--cc=wens@csie.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).