Merge branch 'for-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
[sfrench/cifs-2.6.git] / drivers / clocksource / timer-sprd.c
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);