When one of the MCLK pins is used to supply the FLL enable that clock source.
Signed-off-by: Charles Keepax ckeepax@opensource.cirrus.com --- sound/soc/codecs/madera.c | 109 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 100 insertions(+), 9 deletions(-)
diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c index 9b4b4c52b9e4b..12dc468ae6bf0 100644 --- a/sound/soc/codecs/madera.c +++ b/sound/soc/codecs/madera.c @@ -3858,11 +3858,75 @@ static bool madera_set_fll_phase_integrator(struct madera_fll *fll, return reg_change; }
+static int madera_set_fll_clks_reg(struct madera_fll *fll, bool ena, + unsigned int reg, unsigned int mask, + unsigned int shift) +{ + struct madera *madera = fll->madera; + unsigned int src; + struct clk *clk; + int ret; + + ret = regmap_read(madera->regmap, reg, &src); + if (ret != 0) { + madera_fll_err(fll, "Failed to read current source: %d\n", + ret); + return ret; + } + + src = (src & mask) >> shift; + + switch (src) { + case MADERA_FLL_SRC_MCLK1: + clk = madera->mclk[MADERA_MCLK1].clk; + break; + case MADERA_FLL_SRC_MCLK2: + clk = madera->mclk[MADERA_MCLK2].clk; + break; + case MADERA_FLL_SRC_MCLK3: + clk = madera->mclk[MADERA_MCLK3].clk; + break; + default: + return 0; + } + + if (ena) { + return clk_prepare_enable(clk); + } else { + clk_disable_unprepare(clk); + return 0; + } +} + +static inline int madera_set_fll_clks(struct madera_fll *fll, int base, bool ena) +{ + return madera_set_fll_clks_reg(fll, ena, + base + MADERA_FLL_CONTROL_6_OFFS, + MADERA_FLL1_REFCLK_SRC_MASK, + MADERA_FLL1_REFCLK_DIV_SHIFT); +} + +static inline int madera_set_fllao_clks(struct madera_fll *fll, int base, bool ena) +{ + return madera_set_fll_clks_reg(fll, ena, + base + MADERA_FLLAO_CONTROL_6_OFFS, + MADERA_FLL_AO_REFCLK_SRC_MASK, + MADERA_FLL_AO_REFCLK_SRC_SHIFT); +} + +static inline int madera_set_fllhj_clks(struct madera_fll *fll, int base, bool ena) +{ + return madera_set_fll_clks_reg(fll, ena, + base + MADERA_FLL_CONTROL_1_OFFS, + CS47L92_FLL1_REFCLK_SRC_MASK, + CS47L92_FLL1_REFCLK_SRC_SHIFT); +} + static void madera_disable_fll(struct madera_fll *fll) { struct madera *madera = fll->madera; unsigned int sync_base; - bool change; + bool ref_change, sync_change;
switch (madera->type) { case CS47L35: @@ -3880,18 +3944,23 @@ static void madera_disable_fll(struct madera_fll *fll) MADERA_FLL1_FREERUN, MADERA_FLL1_FREERUN); regmap_update_bits_check(madera->regmap, fll->base + MADERA_FLL_CONTROL_1_OFFS, - MADERA_FLL1_ENA, 0, &change); - regmap_update_bits(madera->regmap, - sync_base + MADERA_FLL_SYNCHRONISER_1_OFFS, - MADERA_FLL1_SYNC_ENA, 0); + MADERA_FLL1_ENA, 0, &ref_change); + regmap_update_bits_check(madera->regmap, + sync_base + MADERA_FLL_SYNCHRONISER_1_OFFS, + MADERA_FLL1_SYNC_ENA, 0, &sync_change); regmap_update_bits(madera->regmap, fll->base + MADERA_FLL_CONTROL_1_OFFS, MADERA_FLL1_FREERUN, 0);
madera_wait_for_fll(fll, false);
- if (change) + if (sync_change) + madera_set_fll_clks(fll, sync_base, false); + + if (ref_change) { + madera_set_fll_clks(fll, fll->base, false); pm_runtime_put_autosuspend(madera->dev); + } }
static int madera_enable_fll(struct madera_fll *fll) @@ -3947,6 +4016,10 @@ static int madera_enable_fll(struct madera_fll *fll) regmap_update_bits(fll->madera->regmap, fll->base + MADERA_FLL_CONTROL_7_OFFS, MADERA_FLL1_GAIN_MASK, 0); + + if (sync_enabled > 0) + madera_set_fll_clks(fll, sync_base, false); + madera_set_fll_clks(fll, fll->base, false); }
/* Apply SYNCCLK setting */ @@ -4025,11 +4098,15 @@ static int madera_enable_fll(struct madera_fll *fll) if (!already_enabled) pm_runtime_get_sync(madera->dev);
- if (have_sync) + if (have_sync) { + madera_set_fll_clks(fll, sync_base, true); regmap_update_bits(madera->regmap, sync_base + MADERA_FLL_SYNCHRONISER_1_OFFS, MADERA_FLL1_SYNC_ENA, MADERA_FLL1_SYNC_ENA); + } + + madera_set_fll_clks(fll, fll->base, true); regmap_update_bits(madera->regmap, fll->base + MADERA_FLL_CONTROL_1_OFFS, MADERA_FLL1_ENA, MADERA_FLL1_ENA); @@ -4201,6 +4278,9 @@ static int madera_enable_fll_ao(struct madera_fll *fll, fll->base + MADERA_FLLAO_CONTROL_1_OFFS, MADERA_FLL_AO_HOLD, MADERA_FLL_AO_HOLD);
+ if (already_enabled) + madera_set_fllao_clks(fll, fll->base, false); + for (i = 0; i < patch_size; i++) { val = patch[i].def;
@@ -4214,6 +4294,8 @@ static int madera_enable_fll_ao(struct madera_fll *fll, regmap_write(madera->regmap, patch[i].reg, val); }
+ madera_set_fllao_clks(fll, fll->base, true); + regmap_update_bits(madera->regmap, fll->base + MADERA_FLLAO_CONTROL_1_OFFS, MADERA_FLL_AO_ENA, MADERA_FLL_AO_ENA); @@ -4257,8 +4339,10 @@ static int madera_disable_fll_ao(struct madera_fll *fll) fll->base + MADERA_FLLAO_CONTROL_2_OFFS, MADERA_FLL_AO_CTRL_UPD_MASK, 0);
- if (change) + if (change) { + madera_set_fllao_clks(fll, fll->base, false); pm_runtime_put_autosuspend(madera->dev); + }
return 0; } @@ -4344,8 +4428,10 @@ static int madera_fllhj_disable(struct madera_fll *fll) fll->base + MADERA_FLL_CONTROL_2_OFFS, MADERA_FLL1_CTRL_UPD_MASK, 0);
- if (change) + if (change) { + madera_set_fllhj_clks(fll, fll->base, false); pm_runtime_put_autosuspend(madera->dev); + }
return 0; } @@ -4517,6 +4603,9 @@ static int madera_fllhj_enable(struct madera_fll *fll) MADERA_FLL1_HOLD_MASK, MADERA_FLL1_HOLD_MASK);
+ if (already_enabled) + madera_set_fllhj_clks(fll, fll->base, false); + /* Apply refclk */ ret = madera_fllhj_apply(fll, fll->ref_freq); if (ret) { @@ -4528,6 +4617,8 @@ static int madera_fllhj_enable(struct madera_fll *fll) CS47L92_FLL1_REFCLK_SRC_MASK, fll->ref_src << CS47L92_FLL1_REFCLK_SRC_SHIFT);
+ madera_set_fllhj_clks(fll, fll->base, true); + regmap_update_bits(madera->regmap, fll->base + MADERA_FLL_CONTROL_1_OFFS, MADERA_FLL1_ENA_MASK,