int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason)
{
struct clkctl_acpu_speed *cur, *next;
cur = drv_state.current_speed;
/* convert to KHz */
rate /= 1000;
dprintf(INFO, "[ACPU] switching to %d MHz\n", ((int) (rate/1000)));
if (rate == cur->acpu_khz || rate == 0)
return 0;
next = acpu_freq_tbl;
for (;;) {
if (next->acpu_khz == rate)
break;
if (next->acpu_khz == 0)
return -1;
next++;
}
if (reason == SETRATE_CPUFREQ) {
/* Increase VDD if needed. */
if (next->vdd > cur->vdd) {
if (acpuclk_set_vdd_level(next->vdd)) {
dprintf(INFO, "acpuclock: Unable to increase ACPU VDD.\n");
return -1;
}
}
}
if (next->clk_sel == SRC_SCPLL) {
/* curr -> standby(MPLL speed) -> target */
if (!IS_ACPU_STANDBY(cur))
select_clock(acpu_stby->clk_sel, acpu_stby->clk_cfg);
scpll_set_freq(next->sc_l_value);
select_clock(SRC_SCPLL, 0);
} else {
if (cur->clk_sel == SRC_SCPLL) {
select_clock(acpu_stby->clk_sel, acpu_stby->clk_cfg);
select_clock(next->clk_sel, next->clk_cfg);
scpll_power_down();
} else {
select_clock(next->clk_sel, next->clk_cfg);
}
}
drv_state.current_speed = next;
/* This will fail anyway, so remove it for now
if (reason == SETRATE_CPUFREQ) {
if (cur->axiclk_khz != next->axiclk_khz)
clk_set_rate(EBI1_CLK, next->axiclk_khz * 1000);
}
*/
if (reason == SETRATE_CPUFREQ) {
/* Drop VDD level if we can. */
if (next->vdd < cur->vdd) {
if (acpuclk_set_vdd_level(next->vdd))
dprintf(INFO, "acpuclock: Unable to drop ACPU VDD.\n");
}
}
return 0;
}