From 179f3659747d9e11db0064c30e27997a71909660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 30 Oct 2023 00:13:15 +0100 Subject: [PATCH] ASoC: apple: mca: Add loopback widgets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add loopback DAPM widgets and routes. Those widgets expose the loopback enable bits of the hardware, but further higher-level DAPM/DPCM rework on the platform and machine driver may be required for it to be possible to usefully engage the loopback. Signed-off-by: Martin PoviĊĦer --- sound/soc/apple/mca.c | 84 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index a29f311a613d..c7da53b31390 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -106,6 +106,8 @@ #define REG_TX_SERDES_SLOTMASK 0x0c #define REG_RX_SERDES_SLOTMASK 0x10 #define REG_RX_SERDES_PORT 0x04 +#define RX_SERDES_PORT_LOOPBACK_TXA BIT(16) +#define RX_SERDES_PORT_LOOPBACK_TXB BIT(17) /* Relative to switch base */ #define REG_DMA_ADAPTER_A(cl) (0x8000 * (cl)) @@ -155,7 +157,9 @@ struct mca_cluster { struct mca_data { struct device *dev; + struct snd_soc_component_driver snd_driver; + __iomem void *clusters_base; __iomem void *switch_base; struct device *pd_dev; @@ -1098,8 +1102,74 @@ static int mca_pcm_new(struct snd_soc_component *component, return 0; } -static const struct snd_soc_component_driver mca_component = { +static const struct snd_soc_dapm_route mca_dapm_routes[] = { + {"PCM0 Loopback", "Switch", "PCM0 TX"}, + {"PCM0 RX", NULL, "PCM0 Loopback"}, + {"PCM1 Loopback", "Switch", "PCM1 TX"}, + {"PCM1 RX", NULL, "PCM1 Loopback"}, + {"PCM2 Loopback", "Switch", "PCM2 TX"}, + {"PCM2 RX", NULL, "PCM2 Loopback"}, + {"PCM3 Loopback", "Switch", "PCM3 TX"}, + {"PCM3 RX", NULL, "PCM3 Loopback"}, + {"PCM4 Loopback", "Switch", "PCM4 TX"}, + {"PCM4 RX", NULL, "PCM4 Loopback"}, + {"PCM5 Loopback", "Switch", "PCM5 TX"}, + {"PCM5 RX", NULL, "PCM5 Loopback"}, +}; + +#define LOOPBACK_CTL_REG(cluster_no) (cluster_no*CLUSTER_STRIDE + CLUSTER_RX_OFF + REG_RX_SERDES_PORT) +#define LOOPBACK_BIT __bf_shf(RX_SERDES_PORT_LOOPBACK_TXA) +static const struct snd_kcontrol_new mca_pcm0_lbctl = + SOC_DAPM_SINGLE("Switch", LOOPBACK_CTL_REG(0), LOOPBACK_BIT, 1, 0); +static const struct snd_kcontrol_new mca_pcm1_lbctl = + SOC_DAPM_SINGLE("Switch", LOOPBACK_CTL_REG(1), LOOPBACK_BIT, 1, 0); +static const struct snd_kcontrol_new mca_pcm2_lbctl = + SOC_DAPM_SINGLE("Switch", LOOPBACK_CTL_REG(2), LOOPBACK_BIT, 1, 0); +static const struct snd_kcontrol_new mca_pcm3_lbctl = + SOC_DAPM_SINGLE("Switch", LOOPBACK_CTL_REG(3), LOOPBACK_BIT, 1, 0); +static const struct snd_kcontrol_new mca_pcm4_lbctl = + SOC_DAPM_SINGLE("Switch", LOOPBACK_CTL_REG(4), LOOPBACK_BIT, 1, 0); +static const struct snd_kcontrol_new mca_pcm5_lbctl = + SOC_DAPM_SINGLE("Switch", LOOPBACK_CTL_REG(5), LOOPBACK_BIT, 1, 0); +#undef LOOPBACK_CTL_REG +#undef LOOPBACK_BIT + +static const struct snd_soc_dapm_widget mca_dapm_widgets[] = { + SND_SOC_DAPM_SWITCH("PCM0 Loopback", SND_SOC_NOPM, 0, 0, + &mca_pcm0_lbctl), + SND_SOC_DAPM_SWITCH("PCM1 Loopback", SND_SOC_NOPM, 0, 0, + &mca_pcm1_lbctl), + SND_SOC_DAPM_SWITCH("PCM2 Loopback", SND_SOC_NOPM, 0, 0, + &mca_pcm2_lbctl), + SND_SOC_DAPM_SWITCH("PCM3 Loopback", SND_SOC_NOPM, 0, 0, + &mca_pcm3_lbctl), + SND_SOC_DAPM_SWITCH("PCM4 Loopback", SND_SOC_NOPM, 0, 0, + &mca_pcm4_lbctl), + SND_SOC_DAPM_SWITCH("PCM5 Loopback", SND_SOC_NOPM, 0, 0, + &mca_pcm5_lbctl), +}; + +static unsigned int mca_read(struct snd_soc_component *component, unsigned int reg) +{ + struct mca_data *mca = snd_soc_component_get_drvdata(component); + + return readl_relaxed(mca->clusters_base + reg); +} + +static int mca_write(struct snd_soc_component *component, unsigned int reg, unsigned int val) +{ + struct mca_data *mca = snd_soc_component_get_drvdata(component); + + writel_relaxed(val, mca->clusters_base + reg); + return 0; +} + +static const struct snd_soc_component_driver apple_mca_snd_driver_template = { .name = "apple-mca", + .dapm_routes = mca_dapm_routes, + .num_dapm_routes = 0, /* filled dynamically */ + .dapm_widgets = mca_dapm_widgets, + .num_dapm_widgets = 0, /* filled dynamically */ .open = mca_pcm_open, .close = mca_close, .hw_params = mca_hw_params, @@ -1107,6 +1177,8 @@ static const struct snd_soc_component_driver mca_component = { .pointer = mca_pointer, .pcm_construct = mca_pcm_new, .pcm_destruct = mca_pcm_free, + .read = mca_read, + .write = mca_write, }; static void apple_mca_release(struct mca_data *mca) @@ -1157,6 +1229,7 @@ static int apple_mca_probe(struct platform_device *pdev) if (!mca) return -ENOMEM; mca->dev = &pdev->dev; + mca->clusters_base = base; mca->nclusters = nclusters; mutex_init(&mca->port_mutex); platform_set_drvdata(pdev, mca); @@ -1272,7 +1345,14 @@ static int apple_mca_probe(struct platform_device *pdev) } } - ret = snd_soc_register_component(&pdev->dev, &mca_component, + memcpy(&mca->snd_driver, &apple_mca_snd_driver_template, + sizeof(mca->snd_driver)); + mca->snd_driver.num_dapm_widgets = + (ARRAY_SIZE(mca_dapm_widgets) / MAX_NCLUSTERS) * nclusters; + mca->snd_driver.num_dapm_routes = + (ARRAY_SIZE(mca_dapm_routes) / MAX_NCLUSTERS) * nclusters; + + ret = snd_soc_register_component(&pdev->dev, &mca->snd_driver, dai_drivers, nclusters * 2); if (ret) { dev_err(&pdev->dev, "unable to register ASoC component: %d\n", -- 2.39.3 (Apple Git-145)