summaryrefslogtreecommitdiffstats
path: root/drivers/clocksource
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2017-05-18 16:17:01 -0400
committerDaniel Lezcano <daniel.lezcano@linaro.org>2017-06-12 04:14:00 -0400
commite7bad212ca0e6b1dcca1e0316ca8658c738c1206 (patch)
tree3d7b90061ad072196bbcc6c73439d18e9eccc40c /drivers/clocksource
parentdd98442e17a66318b021d4342abf53069cc8bed1 (diff)
clocksource/drivers/fttmr010: Use state container
This converts the Faraday FTTMR010 to use the state container design pattern. Take some care to handle the state container and free:ing of resources as has been done in the Moxa driver. Cc: Joel Stanley <joel@jms.id.au> Tested-by: Jonas Jensen <jonas.jensen@gmail.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/timer-fttmr010.c190
1 files changed, 116 insertions, 74 deletions
diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c
index db097db346e3..9ad31489bbef 100644
--- a/drivers/clocksource/timer-fttmr010.c
+++ b/drivers/clocksource/timer-fttmr010.c
@@ -15,6 +15,7 @@
15#include <linux/clocksource.h> 15#include <linux/clocksource.h>
16#include <linux/sched_clock.h> 16#include <linux/sched_clock.h>
17#include <linux/clk.h> 17#include <linux/clk.h>
18#include <linux/slab.h>
18 19
19/* 20/*
20 * Register definitions for the timers 21 * Register definitions for the timers
@@ -62,23 +63,35 @@
62#define TIMER_3_INT_OVERFLOW (1 << 8) 63#define TIMER_3_INT_OVERFLOW (1 << 8)
63#define TIMER_INT_ALL_MASK 0x1ff 64#define TIMER_INT_ALL_MASK 0x1ff
64 65
65static unsigned int tick_rate; 66struct fttmr010 {
66static void __iomem *base; 67 void __iomem *base;
68 unsigned int tick_rate;
69 struct clock_event_device clkevt;
70};
71
72/* A local singleton used by sched_clock, which is stateless */
73static struct fttmr010 *local_fttmr;
74
75static inline struct fttmr010 *to_fttmr010(struct clock_event_device *evt)
76{
77 return container_of(evt, struct fttmr010, clkevt);
78}
67 79
68static u64 notrace fttmr010_read_sched_clock(void) 80static u64 notrace fttmr010_read_sched_clock(void)
69{ 81{
70 return readl(base + TIMER3_COUNT); 82 return readl(local_fttmr->base + TIMER3_COUNT);
71} 83}
72 84
73static int fttmr010_timer_set_next_event(unsigned long cycles, 85static int fttmr010_timer_set_next_event(unsigned long cycles,
74 struct clock_event_device *evt) 86 struct clock_event_device *evt)
75{ 87{
88 struct fttmr010 *fttmr010 = to_fttmr010(evt);
76 u32 cr; 89 u32 cr;
77 90
78 /* Setup the match register */ 91 /* Setup the match register */
79 cr = readl(base + TIMER1_COUNT); 92 cr = readl(fttmr010->base + TIMER1_COUNT);
80 writel(cr + cycles, base + TIMER1_MATCH1); 93 writel(cr + cycles, fttmr010->base + TIMER1_MATCH1);
81 if (readl(base + TIMER1_COUNT) - cr > cycles) 94 if (readl(fttmr010->base + TIMER1_COUNT) - cr > cycles)
82 return -ETIME; 95 return -ETIME;
83 96
84 return 0; 97 return 0;
@@ -86,99 +99,90 @@ static int fttmr010_timer_set_next_event(unsigned long cycles,
86 99
87static int fttmr010_timer_shutdown(struct clock_event_device *evt) 100static int fttmr010_timer_shutdown(struct clock_event_device *evt)
88{ 101{
102 struct fttmr010 *fttmr010 = to_fttmr010(evt);
103 u32 cr;
104
105 /* Stop timer and interrupt. */
106 cr = readl(fttmr010->base + TIMER_CR);
107 cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
108 writel(cr, fttmr010->base + TIMER_CR);
109
110 return 0;
111}
112
113static int fttmr010_timer_set_oneshot(struct clock_event_device *evt)
114{
115 struct fttmr010 *fttmr010 = to_fttmr010(evt);
89 u32 cr; 116 u32 cr;
90 117
91 /*
92 * Disable also for oneshot: the set_next() call will arm the timer
93 * instead.
94 */
95 /* Stop timer and interrupt. */ 118 /* Stop timer and interrupt. */
96 cr = readl(base + TIMER_CR); 119 cr = readl(fttmr010->base + TIMER_CR);
97 cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); 120 cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
98 writel(cr, base + TIMER_CR); 121 writel(cr, fttmr010->base + TIMER_CR);
99 122
100 /* Setup counter start from 0 */ 123 /* Setup counter start from 0 */
101 writel(0, base + TIMER1_COUNT); 124 writel(0, fttmr010->base + TIMER1_COUNT);
102 writel(0, base + TIMER1_LOAD); 125 writel(0, fttmr010->base + TIMER1_LOAD);
103 126
104 /* enable interrupt */ 127 /* Enable interrupt */
105 cr = readl(base + TIMER_INTR_MASK); 128 cr = readl(fttmr010->base + TIMER_INTR_MASK);
106 cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); 129 cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2);
107 cr |= TIMER_1_INT_MATCH1; 130 cr |= TIMER_1_INT_MATCH1;
108 writel(cr, base + TIMER_INTR_MASK); 131 writel(cr, fttmr010->base + TIMER_INTR_MASK);
109 132
110 /* start the timer */ 133 /* Start the timer */
111 cr = readl(base + TIMER_CR); 134 cr = readl(fttmr010->base + TIMER_CR);
112 cr |= TIMER_1_CR_ENABLE; 135 cr |= TIMER_1_CR_ENABLE;
113 writel(cr, base + TIMER_CR); 136 writel(cr, fttmr010->base + TIMER_CR);
114 137
115 return 0; 138 return 0;
116} 139}
117 140
118static int fttmr010_timer_set_periodic(struct clock_event_device *evt) 141static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
119{ 142{
120 u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ); 143 struct fttmr010 *fttmr010 = to_fttmr010(evt);
144 u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ);
121 u32 cr; 145 u32 cr;
122 146
123 /* Stop timer and interrupt */ 147 /* Stop timer and interrupt */
124 cr = readl(base + TIMER_CR); 148 cr = readl(fttmr010->base + TIMER_CR);
125 cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); 149 cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT);
126 writel(cr, base + TIMER_CR); 150 writel(cr, fttmr010->base + TIMER_CR);
127 151
128 /* Setup timer to fire at 1/HT intervals. */ 152 /* Setup timer to fire at 1/HT intervals. */
129 cr = 0xffffffff - (period - 1); 153 cr = 0xffffffff - (period - 1);
130 writel(cr, base + TIMER1_COUNT); 154 writel(cr, fttmr010->base + TIMER1_COUNT);
131 writel(cr, base + TIMER1_LOAD); 155 writel(cr, fttmr010->base + TIMER1_LOAD);
132 156
133 /* enable interrupt on overflow */ 157 /* enable interrupt on overflow */
134 cr = readl(base + TIMER_INTR_MASK); 158 cr = readl(fttmr010->base + TIMER_INTR_MASK);
135 cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); 159 cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2);
136 cr |= TIMER_1_INT_OVERFLOW; 160 cr |= TIMER_1_INT_OVERFLOW;
137 writel(cr, base + TIMER_INTR_MASK); 161 writel(cr, fttmr010->base + TIMER_INTR_MASK);
138 162
139 /* Start the timer */ 163 /* Start the timer */
140 cr = readl(base + TIMER_CR); 164 cr = readl(fttmr010->base + TIMER_CR);
141 cr |= TIMER_1_CR_ENABLE; 165 cr |= TIMER_1_CR_ENABLE;
142 cr |= TIMER_1_CR_INT; 166 cr |= TIMER_1_CR_INT;
143 writel(cr, base + TIMER_CR); 167 writel(cr, fttmr010->base + TIMER_CR);
144 168
145 return 0; 169 return 0;
146} 170}
147 171
148/* Use TIMER1 as clock event */
149static struct clock_event_device fttmr010_clockevent = {
150 .name = "TIMER1",
151 /* Reasonably fast and accurate clock event */
152 .rating = 300,
153 .shift = 32,
154 .features = CLOCK_EVT_FEAT_PERIODIC |
155 CLOCK_EVT_FEAT_ONESHOT,
156 .set_next_event = fttmr010_timer_set_next_event,
157 .set_state_shutdown = fttmr010_timer_shutdown,
158 .set_state_periodic = fttmr010_timer_set_periodic,
159 .set_state_oneshot = fttmr010_timer_shutdown,
160 .tick_resume = fttmr010_timer_shutdown,
161};
162
163/* 172/*
164 * IRQ handler for the timer 173 * IRQ handler for the timer
165 */ 174 */
166static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id) 175static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id)
167{ 176{
168 struct clock_event_device *evt = &fttmr010_clockevent; 177 struct clock_event_device *evt = dev_id;
169 178
170 evt->event_handler(evt); 179 evt->event_handler(evt);
171 return IRQ_HANDLED; 180 return IRQ_HANDLED;
172} 181}
173 182
174static struct irqaction fttmr010_timer_irq = {
175 .name = "Faraday FTTMR010 Timer Tick",
176 .flags = IRQF_TIMER,
177 .handler = fttmr010_timer_interrupt,
178};
179
180static int __init fttmr010_timer_init(struct device_node *np) 183static int __init fttmr010_timer_init(struct device_node *np)
181{ 184{
185 struct fttmr010 *fttmr010;
182 int irq; 186 int irq;
183 struct clk *clk; 187 struct clk *clk;
184 int ret; 188 int ret;
@@ -198,53 +202,91 @@ static int __init fttmr010_timer_init(struct device_node *np)
198 pr_err("failed to enable PCLK\n"); 202 pr_err("failed to enable PCLK\n");
199 return ret; 203 return ret;
200 } 204 }
201 tick_rate = clk_get_rate(clk);
202 205
203 base = of_iomap(np, 0); 206 fttmr010 = kzalloc(sizeof(*fttmr010), GFP_KERNEL);
204 if (!base) { 207 if (!fttmr010) {
208 ret = -ENOMEM;
209 goto out_disable_clock;
210 }
211 fttmr010->tick_rate = clk_get_rate(clk);
212
213 fttmr010->base = of_iomap(np, 0);
214 if (!fttmr010->base) {
205 pr_err("Can't remap registers"); 215 pr_err("Can't remap registers");
206 return -ENXIO; 216 ret = -ENXIO;
217 goto out_free;
207 } 218 }
208 /* IRQ for timer 1 */ 219 /* IRQ for timer 1 */
209 irq = irq_of_parse_and_map(np, 0); 220 irq = irq_of_parse_and_map(np, 0);
210 if (irq <= 0) { 221 if (irq <= 0) {
211 pr_err("Can't parse IRQ"); 222 pr_err("Can't parse IRQ");
212 return -EINVAL; 223 ret = -EINVAL;
224 goto out_unmap;
213 } 225 }
214 226
215 /* 227 /*
216 * Reset the interrupt mask and status 228 * Reset the interrupt mask and status
217 */ 229 */
218 writel(TIMER_INT_ALL_MASK, base + TIMER_INTR_MASK); 230 writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK);
219 writel(0, base + TIMER_INTR_STATE); 231 writel(0, fttmr010->base + TIMER_INTR_STATE);
220 writel(TIMER_DEFAULT_FLAGS, base + TIMER_CR); 232 writel(TIMER_DEFAULT_FLAGS, fttmr010->base + TIMER_CR);
221 233
222 /* 234 /*
223 * Setup free-running clocksource timer (interrupts 235 * Setup free-running clocksource timer (interrupts
224 * disabled.) 236 * disabled.)
225 */ 237 */
226 writel(0, base + TIMER3_COUNT); 238 local_fttmr = fttmr010;
227 writel(0, base + TIMER3_LOAD); 239 writel(0, fttmr010->base + TIMER3_COUNT);
228 writel(0, base + TIMER3_MATCH1); 240 writel(0, fttmr010->base + TIMER3_LOAD);
229 writel(0, base + TIMER3_MATCH2); 241 writel(0, fttmr010->base + TIMER3_MATCH1);
230 clocksource_mmio_init(base + TIMER3_COUNT, 242 writel(0, fttmr010->base + TIMER3_MATCH2);
231 "fttmr010_clocksource", tick_rate, 243 clocksource_mmio_init(fttmr010->base + TIMER3_COUNT,
244 "FTTMR010-TIMER3",
245 fttmr010->tick_rate,
232 300, 32, clocksource_mmio_readl_up); 246 300, 32, clocksource_mmio_readl_up);
233 sched_clock_register(fttmr010_read_sched_clock, 32, tick_rate); 247 sched_clock_register(fttmr010_read_sched_clock, 32,
248 fttmr010->tick_rate);
234 249
235 /* 250 /*
236 * Setup clockevent timer (interrupt-driven.) 251 * Setup clockevent timer (interrupt-driven) on timer 1.
237 */ 252 */
238 writel(0, base + TIMER1_COUNT); 253 writel(0, fttmr010->base + TIMER1_COUNT);
239 writel(0, base + TIMER1_LOAD); 254 writel(0, fttmr010->base + TIMER1_LOAD);
240 writel(0, base + TIMER1_MATCH1); 255 writel(0, fttmr010->base + TIMER1_MATCH1);
241 writel(0, base + TIMER1_MATCH2); 256 writel(0, fttmr010->base + TIMER1_MATCH2);
242 setup_irq(irq, &fttmr010_timer_irq); 257 ret = request_irq(irq, fttmr010_timer_interrupt, IRQF_TIMER,
243 fttmr010_clockevent.cpumask = cpumask_of(0); 258 "FTTMR010-TIMER1", &fttmr010->clkevt);
244 clockevents_config_and_register(&fttmr010_clockevent, tick_rate, 259 if (ret) {
260 pr_err("FTTMR010-TIMER1 no IRQ\n");
261 goto out_unmap;
262 }
263
264 fttmr010->clkevt.name = "FTTMR010-TIMER1";
265 /* Reasonably fast and accurate clock event */
266 fttmr010->clkevt.rating = 300;
267 fttmr010->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
268 CLOCK_EVT_FEAT_ONESHOT;
269 fttmr010->clkevt.set_next_event = fttmr010_timer_set_next_event;
270 fttmr010->clkevt.set_state_shutdown = fttmr010_timer_shutdown;
271 fttmr010->clkevt.set_state_periodic = fttmr010_timer_set_periodic;
272 fttmr010->clkevt.set_state_oneshot = fttmr010_timer_set_oneshot;
273 fttmr010->clkevt.tick_resume = fttmr010_timer_shutdown;
274 fttmr010->clkevt.cpumask = cpumask_of(0);
275 fttmr010->clkevt.irq = irq;
276 clockevents_config_and_register(&fttmr010->clkevt,
277 fttmr010->tick_rate,
245 1, 0xffffffff); 278 1, 0xffffffff);
246 279
247 return 0; 280 return 0;
281
282out_unmap:
283 iounmap(fttmr010->base);
284out_free:
285 kfree(fttmr010);
286out_disable_clock:
287 clk_disable_unprepare(clk);
288
289 return ret;
248} 290}
249CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init); 291CLOCKSOURCE_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init);
250CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init); 292CLOCKSOURCE_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init);