18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * TI DaVinci clocksource driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2019 Texas Instruments 68c2ecf20Sopenharmony_ci * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> 78c2ecf20Sopenharmony_ci * (with tiny parts adopted from code by Kevin Hilman <khilman@baylibre.com>) 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/clk.h> 118c2ecf20Sopenharmony_ci#include <linux/clockchips.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/of_address.h> 158c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 168c2ecf20Sopenharmony_ci#include <linux/sched_clock.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <clocksource/timer-davinci.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#undef pr_fmt 218c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "%s: " fmt, __func__ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_REG_TIM12 0x10 248c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_REG_TIM34 0x14 258c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_REG_PRD12 0x18 268c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_REG_PRD34 0x1c 278c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_REG_TCR 0x20 288c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_REG_TGCR 0x24 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_TIMMODE_MASK GENMASK(3, 2) 318c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_RESET_MASK GENMASK(1, 0) 328c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_TIMMODE_32BIT_UNCHAINED BIT(2) 338c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_UNRESET GENMASK(1, 0) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_ENAMODE_MASK GENMASK(1, 0) 368c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_ENAMODE_DISABLED 0x00 378c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_ENAMODE_ONESHOT BIT(0) 388c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_ENAMODE_PERIODIC BIT(1) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_ENAMODE_SHIFT_TIM12 6 418c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_ENAMODE_SHIFT_TIM34 22 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_MIN_DELTA 0x01 448c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_MAX_DELTA 0xfffffffe 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_CLKSRC_BITS 32 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define DAVINCI_TIMER_TGCR_DEFAULT \ 498c2ecf20Sopenharmony_ci (DAVINCI_TIMER_TIMMODE_32BIT_UNCHAINED | DAVINCI_TIMER_UNRESET) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct davinci_clockevent { 528c2ecf20Sopenharmony_ci struct clock_event_device dev; 538c2ecf20Sopenharmony_ci void __iomem *base; 548c2ecf20Sopenharmony_ci unsigned int cmp_off; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * This must be globally accessible by davinci_timer_read_sched_clock(), so 598c2ecf20Sopenharmony_ci * let's keep it here. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_cistatic struct { 628c2ecf20Sopenharmony_ci struct clocksource dev; 638c2ecf20Sopenharmony_ci void __iomem *base; 648c2ecf20Sopenharmony_ci unsigned int tim_off; 658c2ecf20Sopenharmony_ci} davinci_clocksource; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic struct davinci_clockevent * 688c2ecf20Sopenharmony_cito_davinci_clockevent(struct clock_event_device *clockevent) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci return container_of(clockevent, struct davinci_clockevent, dev); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic unsigned int 748c2ecf20Sopenharmony_cidavinci_clockevent_read(struct davinci_clockevent *clockevent, 758c2ecf20Sopenharmony_ci unsigned int reg) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci return readl_relaxed(clockevent->base + reg); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic void davinci_clockevent_write(struct davinci_clockevent *clockevent, 818c2ecf20Sopenharmony_ci unsigned int reg, unsigned int val) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci writel_relaxed(val, clockevent->base + reg); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic void davinci_tim12_shutdown(void __iomem *base) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci unsigned int tcr; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci tcr = DAVINCI_TIMER_ENAMODE_DISABLED << 918c2ecf20Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM12; 928c2ecf20Sopenharmony_ci /* 938c2ecf20Sopenharmony_ci * This function is only ever called if we're using both timer 948c2ecf20Sopenharmony_ci * halves. In this case TIM34 runs in periodic mode and we must 958c2ecf20Sopenharmony_ci * not modify it. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC << 988c2ecf20Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM34; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void davinci_tim12_set_oneshot(void __iomem *base) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci unsigned int tcr; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci tcr = DAVINCI_TIMER_ENAMODE_ONESHOT << 1088c2ecf20Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM12; 1098c2ecf20Sopenharmony_ci /* Same as above. */ 1108c2ecf20Sopenharmony_ci tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC << 1118c2ecf20Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM34; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int davinci_clockevent_shutdown(struct clock_event_device *dev) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct davinci_clockevent *clockevent; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci clockevent = to_davinci_clockevent(dev); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci davinci_tim12_shutdown(clockevent->base); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return 0; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int davinci_clockevent_set_oneshot(struct clock_event_device *dev) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct davinci_clockevent *clockevent = to_davinci_clockevent(dev); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci davinci_clockevent_write(clockevent, DAVINCI_TIMER_REG_TIM12, 0x0); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci davinci_tim12_set_oneshot(clockevent->base); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int 1398c2ecf20Sopenharmony_cidavinci_clockevent_set_next_event_std(unsigned long cycles, 1408c2ecf20Sopenharmony_ci struct clock_event_device *dev) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct davinci_clockevent *clockevent = to_davinci_clockevent(dev); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci davinci_clockevent_shutdown(dev); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci davinci_clockevent_write(clockevent, DAVINCI_TIMER_REG_TIM12, 0x0); 1478c2ecf20Sopenharmony_ci davinci_clockevent_write(clockevent, DAVINCI_TIMER_REG_PRD12, cycles); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci davinci_clockevent_set_oneshot(dev); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return 0; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic int 1558c2ecf20Sopenharmony_cidavinci_clockevent_set_next_event_cmp(unsigned long cycles, 1568c2ecf20Sopenharmony_ci struct clock_event_device *dev) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct davinci_clockevent *clockevent = to_davinci_clockevent(dev); 1598c2ecf20Sopenharmony_ci unsigned int curr_time; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci curr_time = davinci_clockevent_read(clockevent, 1628c2ecf20Sopenharmony_ci DAVINCI_TIMER_REG_TIM12); 1638c2ecf20Sopenharmony_ci davinci_clockevent_write(clockevent, 1648c2ecf20Sopenharmony_ci clockevent->cmp_off, curr_time + cycles); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return 0; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic irqreturn_t davinci_timer_irq_timer(int irq, void *data) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct davinci_clockevent *clockevent = data; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (!clockevent_state_oneshot(&clockevent->dev)) 1748c2ecf20Sopenharmony_ci davinci_tim12_shutdown(clockevent->base); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci clockevent->dev.event_handler(&clockevent->dev); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic u64 notrace davinci_timer_read_sched_clock(void) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci return readl_relaxed(davinci_clocksource.base + 1848c2ecf20Sopenharmony_ci davinci_clocksource.tim_off); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic u64 davinci_clocksource_read(struct clocksource *dev) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci return davinci_timer_read_sched_clock(); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* 1938c2ecf20Sopenharmony_ci * Standard use-case: we're using tim12 for clockevent and tim34 for 1948c2ecf20Sopenharmony_ci * clocksource. The default is making the former run in oneshot mode 1958c2ecf20Sopenharmony_ci * and the latter in periodic mode. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cistatic void davinci_clocksource_init_tim34(void __iomem *base) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci int tcr; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci tcr = DAVINCI_TIMER_ENAMODE_PERIODIC << 2028c2ecf20Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM34; 2038c2ecf20Sopenharmony_ci tcr |= DAVINCI_TIMER_ENAMODE_ONESHOT << 2048c2ecf20Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM12; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM34); 2078c2ecf20Sopenharmony_ci writel_relaxed(UINT_MAX, base + DAVINCI_TIMER_REG_PRD34); 2088c2ecf20Sopenharmony_ci writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/* 2128c2ecf20Sopenharmony_ci * Special use-case on da830: the DSP may use tim34. We're using tim12 for 2138c2ecf20Sopenharmony_ci * both clocksource and clockevent. We set tim12 to periodic and don't touch 2148c2ecf20Sopenharmony_ci * tim34. 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_cistatic void davinci_clocksource_init_tim12(void __iomem *base) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci unsigned int tcr; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci tcr = DAVINCI_TIMER_ENAMODE_PERIODIC << 2218c2ecf20Sopenharmony_ci DAVINCI_TIMER_ENAMODE_SHIFT_TIM12; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM12); 2248c2ecf20Sopenharmony_ci writel_relaxed(UINT_MAX, base + DAVINCI_TIMER_REG_PRD12); 2258c2ecf20Sopenharmony_ci writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic void davinci_timer_init(void __iomem *base) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci /* Set clock to internal mode and disable it. */ 2318c2ecf20Sopenharmony_ci writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TCR); 2328c2ecf20Sopenharmony_ci /* 2338c2ecf20Sopenharmony_ci * Reset both 32-bit timers, set no prescaler for timer 34, set the 2348c2ecf20Sopenharmony_ci * timer to dual 32-bit unchained mode, unreset both 32-bit timers. 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ci writel_relaxed(DAVINCI_TIMER_TGCR_DEFAULT, 2378c2ecf20Sopenharmony_ci base + DAVINCI_TIMER_REG_TGCR); 2388c2ecf20Sopenharmony_ci /* Init both counters to zero. */ 2398c2ecf20Sopenharmony_ci writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM12); 2408c2ecf20Sopenharmony_ci writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM34); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ciint __init davinci_timer_register(struct clk *clk, 2448c2ecf20Sopenharmony_ci const struct davinci_timer_cfg *timer_cfg) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct davinci_clockevent *clockevent; 2478c2ecf20Sopenharmony_ci unsigned int tick_rate; 2488c2ecf20Sopenharmony_ci void __iomem *base; 2498c2ecf20Sopenharmony_ci int rv; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci rv = clk_prepare_enable(clk); 2528c2ecf20Sopenharmony_ci if (rv) { 2538c2ecf20Sopenharmony_ci pr_err("Unable to prepare and enable the timer clock\n"); 2548c2ecf20Sopenharmony_ci return rv; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (!request_mem_region(timer_cfg->reg.start, 2588c2ecf20Sopenharmony_ci resource_size(&timer_cfg->reg), 2598c2ecf20Sopenharmony_ci "davinci-timer")) { 2608c2ecf20Sopenharmony_ci pr_err("Unable to request memory region\n"); 2618c2ecf20Sopenharmony_ci rv = -EBUSY; 2628c2ecf20Sopenharmony_ci goto exit_clk_disable; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci base = ioremap(timer_cfg->reg.start, resource_size(&timer_cfg->reg)); 2668c2ecf20Sopenharmony_ci if (!base) { 2678c2ecf20Sopenharmony_ci pr_err("Unable to map the register range\n"); 2688c2ecf20Sopenharmony_ci rv = -ENOMEM; 2698c2ecf20Sopenharmony_ci goto exit_mem_region; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci davinci_timer_init(base); 2738c2ecf20Sopenharmony_ci tick_rate = clk_get_rate(clk); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci clockevent = kzalloc(sizeof(*clockevent), GFP_KERNEL); 2768c2ecf20Sopenharmony_ci if (!clockevent) { 2778c2ecf20Sopenharmony_ci rv = -ENOMEM; 2788c2ecf20Sopenharmony_ci goto exit_iounmap_base; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci clockevent->dev.name = "tim12"; 2828c2ecf20Sopenharmony_ci clockevent->dev.features = CLOCK_EVT_FEAT_ONESHOT; 2838c2ecf20Sopenharmony_ci clockevent->dev.cpumask = cpumask_of(0); 2848c2ecf20Sopenharmony_ci clockevent->base = base; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (timer_cfg->cmp_off) { 2878c2ecf20Sopenharmony_ci clockevent->cmp_off = timer_cfg->cmp_off; 2888c2ecf20Sopenharmony_ci clockevent->dev.set_next_event = 2898c2ecf20Sopenharmony_ci davinci_clockevent_set_next_event_cmp; 2908c2ecf20Sopenharmony_ci } else { 2918c2ecf20Sopenharmony_ci clockevent->dev.set_next_event = 2928c2ecf20Sopenharmony_ci davinci_clockevent_set_next_event_std; 2938c2ecf20Sopenharmony_ci clockevent->dev.set_state_oneshot = 2948c2ecf20Sopenharmony_ci davinci_clockevent_set_oneshot; 2958c2ecf20Sopenharmony_ci clockevent->dev.set_state_shutdown = 2968c2ecf20Sopenharmony_ci davinci_clockevent_shutdown; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci rv = request_irq(timer_cfg->irq[DAVINCI_TIMER_CLOCKEVENT_IRQ].start, 3008c2ecf20Sopenharmony_ci davinci_timer_irq_timer, IRQF_TIMER, 3018c2ecf20Sopenharmony_ci "clockevent/tim12", clockevent); 3028c2ecf20Sopenharmony_ci if (rv) { 3038c2ecf20Sopenharmony_ci pr_err("Unable to request the clockevent interrupt\n"); 3048c2ecf20Sopenharmony_ci goto exit_free_clockevent; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci davinci_clocksource.dev.rating = 300; 3088c2ecf20Sopenharmony_ci davinci_clocksource.dev.read = davinci_clocksource_read; 3098c2ecf20Sopenharmony_ci davinci_clocksource.dev.mask = 3108c2ecf20Sopenharmony_ci CLOCKSOURCE_MASK(DAVINCI_TIMER_CLKSRC_BITS); 3118c2ecf20Sopenharmony_ci davinci_clocksource.dev.flags = CLOCK_SOURCE_IS_CONTINUOUS; 3128c2ecf20Sopenharmony_ci davinci_clocksource.base = base; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (timer_cfg->cmp_off) { 3158c2ecf20Sopenharmony_ci davinci_clocksource.dev.name = "tim12"; 3168c2ecf20Sopenharmony_ci davinci_clocksource.tim_off = DAVINCI_TIMER_REG_TIM12; 3178c2ecf20Sopenharmony_ci davinci_clocksource_init_tim12(base); 3188c2ecf20Sopenharmony_ci } else { 3198c2ecf20Sopenharmony_ci davinci_clocksource.dev.name = "tim34"; 3208c2ecf20Sopenharmony_ci davinci_clocksource.tim_off = DAVINCI_TIMER_REG_TIM34; 3218c2ecf20Sopenharmony_ci davinci_clocksource_init_tim34(base); 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci clockevents_config_and_register(&clockevent->dev, tick_rate, 3258c2ecf20Sopenharmony_ci DAVINCI_TIMER_MIN_DELTA, 3268c2ecf20Sopenharmony_ci DAVINCI_TIMER_MAX_DELTA); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci rv = clocksource_register_hz(&davinci_clocksource.dev, tick_rate); 3298c2ecf20Sopenharmony_ci if (rv) { 3308c2ecf20Sopenharmony_ci pr_err("Unable to register clocksource\n"); 3318c2ecf20Sopenharmony_ci goto exit_free_irq; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci sched_clock_register(davinci_timer_read_sched_clock, 3358c2ecf20Sopenharmony_ci DAVINCI_TIMER_CLKSRC_BITS, tick_rate); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ciexit_free_irq: 3408c2ecf20Sopenharmony_ci free_irq(timer_cfg->irq[DAVINCI_TIMER_CLOCKEVENT_IRQ].start, 3418c2ecf20Sopenharmony_ci clockevent); 3428c2ecf20Sopenharmony_ciexit_free_clockevent: 3438c2ecf20Sopenharmony_ci kfree(clockevent); 3448c2ecf20Sopenharmony_ciexit_iounmap_base: 3458c2ecf20Sopenharmony_ci iounmap(base); 3468c2ecf20Sopenharmony_ciexit_mem_region: 3478c2ecf20Sopenharmony_ci release_mem_region(timer_cfg->reg.start, 3488c2ecf20Sopenharmony_ci resource_size(&timer_cfg->reg)); 3498c2ecf20Sopenharmony_ciexit_clk_disable: 3508c2ecf20Sopenharmony_ci clk_disable_unprepare(clk); 3518c2ecf20Sopenharmony_ci return rv; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int __init of_davinci_timer_register(struct device_node *np) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct davinci_timer_cfg timer_cfg = { }; 3578c2ecf20Sopenharmony_ci struct clk *clk; 3588c2ecf20Sopenharmony_ci int rv; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci rv = of_address_to_resource(np, 0, &timer_cfg.reg); 3618c2ecf20Sopenharmony_ci if (rv) { 3628c2ecf20Sopenharmony_ci pr_err("Unable to get the register range for timer\n"); 3638c2ecf20Sopenharmony_ci return rv; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci rv = of_irq_to_resource_table(np, timer_cfg.irq, 3678c2ecf20Sopenharmony_ci DAVINCI_TIMER_NUM_IRQS); 3688c2ecf20Sopenharmony_ci if (rv != DAVINCI_TIMER_NUM_IRQS) { 3698c2ecf20Sopenharmony_ci pr_err("Unable to get the interrupts for timer\n"); 3708c2ecf20Sopenharmony_ci return rv; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci clk = of_clk_get(np, 0); 3748c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 3758c2ecf20Sopenharmony_ci pr_err("Unable to get the timer clock\n"); 3768c2ecf20Sopenharmony_ci return PTR_ERR(clk); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci rv = davinci_timer_register(clk, &timer_cfg); 3808c2ecf20Sopenharmony_ci if (rv) 3818c2ecf20Sopenharmony_ci clk_put(clk); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return rv; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(davinci_timer, "ti,da830-timer", of_davinci_timer_register); 386