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; 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; }
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; }