[][kernel][common][audio][Add mt7986-si3218x machine driver]
[Description]
Add mt7986-si3218x machine driver to fit backport mt7986 audio driver
from kernel 6.7.
[Release-log]
N/A
Change-Id: I9cf7577a2e6dd7ebc2febd165f1eb6c6398e15c9
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/8265958
diff --git a/target/linux/mediatek/files-5.4/sound/soc/mediatek/mt7986/mt7986-si3218x.c b/target/linux/mediatek/files-5.4/sound/soc/mediatek/mt7986/mt7986-si3218x.c
new file mode 100644
index 0000000..b91ee07
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/sound/soc/mediatek/mt7986/mt7986-si3218x.c
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt7986-si3218x.c -- MT7986-SI3218X ALSA SoC machine driver
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ * Maso Huang <maso.huang@mediatek.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include "mt7986-afe-common.h"
+#include "mt7986-reg.h"
+#include "../common/mtk-afe-platform-driver.h"
+
+enum {
+ HOPPING_CLK = 0,
+ APLL_CLK = 1,
+};
+
+enum {
+ I2S = 0,
+ PCMA = 4,
+ PCMB,
+};
+
+enum {
+ ETDM_IN5 = 2,
+ ETDM_OUT5 = 10,
+};
+
+enum {
+ AFE_FS_8K = 0,
+ AFE_FS_11K = 1,
+ AFE_FS_12K = 2,
+ AFE_FS_16K = 4,
+ AFE_FS_22K = 5,
+ AFE_FS_24K = 6,
+ AFE_FS_32K = 8,
+ AFE_FS_44K = 9,
+ AFE_FS_48K = 10,
+ AFE_FS_88K = 13,
+ AFE_FS_96K = 14,
+ AFE_FS_176K = 17,
+ AFE_FS_192K = 18,
+};
+
+enum {
+ ETDM_FS_8K = 0,
+ ETDM_FS_12K = 1,
+ ETDM_FS_16K = 2,
+ ETDM_FS_24K = 3,
+ ETDM_FS_32K = 4,
+ ETDM_FS_48K = 5,
+ ETDM_FS_96K = 7,
+ ETDM_FS_192K = 9,
+ ETDM_FS_11K = 16,
+ ETDM_FS_22K = 17,
+ ETDM_FS_44K = 18,
+ ETDM_FS_88K = 19,
+ ETDM_FS_176K = 20,
+};
+
+static int mt7986_si3218x_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ /* enable clk */
+ ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
+ if (ret) {
+ dev_err(afe->dev, "Failed to enable clocks\n");
+ return ret;
+ }
+
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, 0);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, 0);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0);
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK,
+ AUD_APLL2_EN);
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK,
+ AUD_26M_EN);
+
+ /* set ETDM_IN5_CON0 */
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_SYNC_MASK,
+ ETDM_SYNC);
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_FMT_MASK,
+ FIELD_PREP(ETDM_FMT_MASK, PCMA));
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_BIT_LEN_MASK,
+ FIELD_PREP(ETDM_BIT_LEN_MASK, 16 - 1));
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_WRD_LEN_MASK,
+ FIELD_PREP(ETDM_WRD_LEN_MASK, 16 - 1));
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_CH_NUM_MASK,
+ FIELD_PREP(ETDM_CH_NUM_MASK, 4 - 1));
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, RELATCH_SRC_MASK,
+ FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK));
+
+ /* set ETDM_IN5_CON2 */
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON2, IN_CLK_SRC_MASK,
+ IN_CLK_SRC(APLL_CLK));
+
+ /* set ETDM_IN5_CON3 */
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON3, IN_SEL_FS_MASK,
+ IN_SEL_FS(ETDM_FS_16K));
+
+ /* set ETDM_IN5_CON4 */
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON4, IN_CLK_INV_MASK,
+ IN_CLK_INV);
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON4, IN_RELATCH_MASK,
+ IN_RELATCH(AFE_FS_16K));
+
+ /* set ETDM_OUT5_CON0 */
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_FMT_MASK,
+ FIELD_PREP(ETDM_FMT_MASK, PCMA));
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_BIT_LEN_MASK,
+ FIELD_PREP(ETDM_BIT_LEN_MASK, 16 - 1));
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_WRD_LEN_MASK,
+ FIELD_PREP(ETDM_WRD_LEN_MASK, 16 - 1));
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_CH_NUM_MASK,
+ FIELD_PREP(ETDM_CH_NUM_MASK, 4 - 1));
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, RELATCH_SRC_MASK,
+ FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK));
+
+ /* set ETDM_OUT5_CON4 */
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, OUT_SEL_FS_MASK,
+ OUT_SEL_FS(ETDM_FS_16K));
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, OUT_CLK_SRC_MASK,
+ OUT_CLK_SRC(APLL_CLK));
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, OUT_RELATCH_MASK,
+ OUT_RELATCH(AFE_FS_16K));
+
+ /* set ETDM_OUT5_CON5 */
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON5, OUT_CLK_INV_MASK,
+ OUT_CLK_INV);
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON5, ETDM_CLK_DIV_MASK,
+ ETDM_CLK_DIV);
+
+ /* set external loopback */
+ regmap_update_bits(afe->regmap, ETDM_4_7_COWORK_CON0, OUT_SEL_MASK,
+ OUT_SEL(ETDM_IN5));
+
+ /* enable ETDM */
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
+ ETDM_EN);
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
+ ETDM_EN);
+
+ return 0;
+}
+
+SND_SOC_DAILINK_DEFS(playback,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(codec,
+ DAILINK_COMP_ARRAY(COMP_CPU("ETDM")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "proslic_spi-aif")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt7986_si3218x_dai_links[] = {
+ /* FE */
+ {
+ .name = "si3218x-playback",
+ .stream_name = "si3218x-playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback),
+ },
+ {
+ .name = "si3218x-capture",
+ .stream_name = "si3218x-capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture),
+ },
+ /* BE */
+ {
+ .name = "si3218x-codec",
+ .no_pcm = 1,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_A |
+ SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .init = mt7986_si3218x_init,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(codec),
+ },
+};
+
+static struct snd_soc_card mt7986_si3218x_card = {
+ .name = "mt7986-si3218x",
+ .owner = THIS_MODULE,
+ .dai_link = mt7986_si3218x_dai_links,
+ .num_links = ARRAY_SIZE(mt7986_si3218x_dai_links),
+};
+
+static int mt7986_si3218x_machine_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &mt7986_si3218x_card;
+ struct snd_soc_dai_link *dai_link;
+ struct device_node *platform, *codec;
+ struct device_node *platform_dai_node, *codec_dai_node;
+ int ret, i;
+
+ card->dev = &pdev->dev;
+
+ platform = of_get_child_by_name(pdev->dev.of_node, "platform");
+
+ if (platform) {
+ platform_dai_node = of_parse_phandle(platform, "sound-dai", 0);
+ of_node_put(platform);
+
+ if (!platform_dai_node) {
+ dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n");
+ return -EINVAL;
+ }
+ } else {
+ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->platforms->name)
+ continue;
+ dai_link->platforms->of_node = platform_dai_node;
+ }
+
+ codec = of_get_child_by_name(pdev->dev.of_node, "codec");
+
+ if (codec) {
+ codec_dai_node = of_parse_phandle(codec, "sound-dai", 0);
+ of_node_put(codec);
+
+ if (!codec_dai_node) {
+ of_node_put(platform_dai_node);
+ dev_err(&pdev->dev, "Failed to parse codec/sound-dai property\n");
+ return -EINVAL;
+ }
+ } else {
+ of_node_put(platform_dai_node);
+ dev_err(&pdev->dev, "Property 'codec' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->codecs->name)
+ continue;
+ dai_link->codecs->of_node = codec_dai_node;
+ }
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret) {
+ dev_err(&pdev->dev, "%s snd_soc_register_card fail: %d\n", __func__, ret);
+ goto err_of_node_put;
+ }
+
+err_of_node_put:
+ of_node_put(platform_dai_node);
+ of_node_put(codec_dai_node);
+ return ret;
+}
+
+static const struct of_device_id mt7986_si3218x_machine_dt_match[] = {
+ {.compatible = "mediatek,mt7986-si3218x-sound"},
+ { /* sentinel */ }
+};
+
+static struct platform_driver mt7986_si3218x_machine = {
+ .driver = {
+ .name = "mt7986-si3218x",
+ .of_match_table = mt7986_si3218x_machine_dt_match,
+ },
+ .probe = mt7986_si3218x_machine_probe,
+};
+
+module_platform_driver(mt7986_si3218x_machine);
+
+/* Module information */
+MODULE_DESCRIPTION("MT7986 SI3218X ALSA SoC machine driver");
+MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("mt7986 si3218x soc card");