at master 5.3 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2017 Spreadtrum Communications Inc. 4 */ 5 6#include <linux/init.h> 7#include <linux/interrupt.h> 8 9#include "timer-of.h" 10 11#define TIMER_NAME "sprd_timer" 12 13#define TIMER_LOAD_LO 0x0 14#define TIMER_LOAD_HI 0x4 15#define TIMER_VALUE_LO 0x8 16#define TIMER_VALUE_HI 0xc 17 18#define TIMER_CTL 0x10 19#define TIMER_CTL_PERIOD_MODE BIT(0) 20#define TIMER_CTL_ENABLE BIT(1) 21#define TIMER_CTL_64BIT_WIDTH BIT(16) 22 23#define TIMER_INT 0x14 24#define TIMER_INT_EN BIT(0) 25#define TIMER_INT_RAW_STS BIT(1) 26#define TIMER_INT_MASK_STS BIT(2) 27#define TIMER_INT_CLR BIT(3) 28 29#define TIMER_VALUE_SHDW_LO 0x18 30#define TIMER_VALUE_SHDW_HI 0x1c 31 32#define TIMER_VALUE_LO_MASK GENMASK(31, 0) 33#define TIMER_VALUE_HI_MASK GENMASK(31, 0) 34 35static void sprd_timer_enable(void __iomem *base, u32 flag) 36{ 37 u32 val = readl_relaxed(base + TIMER_CTL); 38 39 val |= TIMER_CTL_ENABLE; 40 if (flag & TIMER_CTL_64BIT_WIDTH) 41 val |= TIMER_CTL_64BIT_WIDTH; 42 else 43 val &= ~TIMER_CTL_64BIT_WIDTH; 44 45 if (flag & TIMER_CTL_PERIOD_MODE) 46 val |= TIMER_CTL_PERIOD_MODE; 47 else 48 val &= ~TIMER_CTL_PERIOD_MODE; 49 50 writel_relaxed(val, base + TIMER_CTL); 51} 52 53static void sprd_timer_disable(void __iomem *base) 54{ 55 u32 val = readl_relaxed(base + TIMER_CTL); 56 57 val &= ~TIMER_CTL_ENABLE; 58 writel_relaxed(val, base + TIMER_CTL); 59} 60 61static void sprd_timer_update_counter(void __iomem *base, unsigned long cycles) 62{ 63 writel_relaxed(cycles & TIMER_VALUE_LO_MASK, base + TIMER_LOAD_LO); 64 writel_relaxed(0, base + TIMER_LOAD_HI); 65} 66 67static void sprd_timer_enable_interrupt(void __iomem *base) 68{ 69 writel_relaxed(TIMER_INT_EN, base + TIMER_INT); 70} 71 72static void sprd_timer_clear_interrupt(void __iomem *base) 73{ 74 u32 val = readl_relaxed(base + TIMER_INT); 75 76 val |= TIMER_INT_CLR; 77 writel_relaxed(val, base + TIMER_INT); 78} 79 80static int sprd_timer_set_next_event(unsigned long cycles, 81 struct clock_event_device *ce) 82{ 83 struct timer_of *to = to_timer_of(ce); 84 85 sprd_timer_disable(timer_of_base(to)); 86 sprd_timer_update_counter(timer_of_base(to), cycles); 87 sprd_timer_enable(timer_of_base(to), 0); 88 89 return 0; 90} 91 92static int sprd_timer_set_periodic(struct clock_event_device *ce) 93{ 94 struct timer_of *to = to_timer_of(ce); 95 96 sprd_timer_disable(timer_of_base(to)); 97 sprd_timer_update_counter(timer_of_base(to), timer_of_period(to)); 98 sprd_timer_enable(timer_of_base(to), TIMER_CTL_PERIOD_MODE); 99 100 return 0; 101} 102 103static int sprd_timer_shutdown(struct clock_event_device *ce) 104{ 105 struct timer_of *to = to_timer_of(ce); 106 107 sprd_timer_disable(timer_of_base(to)); 108 return 0; 109} 110 111static irqreturn_t sprd_timer_interrupt(int irq, void *dev_id) 112{ 113 struct clock_event_device *ce = (struct clock_event_device *)dev_id; 114 struct timer_of *to = to_timer_of(ce); 115 116 sprd_timer_clear_interrupt(timer_of_base(to)); 117 118 if (clockevent_state_oneshot(ce)) 119 sprd_timer_disable(timer_of_base(to)); 120 121 ce->event_handler(ce); 122 return IRQ_HANDLED; 123} 124 125static struct timer_of to = { 126 .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK, 127 128 .clkevt = { 129 .name = TIMER_NAME, 130 .rating = 300, 131 .features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_PERIODIC | 132 CLOCK_EVT_FEAT_ONESHOT, 133 .set_state_shutdown = sprd_timer_shutdown, 134 .set_state_periodic = sprd_timer_set_periodic, 135 .set_next_event = sprd_timer_set_next_event, 136 .cpumask = cpu_possible_mask, 137 }, 138 139 .of_irq = { 140 .handler = sprd_timer_interrupt, 141 .flags = IRQF_TIMER | IRQF_IRQPOLL, 142 }, 143}; 144 145static int __init sprd_timer_init(struct device_node *np) 146{ 147 int ret; 148 149 ret = timer_of_init(np, &to); 150 if (ret) 151 return ret; 152 153 sprd_timer_enable_interrupt(timer_of_base(&to)); 154 clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), 155 1, UINT_MAX); 156 157 return 0; 158} 159 160static struct timer_of suspend_to = { 161 .flags = TIMER_OF_BASE | TIMER_OF_CLOCK, 162}; 163 164static u64 sprd_suspend_timer_read(struct clocksource *cs) 165{ 166 u32 lo, hi; 167 168 do { 169 hi = readl_relaxed(timer_of_base(&suspend_to) + 170 TIMER_VALUE_SHDW_HI); 171 lo = readl_relaxed(timer_of_base(&suspend_to) + 172 TIMER_VALUE_SHDW_LO); 173 } while (hi != readl_relaxed(timer_of_base(&suspend_to) + TIMER_VALUE_SHDW_HI)); 174 175 return ~(((u64)hi << 32) | lo); 176} 177 178static int sprd_suspend_timer_enable(struct clocksource *cs) 179{ 180 writel_relaxed(TIMER_VALUE_LO_MASK, 181 timer_of_base(&suspend_to) + TIMER_LOAD_LO); 182 writel_relaxed(TIMER_VALUE_HI_MASK, 183 timer_of_base(&suspend_to) + TIMER_LOAD_HI); 184 sprd_timer_enable(timer_of_base(&suspend_to), 185 TIMER_CTL_PERIOD_MODE|TIMER_CTL_64BIT_WIDTH); 186 187 return 0; 188} 189 190static void sprd_suspend_timer_disable(struct clocksource *cs) 191{ 192 sprd_timer_disable(timer_of_base(&suspend_to)); 193} 194 195static struct clocksource suspend_clocksource = { 196 .name = "sprd_suspend_timer", 197 .rating = 200, 198 .read = sprd_suspend_timer_read, 199 .enable = sprd_suspend_timer_enable, 200 .disable = sprd_suspend_timer_disable, 201 .mask = CLOCKSOURCE_MASK(64), 202 .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP, 203}; 204 205static int __init sprd_suspend_timer_init(struct device_node *np) 206{ 207 int ret; 208 209 ret = timer_of_init(np, &suspend_to); 210 if (ret) 211 return ret; 212 213 clocksource_register_hz(&suspend_clocksource, 214 timer_of_rate(&suspend_to)); 215 216 return 0; 217} 218 219TIMER_OF_DECLARE(sc9860_timer, "sprd,sc9860-timer", sprd_timer_init); 220TIMER_OF_DECLARE(sc9860_persistent_timer, "sprd,sc9860-suspend-timer", 221 sprd_suspend_timer_init);