Merge remote-tracking branch 'mturquette/clk-3.7' into imx/dt-for-3.7-2
authorShawn Guo <shawn.guo@linaro.org>
Mon, 17 Sep 2012 07:11:28 +0000 (15:11 +0800)
committerShawn Guo <shawn.guo@linaro.org>
Mon, 17 Sep 2012 07:11:28 +0000 (15:11 +0800)
47 files changed:
arch/arm/Kconfig
arch/arm/mach-mmp/Kconfig
arch/arm/mach-prima2/Makefile
arch/arm/mach-prima2/clock.c [deleted file]
arch/arm/mach-prima2/prima2.c
arch/arm/mach-prima2/timer.c
arch/arm/mach-realview/core.c
arch/arm/mach-realview/include/mach/clkdev.h [deleted file]
arch/arm/mach-realview/realview_eb.c
arch/arm/mach-realview/realview_pb1176.c
arch/arm/mach-realview/realview_pb11mp.c
arch/arm/mach-realview/realview_pba8.c
arch/arm/mach-realview/realview_pbx.c
arch/arm/mach-ux500/Kconfig
arch/arm/mach-ux500/Makefile
arch/arm/mach-ux500/clock.c [deleted file]
arch/arm/mach-ux500/clock.h [deleted file]
arch/arm/mach-ux500/cpu.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/clk-ls1x.c [new file with mode: 0644]
drivers/clk/clk-max77686.c [new file with mode: 0644]
drivers/clk/clk-prima2.c [new file with mode: 0644]
drivers/clk/clk.c
drivers/clk/mmp/Makefile [new file with mode: 0644]
drivers/clk/mmp/clk-apbc.c [new file with mode: 0644]
drivers/clk/mmp/clk-apmu.c [new file with mode: 0644]
drivers/clk/mmp/clk-frac.c [new file with mode: 0644]
drivers/clk/mmp/clk-mmp2.c [new file with mode: 0644]
drivers/clk/mmp/clk-pxa168.c [new file with mode: 0644]
drivers/clk/mmp/clk-pxa910.c [new file with mode: 0644]
drivers/clk/mmp/clk.h [new file with mode: 0644]
drivers/clk/ux500/Makefile [new file with mode: 0644]
drivers/clk/ux500/clk-prcc.c [new file with mode: 0644]
drivers/clk/ux500/clk-prcmu.c [new file with mode: 0644]
drivers/clk/ux500/clk.h [new file with mode: 0644]
drivers/clk/ux500/u8500_clk.c [new file with mode: 0644]
drivers/clk/ux500/u8540_clk.c [new file with mode: 0644]
drivers/clk/ux500/u9540_clk.c [new file with mode: 0644]
drivers/clk/versatile/Makefile
drivers/clk/versatile/clk-realview.c [new file with mode: 0644]
drivers/mfd/db8500-prcmu.c
drivers/mfd/dbx500-prcmu-regs.h
include/linux/clk-provider.h
include/linux/mfd/dbx500-prcmu.h
include/linux/platform_data/clk-realview.h [new file with mode: 0644]
include/linux/platform_data/clk-ux500.h [new file with mode: 0644]

index 6d6e18fee9fe08bacf876e749837d4b0156a5fd9..1a01ffa331d04d1fe9c2fa41295aa5eb9fe4b0db 100644 (file)
@@ -273,7 +273,7 @@ config ARCH_INTEGRATOR
        select ARM_AMBA
        select ARCH_HAS_CPUFREQ
        select COMMON_CLK
-       select CLK_VERSATILE
+       select COMMON_CLK_VERSATILE
        select HAVE_TCM
        select ICST
        select GENERIC_CLOCKEVENTS
@@ -289,13 +289,12 @@ config ARCH_INTEGRATOR
 config ARCH_REALVIEW
        bool "ARM Ltd. RealView family"
        select ARM_AMBA
-       select CLKDEV_LOOKUP
-       select HAVE_MACH_CLKDEV
+       select COMMON_CLK
+       select COMMON_CLK_VERSATILE
        select ICST
        select GENERIC_CLOCKEVENTS
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select PLAT_VERSATILE
-       select PLAT_VERSATILE_CLOCK
        select PLAT_VERSATILE_CLCD
        select ARM_TIMER_SP804
        select GPIO_PL061 if GPIOLIB
@@ -413,7 +412,7 @@ config ARCH_PRIMA2
        select NO_IOPORT
        select ARCH_REQUIRE_GPIOLIB
        select GENERIC_CLOCKEVENTS
-       select CLKDEV_LOOKUP
+       select COMMON_CLK
        select GENERIC_IRQ_CHIP
        select MIGHT_HAVE_CACHE_L2X0
        select PINCTRL
index 7fddd01b85b9ec8c585beca0ef5c59584d3bc8a6..d697d07a1bf080fe167c1f434efc96735daeda53 100644 (file)
@@ -108,18 +108,21 @@ endmenu
 config CPU_PXA168
        bool
        select CPU_MOHAWK
+       select COMMON_CLK
        help
          Select code specific to PXA168
 
 config CPU_PXA910
        bool
        select CPU_MOHAWK
+       select COMMON_CLK
        help
          Select code specific to PXA910
 
 config CPU_MMP2
        bool
        select CPU_PJ4
+       select COMMON_CLK
        help
          Select code specific to MMP2. MMP2 is ARMv7 compatible.
 
index 13dd1604d95114edcd7c45efb81ec770395e6d8e..841847d56032657b3855fe3e4a28b6988a3e5244 100644 (file)
@@ -1,6 +1,5 @@
 obj-y := timer.o
 obj-y += irq.o
-obj-y += clock.o
 obj-y += rstc.o
 obj-y += prima2.o
 obj-y += rtciobrg.o
diff --git a/arch/arm/mach-prima2/clock.c b/arch/arm/mach-prima2/clock.c
deleted file mode 100644 (file)
index aebad7e..0000000
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * Clock tree for CSR SiRFprimaII
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- *
- * Licensed under GPLv2 or later.
- */
-
-#include <linux/module.h>
-#include <linux/bitops.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/clkdev.h>
-#include <linux/clk.h>
-#include <linux/spinlock.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <asm/mach/map.h>
-#include <mach/map.h>
-
-#define SIRFSOC_CLKC_CLK_EN0    0x0000
-#define SIRFSOC_CLKC_CLK_EN1    0x0004
-#define SIRFSOC_CLKC_REF_CFG    0x0014
-#define SIRFSOC_CLKC_CPU_CFG    0x0018
-#define SIRFSOC_CLKC_MEM_CFG    0x001c
-#define SIRFSOC_CLKC_SYS_CFG    0x0020
-#define SIRFSOC_CLKC_IO_CFG     0x0024
-#define SIRFSOC_CLKC_DSP_CFG    0x0028
-#define SIRFSOC_CLKC_GFX_CFG    0x002c
-#define SIRFSOC_CLKC_MM_CFG     0x0030
-#define SIRFSOC_LKC_LCD_CFG     0x0034
-#define SIRFSOC_CLKC_MMC_CFG    0x0038
-#define SIRFSOC_CLKC_PLL1_CFG0  0x0040
-#define SIRFSOC_CLKC_PLL2_CFG0  0x0044
-#define SIRFSOC_CLKC_PLL3_CFG0  0x0048
-#define SIRFSOC_CLKC_PLL1_CFG1  0x004c
-#define SIRFSOC_CLKC_PLL2_CFG1  0x0050
-#define SIRFSOC_CLKC_PLL3_CFG1  0x0054
-#define SIRFSOC_CLKC_PLL1_CFG2  0x0058
-#define SIRFSOC_CLKC_PLL2_CFG2  0x005c
-#define SIRFSOC_CLKC_PLL3_CFG2  0x0060
-
-#define SIRFSOC_CLOCK_VA_BASE          SIRFSOC_VA(0x005000)
-
-#define KHZ     1000
-#define MHZ     (KHZ * KHZ)
-
-struct clk_ops {
-       unsigned long (*get_rate)(struct clk *clk);
-       long (*round_rate)(struct clk *clk, unsigned long rate);
-       int (*set_rate)(struct clk *clk, unsigned long rate);
-       int (*enable)(struct clk *clk);
-       int (*disable)(struct clk *clk);
-       struct clk *(*get_parent)(struct clk *clk);
-       int (*set_parent)(struct clk *clk, struct clk *parent);
-};
-
-struct clk {
-       struct clk *parent;     /* parent clk */
-       unsigned long rate;     /* clock rate in Hz */
-       signed char usage;      /* clock enable count */
-       signed char enable_bit; /* enable bit: 0 ~ 63 */
-       unsigned short regofs;  /* register offset */
-       struct clk_ops *ops;    /* clock operation */
-};
-
-static DEFINE_SPINLOCK(clocks_lock);
-
-static inline unsigned long clkc_readl(unsigned reg)
-{
-       return readl(SIRFSOC_CLOCK_VA_BASE + reg);
-}
-
-static inline void clkc_writel(u32 val, unsigned reg)
-{
-       writel(val, SIRFSOC_CLOCK_VA_BASE + reg);
-}
-
-/*
- * osc_rtc - real time oscillator - 32.768KHz
- * osc_sys - high speed oscillator - 26MHz
- */
-
-static struct clk clk_rtc = {
-       .rate = 32768,
-};
-
-static struct clk clk_osc = {
-       .rate = 26 * MHZ,
-};
-
-/*
- * std pll
- */
-static unsigned long std_pll_get_rate(struct clk *clk)
-{
-       unsigned long fin = clk_get_rate(clk->parent);
-       u32 regcfg2 = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 -
-               SIRFSOC_CLKC_PLL1_CFG0;
-
-       if (clkc_readl(regcfg2) & BIT(2)) {
-               /* pll bypass mode */
-               clk->rate = fin;
-       } else {
-               /* fout = fin * nf / nr / od */
-               u32 cfg0 = clkc_readl(clk->regofs);
-               u32 nf = (cfg0 & (BIT(13) - 1)) + 1;
-               u32 nr = ((cfg0 >> 13) & (BIT(6) - 1)) + 1;
-               u32 od = ((cfg0 >> 19) & (BIT(4) - 1)) + 1;
-               WARN_ON(fin % MHZ);
-               clk->rate = fin / MHZ * nf / nr / od * MHZ;
-       }
-
-       return clk->rate;
-}
-
-static int std_pll_set_rate(struct clk *clk, unsigned long rate)
-{
-       unsigned long fin, nf, nr, od, reg;
-
-       /*
-        * fout = fin * nf / (nr * od);
-        * set od = 1, nr = fin/MHz, so fout = nf * MHz
-        */
-
-       nf = rate / MHZ;
-       if (unlikely((rate % MHZ) || nf > BIT(13) || nf < 1))
-               return -EINVAL;
-
-       fin = clk_get_rate(clk->parent);
-       BUG_ON(fin < MHZ);
-
-       nr = fin / MHZ;
-       BUG_ON((fin % MHZ) || nr > BIT(6));
-
-       od = 1;
-
-       reg = (nf - 1) | ((nr - 1) << 13) | ((od - 1) << 19);
-       clkc_writel(reg, clk->regofs);
-
-       reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG1 - SIRFSOC_CLKC_PLL1_CFG0;
-       clkc_writel((nf >> 1) - 1, reg);
-
-       reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - SIRFSOC_CLKC_PLL1_CFG0;
-       while (!(clkc_readl(reg) & BIT(6)))
-               cpu_relax();
-
-       clk->rate = 0; /* set to zero will force recalculation */
-       return 0;
-}
-
-static struct clk_ops std_pll_ops = {
-       .get_rate = std_pll_get_rate,
-       .set_rate = std_pll_set_rate,
-};
-
-static struct clk clk_pll1 = {
-       .parent = &clk_osc,
-       .regofs = SIRFSOC_CLKC_PLL1_CFG0,
-       .ops = &std_pll_ops,
-};
-
-static struct clk clk_pll2 = {
-       .parent = &clk_osc,
-       .regofs = SIRFSOC_CLKC_PLL2_CFG0,
-       .ops = &std_pll_ops,
-};
-
-static struct clk clk_pll3 = {
-       .parent = &clk_osc,
-       .regofs = SIRFSOC_CLKC_PLL3_CFG0,
-       .ops = &std_pll_ops,
-};
-
-/*
- * clock domains - cpu, mem, sys/io
- */
-
-static struct clk clk_mem;
-
-static struct clk *dmn_get_parent(struct clk *clk)
-{
-       struct clk *clks[] = {
-               &clk_osc, &clk_rtc, &clk_pll1, &clk_pll2, &clk_pll3
-       };
-       u32 cfg = clkc_readl(clk->regofs);
-       WARN_ON((cfg & (BIT(3) - 1)) > 4);
-       return clks[cfg & (BIT(3) - 1)];
-}
-
-static int dmn_set_parent(struct clk *clk, struct clk *parent)
-{
-       const struct clk *clks[] = {
-               &clk_osc, &clk_rtc, &clk_pll1, &clk_pll2, &clk_pll3
-       };
-       u32 cfg = clkc_readl(clk->regofs);
-       int i;
-       for (i = 0; i < ARRAY_SIZE(clks); i++) {
-               if (clks[i] == parent) {
-                       cfg &= ~(BIT(3) - 1);
-                       clkc_writel(cfg | i, clk->regofs);
-                       /* BIT(3) - switching status: 1 - busy, 0 - done */
-                       while (clkc_readl(clk->regofs) & BIT(3))
-                               cpu_relax();
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-static unsigned long dmn_get_rate(struct clk *clk)
-{
-       unsigned long fin = clk_get_rate(clk->parent);
-       u32 cfg = clkc_readl(clk->regofs);
-       if (cfg & BIT(24)) {
-               /* fcd bypass mode */
-               clk->rate = fin;
-       } else {
-               /*
-                * wait count: bit[19:16], hold count: bit[23:20]
-                */
-               u32 wait = (cfg >> 16) & (BIT(4) - 1);
-               u32 hold = (cfg >> 20) & (BIT(4) - 1);
-
-               clk->rate = fin / (wait + hold + 2);
-       }
-
-       return clk->rate;
-}
-
-static int dmn_set_rate(struct clk *clk, unsigned long rate)
-{
-       unsigned long fin;
-       unsigned ratio, wait, hold, reg;
-       unsigned bits = (clk == &clk_mem) ? 3 : 4;
-
-       fin = clk_get_rate(clk->parent);
-       ratio = fin / rate;
-
-       if (unlikely(ratio < 2 || ratio > BIT(bits + 1)))
-               return -EINVAL;
-
-       WARN_ON(fin % rate);
-
-       wait = (ratio >> 1) - 1;
-       hold = ratio - wait - 2;
-
-       reg = clkc_readl(clk->regofs);
-       reg &= ~(((BIT(bits) - 1) << 16) | ((BIT(bits) - 1) << 20));
-       reg |= (wait << 16) | (hold << 20) | BIT(25);
-       clkc_writel(reg, clk->regofs);
-
-       /* waiting FCD been effective */
-       while (clkc_readl(clk->regofs) & BIT(25))
-               cpu_relax();
-
-       clk->rate = 0; /* set to zero will force recalculation */
-
-       return 0;
-}
-
-/*
- * cpu clock has no FCD register in Prima2, can only change pll
- */
-static int cpu_set_rate(struct clk *clk, unsigned long rate)
-{
-       int ret1, ret2;
-       struct clk *cur_parent, *tmp_parent;
-
-       cur_parent = dmn_get_parent(clk);
-       BUG_ON(cur_parent == NULL || cur_parent->usage > 1);
-
-       /* switch to tmp pll before setting parent clock's rate */
-       tmp_parent = cur_parent == &clk_pll1 ? &clk_pll2 : &clk_pll1;
-       ret1 = dmn_set_parent(clk, tmp_parent);
-       BUG_ON(ret1);
-
-       ret2 = clk_set_rate(cur_parent, rate);
-
-       ret1 = dmn_set_parent(clk, cur_parent);
-
-       clk->rate = 0; /* set to zero will force recalculation */
-
-       return ret2 ? ret2 : ret1;
-}
-
-static struct clk_ops cpu_ops = {
-       .get_parent = dmn_get_parent,
-       .set_parent = dmn_set_parent,
-       .set_rate = cpu_set_rate,
-};
-
-static struct clk clk_cpu = {
-       .parent = &clk_pll1,
-       .regofs = SIRFSOC_CLKC_CPU_CFG,
-       .ops = &cpu_ops,
-};
-
-
-static struct clk_ops msi_ops = {
-       .set_rate = dmn_set_rate,
-       .get_rate = dmn_get_rate,
-       .set_parent = dmn_set_parent,
-       .get_parent = dmn_get_parent,
-};
-
-static struct clk clk_mem = {
-       .parent = &clk_pll2,
-       .regofs = SIRFSOC_CLKC_MEM_CFG,
-       .ops = &msi_ops,
-};
-
-static struct clk clk_sys = {
-       .parent = &clk_pll3,
-       .regofs = SIRFSOC_CLKC_SYS_CFG,
-       .ops = &msi_ops,
-};
-
-static struct clk clk_io = {
-       .parent = &clk_pll3,
-       .regofs = SIRFSOC_CLKC_IO_CFG,
-       .ops = &msi_ops,
-};
-
-/*
- * on-chip clock sets
- */
-static struct clk_lookup onchip_clks[] = {
-       {
-               .dev_id = "rtc",
-               .clk = &clk_rtc,
-       }, {
-               .dev_id = "osc",
-               .clk = &clk_osc,
-       }, {
-               .dev_id = "pll1",
-               .clk = &clk_pll1,
-       }, {
-               .dev_id = "pll2",
-               .clk = &clk_pll2,
-       }, {
-               .dev_id = "pll3",
-               .clk = &clk_pll3,
-       }, {
-               .dev_id = "cpu",
-               .clk = &clk_cpu,
-       }, {
-               .dev_id = "mem",
-               .clk = &clk_mem,
-       }, {
-               .dev_id = "sys",
-               .clk = &clk_sys,
-       }, {
-               .dev_id = "io",
-               .clk = &clk_io,
-       },
-};
-
-int clk_enable(struct clk *clk)
-{
-       unsigned long flags;
-
-       if (unlikely(IS_ERR_OR_NULL(clk)))
-               return -EINVAL;
-
-       if (clk->parent)
-               clk_enable(clk->parent);
-
-       spin_lock_irqsave(&clocks_lock, flags);
-       if (!clk->usage++ && clk->ops && clk->ops->enable)
-               clk->ops->enable(clk);
-       spin_unlock_irqrestore(&clocks_lock, flags);
-       return 0;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
-       unsigned long flags;
-
-       if (unlikely(IS_ERR_OR_NULL(clk)))
-               return;
-
-       WARN_ON(!clk->usage);
-
-       spin_lock_irqsave(&clocks_lock, flags);
-       if (--clk->usage == 0 && clk->ops && clk->ops->disable)
-               clk->ops->disable(clk);
-       spin_unlock_irqrestore(&clocks_lock, flags);
-
-       if (clk->parent)
-               clk_disable(clk->parent);
-}
-EXPORT_SYMBOL(clk_disable);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
-       if (unlikely(IS_ERR_OR_NULL(clk)))
-               return 0;
-
-       if (clk->rate)
-               return clk->rate;
-
-       if (clk->ops && clk->ops->get_rate)
-               return clk->ops->get_rate(clk);
-
-       return clk_get_rate(clk->parent);
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
-       if (unlikely(IS_ERR_OR_NULL(clk)))
-               return 0;
-
-       if (clk->ops && clk->ops->round_rate)
-               return clk->ops->round_rate(clk, rate);
-
-       return 0;
-}
-EXPORT_SYMBOL(clk_round_rate);
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
-       if (unlikely(IS_ERR_OR_NULL(clk)))
-               return -EINVAL;
-
-       if (!clk->ops || !clk->ops->set_rate)
-               return -EINVAL;
-
-       return clk->ops->set_rate(clk, rate);
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
-       int ret;
-       unsigned long flags;
-
-       if (unlikely(IS_ERR_OR_NULL(clk)))
-               return -EINVAL;
-
-       if (!clk->ops || !clk->ops->set_parent)
-               return -EINVAL;
-
-       spin_lock_irqsave(&clocks_lock, flags);
-       ret = clk->ops->set_parent(clk, parent);
-       if (!ret) {
-               parent->usage += clk->usage;
-               clk->parent->usage -= clk->usage;
-               BUG_ON(clk->parent->usage < 0);
-               clk->parent = parent;
-       }
-       spin_unlock_irqrestore(&clocks_lock, flags);
-       return ret;
-}
-EXPORT_SYMBOL(clk_set_parent);
-
-struct clk *clk_get_parent(struct clk *clk)
-{
-       unsigned long flags;
-
-       if (unlikely(IS_ERR_OR_NULL(clk)))
-               return NULL;
-
-       if (!clk->ops || !clk->ops->get_parent)
-               return clk->parent;
-
-       spin_lock_irqsave(&clocks_lock, flags);
-       clk->parent = clk->ops->get_parent(clk);
-       spin_unlock_irqrestore(&clocks_lock, flags);
-       return clk->parent;
-}
-EXPORT_SYMBOL(clk_get_parent);
-
-static void __init sirfsoc_clk_init(void)
-{
-       clkdev_add_table(onchip_clks, ARRAY_SIZE(onchip_clks));
-}
-
-static struct of_device_id clkc_ids[] = {
-       { .compatible = "sirf,prima2-clkc" },
-       {},
-};
-
-void __init sirfsoc_of_clk_init(void)
-{
-       struct device_node *np;
-       struct resource res;
-       struct map_desc sirfsoc_clkc_iodesc = {
-               .virtual = SIRFSOC_CLOCK_VA_BASE,
-               .type    = MT_DEVICE,
-       };
-
-       np = of_find_matching_node(NULL, clkc_ids);
-       if (!np)
-               panic("unable to find compatible clkc node in dtb\n");
-
-       if (of_address_to_resource(np, 0, &res))
-               panic("unable to find clkc range in dtb");
-       of_node_put(np);
-
-       sirfsoc_clkc_iodesc.pfn = __phys_to_pfn(res.start);
-       sirfsoc_clkc_iodesc.length = 1 + res.end - res.start;
-
-       iotable_init(&sirfsoc_clkc_iodesc, 1);
-
-       sirfsoc_clk_init();
-}
index 8f0429d4b79f698d5c0e77117a75a3210f49c34b..e9a17aebe0d6ba734fb2543fbce14bfb5e72d065 100644 (file)
@@ -38,7 +38,6 @@ static const char *prima2cb_dt_match[] __initdata = {
 MACHINE_START(PRIMA2_EVB, "prima2cb")
        /* Maintainer: Barry Song <baohua.song@csr.com> */
        .atag_offset    = 0x100,
-       .init_early     = sirfsoc_of_clk_init,
        .map_io         = sirfsoc_map_lluart,
        .init_irq       = sirfsoc_of_irq_init,
        .timer          = &sirfsoc_timer,
index f224107de7bced279e6c007c54251183f72d8e77..d95bf252f6945698502b96b33570e85517b22e68 100644 (file)
@@ -21,6 +21,8 @@
 #include <asm/sched_clock.h>
 #include <asm/mach/time.h>
 
+#include "common.h"
+
 #define SIRFSOC_TIMER_COUNTER_LO       0x0000
 #define SIRFSOC_TIMER_COUNTER_HI       0x0004
 #define SIRFSOC_TIMER_MATCH_0          0x0008
@@ -188,9 +190,13 @@ static void __init sirfsoc_clockevent_init(void)
 static void __init sirfsoc_timer_init(void)
 {
        unsigned long rate;
+       struct clk *clk;
+
+       /* initialize clocking early, we want to set the OS timer */
+       sirfsoc_of_clk_init();
 
        /* timer's input clock is io clock */
-       struct clk *clk = clk_get_sys("io", NULL);
+       clk = clk_get_sys("io", NULL);
 
        BUG_ON(IS_ERR(clk));
 
index 45868bb43cbd2fbcbfcdfff638dc15f1cbd7d38b..ff007d15e0ec99b165e540e4d5eefee40ceb8f86 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/ata_platform.h>
 #include <linux/amba/mmci.h>
 #include <linux/gfp.h>
-#include <linux/clkdev.h>
 #include <linux/mtd/physmap.h>
 
 #include <mach/hardware.h>
@@ -226,115 +225,10 @@ struct mmci_platform_data realview_mmc1_plat_data = {
        .cd_invert      = true,
 };
 
-/*
- * Clock handling
- */
-static const struct icst_params realview_oscvco_params = {
-       .ref            = 24000000,
-       .vco_max        = ICST307_VCO_MAX,
-       .vco_min        = ICST307_VCO_MIN,
-       .vd_min         = 4 + 8,
-       .vd_max         = 511 + 8,
-       .rd_min         = 1 + 2,
-       .rd_max         = 127 + 2,
-       .s2div          = icst307_s2div,
-       .idx2s          = icst307_idx2s,
-};
-
-static void realview_oscvco_set(struct clk *clk, struct icst_vco vco)
-{
-       void __iomem *sys_lock = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LOCK_OFFSET;
-       u32 val;
-
-       val = readl(clk->vcoreg) & ~0x7ffff;
-       val |= vco.v | (vco.r << 9) | (vco.s << 16);
-
-       writel(0xa05f, sys_lock);
-       writel(val, clk->vcoreg);
-       writel(0, sys_lock);
-}
-
-static const struct clk_ops oscvco_clk_ops = {
-       .round  = icst_clk_round,
-       .set    = icst_clk_set,
-       .setvco = realview_oscvco_set,
-};
-
-static struct clk oscvco_clk = {
-       .ops    = &oscvco_clk_ops,
-       .params = &realview_oscvco_params,
-};
-
-/*
- * These are fixed clocks.
- */
-static struct clk ref24_clk = {
-       .rate   = 24000000,
-};
-
-static struct clk sp804_clk = {
-       .rate   = 1000000,
-};
-
-static struct clk dummy_apb_pclk;
-
-static struct clk_lookup lookups[] = {
-       {       /* Bus clock */
-               .con_id         = "apb_pclk",
-               .clk            = &dummy_apb_pclk,
-       }, {    /* UART0 */
-               .dev_id         = "dev:uart0",
-               .clk            = &ref24_clk,
-       }, {    /* UART1 */
-               .dev_id         = "dev:uart1",
-               .clk            = &ref24_clk,
-       }, {    /* UART2 */
-               .dev_id         = "dev:uart2",
-               .clk            = &ref24_clk,
-       }, {    /* UART3 */
-               .dev_id         = "fpga:uart3",
-               .clk            = &ref24_clk,
-       }, {    /* UART3 is on the dev chip in PB1176 */
-               .dev_id         = "dev:uart3",
-               .clk            = &ref24_clk,
-       }, {    /* UART4 only exists in PB1176 */
-               .dev_id         = "fpga:uart4",
-               .clk            = &ref24_clk,
-       }, {    /* KMI0 */
-               .dev_id         = "fpga:kmi0",
-               .clk            = &ref24_clk,
-       }, {    /* KMI1 */
-               .dev_id         = "fpga:kmi1",
-               .clk            = &ref24_clk,
-       }, {    /* MMC0 */
-               .dev_id         = "fpga:mmc0",
-               .clk            = &ref24_clk,
-       }, {    /* CLCD is in the PB1176 and EB DevChip */
-               .dev_id         = "dev:clcd",
-               .clk            = &oscvco_clk,
-       }, {    /* PB:CLCD */
-               .dev_id         = "issp:clcd",
-               .clk            = &oscvco_clk,
-       }, {    /* SSP */
-               .dev_id         = "dev:ssp0",
-               .clk            = &ref24_clk,
-       }, {    /* SP804 timers */
-               .dev_id         = "sp804",
-               .clk            = &sp804_clk,
-       },
-};
-
 void __init realview_init_early(void)
 {
        void __iomem *sys = __io_address(REALVIEW_SYS_BASE);
 
-       if (machine_is_realview_pb1176())
-               oscvco_clk.vcoreg = sys + REALVIEW_SYS_OSC0_OFFSET;
-       else
-               oscvco_clk.vcoreg = sys + REALVIEW_SYS_OSC4_OFFSET;
-
-       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
        versatile_sched_clock_init(sys + REALVIEW_SYS_24MHz_OFFSET, 24000000);
 }
 
diff --git a/arch/arm/mach-realview/include/mach/clkdev.h b/arch/arm/mach-realview/include/mach/clkdev.h
deleted file mode 100644 (file)
index e58d077..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef __ASM_MACH_CLKDEV_H
-#define __ASM_MACH_CLKDEV_H
-
-#include <plat/clock.h>
-
-struct clk {
-       unsigned long           rate;
-       const struct clk_ops    *ops;
-       const struct icst_params *params;
-       void __iomem            *vcoreg;
-};
-
-#define __clk_get(clk) ({ 1; })
-#define __clk_put(clk) do { } while (0)
-
-#endif
index baf382c5e77601957b2ef8982ccdd61552f9b2f2..a33e33b76733100ccf7872dd1f7d3929c39359ab 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/amba/mmci.h>
 #include <linux/amba/pl022.h>
 #include <linux/io.h>
+#include <linux/platform_data/clk-realview.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -414,6 +415,7 @@ static void __init realview_eb_timer_init(void)
        else
                timer_irq = IRQ_EB_TIMER0_1;
 
+       realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
        realview_timer_init(timer_irq);
        realview_eb_twd_init();
 }
index b1d7cafa1a6d2e295c2f95529b1d556df4b85db1..f0298cbc203e98fffda9f0908c87a8d95397d307 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
+#include <linux/platform_data/clk-realview.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -326,6 +327,7 @@ static void __init realview_pb1176_timer_init(void)
        timer2_va_base = __io_address(REALVIEW_PB1176_TIMER2_3_BASE);
        timer3_va_base = __io_address(REALVIEW_PB1176_TIMER2_3_BASE) + 0x20;
 
+       realview_clk_init(__io_address(REALVIEW_SYS_BASE), true);
        realview_timer_init(IRQ_DC1176_TIMER0);
 }
 
index a98c536e3327afa9823a2b29ffd081258be2ae5a..1f019f76f7b5e8c4ad2f4622cdda8f46b1dfe546 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/amba/mmci.h>
 #include <linux/amba/pl022.h>
 #include <linux/io.h>
+#include <linux/platform_data/clk-realview.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -312,6 +313,7 @@ static void __init realview_pb11mp_timer_init(void)
        timer2_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE);
        timer3_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE) + 0x20;
 
