blob: 0779bf194aeaed1a1c383baec40113461944ad44 [file] [log] [blame]
Magnus Damm3fb1b6a2009-01-22 09:55:59 +00001/*
2 * SuperH Timer Support - CMT
3 *
4 * Copyright (C) 2008 Magnus Damm
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#include <linux/init.h>
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000021#include <linux/platform_device.h>
22#include <linux/spinlock.h>
23#include <linux/interrupt.h>
24#include <linux/ioport.h>
25#include <linux/io.h>
26#include <linux/clk.h>
27#include <linux/irq.h>
28#include <linux/err.h>
Magnus Damm3f7e5e22011-07-13 07:59:48 +000029#include <linux/delay.h>
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000030#include <linux/clocksource.h>
31#include <linux/clockchips.h>
Paul Mundt46a12f72009-05-03 17:57:17 +090032#include <linux/sh_timer.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Paul Gortmaker7deeab52011-07-03 13:36:22 -040034#include <linux/module.h>
Rafael J. Wysocki615a4452012-03-13 22:40:06 +010035#include <linux/pm_domain.h>
Rafael J. Wysockibad81382012-08-06 01:48:57 +020036#include <linux/pm_runtime.h>
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000037
Laurent Pinchart2653caf2014-01-27 22:04:17 +010038struct sh_cmt_device;
Laurent Pinchart7269f932014-01-27 15:29:19 +010039
40struct sh_cmt_channel {
Laurent Pinchart2653caf2014-01-27 22:04:17 +010041 struct sh_cmt_device *cmt;
Laurent Pinchart740a9512014-01-27 22:04:17 +010042 unsigned int index;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000043
Laurent Pinchartc924d2d2014-01-27 22:04:17 +010044 void __iomem *base;
45
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000046 unsigned long flags;
47 unsigned long match_value;
48 unsigned long next_match_value;
49 unsigned long max_match_value;
50 unsigned long rate;
Paul Mundt7d0c3992012-05-25 13:36:43 +090051 raw_spinlock_t lock;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000052 struct clock_event_device ced;
Magnus Damm19bdc9d2009-04-17 05:26:31 +000053 struct clocksource cs;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000054 unsigned long total_cycles;
Rafael J. Wysockibad81382012-08-06 01:48:57 +020055 bool cs_enabled;
Laurent Pinchart7269f932014-01-27 15:29:19 +010056};
57
Laurent Pinchart2653caf2014-01-27 22:04:17 +010058struct sh_cmt_device {
Laurent Pinchart7269f932014-01-27 15:29:19 +010059 struct platform_device *pdev;
60
Laurent Pinchart36f1ac92014-01-27 22:04:17 +010061 void __iomem *mapbase_ch;
Laurent Pinchart7269f932014-01-27 15:29:19 +010062 void __iomem *mapbase;
Laurent Pinchart7269f932014-01-27 15:29:19 +010063 struct clk *clk;
64
65 struct sh_cmt_channel channel;
66
67 unsigned long width; /* 16 or 32 bit version of hardware block */
68 unsigned long overflow_bit;
69 unsigned long clear_bits;
Magnus Damma6a912c2012-12-14 14:54:19 +090070
Magnus Dammcccd7042012-12-14 14:54:28 +090071 /* callbacks for CMSTR and CMCSR access */
72 unsigned long (*read_control)(void __iomem *base, unsigned long offs);
73 void (*write_control)(void __iomem *base, unsigned long offs,
74 unsigned long value);
75
Magnus Damma6a912c2012-12-14 14:54:19 +090076 /* callbacks for CMCNT and CMCOR access */
77 unsigned long (*read_count)(void __iomem *base, unsigned long offs);
78 void (*write_count)(void __iomem *base, unsigned long offs,
79 unsigned long value);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000080};
81
Magnus Damm118aee42012-12-14 14:54:37 +090082/* Examples of supported CMT timer register layouts and I/O access widths:
83 *
84 * "16-bit counter and 16-bit control" as found on sh7263:
85 * CMSTR 0xfffec000 16-bit
86 * CMCSR 0xfffec002 16-bit
87 * CMCNT 0xfffec004 16-bit
88 * CMCOR 0xfffec006 16-bit
89 *
90 * "32-bit counter and 16-bit control" as found on sh7372, sh73a0, r8a7740:
91 * CMSTR 0xffca0000 16-bit
92 * CMCSR 0xffca0060 16-bit
93 * CMCNT 0xffca0064 32-bit
94 * CMCOR 0xffca0068 32-bit
Magnus Damm8874c5e2013-06-17 15:40:52 +090095 *
96 * "32-bit counter and 32-bit control" as found on r8a73a4 and r8a7790:
97 * CMSTR 0xffca0500 32-bit
98 * CMCSR 0xffca0510 32-bit
99 * CMCNT 0xffca0514 32-bit
100 * CMCOR 0xffca0518 32-bit
Magnus Damm118aee42012-12-14 14:54:37 +0900101 */
102
Magnus Damma6a912c2012-12-14 14:54:19 +0900103static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs)
Magnus Damm587acb32012-12-14 14:54:10 +0900104{
105 return ioread16(base + (offs << 1));
106}
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000107
Magnus Damma6a912c2012-12-14 14:54:19 +0900108static unsigned long sh_cmt_read32(void __iomem *base, unsigned long offs)
109{
110 return ioread32(base + (offs << 2));
111}
112
113static void sh_cmt_write16(void __iomem *base, unsigned long offs,
114 unsigned long value)
Magnus Damm587acb32012-12-14 14:54:10 +0900115{
116 iowrite16(value, base + (offs << 1));
117}
118
Magnus Damma6a912c2012-12-14 14:54:19 +0900119static void sh_cmt_write32(void __iomem *base, unsigned long offs,
120 unsigned long value)
121{
122 iowrite32(value, base + (offs << 2));
123}
124
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000125#define CMCSR 0 /* channel register */
126#define CMCNT 1 /* channel register */
127#define CMCOR 2 /* channel register */
128
Laurent Pinchart7269f932014-01-27 15:29:19 +0100129static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_channel *ch)
Magnus Damm1b56b962012-12-14 14:54:00 +0900130{
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100131 return ch->cmt->read_control(ch->cmt->mapbase, 0);
Magnus Damm1b56b962012-12-14 14:54:00 +0900132}
133
Laurent Pinchart7269f932014-01-27 15:29:19 +0100134static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_channel *ch)
Magnus Damm1b56b962012-12-14 14:54:00 +0900135{
Laurent Pinchartc924d2d2014-01-27 22:04:17 +0100136 return ch->cmt->read_control(ch->base, CMCSR);
Magnus Damm1b56b962012-12-14 14:54:00 +0900137}
138
Laurent Pinchart7269f932014-01-27 15:29:19 +0100139static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_channel *ch)
Magnus Damm1b56b962012-12-14 14:54:00 +0900140{
Laurent Pinchartc924d2d2014-01-27 22:04:17 +0100141 return ch->cmt->read_count(ch->base, CMCNT);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000142}
143
Laurent Pinchart7269f932014-01-27 15:29:19 +0100144static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch,
Magnus Damm1b56b962012-12-14 14:54:00 +0900145 unsigned long value)
146{
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100147 ch->cmt->write_control(ch->cmt->mapbase, 0, value);
Magnus Damm1b56b962012-12-14 14:54:00 +0900148}
149
Laurent Pinchart7269f932014-01-27 15:29:19 +0100150static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch,
Magnus Damm1b56b962012-12-14 14:54:00 +0900151 unsigned long value)
152{
Laurent Pinchartc924d2d2014-01-27 22:04:17 +0100153 ch->cmt->write_control(ch->base, CMCSR, value);
Magnus Damm1b56b962012-12-14 14:54:00 +0900154}
155
Laurent Pinchart7269f932014-01-27 15:29:19 +0100156static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch,
Magnus Damm1b56b962012-12-14 14:54:00 +0900157 unsigned long value)
158{
Laurent Pinchartc924d2d2014-01-27 22:04:17 +0100159 ch->cmt->write_count(ch->base, CMCNT, value);
Magnus Damm1b56b962012-12-14 14:54:00 +0900160}
161
Laurent Pinchart7269f932014-01-27 15:29:19 +0100162static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch,
Magnus Damm1b56b962012-12-14 14:54:00 +0900163 unsigned long value)
164{
Laurent Pinchartc924d2d2014-01-27 22:04:17 +0100165 ch->cmt->write_count(ch->base, CMCOR, value);
Magnus Damm1b56b962012-12-14 14:54:00 +0900166}
167
Laurent Pinchart7269f932014-01-27 15:29:19 +0100168static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000169 int *has_wrapped)
170{
171 unsigned long v1, v2, v3;
Magnus Damm5b644c72009-04-28 08:17:54 +0000172 int o1, o2;
173
Laurent Pinchart7269f932014-01-27 15:29:19 +0100174 o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->overflow_bit;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000175
176 /* Make sure the timer value is stable. Stolen from acpi_pm.c */
177 do {
Magnus Damm5b644c72009-04-28 08:17:54 +0000178 o2 = o1;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100179 v1 = sh_cmt_read_cmcnt(ch);
180 v2 = sh_cmt_read_cmcnt(ch);
181 v3 = sh_cmt_read_cmcnt(ch);
182 o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->overflow_bit;
Magnus Damm5b644c72009-04-28 08:17:54 +0000183 } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
184 || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000185
Magnus Damm5b644c72009-04-28 08:17:54 +0000186 *has_wrapped = o1;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000187 return v2;
188}
189
Magnus Damm587acb32012-12-14 14:54:10 +0900190static DEFINE_RAW_SPINLOCK(sh_cmt_lock);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000191
Laurent Pinchart7269f932014-01-27 15:29:19 +0100192static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000193{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100194 struct sh_timer_config *cfg = ch->cmt->pdev->dev.platform_data;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000195 unsigned long flags, value;
196
197 /* start stop register shared by multiple timer channels */
Paul Mundt7d0c3992012-05-25 13:36:43 +0900198 raw_spin_lock_irqsave(&sh_cmt_lock, flags);
Laurent Pinchart7269f932014-01-27 15:29:19 +0100199 value = sh_cmt_read_cmstr(ch);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000200
201 if (start)
202 value |= 1 << cfg->timer_bit;
203 else
204 value &= ~(1 << cfg->timer_bit);
205
Laurent Pinchart7269f932014-01-27 15:29:19 +0100206 sh_cmt_write_cmstr(ch, value);
Paul Mundt7d0c3992012-05-25 13:36:43 +0900207 raw_spin_unlock_irqrestore(&sh_cmt_lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000208}
209
Laurent Pinchart7269f932014-01-27 15:29:19 +0100210static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000211{
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000212 int k, ret;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000213
Laurent Pinchart7269f932014-01-27 15:29:19 +0100214 pm_runtime_get_sync(&ch->cmt->pdev->dev);
215 dev_pm_syscore_device(&ch->cmt->pdev->dev, true);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200216
Paul Mundt9436b4a2011-05-31 15:26:42 +0900217 /* enable clock */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100218 ret = clk_enable(ch->cmt->clk);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000219 if (ret) {
Laurent Pinchart740a9512014-01-27 22:04:17 +0100220 dev_err(&ch->cmt->pdev->dev, "ch%u: cannot enable clock\n",
221 ch->index);
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000222 goto err0;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000223 }
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000224
225 /* make sure channel is disabled */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100226 sh_cmt_start_stop_ch(ch, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000227
228 /* configure channel, periodic mode and maximum timeout */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100229 if (ch->cmt->width == 16) {
230 *rate = clk_get_rate(ch->cmt->clk) / 512;
231 sh_cmt_write_cmcsr(ch, 0x43);
Magnus Damm3014f472009-04-29 14:50:37 +0000232 } else {
Laurent Pinchart7269f932014-01-27 15:29:19 +0100233 *rate = clk_get_rate(ch->cmt->clk) / 8;
234 sh_cmt_write_cmcsr(ch, 0x01a4);
Magnus Damm3014f472009-04-29 14:50:37 +0000235 }
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000236
Laurent Pinchart7269f932014-01-27 15:29:19 +0100237 sh_cmt_write_cmcor(ch, 0xffffffff);
238 sh_cmt_write_cmcnt(ch, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000239
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000240 /*
241 * According to the sh73a0 user's manual, as CMCNT can be operated
242 * only by the RCLK (Pseudo 32 KHz), there's one restriction on
243 * modifying CMCNT register; two RCLK cycles are necessary before
244 * this register is either read or any modification of the value
245 * it holds is reflected in the LSI's actual operation.
246 *
247 * While at it, we're supposed to clear out the CMCNT as of this
248 * moment, so make sure it's processed properly here. This will
249 * take RCLKx2 at maximum.
250 */
251 for (k = 0; k < 100; k++) {
Laurent Pinchart7269f932014-01-27 15:29:19 +0100252 if (!sh_cmt_read_cmcnt(ch))
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000253 break;
254 udelay(1);
255 }
256
Laurent Pinchart7269f932014-01-27 15:29:19 +0100257 if (sh_cmt_read_cmcnt(ch)) {
Laurent Pinchart740a9512014-01-27 22:04:17 +0100258 dev_err(&ch->cmt->pdev->dev, "ch%u: cannot clear CMCNT\n",
259 ch->index);
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000260 ret = -ETIMEDOUT;
261 goto err1;
262 }
263
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000264 /* enable channel */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100265 sh_cmt_start_stop_ch(ch, 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000266 return 0;
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000267 err1:
268 /* stop clock */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100269 clk_disable(ch->cmt->clk);
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000270
271 err0:
272 return ret;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000273}
274
Laurent Pinchart7269f932014-01-27 15:29:19 +0100275static void sh_cmt_disable(struct sh_cmt_channel *ch)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000276{
277 /* disable channel */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100278 sh_cmt_start_stop_ch(ch, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000279
Magnus Dammbe890a12009-06-17 05:04:04 +0000280 /* disable interrupts in CMT block */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100281 sh_cmt_write_cmcsr(ch, 0);
Magnus Dammbe890a12009-06-17 05:04:04 +0000282
Paul Mundt9436b4a2011-05-31 15:26:42 +0900283 /* stop clock */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100284 clk_disable(ch->cmt->clk);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200285
Laurent Pinchart7269f932014-01-27 15:29:19 +0100286 dev_pm_syscore_device(&ch->cmt->pdev->dev, false);
287 pm_runtime_put(&ch->cmt->pdev->dev);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000288}
289
290/* private flags */
291#define FLAG_CLOCKEVENT (1 << 0)
292#define FLAG_CLOCKSOURCE (1 << 1)
293#define FLAG_REPROGRAM (1 << 2)
294#define FLAG_SKIPEVENT (1 << 3)
295#define FLAG_IRQCONTEXT (1 << 4)
296
Laurent Pinchart7269f932014-01-27 15:29:19 +0100297static void sh_cmt_clock_event_program_verify(struct sh_cmt_channel *ch,
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000298 int absolute)
299{
300 unsigned long new_match;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100301 unsigned long value = ch->next_match_value;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000302 unsigned long delay = 0;
303 unsigned long now = 0;
304 int has_wrapped;
305
Laurent Pinchart7269f932014-01-27 15:29:19 +0100306 now = sh_cmt_get_counter(ch, &has_wrapped);
307 ch->flags |= FLAG_REPROGRAM; /* force reprogram */
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000308
309 if (has_wrapped) {
310 /* we're competing with the interrupt handler.
311 * -> let the interrupt handler reprogram the timer.
312 * -> interrupt number two handles the event.
313 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100314 ch->flags |= FLAG_SKIPEVENT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000315 return;
316 }
317
318 if (absolute)
319 now = 0;
320
321 do {
322 /* reprogram the timer hardware,
323 * but don't save the new match value yet.
324 */
325 new_match = now + value + delay;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100326 if (new_match > ch->max_match_value)
327 new_match = ch->max_match_value;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000328
Laurent Pinchart7269f932014-01-27 15:29:19 +0100329 sh_cmt_write_cmcor(ch, new_match);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000330
Laurent Pinchart7269f932014-01-27 15:29:19 +0100331 now = sh_cmt_get_counter(ch, &has_wrapped);
332 if (has_wrapped && (new_match > ch->match_value)) {
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000333 /* we are changing to a greater match value,
334 * so this wrap must be caused by the counter
335 * matching the old value.
336 * -> first interrupt reprograms the timer.
337 * -> interrupt number two handles the event.
338 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100339 ch->flags |= FLAG_SKIPEVENT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000340 break;
341 }
342
343 if (has_wrapped) {
344 /* we are changing to a smaller match value,
345 * so the wrap must be caused by the counter
346 * matching the new value.
347 * -> save programmed match value.
348 * -> let isr handle the event.
349 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100350 ch->match_value = new_match;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000351 break;
352 }
353
354 /* be safe: verify hardware settings */
355 if (now < new_match) {
356 /* timer value is below match value, all good.
357 * this makes sure we won't miss any match events.
358 * -> save programmed match value.
359 * -> let isr handle the event.
360 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100361 ch->match_value = new_match;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000362 break;
363 }
364
365 /* the counter has reached a value greater
366 * than our new match value. and since the
367 * has_wrapped flag isn't set we must have
368 * programmed a too close event.
369 * -> increase delay and retry.
370 */
371 if (delay)
372 delay <<= 1;
373 else
374 delay = 1;
375
376 if (!delay)
Laurent Pinchart740a9512014-01-27 22:04:17 +0100377 dev_warn(&ch->cmt->pdev->dev, "ch%u: too long delay\n",
378 ch->index);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000379
380 } while (delay);
381}
382
Laurent Pinchart7269f932014-01-27 15:29:19 +0100383static void __sh_cmt_set_next(struct sh_cmt_channel *ch, unsigned long delta)
Takashi YOSHII65ada542010-12-17 07:25:09 +0000384{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100385 if (delta > ch->max_match_value)
Laurent Pinchart740a9512014-01-27 22:04:17 +0100386 dev_warn(&ch->cmt->pdev->dev, "ch%u: delta out of range\n",
387 ch->index);
Takashi YOSHII65ada542010-12-17 07:25:09 +0000388
Laurent Pinchart7269f932014-01-27 15:29:19 +0100389 ch->next_match_value = delta;
390 sh_cmt_clock_event_program_verify(ch, 0);
Takashi YOSHII65ada542010-12-17 07:25:09 +0000391}
392
Laurent Pinchart7269f932014-01-27 15:29:19 +0100393static void sh_cmt_set_next(struct sh_cmt_channel *ch, unsigned long delta)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000394{
395 unsigned long flags;
396
Laurent Pinchart7269f932014-01-27 15:29:19 +0100397 raw_spin_lock_irqsave(&ch->lock, flags);
398 __sh_cmt_set_next(ch, delta);
399 raw_spin_unlock_irqrestore(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000400}
401
402static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)
403{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100404 struct sh_cmt_channel *ch = dev_id;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000405
406 /* clear flags */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100407 sh_cmt_write_cmcsr(ch, sh_cmt_read_cmcsr(ch) & ch->cmt->clear_bits);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000408
409 /* update clock source counter to begin with if enabled
410 * the wrap flag should be cleared by the timer specific
411 * isr before we end up here.
412 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100413 if (ch->flags & FLAG_CLOCKSOURCE)
414 ch->total_cycles += ch->match_value + 1;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000415
Laurent Pinchart7269f932014-01-27 15:29:19 +0100416 if (!(ch->flags & FLAG_REPROGRAM))
417 ch->next_match_value = ch->max_match_value;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000418
Laurent Pinchart7269f932014-01-27 15:29:19 +0100419 ch->flags |= FLAG_IRQCONTEXT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000420
Laurent Pinchart7269f932014-01-27 15:29:19 +0100421 if (ch->flags & FLAG_CLOCKEVENT) {
422 if (!(ch->flags & FLAG_SKIPEVENT)) {
423 if (ch->ced.mode == CLOCK_EVT_MODE_ONESHOT) {
424 ch->next_match_value = ch->max_match_value;
425 ch->flags |= FLAG_REPROGRAM;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000426 }
427
Laurent Pinchart7269f932014-01-27 15:29:19 +0100428 ch->ced.event_handler(&ch->ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000429 }
430 }
431
Laurent Pinchart7269f932014-01-27 15:29:19 +0100432 ch->flags &= ~FLAG_SKIPEVENT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000433
Laurent Pinchart7269f932014-01-27 15:29:19 +0100434 if (ch->flags & FLAG_REPROGRAM) {
435 ch->flags &= ~FLAG_REPROGRAM;
436 sh_cmt_clock_event_program_verify(ch, 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000437
Laurent Pinchart7269f932014-01-27 15:29:19 +0100438 if (ch->flags & FLAG_CLOCKEVENT)
439 if ((ch->ced.mode == CLOCK_EVT_MODE_SHUTDOWN)
440 || (ch->match_value == ch->next_match_value))
441 ch->flags &= ~FLAG_REPROGRAM;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000442 }
443
Laurent Pinchart7269f932014-01-27 15:29:19 +0100444 ch->flags &= ~FLAG_IRQCONTEXT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000445
446 return IRQ_HANDLED;
447}
448
Laurent Pinchart7269f932014-01-27 15:29:19 +0100449static int sh_cmt_start(struct sh_cmt_channel *ch, unsigned long flag)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000450{
451 int ret = 0;
452 unsigned long flags;
453
Laurent Pinchart7269f932014-01-27 15:29:19 +0100454 raw_spin_lock_irqsave(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000455
Laurent Pinchart7269f932014-01-27 15:29:19 +0100456 if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
457 ret = sh_cmt_enable(ch, &ch->rate);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000458
459 if (ret)
460 goto out;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100461 ch->flags |= flag;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000462
463 /* setup timeout if no clockevent */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100464 if ((flag == FLAG_CLOCKSOURCE) && (!(ch->flags & FLAG_CLOCKEVENT)))
465 __sh_cmt_set_next(ch, ch->max_match_value);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000466 out:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100467 raw_spin_unlock_irqrestore(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000468
469 return ret;
470}
471
Laurent Pinchart7269f932014-01-27 15:29:19 +0100472static void sh_cmt_stop(struct sh_cmt_channel *ch, unsigned long flag)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000473{
474 unsigned long flags;
475 unsigned long f;
476
Laurent Pinchart7269f932014-01-27 15:29:19 +0100477 raw_spin_lock_irqsave(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000478
Laurent Pinchart7269f932014-01-27 15:29:19 +0100479 f = ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE);
480 ch->flags &= ~flag;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000481
Laurent Pinchart7269f932014-01-27 15:29:19 +0100482 if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
483 sh_cmt_disable(ch);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000484
485 /* adjust the timeout to maximum if only clocksource left */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100486 if ((flag == FLAG_CLOCKEVENT) && (ch->flags & FLAG_CLOCKSOURCE))
487 __sh_cmt_set_next(ch, ch->max_match_value);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000488
Laurent Pinchart7269f932014-01-27 15:29:19 +0100489 raw_spin_unlock_irqrestore(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000490}
491
Laurent Pinchart7269f932014-01-27 15:29:19 +0100492static struct sh_cmt_channel *cs_to_sh_cmt(struct clocksource *cs)
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000493{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100494 return container_of(cs, struct sh_cmt_channel, cs);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000495}
496
497static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
498{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100499 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000500 unsigned long flags, raw;
501 unsigned long value;
502 int has_wrapped;
503
Laurent Pinchart7269f932014-01-27 15:29:19 +0100504 raw_spin_lock_irqsave(&ch->lock, flags);
505 value = ch->total_cycles;
506 raw = sh_cmt_get_counter(ch, &has_wrapped);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000507
508 if (unlikely(has_wrapped))
Laurent Pinchart7269f932014-01-27 15:29:19 +0100509 raw += ch->match_value + 1;
510 raw_spin_unlock_irqrestore(&ch->lock, flags);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000511
512 return value + raw;
513}
514
515static int sh_cmt_clocksource_enable(struct clocksource *cs)
516{
Magnus Damm3593f5f2011-04-25 22:32:11 +0900517 int ret;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100518 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000519
Laurent Pinchart7269f932014-01-27 15:29:19 +0100520 WARN_ON(ch->cs_enabled);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200521
Laurent Pinchart7269f932014-01-27 15:29:19 +0100522 ch->total_cycles = 0;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000523
Laurent Pinchart7269f932014-01-27 15:29:19 +0100524 ret = sh_cmt_start(ch, FLAG_CLOCKSOURCE);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200525 if (!ret) {
Laurent Pinchart7269f932014-01-27 15:29:19 +0100526 __clocksource_updatefreq_hz(cs, ch->rate);
527 ch->cs_enabled = true;
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200528 }
Magnus Damm3593f5f2011-04-25 22:32:11 +0900529 return ret;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000530}
531
532static void sh_cmt_clocksource_disable(struct clocksource *cs)
533{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100534 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200535
Laurent Pinchart7269f932014-01-27 15:29:19 +0100536 WARN_ON(!ch->cs_enabled);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200537
Laurent Pinchart7269f932014-01-27 15:29:19 +0100538 sh_cmt_stop(ch, FLAG_CLOCKSOURCE);
539 ch->cs_enabled = false;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000540}
541
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200542static void sh_cmt_clocksource_suspend(struct clocksource *cs)
543{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100544 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200545
Laurent Pinchart7269f932014-01-27 15:29:19 +0100546 sh_cmt_stop(ch, FLAG_CLOCKSOURCE);
547 pm_genpd_syscore_poweroff(&ch->cmt->pdev->dev);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200548}
549
Magnus Dammc8162882010-02-02 14:41:40 -0800550static void sh_cmt_clocksource_resume(struct clocksource *cs)
551{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100552 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200553
Laurent Pinchart7269f932014-01-27 15:29:19 +0100554 pm_genpd_syscore_poweron(&ch->cmt->pdev->dev);
555 sh_cmt_start(ch, FLAG_CLOCKSOURCE);
Magnus Dammc8162882010-02-02 14:41:40 -0800556}
557
Laurent Pinchart7269f932014-01-27 15:29:19 +0100558static int sh_cmt_register_clocksource(struct sh_cmt_channel *ch,
Laurent Pinchart1d053e12014-02-17 16:04:16 +0100559 const char *name, unsigned long rating)
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000560{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100561 struct clocksource *cs = &ch->cs;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000562
563 cs->name = name;
564 cs->rating = rating;
565 cs->read = sh_cmt_clocksource_read;
566 cs->enable = sh_cmt_clocksource_enable;
567 cs->disable = sh_cmt_clocksource_disable;
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200568 cs->suspend = sh_cmt_clocksource_suspend;
Magnus Dammc8162882010-02-02 14:41:40 -0800569 cs->resume = sh_cmt_clocksource_resume;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000570 cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
571 cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
Paul Mundtf4d7c352010-06-02 17:10:44 +0900572
Laurent Pinchart740a9512014-01-27 22:04:17 +0100573 dev_info(&ch->cmt->pdev->dev, "ch%u: used as clock source\n",
574 ch->index);
Paul Mundtf4d7c352010-06-02 17:10:44 +0900575
Magnus Damm3593f5f2011-04-25 22:32:11 +0900576 /* Register with dummy 1 Hz value, gets updated in ->enable() */
577 clocksource_register_hz(cs, 1);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000578 return 0;
579}
580
Laurent Pinchart7269f932014-01-27 15:29:19 +0100581static struct sh_cmt_channel *ced_to_sh_cmt(struct clock_event_device *ced)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000582{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100583 return container_of(ced, struct sh_cmt_channel, ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000584}
585
Laurent Pinchart7269f932014-01-27 15:29:19 +0100586static void sh_cmt_clock_event_start(struct sh_cmt_channel *ch, int periodic)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000587{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100588 struct clock_event_device *ced = &ch->ced;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000589
Laurent Pinchart7269f932014-01-27 15:29:19 +0100590 sh_cmt_start(ch, FLAG_CLOCKEVENT);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000591
592 /* TODO: calculate good shift from rate and counter bit width */
593
594 ced->shift = 32;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100595 ced->mult = div_sc(ch->rate, NSEC_PER_SEC, ced->shift);
596 ced->max_delta_ns = clockevent_delta2ns(ch->max_match_value, ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000597 ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
598
599 if (periodic)
Laurent Pinchart7269f932014-01-27 15:29:19 +0100600 sh_cmt_set_next(ch, ((ch->rate + HZ/2) / HZ) - 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000601 else
Laurent Pinchart7269f932014-01-27 15:29:19 +0100602 sh_cmt_set_next(ch, ch->max_match_value);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000603}
604
605static void sh_cmt_clock_event_mode(enum clock_event_mode mode,
606 struct clock_event_device *ced)
607{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100608 struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000609
610 /* deal with old setting first */
611 switch (ced->mode) {
612 case CLOCK_EVT_MODE_PERIODIC:
613 case CLOCK_EVT_MODE_ONESHOT:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100614 sh_cmt_stop(ch, FLAG_CLOCKEVENT);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000615 break;
616 default:
617 break;
618 }
619
620 switch (mode) {
621 case CLOCK_EVT_MODE_PERIODIC:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100622 dev_info(&ch->cmt->pdev->dev,
Laurent Pinchart740a9512014-01-27 22:04:17 +0100623 "ch%u: used for periodic clock events\n", ch->index);
Laurent Pinchart7269f932014-01-27 15:29:19 +0100624 sh_cmt_clock_event_start(ch, 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000625 break;
626 case CLOCK_EVT_MODE_ONESHOT:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100627 dev_info(&ch->cmt->pdev->dev,
Laurent Pinchart740a9512014-01-27 22:04:17 +0100628 "ch%u: used for oneshot clock events\n", ch->index);
Laurent Pinchart7269f932014-01-27 15:29:19 +0100629 sh_cmt_clock_event_start(ch, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000630 break;
631 case CLOCK_EVT_MODE_SHUTDOWN:
632 case CLOCK_EVT_MODE_UNUSED:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100633 sh_cmt_stop(ch, FLAG_CLOCKEVENT);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000634 break;
635 default:
636 break;
637 }
638}
639
640static int sh_cmt_clock_event_next(unsigned long delta,
641 struct clock_event_device *ced)
642{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100643 struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000644
645 BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
Laurent Pinchart7269f932014-01-27 15:29:19 +0100646 if (likely(ch->flags & FLAG_IRQCONTEXT))
647 ch->next_match_value = delta - 1;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000648 else
Laurent Pinchart7269f932014-01-27 15:29:19 +0100649 sh_cmt_set_next(ch, delta - 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000650
651 return 0;
652}
653
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200654static void sh_cmt_clock_event_suspend(struct clock_event_device *ced)
655{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100656 struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
Laurent Pinchart57dee992013-12-14 15:07:32 +0900657
Laurent Pinchart7269f932014-01-27 15:29:19 +0100658 pm_genpd_syscore_poweroff(&ch->cmt->pdev->dev);
659 clk_unprepare(ch->cmt->clk);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200660}
661
662static void sh_cmt_clock_event_resume(struct clock_event_device *ced)
663{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100664 struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
Laurent Pinchart57dee992013-12-14 15:07:32 +0900665
Laurent Pinchart7269f932014-01-27 15:29:19 +0100666 clk_prepare(ch->cmt->clk);
667 pm_genpd_syscore_poweron(&ch->cmt->pdev->dev);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200668}
669
Laurent Pinchart7269f932014-01-27 15:29:19 +0100670static void sh_cmt_register_clockevent(struct sh_cmt_channel *ch,
Laurent Pinchart1d053e12014-02-17 16:04:16 +0100671 const char *name, unsigned long rating)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000672{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100673 struct clock_event_device *ced = &ch->ced;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000674
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000675 ced->name = name;
676 ced->features = CLOCK_EVT_FEAT_PERIODIC;
677 ced->features |= CLOCK_EVT_FEAT_ONESHOT;
678 ced->rating = rating;
679 ced->cpumask = cpumask_of(0);
680 ced->set_next_event = sh_cmt_clock_event_next;
681 ced->set_mode = sh_cmt_clock_event_mode;
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200682 ced->suspend = sh_cmt_clock_event_suspend;
683 ced->resume = sh_cmt_clock_event_resume;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000684
Laurent Pinchart740a9512014-01-27 22:04:17 +0100685 dev_info(&ch->cmt->pdev->dev, "ch%u: used for clock events\n",
686 ch->index);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000687 clockevents_register_device(ced);
688}
689
Laurent Pinchart1d053e12014-02-17 16:04:16 +0100690static int sh_cmt_register(struct sh_cmt_channel *ch, const char *name,
Paul Mundtd1fcc0a2009-05-03 18:05:42 +0900691 unsigned long clockevent_rating,
692 unsigned long clocksource_rating)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000693{
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000694 if (clockevent_rating)
Laurent Pinchart7269f932014-01-27 15:29:19 +0100695 sh_cmt_register_clockevent(ch, name, clockevent_rating);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000696
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000697 if (clocksource_rating)
Laurent Pinchart7269f932014-01-27 15:29:19 +0100698 sh_cmt_register_clocksource(ch, name, clocksource_rating);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000699
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000700 return 0;
701}
702
Laurent Pinchart740a9512014-01-27 22:04:17 +0100703static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100704 struct sh_cmt_device *cmt)
705{
706 struct sh_timer_config *cfg = cmt->pdev->dev.platform_data;
707 int irq;
708 int ret;
709
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100710 ch->cmt = cmt;
Laurent Pinchartc924d2d2014-01-27 22:04:17 +0100711 ch->base = cmt->mapbase_ch;
Laurent Pinchart740a9512014-01-27 22:04:17 +0100712 ch->index = index;
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100713
714 irq = platform_get_irq(cmt->pdev, 0);
715 if (irq < 0) {
Laurent Pinchart740a9512014-01-27 22:04:17 +0100716 dev_err(&cmt->pdev->dev, "ch%u: failed to get irq\n",
717 ch->index);
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100718 return irq;
719 }
720
721 if (cmt->width == (sizeof(ch->max_match_value) * 8))
722 ch->max_match_value = ~0;
723 else
724 ch->max_match_value = (1 << cmt->width) - 1;
725
726 ch->match_value = ch->max_match_value;
727 raw_spin_lock_init(&ch->lock);
728
Laurent Pinchart1d053e12014-02-17 16:04:16 +0100729 ret = sh_cmt_register(ch, dev_name(&cmt->pdev->dev),
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100730 cfg->clockevent_rating,
731 cfg->clocksource_rating);
732 if (ret) {
Laurent Pinchart740a9512014-01-27 22:04:17 +0100733 dev_err(&cmt->pdev->dev, "ch%u: registration failed\n",
734 ch->index);
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100735 return ret;
736 }
737 ch->cs_enabled = false;
738
739 ret = request_irq(irq, sh_cmt_interrupt,
740 IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
741 dev_name(&cmt->pdev->dev), ch);
742 if (ret) {
Laurent Pinchart740a9512014-01-27 22:04:17 +0100743 dev_err(&cmt->pdev->dev, "ch%u: failed to request irq %d\n",
744 ch->index, irq);
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100745 return ret;
746 }
747
748 return 0;
749}
750
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100751static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000752{
Paul Mundt46a12f72009-05-03 17:57:17 +0900753 struct sh_timer_config *cfg = pdev->dev.platform_data;
Magnus Damm8874c5e2013-06-17 15:40:52 +0900754 struct resource *res, *res2;
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100755 int ret;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000756 ret = -ENXIO;
757
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100758 cmt->pdev = pdev;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000759
760 if (!cfg) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100761 dev_err(&cmt->pdev->dev, "missing platform data\n");
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000762 goto err0;
763 }
764
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100765 res = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000766 if (!res) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100767 dev_err(&cmt->pdev->dev, "failed to get I/O memory\n");
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000768 goto err0;
769 }
770
Magnus Damm8874c5e2013-06-17 15:40:52 +0900771 /* optional resource for the shared timer start/stop register */
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100772 res2 = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 1);
Magnus Damm8874c5e2013-06-17 15:40:52 +0900773
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100774 /* map memory, let mapbase_ch point to our channel */
775 cmt->mapbase_ch = ioremap_nocache(res->start, resource_size(res));
776 if (cmt->mapbase_ch == NULL) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100777 dev_err(&cmt->pdev->dev, "failed to remap I/O memory\n");
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000778 goto err0;
779 }
780
Magnus Damm8874c5e2013-06-17 15:40:52 +0900781 /* map second resource for CMSTR */
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100782 cmt->mapbase = ioremap_nocache(res2 ? res2->start :
783 res->start - cfg->channel_offset,
784 res2 ? resource_size(res2) : 2);
785 if (cmt->mapbase == NULL) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100786 dev_err(&cmt->pdev->dev, "failed to remap I/O second memory\n");
Magnus Damm8874c5e2013-06-17 15:40:52 +0900787 goto err1;
788 }
789
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000790 /* get hold of clock */
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100791 cmt->clk = clk_get(&cmt->pdev->dev, "cmt_fck");
792 if (IS_ERR(cmt->clk)) {
793 dev_err(&cmt->pdev->dev, "cannot get clock\n");
794 ret = PTR_ERR(cmt->clk);
Magnus Damm8874c5e2013-06-17 15:40:52 +0900795 goto err2;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000796 }
797
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100798 ret = clk_prepare(cmt->clk);
Laurent Pinchart57dee992013-12-14 15:07:32 +0900799 if (ret < 0)
800 goto err3;
801
Magnus Damm8874c5e2013-06-17 15:40:52 +0900802 if (res2 && (resource_size(res2) == 4)) {
803 /* assume both CMSTR and CMCSR to be 32-bit */
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100804 cmt->read_control = sh_cmt_read32;
805 cmt->write_control = sh_cmt_write32;
Magnus Damm8874c5e2013-06-17 15:40:52 +0900806 } else {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100807 cmt->read_control = sh_cmt_read16;
808 cmt->write_control = sh_cmt_write16;
Magnus Damm8874c5e2013-06-17 15:40:52 +0900809 }
Magnus Dammcccd7042012-12-14 14:54:28 +0900810
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000811 if (resource_size(res) == 6) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100812 cmt->width = 16;
813 cmt->read_count = sh_cmt_read16;
814 cmt->write_count = sh_cmt_write16;
815 cmt->overflow_bit = 0x80;
816 cmt->clear_bits = ~0x80;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000817 } else {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100818 cmt->width = 32;
819 cmt->read_count = sh_cmt_read32;
820 cmt->write_count = sh_cmt_write32;
821 cmt->overflow_bit = 0x8000;
822 cmt->clear_bits = ~0xc000;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000823 }
824
Laurent Pinchart740a9512014-01-27 22:04:17 +0100825 ret = sh_cmt_setup_channel(&cmt->channel, cfg->timer_bit, cmt);
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100826 if (ret < 0)
Laurent Pinchart57dee992013-12-14 15:07:32 +0900827 goto err4;
Paul Mundtda64c2a2010-02-25 16:37:46 +0900828
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100829 platform_set_drvdata(pdev, cmt);
Magnus Dammadccc692012-12-14 14:53:51 +0900830
Paul Mundtda64c2a2010-02-25 16:37:46 +0900831 return 0;
Laurent Pinchart57dee992013-12-14 15:07:32 +0900832err4:
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100833 clk_unprepare(cmt->clk);
Magnus Damm8874c5e2013-06-17 15:40:52 +0900834err3:
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100835 clk_put(cmt->clk);
Magnus Damm8874c5e2013-06-17 15:40:52 +0900836err2:
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100837 iounmap(cmt->mapbase);
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100838err1:
839 iounmap(cmt->mapbase_ch);
Paul Mundtda64c2a2010-02-25 16:37:46 +0900840err0:
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000841 return ret;
842}
843
Greg Kroah-Hartman18505142012-12-21 15:11:38 -0800844static int sh_cmt_probe(struct platform_device *pdev)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000845{
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100846 struct sh_cmt_device *cmt = platform_get_drvdata(pdev);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200847 struct sh_timer_config *cfg = pdev->dev.platform_data;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000848 int ret;
849
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200850 if (!is_early_platform_device(pdev)) {
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200851 pm_runtime_set_active(&pdev->dev);
852 pm_runtime_enable(&pdev->dev);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200853 }
Rafael J. Wysocki615a4452012-03-13 22:40:06 +0100854
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100855 if (cmt) {
Paul Mundt214a6072010-03-10 16:26:25 +0900856 dev_info(&pdev->dev, "kept as earlytimer\n");
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200857 goto out;
Magnus Damme475eed2009-04-15 10:50:04 +0000858 }
859
Laurent Pinchartb262bc72014-01-27 22:04:17 +0100860 cmt = kzalloc(sizeof(*cmt), GFP_KERNEL);
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100861 if (cmt == NULL) {
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000862 dev_err(&pdev->dev, "failed to allocate driver data\n");
863 return -ENOMEM;
864 }
865
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100866 ret = sh_cmt_setup(cmt, pdev);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000867 if (ret) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100868 kfree(cmt);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200869 pm_runtime_idle(&pdev->dev);
870 return ret;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000871 }
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200872 if (is_early_platform_device(pdev))
873 return 0;
874
875 out:
876 if (cfg->clockevent_rating || cfg->clocksource_rating)
877 pm_runtime_irq_safe(&pdev->dev);
878 else
879 pm_runtime_idle(&pdev->dev);
880
881 return 0;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000882}
883
Greg Kroah-Hartman18505142012-12-21 15:11:38 -0800884static int sh_cmt_remove(struct platform_device *pdev)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000885{
886 return -EBUSY; /* cannot unregister clockevent and clocksource */
887}
888
889static struct platform_driver sh_cmt_device_driver = {
890 .probe = sh_cmt_probe,
Greg Kroah-Hartman18505142012-12-21 15:11:38 -0800891 .remove = sh_cmt_remove,
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000892 .driver = {
893 .name = "sh_cmt",
894 }
895};
896
897static int __init sh_cmt_init(void)
898{
899 return platform_driver_register(&sh_cmt_device_driver);
900}
901
902static void __exit sh_cmt_exit(void)
903{
904 platform_driver_unregister(&sh_cmt_device_driver);
905}
906
Magnus Damme475eed2009-04-15 10:50:04 +0000907early_platform_init("earlytimer", &sh_cmt_device_driver);
Simon Hormane903a032013-03-05 15:40:42 +0900908subsys_initcall(sh_cmt_init);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000909module_exit(sh_cmt_exit);
910
911MODULE_AUTHOR("Magnus Damm");
912MODULE_DESCRIPTION("SuperH CMT Timer Driver");
913MODULE_LICENSE("GPL v2");