static long __slave_div_round_rate(struct clk *c, unsigned long rate, int *best_div) { struct div_clk *d = to_div_clk(c); unsigned int div, min_div, max_div; long p_rate; rate = max(rate, 1UL); min_div = d->data.min_div; max_div = d->data.max_div; p_rate = clk_get_rate(c->parent); div = p_rate / rate; div = max(div, min_div); div = min(div, max_div); if (best_div) *best_div = div; return p_rate / div; }
static int slave_div_set_rate(struct clk *c, unsigned long rate) { struct div_clk *d = to_div_clk(c); int div, rc = 0; long rrate; rrate = __slave_div_round_rate(c, rate, &div); if (rrate != rate) return -EINVAL; if (div == d->data.div) return 0; rc = d->ops->set_div(d, div); if (rc) return rc; d->data.div = div; return 0; }
static enum handoff div_handoff(struct clk *c) { struct div_clk *d = to_div_clk(c); unsigned int div = d->data.div; if (d->ops && d->ops->get_div) div = max(d->ops->get_div(d), 1); div = max(div, 1U); c->rate = clk_get_rate(c->parent) / div; if (!d->ops || !d->ops->set_div) d->data.min_div = d->data.max_div = div; d->data.div = div; if (d->en_mask && d->ops && d->ops->is_enabled) return d->ops->is_enabled(d) ? HANDOFF_ENABLED_CLK : HANDOFF_DISABLED_CLK; return HANDOFF_DISABLED_CLK; }
static int div_set_rate(struct clk *c, unsigned long rate) { struct div_clk *d = to_div_clk(c); int div = 0, rc = 0; long rrate, old_prate, new_prate = 0; struct div_data *data = &d->data; rrate = __div_round_rate(data, rate, c->parent, &div, &new_prate); if (rrate != rate) return -EINVAL; if (div > data->div) rc = d->ops->set_div(d, div); if (rc) return rc; old_prate = clk_get_rate(c->parent); rc = clk_set_rate(c->parent, new_prate); if (rc) goto set_rate_fail; if (div < data->div) rc = d->ops->set_div(d, div); if (rc) goto div_dec_fail; data->div = div; return 0; div_dec_fail: WARN(clk_set_rate(c->parent, old_prate), "Set rate failed for %s. Also in bad state!\n", c->dbg_name); set_rate_fail: if (div > data->div) WARN(d->ops->set_div(d, data->div), "Set rate failed for %s. Also in bad state!\n", c->dbg_name); return rc; }
/* * When the display is turned off, the display registers are wiped out. * Temporarily use the prepare ops to restore the register values. * */ int div_prepare(struct clk *c) { struct div_clk *div = to_div_clk(c); /* Restore the divider's value */ return div->ops->set_div(div, div->div); }
static void div_disable(struct clk *c) { struct div_clk *d = to_div_clk(c); if (d->ops && d->ops->disable) return d->ops->disable(d); }
static long div_round_rate(struct clk *c, unsigned long rate) { struct div_clk *d = to_div_clk(c); return __div_round_rate(&d->data, rate, c->parent, NULL, NULL); }
static int div_set_rate(struct clk *c, unsigned long rate) { struct div_clk *d = to_div_clk(c); int safe_div, div, rc = 0; long rrate, old_prate, new_prate; struct div_data *data = &d->data; rrate = __div_round_rate(data, rate, c->parent, &div, &new_prate); if (rrate != rate) return -EINVAL; /* * For fixed divider clock we don't want to return an error if the * requested rate matches the achievable rate. So, don't check for * !d->ops and return an error. __div_round_rate() ensures div == * d->div if !d->ops. */ safe_div = _find_safe_div(c, rate); if (d->safe_freq && safe_div < 0) { pr_err("No safe div on %s for transitioning from %lu to %lu\n", c->dbg_name, c->rate, rate); return -EINVAL; } safe_div = max(safe_div, div); if (safe_div > data->div) { rc = d->ops->set_div(d, safe_div); if (rc) { pr_err("Failed to set div %d on %s\n", safe_div, c->dbg_name); return rc; } } old_prate = clk_get_rate(c->parent); rc = clk_set_rate(c->parent, new_prate); if (rc) goto set_rate_fail; if (div < data->div) rc = d->ops->set_div(d, div); else if (div < safe_div) rc = d->ops->set_div(d, div); if (rc) goto div_dec_fail; data->div = div; return 0; div_dec_fail: WARN(clk_set_rate(c->parent, old_prate), "Set rate failed for %s. Also in bad state!\n", c->dbg_name); set_rate_fail: if (safe_div > data->div) WARN(d->ops->set_div(d, data->div), "Set rate failed for %s. Also in bad state!\n", c->dbg_name); return rc; }