From 1f93a7dfd1f8d5ff7a5c53246c7534fe2332d6f4 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 02:46:07 +0000 Subject: [PATCH] add audio --- kernel/sound/soc/rockchip/rockchip_i2s_tdm.c | 75 +++++++++++++++++++++++++++++++++++-- 1 files changed, 70 insertions(+), 5 deletions(-) diff --git a/kernel/sound/soc/rockchip/rockchip_i2s_tdm.c b/kernel/sound/soc/rockchip/rockchip_i2s_tdm.c index 1824ea5..a8da138 100644 --- a/kernel/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/kernel/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -27,6 +27,7 @@ #include <sound/dmaengine_pcm.h> #include "rockchip_i2s_tdm.h" +#include "rockchip_dlp.h" #define DRV_NAME "rockchip-i2s-tdm" @@ -266,7 +267,7 @@ writeq(val, addr); break; } - /* fallthrough */ + fallthrough; default: local_irq_save(flags); writel(BIT(tx_offset) | (BIT(tx_offset) << 16), @@ -328,7 +329,7 @@ writeq(val, addr); break; } - /* fallthrough */ + fallthrough; default: local_irq_save(flags); writel((BIT(tx_offset) << 16), @@ -395,6 +396,12 @@ default: return -EINVAL; } + + regmap_update_bits(i2s_tdm->regmap, I2S_CLR, clr, clr); + ret = regmap_read_poll_timeout_atomic(i2s_tdm->regmap, I2S_CLR, val, + !(val & clr), 10, 100); + if (ret == 0) + return 0; /* * Workaround for FIFO clear on SLAVE mode: @@ -654,6 +661,19 @@ case SND_SOC_DAIFMT_CBM_CFM: val = I2S_CKR_MSS_SLAVE; i2s_tdm->is_master_mode = false; + /* + * TRCM require TX/RX enabled at the same time, or need the one + * which provide clk enabled at first for master mode. + * + * It is quite a different for slave mode which does not have + * these restrictions, because the BCLK / LRCK are provided by + * external master devices. + * + * So, we just set the right clk path value on TRCM register on + * stage probe and then drop the trcm value to make TX / RX work + * independently. + */ + i2s_tdm->clk_trcm = 0; break; default: ret = -EINVAL; @@ -924,13 +944,26 @@ switch (i2s_tdm->clk_trcm) { case I2S_CKR_TRCM_TXONLY: parent = clk_get_parent(i2s_tdm->mclk_tx); + /* + * API clk_has_parent is not available yet on GKI, so we + * use clk_set_parent directly and ignore the ret value. + * if the API has addressed on GKI, should remove it. + */ +#ifdef CONFIG_NO_GKI if (clk_has_parent(i2s_tdm->mclk_rx, parent)) ret = clk_set_parent(i2s_tdm->mclk_rx, parent); +#else + clk_set_parent(i2s_tdm->mclk_rx, parent); +#endif break; case I2S_CKR_TRCM_RXONLY: parent = clk_get_parent(i2s_tdm->mclk_rx); +#ifdef CONFIG_NO_GKI if (clk_has_parent(i2s_tdm->mclk_tx, parent)) ret = clk_set_parent(i2s_tdm->mclk_tx, parent); +#else + clk_set_parent(i2s_tdm->mclk_tx, parent); +#endif break; } @@ -1789,6 +1822,12 @@ #ifdef CONFIG_CPU_RK3568 { .compatible = "rockchip,rk3568-i2s-tdm", .data = &rk3568_i2s_soc_data }, #endif +#ifdef CONFIG_CPU_RK3588 + { .compatible = "rockchip,rk3588-i2s-tdm", }, +#endif +#ifdef CONFIG_CPU_RV1106 + { .compatible = "rockchip,rv1106-i2s-tdm", }, +#endif #ifdef CONFIG_CPU_RV1126 { .compatible = "rockchip,rv1126-i2s-tdm", .data = &rv1126_i2s_soc_data }, #endif @@ -1998,6 +2037,28 @@ return rockchip_i2s_tdm_path_prepare(i2s_tdm, np, 1); } +static int rockchip_i2s_tdm_get_fifo_count(struct device *dev, int stream) +{ + struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev); + int val = 0; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + regmap_read(i2s_tdm->regmap, I2S_TXFIFOLR, &val); + else + regmap_read(i2s_tdm->regmap, I2S_RXFIFOLR, &val); + + val = ((val & I2S_FIFOLR_TFL3_MASK) >> I2S_FIFOLR_TFL3_SHIFT) + + ((val & I2S_FIFOLR_TFL2_MASK) >> I2S_FIFOLR_TFL2_SHIFT) + + ((val & I2S_FIFOLR_TFL1_MASK) >> I2S_FIFOLR_TFL1_SHIFT) + + ((val & I2S_FIFOLR_TFL0_MASK) >> I2S_FIFOLR_TFL0_SHIFT); + + return val; +} + +static const struct snd_dlp_config dconfig = { + .get_fifo_count = rockchip_i2s_tdm_get_fifo_count, +}; + static irqreturn_t rockchip_i2s_tdm_isr(int irq, void *devid) { struct rk_i2s_tdm_dev *i2s_tdm = (struct rk_i2s_tdm_dev *)devid; @@ -2050,7 +2111,7 @@ i2s_tdm->dev = &pdev->dev; of_id = of_match_device(rockchip_i2s_tdm_match, &pdev->dev); - if (!of_id || !of_id->data) + if (!of_id) return -EINVAL; spin_lock_init(&i2s_tdm->lock); @@ -2170,7 +2231,7 @@ if (IS_ERR(i2s_tdm->regmap)) return PTR_ERR(i2s_tdm->regmap); - irq = platform_get_irq(pdev, 0); + irq = platform_get_irq_optional(pdev, 0); if (irq > 0) { ret = devm_request_irq(&pdev->dev, irq, rockchip_i2s_tdm_isr, IRQF_SHARED, node->name, i2s_tdm); @@ -2264,7 +2325,11 @@ return 0; } - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (of_property_read_bool(node, "rockchip,digital-loopback")) + ret = devm_snd_dmaengine_dlp_register(&pdev->dev, &dconfig); + else + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) { dev_err(&pdev->dev, "Could not register PCM\n"); return ret; -- Gitblit v1.6.2