static int flexgen_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct flexgen *flexgen = to_flexgen(hw); struct clk_hw *pdiv_hw = &flexgen->pdiv.hw; struct clk_hw *fdiv_hw = &flexgen->fdiv.hw; unsigned long div = 0; int ret = 0; __clk_hw_set_clk(pdiv_hw, hw); __clk_hw_set_clk(fdiv_hw, hw); div = clk_best_div(parent_rate, rate); /* * pdiv is mainly targeted for low freq results, while fdiv * should be used for div <= 64. The other way round can * lead to 'duty cycle' issues. */ if (div <= 64) { clk_divider_ops.set_rate(pdiv_hw, parent_rate, parent_rate); ret = clk_divider_ops.set_rate(fdiv_hw, rate, rate * div); } else { clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate); ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * div); } return ret; }
static int clk_composite_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate, u8 index) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *rate_ops = composite->rate_ops; const struct clk_ops *mux_ops = composite->mux_ops; struct clk_hw *rate_hw = composite->rate_hw; struct clk_hw *mux_hw = composite->mux_hw; unsigned long temp_rate; __clk_hw_set_clk(rate_hw, hw); __clk_hw_set_clk(mux_hw, hw); temp_rate = rate_ops->recalc_rate(rate_hw, parent_rate); if (temp_rate > rate) { rate_ops->set_rate(rate_hw, rate, parent_rate); mux_ops->set_parent(mux_hw, index); } else { mux_ops->set_parent(mux_hw, index); rate_ops->set_rate(rate_hw, rate, parent_rate); } return 0; }
static unsigned long flexgen_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct flexgen *flexgen = to_flexgen(hw); struct clk_hw *pdiv_hw = &flexgen->pdiv.hw; struct clk_hw *fdiv_hw = &flexgen->fdiv.hw; unsigned long mid_rate; __clk_hw_set_clk(pdiv_hw, hw); __clk_hw_set_clk(fdiv_hw, hw); mid_rate = clk_divider_ops.recalc_rate(pdiv_hw, parent_rate); return clk_divider_ops.recalc_rate(fdiv_hw, mid_rate); }
static int flexgen_enable(struct clk_hw *hw) { struct flexgen *flexgen = to_flexgen(hw); struct clk_hw *pgate_hw = &flexgen->pgate.hw; struct clk_hw *fgate_hw = &flexgen->fgate.hw; __clk_hw_set_clk(pgate_hw, hw); __clk_hw_set_clk(fgate_hw, hw); clk_gate_ops.enable(pgate_hw); clk_gate_ops.enable(fgate_hw); pr_debug("%s: flexgen output enabled\n", __clk_get_name(hw->clk)); return 0; }
static void ti_adpll_clkout_disable(struct clk_hw *hw) { struct ti_adpll_clkout_data *co = to_clkout(hw); struct clk_hw *gate_hw = &co->gate.hw; __clk_hw_set_clk(gate_hw, hw); clk_gate_ops.disable(gate_hw); }
static void clkgena_divmux_disable(struct clk_hw *hw) { struct clkgena_divmux *genamux = to_clkgena_divmux(hw); struct clk_hw *mux_hw = &genamux->mux.hw; __clk_hw_set_clk(mux_hw, hw); clk_mux_ops.set_parent(mux_hw, CKGAX_CLKOPSRC_SWITCH_OFF); }
static u8 flexgen_get_parent(struct clk_hw *hw) { struct flexgen *flexgen = to_flexgen(hw); struct clk_hw *mux_hw = &flexgen->mux.hw; __clk_hw_set_clk(mux_hw, hw); return clk_mux_ops.get_parent(mux_hw); }
static int ti_adpll_clkout_is_enabled(struct clk_hw *hw) { struct ti_adpll_clkout_data *co = to_clkout(hw); struct clk_hw *gate_hw = &co->gate.hw; __clk_hw_set_clk(gate_hw, hw); return clk_gate_ops.is_enabled(gate_hw); }
static int flexgen_set_parent(struct clk_hw *hw, u8 index) { struct flexgen *flexgen = to_flexgen(hw); struct clk_hw *mux_hw = &flexgen->mux.hw; __clk_hw_set_clk(mux_hw, hw); return clk_mux_ops.set_parent(mux_hw, index); }
static int clkgena_divmux_is_enabled(struct clk_hw *hw) { struct clkgena_divmux *genamux = to_clkgena_divmux(hw); struct clk_hw *mux_hw = &genamux->mux.hw; __clk_hw_set_clk(mux_hw, hw); return (s8)clk_mux_ops.get_parent(mux_hw) > 0; }
static unsigned long clkgena_divmux_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clkgena_divmux *genamux = to_clkgena_divmux(hw); struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw; __clk_hw_set_clk(div_hw, hw); return clk_divider_ops.recalc_rate(div_hw, parent_rate); }
static int clk_periph_enable(struct clk_hw *hw) { struct tegra_clk_periph *periph = to_clk_periph(hw); const struct clk_ops *gate_ops = periph->gate_ops; struct clk_hw *gate_hw = &periph->gate.hw; __clk_hw_set_clk(gate_hw, hw); return gate_ops->enable(gate_hw); }
static void clk_composite_disable(struct clk_hw *hw) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *gate_ops = composite->gate_ops; struct clk_hw *gate_hw = composite->gate_hw; __clk_hw_set_clk(gate_hw, hw); gate_ops->disable(gate_hw); }
static int clk_composite_set_parent(struct clk_hw *hw, u8 index) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *mux_ops = composite->mux_ops; struct clk_hw *mux_hw = composite->mux_hw; __clk_hw_set_clk(mux_hw, hw); return mux_ops->set_parent(mux_hw, index); }
static int clk_periph_set_parent(struct clk_hw *hw, u8 index) { struct tegra_clk_periph *periph = to_clk_periph(hw); const struct clk_ops *mux_ops = periph->mux_ops; struct clk_hw *mux_hw = &periph->mux.hw; __clk_hw_set_clk(mux_hw, hw); return mux_ops->set_parent(mux_hw, index); }
static int clk_composite_enable(struct clk_hw *hw) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *gate_ops = composite->gate_ops; struct clk_hw *gate_hw = composite->gate_hw; __clk_hw_set_clk(gate_hw, hw); return gate_ops->enable(gate_hw); }
static u8 clk_composite_get_parent(struct clk_hw *hw) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *mux_ops = composite->mux_ops; struct clk_hw *mux_hw = composite->mux_hw; __clk_hw_set_clk(mux_hw, hw); return mux_ops->get_parent(mux_hw); }
static long clkgena_divmux_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { struct clkgena_divmux *genamux = to_clkgena_divmux(hw); struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw; __clk_hw_set_clk(div_hw, hw); return clk_divider_ops.round_rate(div_hw, rate, prate); }
static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *rate_ops = composite->rate_ops; struct clk_hw *rate_hw = composite->rate_hw; __clk_hw_set_clk(rate_hw, hw); return rate_ops->recalc_rate(rate_hw, parent_rate); }
static long clk_composite_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *rate_ops = composite->rate_ops; struct clk_hw *rate_hw = composite->rate_hw; __clk_hw_set_clk(rate_hw, hw); return rate_ops->round_rate(rate_hw, rate, prate); }
static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct tegra_clk_periph *periph = to_clk_periph(hw); const struct clk_ops *div_ops = periph->div_ops; struct clk_hw *div_hw = &periph->divider.hw; __clk_hw_set_clk(div_hw, hw); return div_ops->set_rate(div_hw, rate, parent_rate); }
static void flexgen_disable(struct clk_hw *hw) { struct flexgen *flexgen = to_flexgen(hw); struct clk_hw *fgate_hw = &flexgen->fgate.hw; /* disable only the final gate */ __clk_hw_set_clk(fgate_hw, hw); clk_gate_ops.disable(fgate_hw); pr_debug("%s: flexgen output disabled\n", __clk_get_name(hw->clk)); }
static int flexgen_is_enabled(struct clk_hw *hw) { struct flexgen *flexgen = to_flexgen(hw); struct clk_hw *fgate_hw = &flexgen->fgate.hw; __clk_hw_set_clk(fgate_hw, hw); if (!clk_gate_ops.is_enabled(fgate_hw)) return 0; return 1; }
static u8 clkgena_divmux_get_parent(struct clk_hw *hw) { struct clkgena_divmux *genamux = to_clkgena_divmux(hw); struct clk_hw *mux_hw = &genamux->mux.hw; __clk_hw_set_clk(mux_hw, hw); genamux->muxsel = clk_mux_ops.get_parent(mux_hw); if ((s8)genamux->muxsel < 0) { pr_debug("%s: %s: Invalid parent, setting to default.\n", __func__, clk_hw_get_name(hw)); genamux->muxsel = 0; } return genamux->muxsel; }
static int clkgena_divmux_enable(struct clk_hw *hw) { struct clkgena_divmux *genamux = to_clkgena_divmux(hw); struct clk_hw *mux_hw = &genamux->mux.hw; unsigned long timeout; int ret = 0; __clk_hw_set_clk(mux_hw, hw); ret = clk_mux_ops.set_parent(mux_hw, genamux->muxsel); if (ret) return ret; timeout = jiffies + msecs_to_jiffies(10); while (!clkgena_divmux_is_running(genamux)) { if (time_after(jiffies, timeout)) return -ETIMEDOUT; cpu_relax(); } return 0; }
static int clk_composite_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *rate_ops = composite->rate_ops; const struct clk_ops *mux_ops = composite->mux_ops; struct clk_hw *rate_hw = composite->rate_hw; struct clk_hw *mux_hw = composite->mux_hw; struct clk_hw *parent; unsigned long parent_rate; long tmp_rate, best_rate = 0; unsigned long rate_diff; unsigned long best_rate_diff = ULONG_MAX; long rate; int i; if (rate_hw && rate_ops && rate_ops->determine_rate) { __clk_hw_set_clk(rate_hw, hw); return rate_ops->determine_rate(rate_hw, req); } else if (rate_hw && rate_ops && rate_ops->round_rate && mux_hw && mux_ops && mux_ops->set_parent) { req->best_parent_hw = NULL; if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) { parent = clk_hw_get_parent(mux_hw); req->best_parent_hw = parent; req->best_parent_rate = clk_hw_get_rate(parent); rate = rate_ops->round_rate(rate_hw, req->rate, &req->best_parent_rate); if (rate < 0) return rate; req->rate = rate; return 0; } for (i = 0; i < clk_hw_get_num_parents(mux_hw); i++) { parent = clk_hw_get_parent_by_index(mux_hw, i); if (!parent) continue; parent_rate = clk_hw_get_rate(parent); tmp_rate = rate_ops->round_rate(rate_hw, req->rate, &parent_rate); if (tmp_rate < 0) continue; rate_diff = abs(req->rate - tmp_rate); if (!rate_diff || !req->best_parent_hw || best_rate_diff > rate_diff) { req->best_parent_hw = parent; req->best_parent_rate = parent_rate; best_rate_diff = rate_diff; best_rate = tmp_rate; } if (!rate_diff) return 0; } req->rate = best_rate; return 0; } else if (mux_hw && mux_ops && mux_ops->determine_rate) { __clk_hw_set_clk(mux_hw, hw); return mux_ops->determine_rate(mux_hw, req); } else { pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n"); return -EINVAL; } }
static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long min_rate, unsigned long max_rate, unsigned long *best_parent_rate, struct clk_hw **best_parent_p) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *rate_ops = composite->rate_ops; const struct clk_ops *mux_ops = composite->mux_ops; struct clk_hw *rate_hw = composite->rate_hw; struct clk_hw *mux_hw = composite->mux_hw; struct clk *parent; unsigned long parent_rate; long tmp_rate, best_rate = 0; unsigned long rate_diff; unsigned long best_rate_diff = ULONG_MAX; int i; if (rate_hw && rate_ops && rate_ops->determine_rate) { __clk_hw_set_clk(rate_hw, hw); return rate_ops->determine_rate(rate_hw, rate, min_rate, max_rate, best_parent_rate, best_parent_p); } else if (rate_hw && rate_ops && rate_ops->round_rate && mux_hw && mux_ops && mux_ops->set_parent) { *best_parent_p = NULL; if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) { parent = clk_get_parent(mux_hw->clk); *best_parent_p = __clk_get_hw(parent); *best_parent_rate = __clk_get_rate(parent); return rate_ops->round_rate(rate_hw, rate, best_parent_rate); } for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) { parent = clk_get_parent_by_index(mux_hw->clk, i); if (!parent) continue; parent_rate = __clk_get_rate(parent); tmp_rate = rate_ops->round_rate(rate_hw, rate, &parent_rate); if (tmp_rate < 0) continue; rate_diff = abs(rate - tmp_rate); if (!rate_diff || !*best_parent_p || best_rate_diff > rate_diff) { *best_parent_p = __clk_get_hw(parent); *best_parent_rate = parent_rate; best_rate_diff = rate_diff; best_rate = tmp_rate; } if (!rate_diff) return rate; } return best_rate; } else if (mux_hw && mux_ops && mux_ops->determine_rate) { __clk_hw_set_clk(mux_hw, hw); return mux_ops->determine_rate(mux_hw, rate, min_rate, max_rate, best_parent_rate, best_parent_p); } else { pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n"); return 0; } }