From 6d567d8138da5671676a7b2174cf8af7bdf7f85c Mon Sep 17 00:00:00 2001 From: Shunhua Lan Date: Wed, 28 Feb 2024 16:05:40 +0800 Subject: [PATCH] ASoC: rockchip: sai: Add support for RX/TX route map from DT Signed-off-by: Shunhua Lan Signed-off-by: Sugar Zhang Change-Id: Ia25b4d39d2a3ead68b771ff24bd2a78168ef57d1 --- sound/soc/rockchip/rockchip_sai.c | 106 ++++++++++++++++++++++++++++++ sound/soc/rockchip/rockchip_sai.h | 8 +++ 2 files changed, 114 insertions(+) diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index 348b22a8a91d..0dc77b2b5f21 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -34,6 +34,8 @@ #define WAIT_TIME_MS_MAX 10000 #define QUIRK_ALWAYS_ON BIT(0) +#define MAX_LANES 4 + enum fpw_mode { FPW_ONE_BCLK_WIDTH, FPW_ONE_SLOT_WIDTH, @@ -53,6 +55,8 @@ struct rk_sai_dev { unsigned int wait_time[SNDRV_PCM_STREAM_LAST + 1]; unsigned int tx_lanes; unsigned int rx_lanes; + unsigned int sdi[MAX_LANES]; + unsigned int sdo[MAX_LANES]; unsigned int quirks; unsigned int version; enum fpw_mode fpw; @@ -590,6 +594,104 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream, return 0; } +static int rockchip_sai_path_check(struct rk_sai_dev *sai, + int num, bool is_rx) +{ + unsigned int *data; + int i; + + data = is_rx ? sai->sdi : sai->sdo; + + for (i = 0; i < num; i++) { + if (data[i] >= MAX_LANES) { + dev_err(sai->dev, "%s[%d]: %d, Should less than: %d\n", + is_rx ? "RX" : "TX", i, data[i], MAX_LANES); + + return -EINVAL; + } + } + + return 0; +} + +static void rockchip_sai_path_config(struct rk_sai_dev *sai, + int num, bool is_rx) +{ + int i; + + if (is_rx) + for (i = 0; i < num; i++) + regmap_update_bits(sai->regmap, SAI_PATH_SEL, + SAI_RX_PATH_MASK(i), + SAI_RX_PATH(i, sai->sdi[i])); + else + for (i = 0; i < num; i++) + regmap_update_bits(sai->regmap, SAI_PATH_SEL, + SAI_TX_PATH_MASK(i), + SAI_TX_PATH(i, sai->sdo[i])); +} + +static int rockchip_sai_path_prepare(struct rk_sai_dev *sai, + struct device_node *np, + bool is_rx) +{ + char *path_prop; + unsigned int *data; + int num, ret; + + if (is_rx) { + path_prop = "rockchip,sai-rx-route"; + data = sai->sdi; + } else { + path_prop = "rockchip,sai-tx-route"; + data = sai->sdo; + } + + num = of_count_phandle_with_args(np, path_prop, NULL); + if (num == -ENOENT) { + return 0; + } else if (num != MAX_LANES) { + dev_err(sai->dev, "The property size should be: %d, ret: %d\n", + MAX_LANES, num); + return -EINVAL; + } + + ret = device_property_read_u32_array(sai->dev, path_prop, data, num); + if (ret < 0) { + dev_err(sai->dev, "Failed to read '%s': %d\n", + path_prop, ret); + return ret; + } + + ret = rockchip_sai_path_check(sai, num, is_rx); + if (ret) + return ret; + + rockchip_sai_path_config(sai, num, is_rx); + + return 0; +} + +static int rockchip_sai_parse_paths(struct rk_sai_dev *sai, + struct device_node *np) +{ + int ret; + + ret = rockchip_sai_path_prepare(sai, np, 0); + if (ret < 0) { + dev_err(sai->dev, "Failed to prepare TX path: %d\n", ret); + return ret; + } + + ret = rockchip_sai_path_prepare(sai, np, 1); + if (ret < 0) { + dev_err(sai->dev, "Failed to prepare RX path: %d\n", ret); + return ret; + } + + return ret; +} + static int rockchip_sai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -1490,6 +1592,10 @@ static int rockchip_sai_probe(struct platform_device *pdev) if (ret) goto err_disable_hclk; + ret = rockchip_sai_parse_paths(sai, node); + if (ret) + goto err_disable_hclk; + ret = rockchip_sai_init_dai(sai, res, &dai); if (ret) goto err_disable_hclk; diff --git a/sound/soc/rockchip/rockchip_sai.h b/sound/soc/rockchip/rockchip_sai.h index f9e29e0dfb04..f6145f0513f0 100644 --- a/sound/soc/rockchip/rockchip_sai.h +++ b/sound/soc/rockchip/rockchip_sai.h @@ -118,6 +118,14 @@ #define SAI_INTSR_TXUI_INA 0 #define SAI_INTSR_TXUI_ACT BIT(1) +/* PATH_SEL: Transfer / Receive Path Select Register */ +#define SAI_RX_PATH_SHIFT(x) (8 + (x) * 2) +#define SAI_RX_PATH_MASK(x) (0x3 << SAI_RX_PATH_SHIFT(x)) +#define SAI_RX_PATH(x, v) ((v) << SAI_RX_PATH_SHIFT(x)) +#define SAI_TX_PATH_SHIFT(x) (0 + (x) * 2) +#define SAI_TX_PATH_MASK(x) (0x3 << SAI_TX_PATH_SHIFT(x)) +#define SAI_TX_PATH(x, v) ((v) << SAI_TX_PATH_SHIFT(x)) + /* XSHIFT: Transfer / Receive Frame Sync Shift Register */ #define SAI_XSHIFT_SEL_MASK GENMASK(23, 0) #define SAI_XSHIFT_SEL(x) (x)