OSDN Git Service

ASoC: fsl_xcvr: Add support for i.MX93 platform
authorChancel Liu <chancel.liu@nxp.com>
Wed, 4 Jan 2023 02:39:52 +0000 (10:39 +0800)
committerMark Brown <broonie@kernel.org>
Mon, 9 Jan 2023 13:04:22 +0000 (13:04 +0000)
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>
Link: https://lore.kernel.org/r/20230104023953.2973362-3-chancel.liu@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/fsl/fsl_xcvr.c
sound/soc/fsl/fsl_xcvr.h

index 2a6802f..b794158 100644 (file)
@@ -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 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;
+               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");
index 4769b0f..044058f 100644 (file)
 #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