summaryrefslogtreecommitdiffstats
path: root/drivers/sh
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2013-12-14 16:23:51 +0100
committerSimon Horman <horms+renesas@verge.net.au>2014-02-04 02:22:39 +0100
commita028c6da34d434e35ba8322568c756ea97ff3c18 (patch)
treec35c6e13f7e4d114ccd178345c705f11a25acff0 /drivers/sh
parentLinus 3.14-rc1 (diff)
downloadlinux-a028c6da34d434e35ba8322568c756ea97ff3c18.tar.xz
linux-a028c6da34d434e35ba8322568c756ea97ff3c18.zip
ARM: shmobile: wait for MSTP clock status to toggle, when enabling it
On r-/sh-mobile SoCs MSTP clocks are used by the runtime PM to dynamically enable and disable peripheral clocks. To make sure the clock has really started we have to read back its status register until it confirms success. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski+renesas@gmail.com> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
Diffstat (limited to 'drivers/sh')
-rw-r--r--drivers/sh/clk/cpg.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c
index 1ebe67cd1833..7442bc130055 100644
--- a/drivers/sh/clk/cpg.c
+++ b/drivers/sh/clk/cpg.c
@@ -36,9 +36,47 @@ static void sh_clk_write(int value, struct clk *clk)
iowrite32(value, clk->mapped_reg);
}
+static unsigned int r8(const void __iomem *addr)
+{
+ return ioread8(addr);
+}
+
+static unsigned int r16(const void __iomem *addr)
+{
+ return ioread16(addr);
+}
+
+static unsigned int r32(const void __iomem *addr)
+{
+ return ioread32(addr);
+}
+
static int sh_clk_mstp_enable(struct clk *clk)
{
sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk);
+ if (clk->status_reg) {
+ unsigned int (*read)(const void __iomem *addr);
+ int i;
+ void __iomem *mapped_status = (phys_addr_t)clk->status_reg -
+ (phys_addr_t)clk->enable_reg + clk->mapped_reg;
+
+ if (clk->flags & CLK_ENABLE_REG_8BIT)
+ read = r8;
+ else if (clk->flags & CLK_ENABLE_REG_16BIT)
+ read = r16;
+ else
+ read = r32;
+
+ for (i = 1000;
+ (read(mapped_status) & (1 << clk->enable_bit)) && i;
+ i--)
+ cpu_relax();
+ if (!i) {
+ pr_err("cpg: failed to enable %p[%d]\n",
+ clk->enable_reg, clk->enable_bit);
+ return -ETIMEDOUT;
+ }
+ }
return 0;
}