mirror of https://github.com/torvalds/linux.git
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:
parent
6621b0f118
commit
1e570e7739
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue