diff options
Diffstat (limited to 'sound/soc/fsl/fsl_micfil.c')
-rw-r--r-- | sound/soc/fsl/fsl_micfil.c | 51 |
1 files changed, 40 insertions, 11 deletions
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 0c71a73476df..8c15389c9a04 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -68,6 +68,7 @@ struct fsl_micfil { int vad_detected; struct fsl_micfil_verid verid; struct fsl_micfil_param param; + bool mclk_flag; /* mclk enable flag */ }; struct fsl_micfil_soc_data { @@ -708,7 +709,7 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, /* Enable the module */ ret = regmap_set_bits(micfil->regmap, REG_MICFIL_CTRL1, - MICFIL_CTRL1_PDMIEN); + MICFIL_CTRL1_PDMIEN | MICFIL_CTRL1_ERREN); if (ret) return ret; @@ -724,7 +725,7 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, /* Disable the module */ ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1, - MICFIL_CTRL1_PDMIEN); + MICFIL_CTRL1_PDMIEN | MICFIL_CTRL1_ERREN); if (ret) return ret; @@ -751,7 +752,6 @@ static int fsl_micfil_reparent_rootclk(struct fsl_micfil *micfil, unsigned int s clk = micfil->mclk; /* Disable clock first, for it was enabled by pm_runtime */ - clk_disable_unprepare(clk); fsl_asoc_reparent_pll_clocks(dev, clk, micfil->pll8k_clk, micfil->pll11k_clk, ratio); ret = clk_prepare_enable(clk); @@ -788,6 +788,8 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; + micfil->mclk_flag = true; + ret = clk_set_rate(micfil->mclk, rate * clk_div * osr * 8); if (ret) return ret; @@ -822,6 +824,17 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, return 0; } +static int fsl_micfil_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); + + clk_disable_unprepare(micfil->mclk); + micfil->mclk_flag = false; + + return 0; +} + static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); @@ -878,6 +891,7 @@ static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { .startup = fsl_micfil_startup, .trigger = fsl_micfil_trigger, .hw_params = fsl_micfil_hw_params, + .hw_free = fsl_micfil_hw_free, }; static struct snd_soc_dai_driver fsl_micfil_dai = { @@ -999,6 +1013,7 @@ static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case REG_MICFIL_STAT: + case REG_MICFIL_FIFO_STAT: case REG_MICFIL_DATACH0: case REG_MICFIL_DATACH1: case REG_MICFIL_DATACH2: @@ -1007,6 +1022,7 @@ static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DATACH5: case REG_MICFIL_DATACH6: case REG_MICFIL_DATACH7: + case REG_MICFIL_OUT_STAT: case REG_MICFIL_VERID: case REG_MICFIL_PARAM: case REG_MICFIL_VAD0_STAT: @@ -1028,7 +1044,7 @@ static const struct regmap_config fsl_micfil_regmap_config = { .readable_reg = fsl_micfil_readable_reg, .volatile_reg = fsl_micfil_volatile_reg, .writeable_reg = fsl_micfil_writeable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; /* END OF REGMAP */ @@ -1061,7 +1077,7 @@ static irqreturn_t micfil_isr(int irq, void *devid) regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, MICFIL_STAT_CHXF(i), - 1); + MICFIL_STAT_CHXF(i)); } for (i = 0; i < MICFIL_FIFO_NUM; i++) { @@ -1083,6 +1099,8 @@ static irqreturn_t micfil_err_isr(int irq, void *devid) { struct fsl_micfil *micfil = (struct fsl_micfil *)devid; struct platform_device *pdev = micfil->pdev; + u32 fifo_stat_reg; + u32 out_stat_reg; u32 stat_reg; regmap_read(micfil->regmap, REG_MICFIL_STAT, &stat_reg); @@ -1096,9 +1114,17 @@ static irqreturn_t micfil_err_isr(int irq, void *devid) if (stat_reg & MICFIL_STAT_LOWFREQF) { dev_dbg(&pdev->dev, "isr: ipg_clk_app is too low\n"); regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, - MICFIL_STAT_LOWFREQF, 1); + MICFIL_STAT_LOWFREQF, MICFIL_STAT_LOWFREQF); } + regmap_read(micfil->regmap, REG_MICFIL_FIFO_STAT, &fifo_stat_reg); + regmap_write_bits(micfil->regmap, REG_MICFIL_FIFO_STAT, + fifo_stat_reg, fifo_stat_reg); + + regmap_read(micfil->regmap, REG_MICFIL_OUT_STAT, &out_stat_reg); + regmap_write_bits(micfil->regmap, REG_MICFIL_OUT_STAT, + out_stat_reg, out_stat_reg); + return IRQ_HANDLED; } @@ -1358,7 +1384,8 @@ static int fsl_micfil_runtime_suspend(struct device *dev) regcache_cache_only(micfil->regmap, true); - clk_disable_unprepare(micfil->mclk); + if (micfil->mclk_flag) + clk_disable_unprepare(micfil->mclk); clk_disable_unprepare(micfil->busclk); return 0; @@ -1373,10 +1400,12 @@ static int fsl_micfil_runtime_resume(struct device *dev) if (ret < 0) return ret; - ret = clk_prepare_enable(micfil->mclk); - if (ret < 0) { - clk_disable_unprepare(micfil->busclk); - return ret; + if (micfil->mclk_flag) { + ret = clk_prepare_enable(micfil->mclk); + if (ret < 0) { + clk_disable_unprepare(micfil->busclk); + return ret; + } } regcache_cache_only(micfil->regmap, false); |