Unverified Commit 8c187e22 authored by Mark Brown's avatar Mark Brown
Browse files

Add support for XCVR on i.MX93 platform

Merge series from Chancel Liu <chancel.liu@nxp.com>:

This patchset supports XCVR on i.MX93 platform.

changes in v2:
- remove unnecessary code which causes kernel test robot reporting error

Chancel Liu (3):
  ASoC: dt-bindings: fsl,xcvr: Add compatible string for i.MX93 platform
  ASoC: fsl_xcvr: Add support for i.MX93 platform
  ASoC: fsl_xcvr: Add constraints of period size while using eDMA

 .../devicetree/bindings/sound/fsl,xcvr.yaml   |   1 +
 sound/soc/fsl/fsl_xcvr.c                      | 155 ++++++++++++------
 sound/soc/fsl/fsl_xcvr.h                      |   7 +
 3 files changed, 115 insertions(+), 48 deletions(-)

--
2.25.1
parents 9951dc8a 1760df5b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ properties:
  compatible:
    enum:
      - fsl,imx8mp-xcvr
      - fsl,imx93-xcvr

  reg:
    items:
+107 −48
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@

struct fsl_xcvr_soc_data {
	const char *fw_name;
	bool spdif_only;
	bool use_edma;
};

struct fsl_xcvr {
@@ -261,6 +263,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 +358,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 +371,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);
@@ -531,6 +539,16 @@ static int fsl_xcvr_startup(struct snd_pcm_substream *substream,
		return -EBUSY;
	}

	/*
	 * EDMA controller needs period size to be a multiple of
	 * tx/rx maxburst
	 */
	if (xcvr->soc_data->use_edma)
		snd_pcm_hw_constraint_step(substream->runtime, 0,
					   SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
					   tx ? xcvr->dma_prms_tx.maxburst :
					   xcvr->dma_prms_rx.maxburst);

	switch (xcvr->mode) {
	case FSL_XCVR_MODE_SPDIF:
	case FSL_XCVR_MODE_ARC:
@@ -547,10 +565,12 @@ static int fsl_xcvr_startup(struct snd_pcm_substream *substream,

	xcvr->streams |= BIT(substream->stream);

	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 +587,13 @@ static void fsl_xcvr_shutdown(struct snd_pcm_substream *substream,

	/* Enable XCVR controls if there is no stream started */
	if (!xcvr->streams) {
		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,6 +694,9 @@ 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;
				}
				if (xcvr->soc_data->spdif_only)
					break;
				else
					fallthrough;
			case FSL_XCVR_MODE_EARC:
				/* clear ISR_CMDC_TX_EN, W1C */
@@ -877,9 +901,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);

	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 +958,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 +995,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 +1026,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 +1068,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,6 +1149,7 @@ 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;
		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,
@@ -1131,6 +1178,7 @@ static irqreturn_t irq0_isr(int irq, void *devid)
				memset_io(reg_ctrl, 0, sizeof(val));
			}
		}
	}
	if (isr & FSL_XCVR_IRQ_NEW_UD) {
		dev_dbg(dev, "Received new UD block\n");
		isr_clr |= FSL_XCVR_IRQ_NEW_UD;
@@ -1168,8 +1216,14 @@ 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,
	.use_edma = 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 +1283,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 +1360,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);

	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 +1423,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");
+7 −0
Original line number Diff line number Diff line
@@ -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