162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Marvell Armada 370/XP SoC timer handling. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 Marvell 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Lior Amsalem <alior@marvell.com> 862306a36Sopenharmony_ci * Gregory CLEMENT <gregory.clement@free-electrons.com> 962306a36Sopenharmony_ci * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Timer 0 is used as free-running clocksource, while timer 1 is 1262306a36Sopenharmony_ci * used as clock_event_device. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * --- 1562306a36Sopenharmony_ci * Clocksource driver for Armada 370 and Armada XP SoC. 1662306a36Sopenharmony_ci * This driver implements one compatible string for each SoC, given 1762306a36Sopenharmony_ci * each has its own characteristics: 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * * Armada 370 has no 25 MHz fixed timer. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * * Armada XP cannot work properly without such 25 MHz fixed timer as 2262306a36Sopenharmony_ci * doing otherwise leads to using a clocksource whose frequency varies 2362306a36Sopenharmony_ci * when doing cpufreq frequency changes. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * See Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <linux/init.h> 2962306a36Sopenharmony_ci#include <linux/platform_device.h> 3062306a36Sopenharmony_ci#include <linux/kernel.h> 3162306a36Sopenharmony_ci#include <linux/clk.h> 3262306a36Sopenharmony_ci#include <linux/cpu.h> 3362306a36Sopenharmony_ci#include <linux/timer.h> 3462306a36Sopenharmony_ci#include <linux/clockchips.h> 3562306a36Sopenharmony_ci#include <linux/interrupt.h> 3662306a36Sopenharmony_ci#include <linux/of.h> 3762306a36Sopenharmony_ci#include <linux/of_irq.h> 3862306a36Sopenharmony_ci#include <linux/of_address.h> 3962306a36Sopenharmony_ci#include <linux/irq.h> 4062306a36Sopenharmony_ci#include <linux/module.h> 4162306a36Sopenharmony_ci#include <linux/sched_clock.h> 4262306a36Sopenharmony_ci#include <linux/percpu.h> 4362306a36Sopenharmony_ci#include <linux/syscore_ops.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include <asm/delay.h> 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * Timer block registers. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_ci#define TIMER_CTRL_OFF 0x0000 5162306a36Sopenharmony_ci#define TIMER0_EN BIT(0) 5262306a36Sopenharmony_ci#define TIMER0_RELOAD_EN BIT(1) 5362306a36Sopenharmony_ci#define TIMER0_25MHZ BIT(11) 5462306a36Sopenharmony_ci#define TIMER0_DIV(div) ((div) << 19) 5562306a36Sopenharmony_ci#define TIMER1_EN BIT(2) 5662306a36Sopenharmony_ci#define TIMER1_RELOAD_EN BIT(3) 5762306a36Sopenharmony_ci#define TIMER1_25MHZ BIT(12) 5862306a36Sopenharmony_ci#define TIMER1_DIV(div) ((div) << 22) 5962306a36Sopenharmony_ci#define TIMER_EVENTS_STATUS 0x0004 6062306a36Sopenharmony_ci#define TIMER0_CLR_MASK (~0x1) 6162306a36Sopenharmony_ci#define TIMER1_CLR_MASK (~0x100) 6262306a36Sopenharmony_ci#define TIMER0_RELOAD_OFF 0x0010 6362306a36Sopenharmony_ci#define TIMER0_VAL_OFF 0x0014 6462306a36Sopenharmony_ci#define TIMER1_RELOAD_OFF 0x0018 6562306a36Sopenharmony_ci#define TIMER1_VAL_OFF 0x001c 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define LCL_TIMER_EVENTS_STATUS 0x0028 6862306a36Sopenharmony_ci/* Global timers are connected to the coherency fabric clock, and the 6962306a36Sopenharmony_ci below divider reduces their incrementing frequency. */ 7062306a36Sopenharmony_ci#define TIMER_DIVIDER_SHIFT 5 7162306a36Sopenharmony_ci#define TIMER_DIVIDER (1 << TIMER_DIVIDER_SHIFT) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* 7462306a36Sopenharmony_ci * SoC-specific data. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_cistatic void __iomem *timer_base, *local_base; 7762306a36Sopenharmony_cistatic unsigned int timer_clk; 7862306a36Sopenharmony_cistatic bool timer25Mhz = true; 7962306a36Sopenharmony_cistatic u32 enable_mask; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * Number of timer ticks per jiffy. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_cistatic u32 ticks_per_jiffy; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic struct clock_event_device __percpu *armada_370_xp_evt; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic void local_timer_ctrl_clrset(u32 clr, u32 set) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set, 9162306a36Sopenharmony_ci local_base + TIMER_CTRL_OFF); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic u64 notrace armada_370_xp_read_sched_clock(void) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci return ~readl(timer_base + TIMER0_VAL_OFF); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* 10062306a36Sopenharmony_ci * Clockevent handling. 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_cistatic int 10362306a36Sopenharmony_ciarmada_370_xp_clkevt_next_event(unsigned long delta, 10462306a36Sopenharmony_ci struct clock_event_device *dev) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci /* 10762306a36Sopenharmony_ci * Clear clockevent timer interrupt. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* 11262306a36Sopenharmony_ci * Setup new clockevent timer value. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ci writel(delta, local_base + TIMER0_VAL_OFF); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* 11762306a36Sopenharmony_ci * Enable the timer. 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci local_timer_ctrl_clrset(TIMER0_RELOAD_EN, enable_mask); 12062306a36Sopenharmony_ci return 0; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int armada_370_xp_clkevt_shutdown(struct clock_event_device *evt) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci /* 12662306a36Sopenharmony_ci * Disable timer. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci local_timer_ctrl_clrset(TIMER0_EN, 0); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* 13162306a36Sopenharmony_ci * ACK pending timer interrupt. 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); 13462306a36Sopenharmony_ci return 0; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int armada_370_xp_clkevt_set_periodic(struct clock_event_device *evt) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci /* 14062306a36Sopenharmony_ci * Setup timer to fire at 1/HZ intervals. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF); 14362306a36Sopenharmony_ci writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* 14662306a36Sopenharmony_ci * Enable timer. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | enable_mask); 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int armada_370_xp_clkevt_irq; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci /* 15762306a36Sopenharmony_ci * ACK timer interrupt and call event handler. 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ci struct clock_event_device *evt = dev_id; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); 16262306a36Sopenharmony_ci evt->event_handler(evt); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return IRQ_HANDLED; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* 16862306a36Sopenharmony_ci * Setup the local clock events for a CPU. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_cistatic int armada_370_xp_timer_starting_cpu(unsigned int cpu) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct clock_event_device *evt = per_cpu_ptr(armada_370_xp_evt, cpu); 17362306a36Sopenharmony_ci u32 clr = 0, set = 0; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (timer25Mhz) 17662306a36Sopenharmony_ci set = TIMER0_25MHZ; 17762306a36Sopenharmony_ci else 17862306a36Sopenharmony_ci clr = TIMER0_25MHZ; 17962306a36Sopenharmony_ci local_timer_ctrl_clrset(clr, set); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci evt->name = "armada_370_xp_per_cpu_tick"; 18262306a36Sopenharmony_ci evt->features = CLOCK_EVT_FEAT_ONESHOT | 18362306a36Sopenharmony_ci CLOCK_EVT_FEAT_PERIODIC; 18462306a36Sopenharmony_ci evt->shift = 32; 18562306a36Sopenharmony_ci evt->rating = 300; 18662306a36Sopenharmony_ci evt->set_next_event = armada_370_xp_clkevt_next_event; 18762306a36Sopenharmony_ci evt->set_state_shutdown = armada_370_xp_clkevt_shutdown; 18862306a36Sopenharmony_ci evt->set_state_periodic = armada_370_xp_clkevt_set_periodic; 18962306a36Sopenharmony_ci evt->set_state_oneshot = armada_370_xp_clkevt_shutdown; 19062306a36Sopenharmony_ci evt->tick_resume = armada_370_xp_clkevt_shutdown; 19162306a36Sopenharmony_ci evt->irq = armada_370_xp_clkevt_irq; 19262306a36Sopenharmony_ci evt->cpumask = cpumask_of(cpu); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe); 19562306a36Sopenharmony_ci enable_percpu_irq(evt->irq, 0); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic int armada_370_xp_timer_dying_cpu(unsigned int cpu) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct clock_event_device *evt = per_cpu_ptr(armada_370_xp_evt, cpu); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci evt->set_state_shutdown(evt); 20562306a36Sopenharmony_ci disable_percpu_irq(evt->irq); 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic u32 timer0_ctrl_reg, timer0_local_ctrl_reg; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic int armada_370_xp_timer_suspend(void) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci timer0_ctrl_reg = readl(timer_base + TIMER_CTRL_OFF); 21462306a36Sopenharmony_ci timer0_local_ctrl_reg = readl(local_base + TIMER_CTRL_OFF); 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic void armada_370_xp_timer_resume(void) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci writel(0xffffffff, timer_base + TIMER0_VAL_OFF); 22162306a36Sopenharmony_ci writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); 22262306a36Sopenharmony_ci writel(timer0_ctrl_reg, timer_base + TIMER_CTRL_OFF); 22362306a36Sopenharmony_ci writel(timer0_local_ctrl_reg, local_base + TIMER_CTRL_OFF); 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic struct syscore_ops armada_370_xp_timer_syscore_ops = { 22762306a36Sopenharmony_ci .suspend = armada_370_xp_timer_suspend, 22862306a36Sopenharmony_ci .resume = armada_370_xp_timer_resume, 22962306a36Sopenharmony_ci}; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic unsigned long armada_370_delay_timer_read(void) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci return ~readl(timer_base + TIMER0_VAL_OFF); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic struct delay_timer armada_370_delay_timer = { 23762306a36Sopenharmony_ci .read_current_timer = armada_370_delay_timer_read, 23862306a36Sopenharmony_ci}; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic int __init armada_370_xp_timer_common_init(struct device_node *np) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci u32 clr = 0, set = 0; 24362306a36Sopenharmony_ci int res; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci timer_base = of_iomap(np, 0); 24662306a36Sopenharmony_ci if (!timer_base) { 24762306a36Sopenharmony_ci pr_err("Failed to iomap\n"); 24862306a36Sopenharmony_ci return -ENXIO; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci local_base = of_iomap(np, 1); 25262306a36Sopenharmony_ci if (!local_base) { 25362306a36Sopenharmony_ci pr_err("Failed to iomap\n"); 25462306a36Sopenharmony_ci return -ENXIO; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (timer25Mhz) { 25862306a36Sopenharmony_ci set = TIMER0_25MHZ; 25962306a36Sopenharmony_ci enable_mask = TIMER0_EN; 26062306a36Sopenharmony_ci } else { 26162306a36Sopenharmony_ci clr = TIMER0_25MHZ; 26262306a36Sopenharmony_ci enable_mask = TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT); 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci atomic_io_modify(timer_base + TIMER_CTRL_OFF, clr | set, set); 26562306a36Sopenharmony_ci local_timer_ctrl_clrset(clr, set); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* 26862306a36Sopenharmony_ci * We use timer 0 as clocksource, and private(local) timer 0 26962306a36Sopenharmony_ci * for clockevents 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci armada_370_xp_clkevt_irq = irq_of_parse_and_map(np, 4); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci ticks_per_jiffy = (timer_clk + HZ / 2) / HZ; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* 27662306a36Sopenharmony_ci * Setup free-running clocksource timer (interrupts 27762306a36Sopenharmony_ci * disabled). 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_ci writel(0xffffffff, timer_base + TIMER0_VAL_OFF); 28062306a36Sopenharmony_ci writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci atomic_io_modify(timer_base + TIMER_CTRL_OFF, 28362306a36Sopenharmony_ci TIMER0_RELOAD_EN | enable_mask, 28462306a36Sopenharmony_ci TIMER0_RELOAD_EN | enable_mask); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci armada_370_delay_timer.freq = timer_clk; 28762306a36Sopenharmony_ci register_current_timer_delay(&armada_370_delay_timer); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* 29062306a36Sopenharmony_ci * Set scale and timer for sched_clock. 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_ci sched_clock_register(armada_370_xp_read_sched_clock, 32, timer_clk); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci res = clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, 29562306a36Sopenharmony_ci "armada_370_xp_clocksource", 29662306a36Sopenharmony_ci timer_clk, 300, 32, clocksource_mmio_readl_down); 29762306a36Sopenharmony_ci if (res) { 29862306a36Sopenharmony_ci pr_err("Failed to initialize clocksource mmio\n"); 29962306a36Sopenharmony_ci return res; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci armada_370_xp_evt = alloc_percpu(struct clock_event_device); 30362306a36Sopenharmony_ci if (!armada_370_xp_evt) 30462306a36Sopenharmony_ci return -ENOMEM; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* 30762306a36Sopenharmony_ci * Setup clockevent timer (interrupt-driven). 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_ci res = request_percpu_irq(armada_370_xp_clkevt_irq, 31062306a36Sopenharmony_ci armada_370_xp_timer_interrupt, 31162306a36Sopenharmony_ci "armada_370_xp_per_cpu_tick", 31262306a36Sopenharmony_ci armada_370_xp_evt); 31362306a36Sopenharmony_ci /* Immediately configure the timer on the boot CPU */ 31462306a36Sopenharmony_ci if (res) { 31562306a36Sopenharmony_ci pr_err("Failed to request percpu irq\n"); 31662306a36Sopenharmony_ci return res; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci res = cpuhp_setup_state(CPUHP_AP_ARMADA_TIMER_STARTING, 32062306a36Sopenharmony_ci "clockevents/armada:starting", 32162306a36Sopenharmony_ci armada_370_xp_timer_starting_cpu, 32262306a36Sopenharmony_ci armada_370_xp_timer_dying_cpu); 32362306a36Sopenharmony_ci if (res) { 32462306a36Sopenharmony_ci pr_err("Failed to setup hotplug state and timer\n"); 32562306a36Sopenharmony_ci return res; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci register_syscore_ops(&armada_370_xp_timer_syscore_ops); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return 0; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int __init armada_xp_timer_init(struct device_node *np) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct clk *clk = of_clk_get_by_name(np, "fixed"); 33662306a36Sopenharmony_ci int ret; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (IS_ERR(clk)) { 33962306a36Sopenharmony_ci pr_err("Failed to get clock\n"); 34062306a36Sopenharmony_ci return PTR_ERR(clk); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci ret = clk_prepare_enable(clk); 34462306a36Sopenharmony_ci if (ret) 34562306a36Sopenharmony_ci return ret; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci timer_clk = clk_get_rate(clk); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return armada_370_xp_timer_common_init(np); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ciTIMER_OF_DECLARE(armada_xp, "marvell,armada-xp-timer", 35262306a36Sopenharmony_ci armada_xp_timer_init); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic int __init armada_375_timer_init(struct device_node *np) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct clk *clk; 35762306a36Sopenharmony_ci int ret; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci clk = of_clk_get_by_name(np, "fixed"); 36062306a36Sopenharmony_ci if (!IS_ERR(clk)) { 36162306a36Sopenharmony_ci ret = clk_prepare_enable(clk); 36262306a36Sopenharmony_ci if (ret) 36362306a36Sopenharmony_ci return ret; 36462306a36Sopenharmony_ci timer_clk = clk_get_rate(clk); 36562306a36Sopenharmony_ci } else { 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* 36862306a36Sopenharmony_ci * This fallback is required in order to retain proper 36962306a36Sopenharmony_ci * devicetree backwards compatibility. 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_ci clk = of_clk_get(np, 0); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* Must have at least a clock */ 37462306a36Sopenharmony_ci if (IS_ERR(clk)) { 37562306a36Sopenharmony_ci pr_err("Failed to get clock\n"); 37662306a36Sopenharmony_ci return PTR_ERR(clk); 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ret = clk_prepare_enable(clk); 38062306a36Sopenharmony_ci if (ret) 38162306a36Sopenharmony_ci return ret; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci timer_clk = clk_get_rate(clk) / TIMER_DIVIDER; 38462306a36Sopenharmony_ci timer25Mhz = false; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci return armada_370_xp_timer_common_init(np); 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ciTIMER_OF_DECLARE(armada_375, "marvell,armada-375-timer", 39062306a36Sopenharmony_ci armada_375_timer_init); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic int __init armada_370_timer_init(struct device_node *np) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct clk *clk; 39562306a36Sopenharmony_ci int ret; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci clk = of_clk_get(np, 0); 39862306a36Sopenharmony_ci if (IS_ERR(clk)) { 39962306a36Sopenharmony_ci pr_err("Failed to get clock\n"); 40062306a36Sopenharmony_ci return PTR_ERR(clk); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci ret = clk_prepare_enable(clk); 40462306a36Sopenharmony_ci if (ret) 40562306a36Sopenharmony_ci return ret; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci timer_clk = clk_get_rate(clk) / TIMER_DIVIDER; 40862306a36Sopenharmony_ci timer25Mhz = false; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return armada_370_xp_timer_common_init(np); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ciTIMER_OF_DECLARE(armada_370, "marvell,armada-370-timer", 41362306a36Sopenharmony_ci armada_370_timer_init); 414