On Wed, Jan 4, 2023 at 10:40 AM Chancel Liu chancel.liu@nxp.com wrote:
Add compatible string and specific soc data to support XCVR on i.MX93 platform. XCVR IP on i.MX93 is cut to SPDIF only by removing external PHY.
Signed-off-by: Chancel Liu chancel.liu@nxp.com
Acked-by: Shengjiu Wang shengjiu.wang@gmail.com
best regards wang Shengjiu
sound/soc/fsl/fsl_xcvr.c | 143 ++++++++++++++++++++++++++------------- sound/soc/fsl/fsl_xcvr.h | 7 ++ 2 files changed, 102 insertions(+), 48 deletions(-)
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 2a6802fb2a8b..b794158a7876 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -21,6 +21,7 @@
struct fsl_xcvr_soc_data { const char *fw_name;
bool spdif_only;
};
struct fsl_xcvr { @@ -261,6 +262,9 @@ static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx) u32 i, div = 0, log2; int ret;
if (xcvr->soc_data->spdif_only)
return 0;
for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) { if (fsl_xcvr_pll_cfg[i].fout % freq == 0) { div = fsl_xcvr_pll_cfg[i].fout / freq;
@@ -353,6 +357,7 @@ static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq) struct device *dev = &xcvr->pdev->dev; int ret;
freq = xcvr->soc_data->spdif_only ? freq / 10 : freq; clk_disable_unprepare(xcvr->phy_clk); ret = clk_set_rate(xcvr->phy_clk, freq); if (ret < 0) {
@@ -365,6 +370,8 @@ static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq) return ret; }
if (xcvr->soc_data->spdif_only)
return 0; /* Release AI interface from reset */ ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, FSL_XCVR_PHY_AI_CTRL_AI_RESETN);
@@ -547,10 +554,12 @@ static int fsl_xcvr_startup(struct snd_pcm_substream *substream,
xcvr->streams |= BIT(substream->stream);
/* Disable XCVR controls if there is stream started */
fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, false);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, false);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, false);
if (!xcvr->soc_data->spdif_only) {
/* Disable XCVR controls if there is stream started */
fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name,
false);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
false);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
false);
} return 0;
} @@ -567,12 +576,13 @@ static void fsl_xcvr_shutdown(struct snd_pcm_substream *substream,
/* Enable XCVR controls if there is no stream started */ if (!xcvr->streams) {
fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, true);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_ARC));
fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_EARC));
if (!xcvr->soc_data->spdif_only) {
fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name,
true);
fsl_xcvr_activate_ctl(dai,
fsl_xcvr_arc_mode_kctl.name,
(xcvr->mode ==
FSL_XCVR_MODE_ARC));
fsl_xcvr_activate_ctl(dai,
fsl_xcvr_earc_capds_kctl.name,
(xcvr->mode ==
FSL_XCVR_MODE_EARC));
} ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, FSL_XCVR_IRQ_EARC_ALL, 0); if (ret < 0) {
@@ -673,7 +683,10 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret); return ret; }
fallthrough;
if (xcvr->soc_data->spdif_only)
break;
else
fallthrough; case FSL_XCVR_MODE_EARC: /* clear ISR_CMDC_TX_EN, W1C */ ret = regmap_write(xcvr->regmap,
@@ -877,9 +890,13 @@ static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai)
snd_soc_dai_init_dma_data(dai, &xcvr->dma_prms_tx,
&xcvr->dma_prms_rx);
snd_soc_add_dai_controls(dai, &fsl_xcvr_mode_kctl, 1);
snd_soc_add_dai_controls(dai, &fsl_xcvr_arc_mode_kctl, 1);
snd_soc_add_dai_controls(dai, &fsl_xcvr_earc_capds_kctl, 1);
if (xcvr->soc_data->spdif_only)
xcvr->mode = FSL_XCVR_MODE_SPDIF;
else {
snd_soc_add_dai_controls(dai, &fsl_xcvr_mode_kctl, 1);
snd_soc_add_dai_controls(dai, &fsl_xcvr_arc_mode_kctl, 1);
snd_soc_add_dai_controls(dai, &fsl_xcvr_earc_capds_kctl,
1);
} snd_soc_add_dai_controls(dai, fsl_xcvr_tx_ctls, ARRAY_SIZE(fsl_xcvr_tx_ctls)); snd_soc_add_dai_controls(dai, fsl_xcvr_rx_ctls,
@@ -930,10 +947,11 @@ static const struct reg_default fsl_xcvr_reg_defaults[] = { { FSL_XCVR_ISR_SET, 0x00000000 }, { FSL_XCVR_ISR_CLR, 0x00000000 }, { FSL_XCVR_ISR_TOG, 0x00000000 },
{ FSL_XCVR_RX_DPTH_CTRL, 0x00002C89 },
{ FSL_XCVR_RX_DPTH_CTRL_SET, 0x00002C89 },
{ FSL_XCVR_RX_DPTH_CTRL_CLR, 0x00002C89 },
{ FSL_XCVR_RX_DPTH_CTRL_TOG, 0x00002C89 },
{ FSL_XCVR_CLK_CTRL, 0x0000018F },
{ FSL_XCVR_RX_DPTH_CTRL, 0x00040CC1 },
{ FSL_XCVR_RX_DPTH_CTRL_SET, 0x00040CC1 },
{ FSL_XCVR_RX_DPTH_CTRL_CLR, 0x00040CC1 },
{ FSL_XCVR_RX_DPTH_CTRL_TOG, 0x00040CC1 }, { FSL_XCVR_RX_DPTH_CNTR_CTRL, 0x00000000 }, { FSL_XCVR_RX_DPTH_CNTR_CTRL_SET, 0x00000000 }, { FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR, 0x00000000 },
@@ -966,6 +984,12 @@ static const struct reg_default fsl_xcvr_reg_defaults[] = {
static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg) {
struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
if (xcvr->soc_data->spdif_only)
if ((reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA)
||
reg > FSL_XCVR_TX_DPTH_BCRR)
return false; switch (reg) { case FSL_XCVR_VERSION: case FSL_XCVR_EXT_CTRL:
@@ -991,6 +1015,12 @@ static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg) case FSL_XCVR_RX_DPTH_CTRL_SET: case FSL_XCVR_RX_DPTH_CTRL_CLR: case FSL_XCVR_RX_DPTH_CTRL_TOG:
case FSL_XCVR_RX_CS_DATA_0:
case FSL_XCVR_RX_CS_DATA_1:
case FSL_XCVR_RX_CS_DATA_2:
case FSL_XCVR_RX_CS_DATA_3:
case FSL_XCVR_RX_CS_DATA_4:
case FSL_XCVR_RX_CS_DATA_5: case FSL_XCVR_RX_DPTH_CNTR_CTRL: case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET: case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR:
@@ -1027,6 +1057,11 @@ static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg)
static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg) {
struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
if (xcvr->soc_data->spdif_only)
if (reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA)
return false; switch (reg) { case FSL_XCVR_EXT_CTRL: case FSL_XCVR_EXT_IER0:
@@ -1103,32 +1138,34 @@ static irqreturn_t irq0_isr(int irq, void *devid) if (isr & FSL_XCVR_IRQ_NEW_CS) { dev_dbg(dev, "Received new CS block\n"); isr_clr |= FSL_XCVR_IRQ_NEW_CS;
/* Data RAM is 4KiB, last two pages: 8 and 9. Select page
- */
regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_PAGE_MASK,
FSL_XCVR_EXT_CTRL_PAGE(8));
/* Find updated CS buffer */
reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_0;
reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_0;
memcpy_fromio(&val, reg_ctrl, sizeof(val));
if (!val) {
reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_1;
reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_1;
if (!xcvr->soc_data->spdif_only) {
/* Data RAM is 4KiB, last two pages: 8 and 9.
Select page 8. */
regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_PAGE_MASK,
FSL_XCVR_EXT_CTRL_PAGE(8));
/* Find updated CS buffer */
reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_0;
reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_0; memcpy_fromio(&val, reg_ctrl, sizeof(val));
}
if (!val) {
reg_ctrl = xcvr->ram_addr +
FSL_XCVR_RX_CS_CTRL_1;
reg_buff = xcvr->ram_addr +
FSL_XCVR_RX_CS_BUFF_1;
memcpy_fromio(&val, reg_ctrl, sizeof(val));
}
if (val) {
/* copy CS buffer */
memcpy_fromio(&xcvr->rx_iec958.status, reg_buff,
sizeof(xcvr->rx_iec958.status));
for (i = 0; i < 6; i++) {
val = *(u32 *)(xcvr->rx_iec958.status +
i*4);
*(u32 *)(xcvr->rx_iec958.status + i*4) =
bitrev32(val);
if (val) {
/* copy CS buffer */
memcpy_fromio(&xcvr->rx_iec958.status,
reg_buff,
sizeof(xcvr->rx_iec958.status));
for (i = 0; i < 6; i++) {
val = *(u32
*)(xcvr->rx_iec958.status + i*4);
*(u32 *)(xcvr->rx_iec958.status +
i*4) =
bitrev32(val);
}
/* clear CS control register */
memset_io(reg_ctrl, 0, sizeof(val)); }
/* clear CS control register */
memset_io(reg_ctrl, 0, sizeof(val)); } } if (isr & FSL_XCVR_IRQ_NEW_UD) {
@@ -1168,8 +1205,13 @@ static const struct fsl_xcvr_soc_data fsl_xcvr_imx8mp_data = { .fw_name = "imx/xcvr/xcvr-imx8mp.bin", };
+static const struct fsl_xcvr_soc_data fsl_xcvr_imx93_data = {
.spdif_only = true,
+};
static const struct of_device_id fsl_xcvr_dt_ids[] = { { .compatible = "fsl,imx8mp-xcvr", .data = &fsl_xcvr_imx8mp_data },
{ .compatible = "fsl,imx93-xcvr", .data = &fsl_xcvr_imx93_data}, { /* sentinel */ }
}; MODULE_DEVICE_TABLE(of, fsl_xcvr_dt_ids); @@ -1229,7 +1271,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev) return PTR_ERR(xcvr->regmap); }
xcvr->reset = devm_reset_control_get_exclusive(dev, NULL);
xcvr->reset = devm_reset_control_get_optional_exclusive(dev, NULL); if (IS_ERR(xcvr->reset)) { dev_err(dev, "failed to get XCVR reset control\n"); return PTR_ERR(xcvr->reset);
@@ -1306,12 +1348,14 @@ static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev) if (ret < 0) dev_err(dev, "Failed to clear IER0: %d\n", ret);
/* Assert M0+ reset */
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_CORE_RESET,
FSL_XCVR_EXT_CTRL_CORE_RESET);
if (ret < 0)
dev_err(dev, "Failed to assert M0+ core: %d\n", ret);
if (!xcvr->soc_data->spdif_only) {
/* Assert M0+ reset */
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_CORE_RESET,
FSL_XCVR_EXT_CTRL_CORE_RESET);
if (ret < 0)
dev_err(dev, "Failed to assert M0+ core: %d\n",
ret);
} regcache_cache_only(xcvr->regmap, true);
@@ -1367,6 +1411,9 @@ static __maybe_unused int fsl_xcvr_runtime_resume(struct device *dev) goto stop_spba_clk; }
if (xcvr->soc_data->spdif_only)
return 0;
ret = reset_control_deassert(xcvr->reset); if (ret) { dev_err(dev, "failed to deassert M0+ reset.\n");
diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h index 4769b0fca21d..044058fc6aa2 100644 --- a/sound/soc/fsl/fsl_xcvr.h +++ b/sound/soc/fsl/fsl_xcvr.h @@ -49,6 +49,13 @@ #define FSL_XCVR_RX_DPTH_CTRL_CLR 0x188 #define FSL_XCVR_RX_DPTH_CTRL_TOG 0x18c
+#define FSL_XCVR_RX_CS_DATA_0 0x190 +#define FSL_XCVR_RX_CS_DATA_1 0x194 +#define FSL_XCVR_RX_CS_DATA_2 0x198 +#define FSL_XCVR_RX_CS_DATA_3 0x19C +#define FSL_XCVR_RX_CS_DATA_4 0x1A0 +#define FSL_XCVR_RX_CS_DATA_5 0x1A4
#define FSL_XCVR_RX_DPTH_CNTR_CTRL 0x1C0 #define FSL_XCVR_RX_DPTH_CNTR_CTRL_SET 0x1C4
#define FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR 0x1C8
2.25.1