timer-sprd.c (4944B)
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 34static void sprd_timer_enable(void __iomem *base, u32 flag) 35{ 36 u32 val = readl_relaxed(base + TIMER_CTL); 37 38 val |= TIMER_CTL_ENABLE; 39 if (flag & TIMER_CTL_64BIT_WIDTH) 40 val |= TIMER_CTL_64BIT_WIDTH; 41 else 42 val &= ~TIMER_CTL_64BIT_WIDTH; 43 44 if (flag & TIMER_CTL_PERIOD_MODE) 45 val |= TIMER_CTL_PERIOD_MODE; 46 else 47 val &= ~TIMER_CTL_PERIOD_MODE; 48 49 writel_relaxed(val, base + TIMER_CTL); 50} 51 52static void sprd_timer_disable(void __iomem *base) 53{ 54 u32 val = readl_relaxed(base + TIMER_CTL); 55 56 val &= ~TIMER_CTL_ENABLE; 57 writel_relaxed(val, base + TIMER_CTL); 58} 59 60static void sprd_timer_update_counter(void __iomem *base, unsigned long cycles) 61{ 62 writel_relaxed(cycles & TIMER_VALUE_LO_MASK, base + TIMER_LOAD_LO); 63 writel_relaxed(0, base + TIMER_LOAD_HI); 64} 65 66static void sprd_timer_enable_interrupt(void __iomem *base) 67{ 68 writel_relaxed(TIMER_INT_EN, base + TIMER_INT); 69} 70 71static void sprd_timer_clear_interrupt(void __iomem *base) 72{ 73 u32 val = readl_relaxed(base + TIMER_INT); 74 75 val |= TIMER_INT_CLR; 76 writel_relaxed(val, base + TIMER_INT); 77} 78 79static int sprd_timer_set_next_event(unsigned long cycles, 80 struct clock_event_device *ce) 81{ 82 struct timer_of *to = to_timer_of(ce); 83 84 sprd_timer_disable(timer_of_base(to)); 85 sprd_timer_update_counter(timer_of_base(to), cycles); 86 sprd_timer_enable(timer_of_base(to), 0); 87 88 return 0; 89} 90 91static int sprd_timer_set_periodic(struct clock_event_device *ce) 92{ 93 struct timer_of *to = to_timer_of(ce); 94 95 sprd_timer_disable(timer_of_base(to)); 96 sprd_timer_update_counter(timer_of_base(to), timer_of_period(to)); 97 sprd_timer_enable(timer_of_base(to), TIMER_CTL_PERIOD_MODE); 98 99 return 0; 100} 101 102static int sprd_timer_shutdown(struct clock_event_device *ce) 103{ 104 struct timer_of *to = to_timer_of(ce); 105 106 sprd_timer_disable(timer_of_base(to)); 107 return 0; 108} 109 110static irqreturn_t sprd_timer_interrupt(int irq, void *dev_id) 111{ 112 struct clock_event_device *ce = (struct clock_event_device *)dev_id; 113 struct timer_of *to = to_timer_of(ce); 114 115 sprd_timer_clear_interrupt(timer_of_base(to)); 116 117 if (clockevent_state_oneshot(ce)) 118 sprd_timer_disable(timer_of_base(to)); 119 120 ce->event_handler(ce); 121 return IRQ_HANDLED; 122} 123 124static struct timer_of to = { 125 .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK, 126 127 .clkevt = { 128 .name = TIMER_NAME, 129 .rating = 300, 130 .features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_PERIODIC | 131 CLOCK_EVT_FEAT_ONESHOT, 132 .set_state_shutdown = sprd_timer_shutdown, 133 .set_state_periodic = sprd_timer_set_periodic, 134 .set_next_event = sprd_timer_set_next_event, 135 .cpumask = cpu_possible_mask, 136 }, 137 138 .of_irq = { 139 .handler = sprd_timer_interrupt, 140 .flags = IRQF_TIMER | IRQF_IRQPOLL, 141 }, 142}; 143 144static int __init sprd_timer_init(struct device_node *np) 145{ 146 int ret; 147 148 ret = timer_of_init(np, &to); 149 if (ret) 150 return ret; 151 152 sprd_timer_enable_interrupt(timer_of_base(&to)); 153 clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), 154 1, UINT_MAX); 155 156 return 0; 157} 158 159static struct timer_of suspend_to = { 160 .flags = TIMER_OF_BASE | TIMER_OF_CLOCK, 161}; 162 163static u64 sprd_suspend_timer_read(struct clocksource *cs) 164{ 165 return ~(u64)readl_relaxed(timer_of_base(&suspend_to) + 166 TIMER_VALUE_SHDW_LO) & cs->mask; 167} 168 169static int sprd_suspend_timer_enable(struct clocksource *cs) 170{ 171 sprd_timer_update_counter(timer_of_base(&suspend_to), 172 TIMER_VALUE_LO_MASK); 173 sprd_timer_enable(timer_of_base(&suspend_to), TIMER_CTL_PERIOD_MODE); 174 175 return 0; 176} 177 178static void sprd_suspend_timer_disable(struct clocksource *cs) 179{ 180 sprd_timer_disable(timer_of_base(&suspend_to)); 181} 182 183static struct clocksource suspend_clocksource = { 184 .name = "sprd_suspend_timer", 185 .rating = 200, 186 .read = sprd_suspend_timer_read, 187 .enable = sprd_suspend_timer_enable, 188 .disable = sprd_suspend_timer_disable, 189 .mask = CLOCKSOURCE_MASK(32), 190 .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP, 191}; 192 193static int __init sprd_suspend_timer_init(struct device_node *np) 194{ 195 int ret; 196 197 ret = timer_of_init(np, &suspend_to); 198 if (ret) 199 return ret; 200 201 clocksource_register_hz(&suspend_clocksource, 202 timer_of_rate(&suspend_to)); 203 204 return 0; 205} 206 207TIMER_OF_DECLARE(sc9860_timer, "sprd,sc9860-timer", sprd_timer_init); 208TIMER_OF_DECLARE(sc9860_persistent_timer, "sprd,sc9860-suspend-timer", 209 sprd_suspend_timer_init);