blob: 926abe28812612bcc013b1758c67ee5650395aaf [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
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +010040/*
41 * The CMT comes in 5 different identified flavours, depending not only on the
42 * SoC but also on the particular instance. The following table lists the main
43 * characteristics of those flavours.
44 *
45 * 16B 32B 32B-F 48B 48B-2
46 * -----------------------------------------------------------------------------
47 * Channels 2 1/4 1 6 2/8
48 * Control Width 16 16 16 16 32
49 * Counter Width 16 32 32 32/48 32/48
50 * Shared Start/Stop Y Y Y Y N
51 *
52 * The 48-bit gen2 version has a per-channel start/stop register located in the
53 * channel registers block. All other versions have a shared start/stop register
54 * located in the global space.
55 *
56 * Note that CMT0 on r8a73a4, r8a7790 and r8a7791, while implementing 32-bit
57 * channels only, is a 48-bit gen2 CMT with the 48-bit channels unavailable.
58 */
59
60enum sh_cmt_model {
61 SH_CMT_16BIT,
62 SH_CMT_32BIT,
63 SH_CMT_32BIT_FAST,
64 SH_CMT_48BIT,
65 SH_CMT_48BIT_GEN2,
66};
67
68struct sh_cmt_info {
69 enum sh_cmt_model model;
70
71 unsigned long width; /* 16 or 32 bit version of hardware block */
72 unsigned long overflow_bit;
73 unsigned long clear_bits;
74
75 /* callbacks for CMSTR and CMCSR access */
76 unsigned long (*read_control)(void __iomem *base, unsigned long offs);
77 void (*write_control)(void __iomem *base, unsigned long offs,
78 unsigned long value);
79
80 /* callbacks for CMCNT and CMCOR access */
81 unsigned long (*read_count)(void __iomem *base, unsigned long offs);
82 void (*write_count)(void __iomem *base, unsigned long offs,
83 unsigned long value);
84};
85
Laurent Pinchart7269f932014-01-27 15:29:19 +010086struct sh_cmt_channel {
Laurent Pinchart2653caf2014-01-27 22:04:17 +010087 struct sh_cmt_device *cmt;
Laurent Pinchart740a9512014-01-27 22:04:17 +010088 unsigned int index;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000089
Laurent Pinchartc924d2d2014-01-27 22:04:17 +010090 void __iomem *base;
91
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000092 unsigned long flags;
93 unsigned long match_value;
94 unsigned long next_match_value;
95 unsigned long max_match_value;
96 unsigned long rate;
Paul Mundt7d0c3992012-05-25 13:36:43 +090097 raw_spinlock_t lock;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +000098 struct clock_event_device ced;
Magnus Damm19bdc9d2009-04-17 05:26:31 +000099 struct clocksource cs;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000100 unsigned long total_cycles;
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200101 bool cs_enabled;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100102};
103
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100104struct sh_cmt_device {
Laurent Pinchart7269f932014-01-27 15:29:19 +0100105 struct platform_device *pdev;
106
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100107 const struct sh_cmt_info *info;
108
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100109 void __iomem *mapbase_ch;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100110 void __iomem *mapbase;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100111 struct clk *clk;
112
Laurent Pinchartf5ec9b12014-01-27 22:04:17 +0100113 struct sh_cmt_channel *channels;
114 unsigned int num_channels;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000115};
116
Laurent Pinchartd14be992014-01-29 00:33:08 +0100117#define SH_CMT16_CMCSR_CMF (1 << 7)
118#define SH_CMT16_CMCSR_CMIE (1 << 6)
119#define SH_CMT16_CMCSR_CKS8 (0 << 0)
120#define SH_CMT16_CMCSR_CKS32 (1 << 0)
121#define SH_CMT16_CMCSR_CKS128 (2 << 0)
122#define SH_CMT16_CMCSR_CKS512 (3 << 0)
123#define SH_CMT16_CMCSR_CKS_MASK (3 << 0)
124
125#define SH_CMT32_CMCSR_CMF (1 << 15)
126#define SH_CMT32_CMCSR_OVF (1 << 14)
127#define SH_CMT32_CMCSR_WRFLG (1 << 13)
128#define SH_CMT32_CMCSR_STTF (1 << 12)
129#define SH_CMT32_CMCSR_STPF (1 << 11)
130#define SH_CMT32_CMCSR_SSIE (1 << 10)
131#define SH_CMT32_CMCSR_CMS (1 << 9)
132#define SH_CMT32_CMCSR_CMM (1 << 8)
133#define SH_CMT32_CMCSR_CMTOUT_IE (1 << 7)
134#define SH_CMT32_CMCSR_CMR_NONE (0 << 4)
135#define SH_CMT32_CMCSR_CMR_DMA (1 << 4)
136#define SH_CMT32_CMCSR_CMR_IRQ (2 << 4)
137#define SH_CMT32_CMCSR_CMR_MASK (3 << 4)
138#define SH_CMT32_CMCSR_DBGIVD (1 << 3)
139#define SH_CMT32_CMCSR_CKS_RCLK8 (4 << 0)
140#define SH_CMT32_CMCSR_CKS_RCLK32 (5 << 0)
141#define SH_CMT32_CMCSR_CKS_RCLK128 (6 << 0)
142#define SH_CMT32_CMCSR_CKS_RCLK1 (7 << 0)
143#define SH_CMT32_CMCSR_CKS_MASK (7 << 0)
144
Magnus Damma6a912c2012-12-14 14:54:19 +0900145static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs)
Magnus Damm587acb32012-12-14 14:54:10 +0900146{
147 return ioread16(base + (offs << 1));
148}
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000149
Magnus Damma6a912c2012-12-14 14:54:19 +0900150static unsigned long sh_cmt_read32(void __iomem *base, unsigned long offs)
151{
152 return ioread32(base + (offs << 2));
153}
154
155static void sh_cmt_write16(void __iomem *base, unsigned long offs,
156 unsigned long value)
Magnus Damm587acb32012-12-14 14:54:10 +0900157{
158 iowrite16(value, base + (offs << 1));
159}
160
Magnus Damma6a912c2012-12-14 14:54:19 +0900161static void sh_cmt_write32(void __iomem *base, unsigned long offs,
162 unsigned long value)
163{
164 iowrite32(value, base + (offs << 2));
165}
166
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100167static const struct sh_cmt_info sh_cmt_info[] = {
168 [SH_CMT_16BIT] = {
169 .model = SH_CMT_16BIT,
170 .width = 16,
Laurent Pinchartd14be992014-01-29 00:33:08 +0100171 .overflow_bit = SH_CMT16_CMCSR_CMF,
172 .clear_bits = ~SH_CMT16_CMCSR_CMF,
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100173 .read_control = sh_cmt_read16,
174 .write_control = sh_cmt_write16,
175 .read_count = sh_cmt_read16,
176 .write_count = sh_cmt_write16,
177 },
178 [SH_CMT_32BIT] = {
179 .model = SH_CMT_32BIT,
180 .width = 32,
Laurent Pinchartd14be992014-01-29 00:33:08 +0100181 .overflow_bit = SH_CMT32_CMCSR_CMF,
182 .clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF),
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100183 .read_control = sh_cmt_read16,
184 .write_control = sh_cmt_write16,
185 .read_count = sh_cmt_read32,
186 .write_count = sh_cmt_write32,
187 },
188 [SH_CMT_32BIT_FAST] = {
189 .model = SH_CMT_32BIT_FAST,
190 .width = 32,
Laurent Pinchartd14be992014-01-29 00:33:08 +0100191 .overflow_bit = SH_CMT32_CMCSR_CMF,
192 .clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF),
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100193 .read_control = sh_cmt_read16,
194 .write_control = sh_cmt_write16,
195 .read_count = sh_cmt_read32,
196 .write_count = sh_cmt_write32,
197 },
198 [SH_CMT_48BIT] = {
199 .model = SH_CMT_48BIT,
200 .width = 32,
Laurent Pinchartd14be992014-01-29 00:33:08 +0100201 .overflow_bit = SH_CMT32_CMCSR_CMF,
202 .clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF),
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100203 .read_control = sh_cmt_read32,
204 .write_control = sh_cmt_write32,
205 .read_count = sh_cmt_read32,
206 .write_count = sh_cmt_write32,
207 },
208 [SH_CMT_48BIT_GEN2] = {
209 .model = SH_CMT_48BIT_GEN2,
210 .width = 32,
Laurent Pinchartd14be992014-01-29 00:33:08 +0100211 .overflow_bit = SH_CMT32_CMCSR_CMF,
212 .clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF),
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100213 .read_control = sh_cmt_read32,
214 .write_control = sh_cmt_write32,
215 .read_count = sh_cmt_read32,
216 .write_count = sh_cmt_write32,
217 },
218};
219
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000220#define CMCSR 0 /* channel register */
221#define CMCNT 1 /* channel register */
222#define CMCOR 2 /* channel register */
223
Laurent Pinchart7269f932014-01-27 15:29:19 +0100224static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_channel *ch)
Magnus Damm1b56b962012-12-14 14:54:00 +0900225{
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100226 return ch->cmt->info->read_control(ch->cmt->mapbase, 0);
Magnus Damm1b56b962012-12-14 14:54:00 +0900227}
228
Laurent Pinchart7269f932014-01-27 15:29:19 +0100229static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_channel *ch)
Magnus Damm1b56b962012-12-14 14:54:00 +0900230{
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100231 return ch->cmt->info->read_control(ch->base, CMCSR);
Magnus Damm1b56b962012-12-14 14:54:00 +0900232}
233
Laurent Pinchart7269f932014-01-27 15:29:19 +0100234static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_channel *ch)
Magnus Damm1b56b962012-12-14 14:54:00 +0900235{
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100236 return ch->cmt->info->read_count(ch->base, CMCNT);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000237}
238
Laurent Pinchart7269f932014-01-27 15:29:19 +0100239static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch,
Magnus Damm1b56b962012-12-14 14:54:00 +0900240 unsigned long value)
241{
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100242 ch->cmt->info->write_control(ch->cmt->mapbase, 0, value);
Magnus Damm1b56b962012-12-14 14:54:00 +0900243}
244
Laurent Pinchart7269f932014-01-27 15:29:19 +0100245static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch,
Magnus Damm1b56b962012-12-14 14:54:00 +0900246 unsigned long value)
247{
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100248 ch->cmt->info->write_control(ch->base, CMCSR, value);
Magnus Damm1b56b962012-12-14 14:54:00 +0900249}
250
Laurent Pinchart7269f932014-01-27 15:29:19 +0100251static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch,
Magnus Damm1b56b962012-12-14 14:54:00 +0900252 unsigned long value)
253{
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100254 ch->cmt->info->write_count(ch->base, CMCNT, value);
Magnus Damm1b56b962012-12-14 14:54:00 +0900255}
256
Laurent Pinchart7269f932014-01-27 15:29:19 +0100257static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch,
Magnus Damm1b56b962012-12-14 14:54:00 +0900258 unsigned long value)
259{
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100260 ch->cmt->info->write_count(ch->base, CMCOR, value);
Magnus Damm1b56b962012-12-14 14:54:00 +0900261}
262
Laurent Pinchart7269f932014-01-27 15:29:19 +0100263static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000264 int *has_wrapped)
265{
266 unsigned long v1, v2, v3;
Magnus Damm5b644c72009-04-28 08:17:54 +0000267 int o1, o2;
268
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100269 o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->info->overflow_bit;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000270
271 /* Make sure the timer value is stable. Stolen from acpi_pm.c */
272 do {
Magnus Damm5b644c72009-04-28 08:17:54 +0000273 o2 = o1;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100274 v1 = sh_cmt_read_cmcnt(ch);
275 v2 = sh_cmt_read_cmcnt(ch);
276 v3 = sh_cmt_read_cmcnt(ch);
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100277 o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->info->overflow_bit;
Magnus Damm5b644c72009-04-28 08:17:54 +0000278 } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
279 || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000280
Magnus Damm5b644c72009-04-28 08:17:54 +0000281 *has_wrapped = o1;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000282 return v2;
283}
284
Magnus Damm587acb32012-12-14 14:54:10 +0900285static DEFINE_RAW_SPINLOCK(sh_cmt_lock);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000286
Laurent Pinchart7269f932014-01-27 15:29:19 +0100287static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000288{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100289 struct sh_timer_config *cfg = ch->cmt->pdev->dev.platform_data;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000290 unsigned long flags, value;
291
292 /* start stop register shared by multiple timer channels */
Paul Mundt7d0c3992012-05-25 13:36:43 +0900293 raw_spin_lock_irqsave(&sh_cmt_lock, flags);
Laurent Pinchart7269f932014-01-27 15:29:19 +0100294 value = sh_cmt_read_cmstr(ch);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000295
296 if (start)
297 value |= 1 << cfg->timer_bit;
298 else
299 value &= ~(1 << cfg->timer_bit);
300
Laurent Pinchart7269f932014-01-27 15:29:19 +0100301 sh_cmt_write_cmstr(ch, value);
Paul Mundt7d0c3992012-05-25 13:36:43 +0900302 raw_spin_unlock_irqrestore(&sh_cmt_lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000303}
304
Laurent Pinchart7269f932014-01-27 15:29:19 +0100305static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000306{
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000307 int k, ret;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000308
Laurent Pinchart7269f932014-01-27 15:29:19 +0100309 pm_runtime_get_sync(&ch->cmt->pdev->dev);
310 dev_pm_syscore_device(&ch->cmt->pdev->dev, true);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200311
Paul Mundt9436b4a2011-05-31 15:26:42 +0900312 /* enable clock */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100313 ret = clk_enable(ch->cmt->clk);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000314 if (ret) {
Laurent Pinchart740a9512014-01-27 22:04:17 +0100315 dev_err(&ch->cmt->pdev->dev, "ch%u: cannot enable clock\n",
316 ch->index);
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000317 goto err0;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000318 }
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000319
320 /* make sure channel is disabled */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100321 sh_cmt_start_stop_ch(ch, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000322
323 /* configure channel, periodic mode and maximum timeout */
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100324 if (ch->cmt->info->width == 16) {
Laurent Pinchart7269f932014-01-27 15:29:19 +0100325 *rate = clk_get_rate(ch->cmt->clk) / 512;
Laurent Pinchartd14be992014-01-29 00:33:08 +0100326 sh_cmt_write_cmcsr(ch, SH_CMT16_CMCSR_CMIE |
327 SH_CMT16_CMCSR_CKS512);
Magnus Damm3014f472009-04-29 14:50:37 +0000328 } else {
Laurent Pinchart7269f932014-01-27 15:29:19 +0100329 *rate = clk_get_rate(ch->cmt->clk) / 8;
Laurent Pinchartd14be992014-01-29 00:33:08 +0100330 sh_cmt_write_cmcsr(ch, SH_CMT32_CMCSR_CMM |
331 SH_CMT32_CMCSR_CMTOUT_IE |
332 SH_CMT32_CMCSR_CMR_IRQ |
333 SH_CMT32_CMCSR_CKS_RCLK8);
Magnus Damm3014f472009-04-29 14:50:37 +0000334 }
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000335
Laurent Pinchart7269f932014-01-27 15:29:19 +0100336 sh_cmt_write_cmcor(ch, 0xffffffff);
337 sh_cmt_write_cmcnt(ch, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000338
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000339 /*
340 * According to the sh73a0 user's manual, as CMCNT can be operated
341 * only by the RCLK (Pseudo 32 KHz), there's one restriction on
342 * modifying CMCNT register; two RCLK cycles are necessary before
343 * this register is either read or any modification of the value
344 * it holds is reflected in the LSI's actual operation.
345 *
346 * While at it, we're supposed to clear out the CMCNT as of this
347 * moment, so make sure it's processed properly here. This will
348 * take RCLKx2 at maximum.
349 */
350 for (k = 0; k < 100; k++) {
Laurent Pinchart7269f932014-01-27 15:29:19 +0100351 if (!sh_cmt_read_cmcnt(ch))
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000352 break;
353 udelay(1);
354 }
355
Laurent Pinchart7269f932014-01-27 15:29:19 +0100356 if (sh_cmt_read_cmcnt(ch)) {
Laurent Pinchart740a9512014-01-27 22:04:17 +0100357 dev_err(&ch->cmt->pdev->dev, "ch%u: cannot clear CMCNT\n",
358 ch->index);
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000359 ret = -ETIMEDOUT;
360 goto err1;
361 }
362
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000363 /* enable channel */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100364 sh_cmt_start_stop_ch(ch, 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000365 return 0;
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000366 err1:
367 /* stop clock */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100368 clk_disable(ch->cmt->clk);
Magnus Damm3f7e5e22011-07-13 07:59:48 +0000369
370 err0:
371 return ret;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000372}
373
Laurent Pinchart7269f932014-01-27 15:29:19 +0100374static void sh_cmt_disable(struct sh_cmt_channel *ch)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000375{
376 /* disable channel */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100377 sh_cmt_start_stop_ch(ch, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000378
Magnus Dammbe890a12009-06-17 05:04:04 +0000379 /* disable interrupts in CMT block */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100380 sh_cmt_write_cmcsr(ch, 0);
Magnus Dammbe890a12009-06-17 05:04:04 +0000381
Paul Mundt9436b4a2011-05-31 15:26:42 +0900382 /* stop clock */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100383 clk_disable(ch->cmt->clk);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200384
Laurent Pinchart7269f932014-01-27 15:29:19 +0100385 dev_pm_syscore_device(&ch->cmt->pdev->dev, false);
386 pm_runtime_put(&ch->cmt->pdev->dev);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000387}
388
389/* private flags */
390#define FLAG_CLOCKEVENT (1 << 0)
391#define FLAG_CLOCKSOURCE (1 << 1)
392#define FLAG_REPROGRAM (1 << 2)
393#define FLAG_SKIPEVENT (1 << 3)
394#define FLAG_IRQCONTEXT (1 << 4)
395
Laurent Pinchart7269f932014-01-27 15:29:19 +0100396static void sh_cmt_clock_event_program_verify(struct sh_cmt_channel *ch,
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000397 int absolute)
398{
399 unsigned long new_match;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100400 unsigned long value = ch->next_match_value;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000401 unsigned long delay = 0;
402 unsigned long now = 0;
403 int has_wrapped;
404
Laurent Pinchart7269f932014-01-27 15:29:19 +0100405 now = sh_cmt_get_counter(ch, &has_wrapped);
406 ch->flags |= FLAG_REPROGRAM; /* force reprogram */
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000407
408 if (has_wrapped) {
409 /* we're competing with the interrupt handler.
410 * -> let the interrupt handler reprogram the timer.
411 * -> interrupt number two handles the event.
412 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100413 ch->flags |= FLAG_SKIPEVENT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000414 return;
415 }
416
417 if (absolute)
418 now = 0;
419
420 do {
421 /* reprogram the timer hardware,
422 * but don't save the new match value yet.
423 */
424 new_match = now + value + delay;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100425 if (new_match > ch->max_match_value)
426 new_match = ch->max_match_value;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000427
Laurent Pinchart7269f932014-01-27 15:29:19 +0100428 sh_cmt_write_cmcor(ch, new_match);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000429
Laurent Pinchart7269f932014-01-27 15:29:19 +0100430 now = sh_cmt_get_counter(ch, &has_wrapped);
431 if (has_wrapped && (new_match > ch->match_value)) {
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000432 /* we are changing to a greater match value,
433 * so this wrap must be caused by the counter
434 * matching the old value.
435 * -> first interrupt reprograms the timer.
436 * -> interrupt number two handles the event.
437 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100438 ch->flags |= FLAG_SKIPEVENT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000439 break;
440 }
441
442 if (has_wrapped) {
443 /* we are changing to a smaller match value,
444 * so the wrap must be caused by the counter
445 * matching the new value.
446 * -> save programmed match value.
447 * -> let isr handle the event.
448 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100449 ch->match_value = new_match;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000450 break;
451 }
452
453 /* be safe: verify hardware settings */
454 if (now < new_match) {
455 /* timer value is below match value, all good.
456 * this makes sure we won't miss any match events.
457 * -> save programmed match value.
458 * -> let isr handle the event.
459 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100460 ch->match_value = new_match;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000461 break;
462 }
463
464 /* the counter has reached a value greater
465 * than our new match value. and since the
466 * has_wrapped flag isn't set we must have
467 * programmed a too close event.
468 * -> increase delay and retry.
469 */
470 if (delay)
471 delay <<= 1;
472 else
473 delay = 1;
474
475 if (!delay)
Laurent Pinchart740a9512014-01-27 22:04:17 +0100476 dev_warn(&ch->cmt->pdev->dev, "ch%u: too long delay\n",
477 ch->index);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000478
479 } while (delay);
480}
481
Laurent Pinchart7269f932014-01-27 15:29:19 +0100482static void __sh_cmt_set_next(struct sh_cmt_channel *ch, unsigned long delta)
Takashi YOSHII65ada542010-12-17 07:25:09 +0000483{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100484 if (delta > ch->max_match_value)
Laurent Pinchart740a9512014-01-27 22:04:17 +0100485 dev_warn(&ch->cmt->pdev->dev, "ch%u: delta out of range\n",
486 ch->index);
Takashi YOSHII65ada542010-12-17 07:25:09 +0000487
Laurent Pinchart7269f932014-01-27 15:29:19 +0100488 ch->next_match_value = delta;
489 sh_cmt_clock_event_program_verify(ch, 0);
Takashi YOSHII65ada542010-12-17 07:25:09 +0000490}
491
Laurent Pinchart7269f932014-01-27 15:29:19 +0100492static void sh_cmt_set_next(struct sh_cmt_channel *ch, unsigned long delta)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000493{
494 unsigned long flags;
495
Laurent Pinchart7269f932014-01-27 15:29:19 +0100496 raw_spin_lock_irqsave(&ch->lock, flags);
497 __sh_cmt_set_next(ch, delta);
498 raw_spin_unlock_irqrestore(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000499}
500
501static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)
502{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100503 struct sh_cmt_channel *ch = dev_id;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000504
505 /* clear flags */
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100506 sh_cmt_write_cmcsr(ch, sh_cmt_read_cmcsr(ch) &
507 ch->cmt->info->clear_bits);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000508
509 /* update clock source counter to begin with if enabled
510 * the wrap flag should be cleared by the timer specific
511 * isr before we end up here.
512 */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100513 if (ch->flags & FLAG_CLOCKSOURCE)
514 ch->total_cycles += ch->match_value + 1;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000515
Laurent Pinchart7269f932014-01-27 15:29:19 +0100516 if (!(ch->flags & FLAG_REPROGRAM))
517 ch->next_match_value = ch->max_match_value;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000518
Laurent Pinchart7269f932014-01-27 15:29:19 +0100519 ch->flags |= FLAG_IRQCONTEXT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000520
Laurent Pinchart7269f932014-01-27 15:29:19 +0100521 if (ch->flags & FLAG_CLOCKEVENT) {
522 if (!(ch->flags & FLAG_SKIPEVENT)) {
523 if (ch->ced.mode == CLOCK_EVT_MODE_ONESHOT) {
524 ch->next_match_value = ch->max_match_value;
525 ch->flags |= FLAG_REPROGRAM;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000526 }
527
Laurent Pinchart7269f932014-01-27 15:29:19 +0100528 ch->ced.event_handler(&ch->ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000529 }
530 }
531
Laurent Pinchart7269f932014-01-27 15:29:19 +0100532 ch->flags &= ~FLAG_SKIPEVENT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000533
Laurent Pinchart7269f932014-01-27 15:29:19 +0100534 if (ch->flags & FLAG_REPROGRAM) {
535 ch->flags &= ~FLAG_REPROGRAM;
536 sh_cmt_clock_event_program_verify(ch, 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000537
Laurent Pinchart7269f932014-01-27 15:29:19 +0100538 if (ch->flags & FLAG_CLOCKEVENT)
539 if ((ch->ced.mode == CLOCK_EVT_MODE_SHUTDOWN)
540 || (ch->match_value == ch->next_match_value))
541 ch->flags &= ~FLAG_REPROGRAM;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000542 }
543
Laurent Pinchart7269f932014-01-27 15:29:19 +0100544 ch->flags &= ~FLAG_IRQCONTEXT;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000545
546 return IRQ_HANDLED;
547}
548
Laurent Pinchart7269f932014-01-27 15:29:19 +0100549static int sh_cmt_start(struct sh_cmt_channel *ch, unsigned long flag)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000550{
551 int ret = 0;
552 unsigned long flags;
553
Laurent Pinchart7269f932014-01-27 15:29:19 +0100554 raw_spin_lock_irqsave(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000555
Laurent Pinchart7269f932014-01-27 15:29:19 +0100556 if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
557 ret = sh_cmt_enable(ch, &ch->rate);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000558
559 if (ret)
560 goto out;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100561 ch->flags |= flag;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000562
563 /* setup timeout if no clockevent */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100564 if ((flag == FLAG_CLOCKSOURCE) && (!(ch->flags & FLAG_CLOCKEVENT)))
565 __sh_cmt_set_next(ch, ch->max_match_value);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000566 out:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100567 raw_spin_unlock_irqrestore(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000568
569 return ret;
570}
571
Laurent Pinchart7269f932014-01-27 15:29:19 +0100572static void sh_cmt_stop(struct sh_cmt_channel *ch, unsigned long flag)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000573{
574 unsigned long flags;
575 unsigned long f;
576
Laurent Pinchart7269f932014-01-27 15:29:19 +0100577 raw_spin_lock_irqsave(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000578
Laurent Pinchart7269f932014-01-27 15:29:19 +0100579 f = ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE);
580 ch->flags &= ~flag;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000581
Laurent Pinchart7269f932014-01-27 15:29:19 +0100582 if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
583 sh_cmt_disable(ch);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000584
585 /* adjust the timeout to maximum if only clocksource left */
Laurent Pinchart7269f932014-01-27 15:29:19 +0100586 if ((flag == FLAG_CLOCKEVENT) && (ch->flags & FLAG_CLOCKSOURCE))
587 __sh_cmt_set_next(ch, ch->max_match_value);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000588
Laurent Pinchart7269f932014-01-27 15:29:19 +0100589 raw_spin_unlock_irqrestore(&ch->lock, flags);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000590}
591
Laurent Pinchart7269f932014-01-27 15:29:19 +0100592static struct sh_cmt_channel *cs_to_sh_cmt(struct clocksource *cs)
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000593{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100594 return container_of(cs, struct sh_cmt_channel, cs);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000595}
596
597static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
598{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100599 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000600 unsigned long flags, raw;
601 unsigned long value;
602 int has_wrapped;
603
Laurent Pinchart7269f932014-01-27 15:29:19 +0100604 raw_spin_lock_irqsave(&ch->lock, flags);
605 value = ch->total_cycles;
606 raw = sh_cmt_get_counter(ch, &has_wrapped);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000607
608 if (unlikely(has_wrapped))
Laurent Pinchart7269f932014-01-27 15:29:19 +0100609 raw += ch->match_value + 1;
610 raw_spin_unlock_irqrestore(&ch->lock, flags);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000611
612 return value + raw;
613}
614
615static int sh_cmt_clocksource_enable(struct clocksource *cs)
616{
Magnus Damm3593f5f2011-04-25 22:32:11 +0900617 int ret;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100618 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000619
Laurent Pinchart7269f932014-01-27 15:29:19 +0100620 WARN_ON(ch->cs_enabled);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200621
Laurent Pinchart7269f932014-01-27 15:29:19 +0100622 ch->total_cycles = 0;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000623
Laurent Pinchart7269f932014-01-27 15:29:19 +0100624 ret = sh_cmt_start(ch, FLAG_CLOCKSOURCE);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200625 if (!ret) {
Laurent Pinchart7269f932014-01-27 15:29:19 +0100626 __clocksource_updatefreq_hz(cs, ch->rate);
627 ch->cs_enabled = true;
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200628 }
Magnus Damm3593f5f2011-04-25 22:32:11 +0900629 return ret;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000630}
631
632static void sh_cmt_clocksource_disable(struct clocksource *cs)
633{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100634 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200635
Laurent Pinchart7269f932014-01-27 15:29:19 +0100636 WARN_ON(!ch->cs_enabled);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200637
Laurent Pinchart7269f932014-01-27 15:29:19 +0100638 sh_cmt_stop(ch, FLAG_CLOCKSOURCE);
639 ch->cs_enabled = false;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000640}
641
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200642static void sh_cmt_clocksource_suspend(struct clocksource *cs)
643{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100644 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200645
Laurent Pinchart7269f932014-01-27 15:29:19 +0100646 sh_cmt_stop(ch, FLAG_CLOCKSOURCE);
647 pm_genpd_syscore_poweroff(&ch->cmt->pdev->dev);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200648}
649
Magnus Dammc8162882010-02-02 14:41:40 -0800650static void sh_cmt_clocksource_resume(struct clocksource *cs)
651{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100652 struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200653
Laurent Pinchart7269f932014-01-27 15:29:19 +0100654 pm_genpd_syscore_poweron(&ch->cmt->pdev->dev);
655 sh_cmt_start(ch, FLAG_CLOCKSOURCE);
Magnus Dammc8162882010-02-02 14:41:40 -0800656}
657
Laurent Pinchart7269f932014-01-27 15:29:19 +0100658static int sh_cmt_register_clocksource(struct sh_cmt_channel *ch,
Laurent Pinchart1d053e12014-02-17 16:04:16 +0100659 const char *name, unsigned long rating)
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000660{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100661 struct clocksource *cs = &ch->cs;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000662
663 cs->name = name;
664 cs->rating = rating;
665 cs->read = sh_cmt_clocksource_read;
666 cs->enable = sh_cmt_clocksource_enable;
667 cs->disable = sh_cmt_clocksource_disable;
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200668 cs->suspend = sh_cmt_clocksource_suspend;
Magnus Dammc8162882010-02-02 14:41:40 -0800669 cs->resume = sh_cmt_clocksource_resume;
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000670 cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
671 cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
Paul Mundtf4d7c352010-06-02 17:10:44 +0900672
Laurent Pinchart740a9512014-01-27 22:04:17 +0100673 dev_info(&ch->cmt->pdev->dev, "ch%u: used as clock source\n",
674 ch->index);
Paul Mundtf4d7c352010-06-02 17:10:44 +0900675
Magnus Damm3593f5f2011-04-25 22:32:11 +0900676 /* Register with dummy 1 Hz value, gets updated in ->enable() */
677 clocksource_register_hz(cs, 1);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000678 return 0;
679}
680
Laurent Pinchart7269f932014-01-27 15:29:19 +0100681static struct sh_cmt_channel *ced_to_sh_cmt(struct clock_event_device *ced)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000682{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100683 return container_of(ced, struct sh_cmt_channel, ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000684}
685
Laurent Pinchart7269f932014-01-27 15:29:19 +0100686static void sh_cmt_clock_event_start(struct sh_cmt_channel *ch, int periodic)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000687{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100688 struct clock_event_device *ced = &ch->ced;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000689
Laurent Pinchart7269f932014-01-27 15:29:19 +0100690 sh_cmt_start(ch, FLAG_CLOCKEVENT);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000691
692 /* TODO: calculate good shift from rate and counter bit width */
693
694 ced->shift = 32;
Laurent Pinchart7269f932014-01-27 15:29:19 +0100695 ced->mult = div_sc(ch->rate, NSEC_PER_SEC, ced->shift);
696 ced->max_delta_ns = clockevent_delta2ns(ch->max_match_value, ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000697 ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
698
699 if (periodic)
Laurent Pinchart7269f932014-01-27 15:29:19 +0100700 sh_cmt_set_next(ch, ((ch->rate + HZ/2) / HZ) - 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000701 else
Laurent Pinchart7269f932014-01-27 15:29:19 +0100702 sh_cmt_set_next(ch, ch->max_match_value);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000703}
704
705static void sh_cmt_clock_event_mode(enum clock_event_mode mode,
706 struct clock_event_device *ced)
707{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100708 struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000709
710 /* deal with old setting first */
711 switch (ced->mode) {
712 case CLOCK_EVT_MODE_PERIODIC:
713 case CLOCK_EVT_MODE_ONESHOT:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100714 sh_cmt_stop(ch, FLAG_CLOCKEVENT);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000715 break;
716 default:
717 break;
718 }
719
720 switch (mode) {
721 case CLOCK_EVT_MODE_PERIODIC:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100722 dev_info(&ch->cmt->pdev->dev,
Laurent Pinchart740a9512014-01-27 22:04:17 +0100723 "ch%u: used for periodic clock events\n", ch->index);
Laurent Pinchart7269f932014-01-27 15:29:19 +0100724 sh_cmt_clock_event_start(ch, 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000725 break;
726 case CLOCK_EVT_MODE_ONESHOT:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100727 dev_info(&ch->cmt->pdev->dev,
Laurent Pinchart740a9512014-01-27 22:04:17 +0100728 "ch%u: used for oneshot clock events\n", ch->index);
Laurent Pinchart7269f932014-01-27 15:29:19 +0100729 sh_cmt_clock_event_start(ch, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000730 break;
731 case CLOCK_EVT_MODE_SHUTDOWN:
732 case CLOCK_EVT_MODE_UNUSED:
Laurent Pinchart7269f932014-01-27 15:29:19 +0100733 sh_cmt_stop(ch, FLAG_CLOCKEVENT);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000734 break;
735 default:
736 break;
737 }
738}
739
740static int sh_cmt_clock_event_next(unsigned long delta,
741 struct clock_event_device *ced)
742{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100743 struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000744
745 BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
Laurent Pinchart7269f932014-01-27 15:29:19 +0100746 if (likely(ch->flags & FLAG_IRQCONTEXT))
747 ch->next_match_value = delta - 1;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000748 else
Laurent Pinchart7269f932014-01-27 15:29:19 +0100749 sh_cmt_set_next(ch, delta - 1);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000750
751 return 0;
752}
753
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200754static void sh_cmt_clock_event_suspend(struct clock_event_device *ced)
755{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100756 struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
Laurent Pinchart57dee992013-12-14 15:07:32 +0900757
Laurent Pinchart7269f932014-01-27 15:29:19 +0100758 pm_genpd_syscore_poweroff(&ch->cmt->pdev->dev);
759 clk_unprepare(ch->cmt->clk);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200760}
761
762static void sh_cmt_clock_event_resume(struct clock_event_device *ced)
763{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100764 struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
Laurent Pinchart57dee992013-12-14 15:07:32 +0900765
Laurent Pinchart7269f932014-01-27 15:29:19 +0100766 clk_prepare(ch->cmt->clk);
767 pm_genpd_syscore_poweron(&ch->cmt->pdev->dev);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200768}
769
Laurent Pinchart7269f932014-01-27 15:29:19 +0100770static void sh_cmt_register_clockevent(struct sh_cmt_channel *ch,
Laurent Pinchart1d053e12014-02-17 16:04:16 +0100771 const char *name, unsigned long rating)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000772{
Laurent Pinchart7269f932014-01-27 15:29:19 +0100773 struct clock_event_device *ced = &ch->ced;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000774
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000775 ced->name = name;
776 ced->features = CLOCK_EVT_FEAT_PERIODIC;
777 ced->features |= CLOCK_EVT_FEAT_ONESHOT;
778 ced->rating = rating;
Laurent Pinchartf1ebe1e2014-02-19 16:19:44 +0100779 ced->cpumask = cpu_possible_mask;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000780 ced->set_next_event = sh_cmt_clock_event_next;
781 ced->set_mode = sh_cmt_clock_event_mode;
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200782 ced->suspend = sh_cmt_clock_event_suspend;
783 ced->resume = sh_cmt_clock_event_resume;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000784
Laurent Pinchart740a9512014-01-27 22:04:17 +0100785 dev_info(&ch->cmt->pdev->dev, "ch%u: used for clock events\n",
786 ch->index);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000787 clockevents_register_device(ced);
788}
789
Laurent Pinchart1d053e12014-02-17 16:04:16 +0100790static int sh_cmt_register(struct sh_cmt_channel *ch, const char *name,
Paul Mundtd1fcc0a2009-05-03 18:05:42 +0900791 unsigned long clockevent_rating,
792 unsigned long clocksource_rating)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000793{
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000794 if (clockevent_rating)
Laurent Pinchart7269f932014-01-27 15:29:19 +0100795 sh_cmt_register_clockevent(ch, name, clockevent_rating);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000796
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000797 if (clocksource_rating)
Laurent Pinchart7269f932014-01-27 15:29:19 +0100798 sh_cmt_register_clocksource(ch, name, clocksource_rating);
Magnus Damm19bdc9d2009-04-17 05:26:31 +0000799
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000800 return 0;
801}
802
Laurent Pinchart740a9512014-01-27 22:04:17 +0100803static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100804 struct sh_cmt_device *cmt)
805{
806 struct sh_timer_config *cfg = cmt->pdev->dev.platform_data;
807 int irq;
808 int ret;
809
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100810 ch->cmt = cmt;
Laurent Pinchartc924d2d2014-01-27 22:04:17 +0100811 ch->base = cmt->mapbase_ch;
Laurent Pinchart740a9512014-01-27 22:04:17 +0100812 ch->index = index;
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100813
814 irq = platform_get_irq(cmt->pdev, 0);
815 if (irq < 0) {
Laurent Pinchart740a9512014-01-27 22:04:17 +0100816 dev_err(&cmt->pdev->dev, "ch%u: failed to get irq\n",
817 ch->index);
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100818 return irq;
819 }
820
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100821 if (cmt->info->width == (sizeof(ch->max_match_value) * 8))
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100822 ch->max_match_value = ~0;
823 else
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100824 ch->max_match_value = (1 << cmt->info->width) - 1;
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100825
826 ch->match_value = ch->max_match_value;
827 raw_spin_lock_init(&ch->lock);
828
Laurent Pinchart1d053e12014-02-17 16:04:16 +0100829 ret = sh_cmt_register(ch, dev_name(&cmt->pdev->dev),
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100830 cfg->clockevent_rating,
831 cfg->clocksource_rating);
832 if (ret) {
Laurent Pinchart740a9512014-01-27 22:04:17 +0100833 dev_err(&cmt->pdev->dev, "ch%u: registration failed\n",
834 ch->index);
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100835 return ret;
836 }
837 ch->cs_enabled = false;
838
839 ret = request_irq(irq, sh_cmt_interrupt,
840 IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
841 dev_name(&cmt->pdev->dev), ch);
842 if (ret) {
Laurent Pinchart740a9512014-01-27 22:04:17 +0100843 dev_err(&cmt->pdev->dev, "ch%u: failed to request irq %d\n",
844 ch->index, irq);
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100845 return ret;
846 }
847
848 return 0;
849}
850
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100851static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000852{
Paul Mundt46a12f72009-05-03 17:57:17 +0900853 struct sh_timer_config *cfg = pdev->dev.platform_data;
Magnus Damm8874c5e2013-06-17 15:40:52 +0900854 struct resource *res, *res2;
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100855 int ret;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000856 ret = -ENXIO;
857
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100858 cmt->pdev = pdev;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000859
860 if (!cfg) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100861 dev_err(&cmt->pdev->dev, "missing platform data\n");
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000862 goto err0;
863 }
864
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100865 res = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 0);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000866 if (!res) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100867 dev_err(&cmt->pdev->dev, "failed to get I/O memory\n");
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000868 goto err0;
869 }
870
Magnus Damm8874c5e2013-06-17 15:40:52 +0900871 /* optional resource for the shared timer start/stop register */
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100872 res2 = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 1);
Magnus Damm8874c5e2013-06-17 15:40:52 +0900873
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100874 /* map memory, let mapbase_ch point to our channel */
875 cmt->mapbase_ch = ioremap_nocache(res->start, resource_size(res));
876 if (cmt->mapbase_ch == NULL) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100877 dev_err(&cmt->pdev->dev, "failed to remap I/O memory\n");
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000878 goto err0;
879 }
880
Magnus Damm8874c5e2013-06-17 15:40:52 +0900881 /* map second resource for CMSTR */
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100882 cmt->mapbase = ioremap_nocache(res2 ? res2->start :
883 res->start - cfg->channel_offset,
884 res2 ? resource_size(res2) : 2);
885 if (cmt->mapbase == NULL) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100886 dev_err(&cmt->pdev->dev, "failed to remap I/O second memory\n");
Magnus Damm8874c5e2013-06-17 15:40:52 +0900887 goto err1;
888 }
889
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000890 /* get hold of clock */
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100891 cmt->clk = clk_get(&cmt->pdev->dev, "cmt_fck");
892 if (IS_ERR(cmt->clk)) {
893 dev_err(&cmt->pdev->dev, "cannot get clock\n");
894 ret = PTR_ERR(cmt->clk);
Magnus Damm8874c5e2013-06-17 15:40:52 +0900895 goto err2;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000896 }
897
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100898 ret = clk_prepare(cmt->clk);
Laurent Pinchart57dee992013-12-14 15:07:32 +0900899 if (ret < 0)
900 goto err3;
901
Laurent Pinchart2cda3ac2014-02-11 23:46:48 +0100902 /* identify the model based on the resources */
903 if (resource_size(res) == 6)
904 cmt->info = &sh_cmt_info[SH_CMT_16BIT];
905 else if (res2 && (resource_size(res2) == 4))
906 cmt->info = &sh_cmt_info[SH_CMT_48BIT_GEN2];
907 else
908 cmt->info = &sh_cmt_info[SH_CMT_32BIT];
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000909
Laurent Pinchartf5ec9b12014-01-27 22:04:17 +0100910 cmt->channels = kzalloc(sizeof(*cmt->channels), GFP_KERNEL);
911 if (cmt->channels == NULL) {
912 ret = -ENOMEM;
913 goto err4;
914 }
915
916 cmt->num_channels = 1;
917
918 ret = sh_cmt_setup_channel(&cmt->channels[0], cfg->timer_bit, cmt);
Laurent Pinchartb882e7b2014-01-27 22:04:17 +0100919 if (ret < 0)
Laurent Pinchart57dee992013-12-14 15:07:32 +0900920 goto err4;
Paul Mundtda64c2a2010-02-25 16:37:46 +0900921
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100922 platform_set_drvdata(pdev, cmt);
Magnus Dammadccc692012-12-14 14:53:51 +0900923
Paul Mundtda64c2a2010-02-25 16:37:46 +0900924 return 0;
Laurent Pinchart57dee992013-12-14 15:07:32 +0900925err4:
Laurent Pinchartf5ec9b12014-01-27 22:04:17 +0100926 kfree(cmt->channels);
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100927 clk_unprepare(cmt->clk);
Magnus Damm8874c5e2013-06-17 15:40:52 +0900928err3:
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100929 clk_put(cmt->clk);
Magnus Damm8874c5e2013-06-17 15:40:52 +0900930err2:
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100931 iounmap(cmt->mapbase);
Laurent Pinchart36f1ac92014-01-27 22:04:17 +0100932err1:
933 iounmap(cmt->mapbase_ch);
Paul Mundtda64c2a2010-02-25 16:37:46 +0900934err0:
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000935 return ret;
936}
937
Greg Kroah-Hartman18505142012-12-21 15:11:38 -0800938static int sh_cmt_probe(struct platform_device *pdev)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000939{
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100940 struct sh_cmt_device *cmt = platform_get_drvdata(pdev);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200941 struct sh_timer_config *cfg = pdev->dev.platform_data;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000942 int ret;
943
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200944 if (!is_early_platform_device(pdev)) {
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200945 pm_runtime_set_active(&pdev->dev);
946 pm_runtime_enable(&pdev->dev);
Rafael J. Wysocki9bb5ec82012-08-06 01:43:03 +0200947 }
Rafael J. Wysocki615a4452012-03-13 22:40:06 +0100948
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100949 if (cmt) {
Paul Mundt214a6072010-03-10 16:26:25 +0900950 dev_info(&pdev->dev, "kept as earlytimer\n");
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200951 goto out;
Magnus Damme475eed2009-04-15 10:50:04 +0000952 }
953
Laurent Pinchartb262bc72014-01-27 22:04:17 +0100954 cmt = kzalloc(sizeof(*cmt), GFP_KERNEL);
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100955 if (cmt == NULL) {
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000956 dev_err(&pdev->dev, "failed to allocate driver data\n");
957 return -ENOMEM;
958 }
959
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100960 ret = sh_cmt_setup(cmt, pdev);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000961 if (ret) {
Laurent Pinchart2653caf2014-01-27 22:04:17 +0100962 kfree(cmt);
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200963 pm_runtime_idle(&pdev->dev);
964 return ret;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000965 }
Rafael J. Wysockibad81382012-08-06 01:48:57 +0200966 if (is_early_platform_device(pdev))
967 return 0;
968
969 out:
970 if (cfg->clockevent_rating || cfg->clocksource_rating)
971 pm_runtime_irq_safe(&pdev->dev);
972 else
973 pm_runtime_idle(&pdev->dev);
974
975 return 0;
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000976}
977
Greg Kroah-Hartman18505142012-12-21 15:11:38 -0800978static int sh_cmt_remove(struct platform_device *pdev)
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000979{
980 return -EBUSY; /* cannot unregister clockevent and clocksource */
981}
982
983static struct platform_driver sh_cmt_device_driver = {
984 .probe = sh_cmt_probe,
Greg Kroah-Hartman18505142012-12-21 15:11:38 -0800985 .remove = sh_cmt_remove,
Magnus Damm3fb1b6a2009-01-22 09:55:59 +0000986 .driver = {
987 .name = "sh_cmt",
988 }
989};
990
991static int __init sh_cmt_init(void)
992{
993 return platform_driver_register(&sh_cmt_device_driver);
994}
995
996static void __exit sh_cmt_exit(void)
997{
998 platform_driver_unregister(&sh_cmt_device_driver);
999}
1000
Magnus Damme475eed2009-04-15 10:50:04 +00001001early_platform_init("earlytimer", &sh_cmt_device_driver);
Simon Hormane903a032013-03-05 15:40:42 +09001002subsys_initcall(sh_cmt_init);
Magnus Damm3fb1b6a2009-01-22 09:55:59 +00001003module_exit(sh_cmt_exit);
1004
1005MODULE_AUTHOR("Magnus Damm");
1006MODULE_DESCRIPTION("SuperH CMT Timer Driver");
1007MODULE_LICENSE("GPL v2");