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_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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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];
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
ret = __mxs_saif_get_mclk(saif);
|
||||
if (ret)
|
||||
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);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
Loading…
Reference in New Issue