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 34 static 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 52 static 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 60 static 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 66 static void sprd_timer_enable_interrupt(void __iomem *base) 67 { 68 writel_relaxed(TIMER_INT_EN, base + TIMER_INT); 69 } 70 71 static 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 79 static 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 91 static 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 102 static 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 110 static 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 124 static 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 144 static 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 159 TIMER_OF_DECLARE(sc9860_timer, "sprd,sc9860-timer", sprd_timer_init); 160