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(3, 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 56 static 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 68 static 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 80 static 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 88 val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); 89 val |= NPCM7XX_START_ONESHOT_Tx; 90 writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 91 92 return 0; 93 } 94 95 static int npcm7xx_timer_periodic(struct clock_event_device *evt) 96 { 97 struct timer_of *to = to_timer_of(evt); 98 u32 val; 99 100 val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); 101 val &= ~NPCM7XX_Tx_OPER; 102 103 writel(timer_of_period(to), timer_of_base(to) + NPCM7XX_REG_TICR0); 104 val |= NPCM7XX_START_PERIODIC_Tx; 105 106 writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 107 108 return 0; 109 } 110 111 static int npcm7xx_clockevent_set_next_event(unsigned long evt, 112 struct clock_event_device *clk) 113 { 114 struct timer_of *to = to_timer_of(clk); 115 u32 val; 116 117 writel(evt, timer_of_base(to) + NPCM7XX_REG_TICR0); 118 val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); 119 val |= NPCM7XX_START_Tx; 120 writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 121 122 return 0; 123 } 124 125 static irqreturn_t npcm7xx_timer0_interrupt(int irq, void *dev_id) 126 { 127 struct clock_event_device *evt = (struct clock_event_device *)dev_id; 128 struct timer_of *to = to_timer_of(evt); 129 130 writel(NPCM7XX_T0_CLR_INT, timer_of_base(to) + NPCM7XX_REG_TISR); 131 132 evt->event_handler(evt); 133 134 return IRQ_HANDLED; 135 } 136 137 static struct timer_of npcm7xx_to = { 138 .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK, 139 140 .clkevt = { 141 .name = "npcm7xx-timer0", 142 .features = CLOCK_EVT_FEAT_PERIODIC | 143 CLOCK_EVT_FEAT_ONESHOT, 144 .set_next_event = npcm7xx_clockevent_set_next_event, 145 .set_state_shutdown = npcm7xx_timer_shutdown, 146 .set_state_periodic = npcm7xx_timer_periodic, 147 .set_state_oneshot = npcm7xx_timer_oneshot, 148 .tick_resume = npcm7xx_timer_resume, 149 .rating = 300, 150 }, 151 152 .of_irq = { 153 .handler = npcm7xx_timer0_interrupt, 154 .flags = IRQF_TIMER | IRQF_IRQPOLL, 155 }, 156 }; 157 158 static void __init npcm7xx_clockevents_init(void) 159 { 160 writel(NPCM7XX_DEFAULT_CSR, 161 timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR0); 162 163 writel(NPCM7XX_Tx_RESETINT, 164 timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TISR); 165 166 npcm7xx_to.clkevt.cpumask = cpumask_of(0); 167 clockevents_config_and_register(&npcm7xx_to.clkevt, 168 timer_of_rate(&npcm7xx_to), 169 0x1, NPCM7XX_Tx_MAX_CNT); 170 } 171 172 static void __init npcm7xx_clocksource_init(void) 173 { 174 u32 val; 175 176 writel(NPCM7XX_DEFAULT_CSR, 177 timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1); 178 writel(NPCM7XX_Tx_MAX_CNT, 179 timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TICR1); 180 181 val = readl(timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1); 182 val |= NPCM7XX_START_Tx; 183 writel(val, timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1); 184 185 clocksource_mmio_init(timer_of_base(&npcm7xx_to) + 186 NPCM7XX_REG_TDR1, 187 "npcm7xx-timer1", timer_of_rate(&npcm7xx_to), 188 200, (unsigned int)NPCM7XX_Tx_TDR_MASK_BITS, 189 clocksource_mmio_readl_down); 190 } 191 192 static int __init npcm7xx_timer_init(struct device_node *np) 193 { 194 int ret; 195 196 ret = timer_of_init(np, &npcm7xx_to); 197 if (ret) 198 return ret; 199 200 /* Clock input is divided by PRESCALE + 1 before it is fed */ 201 /* to the counter */ 202 npcm7xx_to.of_clk.rate = npcm7xx_to.of_clk.rate / 203 (NPCM7XX_Tx_MIN_PRESCALE + 1); 204 205 npcm7xx_clocksource_init(); 206 npcm7xx_clockevents_init(); 207 208 pr_info("Enabling NPCM7xx clocksource timer base: %px, IRQ: %d ", 209 timer_of_base(&npcm7xx_to), timer_of_irq(&npcm7xx_to)); 210 211 return 0; 212 } 213 214 TIMER_OF_DECLARE(npcm7xx, "nuvoton,npcm750-timer", npcm7xx_timer_init); 215 216