From f45e756958099c35d6afb746df1d40a1c6302cfc Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 07 Nov 2023 06:20:23 +0000
Subject: [PATCH] enable wifi gpio
---
kernel/sound/soc/rockchip/rockchip_sai.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 201 insertions(+), 25 deletions(-)
diff --git a/kernel/sound/soc/rockchip/rockchip_sai.c b/kernel/sound/soc/rockchip/rockchip_sai.c
index fa0a8bb..c626142 100644
--- a/kernel/sound/soc/rockchip/rockchip_sai.c
+++ b/kernel/sound/soc/rockchip/rockchip_sai.c
@@ -24,6 +24,10 @@
#define FW_RATIO_MAX 8
#define FW_RATIO_MIN 1
+#define MAXBURST_PER_FIFO 8
+
+#define DEFAULT_FS 48000
+#define QUIRK_ALWAYS_ON BIT(0)
enum fpw_mode {
FPW_ONE_BCLK_WIDTH,
@@ -41,14 +45,28 @@
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
struct snd_pcm_substream *substreams[SNDRV_PCM_STREAM_LAST + 1];
+ unsigned int tx_lanes;
+ unsigned int rx_lanes;
+ unsigned int quirks;
enum fpw_mode fpw;
- int fw_ratio;
+ int fw_ratio;
bool has_capture;
bool has_playback;
bool is_master_mode;
+ bool is_tdm;
};
-static int sai_runtime_suspend(struct device *dev)
+static const struct sai_of_quirks {
+ char *quirk;
+ int id;
+} of_quirks[] = {
+ {
+ .quirk = "rockchip,always-on",
+ .id = QUIRK_ALWAYS_ON,
+ },
+};
+
+static int rockchip_sai_runtime_suspend(struct device *dev)
{
struct rk_sai_dev *sai = dev_get_drvdata(dev);
unsigned int val;
@@ -68,14 +86,19 @@
regcache_cache_only(sai->regmap, true);
clk_disable_unprepare(sai->mclk);
+ clk_disable_unprepare(sai->hclk);
return 0;
}
-static int sai_runtime_resume(struct device *dev)
+static int rockchip_sai_runtime_resume(struct device *dev)
{
struct rk_sai_dev *sai = dev_get_drvdata(dev);
int ret;
+
+ ret = clk_prepare_enable(sai->hclk);
+ if (ret)
+ goto err_hclk;
ret = clk_prepare_enable(sai->mclk);
if (ret)
@@ -99,6 +122,8 @@
err_regmap:
clk_disable_unprepare(sai->mclk);
err_mclk:
+ clk_disable_unprepare(sai->hclk);
+err_hclk:
return ret;
}
@@ -359,19 +384,42 @@
return ret;
}
+static unsigned int rockchip_sai_lanes_auto(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+ unsigned int lanes = 1;
+
+ if (!sai->is_tdm)
+ lanes = DIV_ROUND_UP(params_channels(params), 2);
+
+ return lanes;
+}
+
static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+ struct snd_dmaengine_dai_dma_data *dma_data;
unsigned int mclk_rate, bclk_rate, div_bclk;
unsigned int ch_per_lane, lanes, slot_width;
unsigned int val, fscr, reg;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_data = snd_soc_dai_get_dma_data(dai, substream);
+ dma_data->maxburst = MAXBURST_PER_FIFO * params_channels(params) / 2;
+
+ lanes = rockchip_sai_lanes_auto(params, dai);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
reg = SAI_TXCR;
- else
+ if (sai->tx_lanes)
+ lanes = sai->tx_lanes;
+ } else {
reg = SAI_RXCR;
+ if (sai->rx_lanes)
+ lanes = sai->rx_lanes;
+ }
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
@@ -391,12 +439,13 @@
return -EINVAL;
}
- regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK, val);
+ val |= SAI_XCR_CSR(lanes);
+
+ regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
regmap_read(sai->regmap, reg, &val);
slot_width = SAI_XCR_SBW_V(val);
- lanes = SAI_XCR_CSR_V(val);
ch_per_lane = params_channels(params) / lanes;
regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
@@ -525,6 +574,8 @@
regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
SAI_XCR_SBW(slot_width));
pm_runtime_put(dai->dev);
+
+ sai->is_tdm = true;
return 0;
}
@@ -699,7 +750,7 @@
sai->playback_dma_data.addr = res->start + SAI_TXDR;
sai->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- sai->playback_dma_data.maxburst = 8;
+ sai->playback_dma_data.maxburst = MAXBURST_PER_FIFO;
}
if (sai->has_capture) {
@@ -714,7 +765,7 @@
sai->capture_dma_data.addr = res->start + SAI_RXDR;
sai->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- sai->capture_dma_data.maxburst = 8;
+ sai->capture_dma_data.maxburst = MAXBURST_PER_FIFO;
}
regmap_update_bits(sai->regmap, SAI_DMACR, SAI_DMACR_TDL_MASK,
@@ -728,8 +779,8 @@
return 0;
}
-static const char * const tcsr_text[] = { "SDOx1", "SDOx2", "SDOx3", "SDOx4" };
-static const char * const rcsr_text[] = { "SDIx1", "SDIx2", "SDIx3", "SDIx4" };
+static const char * const tx_lanes_text[] = { "Auto", "SDOx1", "SDOx2", "SDOx3", "SDOx4" };
+static const char * const rx_lanes_text[] = { "Auto", "SDIx1", "SDIx2", "SDIx3", "SDIx4" };
static const char * const edge_text[] = { "Rising Edge", "Dual Edge" };
static const char * const edge_shift_text[] = { "Normal", "Shift 1 Edge" };
@@ -771,7 +822,8 @@
/* TXCR */
static SOC_ENUM_SINGLE_DECL(tsft_enum, SAI_TXCR, 22, edge_shift_text);
-static SOC_ENUM_SINGLE_DECL(tcsr_enum, SAI_TXCR, 20, tcsr_text);
+static const struct soc_enum tx_lanes_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tx_lanes_text), tx_lanes_text);
static SOC_ENUM_SINGLE_DECL(tsjm_enum, SAI_TXCR, 19, sjm_text);
static SOC_ENUM_SINGLE_DECL(tfbm_enum, SAI_TXCR, 18, fbm_text);
static SOC_ENUM_SINGLE_DECL(tvdj_enum, SAI_TXCR, 10, vdj_text);
@@ -786,7 +838,8 @@
/* RXCR */
static SOC_ENUM_SINGLE_DECL(rsft_enum, SAI_RXCR, 22, edge_shift_text);
-static SOC_ENUM_SINGLE_DECL(rcsr_enum, SAI_RXCR, 20, rcsr_text);
+static const struct soc_enum rx_lanes_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_lanes_text), rx_lanes_text);
static SOC_ENUM_SINGLE_DECL(rsjm_enum, SAI_RXCR, 19, sjm_text);
static SOC_ENUM_SINGLE_DECL(rfbm_enum, SAI_RXCR, 18, fbm_text);
static SOC_ENUM_SINGLE_DECL(rvdj_enum, SAI_RXCR, 10, vdj_text);
@@ -874,19 +927,75 @@
return 1;
}
+static int rockchip_sai_tx_lanes_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.enumerated.item[0] = sai->tx_lanes;
+
+ return 0;
+}
+
+static int rockchip_sai_tx_lanes_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
+ int num;
+
+ num = ucontrol->value.enumerated.item[0];
+ if (num >= ARRAY_SIZE(tx_lanes_text))
+ return -EINVAL;
+
+ sai->tx_lanes = num;
+
+ return 1;
+}
+
+static int rockchip_sai_rx_lanes_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.enumerated.item[0] = sai->rx_lanes;
+
+ return 0;
+}
+
+static int rockchip_sai_rx_lanes_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
+ int num;
+
+ num = ucontrol->value.enumerated.item[0];
+ if (num >= ARRAY_SIZE(rx_lanes_text))
+ return -EINVAL;
+
+ sai->rx_lanes = num;
+
+ return 1;
+}
+
static DECLARE_TLV_DB_SCALE(fs_shift_tlv, 0, 8192, 0);
static const struct snd_kcontrol_new rockchip_sai_controls[] = {
SOC_ENUM("Transmit Edge Shift", tsft_enum),
- SOC_ENUM("Transmit SDOx Select", tcsr_enum),
+ SOC_ENUM_EXT("Transmit SDOx Select", tx_lanes_enum,
+ rockchip_sai_tx_lanes_get, rockchip_sai_tx_lanes_put),
SOC_ENUM("Transmit Store Justified Mode", tsjm_enum),
SOC_ENUM("Transmit First Bit Mode", tfbm_enum),
SOC_ENUM("Transmit Valid Data Justified", tvdj_enum),
SOC_ENUM("Transmit Slot Bit Width", tsbw_enum),
SOC_ENUM("Receive Edge Shift", rsft_enum),
- SOC_ENUM("Receive SDIx Select", rcsr_enum),
+ SOC_ENUM_EXT("Receive SDIx Select", rx_lanes_enum,
+ rockchip_sai_rx_lanes_get, rockchip_sai_rx_lanes_put),
SOC_ENUM("Receive Store Justified Mode", rsjm_enum),
SOC_ENUM("Receive First Bit Mode", rfbm_enum),
SOC_ENUM("Receive Valid Data Justified", rvdj_enum),
@@ -966,6 +1075,50 @@
return IRQ_HANDLED;
}
+static int rockchip_sai_keep_clk_always_on(struct rk_sai_dev *sai)
+{
+ unsigned int mclk_rate, bclk_rate, div_bclk;
+
+ sai->is_master_mode = true;
+
+ /* init I2S fmt default */
+ rockchip_sai_fmt_create(sai, SND_SOC_DAIFMT_I2S);
+
+ regmap_update_bits(sai->regmap, SAI_FSCR,
+ SAI_FSCR_FW_MASK |
+ SAI_FSCR_FPW_MASK,
+ SAI_FSCR_FW(64) |
+ SAI_FSCR_FPW(32));
+
+ mclk_rate = clk_get_rate(sai->mclk);
+ bclk_rate = DEFAULT_FS * 64;
+ div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
+
+ regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK,
+ SAI_CKR_MDIV(div_bclk));
+
+ pm_runtime_forbid(sai->dev);
+
+ dev_info(sai->dev, "CLK-ALWAYS-ON: mclk: %d, bclk: %d, fsync: %d\n",
+ mclk_rate, bclk_rate, DEFAULT_FS);
+
+ return 0;
+}
+
+static int rockchip_sai_parse_quirks(struct rk_sai_dev *sai)
+{
+ int ret = 0, i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(of_quirks); i++)
+ if (of_property_read_bool(sai->dev->of_node, of_quirks[i].quirk))
+ sai->quirks |= of_quirks[i].id;
+
+ if (sai->quirks & QUIRK_ALWAYS_ON)
+ ret = rockchip_sai_keep_clk_always_on(sai);
+
+ return ret;
+}
+
static int rockchip_sai_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -1022,13 +1175,13 @@
return PTR_ERR(sai->hclk);
}
- ret = clk_prepare_enable(sai->hclk);
+ ret = rockchip_sai_parse_quirks(sai);
if (ret)
return ret;
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
- ret = sai_runtime_resume(&pdev->dev);
+ ret = rockchip_sai_runtime_resume(&pdev->dev);
if (ret)
goto err_runtime_disable;
}
@@ -1051,29 +1204,52 @@
err_runtime_suspend:
if (!pm_runtime_status_suspended(&pdev->dev))
- sai_runtime_suspend(&pdev->dev);
+ rockchip_sai_runtime_suspend(&pdev->dev);
err_runtime_disable:
pm_runtime_disable(&pdev->dev);
- clk_disable_unprepare(sai->hclk);
return ret;
}
static int rockchip_sai_remove(struct platform_device *pdev)
{
- struct rk_sai_dev *sai = dev_get_drvdata(&pdev->dev);
-
pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
- sai_runtime_suspend(&pdev->dev);
-
- clk_disable_unprepare(sai->hclk);
+ rockchip_sai_runtime_suspend(&pdev->dev);
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int rockchip_sai_suspend(struct device *dev)
+{
+ struct rk_sai_dev *sai = dev_get_drvdata(dev);
+
+ regcache_mark_dirty(sai->regmap);
+
+ return 0;
+}
+
+static int rockchip_sai_resume(struct device *dev)
+{
+ struct rk_sai_dev *sai = dev_get_drvdata(dev);
+ int ret = pm_runtime_get_sync(dev);
+
+ if (ret < 0) {
+ pm_runtime_put_noidle(dev);
+ return ret;
+ }
+
+ ret = regcache_sync(sai->regmap);
+ pm_runtime_put(dev);
+
+ return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
static const struct dev_pm_ops rockchip_sai_pm_ops = {
- SET_RUNTIME_PM_OPS(sai_runtime_suspend, sai_runtime_resume, NULL)
+ SET_RUNTIME_PM_OPS(rockchip_sai_runtime_suspend, rockchip_sai_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(rockchip_sai_suspend, rockchip_sai_resume)
};
static struct platform_driver rockchip_sai_driver = {
--
Gitblit v1.6.2