.. | .. |
---|
27 | 27 | #include <sound/dmaengine_pcm.h> |
---|
28 | 28 | |
---|
29 | 29 | #include "rockchip_i2s_tdm.h" |
---|
| 30 | +#include "rockchip_dlp.h" |
---|
30 | 31 | |
---|
31 | 32 | #define DRV_NAME "rockchip-i2s-tdm" |
---|
32 | 33 | |
---|
.. | .. |
---|
266 | 267 | writeq(val, addr); |
---|
267 | 268 | break; |
---|
268 | 269 | } |
---|
269 | | - /* fallthrough */ |
---|
| 270 | + fallthrough; |
---|
270 | 271 | default: |
---|
271 | 272 | local_irq_save(flags); |
---|
272 | 273 | writel(BIT(tx_offset) | (BIT(tx_offset) << 16), |
---|
.. | .. |
---|
328 | 329 | writeq(val, addr); |
---|
329 | 330 | break; |
---|
330 | 331 | } |
---|
331 | | - /* fallthrough */ |
---|
| 332 | + fallthrough; |
---|
332 | 333 | default: |
---|
333 | 334 | local_irq_save(flags); |
---|
334 | 335 | writel((BIT(tx_offset) << 16), |
---|
.. | .. |
---|
395 | 396 | default: |
---|
396 | 397 | return -EINVAL; |
---|
397 | 398 | } |
---|
| 399 | + |
---|
| 400 | + regmap_update_bits(i2s_tdm->regmap, I2S_CLR, clr, clr); |
---|
| 401 | + ret = regmap_read_poll_timeout_atomic(i2s_tdm->regmap, I2S_CLR, val, |
---|
| 402 | + !(val & clr), 10, 100); |
---|
| 403 | + if (ret == 0) |
---|
| 404 | + return 0; |
---|
398 | 405 | |
---|
399 | 406 | /* |
---|
400 | 407 | * Workaround for FIFO clear on SLAVE mode: |
---|
.. | .. |
---|
654 | 661 | case SND_SOC_DAIFMT_CBM_CFM: |
---|
655 | 662 | val = I2S_CKR_MSS_SLAVE; |
---|
656 | 663 | i2s_tdm->is_master_mode = false; |
---|
| 664 | + /* |
---|
| 665 | + * TRCM require TX/RX enabled at the same time, or need the one |
---|
| 666 | + * which provide clk enabled at first for master mode. |
---|
| 667 | + * |
---|
| 668 | + * It is quite a different for slave mode which does not have |
---|
| 669 | + * these restrictions, because the BCLK / LRCK are provided by |
---|
| 670 | + * external master devices. |
---|
| 671 | + * |
---|
| 672 | + * So, we just set the right clk path value on TRCM register on |
---|
| 673 | + * stage probe and then drop the trcm value to make TX / RX work |
---|
| 674 | + * independently. |
---|
| 675 | + */ |
---|
| 676 | + i2s_tdm->clk_trcm = 0; |
---|
657 | 677 | break; |
---|
658 | 678 | default: |
---|
659 | 679 | ret = -EINVAL; |
---|
.. | .. |
---|
924 | 944 | switch (i2s_tdm->clk_trcm) { |
---|
925 | 945 | case I2S_CKR_TRCM_TXONLY: |
---|
926 | 946 | parent = clk_get_parent(i2s_tdm->mclk_tx); |
---|
| 947 | + /* |
---|
| 948 | + * API clk_has_parent is not available yet on GKI, so we |
---|
| 949 | + * use clk_set_parent directly and ignore the ret value. |
---|
| 950 | + * if the API has addressed on GKI, should remove it. |
---|
| 951 | + */ |
---|
| 952 | +#ifdef CONFIG_NO_GKI |
---|
927 | 953 | if (clk_has_parent(i2s_tdm->mclk_rx, parent)) |
---|
928 | 954 | ret = clk_set_parent(i2s_tdm->mclk_rx, parent); |
---|
| 955 | +#else |
---|
| 956 | + clk_set_parent(i2s_tdm->mclk_rx, parent); |
---|
| 957 | +#endif |
---|
929 | 958 | break; |
---|
930 | 959 | case I2S_CKR_TRCM_RXONLY: |
---|
931 | 960 | parent = clk_get_parent(i2s_tdm->mclk_rx); |
---|
| 961 | +#ifdef CONFIG_NO_GKI |
---|
932 | 962 | if (clk_has_parent(i2s_tdm->mclk_tx, parent)) |
---|
933 | 963 | ret = clk_set_parent(i2s_tdm->mclk_tx, parent); |
---|
| 964 | +#else |
---|
| 965 | + clk_set_parent(i2s_tdm->mclk_tx, parent); |
---|
| 966 | +#endif |
---|
934 | 967 | break; |
---|
935 | 968 | } |
---|
936 | 969 | |
---|
.. | .. |
---|
1789 | 1822 | #ifdef CONFIG_CPU_RK3568 |
---|
1790 | 1823 | { .compatible = "rockchip,rk3568-i2s-tdm", .data = &rk3568_i2s_soc_data }, |
---|
1791 | 1824 | #endif |
---|
| 1825 | +#ifdef CONFIG_CPU_RK3588 |
---|
| 1826 | + { .compatible = "rockchip,rk3588-i2s-tdm", }, |
---|
| 1827 | +#endif |
---|
| 1828 | +#ifdef CONFIG_CPU_RV1106 |
---|
| 1829 | + { .compatible = "rockchip,rv1106-i2s-tdm", }, |
---|
| 1830 | +#endif |
---|
1792 | 1831 | #ifdef CONFIG_CPU_RV1126 |
---|
1793 | 1832 | { .compatible = "rockchip,rv1126-i2s-tdm", .data = &rv1126_i2s_soc_data }, |
---|
1794 | 1833 | #endif |
---|
.. | .. |
---|
1998 | 2037 | return rockchip_i2s_tdm_path_prepare(i2s_tdm, np, 1); |
---|
1999 | 2038 | } |
---|
2000 | 2039 | |
---|
| 2040 | +static int rockchip_i2s_tdm_get_fifo_count(struct device *dev, int stream) |
---|
| 2041 | +{ |
---|
| 2042 | + struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev); |
---|
| 2043 | + int val = 0; |
---|
| 2044 | + |
---|
| 2045 | + if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
| 2046 | + regmap_read(i2s_tdm->regmap, I2S_TXFIFOLR, &val); |
---|
| 2047 | + else |
---|
| 2048 | + regmap_read(i2s_tdm->regmap, I2S_RXFIFOLR, &val); |
---|
| 2049 | + |
---|
| 2050 | + val = ((val & I2S_FIFOLR_TFL3_MASK) >> I2S_FIFOLR_TFL3_SHIFT) + |
---|
| 2051 | + ((val & I2S_FIFOLR_TFL2_MASK) >> I2S_FIFOLR_TFL2_SHIFT) + |
---|
| 2052 | + ((val & I2S_FIFOLR_TFL1_MASK) >> I2S_FIFOLR_TFL1_SHIFT) + |
---|
| 2053 | + ((val & I2S_FIFOLR_TFL0_MASK) >> I2S_FIFOLR_TFL0_SHIFT); |
---|
| 2054 | + |
---|
| 2055 | + return val; |
---|
| 2056 | +} |
---|
| 2057 | + |
---|
| 2058 | +static const struct snd_dlp_config dconfig = { |
---|
| 2059 | + .get_fifo_count = rockchip_i2s_tdm_get_fifo_count, |
---|
| 2060 | +}; |
---|
| 2061 | + |
---|
2001 | 2062 | static irqreturn_t rockchip_i2s_tdm_isr(int irq, void *devid) |
---|
2002 | 2063 | { |
---|
2003 | 2064 | struct rk_i2s_tdm_dev *i2s_tdm = (struct rk_i2s_tdm_dev *)devid; |
---|
.. | .. |
---|
2050 | 2111 | i2s_tdm->dev = &pdev->dev; |
---|
2051 | 2112 | |
---|
2052 | 2113 | of_id = of_match_device(rockchip_i2s_tdm_match, &pdev->dev); |
---|
2053 | | - if (!of_id || !of_id->data) |
---|
| 2114 | + if (!of_id) |
---|
2054 | 2115 | return -EINVAL; |
---|
2055 | 2116 | |
---|
2056 | 2117 | spin_lock_init(&i2s_tdm->lock); |
---|
.. | .. |
---|
2170 | 2231 | if (IS_ERR(i2s_tdm->regmap)) |
---|
2171 | 2232 | return PTR_ERR(i2s_tdm->regmap); |
---|
2172 | 2233 | |
---|
2173 | | - irq = platform_get_irq(pdev, 0); |
---|
| 2234 | + irq = platform_get_irq_optional(pdev, 0); |
---|
2174 | 2235 | if (irq > 0) { |
---|
2175 | 2236 | ret = devm_request_irq(&pdev->dev, irq, rockchip_i2s_tdm_isr, |
---|
2176 | 2237 | IRQF_SHARED, node->name, i2s_tdm); |
---|
.. | .. |
---|
2264 | 2325 | return 0; |
---|
2265 | 2326 | } |
---|
2266 | 2327 | |
---|
2267 | | - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); |
---|
| 2328 | + if (of_property_read_bool(node, "rockchip,digital-loopback")) |
---|
| 2329 | + ret = devm_snd_dmaengine_dlp_register(&pdev->dev, &dconfig); |
---|
| 2330 | + else |
---|
| 2331 | + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); |
---|
| 2332 | + |
---|
2268 | 2333 | if (ret) { |
---|
2269 | 2334 | dev_err(&pdev->dev, "Could not register PCM\n"); |
---|
2270 | 2335 | return ret; |
---|