blob: 4fcb05dc9ea45463c66447546bf5c80f8cdd7f0a [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;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000042
Laurent Pinchartc924d2d2014-01-27 22:04:17 +010043 void __iomem *base;
44
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000045 unsigned long flags;
46 unsigned long match_value;
47 unsigned long next_match_value;
48 unsigned long max_match_value;
49 unsigned long rate;
Paul Mundt7d0c3992012-05-25 13:36:43 +090050 raw_spinlock_t lock;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000051 struct clock_event_device ced;
Magnus Damm19bdc9d2009-04-17 05:26:31 +000052 struct clocksource cs;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000053 unsigned long total_cycles;
Rafael J. Wysockibad81382012-08-06 01:48:57 +020054 bool cs_enabled;
Laurent Pinchart7269f932014-01-27 15:29:19 +010055};
56
Laurent Pinchart2653caf2014-01-27 22:04:17 +010057struct sh_cmt_device {
Laurent Pinchart7269f932014-01-27 15:29:19 +010058 struct platform_device *pdev;
59
Laurent Pinchart36f1ac92014-01-27 22:04:17 +010060 void __iomem *mapbase_ch;
Laurent Pinchart7269f932014-01-27 15:29:19 +010061 void __iomem *mapbase;
Laurent Pinchart7269f932014-01-27 15:29:19 +010062 struct clk *clk;
63
64 struct sh_cmt_channel channel;
65
66 unsigned long width; /* 16 or 32 bit version of hardware block */
67 unsigned long overflow_bit;
68 unsigned long clear_bits;
Magnus Damma6a912c2012-12-14 14:54:19 +090069
Magnus Dammcccd7042012-12-14 14:54:28 +090070 /* callbacks for CMSTR and CMCSR access */
71 unsigned long (*read_control)(void __iomem *base, unsigned long offs);
72 void (*write_control)(void __iomem *base, unsigned long offs,
73 unsigned long value);
74
Magnus Damma6a912c2012-12-14 14:54:19 +090075 /* callbacks for CMCNT and CMCOR access */
76 unsigned long (*read_count)(void __iomem *base, unsigned long offs);
77 void (*write_count)(void __iomem *base, unsigned long offs,
78 unsigned long value);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000079};
80
Magnus Damm118aee42012-12-14 14:54:37 +090081/* Examples of supported CMT timer register layouts and I/O access widths:
82 *
83 * "16-bit counter and 16-bit control" as found on sh7263:
84 * CMSTR 0xfffec000 16-bit
85 * CMCSR 0xfffec002 16-bit
86 * CMCNT 0xfffec004 16-bit
87 * CMCOR 0xfffec006 16-bit
88 *
89 * "32-bit counter and 16-bit control" as found on sh7372, sh73a0, r8a7740:
90 * CMSTR 0xffca0000 16-bit
91 * CMCSR 0xffca0060 16-bit
92 * CMCNT 0xffca0064 32-bit
93 * CMCOR 0xffca0068 32-bit
Magnus Damm8874c5e2013-06-17 15:40:52 +090094 *
95 * "32-bit counter and 32-bit control" as found on r8a73a4 and r8a7790:
96 * CMSTR 0xffca0500 32-bit
97 * CMCSR 0xffca0510 32-bit
98 * CMCNT 0xffca0514 32-bit
99 * CMCOR 0xffca0518 32-bit
Magnus Damm118aee42012-12-14 14:54:37 +0900100 */
101
Magnus Damma6a912c2012-12-14 14:54:19 +0900102static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs)
Magnus Damm587acb32012-12-14 14:54:10 +0900103{
104 return ioread16(base + (offs << 1));
105}
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000106
Magnus Damma6a912c2012-12-14 14:54:19 +0900107static unsigned long sh_cmt_read32(void __iomem *base, unsigned long offs)
108{
109 return ioread32(base + (offs << 2));
110}
111
112static void sh_cmt_write16(void __iomem *base, unsigned long offs,
113 unsigned long value)
Magnus Damm587acb32012-12-14 14:54:10 +0900114{
115 iowrite16(value, base + (offs << 1));
116}
117
Magnus Damma6a912c2012-12-14 14:54:19 +0900118static void sh_cmt_write32(void __iomem *base, unsigned long offs,
119 unsigned long value)
120{
121 iowrite32(value, base + (offs << 2));
122}
123
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000124#define CMCSR 0 /* channel register */
125#define CMCNT 1 /* channel register */
126#define CMCOR 2 /* channel register */
127
Laurent Pinchart7269f932014-01-27 15:29:19 +0100128static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_channel *ch)
Magnus Damm1b56b962012-12-14 14:54:00 +0900129{
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100130 return ch->cmt->read_control(ch->cmt->mapbase, 0);
Magnus Damm1b56b962012-12-14 14:54:00 +0900131}
132
Laurent Pinchart7269f932014-01-27 15:29:19 +0100133static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_channel *ch)
Magnus Damm1b56b962012-12-14 14:54:00 +0900134{
Laurent Pinchartc924d2d2014-01-27 22:04:17 +0100135 return ch->cmt->read_control(ch->base, CMCSR);
Magnus Damm1b56b962012-12-14 14:54:00 +0900136}
137
Laurent Pinchart7269f932014-01-27 15:29:19 +0100138static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_channel *ch)
Magnus Damm1b56b962012-12-14 14:54:00 +0900139{
Laurent Pinchartc924d2d2014-01-27 22:04:17 +0100140 return ch->cmt->read_count(ch->base, CMCNT);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000141}
142
Laurent Pinchart7269f932014-01-27 15:29:19 +0100143static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch,
Magnus Damm1b56b962012-12-14 14:54:00 +0900144 unsigned long value)
145{
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100146 ch->cmt->write_control(ch->cmt->mapbase, 0, value);
Magnus Damm1b56b962012-12-14 14:54:00 +0900147}
148
Laurent Pinchart7269f932014-01-27 15:29:19 +0100149static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch,
Magnus Damm1b56b962012-12-14 14:54:00 +0900150 unsigned long value)
151{
Laurent Pinchartc924d2d2014-01-27 22:04:17 +0100152 ch->cmt->write_control(ch->base, CMCSR, value);
Magnus Damm1b56b962012-12-14 14:54:00 +0900153}
154
Laurent Pinchart7269f932014-01-27 15:29:19 +0100155static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch,
Magnus Damm1b56b962012-12-14 14:54:00 +0900156 unsigned long value)
157{
Laurent Pinchartc924d2d2014-01-27 22:04:17 +0100158 ch->cmt->write_count(ch->base, CMCNT, value);
Magnus Damm1b56b962012-12-14 14:54:00 +0900159}
160
Laurent Pinchart7269f932014-01-27 15:29:19 +0100161static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch,
Magnus Damm1b56b962012-12-14 14:54:00 +0900162 unsigned long value)
163{
Laurent Pinchartc924d2d2014-01-27 22:04:17 +0100164 ch->cmt->write_count(ch->base, CMCOR, value);
Magnus Damm1b56b962012-12-14 14:54:00 +0900165}
166
Laurent Pinchart7269f932014-01-27 15:29:19 +0100167static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000168 int *has_wrapped)
169{
170 unsigned long v1, v2, v3;
Magnus Damm5b644c72009-04-28 08:17:54 +0000171 int o1, o2;
172
Laurent Pinchart7269f932014-01-27 15:29:19 +0100173 o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->overflow_bit;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000174
175 /* Make sure the timer value is stable. Stolen from acpi_pm.c */
176 do {
Magnus Damm5b644c72009-04-28 08:17:54 +0000177 o2 = o1;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100178 v1 = sh_cmt_read_cmcnt(ch);
179 v2 = sh_cmt_read_cmcnt(ch);
180 v3 = sh_cmt_read_cmcnt(ch);
181 o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->overflow_bit;
Magnus Damm5b644c72009-04-28 08:17:54 +0000182 } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
183 || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000184
Magnus Damm5b644c72009-04-28 08:17:54 +0000185 *has_wrapped = o1;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000186 return v2;
187}
188
Magnus Damm587acb32012-12-14 14:54:10 +0900189static DEFINE_RAW_SPINLOCK(sh_cmt_lock);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000190
Laurent Pinchart7269f932014-01-27 15:29:19 +0100191static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000192{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100193 struct sh_timer_config *cfg = ch->cmt->pdev->dev.platform_data;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000194 unsigned long flags, value;
195
196 /* start stop register shared by multiple timer channels */
Paul Mundt7d0c3992012-05-25 13:36:43 +0900197 raw_spin_lock_irqsave(&sh_cmt_lock, flags);
Laurent Pinchart7269f932014-01-27 15:29:19 +0100198 value = sh_cmt_read_cmstr(ch);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000199
200 if (start)
201 value |= 1 << cfg->timer_bit;
202 else
203 value &= ~(1 << cfg->timer_bit);
204
Laurent Pinchart7269f932014-01-27 15:29:19 +0100205 sh_cmt_write_cmstr(ch, value);
Paul Mundt7d0c3992012-05-25 13:36:43 +0900206 raw_spin_unlock_irqrestore(&sh_cmt_lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000207}
208
Laurent Pinchart7269f932014-01-27 15:29:19 +0100209static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000210{
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000211 int k, ret;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000212
Laurent Pinchart7269f932014-01-27 15:29:19 +0100213 pm_runtime_get_sync(&ch->cmt->pdev->dev);
214 dev_pm_syscore_device(&ch->cmt->pdev->dev, true);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200215
Paul Mundt9436b4a2011-05-31 15:26:42 +0900216 /* enable clock */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100217 ret = clk_enable(ch->cmt->clk);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000218 if (ret) {
Laurent Pinchart7269f932014-01-27 15:29:19 +0100219 dev_err(&ch->cmt->pdev->dev, "cannot enable clock\n");
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000220 goto err0;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000221 }
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000222
223 /* make sure channel is disabled */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100224 sh_cmt_start_stop_ch(ch, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000225
226 /* configure channel, periodic mode and maximum timeout */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100227 if (ch->cmt->width == 16) {
228 *rate = clk_get_rate(ch->cmt->clk) / 512;
229 sh_cmt_write_cmcsr(ch, 0x43);
Magnus Damm3014f472009-04-29 14:50:37 +0000230 } else {
Laurent Pinchart7269f932014-01-27 15:29:19 +0100231 *rate = clk_get_rate(ch->cmt->clk) / 8;
232 sh_cmt_write_cmcsr(ch, 0x01a4);
Magnus Damm3014f472009-04-29 14:50:37 +0000233 }
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000234
Laurent Pinchart7269f932014-01-27 15:29:19 +0100235 sh_cmt_write_cmcor(ch, 0xffffffff);
236 sh_cmt_write_cmcnt(ch, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000237
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000238 /*
239 * According to the sh73a0 user's manual, as CMCNT can be operated
240 * only by the RCLK (Pseudo 32 KHz), there's one restriction on
241 * modifying CMCNT register; two RCLK cycles are necessary before
242 * this register is either read or any modification of the value
243 * it holds is reflected in the LSI's actual operation.
244 *
245 * While at it, we're supposed to clear out the CMCNT as of this
246 * moment, so make sure it's processed properly here. This will
247 * take RCLKx2 at maximum.
248 */
249 for (k = 0; k < 100; k++) {
Laurent Pinchart7269f932014-01-27 15:29:19 +0100250 if (!sh_cmt_read_cmcnt(ch))
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000251 break;
252 udelay(1);
253 }
254
Laurent Pinchart7269f932014-01-27 15:29:19 +0100255 if (sh_cmt_read_cmcnt(ch)) {
256 dev_err(&ch->cmt->pdev->dev, "cannot clear CMCNT\n");
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000257 ret = -ETIMEDOUT;
258 goto err1;
259 }
260
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000261 /* enable channel */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100262 sh_cmt_start_stop_ch(ch, 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000263 return 0;
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000264 err1:
265 /* stop clock */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100266 clk_disable(ch->cmt->clk);
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000267
268 err0:
269 return ret;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000270}
271
Laurent Pinchart7269f932014-01-27 15:29:19 +0100272static void sh_cmt_disable(struct sh_cmt_channel *ch)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000273{
274 /* disable channel */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100275 sh_cmt_start_stop_ch(ch, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000276
Magnus Dammbe890a12009-06-17 05:04:04 +0000277 /* disable interrupts in CMT block */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100278 sh_cmt_write_cmcsr(ch, 0);
Magnus Dammbe890a12009-06-17 05:04:04 +0000279
Paul Mundt9436b4a2011-05-31 15:26:42 +0900280 /* stop clock */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100281 clk_disable(ch->cmt->clk);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200282
Laurent Pinchart7269f932014-01-27 15:29:19 +0100283 dev_pm_syscore_device(&ch->cmt->pdev->dev, false);
284 pm_runtime_put(&ch->cmt->pdev->dev);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000285}
286
287/* private flags */
288#define FLAG_CLOCKEVENT (1 << 0)
289#define FLAG_CLOCKSOURCE (1 << 1)
290#define FLAG_REPROGRAM (1 << 2)
291#define FLAG_SKIPEVENT (1 << 3)
292#define FLAG_IRQCONTEXT (1 << 4)
293
Laurent Pinchart7269f932014-01-27 15:29:19 +0100294static void sh_cmt_clock_event_program_verify(struct sh_cmt_channel *ch,
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000295 int absolute)
296{
297 unsigned long new_match;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100298 unsigned long value = ch->next_match_value;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000299 unsigned long delay = 0;
300 unsigned long now = 0;
301 int has_wrapped;
302
Laurent Pinchart7269f932014-01-27 15:29:19 +0100303 now = sh_cmt_get_counter(ch, &has_wrapped);
304 ch->flags |= FLAG_REPROGRAM; /* force reprogram */
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000305
306 if (has_wrapped) {
307 /* we're competing with the interrupt handler.
308 * -> let the interrupt handler reprogram the timer.
309 * -> interrupt number two handles the event.
310 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100311 ch->flags |= FLAG_SKIPEVENT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000312 return;
313 }
314
315 if (absolute)
316 now = 0;
317
318 do {
319 /* reprogram the timer hardware,
320 * but don't save the new match value yet.
321 */
322 new_match = now + value + delay;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100323 if (new_match > ch->max_match_value)
324 new_match = ch->max_match_value;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000325
Laurent Pinchart7269f932014-01-27 15:29:19 +0100326 sh_cmt_write_cmcor(ch, new_match);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000327
Laurent Pinchart7269f932014-01-27 15:29:19 +0100328 now = sh_cmt_get_counter(ch, &has_wrapped);
329 if (has_wrapped && (new_match > ch->match_value)) {
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000330 /* we are changing to a greater match value,
331 * so this wrap must be caused by the counter
332 * matching the old value.
333 * -> first interrupt reprograms the timer.
334 * -> interrupt number two handles the event.
335 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100336 ch->flags |= FLAG_SKIPEVENT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000337 break;
338 }
339
340 if (has_wrapped) {
341 /* we are changing to a smaller match value,
342 * so the wrap must be caused by the counter
343 * matching the new value.
344 * -> save programmed match value.
345 * -> let isr handle the event.
346 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100347 ch->match_value = new_match;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000348 break;
349 }
350
351 /* be safe: verify hardware settings */
352 if (now < new_match) {
353 /* timer value is below match value, all good.
354 * this makes sure we won't miss any match events.
355 * -> save programmed match value.
356 * -> let isr handle the event.
357 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100358 ch->match_value = new_match;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000359 break;
360 }
361
362 /* the counter has reached a value greater
363 * than our new match value. and since the
364 * has_wrapped flag isn't set we must have
365 * programmed a too close event.
366 * -> increase delay and retry.
367 */
368 if (delay)
369 delay <<= 1;
370 else
371 delay = 1;
372
373 if (!delay)
Laurent Pinchart7269f932014-01-27 15:29:19 +0100374 dev_warn(&ch->cmt->pdev->dev, "too long delay\n");
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000375
376 } while (delay);
377}
378
Laurent Pinchart7269f932014-01-27 15:29:19 +0100379static void __sh_cmt_set_next(struct sh_cmt_channel *ch, unsigned long delta)
Takashi YOSHII65ada542010-12-17 07:25:09 +0000380{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100381 if (delta > ch->max_match_value)
382 dev_warn(&ch->cmt->pdev->dev, "delta out of range\n");
Takashi YOSHII65ada542010-12-17 07:25:09 +0000383
Laurent Pinchart7269f932014-01-27 15:29:19 +0100384 ch->next_match_value = delta;
385 sh_cmt_clock_event_program_verify(ch, 0);
Takashi YOSHII65ada542010-12-17 07:25:09 +0000386}
387
Laurent Pinchart7269f932014-01-27 15:29:19 +0100388static void sh_cmt_set_next(struct sh_cmt_channel *ch, unsigned long delta)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000389{
390 unsigned long flags;
391
Laurent Pinchart7269f932014-01-27 15:29:19 +0100392 raw_spin_lock_irqsave(&ch->lock, flags);
393 __sh_cmt_set_next(ch, delta);
394 raw_spin_unlock_irqrestore(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000395}
396
397static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)
398{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100399 struct sh_cmt_channel *ch = dev_id;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000400
401 /* clear flags */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100402 sh_cmt_write_cmcsr(ch, sh_cmt_read_cmcsr(ch) & ch->cmt->clear_bits);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000403
404 /* update clock source counter to begin with if enabled
405 * the wrap flag should be cleared by the timer specific
406 * isr before we end up here.
407 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100408 if (ch->flags & FLAG_CLOCKSOURCE)
409 ch->total_cycles += ch->match_value + 1;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000410
Laurent Pinchart7269f932014-01-27 15:29:19 +0100411 if (!(ch->flags & FLAG_REPROGRAM))
412 ch->next_match_value = ch->max_match_value;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000413
Laurent Pinchart7269f932014-01-27 15:29:19 +0100414 ch->flags |= FLAG_IRQCONTEXT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000415
Laurent Pinchart7269f932014-01-27 15:29:19 +0100416 if (ch->flags & FLAG_CLOCKEVENT) {
417 if (!(ch->flags & FLAG_SKIPEVENT)) {
418 if (ch->ced.mode == CLOCK_EVT_MODE_ONESHOT) {
419 ch->next_match_value = ch->max_match_value;
420 ch->flags |= FLAG_REPROGRAM;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000421 }
422
Laurent Pinchart7269f932014-01-27 15:29:19 +0100423 ch->ced.event_handler(&ch->ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000424 }
425 }
426
Laurent Pinchart7269f932014-01-27 15:29:19 +0100427 ch->flags &= ~FLAG_SKIPEVENT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000428
Laurent Pinchart7269f932014-01-27 15:29:19 +0100429 if (ch->flags & FLAG_REPROGRAM) {
430 ch->flags &= ~FLAG_REPROGRAM;
431 sh_cmt_clock_event_program_verify(ch, 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000432
Laurent Pinchart7269f932014-01-27 15:29:19 +0100433 if (ch->flags & FLAG_CLOCKEVENT)
434 if ((ch->ced.mode == CLOCK_EVT_MODE_SHUTDOWN)
435 || (ch->match_value == ch->next_match_value))
436 ch->flags &= ~FLAG_REPROGRAM;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000437 }
438
Laurent Pinchart7269f932014-01-27 15:29:19 +0100439 ch->flags &= ~FLAG_IRQCONTEXT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000440
441 return IRQ_HANDLED;
442}
443
Laurent Pinchart7269f932014-01-27 15:29:19 +0100444static int sh_cmt_start(struct sh_cmt_channel *ch, unsigned long flag)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000445{
446 int ret = 0;
447 unsigned long flags;
448
Laurent Pinchart7269f932014-01-27 15:29:19 +0100449 raw_spin_lock_irqsave(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000450
Laurent Pinchart7269f932014-01-27 15:29:19 +0100451 if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
452 ret = sh_cmt_enable(ch, &ch->rate);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000453
454 if (ret)
455 goto out;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100456 ch->flags |= flag;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000457
458 /* setup timeout if no clockevent */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100459 if ((flag == FLAG_CLOCKSOURCE) && (!(ch->flags & FLAG_CLOCKEVENT)))
460 __sh_cmt_set_next(ch, ch->max_match_value);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000461 out:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100462 raw_spin_unlock_irqrestore(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000463
464 return ret;
465}
466
Laurent Pinchart7269f932014-01-27 15:29:19 +0100467static void sh_cmt_stop(struct sh_cmt_channel *ch, unsigned long flag)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000468{
469 unsigned long flags;
470 unsigned long f;
471
Laurent Pinchart7269f932014-01-27 15:29:19 +0100472 raw_spin_lock_irqsave(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000473
Laurent Pinchart7269f932014-01-27 15:29:19 +0100474 f = ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE);
475 ch->flags &= ~flag;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000476
Laurent Pinchart7269f932014-01-27 15:29:19 +0100477 if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
478 sh_cmt_disable(ch);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000479
480 /* adjust the timeout to maximum if only clocksource left */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100481 if ((flag == FLAG_CLOCKEVENT) && (ch->flags & FLAG_CLOCKSOURCE))
482 __sh_cmt_set_next(ch, ch->max_match_value);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000483
Laurent Pinchart7269f932014-01-27 15:29:19 +0100484 raw_spin_unlock_irqrestore(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000485}
486
Laurent Pinchart7269f932014-01-27 15:29:19 +0100487static struct sh_cmt_channel *cs_to_sh_cmt(struct clocksource *cs)
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000488{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100489 return container_of(cs, struct sh_cmt_channel, cs);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000490}
491
492static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
493{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100494 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000495 unsigned long flags, raw;
496 unsigned long value;
497 int has_wrapped;
498
Laurent Pinchart7269f932014-01-27 15:29:19 +0100499 raw_spin_lock_irqsave(&ch->lock, flags);
500 value = ch->total_cycles;
501 raw = sh_cmt_get_counter(ch, &has_wrapped);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000502
503 if (unlikely(has_wrapped))
Laurent Pinchart7269f932014-01-27 15:29:19 +0100504 raw += ch->match_value + 1;
505 raw_spin_unlock_irqrestore(&ch->lock, flags);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000506
507 return value + raw;
508}
509
510static int sh_cmt_clocksource_enable(struct clocksource *cs)
511{
Magnus Damm3593f5f2011-04-25 22:32:11 +0900512 int ret;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100513 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000514
Laurent Pinchart7269f932014-01-27 15:29:19 +0100515 WARN_ON(ch->cs_enabled);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200516
Laurent Pinchart7269f932014-01-27 15:29:19 +0100517 ch->total_cycles = 0;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000518
Laurent Pinchart7269f932014-01-27 15:29:19 +0100519 ret = sh_cmt_start(ch, FLAG_CLOCKSOURCE);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200520 if (!ret) {
Laurent Pinchart7269f932014-01-27 15:29:19 +0100521 __clocksource_updatefreq_hz(cs, ch->rate);
522 ch->cs_enabled = true;
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200523 }
Magnus Damm3593f5f2011-04-25 22:32:11 +0900524 return ret;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000525}
526
527static void sh_cmt_clocksource_disable(struct clocksource *cs)
528{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100529 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200530
Laurent Pinchart7269f932014-01-27 15:29:19 +0100531 WARN_ON(!ch->cs_enabled);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200532
Laurent Pinchart7269f932014-01-27 15:29:19 +0100533 sh_cmt_stop(ch, FLAG_CLOCKSOURCE);
534 ch->cs_enabled = false;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000535}
536
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200537static void sh_cmt_clocksource_suspend(struct clocksource *cs)
538{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100539 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200540
Laurent Pinchart7269f932014-01-27 15:29:19 +0100541 sh_cmt_stop(ch, FLAG_CLOCKSOURCE);
542 pm_genpd_syscore_poweroff(&ch->cmt->pdev->dev);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200543}
544
Magnus Dammc8162882010-02-02 14:41:40 -0800545static void sh_cmt_clocksource_resume(struct clocksource *cs)
546{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100547 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200548
Laurent Pinchart7269f932014-01-27 15:29:19 +0100549 pm_genpd_syscore_poweron(&ch->cmt->pdev->dev);
550 sh_cmt_start(ch, FLAG_CLOCKSOURCE);
Magnus Dammc8162882010-02-02 14:41:40 -0800551}
552
Laurent Pinchart7269f932014-01-27 15:29:19 +0100553static int sh_cmt_register_clocksource(struct sh_cmt_channel *ch,
Laurent Pinchart1d053e12014-02-17 16:04:16 +0100554 const char *name, unsigned long rating)
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000555{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100556 struct clocksource *cs = &ch->cs;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000557
558 cs->name = name;
559 cs->rating = rating;
560 cs->read = sh_cmt_clocksource_read;
561 cs->enable = sh_cmt_clocksource_enable;
562 cs->disable = sh_cmt_clocksource_disable;
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200563 cs->suspend = sh_cmt_clocksource_suspend;
Magnus Dammc8162882010-02-02 14:41:40 -0800564 cs->resume = sh_cmt_clocksource_resume;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000565 cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
566 cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
Paul Mundtf4d7c352010-06-02 17:10:44 +0900567
Laurent Pinchart7269f932014-01-27 15:29:19 +0100568 dev_info(&ch->cmt->pdev->dev, "used as clock source\n");
Paul Mundtf4d7c352010-06-02 17:10:44 +0900569
Magnus Damm3593f5f2011-04-25 22:32:11 +0900570 /* Register with dummy 1 Hz value, gets updated in ->enable() */
571 clocksource_register_hz(cs, 1);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000572 return 0;
573}
574
Laurent Pinchart7269f932014-01-27 15:29:19 +0100575static struct sh_cmt_channel *ced_to_sh_cmt(struct clock_event_device *ced)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000576{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100577 return container_of(ced, struct sh_cmt_channel, ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000578}
579
Laurent Pinchart7269f932014-01-27 15:29:19 +0100580static void sh_cmt_clock_event_start(struct sh_cmt_channel *ch, int periodic)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000581{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100582 struct clock_event_device *ced = &ch->ced;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000583
Laurent Pinchart7269f932014-01-27 15:29:19 +0100584 sh_cmt_start(ch, FLAG_CLOCKEVENT);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000585
586 /* TODO: calculate good shift from rate and counter bit width */
587
588 ced->shift = 32;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100589 ced->mult = div_sc(ch->rate, NSEC_PER_SEC, ced->shift);
590 ced->max_delta_ns = clockevent_delta2ns(ch->max_match_value, ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000591 ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
592
593 if (periodic)
Laurent Pinchart7269f932014-01-27 15:29:19 +0100594 sh_cmt_set_next(ch, ((ch->rate + HZ/2) / HZ) - 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000595 else
Laurent Pinchart7269f932014-01-27 15:29:19 +0100596 sh_cmt_set_next(ch, ch->max_match_value);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000597}
598
599static void sh_cmt_clock_event_mode(enum clock_event_mode mode,
600 struct clock_event_device *ced)
601{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100602 struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000603
604 /* deal with old setting first */
605 switch (ced->mode) {
606 case CLOCK_EVT_MODE_PERIODIC:
607 case CLOCK_EVT_MODE_ONESHOT:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100608 sh_cmt_stop(ch, FLAG_CLOCKEVENT);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000609 break;
610 default:
611 break;
612 }
613
614 switch (mode) {
615 case CLOCK_EVT_MODE_PERIODIC:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100616 dev_info(&ch->cmt->pdev->dev,
617 "used for periodic clock events\n");
618 sh_cmt_clock_event_start(ch, 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000619 break;
620 case CLOCK_EVT_MODE_ONESHOT:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100621 dev_info(&ch->cmt->pdev->dev,
622 "used for oneshot clock events\n");
623 sh_cmt_clock_event_start(ch, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000624 break;
625 case CLOCK_EVT_MODE_SHUTDOWN:
626 case CLOCK_EVT_MODE_UNUSED:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100627 sh_cmt_stop(ch, FLAG_CLOCKEVENT);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000628 break;
629 default:
630 break;
631 }
632}
633
634static int sh_cmt_clock_event_next(unsigned long delta,
635 struct clock_event_device *ced)
636{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100637 struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000638
639 BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
Laurent Pinchart7269f932014-01-27 15:29:19 +0100640 if (likely(ch->flags & FLAG_IRQCONTEXT))
641 ch->next_match_value = delta - 1;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000642 else
Laurent Pinchart7269f932014-01-27 15:29:19 +0100643 sh_cmt_set_next(ch, delta - 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000644
645 return 0;
646}
647
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200648static void sh_cmt_clock_event_suspend(struct clock_event_device *ced)
649{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100650 struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
Laurent Pinchart57dee992013-12-14 15:07:32 +0900651
Laurent Pinchart7269f932014-01-27 15:29:19 +0100652 pm_genpd_syscore_poweroff(&ch->cmt->pdev->dev);
653 clk_unprepare(ch->cmt->clk);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200654}
655
656static void sh_cmt_clock_event_resume(struct clock_event_device *ced)
657{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100658 struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
Laurent Pinchart57dee992013-12-14 15:07:32 +0900659
Laurent Pinchart7269f932014-01-27 15:29:19 +0100660 clk_prepare(ch->cmt->clk);
661 pm_genpd_syscore_poweron(&ch->cmt->pdev->dev);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200662}
663
Laurent Pinchart7269f932014-01-27 15:29:19 +0100664static void sh_cmt_register_clockevent(struct sh_cmt_channel *ch,
Laurent Pinchart1d053e12014-02-17 16:04:16 +0100665 const char *name, unsigned long rating)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000666{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100667 struct clock_event_device *ced = &ch->ced;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000668
669 memset(ced, 0, sizeof(*ced));
670
671 ced->name = name;
672 ced->features = CLOCK_EVT_FEAT_PERIODIC;
673 ced->features |= CLOCK_EVT_FEAT_ONESHOT;
674 ced->rating = rating;
675 ced->cpumask = cpumask_of(0);
676 ced->set_next_event = sh_cmt_clock_event_next;
677 ced->set_mode = sh_cmt_clock_event_mode;
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200678 ced->suspend = sh_cmt_clock_event_suspend;
679 ced->resume = sh_cmt_clock_event_resume;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000680
Laurent Pinchart7269f932014-01-27 15:29:19 +0100681 dev_info(&ch->cmt->pdev->dev, "used for clock events\n");
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000682 clockevents_register_device(ced);
683}
684
Laurent Pinchart1d053e12014-02-17 16:04:16 +0100685static int sh_cmt_register(struct sh_cmt_channel *ch, const char *name,
Paul Mundtd1fcc0a2009-05-03 18:05:42 +0900686 unsigned long clockevent_rating,
687 unsigned long clocksource_rating)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000688{
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000689 if (clockevent_rating)
Laurent Pinchart7269f932014-01-27 15:29:19 +0100690 sh_cmt_register_clockevent(ch, name, clockevent_rating);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000691
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000692 if (clocksource_rating)
Laurent Pinchart7269f932014-01-27 15:29:19 +0100693 sh_cmt_register_clocksource(ch, name, clocksource_rating);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000694
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000695 return 0;
696}
697
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100698static int sh_cmt_setup_channel(struct sh_cmt_channel *ch,
699 struct sh_cmt_device *cmt)
700{
701 struct sh_timer_config *cfg = cmt->pdev->dev.platform_data;
702 int irq;
703 int ret;
704
705 memset(ch, 0, sizeof(*ch));
706 ch->cmt = cmt;
Laurent Pinchartc924d2d2014-01-27 22:04:17 +0100707 ch->base = cmt->mapbase_ch;
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100708
709 irq = platform_get_irq(cmt->pdev, 0);
710 if (irq < 0) {
711 dev_err(&cmt->pdev->dev, "failed to get irq\n");
712 return irq;
713 }
714
715 if (cmt->width == (sizeof(ch->max_match_value) * 8))
716 ch->max_match_value = ~0;
717 else
718 ch->max_match_value = (1 << cmt->width) - 1;
719
720 ch->match_value = ch->max_match_value;
721 raw_spin_lock_init(&ch->lock);
722
Laurent Pinchart1d053e12014-02-17 16:04:16 +0100723 ret = sh_cmt_register(ch, dev_name(&cmt->pdev->dev),
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100724 cfg->clockevent_rating,
725 cfg->clocksource_rating);
726 if (ret) {
727 dev_err(&cmt->pdev->dev, "registration failed\n");
728 return ret;
729 }
730 ch->cs_enabled = false;
731
732 ret = request_irq(irq, sh_cmt_interrupt,
733 IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
734 dev_name(&cmt->pdev->dev), ch);
735 if (ret) {
736 dev_err(&cmt->pdev->dev, "failed to request irq %d\n", irq);
737 return ret;
738 }
739
740 return 0;
741}
742
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100743static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000744{
Paul Mundt46a12f72009-05-03 17:57:17 +0900745 struct sh_timer_config *cfg = pdev->dev.platform_data;
Magnus Damm8874c5e2013-06-17 15:40:52 +0900746 struct resource *res, *res2;
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100747 int ret;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000748 ret = -ENXIO;
749
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100750 memset(cmt, 0, sizeof(*cmt));
751 cmt->pdev = pdev;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000752
753 if (!cfg) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100754 dev_err(&cmt->pdev->dev, "missing platform data\n");
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000755 goto err0;
756 }
757
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100758 res = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000759 if (!res) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100760 dev_err(&cmt->pdev->dev, "failed to get I/O memory\n");
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000761 goto err0;
762 }
763
Magnus Damm8874c5e2013-06-17 15:40:52 +0900764 /* optional resource for the shared timer start/stop register */
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100765 res2 = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 1);
Magnus Damm8874c5e2013-06-17 15:40:52 +0900766
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100767 /* map memory, let mapbase_ch point to our channel */
768 cmt->mapbase_ch = ioremap_nocache(res->start, resource_size(res));
769 if (cmt->mapbase_ch == NULL) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100770 dev_err(&cmt->pdev->dev, "failed to remap I/O memory\n");
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000771 goto err0;
772 }
773
Magnus Damm8874c5e2013-06-17 15:40:52 +0900774 /* map second resource for CMSTR */
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100775 cmt->mapbase = ioremap_nocache(res2 ? res2->start :
776 res->start - cfg->channel_offset,
777 res2 ? resource_size(res2) : 2);
778 if (cmt->mapbase == NULL) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100779 dev_err(&cmt->pdev->dev, "failed to remap I/O second memory\n");
Magnus Damm8874c5e2013-06-17 15:40:52 +0900780 goto err1;
781 }
782
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000783 /* get hold of clock */
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100784 cmt->clk = clk_get(&cmt->pdev->dev, "cmt_fck");
785 if (IS_ERR(cmt->clk)) {
786 dev_err(&cmt->pdev->dev, "cannot get clock\n");
787 ret = PTR_ERR(cmt->clk);
Magnus Damm8874c5e2013-06-17 15:40:52 +0900788 goto err2;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000789 }
790
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100791 ret = clk_prepare(cmt->clk);
Laurent Pinchart57dee992013-12-14 15:07:32 +0900792 if (ret < 0)
793 goto err3;
794
Magnus Damm8874c5e2013-06-17 15:40:52 +0900795 if (res2 && (resource_size(res2) == 4)) {
796 /* assume both CMSTR and CMCSR to be 32-bit */
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100797 cmt->read_control = sh_cmt_read32;
798 cmt->write_control = sh_cmt_write32;
Magnus Damm8874c5e2013-06-17 15:40:52 +0900799 } else {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100800 cmt->read_control = sh_cmt_read16;
801 cmt->write_control = sh_cmt_write16;
Magnus Damm8874c5e2013-06-17 15:40:52 +0900802 }
Magnus Dammcccd7042012-12-14 14:54:28 +0900803
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000804 if (resource_size(res) == 6) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100805 cmt->width = 16;
806 cmt->read_count = sh_cmt_read16;
807 cmt->write_count = sh_cmt_write16;
808 cmt->overflow_bit = 0x80;
809 cmt->clear_bits = ~0x80;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000810 } else {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100811 cmt->width = 32;
812 cmt->read_count = sh_cmt_read32;
813 cmt->write_count = sh_cmt_write32;
814 cmt->overflow_bit = 0x8000;
815 cmt->clear_bits = ~0xc000;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000816 }
817
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100818 ret = sh_cmt_setup_channel(&cmt->channel, cmt);
819 if (ret < 0)
Laurent Pinchart57dee992013-12-14 15:07:32 +0900820 goto err4;
Paul Mundtda64c2a2010-02-25 16:37:46 +0900821
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100822 platform_set_drvdata(pdev, cmt);
Magnus Dammadccc692012-12-14 14:53:51 +0900823
Paul Mundtda64c2a2010-02-25 16:37:46 +0900824 return 0;
Laurent Pinchart57dee992013-12-14 15:07:32 +0900825err4:
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100826 clk_unprepare(cmt->clk);
Magnus Damm8874c5e2013-06-17 15:40:52 +0900827err3:
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100828 clk_put(cmt->clk);
Magnus Damm8874c5e2013-06-17 15:40:52 +0900829err2:
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100830 iounmap(cmt->mapbase);
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100831err1:
832 iounmap(cmt->mapbase_ch);
Paul Mundtda64c2a2010-02-25 16:37:46 +0900833err0:
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000834 return ret;
835}
836
Greg Kroah-Hartman18505142012-12-21 15:11:38 -0800837static int sh_cmt_probe(struct platform_device *pdev)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000838{
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100839 struct sh_cmt_device *cmt = platform_get_drvdata(pdev);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200840 struct sh_timer_config *cfg = pdev->dev.platform_data;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000841 int ret;
842
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200843 if (!is_early_platform_device(pdev)) {
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200844 pm_runtime_set_active(&pdev->dev);
845 pm_runtime_enable(&pdev->dev);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200846 }
Rafael J. Wysocki615a4452012-03-13 22:40:06 +0100847
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100848 if (cmt) {
Paul Mundt214a6072010-03-10 16:26:25 +0900849 dev_info(&pdev->dev, "kept as earlytimer\n");
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200850 goto out;
Magnus Damme475eed2009-04-15 10:50:04 +0000851 }
852
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100853 cmt = kmalloc(sizeof(*cmt), GFP_KERNEL);
854 if (cmt == NULL) {
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000855 dev_err(&pdev->dev, "failed to allocate driver data\n");
856 return -ENOMEM;
857 }
858
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100859 ret = sh_cmt_setup(cmt, pdev);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000860 if (ret) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100861 kfree(cmt);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200862 pm_runtime_idle(&pdev->dev);
863 return ret;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000864 }
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200865 if (is_early_platform_device(pdev))
866 return 0;
867
868 out:
869 if (cfg->clockevent_rating || cfg->clocksource_rating)
870 pm_runtime_irq_safe(&pdev->dev);
871 else
872 pm_runtime_idle(&pdev->dev);
873
874 return 0;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000875}
876
Greg Kroah-Hartman18505142012-12-21 15:11:38 -0800877static int sh_cmt_remove(struct platform_device *pdev)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000878{
879 return -EBUSY; /* cannot unregister clockevent and clocksource */
880}
881
882static struct platform_driver sh_cmt_device_driver = {
883 .probe = sh_cmt_probe,
Greg Kroah-Hartman18505142012-12-21 15:11:38 -0800884 .remove = sh_cmt_remove,
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000885 .driver = {
886 .name = "sh_cmt",
887 }
888};
889
890static int __init sh_cmt_init(void)
891{
892 return platform_driver_register(&sh_cmt_device_driver);
893}
894
895static void __exit sh_cmt_exit(void)
896{
897 platform_driver_unregister(&sh_cmt_device_driver);
898}
899
Magnus Damme475eed2009-04-15 10:50:04 +0000900early_platform_init("earlytimer", &sh_cmt_device_driver);
Simon Hormane903a032013-03-05 15:40:42 +0900901subsys_initcall(sh_cmt_init);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000902module_exit(sh_cmt_exit);
903
904MODULE_AUTHOR("Magnus Damm");
905MODULE_DESCRIPTION("SuperH CMT Timer Driver");
906MODULE_LICENSE("GPL v2");