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: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
Link: https://patch.msgid.link/20250924130749.3012071-1-dario.binacchi@amarulasolutions.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Dario Binacchi 2025-09-24 15:07:44 +02:00 committed by Mark Brown
parent 6621b0f118
commit 1e570e7739
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
1 changed files with 90 additions and 33 deletions

View File

@ -24,8 +24,79 @@
#define MXS_SET_ADDR 0x4 #define MXS_SET_ADDR 0x4
#define MXS_CLR_ADDR 0x8 #define MXS_CLR_ADDR 0x8
#define MXS_SAIF_BUSY_TIMEOUT_US 10000
static struct mxs_saif *mxs_saif[2]; 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. * 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) int clk_id, unsigned int freq, int dir)
{ {
struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
int ret;
switch (clk_id) { switch (clk_id) {
case MXS_SAIF_MCLK: case MXS_SAIF_MCLK:
@ -56,18 +128,22 @@ static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
default: default:
return -EINVAL; return -EINVAL;
} }
return 0;
}
/* if (!saif->mclk_in_use && freq) {
* Since SAIF may work on EXTMASTER mode, IOW, it's working BITCLK&LRCLK ret = __mxs_saif_get_mclk(saif);
* is provided by other SAIF, we provide a interface here to get its master if (ret)
* from its master_id. return ret;
* Note that the master could be itself.
*/ /* enable MCLK output */
static inline struct mxs_saif *mxs_saif_get_master(struct mxs_saif * saif) __raw_writel(BM_SAIF_CTRL_RUN,
{ saif->base + SAIF_CTRL + MXS_SET_ADDR);
return mxs_saif[saif->master_id]; } else if (saif->mclk_in_use && freq == 0) {
ret = __mxs_saif_put_mclk(saif);
if (ret)
return ret;
}
return 0;
} }
/* /*
@ -238,34 +314,15 @@ int mxs_saif_get_mclk(unsigned int saif_id, unsigned int mclk,
unsigned int rate) unsigned int rate)
{ {
struct mxs_saif *saif = mxs_saif[saif_id]; struct mxs_saif *saif = mxs_saif[saif_id];
u32 stat;
int ret; int ret;
struct mxs_saif *master_saif;
if (!saif) if (!saif)
return -EINVAL; return -EINVAL;
/* Clear Reset */ ret = __mxs_saif_get_mclk(saif);
__raw_writel(BM_SAIF_CTRL_SFTRST, if (ret)
saif->base + SAIF_CTRL + MXS_CLR_ADDR); return ret;
/* 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;
ret = mxs_saif_set_clk(saif, mclk, rate); ret = mxs_saif_set_clk(saif, mclk, rate);
if (ret) if (ret)
return ret; return ret;