From b22da3d8526a935aa31e086e63f60ff3246cb61c Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 09 Dec 2023 07:24:11 +0000
Subject: [PATCH] add stmac read mac form eeprom
---
kernel/sound/soc/rockchip/rockchip_sai.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 230 insertions(+), 21 deletions(-)
diff --git a/kernel/sound/soc/rockchip/rockchip_sai.c b/kernel/sound/soc/rockchip/rockchip_sai.c
index c626142..3e50ba0 100644
--- a/kernel/sound/soc/rockchip/rockchip_sai.c
+++ b/kernel/sound/soc/rockchip/rockchip_sai.c
@@ -27,6 +27,8 @@
#define MAXBURST_PER_FIFO 8
#define DEFAULT_FS 48000
+#define TIMEOUT_US 1000
+#define WAIT_TIME_MS_MAX 10000
#define QUIRK_ALWAYS_ON BIT(0)
enum fpw_mode {
@@ -45,6 +47,7 @@
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 wait_time[SNDRV_PCM_STREAM_LAST + 1];
unsigned int tx_lanes;
unsigned int rx_lanes;
unsigned int quirks;
@@ -54,6 +57,7 @@
bool has_playback;
bool is_master_mode;
bool is_tdm;
+ bool is_clk_auto;
};
static const struct sai_of_quirks {
@@ -80,11 +84,26 @@
SAI_XFER_FSS_DIS);
ret = regmap_read_poll_timeout_atomic(sai->regmap, SAI_XFER, val,
- (val & SAI_XFER_FS_IDLE), 10, 100);
+ (val & SAI_XFER_FS_IDLE), 10, TIMEOUT_US);
if (ret < 0)
dev_warn(sai->dev, "Failed to idle FS\n");
regcache_cache_only(sai->regmap, true);
+ /*
+ * After FS idle, should wait at least 2 BCLK cycle to make sure
+ * the CLK gate operation done, and then disable mclk.
+ *
+ * Otherwise, the BCLK is still ungated. once the mclk is enabled,
+ * there maybe a risk that a few BCLK cycle leak. especially for
+ * low speed situation, such as 8k samplerate.
+ *
+ * The best way is to use delay per samplerate, but, the max time
+ * is quite a tiny value, so, let's make it simple to use the max
+ * time.
+ *
+ * The max BCLK cycle time is: 31us @ 8K-8Bit (64K BCLK)
+ */
+ udelay(40);
clk_disable_unprepare(sai->mclk);
clk_disable_unprepare(sai->hclk);
@@ -110,7 +129,7 @@
if (ret)
goto err_regmap;
- if (sai->is_master_mode)
+ if (sai->quirks & QUIRK_ALWAYS_ON && sai->is_master_mode)
regmap_update_bits(sai->regmap, SAI_XFER,
SAI_XFER_CLK_MASK |
SAI_XFER_FSS_MASK,
@@ -203,7 +222,7 @@
regmap_update_bits(sai->regmap, SAI_CLR, clr, clr);
ret = regmap_read_poll_timeout_atomic(sai->regmap, SAI_CLR, val,
- !(val & clr), 10, 100);
+ !(val & clr), 10, TIMEOUT_US);
if (ret < 0) {
dev_warn(sai->dev, "Failed to clear %u\n", clr);
goto reset;
@@ -249,7 +268,7 @@
regmap_update_bits(sai->regmap, SAI_XFER, msk, val);
ret = regmap_read_poll_timeout_atomic(sai->regmap, SAI_XFER, val,
- (val & idle), 10, 100);
+ (val & idle), 10, TIMEOUT_US);
if (ret < 0)
dev_warn(sai->dev, "Failed to idle stream %d\n", stream);
@@ -433,6 +452,7 @@
val = SAI_XCR_VDW(24);
break;
case SNDRV_PCM_FORMAT_S32_LE:
+ case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
val = SAI_XCR_VDW(32);
break;
default:
@@ -473,6 +493,8 @@
if (sai->is_master_mode) {
bclk_rate = sai->fw_ratio * slot_width * ch_per_lane * params_rate(params);
+ if (sai->is_clk_auto)
+ clk_set_rate(sai->mclk, bclk_rate);
mclk_rate = clk_get_rate(sai->mclk);
if (mclk_rate < bclk_rate) {
dev_err(sai->dev, "Mismatch mclk: %u, expected %u at least\n",
@@ -484,6 +506,22 @@
regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK,
SAI_CKR_MDIV(div_bclk));
+ /*
+ * Should wait for one BCLK ready after DIV and then ungate
+ * output clk to achieve the clean clk.
+ *
+ * The best way is to use delay per samplerate, but, the max time
+ * is quite a tiny value, so, let's make it simple to use the max
+ * time.
+ *
+ * The max BCLK cycle time is: 15.6us @ 8K-8Bit (64K BCLK)
+ */
+ udelay(20);
+ regmap_update_bits(sai->regmap, SAI_XFER,
+ SAI_XFER_CLK_MASK |
+ SAI_XFER_FSS_MASK,
+ SAI_XFER_CLK_EN |
+ SAI_XFER_FSS_EN);
}
return 0;
@@ -520,7 +558,7 @@
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
int ret;
- if (!freq)
+ if (!freq || sai->is_clk_auto)
return 0;
ret = clk_set_rate(sai->mclk, freq);
@@ -545,11 +583,15 @@
struct snd_soc_dai *dai)
{
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+ int stream = substream->stream;
- if (sai->substreams[substream->stream])
+ if (sai->substreams[stream])
return -EBUSY;
- sai->substreams[substream->stream] = substream;
+ if (sai->wait_time[stream])
+ substream->wait_time = msecs_to_jiffies(sai->wait_time[stream]);
+
+ sai->substreams[stream] = substream;
return 0;
}
@@ -746,7 +788,8 @@
dai->playback.formats = SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE;
+ SNDRV_PCM_FMTBIT_S32_LE |
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
sai->playback_dma_data.addr = res->start + SAI_TXDR;
sai->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -761,7 +804,8 @@
dai->capture.formats = SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE;
+ SNDRV_PCM_FMTBIT_S32_LE |
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
sai->capture_dma_data.addr = res->start + SAI_RXDR;
sai->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -794,8 +838,8 @@
static const char * const vdj_text[] = { "Right J", "Left J" };
static const char * const sbw_text[] = {
- " 0", " 0", " 0", " 0", " 0", " 0", " 0", " 8",
- " 9", "10", "11", "12", "13", "14", "15", "16",
+ "0", "0", "0", "0", "0", "0", "0", "8",
+ "9", "10", "11", "12", "13", "14", "15", "16",
"17", "18", "19", "20", "21", "22", "23", "24",
"25", "26", "27", "28", "29", "30", "31", "32", };
@@ -803,7 +847,7 @@
static DECLARE_TLV_DB_SCALE(rmss_tlv, 0, 128, 0);
-static const char * const mss_text[] = { "Master", "Slave" };
+static const char * const mss_text[] = { "Slave", "Master" };
static const char * const ckp_text[] = { "Normal", "Inverted" };
@@ -850,7 +894,8 @@
static SOC_ENUM_SINGLE_DECL(tmono_switch, SAI_MONO_CR, 0, mono_text);
/* CKR */
-static SOC_ENUM_SINGLE_DECL(mss_switch, SAI_CKR, 2, mss_text);
+static const struct soc_enum mss_switch =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mss_text), mss_text);
static SOC_ENUM_SINGLE_DECL(sp_switch, SAI_CKR, 1, ckp_text);
static SOC_ENUM_SINGLE_DECL(fp_switch, SAI_CKR, 0, ckp_text);
@@ -981,6 +1026,154 @@
return 1;
}
+static int rockchip_sai_mss_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->is_master_mode;
+
+ return 0;
+}
+
+static int rockchip_sai_mss_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);
+ bool mss;
+
+ /* MUST: do not update mode while stream is running */
+ if (snd_soc_component_active(component))
+ return -EPERM;
+
+ mss = !!ucontrol->value.enumerated.item[0];
+ if (mss == sai->is_master_mode)
+ return 0;
+
+ sai->is_master_mode = mss;
+
+ pm_runtime_get_sync(sai->dev);
+ if (sai->is_master_mode) {
+ /* Switch from Slave to Master */
+ regmap_update_bits(sai->regmap, SAI_CKR,
+ SAI_CKR_MSS_MASK,
+ SAI_CKR_MSS_MASTER);
+ regmap_update_bits(sai->regmap, SAI_XFER,
+ SAI_XFER_CLK_MASK |
+ SAI_XFER_FSS_MASK,
+ SAI_XFER_CLK_EN |
+ SAI_XFER_FSS_EN);
+ } else {
+ /* Switch from Master to Slave */
+ regmap_update_bits(sai->regmap, SAI_CKR,
+ SAI_CKR_MSS_MASK,
+ SAI_CKR_MSS_SLAVE);
+ regmap_update_bits(sai->regmap, SAI_XFER,
+ SAI_XFER_CLK_MASK |
+ SAI_XFER_FSS_MASK,
+ SAI_XFER_CLK_DIS |
+ SAI_XFER_FSS_DIS);
+ }
+ pm_runtime_put(sai->dev);
+
+ return 1;
+}
+
+static int rockchip_sai_clk_auto_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.integer.value[0] = sai->is_clk_auto;
+
+ return 0;
+}
+
+static int rockchip_sai_clk_auto_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);
+ bool clk_auto = ucontrol->value.integer.value[0];
+
+ if (clk_auto == sai->is_clk_auto)
+ return 0;
+
+ sai->is_clk_auto = clk_auto;
+
+ return 1;
+}
+
+static int rockchip_sai_wait_time_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = WAIT_TIME_MS_MAX;
+ uinfo->value.integer.step = 1;
+
+ return 0;
+}
+
+static int rockchip_sai_rd_wait_time_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.integer.value[0] = sai->wait_time[SNDRV_PCM_STREAM_CAPTURE];
+
+ return 0;
+}
+
+static int rockchip_sai_rd_wait_time_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);
+
+ if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX)
+ return -EINVAL;
+
+ sai->wait_time[SNDRV_PCM_STREAM_CAPTURE] = ucontrol->value.integer.value[0];
+
+ return 1;
+}
+
+static int rockchip_sai_wr_wait_time_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.integer.value[0] = sai->wait_time[SNDRV_PCM_STREAM_PLAYBACK];
+
+ return 0;
+}
+
+static int rockchip_sai_wr_wait_time_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);
+
+ if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX)
+ return -EINVAL;
+
+ sai->wait_time[SNDRV_PCM_STREAM_PLAYBACK] = ucontrol->value.integer.value[0];
+
+ return 1;
+}
+
+#define SAI_PCM_WAIT_TIME(xname, xhandler_get, xhandler_put) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, \
+ .info = rockchip_sai_wait_time_info, \
+ .get = xhandler_get, .put = xhandler_put }
+
static DECLARE_TLV_DB_SCALE(fs_shift_tlv, 0, 8192, 0);
static const struct snd_kcontrol_new rockchip_sai_controls[] = {
@@ -1012,7 +1205,8 @@
SOC_ENUM("Receive Mono Switch", rmono_switch),
SOC_ENUM("Transmit Mono Switch", tmono_switch),
- SOC_ENUM("Master / Slave Mode Select", mss_switch),
+ SOC_ENUM_EXT("Master / Slave Mode Select", mss_switch,
+ rockchip_sai_mss_get, rockchip_sai_mss_put),
SOC_ENUM("Sclk Polarity", sp_switch),
SOC_ENUM("Frame Sync Polarity", fp_switch),
@@ -1039,6 +1233,17 @@
0, 8192, 0, fs_shift_tlv),
SOC_SINGLE_TLV("Receive Frame Shift Select", SAI_RX_SHIFT,
0, 8192, 0, fs_shift_tlv),
+
+ SOC_SINGLE_BOOL_EXT("Clk Auto Switch", 0,
+ rockchip_sai_clk_auto_get,
+ rockchip_sai_clk_auto_put),
+
+ SAI_PCM_WAIT_TIME("PCM Read Wait Time MS",
+ rockchip_sai_rd_wait_time_get,
+ rockchip_sai_rd_wait_time_put),
+ SAI_PCM_WAIT_TIME("PCM Write Wait Time MS",
+ rockchip_sai_wr_wait_time_get,
+ rockchip_sai_wr_wait_time_put),
};
static const struct snd_soc_component_driver rockchip_sai_component = {
@@ -1110,7 +1315,7 @@
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))
+ if (device_property_read_bool(sai->dev, of_quirks[i].quirk))
sai->quirks |= of_quirks[i].id;
if (sai->quirks & QUIRK_ALWAYS_ON)
@@ -1134,6 +1339,8 @@
sai->dev = &pdev->dev;
sai->fw_ratio = 1;
+ /* match to register default */
+ sai->is_master_mode = true;
dev_set_drvdata(&pdev->dev, sai);
sai->rst_h = devm_reset_control_get_optional_exclusive(&pdev->dev, "h");
@@ -1153,7 +1360,7 @@
if (IS_ERR(sai->regmap))
return PTR_ERR(sai->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_sai_isr,
IRQF_SHARED, node->name, sai);
@@ -1196,6 +1403,11 @@
if (ret)
goto err_runtime_suspend;
+ if (device_property_read_bool(&pdev->dev, "rockchip,no-dmaengine")) {
+ dev_info(&pdev->dev, "Used for Multi-DAI\n");
+ return 0;
+ }
+
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (ret)
goto err_runtime_suspend;
@@ -1233,13 +1445,10 @@
static int rockchip_sai_resume(struct device *dev)
{
struct rk_sai_dev *sai = dev_get_drvdata(dev);
- int ret = pm_runtime_get_sync(dev);
+ int ret = pm_runtime_resume_and_get(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
+ if (ret < 0)
return ret;
- }
-
ret = regcache_sync(sai->regmap);
pm_runtime_put(dev);
--
Gitblit v1.6.2