Unverified Commit 1e570e77 authored by Dario Binacchi's avatar Dario Binacchi Committed by Mark Brown
Browse files

ASoC: mxs-saif: support usage with simple-audio-card



Add support for enabling MCLK output when using the simple-audio-card
driver. In the sound/soc/mxs/mxs-sgtl5000.c use case, that driver
handles MCLK enable/disable by calling mxs_saif_get_mclk() and
mxs_saif_put_mclk() at probe/remove. This does not happen when the
simple-audio-card driver is used. Extend the mxs-saif driver to enable
MCLK output in that scenario.

Co-developed-by: default avatarMichael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: default avatarMichael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: default avatarDario Binacchi <dario.binacchi@amarulasolutions.com>
Link: https://patch.msgid.link/20250924130749.3012071-1-dario.binacchi@amarulasolutions.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 6621b0f1
Loading
Loading
Loading
Loading
+90 −33
Original line number Diff line number Diff line
@@ -24,8 +24,79 @@
#define MXS_SET_ADDR	0x4
#define MXS_CLR_ADDR	0x8

#define MXS_SAIF_BUSY_TIMEOUT_US 10000

static struct mxs_saif *mxs_saif[2];

/*
 * Since SAIF may work on EXTMASTER mode, IOW, it's working BITCLK&LRCLK
 * is provided by other SAIF, we provide a interface here to get its master
 * from its master_id.
 * Note that the master could be itself.
 */
static inline struct mxs_saif *mxs_saif_get_master(struct mxs_saif *saif)
{
	return mxs_saif[saif->master_id];
}

static int __mxs_saif_put_mclk(struct mxs_saif *saif)
{
	u32 stat;
	int ret;

	ret = readx_poll_timeout(__raw_readl, saif->base + SAIF_STAT, stat,
				 (stat & BM_SAIF_STAT_BUSY) == 0,
				 MXS_SAIF_BUSY_TIMEOUT_US,
				 USEC_PER_SEC);
	if (ret) {
		dev_err(saif->dev, "error: busy\n");
		return -EBUSY;
	}

	/* disable MCLK output */
	__raw_writel(BM_SAIF_CTRL_CLKGATE,
		saif->base + SAIF_CTRL + MXS_SET_ADDR);
	__raw_writel(BM_SAIF_CTRL_RUN,
		saif->base + SAIF_CTRL + MXS_CLR_ADDR);

	saif->mclk_in_use = 0;

	return 0;
}

static int __mxs_saif_get_mclk(struct mxs_saif *saif)
{
	u32 stat;
	struct mxs_saif *master_saif;

	if (!saif)
		return -EINVAL;

	/* Clear Reset */
	__raw_writel(BM_SAIF_CTRL_SFTRST,
		saif->base + SAIF_CTRL + MXS_CLR_ADDR);

	/* FIXME: need clear clk gate for register r/w */
	__raw_writel(BM_SAIF_CTRL_CLKGATE,
		saif->base + SAIF_CTRL + MXS_CLR_ADDR);

	master_saif = mxs_saif_get_master(saif);
	if (saif != master_saif) {
		dev_err(saif->dev, "can not get mclk from a non-master saif\n");
		return -EINVAL;
	}

	stat = __raw_readl(saif->base + SAIF_STAT);
	if (stat & BM_SAIF_STAT_BUSY) {
		dev_err(saif->dev, "error: busy\n");
		return -EBUSY;
	}

	saif->mclk_in_use = 1;

	return 0;
}

/*
 * SAIF is a little different with other normal SOC DAIs on clock using.
 *
@@ -48,6 +119,7 @@ static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
			int clk_id, unsigned int freq, int dir)
{
	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
	int ret;

	switch (clk_id) {
	case MXS_SAIF_MCLK:
@@ -56,18 +128,22 @@ static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
	default:
		return -EINVAL;
	}
	return 0;

	if (!saif->mclk_in_use && freq) {
		ret = __mxs_saif_get_mclk(saif);
		if (ret)
			return ret;

		/* enable MCLK output */
		__raw_writel(BM_SAIF_CTRL_RUN,
		saif->base + SAIF_CTRL + MXS_SET_ADDR);
	} else if (saif->mclk_in_use && freq == 0) {
		ret = __mxs_saif_put_mclk(saif);
		if (ret)
			return ret;
	}

/*
 * Since SAIF may work on EXTMASTER mode, IOW, it's working BITCLK&LRCLK
 * is provided by other SAIF, we provide a interface here to get its master
 * from its master_id.
 * Note that the master could be itself.
 */
static inline struct mxs_saif *mxs_saif_get_master(struct mxs_saif * saif)
{
	return mxs_saif[saif->master_id];
	return 0;
}

/*
@@ -238,34 +314,15 @@ int mxs_saif_get_mclk(unsigned int saif_id, unsigned int mclk,
					unsigned int rate)
{
	struct mxs_saif *saif = mxs_saif[saif_id];
	u32 stat;
	int ret;
	struct mxs_saif *master_saif;

	if (!saif)
		return -EINVAL;

	/* Clear Reset */
	__raw_writel(BM_SAIF_CTRL_SFTRST,
		saif->base + SAIF_CTRL + MXS_CLR_ADDR);

	/* FIXME: need clear clk gate for register r/w */
	__raw_writel(BM_SAIF_CTRL_CLKGATE,
		saif->base + SAIF_CTRL + MXS_CLR_ADDR);

	master_saif = mxs_saif_get_master(saif);
	if (saif != master_saif) {
		dev_err(saif->dev, "can not get mclk from a non-master saif\n");
		return -EINVAL;
	}

	stat = __raw_readl(saif->base + SAIF_STAT);
	if (stat & BM_SAIF_STAT_BUSY) {
		dev_err(saif->dev, "error: busy\n");
		return -EBUSY;
	}
	ret = __mxs_saif_get_mclk(saif);
	if (ret)
		return ret;

	saif->mclk_in_use = 1;
	ret = mxs_saif_set_clk(saif, mclk, rate);
	if (ret)
		return ret;