in ingenic-timer.c [141:202]
static int ingenic_tcu_setup_cevt(unsigned int cpu)
{
struct ingenic_tcu *tcu = ingenic_tcu;
struct ingenic_tcu_timer *timer = &tcu->timers[cpu];
unsigned int timer_virq;
struct irq_domain *domain;
unsigned long rate;
int err;
timer->clk = ingenic_tcu_get_clock(tcu->np, timer->channel);
if (IS_ERR(timer->clk))
return PTR_ERR(timer->clk);
err = clk_prepare_enable(timer->clk);
if (err)
goto err_clk_put;
rate = clk_get_rate(timer->clk);
if (!rate) {
err = -EINVAL;
goto err_clk_disable;
}
domain = irq_find_host(tcu->np);
if (!domain) {
err = -ENODEV;
goto err_clk_disable;
}
timer_virq = irq_create_mapping(domain, timer->channel);
if (!timer_virq) {
err = -EINVAL;
goto err_clk_disable;
}
snprintf(timer->name, sizeof(timer->name), "TCU%u", timer->channel);
err = request_irq(timer_virq, ingenic_tcu_cevt_cb, IRQF_TIMER,
timer->name, timer);
if (err)
goto err_irq_dispose_mapping;
timer->cpu = smp_processor_id();
timer->cevt.cpumask = cpumask_of(smp_processor_id());
timer->cevt.features = CLOCK_EVT_FEAT_ONESHOT;
timer->cevt.name = timer->name;
timer->cevt.rating = 200;
timer->cevt.set_state_shutdown = ingenic_tcu_cevt_set_state_shutdown;
timer->cevt.set_next_event = ingenic_tcu_cevt_set_next;
clockevents_config_and_register(&timer->cevt, rate, 10, 0xffff);
return 0;
err_irq_dispose_mapping:
irq_dispose_mapping(timer_virq);
err_clk_disable:
clk_disable_unprepare(timer->clk);
err_clk_put:
clk_put(timer->clk);
return err;
}