in timer-sun5i.c [186:247]
static int __init sun5i_setup_clocksource(struct device_node *node,
void __iomem *base,
struct clk *clk, int irq)
{
struct sun5i_timer_clksrc *cs;
unsigned long rate;
int ret;
cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs)
return -ENOMEM;
ret = clk_prepare_enable(clk);
if (ret) {
pr_err("Couldn't enable parent clock\n");
goto err_free;
}
rate = clk_get_rate(clk);
if (!rate) {
pr_err("Couldn't get parent clock rate\n");
ret = -EINVAL;
goto err_disable_clk;
}
cs->timer.base = base;
cs->timer.clk = clk;
cs->timer.clk_rate_cb.notifier_call = sun5i_rate_cb_clksrc;
cs->timer.clk_rate_cb.next = NULL;
ret = clk_notifier_register(clk, &cs->timer.clk_rate_cb);
if (ret) {
pr_err("Unable to register clock notifier.\n");
goto err_disable_clk;
}
writel(~0, base + TIMER_INTVAL_LO_REG(1));
writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
base + TIMER_CTL_REG(1));
cs->clksrc.name = node->name;
cs->clksrc.rating = 340;
cs->clksrc.read = sun5i_clksrc_read;
cs->clksrc.mask = CLOCKSOURCE_MASK(32);
cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
ret = clocksource_register_hz(&cs->clksrc, rate);
if (ret) {
pr_err("Couldn't register clock source.\n");
goto err_remove_notifier;
}
return 0;
err_remove_notifier:
clk_notifier_unregister(clk, &cs->timer.clk_rate_cb);
err_disable_clk:
clk_disable_unprepare(clk);
err_free:
kfree(cs);
return ret;
}