+       realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
        realview_timer_init(IRQ_TC11MP_TIMER0_1);
        realview_pb11mp_twd_init();
 }
index 59650174e6ed39e9c3bc9e44441beb48b22a4214..5032775dbfeefb51bb07bfce6d1e34fc9819127c 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/amba/mmci.h>
 #include <linux/amba/pl022.h>
 #include <linux/io.h>
+#include <linux/platform_data/clk-realview.h>
 
 #include <asm/irq.h>
 #include <asm/leds.h>
@@ -261,6 +262,7 @@ static void __init realview_pba8_timer_init(void)
        timer2_va_base = __io_address(REALVIEW_PBA8_TIMER2_3_BASE);
        timer3_va_base = __io_address(REALVIEW_PBA8_TIMER2_3_BASE) + 0x20;
 
+       realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
        realview_timer_init(IRQ_PBA8_TIMER0_1);
 }
 
index 3f2f605624e95270fd1039e64a3a0a2d2180cd06..de64ba0ddb956822a27e0b4b7c77f2d04e45e699 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/amba/mmci.h>
 #include <linux/amba/pl022.h>
 #include <linux/io.h>
+#include <linux/platform_data/clk-realview.h>
 
 #include <asm/irq.h>
 #include <asm/leds.h>
@@ -320,6 +321,7 @@ static void __init realview_pbx_timer_init(void)
        timer2_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE);
        timer3_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE) + 0x20;
 
+       realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
        realview_timer_init(IRQ_PBX_TIMER0_1);
        realview_pbx_twd_init();
 }
index c013bbf79cac0d0eff64edfd5221d7815bb04879..2d76e4f9c97e91e1f597c31af364188f12decd7d 100644 (file)
@@ -11,6 +11,7 @@ config UX500_SOC_COMMON
        select CACHE_L2X0
        select PINCTRL
        select PINCTRL_NOMADIK
+       select COMMON_CLK
 
 config UX500_SOC_DB8500
        bool
index 026086ff9e6c1e02f83de04c174742ad41b2f374..5691ef679d014cf412b2611817b29ad7881fbc3e 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux kernel, U8500 machine.
 #
 
