timer-npcm7xx.c (5831B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2014-2018 Nuvoton Technologies tomer.maimon@nuvoton.com 4 * All rights reserved. 5 * 6 * Copyright 2017 Google, Inc. 7 */ 8 9#include <linux/kernel.h> 10#include <linux/sched.h> 11#include <linux/init.h> 12#include <linux/interrupt.h> 13#include <linux/err.h> 14#include <linux/clk.h> 15#include <linux/io.h> 16#include <linux/clockchips.h> 17#include <linux/of_irq.h> 18#include <linux/of_address.h> 19#include "timer-of.h" 20 21/* Timers registers */ 22#define NPCM7XX_REG_TCSR0 0x0 /* Timer 0 Control and Status Register */ 23#define NPCM7XX_REG_TICR0 0x8 /* Timer 0 Initial Count Register */ 24#define NPCM7XX_REG_TCSR1 0x4 /* Timer 1 Control and Status Register */ 25#define NPCM7XX_REG_TICR1 0xc /* Timer 1 Initial Count Register */ 26#define NPCM7XX_REG_TDR1 0x14 /* Timer 1 Data Register */ 27#define NPCM7XX_REG_TISR 0x18 /* Timer Interrupt Status Register */ 28 29/* Timers control */ 30#define NPCM7XX_Tx_RESETINT 0x1f 31#define NPCM7XX_Tx_PERIOD BIT(27) 32#define NPCM7XX_Tx_INTEN BIT(29) 33#define NPCM7XX_Tx_COUNTEN BIT(30) 34#define NPCM7XX_Tx_ONESHOT 0x0 35#define NPCM7XX_Tx_OPER GENMASK(28, 27) 36#define NPCM7XX_Tx_MIN_PRESCALE 0x1 37#define NPCM7XX_Tx_TDR_MASK_BITS 24 38#define NPCM7XX_Tx_MAX_CNT 0xFFFFFF 39#define NPCM7XX_T0_CLR_INT 0x1 40#define NPCM7XX_Tx_CLR_CSR 0x0 41 42/* Timers operating mode */ 43#define NPCM7XX_START_PERIODIC_Tx (NPCM7XX_Tx_PERIOD | NPCM7XX_Tx_COUNTEN | \ 44 NPCM7XX_Tx_INTEN | \ 45 NPCM7XX_Tx_MIN_PRESCALE) 46 47#define NPCM7XX_START_ONESHOT_Tx (NPCM7XX_Tx_ONESHOT | NPCM7XX_Tx_COUNTEN | \ 48 NPCM7XX_Tx_INTEN | \ 49 NPCM7XX_Tx_MIN_PRESCALE) 50 51#define NPCM7XX_START_Tx (NPCM7XX_Tx_COUNTEN | NPCM7XX_Tx_PERIOD | \ 52 NPCM7XX_Tx_MIN_PRESCALE) 53 54#define NPCM7XX_DEFAULT_CSR (NPCM7XX_Tx_CLR_CSR | NPCM7XX_Tx_MIN_PRESCALE) 55 56static int npcm7xx_timer_resume(struct clock_event_device *evt) 57{ 58 struct timer_of *to = to_timer_of(evt); 59 u32 val; 60 61 val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); 62 val |= NPCM7XX_Tx_COUNTEN; 63 writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 64 65 return 0; 66} 67 68static int npcm7xx_timer_shutdown(struct clock_event_device *evt) 69{ 70 struct timer_of *to = to_timer_of(evt); 71 u32 val; 72 73 val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); 74 val &= ~NPCM7XX_Tx_COUNTEN; 75 writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 76 77 return 0; 78} 79 80static int npcm7xx_timer_oneshot(struct clock_event_device *evt) 81{ 82 struct timer_of *to = to_timer_of(evt); 83 u32 val; 84 85 val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); 86 val &= ~NPCM7XX_Tx_OPER; 87 val |= NPCM7XX_START_ONESHOT_Tx; 88 writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 89 90 return 0; 91} 92 93static int npcm7xx_timer_periodic(struct clock_event_device *evt) 94{ 95 struct timer_of *to = to_timer_of(evt); 96 u32 val; 97 98 writel(timer_of_period(to), timer_of_base(to) + NPCM7XX_REG_TICR0); 99 100 val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); 101 val &= ~NPCM7XX_Tx_OPER; 102 val |= NPCM7XX_START_PERIODIC_Tx; 103 writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 104 105 return 0; 106} 107 108static int npcm7xx_clockevent_set_next_event(unsigned long evt, 109 struct clock_event_device *clk) 110{ 111 struct timer_of *to = to_timer_of(clk); 112 u32 val; 113 114 writel(evt, timer_of_base(to) + NPCM7XX_REG_TICR0); 115 val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); 116 val |= NPCM7XX_START_Tx; 117 writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 118 119 return 0; 120} 121 122static irqreturn_t npcm7xx_timer0_interrupt(int irq, void *dev_id) 123{ 124 struct clock_event_device *evt = (struct clock_event_device *)dev_id; 125 struct timer_of *to = to_timer_of(evt); 126 127 writel(NPCM7XX_T0_CLR_INT, timer_of_base(to) + NPCM7XX_REG_TISR); 128 129 evt->event_handler(evt); 130 131 return IRQ_HANDLED; 132} 133 134static struct timer_of npcm7xx_to = { 135 .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK, 136 137 .clkevt = { 138 .name = "npcm7xx-timer0", 139 .features = CLOCK_EVT_FEAT_PERIODIC | 140 CLOCK_EVT_FEAT_ONESHOT, 141 .set_next_event = npcm7xx_clockevent_set_next_event, 142 .set_state_shutdown = npcm7xx_timer_shutdown, 143 .set_state_periodic = npcm7xx_timer_periodic, 144 .set_state_oneshot = npcm7xx_timer_oneshot, 145 .tick_resume = npcm7xx_timer_resume, 146 .rating = 300, 147 }, 148 149 .of_irq = { 150 .handler = npcm7xx_timer0_interrupt, 151 .flags = IRQF_TIMER | IRQF_IRQPOLL, 152 }, 153}; 154 155static void __init npcm7xx_clockevents_init(void) 156{ 157 writel(NPCM7XX_DEFAULT_CSR, 158 timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR0); 159 160 writel(NPCM7XX_Tx_RESETINT, 161 timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TISR); 162 163 npcm7xx_to.clkevt.cpumask = cpumask_of(0); 164 clockevents_config_and_register(&npcm7xx_to.clkevt, 165 timer_of_rate(&npcm7xx_to), 166 0x1, NPCM7XX_Tx_MAX_CNT); 167} 168 169static void __init npcm7xx_clocksource_init(void) 170{ 171 u32 val; 172 173 writel(NPCM7XX_DEFAULT_CSR, 174 timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1); 175 writel(NPCM7XX_Tx_MAX_CNT, 176 timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TICR1); 177 178 val = readl(timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1); 179 val |= NPCM7XX_START_Tx; 180 writel(val, timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1); 181 182 clocksource_mmio_init(timer_of_base(&npcm7xx_to) + 183 NPCM7XX_REG_TDR1, 184 "npcm7xx-timer1", timer_of_rate(&npcm7xx_to), 185 200, (unsigned int)NPCM7XX_Tx_TDR_MASK_BITS, 186 clocksource_mmio_readl_down); 187} 188 189static int __init npcm7xx_timer_init(struct device_node *np) 190{ 191 int ret; 192 193 ret = timer_of_init(np, &npcm7xx_to); 194 if (ret) 195 return ret; 196 197 /* Clock input is divided by PRESCALE + 1 before it is fed */ 198 /* to the counter */ 199 npcm7xx_to.of_clk.rate = npcm7xx_to.of_clk.rate / 200 (NPCM7XX_Tx_MIN_PRESCALE + 1); 201 202 npcm7xx_clocksource_init(); 203 npcm7xx_clockevents_init(); 204 205 pr_info("Enabling NPCM7xx clocksource timer base: %px, IRQ: %d ", 206 timer_of_base(&npcm7xx_to), timer_of_irq(&npcm7xx_to)); 207 208 return 0; 209} 210 211TIMER_OF_DECLARE(wpcm450, "nuvoton,wpcm450-timer", npcm7xx_timer_init); 212TIMER_OF_DECLARE(npcm7xx, "nuvoton,npcm750-timer", npcm7xx_timer_init); 213