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 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 val |= NPCM7XX_START_ONESHOT_Tx; 88 writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 89 90 return 0; 91 } 92 93 static 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 108 static 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 122 static 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 134 static 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 155 static 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 169 static 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 189 static 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 211 TIMER_OF_DECLARE(npcm7xx, "nuvoton,npcm750-timer", npcm7xx_timer_init); 212 213