-obj-y                          := clock.o cpu.o devices.o devices-common.o \
+obj-y                          := cpu.o devices.o devices-common.o \
                                   id.o usb.o timer.o
 obj-$(CONFIG_CPU_IDLE)          += cpuidle.o
 obj-$(CONFIG_CACHE_L2X0)       += cache-l2x0.o
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
deleted file mode 100644 (file)
index 8d73b06..0000000
+++ /dev/null
@@ -1,715 +0,0 @@
-/*
- *  Copyright (C) 2009 ST-Ericsson
- *  Copyright (C) 2009 STMicroelectronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/clkdev.h>
-#include <linux/cpufreq.h>
-
-#include <plat/mtu.h>
-#include <mach/hardware.h>
-#include "clock.h"
-
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>     /* for copy_from_user */
-static LIST_HEAD(clk_list);
-#endif
-
-#define PRCC_PCKEN             0x00
-#define PRCC_PCKDIS            0x04
-#define PRCC_KCKEN             0x08
-#define PRCC_KCKDIS            0x0C
-
-#define PRCM_YYCLKEN0_MGT_SET  0x510
-#define PRCM_YYCLKEN1_MGT_SET  0x514
-#define PRCM_YYCLKEN0_MGT_CLR  0x518
-#define PRCM_YYCLKEN1_MGT_CLR  0x51C
-#define PRCM_YYCLKEN0_MGT_VAL  0x520
-#define PRCM_YYCLKEN1_MGT_VAL  0x524
-
-#define PRCM_SVAMMDSPCLK_MGT   0x008
-#define PRCM_SIAMMDSPCLK_MGT   0x00C
-#define PRCM_SGACLK_MGT                0x014
-#define PRCM_UARTCLK_MGT       0x018
-#define PRCM_MSP02CLK_MGT      0x01C
-#define PRCM_MSP1CLK_MGT       0x288
-#define PRCM_I2CCLK_MGT                0x020
-#define PRCM_SDMMCCLK_MGT      0x024
-#define PRCM_SLIMCLK_MGT       0x028
-#define PRCM_PER1CLK_MGT       0x02C
-#define PRCM_PER2CLK_MGT       0x030
-#define PRCM_PER3CLK_MGT       0x034
-#define PRCM_PER5CLK_MGT       0x038
-#define PRCM_PER6CLK_MGT       0x03C
-#define PRCM_PER7CLK_MGT       0x040
-#define PRCM_LCDCLK_MGT                0x044
-#define PRCM_BMLCLK_MGT                0x04C
-#define PRCM_HSITXCLK_MGT      0x050
-#define PRCM_HSIRXCLK_MGT      0x054
-#define PRCM_HDMICLK_MGT       0x058
-#define PRCM_APEATCLK_MGT      0x05C
-#define PRCM_APETRACECLK_MGT   0x060
-#define PRCM_MCDECLK_MGT       0x064
-#define PRCM_IPI2CCLK_MGT      0x068
-#define PRCM_DSIALTCLK_MGT     0x06C
-#define PRCM_DMACLK_MGT                0x074
-#define PRCM_B2R2CLK_MGT       0x078
-#define PRCM_TVCLK_MGT         0x07C
-#define PRCM_TCR               0x1C8
-#define PRCM_TCR_STOPPED       (1 << 16)
-#define PRCM_TCR_DOZE_MODE     (1 << 17)
-#define PRCM_UNIPROCLK_MGT     0x278
-#define PRCM_SSPCLK_MGT                0x280
-#define PRCM_RNGCLK_MGT                0x284
-#define PRCM_UICCCLK_MGT       0x27C
-
-#define PRCM_MGT_ENABLE                (1 << 8)
-
-static DEFINE_SPINLOCK(clocks_lock);
-
-static void __clk_enable(struct clk *clk)
-{
-       if (clk->enabled++ == 0) {
-               if (clk->parent_cluster)
-                       __clk_enable(clk->parent_cluster);
-
-               if (clk->parent_periph)
-                       __clk_enable(clk->parent_periph);
-
-               if (clk->ops && clk->ops->enable)
-                       clk->ops->enable(clk);
-       }
-}
-
-int clk_enable(struct clk *clk)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&clocks_lock, flags);
-       __clk_enable(clk);
-       spin_unlock_irqrestore(&clocks_lock, flags);
-
-       return 0;
-}
-EXPORT_SYMBOL(clk_enable);
-
-static void __clk_disable(struct clk *clk)
-{
-       if (--clk->enabled == 0) {
-               if (clk->ops && clk->ops->disable)
-                       clk->ops->disable(clk);
-
-               if (clk->parent_periph)
-                       __clk_disable(clk->parent_periph);
-
-               if (clk->parent_cluster)
-                       __clk_disable(clk->parent_cluster);
-       }
-}
-
-void clk_disable(struct clk *clk)
-{
-       unsigned long flags;
-
-       WARN_ON(!clk->enabled);
-
-       spin_lock_irqsave(&clocks_lock, flags);
-       __clk_disable(clk);
-       spin_unlock_irqrestore(&clocks_lock, flags);
-}
-EXPORT_SYMBOL(clk_disable);
-
-/*
- * The MTU has a separate, rather complex muxing setup
- * with alternative parents (peripheral cluster or
- * ULP or fixed 32768 Hz) depending on settings
- */
-static unsigned long clk_mtu_get_rate(struct clk *clk)
-{
-       void __iomem *addr;
-       u32 tcr;
-       int mtu = (int) clk->data;
-       /*
-        * One of these is selected eventually
-        * TODO: Replace the constant with a reference
-        * to the ULP source once this is modeled.
-        */
-       unsigned long clk32k = 32768;
-       unsigned long mturate;
-       unsigned long retclk;
-
-       if (cpu_is_u8500_family())
-               addr = __io_address(U8500_PRCMU_BASE);
-       else
-               ux500_unknown_soc();
-
-       /*
-        * On a startup, always conifgure the TCR to the doze mode;
-        * bootloaders do it for us. Do this in the kernel too.
-        */
-       writel(PRCM_TCR_DOZE_MODE, addr + PRCM_TCR);
-
-       tcr = readl(addr + PRCM_TCR);
-
-       /* Get the rate from the parent as a default */
-       if (clk->parent_periph)
-               mturate = clk_get_rate(clk->parent_periph);
-       else if (clk->parent_cluster)
-               mturate = clk_get_rate(clk->parent_cluster);
-       else
-               /* We need to be connected SOMEWHERE */
-               BUG();
-
-       /* Return the clock selected for this MTU */
-       if (tcr & (1 << mtu))
-               retclk = clk32k;
-       else
-               retclk = mturate;
-
-       pr_info("MTU%d clock rate: %lu Hz\n", mtu, retclk);
-       return retclk;
-}
-
-unsigned long clk_get_rate(struct clk *clk)
-{
-       unsigned long rate;
-
-       /*
-        * If there is a custom getrate callback for this clock,
-        * it will take precedence.
-        */
-       if (clk->get_rate)
-               return clk->get_rate(clk);
-
-       if (clk->ops && clk->ops->get_rate)
-               return clk->ops->get_rate(clk);
-
-       rate = clk->rate;
-       if (!rate) {
-               if (clk->parent_periph)
-                       rate = clk_get_rate(clk->parent_periph);
-               else if (clk->parent_cluster)
-                       rate = clk_get_rate(clk->parent_cluster);
-       }
-
-       return rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
-       /*TODO*/
-       return rate;
-}
-EXPORT_SYMBOL(clk_round_rate);
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
-       clk->rate = rate;
-       return 0;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
-       /*TODO*/
-       return -ENOSYS;
-}
-EXPORT_SYMBOL(clk_set_parent);
-
-static void clk_prcmu_enable(struct clk *clk)
-{
-       void __iomem *cg_set_reg = __io_address(U8500_PRCMU_BASE)
-                                  + PRCM_YYCLKEN0_MGT_SET + clk->prcmu_cg_off;
-
-       writel(1 << clk->prcmu_cg_bit, cg_set_reg);
-}
-
-static void clk_prcmu_disable(struct clk *clk)
-{
-       void __iomem *cg_clr_reg = __io_address(U8500_PRCMU_BASE)
-                                  + PRCM_YYCLKEN0_MGT_CLR + clk->prcmu_cg_off;
-
-       writel(1 << clk->prcmu_cg_bit, cg_clr_reg);
-}
-
-static struct clkops clk_prcmu_ops = {
-       .enable = clk_prcmu_enable,
-       .disable = clk_prcmu_disable,
-};
-
-static unsigned int clkrst_base[] = {
-       [1] = U8500_CLKRST1_BASE,
-       [2] = U8500_CLKRST2_BASE,
-       [3] = U8500_CLKRST3_BASE,
-       [5] = U8500_CLKRST5_BASE,
-       [6] = U8500_CLKRST6_BASE,
-};
-
-static void clk_prcc_enable(struct clk *clk)
-{
-       void __iomem *addr = __io_address(clkrst_base[clk->cluster]);
-
-       if (clk->prcc_kernel != -1)
-               writel(1 << clk->prcc_kernel, addr + PRCC_KCKEN);
-
-       if (clk->prcc_bus != -1)
-               writel(1 << clk->prcc_bus, addr + PRCC_PCKEN);
-}
-
-static void clk_prcc_disable(struct clk *clk)
-{
-       void __iomem *addr = __io_address(clkrst_base[clk->cluster]);
-
-       if (clk->prcc_bus != -1)
-               writel(1 << clk->prcc_bus, addr + PRCC_PCKDIS);
-
-       if (clk->prcc_kernel != -1)
-               writel(1 << clk->prcc_kernel, addr + PRCC_KCKDIS);
-}
-
-static struct clkops clk_prcc_ops = {
-       .enable = clk_prcc_enable,
-       .disable = clk_prcc_disable,
-};
-
-static struct clk clk_32khz = {
-       .name =  "clk_32khz",
-       .rate = 32000,
-};
-
-/*
- * PRCMU level clock gating
- */
-
-/* Bank 0 */
-static DEFINE_PRCMU_CLK(svaclk,                0x0, 2, SVAMMDSPCLK);
-static DEFINE_PRCMU_CLK(siaclk,                0x0, 3, SIAMMDSPCLK);
-static DEFINE_PRCMU_CLK(sgaclk,                0x0, 4, SGACLK);
-static DEFINE_PRCMU_CLK_RATE(uartclk,  0x0, 5, UARTCLK, 38400000);
-static DEFINE_PRCMU_CLK(msp02clk,      0x0, 6, MSP02CLK);
-static DEFINE_PRCMU_CLK(msp1clk,       0x0, 7, MSP1CLK); /* v1 */
-static DEFINE_PRCMU_CLK_RATE(i2cclk,   0x0, 8, I2CCLK, 48000000);
-static DEFINE_PRCMU_CLK_RATE(sdmmcclk, 0x0, 9, SDMMCCLK, 100000000);
-static DEFINE_PRCMU_CLK(slimclk,       0x0, 10, SLIMCLK);
-static DEFINE_PRCMU_CLK(per1clk,       0x0, 11, PER1CLK);
-static DEFINE_PRCMU_CLK(per2clk,       0x0, 12, PER2CLK);
-static DEFINE_PRCMU_CLK(per3clk,       0x0, 13, PER3CLK);
-static DEFINE_PRCMU_CLK(per5clk,       0x0, 14, PER5CLK);
-static DEFINE_PRCMU_CLK_RATE(per6clk,  0x0, 15, PER6CLK, 133330000);
-static DEFINE_PRCMU_CLK(lcdclk,                0x0, 17, LCDCLK);
-static DEFINE_PRCMU_CLK(bmlclk,                0x0, 18, BMLCLK);
-static DEFINE_PRCMU_CLK(hsitxclk,      0x0, 19, HSITXCLK);
-static DEFINE_PRCMU_CLK(hsirxclk,      0x0, 20, HSIRXCLK);
-static DEFINE_PRCMU_CLK(hdmiclk,       0x0, 21, HDMICLK);
-static DEFINE_PRCMU_CLK(apeatclk,      0x0, 22, APEATCLK);
-static DEFINE_PRCMU_CLK(apetraceclk,   0x0, 23, APETRACECLK);
-static DEFINE_PRCMU_CLK(mcdeclk,       0x0, 24, MCDECLK);
-static DEFINE_PRCMU_CLK(ipi2clk,       0x0, 25, IPI2CCLK);
-static DEFINE_PRCMU_CLK(dsialtclk,     0x0, 26, DSIALTCLK); /* v1 */
-static DEFINE_PRCMU_CLK(dmaclk,                0x0, 27, DMACLK);
-static DEFINE_PRCMU_CLK(b2r2clk,       0x0, 28, B2R2CLK);
-static DEFINE_PRCMU_CLK(tvclk,         0x0, 29, TVCLK);
-static DEFINE_PRCMU_CLK(uniproclk,     0x0, 30, UNIPROCLK); /* v1 */
-static DEFINE_PRCMU_CLK_RATE(sspclk,   0x0, 31, SSPCLK, 48000000); /* v1 */
-
-/* Bank 1 */
-static DEFINE_PRCMU_CLK(rngclk,                0x4, 0, RNGCLK); /* v1 */
-static DEFINE_PRCMU_CLK(uiccclk,       0x4, 1, UICCCLK); /* v1 */
-
-/*
- * PRCC level clock gating
- * Format: per#, clk, PCKEN bit, KCKEN bit, parent
- */
-
-/* Peripheral Cluster #1 */
-static DEFINE_PRCC_CLK(1, msp3,                11, 10, &clk_msp1clk);
-static DEFINE_PRCC_CLK(1, i2c4,                10, 9, &clk_i2cclk);
-static DEFINE_PRCC_CLK(1, gpio0,       9, -1, NULL);
-static DEFINE_PRCC_CLK(1, slimbus0,    8,  8, &clk_slimclk);
-static DEFINE_PRCC_CLK(1, spi3,                7, -1, NULL);
-static DEFINE_PRCC_CLK(1, i2c2,                6,  6, &clk_i2cclk);
-static DEFINE_PRCC_CLK(1, sdi0,                5,  5, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(1, msp1,                4,  4, &clk_msp1clk);
-static DEFINE_PRCC_CLK(1, msp0,                3,  3, &clk_msp02clk);
-static DEFINE_PRCC_CLK(1, i2c1,                2,  2, &clk_i2cclk);
-static DEFINE_PRCC_CLK(1, uart1,       1,  1, &clk_uartclk);
-static DEFINE_PRCC_CLK(1, uart0,       0,  0, &clk_uartclk);
-
-/* Peripheral Cluster #2 */
-static DEFINE_PRCC_CLK(2, gpio1,       11, -1, NULL);
-static DEFINE_PRCC_CLK(2, ssitx,       10,  7, NULL);
-static DEFINE_PRCC_CLK(2, ssirx,        9,  6, NULL);
-static DEFINE_PRCC_CLK(2, spi0,                8, -1, NULL);
-static DEFINE_PRCC_CLK(2, sdi3,                7,  5, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(2, sdi1,                6,  4, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(2, msp2,                5,  3, &clk_msp02clk);
-static DEFINE_PRCC_CLK(2, sdi4,                4,  2, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(2, pwl,         3,  1, NULL);
-static DEFINE_PRCC_CLK(2, spi1,                2, -1, NULL);
-static DEFINE_PRCC_CLK(2, spi2,                1, -1, NULL);
-static DEFINE_PRCC_CLK(2, i2c3,                0,  0, &clk_i2cclk);
-
-/* Peripheral Cluster #3 */
-static DEFINE_PRCC_CLK(3, gpio2,       8, -1, NULL);
-static DEFINE_PRCC_CLK(3, sdi5,                7,  7, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(3, uart2,       6,  6, &clk_uartclk);
-static DEFINE_PRCC_CLK(3, ske,         5,  5, &clk_32khz);
-static DEFINE_PRCC_CLK(3, sdi2,                4,  4, &clk_sdmmcclk);
-static DEFINE_PRCC_CLK(3, i2c0,                3,  3, &clk_i2cclk);
-static DEFINE_PRCC_CLK(3, ssp1,                2,  2, &clk_sspclk);
-static DEFINE_PRCC_CLK(3, ssp0,                1,  1, &clk_sspclk);
-static DEFINE_PRCC_CLK(3, fsmc,                0, -1, NULL);
-
-/* Peripheral Cluster #4 is in the always on domain */
-
-/* Peripheral Cluster #5 */
-static DEFINE_PRCC_CLK(5, gpio3,       1, -1, NULL);
-static DEFINE_PRCC_CLK(5, usb,         0,  0, NULL);
-
-/* Peripheral Cluster #6 */
-
-/* MTU ID in data */
-static DEFINE_PRCC_CLK_CUSTOM(6, mtu1, 9, -1, NULL, clk_mtu_get_rate, 1);
-static DEFINE_PRCC_CLK_CUSTOM(6, mtu0, 8, -1, NULL, clk_mtu_get_rate, 0);
-static DEFINE_PRCC_CLK(6, cfgreg,      7,  7, NULL);
-static DEFINE_PRCC_CLK(6, hash1,       6, -1, NULL);
-static DEFINE_PRCC_CLK(6, unipro,      5,  1, &clk_uniproclk);
-static DEFINE_PRCC_CLK(6, pka,         4, -1, NULL);
-static DEFINE_PRCC_CLK(6, hash0,       3, -1, NULL);
-static DEFINE_PRCC_CLK(6, cryp0,       2, -1, NULL);
-static DEFINE_PRCC_CLK(6, cryp1,    1, -1, NULL);
-static DEFINE_PRCC_CLK(6, rng, 0,  0, &clk_rngclk);
-
-static struct clk clk_dummy_apb_pclk = {
-       .name = "apb_pclk",
-};
-
-static struct clk_lookup u8500_clks[] = {
-       CLK(dummy_apb_pclk, NULL,       "apb_pclk"),
-
-       /* Peripheral Cluster #1 */
-       CLK(gpio0,      "gpio.0",       NULL),
-       CLK(gpio0,      "gpio.1",       NULL),
-       CLK(slimbus0,   "slimbus0",     NULL),
-       CLK(i2c2,       "nmk-i2c.2",    NULL),
-       CLK(sdi0,       "sdi0",         NULL),
-       CLK(msp0,       "ux500-msp-i2s.0",      NULL),
-       CLK(i2c1,       "nmk-i2c.1",    NULL),
-       CLK(uart1,      "uart1",        NULL),
-       CLK(uart0,      "uart0",        NULL),
-
-       /* Peripheral Cluster #3 */
-       CLK(gpio2,      "gpio.2",       NULL),
-       CLK(gpio2,      "gpio.3",       NULL),
-       CLK(gpio2,      "gpio.4",       NULL),
-       CLK(gpio2,      "gpio.5",       NULL),
-       CLK(sdi5,       "sdi5",         NULL),
-       CLK(uart2,      "uart2",        NULL),
-       CLK(ske,        "ske",          NULL),
-       CLK(ske,        "nmk-ske-keypad",       NULL),
-       CLK(sdi2,       "sdi2",         NULL),
-       CLK(i2c0,       "nmk-i2c.0",    NULL),
-       CLK(fsmc,       "fsmc",         NULL),
-
-       /* Peripheral Cluster #5 */
-       CLK(gpio3,      "gpio.8",       NULL),
-
-       /* Peripheral Cluster #6 */
-       CLK(hash1,      "hash1",        NULL),
-       CLK(pka,        "pka",          NULL),
-       CLK(hash0,      "hash0",        NULL),
-       CLK(cryp0,      "cryp0",        NULL),
-       CLK(cryp1,  "cryp1",    NULL),
-
-       /* PRCMU level clock gating */
-
-       /* Bank 0 */
-       CLK(svaclk,     "sva",          NULL),
-       CLK(siaclk,     "sia",          NULL),
-       CLK(sgaclk,     "sga",          NULL),
-       CLK(slimclk,    "slim",         NULL),
-       CLK(lcdclk,     "lcd",          NULL),
-       CLK(bmlclk,     "bml",          NULL),
-       CLK(hsitxclk,   "stm-hsi.0",    NULL),
-       CLK(hsirxclk,   "stm-hsi.1",    NULL),
-       CLK(hdmiclk,    "hdmi",         NULL),
-       CLK(apeatclk,   "apeat",        NULL),
-       CLK(apetraceclk,        "apetrace",     NULL),
-       CLK(mcdeclk,    "mcde",         NULL),
-       CLK(ipi2clk,    "ipi2",         NULL),
-       CLK(dmaclk,     "dma40.0",      NULL),
-       CLK(b2r2clk,    "b2r2",         NULL),
-       CLK(tvclk,      "tv",           NULL),
-
-       /* Peripheral Cluster #1 */
-       CLK(i2c4,       "nmk-i2c.4",    NULL),
-       CLK(spi3,       "spi3",         NULL),
-       CLK(msp1,       "ux500-msp-i2s.1",      NULL),
-       CLK(msp3,       "ux500-msp-i2s.3",      NULL),
-
-       /* Peripheral Cluster #2 */
-       CLK(gpio1,      "gpio.6",       NULL),
-       CLK(gpio1,      "gpio.7",       NULL),
-       CLK(ssitx,      "ssitx",        NULL),
-       CLK(ssirx,      "ssirx",        NULL),
-       CLK(spi0,       "spi0",         NULL),
-       CLK(sdi3,       "sdi3",         NULL),
-       CLK(sdi1,       "sdi1",         NULL),
-       CLK(msp2,       "ux500-msp-i2s.2",      NULL),
-       CLK(sdi4,       "sdi4",         NULL),
-       CLK(pwl,        "pwl",          NULL),
-       CLK(spi1,       "spi1",         NULL),
-       CLK(spi2,       "spi2",         NULL),
-       CLK(i2c3,       "nmk-i2c.3",    NULL),
-
-       /* Peripheral Cluster #3 */
-       CLK(ssp1,       "ssp1",         NULL),
-       CLK(ssp0,       "ssp0",         NULL),
-
-       /* Peripheral Cluster #5 */
-       CLK(usb,        "musb-ux500.0", "usb"),
-
-       /* Peripheral Cluster #6 */
-       CLK(mtu1,       "mtu1",         NULL),
-       CLK(mtu0,       "mtu0",         NULL),
-       CLK(cfgreg,     "cfgreg",       NULL),
-       CLK(hash1,      "hash1",        NULL),
-       CLK(unipro,     "unipro",       NULL),
-       CLK(rng,        "rng",          NULL),
-
-       /* PRCMU level clock gating */
-
-       /* Bank 0 */
-       CLK(uniproclk,  "uniproclk",    NULL),
-       CLK(dsialtclk,  "dsialt",       NULL),
-
-       /* Bank 1 */
-       CLK(rngclk,     "rng",          NULL),
-       CLK(uiccclk,    "uicc",         NULL),
-};
-
-#ifdef CONFIG_DEBUG_FS
-/*
- *     debugfs support to trace clock tree hierarchy and attributes with
- *     powerdebug
- */
-static struct dentry *clk_debugfs_root;
-
-void __init clk_debugfs_add_table(struct clk_lookup *cl, size_t num)
-{
-       while (num--) {
-               /* Check that the clock has not been already registered */
-               if (!(cl->clk->list.prev != cl->clk->list.next))
-                       list_add_tail(&cl->clk->list, &clk_list);
-
-               cl++;
-       }
-}
-
-static ssize_t usecount_dbg_read(struct file *file, char __user *buf,
-                                                 size_t size, loff_t *off)
-{
-       struct clk *clk = file->f_dentry->d_inode->i_private;
-       char cusecount[128];
-       unsigned int len;
-
-       len = sprintf(cusecount, "%u\n", clk->enabled);
-       return simple_read_from_buffer(buf, size, off, cusecount, len);
-}
-
-static ssize_t rate_dbg_read(struct file *file, char __user *buf,
-                                         size_t size, loff_t *off)
-{
-       struct clk *clk = file->f_dentry->d_inode->i_private;
-       char crate[128];
-       unsigned int rate;
-       unsigned int len;
-
-       rate = clk_get_rate(clk);
-       len = sprintf(crate, "%u\n", rate);
-       return simple_read_from_buffer(buf, size, off, crate, len);
-}
-
-static const struct file_operations usecount_fops = {
-       .read = usecount_dbg_read,
-};
-
-static const struct file_operations set_rate_fops = {
-       .read = rate_dbg_read,
-};
-
-static struct dentry *clk_debugfs_register_dir(struct clk *c,
-                                               struct dentry *p_dentry)
-{
-       struct dentry *d, *clk_d;
-       const char *p = c->name;
-
-       if (!p)
-               p = "BUG";
-
-       clk_d = debugfs_create_dir(p, p_dentry);
-       if (!clk_d)
-               return NULL;
-
-       d = debugfs_create_file("usecount", S_IRUGO,
-                               clk_d, c, &usecount_fops);
-       if (!d)
-               goto err_out;
-       d = debugfs_create_file("rate", S_IRUGO,
-                               clk_d, c, &set_rate_fops);
-       if (!d)
-               goto err_out;
-       /*
-        * TODO : not currently available in ux500
-        * d = debugfs_create_x32("flags", S_IRUGO, clk_d, (u32 *)&c->flags);
-        * if (!d)
-        *      goto err_out;
-        */
-
-       return clk_d;
-
-err_out:
-       debugfs_remove_recursive(clk_d);
-       return NULL;
-}
-
-static int clk_debugfs_register_one(struct clk *c)
-{
-       struct clk *pa = c->parent_periph;
-       struct clk *bpa = c->parent_cluster;
-
-       if (!(bpa && !pa)) {
-               c->dent = clk_debugfs_register_dir(c,
-                               pa ? pa->dent : clk_debugfs_root);
-               if (!c->dent)
-                       return -ENOMEM;
-       }
-
-       if (bpa) {
-               c->dent_bus = clk_debugfs_register_dir(c,
-                               bpa->dent_bus ? bpa->dent_bus : bpa->dent);
-               if ((!c->dent_bus) &&  (c->dent)) {
-                       debugfs_remove_recursive(c->dent);
-                       c->dent = NULL;
-                       return -ENOMEM;
-               }
-       }
-       return 0;
-}
-
-static int clk_debugfs_register(struct clk *c)
-{
-       int err;
-       struct clk *pa = c->parent_periph;
-       struct clk *bpa = c->parent_cluster;
-
-       if (pa && (!pa->dent && !pa->dent_bus)) {
-               err = clk_debugfs_register(pa);
-               if (err)
-                       return err;
-       }
-
-       if (bpa && (!bpa->dent && !bpa->dent_bus)) {
-               err = clk_debugfs_register(bpa);
-               if (err)
-                       return err;
-       }
-
-       if ((!c->dent) && (!c->dent_bus)) {
-               err = clk_debugfs_register_one(c);
-               if (err)
-                       return err;
-       }
-       return 0;
-}
-
-int __init clk_debugfs_init(void)
-{
-       struct clk *c;
-       struct dentry *d;
-       int err;
-
-       d = debugfs_create_dir("clock", NULL);
-       if (!d)
-               return -ENOMEM;
-       clk_debugfs_root = d;
-
-       list_for_each_entry(c, &clk_list, list) {
-               err = clk_debugfs_register(c);
-               if (err)
-                       goto err_out;
-       }
-       return 0;
-err_out:
-       debugfs_remove_recursive(clk_debugfs_root);
-       return err;
-}
-
-#endif /* defined(CONFIG_DEBUG_FS) */
-
-unsigned long clk_smp_twd_rate = 500000000;
-
-unsigned long clk_smp_twd_get_rate(struct clk *clk)
-{
-       return clk_smp_twd_rate;
-}
-
-static struct clk clk_smp_twd = {
-       .get_rate = clk_smp_twd_get_rate,
-       .name =  "smp_twd",
-};
-
-static struct clk_lookup clk_smp_twd_lookup = {
-       .dev_id = "smp_twd",
-       .clk = &clk_smp_twd,
-};
-
-#ifdef CONFIG_CPU_FREQ
-
-static int clk_twd_cpufreq_transition(struct notifier_block *nb,
-                                     unsigned long state, void *data)
-{
-       struct cpufreq_freqs *f = data;
-
-       if (state == CPUFREQ_PRECHANGE) {
-               /* Save frequency in simple Hz */
-               clk_smp_twd_rate = (f->new * 1000) / 2;
-       }
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block clk_twd_cpufreq_nb = {
-       .notifier_call = clk_twd_cpufreq_transition,
-};
-
-int clk_init_smp_twd_cpufreq(void)
-{
-       return cpufreq_register_notifier(&clk_twd_cpufreq_nb,
-                                 CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-#endif
-
-int __init clk_init(void)
-{
-       clkdev_add_table(u8500_clks, ARRAY_SIZE(u8500_clks));
-       clkdev_add(&clk_smp_twd_lookup);
-
-#ifdef CONFIG_DEBUG_FS
-       clk_debugfs_add_table(u8500_clks, ARRAY_SIZE(u8500_clks));
-#endif
-       return 0;
-}
diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h
deleted file mode 100644 (file)
index 65d27a1..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- *  Copyright (C) 2010 ST-Ericsson
- *  Copyright (C) 2009 STMicroelectronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/**
- * struct clkops - ux500 clock operations
- * @enable:    function to enable the clock
- * @disable:   function to disable the clock
- * @get_rate:  function to get the current clock rate
- *
- * This structure contains function pointers to functions that will be used to
- * control the clock.  All of these functions are optional.  If get_rate is
- * NULL, the rate in the struct clk will be used.
- */
-struct clkops {
-       void (*enable) (struct clk *);
-       void (*disable) (struct clk *);
-       unsigned long (*get_rate) (struct clk *);
-       int (*set_parent)(struct clk *, struct clk *);
-};
-
-/**
- * struct clk - ux500 clock structure
- * @ops:               pointer to clkops struct used to control this clock
- * @name:              name, for debugging
- * @enabled:           refcount. positive if enabled, zero if disabled
- * @get_rate:          custom callback for getting the clock rate
- * @data:              custom per-clock data for example for the get_rate
- *                     callback
- * @rate:              fixed rate for clocks which don't implement
- *                     ops->getrate
- * @prcmu_cg_off:      address offset of the combined enable/disable register
- *                     (used on u8500v1)
- * @prcmu_cg_bit:      bit in the combined enable/disable register (used on
- *                     u8500v1)
- * @prcmu_cg_mgt:      address of the enable/disable register (used on
- *                     u8500ed)
- * @cluster:           peripheral cluster number
- * @prcc_bus:          bit for the bus clock in the peripheral's CLKRST
- * @prcc_kernel:       bit for the kernel clock in the peripheral's CLKRST.
- *                     -1 if no kernel clock exists.
- * @parent_cluster:    pointer to parent's cluster clk struct
- * @parent_periph:     pointer to parent's peripheral clk struct
- *
- * Peripherals are organised into clusters, and each cluster has an associated
- * bus clock.  Some peripherals also have a parent peripheral clock.
- *
- * In order to enable a clock for a peripheral, we need to enable:
- *     (1) the parent cluster (bus) clock at the PRCMU level
- *     (2) the parent peripheral clock (if any) at the PRCMU level
- *     (3) the peripheral's bus & kernel clock at the PRCC level
- *
- * (1) and (2) are handled by defining clk structs (DEFINE_PRCMU_CLK) for each
- * of the cluster and peripheral clocks, and hooking these as the parents of
- * the individual peripheral clocks.
- *
- * (3) is handled by specifying the bits in the PRCC control registers required
- * to enable these clocks and modifying them in the ->enable and
- * ->disable callbacks of the peripheral clocks (DEFINE_PRCC_CLK).
- *
- * This structure describes both the PRCMU-level clocks and PRCC-level clocks.
- * The prcmu_* fields are only used for the PRCMU clocks, and the cluster,
- * prcc, and parent pointers are only used for the PRCC-level clocks.
- */
-struct clk {
-       const struct clkops     *ops;
-       const char              *name;
-       unsigned int            enabled;
-       unsigned long           (*get_rate)(struct clk *);
-       void                    *data;
-
-       unsigned long           rate;
-       struct list_head        list;
-
-       /* These three are only for PRCMU clks */
-
-       unsigned int            prcmu_cg_off;
-       unsigned int            prcmu_cg_bit;
-       unsigned int            prcmu_cg_mgt;
-
-       /* The rest are only for PRCC clks */
-
-       int                     cluster;
-       unsigned int            prcc_bus;
-       unsigned int            prcc_kernel;
-
-       struct clk              *parent_cluster;
-       struct clk              *parent_periph;
-#if defined(CONFIG_DEBUG_FS)
-       struct dentry           *dent;          /* For visible tree hierarchy */
-       struct dentry           *dent_bus;      /* For visible tree hierarchy */
-#endif
-};
-
-#define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg)                \
-struct clk clk_##_name = {                                     \
-               .name           = #_name,                       \
-               .ops            = &clk_prcmu_ops,               \
-               .prcmu_cg_off   = _cg_off,                      \
-               .prcmu_cg_bit   = _cg_bit,                      \
-               .prcmu_cg_mgt   = PRCM_##_reg##_MGT             \
-       }
-
-#define DEFINE_PRCMU_CLK_RATE(_name, _cg_off, _cg_bit, _reg, _rate)    \
-struct clk clk_##_name = {                                             \
-               .name           = #_name,                               \
-               .ops            = &clk_prcmu_ops,                       \
-               .prcmu_cg_off   = _cg_off,                              \
-               .prcmu_cg_bit   = _cg_bit,                              \
-               .rate           = _rate,                                \
-               .prcmu_cg_mgt   = PRCM_##_reg##_MGT                     \
-       }
-
-#define DEFINE_PRCC_CLK(_pclust, _name, _bus_en, _kernel_en, _kernclk) \
-struct clk clk_##_name = {                                             \
-               .name           = #_name,                               \
-               .ops            = &clk_prcc_ops,                        \
-               .cluster        = _pclust,                              \
-               .prcc_bus       = _bus_en,                              \
-               .prcc_kernel    = _kernel_en,                           \
-               .parent_cluster = &clk_per##_pclust##clk,               \
-               .parent_periph  = _kernclk                              \
-       }
-
-#define DEFINE_PRCC_CLK_CUSTOM(_pclust, _name, _bus_en, _kernel_en, _kernclk, _callback, _data) \
-struct clk clk_##_name = {                                             \
-               .name           = #_name,                               \
-               .ops            = &clk_prcc_ops,                        \
-               .cluster        = _pclust,                              \
-               .prcc_bus       = _bus_en,                              \
-               .prcc_kernel    = _kernel_en,                           \
-               .parent_cluster = &clk_per##_pclust##clk,               \
-               .parent_periph  = _kernclk,                             \
-               .get_rate       = _callback,                            \
-               .data           = (void *) _data                        \
-       }
-
-
-#define CLK(_clk, _devname, _conname)                  \
-       {                                               \
-               .clk    = &clk_##_clk,                  \
-               .dev_id = _devname,                     \
-               .con_id = _conname,                     \
-       }
-
-int __init clk_db8500_ed_fixup(void);
-int __init clk_init(void);
-
-#ifdef CONFIG_DEBUG_FS
-int clk_debugfs_init(void);
-#else
-static inline int clk_debugfs_init(void) { return 0; }
-#endif
-
-#ifdef CONFIG_CPU_FREQ
-int clk_init_smp_twd_cpufreq(void);
-#else
-static inline int clk_init_smp_twd_cpufreq(void) { return 0; }
-#endif
index e2360e7c770d3a6c99b8abedfc38810503f290a7..17a78ec516ff8950be37330acceaae172d89731a 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/clk.h>
 #include <linux/mfd/db8500-prcmu.h>
 #include <linux/clksrc-dbx500-prcmu.h>
 #include <linux/sys_soc.h>
@@ -17,6 +16,7 @@
 #include <linux/stat.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
+#include <linux/platform_data/clk-ux500.h>
 
 #include <asm/hardware/gic.h>
 #include <asm/mach/map.h>
@@ -25,8 +25,6 @@
 #include <mach/setup.h>
 #include <mach/devices.h>
 
-#include "clock.h"
-
 void __iomem *_PRCMU_BASE;
 
 /*
@@ -70,13 +68,17 @@ void __init ux500_init_irq(void)
         */
        if (cpu_is_u8500_family())
                db8500_prcmu_early_init();
-       clk_init();
+
+       if (cpu_is_u8500_family())
+               u8500_clk_init();
+       else if (cpu_is_u9540())
+               u9540_clk_init();
+       else if (cpu_is_u8540())
+               u8540_clk_init();
 }
 
 void __init ux500_init_late(void)
 {
-       clk_debugfs_init();
-       clk_init_smp_twd_cpufreq();
 }
 
 static const char * __init ux500_get_machine(void)
index 7f0b5ca785160733839e6652cf7d67b410fe32e9..bace9e98f75d48c87f79fd91f1319144a3e4c82e 100644 (file)
@@ -40,4 +40,17 @@ config COMMON_CLK_WM831X
           Supports the clocking subsystem of the WM831x/2x series of
          PMICs from Wolfson Microlectronics.
 
+config COMMON_CLK_VERSATILE
+       bool "Clock driver for ARM Reference designs"
+       depends on ARCH_INTEGRATOR || ARCH_REALVIEW
+       ---help---
+          Supports clocking on ARM Reference designs Integrator/AP,
+         Integrator/CP, RealView PB1176, EB, PB11MP and PBX.
+
+config COMMON_CLK_MAX77686
+       tristate "Clock driver for Maxim 77686 MFD"
+       depends on MFD_MAX77686
+       ---help---
+         This driver supports Maxim 77686 crystal oscillator clock. 
+
 endmenu
index 5869ea3870545f0f7c3ab64a185e1c486243b4e1..6327536b4900ae5e06d8da313af721c9dc4b9c4a 100644 (file)
@@ -9,7 +9,14 @@ obj-$(CONFIG_ARCH_MXS)         += mxs/
 obj-$(CONFIG_ARCH_SOCFPGA)     += socfpga/
 obj-$(CONFIG_PLAT_SPEAR)       += spear/
 obj-$(CONFIG_ARCH_U300)                += clk-u300.o
-obj-$(CONFIG_ARCH_INTEGRATOR)  += versatile/
+obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
+obj-$(CONFIG_ARCH_PRIMA2)      += clk-prima2.o
+ifeq ($(CONFIG_COMMON_CLK), y)
+obj-$(CONFIG_ARCH_MMP)         += mmp/
+endif
+obj-$(CONFIG_MACH_LOONGSON1)   += clk-ls1x.o
+obj-$(CONFIG_ARCH_U8500)       += ux500/
 
 # Chip specific
 obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
+obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
diff --git a/drivers/clk/clk-ls1x.c b/drivers/clk/clk-ls1x.c
new file mode 100644 (file)
index 0000000..f20b750
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#include <loongson1.h>
+
+#define OSC    33
+
+static DEFINE_SPINLOCK(_lock);
+
+static int ls1x_pll_clk_enable(struct clk_hw *hw)
+{
+       return 0;
+}
+
+static void ls1x_pll_clk_disable(struct clk_hw *hw)
+{
+}
+
+static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw,
+                                            unsigned long parent_rate)
+{
+       u32 pll, rate;
+
+       pll = __raw_readl(LS1X_CLK_PLL_FREQ);
+       rate = ((12 + (pll & 0x3f)) * 1000000) +
+               ((((pll >> 8) & 0x3ff) * 1000000) >> 10);
+       rate *= OSC;
+       rate >>= 1;
+
+       return rate;
+}
+
+static const struct clk_ops ls1x_pll_clk_ops = {
+       .enable = ls1x_pll_clk_enable,
+       .disable = ls1x_pll_clk_disable,
+       .recalc_rate = ls1x_pll_recalc_rate,
+};
+
+static struct clk * __init clk_register_pll(struct device *dev,
+        const char *name, const char *parent_name, unsigned long flags)
+{
+       struct clk_hw *hw;
+       struct clk *clk;
+       struct clk_init_data init;
+
+       /* allocate the divider */
+       hw = kzalloc(sizeof(struct clk_hw), GFP_KERNEL);
+       if (!hw) {
+               pr_err("%s: could not allocate clk_hw\n", __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       init.name = name;
+       init.ops = &ls1x_pll_clk_ops;
+       init.flags = flags | CLK_IS_BASIC;
+       init.parent_names = (parent_name ? &parent_name : NULL);
+       init.num_parents = (parent_name ? 1 : 0);
+       hw->init = &init;
+
+       /* register the clock */
+       clk = clk_register(dev, hw);
+
+       if (IS_ERR(clk))
+               kfree(hw);
+
+       return clk;
+}
+
+void __init ls1x_clk_init(void)
+{
+       struct clk *clk;
+
+       clk = clk_register_pll(NULL, "pll_clk", NULL, CLK_IS_ROOT);
+       clk_prepare_enable(clk);
+
+       clk = clk_register_divider(NULL, "cpu_clk", "pll_clk",
+                       CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_CPU_SHIFT,
+                       DIV_CPU_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock);
+       clk_prepare_enable(clk);
+       clk_register_clkdev(clk, "cpu", NULL);
+
+       clk = clk_register_divider(NULL, "dc_clk", "pll_clk",
+                       CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT,
+                       DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock);
+       clk_prepare_enable(clk);
+       clk_register_clkdev(clk, "dc", NULL);
+
+       clk = clk_register_divider(NULL, "ahb_clk", "pll_clk",
+                       CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT,
+                       DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock);
+       clk_prepare_enable(clk);
+       clk_register_clkdev(clk, "ahb", NULL);
+       clk_register_clkdev(clk, "stmmaceth", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, 2);
+       clk_prepare_enable(clk);
+       clk_register_clkdev(clk, "apb", NULL);
+       clk_register_clkdev(clk, "serial8250", NULL);
+}
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
new file mode 100644 (file)
index 0000000..ac5f543
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * clk-max77686.c - Clock driver for Maxim 77686
+ *
+ * Copyright (C) 2012 Samsung Electornics
+ * Jonghwa Lee <jonghwa3.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max77686.h>
+#include <linux/mfd/max77686-private.h>
+#include <linux/clk-provider.h>
+#include <linux/mutex.h>
+#include <linux/clkdev.h>
+
+enum {
+       MAX77686_CLK_AP = 0,
+       MAX77686_CLK_CP,
+       MAX77686_CLK_PMIC,
+       MAX77686_CLKS_NUM,
+};
+
+struct max77686_clk {
+       struct max77686_dev *iodev;
+       u32 mask;
+       struct clk_hw hw;
+       struct clk_lookup *lookup;
+};
+
+static struct max77686_clk *get_max77686_clk(struct clk_hw *hw)
+{
+       return container_of(hw, struct max77686_clk, hw);
+}
+
+static int max77686_clk_prepare(struct clk_hw *hw)
+{
+       struct max77686_clk *max77686;
+       int ret;
+
+       max77686 = get_max77686_clk(hw);
+       if (!max77686)
+               return -ENOMEM;
+
+       ret = regmap_update_bits(max77686->iodev->regmap,
+               MAX77686_REG_32KHZ, max77686->mask, max77686->mask);
+
+       return ret;
+}
+
+static void max77686_clk_unprepare(struct clk_hw *hw)
+{
+       struct max77686_clk *max77686;
+
+       max77686 = get_max77686_clk(hw);
+       if (!max77686)
+               return;
+
+       regmap_update_bits(max77686->iodev->regmap,
+               MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask);
+}
+
+static int max77686_clk_is_enabled(struct clk_hw *hw)
+{
+       struct max77686_clk *max77686;
+       int ret;
+       u32 val;
+
+       max77686 = get_max77686_clk(hw);
+       if (!max77686)
+               return -ENOMEM;
+
+       ret = regmap_read(max77686->iodev->regmap,
+                               MAX77686_REG_32KHZ, &val);
+
+       if (ret < 0)
+               return -EINVAL;
+
+       return val & max77686->mask;
+}
+
+static struct clk_ops max77686_clk_ops = {
+       .prepare        = max77686_clk_prepare,
+       .unprepare      = max77686_clk_unprepare,
+       .is_enabled     = max77686_clk_is_enabled,
+};
+
+static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = {
+       [MAX77686_CLK_AP] = {
+               .name = "32khz_ap",
+               .ops = &max77686_clk_ops,
+               .flags = CLK_IS_ROOT,
+       },
+       [MAX77686_CLK_CP] = {
+               .name = "32khz_cp",
+               .ops = &max77686_clk_ops,
+               .flags = CLK_IS_ROOT,
+       },
+       [MAX77686_CLK_PMIC] = {
+               .name = "32khz_pmic",
+               .ops = &max77686_clk_ops,
+               .flags = CLK_IS_ROOT,
+       },
+};
+
+static int max77686_clk_register(struct device *dev,
+                               struct max77686_clk *max77686)
+{
+       struct clk *clk;
+       struct clk_hw *hw = &max77686->hw;
+
+       clk = clk_register(dev, hw);
+
+       if (IS_ERR(clk))
+               return -ENOMEM;
+
+       max77686->lookup = devm_kzalloc(dev, sizeof(struct clk_lookup),
+                                       GFP_KERNEL);
+       if (IS_ERR(max77686->lookup))
+               return -ENOMEM;
+
+       max77686->lookup->con_id = hw->init->name;
+       max77686->lookup->clk = clk;
+
+       clkdev_add(max77686->lookup);
+
+       return 0;
+}
+
+static __devinit int max77686_clk_probe(struct platform_device *pdev)
+{
+       struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct max77686_clk **max77686_clks;
+       int i, ret;
+
+       max77686_clks = devm_kzalloc(&pdev->dev, sizeof(struct max77686_clk *)
+                                       * MAX77686_CLKS_NUM, GFP_KERNEL);
+       if (IS_ERR(max77686_clks))
+               return -ENOMEM;
+
+       for (i = 0; i < MAX77686_CLKS_NUM; i++) {
+               max77686_clks[i] = devm_kzalloc(&pdev->dev,
+                                       sizeof(struct max77686_clk), GFP_KERNEL);
+               if (IS_ERR(max77686_clks[i]))
+                       return -ENOMEM;
+       }
+
+       for (i = 0; i < MAX77686_CLKS_NUM; i++) {
+               max77686_clks[i]->iodev = iodev;
+               max77686_clks[i]->mask = 1 << i;
+               max77686_clks[i]->hw.init = &max77686_clks_init[i];
+
+               ret = max77686_clk_register(&pdev->dev, max77686_clks[i]);
+               if (ret) {
+                       switch (i) {
+                       case MAX77686_CLK_AP:
+                               dev_err(&pdev->dev, "Fail to register CLK_AP\n");
+                               goto err_clk_ap;
+                               break;
+                       case MAX77686_CLK_CP:
+                               dev_err(&pdev->dev, "Fail to register CLK_CP\n");
+                               goto err_clk_cp;
+                               break;
+                       case MAX77686_CLK_PMIC:
+                               dev_err(&pdev->dev, "Fail to register CLK_PMIC\n");
+                               goto err_clk_pmic;
+                       }
+               }
+       }
+
+       platform_set_drvdata(pdev, max77686_clks);
+
+       goto out;
+
+err_clk_pmic:
+       clkdev_drop(max77686_clks[MAX77686_CLK_CP]->lookup);
+       kfree(max77686_clks[MAX77686_CLK_CP]->hw.clk);
+err_clk_cp:
+       clkdev_drop(max77686_clks[MAX77686_CLK_AP]->lookup);
+       kfree(max77686_clks[MAX77686_CLK_AP]->hw.clk);
+err_clk_ap:
+out:
+       return ret;
+}
+
+static int __devexit max77686_clk_remove(struct platform_device *pdev)
+{
+       struct max77686_clk **max77686_clks = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < MAX77686_CLKS_NUM; i++) {
+               clkdev_drop(max77686_clks[i]->lookup);
+               kfree(max77686_clks[i]->hw.clk);
+       }
+       return 0;
+}
+
+static const struct platform_device_id max77686_clk_id[] = {
+       { "max77686-clk", 0},
+       { },
+};
+MODULE_DEVICE_TABLE(platform, max77686_clk_id);
+
+static struct platform_driver max77686_clk_driver = {
+       .driver = {
+               .name  = "max77686-clk",
+               .owner = THIS_MODULE,
+       },
+       .probe = max77686_clk_probe,
+       .remove = __devexit_p(max77686_clk_remove),
+       .id_table = max77686_clk_id,
+};
+
+static int __init max77686_clk_init(void)
+{
+       return platform_driver_register(&max77686_clk_driver);
+}
+subsys_initcall(max77686_clk_init);
+
+static void __init max77686_clk_cleanup(void)
+{
+       platform_driver_unregister(&max77686_clk_driver);
+}
+module_exit(max77686_clk_cleanup);
+
+MODULE_DESCRIPTION("MAXIM 77686 Clock Driver");
+MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-prima2.c b/drivers/clk/clk-prima2.c
new file mode 100644 (file)
index 0000000..517874f
--- /dev/null
@@ -0,0 +1,1171 @@
+/*
+ * Clock tree for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+
+#define SIRFSOC_CLKC_CLK_EN0    0x0000
+#define SIRFSOC_CLKC_CLK_EN1    0x0004
+#define SIRFSOC_CLKC_REF_CFG    0x0014
+#define SIRFSOC_CLKC_CPU_CFG    0x0018
+#define SIRFSOC_CLKC_MEM_CFG    0x001c
+#define SIRFSOC_CLKC_SYS_CFG    0x0020
+#define SIRFSOC_CLKC_IO_CFG     0x0024
+#define SIRFSOC_CLKC_DSP_CFG    0x0028
+#define SIRFSOC_CLKC_GFX_CFG    0x002c
+#define SIRFSOC_CLKC_MM_CFG     0x0030
+#define SIRFSOC_CLKC_LCD_CFG     0x0034
+#define SIRFSOC_CLKC_MMC_CFG    0x0038
+#define SIRFSOC_CLKC_PLL1_CFG0  0x0040
+#define SIRFSOC_CLKC_PLL2_CFG0  0x0044
+#define SIRFSOC_CLKC_PLL3_CFG0  0x0048
+#define SIRFSOC_CLKC_PLL1_CFG1  0x004c
+#define SIRFSOC_CLKC_PLL2_CFG1  0x0050
+#define SIRFSOC_CLKC_PLL3_CFG1  0x0054
+#define SIRFSOC_CLKC_PLL1_CFG2  0x0058
+#define SIRFSOC_CLKC_PLL2_CFG2  0x005c
+#define SIRFSOC_CLKC_PLL3_CFG2  0x0060
+#define SIRFSOC_USBPHY_PLL_CTRL 0x0008
+#define SIRFSOC_USBPHY_PLL_POWERDOWN  BIT(1)
+#define SIRFSOC_USBPHY_PLL_BYPASS     BIT(2)
+#define SIRFSOC_USBPHY_PLL_LOCK       BIT(3)
+
+static void *sirfsoc_clk_vbase, *sirfsoc_rsc_vbase;
+
+#define KHZ     1000
+#define MHZ     (KHZ * KHZ)
+
+/*
+ * SiRFprimaII clock controller
+ * - 2 oscillators: osc-26MHz, rtc-32.768KHz
+ * - 3 standard configurable plls: pll1, pll2 & pll3
+ * - 2 exclusive plls: usb phy pll and sata phy pll
+ * - 8 clock domains: cpu/cpudiv, mem/memdiv, sys/io, dsp, graphic, multimedia,
+ *     display and sdphy.
+ *     Each clock domain can select its own clock source from five clock sources,
+ *     X_XIN, X_XINW, PLL1, PLL2 and PLL3. The domain clock is used as the source
+ *     clock of the group clock.
+ *     - dsp domain: gps, mf
+ *     - io domain: dmac, nand, audio, uart, i2c, spi, usp, pwm, pulse
+ *     - sys domain: security
+ */
+
+struct clk_pll {
+       struct clk_hw hw;
+       unsigned short regofs;  /* register offset */
+};
+
+#define to_pllclk(_hw) container_of(_hw, struct clk_pll, hw)
+
+struct clk_dmn {
+       struct clk_hw hw;
+       signed char enable_bit; /* enable bit: 0 ~ 63 */
+       unsigned short regofs;  /* register offset */
+};
+
+#define to_dmnclk(_hw) container_of(_hw, struct clk_dmn, hw)
+
+struct clk_std {
+       struct clk_hw hw;
+       signed char enable_bit; /* enable bit: 0 ~ 63 */
+};
+
+#define to_stdclk(_hw) container_of(_hw, struct clk_std, hw)
+
+static int std_clk_is_enabled(struct clk_hw *hw);
+static int std_clk_enable(struct clk_hw *hw);
+static void std_clk_disable(struct clk_hw *hw);
+
+static inline unsigned long clkc_readl(unsigned reg)
+{
+       return readl(sirfsoc_clk_vbase + reg);
+}
+
+static inline void clkc_writel(u32 val, unsigned reg)
+{
+       writel(val, sirfsoc_clk_vbase + reg);
+}
+
+/*
+ * std pll
+ */
+
+static unsigned long pll_clk_recalc_rate(struct clk_hw *hw,
+       unsigned long parent_rate)
+{
+       unsigned long fin = parent_rate;
+       struct clk_pll *clk = to_pllclk(hw);
+       u32 regcfg2 = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 -
+               SIRFSOC_CLKC_PLL1_CFG0;
+
+       if (clkc_readl(regcfg2) & BIT(2)) {
+               /* pll bypass mode */
+               return fin;
+       } else {
+               /* fout = fin * nf / nr / od */
+               u32 cfg0 = clkc_readl(clk->regofs);
+               u32 nf = (cfg0 & (BIT(13) - 1)) + 1;
+               u32 nr = ((cfg0 >> 13) & (BIT(6) - 1)) + 1;
+               u32 od = ((cfg0 >> 19) & (BIT(4) - 1)) + 1;
+               WARN_ON(fin % MHZ);
+               return fin / MHZ * nf / nr / od * MHZ;
+       }
+}
+
+static long pll_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+       unsigned long *parent_rate)
+{
+       unsigned long fin, nf, nr, od;
+
+       /*
+        * fout = fin * nf / (nr * od);
+        * set od = 1, nr = fin/MHz, so fout = nf * MHz
+        */
+       rate = rate - rate % MHZ;
+
+       nf = rate / MHZ;
+       if (nf > BIT(13))
+               nf = BIT(13);
+       if (nf < 1)
+               nf = 1;
+
+       fin = *parent_rate;
+
+       nr = fin / MHZ;
+       if (nr > BIT(6))
+               nr = BIT(6);
+       od = 1;
+
+       return fin * nf / (nr * od);
+}
+
+static int pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+       unsigned long parent_rate)
+{
+       struct clk_pll *clk = to_pllclk(hw);
+       unsigned long fin, nf, nr, od, reg;
+
+       /*
+        * fout = fin * nf / (nr * od);
+        * set od = 1, nr = fin/MHz, so fout = nf * MHz
+        */
+
+       nf = rate / MHZ;
+       if (unlikely((rate % MHZ) || nf > BIT(13) || nf < 1))
+               return -EINVAL;
+
+       fin = parent_rate;
+       BUG_ON(fin < MHZ);
+
+       nr = fin / MHZ;
+       BUG_ON((fin % MHZ) || nr > BIT(6));
+
+       od = 1;
+
+       reg = (nf - 1) | ((nr - 1) << 13) | ((od - 1) << 19);
+       clkc_writel(reg, clk->regofs);
+
+       reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG1 - SIRFSOC_CLKC_PLL1_CFG0;
+       clkc_writel((nf >> 1) - 1, reg);
+
+       reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - SIRFSOC_CLKC_PLL1_CFG0;
+       while (!(clkc_readl(reg) & BIT(6)))
+               cpu_relax();
+
+       return 0;
+}
+
+static struct clk_ops std_pll_ops = {
+       .recalc_rate = pll_clk_recalc_rate,
+       .round_rate = pll_clk_round_rate,
+       .set_rate = pll_clk_set_rate,
+};
+
+static const char *pll_clk_parents[] = {
+       "osc",
+};
+
+static struct clk_init_data clk_pll1_init = {
+       .name = "pll1",
+       .ops = &std_pll_ops,
+       .parent_names = pll_clk_parents,
+       .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_init_data clk_pll2_init = {
+       .name = "pll2",
+       .ops = &std_pll_ops,
+       .parent_names = pll_clk_parents,
+       .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_init_data clk_pll3_init = {
+       .name = "pll3",
+       .ops = &std_pll_ops,
+       .parent_names = pll_clk_parents,
+       .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_pll clk_pll1 = {
+       .regofs = SIRFSOC_CLKC_PLL1_CFG0,
+       .hw = {
+               .init = &clk_pll1_init,
+       },
+};
+
+static struct clk_pll clk_pll2 = {
+       .regofs = SIRFSOC_CLKC_PLL2_CFG0,
+       .hw = {
+               .init = &clk_pll2_init,
+       },
+};
+
+static struct clk_pll clk_pll3 = {
+       .regofs = SIRFSOC_CLKC_PLL3_CFG0,
+       .hw = {
+               .init = &clk_pll3_init,
+       },
+};
+
+/*
+ * usb uses specified pll
+ */
+
+static int usb_pll_clk_enable(struct clk_hw *hw)
+{
+       u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
+       reg &= ~(SIRFSOC_USBPHY_PLL_POWERDOWN | SIRFSOC_USBPHY_PLL_BYPASS);
+       writel(reg, sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
+       while (!(readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL) &
+                       SIRFSOC_USBPHY_PLL_LOCK))
+               cpu_relax();
+
+       return 0;
+}
+
+static void usb_pll_clk_disable(struct clk_hw *clk)
+{
+       u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
+       reg |= (SIRFSOC_USBPHY_PLL_POWERDOWN | SIRFSOC_USBPHY_PLL_BYPASS);
+       writel(reg, sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
+}
+
+static unsigned long usb_pll_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+       u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
+       return (reg & SIRFSOC_USBPHY_PLL_BYPASS) ? parent_rate : 48*MHZ;
+}
+
+static struct clk_ops usb_pll_ops = {
+       .enable = usb_pll_clk_enable,
+       .disable = usb_pll_clk_disable,
+       .recalc_rate = usb_pll_clk_recalc_rate,
+};
+
+static struct clk_init_data clk_usb_pll_init = {
+       .name = "usb_pll",
+       .ops = &usb_pll_ops,
+       .parent_names = pll_clk_parents,
+       .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_hw usb_pll_clk_hw = {
+       .init = &clk_usb_pll_init,
+};
+
+/*
+ * clock domains - cpu, mem, sys/io, dsp, gfx
+ */
+
+static const char *dmn_clk_parents[] = {
+       "rtc",
+       "osc",
+       "pll1",
+       "pll2",
+       "pll3",
+};
+
+static u8 dmn_clk_get_parent(struct clk_hw *hw)
+{
+       struct clk_dmn *clk = to_dmnclk(hw);
+       u32 cfg = clkc_readl(clk->regofs);
+
+       /* parent of io domain can only be pll3 */
+       if (strcmp(hw->init->name, "io") == 0)
+               return 4;
+
+       WARN_ON((cfg & (BIT(3) - 1)) > 4);
+
+       return cfg & (BIT(3) - 1);
+}
+
+static int dmn_clk_set_parent(struct clk_hw *hw, u8 parent)
+{
+       struct clk_dmn *clk = to_dmnclk(hw);
+       u32 cfg = clkc_readl(clk->regofs);
+
+       /* parent of io domain can only be pll3 */
+       if (strcmp(hw->init->name, "io") == 0)
+               return -EINVAL;
+
+       cfg &= ~(BIT(3) - 1);
+       clkc_writel(cfg | parent, clk->regofs);
+       /* BIT(3) - switching status: 1 - busy, 0 - done */
+       while (clkc_readl(clk->regofs) & BIT(3))
+               cpu_relax();
+
+       return 0;
+}
+
+static unsigned long dmn_clk_recalc_rate(struct clk_hw *hw,
+       unsigned long parent_rate)
+
+{
+       unsigned long fin = parent_rate;
+       struct clk_dmn *clk = to_dmnclk(hw);
+
+       u32 cfg = clkc_readl(clk->regofs);
+
+       if (cfg & BIT(24)) {
+               /* fcd bypass mode */
+               return fin;
+       } else {
+               /*
+                * wait count: bit[19:16], hold count: bit[23:20]
+                */
+               u32 wait = (cfg >> 16) & (BIT(4) - 1);
+               u32 hold = (cfg >> 20) & (BIT(4) - 1);
+
+               return fin / (wait + hold + 2);
+       }
+}
+
+static long dmn_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+       unsigned long *parent_rate)
+{
+       unsigned long fin;
+       unsigned ratio, wait, hold;
+       unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4;
+
+       fin = *parent_rate;
+       ratio = fin / rate;
+
+       if (ratio < 2)
+               ratio = 2;
+       if (ratio > BIT(bits + 1))
+               ratio = BIT(bits + 1);
+
+       wait = (ratio >> 1) - 1;
+       hold = ratio - wait - 2;
+
+       return fin / (wait + hold + 2);
+}
+
+static int dmn_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+       unsigned long parent_rate)
+{
+       struct clk_dmn *clk = to_dmnclk(hw);
+       unsigned long fin;
+       unsigned ratio, wait, hold, reg;
+       unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4;
+
+       fin = parent_rate;
+       ratio = fin / rate;
+
+       if (unlikely(ratio < 2 || ratio > BIT(bits + 1)))
+               return -EINVAL;
+
+       WARN_ON(fin % rate);
+
+       wait = (ratio >> 1) - 1;
+       hold = ratio - wait - 2;
+
+       reg = clkc_readl(clk->regofs);
+       reg &= ~(((BIT(bits) - 1) << 16) | ((BIT(bits) - 1) << 20));
+       reg |= (wait << 16) | (hold << 20) | BIT(25);
+       clkc_writel(reg, clk->regofs);
+
+       /* waiting FCD been effective */
+       while (clkc_readl(clk->regofs) & BIT(25))
+               cpu_relax();
+
+       return 0;
+}
+
+static struct clk_ops msi_ops = {
+       .set_rate = dmn_clk_set_rate,
+       .round_rate = dmn_clk_round_rate,
+       .recalc_rate = dmn_clk_recalc_rate,
+       .set_parent = dmn_clk_set_parent,
+       .get_parent = dmn_clk_get_parent,
+};
+
+static struct clk_init_data clk_mem_init = {
+       .name = "mem",
+       .ops = &msi_ops,
+       .parent_names = dmn_clk_parents,
+       .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_mem = {
+       .regofs = SIRFSOC_CLKC_MEM_CFG,
+       .hw = {
+               .init = &clk_mem_init,
+       },
+};
+
+static struct clk_init_data clk_sys_init = {
+       .name = "sys",
+       .ops = &msi_ops,
+       .parent_names = dmn_clk_parents,
+       .num_parents = ARRAY_SIZE(dmn_clk_parents),
+       .flags = CLK_SET_RATE_GATE,
+};
+
+static struct clk_dmn clk_sys = {
+       .regofs = SIRFSOC_CLKC_SYS_CFG,
+       .hw = {
+               .init = &clk_sys_init,
+       },
+};
+
+static struct clk_init_data clk_io_init = {
+       .name = "io",
+       .ops = &msi_ops,
+       .parent_names = dmn_clk_parents,
+       .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_io = {
+       .regofs = SIRFSOC_CLKC_IO_CFG,
+       .hw = {
+               .init = &clk_io_init,
+       },
+};
+
+static struct clk_ops cpu_ops = {
+       .set_parent = dmn_clk_set_parent,
+       .get_parent = dmn_clk_get_parent,
+};
+
+static struct clk_init_data clk_cpu_init = {
+       .name = "cpu",
+       .ops = &cpu_ops,
+       .parent_names = dmn_clk_parents,
+       .num_parents = ARRAY_SIZE(dmn_clk_parents),
+       .flags = CLK_SET_RATE_PARENT,
+};
+
+static struct clk_dmn clk_cpu = {
+       .regofs = SIRFSOC_CLKC_CPU_CFG,
+       .hw = {
+               .init = &clk_cpu_init,
+       },
+};
+
+static struct clk_ops dmn_ops = {
+       .is_enabled = std_clk_is_enabled,
+       .enable = std_clk_enable,
+       .disable = std_clk_disable,
+       .set_rate = dmn_clk_set_rate,
+       .round_rate = dmn_clk_round_rate,
+       .recalc_rate = dmn_clk_recalc_rate,
+       .set_parent = dmn_clk_set_parent,
+       .get_parent = dmn_clk_get_parent,
+};
+
+/* dsp, gfx, mm, lcd and vpp domain */
+
+static struct clk_init_data clk_dsp_init = {
+       .name = "dsp",
+       .ops = &dmn_ops,
+       .parent_names = dmn_clk_parents,
+       .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_dsp = {
+       .regofs = SIRFSOC_CLKC_DSP_CFG,
+       .enable_bit = 0,
+       .hw = {
+               .init = &clk_dsp_init,
+       },
+};
+
+static struct clk_init_data clk_gfx_init = {
+       .name = "gfx",
+       .ops = &dmn_ops,
+       .parent_names = dmn_clk_parents,
+       .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_gfx = {
+       .regofs = SIRFSOC_CLKC_GFX_CFG,
+       .enable_bit = 8,
+       .hw = {
+               .init = &clk_gfx_init,
+       },
+};
+
+static struct clk_init_data clk_mm_init = {
+       .name = "mm",
+       .ops = &dmn_ops,
+       .parent_names = dmn_clk_parents,
+       .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_mm = {
+       .regofs = SIRFSOC_CLKC_MM_CFG,
+       .enable_bit = 9,
+       .hw = {
+               .init = &clk_mm_init,
+       },
+};
+
+static struct clk_init_data clk_lcd_init = {
+       .name = "lcd",
+       .ops = &dmn_ops,
+       .parent_names = dmn_clk_parents,
+       .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_lcd = {
+       .regofs = SIRFSOC_CLKC_LCD_CFG,
+       .enable_bit = 10,
+       .hw = {
+               .init = &clk_lcd_init,
+       },
+};
+
+static struct clk_init_data clk_vpp_init = {
+       .name = "vpp",
+       .ops = &dmn_ops,
+       .parent_names = dmn_clk_parents,
+       .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_vpp = {
+       .regofs = SIRFSOC_CLKC_LCD_CFG,
+       .enable_bit = 11,
+       .hw = {
+               .init = &clk_vpp_init,
+       },
+};
+
+static struct clk_init_data clk_mmc01_init = {
+       .name = "mmc01",
+       .ops = &dmn_ops,
+       .parent_names = dmn_clk_parents,
+       .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_mmc01 = {
+       .regofs = SIRFSOC_CLKC_MMC_CFG,
+       .enable_bit = 59,
+       .hw = {
+               .init = &clk_mmc01_init,
+       },
+};
+
+static struct clk_init_data clk_mmc23_init = {
+       .name = "mmc23",
+       .ops = &dmn_ops,
+       .parent_names = dmn_clk_parents,
+       .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_mmc23 = {
+       .regofs = SIRFSOC_CLKC_MMC_CFG,
+       .enable_bit = 60,
+       .hw = {
+               .init = &clk_mmc23_init,
+       },
+};
+
+static struct clk_init_data clk_mmc45_init = {
+       .name = "mmc45",
+       .ops = &dmn_ops,
+       .parent_names = dmn_clk_parents,
+       .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_mmc45 = {
+       .regofs = SIRFSOC_CLKC_MMC_CFG,
+       .enable_bit = 61,
+       .hw = {
+               .init = &clk_mmc45_init,
+       },
+};
+
+/*
+ * peripheral controllers in io domain
+ */
+
+static int std_clk_is_enabled(struct clk_hw *hw)
+{
+       u32 reg;
+       int bit;
+       struct clk_std *clk = to_stdclk(hw);
+
+       bit = clk->enable_bit % 32;
+       reg = clk->enable_bit / 32;
+       reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg);
+
+       return !!(clkc_readl(reg) & BIT(bit));
+}
+
+static int std_clk_enable(struct clk_hw *hw)
+{
+       u32 val, reg;
+       int bit;
+       struct clk_std *clk = to_stdclk(hw);
+
+       BUG_ON(clk->enable_bit < 0 || clk->enable_bit > 63);
+
+       bit = clk->enable_bit % 32;
+       reg = clk->enable_bit / 32;
+       reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg);
+
+       val = clkc_readl(reg) | BIT(bit);
+       clkc_writel(val, reg);
+       return 0;
+}
+
+static void std_clk_disable(struct clk_hw *hw)
+{
+       u32 val, reg;
+       int bit;
+       struct clk_std *clk = to_stdclk(hw);
+
+       BUG_ON(clk->enable_bit < 0 || clk->enable_bit > 63);
+
+       bit = clk->enable_bit % 32;
+       reg = clk->enable_bit / 32;
+       reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg);
+
+       val = clkc_readl(reg) & ~BIT(bit);
+       clkc_writel(val, reg);
+}
+
+static const char *std_clk_io_parents[] = {
+       "io",
+};
+
+static struct clk_ops ios_ops = {
+       .is_enabled = std_clk_is_enabled,
+       .enable = std_clk_enable,
+       .disable = std_clk_disable,
+};
+
+static struct clk_init_data clk_dmac0_init = {
+       .name = "dmac0",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_dmac0 = {
+       .enable_bit = 32,
+       .hw = {
+               .init = &clk_dmac0_init,
+       },
+};
+
+static struct clk_init_data clk_dmac1_init = {
+       .name = "dmac1",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_dmac1 = {
+       .enable_bit = 33,
+       .hw = {
+               .init = &clk_dmac1_init,
+       },
+};
+
+static struct clk_init_data clk_nand_init = {
+       .name = "nand",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_nand = {
+       .enable_bit = 34,
+       .hw = {
+               .init = &clk_nand_init,
+       },
+};
+
+static struct clk_init_data clk_audio_init = {
+       .name = "audio",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_audio = {
+       .enable_bit = 35,
+       .hw = {
+               .init = &clk_audio_init,
+       },
+};
+
+static struct clk_init_data clk_uart0_init = {
+       .name = "uart0",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_uart0 = {
+       .enable_bit = 36,
+       .hw = {
+               .init = &clk_uart0_init,
+       },
+};
+
+static struct clk_init_data clk_uart1_init = {
+       .name = "uart1",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_uart1 = {
+       .enable_bit = 37,
+       .hw = {
+               .init = &clk_uart1_init,
+       },
+};
+
+static struct clk_init_data clk_uart2_init = {
+       .name = "uart2",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_uart2 = {
+       .enable_bit = 38,
+       .hw = {
+               .init = &clk_uart2_init,
+       },
+};
+
+static struct clk_init_data clk_usp0_init = {
+       .name = "usp0",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_usp0 = {
+       .enable_bit = 39,
+       .hw = {
+               .init = &clk_usp0_init,
+       },
+};
+
+static struct clk_init_data clk_usp1_init = {
+       .name = "usp1",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_usp1 = {
+       .enable_bit = 40,
+       .hw = {
+               .init = &clk_usp1_init,
+       },
+};
+
+static struct clk_init_data clk_usp2_init = {
+       .name = "usp2",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_usp2 = {
+       .enable_bit = 41,
+       .hw = {
+               .init = &clk_usp2_init,
+       },
+};
+
+static struct clk_init_data clk_vip_init = {
+       .name = "vip",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_vip = {
+       .enable_bit = 42,
+       .hw = {
+               .init = &clk_vip_init,
+       },
+};
+
+static struct clk_init_data clk_spi0_init = {
+       .name = "spi0",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_spi0 = {
+       .enable_bit = 43,
+       .hw = {
+               .init = &clk_spi0_init,
+       },
+};
+
+static struct clk_init_data clk_spi1_init = {
+       .name = "spi1",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_spi1 = {
+       .enable_bit = 44,
+       .hw = {
+               .init = &clk_spi1_init,
+       },
+};
+
+static struct clk_init_data clk_tsc_init = {
+       .name = "tsc",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_tsc = {
+       .enable_bit = 45,
+       .hw = {
+               .init = &clk_tsc_init,
+       },
+};
+
+static struct clk_init_data clk_i2c0_init = {
+       .name = "i2c0",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_i2c0 = {
+       .enable_bit = 46,
+       .hw = {
+               .init = &clk_i2c0_init,
+       },
+};
+
+static struct clk_init_data clk_i2c1_init = {
+       .name = "i2c1",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_i2c1 = {
+       .enable_bit = 47,
+       .hw = {
+               .init = &clk_i2c1_init,
+       },
+};
+
+static struct clk_init_data clk_pwmc_init = {
+       .name = "pwmc",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_pwmc = {
+       .enable_bit = 48,
+       .hw = {
+               .init = &clk_pwmc_init,
+       },
+};
+
+static struct clk_init_data clk_efuse_init = {
+       .name = "efuse",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_efuse = {
+       .enable_bit = 49,
+       .hw = {
+               .init = &clk_efuse_init,
+       },
+};
+
+static struct clk_init_data clk_pulse_init = {
+       .name = "pulse",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_pulse = {
+       .enable_bit = 50,
+       .hw = {
+               .init = &clk_pulse_init,
+       },
+};
+
+static const char *std_clk_dsp_parents[] = {
+       "dsp",
+};
+
+static struct clk_init_data clk_gps_init = {
+       .name = "gps",
+       .ops = &ios_ops,
+       .parent_names = std_clk_dsp_parents,
+       .num_parents = ARRAY_SIZE(std_clk_dsp_parents),
+};
+
+static struct clk_std clk_gps = {
+       .enable_bit = 1,
+       .hw = {
+               .init = &clk_gps_init,
+       },
+};
+
+static struct clk_init_data clk_mf_init = {
+       .name = "mf",
+       .ops = &ios_ops,
+       .parent_names = std_clk_io_parents,
+       .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_mf = {
+       .enable_bit = 2,
+       .hw = {
+               .init = &clk_mf_init,
+       },
+};
+
+static const char *std_clk_sys_parents[] = {
+       "sys",
+};
+
+static struct clk_init_data clk_security_init = {
+       .name = "mf",
+       .ops = &ios_ops,
+       .parent_names = std_clk_sys_parents,
+       .num_parents = ARRAY_SIZE(std_clk_sys_parents),
+};
+
+static struct clk_std clk_security = {
+       .enable_bit = 19,
+       .hw = {
+               .init = &clk_security_init,
+       },
+};
+
+static const char *std_clk_usb_parents[] = {
+       "usb_pll",
+};
+
+static struct clk_init_data clk_usb0_init = {
+       .name = "usb0",
+       .ops = &ios_ops,
+       .parent_names = std_clk_usb_parents,
+       .num_parents = ARRAY_SIZE(std_clk_usb_parents),
+};
+
+static struct clk_std clk_usb0 = {
+       .enable_bit = 16,
+       .hw = {
+               .init = &clk_usb0_init,
+       },
+};
+
+static struct clk_init_data clk_usb1_init = {
+       .name = "usb1",
+       .ops = &ios_ops,
+       .parent_names = std_clk_usb_parents,
+       .num_parents = ARRAY_SIZE(std_clk_usb_parents),
+};
+
+static struct clk_std clk_usb1 = {
+       .enable_bit = 17,
+       .hw = {
+               .init = &clk_usb1_init,
+       },
+};
+
+static struct of_device_id clkc_ids[] = {
+       { .compatible = "sirf,prima2-clkc" },
+       {},
+};
+
+static struct of_device_id rsc_ids[] = {
+       { .compatible = "sirf,prima2-rsc" },
+       {},
+};
+
+void __init sirfsoc_of_clk_init(void)
+{
+       struct clk *clk;
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, clkc_ids);
+       if (!np)
+               panic("unable to find compatible clkc node in dtb\n");
+
+       sirfsoc_clk_vbase = of_iomap(np, 0);
+       if (!sirfsoc_clk_vbase)
+               panic("unable to map clkc registers\n");
+
+       of_node_put(np);
+
+       np = of_find_matching_node(NULL, rsc_ids);
+       if (!np)
+               panic("unable to find compatible rsc node in dtb\n");
+
+       sirfsoc_rsc_vbase = of_iomap(np, 0);
+       if (!sirfsoc_rsc_vbase)
+               panic("unable to map rsc registers\n");
+
+       of_node_put(np);
+
+
+       /* These are always available (RTC and 26MHz OSC)*/
+       clk = clk_register_fixed_rate(NULL, "rtc", NULL,
+               CLK_IS_ROOT, 32768);
+       BUG_ON(!clk);
+       clk = clk_register_fixed_rate(NULL, "osc", NULL,
+               CLK_IS_ROOT, 26000000);
+       BUG_ON(!clk);
+
+       clk = clk_register(NULL, &clk_pll1.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_pll2.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_pll3.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_mem.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_sys.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_security.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b8030000.security");
+       clk = clk_register(NULL, &clk_dsp.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_gps.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "a8010000.gps");
+       clk = clk_register(NULL, &clk_mf.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_io.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "io");
+       clk = clk_register(NULL, &clk_cpu.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "cpu");
+       clk = clk_register(NULL, &clk_uart0.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b0050000.uart");
+       clk = clk_register(NULL, &clk_uart1.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b0060000.uart");
+       clk = clk_register(NULL, &clk_uart2.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b0070000.uart");
+       clk = clk_register(NULL, &clk_tsc.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b0110000.tsc");
+       clk = clk_register(NULL, &clk_i2c0.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b00e0000.i2c");
+       clk = clk_register(NULL, &clk_i2c1.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b00f0000.i2c");
+       clk = clk_register(NULL, &clk_spi0.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b00d0000.spi");
+       clk = clk_register(NULL, &clk_spi1.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b0170000.spi");
+       clk = clk_register(NULL, &clk_pwmc.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b0130000.pwm");
+       clk = clk_register(NULL, &clk_efuse.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b0140000.efusesys");
+       clk = clk_register(NULL, &clk_pulse.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b0150000.pulsec");
+       clk = clk_register(NULL, &clk_dmac0.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b00b0000.dma-controller");
+       clk = clk_register(NULL, &clk_dmac1.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b0160000.dma-controller");
+       clk = clk_register(NULL, &clk_nand.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b0030000.nand");
+       clk = clk_register(NULL, &clk_audio.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b0040000.audio");
+       clk = clk_register(NULL, &clk_usp0.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b0080000.usp");
+       clk = clk_register(NULL, &clk_usp1.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b0090000.usp");
+       clk = clk_register(NULL, &clk_usp2.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b00a0000.usp");
+       clk = clk_register(NULL, &clk_vip.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b00c0000.vip");
+       clk = clk_register(NULL, &clk_gfx.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "98000000.graphics");
+       clk = clk_register(NULL, &clk_mm.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "a0000000.multimedia");
+       clk = clk_register(NULL, &clk_lcd.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "90010000.display");
+       clk = clk_register(NULL, &clk_vpp.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "90020000.vpp");
+       clk = clk_register(NULL, &clk_mmc01.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_mmc23.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_mmc45.hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &usb_pll_clk_hw);
+       BUG_ON(!clk);
+       clk = clk_register(NULL, &clk_usb0.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b00e0000.usb");
+       clk = clk_register(NULL, &clk_usb1.hw);
+       BUG_ON(!clk);
+       clk_register_clkdev(clk, NULL, "b00f0000.usb");
+}
index efdfd009c2701a40b18a7ec8025ce7500fb98c53..56e4495ebeb118694237c9b542b381b0c1de4f02 100644 (file)
@@ -557,25 +557,6 @@ int clk_enable(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(clk_enable);
 
-/**
- * clk_get_rate - return the rate of clk
- * @clk: the clk whose rate is being returned
- *
- * Simply returns the cached rate of the clk.  Does not query the hardware.  If
- * clk is NULL then returns 0.
- */
-unsigned long clk_get_rate(struct clk *clk)
-{
-       unsigned long rate;
-
-       mutex_lock(&prepare_lock);
-       rate = __clk_get_rate(clk);
-       mutex_unlock(&prepare_lock);
-
-       return rate;
-}
-EXPORT_SYMBOL_GPL(clk_get_rate);
-
 /**
  * __clk_round_rate - round the given rate for a clk
  * @clk: round the rate of this clock
@@ -701,6 +682,30 @@ static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
                __clk_recalc_rates(child, msg);
 }
 
+/**
+ * clk_get_rate - return the rate of clk
+ * @clk: the clk whose rate is being returned
+ *
+ * Simply returns the cached rate of the clk, unless CLK_GET_RATE_NOCACHE flag
+ * is set, which means a recalc_rate will be issued.
+ * If clk is NULL then returns 0.
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+       unsigned long rate;
+
+       mutex_lock(&prepare_lock);
+
+       if (clk && (clk->flags & CLK_GET_RATE_NOCACHE))
+               __clk_recalc_rates(clk, 0);
+
+       rate = __clk_get_rate(clk);
+       mutex_unlock(&prepare_lock);
+
+       return rate;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
 /**
  * __clk_speculate_rates
  * @clk: first clk in the subtree
@@ -1582,6 +1587,20 @@ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
 }
 EXPORT_SYMBOL_GPL(of_clk_src_simple_get);
 
+struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data)
+{
+       struct clk_onecell_data *clk_data = data;
+       unsigned int idx = clkspec->args[0];
+
+       if (idx >= clk_data->clk_num) {
+               pr_err("%s: invalid clock index %d\n", __func__, idx);
+               return ERR_PTR(-EINVAL);
+       }
+
+       return clk_data->clks[idx];
+}
+EXPORT_SYMBOL_GPL(of_clk_src_onecell_get);
+
 /**
  * of_clk_add_provider() - Register a clock provider for a node
  * @np: Device node pointer associated with clock provider
diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
new file mode 100644 (file)
index 0000000..392d780
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Makefile for mmp specific clk
+#
+
+obj-y += clk-apbc.o clk-apmu.o clk-frac.o
+
+obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
+obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
+obj-$(CONFIG_CPU_MMP2) += clk-mmp2.o
diff --git a/drivers/clk/mmp/clk-apbc.c b/drivers/clk/mmp/clk-apbc.c
new file mode 100644 (file)
index 0000000..d14120e
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * mmp APB clock operation source file
+ *
+ * Copyright (C) 2012 Marvell
+ * Chao Xie <xiechao.mail@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+/* Common APB clock register bit definitions */
+#define APBC_APBCLK    (1 << 0)  /* APB Bus Clock Enable */
+#define APBC_FNCLK     (1 << 1)  /* Functional Clock Enable */
+#define APBC_RST       (1 << 2)  /* Reset Generation */
+#define APBC_POWER     (1 << 7)  /* Reset Generation */
+
+#define to_clk_apbc(hw) container_of(hw, struct clk_apbc, hw)
+struct clk_apbc {
+       struct clk_hw           hw;
+       void __iomem            *base;
+       unsigned int            delay;
+       unsigned int            flags;
+       spinlock_t              *lock;
+};
+
+static int clk_apbc_prepare(struct clk_hw *hw)
+{
+       struct clk_apbc *apbc = to_clk_apbc(hw);
+       unsigned int data;
+       unsigned long flags = 0;
+
+       /*
+        * It may share same register as MUX clock,
+        * and it will impact FNCLK enable. Spinlock is needed
+        */
+       if (apbc->lock)
+               spin_lock_irqsave(apbc->lock, flags);
+
+       data = readl_relaxed(apbc->base);
+       if (apbc->flags & APBC_POWER_CTRL)
+               data |= APBC_POWER;
+       data |= APBC_FNCLK;
+       writel_relaxed(data, apbc->base);
+
+       if (apbc->lock)
+               spin_unlock_irqrestore(apbc->lock, flags);
+
+       udelay(apbc->delay);
+
+       if (apbc->lock)
+               spin_lock_irqsave(apbc->lock, flags);
+
+       data = readl_relaxed(apbc->base);
+       data |= APBC_APBCLK;
+       writel_relaxed(data, apbc->base);
+
+       if (apbc->lock)
+               spin_unlock_irqrestore(apbc->lock, flags);
+
+       udelay(apbc->delay);
+
+       if (!(apbc->flags & APBC_NO_BUS_CTRL)) {
+               if (apbc->lock)
+                       spin_lock_irqsave(apbc->lock, flags);
+
+               data = readl_relaxed(apbc->base);
+               data &= ~APBC_RST;
+               writel_relaxed(data, apbc->base);
+
+               if (apbc->lock)
+                       spin_unlock_irqrestore(apbc->lock, flags);
+       }
+
+       return 0;
+}
+
+static void clk_apbc_unprepare(struct clk_hw *hw)
+{
+       struct clk_apbc *apbc = to_clk_apbc(hw);
+       unsigned long data;
+       unsigned long flags = 0;
+
+       if (apbc->lock)
+               spin_lock_irqsave(apbc->lock, flags);
+
+       data = readl_relaxed(apbc->base);
+       if (apbc->flags & APBC_POWER_CTRL)
+               data &= ~APBC_POWER;
+       data &= ~APBC_FNCLK;
+       writel_relaxed(data, apbc->base);
+
+       if (apbc->lock)
+               spin_unlock_irqrestore(apbc->lock, flags);
+
+       udelay(10);
+
+       if (apbc->lock)
+               spin_lock_irqsave(apbc->lock, flags);
+
+       data = readl_relaxed(apbc->base);
+       data &= ~APBC_APBCLK;
+       writel_relaxed(data, apbc->base);
+
+       if (apbc->lock)
+               spin_unlock_irqrestore(apbc->lock, flags);
+}
+
+struct clk_ops clk_apbc_ops = {
+       .prepare = clk_apbc_prepare,
+       .unprepare = clk_apbc_unprepare,
+};
+
+struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name,
+               void __iomem *base, unsigned int delay,
+               unsigned int apbc_flags, spinlock_t *lock)
+{
+       struct clk_apbc *apbc;
+       struct clk *clk;
+       struct clk_init_data init;
+
+       apbc = kzalloc(sizeof(*apbc), GFP_KERNEL);
+       if (!apbc)
+               return NULL;
+
+       init.name = name;
+       init.ops = &clk_apbc_ops;
+       init.flags = CLK_SET_RATE_PARENT;
+       init.parent_names = (parent_name ? &parent_name : NULL);
+       init.num_parents = (parent_name ? 1 : 0);
+
+       apbc->base = base;
+       apbc->delay = delay;
+       apbc->flags = apbc_flags;
+       apbc->lock = lock;
+       apbc->hw.init = &init;
+
+       clk = clk_register(NULL, &apbc->hw);
+       if (IS_ERR(clk))
+               kfree(apbc);
+
+       return clk;
+}
diff --git a/drivers/clk/mmp/clk-apmu.c b/drivers/clk/mmp/clk-apmu.c
new file mode 100644 (file)
index 0000000..abe182b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * mmp AXI peripharal clock operation source file
+ *
+ * Copyright (C) 2012 Marvell
+ * Chao Xie <xiechao.mail@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+#define to_clk_apmu(clk) (container_of(clk, struct clk_apmu, clk))
+struct clk_apmu {
+       struct clk_hw   hw;
+       void __iomem    *base;
+       u32             rst_mask;
+       u32             enable_mask;
+       spinlock_t      *lock;
+};
+
+static int clk_apmu_enable(struct clk_hw *hw)
+{
+       struct clk_apmu *apmu = to_clk_apmu(hw);
+       unsigned long data;
+       unsigned long flags = 0;
+
+       if (apmu->lock)
+               spin_lock_irqsave(apmu->lock, flags);
+
+       data = readl_relaxed(apmu->base) | apmu->enable_mask;
+       writel_relaxed(data, apmu->base);
+
+       if (apmu->lock)
+               spin_unlock_irqrestore(apmu->lock, flags);
+
+       return 0;
+}
+
+static void clk_apmu_disable(struct clk_hw *hw)
+{
+       struct clk_apmu *apmu = to_clk_apmu(hw);
+       unsigned long data;
+       unsigned long flags = 0;
+
+       if (apmu->lock)
+               spin_lock_irqsave(apmu->lock, flags);
+
+       data = readl_relaxed(apmu->base) & ~apmu->enable_mask;
+       writel_relaxed(data, apmu->base);
+
+       if (apmu->lock)
+               spin_unlock_irqrestore(apmu->lock, flags);
+}
+
+struct clk_ops clk_apmu_ops = {
+       .enable = clk_apmu_enable,
+       .disable = clk_apmu_disable,
+};
+
+struct clk *mmp_clk_register_apmu(const char *name, const char *parent_name,
+               void __iomem *base, u32 enable_mask, spinlock_t *lock)
+{
+       struct clk_apmu *apmu;
+       struct clk *clk;
+       struct clk_init_data init;
+
+       apmu = kzalloc(sizeof(*apmu), GFP_KERNEL);
+       if (!apmu)
+               return NULL;
+
+       init.name = name;
+       init.ops = &clk_apmu_ops;
+       init.flags = CLK_SET_RATE_PARENT;
+       init.parent_names = (parent_name ? &parent_name : NULL);
+       init.num_parents = (parent_name ? 1 : 0);
+
+       apmu->base = base;
+       apmu->enable_mask = enable_mask;
+       apmu->lock = lock;
+       apmu->hw.init = &init;
+
+       clk = clk_register(NULL, &apmu->hw);
+
+       if (IS_ERR(clk))
+               kfree(apmu);
+
+       return clk;
+}
diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c
new file mode 100644 (file)
index 0000000..80c1dd1
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * mmp factor clock operation source file
+ *
+ * Copyright (C) 2012 Marvell
+ * Chao Xie <xiechao.mail@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include "clk.h"
+/*
+ * It is M/N clock
+ *
+ * Fout from synthesizer can be given from two equations:
+ * numerator/denominator = Fin / (Fout * factor)
+ */
+
+#define to_clk_factor(hw) container_of(hw, struct clk_factor, hw)
+struct clk_factor {
+       struct clk_hw           hw;
+       void __iomem            *base;
+       struct clk_factor_masks *masks;
+       struct clk_factor_tbl   *ftbl;
+       unsigned int            ftbl_cnt;
+};
+
+static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate,
+               unsigned long *prate)
+{
+       struct clk_factor *factor = to_clk_factor(hw);
+       unsigned long rate = 0, prev_rate;
+       int i;
+
+       for (i = 0; i < factor->ftbl_cnt; i++) {
+               prev_rate = rate;
+               rate = (((*prate / 10000) * factor->ftbl[i].num) /
+                       (factor->ftbl[i].den * factor->masks->factor)) * 10000;
+               if (rate > drate)
+                       break;
+       }
+       if (i == 0)
+               return rate;
+       else
+               return prev_rate;
+}
+
+static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct clk_factor *factor = to_clk_factor(hw);
+       struct clk_factor_masks *masks = factor->masks;
+       unsigned int val, num, den;
+
+       val = readl_relaxed(factor->base);
+
+       /* calculate numerator */
+       num = (val >> masks->num_shift) & masks->num_mask;
+
+       /* calculate denominator */
+       den = (val >> masks->den_shift) & masks->num_mask;
+
+       if (!den)
+               return 0;
+
+       return (((parent_rate / 10000)  * den) /
+                       (num * factor->masks->factor)) * 10000;
+}
+
+/* Configures new clock rate*/
+static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
+                               unsigned long prate)
+{
+       struct clk_factor *factor = to_clk_factor(hw);
+       struct clk_factor_masks *masks = factor->masks;
+       int i;
+       unsigned long val;
+       unsigned long prev_rate, rate = 0;
+
+       for (i = 0; i < factor->ftbl_cnt; i++) {
+               prev_rate = rate;
+               rate = (((prate / 10000) * factor->ftbl[i].num) /
+                       (factor->ftbl[i].den * factor->masks->factor)) * 10000;
+               if (rate > drate)
+                       break;
+       }
+       if (i > 0)
+               i--;
+
+       val = readl_relaxed(factor->base);
+
+       val &= ~(masks->num_mask << masks->num_shift);
+       val |= (factor->ftbl[i].num & masks->num_mask) << masks->num_shift;
+
+       val &= ~(masks->den_mask << masks->den_shift);
+       val |= (factor->ftbl[i].den & masks->den_mask) << masks->den_shift;
+
+       writel_relaxed(val, factor->base);
+
+       return 0;
+}
+
+static struct clk_ops clk_factor_ops = {
+       .recalc_rate = clk_factor_recalc_rate,
+       .round_rate = clk_factor_round_rate,
+       .set_rate = clk_factor_set_rate,
+};
+
+struct clk *mmp_clk_register_factor(const char *name, const char *parent_name,
+               unsigned long flags, void __iomem *base,
+               struct clk_factor_masks *masks, struct clk_factor_tbl *ftbl,
+               unsigned int ftbl_cnt)
+{
+       struct clk_factor *factor;
+       struct clk_init_data init;
+       struct clk *clk;
+
+       if (!masks) {
+               pr_err("%s: must pass a clk_factor_mask\n", __func__);
+               return ERR_PTR(-EINVAL);
+       }
+
+       factor = kzalloc(sizeof(*factor), GFP_KERNEL);
+       if (!factor) {
+               pr_err("%s: could not allocate factor  clk\n", __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       /* struct clk_aux assignments */
+       factor->base = base;
+       factor->masks = masks;
+       factor->ftbl = ftbl;
+       factor->ftbl_cnt = ftbl_cnt;
+       factor->hw.init = &init;
+
+       init.name = name;
+       init.ops = &clk_factor_ops;
+       init.flags = flags;
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+
+       clk = clk_register(NULL, &factor->hw);
+       if (IS_ERR_OR_NULL(clk))
+               kfree(factor);
+
+       return clk;
+}
diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c
new file mode 100644 (file)
index 0000000..ade4358
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * mmp2 clock framework source file
+ *
+ * Copyright (C) 2012 Marvell
+ * Chao Xie <xiechao.mail@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <mach/addr-map.h>
+
+#include "clk.h"
+
+#define APBC_RTC       0x0
+#define APBC_TWSI0     0x4
+#define APBC_TWSI1     0x8
+#define APBC_TWSI2     0xc
+#define APBC_TWSI3     0x10
+#define APBC_TWSI4     0x7c
+#define APBC_TWSI5     0x80
+#define APBC_KPC       0x18
+#define APBC_UART0     0x2c
+#define APBC_UART1     0x30
+#define APBC_UART2     0x34
+#define APBC_UART3     0x88
+#define APBC_GPIO      0x38
+#define APBC_PWM0      0x3c
+#define APBC_PWM1      0x40
+#define APBC_PWM2      0x44
+#define APBC_PWM3      0x48
+#define APBC_SSP0      0x50
+#define APBC_SSP1      0x54
+#define APBC_SSP2      0x58
+#define APBC_SSP3      0x5c
+#define APMU_SDH0      0x54
+#define APMU_SDH1      0x58
+#define APMU_SDH2      0xe8
+#define APMU_SDH3      0xec
+#define APMU_USB       0x5c
+#define APMU_DISP0     0x4c
+#define APMU_DISP1     0x110
+#define APMU_CCIC0     0x50
+#define APMU_CCIC1     0xf4
+#define MPMU_UART_PLL  0x14
+
+static DEFINE_SPINLOCK(clk_lock);
+
+static struct clk_factor_masks uart_factor_masks = {
+       .factor = 2,
+       .num_mask = 0x1fff,
+       .den_mask = 0x1fff,
+       .num_shift = 16,
+       .den_shift = 0,
+};
+
+static struct clk_factor_tbl uart_factor_tbl[] = {
+       {.num = 14634, .den = 2165},    /*14.745MHZ */
+       {.num = 3521, .den = 689},      /*19.23MHZ */
+       {.num = 9679, .den = 5728},     /*58.9824MHZ */
+       {.num = 15850, .den = 9451},    /*59.429MHZ */
+};
+
+static const char *uart_parent[] = {"uart_pll", "vctcxo"};
+static const char *ssp_parent[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"};
+static const char *sdh_parent[] = {"pll1_4", "pll2", "usb_pll", "pll1"};
+static const char *disp_parent[] = {"pll1", "pll1_16", "pll2", "vctcxo"};
+static const char *ccic_parent[] = {"pll1_2", "pll1_16", "vctcxo"};
+
+void __init mmp2_clk_init(void)
+{
+       struct clk *clk;
+       struct clk *vctcxo;
+       void __iomem *mpmu_base;
+       void __iomem *apmu_base;
+       void __iomem *apbc_base;
+
+       mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K);
+       if (mpmu_base == NULL) {
+               pr_err("error to ioremap MPMU base\n");
+               return;
+       }
+
+       apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K);
+       if (apmu_base == NULL) {
+               pr_err("error to ioremap APMU base\n");
+               return;
+       }
+
+       apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K);
+       if (apbc_base == NULL) {
+               pr_err("error to ioremap APBC base\n");
+               return;
+       }
+
+       clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200);
+       clk_register_clkdev(clk, "clk32", NULL);
+
+       vctcxo = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT,
+                               26000000);
+       clk_register_clkdev(vctcxo, "vctcxo", NULL);
+
+       clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT,
+                               800000000);
+       clk_register_clkdev(clk, "pll1", NULL);
+
+       clk = clk_register_fixed_rate(NULL, "usb_pll", NULL, CLK_IS_ROOT,
+                               480000000);
+       clk_register_clkdev(clk, "usb_pll", NULL);
+
+       clk = clk_register_fixed_rate(NULL, "pll2", NULL, CLK_IS_ROOT,
+                               960000000);
+       clk_register_clkdev(clk, "pll2", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_2", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_4", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_8", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_16", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_20", "pll1_4",
+                               CLK_SET_RATE_PARENT, 1, 5);
+       clk_register_clkdev(clk, "pll1_20", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_3", "pll1",
+                               CLK_SET_RATE_PARENT, 1, 3);
+       clk_register_clkdev(clk, "pll1_3", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_3",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_6", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_12", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll2_2", "pll2",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll2_2", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll2_4", "pll2_2",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll2_4", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll2_8", "pll2_4",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll2_8", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll2_16", "pll2_8",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll2_16", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll2_3", "pll2",
+                               CLK_SET_RATE_PARENT, 1, 3);
+       clk_register_clkdev(clk, "pll2_3", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll2_6", "pll2_3",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll2_6", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll2_12", "pll2_6",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll2_12", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "vctcxo_2", "vctcxo",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "vctcxo_2", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "vctcxo_4", "vctcxo_2",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "vctcxo_4", NULL);
+
+       clk = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
+                               mpmu_base + MPMU_UART_PLL,
+                               &uart_factor_masks, uart_factor_tbl,
+                               ARRAY_SIZE(uart_factor_tbl));
+       clk_set_rate(clk, 14745600);
+       clk_register_clkdev(clk, "uart_pll", NULL);
+
+       clk = mmp_clk_register_apbc("twsi0", "vctcxo",
+                               apbc_base + APBC_TWSI0, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0");
+
+       clk = mmp_clk_register_apbc("twsi1", "vctcxo",
+                               apbc_base + APBC_TWSI1, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1");
+
+       clk = mmp_clk_register_apbc("twsi2", "vctcxo",
+                               apbc_base + APBC_TWSI2, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-i2c.2");
+
+       clk = mmp_clk_register_apbc("twsi3", "vctcxo",
+                               apbc_base + APBC_TWSI3, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-i2c.3");
+
+       clk = mmp_clk_register_apbc("twsi4", "vctcxo",
+                               apbc_base + APBC_TWSI4, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-i2c.4");
+
+       clk = mmp_clk_register_apbc("twsi5", "vctcxo",
+                               apbc_base + APBC_TWSI5, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-i2c.5");
+
+       clk = mmp_clk_register_apbc("gpio", "vctcxo",
+                               apbc_base + APBC_GPIO, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa-gpio");
+
+       clk = mmp_clk_register_apbc("kpc", "clk32",
+                               apbc_base + APBC_KPC, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa27x-keypad");
+
+       clk = mmp_clk_register_apbc("rtc", "clk32",
+                               apbc_base + APBC_RTC, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-rtc");
+
+       clk = mmp_clk_register_apbc("pwm0", "vctcxo",
+                               apbc_base + APBC_PWM0, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp2-pwm.0");
+
+       clk = mmp_clk_register_apbc("pwm1", "vctcxo",
+                               apbc_base + APBC_PWM1, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp2-pwm.1");
+
+       clk = mmp_clk_register_apbc("pwm2", "vctcxo",
+                               apbc_base + APBC_PWM2, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp2-pwm.2");
+
+       clk = mmp_clk_register_apbc("pwm3", "vctcxo",
+                               apbc_base + APBC_PWM3, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp2-pwm.3");
+
+       clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
+                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
+       clk_set_parent(clk, vctcxo);
+       clk_register_clkdev(clk, "uart_mux.0", NULL);
+
+       clk = mmp_clk_register_apbc("uart0", "uart0_mux",
+                               apbc_base + APBC_UART0, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
+
+       clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
+                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
+       clk_set_parent(clk, vctcxo);
+       clk_register_clkdev(clk, "uart_mux.1", NULL);
+
+       clk = mmp_clk_register_apbc("uart1", "uart1_mux",
+                               apbc_base + APBC_UART1, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
+
+       clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
+                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_UART2, 4, 3, 0, &clk_lock);
+       clk_set_parent(clk, vctcxo);
+       clk_register_clkdev(clk, "uart_mux.2", NULL);
+
+       clk = mmp_clk_register_apbc("uart2", "uart2_mux",
+                               apbc_base + APBC_UART2, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
+
+       clk = clk_register_mux(NULL, "uart3_mux", uart_parent,
+                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_UART3, 4, 3, 0, &clk_lock);
+       clk_set_parent(clk, vctcxo);
+       clk_register_clkdev(clk, "uart_mux.3", NULL);
+
+       clk = mmp_clk_register_apbc("uart3", "uart3_mux",
+                               apbc_base + APBC_UART3, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-uart.3");
+
+       clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
+                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
+       clk_register_clkdev(clk, "uart_mux.0", NULL);
+
+       clk = mmp_clk_register_apbc("ssp0", "ssp0_mux",
+                               apbc_base + APBC_SSP0, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-ssp.0");
+
+       clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
+                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
+       clk_register_clkdev(clk, "ssp_mux.1", NULL);
+
+       clk = mmp_clk_register_apbc("ssp1", "ssp1_mux",
+                               apbc_base + APBC_SSP1, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-ssp.1");
+
+       clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent,
+                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock);
+       clk_register_clkdev(clk, "ssp_mux.2", NULL);
+
+       clk = mmp_clk_register_apbc("ssp2", "ssp2_mux",
+                               apbc_base + APBC_SSP2, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-ssp.2");
+
+       clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent,
+                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock);
+       clk_register_clkdev(clk, "ssp_mux.3", NULL);
+
+       clk = mmp_clk_register_apbc("ssp3", "ssp3_mux",
+                               apbc_base + APBC_SSP3, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-ssp.3");
+
+       clk = clk_register_mux(NULL, "sdh_mux", sdh_parent,
+                               ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+                               apmu_base + APMU_SDH0, 8, 2, 0, &clk_lock);
+       clk_register_clkdev(clk, "sdh_mux", NULL);
+
+       clk = clk_register_divider(NULL, "sdh_div", "sdh_mux",
+                               CLK_SET_RATE_PARENT, apmu_base + APMU_SDH0,
+                               10, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
+       clk_register_clkdev(clk, "sdh_div", NULL);
+
+       clk = mmp_clk_register_apmu("sdh0", "sdh_div", apmu_base + APMU_SDH0,
+                               0x1b, &clk_lock);
+       clk_register_clkdev(clk, NULL, "sdhci-pxav3.0");
+
+       clk = mmp_clk_register_apmu("sdh1", "sdh_div", apmu_base + APMU_SDH1,
+                               0x1b, &clk_lock);
+       clk_register_clkdev(clk, NULL, "sdhci-pxav3.1");
+
+       clk = mmp_clk_register_apmu("sdh2", "sdh_div", apmu_base + APMU_SDH2,
+                               0x1b, &clk_lock);
+       clk_register_clkdev(clk, NULL, "sdhci-pxav3.2");
+
+       clk = mmp_clk_register_apmu("sdh3", "sdh_div", apmu_base + APMU_SDH3,
+                               0x1b, &clk_lock);
+       clk_register_clkdev(clk, NULL, "sdhci-pxav3.3");
+
+       clk = mmp_clk_register_apmu("usb", "usb_pll", apmu_base + APMU_USB,
+                               0x9, &clk_lock);
+       clk_register_clkdev(clk, "usb_clk", NULL);
+
+       clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
+                               ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+                               apmu_base + APMU_DISP0, 6, 2, 0, &clk_lock);
+       clk_register_clkdev(clk, "disp_mux.0", NULL);
+
+       clk = clk_register_divider(NULL, "disp0_div", "disp0_mux",
+                               CLK_SET_RATE_PARENT, apmu_base + APMU_DISP0,
+                               8, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
+       clk_register_clkdev(clk, "disp_div.0", NULL);
+
+       clk = mmp_clk_register_apmu("disp0", "disp0_div",
+                               apmu_base + APMU_DISP0, 0x1b, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-disp.0");
+
+       clk = clk_register_divider(NULL, "disp0_sphy_div", "disp0_mux", 0,
+                               apmu_base + APMU_DISP0, 15, 5, 0, &clk_lock);
+       clk_register_clkdev(clk, "disp_sphy_div.0", NULL);
+
+       clk = mmp_clk_register_apmu("disp0_sphy", "disp0_sphy_div",
+                               apmu_base + APMU_DISP0, 0x1024, &clk_lock);
+       clk_register_clkdev(clk, "disp_sphy.0", NULL);
+
+       clk = clk_register_mux(NULL, "disp1_mux", disp_parent,
+                               ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+                               apmu_base + APMU_DISP1, 6, 2, 0, &clk_lock);
+       clk_register_clkdev(clk, "disp_mux.1", NULL);
+
+       clk = clk_register_divider(NULL, "disp1_div", "disp1_mux",
+                               CLK_SET_RATE_PARENT, apmu_base + APMU_DISP1,
+                               8, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
+       clk_register_clkdev(clk, "disp_div.1", NULL);
+
+       clk = mmp_clk_register_apmu("disp1", "disp1_div",
+                               apmu_base + APMU_DISP1, 0x1b, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-disp.1");
+
+       clk = mmp_clk_register_apmu("ccic_arbiter", "vctcxo",
+                               apmu_base + APMU_CCIC0, 0x1800, &clk_lock);
+       clk_register_clkdev(clk, "ccic_arbiter", NULL);
+
+       clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
+                               ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+                               apmu_base + APMU_CCIC0, 6, 2, 0, &clk_lock);
+       clk_register_clkdev(clk, "ccic_mux.0", NULL);
+
+       clk = clk_register_divider(NULL, "ccic0_div", "ccic0_mux",
+                               CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
+                               17, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
+       clk_register_clkdev(clk, "ccic_div.0", NULL);
+
+       clk = mmp_clk_register_apmu("ccic0", "ccic0_div",
+                               apmu_base + APMU_CCIC0, 0x1b, &clk_lock);
+       clk_register_clkdev(clk, "fnclk", "mmp-ccic.0");
+
+       clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_div",
+                               apmu_base + APMU_CCIC0, 0x24, &clk_lock);
+       clk_register_clkdev(clk, "phyclk", "mmp-ccic.0");
+
+       clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_div",
+                               CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
+                               10, 5, 0, &clk_lock);
+       clk_register_clkdev(clk, "sphyclk_div", "mmp-ccic.0");
+
+       clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div",
+                               apmu_base + APMU_CCIC0, 0x300, &clk_lock);
+       clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0");
+
+       clk = clk_register_mux(NULL, "ccic1_mux", ccic_parent,
+                               ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+                               apmu_base + APMU_CCIC1, 6, 2, 0, &clk_lock);
+       clk_register_clkdev(clk, "ccic_mux.1", NULL);
+
+       clk = clk_register_divider(NULL, "ccic1_div", "ccic1_mux",
+                               CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC1,
+                               16, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
+       clk_register_clkdev(clk, "ccic_div.1", NULL);
+
+       clk = mmp_clk_register_apmu("ccic1", "ccic1_div",
+                               apmu_base + APMU_CCIC1, 0x1b, &clk_lock);
+       clk_register_clkdev(clk, "fnclk", "mmp-ccic.1");
+
+       clk = mmp_clk_register_apmu("ccic1_phy", "ccic1_div",
+                               apmu_base + APMU_CCIC1, 0x24, &clk_lock);
+       clk_register_clkdev(clk, "phyclk", "mmp-ccic.1");
+
+       clk = clk_register_divider(NULL, "ccic1_sphy_div", "ccic1_div",
+                               CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC1,
+                               10, 5, 0, &clk_lock);
+       clk_register_clkdev(clk, "sphyclk_div", "mmp-ccic.1");
+
+       clk = mmp_clk_register_apmu("ccic1_sphy", "ccic1_sphy_div",
+                               apmu_base + APMU_CCIC1, 0x300, &clk_lock);
+       clk_register_clkdev(clk, "sphyclk", "mmp-ccic.1");
+}
diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c
new file mode 100644 (file)
index 0000000..e8d036c
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * pxa168 clock framework source file
+ *
+ * Copyright (C) 2012 Marvell
+ * Chao Xie <xiechao.mail@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <mach/addr-map.h>
+
+#include "clk.h"
+
+#define APBC_RTC       0x28
+#define APBC_TWSI0     0x2c
+#define APBC_KPC       0x30
+#define APBC_UART0     0x0
+#define APBC_UART1     0x4
+#define APBC_GPIO      0x8
+#define APBC_PWM0      0xc
+#define APBC_PWM1      0x10
+#define APBC_PWM2      0x14
+#define APBC_PWM3      0x18
+#define APBC_SSP0      0x81c
+#define APBC_SSP1      0x820
+#define APBC_SSP2      0x84c
+#define APBC_SSP3      0x858
+#define APBC_SSP4      0x85c
+#define APBC_TWSI1     0x6c
+#define APBC_UART2     0x70
+#define APMU_SDH0      0x54
+#define APMU_SDH1      0x58
+#define APMU_USB       0x5c
+#define APMU_DISP0     0x4c
+#define APMU_CCIC0     0x50
+#define APMU_DFC       0x60
+#define MPMU_UART_PLL  0x14
+
+static DEFINE_SPINLOCK(clk_lock);
+
+static struct clk_factor_masks uart_factor_masks = {
+       .factor = 2,
+       .num_mask = 0x1fff,
+       .den_mask = 0x1fff,
+       .num_shift = 16,
+       .den_shift = 0,
+};
+
+static struct clk_factor_tbl uart_factor_tbl[] = {
+       {.num = 8125, .den = 1536},     /*14.745MHZ */
+};
+
+static const char *uart_parent[] = {"pll1_3_16", "uart_pll"};
+static const char *ssp_parent[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
+static const char *sdh_parent[] = {"pll1_12", "pll1_13"};
+static const char *disp_parent[] = {"pll1_2", "pll1_12"};
+static const char *ccic_parent[] = {"pll1_2", "pll1_12"};
+static const char *ccic_phy_parent[] = {"pll1_6", "pll1_12"};
+
+void __init pxa168_clk_init(void)
+{
+       struct clk *clk;
+       struct clk *uart_pll;
+       void __iomem *mpmu_base;
+       void __iomem *apmu_base;
+       void __iomem *apbc_base;
+
+       mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K);
+       if (mpmu_base == NULL) {
+               pr_err("error to ioremap MPMU base\n");
+               return;
+       }
+
+       apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K);
+       if (apmu_base == NULL) {
+               pr_err("error to ioremap APMU base\n");
+               return;
+       }
+
+       apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K);
+       if (apbc_base == NULL) {
+               pr_err("error to ioremap APBC base\n");
+               return;
+       }
+
+       clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200);
+       clk_register_clkdev(clk, "clk32", NULL);
+
+       clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT,
+                               26000000);
+       clk_register_clkdev(clk, "vctcxo", NULL);
+
+       clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT,
+                               624000000);
+       clk_register_clkdev(clk, "pll1", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_2", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_4", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_8", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_16", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_2",
+                               CLK_SET_RATE_PARENT, 1, 3);
+       clk_register_clkdev(clk, "pll1_6", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_12", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_24", "pll1_12",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_24", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_48", "pll1_24",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_48", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_96", "pll1_48",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_96", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_13", "pll1",
+                               CLK_SET_RATE_PARENT, 1, 13);
+       clk_register_clkdev(clk, "pll1_13", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_13_1_5", "pll1",
+                               CLK_SET_RATE_PARENT, 2, 3);
+       clk_register_clkdev(clk, "pll1_13_1_5", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_2_1_5", "pll1",
+                               CLK_SET_RATE_PARENT, 2, 3);
+       clk_register_clkdev(clk, "pll1_2_1_5", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_3_16", "pll1",
+                               CLK_SET_RATE_PARENT, 3, 16);
+       clk_register_clkdev(clk, "pll1_3_16", NULL);
+
+       uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
+                               mpmu_base + MPMU_UART_PLL,
+                               &uart_factor_masks, uart_factor_tbl,
+                               ARRAY_SIZE(uart_factor_tbl));
+       clk_set_rate(uart_pll, 14745600);
+       clk_register_clkdev(uart_pll, "uart_pll", NULL);
+
+       clk = mmp_clk_register_apbc("twsi0", "pll1_13_1_5",
+                               apbc_base + APBC_TWSI0, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0");
+
+       clk = mmp_clk_register_apbc("twsi1", "pll1_13_1_5",
+                               apbc_base + APBC_TWSI1, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1");
+
+       clk = mmp_clk_register_apbc("gpio", "vctcxo",
+                               apbc_base + APBC_GPIO, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa-gpio");
+
+       clk = mmp_clk_register_apbc("kpc", "clk32",
+                               apbc_base + APBC_KPC, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa27x-keypad");
+
+       clk = mmp_clk_register_apbc("rtc", "clk32",
+                               apbc_base + APBC_RTC, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "sa1100-rtc");
+
+       clk = mmp_clk_register_apbc("pwm0", "pll1_48",
+                               apbc_base + APBC_PWM0, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa168-pwm.0");
+
+       clk = mmp_clk_register_apbc("pwm1", "pll1_48",
+                               apbc_base + APBC_PWM1, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa168-pwm.1");
+
+       clk = mmp_clk_register_apbc("pwm2", "pll1_48",
+                               apbc_base + APBC_PWM2, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa168-pwm.2");
+
+       clk = mmp_clk_register_apbc("pwm3", "pll1_48",
+                               apbc_base + APBC_PWM3, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa168-pwm.3");
+
+       clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
+                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
+       clk_set_parent(clk, uart_pll);
+       clk_register_clkdev(clk, "uart_mux.0", NULL);
+
+       clk = mmp_clk_register_apbc("uart0", "uart0_mux",
+                               apbc_base + APBC_UART0, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
+
+       clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
+                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
+       clk_set_parent(clk, uart_pll);
+       clk_register_clkdev(clk, "uart_mux.1", NULL);
+
+       clk = mmp_clk_register_apbc("uart1", "uart1_mux",
+                               apbc_base + APBC_UART1, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
+
+       clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
+                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_UART2, 4, 3, 0, &clk_lock);
+       clk_set_parent(clk, uart_pll);
+       clk_register_clkdev(clk, "uart_mux.2", NULL);
+
+       clk = mmp_clk_register_apbc("uart2", "uart2_mux",
+                               apbc_base + APBC_UART2, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
+
+       clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
+                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
+       clk_register_clkdev(clk, "uart_mux.0", NULL);
+
+       clk = mmp_clk_register_apbc("ssp0", "ssp0_mux", apbc_base + APBC_SSP0,
+                               10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-ssp.0");
+
+       clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
+                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
+       clk_register_clkdev(clk, "ssp_mux.1", NULL);
+
+       clk = mmp_clk_register_apbc("ssp1", "ssp1_mux", apbc_base + APBC_SSP1,
+                               10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-ssp.1");
+
+       clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent,
+                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock);
+       clk_register_clkdev(clk, "ssp_mux.2", NULL);
+
+       clk = mmp_clk_register_apbc("ssp2", "ssp1_mux", apbc_base + APBC_SSP2,
+                               10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-ssp.2");
+
+       clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent,
+                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock);
+       clk_register_clkdev(clk, "ssp_mux.3", NULL);
+
+       clk = mmp_clk_register_apbc("ssp3", "ssp1_mux", apbc_base + APBC_SSP3,
+                               10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-ssp.3");
+
+       clk = clk_register_mux(NULL, "ssp4_mux", ssp_parent,
+                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_SSP4, 4, 3, 0, &clk_lock);
+       clk_register_clkdev(clk, "ssp_mux.4", NULL);
+
+       clk = mmp_clk_register_apbc("ssp4", "ssp1_mux", apbc_base + APBC_SSP4,
+                               10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-ssp.4");
+
+       clk = mmp_clk_register_apmu("dfc", "pll1_4", apmu_base + APMU_DFC,
+                               0x19b, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa3xx-nand.0");
+
+       clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent,
+                               ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+                               apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock);
+       clk_register_clkdev(clk, "sdh0_mux", NULL);
+
+       clk = mmp_clk_register_apmu("sdh0", "sdh_mux", apmu_base + APMU_SDH0,
+                               0x1b, &clk_lock);
+       clk_register_clkdev(clk, NULL, "sdhci-pxa.0");
+
+       clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent,
+                               ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+                               apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock);
+       clk_register_clkdev(clk, "sdh1_mux", NULL);
+
+       clk = mmp_clk_register_apmu("sdh1", "sdh1_mux", apmu_base + APMU_SDH1,
+                               0x1b, &clk_lock);
+       clk_register_clkdev(clk, NULL, "sdhci-pxa.1");
+
+       clk = mmp_clk_register_apmu("usb", "usb_pll", apmu_base + APMU_USB,
+                               0x9, &clk_lock);
+       clk_register_clkdev(clk, "usb_clk", NULL);
+
+       clk = mmp_clk_register_apmu("sph", "usb_pll", apmu_base + APMU_USB,
+                               0x12, &clk_lock);
+       clk_register_clkdev(clk, "sph_clk", NULL);
+
+       clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
+                               ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+                               apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock);
+       clk_register_clkdev(clk, "disp_mux.0", NULL);
+
+       clk = mmp_clk_register_apmu("disp0", "disp0_mux",
+                               apmu_base + APMU_DISP0, 0x1b, &clk_lock);
+       clk_register_clkdev(clk, "fnclk", "mmp-disp.0");
+
+       clk = mmp_clk_register_apmu("disp0_hclk", "disp0_mux",
+                               apmu_base + APMU_DISP0, 0x24, &clk_lock);
+       clk_register_clkdev(clk, "hclk", "mmp-disp.0");
+
+       clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
+                               ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+                               apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock);
+       clk_register_clkdev(clk, "ccic_mux.0", NULL);
+
+       clk = mmp_clk_register_apmu("ccic0", "ccic0_mux",
+                               apmu_base + APMU_CCIC0, 0x1b, &clk_lock);
+       clk_register_clkdev(clk, "fnclk", "mmp-ccic.0");
+
+       clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent,
+                               ARRAY_SIZE(ccic_phy_parent),
+                               CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
+                               7, 1, 0, &clk_lock);
+       clk_register_clkdev(clk, "ccic_phy_mux.0", NULL);
+
+       clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux",
+                               apmu_base + APMU_CCIC0, 0x24, &clk_lock);
+       clk_register_clkdev(clk, "phyclk", "mmp-ccic.0");
+
+       clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_mux",
+                               CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
+                               10, 5, 0, &clk_lock);
+       clk_register_clkdev(clk, "sphyclk_div", NULL);
+
+       clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div",
+                               apmu_base + APMU_CCIC0, 0x300, &clk_lock);
+       clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0");
+}
diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c
new file mode 100644 (file)
index 0000000..7048c31
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * pxa910 clock framework source file
+ *
+ * Copyright (C) 2012 Marvell
+ * Chao Xie <xiechao.mail@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <mach/addr-map.h>
+
+#include "clk.h"
+
+#define APBC_RTC       0x28
+#define APBC_TWSI0     0x2c
+#define APBC_KPC       0x18
+#define APBC_UART0     0x0
+#define APBC_UART1     0x4
+#define APBC_GPIO      0x8
+#define APBC_PWM0      0xc
+#define APBC_PWM1      0x10
+#define APBC_PWM2      0x14
+#define APBC_PWM3      0x18
+#define APBC_SSP0      0x1c
+#define APBC_SSP1      0x20
+#define APBC_SSP2      0x4c
+#define APBCP_TWSI1    0x28
+#define APBCP_UART2    0x1c
+#define APMU_SDH0      0x54
+#define APMU_SDH1      0x58
+#define APMU_USB       0x5c
+#define APMU_DISP0     0x4c
+#define APMU_CCIC0     0x50
+#define APMU_DFC       0x60
+#define MPMU_UART_PLL  0x14
+
+static DEFINE_SPINLOCK(clk_lock);
+
+static struct clk_factor_masks uart_factor_masks = {
+       .factor = 2,
+       .num_mask = 0x1fff,
+       .den_mask = 0x1fff,
+       .num_shift = 16,
+       .den_shift = 0,
+};
+
+static struct clk_factor_tbl uart_factor_tbl[] = {
+       {.num = 8125, .den = 1536},     /*14.745MHZ */
+};
+
+static const char *uart_parent[] = {"pll1_3_16", "uart_pll"};
+static const char *ssp_parent[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
+static const char *sdh_parent[] = {"pll1_12", "pll1_13"};
+static const char *disp_parent[] = {"pll1_2", "pll1_12"};
+static const char *ccic_parent[] = {"pll1_2", "pll1_12"};
+static const char *ccic_phy_parent[] = {"pll1_6", "pll1_12"};
+
+void __init pxa910_clk_init(void)
+{
+       struct clk *clk;
+       struct clk *uart_pll;
+       void __iomem *mpmu_base;
+       void __iomem *apmu_base;
+       void __iomem *apbcp_base;
+       void __iomem *apbc_base;
+
+       mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K);
+       if (mpmu_base == NULL) {
+               pr_err("error to ioremap MPMU base\n");
+               return;
+       }
+
+       apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K);
+       if (apmu_base == NULL) {
+               pr_err("error to ioremap APMU base\n");
+               return;
+       }
+
+       apbcp_base = ioremap(APB_PHYS_BASE + 0x3b000, SZ_4K);
+       if (apbcp_base == NULL) {
+               pr_err("error to ioremap APBC extension base\n");
+               return;
+       }
+
+       apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K);
+       if (apbc_base == NULL) {
+               pr_err("error to ioremap APBC base\n");
+               return;
+       }
+
+       clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200);
+       clk_register_clkdev(clk, "clk32", NULL);
+
+       clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT,
+                               26000000);
+       clk_register_clkdev(clk, "vctcxo", NULL);
+
+       clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT,
+                               624000000);
+       clk_register_clkdev(clk, "pll1", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_2", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_4", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_8", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_16", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_2",
+                               CLK_SET_RATE_PARENT, 1, 3);
+       clk_register_clkdev(clk, "pll1_6", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_12", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_24", "pll1_12",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_24", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_48", "pll1_24",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_48", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_96", "pll1_48",
+                               CLK_SET_RATE_PARENT, 1, 2);
+       clk_register_clkdev(clk, "pll1_96", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_13", "pll1",
+                               CLK_SET_RATE_PARENT, 1, 13);
+       clk_register_clkdev(clk, "pll1_13", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_13_1_5", "pll1",
+                               CLK_SET_RATE_PARENT, 2, 3);
+       clk_register_clkdev(clk, "pll1_13_1_5", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_2_1_5", "pll1",
+                               CLK_SET_RATE_PARENT, 2, 3);
+       clk_register_clkdev(clk, "pll1_2_1_5", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "pll1_3_16", "pll1",
+                               CLK_SET_RATE_PARENT, 3, 16);
+       clk_register_clkdev(clk, "pll1_3_16", NULL);
+
+       uart_pll =  mmp_clk_register_factor("uart_pll", "pll1_4", 0,
+                               mpmu_base + MPMU_UART_PLL,
+                               &uart_factor_masks, uart_factor_tbl,
+                               ARRAY_SIZE(uart_factor_tbl));
+       clk_set_rate(uart_pll, 14745600);
+       clk_register_clkdev(uart_pll, "uart_pll", NULL);
+
+       clk = mmp_clk_register_apbc("twsi0", "pll1_13_1_5",
+                               apbc_base + APBC_TWSI0, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0");
+
+       clk = mmp_clk_register_apbc("twsi1", "pll1_13_1_5",
+                               apbcp_base + APBCP_TWSI1, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1");
+
+       clk = mmp_clk_register_apbc("gpio", "vctcxo",
+                               apbc_base + APBC_GPIO, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa-gpio");
+
+       clk = mmp_clk_register_apbc("kpc", "clk32",
+                               apbc_base + APBC_KPC, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa27x-keypad");
+
+       clk = mmp_clk_register_apbc("rtc", "clk32",
+                               apbc_base + APBC_RTC, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "sa1100-rtc");
+
+       clk = mmp_clk_register_apbc("pwm0", "pll1_48",
+                               apbc_base + APBC_PWM0, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa910-pwm.0");
+
+       clk = mmp_clk_register_apbc("pwm1", "pll1_48",
+                               apbc_base + APBC_PWM1, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa910-pwm.1");
+
+       clk = mmp_clk_register_apbc("pwm2", "pll1_48",
+                               apbc_base + APBC_PWM2, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa910-pwm.2");
+
+       clk = mmp_clk_register_apbc("pwm3", "pll1_48",
+                               apbc_base + APBC_PWM3, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa910-pwm.3");
+
+       clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
+                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
+       clk_set_parent(clk, uart_pll);
+       clk_register_clkdev(clk, "uart_mux.0", NULL);
+
+       clk = mmp_clk_register_apbc("uart0", "uart0_mux",
+                               apbc_base + APBC_UART0, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
+
+       clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
+                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
+       clk_set_parent(clk, uart_pll);
+       clk_register_clkdev(clk, "uart_mux.1", NULL);
+
+       clk = mmp_clk_register_apbc("uart1", "uart1_mux",
+                               apbc_base + APBC_UART1, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
+
+       clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
+                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               apbcp_base + APBCP_UART2, 4, 3, 0, &clk_lock);
+       clk_set_parent(clk, uart_pll);
+       clk_register_clkdev(clk, "uart_mux.2", NULL);
+
+       clk = mmp_clk_register_apbc("uart2", "uart2_mux",
+                               apbcp_base + APBCP_UART2, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
+
+       clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
+                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
+       clk_register_clkdev(clk, "uart_mux.0", NULL);
+
+       clk = mmp_clk_register_apbc("ssp0", "ssp0_mux",
+                               apbc_base + APBC_SSP0, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-ssp.0");
+
+       clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
+                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
+       clk_register_clkdev(clk, "ssp_mux.1", NULL);
+
+       clk = mmp_clk_register_apbc("ssp1", "ssp1_mux",
+                               apbc_base + APBC_SSP1, 10, 0, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-ssp.1");
+
+       clk = mmp_clk_register_apmu("dfc", "pll1_4",
+                               apmu_base + APMU_DFC, 0x19b, &clk_lock);
+       clk_register_clkdev(clk, NULL, "pxa3xx-nand.0");
+
+       clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent,
+                               ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+                               apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock);
+       clk_register_clkdev(clk, "sdh0_mux", NULL);
+
+       clk = mmp_clk_register_apmu("sdh0", "sdh_mux",
+                               apmu_base + APMU_SDH0, 0x1b, &clk_lock);
+       clk_register_clkdev(clk, NULL, "sdhci-pxa.0");
+
+       clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent,
+                               ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+                               apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock);
+       clk_register_clkdev(clk, "sdh1_mux", NULL);
+
+       clk = mmp_clk_register_apmu("sdh1", "sdh1_mux",
+                               apmu_base + APMU_SDH1, 0x1b, &clk_lock);
+       clk_register_clkdev(clk, NULL, "sdhci-pxa.1");
+
+       clk = mmp_clk_register_apmu("usb", "usb_pll",
+                               apmu_base + APMU_USB, 0x9, &clk_lock);
+       clk_register_clkdev(clk, "usb_clk", NULL);
+
+       clk = mmp_clk_register_apmu("sph", "usb_pll",
+                               apmu_base + APMU_USB, 0x12, &clk_lock);
+       clk_register_clkdev(clk, "sph_clk", NULL);
+
+       clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
+                               ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+                               apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock);
+       clk_register_clkdev(clk, "disp_mux.0", NULL);
+
+       clk = mmp_clk_register_apmu("disp0", "disp0_mux",
+                               apmu_base + APMU_DISP0, 0x1b, &clk_lock);
+       clk_register_clkdev(clk, NULL, "mmp-disp.0");
+
+       clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
+                               ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+                               apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock);
+       clk_register_clkdev(clk, "ccic_mux.0", NULL);
+
+       clk = mmp_clk_register_apmu("ccic0", "ccic0_mux",
+                               apmu_base + APMU_CCIC0, 0x1b, &clk_lock);
+       clk_register_clkdev(clk, "fnclk", "mmp-ccic.0");
+
+       clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent,
+                               ARRAY_SIZE(ccic_phy_parent),
+                               CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
+                               7, 1, 0, &clk_lock);
+       clk_register_clkdev(clk, "ccic_phy_mux.0", NULL);
+
+       clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux",
+                               apmu_base + APMU_CCIC0, 0x24, &clk_lock);
+       clk_register_clkdev(clk, "phyclk", "mmp-ccic.0");
+
+       clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_mux",
+                               CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
+                               10, 5, 0, &clk_lock);
+       clk_register_clkdev(clk, "sphyclk_div", NULL);
+
+       clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div",
+                               apmu_base + APMU_CCIC0, 0x300, &clk_lock);
+       clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0");
+}
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
new file mode 100644 (file)
index 0000000..ab86dd4
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __MACH_MMP_CLK_H
+#define __MACH_MMP_CLK_H
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+#define APBC_NO_BUS_CTRL       BIT(0)
+#define APBC_POWER_CTRL                BIT(1)
+
+struct clk_factor_masks {
+       unsigned int    factor;
+       unsigned int    num_mask;
+       unsigned int    den_mask;
+       unsigned int    num_shift;
+       unsigned int    den_shift;
+};
+
+struct clk_factor_tbl {
+       unsigned int num;
+       unsigned int den;
+};
+
+extern struct clk *mmp_clk_register_pll2(const char *name,
+               const char *parent_name, unsigned long flags);
+extern struct clk *mmp_clk_register_apbc(const char *name,
+               const char *parent_name, void __iomem *base,
+               unsigned int delay, unsigned int apbc_flags, spinlock_t *lock);
+extern struct clk *mmp_clk_register_apmu(const char *name,
+               const char *parent_name, void __iomem *base, u32 enable_mask,
+               spinlock_t *lock);
+extern struct clk *mmp_clk_register_factor(const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *base, struct clk_factor_masks *masks,
+               struct clk_factor_tbl *ftbl, unsigned int ftbl_cnt);
+#endif
diff --git a/drivers/clk/ux500/Makefile b/drivers/clk/ux500/Makefile
new file mode 100644 (file)
index 0000000..858fbfe
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for ux500 clocks
+#
+
+# Clock types
+obj-y += clk-prcc.o
+obj-y += clk-prcmu.o
+
+# Clock definitions
+obj-y += u8500_clk.o
+obj-y += u9540_clk.o
+obj-y += u8540_clk.o
diff --git a/drivers/clk/ux500/clk-prcc.c b/drivers/clk/ux500/clk-prcc.c
new file mode 100644 (file)
index 0000000..7eee7f7
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * PRCC clock implementation for ux500 platform.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clk-private.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <mach/hardware.h>
+
+#include "clk.h"
+
+#define PRCC_PCKEN                     0x000
+#define PRCC_PCKDIS                    0x004
+#define PRCC_KCKEN                     0x008
+#define PRCC_KCKDIS                    0x00C
+#define PRCC_PCKSR                     0x010
+#define PRCC_KCKSR                     0x014
+
+#define to_clk_prcc(_hw) container_of(_hw, struct clk_prcc, hw)
+
+struct clk_prcc {
+       struct clk_hw hw;
+       void __iomem *base;
+       u32 cg_sel;
+       int is_enabled;
+};
+
+/* PRCC clock operations. */
+
+static int clk_prcc_pclk_enable(struct clk_hw *hw)
+{
+       struct clk_prcc *clk = to_clk_prcc(hw);
+
+       writel(clk->cg_sel, (clk->base + PRCC_PCKEN));
+       while (!(readl(clk->base + PRCC_PCKSR) & clk->cg_sel))
+               cpu_relax();
+
+       clk->is_enabled = 1;
+       return 0;
+}
+
+static void clk_prcc_pclk_disable(struct clk_hw *hw)
+{
+       struct clk_prcc *clk = to_clk_prcc(hw);
+
+       writel(clk->cg_sel, (clk->base + PRCC_PCKDIS));
+       clk->is_enabled = 0;
+}
+
+static int clk_prcc_kclk_enable(struct clk_hw *hw)
+{
+       struct clk_prcc *clk = to_clk_prcc(hw);
+
+       writel(clk->cg_sel, (clk->base + PRCC_KCKEN));
+       while (!(readl(clk->base + PRCC_KCKSR) & clk->cg_sel))
+               cpu_relax();
+
+       clk->is_enabled = 1;
+       return 0;
+}
+
+static void clk_prcc_kclk_disable(struct clk_hw *hw)
+{
+       struct clk_prcc *clk = to_clk_prcc(hw);
+
+       writel(clk->cg_sel, (clk->base + PRCC_KCKDIS));
+       clk->is_enabled = 0;
+}
+
+static int clk_prcc_is_enabled(struct clk_hw *hw)
+{
+       struct clk_prcc *clk = to_clk_prcc(hw);
+       return clk->is_enabled;
+}
+
+static struct clk_ops clk_prcc_pclk_ops = {
+       .enable = clk_prcc_pclk_enable,
+       .disable = clk_prcc_pclk_disable,
+       .is_enabled = clk_prcc_is_enabled,
+};
+
+static struct clk_ops clk_prcc_kclk_ops = {
+       .enable = clk_prcc_kclk_enable,
+       .disable = clk_prcc_kclk_disable,
+       .is_enabled = clk_prcc_is_enabled,
+};
+
+static struct clk *clk_reg_prcc(const char *name,
+                               const char *parent_name,
+                               resource_size_t phy_base,
+                               u32 cg_sel,
+                               unsigned long flags,
+                               struct clk_ops *clk_prcc_ops)
+{
+       struct clk_prcc *clk;
+       struct clk_init_data clk_prcc_init;
+       struct clk *clk_reg;
+
+       if (!name) {
+               pr_err("clk_prcc: %s invalid arguments passed\n", __func__);
+               return ERR_PTR(-EINVAL);
+       }
+
+       clk = kzalloc(sizeof(struct clk_prcc), GFP_KERNEL);
+       if (!clk) {
+               pr_err("clk_prcc: %s could not allocate clk\n", __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       clk->base = ioremap(phy_base, SZ_4K);
+       if (!clk->base)
+               goto free_clk;
+
+       clk->cg_sel = cg_sel;
+       clk->is_enabled = 1;
+
+       clk_prcc_init.name = name;
+       clk_prcc_init.ops = clk_prcc_ops;
+       clk_prcc_init.flags = flags;
+       clk_prcc_init.parent_names = (parent_name ? &parent_name : NULL);
+       clk_prcc_init.num_parents = (parent_name ? 1 : 0);
+       clk->hw.init = &clk_prcc_init;
+
+       clk_reg = clk_register(NULL, &clk->hw);
+       if (IS_ERR_OR_NULL(clk_reg))
+               goto unmap_clk;
+
+       return clk_reg;
+
+unmap_clk:
+       iounmap(clk->base);
+free_clk:
+       kfree(clk);
+       pr_err("clk_prcc: %s failed to register clk\n", __func__);
+       return ERR_PTR(-ENOMEM);
+}
+
+struct clk *clk_reg_prcc_pclk(const char *name,
+                             const char *parent_name,
+                             resource_size_t phy_base,
+                             u32 cg_sel,
+                             unsigned long flags)
+{
+       return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags,
+                       &clk_prcc_pclk_ops);
+}
+
+struct clk *clk_reg_prcc_kclk(const char *name,
+                             const char *parent_name,
+                             resource_size_t phy_base,
+                             u32 cg_sel,
+                             unsigned long flags)
+{
+       return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags,
+                       &clk_prcc_kclk_ops);
+}
diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c
new file mode 100644 (file)
index 0000000..930cdfe
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * PRCMU clock implementation for ux500 platform.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clk-private.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include "clk.h"
+
+#define to_clk_prcmu(_hw) container_of(_hw, struct clk_prcmu, hw)
+
+struct clk_prcmu {
+       struct clk_hw hw;
+       u8 cg_sel;
+       int is_enabled;
+};
+
+/* PRCMU clock operations. */
+
+static int clk_prcmu_prepare(struct clk_hw *hw)
+{
+       struct clk_prcmu *clk = to_clk_prcmu(hw);
+       return prcmu_request_clock(clk->cg_sel, true);
+}
+
+static void clk_prcmu_unprepare(struct clk_hw *hw)
+{
+       struct clk_prcmu *clk = to_clk_prcmu(hw);
+       if (prcmu_request_clock(clk->cg_sel, false))
+               pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
+                       hw->init->name);
+}
+
+static int clk_prcmu_enable(struct clk_hw *hw)
+{
+       struct clk_prcmu *clk = to_clk_prcmu(hw);
+       clk->is_enabled = 1;
+       return 0;
+}
+
+static void clk_prcmu_disable(struct clk_hw *hw)
+{
+       struct clk_prcmu *clk = to_clk_prcmu(hw);
+       clk->is_enabled = 0;
+}
+
+static int clk_prcmu_is_enabled(struct clk_hw *hw)
+{
+       struct clk_prcmu *clk = to_clk_prcmu(hw);
+       return clk->is_enabled;
+}
+
+static unsigned long clk_prcmu_recalc_rate(struct clk_hw *hw,
+                                          unsigned long parent_rate)
+{
+       struct clk_prcmu *clk = to_clk_prcmu(hw);
+       return prcmu_clock_rate(clk->cg_sel);
+}
+
+static long clk_prcmu_round_rate(struct clk_hw *hw, unsigned long rate,
+                                unsigned long *parent_rate)
+{
+       struct clk_prcmu *clk = to_clk_prcmu(hw);
+       return prcmu_round_clock_rate(clk->cg_sel, rate);
+}
+
+static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate,
+                             unsigned long parent_rate)
+{
+       struct clk_prcmu *clk = to_clk_prcmu(hw);
+       return prcmu_set_clock_rate(clk->cg_sel, rate);
+}
+
+static int request_ape_opp100(bool enable)
+{
+       static int reqs;
+       int err = 0;
+
+       if (enable) {
+               if (!reqs)
+                       err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
+                                                       "clock", 100);
+               if (!err)
+                       reqs++;
+       } else {
+               reqs--;
+               if (!reqs)
+                       prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
+                                               "clock");
+       }
+       return err;
+}
+
+static int clk_prcmu_opp_prepare(struct clk_hw *hw)
+{
+       int err;
+       struct clk_prcmu *clk = to_clk_prcmu(hw);
+
+       err = request_ape_opp100(true);
+       if (err) {
+               pr_err("clk_prcmu: %s failed to request APE OPP100 for %s.\n",
+                       __func__, hw->init->name);
+               return err;
+       }
+
+       err = prcmu_request_clock(clk->cg_sel, true);
+       if (err)
+               request_ape_opp100(false);
+
+       return err;
+}
+
+static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
+{
+       struct clk_prcmu *clk = to_clk_prcmu(hw);
+
+       if (prcmu_request_clock(clk->cg_sel, false))
+               goto out_error;
+       if (request_ape_opp100(false))
+               goto out_error;
+       return;
+
+out_error:
+       pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
+               hw->init->name);
+}
+
+static struct clk_ops clk_prcmu_scalable_ops = {
+       .prepare = clk_prcmu_prepare,
+       .unprepare = clk_prcmu_unprepare,
+       .enable = clk_prcmu_enable,
+       .disable = clk_prcmu_disable,
+       .is_enabled = clk_prcmu_is_enabled,
+       .recalc_rate = clk_prcmu_recalc_rate,
+       .round_rate = clk_prcmu_round_rate,
+       .set_rate = clk_prcmu_set_rate,
+};
+
+static struct clk_ops clk_prcmu_gate_ops = {
+       .prepare = clk_prcmu_prepare,
+       .unprepare = clk_prcmu_unprepare,
+       .enable = clk_prcmu_enable,
+       .disable = clk_prcmu_disable,
+       .is_enabled = clk_prcmu_is_enabled,
+       .recalc_rate = clk_prcmu_recalc_rate,
+};
+
+static struct clk_ops clk_prcmu_rate_ops = {
+       .is_enabled = clk_prcmu_is_enabled,
+       .recalc_rate = clk_prcmu_recalc_rate,
+};
+
+static struct clk_ops clk_prcmu_opp_gate_ops = {
+       .prepare = clk_prcmu_opp_prepare,
+       .unprepare = clk_prcmu_opp_unprepare,
+       .enable = clk_prcmu_enable,
+       .disable = clk_prcmu_disable,
+       .is_enabled = clk_prcmu_is_enabled,
+       .recalc_rate = clk_prcmu_recalc_rate,
+};
+
+static struct clk *clk_reg_prcmu(const char *name,
+                                const char *parent_name,
+                                u8 cg_sel,
+                                unsigned long rate,
+                                unsigned long flags,
+                                struct clk_ops *clk_prcmu_ops)
+{
+       struct clk_prcmu *clk;
+       struct clk_init_data clk_prcmu_init;
+       struct clk *clk_reg;
+
+       if (!name) {
+               pr_err("clk_prcmu: %s invalid arguments passed\n", __func__);
+               return ERR_PTR(-EINVAL);
+       }
+
+       clk = kzalloc(sizeof(struct clk_prcmu), GFP_KERNEL);
+       if (!clk) {
+               pr_err("clk_prcmu: %s could not allocate clk\n", __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       clk->cg_sel = cg_sel;
+       clk->is_enabled = 1;
+       /* "rate" can be used for changing the initial frequency */
+       if (rate)
+               prcmu_set_clock_rate(cg_sel, rate);
+
+       clk_prcmu_init.name = name;
+       clk_prcmu_init.ops = clk_prcmu_ops;
+       clk_prcmu_init.flags = flags;
+       clk_prcmu_init.parent_names = (parent_name ? &parent_name : NULL);
+       clk_prcmu_init.num_parents = (parent_name ? 1 : 0);
+       clk->hw.init = &clk_prcmu_init;
+
+       clk_reg = clk_register(NULL, &clk->hw);
+       if (IS_ERR_OR_NULL(clk_reg))
+               goto free_clk;
+
+       return clk_reg;
+
+free_clk:
+       kfree(clk);
+       pr_err("clk_prcmu: %s failed to register clk\n", __func__);
+       return ERR_PTR(-ENOMEM);
+}
+
+struct clk *clk_reg_prcmu_scalable(const char *name,
+                                  const char *parent_name,
+                                  u8 cg_sel,
+                                  unsigned long rate,
+                                  unsigned long flags)
+{
+       return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
+                       &clk_prcmu_scalable_ops);
+}
+
+struct clk *clk_reg_prcmu_gate(const char *name,
+                              const char *parent_name,
+                              u8 cg_sel,
+                              unsigned long flags)
+{
+       return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
+                       &clk_prcmu_gate_ops);
+}
+
+struct clk *clk_reg_prcmu_rate(const char *name,
+                              const char *parent_name,
+                              u8 cg_sel,
+                              unsigned long flags)
+{
+       return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
+                       &clk_prcmu_rate_ops);
+}
+
+struct clk *clk_reg_prcmu_opp_gate(const char *name,
+                                  const char *parent_name,
+                                  u8 cg_sel,
+                                  unsigned long flags)
+{
+       return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
+                       &clk_prcmu_opp_gate_ops);
+}
diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h
new file mode 100644 (file)
index 0000000..836d7d1
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Clocks for ux500 platforms
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __UX500_CLK_H
+#define __UX500_CLK_H
+
+#include <linux/clk.h>
+
+struct clk *clk_reg_prcc_pclk(const char *name,
+                             const char *parent_name,
+                             unsigned int phy_base,
+                             u32 cg_sel,
+                             unsigned long flags);
+
+struct clk *clk_reg_prcc_kclk(const char *name,
+                             const char *parent_name,
+                             unsigned int phy_base,
+                             u32 cg_sel,
+                             unsigned long flags);
+
+struct clk *clk_reg_prcmu_scalable(const char *name,
+                                  const char *parent_name,
+                                  u8 cg_sel,
+                                  unsigned long rate,
+                                  unsigned long flags);
+
+struct clk *clk_reg_prcmu_gate(const char *name,
+                              const char *parent_name,
+                              u8 cg_sel,
+                              unsigned long flags);
+
+struct clk *clk_reg_prcmu_rate(const char *name,
+                              const char *parent_name,
+                              u8 cg_sel,
+                              unsigned long flags);
+
+struct clk *clk_reg_prcmu_opp_gate(const char *name,
+                                  const char *parent_name,
+                                  u8 cg_sel,
+                                  unsigned long flags);
+
+#endif /* __UX500_CLK_H */
diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c
new file mode 100644 (file)
index 0000000..ca4a25e
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ * Clock definitions for u8500 platform.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/platform_data/clk-ux500.h>
+
+#include "clk.h"
+
+void u8500_clk_init(void)
+{
+       struct prcmu_fw_version *fw_version;
+       const char *sgaclk_parent = NULL;
+       struct clk *clk;
+
+       /* Clock sources */
+       clk = clk_reg_prcmu_gate("soc0_pll", NULL, PRCMU_PLLSOC0,
+                               CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+       clk_register_clkdev(clk, "soc0_pll", NULL);
+
+       clk = clk_reg_prcmu_gate("soc1_pll", NULL, PRCMU_PLLSOC1,
+                               CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+       clk_register_clkdev(clk, "soc1_pll", NULL);
+
+       clk = clk_reg_prcmu_gate("ddr_pll", NULL, PRCMU_PLLDDR,
+                               CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+       clk_register_clkdev(clk, "ddr_pll", NULL);
+
+       /* FIXME: Add sys, ulp and int clocks here. */
+
+       clk = clk_register_fixed_rate(NULL, "rtc32k", "NULL",
+                               CLK_IS_ROOT|CLK_IGNORE_UNUSED,
+                               32768);
+       clk_register_clkdev(clk, "clk32k", NULL);
+       clk_register_clkdev(clk, NULL, "rtc-pl031");
+
+       /* PRCMU clocks */
+       fw_version = prcmu_get_fw_version();
+       if (fw_version != NULL) {
+               switch (fw_version->project) {
+               case PRCMU_FW_PROJECT_U8500_C2:
+               case PRCMU_FW_PROJECT_U8520:
+               case PRCMU_FW_PROJECT_U8420:
+                       sgaclk_parent = "soc0_pll";
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if (sgaclk_parent)
+               clk = clk_reg_prcmu_gate("sgclk", sgaclk_parent,
+                                       PRCMU_SGACLK, 0);
+       else
+               clk = clk_reg_prcmu_gate("sgclk", NULL,
+                                       PRCMU_SGACLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "mali");
+
+       clk = clk_reg_prcmu_gate("uartclk", NULL, PRCMU_UARTCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "UART");
+
+       clk = clk_reg_prcmu_gate("msp02clk", NULL, PRCMU_MSP02CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "MSP02");
+
+       clk = clk_reg_prcmu_gate("msp1clk", NULL, PRCMU_MSP1CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "MSP1");
+
+       clk = clk_reg_prcmu_gate("i2cclk", NULL, PRCMU_I2CCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "I2C");
+
+       clk = clk_reg_prcmu_gate("slimclk", NULL, PRCMU_SLIMCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "slim");
+
+       clk = clk_reg_prcmu_gate("per1clk", NULL, PRCMU_PER1CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "PERIPH1");
+
+       clk = clk_reg_prcmu_gate("per2clk", NULL, PRCMU_PER2CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "PERIPH2");
+
+       clk = clk_reg_prcmu_gate("per3clk", NULL, PRCMU_PER3CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "PERIPH3");
+
+       clk = clk_reg_prcmu_gate("per5clk", NULL, PRCMU_PER5CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "PERIPH5");
+
+       clk = clk_reg_prcmu_gate("per6clk", NULL, PRCMU_PER6CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "PERIPH6");
+
+       clk = clk_reg_prcmu_gate("per7clk", NULL, PRCMU_PER7CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "PERIPH7");
+
+       clk = clk_reg_prcmu_scalable("lcdclk", NULL, PRCMU_LCDCLK, 0,
+                               CLK_IS_ROOT|CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "lcd");
+       clk_register_clkdev(clk, "lcd", "mcde");
+
+       clk = clk_reg_prcmu_opp_gate("bmlclk", NULL, PRCMU_BMLCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "bml");
+
+       clk = clk_reg_prcmu_scalable("hsitxclk", NULL, PRCMU_HSITXCLK, 0,
+                               CLK_IS_ROOT|CLK_SET_RATE_GATE);
+
+       clk = clk_reg_prcmu_scalable("hsirxclk", NULL, PRCMU_HSIRXCLK, 0,
+                               CLK_IS_ROOT|CLK_SET_RATE_GATE);
+
+       clk = clk_reg_prcmu_scalable("hdmiclk", NULL, PRCMU_HDMICLK, 0,
+                               CLK_IS_ROOT|CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "hdmi");
+       clk_register_clkdev(clk, "hdmi", "mcde");
+
+       clk = clk_reg_prcmu_gate("apeatclk", NULL, PRCMU_APEATCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "apeat");
+
+       clk = clk_reg_prcmu_gate("apetraceclk", NULL, PRCMU_APETRACECLK,
+                               CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "apetrace");
+
+       clk = clk_reg_prcmu_gate("mcdeclk", NULL, PRCMU_MCDECLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "mcde");
+       clk_register_clkdev(clk, "mcde", "mcde");
+       clk_register_clkdev(clk, "dsisys", "dsilink.0");
+       clk_register_clkdev(clk, "dsisys", "dsilink.1");
+       clk_register_clkdev(clk, "dsisys", "dsilink.2");
+
+       clk = clk_reg_prcmu_opp_gate("ipi2cclk", NULL, PRCMU_IPI2CCLK,
+                               CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "ipi2");
+
+       clk = clk_reg_prcmu_gate("dsialtclk", NULL, PRCMU_DSIALTCLK,
+                               CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "dsialt");
+
+       clk = clk_reg_prcmu_gate("dmaclk", NULL, PRCMU_DMACLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "dma40.0");
+
+       clk = clk_reg_prcmu_gate("b2r2clk", NULL, PRCMU_B2R2CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "b2r2");
+       clk_register_clkdev(clk, NULL, "b2r2_core");
+       clk_register_clkdev(clk, NULL, "U8500-B2R2.0");
+
+       clk = clk_reg_prcmu_scalable("tvclk", NULL, PRCMU_TVCLK, 0,
+                               CLK_IS_ROOT|CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "tv");
+       clk_register_clkdev(clk, "tv", "mcde");
+
+       clk = clk_reg_prcmu_gate("sspclk", NULL, PRCMU_SSPCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "SSP");
+
+       clk = clk_reg_prcmu_gate("rngclk", NULL, PRCMU_RNGCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "rngclk");
+
+       clk = clk_reg_prcmu_gate("uiccclk", NULL, PRCMU_UICCCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "uicc");
+
+       /*
+        * FIXME: The MTU clocks might need some kind of "parent muxed join"
+        * and these have no K-clocks. For now, we ignore the missing
+        * connection to the corresponding P-clocks, p6_mtu0_clk and
+        * p6_mtu1_clk. Instead timclk is used which is the valid parent.
+        */
+       clk = clk_reg_prcmu_gate("timclk", NULL, PRCMU_TIMCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "mtu0");
+       clk_register_clkdev(clk, NULL, "mtu1");
+
+       clk = clk_reg_prcmu_gate("sdmmcclk", NULL, PRCMU_SDMMCCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "sdmmc");
+
+
+       clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk",
+                               PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "dsihs2", "mcde");
+       clk_register_clkdev(clk, "dsihs2", "dsilink.2");
+
+
+       clk = clk_reg_prcmu_scalable("dsi0clk", "dsi_pll",
+                               PRCMU_DSI0CLK, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "dsihs0", "mcde");
+       clk_register_clkdev(clk, "dsihs0", "dsilink.0");
+
+       clk = clk_reg_prcmu_scalable("dsi1clk", "dsi_pll",
+                               PRCMU_DSI1CLK, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "dsihs1", "mcde");
+       clk_register_clkdev(clk, "dsihs1", "dsilink.1");
+
+       clk = clk_reg_prcmu_scalable("dsi0escclk", "tvclk",
+                               PRCMU_DSI0ESCCLK, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "dsilp0", "dsilink.0");
+       clk_register_clkdev(clk, "dsilp0", "mcde");
+
+       clk = clk_reg_prcmu_scalable("dsi1escclk", "tvclk",
+                               PRCMU_DSI1ESCCLK, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "dsilp1", "dsilink.1");
+       clk_register_clkdev(clk, "dsilp1", "mcde");
+
+       clk = clk_reg_prcmu_scalable("dsi2escclk", "tvclk",
+                               PRCMU_DSI2ESCCLK, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "dsilp2", "dsilink.2");
+       clk_register_clkdev(clk, "dsilp2", "mcde");
+
+       clk = clk_reg_prcmu_rate("smp_twd", NULL, PRCMU_ARMSS,
+                               CLK_IS_ROOT|CLK_GET_RATE_NOCACHE|
+                               CLK_IGNORE_UNUSED);
+       clk_register_clkdev(clk, NULL, "smp_twd");
+
+       /*
+        * FIXME: Add special handled PRCMU clocks here:
+        * 1. clk_arm, use PRCMU_ARMCLK.
+        * 2. clkout0yuv, use PRCMU as parent + need regulator + pinctrl.
+        * 3. ab9540_clkout1yuv, see clkout0yuv
+        */
+
+       /* PRCC P-clocks */
+       clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", U8500_CLKRST1_BASE,
+                               BIT(0), 0);
+       clk_register_clkdev(clk, "apb_pclk", "uart0");
+
+       clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", U8500_CLKRST1_BASE,
+                               BIT(1), 0);
+       clk_register_clkdev(clk, "apb_pclk", "uart1");
+
+       clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", U8500_CLKRST1_BASE,
+                               BIT(2), 0);
+       clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", U8500_CLKRST1_BASE,
+                               BIT(3), 0);
+       clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", U8500_CLKRST1_BASE,
+                               BIT(4), 0);
+
+       clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", U8500_CLKRST1_BASE,
+                               BIT(5), 0);
+       clk_register_clkdev(clk, "apb_pclk", "sdi0");
+
+       clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", U8500_CLKRST1_BASE,
+                               BIT(6), 0);
+
+       clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", U8500_CLKRST1_BASE,
+                               BIT(7), 0);
+       clk_register_clkdev(clk, NULL, "spi3");
+
+       clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", U8500_CLKRST1_BASE,
+                               BIT(8), 0);
+
+       clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", U8500_CLKRST1_BASE,
+                               BIT(9), 0);
+       clk_register_clkdev(clk, NULL, "gpio.0");
+       clk_register_clkdev(clk, NULL, "gpio.1");
+       clk_register_clkdev(clk, NULL, "gpioblock0");
+
+       clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", U8500_CLKRST1_BASE,
+                               BIT(10), 0);
+       clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", U8500_CLKRST1_BASE,
+                               BIT(11), 0);
+
+       clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", U8500_CLKRST2_BASE,
+                               BIT(0), 0);
+
+       clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", U8500_CLKRST2_BASE,
+                               BIT(1), 0);
+       clk_register_clkdev(clk, NULL, "spi2");
+
+       clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", U8500_CLKRST2_BASE,
+                               BIT(2), 0);
+       clk_register_clkdev(clk, NULL, "spi1");
+
+       clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", U8500_CLKRST2_BASE,
+                               BIT(3), 0);
+       clk_register_clkdev(clk, NULL, "pwl");
+
+       clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", U8500_CLKRST2_BASE,
+                               BIT(4), 0);
+       clk_register_clkdev(clk, "apb_pclk", "sdi4");
+
+       clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", U8500_CLKRST2_BASE,
+                               BIT(5), 0);
+
+       clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", U8500_CLKRST2_BASE,
+                               BIT(6), 0);
+       clk_register_clkdev(clk, "apb_pclk", "sdi1");
+
+
+       clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", U8500_CLKRST2_BASE,
+                               BIT(7), 0);
+       clk_register_clkdev(clk, "apb_pclk", "sdi3");
+
+       clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", U8500_CLKRST2_BASE,
+                               BIT(8), 0);
+       clk_register_clkdev(clk, NULL, "spi0");
+
+       clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", U8500_CLKRST2_BASE,
+                               BIT(9), 0);
+       clk_register_clkdev(clk, "hsir_hclk", "ste_hsi.0");
+
+       clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", U8500_CLKRST2_BASE,
+                               BIT(10), 0);
+       clk_register_clkdev(clk, "hsit_hclk", "ste_hsi.0");
+
+       clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", U8500_CLKRST2_BASE,
+                               BIT(11), 0);
+       clk_register_clkdev(clk, NULL, "gpio.6");
+       clk_register_clkdev(clk, NULL, "gpio.7");
+       clk_register_clkdev(clk, NULL, "gpioblock1");
+
+       clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", U8500_CLKRST2_BASE,
+                               BIT(11), 0);
+
+       clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", U8500_CLKRST3_BASE,
+                               BIT(0), 0);
+       clk_register_clkdev(clk, NULL, "fsmc");
+
+       clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", U8500_CLKRST3_BASE,
+                               BIT(1), 0);
+       clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", U8500_CLKRST3_BASE,
+                               BIT(2), 0);
+       clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", U8500_CLKRST3_BASE,
+                               BIT(3), 0);
+
+       clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", U8500_CLKRST3_BASE,
+                               BIT(4), 0);
+       clk_register_clkdev(clk, "apb_pclk", "sdi2");
+
+       clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", U8500_CLKRST3_BASE,
+                               BIT(5), 0);
+
+       clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", U8500_CLKRST3_BASE,
+                               BIT(6), 0);
+       clk_register_clkdev(clk, "apb_pclk", "uart2");
+
+       clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", U8500_CLKRST3_BASE,
+                               BIT(7), 0);
+       clk_register_clkdev(clk, "apb_pclk", "sdi5");
+
+       clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", U8500_CLKRST3_BASE,
+                               BIT(8), 0);
+       clk_register_clkdev(clk, NULL, "gpio.2");
+       clk_register_clkdev(clk, NULL, "gpio.3");
+       clk_register_clkdev(clk, NULL, "gpio.4");
+       clk_register_clkdev(clk, NULL, "gpio.5");
+       clk_register_clkdev(clk, NULL, "gpioblock2");
+
+       clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", U8500_CLKRST5_BASE,
+                               BIT(0), 0);
+       clk_register_clkdev(clk, "usb", "musb-ux500.0");
+
+       clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", U8500_CLKRST5_BASE,
+                               BIT(1), 0);
+       clk_register_clkdev(clk, NULL, "gpio.8");
+       clk_register_clkdev(clk, NULL, "gpioblock3");
+
+       clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", U8500_CLKRST6_BASE,
+                               BIT(0), 0);
+
+       clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", U8500_CLKRST6_BASE,
+                               BIT(1), 0);
+       clk_register_clkdev(clk, NULL, "cryp0");
+       clk_register_clkdev(clk, NULL, "cryp1");
+
+       clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", U8500_CLKRST6_BASE,
+                               BIT(2), 0);
+       clk_register_clkdev(clk, NULL, "hash0");
+
+       clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", U8500_CLKRST6_BASE,
+                               BIT(3), 0);
+       clk_register_clkdev(clk, NULL, "pka");
+
+       clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", U8500_CLKRST6_BASE,
+                               BIT(4), 0);
+       clk_register_clkdev(clk, NULL, "hash1");
+
+       clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", U8500_CLKRST6_BASE,
+                               BIT(5), 0);
+       clk_register_clkdev(clk, NULL, "cfgreg");
+
+       clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", U8500_CLKRST6_BASE,
+                               BIT(6), 0);
+       clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", U8500_CLKRST6_BASE,
+                               BIT(7), 0);
+
+       /* PRCC K-clocks
+        *
+        * FIXME: Some drivers requires PERPIH[n| to be automatically enabled
+        * by enabling just the K-clock, even if it is not a valid parent to
+        * the K-clock. Until drivers get fixed we might need some kind of
+        * "parent muxed join".
+        */
+
+       /* Periph1 */
+       clk = clk_reg_prcc_kclk("p1_uart0_kclk", "uartclk",
+                       U8500_CLKRST1_BASE, BIT(0), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "uart0");
+
+       clk = clk_reg_prcc_kclk("p1_uart1_kclk", "uartclk",
+                       U8500_CLKRST1_BASE, BIT(1), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "uart1");
+
+       clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk",
+                       U8500_CLKRST1_BASE, BIT(2), CLK_SET_RATE_GATE);
+       clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk",
+                       U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE);
+       clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk",
+                       U8500_CLKRST1_BASE, BIT(4), CLK_SET_RATE_GATE);
+
+       clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmcclk",
+                       U8500_CLKRST1_BASE, BIT(5), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdi0");
+
+       clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk",
+                       U8500_CLKRST1_BASE, BIT(6), CLK_SET_RATE_GATE);
+       clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk",
+                       U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE);
+       /* FIXME: Redefinition of BIT(3). */
+       clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk",
+                       U8500_CLKRST1_BASE, BIT(9), CLK_SET_RATE_GATE);
+       clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk",
+                       U8500_CLKRST1_BASE, BIT(10), CLK_SET_RATE_GATE);
+
+       /* Periph2 */
+       clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk",
+                       U8500_CLKRST2_BASE, BIT(0), CLK_SET_RATE_GATE);
+
+       clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmcclk",
+                       U8500_CLKRST2_BASE, BIT(2), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdi4");
+
+       clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk",
+                       U8500_CLKRST2_BASE, BIT(3), CLK_SET_RATE_GATE);
+
+       clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmcclk",
+                       U8500_CLKRST2_BASE, BIT(4), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdi1");
+
+       clk = clk_reg_prcc_kclk("p2_sdi3_kclk", "sdmmcclk",
+                       U8500_CLKRST2_BASE, BIT(5), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdi3");
+
+       /* Note that rate is received from parent. */
+       clk = clk_reg_prcc_kclk("p2_ssirx_kclk", "hsirxclk",
+                       U8500_CLKRST2_BASE, BIT(6),
+                       CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
+       clk = clk_reg_prcc_kclk("p2_ssitx_kclk", "hsitxclk",
+                       U8500_CLKRST2_BASE, BIT(7),
+                       CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
+
+       /* Periph3 */
+       clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk",
+                       U8500_CLKRST3_BASE, BIT(1), CLK_SET_RATE_GATE);
+       clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk",
+                       U8500_CLKRST3_BASE, BIT(2), CLK_SET_RATE_GATE);
+       clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk",
+                       U8500_CLKRST3_BASE, BIT(3), CLK_SET_RATE_GATE);
+
+       clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmcclk",
+                       U8500_CLKRST3_BASE, BIT(4), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdi2");
+
+       clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k",
+                       U8500_CLKRST3_BASE, BIT(5), CLK_SET_RATE_GATE);
+
+       clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk",
+                       U8500_CLKRST3_BASE, BIT(6), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "uart2");
+
+       clk = clk_reg_prcc_kclk("p3_sdi5_kclk", "sdmmcclk",
+                       U8500_CLKRST3_BASE, BIT(7), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdi5");
+
+       /* Periph6 */
+       clk = clk_reg_prcc_kclk("p3_rng_kclk", "rngclk",
+                       U8500_CLKRST6_BASE, BIT(0), CLK_SET_RATE_GATE);
+
+}
diff --git a/drivers/clk/ux500/u8540_clk.c b/drivers/clk/ux500/u8540_clk.c
new file mode 100644 (file)
index 0000000..10adfd2
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Clock definitions for u8540 platform.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/platform_data/clk-ux500.h>
+
+#include "clk.h"
+
+void u8540_clk_init(void)
+{
+       /* register clocks here */
+}
diff --git a/drivers/clk/ux500/u9540_clk.c b/drivers/clk/ux500/u9540_clk.c
new file mode 100644 (file)
index 0000000..dbc0191
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Clock definitions for u9540 platform.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/platform_data/clk-ux500.h>
+
+#include "clk.h"
+
+void u9540_clk_init(void)
+{
+       /* register clocks here */
+}
index 50cf6a2ee693ce1d8d8d032047e8718a77963a7e..c0a0f647879848ff245db88cd7ef0306796b85f9 100644 (file)
@@ -1,3 +1,4 @@
 # Makefile for Versatile-specific clocks
 obj-$(CONFIG_ICST)             += clk-icst.o
 obj-$(CONFIG_ARCH_INTEGRATOR)  += clk-integrator.o
+obj-$(CONFIG_ARCH_REALVIEW)    += clk-realview.o
diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c
new file mode 100644 (file)
index 0000000..e21a99c
--- /dev/null
@@ -0,0 +1,114 @@
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+#include "clk-icst.h"
+
+/*
+ * Implementation of the ARM RealView clock trees.
+ */
+
+static void __iomem *sys_lock;
+static void __iomem *sys_vcoreg;
+
+/**
+ * realview_oscvco_get() - get ICST OSC settings for the RealView
+ */
+static struct icst_vco realview_oscvco_get(void)
+{
+       u32 val;
+       struct icst_vco vco;
+
+       val = readl(sys_vcoreg);
+       vco.v = val & 0x1ff;
+       vco.r = (val >> 9) & 0x7f;
+       vco.s = (val >> 16) & 03;
+       return vco;
+}
+
+static void realview_oscvco_set(struct icst_vco vco)
+{
+       u32 val;
+
+       val = readl(sys_vcoreg) & ~0x7ffff;
+       val |= vco.v | (vco.r << 9) | (vco.s << 16);
+
+       /* This magic unlocks the CM VCO so it can be controlled */
+       writel(0xa05f, sys_lock);
+       writel(val, sys_vcoreg);
+       /* This locks the CM again */
+       writel(0, sys_lock);
+}
+
+static const struct icst_params realview_oscvco_params = {
+       .ref            = 24000000,
+       .vco_max        = ICST307_VCO_MAX,
+       .vco_min        = ICST307_VCO_MIN,
+       .vd_min         = 4 + 8,
+       .vd_max         = 511 + 8,
+       .rd_min         = 1 + 2,
+       .rd_max         = 127 + 2,
+       .s2div          = icst307_s2div,
+       .idx2s          = icst307_idx2s,
+};
+
+static const struct clk_icst_desc __initdata realview_icst_desc = {
+       .params = &realview_oscvco_params,
+       .getvco = realview_oscvco_get,
+       .setvco = realview_oscvco_set,
+};
+
+/*
+ * realview_clk_init() - set up the RealView clock tree
+ */
+void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
+{
+       struct clk *clk;
+
+       sys_lock = sysbase + REALVIEW_SYS_LOCK_OFFSET;
+       if (is_pb1176)
+               sys_vcoreg = sysbase + REALVIEW_SYS_OSC0_OFFSET;
+       else
+               sys_vcoreg = sysbase + REALVIEW_SYS_OSC4_OFFSET;
+
+
+       /* APB clock dummy */
+       clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
+       clk_register_clkdev(clk, "apb_pclk", NULL);
+
+       /* 24 MHz clock */
+       clk = clk_register_fixed_rate(NULL, "clk24mhz", NULL, CLK_IS_ROOT,
+                               24000000);
+       clk_register_clkdev(clk, NULL, "dev:uart0");
+       clk_register_clkdev(clk, NULL, "dev:uart1");
+       clk_register_clkdev(clk, NULL, "dev:uart2");
+       clk_register_clkdev(clk, NULL, "fpga:kmi0");
+       clk_register_clkdev(clk, NULL, "fpga:kmi1");
+       clk_register_clkdev(clk, NULL, "fpga:mmc0");
+       clk_register_clkdev(clk, NULL, "dev:ssp0");
+       if (is_pb1176) {
+               /*
+                * UART3 is on the dev chip in PB1176
+                * UART4 only exists in PB1176
+                */
+               clk_register_clkdev(clk, NULL, "dev:uart3");
+               clk_register_clkdev(clk, NULL, "dev:uart4");
+       } else
+               clk_register_clkdev(clk, NULL, "fpga:uart3");
+
+
+       /* 1 MHz clock */
+       clk = clk_register_fixed_rate(NULL, "clk1mhz", NULL, CLK_IS_ROOT,
+                                     1000000);
+       clk_register_clkdev(clk, NULL, "sp804");
+
+       /* ICST VCO clock */
+       clk = icst_clk_register(NULL, &realview_icst_desc);
+       clk_register_clkdev(clk, NULL, "dev:clcd");
+       clk_register_clkdev(clk, NULL, "issp:clcd");
+}
index 7040a0081130c93ce6b73145355abec0a8c571b8..6b37e2d6ed8f5dd579c9ba655373641463ccfe99 100644 (file)
@@ -418,6 +418,9 @@ static struct {
 
 static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
 
+/* Functions definition */
+static void compute_armss_rate(void);
+
 /* Spinlocks */
 static DEFINE_SPINLOCK(prcmu_lock);
 static DEFINE_SPINLOCK(clkout_lock);
@@ -517,6 +520,7 @@ static struct dsiescclk dsiescclk[3] = {
        }
 };
 
+
 /*
 * Used by MCDE to setup all necessary PRCMU registers
 */
@@ -1013,6 +1017,7 @@ int db8500_prcmu_set_arm_opp(u8 opp)
                (mb1_transfer.ack.arm_opp != opp))
                r = -EIO;
 
+       compute_armss_rate();
        mutex_unlock(&mb1_transfer.lock);
 
        return r;
@@ -1612,6 +1617,7 @@ static unsigned long pll_rate(void __iomem *reg, unsigned long src_rate,
        if ((branch == PLL_FIX) || ((branch == PLL_DIV) &&
                (val & PRCM_PLL_FREQ_DIV2EN) &&
                ((reg == PRCM_PLLSOC0_FREQ) ||
+                (reg == PRCM_PLLARM_FREQ) ||
                 (reg == PRCM_PLLDDR_FREQ))))
                div *= 2;
 
@@ -1661,6 +1667,39 @@ static unsigned long clock_rate(u8 clock)
        else
                return 0;
 }
+static unsigned long latest_armss_rate;
+static unsigned long armss_rate(void)
+{
+       return latest_armss_rate;
+}
+
+static void compute_armss_rate(void)
+{
+       u32 r;
+       unsigned long rate;
+
+       r = readl(PRCM_ARM_CHGCLKREQ);
+
+       if (r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ) {
+               /* External ARMCLKFIX clock */
+
+               rate = pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_FIX);
+
+               /* Check PRCM_ARM_CHGCLKREQ divider */
+               if (!(r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL))
+                       rate /= 2;
+
+               /* Check PRCM_ARMCLKFIX_MGT divider */
+               r = readl(PRCM_ARMCLKFIX_MGT);
+               r &= PRCM_CLK_MGT_CLKPLLDIV_MASK;
+               rate /= r;
+
+       } else {/* ARM PLL */
+               rate = pll_rate(PRCM_PLLARM_FREQ, ROOT_CLOCK_RATE, PLL_DIV);
+       }
+
+       latest_armss_rate = rate;
+}
 
 static unsigned long dsiclk_rate(u8 n)
 {
@@ -1707,6 +1746,8 @@ unsigned long prcmu_clock_rate(u8 clock)
                return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
        else if (clock == PRCMU_PLLSOC1)
                return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+       else if (clock == PRCMU_ARMSS)
+               return armss_rate();
        else if (clock == PRCMU_PLLDDR)
                return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
        else if (clock == PRCMU_PLLDSI)
@@ -2693,6 +2734,7 @@ void __init db8500_prcmu_early_init(void)
                                         handle_simple_irq);
                set_irq_flags(irq, IRQF_VALID);
        }
+       compute_armss_rate();
 }
 
 static void __init init_prcm_registers(void)
index 23108a6e316782612eafda90cb2944b37a644e0e..79c76ebdba525c7e57970512aa6e02e7c7d28a88 100644 (file)
@@ -61,7 +61,8 @@
 #define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3   0x2
 
 #define PRCM_ARM_CHGCLKREQ     (_PRCMU_BASE + 0x114)
-#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ  0x1
+#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ  BIT(0)
+#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL     BIT(16)
 
 #define PRCM_PLLARM_ENABLE     (_PRCMU_BASE + 0x98)
 #define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE  0x1
 /* PRCMU clock/PLL/reset registers */
 #define PRCM_PLLSOC0_FREQ         (_PRCMU_BASE + 0x080)
 #define PRCM_PLLSOC1_FREQ         (_PRCMU_BASE + 0x084)
+#define PRCM_PLLARM_FREQ          (_PRCMU_BASE + 0x088)
 #define PRCM_PLLDDR_FREQ          (_PRCMU_BASE + 0x08C)
 #define PRCM_PLL_FREQ_D_SHIFT  0
 #define PRCM_PLL_FREQ_D_MASK   BITS(0, 7)
index 77335fac943e74b2ca7748ec74665657d828572f..c127315829208046fbd9327488dfc258cc1d0372 100644 (file)
@@ -26,6 +26,7 @@
 #define CLK_IGNORE_UNUSED      BIT(3) /* do not gate even if unused */
 #define CLK_IS_ROOT            BIT(4) /* root clk, has no parent */
 #define CLK_IS_BASIC           BIT(5) /* Basic clk, can't do a to_clk_foo() */
+#define CLK_GET_RATE_NOCACHE   BIT(6) /* do not use the cached clk rate */
 
 struct clk_hw;
 
@@ -360,6 +361,11 @@ int of_clk_add_provider(struct device_node *np,
 void of_clk_del_provider(struct device_node *np);
 struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
                                  void *data);
+struct clk_onecell_data {
+       struct clk **clks;
+       unsigned int clk_num;
+};
+struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
 const char *of_clk_get_parent_name(struct device_node *np, int index);
 void of_clk_init(const struct of_device_id *matches);
 
index 5b90e94399e1b2d8707885ee85be713b9288ab57..c410d99bd6678ea86dc7f704f0355a4e40517218 100644 (file)
@@ -136,6 +136,7 @@ enum prcmu_clock {
        PRCMU_TIMCLK,
        PRCMU_PLLSOC0,
        PRCMU_PLLSOC1,
+       PRCMU_ARMSS,
        PRCMU_PLLDDR,
        PRCMU_PLLDSI,
        PRCMU_DSI0CLK,
diff --git a/include/linux/platform_data/clk-realview.h b/include/linux/platform_data/clk-realview.h
new file mode 100644 (file)
index 0000000..2e426a7
--- /dev/null
@@ -0,0 +1 @@
+void realview_clk_init(void __iomem *sysbase, bool is_pb1176);
diff --git a/include/linux/platform_data/clk-ux500.h b/include/linux/platform_data/clk-ux500.h
new file mode 100644 (file)
index 0000000..3af0da1
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Clock definitions for ux500 platforms
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __CLK_UX500_H
+#define __CLK_UX500_H
+
+void u8500_clk_init(void);
+void u9540_clk_init(void);
+void u8540_clk_init(void);
+
+#endif /* __CLK_UX500_H */
This page took 0.145536 seconds and 5 git commands to generate.