1f5bf0ee4SLinus Walleij /* 2f5bf0ee4SLinus Walleij * Faraday Technology FTTMR010 timer driver 3f5bf0ee4SLinus Walleij * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> 4f5bf0ee4SLinus Walleij * 5f5bf0ee4SLinus Walleij * Based on a rewrite of arch/arm/mach-gemini/timer.c: 6f5bf0ee4SLinus Walleij * Copyright (C) 2001-2006 Storlink, Corp. 7f5bf0ee4SLinus Walleij * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> 8f5bf0ee4SLinus Walleij */ 9f5bf0ee4SLinus Walleij #include <linux/interrupt.h> 10f5bf0ee4SLinus Walleij #include <linux/io.h> 11f5bf0ee4SLinus Walleij #include <linux/of.h> 12f5bf0ee4SLinus Walleij #include <linux/of_address.h> 13f5bf0ee4SLinus Walleij #include <linux/of_irq.h> 14f5bf0ee4SLinus Walleij #include <linux/clockchips.h> 15f5bf0ee4SLinus Walleij #include <linux/clocksource.h> 16f5bf0ee4SLinus Walleij #include <linux/sched_clock.h> 1728e71e2fSLinus Walleij #include <linux/clk.h> 18e7bad212SLinus Walleij #include <linux/slab.h> 19d0d76d57SLinus Walleij #include <linux/bitops.h> 20385c98fcSLinus Walleij #include <linux/delay.h> 21f5bf0ee4SLinus Walleij 22f5bf0ee4SLinus Walleij /* 23f5bf0ee4SLinus Walleij * Register definitions for the timers 24f5bf0ee4SLinus Walleij */ 25f5bf0ee4SLinus Walleij #define TIMER1_COUNT (0x00) 26f5bf0ee4SLinus Walleij #define TIMER1_LOAD (0x04) 27f5bf0ee4SLinus Walleij #define TIMER1_MATCH1 (0x08) 28f5bf0ee4SLinus Walleij #define TIMER1_MATCH2 (0x0c) 29f5bf0ee4SLinus Walleij #define TIMER2_COUNT (0x10) 30f5bf0ee4SLinus Walleij #define TIMER2_LOAD (0x14) 31f5bf0ee4SLinus Walleij #define TIMER2_MATCH1 (0x18) 32f5bf0ee4SLinus Walleij #define TIMER2_MATCH2 (0x1c) 33f5bf0ee4SLinus Walleij #define TIMER3_COUNT (0x20) 34f5bf0ee4SLinus Walleij #define TIMER3_LOAD (0x24) 35f5bf0ee4SLinus Walleij #define TIMER3_MATCH1 (0x28) 36f5bf0ee4SLinus Walleij #define TIMER3_MATCH2 (0x2c) 37f5bf0ee4SLinus Walleij #define TIMER_CR (0x30) 38f5bf0ee4SLinus Walleij #define TIMER_INTR_STATE (0x34) 39f5bf0ee4SLinus Walleij #define TIMER_INTR_MASK (0x38) 40f5bf0ee4SLinus Walleij 41d0d76d57SLinus Walleij #define TIMER_1_CR_ENABLE BIT(0) 42d0d76d57SLinus Walleij #define TIMER_1_CR_CLOCK BIT(1) 43d0d76d57SLinus Walleij #define TIMER_1_CR_INT BIT(2) 44d0d76d57SLinus Walleij #define TIMER_2_CR_ENABLE BIT(3) 45d0d76d57SLinus Walleij #define TIMER_2_CR_CLOCK BIT(4) 46d0d76d57SLinus Walleij #define TIMER_2_CR_INT BIT(5) 47d0d76d57SLinus Walleij #define TIMER_3_CR_ENABLE BIT(6) 48d0d76d57SLinus Walleij #define TIMER_3_CR_CLOCK BIT(7) 49d0d76d57SLinus Walleij #define TIMER_3_CR_INT BIT(8) 50d0d76d57SLinus Walleij #define TIMER_1_CR_UPDOWN BIT(9) 51d0d76d57SLinus Walleij #define TIMER_2_CR_UPDOWN BIT(10) 52d0d76d57SLinus Walleij #define TIMER_3_CR_UPDOWN BIT(11) 53f5bf0ee4SLinus Walleij 54ec14ba1eSLinus Walleij /* 55ec14ba1eSLinus Walleij * The Aspeed AST2400 moves bits around in the control register 56ec14ba1eSLinus Walleij * and lacks bits for setting the timer to count upwards. 57ec14ba1eSLinus Walleij */ 58ec14ba1eSLinus Walleij #define TIMER_1_CR_ASPEED_ENABLE BIT(0) 59ec14ba1eSLinus Walleij #define TIMER_1_CR_ASPEED_CLOCK BIT(1) 60ec14ba1eSLinus Walleij #define TIMER_1_CR_ASPEED_INT BIT(2) 61ec14ba1eSLinus Walleij #define TIMER_2_CR_ASPEED_ENABLE BIT(4) 62ec14ba1eSLinus Walleij #define TIMER_2_CR_ASPEED_CLOCK BIT(5) 63ec14ba1eSLinus Walleij #define TIMER_2_CR_ASPEED_INT BIT(6) 64ec14ba1eSLinus Walleij #define TIMER_3_CR_ASPEED_ENABLE BIT(8) 65ec14ba1eSLinus Walleij #define TIMER_3_CR_ASPEED_CLOCK BIT(9) 66ec14ba1eSLinus Walleij #define TIMER_3_CR_ASPEED_INT BIT(10) 67ec14ba1eSLinus Walleij 68d0d76d57SLinus Walleij #define TIMER_1_INT_MATCH1 BIT(0) 69d0d76d57SLinus Walleij #define TIMER_1_INT_MATCH2 BIT(1) 70d0d76d57SLinus Walleij #define TIMER_1_INT_OVERFLOW BIT(2) 71d0d76d57SLinus Walleij #define TIMER_2_INT_MATCH1 BIT(3) 72d0d76d57SLinus Walleij #define TIMER_2_INT_MATCH2 BIT(4) 73d0d76d57SLinus Walleij #define TIMER_2_INT_OVERFLOW BIT(5) 74d0d76d57SLinus Walleij #define TIMER_3_INT_MATCH1 BIT(6) 75d0d76d57SLinus Walleij #define TIMER_3_INT_MATCH2 BIT(7) 76d0d76d57SLinus Walleij #define TIMER_3_INT_OVERFLOW BIT(8) 77f5bf0ee4SLinus Walleij #define TIMER_INT_ALL_MASK 0x1ff 78f5bf0ee4SLinus Walleij 79e7bad212SLinus Walleij struct fttmr010 { 80e7bad212SLinus Walleij void __iomem *base; 81e7bad212SLinus Walleij unsigned int tick_rate; 82ec14ba1eSLinus Walleij bool count_down; 83ec14ba1eSLinus Walleij u32 t1_enable_val; 84e7bad212SLinus Walleij struct clock_event_device clkevt; 85385c98fcSLinus Walleij #ifdef CONFIG_ARM 86385c98fcSLinus Walleij struct delay_timer delay_timer; 87385c98fcSLinus Walleij #endif 88e7bad212SLinus Walleij }; 89e7bad212SLinus Walleij 90385c98fcSLinus Walleij /* 91385c98fcSLinus Walleij * A local singleton used by sched_clock and delay timer reads, which are 92385c98fcSLinus Walleij * fast and stateless 93385c98fcSLinus Walleij */ 94e7bad212SLinus Walleij static struct fttmr010 *local_fttmr; 95e7bad212SLinus Walleij 96e7bad212SLinus Walleij static inline struct fttmr010 *to_fttmr010(struct clock_event_device *evt) 97e7bad212SLinus Walleij { 98e7bad212SLinus Walleij return container_of(evt, struct fttmr010, clkevt); 99e7bad212SLinus Walleij } 100f5bf0ee4SLinus Walleij 101385c98fcSLinus Walleij static unsigned long fttmr010_read_current_timer_up(void) 102385c98fcSLinus Walleij { 103385c98fcSLinus Walleij return readl(local_fttmr->base + TIMER2_COUNT); 104385c98fcSLinus Walleij } 105385c98fcSLinus Walleij 106385c98fcSLinus Walleij static unsigned long fttmr010_read_current_timer_down(void) 107385c98fcSLinus Walleij { 108385c98fcSLinus Walleij return ~readl(local_fttmr->base + TIMER2_COUNT); 109385c98fcSLinus Walleij } 110385c98fcSLinus Walleij 111c4779902SLinus Walleij static u64 notrace fttmr010_read_sched_clock_up(void) 112c4779902SLinus Walleij { 113c4779902SLinus Walleij return fttmr010_read_current_timer_up(); 114c4779902SLinus Walleij } 115c4779902SLinus Walleij 116c4779902SLinus Walleij static u64 notrace fttmr010_read_sched_clock_down(void) 117c4779902SLinus Walleij { 118c4779902SLinus Walleij return fttmr010_read_current_timer_down(); 119c4779902SLinus Walleij } 120385c98fcSLinus Walleij 121f5bf0ee4SLinus Walleij static int fttmr010_timer_set_next_event(unsigned long cycles, 122f5bf0ee4SLinus Walleij struct clock_event_device *evt) 123f5bf0ee4SLinus Walleij { 124e7bad212SLinus Walleij struct fttmr010 *fttmr010 = to_fttmr010(evt); 125f5bf0ee4SLinus Walleij u32 cr; 126f5bf0ee4SLinus Walleij 127ec14ba1eSLinus Walleij /* Stop */ 128ec14ba1eSLinus Walleij cr = readl(fttmr010->base + TIMER_CR); 129ec14ba1eSLinus Walleij cr &= ~fttmr010->t1_enable_val; 130ec14ba1eSLinus Walleij writel(cr, fttmr010->base + TIMER_CR); 131ec14ba1eSLinus Walleij 132ec14ba1eSLinus Walleij /* Setup the match register forward/backward in time */ 133e7bad212SLinus Walleij cr = readl(fttmr010->base + TIMER1_COUNT); 134ec14ba1eSLinus Walleij if (fttmr010->count_down) 135ec14ba1eSLinus Walleij cr -= cycles; 136ec14ba1eSLinus Walleij else 137ec14ba1eSLinus Walleij cr += cycles; 138ec14ba1eSLinus Walleij writel(cr, fttmr010->base + TIMER1_MATCH1); 139ec14ba1eSLinus Walleij 140ec14ba1eSLinus Walleij /* Start */ 141ec14ba1eSLinus Walleij cr = readl(fttmr010->base + TIMER_CR); 142ec14ba1eSLinus Walleij cr |= fttmr010->t1_enable_val; 143ec14ba1eSLinus Walleij writel(cr, fttmr010->base + TIMER_CR); 144f5bf0ee4SLinus Walleij 145f5bf0ee4SLinus Walleij return 0; 146f5bf0ee4SLinus Walleij } 147f5bf0ee4SLinus Walleij 148f5bf0ee4SLinus Walleij static int fttmr010_timer_shutdown(struct clock_event_device *evt) 149f5bf0ee4SLinus Walleij { 150e7bad212SLinus Walleij struct fttmr010 *fttmr010 = to_fttmr010(evt); 151f5bf0ee4SLinus Walleij u32 cr; 152f5bf0ee4SLinus Walleij 153ec14ba1eSLinus Walleij /* Stop */ 154e7bad212SLinus Walleij cr = readl(fttmr010->base + TIMER_CR); 155ec14ba1eSLinus Walleij cr &= ~fttmr010->t1_enable_val; 156e7bad212SLinus Walleij writel(cr, fttmr010->base + TIMER_CR); 157e7bad212SLinus Walleij 158e7bad212SLinus Walleij return 0; 159e7bad212SLinus Walleij } 160e7bad212SLinus Walleij 161e7bad212SLinus Walleij static int fttmr010_timer_set_oneshot(struct clock_event_device *evt) 162e7bad212SLinus Walleij { 163e7bad212SLinus Walleij struct fttmr010 *fttmr010 = to_fttmr010(evt); 164e7bad212SLinus Walleij u32 cr; 165e7bad212SLinus Walleij 166ec14ba1eSLinus Walleij /* Stop */ 167e7bad212SLinus Walleij cr = readl(fttmr010->base + TIMER_CR); 168ec14ba1eSLinus Walleij cr &= ~fttmr010->t1_enable_val; 169e7bad212SLinus Walleij writel(cr, fttmr010->base + TIMER_CR); 170f5bf0ee4SLinus Walleij 171ec14ba1eSLinus Walleij /* Setup counter start from 0 or ~0 */ 172e7bad212SLinus Walleij writel(0, fttmr010->base + TIMER1_COUNT); 173ec14ba1eSLinus Walleij if (fttmr010->count_down) 174ec14ba1eSLinus Walleij writel(~0, fttmr010->base + TIMER1_LOAD); 175ec14ba1eSLinus Walleij else 176e7bad212SLinus Walleij writel(0, fttmr010->base + TIMER1_LOAD); 177f5bf0ee4SLinus Walleij 178e7bad212SLinus Walleij /* Enable interrupt */ 179e7bad212SLinus Walleij cr = readl(fttmr010->base + TIMER_INTR_MASK); 180f5bf0ee4SLinus Walleij cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); 181f5bf0ee4SLinus Walleij cr |= TIMER_1_INT_MATCH1; 182e7bad212SLinus Walleij writel(cr, fttmr010->base + TIMER_INTR_MASK); 183f5bf0ee4SLinus Walleij 184f5bf0ee4SLinus Walleij return 0; 185f5bf0ee4SLinus Walleij } 186f5bf0ee4SLinus Walleij 187f5bf0ee4SLinus Walleij static int fttmr010_timer_set_periodic(struct clock_event_device *evt) 188f5bf0ee4SLinus Walleij { 189e7bad212SLinus Walleij struct fttmr010 *fttmr010 = to_fttmr010(evt); 190e7bad212SLinus Walleij u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ); 191f5bf0ee4SLinus Walleij u32 cr; 192f5bf0ee4SLinus Walleij 193ec14ba1eSLinus Walleij /* Stop */ 194e7bad212SLinus Walleij cr = readl(fttmr010->base + TIMER_CR); 195ec14ba1eSLinus Walleij cr &= ~fttmr010->t1_enable_val; 196e7bad212SLinus Walleij writel(cr, fttmr010->base + TIMER_CR); 197f5bf0ee4SLinus Walleij 198ec14ba1eSLinus Walleij /* Setup timer to fire at 1/HZ intervals. */ 199ec14ba1eSLinus Walleij if (fttmr010->count_down) { 200ec14ba1eSLinus Walleij writel(period, fttmr010->base + TIMER1_LOAD); 201ec14ba1eSLinus Walleij writel(0, fttmr010->base + TIMER1_MATCH1); 202ec14ba1eSLinus Walleij } else { 203f5bf0ee4SLinus Walleij cr = 0xffffffff - (period - 1); 204e7bad212SLinus Walleij writel(cr, fttmr010->base + TIMER1_COUNT); 205e7bad212SLinus Walleij writel(cr, fttmr010->base + TIMER1_LOAD); 206f5bf0ee4SLinus Walleij 207ec14ba1eSLinus Walleij /* Enable interrupt on overflow */ 208e7bad212SLinus Walleij cr = readl(fttmr010->base + TIMER_INTR_MASK); 209f5bf0ee4SLinus Walleij cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); 210f5bf0ee4SLinus Walleij cr |= TIMER_1_INT_OVERFLOW; 211e7bad212SLinus Walleij writel(cr, fttmr010->base + TIMER_INTR_MASK); 212ec14ba1eSLinus Walleij } 213f5bf0ee4SLinus Walleij 214f5bf0ee4SLinus Walleij /* Start the timer */ 215e7bad212SLinus Walleij cr = readl(fttmr010->base + TIMER_CR); 216ec14ba1eSLinus Walleij cr |= fttmr010->t1_enable_val; 217e7bad212SLinus Walleij writel(cr, fttmr010->base + TIMER_CR); 218f5bf0ee4SLinus Walleij 219f5bf0ee4SLinus Walleij return 0; 220f5bf0ee4SLinus Walleij } 221f5bf0ee4SLinus Walleij 222f5bf0ee4SLinus Walleij /* 223f5bf0ee4SLinus Walleij * IRQ handler for the timer 224f5bf0ee4SLinus Walleij */ 225f5bf0ee4SLinus Walleij static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id) 226f5bf0ee4SLinus Walleij { 227e7bad212SLinus Walleij struct clock_event_device *evt = dev_id; 228f5bf0ee4SLinus Walleij 229f5bf0ee4SLinus Walleij evt->event_handler(evt); 230f5bf0ee4SLinus Walleij return IRQ_HANDLED; 231f5bf0ee4SLinus Walleij } 232f5bf0ee4SLinus Walleij 233ef89718aSDaniel Lezcano static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed) 234f5bf0ee4SLinus Walleij { 235e7bad212SLinus Walleij struct fttmr010 *fttmr010; 236f5bf0ee4SLinus Walleij int irq; 237dd98442eSLinus Walleij struct clk *clk; 238dd98442eSLinus Walleij int ret; 239ec14ba1eSLinus Walleij u32 val; 240dd98442eSLinus Walleij 241dd98442eSLinus Walleij /* 242dd98442eSLinus Walleij * These implementations require a clock reference. 243dd98442eSLinus Walleij * FIXME: we currently only support clocking using PCLK 244dd98442eSLinus Walleij * and using EXTCLK is not supported in the driver. 245dd98442eSLinus Walleij */ 246dd98442eSLinus Walleij clk = of_clk_get_by_name(np, "PCLK"); 247dd98442eSLinus Walleij if (IS_ERR(clk)) { 248dd98442eSLinus Walleij pr_err("could not get PCLK\n"); 249dd98442eSLinus Walleij return PTR_ERR(clk); 250dd98442eSLinus Walleij } 251dd98442eSLinus Walleij ret = clk_prepare_enable(clk); 252dd98442eSLinus Walleij if (ret) { 253dd98442eSLinus Walleij pr_err("failed to enable PCLK\n"); 254dd98442eSLinus Walleij return ret; 255dd98442eSLinus Walleij } 256f5bf0ee4SLinus Walleij 257e7bad212SLinus Walleij fttmr010 = kzalloc(sizeof(*fttmr010), GFP_KERNEL); 258e7bad212SLinus Walleij if (!fttmr010) { 259e7bad212SLinus Walleij ret = -ENOMEM; 260e7bad212SLinus Walleij goto out_disable_clock; 261e7bad212SLinus Walleij } 262e7bad212SLinus Walleij fttmr010->tick_rate = clk_get_rate(clk); 263e7bad212SLinus Walleij 264e7bad212SLinus Walleij fttmr010->base = of_iomap(np, 0); 265e7bad212SLinus Walleij if (!fttmr010->base) { 266*1893428bSArvind Yadav pr_err("Can't remap registers\n"); 267e7bad212SLinus Walleij ret = -ENXIO; 268e7bad212SLinus Walleij goto out_free; 269f5bf0ee4SLinus Walleij } 270f5bf0ee4SLinus Walleij /* IRQ for timer 1 */ 271f5bf0ee4SLinus Walleij irq = irq_of_parse_and_map(np, 0); 272f5bf0ee4SLinus Walleij if (irq <= 0) { 273*1893428bSArvind Yadav pr_err("Can't parse IRQ\n"); 274e7bad212SLinus Walleij ret = -EINVAL; 275e7bad212SLinus Walleij goto out_unmap; 276f5bf0ee4SLinus Walleij } 277f5bf0ee4SLinus Walleij 278f5bf0ee4SLinus Walleij /* 279ec14ba1eSLinus Walleij * The Aspeed AST2400 moves bits around in the control register, 280ec14ba1eSLinus Walleij * otherwise it works the same. 281ec14ba1eSLinus Walleij */ 282ef89718aSDaniel Lezcano if (is_aspeed) { 283ec14ba1eSLinus Walleij fttmr010->t1_enable_val = TIMER_1_CR_ASPEED_ENABLE | 284ec14ba1eSLinus Walleij TIMER_1_CR_ASPEED_INT; 285ec14ba1eSLinus Walleij /* Downward not available */ 286ec14ba1eSLinus Walleij fttmr010->count_down = true; 287ec14ba1eSLinus Walleij } else { 288ec14ba1eSLinus Walleij fttmr010->t1_enable_val = TIMER_1_CR_ENABLE | TIMER_1_CR_INT; 289ec14ba1eSLinus Walleij } 290ec14ba1eSLinus Walleij 291ec14ba1eSLinus Walleij /* 292f5bf0ee4SLinus Walleij * Reset the interrupt mask and status 293f5bf0ee4SLinus Walleij */ 294e7bad212SLinus Walleij writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK); 295e7bad212SLinus Walleij writel(0, fttmr010->base + TIMER_INTR_STATE); 296ec14ba1eSLinus Walleij 297ec14ba1eSLinus Walleij /* 298ec14ba1eSLinus Walleij * Enable timer 1 count up, timer 2 count up, except on Aspeed, 299ec14ba1eSLinus Walleij * where everything just counts down. 300ec14ba1eSLinus Walleij */ 301ef89718aSDaniel Lezcano if (is_aspeed) 302ec14ba1eSLinus Walleij val = TIMER_2_CR_ASPEED_ENABLE; 303ec14ba1eSLinus Walleij else { 304ec14ba1eSLinus Walleij val = TIMER_2_CR_ENABLE; 305ec14ba1eSLinus Walleij if (!fttmr010->count_down) 306ec14ba1eSLinus Walleij val |= TIMER_1_CR_UPDOWN | TIMER_2_CR_UPDOWN; 307ec14ba1eSLinus Walleij } 308ec14ba1eSLinus Walleij writel(val, fttmr010->base + TIMER_CR); 309f5bf0ee4SLinus Walleij 310f5bf0ee4SLinus Walleij /* 311f5bf0ee4SLinus Walleij * Setup free-running clocksource timer (interrupts 312f5bf0ee4SLinus Walleij * disabled.) 313f5bf0ee4SLinus Walleij */ 314e7bad212SLinus Walleij local_fttmr = fttmr010; 315b589da8bSLinus Walleij writel(0, fttmr010->base + TIMER2_COUNT); 316b589da8bSLinus Walleij writel(0, fttmr010->base + TIMER2_MATCH1); 317b589da8bSLinus Walleij writel(0, fttmr010->base + TIMER2_MATCH2); 318ec14ba1eSLinus Walleij 319ec14ba1eSLinus Walleij if (fttmr010->count_down) { 320ec14ba1eSLinus Walleij writel(~0, fttmr010->base + TIMER2_LOAD); 321ec14ba1eSLinus Walleij clocksource_mmio_init(fttmr010->base + TIMER2_COUNT, 322ec14ba1eSLinus Walleij "FTTMR010-TIMER2", 323ec14ba1eSLinus Walleij fttmr010->tick_rate, 324ec14ba1eSLinus Walleij 300, 32, clocksource_mmio_readl_down); 325740e237aSLinus Walleij sched_clock_register(fttmr010_read_sched_clock_down, 32, 326740e237aSLinus Walleij fttmr010->tick_rate); 327ec14ba1eSLinus Walleij } else { 328ec14ba1eSLinus Walleij writel(0, fttmr010->base + TIMER2_LOAD); 329b589da8bSLinus Walleij clocksource_mmio_init(fttmr010->base + TIMER2_COUNT, 330b589da8bSLinus Walleij "FTTMR010-TIMER2", 331e7bad212SLinus Walleij fttmr010->tick_rate, 332f5bf0ee4SLinus Walleij 300, 32, clocksource_mmio_readl_up); 333740e237aSLinus Walleij sched_clock_register(fttmr010_read_sched_clock_up, 32, 334e7bad212SLinus Walleij fttmr010->tick_rate); 335740e237aSLinus Walleij } 336f5bf0ee4SLinus Walleij 337f5bf0ee4SLinus Walleij /* 338e7bad212SLinus Walleij * Setup clockevent timer (interrupt-driven) on timer 1. 339f5bf0ee4SLinus Walleij */ 340e7bad212SLinus Walleij writel(0, fttmr010->base + TIMER1_COUNT); 341e7bad212SLinus Walleij writel(0, fttmr010->base + TIMER1_LOAD); 342e7bad212SLinus Walleij writel(0, fttmr010->base + TIMER1_MATCH1); 343e7bad212SLinus Walleij writel(0, fttmr010->base + TIMER1_MATCH2); 344e7bad212SLinus Walleij ret = request_irq(irq, fttmr010_timer_interrupt, IRQF_TIMER, 345e7bad212SLinus Walleij "FTTMR010-TIMER1", &fttmr010->clkevt); 346e7bad212SLinus Walleij if (ret) { 347e7bad212SLinus Walleij pr_err("FTTMR010-TIMER1 no IRQ\n"); 348e7bad212SLinus Walleij goto out_unmap; 349e7bad212SLinus Walleij } 350e7bad212SLinus Walleij 351e7bad212SLinus Walleij fttmr010->clkevt.name = "FTTMR010-TIMER1"; 352e7bad212SLinus Walleij /* Reasonably fast and accurate clock event */ 353e7bad212SLinus Walleij fttmr010->clkevt.rating = 300; 354e7bad212SLinus Walleij fttmr010->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | 355e7bad212SLinus Walleij CLOCK_EVT_FEAT_ONESHOT; 356e7bad212SLinus Walleij fttmr010->clkevt.set_next_event = fttmr010_timer_set_next_event; 357e7bad212SLinus Walleij fttmr010->clkevt.set_state_shutdown = fttmr010_timer_shutdown; 358e7bad212SLinus Walleij fttmr010->clkevt.set_state_periodic = fttmr010_timer_set_periodic; 359e7bad212SLinus Walleij fttmr010->clkevt.set_state_oneshot = fttmr010_timer_set_oneshot; 360e7bad212SLinus Walleij fttmr010->clkevt.tick_resume = fttmr010_timer_shutdown; 361e7bad212SLinus Walleij fttmr010->clkevt.cpumask = cpumask_of(0); 362e7bad212SLinus Walleij fttmr010->clkevt.irq = irq; 363e7bad212SLinus Walleij clockevents_config_and_register(&fttmr010->clkevt, 364e7bad212SLinus Walleij fttmr010->tick_rate, 365f5bf0ee4SLinus Walleij 1, 0xffffffff); 366f5bf0ee4SLinus Walleij 367385c98fcSLinus Walleij #ifdef CONFIG_ARM 368385c98fcSLinus Walleij /* Also use this timer for delays */ 369385c98fcSLinus Walleij if (fttmr010->count_down) 370385c98fcSLinus Walleij fttmr010->delay_timer.read_current_timer = 371385c98fcSLinus Walleij fttmr010_read_current_timer_down; 372385c98fcSLinus Walleij else 373385c98fcSLinus Walleij fttmr010->delay_timer.read_current_timer = 374385c98fcSLinus Walleij fttmr010_read_current_timer_up; 375385c98fcSLinus Walleij fttmr010->delay_timer.freq = fttmr010->tick_rate; 376385c98fcSLinus Walleij register_current_timer_delay(&fttmr010->delay_timer); 377385c98fcSLinus Walleij #endif 378385c98fcSLinus Walleij 379f5bf0ee4SLinus Walleij return 0; 380e7bad212SLinus Walleij 381e7bad212SLinus Walleij out_unmap: 382e7bad212SLinus Walleij iounmap(fttmr010->base); 383e7bad212SLinus Walleij out_free: 384e7bad212SLinus Walleij kfree(fttmr010); 385e7bad212SLinus Walleij out_disable_clock: 386e7bad212SLinus Walleij clk_disable_unprepare(clk); 387e7bad212SLinus Walleij 388e7bad212SLinus Walleij return ret; 389f5bf0ee4SLinus Walleij } 390ef89718aSDaniel Lezcano 391ef89718aSDaniel Lezcano static __init int aspeed_timer_init(struct device_node *np) 392ef89718aSDaniel Lezcano { 393ef89718aSDaniel Lezcano return fttmr010_common_init(np, true); 394ef89718aSDaniel Lezcano } 395ef89718aSDaniel Lezcano 396ef89718aSDaniel Lezcano static __init int fttmr010_timer_init(struct device_node *np) 397ef89718aSDaniel Lezcano { 398ef89718aSDaniel Lezcano return fttmr010_common_init(np, false); 399ef89718aSDaniel Lezcano } 400ef89718aSDaniel Lezcano 40117273395SDaniel Lezcano TIMER_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init); 40217273395SDaniel Lezcano TIMER_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init); 40317273395SDaniel Lezcano TIMER_OF_DECLARE(moxart, "moxa,moxart-timer", fttmr010_timer_init); 40417273395SDaniel Lezcano TIMER_OF_DECLARE(ast2400, "aspeed,ast2400-timer", aspeed_timer_init); 40517273395SDaniel Lezcano TIMER_OF_DECLARE(ast2500, "aspeed,ast2500-timer", aspeed_timer_init); 406