MLK-13945-1: ASoC: fsl_mqs: refine the mqs driver for support imx8qm
IOMUXC_GPR2 register is not used for imx8, there is a new register designed for this usage in imx8, so it also need the ipg clock. Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com> Reviewed-by: Daniel Baluta <daniel.baluta@nxp.com>5.4-rM2-2.2.x-imx-squashed
parent
0a37960199
commit
56b42dc792
|
@ -2,7 +2,8 @@ fsl,mqs audio CODEC
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
|
|
||||||
- compatible : must contain one of "fsl,imx6sx-mqs" and "fsl,codec-mqs"
|
- compatible : must contain one of "fsl,imx6sx-mqs", "fsl,codec-mqs"
|
||||||
|
"fsl,imx8qm-mqs".
|
||||||
|
|
||||||
- clocks : a list of phandles + clock-specifiers, one for each entry in
|
- clocks : a list of phandles + clock-specifiers, one for each entry in
|
||||||
clock-names
|
clock-names
|
||||||
|
|
|
@ -20,17 +20,32 @@
|
||||||
#include <sound/initval.h>
|
#include <sound/initval.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define REG_MQS_CTRL 0x00
|
||||||
|
|
||||||
|
#define MQS_EN_MASK (0x1 << 28)
|
||||||
|
#define MQS_EN_SHIFT (28)
|
||||||
|
#define MQS_SW_RST_MASK (0x1 << 24)
|
||||||
|
#define MQS_SW_RST_SHIFT (24)
|
||||||
|
#define MQS_OVERSAMPLE_MASK (0x1 << 20)
|
||||||
|
#define MQS_OVERSAMPLE_SHIFT (20)
|
||||||
|
#define MQS_CLK_DIV_MASK (0xFF << 0)
|
||||||
|
#define MQS_CLK_DIV_SHIFT (0)
|
||||||
|
|
||||||
|
|
||||||
/* codec private data */
|
/* codec private data */
|
||||||
struct fsl_mqs {
|
struct fsl_mqs {
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
struct regmap *gpr;
|
struct regmap *gpr;
|
||||||
|
struct regmap *regmap;
|
||||||
struct clk *mclk;
|
struct clk *mclk;
|
||||||
|
struct clk *ipg;
|
||||||
|
|
||||||
unsigned long mclk_rate;
|
unsigned long mclk_rate;
|
||||||
|
|
||||||
int sysclk_rate;
|
int sysclk_rate;
|
||||||
int bclk;
|
int bclk;
|
||||||
int lrclk;
|
int lrclk;
|
||||||
|
bool use_gpr;
|
||||||
char name[32];
|
char name[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,10 +74,21 @@ static int fsl_mqs_hw_params(struct snd_pcm_substream *substream,
|
||||||
res = mqs_priv->mclk_rate % (32 * 2 * mqs_priv->lrclk * 8);
|
res = mqs_priv->mclk_rate % (32 * 2 * mqs_priv->lrclk * 8);
|
||||||
|
|
||||||
if (res == 0 && div > 0 && div <= 256) {
|
if (res == 0 && div > 0 && div <= 256) {
|
||||||
regmap_update_bits(mqs_priv->gpr, IOMUXC_GPR2,
|
if (mqs_priv->use_gpr) {
|
||||||
IMX6SX_GPR2_MQS_CLK_DIV_MASK, (div-1) << IMX6SX_GPR2_MQS_CLK_DIV_SHIFT);
|
regmap_update_bits(mqs_priv->gpr, IOMUXC_GPR2,
|
||||||
regmap_update_bits(mqs_priv->gpr, IOMUXC_GPR2,
|
IMX6SX_GPR2_MQS_CLK_DIV_MASK,
|
||||||
IMX6SX_GPR2_MQS_OVERSAMPLE_MASK, 0 << IMX6SX_GPR2_MQS_OVERSAMPLE_SHIFT);
|
(div-1) << IMX6SX_GPR2_MQS_CLK_DIV_SHIFT);
|
||||||
|
regmap_update_bits(mqs_priv->gpr, IOMUXC_GPR2,
|
||||||
|
IMX6SX_GPR2_MQS_OVERSAMPLE_MASK,
|
||||||
|
0 << IMX6SX_GPR2_MQS_OVERSAMPLE_SHIFT);
|
||||||
|
} else {
|
||||||
|
regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
|
||||||
|
MQS_CLK_DIV_MASK,
|
||||||
|
(div-1) << MQS_CLK_DIV_SHIFT);
|
||||||
|
regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
|
||||||
|
MQS_OVERSAMPLE_MASK,
|
||||||
|
0 << MQS_OVERSAMPLE_SHIFT);
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
dev_err(&mqs_priv->pdev->dev, "can't get proper divider\n");
|
dev_err(&mqs_priv->pdev->dev, "can't get proper divider\n");
|
||||||
|
|
||||||
|
@ -112,8 +138,19 @@ static int fsl_mqs_startup(struct snd_pcm_substream *substream,
|
||||||
struct snd_soc_codec *codec = dai->codec;
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
struct fsl_mqs *mqs_priv = snd_soc_codec_get_drvdata(codec);
|
struct fsl_mqs *mqs_priv = snd_soc_codec_get_drvdata(codec);
|
||||||
|
|
||||||
regmap_update_bits(mqs_priv->gpr, IOMUXC_GPR2, IMX6SX_GPR2_MQS_EN_MASK,
|
if (mqs_priv->ipg)
|
||||||
|
clk_prepare_enable(mqs_priv->ipg);
|
||||||
|
|
||||||
|
if (mqs_priv->mclk)
|
||||||
|
clk_prepare_enable(mqs_priv->mclk);
|
||||||
|
|
||||||
|
if (mqs_priv->use_gpr)
|
||||||
|
regmap_update_bits(mqs_priv->gpr, IOMUXC_GPR2, IMX6SX_GPR2_MQS_EN_MASK,
|
||||||
1 << IMX6SX_GPR2_MQS_EN_SHIFT);
|
1 << IMX6SX_GPR2_MQS_EN_SHIFT);
|
||||||
|
else
|
||||||
|
regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
|
||||||
|
MQS_EN_MASK,
|
||||||
|
1 << MQS_EN_SHIFT);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,9 +160,18 @@ static void fsl_mqs_shutdown(struct snd_pcm_substream *substream,
|
||||||
struct snd_soc_codec *codec = dai->codec;
|
struct snd_soc_codec *codec = dai->codec;
|
||||||
struct fsl_mqs *mqs_priv = snd_soc_codec_get_drvdata(codec);
|
struct fsl_mqs *mqs_priv = snd_soc_codec_get_drvdata(codec);
|
||||||
|
|
||||||
regmap_update_bits(mqs_priv->gpr, IOMUXC_GPR2,
|
if (mqs_priv->use_gpr)
|
||||||
|
regmap_update_bits(mqs_priv->gpr, IOMUXC_GPR2,
|
||||||
IMX6SX_GPR2_MQS_EN_MASK, 0);
|
IMX6SX_GPR2_MQS_EN_MASK, 0);
|
||||||
|
else
|
||||||
|
regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
|
||||||
|
MQS_EN_MASK, 0);
|
||||||
|
|
||||||
|
if (mqs_priv->mclk)
|
||||||
|
clk_disable_unprepare(mqs_priv->mclk);
|
||||||
|
|
||||||
|
if (mqs_priv->ipg)
|
||||||
|
clk_disable_unprepare(mqs_priv->ipg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -151,11 +197,21 @@ static struct snd_soc_dai_driver fsl_mqs_dai = {
|
||||||
.ops = &fsl_mqs_dai_ops,
|
.ops = &fsl_mqs_dai_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct regmap_config fsl_mqs_regmap_config = {
|
||||||
|
.reg_bits = 32,
|
||||||
|
.reg_stride = 4,
|
||||||
|
.val_bits = 32,
|
||||||
|
.max_register = REG_MQS_CTRL,
|
||||||
|
.cache_type = REGCACHE_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
static int fsl_mqs_probe(struct platform_device *pdev)
|
static int fsl_mqs_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
struct device_node *gpr_np;
|
struct device_node *gpr_np;
|
||||||
struct fsl_mqs *mqs_priv;
|
struct fsl_mqs *mqs_priv;
|
||||||
|
struct resource *res;
|
||||||
|
void __iomem *regs;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mqs_priv = devm_kzalloc(&pdev->dev, sizeof(*mqs_priv), GFP_KERNEL);
|
mqs_priv = devm_kzalloc(&pdev->dev, sizeof(*mqs_priv), GFP_KERNEL);
|
||||||
|
@ -165,18 +221,45 @@ static int fsl_mqs_probe(struct platform_device *pdev)
|
||||||
mqs_priv->pdev = pdev;
|
mqs_priv->pdev = pdev;
|
||||||
strncpy(mqs_priv->name, np->name, sizeof(mqs_priv->name) - 1);
|
strncpy(mqs_priv->name, np->name, sizeof(mqs_priv->name) - 1);
|
||||||
|
|
||||||
gpr_np = of_parse_phandle(np, "gpr", 0);
|
if (of_device_is_compatible(np, "fsl,imx8qm-mqs"))
|
||||||
if (IS_ERR(gpr_np)) {
|
mqs_priv->use_gpr = false;
|
||||||
dev_err(&pdev->dev, "failed to get gpr node by phandle\n");
|
else
|
||||||
ret = PTR_ERR(gpr_np);
|
mqs_priv->use_gpr = true;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
mqs_priv->gpr = syscon_node_to_regmap(gpr_np);
|
if (mqs_priv->use_gpr) {
|
||||||
if (IS_ERR(mqs_priv->gpr)) {
|
gpr_np = of_parse_phandle(np, "gpr", 0);
|
||||||
dev_err(&pdev->dev, "failed to get gpr regmap\n");
|
if (IS_ERR(gpr_np)) {
|
||||||
ret = PTR_ERR(mqs_priv->gpr);
|
dev_err(&pdev->dev, "failed to get gpr node by phandle\n");
|
||||||
goto out;
|
ret = PTR_ERR(gpr_np);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
mqs_priv->gpr = syscon_node_to_regmap(gpr_np);
|
||||||
|
if (IS_ERR(mqs_priv->gpr)) {
|
||||||
|
dev_err(&pdev->dev, "failed to get gpr regmap\n");
|
||||||
|
ret = PTR_ERR(mqs_priv->gpr);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
regs = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
if (IS_ERR(regs))
|
||||||
|
return PTR_ERR(regs);
|
||||||
|
|
||||||
|
mqs_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
|
||||||
|
"core", regs, &fsl_mqs_regmap_config);
|
||||||
|
if (IS_ERR(mqs_priv->regmap)) {
|
||||||
|
dev_err(&pdev->dev, "failed to init regmap: %ld\n",
|
||||||
|
PTR_ERR(mqs_priv->regmap));
|
||||||
|
return PTR_ERR(mqs_priv->regmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
mqs_priv->ipg = devm_clk_get(&pdev->dev, "core");
|
||||||
|
if (IS_ERR(mqs_priv->ipg)) {
|
||||||
|
dev_err(&pdev->dev, "failed to get the clock: %ld\n",
|
||||||
|
PTR_ERR(mqs_priv->ipg));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mqs_priv->mclk = devm_clk_get(&pdev->dev, "mclk");
|
mqs_priv->mclk = devm_clk_get(&pdev->dev, "mclk");
|
||||||
|
@ -205,6 +288,7 @@ static int fsl_mqs_remove(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id fsl_mqs_dt_ids[] = {
|
static const struct of_device_id fsl_mqs_dt_ids[] = {
|
||||||
|
{ .compatible = "fsl,imx8qm-mqs", },
|
||||||
{ .compatible = "fsl,imx6sx-mqs", },
|
{ .compatible = "fsl,imx6sx-mqs", },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue