162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/drivers/clocksource/timer-sp.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1999 - 2003 ARM Limited 662306a36Sopenharmony_ci * Copyright (C) 2000 Deep Blue Solutions Ltd 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/clk.h> 1262306a36Sopenharmony_ci#include <linux/clocksource.h> 1362306a36Sopenharmony_ci#include <linux/clockchips.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/irq.h> 1762306a36Sopenharmony_ci#include <linux/io.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/of_address.h> 2062306a36Sopenharmony_ci#include <linux/of_clk.h> 2162306a36Sopenharmony_ci#include <linux/of_irq.h> 2262306a36Sopenharmony_ci#include <linux/sched_clock.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "timer-sp.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Hisilicon 64-bit timer(a variant of ARM SP804) */ 2762306a36Sopenharmony_ci#define HISI_TIMER_1_BASE 0x00 2862306a36Sopenharmony_ci#define HISI_TIMER_2_BASE 0x40 2962306a36Sopenharmony_ci#define HISI_TIMER_LOAD 0x00 3062306a36Sopenharmony_ci#define HISI_TIMER_LOAD_H 0x04 3162306a36Sopenharmony_ci#define HISI_TIMER_VALUE 0x08 3262306a36Sopenharmony_ci#define HISI_TIMER_VALUE_H 0x0c 3362306a36Sopenharmony_ci#define HISI_TIMER_CTRL 0x10 3462306a36Sopenharmony_ci#define HISI_TIMER_INTCLR 0x14 3562306a36Sopenharmony_ci#define HISI_TIMER_RIS 0x18 3662306a36Sopenharmony_ci#define HISI_TIMER_MIS 0x1c 3762306a36Sopenharmony_ci#define HISI_TIMER_BGLOAD 0x20 3862306a36Sopenharmony_ci#define HISI_TIMER_BGLOAD_H 0x24 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic struct sp804_timer arm_sp804_timer __initdata = { 4162306a36Sopenharmony_ci .load = TIMER_LOAD, 4262306a36Sopenharmony_ci .value = TIMER_VALUE, 4362306a36Sopenharmony_ci .ctrl = TIMER_CTRL, 4462306a36Sopenharmony_ci .intclr = TIMER_INTCLR, 4562306a36Sopenharmony_ci .timer_base = {TIMER_1_BASE, TIMER_2_BASE}, 4662306a36Sopenharmony_ci .width = 32, 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic struct sp804_timer hisi_sp804_timer __initdata = { 5062306a36Sopenharmony_ci .load = HISI_TIMER_LOAD, 5162306a36Sopenharmony_ci .load_h = HISI_TIMER_LOAD_H, 5262306a36Sopenharmony_ci .value = HISI_TIMER_VALUE, 5362306a36Sopenharmony_ci .value_h = HISI_TIMER_VALUE_H, 5462306a36Sopenharmony_ci .ctrl = HISI_TIMER_CTRL, 5562306a36Sopenharmony_ci .intclr = HISI_TIMER_INTCLR, 5662306a36Sopenharmony_ci .timer_base = {HISI_TIMER_1_BASE, HISI_TIMER_2_BASE}, 5762306a36Sopenharmony_ci .width = 64, 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic struct sp804_clkevt sp804_clkevt[NR_TIMERS]; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic long __init sp804_get_clock_rate(struct clk *clk, const char *name) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci int err; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (!clk) 6762306a36Sopenharmony_ci clk = clk_get_sys("sp804", name); 6862306a36Sopenharmony_ci if (IS_ERR(clk)) { 6962306a36Sopenharmony_ci pr_err("%s clock not found: %ld\n", name, PTR_ERR(clk)); 7062306a36Sopenharmony_ci return PTR_ERR(clk); 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci err = clk_prepare_enable(clk); 7462306a36Sopenharmony_ci if (err) { 7562306a36Sopenharmony_ci pr_err("clock failed to enable: %d\n", err); 7662306a36Sopenharmony_ci clk_put(clk); 7762306a36Sopenharmony_ci return err; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci return clk_get_rate(clk); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic struct sp804_clkevt * __init sp804_clkevt_get(void __iomem *base) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci int i; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci for (i = 0; i < NR_TIMERS; i++) { 8862306a36Sopenharmony_ci if (sp804_clkevt[i].base == base) 8962306a36Sopenharmony_ci return &sp804_clkevt[i]; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* It's impossible to reach here */ 9362306a36Sopenharmony_ci WARN_ON(1); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return NULL; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic struct sp804_clkevt *sched_clkevt; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic u64 notrace sp804_read(void) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci return ~readl_relaxed(sched_clkevt->value); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic int __init sp804_clocksource_and_sched_clock_init(void __iomem *base, 10662306a36Sopenharmony_ci const char *name, 10762306a36Sopenharmony_ci struct clk *clk, 10862306a36Sopenharmony_ci int use_sched_clock) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci long rate; 11162306a36Sopenharmony_ci struct sp804_clkevt *clkevt; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci rate = sp804_get_clock_rate(clk, name); 11462306a36Sopenharmony_ci if (rate < 0) 11562306a36Sopenharmony_ci return -EINVAL; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci clkevt = sp804_clkevt_get(base); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci writel(0, clkevt->ctrl); 12062306a36Sopenharmony_ci writel(0xffffffff, clkevt->load); 12162306a36Sopenharmony_ci writel(0xffffffff, clkevt->value); 12262306a36Sopenharmony_ci if (clkevt->width == 64) { 12362306a36Sopenharmony_ci writel(0xffffffff, clkevt->load_h); 12462306a36Sopenharmony_ci writel(0xffffffff, clkevt->value_h); 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, 12762306a36Sopenharmony_ci clkevt->ctrl); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci clocksource_mmio_init(clkevt->value, name, 13062306a36Sopenharmony_ci rate, 200, 32, clocksource_mmio_readl_down); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (use_sched_clock) { 13362306a36Sopenharmony_ci sched_clkevt = clkevt; 13462306a36Sopenharmony_ci sched_clock_register(sp804_read, 32, rate); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return 0; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic struct sp804_clkevt *common_clkevt; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* 14462306a36Sopenharmony_ci * IRQ handler for the timer 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_cistatic irqreturn_t sp804_timer_interrupt(int irq, void *dev_id) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct clock_event_device *evt = dev_id; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* clear the interrupt */ 15162306a36Sopenharmony_ci writel(1, common_clkevt->intclr); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci evt->event_handler(evt); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return IRQ_HANDLED; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic inline void evt_timer_shutdown(struct clock_event_device *evt) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci writel(0, common_clkevt->ctrl); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic int sp804_shutdown(struct clock_event_device *evt) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci evt_timer_shutdown(evt); 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int sp804_set_periodic(struct clock_event_device *evt) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE | 17262306a36Sopenharmony_ci TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci evt_timer_shutdown(evt); 17562306a36Sopenharmony_ci writel(common_clkevt->reload, common_clkevt->load); 17662306a36Sopenharmony_ci writel(ctrl, common_clkevt->ctrl); 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int sp804_set_next_event(unsigned long next, 18162306a36Sopenharmony_ci struct clock_event_device *evt) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE | 18462306a36Sopenharmony_ci TIMER_CTRL_ONESHOT | TIMER_CTRL_ENABLE; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci writel(next, common_clkevt->load); 18762306a36Sopenharmony_ci writel(ctrl, common_clkevt->ctrl); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return 0; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic struct clock_event_device sp804_clockevent = { 19362306a36Sopenharmony_ci .features = CLOCK_EVT_FEAT_PERIODIC | 19462306a36Sopenharmony_ci CLOCK_EVT_FEAT_ONESHOT | 19562306a36Sopenharmony_ci CLOCK_EVT_FEAT_DYNIRQ, 19662306a36Sopenharmony_ci .set_state_shutdown = sp804_shutdown, 19762306a36Sopenharmony_ci .set_state_periodic = sp804_set_periodic, 19862306a36Sopenharmony_ci .set_state_oneshot = sp804_shutdown, 19962306a36Sopenharmony_ci .tick_resume = sp804_shutdown, 20062306a36Sopenharmony_ci .set_next_event = sp804_set_next_event, 20162306a36Sopenharmony_ci .rating = 300, 20262306a36Sopenharmony_ci}; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int __init sp804_clockevents_init(void __iomem *base, unsigned int irq, 20562306a36Sopenharmony_ci struct clk *clk, const char *name) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct clock_event_device *evt = &sp804_clockevent; 20862306a36Sopenharmony_ci long rate; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci rate = sp804_get_clock_rate(clk, name); 21162306a36Sopenharmony_ci if (rate < 0) 21262306a36Sopenharmony_ci return -EINVAL; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci common_clkevt = sp804_clkevt_get(base); 21562306a36Sopenharmony_ci common_clkevt->reload = DIV_ROUND_CLOSEST(rate, HZ); 21662306a36Sopenharmony_ci evt->name = name; 21762306a36Sopenharmony_ci evt->irq = irq; 21862306a36Sopenharmony_ci evt->cpumask = cpu_possible_mask; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci writel(0, common_clkevt->ctrl); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (request_irq(irq, sp804_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL, 22362306a36Sopenharmony_ci "timer", &sp804_clockevent)) 22462306a36Sopenharmony_ci pr_err("request_irq() failed\n"); 22562306a36Sopenharmony_ci clockevents_config_and_register(evt, rate, 0xf, 0xffffffff); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic void __init sp804_clkevt_init(struct sp804_timer *timer, void __iomem *base) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci int i; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci for (i = 0; i < NR_TIMERS; i++) { 23562306a36Sopenharmony_ci void __iomem *timer_base; 23662306a36Sopenharmony_ci struct sp804_clkevt *clkevt; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci timer_base = base + timer->timer_base[i]; 23962306a36Sopenharmony_ci clkevt = &sp804_clkevt[i]; 24062306a36Sopenharmony_ci clkevt->base = timer_base; 24162306a36Sopenharmony_ci clkevt->load = timer_base + timer->load; 24262306a36Sopenharmony_ci clkevt->load_h = timer_base + timer->load_h; 24362306a36Sopenharmony_ci clkevt->value = timer_base + timer->value; 24462306a36Sopenharmony_ci clkevt->value_h = timer_base + timer->value_h; 24562306a36Sopenharmony_ci clkevt->ctrl = timer_base + timer->ctrl; 24662306a36Sopenharmony_ci clkevt->intclr = timer_base + timer->intclr; 24762306a36Sopenharmony_ci clkevt->width = timer->width; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int __init sp804_of_init(struct device_node *np, struct sp804_timer *timer) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci static bool initialized = false; 25462306a36Sopenharmony_ci void __iomem *base; 25562306a36Sopenharmony_ci void __iomem *timer1_base; 25662306a36Sopenharmony_ci void __iomem *timer2_base; 25762306a36Sopenharmony_ci int irq, ret = -EINVAL; 25862306a36Sopenharmony_ci u32 irq_num = 0; 25962306a36Sopenharmony_ci struct clk *clk1, *clk2; 26062306a36Sopenharmony_ci const char *name = of_get_property(np, "compatible", NULL); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (initialized) { 26362306a36Sopenharmony_ci pr_debug("%pOF: skipping further SP804 timer device\n", np); 26462306a36Sopenharmony_ci return 0; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci base = of_iomap(np, 0); 26862306a36Sopenharmony_ci if (!base) 26962306a36Sopenharmony_ci return -ENXIO; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci timer1_base = base + timer->timer_base[0]; 27262306a36Sopenharmony_ci timer2_base = base + timer->timer_base[1]; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Ensure timers are disabled */ 27562306a36Sopenharmony_ci writel(0, timer1_base + timer->ctrl); 27662306a36Sopenharmony_ci writel(0, timer2_base + timer->ctrl); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci clk1 = of_clk_get(np, 0); 27962306a36Sopenharmony_ci if (IS_ERR(clk1)) 28062306a36Sopenharmony_ci clk1 = NULL; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* Get the 2nd clock if the timer has 3 timer clocks */ 28362306a36Sopenharmony_ci if (of_clk_get_parent_count(np) == 3) { 28462306a36Sopenharmony_ci clk2 = of_clk_get(np, 1); 28562306a36Sopenharmony_ci if (IS_ERR(clk2)) { 28662306a36Sopenharmony_ci pr_err("%pOFn clock not found: %d\n", np, 28762306a36Sopenharmony_ci (int)PTR_ERR(clk2)); 28862306a36Sopenharmony_ci clk2 = NULL; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci } else 29162306a36Sopenharmony_ci clk2 = clk1; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci irq = irq_of_parse_and_map(np, 0); 29462306a36Sopenharmony_ci if (irq <= 0) 29562306a36Sopenharmony_ci goto err; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci sp804_clkevt_init(timer, base); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci of_property_read_u32(np, "arm,sp804-has-irq", &irq_num); 30062306a36Sopenharmony_ci if (irq_num == 2) { 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci ret = sp804_clockevents_init(timer2_base, irq, clk2, name); 30362306a36Sopenharmony_ci if (ret) 30462306a36Sopenharmony_ci goto err; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci ret = sp804_clocksource_and_sched_clock_init(timer1_base, 30762306a36Sopenharmony_ci name, clk1, 1); 30862306a36Sopenharmony_ci if (ret) 30962306a36Sopenharmony_ci goto err; 31062306a36Sopenharmony_ci } else { 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci ret = sp804_clockevents_init(timer1_base, irq, clk1, name); 31362306a36Sopenharmony_ci if (ret) 31462306a36Sopenharmony_ci goto err; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci ret = sp804_clocksource_and_sched_clock_init(timer2_base, 31762306a36Sopenharmony_ci name, clk2, 1); 31862306a36Sopenharmony_ci if (ret) 31962306a36Sopenharmony_ci goto err; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci initialized = true; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_cierr: 32562306a36Sopenharmony_ci iounmap(base); 32662306a36Sopenharmony_ci return ret; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int __init arm_sp804_of_init(struct device_node *np) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci return sp804_of_init(np, &arm_sp804_timer); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ciTIMER_OF_DECLARE(sp804, "arm,sp804", arm_sp804_of_init); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int __init hisi_sp804_of_init(struct device_node *np) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci return sp804_of_init(np, &hisi_sp804_timer); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ciTIMER_OF_DECLARE(hisi_sp804, "hisilicon,sp804", hisi_sp804_of_init); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic int __init integrator_cp_of_init(struct device_node *np) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci static int init_count = 0; 34462306a36Sopenharmony_ci void __iomem *base; 34562306a36Sopenharmony_ci int irq, ret = -EINVAL; 34662306a36Sopenharmony_ci const char *name = of_get_property(np, "compatible", NULL); 34762306a36Sopenharmony_ci struct clk *clk; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci base = of_iomap(np, 0); 35062306a36Sopenharmony_ci if (!base) { 35162306a36Sopenharmony_ci pr_err("Failed to iomap\n"); 35262306a36Sopenharmony_ci return -ENXIO; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci clk = of_clk_get(np, 0); 35662306a36Sopenharmony_ci if (IS_ERR(clk)) { 35762306a36Sopenharmony_ci pr_err("Failed to get clock\n"); 35862306a36Sopenharmony_ci return PTR_ERR(clk); 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* Ensure timer is disabled */ 36262306a36Sopenharmony_ci writel(0, base + arm_sp804_timer.ctrl); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (init_count == 2 || !of_device_is_available(np)) 36562306a36Sopenharmony_ci goto err; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci sp804_clkevt_init(&arm_sp804_timer, base); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (!init_count) { 37062306a36Sopenharmony_ci ret = sp804_clocksource_and_sched_clock_init(base, 37162306a36Sopenharmony_ci name, clk, 0); 37262306a36Sopenharmony_ci if (ret) 37362306a36Sopenharmony_ci goto err; 37462306a36Sopenharmony_ci } else { 37562306a36Sopenharmony_ci irq = irq_of_parse_and_map(np, 0); 37662306a36Sopenharmony_ci if (irq <= 0) 37762306a36Sopenharmony_ci goto err; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ret = sp804_clockevents_init(base, irq, clk, name); 38062306a36Sopenharmony_ci if (ret) 38162306a36Sopenharmony_ci goto err; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci init_count++; 38562306a36Sopenharmony_ci return 0; 38662306a36Sopenharmony_cierr: 38762306a36Sopenharmony_ci iounmap(base); 38862306a36Sopenharmony_ci return ret; 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ciTIMER_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); 391