Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clocksource/drivers/npcm: Add NPCM7xx timer driver

Add Nuvoton BMC NPCM7xx timer driver.

The clocksource Enable 24-bit TIMER0 and TIMER1 counters,
while TIMER0 serve as clockevent and TIMER1 serve as clocksource.

Signed-off-by: Tomer Maimon <tmaimon77@gmail.com>
Reviewed-by: Brendan Higgins <brendanhiggins@xxxxxxxxxx>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>

authored by

Tomer Maimon and committed by
Daniel Lezcano
1c00289e ff2969c4

+224
+8
drivers/clocksource/Kconfig
··· 130 130 help 131 131 Enables support for the VT8500 driver. 132 132 133 + config NPCM7XX_TIMER 134 + bool "NPCM7xx timer driver" if COMPILE_TEST 135 + depends on HAS_IOMEM 136 + select CLKSRC_MMIO 137 + help 138 + Enable 24-bit TIMER0 and TIMER1 counters in the NPCM7xx architecture, 139 + While TIMER0 serves as clockevent and TIMER1 serves as clocksource. 140 + 133 141 config CADENCE_TTC_TIMER 134 142 bool "Cadence TTC timer driver" if COMPILE_TEST 135 143 depends on COMMON_CLK
+1
drivers/clocksource/Makefile
··· 55 55 obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o 56 56 obj-$(CONFIG_OWL_TIMER) += owl-timer.o 57 57 obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o 58 + obj-$(CONFIG_NPCM7XX_TIMER) += timer-npcm7xx.o 58 59 59 60 obj-$(CONFIG_ARC_TIMERS) += arc_timer.o 60 61 obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
+215
drivers/clocksource/timer-npcm7xx.c
··· 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 +