diff options
Diffstat (limited to 'sound/soc/fsl/fsl_esai.c')
-rw-r--r-- | sound/soc/fsl/fsl_esai.c | 56 |
1 files changed, 42 insertions, 14 deletions
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index c84026c99134..496ce2eb2f1f 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -18,6 +18,7 @@ #include "fsl_esai.h" #include "imx-pcm.h" +#include "fsl_utils.h" #define FSL_ESAI_RATES SNDRV_PCM_RATE_8000_192000 #define FSL_ESAI_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ @@ -257,10 +258,16 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, return -EINVAL; } - if (ratio == 1) { + /* Only EXTAL source can be output directly without using PSR and PM */ + if (ratio == 1 && clksrc == esai_priv->extalclk) { /* Bypass all the dividers if not being needed */ ecr |= tx ? ESAI_ECR_ETO : ESAI_ECR_ERO; goto out; + } else if (ratio < 2) { + /* The ratio should be no less than 2 if using other sources */ + dev_err(dai->dev, "failed to derive required HCK%c rate\n", + tx ? 'T' : 'R'); + return -EINVAL; } ret = fsl_esai_divisor_cal(dai, tx, ratio, false, 0); @@ -306,7 +313,8 @@ static int fsl_esai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) return -EINVAL; } - if (esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) { + /* The ratio should be contented by FP alone if bypassing PM and PSR */ + if (!esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) { dev_err(dai->dev, "the ratio is out of range (1 ~ 16)\n"); return -EINVAL; } @@ -431,25 +439,28 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) static int fsl_esai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + int ret; struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); /* * Some platforms might use the same bit to gate all three or two of * clocks, so keep all clocks open/close at the same time for safety */ - clk_prepare_enable(esai_priv->coreclk); - if (!IS_ERR(esai_priv->extalclk)) - clk_prepare_enable(esai_priv->extalclk); - if (!IS_ERR(esai_priv->fsysclk)) - clk_prepare_enable(esai_priv->fsysclk); + ret = clk_prepare_enable(esai_priv->coreclk); + if (ret) + return ret; + if (!IS_ERR(esai_priv->extalclk)) { + ret = clk_prepare_enable(esai_priv->extalclk); + if (ret) + goto err_extalck; + } + if (!IS_ERR(esai_priv->fsysclk)) { + ret = clk_prepare_enable(esai_priv->fsysclk); + if (ret) + goto err_fsysclk; + } if (!dai->active) { - /* Reset Port C */ - regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, - ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC, - ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO)); - /* Set synchronous mode */ regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR, ESAI_SAICR_SYNC, esai_priv->synchronous ? @@ -463,6 +474,14 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream, } return 0; + +err_fsysclk: + if (!IS_ERR(esai_priv->extalclk)) + clk_disable_unprepare(esai_priv->extalclk); +err_extalck: + clk_disable_unprepare(esai_priv->coreclk); + + return ret; } static int fsl_esai_hw_params(struct snd_pcm_substream *substream, @@ -501,6 +520,11 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val); + /* Remove ESAI personal reset by configuring ESAI_PCRC and ESAI_PRRC */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, + ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC, + ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO)); return 0; } @@ -564,6 +588,7 @@ static struct snd_soc_dai_ops fsl_esai_dai_ops = { .hw_params = fsl_esai_hw_params, .set_sysclk = fsl_esai_set_dai_sysclk, .set_fmt = fsl_esai_set_dai_fmt, + .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask, .set_tdm_slot = fsl_esai_set_dai_tdm_slot, }; @@ -661,7 +686,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg) } } -static const struct regmap_config fsl_esai_regmap_config = { +static struct regmap_config fsl_esai_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -687,6 +712,9 @@ static int fsl_esai_probe(struct platform_device *pdev) esai_priv->pdev = pdev; strcpy(esai_priv->name, np->name); + if (of_property_read_bool(np, "big-endian")) + fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; + /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); |