aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/sh_cmt.c
diff options
context:
space:
mode:
authorMagnus Damm <damm@opensource.se>2011-07-13 03:59:48 -0400
committerPaul Mundt <lethal@linux-sh.org>2011-07-21 03:16:51 -0400
commit3f7e5e2423f6233f7665d54061ba7761ca90cf52 (patch)
tree0d7836cfd49ff12614f46d32f6ab483814a31527 /drivers/clocksource/sh_cmt.c
parentcf6ace16a3cd8b728fb0afa68368fd40bbeae19f (diff)
clocksource: sh_cmt: wait for CMCNT on init V2
Add code to the CMT driver to wait for CMCNT V2. This to let the register value settle before starting the timer channel. Makes the driver more robust. Needed for CMT2 on sh7372 and certain CMT channels on sh73a0. Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/clocksource/sh_cmt.c')
-rw-r--r--drivers/clocksource/sh_cmt.c34
1 files changed, 32 insertions, 2 deletions
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index dc7c033ef587..32a77becc098 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -26,6 +26,7 @@
26#include <linux/clk.h> 26#include <linux/clk.h>
27#include <linux/irq.h> 27#include <linux/irq.h>
28#include <linux/err.h> 28#include <linux/err.h>
29#include <linux/delay.h>
29#include <linux/clocksource.h> 30#include <linux/clocksource.h>
30#include <linux/clockchips.h> 31#include <linux/clockchips.h>
31#include <linux/sh_timer.h> 32#include <linux/sh_timer.h>
@@ -150,13 +151,13 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start)
150 151
151static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate) 152static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
152{ 153{
153 int ret; 154 int k, ret;
154 155
155 /* enable clock */ 156 /* enable clock */
156 ret = clk_enable(p->clk); 157 ret = clk_enable(p->clk);
157 if (ret) { 158 if (ret) {
158 dev_err(&p->pdev->dev, "cannot enable clock\n"); 159 dev_err(&p->pdev->dev, "cannot enable clock\n");
159 return ret; 160 goto err0;
160 } 161 }
161 162
162 /* make sure channel is disabled */ 163 /* make sure channel is disabled */
@@ -174,9 +175,38 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
174 sh_cmt_write(p, CMCOR, 0xffffffff); 175 sh_cmt_write(p, CMCOR, 0xffffffff);
175 sh_cmt_write(p, CMCNT, 0); 176 sh_cmt_write(p, CMCNT, 0);
176 177
178 /*
179 * According to the sh73a0 user's manual, as CMCNT can be operated
180 * only by the RCLK (Pseudo 32 KHz), there's one restriction on
181 * modifying CMCNT register; two RCLK cycles are necessary before
182 * this register is either read or any modification of the value
183 * it holds is reflected in the LSI's actual operation.
184 *
185 * While at it, we're supposed to clear out the CMCNT as of this
186 * moment, so make sure it's processed properly here. This will
187 * take RCLKx2 at maximum.
188 */
189 for (k = 0; k < 100; k++) {
190 if (!sh_cmt_read(p, CMCNT))
191 break;
192 udelay(1);
193 }
194
195 if (sh_cmt_read(p, CMCNT)) {
196 dev_err(&p->pdev->dev, "cannot clear CMCNT\n");
197 ret = -ETIMEDOUT;
198 goto err1;
199 }
200
177 /* enable channel */ 201 /* enable channel */
178 sh_cmt_start_stop_ch(p, 1); 202 sh_cmt_start_stop_ch(p, 1);
179 return 0; 203 return 0;
204 err1:
205 /* stop clock */
206 clk_disable(p->clk);
207
208 err0:
209 return ret;
180} 210}
181 211
182static void sh_cmt_disable(struct sh_cmt_priv *p) 212static void sh_cmt_disable(struct sh_cmt_priv *p)