162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * TI DaVinci clocksource driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2019 Texas Instruments 662306a36Sopenharmony_ci * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> 762306a36Sopenharmony_ci * (with tiny parts adopted from code by Kevin Hilman <khilman@baylibre.com>) 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define pr_fmt(fmt) "%s: " fmt, __func__ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/clk.h> 1362306a36Sopenharmony_ci#include <linux/clockchips.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/of_address.h> 1762306a36Sopenharmony_ci#include <linux/of_irq.h> 1862306a36Sopenharmony_ci#include <linux/sched_clock.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <clocksource/timer-davinci.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define DAVINCI_TIMER_REG_TIM12 0x10 2362306a36Sopenharmony_ci#define DAVINCI_TIMER_REG_TIM34 0x14 2462306a36Sopenharmony_ci#define DAVINCI_TIMER_REG_PRD12 0x18 2562306a36Sopenharmony_ci#define DAVINCI_TIMER_REG_PRD34 0x1c 2662306a36Sopenharmony_ci#define DAVINCI_TIMER_REG_TCR 0x20 2762306a36Sopenharmony_ci#define DAVINCI_TIMER_REG_TGCR 0x24 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define DAVINCI_TIMER_TIMMODE_MASK GENMASK(3, 2) 3062306a36Sopenharmony_ci#define DAVINCI_TIMER_RESET_MASK GENMASK(1, 0) 3162306a36Sopenharmony_ci#define DAVINCI_TIMER_TIMMODE_32BIT_UNCHAINED BIT(2) 3262306a36Sopenharmony_ci#define DAVINCI_TIMER_UNRESET GENMASK(1, 0) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define DAVINCI_TIMER_ENAMODE_MASK GENMASK(1, 0) 3562306a36Sopenharmony_ci#define DAVINCI_TIMER_ENAMODE_DISABLED 0x00 3662306a36Sopenharmony_ci#define DAVINCI_TIMER_ENAMODE_ONESHOT BIT(0) 3762306a36Sopenharmony_ci#define DAVINCI_TIMER_ENAMODE_PERIODIC BIT(1) 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define DAVINCI_TIMER_ENAMODE_SHIFT_TIM12 6 4062306a36Sopenharmony_ci#define DAVINCI_TIMER_ENAMODE_SHIFT_TIM34 22 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define DAVINCI_TIMER_MIN_DELTA 0x01 4362306a36Sopenharmony_ci#define DAVINCI_TIMER_MAX_DELTA 0xfffffffe 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define DAVINCI_TIMER_CLKSRC_BITS 32 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define DAVINCI_TIMER_TGCR_DEFAULT \ 4862306a36Sopenharmony_ci (DAVINCI_TIMER_TIMMODE_32BIT_UNCHAINED | DAVINCI_TIMER_UNRESET) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistruct davinci_clockevent { 5162306a36Sopenharmony_ci struct clock_event_device dev; 5262306a36Sopenharmony_ci void __iomem *base; 5362306a36Sopenharmony_ci unsigned int cmp_off; 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * This must be globally accessible by davinci_timer_read_sched_clock(), so 5862306a36Sopenharmony_ci * let's keep it here. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistatic struct { 6162306a36Sopenharmony_ci struct clocksource dev; 6262306a36Sopenharmony_ci void __iomem *base; 6362306a36Sopenharmony_ci unsigned int tim_off; 6462306a36Sopenharmony_ci} davinci_clocksource; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic struct davinci_clockevent * 6762306a36Sopenharmony_cito_davinci_clockevent(struct clock_event_device *clockevent) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci return container_of(clockevent, struct davinci_clockevent, dev); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic unsigned int 7362306a36Sopenharmony_cidavinci_clockevent_read(struct davinci_clockevent *clockevent, 7462306a36Sopenharmony_ci unsigned int reg) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci return readl_relaxed(clockevent->base + reg); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void davinci_clockevent_write(struct davinci_clockevent *clockevent, 8062306a36Sopenharmony_ci unsigned int reg, unsigned int val) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci writel_relaxed(val, clockevent->base + reg); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic void davinci_tim12_shutdown(void __iomem *base) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci unsigned int tcr; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci tcr = DAVINCI_TIMER_ENAMODE_DISABLED << 9062306a36Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM12; 9162306a36Sopenharmony_ci /* 9262306a36Sopenharmony_ci * This function is only ever called if we're using both timer 9362306a36Sopenharmony_ci * halves. In this case TIM34 runs in periodic mode and we must 9462306a36Sopenharmony_ci * not modify it. 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC << 9762306a36Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM34; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic void davinci_tim12_set_oneshot(void __iomem *base) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci unsigned int tcr; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci tcr = DAVINCI_TIMER_ENAMODE_ONESHOT << 10762306a36Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM12; 10862306a36Sopenharmony_ci /* Same as above. */ 10962306a36Sopenharmony_ci tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC << 11062306a36Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM34; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic int davinci_clockevent_shutdown(struct clock_event_device *dev) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci struct davinci_clockevent *clockevent; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci clockevent = to_davinci_clockevent(dev); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci davinci_tim12_shutdown(clockevent->base); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return 0; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int davinci_clockevent_set_oneshot(struct clock_event_device *dev) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct davinci_clockevent *clockevent = to_davinci_clockevent(dev); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci davinci_clockevent_write(clockevent, DAVINCI_TIMER_REG_TIM12, 0x0); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci davinci_tim12_set_oneshot(clockevent->base); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci return 0; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int 13862306a36Sopenharmony_cidavinci_clockevent_set_next_event_std(unsigned long cycles, 13962306a36Sopenharmony_ci struct clock_event_device *dev) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct davinci_clockevent *clockevent = to_davinci_clockevent(dev); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci davinci_clockevent_shutdown(dev); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci davinci_clockevent_write(clockevent, DAVINCI_TIMER_REG_TIM12, 0x0); 14662306a36Sopenharmony_ci davinci_clockevent_write(clockevent, DAVINCI_TIMER_REG_PRD12, cycles); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci davinci_clockevent_set_oneshot(dev); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return 0; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic int 15462306a36Sopenharmony_cidavinci_clockevent_set_next_event_cmp(unsigned long cycles, 15562306a36Sopenharmony_ci struct clock_event_device *dev) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct davinci_clockevent *clockevent = to_davinci_clockevent(dev); 15862306a36Sopenharmony_ci unsigned int curr_time; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci curr_time = davinci_clockevent_read(clockevent, 16162306a36Sopenharmony_ci DAVINCI_TIMER_REG_TIM12); 16262306a36Sopenharmony_ci davinci_clockevent_write(clockevent, 16362306a36Sopenharmony_ci clockevent->cmp_off, curr_time + cycles); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return 0; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic irqreturn_t davinci_timer_irq_timer(int irq, void *data) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct davinci_clockevent *clockevent = data; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (!clockevent_state_oneshot(&clockevent->dev)) 17362306a36Sopenharmony_ci davinci_tim12_shutdown(clockevent->base); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci clockevent->dev.event_handler(&clockevent->dev); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return IRQ_HANDLED; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic u64 notrace davinci_timer_read_sched_clock(void) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci return readl_relaxed(davinci_clocksource.base + 18362306a36Sopenharmony_ci davinci_clocksource.tim_off); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic u64 davinci_clocksource_read(struct clocksource *dev) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci return davinci_timer_read_sched_clock(); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci/* 19262306a36Sopenharmony_ci * Standard use-case: we're using tim12 for clockevent and tim34 for 19362306a36Sopenharmony_ci * clocksource. The default is making the former run in oneshot mode 19462306a36Sopenharmony_ci * and the latter in periodic mode. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_cistatic void davinci_clocksource_init_tim34(void __iomem *base) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci int tcr; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci tcr = DAVINCI_TIMER_ENAMODE_PERIODIC << 20162306a36Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM34; 20262306a36Sopenharmony_ci tcr |= DAVINCI_TIMER_ENAMODE_ONESHOT << 20362306a36Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM12; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM34); 20662306a36Sopenharmony_ci writel_relaxed(UINT_MAX, base + DAVINCI_TIMER_REG_PRD34); 20762306a36Sopenharmony_ci writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/* 21162306a36Sopenharmony_ci * Special use-case on da830: the DSP may use tim34. We're using tim12 for 21262306a36Sopenharmony_ci * both clocksource and clockevent. We set tim12 to periodic and don't touch 21362306a36Sopenharmony_ci * tim34. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_cistatic void davinci_clocksource_init_tim12(void __iomem *base) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci unsigned int tcr; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci tcr = DAVINCI_TIMER_ENAMODE_PERIODIC << 22062306a36Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM12; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM12); 22362306a36Sopenharmony_ci writel_relaxed(UINT_MAX, base + DAVINCI_TIMER_REG_PRD12); 22462306a36Sopenharmony_ci writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic void davinci_timer_init(void __iomem *base) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci /* Set clock to internal mode and disable it. */ 23062306a36Sopenharmony_ci writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TCR); 23162306a36Sopenharmony_ci /* 23262306a36Sopenharmony_ci * Reset both 32-bit timers, set no prescaler for timer 34, set the 23362306a36Sopenharmony_ci * timer to dual 32-bit unchained mode, unreset both 32-bit timers. 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_ci writel_relaxed(DAVINCI_TIMER_TGCR_DEFAULT, 23662306a36Sopenharmony_ci base + DAVINCI_TIMER_REG_TGCR); 23762306a36Sopenharmony_ci /* Init both counters to zero. */ 23862306a36Sopenharmony_ci writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM12); 23962306a36Sopenharmony_ci writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM34); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ciint __init davinci_timer_register(struct clk *clk, 24362306a36Sopenharmony_ci const struct davinci_timer_cfg *timer_cfg) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct davinci_clockevent *clockevent; 24662306a36Sopenharmony_ci unsigned int tick_rate; 24762306a36Sopenharmony_ci void __iomem *base; 24862306a36Sopenharmony_ci int rv; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci rv = clk_prepare_enable(clk); 25162306a36Sopenharmony_ci if (rv) { 25262306a36Sopenharmony_ci pr_err("Unable to prepare and enable the timer clock\n"); 25362306a36Sopenharmony_ci return rv; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (!request_mem_region(timer_cfg->reg.start, 25762306a36Sopenharmony_ci resource_size(&timer_cfg->reg), 25862306a36Sopenharmony_ci "davinci-timer")) { 25962306a36Sopenharmony_ci pr_err("Unable to request memory region\n"); 26062306a36Sopenharmony_ci rv = -EBUSY; 26162306a36Sopenharmony_ci goto exit_clk_disable; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci base = ioremap(timer_cfg->reg.start, resource_size(&timer_cfg->reg)); 26562306a36Sopenharmony_ci if (!base) { 26662306a36Sopenharmony_ci pr_err("Unable to map the register range\n"); 26762306a36Sopenharmony_ci rv = -ENOMEM; 26862306a36Sopenharmony_ci goto exit_mem_region; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci davinci_timer_init(base); 27262306a36Sopenharmony_ci tick_rate = clk_get_rate(clk); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci clockevent = kzalloc(sizeof(*clockevent), GFP_KERNEL); 27562306a36Sopenharmony_ci if (!clockevent) { 27662306a36Sopenharmony_ci rv = -ENOMEM; 27762306a36Sopenharmony_ci goto exit_iounmap_base; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci clockevent->dev.name = "tim12"; 28162306a36Sopenharmony_ci clockevent->dev.features = CLOCK_EVT_FEAT_ONESHOT; 28262306a36Sopenharmony_ci clockevent->dev.cpumask = cpumask_of(0); 28362306a36Sopenharmony_ci clockevent->base = base; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (timer_cfg->cmp_off) { 28662306a36Sopenharmony_ci clockevent->cmp_off = timer_cfg->cmp_off; 28762306a36Sopenharmony_ci clockevent->dev.set_next_event = 28862306a36Sopenharmony_ci davinci_clockevent_set_next_event_cmp; 28962306a36Sopenharmony_ci } else { 29062306a36Sopenharmony_ci clockevent->dev.set_next_event = 29162306a36Sopenharmony_ci davinci_clockevent_set_next_event_std; 29262306a36Sopenharmony_ci clockevent->dev.set_state_oneshot = 29362306a36Sopenharmony_ci davinci_clockevent_set_oneshot; 29462306a36Sopenharmony_ci clockevent->dev.set_state_shutdown = 29562306a36Sopenharmony_ci davinci_clockevent_shutdown; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci rv = request_irq(timer_cfg->irq[DAVINCI_TIMER_CLOCKEVENT_IRQ].start, 29962306a36Sopenharmony_ci davinci_timer_irq_timer, IRQF_TIMER, 30062306a36Sopenharmony_ci "clockevent/tim12", clockevent); 30162306a36Sopenharmony_ci if (rv) { 30262306a36Sopenharmony_ci pr_err("Unable to request the clockevent interrupt\n"); 30362306a36Sopenharmony_ci goto exit_free_clockevent; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci davinci_clocksource.dev.rating = 300; 30762306a36Sopenharmony_ci davinci_clocksource.dev.read = davinci_clocksource_read; 30862306a36Sopenharmony_ci davinci_clocksource.dev.mask = 30962306a36Sopenharmony_ci CLOCKSOURCE_MASK(DAVINCI_TIMER_CLKSRC_BITS); 31062306a36Sopenharmony_ci davinci_clocksource.dev.flags = CLOCK_SOURCE_IS_CONTINUOUS; 31162306a36Sopenharmony_ci davinci_clocksource.base = base; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (timer_cfg->cmp_off) { 31462306a36Sopenharmony_ci davinci_clocksource.dev.name = "tim12"; 31562306a36Sopenharmony_ci davinci_clocksource.tim_off = DAVINCI_TIMER_REG_TIM12; 31662306a36Sopenharmony_ci davinci_clocksource_init_tim12(base); 31762306a36Sopenharmony_ci } else { 31862306a36Sopenharmony_ci davinci_clocksource.dev.name = "tim34"; 31962306a36Sopenharmony_ci davinci_clocksource.tim_off = DAVINCI_TIMER_REG_TIM34; 32062306a36Sopenharmony_ci davinci_clocksource_init_tim34(base); 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci clockevents_config_and_register(&clockevent->dev, tick_rate, 32462306a36Sopenharmony_ci DAVINCI_TIMER_MIN_DELTA, 32562306a36Sopenharmony_ci DAVINCI_TIMER_MAX_DELTA); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci rv = clocksource_register_hz(&davinci_clocksource.dev, tick_rate); 32862306a36Sopenharmony_ci if (rv) { 32962306a36Sopenharmony_ci pr_err("Unable to register clocksource\n"); 33062306a36Sopenharmony_ci goto exit_free_irq; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci sched_clock_register(davinci_timer_read_sched_clock, 33462306a36Sopenharmony_ci DAVINCI_TIMER_CLKSRC_BITS, tick_rate); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return 0; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ciexit_free_irq: 33962306a36Sopenharmony_ci free_irq(timer_cfg->irq[DAVINCI_TIMER_CLOCKEVENT_IRQ].start, 34062306a36Sopenharmony_ci clockevent); 34162306a36Sopenharmony_ciexit_free_clockevent: 34262306a36Sopenharmony_ci kfree(clockevent); 34362306a36Sopenharmony_ciexit_iounmap_base: 34462306a36Sopenharmony_ci iounmap(base); 34562306a36Sopenharmony_ciexit_mem_region: 34662306a36Sopenharmony_ci release_mem_region(timer_cfg->reg.start, 34762306a36Sopenharmony_ci resource_size(&timer_cfg->reg)); 34862306a36Sopenharmony_ciexit_clk_disable: 34962306a36Sopenharmony_ci clk_disable_unprepare(clk); 35062306a36Sopenharmony_ci return rv; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic int __init of_davinci_timer_register(struct device_node *np) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct davinci_timer_cfg timer_cfg = { }; 35662306a36Sopenharmony_ci struct clk *clk; 35762306a36Sopenharmony_ci int rv; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci rv = of_address_to_resource(np, 0, &timer_cfg.reg); 36062306a36Sopenharmony_ci if (rv) { 36162306a36Sopenharmony_ci pr_err("Unable to get the register range for timer\n"); 36262306a36Sopenharmony_ci return rv; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci rv = of_irq_to_resource_table(np, timer_cfg.irq, 36662306a36Sopenharmony_ci DAVINCI_TIMER_NUM_IRQS); 36762306a36Sopenharmony_ci if (rv != DAVINCI_TIMER_NUM_IRQS) { 36862306a36Sopenharmony_ci pr_err("Unable to get the interrupts for timer\n"); 36962306a36Sopenharmony_ci return rv; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci clk = of_clk_get(np, 0); 37362306a36Sopenharmony_ci if (IS_ERR(clk)) { 37462306a36Sopenharmony_ci pr_err("Unable to get the timer clock\n"); 37562306a36Sopenharmony_ci return PTR_ERR(clk); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci rv = davinci_timer_register(clk, &timer_cfg); 37962306a36Sopenharmony_ci if (rv) 38062306a36Sopenharmony_ci clk_put(clk); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return rv; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ciTIMER_OF_DECLARE(davinci_timer, "ti,da830-timer", of_davinci_timer_register); 385