static void arizona_enable_fll(struct arizona_fll *fll, struct arizona_fll_cfg *ref, struct arizona_fll_cfg *sync) { struct arizona *arizona = fll->arizona; int ret; bool use_sync = false; /* * If we have both REFCLK and SYNCCLK then enable both, * otherwise apply the SYNCCLK settings to REFCLK. */ if (fll->ref_src >= 0 && fll->ref_freq && fll->ref_src != fll->sync_src) { regmap_update_bits(arizona->regmap, fll->base + 5, ARIZONA_FLL1_OUTDIV_MASK, ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); arizona_apply_fll(arizona, fll->base, ref, fll->ref_src, false); if (fll->sync_src >= 0) { arizona_apply_fll(arizona, fll->base + 0x10, sync, fll->sync_src, true); use_sync = true; } } else if (fll->sync_src >= 0) { regmap_update_bits(arizona->regmap, fll->base + 5, ARIZONA_FLL1_OUTDIV_MASK, sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); arizona_apply_fll(arizona, fll->base, sync, fll->sync_src, false); regmap_update_bits(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, 0); } else { arizona_fll_err(fll, "No clocks provided\n"); return; } /* * Increase the bandwidth if we're not using a low frequency * sync source. */ if (use_sync && fll->sync_freq > 100000) regmap_update_bits(arizona->regmap, fll->base + 0x17, ARIZONA_FLL1_SYNC_BW, 0); else regmap_update_bits(arizona->regmap, fll->base + 0x17, ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW); if (!arizona_is_enabled_fll(fll)) pm_runtime_get(arizona->dev); /* Clear any pending completions */ try_wait_for_completion(&fll->ok); regmap_update_bits(arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, 0); regmap_update_bits(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); if (use_sync) regmap_update_bits(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); ret = wait_for_completion_timeout(&fll->ok, msecs_to_jiffies(250)); if (ret == 0) arizona_fll_warn(fll, "Timed out waiting for lock\n"); }
int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { struct arizona *arizona = fll->arizona; struct arizona_fll_cfg cfg, sync; unsigned int reg, val; int syncsrc; bool ena; int ret; ret = regmap_read(arizona->regmap, fll->base + 1, ®); if (ret != 0) { arizona_fll_err(fll, "Failed to read current state: %d\n", ret); return ret; } ena = reg & ARIZONA_FLL1_ENA; if (Fout) { /* Do we have a 32kHz reference? */ regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val); switch (val & ARIZONA_CLK_32K_SRC_MASK) { case ARIZONA_CLK_SRC_MCLK1: case ARIZONA_CLK_SRC_MCLK2: syncsrc = val & ARIZONA_CLK_32K_SRC_MASK; break; default: syncsrc = -1; } if (source == syncsrc) syncsrc = -1; if (syncsrc >= 0) { ret = arizona_calc_fll(fll, &sync, Fref, Fout); if (ret != 0) return ret; ret = arizona_calc_fll(fll, &cfg, 32768, Fout); if (ret != 0) return ret; } else { ret = arizona_calc_fll(fll, &cfg, Fref, Fout); if (ret != 0) return ret; } } else { regmap_update_bits(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, 0); regmap_update_bits(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, 0); if (ena) pm_runtime_put_autosuspend(arizona->dev); return 0; } regmap_update_bits(arizona->regmap, fll->base + 5, ARIZONA_FLL1_OUTDIV_MASK, cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); if (syncsrc >= 0) { arizona_apply_fll(arizona, fll->base, &cfg, syncsrc); arizona_apply_fll(arizona, fll->base + 0x10, &sync, source); } else { arizona_apply_fll(arizona, fll->base, &cfg, source); } if (!ena) pm_runtime_get(arizona->dev); /* Clear any pending completions */ try_wait_for_completion(&fll->ok); regmap_update_bits(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); if (syncsrc >= 0) regmap_update_bits(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); ret = wait_for_completion_timeout(&fll->ok, msecs_to_jiffies(25)); if (ret == 0) arizona_fll_warn(fll, "Timed out waiting for lock\n"); return 0; }