aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/Kconfig19
-rw-r--r--drivers/clk/Makefile6
-rw-r--r--drivers/clk/at91/Makefile4
-rw-r--r--drivers/clk/at91/clk-main.c577
-rw-r--r--drivers/clk/at91/clk-slow.c467
-rw-r--r--drivers/clk/at91/pmc.c17
-rw-r--r--drivers/clk/at91/pmc.h9
-rw-r--r--drivers/clk/at91/sckc.c57
-rw-r--r--drivers/clk/at91/sckc.h22
-rw-r--r--drivers/clk/bcm/Kconfig2
-rw-r--r--drivers/clk/bcm/Makefile1
-rw-r--r--drivers/clk/bcm/clk-bcm21664.c290
-rw-r--r--drivers/clk/bcm/clk-bcm281xx.c231
-rw-r--r--drivers/clk/bcm/clk-kona-setup.c229
-rw-r--r--drivers/clk/bcm/clk-kona.c266
-rw-r--r--drivers/clk/bcm/clk-kona.h160
-rw-r--r--drivers/clk/berlin/Makefile4
-rw-r--r--drivers/clk/berlin/berlin2-avpll.c393
-rw-r--r--drivers/clk/berlin/berlin2-avpll.h36
-rw-r--r--drivers/clk/berlin/berlin2-div.c265
-rw-r--r--drivers/clk/berlin/berlin2-div.h89
-rw-r--r--drivers/clk/berlin/berlin2-pll.c117
-rw-r--r--drivers/clk/berlin/berlin2-pll.h37
-rw-r--r--drivers/clk/berlin/bg2.c691
-rw-r--r--drivers/clk/berlin/bg2q.c389
-rw-r--r--drivers/clk/berlin/common.h29
-rw-r--r--drivers/clk/clk-axm5516.c615
-rw-r--r--drivers/clk/clk-divider.c93
-rw-r--r--drivers/clk/clk-fractional-divider.c135
-rw-r--r--drivers/clk/clk-s2mps11.c95
-rw-r--r--drivers/clk/clk-si570.c2
-rw-r--r--drivers/clk/clk-u300.c1
-rw-r--r--drivers/clk/clk.c47
-rw-r--r--drivers/clk/clk.h1
-rw-r--r--drivers/clk/clkdev.c34
-rw-r--r--drivers/clk/hisilicon/Makefile1
-rw-r--r--drivers/clk/hisilicon/clk-hix5hd2.c101
-rw-r--r--drivers/clk/hisilicon/clk.c41
-rw-r--r--drivers/clk/hisilicon/clk.h3
-rw-r--r--drivers/clk/mvebu/Kconfig4
-rw-r--r--drivers/clk/mvebu/Makefile1
-rw-r--r--drivers/clk/mvebu/orion.c210
-rw-r--r--drivers/clk/qcom/Kconfig4
-rw-r--r--drivers/clk/qcom/Makefile1
-rw-r--r--drivers/clk/qcom/clk-rcg.h3
-rw-r--r--drivers/clk/qcom/clk-rcg2.c304
-rw-r--r--drivers/clk/qcom/common.c101
-rw-r--r--drivers/clk/qcom/common.h34
-rw-r--r--drivers/clk/qcom/gcc-msm8660.c77
-rw-r--r--drivers/clk/qcom/gcc-msm8960.c109
-rw-r--r--drivers/clk/qcom/gcc-msm8974.c207
-rw-r--r--drivers/clk/qcom/mmcc-msm8960.c80
-rw-r--r--drivers/clk/qcom/mmcc-msm8974.c198
-rw-r--r--drivers/clk/rockchip/clk-rockchip.c3
-rw-r--r--drivers/clk/samsung/Kconfig26
-rw-r--r--drivers/clk/samsung/Makefile7
-rw-r--r--drivers/clk/samsung/clk-exynos3250.c780
-rw-r--r--drivers/clk/samsung/clk-exynos4.c71
-rw-r--r--drivers/clk/samsung/clk-exynos5250.c118
-rw-r--r--drivers/clk/samsung/clk-exynos5260.c1980
-rw-r--r--drivers/clk/samsung/clk-exynos5260.h459
-rw-r--r--drivers/clk/samsung/clk-exynos5410.c209
-rw-r--r--drivers/clk/samsung/clk-exynos5420.c1156
-rw-r--r--drivers/clk/samsung/clk-exynos5440.c18
-rw-r--r--drivers/clk/samsung/clk-pll.c489
-rw-r--r--drivers/clk/samsung/clk-pll.h8
-rw-r--r--drivers/clk/samsung/clk-s3c2410-dclk.c440
-rw-r--r--drivers/clk/samsung/clk-s3c2410.c487
-rw-r--r--drivers/clk/samsung/clk-s3c2412.c274
-rw-r--r--drivers/clk/samsung/clk-s3c2443.c466
-rw-r--r--drivers/clk/samsung/clk-s3c64xx.c50
-rw-r--r--drivers/clk/samsung/clk.c123
-rw-r--r--drivers/clk/samsung/clk.h72
-rw-r--r--drivers/clk/shmobile/Makefile2
-rw-r--r--drivers/clk/shmobile/clk-mstp.c2
-rw-r--r--drivers/clk/shmobile/clk-r8a7740.c199
-rw-r--r--drivers/clk/shmobile/clk-r8a7779.c180
-rw-r--r--drivers/clk/socfpga/clk-gate.c1
-rw-r--r--drivers/clk/socfpga/clk-periph.c22
-rw-r--r--drivers/clk/socfpga/clk.h4
-rw-r--r--drivers/clk/spear/spear3xx_clock.c16
-rw-r--r--drivers/clk/st/clkgen-pll.c1
-rw-r--r--drivers/clk/sunxi/Makefile4
-rw-r--r--drivers/clk/sunxi/clk-a10-hosc.c73
-rw-r--r--drivers/clk/sunxi/clk-a20-gmac.c119
-rw-r--r--drivers/clk/sunxi/clk-factors.c36
-rw-r--r--drivers/clk/sunxi/clk-sun6i-apb0-gates.c99
-rw-r--r--drivers/clk/sunxi/clk-sun6i-apb0.c77
-rw-r--r--drivers/clk/sunxi/clk-sun6i-ar100.c233
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c253
-rw-r--r--drivers/clk/tegra/clk-id.h1
-rw-r--r--drivers/clk/tegra/clk-pll.c33
-rw-r--r--drivers/clk/tegra/clk-tegra-periph.c10
-rw-r--r--drivers/clk/tegra/clk-tegra114.c22
-rw-r--r--drivers/clk/tegra/clk-tegra124.c21
-rw-r--r--drivers/clk/ti/Makefile4
-rw-r--r--drivers/clk/ti/apll.c187
-rw-r--r--drivers/clk/ti/clk-2xxx.c256
-rw-r--r--drivers/clk/ti/clk-43xx.c22
-rw-r--r--drivers/clk/ti/clk-54xx.c6
-rw-r--r--drivers/clk/ti/clk-7xx.c2
-rw-r--r--drivers/clk/ti/clk-dra7-atl.c312
-rw-r--r--drivers/clk/ti/dpll.c143
-rw-r--r--drivers/clk/ti/gate.c4
-rw-r--r--drivers/clk/ti/interface.c11
-rw-r--r--drivers/clk/ti/mux.c2
-rw-r--r--drivers/clk/versatile/Kconfig26
-rw-r--r--drivers/clk/versatile/Makefile5
-rw-r--r--drivers/clk/versatile/clk-icst.c2
-rw-r--r--drivers/clk/versatile/clk-impd1.c38
-rw-r--r--drivers/clk/versatile/clk-vexpress-osc.c96
-rw-r--r--drivers/clk/zynq/clkc.c12
112 files changed, 15051 insertions, 1630 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 6f56d3a4f010..9f9c5ae5359b 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -30,14 +30,7 @@ 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 || ARCH_VEXPRESS || ARM64
- ---help---
- Supports clocking on ARM Reference designs:
- - Integrator/AP and Integrator/CP
- - RealView PB1176, EB, PB11MP and PBX
- - Versatile Express
+source "drivers/clk/versatile/Kconfig"
config COMMON_CLK_MAX77686
tristate "Clock driver for Maxim 77686 MFD"
@@ -65,12 +58,12 @@ config COMMON_CLK_SI570
clock generators.
config COMMON_CLK_S2MPS11
- tristate "Clock driver for S2MPS11/S5M8767 MFD"
+ tristate "Clock driver for S2MPS1X/S5M8767 MFD"
depends on MFD_SEC_CORE
---help---
- This driver supports S2MPS11/S5M8767 crystal oscillator clock. These
- multi-function devices have 3 fixed-rate oscillators, clocked at
- 32KHz each.
+ This driver supports S2MPS11/S2MPS14/S5M8767 crystal oscillator
+ clock. These multi-function devices have two (S2MPS14) or three
+ (S2MPS11, S5M8767) fixed-rate oscillators, clocked at 32KHz each.
config CLK_TWL6040
tristate "External McPDM functional clock from twl6040"
@@ -115,3 +108,5 @@ endmenu
source "drivers/clk/bcm/Kconfig"
source "drivers/clk/mvebu/Kconfig"
+
+source "drivers/clk/samsung/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 5f8a28735c96..567f10259029 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -8,10 +8,12 @@ obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
obj-$(CONFIG_COMMON_CLK) += clk-gate.o
obj-$(CONFIG_COMMON_CLK) += clk-mux.o
obj-$(CONFIG_COMMON_CLK) += clk-composite.o
+obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o
# hardware specific clock types
# please keep this section sorted lexicographically by file/directory path name
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
+obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
@@ -31,8 +33,10 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
obj-$(CONFIG_COMMON_CLK_AT91) += at91/
obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/
+obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
obj-$(CONFIG_ARCH_HIP04) += hisilicon/
+obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
@@ -41,7 +45,7 @@ obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-$(CONFIG_ARCH_MXS) += mxs/
obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
-obj-$(CONFIG_PLAT_SAMSUNG) += samsung/
+obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/
obj-$(CONFIG_ARCH_SIRF) += sirf/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index 46c1d3d0d66b..4998aee59267 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -2,8 +2,8 @@
# Makefile for at91 specific clk
#
-obj-y += pmc.o
-obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o
+obj-y += pmc.o sckc.o
+obj-y += clk-slow.o clk-main.o clk-pll.o clk-plldiv.o clk-master.o
obj-y += clk-system.o clk-peripheral.o clk-programmable.o
obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
index 8e9e8cc0412d..733306131b99 100644
--- a/drivers/clk/at91/clk-main.c
+++ b/drivers/clk/at91/clk-main.c
@@ -30,99 +30,546 @@
#define MAINF_LOOP_MIN_WAIT (USEC_PER_SEC / SLOW_CLOCK_FREQ)
#define MAINF_LOOP_MAX_WAIT MAINFRDY_TIMEOUT
-struct clk_main {
+#define MOR_KEY_MASK (0xff << 16)
+
+struct clk_main_osc {
struct clk_hw hw;
struct at91_pmc *pmc;
- unsigned long rate;
unsigned int irq;
wait_queue_head_t wait;
};
-#define to_clk_main(hw) container_of(hw, struct clk_main, hw)
+#define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw)
+
+struct clk_main_rc_osc {
+ struct clk_hw hw;
+ struct at91_pmc *pmc;
+ unsigned int irq;
+ wait_queue_head_t wait;
+ unsigned long frequency;
+ unsigned long accuracy;
+};
+
+#define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw)
+
+struct clk_rm9200_main {
+ struct clk_hw hw;
+ struct at91_pmc *pmc;
+};
+
+#define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw)
-static irqreturn_t clk_main_irq_handler(int irq, void *dev_id)
+struct clk_sam9x5_main {
+ struct clk_hw hw;
+ struct at91_pmc *pmc;
+ unsigned int irq;
+ wait_queue_head_t wait;
+ u8 parent;
+};
+
+#define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw)
+
+static irqreturn_t clk_main_osc_irq_handler(int irq, void *dev_id)
{
- struct clk_main *clkmain = (struct clk_main *)dev_id;
+ struct clk_main_osc *osc = dev_id;
- wake_up(&clkmain->wait);
- disable_irq_nosync(clkmain->irq);
+ wake_up(&osc->wait);
+ disable_irq_nosync(osc->irq);
return IRQ_HANDLED;
}
-static int clk_main_prepare(struct clk_hw *hw)
+static int clk_main_osc_prepare(struct clk_hw *hw)
{
- struct clk_main *clkmain = to_clk_main(hw);
- struct at91_pmc *pmc = clkmain->pmc;
- unsigned long halt_time, timeout;
+ struct clk_main_osc *osc = to_clk_main_osc(hw);
+ struct at91_pmc *pmc = osc->pmc;
u32 tmp;
+ tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK;
+ if (tmp & AT91_PMC_OSCBYPASS)
+ return 0;
+
+ if (!(tmp & AT91_PMC_MOSCEN)) {
+ tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
+ pmc_write(pmc, AT91_CKGR_MOR, tmp);
+ }
+
while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) {
- enable_irq(clkmain->irq);
- wait_event(clkmain->wait,
+ enable_irq(osc->irq);
+ wait_event(osc->wait,
pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
}
- if (clkmain->rate)
- return 0;
+ return 0;
+}
+
+static void clk_main_osc_unprepare(struct clk_hw *hw)
+{
+ struct clk_main_osc *osc = to_clk_main_osc(hw);
+ struct at91_pmc *pmc = osc->pmc;
+ u32 tmp = pmc_read(pmc, AT91_CKGR_MOR);
+
+ if (tmp & AT91_PMC_OSCBYPASS)
+ return;
+
+ if (!(tmp & AT91_PMC_MOSCEN))
+ return;
+
+ tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
+ pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
+}
+
+static int clk_main_osc_is_prepared(struct clk_hw *hw)
+{
+ struct clk_main_osc *osc = to_clk_main_osc(hw);
+ struct at91_pmc *pmc = osc->pmc;
+ u32 tmp = pmc_read(pmc, AT91_CKGR_MOR);
+
+ if (tmp & AT91_PMC_OSCBYPASS)
+ return 1;
+
+ return !!((pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS) &&
+ (pmc_read(pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCEN));
+}
+
+static const struct clk_ops main_osc_ops = {
+ .prepare = clk_main_osc_prepare,
+ .unprepare = clk_main_osc_unprepare,
+ .is_prepared = clk_main_osc_is_prepared,
+};
+
+static struct clk * __init
+at91_clk_register_main_osc(struct at91_pmc *pmc,
+ unsigned int irq,
+ const char *name,
+ const char *parent_name,
+ bool bypass)
+{
+ int ret;
+ struct clk_main_osc *osc;
+ struct clk *clk = NULL;
+ struct clk_init_data init;
+
+ if (!pmc || !irq || !name || !parent_name)
+ return ERR_PTR(-EINVAL);
+
+ osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+ if (!osc)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &main_osc_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ init.flags = CLK_IGNORE_UNUSED;
+
+ osc->hw.init = &init;
+ osc->pmc = pmc;
+ osc->irq = irq;
+
+ init_waitqueue_head(&osc->wait);
+ irq_set_status_flags(osc->irq, IRQ_NOAUTOEN);
+ ret = request_irq(osc->irq, clk_main_osc_irq_handler,
+ IRQF_TRIGGER_HIGH, name, osc);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (bypass)
+ pmc_write(pmc, AT91_CKGR_MOR,
+ (pmc_read(pmc, AT91_CKGR_MOR) &
+ ~(MOR_KEY_MASK | AT91_PMC_MOSCEN)) |
+ AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
+
+ clk = clk_register(NULL, &osc->hw);
+ if (IS_ERR(clk)) {
+ free_irq(irq, osc);
+ kfree(osc);
+ }
+
+ return clk;
+}
+
+void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np,
+ struct at91_pmc *pmc)
+{
+ struct clk *clk;
+ unsigned int irq;
+ const char *name = np->name;
+ const char *parent_name;
+ bool bypass;
+
+ of_property_read_string(np, "clock-output-names", &name);
+ bypass = of_property_read_bool(np, "atmel,osc-bypass");
+ parent_name = of_clk_get_parent_name(np, 0);
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq)
+ return;
+
+ clk = at91_clk_register_main_osc(pmc, irq, name, parent_name, bypass);
+ if (IS_ERR(clk))
+ return;
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+static irqreturn_t clk_main_rc_osc_irq_handler(int irq, void *dev_id)
+{
+ struct clk_main_rc_osc *osc = dev_id;
+
+ wake_up(&osc->wait);
+ disable_irq_nosync(osc->irq);
+
+ return IRQ_HANDLED;
+}
+
+static int clk_main_rc_osc_prepare(struct clk_hw *hw)
+{
+ struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
+ struct at91_pmc *pmc = osc->pmc;
+ u32 tmp;
+
+ tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK;
+
+ if (!(tmp & AT91_PMC_MOSCRCEN)) {
+ tmp |= AT91_PMC_MOSCRCEN | AT91_PMC_KEY;
+ pmc_write(pmc, AT91_CKGR_MOR, tmp);
+ }
+
+ while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS)) {
+ enable_irq(osc->irq);
+ wait_event(osc->wait,
+ pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS);
+ }
+
+ return 0;
+}
+
+static void clk_main_rc_osc_unprepare(struct clk_hw *hw)
+{
+ struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
+ struct at91_pmc *pmc = osc->pmc;
+ u32 tmp = pmc_read(pmc, AT91_CKGR_MOR);
+
+ if (!(tmp & AT91_PMC_MOSCRCEN))
+ return;
+
+ tmp &= ~(MOR_KEY_MASK | AT91_PMC_MOSCRCEN);
+ pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
+}
+
+static int clk_main_rc_osc_is_prepared(struct clk_hw *hw)
+{
+ struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
+ struct at91_pmc *pmc = osc->pmc;
+
+ return !!((pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS) &&
+ (pmc_read(pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCRCEN));
+}
+
+static unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
+
+ return osc->frequency;
+}
+
+static unsigned long clk_main_rc_osc_recalc_accuracy(struct clk_hw *hw,
+ unsigned long parent_acc)
+{
+ struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
+
+ return osc->accuracy;
+}
+
+static const struct clk_ops main_rc_osc_ops = {
+ .prepare = clk_main_rc_osc_prepare,
+ .unprepare = clk_main_rc_osc_unprepare,
+ .is_prepared = clk_main_rc_osc_is_prepared,
+ .recalc_rate = clk_main_rc_osc_recalc_rate,
+ .recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
+};
+
+static struct clk * __init
+at91_clk_register_main_rc_osc(struct at91_pmc *pmc,
+ unsigned int irq,
+ const char *name,
+ u32 frequency, u32 accuracy)
+{
+ int ret;
+ struct clk_main_rc_osc *osc;
+ struct clk *clk = NULL;
+ struct clk_init_data init;
+
+ if (!pmc || !irq || !name || !frequency)
+ return ERR_PTR(-EINVAL);
+
+ osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+ if (!osc)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &main_rc_osc_ops;
+ init.parent_names = NULL;
+ init.num_parents = 0;
+ init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED;
+
+ osc->hw.init = &init;
+ osc->pmc = pmc;
+ osc->irq = irq;
+ osc->frequency = frequency;
+ osc->accuracy = accuracy;
+
+ init_waitqueue_head(&osc->wait);
+ irq_set_status_flags(osc->irq, IRQ_NOAUTOEN);
+ ret = request_irq(osc->irq, clk_main_rc_osc_irq_handler,
+ IRQF_TRIGGER_HIGH, name, osc);
+ if (ret)
+ return ERR_PTR(ret);
+
+ clk = clk_register(NULL, &osc->hw);
+ if (IS_ERR(clk)) {
+ free_irq(irq, osc);
+ kfree(osc);
+ }
+
+ return clk;
+}
+
+void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np,
+ struct at91_pmc *pmc)
+{
+ struct clk *clk;
+ unsigned int irq;
+ u32 frequency = 0;
+ u32 accuracy = 0;
+ const char *name = np->name;
+
+ of_property_read_string(np, "clock-output-names", &name);
+ of_property_read_u32(np, "clock-frequency", &frequency);
+ of_property_read_u32(np, "clock-accuracy", &accuracy);
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq)
+ return;
+
+ clk = at91_clk_register_main_rc_osc(pmc, irq, name, frequency,
+ accuracy);
+ if (IS_ERR(clk))
+ return;
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+
+static int clk_main_probe_frequency(struct at91_pmc *pmc)
+{
+ unsigned long prep_time, timeout;
+ u32 tmp;
timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT);
do {
- halt_time = jiffies;
+ prep_time = jiffies;
tmp = pmc_read(pmc, AT91_CKGR_MCFR);
if (tmp & AT91_PMC_MAINRDY)
return 0;
usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
- } while (time_before(halt_time, timeout));
+ } while (time_before(prep_time, timeout));
- return 0;
+ return -ETIMEDOUT;
}
-static int clk_main_is_prepared(struct clk_hw *hw)
+static unsigned long clk_main_recalc_rate(struct at91_pmc *pmc,
+ unsigned long parent_rate)
{
- struct clk_main *clkmain = to_clk_main(hw);
+ u32 tmp;
+
+ if (parent_rate)
+ return parent_rate;
+
+ tmp = pmc_read(pmc, AT91_CKGR_MCFR);
+ if (!(tmp & AT91_PMC_MAINRDY))
+ return 0;
- return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
+ return ((tmp & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
}
-static unsigned long clk_main_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
+static int clk_rm9200_main_prepare(struct clk_hw *hw)
{
- u32 tmp;
- struct clk_main *clkmain = to_clk_main(hw);
+ struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
+
+ return clk_main_probe_frequency(clkmain->pmc);
+}
+
+static int clk_rm9200_main_is_prepared(struct clk_hw *hw)
+{
+ struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
+
+ return !!(pmc_read(clkmain->pmc, AT91_CKGR_MCFR) & AT91_PMC_MAINRDY);
+}
+
+static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
+
+ return clk_main_recalc_rate(clkmain->pmc, parent_rate);
+}
+
+static const struct clk_ops rm9200_main_ops = {
+ .prepare = clk_rm9200_main_prepare,
+ .is_prepared = clk_rm9200_main_is_prepared,
+ .recalc_rate = clk_rm9200_main_recalc_rate,
+};
+
+static struct clk * __init
+at91_clk_register_rm9200_main(struct at91_pmc *pmc,
+ const char *name,
+ const char *parent_name)
+{
+ struct clk_rm9200_main *clkmain;
+ struct clk *clk = NULL;
+ struct clk_init_data init;
+
+ if (!pmc || !name)
+ return ERR_PTR(-EINVAL);
+
+ if (!parent_name)
+ return ERR_PTR(-EINVAL);
+
+ clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
+ if (!clkmain)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &rm9200_main_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ init.flags = 0;
+
+ clkmain->hw.init = &init;
+ clkmain->pmc = pmc;
+
+ clk = clk_register(NULL, &clkmain->hw);
+ if (IS_ERR(clk))
+ kfree(clkmain);
+
+ return clk;
+}
+
+void __init of_at91rm9200_clk_main_setup(struct device_node *np,
+ struct at91_pmc *pmc)
+{
+ struct clk *clk;
+ const char *parent_name;
+ const char *name = np->name;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+ of_property_read_string(np, "clock-output-names", &name);
+
+ clk = at91_clk_register_rm9200_main(pmc, name, parent_name);
+ if (IS_ERR(clk))
+ return;
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+static irqreturn_t clk_sam9x5_main_irq_handler(int irq, void *dev_id)
+{
+ struct clk_sam9x5_main *clkmain = dev_id;
+
+ wake_up(&clkmain->wait);
+ disable_irq_nosync(clkmain->irq);
+
+ return IRQ_HANDLED;
+}
+
+static int clk_sam9x5_main_prepare(struct clk_hw *hw)
+{
+ struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
struct at91_pmc *pmc = clkmain->pmc;
- if (clkmain->rate)
- return clkmain->rate;
+ while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS)) {
+ enable_irq(clkmain->irq);
+ wait_event(clkmain->wait,
+ pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS);
+ }
+
+ return clk_main_probe_frequency(pmc);
+}
- tmp = pmc_read(pmc, AT91_CKGR_MCFR) & AT91_PMC_MAINF;
- clkmain->rate = (tmp * parent_rate) / MAINF_DIV;
+static int clk_sam9x5_main_is_prepared(struct clk_hw *hw)
+{
+ struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
- return clkmain->rate;
+ return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS);
}
-static const struct clk_ops main_ops = {
- .prepare = clk_main_prepare,
- .is_prepared = clk_main_is_prepared,
- .recalc_rate = clk_main_recalc_rate,
+static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
+
+ return clk_main_recalc_rate(clkmain->pmc, parent_rate);
+}
+
+static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
+ struct at91_pmc *pmc = clkmain->pmc;
+ u32 tmp;
+
+ if (index > 1)
+ return -EINVAL;
+
+ tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK;
+
+ if (index && !(tmp & AT91_PMC_MOSCSEL))
+ pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
+ else if (!index && (tmp & AT91_PMC_MOSCSEL))
+ pmc_write(pmc, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
+
+ while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS)) {
+ enable_irq(clkmain->irq);
+ wait_event(clkmain->wait,
+ pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS);
+ }
+
+ return 0;
+}
+
+static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw)
+{
+ struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
+
+ return !!(pmc_read(clkmain->pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCEN);
+}
+
+static const struct clk_ops sam9x5_main_ops = {
+ .prepare = clk_sam9x5_main_prepare,
+ .is_prepared = clk_sam9x5_main_is_prepared,
+ .recalc_rate = clk_sam9x5_main_recalc_rate,
+ .set_parent = clk_sam9x5_main_set_parent,
+ .get_parent = clk_sam9x5_main_get_parent,
};
static struct clk * __init
-at91_clk_register_main(struct at91_pmc *pmc,
- unsigned int irq,
- const char *name,
- const char *parent_name,
- unsigned long rate)
+at91_clk_register_sam9x5_main(struct at91_pmc *pmc,
+ unsigned int irq,
+ const char *name,
+ const char **parent_names,
+ int num_parents)
{
int ret;
- struct clk_main *clkmain;
+ struct clk_sam9x5_main *clkmain;
struct clk *clk = NULL;
struct clk_init_data init;
if (!pmc || !irq || !name)
return ERR_PTR(-EINVAL);
- if (!rate && !parent_name)
+ if (!parent_names || !num_parents)
return ERR_PTR(-EINVAL);
clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
@@ -130,19 +577,20 @@ at91_clk_register_main(struct at91_pmc *pmc,
return ERR_PTR(-ENOMEM);
init.name = name;
- init.ops = &main_ops;
- init.parent_names = parent_name ? &parent_name : NULL;
- init.num_parents = parent_name ? 1 : 0;
- init.flags = parent_name ? 0 : CLK_IS_ROOT;
+ init.ops = &sam9x5_main_ops;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+ init.flags = CLK_SET_PARENT_GATE;
clkmain->hw.init = &init;
- clkmain->rate = rate;
clkmain->pmc = pmc;
clkmain->irq = irq;
+ clkmain->parent = !!(pmc_read(clkmain->pmc, AT91_CKGR_MOR) &
+ AT91_PMC_MOSCEN);
init_waitqueue_head(&clkmain->wait);
irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN);
- ret = request_irq(clkmain->irq, clk_main_irq_handler,
- IRQF_TRIGGER_HIGH, "clk-main", clkmain);
+ ret = request_irq(clkmain->irq, clk_sam9x5_main_irq_handler,
+ IRQF_TRIGGER_HIGH, name, clkmain);
if (ret)
return ERR_PTR(ret);
@@ -155,33 +603,36 @@ at91_clk_register_main(struct at91_pmc *pmc,
return clk;
}
-
-
-static void __init
-of_at91_clk_main_setup(struct device_node *np, struct at91_pmc *pmc)
+void __init of_at91sam9x5_clk_main_setup(struct device_node *np,
+ struct at91_pmc *pmc)
{
struct clk *clk;
+ const char *parent_names[2];
+ int num_parents;
unsigned int irq;
- const char *parent_name;
const char *name = np->name;
- u32 rate = 0;
+ int i;
+
+ num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+ if (num_parents <= 0 || num_parents > 2)
+ return;
+
+ for (i = 0; i < num_parents; ++i) {
+ parent_names[i] = of_clk_get_parent_name(np, i);
+ if (!parent_names[i])
+ return;
+ }
- parent_name = of_clk_get_parent_name(np, 0);
of_property_read_string(np, "clock-output-names", &name);
- of_property_read_u32(np, "clock-frequency", &rate);
+
irq = irq_of_parse_and_map(np, 0);
if (!irq)
return;
- clk = at91_clk_register_main(pmc, irq, name, parent_name, rate);
+ clk = at91_clk_register_sam9x5_main(pmc, irq, name, parent_names,
+ num_parents);
if (IS_ERR(clk))
return;
of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
-
-void __init of_at91rm9200_clk_main_setup(struct device_node *np,
- struct at91_pmc *pmc)
-{
- of_at91_clk_main_setup(np, pmc);
-}
diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c
new file mode 100644
index 000000000000..0300c46ee247
--- /dev/null
+++ b/drivers/clk/at91/clk-slow.c
@@ -0,0 +1,467 @@
+/*
+ * drivers/clk/at91/clk-slow.c
+ *
+ * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.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/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include "pmc.h"
+#include "sckc.h"
+
+#define SLOW_CLOCK_FREQ 32768
+#define SLOWCK_SW_CYCLES 5
+#define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
+ SLOW_CLOCK_FREQ)
+
+#define AT91_SCKC_CR 0x00
+#define AT91_SCKC_RCEN (1 << 0)
+#define AT91_SCKC_OSC32EN (1 << 1)
+#define AT91_SCKC_OSC32BYP (1 << 2)
+#define AT91_SCKC_OSCSEL (1 << 3)
+
+struct clk_slow_osc {
+ struct clk_hw hw;
+ void __iomem *sckcr;
+ unsigned long startup_usec;
+};
+
+#define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
+
+struct clk_slow_rc_osc {
+ struct clk_hw hw;
+ void __iomem *sckcr;
+ unsigned long frequency;
+ unsigned long accuracy;
+ unsigned long startup_usec;
+};
+
+#define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
+
+struct clk_sam9260_slow {
+ struct clk_hw hw;
+ struct at91_pmc *pmc;
+};
+
+#define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
+
+struct clk_sam9x5_slow {
+ struct clk_hw hw;
+ void __iomem *sckcr;
+ u8 parent;
+};
+
+#define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
+
+
+static int clk_slow_osc_prepare(struct clk_hw *hw)
+{
+ struct clk_slow_osc *osc = to_clk_slow_osc(hw);
+ void __iomem *sckcr = osc->sckcr;
+ u32 tmp = readl(sckcr);
+
+ if (tmp & AT91_SCKC_OSC32BYP)
+ return 0;
+
+ writel(tmp | AT91_SCKC_OSC32EN, sckcr);
+
+ usleep_range(osc->startup_usec, osc->startup_usec + 1);
+
+ return 0;
+}
+
+static void clk_slow_osc_unprepare(struct clk_hw *hw)
+{
+ struct clk_slow_osc *osc = to_clk_slow_osc(hw);
+ void __iomem *sckcr = osc->sckcr;
+ u32 tmp = readl(sckcr);
+
+ if (tmp & AT91_SCKC_OSC32BYP)
+ return;
+
+ writel(tmp & ~AT91_SCKC_OSC32EN, sckcr);
+}
+
+static int clk_slow_osc_is_prepared(struct clk_hw *hw)
+{
+ struct clk_slow_osc *osc = to_clk_slow_osc(hw);
+ void __iomem *sckcr = osc->sckcr;
+ u32 tmp = readl(sckcr);
+
+ if (tmp & AT91_SCKC_OSC32BYP)
+ return 1;
+
+ return !!(tmp & AT91_SCKC_OSC32EN);
+}
+
+static const struct clk_ops slow_osc_ops = {
+ .prepare = clk_slow_osc_prepare,
+ .unprepare = clk_slow_osc_unprepare,
+ .is_prepared = clk_slow_osc_is_prepared,
+};
+
+static struct clk * __init
+at91_clk_register_slow_osc(void __iomem *sckcr,
+ const char *name,
+ const char *parent_name,
+ unsigned long startup,
+ bool bypass)
+{
+ struct clk_slow_osc *osc;
+ struct clk *clk = NULL;
+ struct clk_init_data init;
+
+ if (!sckcr || !name || !parent_name)
+ return ERR_PTR(-EINVAL);
+
+ osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+ if (!osc)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &slow_osc_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ init.flags = CLK_IGNORE_UNUSED;
+
+ osc->hw.init = &init;
+ osc->sckcr = sckcr;
+ osc->startup_usec = startup;
+
+ if (bypass)
+ writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
+ sckcr);
+
+ clk = clk_register(NULL, &osc->hw);
+ if (IS_ERR(clk))
+ kfree(osc);
+
+ return clk;
+}
+
+void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np,
+ void __iomem *sckcr)
+{
+ struct clk *clk;
+ const char *parent_name;
+ const char *name = np->name;
+ u32 startup;
+ bool bypass;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+ of_property_read_string(np, "clock-output-names", &name);
+ of_property_read_u32(np, "atmel,startup-time-usec", &startup);
+ bypass = of_property_read_bool(np, "atmel,osc-bypass");
+
+ clk = at91_clk_register_slow_osc(sckcr, name, parent_name, startup,
+ bypass);
+ if (IS_ERR(clk))
+ return;
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
+
+ return osc->frequency;
+}
+
+static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
+ unsigned long parent_acc)
+{
+ struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
+
+ return osc->accuracy;
+}
+
+static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
+{
+ struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
+ void __iomem *sckcr = osc->sckcr;
+
+ writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
+
+ usleep_range(osc->startup_usec, osc->startup_usec + 1);
+
+ return 0;
+}
+
+static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
+{
+ struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
+ void __iomem *sckcr = osc->sckcr;
+
+ writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr);
+}
+
+static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
+{
+ struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
+
+ return !!(readl(osc->sckcr) & AT91_SCKC_RCEN);
+}
+
+static const struct clk_ops slow_rc_osc_ops = {
+ .prepare = clk_slow_rc_osc_prepare,
+ .unprepare = clk_slow_rc_osc_unprepare,
+ .is_prepared = clk_slow_rc_osc_is_prepared,
+ .recalc_rate = clk_slow_rc_osc_recalc_rate,
+ .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
+};
+
+static struct clk * __init
+at91_clk_register_slow_rc_osc(void __iomem *sckcr,
+ const char *name,
+ unsigned long frequency,
+ unsigned long accuracy,
+ unsigned long startup)
+{
+ struct clk_slow_rc_osc *osc;
+ struct clk *clk = NULL;
+ struct clk_init_data init;
+
+ if (!sckcr || !name)
+ return ERR_PTR(-EINVAL);
+
+ osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+ if (!osc)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &slow_rc_osc_ops;
+ init.parent_names = NULL;
+ init.num_parents = 0;
+ init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED;
+
+ osc->hw.init = &init;
+ osc->sckcr = sckcr;
+ osc->frequency = frequency;
+ osc->accuracy = accuracy;
+ osc->startup_usec = startup;
+
+ clk = clk_register(NULL, &osc->hw);
+ if (IS_ERR(clk))
+ kfree(osc);
+
+ return clk;
+}
+
+void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np,
+ void __iomem *sckcr)
+{
+ struct clk *clk;
+ u32 frequency = 0;
+ u32 accuracy = 0;
+ u32 startup = 0;
+ const char *name = np->name;
+
+ of_property_read_string(np, "clock-output-names", &name);
+ of_property_read_u32(np, "clock-frequency", &frequency);
+ of_property_read_u32(np, "clock-accuracy", &accuracy);
+ of_property_read_u32(np, "atmel,startup-time-usec", &startup);
+
+ clk = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy,
+ startup);
+ if (IS_ERR(clk))
+ return;
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
+ void __iomem *sckcr = slowck->sckcr;
+ u32 tmp;
+
+ if (index > 1)
+ return -EINVAL;
+
+ tmp = readl(sckcr);
+
+ if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
+ (index && (tmp & AT91_SCKC_OSCSEL)))
+ return 0;
+
+ if (index)
+ tmp |= AT91_SCKC_OSCSEL;
+ else
+ tmp &= ~AT91_SCKC_OSCSEL;
+
+ writel(tmp, sckcr);
+
+ usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
+
+ return 0;
+}
+
+static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
+{
+ struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
+
+ return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
+}
+
+static const struct clk_ops sam9x5_slow_ops = {
+ .set_parent = clk_sam9x5_slow_set_parent,
+ .get_parent = clk_sam9x5_slow_get_parent,
+};
+
+static struct clk * __init
+at91_clk_register_sam9x5_slow(void __iomem *sckcr,
+ const char *name,
+ const char **parent_names,
+ int num_parents)
+{
+ struct clk_sam9x5_slow *slowck;
+ struct clk *clk = NULL;
+ struct clk_init_data init;
+
+ if (!sckcr || !name || !parent_names || !num_parents)
+ return ERR_PTR(-EINVAL);
+
+ slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
+ if (!slowck)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &sam9x5_slow_ops;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+ init.flags = 0;
+
+ slowck->hw.init = &init;
+ slowck->sckcr = sckcr;
+ slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
+
+ clk = clk_register(NULL, &slowck->hw);
+ if (IS_ERR(clk))
+ kfree(slowck);
+
+ return clk;
+}
+
+void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
+ void __iomem *sckcr)
+{
+ struct clk *clk;
+ const char *parent_names[2];
+ int num_parents;
+ const char *name = np->name;
+ int i;
+
+ num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+ if (num_parents <= 0 || num_parents > 2)
+ return;
+
+ for (i = 0; i < num_parents; ++i) {
+ parent_names[i] = of_clk_get_parent_name(np, i);
+ if (!parent_names[i])
+ return;
+ }
+
+ of_property_read_string(np, "clock-output-names", &name);
+
+ clk = at91_clk_register_sam9x5_slow(sckcr, name, parent_names,
+ num_parents);
+ if (IS_ERR(clk))
+ return;
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
+{
+ struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
+
+ return !!(pmc_read(slowck->pmc, AT91_PMC_SR) & AT91_PMC_OSCSEL);
+}
+
+static const struct clk_ops sam9260_slow_ops = {
+ .get_parent = clk_sam9260_slow_get_parent,
+};
+
+static struct clk * __init
+at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
+ const char *name,
+ const char **parent_names,
+ int num_parents)
+{
+ struct clk_sam9260_slow *slowck;
+ struct clk *clk = NULL;
+ struct clk_init_data init;
+
+ if (!pmc || !name)
+ return ERR_PTR(-EINVAL);
+
+ if (!parent_names || !num_parents)
+ return ERR_PTR(-EINVAL);
+
+ slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
+ if (!slowck)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &sam9260_slow_ops;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+ init.flags = 0;
+
+ slowck->hw.init = &init;
+ slowck->pmc = pmc;
+
+ clk = clk_register(NULL, &slowck->hw);
+ if (IS_ERR(clk))
+ kfree(slowck);
+
+ return clk;
+}
+
+void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
+ struct at91_pmc *pmc)
+{
+ struct clk *clk;
+ const char *parent_names[2];
+ int num_parents;
+ const char *name = np->name;
+ int i;
+
+ num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+ if (num_parents <= 0 || num_parents > 1)
+ return;
+
+ for (i = 0; i < num_parents; ++i) {
+ parent_names[i] = of_clk_get_parent_name(np, i);
+ if (!parent_names[i])
+ return;
+ }
+
+ of_property_read_string(np, "clock-output-names", &name);
+
+ clk = at91_clk_register_sam9260_slow(pmc, name, parent_names,
+ num_parents);
+ if (IS_ERR(clk))
+ return;
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 6a61477a57e0..524196bb35a5 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -229,11 +229,28 @@ out_free_pmc:
}
static const struct of_device_id pmc_clk_ids[] __initconst = {
+ /* Slow oscillator */
+ {
+ .compatible = "atmel,at91sam9260-clk-slow",
+ .data = of_at91sam9260_clk_slow_setup,
+ },
/* Main clock */
{
+ .compatible = "atmel,at91rm9200-clk-main-osc",
+ .data = of_at91rm9200_clk_main_osc_setup,
+ },
+ {
+ .compatible = "atmel,at91sam9x5-clk-main-rc-osc",
+ .data = of_at91sam9x5_clk_main_rc_osc_setup,
+ },
+ {
.compatible = "atmel,at91rm9200-clk-main",
.data = of_at91rm9200_clk_main_setup,
},
+ {
+ .compatible = "atmel,at91sam9x5-clk-main",
+ .data = of_at91sam9x5_clk_main_setup,
+ },
/* PLL clocks */
{
.compatible = "atmel,at91rm9200-clk-pll",
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 441350983ccb..6c7625976113 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -58,8 +58,17 @@ static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value)
int of_at91_get_clk_range(struct device_node *np, const char *propname,
struct clk_range *range);
+extern void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+
+extern void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np,
+ struct at91_pmc *pmc);
+extern void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np,
+ struct at91_pmc *pmc);
extern void __init of_at91rm9200_clk_main_setup(struct device_node *np,
struct at91_pmc *pmc);
+extern void __init of_at91sam9x5_clk_main_setup(struct device_node *np,
+ struct at91_pmc *pmc);
extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
struct at91_pmc *pmc);
diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c
new file mode 100644
index 000000000000..1184d76a7ab7
--- /dev/null
+++ b/drivers/clk/at91/sckc.c
@@ -0,0 +1,57 @@
+/*
+ * drivers/clk/at91/sckc.c
+ *
+ * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.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/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+
+#include "sckc.h"
+
+static const struct of_device_id sckc_clk_ids[] __initconst = {
+ /* Slow clock */
+ {
+ .compatible = "atmel,at91sam9x5-clk-slow-osc",
+ .data = of_at91sam9x5_clk_slow_osc_setup,
+ },
+ {
+ .compatible = "atmel,at91sam9x5-clk-slow-rc-osc",
+ .data = of_at91sam9x5_clk_slow_rc_osc_setup,
+ },
+ {
+ .compatible = "atmel,at91sam9x5-clk-slow",
+ .data = of_at91sam9x5_clk_slow_setup,
+ },
+ { /*sentinel*/ }
+};
+
+static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
+{
+ struct device_node *childnp;
+ void (*clk_setup)(struct device_node *, void __iomem *);
+ const struct of_device_id *clk_id;
+ void __iomem *regbase = of_iomap(np, 0);
+
+ if (!regbase)
+ return;
+
+ for_each_child_of_node(np, childnp) {
+ clk_id = of_match_node(sckc_clk_ids, childnp);
+ if (!clk_id)
+ continue;
+ clk_setup = clk_id->data;
+ clk_setup(childnp, regbase);
+ }
+}
+CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
+ of_at91sam9x5_sckc_setup);
diff --git a/drivers/clk/at91/sckc.h b/drivers/clk/at91/sckc.h
new file mode 100644
index 000000000000..836fcf59820f
--- /dev/null
+++ b/drivers/clk/at91/sckc.h
@@ -0,0 +1,22 @@
+/*
+ * drivers/clk/at91/sckc.h
+ *
+ * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.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.
+ */
+
+#ifndef __AT91_SCKC_H_
+#define __AT91_SCKC_H_
+
+extern void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np,
+ void __iomem *sckcr);
+extern void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np,
+ void __iomem *sckcr);
+extern void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
+ void __iomem *sckcr);
+
+#endif /* __AT91_SCKC_H_ */
diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
index a7262fb8ce55..75506e53075b 100644
--- a/drivers/clk/bcm/Kconfig
+++ b/drivers/clk/bcm/Kconfig
@@ -6,4 +6,4 @@ config CLK_BCM_KONA
help
Enable common clock framework support for Broadcom SoCs
using "Kona" style clock control units, including those
- in the BCM281xx family.
+ in the BCM281xx and BCM21664 families.
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
index cf93359aa862..6297d05a9a10 100644
--- a/drivers/clk/bcm/Makefile
+++ b/drivers/clk/bcm/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
+obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
diff --git a/drivers/clk/bcm/clk-bcm21664.c b/drivers/clk/bcm/clk-bcm21664.c
new file mode 100644
index 000000000000..eeae4cad2281
--- /dev/null
+++ b/drivers/clk/bcm/clk-bcm21664.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ * Copyright 2014 Linaro Limited
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "clk-kona.h"
+#include "dt-bindings/clock/bcm21664.h"
+
+#define BCM21664_CCU_COMMON(_name, _capname) \
+ KONA_CCU_COMMON(BCM21664, _name, _capname)
+
+/* Root CCU */
+
+static struct peri_clk_data frac_1m_data = {
+ .gate = HW_SW_GATE(0x214, 16, 0, 1),
+ .clocks = CLOCKS("ref_crystal"),
+};
+
+static struct ccu_data root_ccu_data = {
+ BCM21664_CCU_COMMON(root, ROOT),
+ /* no policy control */
+ .kona_clks = {
+ [BCM21664_ROOT_CCU_FRAC_1M] =
+ KONA_CLK(root, frac_1m, peri),
+ [BCM21664_ROOT_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* AON CCU */
+
+static struct peri_clk_data hub_timer_data = {
+ .gate = HW_SW_GATE(0x0414, 16, 0, 1),
+ .hyst = HYST(0x0414, 8, 9),
+ .clocks = CLOCKS("bbl_32k",
+ "frac_1m",
+ "dft_19_5m"),
+ .sel = SELECTOR(0x0a10, 0, 2),
+ .trig = TRIGGER(0x0a40, 4),
+};
+
+static struct ccu_data aon_ccu_data = {
+ BCM21664_CCU_COMMON(aon, AON),
+ .policy = {
+ .enable = CCU_LVM_EN(0x0034, 0),
+ .control = CCU_POLICY_CTL(0x000c, 0, 1, 2),
+ },
+ .kona_clks = {
+ [BCM21664_AON_CCU_HUB_TIMER] =
+ KONA_CLK(aon, hub_timer, peri),
+ [BCM21664_AON_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* Master CCU */
+
+static struct peri_clk_data sdio1_data = {
+ .gate = HW_SW_GATE(0x0358, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_52m",
+ "ref_52m",
+ "var_96m",
+ "ref_96m"),
+ .sel = SELECTOR(0x0a28, 0, 3),
+ .div = DIVIDER(0x0a28, 4, 14),
+ .trig = TRIGGER(0x0afc, 9),
+};
+
+static struct peri_clk_data sdio2_data = {
+ .gate = HW_SW_GATE(0x035c, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_52m",
+ "ref_52m",
+ "var_96m",
+ "ref_96m"),
+ .sel = SELECTOR(0x0a2c, 0, 3),
+ .div = DIVIDER(0x0a2c, 4, 14),
+ .trig = TRIGGER(0x0afc, 10),
+};
+
+static struct peri_clk_data sdio3_data = {
+ .gate = HW_SW_GATE(0x0364, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_52m",
+ "ref_52m",
+ "var_96m",
+ "ref_96m"),
+ .sel = SELECTOR(0x0a34, 0, 3),
+ .div = DIVIDER(0x0a34, 4, 14),
+ .trig = TRIGGER(0x0afc, 12),
+};
+
+static struct peri_clk_data sdio4_data = {
+ .gate = HW_SW_GATE(0x0360, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_52m",
+ "ref_52m",
+ "var_96m",
+ "ref_96m"),
+ .sel = SELECTOR(0x0a30, 0, 3),
+ .div = DIVIDER(0x0a30, 4, 14),
+ .trig = TRIGGER(0x0afc, 11),
+};
+
+static struct peri_clk_data sdio1_sleep_data = {
+ .clocks = CLOCKS("ref_32k"), /* Verify */
+ .gate = HW_SW_GATE(0x0358, 18, 2, 3),
+};
+
+static struct peri_clk_data sdio2_sleep_data = {
+ .clocks = CLOCKS("ref_32k"), /* Verify */
+ .gate = HW_SW_GATE(0x035c, 18, 2, 3),
+};
+
+static struct peri_clk_data sdio3_sleep_data = {
+ .clocks = CLOCKS("ref_32k"), /* Verify */
+ .gate = HW_SW_GATE(0x0364, 18, 2, 3),
+};
+
+static struct peri_clk_data sdio4_sleep_data = {
+ .clocks = CLOCKS("ref_32k"), /* Verify */
+ .gate = HW_SW_GATE(0x0360, 18, 2, 3),
+};
+
+static struct ccu_data master_ccu_data = {
+ BCM21664_CCU_COMMON(master, MASTER),
+ .policy = {
+ .enable = CCU_LVM_EN(0x0034, 0),
+ .control = CCU_POLICY_CTL(0x000c, 0, 1, 2),
+ },
+ .kona_clks = {
+ [BCM21664_MASTER_CCU_SDIO1] =
+ KONA_CLK(master, sdio1, peri),
+ [BCM21664_MASTER_CCU_SDIO2] =
+ KONA_CLK(master, sdio2, peri),
+ [BCM21664_MASTER_CCU_SDIO3] =
+ KONA_CLK(master, sdio3, peri),
+ [BCM21664_MASTER_CCU_SDIO4] =
+ KONA_CLK(master, sdio4, peri),
+ [BCM21664_MASTER_CCU_SDIO1_SLEEP] =
+ KONA_CLK(master, sdio1_sleep, peri),
+ [BCM21664_MASTER_CCU_SDIO2_SLEEP] =
+ KONA_CLK(master, sdio2_sleep, peri),
+ [BCM21664_MASTER_CCU_SDIO3_SLEEP] =
+ KONA_CLK(master, sdio3_sleep, peri),
+ [BCM21664_MASTER_CCU_SDIO4_SLEEP] =
+ KONA_CLK(master, sdio4_sleep, peri),
+ [BCM21664_MASTER_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* Slave CCU */
+
+static struct peri_clk_data uartb_data = {
+ .gate = HW_SW_GATE(0x0400, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_156m",
+ "ref_156m"),
+ .sel = SELECTOR(0x0a10, 0, 2),
+ .div = FRAC_DIVIDER(0x0a10, 4, 12, 8),
+ .trig = TRIGGER(0x0afc, 2),
+};
+
+static struct peri_clk_data uartb2_data = {
+ .gate = HW_SW_GATE(0x0404, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_156m",
+ "ref_156m"),
+ .sel = SELECTOR(0x0a14, 0, 2),
+ .div = FRAC_DIVIDER(0x0a14, 4, 12, 8),
+ .trig = TRIGGER(0x0afc, 3),
+};
+
+static struct peri_clk_data uartb3_data = {
+ .gate = HW_SW_GATE(0x0408, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_156m",
+ "ref_156m"),
+ .sel = SELECTOR(0x0a18, 0, 2),
+ .div = FRAC_DIVIDER(0x0a18, 4, 12, 8),
+ .trig = TRIGGER(0x0afc, 4),
+};
+
+static struct peri_clk_data bsc1_data = {
+ .gate = HW_SW_GATE(0x0458, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_104m",
+ "ref_104m",
+ "var_13m",
+ "ref_13m"),
+ .sel = SELECTOR(0x0a64, 0, 3),
+ .trig = TRIGGER(0x0afc, 23),
+};
+
+static struct peri_clk_data bsc2_data = {
+ .gate = HW_SW_GATE(0x045c, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_104m",
+ "ref_104m",
+ "var_13m",
+ "ref_13m"),
+ .sel = SELECTOR(0x0a68, 0, 3),
+ .trig = TRIGGER(0x0afc, 24),
+};
+
+static struct peri_clk_data bsc3_data = {
+ .gate = HW_SW_GATE(0x0470, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_104m",
+ "ref_104m",
+ "var_13m",
+ "ref_13m"),
+ .sel = SELECTOR(0x0a7c, 0, 3),
+ .trig = TRIGGER(0x0afc, 18),
+};
+
+static struct peri_clk_data bsc4_data = {
+ .gate = HW_SW_GATE(0x0474, 18, 2, 3),
+ .clocks = CLOCKS("ref_crystal",
+ "var_104m",
+ "ref_104m",
+ "var_13m",
+ "ref_13m"),
+ .sel = SELECTOR(0x0a80, 0, 3),
+ .trig = TRIGGER(0x0afc, 19),
+};
+
+static struct ccu_data slave_ccu_data = {
+ BCM21664_CCU_COMMON(slave, SLAVE),
+ .policy = {
+ .enable = CCU_LVM_EN(0x0034, 0),
+ .control = CCU_POLICY_CTL(0x000c, 0, 1, 2),
+ },
+ .kona_clks = {
+ [BCM21664_SLAVE_CCU_UARTB] =
+ KONA_CLK(slave, uartb, peri),
+ [BCM21664_SLAVE_CCU_UARTB2] =
+ KONA_CLK(slave, uartb2, peri),
+ [BCM21664_SLAVE_CCU_UARTB3] =
+ KONA_CLK(slave, uartb3, peri),
+ [BCM21664_SLAVE_CCU_BSC1] =
+ KONA_CLK(slave, bsc1, peri),
+ [BCM21664_SLAVE_CCU_BSC2] =
+ KONA_CLK(slave, bsc2, peri),
+ [BCM21664_SLAVE_CCU_BSC3] =
+ KONA_CLK(slave, bsc3, peri),
+ [BCM21664_SLAVE_CCU_BSC4] =
+ KONA_CLK(slave, bsc4, peri),
+ [BCM21664_SLAVE_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* Device tree match table callback functions */
+
+static void __init kona_dt_root_ccu_setup(struct device_node *node)
+{
+ kona_dt_ccu_setup(&root_ccu_data, node);
+}
+
+static void __init kona_dt_aon_ccu_setup(struct device_node *node)
+{
+ kona_dt_ccu_setup(&aon_ccu_data, node);
+}
+
+static void __init kona_dt_master_ccu_setup(struct device_node *node)
+{
+ kona_dt_ccu_setup(&master_ccu_data, node);
+}
+
+static void __init kona_dt_slave_ccu_setup(struct device_node *node)
+{
+ kona_dt_ccu_setup(&slave_ccu_data, node);
+}
+
+CLK_OF_DECLARE(bcm21664_root_ccu, BCM21664_DT_ROOT_CCU_COMPAT,
+ kona_dt_root_ccu_setup);
+CLK_OF_DECLARE(bcm21664_aon_ccu, BCM21664_DT_AON_CCU_COMPAT,
+ kona_dt_aon_ccu_setup);
+CLK_OF_DECLARE(bcm21664_master_ccu, BCM21664_DT_MASTER_CCU_COMPAT,
+ kona_dt_master_ccu_setup);
+CLK_OF_DECLARE(bcm21664_slave_ccu, BCM21664_DT_SLAVE_CCU_COMPAT,
+ kona_dt_slave_ccu_setup);
diff --git a/drivers/clk/bcm/clk-bcm281xx.c b/drivers/clk/bcm/clk-bcm281xx.c
index 3c66de696aeb..502a487d62c5 100644
--- a/drivers/clk/bcm/clk-bcm281xx.c
+++ b/drivers/clk/bcm/clk-bcm281xx.c
@@ -15,14 +15,10 @@
#include "clk-kona.h"
#include "dt-bindings/clock/bcm281xx.h"
-/* bcm11351 CCU device tree "compatible" strings */
-#define BCM11351_DT_ROOT_CCU_COMPAT "brcm,bcm11351-root-ccu"
-#define BCM11351_DT_AON_CCU_COMPAT "brcm,bcm11351-aon-ccu"
-#define BCM11351_DT_HUB_CCU_COMPAT "brcm,bcm11351-hub-ccu"
-#define BCM11351_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu"
-#define BCM11351_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu"
+#define BCM281XX_CCU_COMMON(_name, _ucase_name) \
+ KONA_CCU_COMMON(BCM281XX, _name, _ucase_name)
-/* Root CCU clocks */
+/* Root CCU */
static struct peri_clk_data frac_1m_data = {
.gate = HW_SW_GATE(0x214, 16, 0, 1),
@@ -31,7 +27,16 @@ static struct peri_clk_data frac_1m_data = {
.clocks = CLOCKS("ref_crystal"),
};
-/* AON CCU clocks */
+static struct ccu_data root_ccu_data = {
+ BCM281XX_CCU_COMMON(root, ROOT),
+ .kona_clks = {
+ [BCM281XX_ROOT_CCU_FRAC_1M] =
+ KONA_CLK(root, frac_1m, peri),
+ [BCM281XX_ROOT_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* AON CCU */
static struct peri_clk_data hub_timer_data = {
.gate = HW_SW_GATE(0x0414, 16, 0, 1),
@@ -60,7 +65,20 @@ static struct peri_clk_data pmu_bsc_var_data = {
.trig = TRIGGER(0x0a40, 2),
};
-/* Hub CCU clocks */
+static struct ccu_data aon_ccu_data = {
+ BCM281XX_CCU_COMMON(aon, AON),
+ .kona_clks = {
+ [BCM281XX_AON_CCU_HUB_TIMER] =
+ KONA_CLK(aon, hub_timer, peri),
+ [BCM281XX_AON_CCU_PMU_BSC] =
+ KONA_CLK(aon, pmu_bsc, peri),
+ [BCM281XX_AON_CCU_PMU_BSC_VAR] =
+ KONA_CLK(aon, pmu_bsc_var, peri),
+ [BCM281XX_AON_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* Hub CCU */
static struct peri_clk_data tmon_1m_data = {
.gate = HW_SW_GATE(0x04a4, 18, 2, 3),
@@ -70,7 +88,16 @@ static struct peri_clk_data tmon_1m_data = {
.trig = TRIGGER(0x0e84, 1),
};
-/* Master CCU clocks */
+static struct ccu_data hub_ccu_data = {
+ BCM281XX_CCU_COMMON(hub, HUB),
+ .kona_clks = {
+ [BCM281XX_HUB_CCU_TMON_1M] =
+ KONA_CLK(hub, tmon_1m, peri),
+ [BCM281XX_HUB_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* Master CCU */
static struct peri_clk_data sdio1_data = {
.gate = HW_SW_GATE(0x0358, 18, 2, 3),
@@ -153,7 +180,28 @@ static struct peri_clk_data hsic2_12m_data = {
.trig = TRIGGER(0x0afc, 5),
};
-/* Slave CCU clocks */
+static struct ccu_data master_ccu_data = {
+ BCM281XX_CCU_COMMON(master, MASTER),
+ .kona_clks = {
+ [BCM281XX_MASTER_CCU_SDIO1] =
+ KONA_CLK(master, sdio1, peri),
+ [BCM281XX_MASTER_CCU_SDIO2] =
+ KONA_CLK(master, sdio2, peri),
+ [BCM281XX_MASTER_CCU_SDIO3] =
+ KONA_CLK(master, sdio3, peri),
+ [BCM281XX_MASTER_CCU_SDIO4] =
+ KONA_CLK(master, sdio4, peri),
+ [BCM281XX_MASTER_CCU_USB_IC] =
+ KONA_CLK(master, usb_ic, peri),
+ [BCM281XX_MASTER_CCU_HSIC2_48M] =
+ KONA_CLK(master, hsic2_48m, peri),
+ [BCM281XX_MASTER_CCU_HSIC2_12M] =
+ KONA_CLK(master, hsic2_12m, peri),
+ [BCM281XX_MASTER_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
+
+/* Slave CCU */
static struct peri_clk_data uartb_data = {
.gate = HW_SW_GATE(0x0400, 18, 2, 3),
@@ -261,156 +309,67 @@ static struct peri_clk_data pwm_data = {
.trig = TRIGGER(0x0afc, 15),
};
-/*
- * CCU setup routines
- *
- * These are called from kona_dt_ccu_setup() to initialize the array
- * of clocks provided by the CCU. Once allocated, the entries in
- * the array are initialized by calling kona_clk_setup() with the
- * initialization data for each clock. They return 0 if successful
- * or an error code otherwise.
- */
-static int __init bcm281xx_root_ccu_clks_setup(struct ccu_data *ccu)
-{
- struct clk **clks;
- size_t count = BCM281XX_ROOT_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate root clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_ROOT_CCU_FRAC_1M, frac_1m);
-
- return 0;
-}
-
-static int __init bcm281xx_aon_ccu_clks_setup(struct ccu_data *ccu)
-{
- struct clk **clks;
- size_t count = BCM281XX_AON_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate aon clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_HUB_TIMER, hub_timer);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC, pmu_bsc);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC_VAR, pmu_bsc_var);
-
- return 0;
-}
-
-static int __init bcm281xx_hub_ccu_clks_setup(struct ccu_data *ccu)
-{
- struct clk **clks;
- size_t count = BCM281XX_HUB_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate hub clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_HUB_CCU_TMON_1M, tmon_1m);
-
- return 0;
-}
-
-static int __init bcm281xx_master_ccu_clks_setup(struct ccu_data *ccu)
-{
- struct clk **clks;
- size_t count = BCM281XX_MASTER_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate master clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO1, sdio1);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO2, sdio2);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO3, sdio3);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO4, sdio4);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_USB_IC, usb_ic);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_48M, hsic2_48m);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_12M, hsic2_12m);
-
- return 0;
-}
-
-static int __init bcm281xx_slave_ccu_clks_setup(struct ccu_data *ccu)
-{
- struct clk **clks;
- size_t count = BCM281XX_SLAVE_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate slave clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB, uartb);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB2, uartb2);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB3, uartb3);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB4, uartb4);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP0, ssp0);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP2, ssp2);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC1, bsc1);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC2, bsc2);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC3, bsc3);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_PWM, pwm);
-
- return 0;
-}
+static struct ccu_data slave_ccu_data = {
+ BCM281XX_CCU_COMMON(slave, SLAVE),
+ .kona_clks = {
+ [BCM281XX_SLAVE_CCU_UARTB] =
+ KONA_CLK(slave, uartb, peri),
+ [BCM281XX_SLAVE_CCU_UARTB2] =
+ KONA_CLK(slave, uartb2, peri),
+ [BCM281XX_SLAVE_CCU_UARTB3] =
+ KONA_CLK(slave, uartb3, peri),
+ [BCM281XX_SLAVE_CCU_UARTB4] =
+ KONA_CLK(slave, uartb4, peri),
+ [BCM281XX_SLAVE_CCU_SSP0] =
+ KONA_CLK(slave, ssp0, peri),
+ [BCM281XX_SLAVE_CCU_SSP2] =
+ KONA_CLK(slave, ssp2, peri),
+ [BCM281XX_SLAVE_CCU_BSC1] =
+ KONA_CLK(slave, bsc1, peri),
+ [BCM281XX_SLAVE_CCU_BSC2] =
+ KONA_CLK(slave, bsc2, peri),
+ [BCM281XX_SLAVE_CCU_BSC3] =
+ KONA_CLK(slave, bsc3, peri),
+ [BCM281XX_SLAVE_CCU_PWM] =
+ KONA_CLK(slave, pwm, peri),
+ [BCM281XX_SLAVE_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
+};
/* Device tree match table callback functions */
static void __init kona_dt_root_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_root_ccu_clks_setup);
+ kona_dt_ccu_setup(&root_ccu_data, node);
}
static void __init kona_dt_aon_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_aon_ccu_clks_setup);
+ kona_dt_ccu_setup(&aon_ccu_data, node);
}
static void __init kona_dt_hub_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_hub_ccu_clks_setup);
+ kona_dt_ccu_setup(&hub_ccu_data, node);
}
static void __init kona_dt_master_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_master_ccu_clks_setup);
+ kona_dt_ccu_setup(&master_ccu_data, node);
}
static void __init kona_dt_slave_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_slave_ccu_clks_setup);
+ kona_dt_ccu_setup(&slave_ccu_data, node);
}
-CLK_OF_DECLARE(bcm11351_root_ccu, BCM11351_DT_ROOT_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_root_ccu, BCM281XX_DT_ROOT_CCU_COMPAT,
kona_dt_root_ccu_setup);
-CLK_OF_DECLARE(bcm11351_aon_ccu, BCM11351_DT_AON_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_aon_ccu, BCM281XX_DT_AON_CCU_COMPAT,
kona_dt_aon_ccu_setup);
-CLK_OF_DECLARE(bcm11351_hub_ccu, BCM11351_DT_HUB_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_hub_ccu, BCM281XX_DT_HUB_CCU_COMPAT,
kona_dt_hub_ccu_setup);
-CLK_OF_DECLARE(bcm11351_master_ccu, BCM11351_DT_MASTER_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_master_ccu, BCM281XX_DT_MASTER_CCU_COMPAT,
kona_dt_master_ccu_setup);
-CLK_OF_DECLARE(bcm11351_slave_ccu, BCM11351_DT_SLAVE_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_slave_ccu, BCM281XX_DT_SLAVE_CCU_COMPAT,
kona_dt_slave_ccu_setup);
diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c
index 54a06526f64f..e5aededdd322 100644
--- a/drivers/clk/bcm/clk-kona-setup.c
+++ b/drivers/clk/bcm/clk-kona-setup.c
@@ -25,6 +25,31 @@ LIST_HEAD(ccu_list); /* The list of set up CCUs */
/* Validity checking */
+static bool ccu_data_offsets_valid(struct ccu_data *ccu)
+{
+ struct ccu_policy *ccu_policy = &ccu->policy;
+ u32 limit;
+
+ limit = ccu->range - sizeof(u32);
+ limit = round_down(limit, sizeof(u32));
+ if (ccu_policy_exists(ccu_policy)) {
+ if (ccu_policy->enable.offset > limit) {
+ pr_err("%s: bad policy enable offset for %s "
+ "(%u > %u)\n", __func__,
+ ccu->name, ccu_policy->enable.offset, limit);
+ return false;
+ }
+ if (ccu_policy->control.offset > limit) {
+ pr_err("%s: bad policy control offset for %s "
+ "(%u > %u)\n", __func__,
+ ccu->name, ccu_policy->control.offset, limit);
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool clk_requires_trigger(struct kona_clk *bcm_clk)
{
struct peri_clk_data *peri = bcm_clk->u.peri;
@@ -54,7 +79,9 @@ static bool clk_requires_trigger(struct kona_clk *bcm_clk)
static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk)
{
struct peri_clk_data *peri;
+ struct bcm_clk_policy *policy;
struct bcm_clk_gate *gate;
+ struct bcm_clk_hyst *hyst;
struct bcm_clk_div *div;
struct bcm_clk_sel *sel;
struct bcm_clk_trig *trig;
@@ -64,19 +91,41 @@ static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk)
BUG_ON(bcm_clk->type != bcm_clk_peri);
peri = bcm_clk->u.peri;
- name = bcm_clk->name;
+ name = bcm_clk->init_data.name;
range = bcm_clk->ccu->range;
limit = range - sizeof(u32);
limit = round_down(limit, sizeof(u32));
+ policy = &peri->policy;
+ if (policy_exists(policy)) {
+ if (policy->offset > limit) {
+ pr_err("%s: bad policy offset for %s (%u > %u)\n",
+ __func__, name, policy->offset, limit);
+ return false;
+ }
+ }
+
gate = &peri->gate;
+ hyst = &peri->hyst;
if (gate_exists(gate)) {
if (gate->offset > limit) {
pr_err("%s: bad gate offset for %s (%u > %u)\n",
__func__, name, gate->offset, limit);
return false;
}
+
+ if (hyst_exists(hyst)) {
+ if (hyst->offset > limit) {
+ pr_err("%s: bad hysteresis offset for %s "
+ "(%u > %u)\n", __func__,
+ name, hyst->offset, limit);
+ return false;
+ }
+ }
+ } else if (hyst_exists(hyst)) {
+ pr_err("%s: hysteresis but no gate for %s\n", __func__, name);
+ return false;
}
div = &peri->div;
@@ -167,6 +216,36 @@ static bool bitfield_valid(u32 shift, u32 width, const char *field_name,
return true;
}
+static bool
+ccu_policy_valid(struct ccu_policy *ccu_policy, const char *ccu_name)
+{
+ struct bcm_lvm_en *enable = &ccu_policy->enable;
+ struct bcm_policy_ctl *control;
+
+ if (!bit_posn_valid(enable->bit, "policy enable", ccu_name))
+ return false;
+
+ control = &ccu_policy->control;
+ if (!bit_posn_valid(control->go_bit, "policy control GO", ccu_name))
+ return false;
+
+ if (!bit_posn_valid(control->atl_bit, "policy control ATL", ccu_name))
+ return false;
+
+ if (!bit_posn_valid(control->ac_bit, "policy control AC", ccu_name))
+ return false;
+
+ return true;
+}
+
+static bool policy_valid(struct bcm_clk_policy *policy, const char *clock_name)
+{
+ if (!bit_posn_valid(policy->bit, "policy", clock_name))
+ return false;
+
+ return true;
+}
+
/*
* All gates, if defined, have a status bit, and for hardware-only
* gates, that's it. Gates that can be software controlled also
@@ -196,6 +275,17 @@ static bool gate_valid(struct bcm_clk_gate *gate, const char *field_name,
return true;
}
+static bool hyst_valid(struct bcm_clk_hyst *hyst, const char *clock_name)
+{
+ if (!bit_posn_valid(hyst->en_bit, "hysteresis enable", clock_name))
+ return false;
+
+ if (!bit_posn_valid(hyst->val_bit, "hysteresis value", clock_name))
+ return false;
+
+ return true;
+}
+
/*
* A selector bitfield must be valid. Its parent_sel array must
* also be reasonable for the field.
@@ -312,7 +402,9 @@ static bool
peri_clk_data_valid(struct kona_clk *bcm_clk)
{
struct peri_clk_data *peri;
+ struct bcm_clk_policy *policy;
struct bcm_clk_gate *gate;
+ struct bcm_clk_hyst *hyst;
struct bcm_clk_sel *sel;
struct bcm_clk_div *div;
struct bcm_clk_div *pre_div;
@@ -330,11 +422,20 @@ peri_clk_data_valid(struct kona_clk *bcm_clk)
return false;
peri = bcm_clk->u.peri;
- name = bcm_clk->name;
+ name = bcm_clk->init_data.name;
+
+ policy = &peri->policy;
+ if (policy_exists(policy) && !policy_valid(policy, name))
+ return false;
+
gate = &peri->gate;
if (gate_exists(gate) && !gate_valid(gate, "gate", name))
return false;
+ hyst = &peri->hyst;
+ if (hyst_exists(hyst) && !hyst_valid(hyst, name))
+ return false;
+
sel = &peri->sel;
if (selector_exists(sel)) {
if (!sel_valid(sel, "selector", name))
@@ -567,7 +668,6 @@ static void peri_clk_teardown(struct peri_clk_data *data,
struct clk_init_data *init_data)
{
clk_sel_teardown(&data->sel, init_data);
- init_data->ops = NULL;
}
/*
@@ -576,10 +676,9 @@ static void peri_clk_teardown(struct peri_clk_data *data,
* that can be assigned if the clock has one or more parent clocks
* associated with it.
*/
-static int peri_clk_setup(struct ccu_data *ccu, struct peri_clk_data *data,
- struct clk_init_data *init_data)
+static int
+peri_clk_setup(struct peri_clk_data *data, struct clk_init_data *init_data)
{
- init_data->ops = &kona_peri_clk_ops;
init_data->flags = CLK_IGNORE_UNUSED;
return clk_sel_setup(data->clocks, &data->sel, init_data);
@@ -617,39 +716,26 @@ static void kona_clk_teardown(struct clk *clk)
bcm_clk_teardown(bcm_clk);
}
-struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
- enum bcm_clk_type type, void *data)
+struct clk *kona_clk_setup(struct kona_clk *bcm_clk)
{
- struct kona_clk *bcm_clk;
- struct clk_init_data *init_data;
+ struct clk_init_data *init_data = &bcm_clk->init_data;
struct clk *clk = NULL;
- bcm_clk = kzalloc(sizeof(*bcm_clk), GFP_KERNEL);
- if (!bcm_clk) {
- pr_err("%s: failed to allocate bcm_clk for %s\n", __func__,
- name);
- return NULL;
- }
- bcm_clk->ccu = ccu;
- bcm_clk->name = name;
-
- init_data = &bcm_clk->init_data;
- init_data->name = name;
- switch (type) {
+ switch (bcm_clk->type) {
case bcm_clk_peri:
- if (peri_clk_setup(ccu, data, init_data))
- goto out_free;
+ if (peri_clk_setup(bcm_clk->u.data, init_data))
+ return NULL;
break;
default:
- data = NULL;
- break;
+ pr_err("%s: clock type %d invalid for %s\n", __func__,
+ (int)bcm_clk->type, init_data->name);
+ return NULL;
}
- bcm_clk->type = type;
- bcm_clk->u.data = data;
/* Make sure everything makes sense before we set it up */
if (!kona_clk_valid(bcm_clk)) {
- pr_err("%s: clock data invalid for %s\n", __func__, name);
+ pr_err("%s: clock data invalid for %s\n", __func__,
+ init_data->name);
goto out_teardown;
}
@@ -657,7 +743,7 @@ struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
clk = clk_register(NULL, &bcm_clk->hw);
if (IS_ERR(clk)) {
pr_err("%s: error registering clock %s (%ld)\n", __func__,
- name, PTR_ERR(clk));
+ init_data->name, PTR_ERR(clk));
goto out_teardown;
}
BUG_ON(!clk);
@@ -665,8 +751,6 @@ struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
return clk;
out_teardown:
bcm_clk_teardown(bcm_clk);
-out_free:
- kfree(bcm_clk);
return NULL;
}
@@ -675,50 +759,64 @@ static void ccu_clks_teardown(struct ccu_data *ccu)
{
u32 i;
- for (i = 0; i < ccu->data.clk_num; i++)
- kona_clk_teardown(ccu->data.clks[i]);
- kfree(ccu->data.clks);
+ for (i = 0; i < ccu->clk_data.clk_num; i++)
+ kona_clk_teardown(ccu->clk_data.clks[i]);
+ kfree(ccu->clk_data.clks);
}
static void kona_ccu_teardown(struct ccu_data *ccu)
{
- if (!ccu)
- return;
-
+ kfree(ccu->clk_data.clks);
+ ccu->clk_data.clks = NULL;
if (!ccu->base)
- goto done;
+ return;
of_clk_del_provider(ccu->node); /* safe if never added */
ccu_clks_teardown(ccu);
list_del(&ccu->links);
of_node_put(ccu->node);
+ ccu->node = NULL;
iounmap(ccu->base);
-done:
- kfree(ccu->name);
- kfree(ccu);
+ ccu->base = NULL;
+}
+
+static bool ccu_data_valid(struct ccu_data *ccu)
+{
+ struct ccu_policy *ccu_policy;
+
+ if (!ccu_data_offsets_valid(ccu))
+ return false;
+
+ ccu_policy = &ccu->policy;
+ if (ccu_policy_exists(ccu_policy))
+ if (!ccu_policy_valid(ccu_policy, ccu->name))
+ return false;
+
+ return true;
}
/*
* Set up a CCU. Call the provided ccu_clks_setup callback to
* initialize the array of clocks provided by the CCU.
*/
-void __init kona_dt_ccu_setup(struct device_node *node,
- int (*ccu_clks_setup)(struct ccu_data *))
+void __init kona_dt_ccu_setup(struct ccu_data *ccu,
+ struct device_node *node)
{
- struct ccu_data *ccu;
struct resource res = { 0 };
resource_size_t range;
+ unsigned int i;
int ret;
- ccu = kzalloc(sizeof(*ccu), GFP_KERNEL);
- if (ccu)
- ccu->name = kstrdup(node->name, GFP_KERNEL);
- if (!ccu || !ccu->name) {
- pr_err("%s: unable to allocate CCU struct for %s\n",
- __func__, node->name);
- kfree(ccu);
+ if (ccu->clk_data.clk_num) {
+ size_t size;
- return;
+ size = ccu->clk_data.clk_num * sizeof(*ccu->clk_data.clks);
+ ccu->clk_data.clks = kzalloc(size, GFP_KERNEL);
+ if (!ccu->clk_data.clks) {
+ pr_err("%s: unable to allocate %u clocks for %s\n",
+ __func__, ccu->clk_data.clk_num, node->name);
+ return;
+ }
}
ret = of_address_to_resource(node, 0, &res);
@@ -736,24 +834,33 @@ void __init kona_dt_ccu_setup(struct device_node *node,
}
ccu->range = (u32)range;
+
+ if (!ccu_data_valid(ccu)) {
+ pr_err("%s: ccu data not valid for %s\n", __func__, node->name);
+ goto out_err;
+ }
+
ccu->base = ioremap(res.start, ccu->range);
if (!ccu->base) {
pr_err("%s: unable to map CCU registers for %s\n", __func__,
node->name);
goto out_err;
}
-
- spin_lock_init(&ccu->lock);
- INIT_LIST_HEAD(&ccu->links);
ccu->node = of_node_get(node);
-
list_add_tail(&ccu->links, &ccu_list);
- /* Set up clocks array (in ccu->data) */
- if (ccu_clks_setup(ccu))
- goto out_err;
+ /*
+ * Set up each defined kona clock and save the result in
+ * the clock framework clock array (in ccu->data). Then
+ * register as a provider for these clocks.
+ */
+ for (i = 0; i < ccu->clk_data.clk_num; i++) {
+ if (!ccu->kona_clks[i].ccu)
+ continue;
+ ccu->clk_data.clks[i] = kona_clk_setup(&ccu->kona_clks[i]);
+ }
- ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->data);
+ ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->clk_data);
if (ret) {
pr_err("%s: error adding ccu %s as provider (%d)\n", __func__,
node->name, ret);
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index db11a87449f2..95af2e665dd3 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -16,6 +16,14 @@
#include <linux/delay.h>
+/*
+ * "Policies" affect the frequencies of bus clocks provided by a
+ * CCU. (I believe these polices are named "Deep Sleep", "Economy",
+ * "Normal", and "Turbo".) A lower policy number has lower power
+ * consumption, and policy 2 is the default.
+ */
+#define CCU_POLICY_COUNT 4
+
#define CCU_ACCESS_PASSWORD 0xA5A500
#define CLK_GATE_DELAY_LOOP 2000
@@ -207,9 +215,154 @@ __ccu_wait_bit(struct ccu_data *ccu, u32 reg_offset, u32 bit, bool want)
return true;
udelay(1);
}
+ pr_warn("%s: %s/0x%04x bit %u was never %s\n", __func__,
+ ccu->name, reg_offset, bit, want ? "set" : "clear");
+
return false;
}
+/* Policy operations */
+
+static bool __ccu_policy_engine_start(struct ccu_data *ccu, bool sync)
+{
+ struct bcm_policy_ctl *control = &ccu->policy.control;
+ u32 offset;
+ u32 go_bit;
+ u32 mask;
+ bool ret;
+
+ /* If we don't need to control policy for this CCU, we're done. */
+ if (!policy_ctl_exists(control))
+ return true;
+
+ offset = control->offset;
+ go_bit = control->go_bit;
+
+ /* Ensure we're not busy before we start */
+ ret = __ccu_wait_bit(ccu, offset, go_bit, false);
+ if (!ret) {
+ pr_err("%s: ccu %s policy engine wouldn't go idle\n",
+ __func__, ccu->name);
+ return false;
+ }
+
+ /*
+ * If it's a synchronous request, we'll wait for the voltage
+ * and frequency of the active load to stabilize before
+ * returning. To do this we select the active load by
+ * setting the ATL bit.
+ *
+ * An asynchronous request instead ramps the voltage in the
+ * background, and when that process stabilizes, the target
+ * load is copied to the active load and the CCU frequency
+ * is switched. We do this by selecting the target load
+ * (ATL bit clear) and setting the request auto-copy (AC bit
+ * set).
+ *
+ * Note, we do NOT read-modify-write this register.
+ */
+ mask = (u32)1 << go_bit;
+ if (sync)
+ mask |= 1 << control->atl_bit;
+ else
+ mask |= 1 << control->ac_bit;
+ __ccu_write(ccu, offset, mask);
+
+ /* Wait for indication that operation is complete. */
+ ret = __ccu_wait_bit(ccu, offset, go_bit, false);
+ if (!ret)
+ pr_err("%s: ccu %s policy engine never started\n",
+ __func__, ccu->name);
+
+ return ret;
+}
+
+static bool __ccu_policy_engine_stop(struct ccu_data *ccu)
+{
+ struct bcm_lvm_en *enable = &ccu->policy.enable;
+ u32 offset;
+ u32 enable_bit;
+ bool ret;
+
+ /* If we don't need to control policy for this CCU, we're done. */
+ if (!policy_lvm_en_exists(enable))
+ return true;
+
+ /* Ensure we're not busy before we start */
+ offset = enable->offset;
+ enable_bit = enable->bit;
+ ret = __ccu_wait_bit(ccu, offset, enable_bit, false);
+ if (!ret) {
+ pr_err("%s: ccu %s policy engine already stopped\n",
+ __func__, ccu->name);
+ return false;
+ }
+
+ /* Now set the bit to stop the engine (NO read-modify-write) */
+ __ccu_write(ccu, offset, (u32)1 << enable_bit);
+
+ /* Wait for indication that it has stopped. */
+ ret = __ccu_wait_bit(ccu, offset, enable_bit, false);
+ if (!ret)
+ pr_err("%s: ccu %s policy engine never stopped\n",
+ __func__, ccu->name);
+
+ return ret;
+}
+
+/*
+ * A CCU has four operating conditions ("policies"), and some clocks
+ * can be disabled or enabled based on which policy is currently in
+ * effect. Such clocks have a bit in a "policy mask" register for
+ * each policy indicating whether the clock is enabled for that
+ * policy or not. The bit position for a clock is the same for all
+ * four registers, and the 32-bit registers are at consecutive
+ * addresses.
+ */
+static bool policy_init(struct ccu_data *ccu, struct bcm_clk_policy *policy)
+{
+ u32 offset;
+ u32 mask;
+ int i;
+ bool ret;
+
+ if (!policy_exists(policy))
+ return true;
+
+ /*
+ * We need to stop the CCU policy engine to allow update
+ * of our policy bits.
+ */
+ if (!__ccu_policy_engine_stop(ccu)) {
+ pr_err("%s: unable to stop CCU %s policy engine\n",
+ __func__, ccu->name);
+ return false;
+ }
+
+ /*
+ * For now, if a clock defines its policy bit we just mark
+ * it "enabled" for all four policies.
+ */
+ offset = policy->offset;
+ mask = (u32)1 << policy->bit;
+ for (i = 0; i < CCU_POLICY_COUNT; i++) {
+ u32 reg_val;
+
+ reg_val = __ccu_read(ccu, offset);
+ reg_val |= mask;
+ __ccu_write(ccu, offset, reg_val);
+ offset += sizeof(u32);
+ }
+
+ /* We're done updating; fire up the policy engine again. */
+ ret = __ccu_policy_engine_start(ccu, true);
+ if (!ret)
+ pr_err("%s: unable to restart CCU %s policy engine\n",
+ __func__, ccu->name);
+
+ return ret;
+}
+
/* Gate operations */
/* Determine whether a clock is gated. CCU lock must be held. */
@@ -374,6 +527,35 @@ static int clk_gate(struct ccu_data *ccu, const char *name,
return -EIO;
}
+/* Hysteresis operations */
+
+/*
+ * If a clock gate requires a turn-off delay it will have
+ * "hysteresis" register bits defined. The first, if set, enables
+ * the delay; and if enabled, the second bit determines whether the
+ * delay is "low" or "high" (1 means high). For now, if it's
+ * defined for a clock, we set it.
+ */
+static bool hyst_init(struct ccu_data *ccu, struct bcm_clk_hyst *hyst)
+{
+ u32 offset;
+ u32 reg_val;
+ u32 mask;
+
+ if (!hyst_exists(hyst))
+ return true;
+
+ offset = hyst->offset;
+ mask = (u32)1 << hyst->en_bit;
+ mask |= (u32)1 << hyst->val_bit;
+
+ reg_val = __ccu_read(ccu, offset);
+ reg_val |= mask;
+ __ccu_write(ccu, offset, reg_val);
+
+ return true;
+}
+
/* Trigger operations */
/*
@@ -806,7 +988,7 @@ static int kona_peri_clk_enable(struct clk_hw *hw)
struct kona_clk *bcm_clk = to_kona_clk(hw);
struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate;
- return clk_gate(bcm_clk->ccu, bcm_clk->name, gate, true);
+ return clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, true);
}
static void kona_peri_clk_disable(struct clk_hw *hw)
@@ -814,7 +996,7 @@ static void kona_peri_clk_disable(struct clk_hw *hw)
struct kona_clk *bcm_clk = to_kona_clk(hw);
struct bcm_clk_gate *gate = &bcm_clk->u.peri->gate;
- (void)clk_gate(bcm_clk->ccu, bcm_clk->name, gate, false);
+ (void)clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, false);
}
static int kona_peri_clk_is_enabled(struct clk_hw *hw)
@@ -849,6 +1031,58 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate,
rate ? rate : 1, *parent_rate, NULL);
}
+static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate, struct clk **best_parent)
+{
+ struct kona_clk *bcm_clk = to_kona_clk(hw);
+ struct clk *clk = hw->clk;
+ struct clk *current_parent;
+ unsigned long parent_rate;
+ unsigned long best_delta;
+ unsigned long best_rate;
+ u32 parent_count;
+ u32 which;
+
+ /*
+ * If there is no other parent to choose, use the current one.
+ * Note: We don't honor (or use) CLK_SET_RATE_NO_REPARENT.
+ */
+ WARN_ON_ONCE(bcm_clk->init_data.flags & CLK_SET_RATE_NO_REPARENT);
+ parent_count = (u32)bcm_clk->init_data.num_parents;
+ if (parent_count < 2)
+ return kona_peri_clk_round_rate(hw, rate, best_parent_rate);
+
+ /* Unless we can do better, stick with current parent */
+ current_parent = clk_get_parent(clk);
+ parent_rate = __clk_get_rate(current_parent);
+ best_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate);
+ best_delta = abs(best_rate - rate);
+
+ /* Check whether any other parent clock can produce a better result */
+ for (which = 0; which < parent_count; which++) {
+ struct clk *parent = clk_get_parent_by_index(clk, which);
+ unsigned long delta;
+ unsigned long other_rate;
+
+ BUG_ON(!parent);
+ if (parent == current_parent)
+ continue;
+
+ /* We don't support CLK_SET_RATE_PARENT */
+ parent_rate = __clk_get_rate(parent);
+ other_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate);
+ delta = abs(other_rate - rate);
+ if (delta < best_delta) {
+ best_delta = delta;
+ best_rate = other_rate;
+ *best_parent = parent;
+ *best_parent_rate = parent_rate;
+ }
+ }
+
+ return best_rate;
+}
+
static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index)
{
struct kona_clk *bcm_clk = to_kona_clk(hw);
@@ -872,12 +1106,13 @@ static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index)
ret = selector_write(bcm_clk->ccu, &data->gate, sel, trig, index);
if (ret == -ENXIO) {
- pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name);
+ pr_err("%s: gating failure for %s\n", __func__,
+ bcm_clk->init_data.name);
ret = -EIO; /* Don't proliferate weird errors */
} else if (ret == -EIO) {
pr_err("%s: %strigger failed for %s\n", __func__,
trig == &data->pre_trig ? "pre-" : "",
- bcm_clk->name);
+ bcm_clk->init_data.name);
}
return ret;
@@ -936,10 +1171,12 @@ static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate,
ret = divider_write(bcm_clk->ccu, &data->gate, &data->div,
&data->trig, scaled_div);
if (ret == -ENXIO) {
- pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name);
+ pr_err("%s: gating failure for %s\n", __func__,
+ bcm_clk->init_data.name);
ret = -EIO; /* Don't proliferate weird errors */
} else if (ret == -EIO) {
- pr_err("%s: trigger failed for %s\n", __func__, bcm_clk->name);
+ pr_err("%s: trigger failed for %s\n", __func__,
+ bcm_clk->init_data.name);
}
return ret;
@@ -950,7 +1187,7 @@ struct clk_ops kona_peri_clk_ops = {
.disable = kona_peri_clk_disable,
.is_enabled = kona_peri_clk_is_enabled,
.recalc_rate = kona_peri_clk_recalc_rate,
- .round_rate = kona_peri_clk_round_rate,
+ .determine_rate = kona_peri_clk_determine_rate,
.set_parent = kona_peri_clk_set_parent,
.get_parent = kona_peri_clk_get_parent,
.set_rate = kona_peri_clk_set_rate,
@@ -961,15 +1198,24 @@ static bool __peri_clk_init(struct kona_clk *bcm_clk)
{
struct ccu_data *ccu = bcm_clk->ccu;
struct peri_clk_data *peri = bcm_clk->u.peri;
- const char *name = bcm_clk->name;
+ const char *name = bcm_clk->init_data.name;
struct bcm_clk_trig *trig;
BUG_ON(bcm_clk->type != bcm_clk_peri);
+ if (!policy_init(ccu, &peri->policy)) {
+ pr_err("%s: error initializing policy for %s\n",
+ __func__, name);
+ return false;
+ }
if (!gate_init(ccu, &peri->gate)) {
pr_err("%s: error initializing gate for %s\n", __func__, name);
return false;
}
+ if (!hyst_init(ccu, &peri->hyst)) {
+ pr_err("%s: error initializing hyst for %s\n", __func__, name);
+ return false;
+ }
if (!div_init(ccu, &peri->gate, &peri->div, &peri->trig)) {
pr_err("%s: error initializing divider for %s\n", __func__,
name);
@@ -1014,13 +1260,13 @@ bool __init kona_ccu_init(struct ccu_data *ccu)
{
unsigned long flags;
unsigned int which;
- struct clk **clks = ccu->data.clks;
+ struct clk **clks = ccu->clk_data.clks;
bool success = true;
flags = ccu_lock(ccu);
__ccu_write_enable(ccu);
- for (which = 0; which < ccu->data.clk_num; which++) {
+ for (which = 0; which < ccu->clk_data.clk_num; which++) {
struct kona_clk *bcm_clk;
if (!clks[which])
diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h
index dee690951bb6..2537b3072910 100644
--- a/drivers/clk/bcm/clk-kona.h
+++ b/drivers/clk/bcm/clk-kona.h
@@ -43,8 +43,14 @@
#define FLAG_FLIP(obj, type, flag) ((obj)->flags ^= FLAG(type, flag))
#define FLAG_TEST(obj, type, flag) (!!((obj)->flags & FLAG(type, flag)))
+/* CCU field state tests */
+
+#define ccu_policy_exists(ccu_policy) ((ccu_policy)->enable.offset != 0)
+
/* Clock field state tests */
+#define policy_exists(policy) ((policy)->offset != 0)
+
#define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS)
#define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED)
#define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW)
@@ -54,6 +60,8 @@
#define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED)
+#define hyst_exists(hyst) ((hyst)->offset != 0)
+
#define divider_exists(div) FLAG_TEST(div, DIV, EXISTS)
#define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED)
#define divider_has_fraction(div) (!divider_is_fixed(div) && \
@@ -62,6 +70,9 @@
#define selector_exists(sel) ((sel)->width != 0)
#define trigger_exists(trig) FLAG_TEST(trig, TRIG, EXISTS)
+#define policy_lvm_en_exists(enable) ((enable)->offset != 0)
+#define policy_ctl_exists(control) ((control)->offset != 0)
+
/* Clock type, used to tell common block what it's part of */
enum bcm_clk_type {
bcm_clk_none, /* undefined clock type */
@@ -71,25 +82,26 @@ enum bcm_clk_type {
};
/*
- * Each CCU defines a mapped area of memory containing registers
- * used to manage clocks implemented by the CCU. Access to memory
- * within the CCU's space is serialized by a spinlock. Before any
- * (other) address can be written, a special access "password" value
- * must be written to its WR_ACCESS register (located at the base
- * address of the range). We keep track of the name of each CCU as
- * it is set up, and maintain them in a list.
+ * CCU policy control for clocks. Clocks can be enabled or disabled
+ * based on the CCU policy in effect. One bit in each policy mask
+ * register (one per CCU policy) represents whether the clock is
+ * enabled when that policy is effect or not. The CCU policy engine
+ * must be stopped to update these bits, and must be restarted again
+ * afterward.
*/
-struct ccu_data {
- void __iomem *base; /* base of mapped address space */
- spinlock_t lock; /* serialization lock */
- bool write_enabled; /* write access is currently enabled */
- struct list_head links; /* for ccu_list */
- struct device_node *node;
- struct clk_onecell_data data;
- const char *name;
- u32 range; /* byte range of address space */
+struct bcm_clk_policy {
+ u32 offset; /* first policy mask register offset */
+ u32 bit; /* bit used in all mask registers */
};
+/* Policy initialization macro */
+
+#define POLICY(_offset, _bit) \
+ { \
+ .offset = (_offset), \
+ .bit = (_bit), \
+ }
+
/*
* Gating control and status is managed by a 32-bit gate register.
*
@@ -195,6 +207,22 @@ struct bcm_clk_gate {
.flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \
}
+/* Gate hysteresis for clocks */
+struct bcm_clk_hyst {
+ u32 offset; /* hyst register offset (normally CLKGATE) */
+ u32 en_bit; /* bit used to enable hysteresis */
+ u32 val_bit; /* if enabled: 0 = low delay; 1 = high delay */
+};
+
+/* Hysteresis initialization macro */
+
+#define HYST(_offset, _en_bit, _val_bit) \
+ { \
+ .offset = (_offset), \
+ .en_bit = (_en_bit), \
+ .val_bit = (_val_bit), \
+ }
+
/*
* Each clock can have zero, one, or two dividers which change the
* output rate of the clock. Each divider can be either fixed or
@@ -360,7 +388,9 @@ struct bcm_clk_trig {
}
struct peri_clk_data {
+ struct bcm_clk_policy policy;
struct bcm_clk_gate gate;
+ struct bcm_clk_hyst hyst;
struct bcm_clk_trig pre_trig;
struct bcm_clk_div pre_div;
struct bcm_clk_trig trig;
@@ -373,8 +403,7 @@ struct peri_clk_data {
struct kona_clk {
struct clk_hw hw;
- struct clk_init_data init_data;
- const char *name; /* name of this clock */
+ struct clk_init_data init_data; /* includes name of this clock */
struct ccu_data *ccu; /* ccu this clock is associated with */
enum bcm_clk_type type;
union {
@@ -385,14 +414,92 @@ struct kona_clk {
#define to_kona_clk(_hw) \
container_of(_hw, struct kona_clk, hw)
-/* Exported globals */
+/* Initialization macro for an entry in a CCU's kona_clks[] array. */
+#define KONA_CLK(_ccu_name, _clk_name, _type) \
+ { \
+ .init_data = { \
+ .name = #_clk_name, \
+ .ops = &kona_ ## _type ## _clk_ops, \
+ }, \
+ .ccu = &_ccu_name ## _ccu_data, \
+ .type = bcm_clk_ ## _type, \
+ .u.data = &_clk_name ## _data, \
+ }
+#define LAST_KONA_CLK { .type = bcm_clk_none }
-extern struct clk_ops kona_peri_clk_ops;
+/*
+ * CCU policy control. To enable software update of the policy
+ * tables the CCU policy engine must be stopped by setting the
+ * software update enable bit (LVM_EN). After an update the engine
+ * is restarted using the GO bit and either the GO_ATL or GO_AC bit.
+ */
+struct bcm_lvm_en {
+ u32 offset; /* LVM_EN register offset */
+ u32 bit; /* POLICY_CONFIG_EN bit in register */
+};
+
+/* Policy enable initialization macro */
+#define CCU_LVM_EN(_offset, _bit) \
+ { \
+ .offset = (_offset), \
+ .bit = (_bit), \
+ }
+
+struct bcm_policy_ctl {
+ u32 offset; /* POLICY_CTL register offset */
+ u32 go_bit;
+ u32 atl_bit; /* GO, GO_ATL, and GO_AC bits */
+ u32 ac_bit;
+};
+
+/* Policy control initialization macro */
+#define CCU_POLICY_CTL(_offset, _go_bit, _ac_bit, _atl_bit) \
+ { \
+ .offset = (_offset), \
+ .go_bit = (_go_bit), \
+ .ac_bit = (_ac_bit), \
+ .atl_bit = (_atl_bit), \
+ }
+
+struct ccu_policy {
+ struct bcm_lvm_en enable;
+ struct bcm_policy_ctl control;
+};
+
+/*
+ * Each CCU defines a mapped area of memory containing registers
+ * used to manage clocks implemented by the CCU. Access to memory
+ * within the CCU's space is serialized by a spinlock. Before any
+ * (other) address can be written, a special access "password" value
+ * must be written to its WR_ACCESS register (located at the base
+ * address of the range). We keep track of the name of each CCU as
+ * it is set up, and maintain them in a list.
+ */
+struct ccu_data {
+ void __iomem *base; /* base of mapped address space */
+ spinlock_t lock; /* serialization lock */
+ bool write_enabled; /* write access is currently enabled */
+ struct ccu_policy policy;
+ struct list_head links; /* for ccu_list */
+ struct device_node *node;
+ struct clk_onecell_data clk_data;
+ const char *name;
+ u32 range; /* byte range of address space */
+ struct kona_clk kona_clks[]; /* must be last */
+};
-/* Help functions */
+/* Initialization for common fields in a Kona ccu_data structure */
+#define KONA_CCU_COMMON(_prefix, _name, _ccuname) \
+ .name = #_name "_ccu", \
+ .lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \
+ .links = LIST_HEAD_INIT(_name ## _ccu_data.links), \
+ .clk_data = { \
+ .clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT, \
+ }
+
+/* Exported globals */
-#define PERI_CLK_SETUP(clks, ccu, id, name) \
- clks[id] = kona_clk_setup(ccu, #name, bcm_clk_peri, &name ## _data)
+extern struct clk_ops kona_peri_clk_ops;
/* Externally visible functions */
@@ -401,10 +508,9 @@ extern u64 scaled_div_max(struct bcm_clk_div *div);
extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value,
u32 billionths);
-extern struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
- enum bcm_clk_type type, void *data);
-extern void __init kona_dt_ccu_setup(struct device_node *node,
- int (*ccu_clks_setup)(struct ccu_data *));
+extern struct clk *kona_clk_setup(struct kona_clk *bcm_clk);
+extern void __init kona_dt_ccu_setup(struct ccu_data *ccu,
+ struct device_node *node);
extern bool __init kona_ccu_init(struct ccu_data *ccu);
#endif /* _CLK_KONA_H */
diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
new file mode 100644
index 000000000000..2a36ab710a07
--- /dev/null
+++ b/drivers/clk/berlin/Makefile
@@ -0,0 +1,4 @@
+obj-y += berlin2-avpll.o berlin2-pll.o berlin2-div.o
+obj-$(CONFIG_MACH_BERLIN_BG2) += bg2.o
+obj-$(CONFIG_MACH_BERLIN_BG2CD) += bg2.o
+obj-$(CONFIG_MACH_BERLIN_BG2Q) += bg2q.o
diff --git a/drivers/clk/berlin/berlin2-avpll.c b/drivers/clk/berlin/berlin2-avpll.c
new file mode 100644
index 000000000000..fd0f26c38465
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-avpll.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include "berlin2-avpll.h"
+
+/*
+ * Berlin2 SoCs comprise up to two PLLs called AVPLL built upon a
+ * VCO with 8 channels each, channel 8 is the odd-one-out and does
+ * not provide mul/div.
+ *
+ * Unfortunately, its registers are not named but just numbered. To
+ * get in at least some kind of structure, we split each AVPLL into
+ * the VCOs and each channel into separate clock drivers.
+ *
+ * Also, here and there the VCO registers are a bit different with
+ * respect to bit shifts. Make sure to add a comment for those.
+ */
+#define NUM_CHANNELS 8
+
+#define AVPLL_CTRL(x) ((x) * 0x4)
+
+#define VCO_CTRL0 AVPLL_CTRL(0)
+/* BG2/BG2CDs VCO_B has an additional shift of 4 for its VCO_CTRL0 reg */
+#define VCO_RESET BIT(0)
+#define VCO_POWERUP BIT(1)
+#define VCO_INTERPOL_SHIFT 2
+#define VCO_INTERPOL_MASK (0xf << VCO_INTERPOL_SHIFT)
+#define VCO_REG1V45_SEL_SHIFT 6
+#define VCO_REG1V45_SEL(x) ((x) << VCO_REG1V45_SEL_SHIFT)
+#define VCO_REG1V45_SEL_1V40 VCO_REG1V45_SEL(0)
+#define VCO_REG1V45_SEL_1V45 VCO_REG1V45_SEL(1)
+#define VCO_REG1V45_SEL_1V50 VCO_REG1V45_SEL(2)
+#define VCO_REG1V45_SEL_1V55 VCO_REG1V45_SEL(3)
+#define VCO_REG1V45_SEL_MASK VCO_REG1V45_SEL(3)
+#define VCO_REG0V9_SEL_SHIFT 8
+#define VCO_REG0V9_SEL_MASK (0xf << VCO_REG0V9_SEL_SHIFT)
+#define VCO_VTHCAL_SHIFT 12
+#define VCO_VTHCAL(x) ((x) << VCO_VTHCAL_SHIFT)
+#define VCO_VTHCAL_0V90 VCO_VTHCAL(0)
+#define VCO_VTHCAL_0V95 VCO_VTHCAL(1)
+#define VCO_VTHCAL_1V00 VCO_VTHCAL(2)
+#define VCO_VTHCAL_1V05 VCO_VTHCAL(3)
+#define VCO_VTHCAL_MASK VCO_VTHCAL(3)
+#define VCO_KVCOEXT_SHIFT 14
+#define VCO_KVCOEXT_MASK (0x3 << VCO_KVCOEXT_SHIFT)
+#define VCO_KVCOEXT_ENABLE BIT(17)
+#define VCO_V2IEXT_SHIFT 18
+#define VCO_V2IEXT_MASK (0xf << VCO_V2IEXT_SHIFT)
+#define VCO_V2IEXT_ENABLE BIT(22)
+#define VCO_SPEED_SHIFT 23
+#define VCO_SPEED(x) ((x) << VCO_SPEED_SHIFT)
+#define VCO_SPEED_1G08_1G21 VCO_SPEED(0)
+#define VCO_SPEED_1G21_1G40 VCO_SPEED(1)
+#define VCO_SPEED_1G40_1G61 VCO_SPEED(2)
+#define VCO_SPEED_1G61_1G86 VCO_SPEED(3)
+#define VCO_SPEED_1G86_2G00 VCO_SPEED(4)
+#define VCO_SPEED_2G00_2G22 VCO_SPEED(5)
+#define VCO_SPEED_2G22 VCO_SPEED(6)
+#define VCO_SPEED_MASK VCO_SPEED(0x7)
+#define VCO_CLKDET_ENABLE BIT(26)
+#define VCO_CTRL1 AVPLL_CTRL(1)
+#define VCO_REFDIV_SHIFT 0
+#define VCO_REFDIV(x) ((x) << VCO_REFDIV_SHIFT)
+#define VCO_REFDIV_1 VCO_REFDIV(0)
+#define VCO_REFDIV_2 VCO_REFDIV(1)
+#define VCO_REFDIV_4 VCO_REFDIV(2)
+#define VCO_REFDIV_3 VCO_REFDIV(3)
+#define VCO_REFDIV_MASK VCO_REFDIV(0x3f)
+#define VCO_FBDIV_SHIFT 6
+#define VCO_FBDIV(x) ((x) << VCO_FBDIV_SHIFT)
+#define VCO_FBDIV_MASK VCO_FBDIV(0xff)
+#define VCO_ICP_SHIFT 14
+/* PLL Charge Pump Current = 10uA * (x + 1) */
+#define VCO_ICP(x) ((x) << VCO_ICP_SHIFT)
+#define VCO_ICP_MASK VCO_ICP(0xf)
+#define VCO_LOAD_CAP BIT(18)
+#define VCO_CALIBRATION_START BIT(19)
+#define VCO_FREQOFFSETn(x) AVPLL_CTRL(3 + (x))
+#define VCO_FREQOFFSET_MASK 0x7ffff
+#define VCO_CTRL10 AVPLL_CTRL(10)
+#define VCO_POWERUP_CH1 BIT(20)
+#define VCO_CTRL11 AVPLL_CTRL(11)
+#define VCO_CTRL12 AVPLL_CTRL(12)
+#define VCO_CTRL13 AVPLL_CTRL(13)
+#define VCO_CTRL14 AVPLL_CTRL(14)
+#define VCO_CTRL15 AVPLL_CTRL(15)
+#define VCO_SYNC1n(x) AVPLL_CTRL(15 + (x))
+#define VCO_SYNC1_MASK 0x1ffff
+#define VCO_SYNC2n(x) AVPLL_CTRL(23 + (x))
+#define VCO_SYNC2_MASK 0x1ffff
+#define VCO_CTRL30 AVPLL_CTRL(30)
+#define VCO_DPLL_CH1_ENABLE BIT(17)
+
+struct berlin2_avpll_vco {
+ struct clk_hw hw;
+ void __iomem *base;
+ u8 flags;
+};
+
+#define to_avpll_vco(hw) container_of(hw, struct berlin2_avpll_vco, hw)
+
+static int berlin2_avpll_vco_is_enabled(struct clk_hw *hw)
+{
+ struct berlin2_avpll_vco *vco = to_avpll_vco(hw);
+ u32 reg;
+
+ reg = readl_relaxed(vco->base + VCO_CTRL0);
+ if (vco->flags & BERLIN2_AVPLL_BIT_QUIRK)
+ reg >>= 4;
+
+ return !!(reg & VCO_POWERUP);
+}
+
+static int berlin2_avpll_vco_enable(struct clk_hw *hw)
+{
+ struct berlin2_avpll_vco *vco = to_avpll_vco(hw);
+ u32 reg;
+
+ reg = readl_relaxed(vco->base + VCO_CTRL0);
+ if (vco->flags & BERLIN2_AVPLL_BIT_QUIRK)
+ reg |= VCO_POWERUP << 4;
+ else
+ reg |= VCO_POWERUP;
+ writel_relaxed(reg, vco->base + VCO_CTRL0);
+
+ return 0;
+}
+
+static void berlin2_avpll_vco_disable(struct clk_hw *hw)
+{
+ struct berlin2_avpll_vco *vco = to_avpll_vco(hw);
+ u32 reg;
+
+ reg = readl_relaxed(vco->base + VCO_CTRL0);
+ if (vco->flags & BERLIN2_AVPLL_BIT_QUIRK)
+ reg &= ~(VCO_POWERUP << 4);
+ else
+ reg &= ~VCO_POWERUP;
+ writel_relaxed(reg, vco->base + VCO_CTRL0);
+}
+
+static u8 vco_refdiv[] = { 1, 2, 4, 3 };
+
+static unsigned long
+berlin2_avpll_vco_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct berlin2_avpll_vco *vco = to_avpll_vco(hw);
+ u32 reg, refdiv, fbdiv;
+ u64 freq = parent_rate;
+
+ /* AVPLL VCO frequency: Fvco = (Fref / refdiv) * fbdiv */
+ reg = readl_relaxed(vco->base + VCO_CTRL1);
+ refdiv = (reg & VCO_REFDIV_MASK) >> VCO_REFDIV_SHIFT;
+ refdiv = vco_refdiv[refdiv];
+ fbdiv = (reg & VCO_FBDIV_MASK) >> VCO_FBDIV_SHIFT;
+ freq *= fbdiv;
+ do_div(freq, refdiv);
+
+ return (unsigned long)freq;
+}
+
+static const struct clk_ops berlin2_avpll_vco_ops = {
+ .is_enabled = berlin2_avpll_vco_is_enabled,
+ .enable = berlin2_avpll_vco_enable,
+ .disable = berlin2_avpll_vco_disable,
+ .recalc_rate = berlin2_avpll_vco_recalc_rate,
+};
+
+struct clk * __init berlin2_avpll_vco_register(void __iomem *base,
+ const char *name, const char *parent_name,
+ u8 vco_flags, unsigned long flags)
+{
+ struct berlin2_avpll_vco *vco;
+ struct clk_init_data init;
+
+ vco = kzalloc(sizeof(*vco), GFP_KERNEL);
+ if (!vco)
+ return ERR_PTR(-ENOMEM);
+
+ vco->base = base;
+ vco->flags = vco_flags;
+ vco->hw.init = &init;
+ init.name = name;
+ init.ops = &berlin2_avpll_vco_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ init.flags = flags;
+
+ return clk_register(NULL, &vco->hw);
+}
+
+struct berlin2_avpll_channel {
+ struct clk_hw hw;
+ void __iomem *base;
+ u8 flags;
+ u8 index;
+};
+
+#define to_avpll_channel(hw) container_of(hw, struct berlin2_avpll_channel, hw)
+
+static int berlin2_avpll_channel_is_enabled(struct clk_hw *hw)
+{
+ struct berlin2_avpll_channel *ch = to_avpll_channel(hw);
+ u32 reg;
+
+ if (ch->index == 7)
+ return 1;
+
+ reg = readl_relaxed(ch->base + VCO_CTRL10);
+ reg &= VCO_POWERUP_CH1 << ch->index;
+
+ return !!reg;
+}
+
+static int berlin2_avpll_channel_enable(struct clk_hw *hw)
+{
+ struct berlin2_avpll_channel *ch = to_avpll_channel(hw);
+ u32 reg;
+
+ reg = readl_relaxed(ch->base + VCO_CTRL10);
+ reg |= VCO_POWERUP_CH1 << ch->index;
+ writel_relaxed(reg, ch->base + VCO_CTRL10);
+
+ return 0;
+}
+
+static void berlin2_avpll_channel_disable(struct clk_hw *hw)
+{
+ struct berlin2_avpll_channel *ch = to_avpll_channel(hw);
+ u32 reg;
+
+ reg = readl_relaxed(ch->base + VCO_CTRL10);
+ reg &= ~(VCO_POWERUP_CH1 << ch->index);
+ writel_relaxed(reg, ch->base + VCO_CTRL10);
+}
+
+static const u8 div_hdmi[] = { 1, 2, 4, 6 };
+static const u8 div_av1[] = { 1, 2, 5, 5 };
+
+static unsigned long
+berlin2_avpll_channel_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct berlin2_avpll_channel *ch = to_avpll_channel(hw);
+ u32 reg, div_av2, div_av3, divider = 1;
+ u64 freq = parent_rate;
+
+ reg = readl_relaxed(ch->base + VCO_CTRL30);
+ if ((reg & (VCO_DPLL_CH1_ENABLE << ch->index)) == 0)
+ goto skip_div;
+
+ /*
+ * Fch = (Fref * sync2) /
+ * (sync1 * div_hdmi * div_av1 * div_av2 * div_av3)
+ */
+
+ reg = readl_relaxed(ch->base + VCO_SYNC1n(ch->index));
+ /* BG2/BG2CDs SYNC1 reg on AVPLL_B channel 1 is shifted by 4 */
+ if (ch->flags & BERLIN2_AVPLL_BIT_QUIRK && ch->index == 0)
+ reg >>= 4;
+ divider = reg & VCO_SYNC1_MASK;
+
+ reg = readl_relaxed(ch->base + VCO_SYNC2n(ch->index));
+ freq *= reg & VCO_SYNC2_MASK;
+
+ /* Channel 8 has no dividers */
+ if (ch->index == 7)
+ goto skip_div;
+
+ /*
+ * HDMI divider start at VCO_CTRL11, bit 7; MSB is enable, lower 2 bit
+ * determine divider.
+ */
+ reg = readl_relaxed(ch->base + VCO_CTRL11) >> 7;
+ reg = (reg >> (ch->index * 3));
+ if (reg & BIT(2))
+ divider *= div_hdmi[reg & 0x3];
+
+ /*
+ * AV1 divider start at VCO_CTRL11, bit 28; MSB is enable, lower 2 bit
+ * determine divider.
+ */
+ if (ch->index == 0) {
+ reg = readl_relaxed(ch->base + VCO_CTRL11);
+ reg >>= 28;
+ } else {
+ reg = readl_relaxed(ch->base + VCO_CTRL12);
+ reg >>= (ch->index-1) * 3;
+ }
+ if (reg & BIT(2))
+ divider *= div_av1[reg & 0x3];
+
+ /*
+ * AV2 divider start at VCO_CTRL12, bit 18; each 7 bits wide,
+ * zero is not a valid value.
+ */
+ if (ch->index < 2) {
+ reg = readl_relaxed(ch->base + VCO_CTRL12);
+ reg >>= 18 + (ch->index * 7);
+ } else if (ch->index < 7) {
+ reg = readl_relaxed(ch->base + VCO_CTRL13);
+ reg >>= (ch->index - 2) * 7;
+ } else {
+ reg = readl_relaxed(ch->base + VCO_CTRL14);
+ }
+ div_av2 = reg & 0x7f;
+ if (div_av2)
+ divider *= div_av2;
+
+ /*
+ * AV3 divider start at VCO_CTRL14, bit 7; each 4 bits wide.
+ * AV2/AV3 form a fractional divider, where only specfic values for AV3
+ * are allowed. AV3 != 0 divides by AV2/2, AV3=0 is bypass.
+ */
+ if (ch->index < 6) {
+ reg = readl_relaxed(ch->base + VCO_CTRL14);
+ reg >>= 7 + (ch->index * 4);
+ } else {
+ reg = readl_relaxed(ch->base + VCO_CTRL15);
+ }
+ div_av3 = reg & 0xf;
+ if (div_av2 && div_av3)
+ freq *= 2;
+
+skip_div:
+ do_div(freq, divider);
+ return (unsigned long)freq;
+}
+
+static const struct clk_ops berlin2_avpll_channel_ops = {
+ .is_enabled = berlin2_avpll_channel_is_enabled,
+ .enable = berlin2_avpll_channel_enable,
+ .disable = berlin2_avpll_channel_disable,
+ .recalc_rate = berlin2_avpll_channel_recalc_rate,
+};
+
+/*
+ * Another nice quirk:
+ * On some production SoCs, AVPLL channels are scrambled with respect
+ * to the channel numbering in the registers but still referenced by
+ * their original channel numbers. We deal with it by having a flag
+ * and a translation table for the index.
+ */
+static const u8 quirk_index[] __initconst = { 0, 6, 5, 4, 3, 2, 1, 7 };
+
+struct clk * __init berlin2_avpll_channel_register(void __iomem *base,
+ const char *name, u8 index, const char *parent_name,
+ u8 ch_flags, unsigned long flags)
+{
+ struct berlin2_avpll_channel *ch;
+ struct clk_init_data init;
+
+ ch = kzalloc(sizeof(*ch), GFP_KERNEL);
+ if (!ch)
+ return ERR_PTR(-ENOMEM);
+
+ ch->base = base;
+ if (ch_flags & BERLIN2_AVPLL_SCRAMBLE_QUIRK)
+ ch->index = quirk_index[index];
+ else
+ ch->index = index;
+
+ ch->flags = ch_flags;
+ ch->hw.init = &init;
+ init.name = name;
+ init.ops = &berlin2_avpll_channel_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ init.flags = flags;
+
+ return clk_register(NULL, &ch->hw);
+}
diff --git a/drivers/clk/berlin/berlin2-avpll.h b/drivers/clk/berlin/berlin2-avpll.h
new file mode 100644
index 000000000000..a37f5068d299
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-avpll.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __BERLIN2_AVPLL_H
+#define __BERLIN2_AVPLL_H
+
+struct clk;
+
+#define BERLIN2_AVPLL_BIT_QUIRK BIT(0)
+#define BERLIN2_AVPLL_SCRAMBLE_QUIRK BIT(1)
+
+struct clk * __init
+berlin2_avpll_vco_register(void __iomem *base, const char *name,
+ const char *parent_name, u8 vco_flags, unsigned long flags);
+
+struct clk * __init
+berlin2_avpll_channel_register(void __iomem *base, const char *name,
+ u8 index, const char *parent_name, u8 ch_flags,
+ unsigned long flags);
+
+#endif /* __BERLIN2_AVPLL_H */
diff --git a/drivers/clk/berlin/berlin2-div.c b/drivers/clk/berlin/berlin2-div.c
new file mode 100644
index 000000000000..81ff97f8aa0b
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-div.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "berlin2-div.h"
+
+/*
+ * Clock dividers in Berlin2 SoCs comprise a complex cell to select
+ * input pll and divider. The virtual structure as it is used in Marvell
+ * BSP code can be seen as:
+ *
+ * +---+
+ * pll0 --------------->| 0 | +---+
+ * +---+ |(B)|--+--------------->| 0 | +---+
+ * pll1.0 -->| 0 | +-->| 1 | | +--------+ |(E)|----->| 0 | +---+
+ * pll1.1 -->| 1 | | +---+ +-->|(C) 1:M |-->| 1 | |(F)|-->|(G)|->
+ * ... -->|(A)|--+ | +--------+ +---+ +-->| 1 | +---+
+ * ... -->| | +-->|(D) 1:3 |----------+ +---+
+ * pll1.N -->| N | +---------
+ * +---+
+ *
+ * (A) input pll clock mux controlled by <PllSelect[1:n]>
+ * (B) input pll bypass mux controlled by <PllSwitch>
+ * (C) programmable clock divider controlled by <Select[1:n]>
+ * (D) constant div-by-3 clock divider
+ * (E) programmable clock divider bypass controlled by <Switch>
+ * (F) constant div-by-3 clock mux controlled by <D3Switch>
+ * (G) clock gate controlled by <Enable>
+ *
+ * For whatever reason, above control signals come in two flavors:
+ * - single register dividers with all bits in one register
+ * - shared register dividers with bits spread over multiple registers
+ * (including signals for the same cell spread over consecutive registers)
+ *
+ * Also, clock gate and pll mux is not available on every div cell, so
+ * we have to deal with those, too. We reuse common clock composite driver
+ * for it.
+ */
+
+#define PLL_SELECT_MASK 0x7
+#define DIV_SELECT_MASK 0x7
+
+struct berlin2_div {
+ struct clk_hw hw;
+ void __iomem *base;
+ struct berlin2_div_map map;
+ spinlock_t *lock;
+};
+
+#define to_berlin2_div(hw) container_of(hw, struct berlin2_div, hw)
+
+static u8 clk_div[] = { 1, 2, 4, 6, 8, 12, 1, 1 };
+
+static int berlin2_div_is_enabled(struct clk_hw *hw)
+{
+ struct berlin2_div *div = to_berlin2_div(hw);
+ struct berlin2_div_map *map = &div->map;
+ u32 reg;
+
+ if (div->lock)
+ spin_lock(div->lock);
+
+ reg = readl_relaxed(div->base + map->gate_offs);
+ reg >>= map->gate_shift;
+
+ if (div->lock)
+ spin_unlock(div->lock);
+
+ return (reg & 0x1);
+}
+
+static int berlin2_div_enable(struct clk_hw *hw)
+{
+ struct berlin2_div *div = to_berlin2_div(hw);
+ struct berlin2_div_map *map = &div->map;
+ u32 reg;
+
+ if (div->lock)
+ spin_lock(div->lock);
+
+ reg = readl_relaxed(div->base + map->gate_offs);
+ reg |= BIT(map->gate_shift);
+ writel_relaxed(reg, div->base + map->gate_offs);
+
+ if (div->lock)
+ spin_unlock(div->lock);
+
+ return 0;
+}
+
+static void berlin2_div_disable(struct clk_hw *hw)
+{
+ struct berlin2_div *div = to_berlin2_div(hw);
+ struct berlin2_div_map *map = &div->map;
+ u32 reg;
+
+ if (div->lock)
+ spin_lock(div->lock);
+
+ reg = readl_relaxed(div->base + map->gate_offs);
+ reg &= ~BIT(map->gate_shift);
+ writel_relaxed(reg, div->base + map->gate_offs);
+
+ if (div->lock)
+ spin_unlock(div->lock);
+}
+
+static int berlin2_div_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct berlin2_div *div = to_berlin2_div(hw);
+ struct berlin2_div_map *map = &div->map;
+ u32 reg;
+
+ if (div->lock)
+ spin_lock(div->lock);
+
+ /* index == 0 is PLL_SWITCH */
+ reg = readl_relaxed(div->base + map->pll_switch_offs);
+ if (index == 0)
+ reg &= ~BIT(map->pll_switch_shift);
+ else
+ reg |= BIT(map->pll_switch_shift);
+ writel_relaxed(reg, div->base + map->pll_switch_offs);
+
+ /* index > 0 is PLL_SELECT */
+ if (index > 0) {
+ reg = readl_relaxed(div->base + map->pll_select_offs);
+ reg &= ~(PLL_SELECT_MASK << map->pll_select_shift);
+ reg |= (index - 1) << map->pll_select_shift;
+ writel_relaxed(reg, div->base + map->pll_select_offs);
+ }
+
+ if (div->lock)
+ spin_unlock(div->lock);
+
+ return 0;
+}
+
+static u8 berlin2_div_get_parent(struct clk_hw *hw)
+{
+ struct berlin2_div *div = to_berlin2_div(hw);
+ struct berlin2_div_map *map = &div->map;
+ u32 reg;
+ u8 index = 0;
+
+ if (div->lock)
+ spin_lock(div->lock);
+
+ /* PLL_SWITCH == 0 is index 0 */
+ reg = readl_relaxed(div->base + map->pll_switch_offs);
+ reg &= BIT(map->pll_switch_shift);
+ if (reg) {
+ reg = readl_relaxed(div->base + map->pll_select_offs);
+ reg >>= map->pll_select_shift;
+ reg &= PLL_SELECT_MASK;
+ index = 1 + reg;
+ }
+
+ if (div->lock)
+ spin_unlock(div->lock);
+
+ return index;
+}
+
+static unsigned long berlin2_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct berlin2_div *div = to_berlin2_div(hw);
+ struct berlin2_div_map *map = &div->map;
+ u32 divsw, div3sw, divider = 1;
+
+ if (div->lock)
+ spin_lock(div->lock);
+
+ divsw = readl_relaxed(div->base + map->div_switch_offs) &
+ (1 << map->div_switch_shift);
+ div3sw = readl_relaxed(div->base + map->div3_switch_offs) &
+ (1 << map->div3_switch_shift);
+
+ /* constant divide-by-3 (dominant) */
+ if (div3sw != 0) {
+ divider = 3;
+ /* divider can be bypassed with DIV_SWITCH == 0 */
+ } else if (divsw == 0) {
+ divider = 1;
+ /* clock divider determined by DIV_SELECT */
+ } else {
+ u32 reg;
+ reg = readl_relaxed(div->base + map->div_select_offs);
+ reg >>= map->div_select_shift;
+ reg &= DIV_SELECT_MASK;
+ divider = clk_div[reg];
+ }
+
+ if (div->lock)
+ spin_unlock(div->lock);
+
+ return parent_rate / divider;
+}
+
+static const struct clk_ops berlin2_div_rate_ops = {
+ .recalc_rate = berlin2_div_recalc_rate,
+};
+
+static const struct clk_ops berlin2_div_gate_ops = {
+ .is_enabled = berlin2_div_is_enabled,
+ .enable = berlin2_div_enable,
+ .disable = berlin2_div_disable,
+};
+
+static const struct clk_ops berlin2_div_mux_ops = {
+ .set_parent = berlin2_div_set_parent,
+ .get_parent = berlin2_div_get_parent,
+};
+
+struct clk * __init
+berlin2_div_register(const struct berlin2_div_map *map,
+ void __iomem *base, const char *name, u8 div_flags,
+ const char **parent_names, int num_parents,
+ unsigned long flags, spinlock_t *lock)
+{
+ const struct clk_ops *mux_ops = &berlin2_div_mux_ops;
+ const struct clk_ops *rate_ops = &berlin2_div_rate_ops;
+ const struct clk_ops *gate_ops = &berlin2_div_gate_ops;
+ struct berlin2_div *div;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ /* copy div_map to allow __initconst */
+ memcpy(&div->map, map, sizeof(*map));
+ div->base = base;
+ div->lock = lock;
+
+ if ((div_flags & BERLIN2_DIV_HAS_GATE) == 0)
+ gate_ops = NULL;
+ if ((div_flags & BERLIN2_DIV_HAS_MUX) == 0)
+ mux_ops = NULL;
+
+ return clk_register_composite(NULL, name, parent_names, num_parents,
+ &div->hw, mux_ops, &div->hw, rate_ops,
+ &div->hw, gate_ops, flags);
+}
diff --git a/drivers/clk/berlin/berlin2-div.h b/drivers/clk/berlin/berlin2-div.h
new file mode 100644
index 000000000000..15e3384f3116
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-div.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __BERLIN2_DIV_H
+#define __BERLIN2_DIV_H
+
+struct clk;
+
+#define BERLIN2_DIV_HAS_GATE BIT(0)
+#define BERLIN2_DIV_HAS_MUX BIT(1)
+
+#define BERLIN2_PLL_SELECT(_off, _sh) \
+ .pll_select_offs = _off, \
+ .pll_select_shift = _sh
+
+#define BERLIN2_PLL_SWITCH(_off, _sh) \
+ .pll_switch_offs = _off, \
+ .pll_switch_shift = _sh
+
+#define BERLIN2_DIV_SELECT(_off, _sh) \
+ .div_select_offs = _off, \
+ .div_select_shift = _sh
+
+#define BERLIN2_DIV_SWITCH(_off, _sh) \
+ .div_switch_offs = _off, \
+ .div_switch_shift = _sh
+
+#define BERLIN2_DIV_D3SWITCH(_off, _sh) \
+ .div3_switch_offs = _off, \
+ .div3_switch_shift = _sh
+
+#define BERLIN2_DIV_GATE(_off, _sh) \
+ .gate_offs = _off, \
+ .gate_shift = _sh
+
+#define BERLIN2_SINGLE_DIV(_off) \
+ BERLIN2_DIV_GATE(_off, 0), \
+ BERLIN2_PLL_SELECT(_off, 1), \
+ BERLIN2_PLL_SWITCH(_off, 4), \
+ BERLIN2_DIV_SWITCH(_off, 5), \
+ BERLIN2_DIV_D3SWITCH(_off, 6), \
+ BERLIN2_DIV_SELECT(_off, 7)
+
+struct berlin2_div_map {
+ u16 pll_select_offs;
+ u16 pll_switch_offs;
+ u16 div_select_offs;
+ u16 div_switch_offs;
+ u16 div3_switch_offs;
+ u16 gate_offs;
+ u8 pll_select_shift;
+ u8 pll_switch_shift;
+ u8 div_select_shift;
+ u8 div_switch_shift;
+ u8 div3_switch_shift;
+ u8 gate_shift;
+};
+
+struct berlin2_div_data {
+ const char *name;
+ const u8 *parent_ids;
+ int num_parents;
+ unsigned long flags;
+ struct berlin2_div_map map;
+ u8 div_flags;
+};
+
+struct clk * __init
+berlin2_div_register(const struct berlin2_div_map *map,
+ void __iomem *base, const char *name, u8 div_flags,
+ const char **parent_names, int num_parents,
+ unsigned long flags, spinlock_t *lock);
+
+#endif /* __BERLIN2_DIV_H */
diff --git a/drivers/clk/berlin/berlin2-pll.c b/drivers/clk/berlin/berlin2-pll.c
new file mode 100644
index 000000000000..bdc506b03824
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-pll.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+
+#include "berlin2-div.h"
+
+struct berlin2_pll_map {
+ const u8 vcodiv[16];
+ u8 mult;
+ u8 fbdiv_shift;
+ u8 rfdiv_shift;
+ u8 divsel_shift;
+};
+
+struct berlin2_pll {
+ struct clk_hw hw;
+ void __iomem *base;
+ struct berlin2_pll_map map;
+};
+
+#define to_berlin2_pll(hw) container_of(hw, struct berlin2_pll, hw)
+
+#define SPLL_CTRL0 0x00
+#define SPLL_CTRL1 0x04
+#define SPLL_CTRL2 0x08
+#define SPLL_CTRL3 0x0c
+#define SPLL_CTRL4 0x10
+
+#define FBDIV_MASK 0x1ff
+#define RFDIV_MASK 0x1f
+#define DIVSEL_MASK 0xf
+
+/*
+ * The output frequency formula for the pll is:
+ * clkout = fbdiv / refdiv * parent / vcodiv
+ */
+static unsigned long
+berlin2_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct berlin2_pll *pll = to_berlin2_pll(hw);
+ struct berlin2_pll_map *map = &pll->map;
+ u32 val, fbdiv, rfdiv, vcodivsel, vcodiv;
+ u64 rate = parent_rate;
+
+ val = readl_relaxed(pll->base + SPLL_CTRL0);
+ fbdiv = (val >> map->fbdiv_shift) & FBDIV_MASK;
+ rfdiv = (val >> map->rfdiv_shift) & RFDIV_MASK;
+ if (rfdiv == 0) {
+ pr_warn("%s has zero rfdiv\n", __clk_get_name(hw->clk));
+ rfdiv = 1;
+ }
+
+ val = readl_relaxed(pll->base + SPLL_CTRL1);
+ vcodivsel = (val >> map->divsel_shift) & DIVSEL_MASK;
+ vcodiv = map->vcodiv[vcodivsel];
+ if (vcodiv == 0) {
+ pr_warn("%s has zero vcodiv (index %d)\n",
+ __clk_get_name(hw->clk), vcodivsel);
+ vcodiv = 1;
+ }
+
+ rate *= fbdiv * map->mult;
+ do_div(rate, rfdiv * vcodiv);
+
+ return (unsigned long)rate;
+}
+
+static const struct clk_ops berlin2_pll_ops = {
+ .recalc_rate = berlin2_pll_recalc_rate,
+};
+
+struct clk * __init
+berlin2_pll_register(const struct berlin2_pll_map *map,
+ void __iomem *base, const char *name,
+ const char *parent_name, unsigned long flags)
+{
+ struct clk_init_data init;
+ struct berlin2_pll *pll;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ /* copy pll_map to allow __initconst */
+ memcpy(&pll->map, map, sizeof(*map));
+ pll->base = base;
+ pll->hw.init = &init;
+ init.name = name;
+ init.ops = &berlin2_pll_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ init.flags = flags;
+
+ return clk_register(NULL, &pll->hw);
+}
diff --git a/drivers/clk/berlin/berlin2-pll.h b/drivers/clk/berlin/berlin2-pll.h
new file mode 100644
index 000000000000..8831ce27ac1e
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-pll.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __BERLIN2_PLL_H
+#define __BERLIN2_PLL_H
+
+struct clk;
+
+struct berlin2_pll_map {
+ const u8 vcodiv[16];
+ u8 mult;
+ u8 fbdiv_shift;
+ u8 rfdiv_shift;
+ u8 divsel_shift;
+};
+
+struct clk * __init
+berlin2_pll_register(const struct berlin2_pll_map *map,
+ void __iomem *base, const char *name,
+ const char *parent_name, unsigned long flags);
+
+#endif /* __BERLIN2_PLL_H */
diff --git a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c
new file mode 100644
index 000000000000..515fb133495c
--- /dev/null
+++ b/drivers/clk/berlin/bg2.c
@@ -0,0 +1,691 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/berlin2.h>
+
+#include "berlin2-avpll.h"
+#include "berlin2-div.h"
+#include "berlin2-pll.h"
+#include "common.h"
+
+#define REG_PINMUX0 0x0000
+#define REG_PINMUX1 0x0004
+#define REG_SYSPLLCTL0 0x0014
+#define REG_SYSPLLCTL4 0x0024
+#define REG_MEMPLLCTL0 0x0028
+#define REG_MEMPLLCTL4 0x0038
+#define REG_CPUPLLCTL0 0x003c
+#define REG_CPUPLLCTL4 0x004c
+#define REG_AVPLLCTL0 0x0050
+#define REG_AVPLLCTL31 0x00cc
+#define REG_AVPLLCTL62 0x0148
+#define REG_PLLSTATUS 0x014c
+#define REG_CLKENABLE 0x0150
+#define REG_CLKSELECT0 0x0154
+#define REG_CLKSELECT1 0x0158
+#define REG_CLKSELECT2 0x015c
+#define REG_CLKSELECT3 0x0160
+#define REG_CLKSWITCH0 0x0164
+#define REG_CLKSWITCH1 0x0168
+#define REG_RESET_TRIGGER 0x0178
+#define REG_RESET_STATUS0 0x017c
+#define REG_RESET_STATUS1 0x0180
+#define REG_SW_GENERIC0 0x0184
+#define REG_SW_GENERIC3 0x0190
+#define REG_PRODUCTID 0x01cc
+#define REG_PRODUCTID_EXT 0x01d0
+#define REG_GFX3DCORE_CLKCTL 0x022c
+#define REG_GFX3DSYS_CLKCTL 0x0230
+#define REG_ARC_CLKCTL 0x0234
+#define REG_VIP_CLKCTL 0x0238
+#define REG_SDIO0XIN_CLKCTL 0x023c
+#define REG_SDIO1XIN_CLKCTL 0x0240
+#define REG_GFX3DEXTRA_CLKCTL 0x0244
+#define REG_GFX3D_RESET 0x0248
+#define REG_GC360_CLKCTL 0x024c
+#define REG_SDIO_DLLMST_CLKCTL 0x0250
+
+/*
+ * BG2/BG2CD SoCs have the following audio/video I/O units:
+ *
+ * audiohd: HDMI TX audio
+ * audio0: 7.1ch TX
+ * audio1: 2ch TX
+ * audio2: 2ch RX
+ * audio3: SPDIF TX
+ * video0: HDMI video
+ * video1: Secondary video
+ * video2: SD auxiliary video
+ *
+ * There are no external audio clocks (ACLKI0, ACLKI1) and
+ * only one external video clock (VCLKI0).
+ *
+ * Currently missing bits and pieces:
+ * - audio_fast_pll is unknown
+ * - audiohd_pll is unknown
+ * - video0_pll is unknown
+ * - audio[023], audiohd parent pll is assumed to be audio_fast_pll
+ *
+ */
+
+#define MAX_CLKS 41
+static struct clk *clks[MAX_CLKS];
+static struct clk_onecell_data clk_data;
+static DEFINE_SPINLOCK(lock);
+static void __iomem *gbase;
+
+enum {
+ REFCLK, VIDEO_EXT0,
+ SYSPLL, MEMPLL, CPUPLL,
+ AVPLL_A1, AVPLL_A2, AVPLL_A3, AVPLL_A4,
+ AVPLL_A5, AVPLL_A6, AVPLL_A7, AVPLL_A8,
+ AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4,
+ AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8,
+ AUDIO1_PLL, AUDIO_FAST_PLL,
+ VIDEO0_PLL, VIDEO0_IN,
+ VIDEO1_PLL, VIDEO1_IN,
+ VIDEO2_PLL, VIDEO2_IN,
+};
+
+static const char *clk_names[] = {
+ [REFCLK] = "refclk",
+ [VIDEO_EXT0] = "video_ext0",
+ [SYSPLL] = "syspll",
+ [MEMPLL] = "mempll",
+ [CPUPLL] = "cpupll",
+ [AVPLL_A1] = "avpll_a1",
+ [AVPLL_A2] = "avpll_a2",
+ [AVPLL_A3] = "avpll_a3",
+ [AVPLL_A4] = "avpll_a4",
+ [AVPLL_A5] = "avpll_a5",
+ [AVPLL_A6] = "avpll_a6",
+ [AVPLL_A7] = "avpll_a7",
+ [AVPLL_A8] = "avpll_a8",
+ [AVPLL_B1] = "avpll_b1",
+ [AVPLL_B2] = "avpll_b2",
+ [AVPLL_B3] = "avpll_b3",
+ [AVPLL_B4] = "avpll_b4",
+ [AVPLL_B5] = "avpll_b5",
+ [AVPLL_B6] = "avpll_b6",
+ [AVPLL_B7] = "avpll_b7",
+ [AVPLL_B8] = "avpll_b8",
+ [AUDIO1_PLL] = "audio1_pll",
+ [AUDIO_FAST_PLL] = "audio_fast_pll",
+ [VIDEO0_PLL] = "video0_pll",
+ [VIDEO0_IN] = "video0_in",
+ [VIDEO1_PLL] = "video1_pll",
+ [VIDEO1_IN] = "video1_in",
+ [VIDEO2_PLL] = "video2_pll",
+ [VIDEO2_IN] = "video2_in",
+};
+
+static const struct berlin2_pll_map bg2_pll_map __initconst = {
+ .vcodiv = {10, 15, 20, 25, 30, 40, 50, 60, 80},
+ .mult = 10,
+ .fbdiv_shift = 6,
+ .rfdiv_shift = 1,
+ .divsel_shift = 7,
+};
+
+static const u8 default_parent_ids[] = {
+ SYSPLL, AVPLL_B4, AVPLL_A5, AVPLL_B6, AVPLL_B7, SYSPLL
+};
+
+static const struct berlin2_div_data bg2_divs[] __initconst = {
+ {
+ .name = "sys",
+ .parent_ids = (const u8 []){
+ SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL
+ },
+ .num_parents = 6,
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 0),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ {
+ .name = "cpu",
+ .parent_ids = (const u8 []){
+ CPUPLL, MEMPLL, MEMPLL, MEMPLL, MEMPLL
+ },
+ .num_parents = 5,
+ .map = {
+ BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),
+ },
+ .div_flags = BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "drmfigo",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 16),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT0, 17),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT0, 20),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "cfg",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 1),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT0, 23),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT0, 26),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "gfx",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 4),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT0, 29),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT1, 0),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "zsp",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 5),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT1, 3),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT1, 6),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "perif",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 6),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT1, 9),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT1, 12),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ {
+ .name = "pcube",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 2),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT1, 15),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT1, 18),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "vscope",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 3),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT1, 21),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT1, 24),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "nfc_ecc",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 18),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT1, 27),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT2, 0),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "vpp",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 21),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT2, 3),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT2, 6),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 4),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 5),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 6),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "app",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 20),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT2, 9),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT2, 12),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 7),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 8),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 9),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "audio0",
+ .parent_ids = (const u8 []){ AUDIO_FAST_PLL },
+ .num_parents = 1,
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 22),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT2, 17),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 10),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 11),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE,
+ .flags = 0,
+ },
+ {
+ .name = "audio2",
+ .parent_ids = (const u8 []){ AUDIO_FAST_PLL },
+ .num_parents = 1,
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 24),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT2, 20),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 14),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 15),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE,
+ .flags = 0,
+ },
+ {
+ .name = "audio3",
+ .parent_ids = (const u8 []){ AUDIO_FAST_PLL },
+ .num_parents = 1,
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 25),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT2, 23),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 16),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 17),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE,
+ .flags = 0,
+ },
+ {
+ .name = "audio1",
+ .parent_ids = (const u8 []){ AUDIO1_PLL },
+ .num_parents = 1,
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 23),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT3, 0),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 12),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 13),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE,
+ .flags = 0,
+ },
+ {
+ .name = "gfx3d_core",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_SINGLE_DIV(REG_GFX3DCORE_CLKCTL),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "gfx3d_sys",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_SINGLE_DIV(REG_GFX3DSYS_CLKCTL),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "arc",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_SINGLE_DIV(REG_ARC_CLKCTL),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "vip",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_SINGLE_DIV(REG_VIP_CLKCTL),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "sdio0xin",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "sdio1xin",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "gfx3d_extra",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_SINGLE_DIV(REG_GFX3DEXTRA_CLKCTL),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "gc360",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_SINGLE_DIV(REG_GC360_CLKCTL),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "sdio_dllmst",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_SINGLE_DIV(REG_SDIO_DLLMST_CLKCTL),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+};
+
+static const struct berlin2_gate_data bg2_gates[] __initconst = {
+ { "geth0", "perif", 7 },
+ { "geth1", "perif", 8 },
+ { "sata", "perif", 9 },
+ { "ahbapb", "perif", 10, CLK_IGNORE_UNUSED },
+ { "usb0", "perif", 11 },
+ { "usb1", "perif", 12 },
+ { "pbridge", "perif", 13, CLK_IGNORE_UNUSED },
+ { "sdio0", "perif", 14, CLK_IGNORE_UNUSED },
+ { "sdio1", "perif", 15, CLK_IGNORE_UNUSED },
+ { "nfc", "perif", 17 },
+ { "smemc", "perif", 19 },
+ { "audiohd", "audiohd_pll", 26 },
+ { "video0", "video0_in", 27 },
+ { "video1", "video1_in", 28 },
+ { "video2", "video2_in", 29 },
+};
+
+static void __init berlin2_clock_setup(struct device_node *np)
+{
+ const char *parent_names[9];
+ struct clk *clk;
+ u8 avpll_flags = 0;
+ int n;
+
+ gbase = of_iomap(np, 0);
+ if (!gbase)
+ return;
+
+ /* overwrite default clock names with DT provided ones */
+ clk = of_clk_get_by_name(np, clk_names[REFCLK]);
+ if (!IS_ERR(clk)) {
+ clk_names[REFCLK] = __clk_get_name(clk);
+ clk_put(clk);
+ }
+
+ clk = of_clk_get_by_name(np, clk_names[VIDEO_EXT0]);
+ if (!IS_ERR(clk)) {
+ clk_names[VIDEO_EXT0] = __clk_get_name(clk);
+ clk_put(clk);
+ }
+
+ /* simple register PLLs */
+ clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0,
+ clk_names[SYSPLL], clk_names[REFCLK], 0);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+
+ clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0,
+ clk_names[MEMPLL], clk_names[REFCLK], 0);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+
+ clk = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0,
+ clk_names[CPUPLL], clk_names[REFCLK], 0);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+
+ if (of_device_is_compatible(np, "marvell,berlin2-global-register"))
+ avpll_flags |= BERLIN2_AVPLL_SCRAMBLE_QUIRK;
+
+ /* audio/video VCOs */
+ clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA",
+ clk_names[REFCLK], avpll_flags, 0);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+
+ for (n = 0; n < 8; n++) {
+ clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0,
+ clk_names[AVPLL_A1 + n], n, "avpll_vcoA",
+ avpll_flags, 0);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+ }
+
+ clk = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB",
+ clk_names[REFCLK], BERLIN2_AVPLL_BIT_QUIRK |
+ avpll_flags, 0);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+
+ for (n = 0; n < 8; n++) {
+ clk = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31,
+ clk_names[AVPLL_B1 + n], n, "avpll_vcoB",
+ BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+ }
+
+ /* reference clock bypass switches */
+ parent_names[0] = clk_names[SYSPLL];
+ parent_names[1] = clk_names[REFCLK];
+ clk = clk_register_mux(NULL, "syspll_byp", parent_names, 2,
+ 0, gbase + REG_CLKSWITCH0, 0, 1, 0, &lock);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+ clk_names[SYSPLL] = __clk_get_name(clk);
+
+ parent_names[0] = clk_names[MEMPLL];
+ parent_names[1] = clk_names[REFCLK];
+ clk = clk_register_mux(NULL, "mempll_byp", parent_names, 2,
+ 0, gbase + REG_CLKSWITCH0, 1, 1, 0, &lock);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+ clk_names[MEMPLL] = __clk_get_name(clk);
+
+ parent_names[0] = clk_names[CPUPLL];
+ parent_names[1] = clk_names[REFCLK];
+ clk = clk_register_mux(NULL, "cpupll_byp", parent_names, 2,
+ 0, gbase + REG_CLKSWITCH0, 2, 1, 0, &lock);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+ clk_names[CPUPLL] = __clk_get_name(clk);
+
+ /* clock muxes */
+ parent_names[0] = clk_names[AVPLL_B3];
+ parent_names[1] = clk_names[AVPLL_A3];
+ clk = clk_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2,
+ 0, gbase + REG_CLKSELECT2, 29, 1, 0, &lock);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+
+ parent_names[0] = clk_names[VIDEO0_PLL];
+ parent_names[1] = clk_names[VIDEO_EXT0];
+ clk = clk_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2,
+ 0, gbase + REG_CLKSELECT3, 4, 1, 0, &lock);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+
+ parent_names[0] = clk_names[VIDEO1_PLL];
+ parent_names[1] = clk_names[VIDEO_EXT0];
+ clk = clk_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2,
+ 0, gbase + REG_CLKSELECT3, 6, 1, 0, &lock);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+
+ parent_names[0] = clk_names[AVPLL_A2];
+ parent_names[1] = clk_names[AVPLL_B2];
+ clk = clk_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2,
+ 0, gbase + REG_CLKSELECT3, 7, 1, 0, &lock);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+
+ parent_names[0] = clk_names[VIDEO2_PLL];
+ parent_names[1] = clk_names[VIDEO_EXT0];
+ clk = clk_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2,
+ 0, gbase + REG_CLKSELECT3, 9, 1, 0, &lock);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+
+ parent_names[0] = clk_names[AVPLL_B1];
+ parent_names[1] = clk_names[AVPLL_A5];
+ clk = clk_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2,
+ 0, gbase + REG_CLKSELECT3, 10, 1, 0, &lock);
+ if (IS_ERR(clk))
+ goto bg2_fail;
+
+ /* clock divider cells */
+ for (n = 0; n < ARRAY_SIZE(bg2_divs); n++) {
+ const struct berlin2_div_data *dd = &bg2_divs[n];
+ int k;
+
+ for (k = 0; k < dd->num_parents; k++)
+ parent_names[k] = clk_names[dd->parent_ids[k]];
+
+ clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,
+ dd->name, dd->div_flags, parent_names,
+ dd->num_parents, dd->flags, &lock);
+ }
+
+ /* clock gate cells */
+ for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) {
+ const struct berlin2_gate_data *gd = &bg2_gates[n];
+
+ clks[CLKID_GETH0 + n] = clk_register_gate(NULL, gd->name,
+ gd->parent_name, gd->flags, gbase + REG_CLKENABLE,
+ gd->bit_idx, 0, &lock);
+ }
+
+ /* twdclk is derived from cpu/3 */
+ clks[CLKID_TWD] =
+ clk_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
+
+ /* check for errors on leaf clocks */
+ for (n = 0; n < MAX_CLKS; n++) {
+ if (!IS_ERR(clks[n]))
+ continue;
+
+ pr_err("%s: Unable to register leaf clock %d\n",
+ np->full_name, n);
+ goto bg2_fail;
+ }
+
+ /* register clk-provider */
+ clk_data.clks = clks;
+ clk_data.clk_num = MAX_CLKS;
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+
+ return;
+
+bg2_fail:
+ iounmap(gbase);
+}
+CLK_OF_DECLARE(berlin2_clock, "marvell,berlin2-chip-ctrl",
+ berlin2_clock_setup);
+CLK_OF_DECLARE(berlin2cd_clock, "marvell,berlin2cd-chip-ctrl",
+ berlin2_clock_setup);
diff --git a/drivers/clk/berlin/bg2q.c b/drivers/clk/berlin/bg2q.c
new file mode 100644
index 000000000000..21784e4eb3f0
--- /dev/null
+++ b/drivers/clk/berlin/bg2q.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/berlin2q.h>
+
+#include "berlin2-div.h"
+#include "berlin2-pll.h"
+#include "common.h"
+
+#define REG_PINMUX0 0x0018
+#define REG_PINMUX5 0x002c
+#define REG_SYSPLLCTL0 0x0030
+#define REG_SYSPLLCTL4 0x0040
+#define REG_CLKENABLE 0x00e8
+#define REG_CLKSELECT0 0x00ec
+#define REG_CLKSELECT1 0x00f0
+#define REG_CLKSELECT2 0x00f4
+#define REG_CLKSWITCH0 0x00f8
+#define REG_CLKSWITCH1 0x00fc
+#define REG_SW_GENERIC0 0x0110
+#define REG_SW_GENERIC3 0x011c
+#define REG_SDIO0XIN_CLKCTL 0x0158
+#define REG_SDIO1XIN_CLKCTL 0x015c
+
+#define MAX_CLKS 27
+static struct clk *clks[MAX_CLKS];
+static struct clk_onecell_data clk_data;
+static DEFINE_SPINLOCK(lock);
+static void __iomem *gbase;
+static void __iomem *cpupll_base;
+
+enum {
+ REFCLK,
+ SYSPLL, CPUPLL,
+ AVPLL_B1, AVPLL_B2, AVPLL_B3, AVPLL_B4,
+ AVPLL_B5, AVPLL_B6, AVPLL_B7, AVPLL_B8,
+};
+
+static const char *clk_names[] = {
+ [REFCLK] = "refclk",
+ [SYSPLL] = "syspll",
+ [CPUPLL] = "cpupll",
+ [AVPLL_B1] = "avpll_b1",
+ [AVPLL_B2] = "avpll_b2",
+ [AVPLL_B3] = "avpll_b3",
+ [AVPLL_B4] = "avpll_b4",
+ [AVPLL_B5] = "avpll_b5",
+ [AVPLL_B6] = "avpll_b6",
+ [AVPLL_B7] = "avpll_b7",
+ [AVPLL_B8] = "avpll_b8",
+};
+
+static const struct berlin2_pll_map bg2q_pll_map __initconst = {
+ .vcodiv = {1, 0, 2, 0, 3, 4, 0, 6, 8},
+ .mult = 1,
+ .fbdiv_shift = 7,
+ .rfdiv_shift = 2,
+ .divsel_shift = 9,
+};
+
+static const u8 default_parent_ids[] = {
+ SYSPLL, AVPLL_B4, AVPLL_B5, AVPLL_B6, AVPLL_B7, SYSPLL
+};
+
+static const struct berlin2_div_data bg2q_divs[] __initconst = {
+ {
+ .name = "sys",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 0),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ {
+ .name = "drmfigo",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 17),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "cfg",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 1),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT0, 12),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT0, 15),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 9),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 10),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 11),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "gfx2d",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 4),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT0, 18),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT0, 21),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "zsp",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 6),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT0, 24),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT0, 27),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "perif",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 7),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT1, 0),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT1, 3),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+ {
+ .name = "pcube",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 2),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT1, 6),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT1, 9),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "vscope",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 3),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT1, 12),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT1, 15),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "nfc_ecc",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 19),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT1, 18),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT1, 21),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "vpp",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 21),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT1, 24),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT1, 27),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "app",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_DIV_GATE(REG_CLKENABLE, 20),
+ BERLIN2_PLL_SELECT(REG_CLKSELECT2, 0),
+ BERLIN2_DIV_SELECT(REG_CLKSELECT2, 3),
+ BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),
+ BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),
+ BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "sdio0xin",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_SINGLE_DIV(REG_SDIO0XIN_CLKCTL),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+ {
+ .name = "sdio1xin",
+ .parent_ids = default_parent_ids,
+ .num_parents = ARRAY_SIZE(default_parent_ids),
+ .map = {
+ BERLIN2_SINGLE_DIV(REG_SDIO1XIN_CLKCTL),
+ },
+ .div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+ .flags = 0,
+ },
+};
+
+static const struct berlin2_gate_data bg2q_gates[] __initconst = {
+ { "gfx2daxi", "perif", 5 },
+ { "geth0", "perif", 8 },
+ { "sata", "perif", 9 },
+ { "ahbapb", "perif", 10, CLK_IGNORE_UNUSED },
+ { "usb0", "perif", 11 },
+ { "usb1", "perif", 12 },
+ { "usb2", "perif", 13 },
+ { "usb3", "perif", 14 },
+ { "pbridge", "perif", 15, CLK_IGNORE_UNUSED },
+ { "sdio", "perif", 16, CLK_IGNORE_UNUSED },
+ { "nfc", "perif", 18 },
+ { "smemc", "perif", 19 },
+ { "pcie", "perif", 22 },
+};
+
+static void __init berlin2q_clock_setup(struct device_node *np)
+{
+ const char *parent_names[9];
+ struct clk *clk;
+ int n;
+
+ gbase = of_iomap(np, 0);
+ if (!gbase) {
+ pr_err("%s: Unable to map global base\n", np->full_name);
+ return;
+ }
+
+ /* BG2Q CPU PLL is not part of global registers */
+ cpupll_base = of_iomap(np, 1);
+ if (!cpupll_base) {
+ pr_err("%s: Unable to map cpupll base\n", np->full_name);
+ iounmap(gbase);
+ return;
+ }
+
+ /* overwrite default clock names with DT provided ones */
+ clk = of_clk_get_by_name(np, clk_names[REFCLK]);
+ if (!IS_ERR(clk)) {
+ clk_names[REFCLK] = __clk_get_name(clk);
+ clk_put(clk);
+ }
+
+ /* simple register PLLs */
+ clk = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0,
+ clk_names[SYSPLL], clk_names[REFCLK], 0);
+ if (IS_ERR(clk))
+ goto bg2q_fail;
+
+ clk = berlin2_pll_register(&bg2q_pll_map, cpupll_base,
+ clk_names[CPUPLL], clk_names[REFCLK], 0);
+ if (IS_ERR(clk))
+ goto bg2q_fail;
+
+ /* TODO: add BG2Q AVPLL */
+
+ /*
+ * TODO: add reference clock bypass switches:
+ * memPLLSWBypass, cpuPLLSWBypass, and sysPLLSWBypass
+ */
+
+ /* clock divider cells */
+ for (n = 0; n < ARRAY_SIZE(bg2q_divs); n++) {
+ const struct berlin2_div_data *dd = &bg2q_divs[n];
+ int k;
+
+ for (k = 0; k < dd->num_parents; k++)
+ parent_names[k] = clk_names[dd->parent_ids[k]];
+
+ clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase,
+ dd->name, dd->div_flags, parent_names,
+ dd->num_parents, dd->flags, &lock);
+ }
+
+ /* clock gate cells */
+ for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) {
+ const struct berlin2_gate_data *gd = &bg2q_gates[n];
+
+ clks[CLKID_GFX2DAXI + n] = clk_register_gate(NULL, gd->name,
+ gd->parent_name, gd->flags, gbase + REG_CLKENABLE,
+ gd->bit_idx, 0, &lock);
+ }
+
+ /*
+ * twdclk is derived from cpu/3
+ * TODO: use cpupll until cpuclk is not available
+ */
+ clks[CLKID_TWD] =
+ clk_register_fixed_factor(NULL, "twd", clk_names[CPUPLL],
+ 0, 1, 3);
+
+ /* check for errors on leaf clocks */
+ for (n = 0; n < MAX_CLKS; n++) {
+ if (!IS_ERR(clks[n]))
+ continue;
+
+ pr_err("%s: Unable to register leaf clock %d\n",
+ np->full_name, n);
+ goto bg2q_fail;
+ }
+
+ /* register clk-provider */
+ clk_data.clks = clks;
+ clk_data.clk_num = MAX_CLKS;
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+
+ return;
+
+bg2q_fail:
+ iounmap(cpupll_base);
+ iounmap(gbase);
+}
+CLK_OF_DECLARE(berlin2q_clock, "marvell,berlin2q-chip-ctrl",
+ berlin2q_clock_setup);
diff --git a/drivers/clk/berlin/common.h b/drivers/clk/berlin/common.h
new file mode 100644
index 000000000000..bc68a14c4550
--- /dev/null
+++ b/drivers/clk/berlin/common.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __BERLIN2_COMMON_H
+#define __BERLIN2_COMMON_H
+
+struct berlin2_gate_data {
+ const char *name;
+ const char *parent_name;
+ u8 bit_idx;
+ unsigned long flags;
+};
+
+#endif /* BERLIN2_COMMON_H */
diff --git a/drivers/clk/clk-axm5516.c b/drivers/clk/clk-axm5516.c
new file mode 100644
index 000000000000..d2f1e119b450
--- /dev/null
+++ b/drivers/clk/clk-axm5516.c
@@ -0,0 +1,615 @@
+/*
+ * drivers/clk/clk-axm5516.c
+ *
+ * Provides clock implementations for three different types of clock devices on
+ * the Axxia device: PLL clock, a clock divider and a clock mux.
+ *
+ * Copyright (C) 2014 LSI Corporation
+ *
+ * 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/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <dt-bindings/clock/lsi,axm5516-clks.h>
+
+
+/**
+ * struct axxia_clk - Common struct to all Axxia clocks.
+ * @hw: clk_hw for the common clk framework
+ * @regmap: Regmap for the clock control registers
+ */
+struct axxia_clk {
+ struct clk_hw hw;
+ struct regmap *regmap;
+};
+#define to_axxia_clk(_hw) container_of(_hw, struct axxia_clk, hw)
+
+/**
+ * struct axxia_pllclk - Axxia PLL generated clock.
+ * @aclk: Common struct
+ * @reg: Offset into regmap for PLL control register
+ */
+struct axxia_pllclk {
+ struct axxia_clk aclk;
+ u32 reg;
+};
+#define to_axxia_pllclk(_aclk) container_of(_aclk, struct axxia_pllclk, aclk)
+
+/**
+ * axxia_pllclk_recalc - Calculate the PLL generated clock rate given the
+ * parent clock rate.
+ */
+static unsigned long
+axxia_pllclk_recalc(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct axxia_clk *aclk = to_axxia_clk(hw);
+ struct axxia_pllclk *pll = to_axxia_pllclk(aclk);
+ unsigned long rate, fbdiv, refdiv, postdiv;
+ u32 control;
+
+ regmap_read(aclk->regmap, pll->reg, &control);
+ postdiv = ((control >> 0) & 0xf) + 1;
+ fbdiv = ((control >> 4) & 0xfff) + 3;
+ refdiv = ((control >> 16) & 0x1f) + 1;
+ rate = (parent_rate / (refdiv * postdiv)) * fbdiv;
+
+ return rate;
+}
+
+static const struct clk_ops axxia_pllclk_ops = {
+ .recalc_rate = axxia_pllclk_recalc,
+};
+
+/**
+ * struct axxia_divclk - Axxia clock divider
+ * @aclk: Common struct
+ * @reg: Offset into regmap for PLL control register
+ * @shift: Bit position for divider value
+ * @width: Number of bits in divider value
+ */
+struct axxia_divclk {
+ struct axxia_clk aclk;
+ u32 reg;
+ u32 shift;
+ u32 width;
+};
+#define to_axxia_divclk(_aclk) container_of(_aclk, struct axxia_divclk, aclk)
+
+/**
+ * axxia_divclk_recalc_rate - Calculate clock divider output rage
+ */
+static unsigned long
+axxia_divclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct axxia_clk *aclk = to_axxia_clk(hw);
+ struct axxia_divclk *divclk = to_axxia_divclk(aclk);
+ u32 ctrl, div;
+
+ regmap_read(aclk->regmap, divclk->reg, &ctrl);
+ div = 1 + ((ctrl >> divclk->shift) & ((1 << divclk->width)-1));
+
+ return parent_rate / div;
+}
+
+static const struct clk_ops axxia_divclk_ops = {
+ .recalc_rate = axxia_divclk_recalc_rate,
+};
+
+/**
+ * struct axxia_clkmux - Axxia clock mux
+ * @aclk: Common struct
+ * @reg: Offset into regmap for PLL control register
+ * @shift: Bit position for selection value
+ * @width: Number of bits in selection value
+ */
+struct axxia_clkmux {
+ struct axxia_clk aclk;
+ u32 reg;
+ u32 shift;
+ u32 width;
+};
+#define to_axxia_clkmux(_aclk) container_of(_aclk, struct axxia_clkmux, aclk)
+
+/**
+ * axxia_clkmux_get_parent - Return the index of selected parent clock
+ */
+static u8 axxia_clkmux_get_parent(struct clk_hw *hw)
+{
+ struct axxia_clk *aclk = to_axxia_clk(hw);
+ struct axxia_clkmux *mux = to_axxia_clkmux(aclk);
+ u32 ctrl, parent;
+
+ regmap_read(aclk->regmap, mux->reg, &ctrl);
+ parent = (ctrl >> mux->shift) & ((1 << mux->width) - 1);
+
+ return (u8) parent;
+}
+
+static const struct clk_ops axxia_clkmux_ops = {
+ .get_parent = axxia_clkmux_get_parent,
+};
+
+
+/*
+ * PLLs
+ */
+
+static struct axxia_pllclk clk_fab_pll = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_fab_pll",
+ .parent_names = (const char *[]){
+ "clk_ref0"
+ },
+ .num_parents = 1,
+ .ops = &axxia_pllclk_ops,
+ },
+ .reg = 0x01800,
+};
+
+static struct axxia_pllclk clk_cpu_pll = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_cpu_pll",
+ .parent_names = (const char *[]){
+ "clk_ref0"
+ },
+ .num_parents = 1,
+ .ops = &axxia_pllclk_ops,
+ },
+ .reg = 0x02000,
+};
+
+static struct axxia_pllclk clk_sys_pll = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_sys_pll",
+ .parent_names = (const char *[]){
+ "clk_ref0"
+ },
+ .num_parents = 1,
+ .ops = &axxia_pllclk_ops,
+ },
+ .reg = 0x02800,
+};
+
+static struct axxia_pllclk clk_sm0_pll = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_sm0_pll",
+ .parent_names = (const char *[]){
+ "clk_ref2"
+ },
+ .num_parents = 1,
+ .ops = &axxia_pllclk_ops,
+ },
+ .reg = 0x03000,
+};
+
+static struct axxia_pllclk clk_sm1_pll = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_sm1_pll",
+ .parent_names = (const char *[]){
+ "clk_ref1"
+ },
+ .num_parents = 1,
+ .ops = &axxia_pllclk_ops,
+ },
+ .reg = 0x03800,
+};
+
+/*
+ * Clock dividers
+ */
+
+static struct axxia_divclk clk_cpu0_div = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_cpu0_div",
+ .parent_names = (const char *[]){
+ "clk_cpu_pll"
+ },
+ .num_parents = 1,
+ .ops = &axxia_divclk_ops,
+ },
+ .reg = 0x10008,
+ .shift = 0,
+ .width = 4,
+};
+
+static struct axxia_divclk clk_cpu1_div = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_cpu1_div",
+ .parent_names = (const char *[]){
+ "clk_cpu_pll"
+ },
+ .num_parents = 1,
+ .ops = &axxia_divclk_ops,
+ },
+ .reg = 0x10008,
+ .shift = 4,
+ .width = 4,
+};
+
+static struct axxia_divclk clk_cpu2_div = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_cpu2_div",
+ .parent_names = (const char *[]){
+ "clk_cpu_pll"
+ },
+ .num_parents = 1,
+ .ops = &axxia_divclk_ops,
+ },
+ .reg = 0x10008,
+ .shift = 8,
+ .width = 4,
+};
+
+static struct axxia_divclk clk_cpu3_div = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_cpu3_div",
+ .parent_names = (const char *[]){
+ "clk_cpu_pll"
+ },
+ .num_parents = 1,
+ .ops = &axxia_divclk_ops,
+ },
+ .reg = 0x10008,
+ .shift = 12,
+ .width = 4,
+};
+
+static struct axxia_divclk clk_nrcp_div = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_nrcp_div",
+ .parent_names = (const char *[]){
+ "clk_sys_pll"
+ },
+ .num_parents = 1,
+ .ops = &axxia_divclk_ops,
+ },
+ .reg = 0x1000c,
+ .shift = 0,
+ .width = 4,
+};
+
+static struct axxia_divclk clk_sys_div = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_sys_div",
+ .parent_names = (const char *[]){
+ "clk_sys_pll"
+ },
+ .num_parents = 1,
+ .ops = &axxia_divclk_ops,
+ },
+ .reg = 0x1000c,
+ .shift = 4,
+ .width = 4,
+};
+
+static struct axxia_divclk clk_fab_div = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_fab_div",
+ .parent_names = (const char *[]){
+ "clk_fab_pll"
+ },
+ .num_parents = 1,
+ .ops = &axxia_divclk_ops,
+ },
+ .reg = 0x1000c,
+ .shift = 8,
+ .width = 4,
+};
+
+static struct axxia_divclk clk_per_div = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_per_div",
+ .parent_names = (const char *[]){
+ "clk_sm1_pll"
+ },
+ .num_parents = 1,
+ .flags = CLK_IS_BASIC,
+ .ops = &axxia_divclk_ops,
+ },
+ .reg = 0x1000c,
+ .shift = 12,
+ .width = 4,
+};
+
+static struct axxia_divclk clk_mmc_div = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_mmc_div",
+ .parent_names = (const char *[]){
+ "clk_sm1_pll"
+ },
+ .num_parents = 1,
+ .flags = CLK_IS_BASIC,
+ .ops = &axxia_divclk_ops,
+ },
+ .reg = 0x1000c,
+ .shift = 16,
+ .width = 4,
+};
+
+/*
+ * Clock MUXes
+ */
+
+static struct axxia_clkmux clk_cpu0_mux = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_cpu0",
+ .parent_names = (const char *[]){
+ "clk_ref0",
+ "clk_cpu_pll",
+ "clk_cpu0_div",
+ "clk_cpu0_div"
+ },
+ .num_parents = 4,
+ .ops = &axxia_clkmux_ops,
+ },
+ .reg = 0x10000,
+ .shift = 0,
+ .width = 2,
+};
+
+static struct axxia_clkmux clk_cpu1_mux = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_cpu1",
+ .parent_names = (const char *[]){
+ "clk_ref0",
+ "clk_cpu_pll",
+ "clk_cpu1_div",
+ "clk_cpu1_div"
+ },
+ .num_parents = 4,
+ .ops = &axxia_clkmux_ops,
+ },
+ .reg = 0x10000,
+ .shift = 2,
+ .width = 2,
+};
+
+static struct axxia_clkmux clk_cpu2_mux = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_cpu2",
+ .parent_names = (const char *[]){
+ "clk_ref0",
+ "clk_cpu_pll",
+ "clk_cpu2_div",
+ "clk_cpu2_div"
+ },
+ .num_parents = 4,
+ .ops = &axxia_clkmux_ops,
+ },
+ .reg = 0x10000,
+ .shift = 4,
+ .width = 2,
+};
+
+static struct axxia_clkmux clk_cpu3_mux = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_cpu3",
+ .parent_names = (const char *[]){
+ "clk_ref0",
+ "clk_cpu_pll",
+ "clk_cpu3_div",
+ "clk_cpu3_div"
+ },
+ .num_parents = 4,
+ .ops = &axxia_clkmux_ops,
+ },
+ .reg = 0x10000,
+ .shift = 6,
+ .width = 2,
+};
+
+static struct axxia_clkmux clk_nrcp_mux = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_nrcp",
+ .parent_names = (const char *[]){
+ "clk_ref0",
+ "clk_sys_pll",
+ "clk_nrcp_div",
+ "clk_nrcp_div"
+ },
+ .num_parents = 4,
+ .ops = &axxia_clkmux_ops,
+ },
+ .reg = 0x10004,
+ .shift = 0,
+ .width = 2,
+};
+
+static struct axxia_clkmux clk_sys_mux = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_sys",
+ .parent_names = (const char *[]){
+ "clk_ref0",
+ "clk_sys_pll",
+ "clk_sys_div",
+ "clk_sys_div"
+ },
+ .num_parents = 4,
+ .ops = &axxia_clkmux_ops,
+ },
+ .reg = 0x10004,
+ .shift = 2,
+ .width = 2,
+};
+
+static struct axxia_clkmux clk_fab_mux = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_fab",
+ .parent_names = (const char *[]){
+ "clk_ref0",
+ "clk_fab_pll",
+ "clk_fab_div",
+ "clk_fab_div"
+ },
+ .num_parents = 4,
+ .ops = &axxia_clkmux_ops,
+ },
+ .reg = 0x10004,
+ .shift = 4,
+ .width = 2,
+};
+
+static struct axxia_clkmux clk_per_mux = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_per",
+ .parent_names = (const char *[]){
+ "clk_ref1",
+ "clk_per_div"
+ },
+ .num_parents = 2,
+ .ops = &axxia_clkmux_ops,
+ },
+ .reg = 0x10004,
+ .shift = 6,
+ .width = 1,
+};
+
+static struct axxia_clkmux clk_mmc_mux = {
+ .aclk.hw.init = &(struct clk_init_data){
+ .name = "clk_mmc",
+ .parent_names = (const char *[]){
+ "clk_ref1",
+ "clk_mmc_div"
+ },
+ .num_parents = 2,
+ .ops = &axxia_clkmux_ops,
+ },
+ .reg = 0x10004,
+ .shift = 9,
+ .width = 1,
+};
+
+/* Table of all supported clocks indexed by the clock identifiers from the
+ * device tree binding
+ */
+static struct axxia_clk *axmclk_clocks[] = {
+ [AXXIA_CLK_FAB_PLL] = &clk_fab_pll.aclk,
+ [AXXIA_CLK_CPU_PLL] = &clk_cpu_pll.aclk,
+ [AXXIA_CLK_SYS_PLL] = &clk_sys_pll.aclk,
+ [AXXIA_CLK_SM0_PLL] = &clk_sm0_pll.aclk,
+ [AXXIA_CLK_SM1_PLL] = &clk_sm1_pll.aclk,
+ [AXXIA_CLK_FAB_DIV] = &clk_fab_div.aclk,
+ [AXXIA_CLK_SYS_DIV] = &clk_sys_div.aclk,
+ [AXXIA_CLK_NRCP_DIV] = &clk_nrcp_div.aclk,
+ [AXXIA_CLK_CPU0_DIV] = &clk_cpu0_div.aclk,
+ [AXXIA_CLK_CPU1_DIV] = &clk_cpu1_div.aclk,
+ [AXXIA_CLK_CPU2_DIV] = &clk_cpu2_div.aclk,
+ [AXXIA_CLK_CPU3_DIV] = &clk_cpu3_div.aclk,
+ [AXXIA_CLK_PER_DIV] = &clk_per_div.aclk,
+ [AXXIA_CLK_MMC_DIV] = &clk_mmc_div.aclk,
+ [AXXIA_CLK_FAB] = &clk_fab_mux.aclk,
+ [AXXIA_CLK_SYS] = &clk_sys_mux.aclk,
+ [AXXIA_CLK_NRCP] = &clk_nrcp_mux.aclk,
+ [AXXIA_CLK_CPU0] = &clk_cpu0_mux.aclk,
+ [AXXIA_CLK_CPU1] = &clk_cpu1_mux.aclk,
+ [AXXIA_CLK_CPU2] = &clk_cpu2_mux.aclk,
+ [AXXIA_CLK_CPU3] = &clk_cpu3_mux.aclk,
+ [AXXIA_CLK_PER] = &clk_per_mux.aclk,
+ [AXXIA_CLK_MMC] = &clk_mmc_mux.aclk,
+};
+
+static const struct regmap_config axmclk_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x1fffc,
+ .fast_io = true,
+};
+
+static const struct of_device_id axmclk_match_table[] = {
+ { .compatible = "lsi,axm5516-clks" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, axmclk_match_table);
+
+struct axmclk_priv {
+ struct clk_onecell_data onecell;
+ struct clk *clks[];
+};
+
+static int axmclk_probe(struct platform_device *pdev)
+{
+ void __iomem *base;
+ struct resource *res;
+ int i, ret;
+ struct device *dev = &pdev->dev;
+ struct clk *clk;
+ struct regmap *regmap;
+ size_t num_clks;
+ struct axmclk_priv *priv;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = devm_regmap_init_mmio(dev, base, &axmclk_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ num_clks = ARRAY_SIZE(axmclk_clocks);
+ pr_info("axmclk: supporting %u clocks\n", num_clks);
+ priv = devm_kzalloc(dev, sizeof(*priv) + sizeof(*priv->clks) * num_clks,
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->onecell.clks = priv->clks;
+ priv->onecell.clk_num = num_clks;
+
+ /* Update each entry with the allocated regmap and register the clock
+ * with the common clock framework
+ */
+ for (i = 0; i < num_clks; i++) {
+ axmclk_clocks[i]->regmap = regmap;
+ clk = devm_clk_register(dev, &axmclk_clocks[i]->hw);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ priv->clks[i] = clk;
+ }
+
+ ret = of_clk_add_provider(dev->of_node,
+ of_clk_src_onecell_get, &priv->onecell);
+
+ return ret;
+}
+
+static int axmclk_remove(struct platform_device *pdev)
+{
+ of_clk_del_provider(pdev->dev.of_node);
+ return 0;
+}
+
+static struct platform_driver axmclk_driver = {
+ .probe = axmclk_probe,
+ .remove = axmclk_remove,
+ .driver = {
+ .name = "clk-axm5516",
+ .owner = THIS_MODULE,
+ .of_match_table = axmclk_match_table,
+ },
+};
+
+static int __init axmclk_init(void)
+{
+ return platform_driver_register(&axmclk_driver);
+}
+core_initcall(axmclk_init);
+
+static void __exit axmclk_exit(void)
+{
+ platform_driver_unregister(&axmclk_driver);
+}
+module_exit(axmclk_exit);
+
+MODULE_DESCRIPTION("AXM5516 clock driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:clk-axm5516");
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 3fbee4540228..18a9de29df0e 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -43,6 +43,17 @@ static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
return maxdiv;
}
+static unsigned int _get_table_mindiv(const struct clk_div_table *table)
+{
+ unsigned int mindiv = UINT_MAX;
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->div < mindiv)
+ mindiv = clkt->div;
+ return mindiv;
+}
+
static unsigned int _get_maxdiv(struct clk_divider *divider)
{
if (divider->flags & CLK_DIVIDER_ONE_BASED)
@@ -162,6 +173,24 @@ static int _round_up_table(const struct clk_div_table *table, int div)
return up;
}
+static int _round_down_table(const struct clk_div_table *table, int div)
+{
+ const struct clk_div_table *clkt;
+ int down = _get_table_mindiv(table);
+
+ for (clkt = table; clkt->div; clkt++) {
+ if (clkt->div == div)
+ return clkt->div;
+ else if (clkt->div > div)
+ continue;
+
+ if ((div - clkt->div) < (div - down))
+ down = clkt->div;
+ }
+
+ return down;
+}
+
static int _div_round_up(struct clk_divider *divider,
unsigned long parent_rate, unsigned long rate)
{
@@ -175,6 +204,54 @@ static int _div_round_up(struct clk_divider *divider,
return div;
}
+static int _div_round_closest(struct clk_divider *divider,
+ unsigned long parent_rate, unsigned long rate)
+{
+ int up, down, div;
+
+ up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
+
+ if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) {
+ up = __roundup_pow_of_two(div);
+ down = __rounddown_pow_of_two(div);
+ } else if (divider->table) {
+ up = _round_up_table(divider->table, div);
+ down = _round_down_table(divider->table, div);
+ }
+
+ return (up - div) <= (div - down) ? up : down;
+}
+
+static int _div_round(struct clk_divider *divider, unsigned long parent_rate,
+ unsigned long rate)
+{
+ if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
+ return _div_round_closest(divider, parent_rate, rate);
+
+ return _div_round_up(divider, parent_rate, rate);
+}
+
+static bool _is_best_div(struct clk_divider *divider,
+ unsigned long rate, unsigned long now, unsigned long best)
+{
+ if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
+ return abs(rate - now) < abs(rate - best);
+
+ return now <= rate && now > best;
+}
+
+static int _next_div(struct clk_divider *divider, int div)
+{
+ div++;
+
+ if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ return __roundup_pow_of_two(div);
+ if (divider->table)
+ return _round_up_table(divider->table, div);
+
+ return div;
+}
+
static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate)
{
@@ -190,7 +267,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
parent_rate = *best_parent_rate;
- bestdiv = _div_round_up(divider, parent_rate, rate);
+ bestdiv = _div_round(divider, parent_rate, rate);
bestdiv = bestdiv == 0 ? 1 : bestdiv;
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
return bestdiv;
@@ -202,7 +279,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
*/
maxdiv = min(ULONG_MAX / rate, maxdiv);
- for (i = 1; i <= maxdiv; i++) {
+ for (i = 1; i <= maxdiv; i = _next_div(divider, i)) {
if (!_is_valid_div(divider, i))
continue;
if (rate * i == parent_rate_saved) {
@@ -217,7 +294,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i));
now = DIV_ROUND_UP(parent_rate, i);
- if (now <= rate && now > best) {
+ if (_is_best_div(divider, rate, now, best)) {
bestdiv = i;
best = now;
*best_parent_rate = parent_rate;
@@ -284,6 +361,11 @@ const struct clk_ops clk_divider_ops = {
};
EXPORT_SYMBOL_GPL(clk_divider_ops);
+const struct clk_ops clk_divider_ro_ops = {
+ .recalc_rate = clk_divider_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(clk_divider_ro_ops);
+
static struct clk *_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
@@ -309,7 +391,10 @@ static struct clk *_register_divider(struct device *dev, const char *name,
}
init.name = name;
- init.ops = &clk_divider_ops;
+ if (clk_divider_flags & CLK_DIVIDER_READ_ONLY)
+ init.ops = &clk_divider_ro_ops;
+ else
+ init.ops = &clk_divider_ops;
init.flags = flags | CLK_IS_BASIC;
init.parent_names = (parent_name ? &parent_name: NULL);
init.num_parents = (parent_name ? 1 : 0);
diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c
new file mode 100644
index 000000000000..ede685ca0d20
--- /dev/null
+++ b/drivers/clk/clk-fractional-divider.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * 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.
+ *
+ * Adjustable fractional divider clock implementation.
+ * Output rate = (m / n) * parent_rate.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/gcd.h>
+
+#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw)
+
+static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_fractional_divider *fd = to_clk_fd(hw);
+ unsigned long flags = 0;
+ u32 val, m, n;
+ u64 ret;
+
+ if (fd->lock)
+ spin_lock_irqsave(fd->lock, flags);
+
+ val = clk_readl(fd->reg);
+
+ if (fd->lock)
+ spin_unlock_irqrestore(fd->lock, flags);
+
+ m = (val & fd->mmask) >> fd->mshift;
+ n = (val & fd->nmask) >> fd->nshift;
+
+ ret = parent_rate * m;
+ do_div(ret, n);
+
+ return ret;
+}
+
+static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_fractional_divider *fd = to_clk_fd(hw);
+ unsigned maxn = (fd->nmask >> fd->nshift) + 1;
+ unsigned div;
+
+ if (!rate || rate >= *prate)
+ return *prate;
+
+ div = gcd(*prate, rate);
+
+ while ((*prate / div) > maxn) {
+ div <<= 1;
+ rate <<= 1;
+ }
+
+ return rate;
+}
+
+static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_fractional_divider *fd = to_clk_fd(hw);
+ unsigned long flags = 0;
+ unsigned long div;
+ unsigned n, m;
+ u32 val;
+
+ div = gcd(parent_rate, rate);
+ m = rate / div;
+ n = parent_rate / div;
+
+ if (fd->lock)
+ spin_lock_irqsave(fd->lock, flags);
+
+ val = clk_readl(fd->reg);
+ val &= ~(fd->mmask | fd->nmask);
+ val |= (m << fd->mshift) | (n << fd->nshift);
+ clk_writel(val, fd->reg);
+
+ if (fd->lock)
+ spin_unlock_irqrestore(fd->lock, flags);
+
+ return 0;
+}
+
+const struct clk_ops clk_fractional_divider_ops = {
+ .recalc_rate = clk_fd_recalc_rate,
+ .round_rate = clk_fd_round_rate,
+ .set_rate = clk_fd_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_fractional_divider_ops);
+
+struct clk *clk_register_fractional_divider(struct device *dev,
+ const char *name, const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
+ u8 clk_divider_flags, spinlock_t *lock)
+{
+ struct clk_fractional_divider *fd;
+ struct clk_init_data init;
+ struct clk *clk;
+
+ fd = kzalloc(sizeof(*fd), GFP_KERNEL);
+ if (!fd) {
+ dev_err(dev, "could not allocate fractional divider clk\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = name;
+ init.ops = &clk_fractional_divider_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+
+ fd->reg = reg;
+ fd->mshift = mshift;
+ fd->mmask = (BIT(mwidth) - 1) << mshift;
+ fd->nshift = nshift;
+ fd->nmask = (BIT(nwidth) - 1) << nshift;
+ fd->flags = clk_divider_flags;
+ fd->lock = lock;
+ fd->hw.init = &init;
+
+ clk = clk_register(dev, &fd->hw);
+ if (IS_ERR(clk))
+ kfree(fd);
+
+ return clk;
+}
+EXPORT_SYMBOL_GPL(clk_register_fractional_divider);
diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c
index f2f62a1bf61a..3757e9e72d37 100644
--- a/drivers/clk/clk-s2mps11.c
+++ b/drivers/clk/clk-s2mps11.c
@@ -1,7 +1,7 @@
/*
* clk-s2mps11.c - Clock driver for S2MPS11.
*
- * Copyright (C) 2013 Samsung Electornics
+ * Copyright (C) 2013,2014 Samsung Electornics
*
* 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
@@ -13,10 +13,6 @@
* 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/module.h>
@@ -27,6 +23,7 @@
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s2mps14.h>
#include <linux/mfd/samsung/s5m8767.h>
#include <linux/mfd/samsung/core.h>
@@ -44,6 +41,7 @@ enum {
struct s2mps11_clk {
struct sec_pmic_dev *iodev;
+ struct device_node *clk_np;
struct clk_hw hw;
struct clk *clk;
struct clk_lookup *lookup;
@@ -125,7 +123,21 @@ static struct clk_init_data s2mps11_clks_init[S2MPS11_CLKS_NUM] = {
},
};
-static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev)
+static struct clk_init_data s2mps14_clks_init[S2MPS11_CLKS_NUM] = {
+ [S2MPS11_CLK_AP] = {
+ .name = "s2mps14_ap",
+ .ops = &s2mps11_clk_ops,
+ .flags = CLK_IS_ROOT,
+ },
+ [S2MPS11_CLK_BT] = {
+ .name = "s2mps14_bt",
+ .ops = &s2mps11_clk_ops,
+ .flags = CLK_IS_ROOT,
+ },
+};
+
+static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev,
+ struct clk_init_data *clks_init)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct device_node *clk_np;
@@ -140,14 +152,12 @@ static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev)
return ERR_PTR(-EINVAL);
}
- clk_table = devm_kzalloc(&pdev->dev, sizeof(struct clk *) *
- S2MPS11_CLKS_NUM, GFP_KERNEL);
- if (!clk_table)
- return ERR_PTR(-ENOMEM);
-
- for (i = 0; i < S2MPS11_CLKS_NUM; i++)
+ for (i = 0; i < S2MPS11_CLKS_NUM; i++) {
+ if (!clks_init[i].name)
+ continue; /* Skip clocks not present in some devices */
of_property_read_string_index(clk_np, "clock-output-names", i,
- &s2mps11_clks_init[i].name);
+ &clks_init[i].name);
+ }
return clk_np;
}
@@ -156,8 +166,8 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct s2mps11_clk *s2mps11_clks, *s2mps11_clk;
- struct device_node *clk_np = NULL;
unsigned int s2mps11_reg;
+ struct clk_init_data *clks_init;
int i, ret = 0;
u32 val;
@@ -168,25 +178,39 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
s2mps11_clk = s2mps11_clks;
- clk_np = s2mps11_clk_parse_dt(pdev);
- if (IS_ERR(clk_np))
- return PTR_ERR(clk_np);
+ clk_table = devm_kzalloc(&pdev->dev, sizeof(struct clk *) *
+ S2MPS11_CLKS_NUM, GFP_KERNEL);
+ if (!clk_table)
+ return -ENOMEM;
switch(platform_get_device_id(pdev)->driver_data) {
case S2MPS11X:
s2mps11_reg = S2MPS11_REG_RTC_CTRL;
+ clks_init = s2mps11_clks_init;
+ break;
+ case S2MPS14X:
+ s2mps11_reg = S2MPS14_REG_RTCCTRL;
+ clks_init = s2mps14_clks_init;
break;
case S5M8767X:
s2mps11_reg = S5M8767_REG_CTRL1;
+ clks_init = s2mps11_clks_init;
break;
default:
dev_err(&pdev->dev, "Invalid device type\n");
return -EINVAL;
};
+ /* Store clocks of_node in first element of s2mps11_clks array */
+ s2mps11_clks->clk_np = s2mps11_clk_parse_dt(pdev, clks_init);
+ if (IS_ERR(s2mps11_clks->clk_np))
+ return PTR_ERR(s2mps11_clks->clk_np);
+
for (i = 0; i < S2MPS11_CLKS_NUM; i++, s2mps11_clk++) {
+ if (!clks_init[i].name)
+ continue; /* Skip clocks not present in some devices */
s2mps11_clk->iodev = iodev;
- s2mps11_clk->hw.init = &s2mps11_clks_init[i];
+ s2mps11_clk->hw.init = &clks_init[i];
s2mps11_clk->mask = 1 << i;
s2mps11_clk->reg = s2mps11_reg;
@@ -206,28 +230,28 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
goto err_reg;
}
- s2mps11_clk->lookup = devm_kzalloc(&pdev->dev,
- sizeof(struct clk_lookup), GFP_KERNEL);
+ s2mps11_clk->lookup = clkdev_alloc(s2mps11_clk->clk,
+ s2mps11_name(s2mps11_clk), NULL);
if (!s2mps11_clk->lookup) {
ret = -ENOMEM;
goto err_lup;
}
- s2mps11_clk->lookup->con_id = s2mps11_name(s2mps11_clk);
- s2mps11_clk->lookup->clk = s2mps11_clk->clk;
-
clkdev_add(s2mps11_clk->lookup);
}
- if (clk_table) {
- for (i = 0; i < S2MPS11_CLKS_NUM; i++)
- clk_table[i] = s2mps11_clks[i].clk;
-
- clk_data.clks = clk_table;
- clk_data.clk_num = S2MPS11_CLKS_NUM;
- of_clk_add_provider(clk_np, of_clk_src_onecell_get, &clk_data);
+ for (i = 0; i < S2MPS11_CLKS_NUM; i++) {
+ /* Skip clocks not present on S2MPS14 */
+ if (!clks_init[i].name)
+ continue;
+ clk_table[i] = s2mps11_clks[i].clk;
}
+ clk_data.clks = clk_table;
+ clk_data.clk_num = S2MPS11_CLKS_NUM;
+ of_clk_add_provider(s2mps11_clks->clk_np, of_clk_src_onecell_get,
+ &clk_data);
+
platform_set_drvdata(pdev, s2mps11_clks);
return ret;
@@ -250,14 +274,23 @@ static int s2mps11_clk_remove(struct platform_device *pdev)
struct s2mps11_clk *s2mps11_clks = platform_get_drvdata(pdev);
int i;
- for (i = 0; i < S2MPS11_CLKS_NUM; i++)
+ of_clk_del_provider(s2mps11_clks[0].clk_np);
+ /* Drop the reference obtained in s2mps11_clk_parse_dt */
+ of_node_put(s2mps11_clks[0].clk_np);
+
+ for (i = 0; i < S2MPS11_CLKS_NUM; i++) {
+ /* Skip clocks not present on S2MPS14 */
+ if (!s2mps11_clks[i].lookup)
+ continue;
clkdev_drop(s2mps11_clks[i].lookup);
+ }
return 0;
}
static const struct platform_device_id s2mps11_clk_id[] = {
{ "s2mps11-clk", S2MPS11X},
+ { "s2mps14-clk", S2MPS14X},
{ "s5m8767-clk", S5M8767X},
{ },
};
diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c
index 4bbbe32585ec..fc167b3f8919 100644
--- a/drivers/clk/clk-si570.c
+++ b/drivers/clk/clk-si570.c
@@ -526,6 +526,6 @@ static struct i2c_driver si570_driver = {
module_i2c_driver(si570_driver);
MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
-MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com");
+MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>");
MODULE_DESCRIPTION("Si570 driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-u300.c b/drivers/clk/clk-u300.c
index 3efbdd078d14..406bfc1375b2 100644
--- a/drivers/clk/clk-u300.c
+++ b/drivers/clk/clk-u300.c
@@ -1168,6 +1168,7 @@ static const struct of_device_id u300_clk_match[] __initconst = {
.compatible = "stericsson,u300-syscon-mclk",
.data = of_u300_syscon_mclk_init,
},
+ {}
};
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 7cf2c093cc54..8b73edef151d 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -106,12 +106,11 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
if (!c)
return;
- seq_printf(s, "%*s%-*s %-11d %-12d %-10lu %-11lu",
+ seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu\n",
level * 3 + 1, "",
30 - level * 3, c->name,
c->enable_count, c->prepare_count, clk_get_rate(c),
clk_get_accuracy(c));
- seq_printf(s, "\n");
}
static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
@@ -132,8 +131,8 @@ static int clk_summary_show(struct seq_file *s, void *data)
{
struct clk *c;
- seq_printf(s, " clock enable_cnt prepare_cnt rate accuracy\n");
- seq_printf(s, "---------------------------------------------------------------------------------\n");
+ seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy\n");
+ seq_puts(s, "--------------------------------------------------------------------------------\n");
clk_prepare_lock();
@@ -822,6 +821,9 @@ void __clk_unprepare(struct clk *clk)
*/
void clk_unprepare(struct clk *clk)
{
+ if (IS_ERR_OR_NULL(clk))
+ return;
+
clk_prepare_lock();
__clk_unprepare(clk);
clk_prepare_unlock();
@@ -883,9 +885,6 @@ static void __clk_disable(struct clk *clk)
if (!clk)
return;
- if (WARN_ON(IS_ERR(clk)))
- return;
-
if (WARN_ON(clk->enable_count == 0))
return;
@@ -914,6 +913,9 @@ void clk_disable(struct clk *clk)
{
unsigned long flags;
+ if (IS_ERR_OR_NULL(clk))
+ return;
+
flags = clk_enable_lock();
__clk_disable(clk);
clk_enable_unlock(flags);
@@ -1004,6 +1006,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
else
return clk->rate;
}
+EXPORT_SYMBOL_GPL(__clk_round_rate);
/**
* clk_round_rate - round the given rate for a clk
@@ -1115,6 +1118,13 @@ long clk_get_accuracy(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_get_accuracy);
+static unsigned long clk_recalc(struct clk *clk, unsigned long parent_rate)
+{
+ if (clk->ops->recalc_rate)
+ return clk->ops->recalc_rate(clk->hw, parent_rate);
+ return parent_rate;
+}
+
/**
* __clk_recalc_rates
* @clk: first clk in the subtree
@@ -1140,10 +1150,7 @@ static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
if (clk->parent)
parent_rate = clk->parent->rate;
- if (clk->ops->recalc_rate)
- clk->rate = clk->ops->recalc_rate(clk->hw, parent_rate);
- else
- clk->rate = parent_rate;
+ clk->rate = clk_recalc(clk, parent_rate);
/*
* ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE
@@ -1334,10 +1341,7 @@ static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
unsigned long new_rate;
int ret = NOTIFY_DONE;
- if (clk->ops->recalc_rate)
- new_rate = clk->ops->recalc_rate(clk->hw, parent_rate);
- else
- new_rate = parent_rate;
+ new_rate = clk_recalc(clk, parent_rate);
/* abort rate change if a driver returns NOTIFY_BAD or NOTIFY_STOP */
if (clk->notifier_count)
@@ -1373,10 +1377,7 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
new_parent->new_child = clk;
hlist_for_each_entry(child, &clk->children, child_node) {
- if (child->ops->recalc_rate)
- child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
- else
- child->new_rate = new_rate;
+ child->new_rate = clk_recalc(child, new_rate);
clk_calc_subtree(child, child->new_rate, NULL, 0);
}
}
@@ -1524,10 +1525,7 @@ static void clk_change_rate(struct clk *clk)
if (!skip_set_rate && clk->ops->set_rate)
clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate);
- if (clk->ops->recalc_rate)
- clk->rate = clk->ops->recalc_rate(clk->hw, best_parent_rate);
- else
- clk->rate = best_parent_rate;
+ clk->rate = clk_recalc(clk, best_parent_rate);
if (clk->notifier_count && old_rate != clk->rate)
__clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
@@ -1716,9 +1714,6 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
if (!clk)
return 0;
- if (!clk->ops)
- return -EINVAL;
-
/* verify ops for for multi-parent clks */
if ((clk->num_parents > 1) && (!clk->ops->set_parent))
return -ENOSYS;
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index 795cc9f0dac0..c798138f023f 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -10,6 +10,7 @@
*/
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
+struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec);
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec);
void of_clk_lock(void);
void of_clk_unlock(void);
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index a360b2eca5cb..f890b901c6bc 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -27,6 +27,32 @@ static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex);
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
+
+/**
+ * of_clk_get_by_clkspec() - Lookup a clock form a clock provider
+ * @clkspec: pointer to a clock specifier data structure
+ *
+ * This function looks up a struct clk from the registered list of clock
+ * providers, an input is a clock specifier data structure as returned
+ * from the of_parse_phandle_with_args() function call.
+ */
+struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec)
+{
+ struct clk *clk;
+
+ if (!clkspec)
+ return ERR_PTR(-EINVAL);
+
+ of_clk_lock();
+ clk = __of_clk_get_from_provider(clkspec);
+
+ if (!IS_ERR(clk) && !__clk_get(clk))
+ clk = ERR_PTR(-ENOENT);
+
+ of_clk_unlock();
+ return clk;
+}
+
struct clk *of_clk_get(struct device_node *np, int index)
{
struct of_phandle_args clkspec;
@@ -41,13 +67,7 @@ struct clk *of_clk_get(struct device_node *np, int index)
if (rc)
return ERR_PTR(rc);
- of_clk_lock();
- clk = __of_clk_get_from_provider(&clkspec);
-
- if (!IS_ERR(clk) && !__clk_get(clk))
- clk = ERR_PTR(-ENOENT);
-
- of_clk_unlock();
+ clk = of_clk_get_by_clkspec(&clkspec);
of_node_put(clkspec.np);
return clk;
}
diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
index 40b33c6a8257..038c02f4d0e7 100644
--- a/drivers/clk/hisilicon/Makefile
+++ b/drivers/clk/hisilicon/Makefile
@@ -6,3 +6,4 @@ obj-y += clk.o clkgate-separated.o
obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
+obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
diff --git a/drivers/clk/hisilicon/clk-hix5hd2.c b/drivers/clk/hisilicon/clk-hix5hd2.c
new file mode 100644
index 000000000000..e5fcfb4e32ef
--- /dev/null
+++ b/drivers/clk/hisilicon/clk-hix5hd2.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014 Linaro Ltd.
+ * Copyright (c) 2014 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/of_address.h>
+#include <dt-bindings/clock/hix5hd2-clock.h>
+#include "clk.h"
+
+static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = {
+ { HIX5HD2_FIXED_1200M, "1200m", NULL, CLK_IS_ROOT, 1200000000, },
+ { HIX5HD2_FIXED_400M, "400m", NULL, CLK_IS_ROOT, 400000000, },
+ { HIX5HD2_FIXED_48M, "48m", NULL, CLK_IS_ROOT, 48000000, },
+ { HIX5HD2_FIXED_24M, "24m", NULL, CLK_IS_ROOT, 24000000, },
+ { HIX5HD2_FIXED_600M, "600m", NULL, CLK_IS_ROOT, 600000000, },
+ { HIX5HD2_FIXED_300M, "300m", NULL, CLK_IS_ROOT, 300000000, },
+ { HIX5HD2_FIXED_75M, "75m", NULL, CLK_IS_ROOT, 75000000, },
+ { HIX5HD2_FIXED_200M, "200m", NULL, CLK_IS_ROOT, 200000000, },
+ { HIX5HD2_FIXED_100M, "100m", NULL, CLK_IS_ROOT, 100000000, },
+ { HIX5HD2_FIXED_40M, "40m", NULL, CLK_IS_ROOT, 40000000, },
+ { HIX5HD2_FIXED_150M, "150m", NULL, CLK_IS_ROOT, 150000000, },
+ { HIX5HD2_FIXED_1728M, "1728m", NULL, CLK_IS_ROOT, 1728000000, },
+ { HIX5HD2_FIXED_28P8M, "28p8m", NULL, CLK_IS_ROOT, 28000000, },
+ { HIX5HD2_FIXED_432M, "432m", NULL, CLK_IS_ROOT, 432000000, },
+ { HIX5HD2_FIXED_345P6M, "345p6m", NULL, CLK_IS_ROOT, 345000000, },
+ { HIX5HD2_FIXED_288M, "288m", NULL, CLK_IS_ROOT, 288000000, },
+ { HIX5HD2_FIXED_60M, "60m", NULL, CLK_IS_ROOT, 60000000, },
+ { HIX5HD2_FIXED_750M, "750m", NULL, CLK_IS_ROOT, 750000000, },
+ { HIX5HD2_FIXED_500M, "500m", NULL, CLK_IS_ROOT, 500000000, },
+ { HIX5HD2_FIXED_54M, "54m", NULL, CLK_IS_ROOT, 54000000, },
+ { HIX5HD2_FIXED_27M, "27m", NULL, CLK_IS_ROOT, 27000000, },
+ { HIX5HD2_FIXED_1500M, "1500m", NULL, CLK_IS_ROOT, 1500000000, },
+ { HIX5HD2_FIXED_375M, "375m", NULL, CLK_IS_ROOT, 375000000, },
+ { HIX5HD2_FIXED_187M, "187m", NULL, CLK_IS_ROOT, 187000000, },
+ { HIX5HD2_FIXED_250M, "250m", NULL, CLK_IS_ROOT, 250000000, },
+ { HIX5HD2_FIXED_125M, "125m", NULL, CLK_IS_ROOT, 125000000, },
+ { HIX5HD2_FIXED_2P02M, "2m", NULL, CLK_IS_ROOT, 2000000, },
+ { HIX5HD2_FIXED_50M, "50m", NULL, CLK_IS_ROOT, 50000000, },
+ { HIX5HD2_FIXED_25M, "25m", NULL, CLK_IS_ROOT, 25000000, },
+ { HIX5HD2_FIXED_83M, "83m", NULL, CLK_IS_ROOT, 83333333, },
+};
+
+static const char *sfc_mux_p[] __initconst = {
+ "24m", "150m", "200m", "100m", "75m", };
+static u32 sfc_mux_table[] = {0, 4, 5, 6, 7};
+
+static const char *sdio1_mux_p[] __initconst = {
+ "75m", "100m", "50m", "15m", };
+static u32 sdio1_mux_table[] = {0, 1, 2, 3};
+
+static const char *fephy_mux_p[] __initconst = { "25m", "125m"};
+static u32 fephy_mux_table[] = {0, 1};
+
+
+static struct hisi_mux_clock hix5hd2_mux_clks[] __initdata = {
+ { HIX5HD2_SFC_MUX, "sfc_mux", sfc_mux_p, ARRAY_SIZE(sfc_mux_p),
+ CLK_SET_RATE_PARENT, 0x5c, 8, 3, 0, sfc_mux_table, },
+ { HIX5HD2_MMC_MUX, "mmc_mux", sdio1_mux_p, ARRAY_SIZE(sdio1_mux_p),
+ CLK_SET_RATE_PARENT, 0xa0, 8, 2, 0, sdio1_mux_table, },
+ { HIX5HD2_FEPHY_MUX, "fephy_mux",
+ fephy_mux_p, ARRAY_SIZE(fephy_mux_p),
+ CLK_SET_RATE_PARENT, 0x120, 8, 2, 0, fephy_mux_table, },
+};
+
+static struct hisi_gate_clock hix5hd2_gate_clks[] __initdata = {
+ /*sfc*/
+ { HIX5HD2_SFC_CLK, "clk_sfc", "sfc_mux",
+ CLK_SET_RATE_PARENT, 0x5c, 0, 0, },
+ { HIX5HD2_SFC_RST, "rst_sfc", "clk_sfc",
+ CLK_SET_RATE_PARENT, 0x5c, 4, CLK_GATE_SET_TO_DISABLE, },
+ /*sdio1*/
+ { HIX5HD2_MMC_BIU_CLK, "clk_mmc_biu", "200m",
+ CLK_SET_RATE_PARENT, 0xa0, 0, 0, },
+ { HIX5HD2_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux",
+ CLK_SET_RATE_PARENT, 0xa0, 1, 0, },
+ { HIX5HD2_MMC_CIU_RST, "rst_mmc_ciu", "clk_mmc_ciu",
+ CLK_SET_RATE_PARENT, 0xa0, 4, CLK_GATE_SET_TO_DISABLE, },
+};
+
+static void __init hix5hd2_clk_init(struct device_node *np)
+{
+ struct hisi_clock_data *clk_data;
+
+ clk_data = hisi_clk_init(np, HIX5HD2_NR_CLKS);
+ if (!clk_data)
+ return;
+
+ hisi_clk_register_fixed_rate(hix5hd2_fixed_rate_clks,
+ ARRAY_SIZE(hix5hd2_fixed_rate_clks),
+ clk_data);
+ hisi_clk_register_mux(hix5hd2_mux_clks, ARRAY_SIZE(hix5hd2_mux_clks),
+ clk_data);
+ hisi_clk_register_gate(hix5hd2_gate_clks,
+ ARRAY_SIZE(hix5hd2_gate_clks), clk_data);
+}
+
+CLK_OF_DECLARE(hix5hd2_clk, "hisilicon,hix5hd2-clock", hix5hd2_clk_init);
diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
index 276f672e7b1a..a078e84f7b05 100644
--- a/drivers/clk/hisilicon/clk.c
+++ b/drivers/clk/hisilicon/clk.c
@@ -127,11 +127,14 @@ void __init hisi_clk_register_mux(struct hisi_mux_clock *clks,
int i;
for (i = 0; i < nums; i++) {
- clk = clk_register_mux(NULL, clks[i].name, clks[i].parent_names,
- clks[i].num_parents, clks[i].flags,
- base + clks[i].offset, clks[i].shift,
- clks[i].width, clks[i].mux_flags,
- &hisi_clk_lock);
+ u32 mask = BIT(clks[i].width) - 1;
+
+ clk = clk_register_mux_table(NULL, clks[i].name,
+ clks[i].parent_names,
+ clks[i].num_parents, clks[i].flags,
+ base + clks[i].offset, clks[i].shift,
+ mask, clks[i].mux_flags,
+ clks[i].table, &hisi_clk_lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
@@ -174,6 +177,34 @@ void __init hisi_clk_register_divider(struct hisi_divider_clock *clks,
}
}
+void __init hisi_clk_register_gate(struct hisi_gate_clock *clks,
+ int nums, struct hisi_clock_data *data)
+{
+ struct clk *clk;
+ void __iomem *base = data->base;
+ int i;
+
+ for (i = 0; i < nums; i++) {
+ clk = clk_register_gate(NULL, clks[i].name,
+ clks[i].parent_name,
+ clks[i].flags,
+ base + clks[i].offset,
+ clks[i].bit_idx,
+ clks[i].gate_flags,
+ &hisi_clk_lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register clock %s\n",
+ __func__, clks[i].name);
+ continue;
+ }
+
+ if (clks[i].alias)
+ clk_register_clkdev(clk, clks[i].alias, NULL);
+
+ data->clk_data.clks[clks[i].id] = clk;
+ }
+}
+
void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
int nums, struct hisi_clock_data *data)
{
diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h
index 43fa5da88f02..31083ffc0650 100644
--- a/drivers/clk/hisilicon/clk.h
+++ b/drivers/clk/hisilicon/clk.h
@@ -62,6 +62,7 @@ struct hisi_mux_clock {
u8 shift;
u8 width;
u8 mux_flags;
+ u32 *table;
const char *alias;
};
@@ -103,6 +104,8 @@ void __init hisi_clk_register_mux(struct hisi_mux_clock *, int,
struct hisi_clock_data *);
void __init hisi_clk_register_divider(struct hisi_divider_clock *,
int, struct hisi_clock_data *);
+void __init hisi_clk_register_gate(struct hisi_gate_clock *,
+ int, struct hisi_clock_data *);
void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
int, struct hisi_clock_data *);
#endif /* __HISI_CLK_H */
diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig
index 693f7be129f1..3b34dba9178d 100644
--- a/drivers/clk/mvebu/Kconfig
+++ b/drivers/clk/mvebu/Kconfig
@@ -34,3 +34,7 @@ config DOVE_CLK
config KIRKWOOD_CLK
bool
select MVEBU_CLK_COMMON
+
+config ORION_CLK
+ bool
+ select MVEBU_CLK_COMMON
diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile
index 4c66162fb0b4..a9a56fc01901 100644
--- a/drivers/clk/mvebu/Makefile
+++ b/drivers/clk/mvebu/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o
obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o
obj-$(CONFIG_DOVE_CLK) += dove.o
obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o
+obj-$(CONFIG_ORION_CLK) += orion.o
diff --git a/drivers/clk/mvebu/orion.c b/drivers/clk/mvebu/orion.c
new file mode 100644
index 000000000000..fd129566c1ce
--- /dev/null
+++ b/drivers/clk/mvebu/orion.c
@@ -0,0 +1,210 @@
+/*
+ * Marvell Orion SoC clocks
+ *
+ * Copyright (C) 2014 Thomas Petazzoni
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.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-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include "common.h"
+
+static const struct coreclk_ratio orion_coreclk_ratios[] __initconst = {
+ { .id = 0, .name = "ddrclk", }
+};
+
+/*
+ * Orion 5182
+ */
+
+#define SAR_MV88F5182_TCLK_FREQ 8
+#define SAR_MV88F5182_TCLK_FREQ_MASK 0x3
+
+static u32 __init mv88f5182_get_tclk_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F5182_TCLK_FREQ) &
+ SAR_MV88F5182_TCLK_FREQ_MASK;
+ if (opt == 1)
+ return 150000000;
+ else if (opt == 2)
+ return 166666667;
+ else
+ return 0;
+}
+
+#define SAR_MV88F5182_CPU_FREQ 4
+#define SAR_MV88F5182_CPU_FREQ_MASK 0xf
+
+static u32 __init mv88f5182_get_cpu_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) &
+ SAR_MV88F5182_CPU_FREQ_MASK;
+ if (opt == 0)
+ return 333333333;
+ else if (opt == 1 || opt == 2)
+ return 400000000;
+ else if (opt == 3)
+ return 500000000;
+ else
+ return 0;
+}
+
+static void __init mv88f5182_get_clk_ratio(void __iomem *sar, int id,
+ int *mult, int *div)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) &
+ SAR_MV88F5182_CPU_FREQ_MASK;
+ if (opt == 0 || opt == 1) {
+ *mult = 1;
+ *div = 2;
+ } else if (opt == 2 || opt == 3) {
+ *mult = 1;
+ *div = 3;
+ } else {
+ *mult = 0;
+ *div = 1;
+ }
+}
+
+static const struct coreclk_soc_desc mv88f5182_coreclks = {
+ .get_tclk_freq = mv88f5182_get_tclk_freq,
+ .get_cpu_freq = mv88f5182_get_cpu_freq,
+ .get_clk_ratio = mv88f5182_get_clk_ratio,
+ .ratios = orion_coreclk_ratios,
+ .num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
+};
+
+static void __init mv88f5182_clk_init(struct device_node *np)
+{
+ return mvebu_coreclk_setup(np, &mv88f5182_coreclks);
+}
+
+CLK_OF_DECLARE(mv88f5182_clk, "marvell,mv88f5182-core-clock", mv88f5182_clk_init);
+
+/*
+ * Orion 5281
+ */
+
+static u32 __init mv88f5281_get_tclk_freq(void __iomem *sar)
+{
+ /* On 5281, tclk is always 166 Mhz */
+ return 166666667;
+}
+
+#define SAR_MV88F5281_CPU_FREQ 4
+#define SAR_MV88F5281_CPU_FREQ_MASK 0xf
+
+static u32 __init mv88f5281_get_cpu_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) &
+ SAR_MV88F5281_CPU_FREQ_MASK;
+ if (opt == 1 || opt == 2)
+ return 400000000;
+ else if (opt == 3)
+ return 500000000;
+ else
+ return 0;
+}
+
+static void __init mv88f5281_get_clk_ratio(void __iomem *sar, int id,
+ int *mult, int *div)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) &
+ SAR_MV88F5281_CPU_FREQ_MASK;
+ if (opt == 1) {
+ *mult = 1;
+ *div = 2;
+ } else if (opt == 2 || opt == 3) {
+ *mult = 1;
+ *div = 3;
+ } else {
+ *mult = 0;
+ *div = 1;
+ }
+}
+
+static const struct coreclk_soc_desc mv88f5281_coreclks = {
+ .get_tclk_freq = mv88f5281_get_tclk_freq,
+ .get_cpu_freq = mv88f5281_get_cpu_freq,
+ .get_clk_ratio = mv88f5281_get_clk_ratio,
+ .ratios = orion_coreclk_ratios,
+ .num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
+};
+
+static void __init mv88f5281_clk_init(struct device_node *np)
+{
+ return mvebu_coreclk_setup(np, &mv88f5281_coreclks);
+}
+
+CLK_OF_DECLARE(mv88f5281_clk, "marvell,mv88f5281-core-clock", mv88f5281_clk_init);
+
+/*
+ * Orion 6183
+ */
+
+#define SAR_MV88F6183_TCLK_FREQ 9
+#define SAR_MV88F6183_TCLK_FREQ_MASK 0x1
+
+static u32 __init mv88f6183_get_tclk_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F6183_TCLK_FREQ) &
+ SAR_MV88F6183_TCLK_FREQ_MASK;
+ if (opt == 0)
+ return 133333333;
+ else if (opt == 1)
+ return 166666667;
+ else
+ return 0;
+}
+
+#define SAR_MV88F6183_CPU_FREQ 1
+#define SAR_MV88F6183_CPU_FREQ_MASK 0x3f
+
+static u32 __init mv88f6183_get_cpu_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) &
+ SAR_MV88F6183_CPU_FREQ_MASK;
+ if (opt == 9)
+ return 333333333;
+ else if (opt == 17)
+ return 400000000;
+ else
+ return 0;
+}
+
+static void __init mv88f6183_get_clk_ratio(void __iomem *sar, int id,
+ int *mult, int *div)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) &
+ SAR_MV88F6183_CPU_FREQ_MASK;
+ if (opt == 9 || opt == 17) {
+ *mult = 1;
+ *div = 2;
+ } else {
+ *mult = 0;
+ *div = 1;
+ }
+}
+
+static const struct coreclk_soc_desc mv88f6183_coreclks = {
+ .get_tclk_freq = mv88f6183_get_tclk_freq,
+ .get_cpu_freq = mv88f6183_get_cpu_freq,
+ .get_clk_ratio = mv88f6183_get_clk_ratio,
+ .ratios = orion_coreclk_ratios,
+ .num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
+};
+
+
+static void __init mv88f6183_clk_init(struct device_node *np)
+{
+ return mvebu_coreclk_setup(np, &mv88f6183_coreclks);
+}
+
+CLK_OF_DECLARE(mv88f6183_clk, "marvell,mv88f6183-core-clock", mv88f6183_clk_init);
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 995bcfa021a4..7f696b7d4422 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -13,10 +13,10 @@ config MSM_GCC_8660
i2c, USB, SD/eMMC, etc.
config MSM_GCC_8960
- tristate "MSM8960 Global Clock Controller"
+ tristate "APQ8064/MSM8960 Global Clock Controller"
depends on COMMON_CLK_QCOM
help
- Support for the global clock controller on msm8960 devices.
+ Support for the global clock controller on apq8064/msm8960 devices.
Say Y if you want to use peripheral devices such as UART, SPI,
i2c, USB, SD/eMMC, SATA, PCIe, etc.
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index f60db2ef1aee..689e05bf4f95 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o
+clk-qcom-y += common.o
clk-qcom-y += clk-regmap.o
clk-qcom-y += clk-pll.o
clk-qcom-y += clk-rcg.o
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index 1d6b6dece328..b9ec11dfd1b4 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -155,5 +155,8 @@ struct clk_rcg2 {
#define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)
extern const struct clk_ops clk_rcg2_ops;
+extern const struct clk_ops clk_edp_pixel_ops;
+extern const struct clk_ops clk_byte_ops;
+extern const struct clk_ops clk_pixel_ops;
#endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 00f878a04d3f..cd185d5cc67a 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -19,6 +19,7 @@
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/regmap.h>
+#include <linux/math64.h>
#include <asm/div64.h>
@@ -55,7 +56,7 @@ static int clk_rcg2_is_enabled(struct clk_hw *hw)
if (ret)
return ret;
- return (cmd & CMD_ROOT_OFF) != 0;
+ return (cmd & CMD_ROOT_OFF) == 0;
}
static u8 clk_rcg2_get_parent(struct clk_hw *hw)
@@ -181,7 +182,8 @@ struct freq_tbl *find_freq(const struct freq_tbl *f, unsigned long rate)
if (rate <= f->freq)
return f;
- return NULL;
+ /* Default to our fastest rate */
+ return f - 1;
}
static long _freq_tbl_determine_rate(struct clk_hw *hw,
@@ -224,31 +226,25 @@ static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate,
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
}
-static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
+static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
{
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- const struct freq_tbl *f;
u32 cfg, mask;
int ret;
- f = find_freq(rcg->freq_tbl, rate);
- if (!f)
- return -EINVAL;
-
if (rcg->mnd_width && f->n) {
mask = BIT(rcg->mnd_width) - 1;
- ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG,
- mask, f->m);
+ ret = regmap_update_bits(rcg->clkr.regmap,
+ rcg->cmd_rcgr + M_REG, mask, f->m);
if (ret)
return ret;
- ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG,
- mask, ~(f->n - f->m));
+ ret = regmap_update_bits(rcg->clkr.regmap,
+ rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m));
if (ret)
return ret;
- ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + D_REG,
- mask, ~f->n);
+ ret = regmap_update_bits(rcg->clkr.regmap,
+ rcg->cmd_rcgr + D_REG, mask, ~f->n);
if (ret)
return ret;
}
@@ -259,14 +255,26 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
cfg |= rcg->parent_map[f->src] << CFG_SRC_SEL_SHIFT;
if (rcg->mnd_width && f->n)
cfg |= CFG_MODE_DUAL_EDGE;
- ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, mask,
- cfg);
+ ret = regmap_update_bits(rcg->clkr.regmap,
+ rcg->cmd_rcgr + CFG_REG, mask, cfg);
if (ret)
return ret;
return update_config(rcg);
}
+static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ const struct freq_tbl *f;
+
+ f = find_freq(rcg->freq_tbl, rate);
+ if (!f)
+ return -EINVAL;
+
+ return clk_rcg2_configure(rcg, f);
+}
+
static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
@@ -289,3 +297,265 @@ const struct clk_ops clk_rcg2_ops = {
.set_rate_and_parent = clk_rcg2_set_rate_and_parent,
};
EXPORT_SYMBOL_GPL(clk_rcg2_ops);
+
+struct frac_entry {
+ int num;
+ int den;
+};
+
+static const struct frac_entry frac_table_675m[] = { /* link rate of 270M */
+ { 52, 295 }, /* 119 M */
+ { 11, 57 }, /* 130.25 M */
+ { 63, 307 }, /* 138.50 M */
+ { 11, 50 }, /* 148.50 M */
+ { 47, 206 }, /* 154 M */
+ { 31, 100 }, /* 205.25 M */
+ { 107, 269 }, /* 268.50 M */
+ { },
+};
+
+static struct frac_entry frac_table_810m[] = { /* Link rate of 162M */
+ { 31, 211 }, /* 119 M */
+ { 32, 199 }, /* 130.25 M */
+ { 63, 307 }, /* 138.50 M */
+ { 11, 60 }, /* 148.50 M */
+ { 50, 263 }, /* 154 M */
+ { 31, 120 }, /* 205.25 M */
+ { 119, 359 }, /* 268.50 M */
+ { },
+};
+
+static int clk_edp_pixel_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ struct freq_tbl f = *rcg->freq_tbl;
+ const struct frac_entry *frac;
+ int delta = 100000;
+ s64 src_rate = parent_rate;
+ s64 request;
+ u32 mask = BIT(rcg->hid_width) - 1;
+ u32 hid_div;
+
+ if (src_rate == 810000000)
+ frac = frac_table_810m;
+ else
+ frac = frac_table_675m;
+
+ for (; frac->num; frac++) {
+ request = rate;
+ request *= frac->den;
+ request = div_s64(request, frac->num);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
+ &hid_div);
+ f.pre_div = hid_div;
+ f.pre_div >>= CFG_SRC_DIV_SHIFT;
+ f.pre_div &= mask;
+ f.m = frac->num;
+ f.n = frac->den;
+
+ return clk_rcg2_configure(rcg, &f);
+ }
+
+ return -EINVAL;
+}
+
+static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw,
+ unsigned long rate, unsigned long parent_rate, u8 index)
+{
+ /* Parent index is set statically in frequency table */
+ return clk_edp_pixel_set_rate(hw, rate, parent_rate);
+}
+
+static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *p_rate, struct clk **p)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ const struct freq_tbl *f = rcg->freq_tbl;
+ const struct frac_entry *frac;
+ int delta = 100000;
+ s64 src_rate = *p_rate;
+ s64 request;
+ u32 mask = BIT(rcg->hid_width) - 1;
+ u32 hid_div;
+
+ /* Force the correct parent */
+ *p = clk_get_parent_by_index(hw->clk, f->src);
+
+ if (src_rate == 810000000)
+ frac = frac_table_810m;
+ else
+ frac = frac_table_675m;
+
+ for (; frac->num; frac++) {
+ request = rate;
+ request *= frac->den;
+ request = div_s64(request, frac->num);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
+ &hid_div);
+ hid_div >>= CFG_SRC_DIV_SHIFT;
+ hid_div &= mask;
+
+ return calc_rate(src_rate, frac->num, frac->den, !!frac->den,
+ hid_div);
+ }
+
+ return -EINVAL;
+}
+
+const struct clk_ops clk_edp_pixel_ops = {
+ .is_enabled = clk_rcg2_is_enabled,
+ .get_parent = clk_rcg2_get_parent,
+ .set_parent = clk_rcg2_set_parent,
+ .recalc_rate = clk_rcg2_recalc_rate,
+ .set_rate = clk_edp_pixel_set_rate,
+ .set_rate_and_parent = clk_edp_pixel_set_rate_and_parent,
+ .determine_rate = clk_edp_pixel_determine_rate,
+};
+EXPORT_SYMBOL_GPL(clk_edp_pixel_ops);
+
+static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *p_rate, struct clk **p)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ const struct freq_tbl *f = rcg->freq_tbl;
+ unsigned long parent_rate, div;
+ u32 mask = BIT(rcg->hid_width) - 1;
+
+ if (rate == 0)
+ return -EINVAL;
+
+ *p = clk_get_parent_by_index(hw->clk, f->src);
+ *p_rate = parent_rate = __clk_round_rate(*p, rate);
+
+ div = DIV_ROUND_UP((2 * parent_rate), rate) - 1;
+ div = min_t(u32, div, mask);
+
+ return calc_rate(parent_rate, 0, 0, 0, div);
+}
+
+static int clk_byte_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ struct freq_tbl f = *rcg->freq_tbl;
+ unsigned long div;
+ u32 mask = BIT(rcg->hid_width) - 1;
+
+ div = DIV_ROUND_UP((2 * parent_rate), rate) - 1;
+ div = min_t(u32, div, mask);
+
+ f.pre_div = div;
+
+ return clk_rcg2_configure(rcg, &f);
+}
+
+static int clk_byte_set_rate_and_parent(struct clk_hw *hw,
+ unsigned long rate, unsigned long parent_rate, u8 index)
+{
+ /* Parent index is set statically in frequency table */
+ return clk_byte_set_rate(hw, rate, parent_rate);
+}
+
+const struct clk_ops clk_byte_ops = {
+ .is_enabled = clk_rcg2_is_enabled,
+ .get_parent = clk_rcg2_get_parent,
+ .set_parent = clk_rcg2_set_parent,
+ .recalc_rate = clk_rcg2_recalc_rate,
+ .set_rate = clk_byte_set_rate,
+ .set_rate_and_parent = clk_byte_set_rate_and_parent,
+ .determine_rate = clk_byte_determine_rate,
+};
+EXPORT_SYMBOL_GPL(clk_byte_ops);
+
+static const struct frac_entry frac_table_pixel[] = {
+ { 3, 8 },
+ { 2, 9 },
+ { 4, 9 },
+ { 1, 1 },
+ { }
+};
+
+static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *p_rate, struct clk **p)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ unsigned long request, src_rate;
+ int delta = 100000;
+ const struct freq_tbl *f = rcg->freq_tbl;
+ const struct frac_entry *frac = frac_table_pixel;
+ struct clk *parent = *p = clk_get_parent_by_index(hw->clk, f->src);
+
+ for (; frac->num; frac++) {
+ request = (rate * frac->den) / frac->num;
+
+ src_rate = __clk_round_rate(parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ *p_rate = src_rate;
+ return (src_rate * frac->num) / frac->den;
+ }
+
+ return -EINVAL;
+}
+
+static int clk_pixel_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ struct freq_tbl f = *rcg->freq_tbl;
+ const struct frac_entry *frac = frac_table_pixel;
+ unsigned long request, src_rate;
+ int delta = 100000;
+ u32 mask = BIT(rcg->hid_width) - 1;
+ u32 hid_div;
+ struct clk *parent = clk_get_parent_by_index(hw->clk, f.src);
+
+ for (; frac->num; frac++) {
+ request = (rate * frac->den) / frac->num;
+
+ src_rate = __clk_round_rate(parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
+ &hid_div);
+ f.pre_div = hid_div;
+ f.pre_div >>= CFG_SRC_DIV_SHIFT;
+ f.pre_div &= mask;
+ f.m = frac->num;
+ f.n = frac->den;
+
+ return clk_rcg2_configure(rcg, &f);
+ }
+ return -EINVAL;
+}
+
+static int clk_pixel_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate, u8 index)
+{
+ /* Parent index is set statically in frequency table */
+ return clk_pixel_set_rate(hw, rate, parent_rate);
+}
+
+const struct clk_ops clk_pixel_ops = {
+ .is_enabled = clk_rcg2_is_enabled,
+ .get_parent = clk_rcg2_get_parent,
+ .set_parent = clk_rcg2_set_parent,
+ .recalc_rate = clk_rcg2_recalc_rate,
+ .set_rate = clk_pixel_set_rate,
+ .set_rate_and_parent = clk_pixel_set_rate_and_parent,
+ .determine_rate = clk_pixel_determine_rate,
+};
+EXPORT_SYMBOL_GPL(clk_pixel_ops);
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
new file mode 100644
index 000000000000..9b5a1cfc6b91
--- /dev/null
+++ b/drivers/clk/qcom/common.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <linux/export.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/reset-controller.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "reset.h"
+
+struct qcom_cc {
+ struct qcom_reset_controller reset;
+ struct clk_onecell_data data;
+ struct clk *clks[];
+};
+
+int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc)
+{
+ void __iomem *base;
+ struct resource *res;
+ int i, ret;
+ struct device *dev = &pdev->dev;
+ struct clk *clk;
+ struct clk_onecell_data *data;
+ struct clk **clks;
+ struct regmap *regmap;
+ struct qcom_reset_controller *reset;
+ struct qcom_cc *cc;
+ size_t num_clks = desc->num_clks;
+ struct clk_regmap **rclks = desc->clks;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = devm_regmap_init_mmio(dev, base, desc->config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
+ GFP_KERNEL);
+ if (!cc)
+ return -ENOMEM;
+
+ clks = cc->clks;
+ data = &cc->data;
+ data->clks = clks;
+ data->clk_num = num_clks;
+
+ for (i = 0; i < num_clks; i++) {
+ if (!rclks[i]) {
+ clks[i] = ERR_PTR(-ENOENT);
+ continue;
+ }
+ clk = devm_clk_register_regmap(dev, rclks[i]);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ clks[i] = clk;
+ }
+
+ ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
+ if (ret)
+ return ret;
+
+ reset = &cc->reset;
+ reset->rcdev.of_node = dev->of_node;
+ reset->rcdev.ops = &qcom_reset_ops;
+ reset->rcdev.owner = dev->driver->owner;
+ reset->rcdev.nr_resets = desc->num_resets;
+ reset->regmap = regmap;
+ reset->reset_map = desc->resets;
+ platform_set_drvdata(pdev, &reset->rcdev);
+
+ ret = reset_controller_register(&reset->rcdev);
+ if (ret)
+ of_clk_del_provider(dev->of_node);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_cc_probe);
+
+void qcom_cc_remove(struct platform_device *pdev)
+{
+ of_clk_del_provider(pdev->dev.of_node);
+ reset_controller_unregister(platform_get_drvdata(pdev));
+}
+EXPORT_SYMBOL_GPL(qcom_cc_remove);
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
new file mode 100644
index 000000000000..2c3cfc860348
--- /dev/null
+++ b/drivers/clk/qcom/common.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#ifndef __QCOM_CLK_COMMON_H__
+#define __QCOM_CLK_COMMON_H__
+
+struct platform_device;
+struct regmap_config;
+struct clk_regmap;
+struct qcom_reset_map;
+
+struct qcom_cc_desc {
+ const struct regmap_config *config;
+ struct clk_regmap **clks;
+ size_t num_clks;
+ const struct qcom_reset_map *resets;
+ size_t num_resets;
+};
+
+extern int qcom_cc_probe(struct platform_device *pdev,
+ const struct qcom_cc_desc *desc);
+
+extern void qcom_cc_remove(struct platform_device *pdev);
+
+#endif
diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c
index bc0b7f1fcfbe..0c4b727ae429 100644
--- a/drivers/clk/qcom/gcc-msm8660.c
+++ b/drivers/clk/qcom/gcc-msm8660.c
@@ -25,6 +25,7 @@
#include <dt-bindings/clock/qcom,gcc-msm8660.h>
#include <dt-bindings/reset/qcom,gcc-msm8660.h>
+#include "common.h"
#include "clk-regmap.h"
#include "clk-pll.h"
#include "clk-rcg.h"
@@ -2701,51 +2702,24 @@ static const struct regmap_config gcc_msm8660_regmap_config = {
.fast_io = true,
};
+static const struct qcom_cc_desc gcc_msm8660_desc = {
+ .config = &gcc_msm8660_regmap_config,
+ .clks = gcc_msm8660_clks,
+ .num_clks = ARRAY_SIZE(gcc_msm8660_clks),
+ .resets = gcc_msm8660_resets,
+ .num_resets = ARRAY_SIZE(gcc_msm8660_resets),
+};
+
static const struct of_device_id gcc_msm8660_match_table[] = {
{ .compatible = "qcom,gcc-msm8660" },
{ }
};
MODULE_DEVICE_TABLE(of, gcc_msm8660_match_table);
-struct qcom_cc {
- struct qcom_reset_controller reset;
- struct clk_onecell_data data;
- struct clk *clks[];
-};
-
static int gcc_msm8660_probe(struct platform_device *pdev)
{
- void __iomem *base;
- struct resource *res;
- int i, ret;
- struct device *dev = &pdev->dev;
struct clk *clk;
- struct clk_onecell_data *data;
- struct clk **clks;
- struct regmap *regmap;
- size_t num_clks;
- struct qcom_reset_controller *reset;
- struct qcom_cc *cc;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8660_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- num_clks = ARRAY_SIZE(gcc_msm8660_clks);
- cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
- GFP_KERNEL);
- if (!cc)
- return -ENOMEM;
-
- clks = cc->clks;
- data = &cc->data;
- data->clks = clks;
- data->clk_num = num_clks;
+ struct device *dev = &pdev->dev;
/* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000);
@@ -2756,39 +2730,12 @@ static int gcc_msm8660_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
- for (i = 0; i < num_clks; i++) {
- if (!gcc_msm8660_clks[i])
- continue;
- clk = devm_clk_register_regmap(dev, gcc_msm8660_clks[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- clks[i] = clk;
- }
-
- ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
- if (ret)
- return ret;
-
- reset = &cc->reset;
- reset->rcdev.of_node = dev->of_node;
- reset->rcdev.ops = &qcom_reset_ops,
- reset->rcdev.owner = THIS_MODULE,
- reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8660_resets),
- reset->regmap = regmap;
- reset->reset_map = gcc_msm8660_resets,
- platform_set_drvdata(pdev, &reset->rcdev);
-
- ret = reset_controller_register(&reset->rcdev);
- if (ret)
- of_clk_del_provider(dev->of_node);
-
- return ret;
+ return qcom_cc_probe(pdev, &gcc_msm8660_desc);
}
static int gcc_msm8660_remove(struct platform_device *pdev)
{
- of_clk_del_provider(pdev->dev.of_node);
- reset_controller_unregister(platform_get_drvdata(pdev));
+ qcom_cc_remove(pdev);
return 0;
}
diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c
index fd446ab2fd98..f4ffd91901f8 100644
--- a/drivers/clk/qcom/gcc-msm8960.c
+++ b/drivers/clk/qcom/gcc-msm8960.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -25,6 +25,7 @@
#include <dt-bindings/clock/qcom,gcc-msm8960.h>
#include <dt-bindings/reset/qcom,gcc-msm8960.h>
+#include "common.h"
#include "clk-regmap.h"
#include "clk-pll.h"
#include "clk-rcg.h"
@@ -2809,7 +2810,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = {
[PPSS_PROC_RESET] = { 0x2594, 1 },
[PPSS_RESET] = { 0x2594},
[DMA_BAM_RESET] = { 0x25c0, 7 },
- [SIC_TIC_RESET] = { 0x2600, 7 },
+ [SPS_TIC_H_RESET] = { 0x2600, 7 },
[SLIMBUS_H_RESET] = { 0x2620, 7 },
[SFAB_CFPB_M_RESET] = { 0x2680, 7 },
[SFAB_CFPB_S_RESET] = { 0x26c0, 7 },
@@ -2822,7 +2823,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = {
[SFAB_SFPB_M_RESET] = { 0x2780, 7 },
[SFAB_SFPB_S_RESET] = { 0x27a0, 7 },
[RPM_PROC_RESET] = { 0x27c0, 7 },
- [PMIC_SSBI2_RESET] = { 0x270c, 12 },
+ [PMIC_SSBI2_RESET] = { 0x280c, 12 },
[SDC1_RESET] = { 0x2830 },
[SDC2_RESET] = { 0x2850 },
[SDC3_RESET] = { 0x2870 },
@@ -2867,6 +2868,16 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = {
[RIVA_RESET] = { 0x35e0 },
};
+static struct clk_regmap *gcc_apq8064_clks[] = {
+ [PLL8] = &pll8.clkr,
+ [PLL8_VOTE] = &pll8_vote,
+ [GSBI7_UART_SRC] = &gsbi7_uart_src.clkr,
+ [GSBI7_UART_CLK] = &gsbi7_uart_clk.clkr,
+ [GSBI7_QUP_SRC] = &gsbi7_qup_src.clkr,
+ [GSBI7_QUP_CLK] = &gsbi7_qup_clk.clkr,
+ [GSBI7_H_CLK] = &gsbi7_h_clk.clkr,
+};
+
static const struct regmap_config gcc_msm8960_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -2875,51 +2886,38 @@ static const struct regmap_config gcc_msm8960_regmap_config = {
.fast_io = true,
};
+static const struct qcom_cc_desc gcc_msm8960_desc = {
+ .config = &gcc_msm8960_regmap_config,
+ .clks = gcc_msm8960_clks,
+ .num_clks = ARRAY_SIZE(gcc_msm8960_clks),
+ .resets = gcc_msm8960_resets,
+ .num_resets = ARRAY_SIZE(gcc_msm8960_resets),
+};
+
+static const struct qcom_cc_desc gcc_apq8064_desc = {
+ .config = &gcc_msm8960_regmap_config,
+ .clks = gcc_apq8064_clks,
+ .num_clks = ARRAY_SIZE(gcc_apq8064_clks),
+ .resets = gcc_msm8960_resets,
+ .num_resets = ARRAY_SIZE(gcc_msm8960_resets),
+};
+
static const struct of_device_id gcc_msm8960_match_table[] = {
- { .compatible = "qcom,gcc-msm8960" },
+ { .compatible = "qcom,gcc-msm8960", .data = &gcc_msm8960_desc },
+ { .compatible = "qcom,gcc-apq8064", .data = &gcc_apq8064_desc },
{ }
};
MODULE_DEVICE_TABLE(of, gcc_msm8960_match_table);
-struct qcom_cc {
- struct qcom_reset_controller reset;
- struct clk_onecell_data data;
- struct clk *clks[];
-};
-
static int gcc_msm8960_probe(struct platform_device *pdev)
{
- void __iomem *base;
- struct resource *res;
- int i, ret;
- struct device *dev = &pdev->dev;
struct clk *clk;
- struct clk_onecell_data *data;
- struct clk **clks;
- struct regmap *regmap;
- size_t num_clks;
- struct qcom_reset_controller *reset;
- struct qcom_cc *cc;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8960_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- num_clks = ARRAY_SIZE(gcc_msm8960_clks);
- cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
- GFP_KERNEL);
- if (!cc)
- return -ENOMEM;
-
- clks = cc->clks;
- data = &cc->data;
- data->clks = clks;
- data->clk_num = num_clks;
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *match;
+
+ match = of_match_device(gcc_msm8960_match_table, &pdev->dev);
+ if (!match)
+ return -EINVAL;
/* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000);
@@ -2930,39 +2928,12 @@ static int gcc_msm8960_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
- for (i = 0; i < num_clks; i++) {
- if (!gcc_msm8960_clks[i])
- continue;
- clk = devm_clk_register_regmap(dev, gcc_msm8960_clks[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- clks[i] = clk;
- }
-
- ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
- if (ret)
- return ret;
-
- reset = &cc->reset;
- reset->rcdev.of_node = dev->of_node;
- reset->rcdev.ops = &qcom_reset_ops,
- reset->rcdev.owner = THIS_MODULE,
- reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8960_resets),
- reset->regmap = regmap;
- reset->reset_map = gcc_msm8960_resets,
- platform_set_drvdata(pdev, &reset->rcdev);
-
- ret = reset_controller_register(&reset->rcdev);
- if (ret)
- of_clk_del_provider(dev->of_node);
-
- return ret;
+ return qcom_cc_probe(pdev, match->data);
}
static int gcc_msm8960_remove(struct platform_device *pdev)
{
- of_clk_del_provider(pdev->dev.of_node);
- reset_controller_unregister(platform_get_drvdata(pdev));
+ qcom_cc_remove(pdev);
return 0;
}
diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c
index 51d457e2b959..7af7c18d2144 100644
--- a/drivers/clk/qcom/gcc-msm8974.c
+++ b/drivers/clk/qcom/gcc-msm8974.c
@@ -25,6 +25,7 @@
#include <dt-bindings/clock/qcom,gcc-msm8974.h>
#include <dt-bindings/reset/qcom,gcc-msm8974.h>
+#include "common.h"
#include "clk-regmap.h"
#include "clk-pll.h"
#include "clk-rcg.h"
@@ -34,6 +35,7 @@
#define P_XO 0
#define P_GPLL0 1
#define P_GPLL1 1
+#define P_GPLL4 2
static const u8 gcc_xo_gpll0_map[] = {
[P_XO] = 0,
@@ -45,6 +47,18 @@ static const char *gcc_xo_gpll0[] = {
"gpll0_vote",
};
+static const u8 gcc_xo_gpll0_gpll4_map[] = {
+ [P_XO] = 0,
+ [P_GPLL0] = 1,
+ [P_GPLL4] = 5,
+};
+
+static const char *gcc_xo_gpll0_gpll4[] = {
+ "xo",
+ "gpll0_vote",
+ "gpll4_vote",
+};
+
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
static struct clk_pll gpll0 = {
@@ -137,6 +151,33 @@ static struct clk_regmap gpll1_vote = {
},
};
+static struct clk_pll gpll4 = {
+ .l_reg = 0x1dc4,
+ .m_reg = 0x1dc8,
+ .n_reg = 0x1dcc,
+ .config_reg = 0x1dd4,
+ .mode_reg = 0x1dc0,
+ .status_reg = 0x1ddc,
+ .status_bit = 17,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll4",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+static struct clk_regmap gpll4_vote = {
+ .enable_reg = 0x1480,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll4_vote",
+ .parent_names = (const char *[]){ "gpll4" },
+ .num_parents = 1,
+ .ops = &clk_pll_vote_ops,
+ },
+};
+
static const struct freq_tbl ftbl_gcc_usb30_master_clk[] = {
F(125000000, P_GPLL0, 1, 5, 24),
{ }
@@ -811,18 +852,33 @@ static const struct freq_tbl ftbl_gcc_sdcc1_4_apps_clk[] = {
{ }
};
+static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_pro[] = {
+ F(144000, P_XO, 16, 3, 25),
+ F(400000, P_XO, 12, 1, 4),
+ F(20000000, P_GPLL0, 15, 1, 2),
+ F(25000000, P_GPLL0, 12, 1, 2),
+ F(50000000, P_GPLL0, 12, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ F(192000000, P_GPLL4, 4, 0, 0),
+ F(200000000, P_GPLL0, 3, 0, 0),
+ F(384000000, P_GPLL4, 2, 0, 0),
+ { }
+};
+
+static struct clk_init_data sdcc1_apps_clk_src_init = {
+ .name = "sdcc1_apps_clk_src",
+ .parent_names = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+};
+
static struct clk_rcg2 sdcc1_apps_clk_src = {
.cmd_rcgr = 0x04d0,
.mnd_width = 8,
.hid_width = 5,
.parent_map = gcc_xo_gpll0_map,
.freq_tbl = ftbl_gcc_sdcc1_4_apps_clk,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "sdcc1_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
- .ops = &clk_rcg2_ops,
- },
+ .clkr.hw.init = &sdcc1_apps_clk_src_init,
};
static struct clk_rcg2 sdcc2_apps_clk_src = {
@@ -1340,7 +1396,7 @@ static struct clk_branch gcc_blsp1_uart6_apps_clk = {
};
static struct clk_branch gcc_blsp2_ahb_clk = {
- .halt_reg = 0x05c4,
+ .halt_reg = 0x0944,
.halt_check = BRANCH_HALT_VOTED,
.clkr = {
.enable_reg = 0x1484,
@@ -1994,6 +2050,38 @@ static struct clk_branch gcc_sdcc1_apps_clk = {
},
};
+static struct clk_branch gcc_sdcc1_cdccal_ff_clk = {
+ .halt_reg = 0x04e8,
+ .clkr = {
+ .enable_reg = 0x04e8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_cdccal_ff_clk",
+ .parent_names = (const char *[]){
+ "xo"
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_cdccal_sleep_clk = {
+ .halt_reg = 0x04e4,
+ .clkr = {
+ .enable_reg = 0x04e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_cdccal_sleep_clk",
+ .parent_names = (const char *[]){
+ "sleep_clk_src"
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_sdcc2_ahb_clk = {
.halt_reg = 0x0508,
.clkr = {
@@ -2483,6 +2571,10 @@ static struct clk_regmap *gcc_msm8974_clocks[] = {
[GCC_USB_HSIC_IO_CAL_SLEEP_CLK] = &gcc_usb_hsic_io_cal_sleep_clk.clkr,
[GCC_USB_HSIC_SYSTEM_CLK] = &gcc_usb_hsic_system_clk.clkr,
[GCC_MMSS_GPLL0_CLK_SRC] = &gcc_mmss_gpll0_clk_src,
+ [GPLL4] = NULL,
+ [GPLL4_VOTE] = NULL,
+ [GCC_SDCC1_CDCCAL_SLEEP_CLK] = NULL,
+ [GCC_SDCC1_CDCCAL_FF_CLK] = NULL,
};
static const struct qcom_reset_map gcc_msm8974_resets[] = {
@@ -2574,51 +2666,51 @@ static const struct regmap_config gcc_msm8974_regmap_config = {
.fast_io = true,
};
+static const struct qcom_cc_desc gcc_msm8974_desc = {
+ .config = &gcc_msm8974_regmap_config,
+ .clks = gcc_msm8974_clocks,
+ .num_clks = ARRAY_SIZE(gcc_msm8974_clocks),
+ .resets = gcc_msm8974_resets,
+ .num_resets = ARRAY_SIZE(gcc_msm8974_resets),
+};
+
static const struct of_device_id gcc_msm8974_match_table[] = {
{ .compatible = "qcom,gcc-msm8974" },
+ { .compatible = "qcom,gcc-msm8974pro" , .data = (void *)1UL },
+ { .compatible = "qcom,gcc-msm8974pro-ac", .data = (void *)1UL },
{ }
};
MODULE_DEVICE_TABLE(of, gcc_msm8974_match_table);
-struct qcom_cc {
- struct qcom_reset_controller reset;
- struct clk_onecell_data data;
- struct clk *clks[];
-};
+static void msm8974_pro_clock_override(void)
+{
+ sdcc1_apps_clk_src_init.parent_names = gcc_xo_gpll0_gpll4;
+ sdcc1_apps_clk_src_init.num_parents = 3;
+ sdcc1_apps_clk_src.freq_tbl = ftbl_gcc_sdcc1_apps_clk_pro;
+ sdcc1_apps_clk_src.parent_map = gcc_xo_gpll0_gpll4_map;
+
+ gcc_msm8974_clocks[GPLL4] = &gpll4.clkr;
+ gcc_msm8974_clocks[GPLL4_VOTE] = &gpll4_vote;
+ gcc_msm8974_clocks[GCC_SDCC1_CDCCAL_SLEEP_CLK] =
+ &gcc_sdcc1_cdccal_sleep_clk.clkr;
+ gcc_msm8974_clocks[GCC_SDCC1_CDCCAL_FF_CLK] =
+ &gcc_sdcc1_cdccal_ff_clk.clkr;
+}
static int gcc_msm8974_probe(struct platform_device *pdev)
{
- void __iomem *base;
- struct resource *res;
- int i, ret;
- struct device *dev = &pdev->dev;
struct clk *clk;
- struct clk_onecell_data *data;
- struct clk **clks;
- struct regmap *regmap;
- size_t num_clks;
- struct qcom_reset_controller *reset;
- struct qcom_cc *cc;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8974_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- num_clks = ARRAY_SIZE(gcc_msm8974_clocks);
- cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
- GFP_KERNEL);
- if (!cc)
- return -ENOMEM;
-
- clks = cc->clks;
- data = &cc->data;
- data->clks = clks;
- data->clk_num = num_clks;
+ struct device *dev = &pdev->dev;
+ bool pro;
+ const struct of_device_id *id;
+
+ id = of_match_device(gcc_msm8974_match_table, dev);
+ if (!id)
+ return -ENODEV;
+ pro = !!(id->data);
+
+ if (pro)
+ msm8974_pro_clock_override();
/* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000);
@@ -2631,39 +2723,12 @@ static int gcc_msm8974_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
- for (i = 0; i < num_clks; i++) {
- if (!gcc_msm8974_clocks[i])
- continue;
- clk = devm_clk_register_regmap(dev, gcc_msm8974_clocks[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- clks[i] = clk;
- }
-
- ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
- if (ret)
- return ret;
-
- reset = &cc->reset;
- reset->rcdev.of_node = dev->of_node;
- reset->rcdev.ops = &qcom_reset_ops,
- reset->rcdev.owner = THIS_MODULE,
- reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8974_resets),
- reset->regmap = regmap;
- reset->reset_map = gcc_msm8974_resets,
- platform_set_drvdata(pdev, &reset->rcdev);
-
- ret = reset_controller_register(&reset->rcdev);
- if (ret)
- of_clk_del_provider(dev->of_node);
-
- return ret;
+ return qcom_cc_probe(pdev, &gcc_msm8974_desc);
}
static int gcc_msm8974_remove(struct platform_device *pdev)
{
- of_clk_del_provider(pdev->dev.of_node);
- reset_controller_unregister(platform_get_drvdata(pdev));
+ qcom_cc_remove(pdev);
return 0;
}
diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c
index f9b59c7e48e9..4c449b3170f6 100644
--- a/drivers/clk/qcom/mmcc-msm8960.c
+++ b/drivers/clk/qcom/mmcc-msm8960.c
@@ -26,6 +26,7 @@
#include <dt-bindings/clock/qcom,mmcc-msm8960.h>
#include <dt-bindings/reset/qcom,mmcc-msm8960.h>
+#include "common.h"
#include "clk-regmap.h"
#include "clk-pll.h"
#include "clk-rcg.h"
@@ -1208,7 +1209,7 @@ static struct clk_branch rot_clk = {
static u8 mmcc_pxo_hdmi_map[] = {
[P_PXO] = 0,
- [P_HDMI_PLL] = 2,
+ [P_HDMI_PLL] = 3,
};
static const char *mmcc_pxo_hdmi[] = {
@@ -2222,85 +2223,28 @@ static const struct regmap_config mmcc_msm8960_regmap_config = {
.fast_io = true,
};
+static const struct qcom_cc_desc mmcc_msm8960_desc = {
+ .config = &mmcc_msm8960_regmap_config,
+ .clks = mmcc_msm8960_clks,
+ .num_clks = ARRAY_SIZE(mmcc_msm8960_clks),
+ .resets = mmcc_msm8960_resets,
+ .num_resets = ARRAY_SIZE(mmcc_msm8960_resets),
+};
+
static const struct of_device_id mmcc_msm8960_match_table[] = {
{ .compatible = "qcom,mmcc-msm8960" },
{ }
};
MODULE_DEVICE_TABLE(of, mmcc_msm8960_match_table);
-struct qcom_cc {
- struct qcom_reset_controller reset;
- struct clk_onecell_data data;
- struct clk *clks[];
-};
-
static int mmcc_msm8960_probe(struct platform_device *pdev)
{
- void __iomem *base;
- struct resource *res;
- int i, ret;
- struct device *dev = &pdev->dev;
- struct clk *clk;
- struct clk_onecell_data *data;
- struct clk **clks;
- struct regmap *regmap;
- size_t num_clks;
- struct qcom_reset_controller *reset;
- struct qcom_cc *cc;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio(dev, base, &mmcc_msm8960_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- num_clks = ARRAY_SIZE(mmcc_msm8960_clks);
- cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
- GFP_KERNEL);
- if (!cc)
- return -ENOMEM;
-
- clks = cc->clks;
- data = &cc->data;
- data->clks = clks;
- data->clk_num = num_clks;
-
- for (i = 0; i < num_clks; i++) {
- if (!mmcc_msm8960_clks[i])
- continue;
- clk = devm_clk_register_regmap(dev, mmcc_msm8960_clks[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- clks[i] = clk;
- }
-
- ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
- if (ret)
- return ret;
-
- reset = &cc->reset;
- reset->rcdev.of_node = dev->of_node;
- reset->rcdev.ops = &qcom_reset_ops,
- reset->rcdev.owner = THIS_MODULE,
- reset->rcdev.nr_resets = ARRAY_SIZE(mmcc_msm8960_resets),
- reset->regmap = regmap;
- reset->reset_map = mmcc_msm8960_resets,
- platform_set_drvdata(pdev, &reset->rcdev);
-
- ret = reset_controller_register(&reset->rcdev);
- if (ret)
- of_clk_del_provider(dev->of_node);
-
- return ret;
+ return qcom_cc_probe(pdev, &mmcc_msm8960_desc);
}
static int mmcc_msm8960_remove(struct platform_device *pdev)
{
- of_clk_del_provider(pdev->dev.of_node);
- reset_controller_unregister(platform_get_drvdata(pdev));
+ qcom_cc_remove(pdev);
return 0;
}
diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c
index c95774514b81..c65b90515872 100644
--- a/drivers/clk/qcom/mmcc-msm8974.c
+++ b/drivers/clk/qcom/mmcc-msm8974.c
@@ -25,6 +25,7 @@
#include <dt-bindings/clock/qcom,mmcc-msm8974.h>
#include <dt-bindings/reset/qcom,mmcc-msm8974.h>
+#include "common.h"
#include "clk-regmap.h"
#include "clk-pll.h"
#include "clk-rcg.h"
@@ -40,9 +41,11 @@
#define P_EDPVCO 3
#define P_GPLL1 4
#define P_DSI0PLL 4
+#define P_DSI0PLL_BYTE 4
#define P_MMPLL2 4
#define P_MMPLL3 4
#define P_DSI1PLL 5
+#define P_DSI1PLL_BYTE 5
static const u8 mmcc_xo_mmpll0_mmpll1_gpll0_map[] = {
[P_XO] = 0,
@@ -160,6 +163,24 @@ static const char *mmcc_xo_dsi_hdmi_edp_gpll0[] = {
"dsi1pll",
};
+static const u8 mmcc_xo_dsibyte_hdmi_edp_gpll0_map[] = {
+ [P_XO] = 0,
+ [P_EDPLINK] = 4,
+ [P_HDMIPLL] = 3,
+ [P_GPLL0] = 5,
+ [P_DSI0PLL_BYTE] = 1,
+ [P_DSI1PLL_BYTE] = 2,
+};
+
+static const char *mmcc_xo_dsibyte_hdmi_edp_gpll0[] = {
+ "xo",
+ "edp_link_clk",
+ "hdmipll",
+ "gpll0_vote",
+ "dsi0pllbyte",
+ "dsi1pllbyte",
+};
+
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
static struct clk_pll mmpll0 = {
@@ -169,6 +190,7 @@ static struct clk_pll mmpll0 = {
.config_reg = 0x0014,
.mode_reg = 0x0000,
.status_reg = 0x001c,
+ .status_bit = 17,
.clkr.hw.init = &(struct clk_init_data){
.name = "mmpll0",
.parent_names = (const char *[]){ "xo" },
@@ -192,9 +214,10 @@ static struct clk_pll mmpll1 = {
.l_reg = 0x0044,
.m_reg = 0x0048,
.n_reg = 0x004c,
- .config_reg = 0x0054,
+ .config_reg = 0x0050,
.mode_reg = 0x0040,
.status_reg = 0x005c,
+ .status_bit = 17,
.clkr.hw.init = &(struct clk_init_data){
.name = "mmpll1",
.parent_names = (const char *[]){ "xo" },
@@ -218,7 +241,7 @@ static struct clk_pll mmpll2 = {
.l_reg = 0x4104,
.m_reg = 0x4108,
.n_reg = 0x410c,
- .config_reg = 0x4114,
+ .config_reg = 0x4110,
.mode_reg = 0x4100,
.status_reg = 0x411c,
.clkr.hw.init = &(struct clk_init_data){
@@ -233,9 +256,10 @@ static struct clk_pll mmpll3 = {
.l_reg = 0x0084,
.m_reg = 0x0088,
.n_reg = 0x008c,
- .config_reg = 0x0094,
+ .config_reg = 0x0090,
.mode_reg = 0x0080,
.status_reg = 0x009c,
+ .status_bit = 17,
.clkr.hw.init = &(struct clk_init_data){
.name = "mmpll3",
.parent_names = (const char *[]){ "xo" },
@@ -496,15 +520,8 @@ static struct clk_rcg2 jpeg2_clk_src = {
},
};
-static struct freq_tbl ftbl_mdss_pclk0_clk[] = {
- F(125000000, P_DSI0PLL, 2, 0, 0),
- F(250000000, P_DSI0PLL, 1, 0, 0),
- { }
-};
-
-static struct freq_tbl ftbl_mdss_pclk1_clk[] = {
- F(125000000, P_DSI1PLL, 2, 0, 0),
- F(250000000, P_DSI1PLL, 1, 0, 0),
+static struct freq_tbl pixel_freq_tbl[] = {
+ { .src = P_DSI0PLL },
{ }
};
@@ -513,12 +530,13 @@ static struct clk_rcg2 pclk0_clk_src = {
.mnd_width = 8,
.hid_width = 5,
.parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map,
- .freq_tbl = ftbl_mdss_pclk0_clk,
+ .freq_tbl = pixel_freq_tbl,
.clkr.hw.init = &(struct clk_init_data){
.name = "pclk0_clk_src",
.parent_names = mmcc_xo_dsi_hdmi_edp_gpll0,
.num_parents = 6,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_pixel_ops,
+ .flags = CLK_SET_RATE_PARENT,
},
};
@@ -527,12 +545,13 @@ static struct clk_rcg2 pclk1_clk_src = {
.mnd_width = 8,
.hid_width = 5,
.parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map,
- .freq_tbl = ftbl_mdss_pclk1_clk,
+ .freq_tbl = pixel_freq_tbl,
.clkr.hw.init = &(struct clk_init_data){
.name = "pclk1_clk_src",
.parent_names = mmcc_xo_dsi_hdmi_edp_gpll0,
.num_parents = 6,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_pixel_ops,
+ .flags = CLK_SET_RATE_PARENT,
},
};
@@ -750,41 +769,36 @@ static struct clk_rcg2 cpp_clk_src = {
},
};
-static struct freq_tbl ftbl_mdss_byte0_clk[] = {
- F(93750000, P_DSI0PLL, 8, 0, 0),
- F(187500000, P_DSI0PLL, 4, 0, 0),
- { }
-};
-
-static struct freq_tbl ftbl_mdss_byte1_clk[] = {
- F(93750000, P_DSI1PLL, 8, 0, 0),
- F(187500000, P_DSI1PLL, 4, 0, 0),
+static struct freq_tbl byte_freq_tbl[] = {
+ { .src = P_DSI0PLL_BYTE },
{ }
};
static struct clk_rcg2 byte0_clk_src = {
.cmd_rcgr = 0x2120,
.hid_width = 5,
- .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map,
- .freq_tbl = ftbl_mdss_byte0_clk,
+ .parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map,
+ .freq_tbl = byte_freq_tbl,
.clkr.hw.init = &(struct clk_init_data){
.name = "byte0_clk_src",
- .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0,
+ .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0,
.num_parents = 6,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_byte_ops,
+ .flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_rcg2 byte1_clk_src = {
.cmd_rcgr = 0x2140,
.hid_width = 5,
- .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map,
- .freq_tbl = ftbl_mdss_byte1_clk,
+ .parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map,
+ .freq_tbl = byte_freq_tbl,
.clkr.hw.init = &(struct clk_init_data){
.name = "byte1_clk_src",
- .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0,
+ .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0,
.num_parents = 6,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_byte_ops,
+ .flags = CLK_SET_RATE_PARENT,
},
};
@@ -822,12 +836,12 @@ static struct clk_rcg2 edplink_clk_src = {
.parent_names = mmcc_xo_dsi_hdmi_edp_gpll0,
.num_parents = 6,
.ops = &clk_rcg2_ops,
+ .flags = CLK_SET_RATE_PARENT,
},
};
-static struct freq_tbl ftbl_mdss_edppixel_clk[] = {
- F(175000000, P_EDPVCO, 2, 0, 0),
- F(350000000, P_EDPVCO, 11, 0, 0),
+static struct freq_tbl edp_pixel_freq_tbl[] = {
+ { .src = P_EDPVCO },
{ }
};
@@ -836,12 +850,12 @@ static struct clk_rcg2 edppixel_clk_src = {
.mnd_width = 8,
.hid_width = 5,
.parent_map = mmcc_xo_dsi_hdmi_edp_map,
- .freq_tbl = ftbl_mdss_edppixel_clk,
+ .freq_tbl = edp_pixel_freq_tbl,
.clkr.hw.init = &(struct clk_init_data){
.name = "edppixel_clk_src",
.parent_names = mmcc_xo_dsi_hdmi_edp,
.num_parents = 6,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_edp_pixel_ops,
},
};
@@ -853,11 +867,11 @@ static struct freq_tbl ftbl_mdss_esc0_1_clk[] = {
static struct clk_rcg2 esc0_clk_src = {
.cmd_rcgr = 0x2160,
.hid_width = 5,
- .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map,
+ .parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map,
.freq_tbl = ftbl_mdss_esc0_1_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "esc0_clk_src",
- .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0,
+ .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0,
.num_parents = 6,
.ops = &clk_rcg2_ops,
},
@@ -866,26 +880,18 @@ static struct clk_rcg2 esc0_clk_src = {
static struct clk_rcg2 esc1_clk_src = {
.cmd_rcgr = 0x2180,
.hid_width = 5,
- .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map,
+ .parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map,
.freq_tbl = ftbl_mdss_esc0_1_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "esc1_clk_src",
- .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0,
+ .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0,
.num_parents = 6,
.ops = &clk_rcg2_ops,
},
};
-static struct freq_tbl ftbl_mdss_extpclk_clk[] = {
- F(25200000, P_HDMIPLL, 1, 0, 0),
- F(27000000, P_HDMIPLL, 1, 0, 0),
- F(27030000, P_HDMIPLL, 1, 0, 0),
- F(65000000, P_HDMIPLL, 1, 0, 0),
- F(74250000, P_HDMIPLL, 1, 0, 0),
- F(108000000, P_HDMIPLL, 1, 0, 0),
- F(148500000, P_HDMIPLL, 1, 0, 0),
- F(268500000, P_HDMIPLL, 1, 0, 0),
- F(297000000, P_HDMIPLL, 1, 0, 0),
+static struct freq_tbl extpclk_freq_tbl[] = {
+ { .src = P_HDMIPLL },
{ }
};
@@ -893,12 +899,13 @@ static struct clk_rcg2 extpclk_clk_src = {
.cmd_rcgr = 0x2060,
.hid_width = 5,
.parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map,
- .freq_tbl = ftbl_mdss_extpclk_clk,
+ .freq_tbl = extpclk_freq_tbl,
.clkr.hw.init = &(struct clk_init_data){
.name = "extpclk_clk_src",
.parent_names = mmcc_xo_dsi_hdmi_edp_gpll0,
.num_parents = 6,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_byte_ops,
+ .flags = CLK_SET_RATE_PARENT,
},
};
@@ -2318,7 +2325,7 @@ static const struct pll_config mmpll1_config = {
.vco_val = 0x0,
.vco_mask = 0x3 << 20,
.pre_div_val = 0x0,
- .pre_div_mask = 0x3 << 12,
+ .pre_div_mask = 0x7 << 12,
.post_div_val = 0x0,
.post_div_mask = 0x3 << 8,
.mn_ena_mask = BIT(24),
@@ -2332,7 +2339,7 @@ static struct pll_config mmpll3_config = {
.vco_val = 0x0,
.vco_mask = 0x3 << 20,
.pre_div_val = 0x0,
- .pre_div_mask = 0x3 << 12,
+ .pre_div_mask = 0x7 << 12,
.post_div_val = 0x0,
.post_div_mask = 0x3 << 8,
.mn_ena_mask = BIT(24),
@@ -2524,88 +2531,39 @@ static const struct regmap_config mmcc_msm8974_regmap_config = {
.fast_io = true,
};
+static const struct qcom_cc_desc mmcc_msm8974_desc = {
+ .config = &mmcc_msm8974_regmap_config,
+ .clks = mmcc_msm8974_clocks,
+ .num_clks = ARRAY_SIZE(mmcc_msm8974_clocks),
+ .resets = mmcc_msm8974_resets,
+ .num_resets = ARRAY_SIZE(mmcc_msm8974_resets),
+};
+
static const struct of_device_id mmcc_msm8974_match_table[] = {
{ .compatible = "qcom,mmcc-msm8974" },
{ }
};
MODULE_DEVICE_TABLE(of, mmcc_msm8974_match_table);
-struct qcom_cc {
- struct qcom_reset_controller reset;
- struct clk_onecell_data data;
- struct clk *clks[];
-};
-
static int mmcc_msm8974_probe(struct platform_device *pdev)
{
- void __iomem *base;
- struct resource *res;
- int i, ret;
- struct device *dev = &pdev->dev;
- struct clk *clk;
- struct clk_onecell_data *data;
- struct clk **clks;
+ int ret;
struct regmap *regmap;
- size_t num_clks;
- struct qcom_reset_controller *reset;
- struct qcom_cc *cc;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- regmap = devm_regmap_init_mmio(dev, base, &mmcc_msm8974_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- num_clks = ARRAY_SIZE(mmcc_msm8974_clocks);
- cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks,
- GFP_KERNEL);
- if (!cc)
- return -ENOMEM;
-
- clks = cc->clks;
- data = &cc->data;
- data->clks = clks;
- data->clk_num = num_clks;
-
- clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true);
- clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false);
-
- for (i = 0; i < num_clks; i++) {
- if (!mmcc_msm8974_clocks[i])
- continue;
- clk = devm_clk_register_regmap(dev, mmcc_msm8974_clocks[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- clks[i] = clk;
- }
- ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data);
+ ret = qcom_cc_probe(pdev, &mmcc_msm8974_desc);
if (ret)
return ret;
- reset = &cc->reset;
- reset->rcdev.of_node = dev->of_node;
- reset->rcdev.ops = &qcom_reset_ops,
- reset->rcdev.owner = THIS_MODULE,
- reset->rcdev.nr_resets = ARRAY_SIZE(mmcc_msm8974_resets),
- reset->regmap = regmap;
- reset->reset_map = mmcc_msm8974_resets,
- platform_set_drvdata(pdev, &reset->rcdev);
-
- ret = reset_controller_register(&reset->rcdev);
- if (ret)
- of_clk_del_provider(dev->of_node);
+ regmap = dev_get_regmap(&pdev->dev, NULL);
+ clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true);
+ clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false);
- return ret;
+ return 0;
}
static int mmcc_msm8974_remove(struct platform_device *pdev)
{
- of_clk_del_provider(pdev->dev.of_node);
- reset_controller_unregister(platform_get_drvdata(pdev));
+ qcom_cc_remove(pdev);
return 0;
}
diff --git a/drivers/clk/rockchip/clk-rockchip.c b/drivers/clk/rockchip/clk-rockchip.c
index 967c141b1a20..4cf838d52ef6 100644
--- a/drivers/clk/rockchip/clk-rockchip.c
+++ b/drivers/clk/rockchip/clk-rockchip.c
@@ -24,8 +24,7 @@ static DEFINE_SPINLOCK(clk_lock);
* Gate clocks
*/
-static void __init rk2928_gate_clk_init(struct device_node *node,
- void *data)
+static void __init rk2928_gate_clk_init(struct device_node *node)
{
struct clk_onecell_data *clk_data;
const char *clk_parent;
diff --git a/drivers/clk/samsung/Kconfig b/drivers/clk/samsung/Kconfig
new file mode 100644
index 000000000000..84196ecdaa12
--- /dev/null
+++ b/drivers/clk/samsung/Kconfig
@@ -0,0 +1,26 @@
+config COMMON_CLK_SAMSUNG
+ bool
+ select COMMON_CLK
+
+config S3C2410_COMMON_CLK
+ bool
+ select COMMON_CLK_SAMSUNG
+ help
+ Build the s3c2410 clock driver based on the common clock framework.
+
+config S3C2410_COMMON_DCLK
+ bool
+ select COMMON_CLK_SAMSUNG
+ select REGMAP_MMIO
+ help
+ Temporary symbol to build the dclk driver based on the common clock
+ framework.
+
+config S3C2412_COMMON_CLK
+ bool
+ select COMMON_CLK_SAMSUNG
+
+config S3C2443_COMMON_CLK
+ bool
+ select COMMON_CLK_SAMSUNG
+
diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile
index 8eb4799237f0..69e81773164e 100644
--- a/drivers/clk/samsung/Makefile
+++ b/drivers/clk/samsung/Makefile
@@ -3,9 +3,16 @@
#
obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o
+obj-$(CONFIG_SOC_EXYNOS3250) += clk-exynos3250.o
obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o
obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o
+obj-$(CONFIG_SOC_EXYNOS5260) += clk-exynos5260.o
+obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o
obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o
obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o
obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-audss.o
+obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o
+obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o
+obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o
+obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o
obj-$(CONFIG_ARCH_S3C64XX) += clk-s3c64xx.o
diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c
new file mode 100644
index 000000000000..7a17bd40d1dd
--- /dev/null
+++ b/drivers/clk/samsung/clk-exynos3250.c
@@ -0,0 +1,780 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ * Common Clock Framework support for Exynos3250 SoC.
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/syscore_ops.h>
+
+#include <dt-bindings/clock/exynos3250.h>
+
+#include "clk.h"
+#include "clk-pll.h"
+
+#define SRC_LEFTBUS 0x4200
+#define DIV_LEFTBUS 0x4500
+#define GATE_IP_LEFTBUS 0x4800
+#define SRC_RIGHTBUS 0x8200
+#define DIV_RIGHTBUS 0x8500
+#define GATE_IP_RIGHTBUS 0x8800
+#define GATE_IP_PERIR 0x8960
+#define MPLL_LOCK 0xc010
+#define MPLL_CON0 0xc110
+#define VPLL_LOCK 0xc020
+#define VPLL_CON0 0xc120
+#define UPLL_LOCK 0xc030
+#define UPLL_CON0 0xc130
+#define SRC_TOP0 0xc210
+#define SRC_TOP1 0xc214
+#define SRC_CAM 0xc220
+#define SRC_MFC 0xc228
+#define SRC_G3D 0xc22c
+#define SRC_LCD 0xc234
+#define SRC_ISP 0xc238
+#define SRC_FSYS 0xc240
+#define SRC_PERIL0 0xc250
+#define SRC_PERIL1 0xc254
+#define SRC_MASK_TOP 0xc310
+#define SRC_MASK_CAM 0xc320
+#define SRC_MASK_LCD 0xc334
+#define SRC_MASK_ISP 0xc338
+#define SRC_MASK_FSYS 0xc340
+#define SRC_MASK_PERIL0 0xc350
+#define SRC_MASK_PERIL1 0xc354
+#define DIV_TOP 0xc510
+#define DIV_CAM 0xc520
+#define DIV_MFC 0xc528
+#define DIV_G3D 0xc52c
+#define DIV_LCD 0xc534
+#define DIV_ISP 0xc538
+#define DIV_FSYS0 0xc540
+#define DIV_FSYS1 0xc544
+#define DIV_FSYS2 0xc548
+#define DIV_PERIL0 0xc550
+#define DIV_PERIL1 0xc554
+#define DIV_PERIL3 0xc55c
+#define DIV_PERIL4 0xc560
+#define DIV_PERIL5 0xc564
+#define DIV_CAM1 0xc568
+#define CLKDIV2_RATIO 0xc580
+#define GATE_SCLK_CAM 0xc820
+#define GATE_SCLK_MFC 0xc828
+#define GATE_SCLK_G3D 0xc82c
+#define GATE_SCLK_LCD 0xc834
+#define GATE_SCLK_ISP_TOP 0xc838
+#define GATE_SCLK_FSYS 0xc840
+#define GATE_SCLK_PERIL 0xc850
+#define GATE_IP_CAM 0xc920
+#define GATE_IP_MFC 0xc928
+#define GATE_IP_G3D 0xc92c
+#define GATE_IP_LCD 0xc934
+#define GATE_IP_ISP 0xc938
+#define GATE_IP_FSYS 0xc940
+#define GATE_IP_PERIL 0xc950
+#define GATE_BLOCK 0xc970
+#define APLL_LOCK 0x14000
+#define APLL_CON0 0x14100
+#define SRC_CPU 0x14200
+#define DIV_CPU0 0x14500
+#define DIV_CPU1 0x14504
+
+/* list of PLLs to be registered */
+enum exynos3250_plls {
+ apll, mpll, vpll, upll,
+ nr_plls
+};
+
+static void __iomem *reg_base;
+
+/*
+ * Support for CMU save/restore across system suspends
+ */
+#ifdef CONFIG_PM_SLEEP
+static struct samsung_clk_reg_dump *exynos3250_clk_regs;
+
+static unsigned long exynos3250_cmu_clk_regs[] __initdata = {
+ SRC_LEFTBUS,
+ DIV_LEFTBUS,
+ GATE_IP_LEFTBUS,
+ SRC_RIGHTBUS,
+ DIV_RIGHTBUS,
+ GATE_IP_RIGHTBUS,
+ GATE_IP_PERIR,
+ MPLL_LOCK,
+ MPLL_CON0,
+ VPLL_LOCK,
+ VPLL_CON0,
+ UPLL_LOCK,
+ UPLL_CON0,
+ SRC_TOP0,
+ SRC_TOP1,
+ SRC_CAM,
+ SRC_MFC,
+ SRC_G3D,
+ SRC_LCD,
+ SRC_ISP,
+ SRC_FSYS,
+ SRC_PERIL0,
+ SRC_PERIL1,
+ SRC_MASK_TOP,
+ SRC_MASK_CAM,
+ SRC_MASK_LCD,
+ SRC_MASK_ISP,
+ SRC_MASK_FSYS,
+ SRC_MASK_PERIL0,
+ SRC_MASK_PERIL1,
+ DIV_TOP,
+ DIV_CAM,
+ DIV_MFC,
+ DIV_G3D,
+ DIV_LCD,
+ DIV_ISP,
+ DIV_FSYS0,
+ DIV_FSYS1,
+ DIV_FSYS2,
+ DIV_PERIL0,
+ DIV_PERIL1,
+ DIV_PERIL3,
+ DIV_PERIL4,
+ DIV_PERIL5,
+ DIV_CAM1,
+ CLKDIV2_RATIO,
+ GATE_SCLK_CAM,
+ GATE_SCLK_MFC,
+ GATE_SCLK_G3D,
+ GATE_SCLK_LCD,
+ GATE_SCLK_ISP_TOP,
+ GATE_SCLK_FSYS,
+ GATE_SCLK_PERIL,
+ GATE_IP_CAM,
+ GATE_IP_MFC,
+ GATE_IP_G3D,
+ GATE_IP_LCD,
+ GATE_IP_ISP,
+ GATE_IP_FSYS,
+ GATE_IP_PERIL,
+ GATE_BLOCK,
+ APLL_LOCK,
+ SRC_CPU,
+ DIV_CPU0,
+ DIV_CPU1,
+};
+
+static int exynos3250_clk_suspend(void)
+{
+ samsung_clk_save(reg_base, exynos3250_clk_regs,
+ ARRAY_SIZE(exynos3250_cmu_clk_regs));
+ return 0;
+}
+
+static void exynos3250_clk_resume(void)
+{
+ samsung_clk_restore(reg_base, exynos3250_clk_regs,
+ ARRAY_SIZE(exynos3250_cmu_clk_regs));
+}
+
+static struct syscore_ops exynos3250_clk_syscore_ops = {
+ .suspend = exynos3250_clk_suspend,
+ .resume = exynos3250_clk_resume,
+};
+
+static void exynos3250_clk_sleep_init(void)
+{
+ exynos3250_clk_regs =
+ samsung_clk_alloc_reg_dump(exynos3250_cmu_clk_regs,
+ ARRAY_SIZE(exynos3250_cmu_clk_regs));
+ if (!exynos3250_clk_regs) {
+ pr_warn("%s: Failed to allocate sleep save data\n", __func__);
+ goto err;
+ }
+
+ register_syscore_ops(&exynos3250_clk_syscore_ops);
+ return;
+err:
+ kfree(exynos3250_clk_regs);
+}
+#else
+static inline void exynos3250_clk_sleep_init(void) { }
+#endif
+
+/* list of all parent clock list */
+PNAME(mout_vpllsrc_p) = { "fin_pll", };
+
+PNAME(mout_apll_p) = { "fin_pll", "fout_apll", };
+PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", };
+PNAME(mout_vpll_p) = { "fin_pll", "fout_vpll", };
+PNAME(mout_upll_p) = { "fin_pll", "fout_upll", };
+
+PNAME(mout_mpll_user_p) = { "fin_pll", "div_mpll_pre", };
+PNAME(mout_epll_user_p) = { "fin_pll", "mout_epll", };
+PNAME(mout_core_p) = { "mout_apll", "mout_mpll_user_c", };
+PNAME(mout_hpm_p) = { "mout_apll", "mout_mpll_user_c", };
+
+PNAME(mout_ebi_p) = { "div_aclk_200", "div_aclk_160", };
+PNAME(mout_ebi_1_p) = { "mout_ebi", "mout_vpll", };
+
+PNAME(mout_gdl_p) = { "mout_mpll_user_l", };
+PNAME(mout_gdr_p) = { "mout_mpll_user_r", };
+
+PNAME(mout_aclk_400_mcuisp_sub_p)
+ = { "fin_pll", "div_aclk_400_mcuisp", };
+PNAME(mout_aclk_266_0_p) = { "div_mpll_pre", "mout_vpll", };
+PNAME(mout_aclk_266_1_p) = { "mout_epll_user", };
+PNAME(mout_aclk_266_p) = { "mout_aclk_266_0", "mout_aclk_266_1", };
+PNAME(mout_aclk_266_sub_p) = { "fin_pll", "div_aclk_266", };
+
+PNAME(group_div_mpll_pre_p) = { "div_mpll_pre", };
+PNAME(group_epll_vpll_p) = { "mout_epll_user", "mout_vpll" };
+PNAME(group_sclk_p) = { "xxti", "xusbxti",
+ "none", "none",
+ "none", "none", "div_mpll_pre",
+ "mout_epll_user", "mout_vpll", };
+PNAME(group_sclk_audio_p) = { "audiocdclk", "none",
+ "none", "none",
+ "xxti", "xusbxti",
+ "div_mpll_pre", "mout_epll_user",
+ "mout_vpll", };
+PNAME(group_sclk_cam_blk_p) = { "xxti", "xusbxti",
+ "none", "none", "none",
+ "none", "div_mpll_pre",
+ "mout_epll_user", "mout_vpll",
+ "div_cam_blk_320", };
+PNAME(group_sclk_fimd0_p) = { "xxti", "xusbxti",
+ "m_bitclkhsdiv4_2l", "none",
+ "none", "none", "div_mpll_pre",
+ "mout_epll_user", "mout_vpll",
+ "none", "none", "none",
+ "div_lcd_blk_145", };
+
+PNAME(mout_mfc_p) = { "mout_mfc_0", "mout_mfc_1" };
+PNAME(mout_g3d_p) = { "mout_g3d_0", "mout_g3d_1" };
+
+static struct samsung_fixed_factor_clock fixed_factor_clks[] __initdata = {
+ FFACTOR(0, "sclk_mpll_1600", "mout_mpll", 1, 1, 0),
+ FFACTOR(0, "sclk_mpll_mif", "mout_mpll", 1, 2, 0),
+ FFACTOR(0, "sclk_bpll", "fout_bpll", 1, 2, 0),
+ FFACTOR(0, "div_cam_blk_320", "sclk_mpll_1600", 1, 5, 0),
+ FFACTOR(0, "div_lcd_blk_145", "sclk_mpll_1600", 1, 11, 0),
+
+ /* HACK: fin_pll hardcoded to xusbxti until detection is implemented. */
+ FFACTOR(CLK_FIN_PLL, "fin_pll", "xusbxti", 1, 1, 0),
+};
+
+static struct samsung_mux_clock mux_clks[] __initdata = {
+ /*
+ * NOTE: Following table is sorted by register address in ascending
+ * order and then bitfield shift in descending order, as it is done
+ * in the User's Manual. When adding new entries, please make sure
+ * that the order is preserved, to avoid merge conflicts and make
+ * further work with defined data easier.
+ */
+
+ /* SRC_LEFTBUS */
+ MUX(CLK_MOUT_MPLL_USER_L, "mout_mpll_user_l", mout_mpll_user_p,
+ SRC_LEFTBUS, 4, 1),
+ MUX(CLK_MOUT_GDL, "mout_gdl", mout_gdl_p, SRC_LEFTBUS, 0, 1),
+
+ /* SRC_RIGHTBUS */
+ MUX(CLK_MOUT_MPLL_USER_R, "mout_mpll_user_r", mout_mpll_user_p,
+ SRC_RIGHTBUS, 4, 1),
+ MUX(CLK_MOUT_GDR, "mout_gdr", mout_gdr_p, SRC_RIGHTBUS, 0, 1),
+
+ /* SRC_TOP0 */
+ MUX(CLK_MOUT_EBI, "mout_ebi", mout_ebi_p, SRC_TOP0, 28, 1),
+ MUX(CLK_MOUT_ACLK_200, "mout_aclk_200", group_div_mpll_pre_p,SRC_TOP0, 24, 1),
+ MUX(CLK_MOUT_ACLK_160, "mout_aclk_160", group_div_mpll_pre_p, SRC_TOP0, 20, 1),
+ MUX(CLK_MOUT_ACLK_100, "mout_aclk_100", group_div_mpll_pre_p, SRC_TOP0, 16, 1),
+ MUX(CLK_MOUT_ACLK_266_1, "mout_aclk_266_1", mout_aclk_266_1_p, SRC_TOP0, 14, 1),
+ MUX(CLK_MOUT_ACLK_266_0, "mout_aclk_266_0", mout_aclk_266_0_p, SRC_TOP0, 13, 1),
+ MUX(CLK_MOUT_ACLK_266, "mout_aclk_266", mout_aclk_266_p, SRC_TOP0, 12, 1),
+ MUX(CLK_MOUT_VPLL, "mout_vpll", mout_vpll_p, SRC_TOP0, 8, 1),
+ MUX(CLK_MOUT_EPLL_USER, "mout_epll_user", mout_epll_user_p, SRC_TOP0, 4, 1),
+ MUX(CLK_MOUT_EBI_1, "mout_ebi_1", mout_ebi_1_p, SRC_TOP0, 0, 1),
+
+ /* SRC_TOP1 */
+ MUX(CLK_MOUT_UPLL, "mout_upll", mout_upll_p, SRC_TOP1, 28, 1),
+ MUX(CLK_MOUT_ACLK_400_MCUISP_SUB, "mout_aclk_400_mcuisp_sub", mout_aclk_400_mcuisp_sub_p,
+ SRC_TOP1, 24, 1),
+ MUX(CLK_MOUT_ACLK_266_SUB, "mout_aclk_266_sub", mout_aclk_266_sub_p, SRC_TOP1, 20, 1),
+ MUX(CLK_MOUT_MPLL, "mout_mpll", mout_mpll_p, SRC_TOP1, 12, 1),
+ MUX(CLK_MOUT_ACLK_400_MCUISP, "mout_aclk_400_mcuisp", group_div_mpll_pre_p, SRC_TOP1, 8, 1),
+ MUX(CLK_MOUT_VPLLSRC, "mout_vpllsrc", mout_vpllsrc_p, SRC_TOP1, 0, 1),
+
+ /* SRC_CAM */
+ MUX(CLK_MOUT_CAM1, "mout_cam1", group_sclk_p, SRC_CAM, 20, 4),
+ MUX(CLK_MOUT_CAM_BLK, "mout_cam_blk", group_sclk_cam_blk_p, SRC_CAM, 0, 4),
+
+ /* SRC_MFC */
+ MUX(CLK_MOUT_MFC, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1),
+ MUX(CLK_MOUT_MFC_1, "mout_mfc_1", group_epll_vpll_p, SRC_MFC, 4, 1),
+ MUX(CLK_MOUT_MFC_0, "mout_mfc_0", group_div_mpll_pre_p, SRC_MFC, 0, 1),
+
+ /* SRC_G3D */
+ MUX(CLK_MOUT_G3D, "mout_g3d", mout_g3d_p, SRC_G3D, 8, 1),
+ MUX(CLK_MOUT_G3D_1, "mout_g3d_1", group_epll_vpll_p, SRC_G3D, 4, 1),
+ MUX(CLK_MOUT_G3D_0, "mout_g3d_0", group_div_mpll_pre_p, SRC_G3D, 0, 1),
+
+ /* SRC_LCD */
+ MUX(CLK_MOUT_MIPI0, "mout_mipi0", group_sclk_p, SRC_LCD, 12, 4),
+ MUX(CLK_MOUT_FIMD0, "mout_fimd0", group_sclk_fimd0_p, SRC_LCD, 0, 4),
+
+ /* SRC_ISP */
+ MUX(CLK_MOUT_UART_ISP, "mout_uart_isp", group_sclk_p, SRC_ISP, 12, 4),
+ MUX(CLK_MOUT_SPI1_ISP, "mout_spi1_isp", group_sclk_p, SRC_ISP, 8, 4),
+ MUX(CLK_MOUT_SPI0_ISP, "mout_spi0_isp", group_sclk_p, SRC_ISP, 4, 4),
+
+ /* SRC_FSYS */
+ MUX(CLK_MOUT_TSADC, "mout_tsadc", group_sclk_p, SRC_FSYS, 28, 4),
+ MUX(CLK_MOUT_MMC1, "mout_mmc1", group_sclk_p, SRC_FSYS, 4, 3),
+ MUX(CLK_MOUT_MMC0, "mout_mmc0", group_sclk_p, SRC_FSYS, 0, 3),
+
+ /* SRC_PERIL0 */
+ MUX(CLK_MOUT_UART1, "mout_uart1", group_sclk_p, SRC_PERIL0, 4, 4),
+ MUX(CLK_MOUT_UART0, "mout_uart0", group_sclk_p, SRC_PERIL0, 0, 4),
+
+ /* SRC_PERIL1 */
+ MUX(CLK_MOUT_SPI1, "mout_spi1", group_sclk_p, SRC_PERIL1, 20, 4),
+ MUX(CLK_MOUT_SPI0, "mout_spi0", group_sclk_p, SRC_PERIL1, 16, 4),
+ MUX(CLK_MOUT_AUDIO, "mout_audio", group_sclk_audio_p, SRC_PERIL1, 4, 4),
+
+ /* SRC_CPU */
+ MUX(CLK_MOUT_MPLL_USER_C, "mout_mpll_user_c", mout_mpll_user_p,
+ SRC_CPU, 24, 1),
+ MUX(CLK_MOUT_HPM, "mout_hpm", mout_hpm_p, SRC_CPU, 20, 1),
+ MUX(CLK_MOUT_CORE, "mout_core", mout_core_p, SRC_CPU, 16, 1),
+ MUX(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1),
+};
+
+static struct samsung_div_clock div_clks[] __initdata = {
+ /*
+ * NOTE: Following table is sorted by register address in ascending
+ * order and then bitfield shift in descending order, as it is done
+ * in the User's Manual. When adding new entries, please make sure
+ * that the order is preserved, to avoid merge conflicts and make
+ * further work with defined data easier.
+ */
+
+ /* DIV_LEFTBUS */
+ DIV(CLK_DIV_GPL, "div_gpl", "div_gdl", DIV_LEFTBUS, 4, 3),
+ DIV(CLK_DIV_GDL, "div_gdl", "mout_gdl", DIV_LEFTBUS, 0, 4),
+
+ /* DIV_RIGHTBUS */
+ DIV(CLK_DIV_GPR, "div_gpr", "div_gdr", DIV_RIGHTBUS, 4, 3),
+ DIV(CLK_DIV_GDR, "div_gdr", "mout_gdr", DIV_RIGHTBUS, 0, 4),
+
+ /* DIV_TOP */
+ DIV(CLK_DIV_MPLL_PRE, "div_mpll_pre", "sclk_mpll_mif", DIV_TOP, 28, 2),
+ DIV(CLK_DIV_ACLK_400_MCUISP, "div_aclk_400_mcuisp",
+ "mout_aclk_400_mcuisp", DIV_TOP, 24, 3),
+ DIV(CLK_DIV_EBI, "div_ebi", "mout_ebi_1", DIV_TOP, 16, 3),
+ DIV(CLK_DIV_ACLK_200, "div_aclk_200", "mout_aclk_200", DIV_TOP, 12, 3),
+ DIV(CLK_DIV_ACLK_160, "div_aclk_160", "mout_aclk_160", DIV_TOP, 8, 3),
+ DIV(CLK_DIV_ACLK_100, "div_aclk_100", "mout_aclk_100", DIV_TOP, 4, 4),
+ DIV(CLK_DIV_ACLK_266, "div_aclk_266", "mout_aclk_266", DIV_TOP, 0, 3),
+
+ /* DIV_CAM */
+ DIV(CLK_DIV_CAM1, "div_cam1", "mout_cam1", DIV_CAM, 20, 4),
+ DIV(CLK_DIV_CAM_BLK, "div_cam_blk", "mout_cam_blk", DIV_CAM, 0, 4),
+
+ /* DIV_MFC */
+ DIV(CLK_DIV_MFC, "div_mfc", "mout_mfc", DIV_MFC, 0, 4),
+
+ /* DIV_G3D */
+ DIV(CLK_DIV_G3D, "div_g3d", "mout_g3d", DIV_G3D, 0, 4),
+
+ /* DIV_LCD */
+ DIV_F(CLK_DIV_MIPI0_PRE, "div_mipi0_pre", "div_mipi0", DIV_LCD, 20, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV(CLK_DIV_MIPI0, "div_mipi0", "mout_mipi0", DIV_LCD, 16, 4),
+ DIV(CLK_DIV_FIMD0, "div_fimd0", "mout_fimd0", DIV_LCD, 0, 4),
+
+ /* DIV_ISP */
+ DIV(CLK_DIV_UART_ISP, "div_uart_isp", "mout_uart_isp", DIV_ISP, 28, 4),
+ DIV_F(CLK_DIV_SPI1_ISP_PRE, "div_spi1_isp_pre", "div_spi1_isp",
+ DIV_ISP, 20, 8, CLK_SET_RATE_PARENT, 0),
+ DIV(CLK_DIV_SPI1_ISP, "div_spi1_isp", "mout_spi1_isp", DIV_ISP, 16, 4),
+ DIV_F(CLK_DIV_SPI0_ISP_PRE, "div_spi0_isp_pre", "div_spi0_isp",
+ DIV_ISP, 8, 8, CLK_SET_RATE_PARENT, 0),
+ DIV(CLK_DIV_SPI0_ISP, "div_spi0_isp", "mout_spi0_isp", DIV_ISP, 0, 4),
+
+ /* DIV_FSYS0 */
+ DIV_F(CLK_DIV_TSADC_PRE, "div_tsadc_pre", "div_tsadc", DIV_FSYS0, 8, 8,
+ CLK_SET_RATE_PARENT, 0),
+ DIV(CLK_DIV_TSADC, "div_tsadc", "mout_tsadc", DIV_FSYS0, 0, 4),
+
+ /* DIV_FSYS1 */
+ DIV_F(CLK_DIV_MMC1_PRE, "div_mmc1_pre", "div_mmc1", DIV_FSYS1, 24, 8,
+ CLK_SET_RATE_PARENT, 0),
+ DIV(CLK_DIV_MMC1, "div_mmc1", "mout_mmc1", DIV_FSYS1, 16, 4),
+ DIV_F(CLK_DIV_MMC0_PRE, "div_mmc0_pre", "div_mmc0", DIV_FSYS1, 8, 8,
+ CLK_SET_RATE_PARENT, 0),
+ DIV(CLK_DIV_MMC0, "div_mmc0", "mout_mmc0", DIV_FSYS1, 0, 4),
+
+ /* DIV_PERIL0 */
+ DIV(CLK_DIV_UART1, "div_uart1", "mout_uart1", DIV_PERIL0, 4, 4),
+ DIV(CLK_DIV_UART0, "div_uart0", "mout_uart0", DIV_PERIL0, 0, 4),
+
+ /* DIV_PERIL1 */
+ DIV_F(CLK_DIV_SPI1_PRE, "div_spi1_pre", "div_spi1", DIV_PERIL1, 24, 8,
+ CLK_SET_RATE_PARENT, 0),
+ DIV(CLK_DIV_SPI1, "div_spi1", "mout_spi1", DIV_PERIL1, 16, 4),
+ DIV_F(CLK_DIV_SPI0_PRE, "div_spi0_pre", "div_spi0", DIV_PERIL1, 8, 8,
+ CLK_SET_RATE_PARENT, 0),
+ DIV(CLK_DIV_SPI0, "div_spi0", "mout_spi0", DIV_PERIL1, 0, 4),
+
+ /* DIV_PERIL4 */
+ DIV(CLK_DIV_PCM, "div_pcm", "div_audio", DIV_PERIL4, 20, 8),
+ DIV(CLK_DIV_AUDIO, "div_audio", "mout_audio", DIV_PERIL4, 16, 4),
+
+ /* DIV_PERIL5 */
+ DIV(CLK_DIV_I2S, "div_i2s", "div_audio", DIV_PERIL5, 8, 6),
+
+ /* DIV_CPU0 */
+ DIV(CLK_DIV_CORE2, "div_core2", "div_core", DIV_CPU0, 28, 3),
+ DIV(CLK_DIV_APLL, "div_apll", "mout_apll", DIV_CPU0, 24, 3),
+ DIV(CLK_DIV_PCLK_DBG, "div_pclk_dbg", "div_core2", DIV_CPU0, 20, 3),
+ DIV(CLK_DIV_ATB, "div_atb", "div_core2", DIV_CPU0, 16, 3),
+ DIV(CLK_DIV_COREM, "div_corem", "div_core2", DIV_CPU0, 4, 3),
+ DIV(CLK_DIV_CORE, "div_core", "mout_core", DIV_CPU0, 0, 3),
+
+ /* DIV_CPU1 */
+ DIV(CLK_DIV_HPM, "div_hpm", "div_copy", DIV_CPU1, 4, 3),
+ DIV(CLK_DIV_COPY, "div_copy", "mout_hpm", DIV_CPU1, 0, 3),
+};
+
+static struct samsung_gate_clock gate_clks[] __initdata = {
+ /*
+ * NOTE: Following table is sorted by register address in ascending
+ * order and then bitfield shift in descending order, as it is done
+ * in the User's Manual. When adding new entries, please make sure
+ * that the order is preserved, to avoid merge conflicts and make
+ * further work with defined data easier.
+ */
+
+ /* GATE_IP_LEFTBUS */
+ GATE(CLK_ASYNC_G3D, "async_g3d", "div_aclk_100", GATE_IP_LEFTBUS, 6,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_ASYNC_MFCL, "async_mfcl", "div_aclk_100", GATE_IP_LEFTBUS, 4,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PPMULEFT, "ppmuleft", "div_aclk_100", GATE_IP_LEFTBUS, 1,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_GPIO_LEFT, "gpio_left", "div_aclk_100", GATE_IP_LEFTBUS, 0,
+ CLK_IGNORE_UNUSED, 0),
+
+ /* GATE_IP_RIGHTBUS */
+ GATE(CLK_ASYNC_ISPMX, "async_ispmx", "div_aclk_100",
+ GATE_IP_RIGHTBUS, 9, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_ASYNC_FSYSD, "async_fsysd", "div_aclk_100",
+ GATE_IP_RIGHTBUS, 5, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_ASYNC_LCD0X, "async_lcd0x", "div_aclk_100",
+ GATE_IP_RIGHTBUS, 3, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_ASYNC_CAMX, "async_camx", "div_aclk_100", GATE_IP_RIGHTBUS, 2,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PPMURIGHT, "ppmuright", "div_aclk_100", GATE_IP_RIGHTBUS, 1,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_GPIO_RIGHT, "gpio_right", "div_aclk_100", GATE_IP_RIGHTBUS, 0,
+ CLK_IGNORE_UNUSED, 0),
+
+ /* GATE_IP_PERIR */
+ GATE(CLK_MONOCNT, "monocnt", "div_aclk_100", GATE_IP_PERIR, 22,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_TZPC6, "tzpc6", "div_aclk_100", GATE_IP_PERIR, 21,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PROVISIONKEY1, "provisionkey1", "div_aclk_100",
+ GATE_IP_PERIR, 20, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PROVISIONKEY0, "provisionkey0", "div_aclk_100",
+ GATE_IP_PERIR, 19, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_CMU_ISPPART, "cmu_isppart", "div_aclk_100", GATE_IP_PERIR, 18,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_TMU_APBIF, "tmu_apbif", "div_aclk_100",
+ GATE_IP_PERIR, 17, 0, 0),
+ GATE(CLK_KEYIF, "keyif", "div_aclk_100", GATE_IP_PERIR, 16, 0, 0),
+ GATE(CLK_RTC, "rtc", "div_aclk_100", GATE_IP_PERIR, 15, 0, 0),
+ GATE(CLK_WDT, "wdt", "div_aclk_100", GATE_IP_PERIR, 14, 0, 0),
+ GATE(CLK_MCT, "mct", "div_aclk_100", GATE_IP_PERIR, 13, 0, 0),
+ GATE(CLK_SECKEY, "seckey", "div_aclk_100", GATE_IP_PERIR, 12,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_TZPC5, "tzpc5", "div_aclk_100", GATE_IP_PERIR, 10,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_TZPC4, "tzpc4", "div_aclk_100", GATE_IP_PERIR, 9,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_TZPC3, "tzpc3", "div_aclk_100", GATE_IP_PERIR, 8,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_TZPC2, "tzpc2", "div_aclk_100", GATE_IP_PERIR, 7,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_TZPC1, "tzpc1", "div_aclk_100", GATE_IP_PERIR, 6,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_TZPC0, "tzpc0", "div_aclk_100", GATE_IP_PERIR, 5,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_CMU_COREPART, "cmu_corepart", "div_aclk_100", GATE_IP_PERIR, 4,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_CMU_TOPPART, "cmu_toppart", "div_aclk_100", GATE_IP_PERIR, 3,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PMU_APBIF, "pmu_apbif", "div_aclk_100", GATE_IP_PERIR, 2,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_SYSREG, "sysreg", "div_aclk_100", GATE_IP_PERIR, 1,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_CHIP_ID, "chip_id", "div_aclk_100", GATE_IP_PERIR, 0,
+ CLK_IGNORE_UNUSED, 0),
+
+ /* GATE_SCLK_CAM */
+ GATE(CLK_SCLK_JPEG, "sclk_jpeg", "div_cam_blk",
+ GATE_SCLK_CAM, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_M2MSCALER, "sclk_m2mscaler", "div_cam_blk",
+ GATE_SCLK_CAM, 2, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_GSCALER1, "sclk_gscaler1", "div_cam_blk",
+ GATE_SCLK_CAM, 1, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_GSCALER0, "sclk_gscaler0", "div_cam_blk",
+ GATE_SCLK_CAM, 0, CLK_SET_RATE_PARENT, 0),
+
+ /* GATE_SCLK_MFC */
+ GATE(CLK_SCLK_MFC, "sclk_mfc", "div_mfc",
+ GATE_SCLK_MFC, 0, CLK_SET_RATE_PARENT, 0),
+
+ /* GATE_SCLK_G3D */
+ GATE(CLK_SCLK_G3D, "sclk_g3d", "div_g3d",
+ GATE_SCLK_G3D, 0, CLK_SET_RATE_PARENT, 0),
+
+ /* GATE_SCLK_LCD */
+ GATE(CLK_SCLK_MIPIDPHY2L, "sclk_mipidphy2l", "div_mipi0",
+ GATE_SCLK_LCD, 4, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_MIPI0, "sclk_mipi0", "div_mipi0_pre",
+ GATE_SCLK_LCD, 3, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_FIMD0, "sclk_fimd0", "div_fimd0",
+ GATE_SCLK_LCD, 0, CLK_SET_RATE_PARENT, 0),
+
+ /* GATE_SCLK_ISP_TOP */
+ GATE(CLK_SCLK_CAM1, "sclk_cam1", "div_cam1",
+ GATE_SCLK_ISP_TOP, 4, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_UART_ISP, "sclk_uart_isp", "div_uart_isp",
+ GATE_SCLK_ISP_TOP, 3, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_SPI1_ISP, "sclk_spi1_isp", "div_spi1_isp",
+ GATE_SCLK_ISP_TOP, 2, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_SPI0_ISP, "sclk_spi0_isp", "div_spi0_isp",
+ GATE_SCLK_ISP_TOP, 1, CLK_SET_RATE_PARENT, 0),
+
+ /* GATE_SCLK_FSYS */
+ GATE(CLK_SCLK_UPLL, "sclk_upll", "mout_upll", GATE_SCLK_FSYS, 10, 0, 0),
+ GATE(CLK_SCLK_TSADC, "sclk_tsadc", "div_tsadc_pre",
+ GATE_SCLK_FSYS, 9, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_EBI, "sclk_ebi", "div_ebi",
+ GATE_SCLK_FSYS, 6, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_MMC1, "sclk_mmc1", "div_mmc1_pre",
+ GATE_SCLK_FSYS, 1, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_MMC0, "sclk_mmc0", "div_mmc0_pre",
+ GATE_SCLK_FSYS, 0, CLK_SET_RATE_PARENT, 0),
+
+ /* GATE_SCLK_PERIL */
+ GATE(CLK_SCLK_I2S, "sclk_i2s", "div_i2s",
+ GATE_SCLK_PERIL, 18, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_PCM, "sclk_pcm", "div_pcm",
+ GATE_SCLK_PERIL, 16, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_SPI1, "sclk_spi1", "div_spi1_pre",
+ GATE_SCLK_PERIL, 7, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_SPI0, "sclk_spi0", "div_spi0_pre",
+ GATE_SCLK_PERIL, 6, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_UART1, "sclk_uart1", "div_uart1",
+ GATE_SCLK_PERIL, 1, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_UART0, "sclk_uart0", "div_uart0",
+ GATE_SCLK_PERIL, 0, CLK_SET_RATE_PARENT, 0),
+
+ /* GATE_IP_CAM */
+ GATE(CLK_QEJPEG, "qejpeg", "div_cam_blk_320", GATE_IP_CAM, 19,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PIXELASYNCM1, "pixelasyncm1", "div_cam_blk_320",
+ GATE_IP_CAM, 18, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PIXELASYNCM0, "pixelasyncm0", "div_cam_blk_320",
+ GATE_IP_CAM, 17, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PPMUCAMIF, "ppmucamif", "div_cam_blk_320",
+ GATE_IP_CAM, 16, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_QEM2MSCALER, "qem2mscaler", "div_cam_blk_320",
+ GATE_IP_CAM, 14, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_QEGSCALER1, "qegscaler1", "div_cam_blk_320",
+ GATE_IP_CAM, 13, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_QEGSCALER0, "qegscaler0", "div_cam_blk_320",
+ GATE_IP_CAM, 12, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_SMMUJPEG, "smmujpeg", "div_cam_blk_320",
+ GATE_IP_CAM, 11, 0, 0),
+ GATE(CLK_SMMUM2M2SCALER, "smmum2m2scaler", "div_cam_blk_320",
+ GATE_IP_CAM, 9, 0, 0),
+ GATE(CLK_SMMUGSCALER1, "smmugscaler1", "div_cam_blk_320",
+ GATE_IP_CAM, 8, 0, 0),
+ GATE(CLK_SMMUGSCALER0, "smmugscaler0", "div_cam_blk_320",
+ GATE_IP_CAM, 7, 0, 0),
+ GATE(CLK_JPEG, "jpeg", "div_cam_blk_320", GATE_IP_CAM, 6, 0, 0),
+ GATE(CLK_M2MSCALER, "m2mscaler", "div_cam_blk_320",
+ GATE_IP_CAM, 2, 0, 0),
+ GATE(CLK_GSCALER1, "gscaler1", "div_cam_blk_320", GATE_IP_CAM, 1, 0, 0),
+ GATE(CLK_GSCALER0, "gscaler0", "div_cam_blk_320", GATE_IP_CAM, 0, 0, 0),
+
+ /* GATE_IP_MFC */
+ GATE(CLK_QEMFC, "qemfc", "div_aclk_200", GATE_IP_MFC, 5,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PPMUMFC_L, "ppmumfc_l", "div_aclk_200", GATE_IP_MFC, 3,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_SMMUMFC_L, "smmumfc_l", "div_aclk_200", GATE_IP_MFC, 1, 0, 0),
+ GATE(CLK_MFC, "mfc", "div_aclk_200", GATE_IP_MFC, 0, 0, 0),
+
+ /* GATE_IP_G3D */
+ GATE(CLK_SMMUG3D, "smmug3d", "div_aclk_200", GATE_IP_G3D, 3, 0, 0),
+ GATE(CLK_QEG3D, "qeg3d", "div_aclk_200", GATE_IP_G3D, 2,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PPMUG3D, "ppmug3d", "div_aclk_200", GATE_IP_G3D, 1,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_G3D, "g3d", "div_aclk_200", GATE_IP_G3D, 0, 0, 0),
+
+ /* GATE_IP_LCD */
+ GATE(CLK_QE_CH1_LCD, "qe_ch1_lcd", "div_aclk_160", GATE_IP_LCD, 7,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_QE_CH0_LCD, "qe_ch0_lcd", "div_aclk_160", GATE_IP_LCD, 6,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_PPMULCD0, "ppmulcd0", "div_aclk_160", GATE_IP_LCD, 5,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_SMMUFIMD0, "smmufimd0", "div_aclk_160", GATE_IP_LCD, 4, 0, 0),
+ GATE(CLK_DSIM0, "dsim0", "div_aclk_160", GATE_IP_LCD, 3, 0, 0),
+ GATE(CLK_SMIES, "smies", "div_aclk_160", GATE_IP_LCD, 2, 0, 0),
+ GATE(CLK_FIMD0, "fimd0", "div_aclk_160", GATE_IP_LCD, 0, 0, 0),
+
+ /* GATE_IP_ISP */
+ GATE(CLK_CAM1, "cam1", "mout_aclk_266_sub", GATE_IP_ISP, 5, 0, 0),
+ GATE(CLK_UART_ISP_TOP, "uart_isp_top", "mout_aclk_266_sub",
+ GATE_IP_ISP, 3, 0, 0),
+ GATE(CLK_SPI1_ISP_TOP, "spi1_isp_top", "mout_aclk_266_sub",
+ GATE_IP_ISP, 2, 0, 0),
+ GATE(CLK_SPI0_ISP_TOP, "spi0_isp_top", "mout_aclk_266_sub",
+ GATE_IP_ISP, 1, 0, 0),
+
+ /* GATE_IP_FSYS */
+ GATE(CLK_TSADC, "tsadc", "div_aclk_200", GATE_IP_FSYS, 20, 0, 0),
+ GATE(CLK_PPMUFILE, "ppmufile", "div_aclk_200", GATE_IP_FSYS, 17,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_USBOTG, "usbotg", "div_aclk_200", GATE_IP_FSYS, 13, 0, 0),
+ GATE(CLK_USBHOST, "usbhost", "div_aclk_200", GATE_IP_FSYS, 12, 0, 0),
+ GATE(CLK_SROMC, "sromc", "div_aclk_200", GATE_IP_FSYS, 11, 0, 0),
+ GATE(CLK_SDMMC1, "sdmmc1", "div_aclk_200", GATE_IP_FSYS, 6, 0, 0),
+ GATE(CLK_SDMMC0, "sdmmc0", "div_aclk_200", GATE_IP_FSYS, 5, 0, 0),
+ GATE(CLK_PDMA1, "pdma1", "div_aclk_200", GATE_IP_FSYS, 1, 0, 0),
+ GATE(CLK_PDMA0, "pdma0", "div_aclk_200", GATE_IP_FSYS, 0, 0, 0),
+
+ /* GATE_IP_PERIL */
+ GATE(CLK_PWM, "pwm", "div_aclk_100", GATE_IP_PERIL, 24, 0, 0),
+ GATE(CLK_PCM, "pcm", "div_aclk_100", GATE_IP_PERIL, 23, 0, 0),
+ GATE(CLK_I2S, "i2s", "div_aclk_100", GATE_IP_PERIL, 21, 0, 0),
+ GATE(CLK_SPI1, "spi1", "div_aclk_100", GATE_IP_PERIL, 17, 0, 0),
+ GATE(CLK_SPI0, "spi0", "div_aclk_100", GATE_IP_PERIL, 16, 0, 0),
+ GATE(CLK_I2C7, "i2c7", "div_aclk_100", GATE_IP_PERIL, 13, 0, 0),
+ GATE(CLK_I2C6, "i2c6", "div_aclk_100", GATE_IP_PERIL, 12, 0, 0),
+ GATE(CLK_I2C5, "i2c5", "div_aclk_100", GATE_IP_PERIL, 11, 0, 0),
+ GATE(CLK_I2C4, "i2c4", "div_aclk_100", GATE_IP_PERIL, 10, 0, 0),
+ GATE(CLK_I2C3, "i2c3", "div_aclk_100", GATE_IP_PERIL, 9, 0, 0),
+ GATE(CLK_I2C2, "i2c2", "div_aclk_100", GATE_IP_PERIL, 8, 0, 0),
+ GATE(CLK_I2C1, "i2c1", "div_aclk_100", GATE_IP_PERIL, 7, 0, 0),
+ GATE(CLK_I2C0, "i2c0", "div_aclk_100", GATE_IP_PERIL, 6, 0, 0),
+ GATE(CLK_UART1, "uart1", "div_aclk_100", GATE_IP_PERIL, 1, 0, 0),
+ GATE(CLK_UART0, "uart0", "div_aclk_100", GATE_IP_PERIL, 0, 0, 0),
+};
+
+/* APLL & MPLL & BPLL & UPLL */
+static struct samsung_pll_rate_table exynos3250_pll_rates[] = {
+ PLL_35XX_RATE(1200000000, 400, 4, 1),
+ PLL_35XX_RATE(1100000000, 275, 3, 1),
+ PLL_35XX_RATE(1066000000, 533, 6, 1),
+ PLL_35XX_RATE(1000000000, 250, 3, 1),
+ PLL_35XX_RATE( 960000000, 320, 4, 1),
+ PLL_35XX_RATE( 900000000, 300, 4, 1),
+ PLL_35XX_RATE( 850000000, 425, 6, 1),
+ PLL_35XX_RATE( 800000000, 200, 3, 1),
+ PLL_35XX_RATE( 700000000, 175, 3, 1),
+ PLL_35XX_RATE( 667000000, 667, 12, 1),
+ PLL_35XX_RATE( 600000000, 400, 4, 2),
+ PLL_35XX_RATE( 533000000, 533, 6, 2),
+ PLL_35XX_RATE( 520000000, 260, 3, 2),
+ PLL_35XX_RATE( 500000000, 250, 3, 2),
+ PLL_35XX_RATE( 400000000, 200, 3, 2),
+ PLL_35XX_RATE( 200000000, 200, 3, 3),
+ PLL_35XX_RATE( 100000000, 200, 3, 4),
+ { /* sentinel */ }
+};
+
+/* VPLL */
+static struct samsung_pll_rate_table exynos3250_vpll_rates[] = {
+ PLL_36XX_RATE(600000000, 100, 2, 1, 0),
+ PLL_36XX_RATE(533000000, 266, 3, 2, 32768),
+ PLL_36XX_RATE(519230987, 173, 2, 2, 5046),
+ PLL_36XX_RATE(500000000, 250, 3, 2, 0),
+ PLL_36XX_RATE(445500000, 148, 2, 2, 32768),
+ PLL_36XX_RATE(445055007, 148, 2, 2, 23047),
+ PLL_36XX_RATE(400000000, 200, 3, 2, 0),
+ PLL_36XX_RATE(371250000, 123, 2, 2, 49152),
+ PLL_36XX_RATE(370878997, 185, 3, 2, 28803),
+ PLL_36XX_RATE(340000000, 170, 3, 2, 0),
+ PLL_36XX_RATE(335000015, 111, 2, 2, 43691),
+ PLL_36XX_RATE(333000000, 111, 2, 2, 0),
+ PLL_36XX_RATE(330000000, 110, 2, 2, 0),
+ PLL_36XX_RATE(320000015, 106, 2, 2, 43691),
+ PLL_36XX_RATE(300000000, 100, 2, 2, 0),
+ PLL_36XX_RATE(275000000, 275, 3, 3, 0),
+ PLL_36XX_RATE(222750000, 148, 2, 3, 32768),
+ PLL_36XX_RATE(222528007, 148, 2, 3, 23069),
+ PLL_36XX_RATE(160000000, 160, 3, 3, 0),
+ PLL_36XX_RATE(148500000, 99, 2, 3, 0),
+ PLL_36XX_RATE(148352005, 98, 2, 3, 59070),
+ PLL_36XX_RATE(108000000, 144, 2, 4, 0),
+ PLL_36XX_RATE( 74250000, 99, 2, 4, 0),
+ PLL_36XX_RATE( 74176002, 98, 3, 4, 59070),
+ PLL_36XX_RATE( 54054000, 216, 3, 5, 14156),
+ PLL_36XX_RATE( 54000000, 144, 2, 5, 0),
+ { /* sentinel */ }
+};
+
+static struct samsung_pll_clock exynos3250_plls[nr_plls] __initdata = {
+ [apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
+ APLL_LOCK, APLL_CON0, NULL),
+ [mpll] = PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll",
+ MPLL_LOCK, MPLL_CON0, NULL),
+ [vpll] = PLL(pll_36xx, CLK_FOUT_VPLL, "fout_vpll", "fin_pll",
+ VPLL_LOCK, VPLL_CON0, NULL),
+ [upll] = PLL(pll_35xx, CLK_FOUT_UPLL, "fout_upll", "fin_pll",
+ UPLL_LOCK, UPLL_CON0, NULL),
+};
+
+static void __init exynos3250_cmu_init(struct device_node *np)
+{
+ struct samsung_clk_provider *ctx;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base)
+ panic("%s: failed to map registers\n", __func__);
+
+ ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
+ if (!ctx)
+ panic("%s: unable to allocate context.\n", __func__);
+
+ samsung_clk_register_fixed_factor(ctx, fixed_factor_clks,
+ ARRAY_SIZE(fixed_factor_clks));
+
+ exynos3250_plls[apll].rate_table = exynos3250_pll_rates;
+ exynos3250_plls[mpll].rate_table = exynos3250_pll_rates;
+ exynos3250_plls[vpll].rate_table = exynos3250_vpll_rates;
+ exynos3250_plls[upll].rate_table = exynos3250_pll_rates;
+
+ samsung_clk_register_pll(ctx, exynos3250_plls,
+ ARRAY_SIZE(exynos3250_plls), reg_base);
+
+ samsung_clk_register_mux(ctx, mux_clks, ARRAY_SIZE(mux_clks));
+ samsung_clk_register_div(ctx, div_clks, ARRAY_SIZE(div_clks));
+ samsung_clk_register_gate(ctx, gate_clks, ARRAY_SIZE(gate_clks));
+
+ exynos3250_clk_sleep_init();
+}
+CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init);
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index b4f967210175..7f4a473a7ad7 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -324,7 +324,7 @@ static struct syscore_ops exynos4_clk_syscore_ops = {
.resume = exynos4_clk_resume,
};
-static void exynos4_clk_sleep_init(void)
+static void __init exynos4_clk_sleep_init(void)
{
exynos4_save_common = samsung_clk_alloc_reg_dump(exynos4_clk_regs,
ARRAY_SIZE(exynos4_clk_regs));
@@ -359,7 +359,7 @@ err_warn:
__func__);
}
#else
-static void exynos4_clk_sleep_init(void) {}
+static void __init exynos4_clk_sleep_init(void) {}
#endif
/* list of all parent clock list */
@@ -428,7 +428,7 @@ static struct samsung_fixed_rate_clock exynos4_fixed_rate_ext_clks[] __initdata
/* fixed rate clocks generated inside the soc */
static struct samsung_fixed_rate_clock exynos4_fixed_rate_clks[] __initdata = {
FRATE(0, "sclk_hdmi24m", NULL, CLK_IS_ROOT, 24000000),
- FRATE(0, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 27000000),
+ FRATE(CLK_SCLK_HDMIPHY, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 27000000),
FRATE(0, "sclk_usbphy0", NULL, CLK_IS_ROOT, 48000000),
};
@@ -903,7 +903,7 @@ static struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
GATE(CLK_AUDSS, "audss", "sclk_epll", E4X12_GATE_IP_MAUDIO, 0, 0, 0),
GATE(CLK_MDNIE0, "mdnie0", "aclk160", GATE_IP_LCD0, 2, 0, 0),
GATE(CLK_ROTATOR, "rotator", "aclk200", E4X12_GATE_IP_IMAGE, 1, 0, 0),
- GATE(CLK_MDMA2, "mdma2", "aclk200", E4X12_GATE_IP_IMAGE, 2, 0, 0),
+ GATE(CLK_MDMA, "mdma", "aclk200", E4X12_GATE_IP_IMAGE, 2, 0, 0),
GATE(CLK_SMMU_MDMA, "smmu_mdma", "aclk200", E4X12_GATE_IP_IMAGE, 5, 0,
0),
GATE(CLK_MIPI_HSI, "mipi_hsi", "aclk133", GATE_IP_FSYS, 10, 0, 0),
@@ -925,21 +925,13 @@ static struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
GATE(CLK_RTC, "rtc", "aclk100", E4X12_GATE_IP_PERIR, 15,
0, 0),
GATE(CLK_KEYIF, "keyif", "aclk100", E4X12_GATE_IP_PERIR, 16, 0, 0),
- GATE(CLK_SCLK_PWM_ISP, "sclk_pwm_isp", "div_pwm_isp",
- E4X12_SRC_MASK_ISP, 0, CLK_SET_RATE_PARENT, 0),
- GATE(CLK_SCLK_SPI0_ISP, "sclk_spi0_isp", "div_spi0_isp_pre",
- E4X12_SRC_MASK_ISP, 4, CLK_SET_RATE_PARENT, 0),
- GATE(CLK_SCLK_SPI1_ISP, "sclk_spi1_isp", "div_spi1_isp_pre",
- E4X12_SRC_MASK_ISP, 8, CLK_SET_RATE_PARENT, 0),
- GATE(CLK_SCLK_UART_ISP, "sclk_uart_isp", "div_uart_isp",
- E4X12_SRC_MASK_ISP, 12, CLK_SET_RATE_PARENT, 0),
- GATE(CLK_PWM_ISP_SCLK, "pwm_isp_sclk", "sclk_pwm_isp",
+ GATE(CLK_PWM_ISP_SCLK, "pwm_isp_sclk", "div_pwm_isp",
E4X12_GATE_IP_ISP, 0, 0, 0),
- GATE(CLK_SPI0_ISP_SCLK, "spi0_isp_sclk", "sclk_spi0_isp",
+ GATE(CLK_SPI0_ISP_SCLK, "spi0_isp_sclk", "div_spi0_isp_pre",
E4X12_GATE_IP_ISP, 1, 0, 0),
- GATE(CLK_SPI1_ISP_SCLK, "spi1_isp_sclk", "sclk_spi1_isp",
+ GATE(CLK_SPI1_ISP_SCLK, "spi1_isp_sclk", "div_spi1_isp_pre",
E4X12_GATE_IP_ISP, 2, 0, 0),
- GATE(CLK_UART_ISP_SCLK, "uart_isp_sclk", "sclk_uart_isp",
+ GATE(CLK_UART_ISP_SCLK, "uart_isp_sclk", "div_uart_isp",
E4X12_GATE_IP_ISP, 3, 0, 0),
GATE(CLK_WDT, "watchdog", "aclk100", E4X12_GATE_IP_PERIR, 14, 0, 0),
GATE(CLK_PCM0, "pcm0", "aclk100", E4X12_GATE_IP_MAUDIO, 2,
@@ -1043,7 +1035,7 @@ static unsigned long exynos4_get_xom(void)
return xom;
}
-static void __init exynos4_clk_register_finpll(void)
+static void __init exynos4_clk_register_finpll(struct samsung_clk_provider *ctx)
{
struct samsung_fixed_rate_clock fclk;
struct clk *clk;
@@ -1066,7 +1058,7 @@ static void __init exynos4_clk_register_finpll(void)
fclk.parent_name = NULL;
fclk.flags = CLK_IS_ROOT;
fclk.fixed_rate = finpll_f;
- samsung_clk_register_fixed_rate(&fclk, 1);
+ samsung_clk_register_fixed_rate(ctx, &fclk, 1);
}
@@ -1176,22 +1168,25 @@ static struct samsung_pll_clock exynos4x12_plls[nr_plls] __initdata = {
static void __init exynos4_clk_init(struct device_node *np,
enum exynos4_soc soc)
{
+ struct samsung_clk_provider *ctx;
exynos4_soc = soc;
reg_base = of_iomap(np, 0);
if (!reg_base)
panic("%s: failed to map registers\n", __func__);
- samsung_clk_init(np, reg_base, CLK_NR_CLKS);
+ ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
+ if (!ctx)
+ panic("%s: unable to allocate context.\n", __func__);
- samsung_clk_of_register_fixed_ext(exynos4_fixed_rate_ext_clks,
+ samsung_clk_of_register_fixed_ext(ctx, exynos4_fixed_rate_ext_clks,
ARRAY_SIZE(exynos4_fixed_rate_ext_clks),
ext_clk_match);
- exynos4_clk_register_finpll();
+ exynos4_clk_register_finpll(ctx);
if (exynos4_soc == EXYNOS4210) {
- samsung_clk_register_mux(exynos4210_mux_early,
+ samsung_clk_register_mux(ctx, exynos4210_mux_early,
ARRAY_SIZE(exynos4210_mux_early));
if (_get_rate("fin_pll") == 24000000) {
@@ -1205,7 +1200,7 @@ static void __init exynos4_clk_init(struct device_node *np,
exynos4210_plls[vpll].rate_table =
exynos4210_vpll_rates;
- samsung_clk_register_pll(exynos4210_plls,
+ samsung_clk_register_pll(ctx, exynos4210_plls,
ARRAY_SIZE(exynos4210_plls), reg_base);
} else {
if (_get_rate("fin_pll") == 24000000) {
@@ -1217,42 +1212,42 @@ static void __init exynos4_clk_init(struct device_node *np,
exynos4x12_vpll_rates;
}
- samsung_clk_register_pll(exynos4x12_plls,
+ samsung_clk_register_pll(ctx, exynos4x12_plls,
ARRAY_SIZE(exynos4x12_plls), reg_base);
}
- samsung_clk_register_fixed_rate(exynos4_fixed_rate_clks,
+ samsung_clk_register_fixed_rate(ctx, exynos4_fixed_rate_clks,
ARRAY_SIZE(exynos4_fixed_rate_clks));
- samsung_clk_register_mux(exynos4_mux_clks,
+ samsung_clk_register_mux(ctx, exynos4_mux_clks,
ARRAY_SIZE(exynos4_mux_clks));
- samsung_clk_register_div(exynos4_div_clks,
+ samsung_clk_register_div(ctx, exynos4_div_clks,
ARRAY_SIZE(exynos4_div_clks));
- samsung_clk_register_gate(exynos4_gate_clks,
+ samsung_clk_register_gate(ctx, exynos4_gate_clks,
ARRAY_SIZE(exynos4_gate_clks));
if (exynos4_soc == EXYNOS4210) {
- samsung_clk_register_fixed_rate(exynos4210_fixed_rate_clks,
+ samsung_clk_register_fixed_rate(ctx, exynos4210_fixed_rate_clks,
ARRAY_SIZE(exynos4210_fixed_rate_clks));
- samsung_clk_register_mux(exynos4210_mux_clks,
+ samsung_clk_register_mux(ctx, exynos4210_mux_clks,
ARRAY_SIZE(exynos4210_mux_clks));
- samsung_clk_register_div(exynos4210_div_clks,
+ samsung_clk_register_div(ctx, exynos4210_div_clks,
ARRAY_SIZE(exynos4210_div_clks));
- samsung_clk_register_gate(exynos4210_gate_clks,
+ samsung_clk_register_gate(ctx, exynos4210_gate_clks,
ARRAY_SIZE(exynos4210_gate_clks));
- samsung_clk_register_alias(exynos4210_aliases,
+ samsung_clk_register_alias(ctx, exynos4210_aliases,
ARRAY_SIZE(exynos4210_aliases));
} else {
- samsung_clk_register_mux(exynos4x12_mux_clks,
+ samsung_clk_register_mux(ctx, exynos4x12_mux_clks,
ARRAY_SIZE(exynos4x12_mux_clks));
- samsung_clk_register_div(exynos4x12_div_clks,
+ samsung_clk_register_div(ctx, exynos4x12_div_clks,
ARRAY_SIZE(exynos4x12_div_clks));
- samsung_clk_register_gate(exynos4x12_gate_clks,
+ samsung_clk_register_gate(ctx, exynos4x12_gate_clks,
ARRAY_SIZE(exynos4x12_gate_clks));
- samsung_clk_register_alias(exynos4x12_aliases,
+ samsung_clk_register_alias(ctx, exynos4x12_aliases,
ARRAY_SIZE(exynos4x12_aliases));
}
- samsung_clk_register_alias(exynos4_aliases,
+ samsung_clk_register_alias(ctx, exynos4_aliases,
ARRAY_SIZE(exynos4_aliases));
exynos4_clk_sleep_init();
diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c
index e7ee4420da81..184f64293b26 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -24,10 +24,14 @@
#define APLL_CON0 0x100
#define SRC_CPU 0x200
#define DIV_CPU0 0x500
+#define PWR_CTRL1 0x1020
+#define PWR_CTRL2 0x1024
#define MPLL_LOCK 0x4000
#define MPLL_CON0 0x4100
#define SRC_CORE1 0x4204
#define GATE_IP_ACP 0x8800
+#define GATE_IP_ISP0 0xc800
+#define GATE_IP_ISP1 0xc804
#define CPLL_LOCK 0x10020
#define EPLL_LOCK 0x10030
#define VPLL_LOCK 0x10040
@@ -37,6 +41,7 @@
#define VPLL_CON0 0x10140
#define GPLL_CON0 0x10150
#define SRC_TOP0 0x10210
+#define SRC_TOP1 0x10214
#define SRC_TOP2 0x10218
#define SRC_TOP3 0x1021c
#define SRC_GSCL 0x10220
@@ -71,6 +76,7 @@
#define GATE_IP_GSCL 0x10920
#define GATE_IP_DISP1 0x10928
#define GATE_IP_MFC 0x1092c
+#define GATE_IP_G3D 0x10930
#define GATE_IP_GEN 0x10934
#define GATE_IP_FSYS 0x10944
#define GATE_IP_PERIC 0x10950
@@ -80,6 +86,23 @@
#define SRC_CDREX 0x20200
#define PLL_DIV2_SEL 0x20a24
+/*Below definitions are used for PWR_CTRL settings*/
+#define PWR_CTRL1_CORE2_DOWN_RATIO (7 << 28)
+#define PWR_CTRL1_CORE1_DOWN_RATIO (7 << 16)
+#define PWR_CTRL1_DIV2_DOWN_EN (1 << 9)
+#define PWR_CTRL1_DIV1_DOWN_EN (1 << 8)
+#define PWR_CTRL1_USE_CORE1_WFE (1 << 5)
+#define PWR_CTRL1_USE_CORE0_WFE (1 << 4)
+#define PWR_CTRL1_USE_CORE1_WFI (1 << 1)
+#define PWR_CTRL1_USE_CORE0_WFI (1 << 0)
+
+#define PWR_CTRL2_DIV2_UP_EN (1 << 25)
+#define PWR_CTRL2_DIV1_UP_EN (1 << 24)
+#define PWR_CTRL2_DUR_STANDBY2_VAL (1 << 16)
+#define PWR_CTRL2_DUR_STANDBY1_VAL (1 << 8)
+#define PWR_CTRL2_CORE2_UP_RATIO (1 << 4)
+#define PWR_CTRL2_CORE1_UP_RATIO (1 << 0)
+
/* list of PLLs to be registered */
enum exynos5250_plls {
apll, mpll, cpll, epll, vpll, gpll, bpll,
@@ -98,8 +121,11 @@ static struct samsung_clk_reg_dump *exynos5250_save;
static unsigned long exynos5250_clk_regs[] __initdata = {
SRC_CPU,
DIV_CPU0,
+ PWR_CTRL1,
+ PWR_CTRL2,
SRC_CORE1,
SRC_TOP0,
+ SRC_TOP1,
SRC_TOP2,
SRC_TOP3,
SRC_GSCL,
@@ -133,6 +159,7 @@ static unsigned long exynos5250_clk_regs[] __initdata = {
DIV_PERIC5,
GATE_IP_GSCL,
GATE_IP_MFC,
+ GATE_IP_G3D,
GATE_IP_GEN,
GATE_IP_FSYS,
GATE_IP_PERIC,
@@ -141,6 +168,8 @@ static unsigned long exynos5250_clk_regs[] __initdata = {
PLL_DIV2_SEL,
GATE_IP_DISP1,
GATE_IP_ACP,
+ GATE_IP_ISP0,
+ GATE_IP_ISP1,
};
static int exynos5250_clk_suspend(void)
@@ -189,13 +218,16 @@ PNAME(mout_vpllsrc_p) = { "fin_pll", "sclk_hdmi27m" };
PNAME(mout_vpll_p) = { "mout_vpllsrc", "fout_vpll" };
PNAME(mout_cpll_p) = { "fin_pll", "fout_cpll" };
PNAME(mout_epll_p) = { "fin_pll", "fout_epll" };
+PNAME(mout_gpll_p) = { "fin_pll", "fout_gpll" };
PNAME(mout_mpll_user_p) = { "fin_pll", "mout_mpll" };
PNAME(mout_bpll_user_p) = { "fin_pll", "mout_bpll" };
PNAME(mout_aclk166_p) = { "mout_cpll", "mout_mpll_user" };
PNAME(mout_aclk200_p) = { "mout_mpll_user", "mout_bpll_user" };
+PNAME(mout_aclk400_p) = { "mout_aclk400_g3d_mid", "mout_gpll" };
PNAME(mout_aclk200_sub_p) = { "fin_pll", "div_aclk200" };
PNAME(mout_aclk266_sub_p) = { "fin_pll", "div_aclk266" };
PNAME(mout_aclk333_sub_p) = { "fin_pll", "div_aclk333" };
+PNAME(mout_aclk400_isp_sub_p) = { "fin_pll", "div_aclk400_isp" };
PNAME(mout_hdmi_p) = { "div_hdmi_pixel", "sclk_hdmiphy" };
PNAME(mout_usb3_p) = { "mout_mpll_user", "mout_cpll" };
PNAME(mout_group1_p) = { "fin_pll", "fin_pll", "sclk_hdmi27m",
@@ -273,15 +305,23 @@ static struct samsung_mux_clock exynos5250_mux_clks[] __initdata = {
MUX(0, "mout_aclk166", mout_aclk166_p, SRC_TOP0, 8, 1),
MUX(0, "mout_aclk200", mout_aclk200_p, SRC_TOP0, 12, 1),
MUX(0, "mout_aclk333", mout_aclk166_p, SRC_TOP0, 16, 1),
+ MUX(0, "mout_aclk400_g3d_mid", mout_aclk200_p, SRC_TOP0, 20, 1),
+
+ MUX(0, "mout_aclk400_isp", mout_aclk200_p, SRC_TOP1, 24, 1),
+ MUX(0, "mout_aclk400_g3d", mout_aclk400_p, SRC_TOP1, 28, 1),
MUX(0, "mout_cpll", mout_cpll_p, SRC_TOP2, 8, 1),
MUX(0, "mout_epll", mout_epll_p, SRC_TOP2, 12, 1),
MUX(0, "mout_vpll", mout_vpll_p, SRC_TOP2, 16, 1),
MUX(0, "mout_mpll_user", mout_mpll_user_p, SRC_TOP2, 20, 1),
MUX(0, "mout_bpll_user", mout_bpll_user_p, SRC_TOP2, 24, 1),
+ MUX(CLK_MOUT_GPLL, "mout_gpll", mout_gpll_p, SRC_TOP2, 28, 1),
MUX(0, "mout_aclk200_disp1_sub", mout_aclk200_sub_p, SRC_TOP3, 4, 1),
MUX(0, "mout_aclk266_gscl_sub", mout_aclk266_sub_p, SRC_TOP3, 8, 1),
+ MUX(0, "mout_aclk_266_isp_sub", mout_aclk266_sub_p, SRC_TOP3, 16, 1),
+ MUX(0, "mout_aclk_400_isp_sub", mout_aclk400_isp_sub_p,
+ SRC_TOP3, 20, 1),
MUX(0, "mout_aclk333_sub", mout_aclk333_sub_p, SRC_TOP3, 24, 1),
MUX(0, "mout_cam_bayer", mout_group1_p, SRC_GSCL, 12, 4),
@@ -351,7 +391,10 @@ static struct samsung_div_clock exynos5250_div_clks[] __initdata = {
DIV(0, "div_aclk200", "mout_aclk200", DIV_TOP0, 12, 3),
DIV(0, "div_aclk266", "mout_mpll_user", DIV_TOP0, 16, 3),
DIV(0, "div_aclk333", "mout_aclk333", DIV_TOP0, 20, 3),
+ DIV(0, "div_aclk400_g3d", "mout_aclk400_g3d", DIV_TOP0,
+ 24, 3),
+ DIV(0, "div_aclk400_isp", "mout_aclk400_isp", DIV_TOP1, 20, 3),
DIV(0, "div_aclk66_pre", "mout_mpll_user", DIV_TOP1, 24, 3),
DIV(0, "div_cam_bayer", "mout_cam_bayer", DIV_GSCL, 12, 4),
@@ -428,6 +471,7 @@ static struct samsung_gate_clock exynos5250_gate_clks[] __initdata = {
* CMU_ACP
*/
GATE(CLK_MDMA0, "mdma0", "div_aclk266", GATE_IP_ACP, 1, 0, 0),
+ GATE(CLK_SSS, "sss", "div_aclk266", GATE_IP_ACP, 2, 0, 0),
GATE(CLK_G2D, "g2d", "div_aclk200", GATE_IP_ACP, 3, 0, 0),
GATE(CLK_SMMU_MDMA0, "smmu_mdma0", "div_aclk266", GATE_IP_ACP, 5, 0, 0),
@@ -533,7 +577,8 @@ static struct samsung_gate_clock exynos5250_gate_clks[] __initdata = {
0),
GATE(CLK_SMMU_MFCL, "smmu_mfcl", "mout_aclk333_sub", GATE_IP_MFC, 2, 0,
0),
-
+ GATE(CLK_G3D, "g3d", "div_aclk400_g3d", GATE_IP_G3D, 0,
+ CLK_SET_RATE_PARENT, 0),
GATE(CLK_ROTATOR, "rotator", "div_aclk266", GATE_IP_GEN, 1, 0, 0),
GATE(CLK_JPEG, "jpeg", "div_aclk166", GATE_IP_GEN, 2, 0, 0),
GATE(CLK_MDMA1, "mdma1", "div_aclk266", GATE_IP_GEN, 4, 0, 0),
@@ -615,6 +660,31 @@ static struct samsung_gate_clock exynos5250_gate_clks[] __initdata = {
GATE(CLK_WDT, "wdt", "div_aclk66", GATE_IP_PERIS, 19, 0, 0),
GATE(CLK_RTC, "rtc", "div_aclk66", GATE_IP_PERIS, 20, 0, 0),
GATE(CLK_TMU, "tmu", "div_aclk66", GATE_IP_PERIS, 21, 0, 0),
+ GATE(CLK_SMMU_TV, "smmu_tv", "mout_aclk200_disp1_sub",
+ GATE_IP_DISP1, 9, 0, 0),
+ GATE(CLK_SMMU_FIMD1, "smmu_fimd1", "mout_aclk200_disp1_sub",
+ GATE_IP_DISP1, 8, 0, 0),
+ GATE(CLK_SMMU_2D, "smmu_2d", "div_aclk200", GATE_IP_ACP, 7, 0, 0),
+ GATE(CLK_SMMU_FIMC_ISP, "smmu_fimc_isp", "mout_aclk_266_isp_sub",
+ GATE_IP_ISP0, 8, 0, 0),
+ GATE(CLK_SMMU_FIMC_DRC, "smmu_fimc_drc", "mout_aclk_266_isp_sub",
+ GATE_IP_ISP0, 9, 0, 0),
+ GATE(CLK_SMMU_FIMC_FD, "smmu_fimc_fd", "mout_aclk_266_isp_sub",
+ GATE_IP_ISP0, 10, 0, 0),
+ GATE(CLK_SMMU_FIMC_SCC, "smmu_fimc_scc", "mout_aclk_266_isp_sub",
+ GATE_IP_ISP0, 11, 0, 0),
+ GATE(CLK_SMMU_FIMC_SCP, "smmu_fimc_scp", "mout_aclk_266_isp_sub",
+ GATE_IP_ISP0, 12, 0, 0),
+ GATE(CLK_SMMU_FIMC_MCU, "smmu_fimc_mcu", "mout_aclk_400_isp_sub",
+ GATE_IP_ISP0, 13, 0, 0),
+ GATE(CLK_SMMU_FIMC_ODC, "smmu_fimc_odc", "mout_aclk_266_isp_sub",
+ GATE_IP_ISP1, 4, 0, 0),
+ GATE(CLK_SMMU_FIMC_DIS0, "smmu_fimc_dis0", "mout_aclk_266_isp_sub",
+ GATE_IP_ISP1, 5, 0, 0),
+ GATE(CLK_SMMU_FIMC_DIS1, "smmu_fimc_dis1", "mout_aclk_266_isp_sub",
+ GATE_IP_ISP1, 6, 0, 0),
+ GATE(CLK_SMMU_FIMC_3DNR, "smmu_fimc_3dnr", "mout_aclk_266_isp_sub",
+ GATE_IP_ISP1, 7, 0, 0),
};
static struct samsung_pll_rate_table vpll_24mhz_tbl[] __initdata = {
@@ -686,6 +756,9 @@ static struct of_device_id ext_clk_match[] __initdata = {
/* register exynox5250 clocks */
static void __init exynos5250_clk_init(struct device_node *np)
{
+ struct samsung_clk_provider *ctx;
+ unsigned int tmp;
+
if (np) {
reg_base = of_iomap(np, 0);
if (!reg_base)
@@ -694,11 +767,13 @@ static void __init exynos5250_clk_init(struct device_node *np)
panic("%s: unable to determine soc\n", __func__);
}
- samsung_clk_init(np, reg_base, CLK_NR_CLKS);
- samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks,
+ ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
+ if (!ctx)
+ panic("%s: unable to allocate context.\n", __func__);
+ samsung_clk_of_register_fixed_ext(ctx, exynos5250_fixed_rate_ext_clks,
ARRAY_SIZE(exynos5250_fixed_rate_ext_clks),
ext_clk_match);
- samsung_clk_register_mux(exynos5250_pll_pmux_clks,
+ samsung_clk_register_mux(ctx, exynos5250_pll_pmux_clks,
ARRAY_SIZE(exynos5250_pll_pmux_clks));
if (_get_rate("fin_pll") == 24 * MHZ) {
@@ -709,19 +784,40 @@ static void __init exynos5250_clk_init(struct device_node *np)
if (_get_rate("mout_vpllsrc") == 24 * MHZ)
exynos5250_plls[vpll].rate_table = vpll_24mhz_tbl;
- samsung_clk_register_pll(exynos5250_plls, ARRAY_SIZE(exynos5250_plls),
- reg_base);
- samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks,
+ samsung_clk_register_pll(ctx, exynos5250_plls,
+ ARRAY_SIZE(exynos5250_plls),
+ reg_base);
+ samsung_clk_register_fixed_rate(ctx, exynos5250_fixed_rate_clks,
ARRAY_SIZE(exynos5250_fixed_rate_clks));
- samsung_clk_register_fixed_factor(exynos5250_fixed_factor_clks,
+ samsung_clk_register_fixed_factor(ctx, exynos5250_fixed_factor_clks,
ARRAY_SIZE(exynos5250_fixed_factor_clks));
- samsung_clk_register_mux(exynos5250_mux_clks,
+ samsung_clk_register_mux(ctx, exynos5250_mux_clks,
ARRAY_SIZE(exynos5250_mux_clks));
- samsung_clk_register_div(exynos5250_div_clks,
+ samsung_clk_register_div(ctx, exynos5250_div_clks,
ARRAY_SIZE(exynos5250_div_clks));
- samsung_clk_register_gate(exynos5250_gate_clks,
+ samsung_clk_register_gate(ctx, exynos5250_gate_clks,
ARRAY_SIZE(exynos5250_gate_clks));
+ /*
+ * Enable arm clock down (in idle) and set arm divider
+ * ratios in WFI/WFE state.
+ */
+ tmp = (PWR_CTRL1_CORE2_DOWN_RATIO | PWR_CTRL1_CORE1_DOWN_RATIO |
+ PWR_CTRL1_DIV2_DOWN_EN | PWR_CTRL1_DIV1_DOWN_EN |
+ PWR_CTRL1_USE_CORE1_WFE | PWR_CTRL1_USE_CORE0_WFE |
+ PWR_CTRL1_USE_CORE1_WFI | PWR_CTRL1_USE_CORE0_WFI);
+ __raw_writel(tmp, reg_base + PWR_CTRL1);
+
+ /*
+ * Enable arm clock up (on exiting idle). Set arm divider
+ * ratios when not in idle along with the standby duration
+ * ratios.
+ */
+ tmp = (PWR_CTRL2_DIV2_UP_EN | PWR_CTRL2_DIV1_UP_EN |
+ PWR_CTRL2_DUR_STANDBY2_VAL | PWR_CTRL2_DUR_STANDBY1_VAL |
+ PWR_CTRL2_CORE2_UP_RATIO | PWR_CTRL2_CORE1_UP_RATIO);
+ __raw_writel(tmp, reg_base + PWR_CTRL2);
+
exynos5250_clk_sleep_init();
pr_info("Exynos5250: clock setup completed, armclk=%ld\n",
diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c
new file mode 100644
index 000000000000..64596ba58df1
--- /dev/null
+++ b/drivers/clk/samsung/clk-exynos5260.c
@@ -0,0 +1,1980 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Rahul Sharma <rahul.sharma@samsung.com>
+ *
+ * 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.
+ *
+ * Common Clock Framework support for Exynos5260 SoC.
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+
+#include "clk-exynos5260.h"
+#include "clk.h"
+#include "clk-pll.h"
+
+#include <dt-bindings/clock/exynos5260-clk.h>
+
+static LIST_HEAD(clock_reg_cache_list);
+
+struct exynos5260_clock_reg_cache {
+ struct list_head node;
+ void __iomem *reg_base;
+ struct samsung_clk_reg_dump *rdump;
+ unsigned int rd_num;
+};
+
+struct exynos5260_cmu_info {
+ /* list of pll clocks and respective count */
+ struct samsung_pll_clock *pll_clks;
+ unsigned int nr_pll_clks;
+ /* list of mux clocks and respective count */
+ struct samsung_mux_clock *mux_clks;
+ unsigned int nr_mux_clks;
+ /* list of div clocks and respective count */
+ struct samsung_div_clock *div_clks;
+ unsigned int nr_div_clks;
+ /* list of gate clocks and respective count */
+ struct samsung_gate_clock *gate_clks;
+ unsigned int nr_gate_clks;
+ /* list of fixed clocks and respective count */
+ struct samsung_fixed_rate_clock *fixed_clks;
+ unsigned int nr_fixed_clks;
+ /* total number of clocks with IDs assigned*/
+ unsigned int nr_clk_ids;
+
+ /* list and number of clocks registers */
+ unsigned long *clk_regs;
+ unsigned int nr_clk_regs;
+};
+
+/*
+ * Applicable for all 2550 Type PLLS for Exynos5260, listed below
+ * DISP_PLL, EGL_PLL, KFC_PLL, MEM_PLL, BUS_PLL, MEDIA_PLL, G3D_PLL.
+ */
+static struct samsung_pll_rate_table pll2550_24mhz_tbl[] __initdata = {
+ PLL_35XX_RATE(1700000000, 425, 6, 0),
+ PLL_35XX_RATE(1600000000, 200, 3, 0),
+ PLL_35XX_RATE(1500000000, 250, 4, 0),
+ PLL_35XX_RATE(1400000000, 175, 3, 0),
+ PLL_35XX_RATE(1300000000, 325, 6, 0),
+ PLL_35XX_RATE(1200000000, 400, 4, 1),
+ PLL_35XX_RATE(1100000000, 275, 3, 1),
+ PLL_35XX_RATE(1000000000, 250, 3, 1),
+ PLL_35XX_RATE(933000000, 311, 4, 1),
+ PLL_35XX_RATE(900000000, 300, 4, 1),
+ PLL_35XX_RATE(800000000, 200, 3, 1),
+ PLL_35XX_RATE(733000000, 733, 12, 1),
+ PLL_35XX_RATE(700000000, 175, 3, 1),
+ PLL_35XX_RATE(667000000, 667, 12, 1),
+ PLL_35XX_RATE(633000000, 211, 4, 1),
+ PLL_35XX_RATE(620000000, 310, 3, 2),
+ PLL_35XX_RATE(600000000, 400, 4, 2),
+ PLL_35XX_RATE(543000000, 362, 4, 2),
+ PLL_35XX_RATE(533000000, 533, 6, 2),
+ PLL_35XX_RATE(500000000, 250, 3, 2),
+ PLL_35XX_RATE(450000000, 300, 4, 2),
+ PLL_35XX_RATE(400000000, 200, 3, 2),
+ PLL_35XX_RATE(350000000, 175, 3, 2),
+ PLL_35XX_RATE(300000000, 400, 4, 3),
+ PLL_35XX_RATE(266000000, 266, 3, 3),
+ PLL_35XX_RATE(200000000, 200, 3, 3),
+ PLL_35XX_RATE(160000000, 160, 3, 3),
+};
+
+/*
+ * Applicable for 2650 Type PLL for AUD_PLL.
+ */
+static struct samsung_pll_rate_table pll2650_24mhz_tbl[] __initdata = {
+ PLL_36XX_RATE(1600000000, 200, 3, 0, 0),
+ PLL_36XX_RATE(1200000000, 100, 2, 0, 0),
+ PLL_36XX_RATE(1000000000, 250, 3, 1, 0),
+ PLL_36XX_RATE(800000000, 200, 3, 1, 0),
+ PLL_36XX_RATE(600000000, 100, 2, 1, 0),
+ PLL_36XX_RATE(532000000, 266, 3, 2, 0),
+ PLL_36XX_RATE(480000000, 160, 2, 2, 0),
+ PLL_36XX_RATE(432000000, 144, 2, 2, 0),
+ PLL_36XX_RATE(400000000, 200, 3, 2, 0),
+ PLL_36XX_RATE(394073130, 459, 7, 2, 49282),
+ PLL_36XX_RATE(333000000, 111, 2, 2, 0),
+ PLL_36XX_RATE(300000000, 100, 2, 2, 0),
+ PLL_36XX_RATE(266000000, 266, 3, 3, 0),
+ PLL_36XX_RATE(200000000, 200, 3, 3, 0),
+ PLL_36XX_RATE(166000000, 166, 3, 3, 0),
+ PLL_36XX_RATE(133000000, 266, 3, 4, 0),
+ PLL_36XX_RATE(100000000, 200, 3, 4, 0),
+ PLL_36XX_RATE(66000000, 176, 2, 5, 0),
+};
+
+#ifdef CONFIG_PM_SLEEP
+
+static int exynos5260_clk_suspend(void)
+{
+ struct exynos5260_clock_reg_cache *cache;
+
+ list_for_each_entry(cache, &clock_reg_cache_list, node)
+ samsung_clk_save(cache->reg_base, cache->rdump,
+ cache->rd_num);
+
+ return 0;
+}
+
+static void exynos5260_clk_resume(void)
+{
+ struct exynos5260_clock_reg_cache *cache;
+
+ list_for_each_entry(cache, &clock_reg_cache_list, node)
+ samsung_clk_restore(cache->reg_base, cache->rdump,
+ cache->rd_num);
+}
+
+static struct syscore_ops exynos5260_clk_syscore_ops = {
+ .suspend = exynos5260_clk_suspend,
+ .resume = exynos5260_clk_resume,
+};
+
+static void exynos5260_clk_sleep_init(void __iomem *reg_base,
+ unsigned long *rdump,
+ unsigned long nr_rdump)
+{
+ struct exynos5260_clock_reg_cache *reg_cache;
+
+ reg_cache = kzalloc(sizeof(struct exynos5260_clock_reg_cache),
+ GFP_KERNEL);
+ if (!reg_cache)
+ panic("could not allocate register cache.\n");
+
+ reg_cache->rdump = samsung_clk_alloc_reg_dump(rdump, nr_rdump);
+
+ if (!reg_cache->rdump)
+ panic("could not allocate register dump storage.\n");
+
+ if (list_empty(&clock_reg_cache_list))
+ register_syscore_ops(&exynos5260_clk_syscore_ops);
+
+ reg_cache->rd_num = nr_rdump;
+ reg_cache->reg_base = reg_base;
+ list_add_tail(&reg_cache->node, &clock_reg_cache_list);
+}
+
+#else
+static void exynos5260_clk_sleep_init(void __iomem *reg_base,
+ unsigned long *rdump,
+ unsigned long nr_rdump){}
+#endif
+
+/*
+ * Common function which registers plls, muxes, dividers and gates
+ * for each CMU. It also add CMU register list to register cache.
+ */
+
+void __init exynos5260_cmu_register_one(struct device_node *np,
+ struct exynos5260_cmu_info *cmu)
+{
+ void __iomem *reg_base;
+ struct samsung_clk_provider *ctx;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base)
+ panic("%s: failed to map registers\n", __func__);
+
+ ctx = samsung_clk_init(np, reg_base, cmu->nr_clk_ids);
+ if (!ctx)
+ panic("%s: unable to alllocate ctx\n", __func__);
+
+ if (cmu->pll_clks)
+ samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks,
+ reg_base);
+ if (cmu->mux_clks)
+ samsung_clk_register_mux(ctx, cmu->mux_clks,
+ cmu->nr_mux_clks);
+ if (cmu->div_clks)
+ samsung_clk_register_div(ctx, cmu->div_clks, cmu->nr_div_clks);
+ if (cmu->gate_clks)
+ samsung_clk_register_gate(ctx, cmu->gate_clks,
+ cmu->nr_gate_clks);
+ if (cmu->fixed_clks)
+ samsung_clk_register_fixed_rate(ctx, cmu->fixed_clks,
+ cmu->nr_fixed_clks);
+ if (cmu->clk_regs)
+ exynos5260_clk_sleep_init(reg_base, cmu->clk_regs,
+ cmu->nr_clk_regs);
+}
+
+
+/* CMU_AUD */
+
+static unsigned long aud_clk_regs[] __initdata = {
+ MUX_SEL_AUD,
+ DIV_AUD0,
+ DIV_AUD1,
+ EN_ACLK_AUD,
+ EN_PCLK_AUD,
+ EN_SCLK_AUD,
+ EN_IP_AUD,
+};
+
+PNAME(mout_aud_pll_user_p) = {"fin_pll", "fout_aud_pll"};
+PNAME(mout_sclk_aud_i2s_p) = {"mout_aud_pll_user", "ioclk_i2s_cdclk"};
+PNAME(mout_sclk_aud_pcm_p) = {"mout_aud_pll_user", "ioclk_pcm_extclk"};
+
+struct samsung_mux_clock aud_mux_clks[] __initdata = {
+ MUX(AUD_MOUT_AUD_PLL_USER, "mout_aud_pll_user", mout_aud_pll_user_p,
+ MUX_SEL_AUD, 0, 1),
+ MUX(AUD_MOUT_SCLK_AUD_I2S, "mout_sclk_aud_i2s", mout_sclk_aud_i2s_p,
+ MUX_SEL_AUD, 4, 1),
+ MUX(AUD_MOUT_SCLK_AUD_PCM, "mout_sclk_aud_pcm", mout_sclk_aud_pcm_p,
+ MUX_SEL_AUD, 8, 1),
+};
+
+struct samsung_div_clock aud_div_clks[] __initdata = {
+ DIV(AUD_DOUT_ACLK_AUD_131, "dout_aclk_aud_131", "mout_aud_pll_user",
+ DIV_AUD0, 0, 4),
+
+ DIV(AUD_DOUT_SCLK_AUD_I2S, "dout_sclk_aud_i2s", "mout_sclk_aud_i2s",
+ DIV_AUD1, 0, 4),
+ DIV(AUD_DOUT_SCLK_AUD_PCM, "dout_sclk_aud_pcm", "mout_sclk_aud_pcm",
+ DIV_AUD1, 4, 8),
+ DIV(AUD_DOUT_SCLK_AUD_UART, "dout_sclk_aud_uart", "mout_aud_pll_user",
+ DIV_AUD1, 12, 4),
+};
+
+struct samsung_gate_clock aud_gate_clks[] __initdata = {
+ GATE(AUD_SCLK_I2S, "sclk_aud_i2s", "dout_sclk_aud_i2s",
+ EN_SCLK_AUD, 0, CLK_SET_RATE_PARENT, 0),
+ GATE(AUD_SCLK_PCM, "sclk_aud_pcm", "dout_sclk_aud_pcm",
+ EN_SCLK_AUD, 1, CLK_SET_RATE_PARENT, 0),
+ GATE(AUD_SCLK_AUD_UART, "sclk_aud_uart", "dout_sclk_aud_uart",
+ EN_SCLK_AUD, 2, CLK_SET_RATE_PARENT, 0),
+
+ GATE(AUD_CLK_SRAMC, "clk_sramc", "dout_aclk_aud_131", EN_IP_AUD,
+ 0, 0, 0),
+ GATE(AUD_CLK_DMAC, "clk_dmac", "dout_aclk_aud_131",
+ EN_IP_AUD, 1, 0, 0),
+ GATE(AUD_CLK_I2S, "clk_i2s", "dout_aclk_aud_131", EN_IP_AUD, 2, 0, 0),
+ GATE(AUD_CLK_PCM, "clk_pcm", "dout_aclk_aud_131", EN_IP_AUD, 3, 0, 0),
+ GATE(AUD_CLK_AUD_UART, "clk_aud_uart", "dout_aclk_aud_131",
+ EN_IP_AUD, 4, 0, 0),
+};
+
+static void __init exynos5260_clk_aud_init(struct device_node *np)
+{
+ struct exynos5260_cmu_info cmu = {0};
+
+ cmu.mux_clks = aud_mux_clks;
+ cmu.nr_mux_clks = ARRAY_SIZE(aud_mux_clks);
+ cmu.div_clks = aud_div_clks;
+ cmu.nr_div_clks = ARRAY_SIZE(aud_div_clks);
+ cmu.gate_clks = aud_gate_clks;
+ cmu.nr_gate_clks = ARRAY_SIZE(aud_gate_clks);
+ cmu.nr_clk_ids = AUD_NR_CLK;
+ cmu.clk_regs = aud_clk_regs;
+ cmu.nr_clk_regs = ARRAY_SIZE(aud_clk_regs);
+
+ exynos5260_cmu_register_one(np, &cmu);
+}
+
+CLK_OF_DECLARE(exynos5260_clk_aud, "samsung,exynos5260-clock-aud",
+ exynos5260_clk_aud_init);
+
+
+/* CMU_DISP */
+
+static unsigned long disp_clk_regs[] __initdata = {
+ MUX_SEL_DISP0,
+ MUX_SEL_DISP1,
+ MUX_SEL_DISP2,
+ MUX_SEL_DISP3,
+ MUX_SEL_DISP4,
+ DIV_DISP,
+ EN_ACLK_DISP,
+ EN_PCLK_DISP,
+ EN_SCLK_DISP0,
+ EN_SCLK_DISP1,
+ EN_IP_DISP,
+ EN_IP_DISP_BUS,
+};
+
+PNAME(mout_phyclk_dptx_phy_ch3_txd_clk_user_p) = {"fin_pll",
+ "phyclk_dptx_phy_ch3_txd_clk"};
+PNAME(mout_phyclk_dptx_phy_ch2_txd_clk_user_p) = {"fin_pll",
+ "phyclk_dptx_phy_ch2_txd_clk"};
+PNAME(mout_phyclk_dptx_phy_ch1_txd_clk_user_p) = {"fin_pll",
+ "phyclk_dptx_phy_ch1_txd_clk"};
+PNAME(mout_phyclk_dptx_phy_ch0_txd_clk_user_p) = {"fin_pll",
+ "phyclk_dptx_phy_ch0_txd_clk"};
+PNAME(mout_aclk_disp_222_user_p) = {"fin_pll", "dout_aclk_disp_222"};
+PNAME(mout_sclk_disp_pixel_user_p) = {"fin_pll", "dout_sclk_disp_pixel"};
+PNAME(mout_aclk_disp_333_user_p) = {"fin_pll", "dout_aclk_disp_333"};
+PNAME(mout_phyclk_hdmi_phy_tmds_clko_user_p) = {"fin_pll",
+ "phyclk_hdmi_phy_tmds_clko"};
+PNAME(mout_phyclk_hdmi_phy_ref_clko_user_p) = {"fin_pll",
+ "phyclk_hdmi_phy_ref_clko"};
+PNAME(mout_phyclk_hdmi_phy_pixel_clko_user_p) = {"fin_pll",
+ "phyclk_hdmi_phy_pixel_clko"};
+PNAME(mout_phyclk_hdmi_link_o_tmds_clkhi_user_p) = {"fin_pll",
+ "phyclk_hdmi_link_o_tmds_clkhi"};
+PNAME(mout_phyclk_mipi_dphy_4l_m_txbyte_clkhs_p) = {"fin_pll",
+ "phyclk_mipi_dphy_4l_m_txbyte_clkhs"};
+PNAME(mout_phyclk_dptx_phy_o_ref_clk_24m_user_p) = {"fin_pll",
+ "phyclk_dptx_phy_o_ref_clk_24m"};
+PNAME(mout_phyclk_dptx_phy_clk_div2_user_p) = {"fin_pll",
+ "phyclk_dptx_phy_clk_div2"};
+PNAME(mout_sclk_hdmi_pixel_p) = {"mout_sclk_disp_pixel_user",
+ "mout_aclk_disp_222_user"};
+PNAME(mout_phyclk_mipi_dphy_4lmrxclk_esc0_user_p) = {"fin_pll",
+ "phyclk_mipi_dphy_4l_m_rxclkesc0"};
+PNAME(mout_sclk_hdmi_spdif_p) = {"fin_pll", "ioclk_spdif_extclk",
+ "dout_aclk_peri_aud", "phyclk_hdmi_phy_ref_cko"};
+
+struct samsung_mux_clock disp_mux_clks[] __initdata = {
+ MUX(DISP_MOUT_ACLK_DISP_333_USER, "mout_aclk_disp_333_user",
+ mout_aclk_disp_333_user_p,
+ MUX_SEL_DISP0, 0, 1),
+ MUX(DISP_MOUT_SCLK_DISP_PIXEL_USER, "mout_sclk_disp_pixel_user",
+ mout_sclk_disp_pixel_user_p,
+ MUX_SEL_DISP0, 4, 1),
+ MUX(DISP_MOUT_ACLK_DISP_222_USER, "mout_aclk_disp_222_user",
+ mout_aclk_disp_222_user_p,
+ MUX_SEL_DISP0, 8, 1),
+ MUX(DISP_MOUT_PHYCLK_DPTX_PHY_CH0_TXD_CLK_USER,
+ "mout_phyclk_dptx_phy_ch0_txd_clk_user",
+ mout_phyclk_dptx_phy_ch0_txd_clk_user_p,
+ MUX_SEL_DISP0, 16, 1),
+ MUX(DISP_MOUT_PHYCLK_DPTX_PHY_CH1_TXD_CLK_USER,
+ "mout_phyclk_dptx_phy_ch1_txd_clk_user",
+ mout_phyclk_dptx_phy_ch1_txd_clk_user_p,
+ MUX_SEL_DISP0, 20, 1),
+ MUX(DISP_MOUT_PHYCLK_DPTX_PHY_CH2_TXD_CLK_USER,
+ "mout_phyclk_dptx_phy_ch2_txd_clk_user",
+ mout_phyclk_dptx_phy_ch2_txd_clk_user_p,
+ MUX_SEL_DISP0, 24, 1),
+ MUX(DISP_MOUT_PHYCLK_DPTX_PHY_CH3_TXD_CLK_USER,
+ "mout_phyclk_dptx_phy_ch3_txd_clk_user",
+ mout_phyclk_dptx_phy_ch3_txd_clk_user_p,
+ MUX_SEL_DISP0, 28, 1),
+
+ MUX(DISP_MOUT_PHYCLK_DPTX_PHY_CLK_DIV2_USER,
+ "mout_phyclk_dptx_phy_clk_div2_user",
+ mout_phyclk_dptx_phy_clk_div2_user_p,
+ MUX_SEL_DISP1, 0, 1),
+ MUX(DISP_MOUT_PHYCLK_DPTX_PHY_O_REF_CLK_24M_USER,
+ "mout_phyclk_dptx_phy_o_ref_clk_24m_user",
+ mout_phyclk_dptx_phy_o_ref_clk_24m_user_p,
+ MUX_SEL_DISP1, 4, 1),
+ MUX(DISP_MOUT_PHYCLK_MIPI_DPHY_4L_M_TXBYTE_CLKHS,
+ "mout_phyclk_mipi_dphy_4l_m_txbyte_clkhs",
+ mout_phyclk_mipi_dphy_4l_m_txbyte_clkhs_p,
+ MUX_SEL_DISP1, 8, 1),
+ MUX(DISP_MOUT_PHYCLK_HDMI_LINK_O_TMDS_CLKHI_USER,
+ "mout_phyclk_hdmi_link_o_tmds_clkhi_user",
+ mout_phyclk_hdmi_link_o_tmds_clkhi_user_p,
+ MUX_SEL_DISP1, 16, 1),
+ MUX(DISP_MOUT_HDMI_PHY_PIXEL,
+ "mout_phyclk_hdmi_phy_pixel_clko_user",
+ mout_phyclk_hdmi_phy_pixel_clko_user_p,
+ MUX_SEL_DISP1, 20, 1),
+ MUX(DISP_MOUT_PHYCLK_HDMI_PHY_REF_CLKO_USER,
+ "mout_phyclk_hdmi_phy_ref_clko_user",
+ mout_phyclk_hdmi_phy_ref_clko_user_p,
+ MUX_SEL_DISP1, 24, 1),
+ MUX(DISP_MOUT_PHYCLK_HDMI_PHY_TMDS_CLKO_USER,
+ "mout_phyclk_hdmi_phy_tmds_clko_user",
+ mout_phyclk_hdmi_phy_tmds_clko_user_p,
+ MUX_SEL_DISP1, 28, 1),
+
+ MUX(DISP_MOUT_PHYCLK_MIPI_DPHY_4LMRXCLK_ESC0_USER,
+ "mout_phyclk_mipi_dphy_4lmrxclk_esc0_user",
+ mout_phyclk_mipi_dphy_4lmrxclk_esc0_user_p,
+ MUX_SEL_DISP2, 0, 1),
+ MUX(DISP_MOUT_SCLK_HDMI_PIXEL, "mout_sclk_hdmi_pixel",
+ mout_sclk_hdmi_pixel_p,
+ MUX_SEL_DISP2, 4, 1),
+
+ MUX(DISP_MOUT_SCLK_HDMI_SPDIF, "mout_sclk_hdmi_spdif",
+ mout_sclk_hdmi_spdif_p,
+ MUX_SEL_DISP4, 4, 2),
+};
+
+struct samsung_div_clock disp_div_clks[] __initdata = {
+ DIV(DISP_DOUT_PCLK_DISP_111, "dout_pclk_disp_111",
+ "mout_aclk_disp_222_user",
+ DIV_DISP, 8, 4),
+ DIV(DISP_DOUT_SCLK_FIMD1_EXTCLKPLL, "dout_sclk_fimd1_extclkpll",
+ "mout_sclk_disp_pixel_user",
+ DIV_DISP, 12, 4),
+ DIV(DISP_DOUT_SCLK_HDMI_PHY_PIXEL_CLKI,
+ "dout_sclk_hdmi_phy_pixel_clki",
+ "mout_sclk_hdmi_pixel",
+ DIV_DISP, 16, 4),
+};
+
+struct samsung_gate_clock disp_gate_clks[] __initdata = {
+ GATE(DISP_MOUT_HDMI_PHY_PIXEL_USER, "sclk_hdmi_link_i_pixel",
+ "mout_phyclk_hdmi_phy_pixel_clko_user",
+ EN_SCLK_DISP0, 26, CLK_SET_RATE_PARENT, 0),
+ GATE(DISP_SCLK_PIXEL, "sclk_hdmi_phy_pixel_clki",
+ "dout_sclk_hdmi_phy_pixel_clki",
+ EN_SCLK_DISP0, 29, CLK_SET_RATE_PARENT, 0),
+
+ GATE(DISP_CLK_DP, "clk_dptx_link", "mout_aclk_disp_222_user",
+ EN_IP_DISP, 4, 0, 0),
+ GATE(DISP_CLK_DPPHY, "clk_dptx_phy", "mout_aclk_disp_222_user",
+ EN_IP_DISP, 5, 0, 0),
+ GATE(DISP_CLK_DSIM1, "clk_dsim1", "mout_aclk_disp_222_user",
+ EN_IP_DISP, 6, 0, 0),
+ GATE(DISP_CLK_FIMD1, "clk_fimd1", "mout_aclk_disp_222_user",
+ EN_IP_DISP, 7, 0, 0),
+ GATE(DISP_CLK_HDMI, "clk_hdmi", "mout_aclk_disp_222_user",
+ EN_IP_DISP, 8, 0, 0),
+ GATE(DISP_CLK_HDMIPHY, "clk_hdmiphy", "mout_aclk_disp_222_user",
+ EN_IP_DISP, 9, 0, 0),
+ GATE(DISP_CLK_MIPIPHY, "clk_mipi_dphy", "mout_aclk_disp_222_user",
+ EN_IP_DISP, 10, 0, 0),
+ GATE(DISP_CLK_MIXER, "clk_mixer", "mout_aclk_disp_222_user",
+ EN_IP_DISP, 11, 0, 0),
+ GATE(DISP_CLK_PIXEL_DISP, "clk_pixel_disp", "mout_aclk_disp_222_user",
+ EN_IP_DISP, 12, CLK_IGNORE_UNUSED, 0),
+ GATE(DISP_CLK_PIXEL_MIXER, "clk_pixel_mixer", "mout_aclk_disp_222_user",
+ EN_IP_DISP, 13, CLK_IGNORE_UNUSED, 0),
+ GATE(DISP_CLK_SMMU_FIMD1M0, "clk_smmu3_fimd1m0",
+ "mout_aclk_disp_222_user",
+ EN_IP_DISP, 22, 0, 0),
+ GATE(DISP_CLK_SMMU_FIMD1M1, "clk_smmu3_fimd1m1",
+ "mout_aclk_disp_222_user",
+ EN_IP_DISP, 23, 0, 0),
+ GATE(DISP_CLK_SMMU_TV, "clk_smmu3_tv", "mout_aclk_disp_222_user",
+ EN_IP_DISP, 25, 0, 0),
+};
+
+static void __init exynos5260_clk_disp_init(struct device_node *np)
+{
+ struct exynos5260_cmu_info cmu = {0};
+
+ cmu.mux_clks = disp_mux_clks;
+ cmu.nr_mux_clks = ARRAY_SIZE(disp_mux_clks);
+ cmu.div_clks = disp_div_clks;
+ cmu.nr_div_clks = ARRAY_SIZE(disp_div_clks);
+ cmu.gate_clks = disp_gate_clks;
+ cmu.nr_gate_clks = ARRAY_SIZE(disp_gate_clks);
+ cmu.nr_clk_ids = DISP_NR_CLK;
+ cmu.clk_regs = disp_clk_regs;
+ cmu.nr_clk_regs = ARRAY_SIZE(disp_clk_regs);
+
+ exynos5260_cmu_register_one(np, &cmu);
+}
+
+CLK_OF_DECLARE(exynos5260_clk_disp, "samsung,exynos5260-clock-disp",
+ exynos5260_clk_disp_init);
+
+
+/* CMU_EGL */
+
+static unsigned long egl_clk_regs[] __initdata = {
+ EGL_PLL_LOCK,
+ EGL_PLL_CON0,
+ EGL_PLL_CON1,
+ EGL_PLL_FREQ_DET,
+ MUX_SEL_EGL,
+ MUX_ENABLE_EGL,
+ DIV_EGL,
+ DIV_EGL_PLL_FDET,
+ EN_ACLK_EGL,
+ EN_PCLK_EGL,
+ EN_SCLK_EGL,
+};
+
+PNAME(mout_egl_b_p) = {"mout_egl_pll", "dout_bus_pll"};
+PNAME(mout_egl_pll_p) = {"fin_pll", "fout_egl_pll"};
+
+struct samsung_mux_clock egl_mux_clks[] __initdata = {
+ MUX(EGL_MOUT_EGL_PLL, "mout_egl_pll", mout_egl_pll_p,
+ MUX_SEL_EGL, 4, 1),
+ MUX(EGL_MOUT_EGL_B, "mout_egl_b", mout_egl_b_p, MUX_SEL_EGL, 16, 1),
+};
+
+struct samsung_div_clock egl_div_clks[] __initdata = {
+ DIV(EGL_DOUT_EGL1, "dout_egl1", "mout_egl_b", DIV_EGL, 0, 3),
+ DIV(EGL_DOUT_EGL2, "dout_egl2", "dout_egl1", DIV_EGL, 4, 3),
+ DIV(EGL_DOUT_ACLK_EGL, "dout_aclk_egl", "dout_egl2", DIV_EGL, 8, 3),
+ DIV(EGL_DOUT_PCLK_EGL, "dout_pclk_egl", "dout_egl_atclk",
+ DIV_EGL, 12, 3),
+ DIV(EGL_DOUT_EGL_ATCLK, "dout_egl_atclk", "dout_egl2", DIV_EGL, 16, 3),
+ DIV(EGL_DOUT_EGL_PCLK_DBG, "dout_egl_pclk_dbg", "dout_egl_atclk",
+ DIV_EGL, 20, 3),
+ DIV(EGL_DOUT_EGL_PLL, "dout_egl_pll", "mout_egl_b", DIV_EGL, 24, 3),
+};
+
+static struct samsung_pll_clock egl_pll_clks[] __initdata = {
+ PLL(pll_2550xx, EGL_FOUT_EGL_PLL, "fout_egl_pll", "fin_pll",
+ EGL_PLL_LOCK, EGL_PLL_CON0,
+ pll2550_24mhz_tbl),
+};
+
+static void __init exynos5260_clk_egl_init(struct device_node *np)
+{
+ struct exynos5260_cmu_info cmu = {0};
+
+ cmu.pll_clks = egl_pll_clks;
+ cmu.nr_pll_clks = ARRAY_SIZE(egl_pll_clks);
+ cmu.mux_clks = egl_mux_clks;
+ cmu.nr_mux_clks = ARRAY_SIZE(egl_mux_clks);
+ cmu.div_clks = egl_div_clks;
+ cmu.nr_div_clks = ARRAY_SIZE(egl_div_clks);
+ cmu.nr_clk_ids = EGL_NR_CLK;
+ cmu.clk_regs = egl_clk_regs;
+ cmu.nr_clk_regs = ARRAY_SIZE(egl_clk_regs);
+
+ exynos5260_cmu_register_one(np, &cmu);
+}
+
+CLK_OF_DECLARE(exynos5260_clk_egl, "samsung,exynos5260-clock-egl",
+ exynos5260_clk_egl_init);
+
+
+/* CMU_FSYS */
+
+static unsigned long fsys_clk_regs[] __initdata = {
+ MUX_SEL_FSYS0,
+ MUX_SEL_FSYS1,
+ EN_ACLK_FSYS,
+ EN_ACLK_FSYS_SECURE_RTIC,
+ EN_ACLK_FSYS_SECURE_SMMU_RTIC,
+ EN_SCLK_FSYS,
+ EN_IP_FSYS,
+ EN_IP_FSYS_SECURE_RTIC,
+ EN_IP_FSYS_SECURE_SMMU_RTIC,
+};
+
+PNAME(mout_phyclk_usbhost20_phyclk_user_p) = {"fin_pll",
+ "phyclk_usbhost20_phy_phyclock"};
+PNAME(mout_phyclk_usbhost20_freeclk_user_p) = {"fin_pll",
+ "phyclk_usbhost20_phy_freeclk"};
+PNAME(mout_phyclk_usbhost20_clk48mohci_user_p) = {"fin_pll",
+ "phyclk_usbhost20_phy_clk48mohci"};
+PNAME(mout_phyclk_usbdrd30_pipe_pclk_user_p) = {"fin_pll",
+ "phyclk_usbdrd30_udrd30_pipe_pclk"};
+PNAME(mout_phyclk_usbdrd30_phyclock_user_p) = {"fin_pll",
+ "phyclk_usbdrd30_udrd30_phyclock"};
+
+struct samsung_mux_clock fsys_mux_clks[] __initdata = {
+ MUX(FSYS_MOUT_PHYCLK_USBDRD30_PHYCLOCK_USER,
+ "mout_phyclk_usbdrd30_phyclock_user",
+ mout_phyclk_usbdrd30_phyclock_user_p,
+ MUX_SEL_FSYS1, 0, 1),
+ MUX(FSYS_MOUT_PHYCLK_USBDRD30_PIPE_PCLK_USER,
+ "mout_phyclk_usbdrd30_pipe_pclk_user",
+ mout_phyclk_usbdrd30_pipe_pclk_user_p,
+ MUX_SEL_FSYS1, 4, 1),
+ MUX(FSYS_MOUT_PHYCLK_USBHOST20_CLK48MOHCI_USER,
+ "mout_phyclk_usbhost20_clk48mohci_user",
+ mout_phyclk_usbhost20_clk48mohci_user_p,
+ MUX_SEL_FSYS1, 8, 1),
+ MUX(FSYS_MOUT_PHYCLK_USBHOST20_FREECLK_USER,
+ "mout_phyclk_usbhost20_freeclk_user",
+ mout_phyclk_usbhost20_freeclk_user_p,
+ MUX_SEL_FSYS1, 12, 1),
+ MUX(FSYS_MOUT_PHYCLK_USBHOST20_PHYCLK_USER,
+ "mout_phyclk_usbhost20_phyclk_user",
+ mout_phyclk_usbhost20_phyclk_user_p,
+ MUX_SEL_FSYS1, 16, 1),
+};
+
+struct samsung_gate_clock fsys_gate_clks[] __initdata = {
+ GATE(FSYS_PHYCLK_USBHOST20, "phyclk_usbhost20_phyclock",
+ "mout_phyclk_usbdrd30_phyclock_user",
+ EN_SCLK_FSYS, 1, 0, 0),
+ GATE(FSYS_PHYCLK_USBDRD30, "phyclk_usbdrd30_udrd30_phyclock_g",
+ "mout_phyclk_usbdrd30_phyclock_user",
+ EN_SCLK_FSYS, 7, 0, 0),
+
+ GATE(FSYS_CLK_MMC0, "clk_mmc0", "dout_aclk_fsys_200",
+ EN_IP_FSYS, 6, 0, 0),
+ GATE(FSYS_CLK_MMC1, "clk_mmc1", "dout_aclk_fsys_200",
+ EN_IP_FSYS, 7, 0, 0),
+ GATE(FSYS_CLK_MMC2, "clk_mmc2", "dout_aclk_fsys_200",
+ EN_IP_FSYS, 8, 0, 0),
+ GATE(FSYS_CLK_PDMA, "clk_pdma", "dout_aclk_fsys_200",
+ EN_IP_FSYS, 9, 0, 0),
+ GATE(FSYS_CLK_SROMC, "clk_sromc", "dout_aclk_fsys_200",
+ EN_IP_FSYS, 13, 0, 0),
+ GATE(FSYS_CLK_USBDRD30, "clk_usbdrd30", "dout_aclk_fsys_200",
+ EN_IP_FSYS, 14, 0, 0),
+ GATE(FSYS_CLK_USBHOST20, "clk_usbhost20", "dout_aclk_fsys_200",
+ EN_IP_FSYS, 15, 0, 0),
+ GATE(FSYS_CLK_USBLINK, "clk_usblink", "dout_aclk_fsys_200",
+ EN_IP_FSYS, 18, 0, 0),
+ GATE(FSYS_CLK_TSI, "clk_tsi", "dout_aclk_fsys_200",
+ EN_IP_FSYS, 20, 0, 0),
+
+ GATE(FSYS_CLK_RTIC, "clk_rtic", "dout_aclk_fsys_200",
+ EN_IP_FSYS_SECURE_RTIC, 11, 0, 0),
+ GATE(FSYS_CLK_SMMU_RTIC, "clk_smmu_rtic", "dout_aclk_fsys_200",
+ EN_IP_FSYS_SECURE_SMMU_RTIC, 12, 0, 0),
+};
+
+static void __init exynos5260_clk_fsys_init(struct device_node *np)
+{
+ struct exynos5260_cmu_info cmu = {0};
+
+ cmu.mux_clks = fsys_mux_clks;
+ cmu.nr_mux_clks = ARRAY_SIZE(fsys_mux_clks);
+ cmu.gate_clks = fsys_gate_clks;
+ cmu.nr_gate_clks = ARRAY_SIZE(fsys_gate_clks);
+ cmu.nr_clk_ids = FSYS_NR_CLK;
+ cmu.clk_regs = fsys_clk_regs;
+ cmu.nr_clk_regs = ARRAY_SIZE(fsys_clk_regs);
+
+ exynos5260_cmu_register_one(np, &cmu);
+}
+
+CLK_OF_DECLARE(exynos5260_clk_fsys, "samsung,exynos5260-clock-fsys",
+ exynos5260_clk_fsys_init);
+
+
+/* CMU_G2D */
+
+static unsigned long g2d_clk_regs[] __initdata = {
+ MUX_SEL_G2D,
+ MUX_STAT_G2D,
+ DIV_G2D,
+ EN_ACLK_G2D,
+ EN_ACLK_G2D_SECURE_SSS,
+ EN_ACLK_G2D_SECURE_SLIM_SSS,
+ EN_ACLK_G2D_SECURE_SMMU_SLIM_SSS,
+ EN_ACLK_G2D_SECURE_SMMU_SSS,
+ EN_ACLK_G2D_SECURE_SMMU_MDMA,
+ EN_ACLK_G2D_SECURE_SMMU_G2D,
+ EN_PCLK_G2D,
+ EN_PCLK_G2D_SECURE_SMMU_SLIM_SSS,
+ EN_PCLK_G2D_SECURE_SMMU_SSS,
+ EN_PCLK_G2D_SECURE_SMMU_MDMA,
+ EN_PCLK_G2D_SECURE_SMMU_G2D,
+ EN_IP_G2D,
+ EN_IP_G2D_SECURE_SSS,
+ EN_IP_G2D_SECURE_SLIM_SSS,
+ EN_IP_G2D_SECURE_SMMU_SLIM_SSS,
+ EN_IP_G2D_SECURE_SMMU_SSS,
+ EN_IP_G2D_SECURE_SMMU_MDMA,
+ EN_IP_G2D_SECURE_SMMU_G2D,
+};
+
+PNAME(mout_aclk_g2d_333_user_p) = {"fin_pll", "dout_aclk_g2d_333"};
+
+struct samsung_mux_clock g2d_mux_clks[] __initdata = {
+ MUX(G2D_MOUT_ACLK_G2D_333_USER, "mout_aclk_g2d_333_user",
+ mout_aclk_g2d_333_user_p,
+ MUX_SEL_G2D, 0, 1),
+};
+
+struct samsung_div_clock g2d_div_clks[] __initdata = {
+ DIV(G2D_DOUT_PCLK_G2D_83, "dout_pclk_g2d_83", "mout_aclk_g2d_333_user",
+ DIV_G2D, 0, 3),
+};
+
+struct samsung_gate_clock g2d_gate_clks[] __initdata = {
+ GATE(G2D_CLK_G2D, "clk_g2d", "mout_aclk_g2d_333_user",
+ EN_IP_G2D, 4, 0, 0),
+ GATE(G2D_CLK_JPEG, "clk_jpeg", "mout_aclk_g2d_333_user",
+ EN_IP_G2D, 5, 0, 0),
+ GATE(G2D_CLK_MDMA, "clk_mdma", "mout_aclk_g2d_333_user",
+ EN_IP_G2D, 6, 0, 0),
+ GATE(G2D_CLK_SMMU3_JPEG, "clk_smmu3_jpeg", "mout_aclk_g2d_333_user",
+ EN_IP_G2D, 16, 0, 0),
+
+ GATE(G2D_CLK_SSS, "clk_sss", "mout_aclk_g2d_333_user",
+ EN_IP_G2D_SECURE_SSS, 17, 0, 0),
+
+ GATE(G2D_CLK_SLIM_SSS, "clk_slim_sss", "mout_aclk_g2d_333_user",
+ EN_IP_G2D_SECURE_SLIM_SSS, 11, 0, 0),
+
+ GATE(G2D_CLK_SMMU_SLIM_SSS, "clk_smmu_slim_sss",
+ "mout_aclk_g2d_333_user",
+ EN_IP_G2D_SECURE_SMMU_SLIM_SSS, 13, 0, 0),
+
+ GATE(G2D_CLK_SMMU_SSS, "clk_smmu_sss", "mout_aclk_g2d_333_user",
+ EN_IP_G2D_SECURE_SMMU_SSS, 14, 0, 0),
+
+ GATE(G2D_CLK_SMMU_MDMA, "clk_smmu_mdma", "mout_aclk_g2d_333_user",
+ EN_IP_G2D_SECURE_SMMU_MDMA, 12, 0, 0),
+
+ GATE(G2D_CLK_SMMU3_G2D, "clk_smmu3_g2d", "mout_aclk_g2d_333_user",
+ EN_IP_G2D_SECURE_SMMU_G2D, 15, 0, 0),
+};
+
+static void __init exynos5260_clk_g2d_init(struct device_node *np)
+{
+ struct exynos5260_cmu_info cmu = {0};
+
+ cmu.mux_clks = g2d_mux_clks;
+ cmu.nr_mux_clks = ARRAY_SIZE(g2d_mux_clks);
+ cmu.div_clks = g2d_div_clks;
+ cmu.nr_div_clks = ARRAY_SIZE(g2d_div_clks);
+ cmu.gate_clks = g2d_gate_clks;
+ cmu.nr_gate_clks = ARRAY_SIZE(g2d_gate_clks);
+ cmu.nr_clk_ids = G2D_NR_CLK;
+ cmu.clk_regs = g2d_clk_regs;
+ cmu.nr_clk_regs = ARRAY_SIZE(g2d_clk_regs);
+
+ exynos5260_cmu_register_one(np, &cmu);
+}
+
+CLK_OF_DECLARE(exynos5260_clk_g2d, "samsung,exynos5260-clock-g2d",
+ exynos5260_clk_g2d_init);
+
+
+/* CMU_G3D */
+
+static unsigned long g3d_clk_regs[] __initdata = {
+ G3D_PLL_LOCK,
+ G3D_PLL_CON0,
+ G3D_PLL_CON1,
+ G3D_PLL_FDET,
+ MUX_SEL_G3D,
+ DIV_G3D,
+ DIV_G3D_PLL_FDET,
+ EN_ACLK_G3D,
+ EN_PCLK_G3D,
+ EN_SCLK_G3D,
+ EN_IP_G3D,
+};
+
+PNAME(mout_g3d_pll_p) = {"fin_pll", "fout_g3d_pll"};
+
+struct samsung_mux_clock g3d_mux_clks[] __initdata = {
+ MUX(G3D_MOUT_G3D_PLL, "mout_g3d_pll", mout_g3d_pll_p,
+ MUX_SEL_G3D, 0, 1),
+};
+
+struct samsung_div_clock g3d_div_clks[] __initdata = {
+ DIV(G3D_DOUT_PCLK_G3D, "dout_pclk_g3d", "dout_aclk_g3d", DIV_G3D, 0, 3),
+ DIV(G3D_DOUT_ACLK_G3D, "dout_aclk_g3d", "mout_g3d_pll", DIV_G3D, 4, 3),
+};
+
+struct samsung_gate_clock g3d_gate_clks[] __initdata = {
+ GATE(G3D_CLK_G3D, "clk_g3d", "dout_aclk_g3d", EN_IP_G3D, 2, 0, 0),
+ GATE(G3D_CLK_G3D_HPM, "clk_g3d_hpm", "dout_aclk_g3d",
+ EN_IP_G3D, 3, 0, 0),
+};
+
+static struct samsung_pll_clock g3d_pll_clks[] __initdata = {
+ PLL(pll_2550, G3D_FOUT_G3D_PLL, "fout_g3d_pll", "fin_pll",
+ G3D_PLL_LOCK, G3D_PLL_CON0,
+ pll2550_24mhz_tbl),
+};
+
+static void __init exynos5260_clk_g3d_init(struct device_node *np)
+{
+ struct exynos5260_cmu_info cmu = {0};
+
+ cmu.pll_clks = g3d_pll_clks;
+ cmu.nr_pll_clks = ARRAY_SIZE(g3d_pll_clks);
+ cmu.mux_clks = g3d_mux_clks;
+ cmu.nr_mux_clks = ARRAY_SIZE(g3d_mux_clks);
+ cmu.div_clks = g3d_div_clks;
+ cmu.nr_div_clks = ARRAY_SIZE(g3d_div_clks);
+ cmu.gate_clks = g3d_gate_clks;
+ cmu.nr_gate_clks = ARRAY_SIZE(g3d_gate_clks);
+ cmu.nr_clk_ids = G3D_NR_CLK;
+ cmu.clk_regs = g3d_clk_regs;
+ cmu.nr_clk_regs = ARRAY_SIZE(g3d_clk_regs);
+
+ exynos5260_cmu_register_one(np, &cmu);
+}
+
+CLK_OF_DECLARE(exynos5260_clk_g3d, "samsung,exynos5260-clock-g3d",
+ exynos5260_clk_g3d_init);
+
+
+/* CMU_GSCL */
+
+static unsigned long gscl_clk_regs[] __initdata = {
+ MUX_SEL_GSCL,
+ DIV_GSCL,
+ EN_ACLK_GSCL,
+ EN_ACLK_GSCL_FIMC,
+ EN_ACLK_GSCL_SECURE_SMMU_GSCL0,
+ EN_ACLK_GSCL_SECURE_SMMU_GSCL1,
+ EN_ACLK_GSCL_SECURE_SMMU_MSCL0,
+ EN_ACLK_GSCL_SECURE_SMMU_MSCL1,
+ EN_PCLK_GSCL,
+ EN_PCLK_GSCL_FIMC,
+ EN_PCLK_GSCL_SECURE_SMMU_GSCL0,
+ EN_PCLK_GSCL_SECURE_SMMU_GSCL1,
+ EN_PCLK_GSCL_SECURE_SMMU_MSCL0,
+ EN_PCLK_GSCL_SECURE_SMMU_MSCL1,
+ EN_SCLK_GSCL,
+ EN_SCLK_GSCL_FIMC,
+ EN_IP_GSCL,
+ EN_IP_GSCL_FIMC,
+ EN_IP_GSCL_SECURE_SMMU_GSCL0,
+ EN_IP_GSCL_SECURE_SMMU_GSCL1,
+ EN_IP_GSCL_SECURE_SMMU_MSCL0,
+ EN_IP_GSCL_SECURE_SMMU_MSCL1,
+};
+
+PNAME(mout_aclk_gscl_333_user_p) = {"fin_pll", "dout_aclk_gscl_333"};
+PNAME(mout_aclk_m2m_400_user_p) = {"fin_pll", "dout_aclk_gscl_400"};
+PNAME(mout_aclk_gscl_fimc_user_p) = {"fin_pll", "dout_aclk_gscl_400"};
+PNAME(mout_aclk_csis_p) = {"dout_aclk_csis_200", "mout_aclk_gscl_fimc_user"};
+
+struct samsung_mux_clock gscl_mux_clks[] __initdata = {
+ MUX(GSCL_MOUT_ACLK_GSCL_333_USER, "mout_aclk_gscl_333_user",
+ mout_aclk_gscl_333_user_p,
+ MUX_SEL_GSCL, 0, 1),
+ MUX(GSCL_MOUT_ACLK_M2M_400_USER, "mout_aclk_m2m_400_user",
+ mout_aclk_m2m_400_user_p,
+ MUX_SEL_GSCL, 4, 1),
+ MUX(GSCL_MOUT_ACLK_GSCL_FIMC_USER, "mout_aclk_gscl_fimc_user",
+ mout_aclk_gscl_fimc_user_p,
+ MUX_SEL_GSCL, 8, 1),
+ MUX(GSCL_MOUT_ACLK_CSIS, "mout_aclk_csis", mout_aclk_csis_p,
+ MUX_SEL_GSCL, 24, 1),
+};
+
+struct samsung_div_clock gscl_div_clks[] __initdata = {
+ DIV(GSCL_DOUT_PCLK_M2M_100, "dout_pclk_m2m_100",
+ "mout_aclk_m2m_400_user",
+ DIV_GSCL, 0, 3),
+ DIV(GSCL_DOUT_ACLK_CSIS_200, "dout_aclk_csis_200",
+ "mout_aclk_m2m_400_user",
+ DIV_GSCL, 4, 3),
+};
+
+struct samsung_gate_clock gscl_gate_clks[] __initdata = {
+ GATE(GSCL_SCLK_CSIS0_WRAP, "sclk_csis0_wrap", "dout_aclk_csis_200",
+ EN_SCLK_GSCL_FIMC, 0, CLK_SET_RATE_PARENT, 0),
+ GATE(GSCL_SCLK_CSIS1_WRAP, "sclk_csis1_wrap", "dout_aclk_csis_200",
+ EN_SCLK_GSCL_FIMC, 1, CLK_SET_RATE_PARENT, 0),
+
+ GATE(GSCL_CLK_GSCL0, "clk_gscl0", "mout_aclk_gscl_333_user",
+ EN_IP_GSCL, 2, 0, 0),
+ GATE(GSCL_CLK_GSCL1, "clk_gscl1", "mout_aclk_gscl_333_user",
+ EN_IP_GSCL, 3, 0, 0),
+ GATE(GSCL_CLK_MSCL0, "clk_mscl0", "mout_aclk_gscl_333_user",
+ EN_IP_GSCL, 4, 0, 0),
+ GATE(GSCL_CLK_MSCL1, "clk_mscl1", "mout_aclk_gscl_333_user",
+ EN_IP_GSCL, 5, 0, 0),
+ GATE(GSCL_CLK_PIXEL_GSCL0, "clk_pixel_gscl0",
+ "mout_aclk_gscl_333_user",
+ EN_IP_GSCL, 8, 0, 0),
+ GATE(GSCL_CLK_PIXEL_GSCL1, "clk_pixel_gscl1",
+ "mout_aclk_gscl_333_user",
+ EN_IP_GSCL, 9, 0, 0),
+
+ GATE(GSCL_CLK_SMMU3_LITE_A, "clk_smmu3_lite_a",
+ "mout_aclk_gscl_fimc_user",
+ EN_IP_GSCL_FIMC, 5, 0, 0),
+ GATE(GSCL_CLK_SMMU3_LITE_B, "clk_smmu3_lite_b",
+ "mout_aclk_gscl_fimc_user",
+ EN_IP_GSCL_FIMC, 6, 0, 0),
+ GATE(GSCL_CLK_SMMU3_LITE_D, "clk_smmu3_lite_d",
+ "mout_aclk_gscl_fimc_user",
+ EN_IP_GSCL_FIMC, 7, 0, 0),
+ GATE(GSCL_CLK_CSIS0, "clk_csis0", "mout_aclk_gscl_fimc_user",
+ EN_IP_GSCL_FIMC, 8, 0, 0),
+ GATE(GSCL_CLK_CSIS1, "clk_csis1", "mout_aclk_gscl_fimc_user",
+ EN_IP_GSCL_FIMC, 9, 0, 0),
+ GATE(GSCL_CLK_FIMC_LITE_A, "clk_fimc_lite_a",
+ "mout_aclk_gscl_fimc_user",
+ EN_IP_GSCL_FIMC, 10, 0, 0),
+ GATE(GSCL_CLK_FIMC_LITE_B, "clk_fimc_lite_b",
+ "mout_aclk_gscl_fimc_user",
+ EN_IP_GSCL_FIMC, 11, 0, 0),
+ GATE(GSCL_CLK_FIMC_LITE_D, "clk_fimc_lite_d",
+ "mout_aclk_gscl_fimc_user",
+ EN_IP_GSCL_FIMC, 12, 0, 0),
+
+ GATE(GSCL_CLK_SMMU3_GSCL0, "clk_smmu3_gscl0",
+ "mout_aclk_gscl_333_user",
+ EN_IP_GSCL_SECURE_SMMU_GSCL0, 17, 0, 0),
+ GATE(GSCL_CLK_SMMU3_GSCL1, "clk_smmu3_gscl1", "mout_aclk_gscl_333_user",
+ EN_IP_GSCL_SECURE_SMMU_GSCL1, 18, 0, 0),
+ GATE(GSCL_CLK_SMMU3_MSCL0, "clk_smmu3_mscl0",
+ "mout_aclk_m2m_400_user",
+ EN_IP_GSCL_SECURE_SMMU_MSCL0, 19, 0, 0),
+ GATE(GSCL_CLK_SMMU3_MSCL1, "clk_smmu3_mscl1",
+ "mout_aclk_m2m_400_user",
+ EN_IP_GSCL_SECURE_SMMU_MSCL1, 20, 0, 0),
+};
+
+static void __init exynos5260_clk_gscl_init(struct device_node *np)
+{
+ struct exynos5260_cmu_info cmu = {0};
+
+ cmu.mux_clks = gscl_mux_clks;
+ cmu.nr_mux_clks = ARRAY_SIZE(gscl_mux_clks);
+ cmu.div_clks = gscl_div_clks;
+ cmu.nr_div_clks = ARRAY_SIZE(gscl_div_clks);
+ cmu.gate_clks = gscl_gate_clks;
+ cmu.nr_gate_clks = ARRAY_SIZE(gscl_gate_clks);
+ cmu.nr_clk_ids = GSCL_NR_CLK;
+ cmu.clk_regs = gscl_clk_regs;
+ cmu.nr_clk_regs = ARRAY_SIZE(gscl_clk_regs);
+
+ exynos5260_cmu_register_one(np, &cmu);
+}
+
+CLK_OF_DECLARE(exynos5260_clk_gscl, "samsung,exynos5260-clock-gscl",
+ exynos5260_clk_gscl_init);
+
+
+/* CMU_ISP */
+
+static unsigned long isp_clk_regs[] __initdata = {
+ MUX_SEL_ISP0,
+ MUX_SEL_ISP1,
+ DIV_ISP,
+ EN_ACLK_ISP0,
+ EN_ACLK_ISP1,
+ EN_PCLK_ISP0,
+ EN_PCLK_ISP1,
+ EN_SCLK_ISP,
+ EN_IP_ISP0,
+ EN_IP_ISP1,
+};
+
+PNAME(mout_isp_400_user_p) = {"fin_pll", "dout_aclk_isp1_400"};
+PNAME(mout_isp_266_user_p) = {"fin_pll", "dout_aclk_isp1_266"};
+
+struct samsung_mux_clock isp_mux_clks[] __initdata = {
+ MUX(ISP_MOUT_ISP_266_USER, "mout_isp_266_user", mout_isp_266_user_p,
+ MUX_SEL_ISP0, 0, 1),
+ MUX(ISP_MOUT_ISP_400_USER, "mout_isp_400_user", mout_isp_400_user_p,
+ MUX_SEL_ISP0, 4, 1),
+};
+
+struct samsung_div_clock isp_div_clks[] __initdata = {
+ DIV(ISP_DOUT_PCLK_ISP_66, "dout_pclk_isp_66", "mout_kfc",
+ DIV_ISP, 0, 3),
+ DIV(ISP_DOUT_PCLK_ISP_133, "dout_pclk_isp_133", "mout_kfc",
+ DIV_ISP, 4, 4),
+ DIV(ISP_DOUT_CA5_ATCLKIN, "dout_ca5_atclkin", "mout_kfc",
+ DIV_ISP, 12, 3),
+ DIV(ISP_DOUT_CA5_PCLKDBG, "dout_ca5_pclkdbg", "mout_kfc",
+ DIV_ISP, 16, 4),
+ DIV(ISP_DOUT_SCLK_MPWM, "dout_sclk_mpwm", "mout_kfc", DIV_ISP, 20, 2),
+};
+
+struct samsung_gate_clock isp_gate_clks[] __initdata = {
+ GATE(ISP_CLK_GIC, "clk_isp_gic", "mout_aclk_isp1_266",
+ EN_IP_ISP0, 15, 0, 0),
+
+ GATE(ISP_CLK_CA5, "clk_isp_ca5", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 1, 0, 0),
+ GATE(ISP_CLK_FIMC_DRC, "clk_isp_fimc_drc", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 2, 0, 0),
+ GATE(ISP_CLK_FIMC_FD, "clk_isp_fimc_fd", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 3, 0, 0),
+ GATE(ISP_CLK_FIMC, "clk_isp_fimc", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 4, 0, 0),
+ GATE(ISP_CLK_FIMC_SCALERC, "clk_isp_fimc_scalerc",
+ "mout_aclk_isp1_266",
+ EN_IP_ISP1, 5, 0, 0),
+ GATE(ISP_CLK_FIMC_SCALERP, "clk_isp_fimc_scalerp",
+ "mout_aclk_isp1_266",
+ EN_IP_ISP1, 6, 0, 0),
+ GATE(ISP_CLK_I2C0, "clk_isp_i2c0", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 7, 0, 0),
+ GATE(ISP_CLK_I2C1, "clk_isp_i2c1", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 8, 0, 0),
+ GATE(ISP_CLK_MCUCTL, "clk_isp_mcuctl", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 9, 0, 0),
+ GATE(ISP_CLK_MPWM, "clk_isp_mpwm", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 10, 0, 0),
+ GATE(ISP_CLK_MTCADC, "clk_isp_mtcadc", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 11, 0, 0),
+ GATE(ISP_CLK_PWM, "clk_isp_pwm", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 14, 0, 0),
+ GATE(ISP_CLK_SMMU_DRC, "clk_smmu_drc", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 21, 0, 0),
+ GATE(ISP_CLK_SMMU_FD, "clk_smmu_fd", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 22, 0, 0),
+ GATE(ISP_CLK_SMMU_ISP, "clk_smmu_isp", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 23, 0, 0),
+ GATE(ISP_CLK_SMMU_ISPCX, "clk_smmu_ispcx", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 24, 0, 0),
+ GATE(ISP_CLK_SMMU_SCALERC, "clk_isp_smmu_scalerc",
+ "mout_aclk_isp1_266",
+ EN_IP_ISP1, 25, 0, 0),
+ GATE(ISP_CLK_SMMU_SCALERP, "clk_isp_smmu_scalerp",
+ "mout_aclk_isp1_266",
+ EN_IP_ISP1, 26, 0, 0),
+ GATE(ISP_CLK_SPI0, "clk_isp_spi0", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 27, 0, 0),
+ GATE(ISP_CLK_SPI1, "clk_isp_spi1", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 28, 0, 0),
+ GATE(ISP_CLK_WDT, "clk_isp_wdt", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 31, 0, 0),
+ GATE(ISP_CLK_UART, "clk_isp_uart", "mout_aclk_isp1_266",
+ EN_IP_ISP1, 30, 0, 0),
+
+ GATE(ISP_SCLK_UART_EXT, "sclk_isp_uart_ext", "fin_pll",
+ EN_SCLK_ISP, 7, CLK_SET_RATE_PARENT, 0),
+ GATE(ISP_SCLK_SPI1_EXT, "sclk_isp_spi1_ext", "fin_pll",
+ EN_SCLK_ISP, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(ISP_SCLK_SPI0_EXT, "sclk_isp_spi0_ext", "fin_pll",
+ EN_SCLK_ISP, 9, CLK_SET_RATE_PARENT, 0),
+};
+
+static void __init exynos5260_clk_isp_init(struct device_node *np)
+{
+ struct exynos5260_cmu_info cmu = {0};
+
+ cmu.mux_clks = isp_mux_clks;
+ cmu.nr_mux_clks = ARRAY_SIZE(isp_mux_clks);
+ cmu.div_clks = isp_div_clks;
+ cmu.nr_div_clks = ARRAY_SIZE(isp_div_clks);
+ cmu.gate_clks = isp_gate_clks;
+ cmu.nr_gate_clks = ARRAY_SIZE(isp_gate_clks);
+ cmu.nr_clk_ids = ISP_NR_CLK;
+ cmu.clk_regs = isp_clk_regs;
+ cmu.nr_clk_regs = ARRAY_SIZE(isp_clk_regs);
+
+ exynos5260_cmu_register_one(np, &cmu);
+}
+
+CLK_OF_DECLARE(exynos5260_clk_isp, "samsung,exynos5260-clock-isp",
+ exynos5260_clk_isp_init);
+
+
+/* CMU_KFC */
+
+static unsigned long kfc_clk_regs[] __initdata = {
+ KFC_PLL_LOCK,
+ KFC_PLL_CON0,
+ KFC_PLL_CON1,
+ KFC_PLL_FDET,
+ MUX_SEL_KFC0,
+ MUX_SEL_KFC2,
+ DIV_KFC,
+ DIV_KFC_PLL_FDET,
+ EN_ACLK_KFC,
+ EN_PCLK_KFC,
+ EN_SCLK_KFC,
+ EN_IP_KFC,
+};
+
+PNAME(mout_kfc_pll_p) = {"fin_pll", "fout_kfc_pll"};
+PNAME(mout_kfc_p) = {"mout_kfc_pll", "dout_media_pll"};
+
+struct samsung_mux_clock kfc_mux_clks[] __initdata = {
+ MUX(KFC_MOUT_KFC_PLL, "mout_kfc_pll", mout_kfc_pll_p,
+ MUX_SEL_KFC0, 0, 1),
+ MUX(KFC_MOUT_KFC, "mout_kfc", mout_kfc_p, MUX_SEL_KFC2, 0, 1),
+};
+
+struct samsung_div_clock kfc_div_clks[] __initdata = {
+ DIV(KFC_DOUT_KFC1, "dout_kfc1", "mout_kfc", DIV_KFC, 0, 3),
+ DIV(KFC_DOUT_KFC2, "dout_kfc2", "dout_kfc1", DIV_KFC, 4, 3),
+ DIV(KFC_DOUT_KFC_ATCLK, "dout_kfc_atclk", "dout_kfc2", DIV_KFC, 8, 3),
+ DIV(KFC_DOUT_KFC_PCLK_DBG, "dout_kfc_pclk_dbg", "dout_kfc2",
+ DIV_KFC, 12, 3),
+ DIV(KFC_DOUT_ACLK_KFC, "dout_aclk_kfc", "dout_kfc2", DIV_KFC, 16, 3),
+ DIV(KFC_DOUT_PCLK_KFC, "dout_pclk_kfc", "dout_kfc2", DIV_KFC, 20, 3),
+ DIV(KFC_DOUT_KFC_PLL, "dout_kfc_pll", "mout_kfc", DIV_KFC, 24, 3),
+};
+
+static struct samsung_pll_clock kfc_pll_clks[] __initdata = {
+ PLL(pll_2550xx, KFC_FOUT_KFC_PLL, "fout_kfc_pll", "fin_pll",
+ KFC_PLL_LOCK, KFC_PLL_CON0,
+ pll2550_24mhz_tbl),
+};
+
+static void __init exynos5260_clk_kfc_init(struct device_node *np)
+{
+ struct exynos5260_cmu_info cmu = {0};
+
+ cmu.pll_clks = kfc_pll_clks;
+ cmu.nr_pll_clks = ARRAY_SIZE(kfc_pll_clks);
+ cmu.mux_clks = kfc_mux_clks;
+ cmu.nr_mux_clks = ARRAY_SIZE(kfc_mux_clks);
+ cmu.div_clks = kfc_div_clks;
+ cmu.nr_div_clks = ARRAY_SIZE(kfc_div_clks);
+ cmu.nr_clk_ids = KFC_NR_CLK;
+ cmu.clk_regs = kfc_clk_regs;
+ cmu.nr_clk_regs = ARRAY_SIZE(kfc_clk_regs);
+
+ exynos5260_cmu_register_one(np, &cmu);
+}
+
+CLK_OF_DECLARE(exynos5260_clk_kfc, "samsung,exynos5260-clock-kfc",
+ exynos5260_clk_kfc_init);
+
+
+/* CMU_MFC */
+
+static unsigned long mfc_clk_regs[] __initdata = {
+ MUX_SEL_MFC,
+ DIV_MFC,
+ EN_ACLK_MFC,
+ EN_ACLK_SECURE_SMMU2_MFC,
+ EN_PCLK_MFC,
+ EN_PCLK_SECURE_SMMU2_MFC,
+ EN_IP_MFC,
+ EN_IP_MFC_SECURE_SMMU2_MFC,
+};
+
+PNAME(mout_aclk_mfc_333_user_p) = {"fin_pll", "dout_aclk_mfc_333"};
+
+struct samsung_mux_clock mfc_mux_clks[] __initdata = {
+ MUX(MFC_MOUT_ACLK_MFC_333_USER, "mout_aclk_mfc_333_user",
+ mout_aclk_mfc_333_user_p,
+ MUX_SEL_MFC, 0, 1),
+};
+
+struct samsung_div_clock mfc_div_clks[] __initdata = {
+ DIV(MFC_DOUT_PCLK_MFC_83, "dout_pclk_mfc_83", "mout_aclk_mfc_333_user",
+ DIV_MFC, 0, 3),
+};
+
+struct samsung_gate_clock mfc_gate_clks[] __initdata = {
+ GATE(MFC_CLK_MFC, "clk_mfc", "mout_aclk_mfc_333_user",
+ EN_IP_MFC, 1, 0, 0),
+ GATE(MFC_CLK_SMMU2_MFCM0, "clk_smmu2_mfcm0", "mout_aclk_mfc_333_user",
+ EN_IP_MFC_SECURE_SMMU2_MFC, 6, 0, 0),
+ GATE(MFC_CLK_SMMU2_MFCM1, "clk_smmu2_mfcm1", "mout_aclk_mfc_333_user",
+ EN_IP_MFC_SECURE_SMMU2_MFC, 7, 0, 0),
+};
+
+static void __init exynos5260_clk_mfc_init(struct device_node *np)
+{
+ struct exynos5260_cmu_info cmu = {0};
+
+ cmu.mux_clks = mfc_mux_clks;
+ cmu.nr_mux_clks = ARRAY_SIZE(mfc_mux_clks);
+ cmu.div_clks = mfc_div_clks;
+ cmu.nr_div_clks = ARRAY_SIZE(mfc_div_clks);
+ cmu.gate_clks = mfc_gate_clks;
+ cmu.nr_gate_clks = ARRAY_SIZE(mfc_gate_clks);
+ cmu.nr_clk_ids = MFC_NR_CLK;
+ cmu.clk_regs = mfc_clk_regs;
+ cmu.nr_clk_regs = ARRAY_SIZE(mfc_clk_regs);
+
+ exynos5260_cmu_register_one(np, &cmu);
+}
+
+CLK_OF_DECLARE(exynos5260_clk_mfc, "samsung,exynos5260-clock-mfc",
+ exynos5260_clk_mfc_init);
+
+
+/* CMU_MIF */
+
+static unsigned long mif_clk_regs[] __initdata = {
+ MEM_PLL_LOCK,
+ BUS_PLL_LOCK,
+ MEDIA_PLL_LOCK,
+ MEM_PLL_CON0,
+ MEM_PLL_CON1,
+ MEM_PLL_FDET,
+ BUS_PLL_CON0,
+ BUS_PLL_CON1,
+ BUS_PLL_FDET,
+ MEDIA_PLL_CON0,
+ MEDIA_PLL_CON1,
+ MEDIA_PLL_FDET,
+ MUX_SEL_MIF,
+ DIV_MIF,
+ DIV_MIF_PLL_FDET,
+ EN_ACLK_MIF,
+ EN_ACLK_MIF_SECURE_DREX1_TZ,
+ EN_ACLK_MIF_SECURE_DREX0_TZ,
+ EN_ACLK_MIF_SECURE_INTMEM,
+ EN_PCLK_MIF,
+ EN_PCLK_MIF_SECURE_MONOCNT,
+ EN_PCLK_MIF_SECURE_RTC_APBIF,
+ EN_PCLK_MIF_SECURE_DREX1_TZ,
+ EN_PCLK_MIF_SECURE_DREX0_TZ,
+ EN_SCLK_MIF,
+ EN_IP_MIF,
+ EN_IP_MIF_SECURE_MONOCNT,
+ EN_IP_MIF_SECURE_RTC_APBIF,
+ EN_IP_MIF_SECURE_DREX1_TZ,
+ EN_IP_MIF_SECURE_DREX0_TZ,
+ EN_IP_MIF_SECURE_INTEMEM,
+};
+
+PNAME(mout_mem_pll_p) = {"fin_pll", "fout_mem_pll"};
+PNAME(mout_bus_pll_p) = {"fin_pll", "fout_bus_pll"};
+PNAME(mout_media_pll_p) = {"fin_pll", "fout_media_pll"};
+PNAME(mout_mif_drex_p) = {"dout_mem_pll", "dout_bus_pll"};
+PNAME(mout_mif_drex2x_p) = {"dout_mem_pll", "dout_bus_pll"};
+PNAME(mout_clkm_phy_p) = {"mout_mif_drex", "dout_media_pll"};
+PNAME(mout_clk2x_phy_p) = {"mout_mif_drex2x", "dout_media_pll"};
+
+struct samsung_mux_clock mif_mux_clks[] __initdata = {
+ MUX(MIF_MOUT_MEM_PLL, "mout_mem_pll", mout_mem_pll_p,
+ MUX_SEL_MIF, 0, 1),
+ MUX(MIF_MOUT_BUS_PLL, "mout_bus_pll", mout_bus_pll_p,
+ MUX_SEL_MIF, 4, 1),
+ MUX(MIF_MOUT_MEDIA_PLL, "mout_media_pll", mout_media_pll_p,
+ MUX_SEL_MIF, 8, 1),
+ MUX(MIF_MOUT_MIF_DREX, "mout_mif_drex", mout_mif_drex_p,
+ MUX_SEL_MIF, 12, 1),
+ MUX(MIF_MOUT_CLKM_PHY, "mout_clkm_phy", mout_clkm_phy_p,
+ MUX_SEL_MIF, 16, 1),
+ MUX(MIF_MOUT_MIF_DREX2X, "mout_mif_drex2x", mout_mif_drex2x_p,
+ MUX_SEL_MIF, 20, 1),
+ MUX(MIF_MOUT_CLK2X_PHY, "mout_clk2x_phy", mout_clk2x_phy_p,
+ MUX_SEL_MIF, 24, 1),
+};
+
+struct samsung_div_clock mif_div_clks[] __initdata = {
+ DIV(MIF_DOUT_MEDIA_PLL, "dout_media_pll", "mout_media_pll",
+ DIV_MIF, 0, 3),
+ DIV(MIF_DOUT_MEM_PLL, "dout_mem_pll", "mout_mem_pll",
+ DIV_MIF, 4, 3),
+ DIV(MIF_DOUT_BUS_PLL, "dout_bus_pll", "mout_bus_pll",
+ DIV_MIF, 8, 3),
+ DIV(MIF_DOUT_CLKM_PHY, "dout_clkm_phy", "mout_clkm_phy",
+ DIV_MIF, 12, 3),
+ DIV(MIF_DOUT_CLK2X_PHY, "dout_clk2x_phy", "mout_clk2x_phy",
+ DIV_MIF, 16, 4),
+ DIV(MIF_DOUT_ACLK_MIF_466, "dout_aclk_mif_466", "dout_clk2x_phy",
+ DIV_MIF, 20, 3),
+ DIV(MIF_DOUT_ACLK_BUS_200, "dout_aclk_bus_200", "dout_bus_pll",
+ DIV_MIF, 24, 3),
+ DIV(MIF_DOUT_ACLK_BUS_100, "dout_aclk_bus_100", "dout_bus_pll",
+ DIV_MIF, 28, 4),
+};
+
+struct samsung_gate_clock mif_gate_clks[] __initdata = {
+ GATE(MIF_CLK_LPDDR3PHY_WRAP0, "clk_lpddr3phy_wrap0", "dout_clk2x_phy",
+ EN_IP_MIF, 12, CLK_IGNORE_UNUSED, 0),
+ GATE(MIF_CLK_LPDDR3PHY_WRAP1, "clk_lpddr3phy_wrap1", "dout_clk2x_phy",
+ EN_IP_MIF, 13, CLK_IGNORE_UNUSED, 0),
+
+ GATE(MIF_CLK_MONOCNT, "clk_monocnt", "dout_aclk_bus_100",
+ EN_IP_MIF_SECURE_MONOCNT, 22,
+ CLK_IGNORE_UNUSED, 0),
+
+ GATE(MIF_CLK_MIF_RTC, "clk_mif_rtc", "dout_aclk_bus_100",
+ EN_IP_MIF_SECURE_RTC_APBIF, 23,
+ CLK_IGNORE_UNUSED, 0),
+
+ GATE(MIF_CLK_DREX1, "clk_drex1", "dout_aclk_mif_466",
+ EN_IP_MIF_SECURE_DREX1_TZ, 9,
+ CLK_IGNORE_UNUSED, 0),
+
+ GATE(MIF_CLK_DREX0, "clk_drex0", "dout_aclk_mif_466",
+ EN_IP_MIF_SECURE_DREX0_TZ, 9,
+ CLK_IGNORE_UNUSED, 0),
+
+ GATE(MIF_CLK_INTMEM, "clk_intmem", "dout_aclk_bus_200",
+ EN_IP_MIF_SECURE_INTEMEM, 11,
+ CLK_IGNORE_UNUSED, 0),
+
+ GATE(MIF_SCLK_LPDDR3PHY_WRAP_U0, "sclk_lpddr3phy_wrap_u0",
+ "dout_clkm_phy", EN_SCLK_MIF, 0,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0),
+ GATE(MIF_SCLK_LPDDR3PHY_WRAP_U1, "sclk_lpddr3phy_wrap_u1",
+ "dout_clkm_phy", EN_SCLK_MIF, 1,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0),
+};
+
+static struct samsung_pll_clock mif_pll_clks[] __initdata = {
+ PLL(pll_2550xx, MIF_FOUT_MEM_PLL, "fout_mem_pll", "fin_pll",
+ MEM_PLL_LOCK, MEM_PLL_CON0,
+ pll2550_24mhz_tbl),
+ PLL(pll_2550xx, MIF_FOUT_BUS_PLL, "fout_bus_pll", "fin_pll",
+ BUS_PLL_LOCK, BUS_PLL_CON0,
+ pll2550_24mhz_tbl),
+ PLL(pll_2550xx, MIF_FOUT_MEDIA_PLL, "fout_media_pll", "fin_pll",
+ MEDIA_PLL_LOCK, MEDIA_PLL_CON0,
+ pll2550_24mhz_tbl),
+};
+
+static void __init exynos5260_clk_mif_init(struct device_node *np)
+{
+ struct exynos5260_cmu_info cmu = {0};
+
+ cmu.pll_clks = mif_pll_clks;
+ cmu.nr_pll_clks = ARRAY_SIZE(mif_pll_clks);
+ cmu.mux_clks = mif_mux_clks;
+ cmu.nr_mux_clks = ARRAY_SIZE(mif_mux_clks);
+ cmu.div_clks = mif_div_clks;
+ cmu.nr_div_clks = ARRAY_SIZE(mif_div_clks);
+ cmu.gate_clks = mif_gate_clks;
+ cmu.nr_gate_clks = ARRAY_SIZE(mif_gate_clks);
+ cmu.nr_clk_ids = MIF_NR_CLK;
+ cmu.clk_regs = mif_clk_regs;
+ cmu.nr_clk_regs = ARRAY_SIZE(mif_clk_regs);
+
+ exynos5260_cmu_register_one(np, &cmu);
+}
+
+CLK_OF_DECLARE(exynos5260_clk_mif, "samsung,exynos5260-clock-mif",
+ exynos5260_clk_mif_init);
+
+
+/* CMU_PERI */
+
+static unsigned long peri_clk_regs[] __initdata = {
+ MUX_SEL_PERI,
+ MUX_SEL_PERI1,
+ DIV_PERI,
+ EN_PCLK_PERI0,
+ EN_PCLK_PERI1,
+ EN_PCLK_PERI2,
+ EN_PCLK_PERI3,
+ EN_PCLK_PERI_SECURE_CHIPID,
+ EN_PCLK_PERI_SECURE_PROVKEY0,
+ EN_PCLK_PERI_SECURE_PROVKEY1,
+ EN_PCLK_PERI_SECURE_SECKEY,
+ EN_PCLK_PERI_SECURE_ANTIRBKCNT,
+ EN_PCLK_PERI_SECURE_TOP_RTC,
+ EN_PCLK_PERI_SECURE_TZPC,
+ EN_SCLK_PERI,
+ EN_SCLK_PERI_SECURE_TOP_RTC,
+ EN_IP_PERI0,
+ EN_IP_PERI1,
+ EN_IP_PERI2,
+ EN_IP_PERI_SECURE_CHIPID,
+ EN_IP_PERI_SECURE_PROVKEY0,
+ EN_IP_PERI_SECURE_PROVKEY1,
+ EN_IP_PERI_SECURE_SECKEY,
+ EN_IP_PERI_SECURE_ANTIRBKCNT,
+ EN_IP_PERI_SECURE_TOP_RTC,
+ EN_IP_PERI_SECURE_TZPC,
+};
+
+PNAME(mout_sclk_pcm_p) = {"ioclk_pcm_extclk", "fin_pll", "dout_aclk_peri_aud",
+ "phyclk_hdmi_phy_ref_cko"};
+PNAME(mout_sclk_i2scod_p) = {"ioclk_i2s_cdclk", "fin_pll", "dout_aclk_peri_aud",
+ "phyclk_hdmi_phy_ref_cko"};
+PNAME(mout_sclk_spdif_p) = {"ioclk_spdif_extclk", "fin_pll",
+ "dout_aclk_peri_aud", "phyclk_hdmi_phy_ref_cko"};
+
+struct samsung_mux_clock peri_mux_clks[] __initdata = {
+ MUX(PERI_MOUT_SCLK_PCM, "mout_sclk_pcm", mout_sclk_pcm_p,
+ MUX_SEL_PERI1, 4, 2),
+ MUX(PERI_MOUT_SCLK_I2SCOD, "mout_sclk_i2scod", mout_sclk_i2scod_p,
+ MUX_SEL_PERI1, 12, 2),
+ MUX(PERI_MOUT_SCLK_SPDIF, "mout_sclk_spdif", mout_sclk_spdif_p,
+ MUX_SEL_PERI1, 20, 2),
+};
+
+struct samsung_div_clock peri_div_clks[] __initdata = {
+ DIV(PERI_DOUT_PCM, "dout_pcm", "mout_sclk_pcm", DIV_PERI, 0, 8),
+ DIV(PERI_DOUT_I2S, "dout_i2s", "mout_sclk_i2scod", DIV_PERI, 8, 6),
+};
+
+struct samsung_gate_clock peri_gate_clks[] __initdata = {
+ GATE(PERI_SCLK_PCM1, "sclk_pcm1", "dout_pcm", EN_SCLK_PERI, 0,
+ CLK_SET_RATE_PARENT, 0),
+ GATE(PERI_SCLK_I2S, "sclk_i2s", "dout_i2s", EN_SCLK_PERI, 1,
+ CLK_SET_RATE_PARENT, 0),
+ GATE(PERI_SCLK_SPDIF, "sclk_spdif", "dout_sclk_peri_spi0_b",
+ EN_SCLK_PERI, 2, CLK_SET_RATE_PARENT, 0),
+ GATE(PERI_SCLK_SPI0, "sclk_spi0", "dout_sclk_peri_spi0_b",
+ EN_SCLK_PERI, 7, CLK_SET_RATE_PARENT, 0),
+ GATE(PERI_SCLK_SPI1, "sclk_spi1", "dout_sclk_peri_spi1_b",
+ EN_SCLK_PERI, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(PERI_SCLK_SPI2, "sclk_spi2", "dout_sclk_peri_spi2_b",
+ EN_SCLK_PERI, 9, CLK_SET_RATE_PARENT, 0),
+ GATE(PERI_SCLK_UART0, "sclk_uart0", "dout_sclk_peri_uart0",
+ EN_SCLK_PERI, 10, CLK_SET_RATE_PARENT, 0),
+ GATE(PERI_SCLK_UART1, "sclk_uart1", "dout_sclk_peri_uart1",
+ EN_SCLK_PERI, 11, CLK_SET_RATE_PARENT, 0),
+ GATE(PERI_SCLK_UART2, "sclk_uart2", "dout_sclk_peri_uart2",
+ EN_SCLK_PERI, 12, CLK_SET_RATE_PARENT, 0),
+
+ GATE(PERI_CLK_ABB, "clk_abb", "dout_aclk_peri_66",
+ EN_IP_PERI0, 1, 0, 0),
+ GATE(PERI_CLK_EFUSE_WRITER, "clk_efuse_writer", "dout_aclk_peri_66",
+ EN_IP_PERI0, 5, 0, 0),
+ GATE(PERI_CLK_HDMICEC, "clk_hdmicec", "dout_aclk_peri_66",
+ EN_IP_PERI0, 6, 0, 0),
+ GATE(PERI_CLK_I2C10, "clk_i2c10", "dout_aclk_peri_66",
+ EN_IP_PERI0, 7, 0, 0),
+ GATE(PERI_CLK_I2C11, "clk_i2c11", "dout_aclk_peri_66",
+ EN_IP_PERI0, 8, 0, 0),
+ GATE(PERI_CLK_I2C8, "clk_i2c8", "dout_aclk_peri_66",
+ EN_IP_PERI0, 9, 0, 0),
+ GATE(PERI_CLK_I2C9, "clk_i2c9", "dout_aclk_peri_66",
+ EN_IP_PERI0, 10, 0, 0),
+ GATE(PERI_CLK_I2C4, "clk_i2c4", "dout_aclk_peri_66",
+ EN_IP_PERI0, 11, 0, 0),
+ GATE(PERI_CLK_I2C5, "clk_i2c5", "dout_aclk_peri_66",
+ EN_IP_PERI0, 12, 0, 0),
+ GATE(PERI_CLK_I2C6, "clk_i2c6", "dout_aclk_peri_66",
+ EN_IP_PERI0, 13, 0, 0),
+ GATE(PERI_CLK_I2C7, "clk_i2c7", "dout_aclk_peri_66",
+ EN_IP_PERI0, 14, 0, 0),
+ GATE(PERI_CLK_I2CHDMI, "clk_i2chdmi", "dout_aclk_peri_66",
+ EN_IP_PERI0, 15, 0, 0),
+ GATE(PERI_CLK_I2S, "clk_peri_i2s", "dout_aclk_peri_66",
+ EN_IP_PERI0, 16, 0, 0),
+ GATE(PERI_CLK_MCT, "clk_mct", "dout_aclk_peri_66",
+ EN_IP_PERI0, 17, 0, 0),
+ GATE(PERI_CLK_PCM, "clk_peri_pcm", "dout_aclk_peri_66",
+ EN_IP_PERI0, 18, 0, 0),
+ GATE(PERI_CLK_HSIC0, "clk_hsic0", "dout_aclk_peri_66",
+ EN_IP_PERI0, 20, 0, 0),
+ GATE(PERI_CLK_HSIC1, "clk_hsic1", "dout_aclk_peri_66",
+ EN_IP_PERI0, 21, 0, 0),
+ GATE(PERI_CLK_HSIC2, "clk_hsic2", "dout_aclk_peri_66",
+ EN_IP_PERI0, 22, 0, 0),
+ GATE(PERI_CLK_HSIC3, "clk_hsic3", "dout_aclk_peri_66",
+ EN_IP_PERI0, 23, 0, 0),
+ GATE(PERI_CLK_WDT_EGL, "clk_wdt_egl", "dout_aclk_peri_66",
+ EN_IP_PERI0, 24, 0, 0),
+ GATE(PERI_CLK_WDT_KFC, "clk_wdt_kfc", "dout_aclk_peri_66",
+ EN_IP_PERI0, 25, 0, 0),
+
+ GATE(PERI_CLK_UART4, "clk_uart4", "dout_aclk_peri_66",
+ EN_IP_PERI2, 0, 0, 0),
+ GATE(PERI_CLK_PWM, "clk_pwm", "dout_aclk_peri_66",
+ EN_IP_PERI2, 3, 0, 0),
+ GATE(PERI_CLK_SPDIF, "clk_spdif", "dout_aclk_peri_66",
+ EN_IP_PERI2, 6, 0, 0),
+ GATE(PERI_CLK_SPI0, "clk_spi0", "dout_aclk_peri_66",
+ EN_IP_PERI2, 7, 0, 0),
+ GATE(PERI_CLK_SPI1, "clk_spi1", "dout_aclk_peri_66",
+ EN_IP_PERI2, 8, 0, 0),
+ GATE(PERI_CLK_SPI2, "clk_spi2", "dout_aclk_peri_66",
+ EN_IP_PERI2, 9, 0, 0),
+ GATE(PERI_CLK_TMU0, "clk_tmu0", "dout_aclk_peri_66",
+ EN_IP_PERI2, 10, 0, 0),
+ GATE(PERI_CLK_TMU1, "clk_tmu1", "dout_aclk_peri_66",
+ EN_IP_PERI2, 11, 0, 0),
+ GATE(PERI_CLK_TMU2, "clk_tmu2", "dout_aclk_peri_66",
+ EN_IP_PERI2, 12, 0, 0),
+ GATE(PERI_CLK_TMU3, "clk_tmu3", "dout_aclk_peri_66",
+ EN_IP_PERI2, 13, 0, 0),
+ GATE(PERI_CLK_TMU4, "clk_tmu4", "dout_aclk_peri_66",
+ EN_IP_PERI2, 14, 0, 0),
+ GATE(PERI_CLK_ADC, "clk_adc", "dout_aclk_peri_66",
+ EN_IP_PERI2, 18, 0, 0),
+ GATE(PERI_CLK_UART0, "clk_uart0", "dout_aclk_peri_66",
+ EN_IP_PERI2, 19, 0, 0),
+ GATE(PERI_CLK_UART1, "clk_uart1", "dout_aclk_peri_66",
+ EN_IP_PERI2, 20, 0, 0),
+ GATE(PERI_CLK_UART2, "clk_uart2", "dout_aclk_peri_66",
+ EN_IP_PERI2, 21, 0, 0),
+
+ GATE(PERI_CLK_CHIPID, "clk_chipid", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_CHIPID, 2, 0, 0),
+
+ GATE(PERI_CLK_PROVKEY0, "clk_provkey0", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_PROVKEY0, 1, 0, 0),
+
+ GATE(PERI_CLK_PROVKEY1, "clk_provkey1", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_PROVKEY1, 2, 0, 0),
+
+ GATE(PERI_CLK_SECKEY, "clk_seckey", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_SECKEY, 5, 0, 0),
+
+ GATE(PERI_CLK_TOP_RTC, "clk_top_rtc", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_TOP_RTC, 5, 0, 0),
+
+ GATE(PERI_CLK_TZPC0, "clk_tzpc0", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_TZPC, 10, 0, 0),
+ GATE(PERI_CLK_TZPC1, "clk_tzpc1", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_TZPC, 11, 0, 0),
+ GATE(PERI_CLK_TZPC2, "clk_tzpc2", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_TZPC, 12, 0, 0),
+ GATE(PERI_CLK_TZPC3, "clk_tzpc3", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_TZPC, 13, 0, 0),
+ GATE(PERI_CLK_TZPC4, "clk_tzpc4", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_TZPC, 14, 0, 0),
+ GATE(PERI_CLK_TZPC5, "clk_tzpc5", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_TZPC, 15, 0, 0),
+ GATE(PERI_CLK_TZPC6, "clk_tzpc6", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_TZPC, 16, 0, 0),
+ GATE(PERI_CLK_TZPC7, "clk_tzpc7", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_TZPC, 17, 0, 0),
+ GATE(PERI_CLK_TZPC8, "clk_tzpc8", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_TZPC, 18, 0, 0),
+ GATE(PERI_CLK_TZPC9, "clk_tzpc9", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_TZPC, 19, 0, 0),
+ GATE(PERI_CLK_TZPC10, "clk_tzpc10", "dout_aclk_peri_66",
+ EN_IP_PERI_SECURE_TZPC, 20, 0, 0),
+};
+
+static void __init exynos5260_clk_peri_init(struct device_node *np)
+{
+ struct exynos5260_cmu_info cmu = {0};
+
+ cmu.mux_clks = peri_mux_clks;
+ cmu.nr_mux_clks = ARRAY_SIZE(peri_mux_clks);
+ cmu.div_clks = peri_div_clks;
+ cmu.nr_div_clks = ARRAY_SIZE(peri_div_clks);
+ cmu.gate_clks = peri_gate_clks;
+ cmu.nr_gate_clks = ARRAY_SIZE(peri_gate_clks);
+ cmu.nr_clk_ids = PERI_NR_CLK;
+ cmu.clk_regs = peri_clk_regs;
+ cmu.nr_clk_regs = ARRAY_SIZE(peri_clk_regs);
+
+ exynos5260_cmu_register_one(np, &cmu);
+}
+
+CLK_OF_DECLARE(exynos5260_clk_peri, "samsung,exynos5260-clock-peri",
+ exynos5260_clk_peri_init);
+
+
+/* CMU_TOP */
+
+static unsigned long top_clk_regs[] __initdata = {
+ DISP_PLL_LOCK,
+ AUD_PLL_LOCK,
+ DISP_PLL_CON0,
+ DISP_PLL_CON1,
+ DISP_PLL_FDET,
+ AUD_PLL_CON0,
+ AUD_PLL_CON1,
+ AUD_PLL_CON2,
+ AUD_PLL_FDET,
+ MUX_SEL_TOP_PLL0,
+ MUX_SEL_TOP_MFC,
+ MUX_SEL_TOP_G2D,
+ MUX_SEL_TOP_GSCL,
+ MUX_SEL_TOP_ISP10,
+ MUX_SEL_TOP_ISP11,
+ MUX_SEL_TOP_DISP0,
+ MUX_SEL_TOP_DISP1,
+ MUX_SEL_TOP_BUS,
+ MUX_SEL_TOP_PERI0,
+ MUX_SEL_TOP_PERI1,
+ MUX_SEL_TOP_FSYS,
+ DIV_TOP_G2D_MFC,
+ DIV_TOP_GSCL_ISP0,
+ DIV_TOP_ISP10,
+ DIV_TOP_ISP11,
+ DIV_TOP_DISP,
+ DIV_TOP_BUS,
+ DIV_TOP_PERI0,
+ DIV_TOP_PERI1,
+ DIV_TOP_PERI2,
+ DIV_TOP_FSYS0,
+ DIV_TOP_FSYS1,
+ DIV_TOP_HPM,
+ DIV_TOP_PLL_FDET,
+ EN_ACLK_TOP,
+ EN_SCLK_TOP,
+ EN_IP_TOP,
+};
+
+/* fixed rate clocks generated inside the soc */
+struct samsung_fixed_rate_clock fixed_rate_clks[] __initdata = {
+ FRATE(PHYCLK_DPTX_PHY_CH3_TXD_CLK, "phyclk_dptx_phy_ch3_txd_clk", NULL,
+ CLK_IS_ROOT, 270000000),
+ FRATE(PHYCLK_DPTX_PHY_CH2_TXD_CLK, "phyclk_dptx_phy_ch2_txd_clk", NULL,
+ CLK_IS_ROOT, 270000000),
+ FRATE(PHYCLK_DPTX_PHY_CH1_TXD_CLK, "phyclk_dptx_phy_ch1_txd_clk", NULL,
+ CLK_IS_ROOT, 270000000),
+ FRATE(PHYCLK_DPTX_PHY_CH0_TXD_CLK, "phyclk_dptx_phy_ch0_txd_clk", NULL,
+ CLK_IS_ROOT, 270000000),
+ FRATE(phyclk_hdmi_phy_tmds_clko, "phyclk_hdmi_phy_tmds_clko", NULL,
+ CLK_IS_ROOT, 250000000),
+ FRATE(PHYCLK_HDMI_PHY_PIXEL_CLKO, "phyclk_hdmi_phy_pixel_clko", NULL,
+ CLK_IS_ROOT, 1660000000),
+ FRATE(PHYCLK_HDMI_LINK_O_TMDS_CLKHI, "phyclk_hdmi_link_o_tmds_clkhi",
+ NULL, CLK_IS_ROOT, 125000000),
+ FRATE(PHYCLK_MIPI_DPHY_4L_M_TXBYTECLKHS,
+ "phyclk_mipi_dphy_4l_m_txbyteclkhs" , NULL,
+ CLK_IS_ROOT, 187500000),
+ FRATE(PHYCLK_DPTX_PHY_O_REF_CLK_24M, "phyclk_dptx_phy_o_ref_clk_24m",
+ NULL, CLK_IS_ROOT, 24000000),
+ FRATE(PHYCLK_DPTX_PHY_CLK_DIV2, "phyclk_dptx_phy_clk_div2", NULL,
+ CLK_IS_ROOT, 135000000),
+ FRATE(PHYCLK_MIPI_DPHY_4L_M_RXCLKESC0,
+ "phyclk_mipi_dphy_4l_m_rxclkesc0", NULL,
+ CLK_IS_ROOT, 20000000),
+ FRATE(PHYCLK_USBHOST20_PHY_PHYCLOCK, "phyclk_usbhost20_phy_phyclock",
+ NULL, CLK_IS_ROOT, 60000000),
+ FRATE(PHYCLK_USBHOST20_PHY_FREECLK, "phyclk_usbhost20_phy_freeclk",
+ NULL, CLK_IS_ROOT, 60000000),
+ FRATE(PHYCLK_USBHOST20_PHY_CLK48MOHCI,
+ "phyclk_usbhost20_phy_clk48mohci",
+ NULL, CLK_IS_ROOT, 48000000),
+ FRATE(PHYCLK_USBDRD30_UDRD30_PIPE_PCLK,
+ "phyclk_usbdrd30_udrd30_pipe_pclk", NULL,
+ CLK_IS_ROOT, 125000000),
+ FRATE(PHYCLK_USBDRD30_UDRD30_PHYCLOCK,
+ "phyclk_usbdrd30_udrd30_phyclock", NULL,
+ CLK_IS_ROOT, 60000000),
+};
+
+PNAME(mout_memtop_pll_user_p) = {"fin_pll", "dout_mem_pll"};
+PNAME(mout_bustop_pll_user_p) = {"fin_pll", "dout_bus_pll"};
+PNAME(mout_mediatop_pll_user_p) = {"fin_pll", "dout_media_pll"};
+PNAME(mout_audtop_pll_user_p) = {"fin_pll", "mout_aud_pll"};
+PNAME(mout_aud_pll_p) = {"fin_pll", "fout_aud_pll"};
+PNAME(mout_disp_pll_p) = {"fin_pll", "fout_disp_pll"};
+PNAME(mout_mfc_bustop_333_p) = {"mout_bustop_pll_user", "mout_disp_pll"};
+PNAME(mout_aclk_mfc_333_p) = {"mout_mediatop_pll_user", "mout_mfc_bustop_333"};
+PNAME(mout_g2d_bustop_333_p) = {"mout_bustop_pll_user", "mout_disp_pll"};
+PNAME(mout_aclk_g2d_333_p) = {"mout_mediatop_pll_user", "mout_g2d_bustop_333"};
+PNAME(mout_gscl_bustop_333_p) = {"mout_bustop_pll_user", "mout_disp_pll"};
+PNAME(mout_aclk_gscl_333_p) = {"mout_mediatop_pll_user",
+ "mout_gscl_bustop_333"};
+PNAME(mout_m2m_mediatop_400_p) = {"mout_mediatop_pll_user", "mout_disp_pll"};
+PNAME(mout_aclk_gscl_400_p) = {"mout_bustop_pll_user",
+ "mout_m2m_mediatop_400"};
+PNAME(mout_gscl_bustop_fimc_p) = {"mout_bustop_pll_user", "mout_disp_pll"};
+PNAME(mout_aclk_gscl_fimc_p) = {"mout_mediatop_pll_user",
+ "mout_gscl_bustop_fimc"};
+PNAME(mout_isp1_media_266_p) = {"mout_mediatop_pll_user",
+ "mout_memtop_pll_user"};
+PNAME(mout_aclk_isp1_266_p) = {"mout_bustop_pll_user", "mout_isp1_media_266"};
+PNAME(mout_isp1_media_400_p) = {"mout_mediatop_pll_user", "mout_disp_pll"};
+PNAME(mout_aclk_isp1_400_p) = {"mout_bustop_pll_user", "mout_isp1_media_400"};
+PNAME(mout_sclk_isp_spi_p) = {"fin_pll", "mout_bustop_pll_user"};
+PNAME(mout_sclk_isp_uart_p) = {"fin_pll", "mout_bustop_pll_user"};
+PNAME(mout_sclk_isp_sensor_p) = {"fin_pll", "mout_bustop_pll_user"};
+PNAME(mout_disp_disp_333_p) = {"mout_disp_pll", "mout_bustop_pll_user"};
+PNAME(mout_aclk_disp_333_p) = {"mout_mediatop_pll_user", "mout_disp_disp_333"};
+PNAME(mout_disp_disp_222_p) = {"mout_disp_pll", "mout_bustop_pll_user"};
+PNAME(mout_aclk_disp_222_p) = {"mout_mediatop_pll_user", "mout_disp_disp_222"};
+PNAME(mout_disp_media_pixel_p) = {"mout_mediatop_pll_user",
+ "mout_bustop_pll_user"};
+PNAME(mout_sclk_disp_pixel_p) = {"mout_disp_pll", "mout_disp_media_pixel"};
+PNAME(mout_bus_bustop_400_p) = {"mout_bustop_pll_user", "mout_memtop_pll_user"};
+PNAME(mout_bus_bustop_100_p) = {"mout_bustop_pll_user", "mout_memtop_pll_user"};
+PNAME(mout_sclk_peri_spi_clk_p) = {"fin_pll", "mout_bustop_pll_user"};
+PNAME(mout_sclk_peri_uart_uclk_p) = {"fin_pll", "mout_bustop_pll_user"};
+PNAME(mout_sclk_fsys_usb_p) = {"fin_pll", "mout_bustop_pll_user"};
+PNAME(mout_sclk_fsys_mmc_sdclkin_a_p) = {"fin_pll", "mout_bustop_pll_user"};
+PNAME(mout_sclk_fsys_mmc0_sdclkin_b_p) = {"mout_sclk_fsys_mmc0_sdclkin_a",
+ "mout_mediatop_pll_user"};
+PNAME(mout_sclk_fsys_mmc1_sdclkin_b_p) = {"mout_sclk_fsys_mmc1_sdclkin_a",
+ "mout_mediatop_pll_user"};
+PNAME(mout_sclk_fsys_mmc2_sdclkin_b_p) = {"mout_sclk_fsys_mmc2_sdclkin_a",
+ "mout_mediatop_pll_user"};
+
+struct samsung_mux_clock top_mux_clks[] __initdata = {
+ MUX(TOP_MOUT_MEDIATOP_PLL_USER, "mout_mediatop_pll_user",
+ mout_mediatop_pll_user_p,
+ MUX_SEL_TOP_PLL0, 0, 1),
+ MUX(TOP_MOUT_MEMTOP_PLL_USER, "mout_memtop_pll_user",
+ mout_memtop_pll_user_p,
+ MUX_SEL_TOP_PLL0, 4, 1),
+ MUX(TOP_MOUT_BUSTOP_PLL_USER, "mout_bustop_pll_user",
+ mout_bustop_pll_user_p,
+ MUX_SEL_TOP_PLL0, 8, 1),
+ MUX(TOP_MOUT_DISP_PLL, "mout_disp_pll", mout_disp_pll_p,
+ MUX_SEL_TOP_PLL0, 12, 1),
+ MUX(TOP_MOUT_AUD_PLL, "mout_aud_pll", mout_aud_pll_p,
+ MUX_SEL_TOP_PLL0, 16, 1),
+ MUX(TOP_MOUT_AUDTOP_PLL_USER, "mout_audtop_pll_user",
+ mout_audtop_pll_user_p,
+ MUX_SEL_TOP_PLL0, 24, 1),
+
+ MUX(TOP_MOUT_DISP_DISP_333, "mout_disp_disp_333", mout_disp_disp_333_p,
+ MUX_SEL_TOP_DISP0, 0, 1),
+ MUX(TOP_MOUT_ACLK_DISP_333, "mout_aclk_disp_333", mout_aclk_disp_333_p,
+ MUX_SEL_TOP_DISP0, 8, 1),
+ MUX(TOP_MOUT_DISP_DISP_222, "mout_disp_disp_222", mout_disp_disp_222_p,
+ MUX_SEL_TOP_DISP0, 12, 1),
+ MUX(TOP_MOUT_ACLK_DISP_222, "mout_aclk_disp_222", mout_aclk_disp_222_p,
+ MUX_SEL_TOP_DISP0, 20, 1),
+
+ MUX(TOP_MOUT_FIMD1, "mout_sclk_disp_pixel", mout_sclk_disp_pixel_p,
+ MUX_SEL_TOP_DISP1, 0, 1),
+ MUX(TOP_MOUT_DISP_MEDIA_PIXEL, "mout_disp_media_pixel",
+ mout_disp_media_pixel_p,
+ MUX_SEL_TOP_DISP1, 8, 1),
+
+ MUX(TOP_MOUT_SCLK_PERI_SPI2_CLK, "mout_sclk_peri_spi2_clk",
+ mout_sclk_peri_spi_clk_p,
+ MUX_SEL_TOP_PERI1, 0, 1),
+ MUX(TOP_MOUT_SCLK_PERI_SPI1_CLK, "mout_sclk_peri_spi1_clk",
+ mout_sclk_peri_spi_clk_p,
+ MUX_SEL_TOP_PERI1, 4, 1),
+ MUX(TOP_MOUT_SCLK_PERI_SPI0_CLK, "mout_sclk_peri_spi0_clk",
+ mout_sclk_peri_spi_clk_p,
+ MUX_SEL_TOP_PERI1, 8, 1),
+ MUX(TOP_MOUT_SCLK_PERI_UART1_UCLK, "mout_sclk_peri_uart1_uclk",
+ mout_sclk_peri_uart_uclk_p,
+ MUX_SEL_TOP_PERI1, 12, 1),
+ MUX(TOP_MOUT_SCLK_PERI_UART2_UCLK, "mout_sclk_peri_uart2_uclk",
+ mout_sclk_peri_uart_uclk_p,
+ MUX_SEL_TOP_PERI1, 16, 1),
+ MUX(TOP_MOUT_SCLK_PERI_UART0_UCLK, "mout_sclk_peri_uart0_uclk",
+ mout_sclk_peri_uart_uclk_p,
+ MUX_SEL_TOP_PERI1, 20, 1),
+
+
+ MUX(TOP_MOUT_BUS1_BUSTOP_400, "mout_bus1_bustop_400",
+ mout_bus_bustop_400_p,
+ MUX_SEL_TOP_BUS, 0, 1),
+ MUX(TOP_MOUT_BUS1_BUSTOP_100, "mout_bus1_bustop_100",
+ mout_bus_bustop_100_p,
+ MUX_SEL_TOP_BUS, 4, 1),
+ MUX(TOP_MOUT_BUS2_BUSTOP_100, "mout_bus2_bustop_100",
+ mout_bus_bustop_100_p,
+ MUX_SEL_TOP_BUS, 8, 1),
+ MUX(TOP_MOUT_BUS2_BUSTOP_400, "mout_bus2_bustop_400",
+ mout_bus_bustop_400_p,
+ MUX_SEL_TOP_BUS, 12, 1),
+ MUX(TOP_MOUT_BUS3_BUSTOP_400, "mout_bus3_bustop_400",
+ mout_bus_bustop_400_p,
+ MUX_SEL_TOP_BUS, 16, 1),
+ MUX(TOP_MOUT_BUS3_BUSTOP_100, "mout_bus3_bustop_100",
+ mout_bus_bustop_100_p,
+ MUX_SEL_TOP_BUS, 20, 1),
+ MUX(TOP_MOUT_BUS4_BUSTOP_400, "mout_bus4_bustop_400",
+ mout_bus_bustop_400_p,
+ MUX_SEL_TOP_BUS, 24, 1),
+ MUX(TOP_MOUT_BUS4_BUSTOP_100, "mout_bus4_bustop_100",
+ mout_bus_bustop_100_p,
+ MUX_SEL_TOP_BUS, 28, 1),
+
+ MUX(TOP_MOUT_SCLK_FSYS_USB, "mout_sclk_fsys_usb",
+ mout_sclk_fsys_usb_p,
+ MUX_SEL_TOP_FSYS, 0, 1),
+ MUX(TOP_MOUT_SCLK_FSYS_MMC2_SDCLKIN_A, "mout_sclk_fsys_mmc2_sdclkin_a",
+ mout_sclk_fsys_mmc_sdclkin_a_p,
+ MUX_SEL_TOP_FSYS, 4, 1),
+ MUX(TOP_MOUT_SCLK_FSYS_MMC2_SDCLKIN_B, "mout_sclk_fsys_mmc2_sdclkin_b",
+ mout_sclk_fsys_mmc2_sdclkin_b_p,
+ MUX_SEL_TOP_FSYS, 8, 1),
+ MUX(TOP_MOUT_SCLK_FSYS_MMC1_SDCLKIN_A, "mout_sclk_fsys_mmc1_sdclkin_a",
+ mout_sclk_fsys_mmc_sdclkin_a_p,
+ MUX_SEL_TOP_FSYS, 12, 1),
+ MUX(TOP_MOUT_SCLK_FSYS_MMC1_SDCLKIN_B, "mout_sclk_fsys_mmc1_sdclkin_b",
+ mout_sclk_fsys_mmc1_sdclkin_b_p,
+ MUX_SEL_TOP_FSYS, 16, 1),
+ MUX(TOP_MOUT_SCLK_FSYS_MMC0_SDCLKIN_A, "mout_sclk_fsys_mmc0_sdclkin_a",
+ mout_sclk_fsys_mmc_sdclkin_a_p,
+ MUX_SEL_TOP_FSYS, 20, 1),
+ MUX(TOP_MOUT_SCLK_FSYS_MMC0_SDCLKIN_B, "mout_sclk_fsys_mmc0_sdclkin_b",
+ mout_sclk_fsys_mmc0_sdclkin_b_p,
+ MUX_SEL_TOP_FSYS, 24, 1),
+
+ MUX(TOP_MOUT_ISP1_MEDIA_400, "mout_isp1_media_400",
+ mout_isp1_media_400_p,
+ MUX_SEL_TOP_ISP10, 4, 1),
+ MUX(TOP_MOUT_ACLK_ISP1_400, "mout_aclk_isp1_400", mout_aclk_isp1_400_p,
+ MUX_SEL_TOP_ISP10, 8 , 1),
+ MUX(TOP_MOUT_ISP1_MEDIA_266, "mout_isp1_media_266",
+ mout_isp1_media_266_p,
+ MUX_SEL_TOP_ISP10, 16, 1),
+ MUX(TOP_MOUT_ACLK_ISP1_266, "mout_aclk_isp1_266", mout_aclk_isp1_266_p,
+ MUX_SEL_TOP_ISP10, 20, 1),
+
+ MUX(TOP_MOUT_SCLK_ISP1_SPI0, "mout_sclk_isp1_spi0", mout_sclk_isp_spi_p,
+ MUX_SEL_TOP_ISP11, 4, 1),
+ MUX(TOP_MOUT_SCLK_ISP1_SPI1, "mout_sclk_isp1_spi1", mout_sclk_isp_spi_p,
+ MUX_SEL_TOP_ISP11, 8, 1),
+ MUX(TOP_MOUT_SCLK_ISP1_UART, "mout_sclk_isp1_uart",
+ mout_sclk_isp_uart_p,
+ MUX_SEL_TOP_ISP11, 12, 1),
+ MUX(TOP_MOUT_SCLK_ISP1_SENSOR0, "mout_sclk_isp1_sensor0",
+ mout_sclk_isp_sensor_p,
+ MUX_SEL_TOP_ISP11, 16, 1),
+ MUX(TOP_MOUT_SCLK_ISP1_SENSOR1, "mout_sclk_isp1_sensor1",
+ mout_sclk_isp_sensor_p,
+ MUX_SEL_TOP_ISP11, 20, 1),
+ MUX(TOP_MOUT_SCLK_ISP1_SENSOR2, "mout_sclk_isp1_sensor2",
+ mout_sclk_isp_sensor_p,
+ MUX_SEL_TOP_ISP11, 24, 1),
+
+ MUX(TOP_MOUT_MFC_BUSTOP_333, "mout_mfc_bustop_333",
+ mout_mfc_bustop_333_p,
+ MUX_SEL_TOP_MFC, 4, 1),
+ MUX(TOP_MOUT_ACLK_MFC_333, "mout_aclk_mfc_333", mout_aclk_mfc_333_p,
+ MUX_SEL_TOP_MFC, 8, 1),
+
+ MUX(TOP_MOUT_G2D_BUSTOP_333, "mout_g2d_bustop_333",
+ mout_g2d_bustop_333_p,
+ MUX_SEL_TOP_G2D, 4, 1),
+ MUX(TOP_MOUT_ACLK_G2D_333, "mout_aclk_g2d_333", mout_aclk_g2d_333_p,
+ MUX_SEL_TOP_G2D, 8, 1),
+
+ MUX(TOP_MOUT_M2M_MEDIATOP_400, "mout_m2m_mediatop_400",
+ mout_m2m_mediatop_400_p,
+ MUX_SEL_TOP_GSCL, 0, 1),
+ MUX(TOP_MOUT_ACLK_GSCL_400, "mout_aclk_gscl_400",
+ mout_aclk_gscl_400_p,
+ MUX_SEL_TOP_GSCL, 4, 1),
+ MUX(TOP_MOUT_GSCL_BUSTOP_333, "mout_gscl_bustop_333",
+ mout_gscl_bustop_333_p,
+ MUX_SEL_TOP_GSCL, 8, 1),
+ MUX(TOP_MOUT_ACLK_GSCL_333, "mout_aclk_gscl_333",
+ mout_aclk_gscl_333_p,
+ MUX_SEL_TOP_GSCL, 12, 1),
+ MUX(TOP_MOUT_GSCL_BUSTOP_FIMC, "mout_gscl_bustop_fimc",
+ mout_gscl_bustop_fimc_p,
+ MUX_SEL_TOP_GSCL, 16, 1),
+ MUX(TOP_MOUT_ACLK_GSCL_FIMC, "mout_aclk_gscl_fimc",
+ mout_aclk_gscl_fimc_p,
+ MUX_SEL_TOP_GSCL, 20, 1),
+};
+
+struct samsung_div_clock top_div_clks[] __initdata = {
+ DIV(TOP_DOUT_ACLK_G2D_333, "dout_aclk_g2d_333", "mout_aclk_g2d_333",
+ DIV_TOP_G2D_MFC, 0, 3),
+ DIV(TOP_DOUT_ACLK_MFC_333, "dout_aclk_mfc_333", "mout_aclk_mfc_333",
+ DIV_TOP_G2D_MFC, 4, 3),
+
+ DIV(TOP_DOUT_ACLK_GSCL_333, "dout_aclk_gscl_333", "mout_aclk_gscl_333",
+ DIV_TOP_GSCL_ISP0, 0, 3),
+ DIV(TOP_DOUT_ACLK_GSCL_400, "dout_aclk_gscl_400", "mout_aclk_gscl_400",
+ DIV_TOP_GSCL_ISP0, 4, 3),
+ DIV(TOP_DOUT_ACLK_GSCL_FIMC, "dout_aclk_gscl_fimc",
+ "mout_aclk_gscl_fimc", DIV_TOP_GSCL_ISP0, 8, 3),
+ DIV(TOP_DOUT_SCLK_ISP1_SENSOR0_A, "dout_sclk_isp1_sensor0_a",
+ "mout_aclk_gscl_fimc", DIV_TOP_GSCL_ISP0, 16, 4),
+ DIV(TOP_DOUT_SCLK_ISP1_SENSOR1_A, "dout_sclk_isp1_sensor1_a",
+ "mout_aclk_gscl_400", DIV_TOP_GSCL_ISP0, 20, 4),
+ DIV(TOP_DOUT_SCLK_ISP1_SENSOR2_A, "dout_sclk_isp1_sensor2_a",
+ "mout_aclk_gscl_fimc", DIV_TOP_GSCL_ISP0, 24, 4),
+
+ DIV(TOP_DOUT_ACLK_ISP1_266, "dout_aclk_isp1_266", "mout_aclk_isp1_266",
+ DIV_TOP_ISP10, 0, 3),
+ DIV(TOP_DOUT_ACLK_ISP1_400, "dout_aclk_isp1_400", "mout_aclk_isp1_400",
+ DIV_TOP_ISP10, 4, 3),
+ DIV(TOP_DOUT_SCLK_ISP1_SPI0_A, "dout_sclk_isp1_spi0_a",
+ "mout_sclk_isp1_spi0", DIV_TOP_ISP10, 12, 4),
+ DIV(TOP_DOUT_SCLK_ISP1_SPI0_B, "dout_sclk_isp1_spi0_b",
+ "dout_sclk_isp1_spi0_a", DIV_TOP_ISP10, 16, 8),
+
+ DIV(TOP_DOUT_SCLK_ISP1_SPI1_A, "dout_sclk_isp1_spi1_a",
+ "mout_sclk_isp1_spi1", DIV_TOP_ISP11, 0, 4),
+ DIV(TOP_DOUT_SCLK_ISP1_SPI1_B, "dout_sclk_isp1_spi1_b",
+ "dout_sclk_isp1_spi1_a", DIV_TOP_ISP11, 4, 8),
+ DIV(TOP_DOUT_SCLK_ISP1_UART, "dout_sclk_isp1_uart",
+ "mout_sclk_isp1_uart", DIV_TOP_ISP11, 12, 4),
+ DIV(TOP_DOUT_SCLK_ISP1_SENSOR0_B, "dout_sclk_isp1_sensor0_b",
+ "dout_sclk_isp1_sensor0_a", DIV_TOP_ISP11, 16, 4),
+ DIV(TOP_DOUT_SCLK_ISP1_SENSOR1_B, "dout_sclk_isp1_sensor1_b",
+ "dout_sclk_isp1_sensor1_a", DIV_TOP_ISP11, 20, 4),
+ DIV(TOP_DOUT_SCLK_ISP1_SENSOR2_B, "dout_sclk_isp1_sensor2_b",
+ "dout_sclk_isp1_sensor2_a", DIV_TOP_ISP11, 24, 4),
+
+ DIV(TOP_DOUTTOP__SCLK_HPM_TARGETCLK, "dout_sclk_hpm_targetclk",
+ "mout_bustop_pll_user", DIV_TOP_HPM, 0, 3),
+
+ DIV(TOP_DOUT_ACLK_DISP_333, "dout_aclk_disp_333", "mout_aclk_disp_333",
+ DIV_TOP_DISP, 0, 3),
+ DIV(TOP_DOUT_ACLK_DISP_222, "dout_aclk_disp_222", "mout_aclk_disp_222",
+ DIV_TOP_DISP, 4, 3),
+ DIV(TOP_DOUT_SCLK_DISP_PIXEL, "dout_sclk_disp_pixel",
+ "mout_sclk_disp_pixel", DIV_TOP_DISP, 8, 3),
+
+ DIV(TOP_DOUT_ACLK_BUS1_400, "dout_aclk_bus1_400",
+ "mout_bus1_bustop_400", DIV_TOP_BUS, 0, 3),
+ DIV(TOP_DOUT_ACLK_BUS1_100, "dout_aclk_bus1_100",
+ "mout_bus1_bustop_100", DIV_TOP_BUS, 4, 4),
+ DIV(TOP_DOUT_ACLK_BUS2_400, "dout_aclk_bus2_400",
+ "mout_bus2_bustop_400", DIV_TOP_BUS, 8, 3),
+ DIV(TOP_DOUT_ACLK_BUS2_100, "dout_aclk_bus2_100",
+ "mout_bus2_bustop_100", DIV_TOP_BUS, 12, 4),
+ DIV(TOP_DOUT_ACLK_BUS3_400, "dout_aclk_bus3_400",
+ "mout_bus3_bustop_400", DIV_TOP_BUS, 16, 3),
+ DIV(TOP_DOUT_ACLK_BUS3_100, "dout_aclk_bus3_100",
+ "mout_bus3_bustop_100", DIV_TOP_BUS, 20, 4),
+ DIV(TOP_DOUT_ACLK_BUS4_400, "dout_aclk_bus4_400",
+ "mout_bus4_bustop_400", DIV_TOP_BUS, 24, 3),
+ DIV(TOP_DOUT_ACLK_BUS4_100, "dout_aclk_bus4_100",
+ "mout_bus4_bustop_100", DIV_TOP_BUS, 28, 4),
+
+ DIV(TOP_DOUT_SCLK_PERI_SPI0_A, "dout_sclk_peri_spi0_a",
+ "mout_sclk_peri_spi0_clk", DIV_TOP_PERI0, 4, 4),
+ DIV(TOP_DOUT_SCLK_PERI_SPI0_B, "dout_sclk_peri_spi0_b",
+ "dout_sclk_peri_spi0_a", DIV_TOP_PERI0, 8, 8),
+ DIV(TOP_DOUT_SCLK_PERI_SPI1_A, "dout_sclk_peri_spi1_a",
+ "mout_sclk_peri_spi1_clk", DIV_TOP_PERI0, 16, 4),
+ DIV(TOP_DOUT_SCLK_PERI_SPI1_B, "dout_sclk_peri_spi1_b",
+ "dout_sclk_peri_spi1_a", DIV_TOP_PERI0, 20, 8),
+
+ DIV(TOP_DOUT_SCLK_PERI_SPI2_A, "dout_sclk_peri_spi2_a",
+ "mout_sclk_peri_spi2_clk", DIV_TOP_PERI1, 0, 4),
+ DIV(TOP_DOUT_SCLK_PERI_SPI2_B, "dout_sclk_peri_spi2_b",
+ "dout_sclk_peri_spi2_a", DIV_TOP_PERI1, 4, 8),
+ DIV(TOP_DOUT_SCLK_PERI_UART1, "dout_sclk_peri_uart1",
+ "mout_sclk_peri_uart1_uclk", DIV_TOP_PERI1, 16, 4),
+ DIV(TOP_DOUT_SCLK_PERI_UART2, "dout_sclk_peri_uart2",
+ "mout_sclk_peri_uart2_uclk", DIV_TOP_PERI1, 20, 4),
+ DIV(TOP_DOUT_SCLK_PERI_UART0, "dout_sclk_peri_uart0",
+ "mout_sclk_peri_uart0_uclk", DIV_TOP_PERI1, 24, 4),
+
+ DIV(TOP_DOUT_ACLK_PERI_66, "dout_aclk_peri_66", "mout_bustop_pll_user",
+ DIV_TOP_PERI2, 20, 4),
+ DIV(TOP_DOUT_ACLK_PERI_AUD, "dout_aclk_peri_aud",
+ "mout_audtop_pll_user", DIV_TOP_PERI2, 24, 3),
+
+ DIV(TOP_DOUT_ACLK_FSYS_200, "dout_aclk_fsys_200",
+ "mout_bustop_pll_user", DIV_TOP_FSYS0, 0, 3),
+ DIV(TOP_DOUT_SCLK_FSYS_USBDRD30_SUSPEND_CLK,
+ "dout_sclk_fsys_usbdrd30_suspend_clk",
+ "mout_sclk_fsys_usb", DIV_TOP_FSYS0, 4, 4),
+ DIV(TOP_DOUT_SCLK_FSYS_MMC0_SDCLKIN_A, "dout_sclk_fsys_mmc0_sdclkin_a",
+ "mout_sclk_fsys_mmc0_sdclkin_b",
+ DIV_TOP_FSYS0, 12, 4),
+ DIV(TOP_DOUT_SCLK_FSYS_MMC0_SDCLKIN_B, "dout_sclk_fsys_mmc0_sdclkin_b",
+ "dout_sclk_fsys_mmc0_sdclkin_a",
+ DIV_TOP_FSYS0, 16, 8),
+
+
+ DIV(TOP_DOUT_SCLK_FSYS_MMC1_SDCLKIN_A, "dout_sclk_fsys_mmc1_sdclkin_a",
+ "mout_sclk_fsys_mmc1_sdclkin_b",
+ DIV_TOP_FSYS1, 0, 4),
+ DIV(TOP_DOUT_SCLK_FSYS_MMC1_SDCLKIN_B, "dout_sclk_fsys_mmc1_sdclkin_b",
+ "dout_sclk_fsys_mmc1_sdclkin_a",
+ DIV_TOP_FSYS1, 4, 8),
+ DIV(TOP_DOUT_SCLK_FSYS_MMC2_SDCLKIN_A, "dout_sclk_fsys_mmc2_sdclkin_a",
+ "mout_sclk_fsys_mmc2_sdclkin_b",
+ DIV_TOP_FSYS1, 12, 4),
+ DIV(TOP_DOUT_SCLK_FSYS_MMC2_SDCLKIN_B, "dout_sclk_fsys_mmc2_sdclkin_b",
+ "dout_sclk_fsys_mmc2_sdclkin_a",
+ DIV_TOP_FSYS1, 16, 8),
+
+};
+
+struct samsung_gate_clock top_gate_clks[] __initdata = {
+ GATE(TOP_SCLK_MMC0, "sclk_fsys_mmc0_sdclkin",
+ "dout_sclk_fsys_mmc0_sdclkin_b",
+ EN_SCLK_TOP, 7, CLK_SET_RATE_PARENT, 0),
+ GATE(TOP_SCLK_MMC1, "sclk_fsys_mmc1_sdclkin",
+ "dout_sclk_fsys_mmc1_sdclkin_b",
+ EN_SCLK_TOP, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(TOP_SCLK_MMC2, "sclk_fsys_mmc2_sdclkin",
+ "dout_sclk_fsys_mmc2_sdclkin_b",
+ EN_SCLK_TOP, 9, CLK_SET_RATE_PARENT, 0),
+ GATE(TOP_SCLK_FIMD1, "sclk_disp_pixel", "dout_sclk_disp_pixel",
+ EN_ACLK_TOP, 10, CLK_IGNORE_UNUSED |
+ CLK_SET_RATE_PARENT, 0),
+};
+
+static struct samsung_pll_clock top_pll_clks[] __initdata = {
+ PLL(pll_2550xx, TOP_FOUT_DISP_PLL, "fout_disp_pll", "fin_pll",
+ DISP_PLL_LOCK, DISP_PLL_CON0,
+ pll2550_24mhz_tbl),
+ PLL(pll_2650xx, TOP_FOUT_AUD_PLL, "fout_aud_pll", "fin_pll",
+ AUD_PLL_LOCK, AUD_PLL_CON0,
+ pll2650_24mhz_tbl),
+};
+
+static void __init exynos5260_clk_top_init(struct device_node *np)
+{
+ struct exynos5260_cmu_info cmu = {0};
+
+ cmu.pll_clks = top_pll_clks;
+ cmu.nr_pll_clks = ARRAY_SIZE(top_pll_clks);
+ cmu.mux_clks = top_mux_clks;
+ cmu.nr_mux_clks = ARRAY_SIZE(top_mux_clks);
+ cmu.div_clks = top_div_clks;
+ cmu.nr_div_clks = ARRAY_SIZE(top_div_clks);
+ cmu.gate_clks = top_gate_clks;
+ cmu.nr_gate_clks = ARRAY_SIZE(top_gate_clks);
+ cmu.fixed_clks = fixed_rate_clks;
+ cmu.nr_fixed_clks = ARRAY_SIZE(fixed_rate_clks);
+ cmu.nr_clk_ids = TOP_NR_CLK;
+ cmu.clk_regs = top_clk_regs;
+ cmu.nr_clk_regs = ARRAY_SIZE(top_clk_regs);
+
+ exynos5260_cmu_register_one(np, &cmu);
+}
+
+CLK_OF_DECLARE(exynos5260_clk_top, "samsung,exynos5260-clock-top",
+ exynos5260_clk_top_init);
diff --git a/drivers/clk/samsung/clk-exynos5260.h b/drivers/clk/samsung/clk-exynos5260.h
new file mode 100644
index 000000000000..d739716d6ea1
--- /dev/null
+++ b/drivers/clk/samsung/clk-exynos5260.h
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Rahul Sharma <rahul.sharma@samsung.com>
+ *
+ * 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.
+ *
+ * Common Clock Framework support for Exynos5260 SoC.
+ */
+
+#ifndef __CLK_EXYNOS5260_H
+#define __CLK_EXYNOS5260_H
+
+/*
+*Registers for CMU_AUD
+*/
+#define MUX_SEL_AUD 0x0200
+#define MUX_ENABLE_AUD 0x0300
+#define MUX_STAT_AUD 0x0400
+#define MUX_IGNORE_AUD 0x0500
+#define DIV_AUD0 0x0600
+#define DIV_AUD1 0x0604
+#define DIV_STAT_AUD0 0x0700
+#define DIV_STAT_AUD1 0x0704
+#define EN_ACLK_AUD 0x0800
+#define EN_PCLK_AUD 0x0900
+#define EN_SCLK_AUD 0x0a00
+#define EN_IP_AUD 0x0b00
+
+/*
+*Registers for CMU_DISP
+*/
+#define MUX_SEL_DISP0 0x0200
+#define MUX_SEL_DISP1 0x0204
+#define MUX_SEL_DISP2 0x0208
+#define MUX_SEL_DISP3 0x020C
+#define MUX_SEL_DISP4 0x0210
+#define MUX_ENABLE_DISP0 0x0300
+#define MUX_ENABLE_DISP1 0x0304
+#define MUX_ENABLE_DISP2 0x0308
+#define MUX_ENABLE_DISP3 0x030c
+#define MUX_ENABLE_DISP4 0x0310
+#define MUX_STAT_DISP0 0x0400
+#define MUX_STAT_DISP1 0x0404
+#define MUX_STAT_DISP2 0x0408
+#define MUX_STAT_DISP3 0x040c
+#define MUX_STAT_DISP4 0x0410
+#define MUX_IGNORE_DISP0 0x0500
+#define MUX_IGNORE_DISP1 0x0504
+#define MUX_IGNORE_DISP2 0x0508
+#define MUX_IGNORE_DISP3 0x050c
+#define MUX_IGNORE_DISP4 0x0510
+#define DIV_DISP 0x0600
+#define DIV_STAT_DISP 0x0700
+#define EN_ACLK_DISP 0x0800
+#define EN_PCLK_DISP 0x0900
+#define EN_SCLK_DISP0 0x0a00
+#define EN_SCLK_DISP1 0x0a04
+#define EN_IP_DISP 0x0b00
+#define EN_IP_DISP_BUS 0x0b04
+
+
+/*
+*Registers for CMU_EGL
+*/
+#define EGL_PLL_LOCK 0x0000
+#define EGL_DPLL_LOCK 0x0004
+#define EGL_PLL_CON0 0x0100
+#define EGL_PLL_CON1 0x0104
+#define EGL_PLL_FREQ_DET 0x010c
+#define EGL_DPLL_CON0 0x0110
+#define EGL_DPLL_CON1 0x0114
+#define EGL_DPLL_FREQ_DET 0x011c
+#define MUX_SEL_EGL 0x0200
+#define MUX_ENABLE_EGL 0x0300
+#define MUX_STAT_EGL 0x0400
+#define DIV_EGL 0x0600
+#define DIV_EGL_PLL_FDET 0x0604
+#define DIV_STAT_EGL 0x0700
+#define DIV_STAT_EGL_PLL_FDET 0x0704
+#define EN_ACLK_EGL 0x0800
+#define EN_PCLK_EGL 0x0900
+#define EN_SCLK_EGL 0x0a00
+#define EN_IP_EGL 0x0b00
+#define CLKOUT_CMU_EGL 0x0c00
+#define CLKOUT_CMU_EGL_DIV_STAT 0x0c04
+#define ARMCLK_STOPCTRL 0x1000
+#define EAGLE_EMA_CTRL 0x1008
+#define EAGLE_EMA_STATUS 0x100c
+#define PWR_CTRL 0x1020
+#define PWR_CTRL2 0x1024
+#define CLKSTOP_CTRL 0x1028
+#define INTR_SPREAD_EN 0x1080
+#define INTR_SPREAD_USE_STANDBYWFI 0x1084
+#define INTR_SPREAD_BLOCKING_DURATION 0x1088
+#define CMU_EGL_SPARE0 0x2000
+#define CMU_EGL_SPARE1 0x2004
+#define CMU_EGL_SPARE2 0x2008
+#define CMU_EGL_SPARE3 0x200c
+#define CMU_EGL_SPARE4 0x2010
+
+/*
+*Registers for CMU_FSYS
+*/
+
+#define MUX_SEL_FSYS0 0x0200
+#define MUX_SEL_FSYS1 0x0204
+#define MUX_ENABLE_FSYS0 0x0300
+#define MUX_ENABLE_FSYS1 0x0304
+#define MUX_STAT_FSYS0 0x0400
+#define MUX_STAT_FSYS1 0x0404
+#define MUX_IGNORE_FSYS0 0x0500
+#define MUX_IGNORE_FSYS1 0x0504
+#define EN_ACLK_FSYS 0x0800
+#define EN_ACLK_FSYS_SECURE_RTIC 0x0804
+#define EN_ACLK_FSYS_SECURE_SMMU_RTIC 0x0808
+#define EN_PCLK_FSYS 0x0900
+#define EN_SCLK_FSYS 0x0a00
+#define EN_IP_FSYS 0x0b00
+#define EN_IP_FSYS_SECURE_RTIC 0x0b04
+#define EN_IP_FSYS_SECURE_SMMU_RTIC 0x0b08
+
+/*
+*Registers for CMU_G2D
+*/
+
+#define MUX_SEL_G2D 0x0200
+#define MUX_ENABLE_G2D 0x0300
+#define MUX_STAT_G2D 0x0400
+#define DIV_G2D 0x0600
+#define DIV_STAT_G2D 0x0700
+#define EN_ACLK_G2D 0x0800
+#define EN_ACLK_G2D_SECURE_SSS 0x0804
+#define EN_ACLK_G2D_SECURE_SLIM_SSS 0x0808
+#define EN_ACLK_G2D_SECURE_SMMU_SLIM_SSS 0x080c
+#define EN_ACLK_G2D_SECURE_SMMU_SSS 0x0810
+#define EN_ACLK_G2D_SECURE_SMMU_MDMA 0x0814
+#define EN_ACLK_G2D_SECURE_SMMU_G2D 0x0818
+#define EN_PCLK_G2D 0x0900
+#define EN_PCLK_G2D_SECURE_SMMU_SLIM_SSS 0x0904
+#define EN_PCLK_G2D_SECURE_SMMU_SSS 0x0908
+#define EN_PCLK_G2D_SECURE_SMMU_MDMA 0x090c
+#define EN_PCLK_G2D_SECURE_SMMU_G2D 0x0910
+#define EN_IP_G2D 0x0b00
+#define EN_IP_G2D_SECURE_SSS 0x0b04
+#define EN_IP_G2D_SECURE_SLIM_SSS 0x0b08
+#define EN_IP_G2D_SECURE_SMMU_SLIM_SSS 0x0b0c
+#define EN_IP_G2D_SECURE_SMMU_SSS 0x0b10
+#define EN_IP_G2D_SECURE_SMMU_MDMA 0x0b14
+#define EN_IP_G2D_SECURE_SMMU_G2D 0x0b18
+
+/*
+*Registers for CMU_G3D
+*/
+
+#define G3D_PLL_LOCK 0x0000
+#define G3D_PLL_CON0 0x0100
+#define G3D_PLL_CON1 0x0104
+#define G3D_PLL_FDET 0x010c
+#define MUX_SEL_G3D 0x0200
+#define MUX_EN_G3D 0x0300
+#define MUX_STAT_G3D 0x0400
+#define MUX_IGNORE_G3D 0x0500
+#define DIV_G3D 0x0600
+#define DIV_G3D_PLL_FDET 0x0604
+#define DIV_STAT_G3D 0x0700
+#define DIV_STAT_G3D_PLL_FDET 0x0704
+#define EN_ACLK_G3D 0x0800
+#define EN_PCLK_G3D 0x0900
+#define EN_SCLK_G3D 0x0a00
+#define EN_IP_G3D 0x0b00
+#define CLKOUT_CMU_G3D 0x0c00
+#define CLKOUT_CMU_G3D_DIV_STAT 0x0c04
+#define G3DCLK_STOPCTRL 0x1000
+#define G3D_EMA_CTRL 0x1008
+#define G3D_EMA_STATUS 0x100c
+
+/*
+*Registers for CMU_GSCL
+*/
+
+#define MUX_SEL_GSCL 0x0200
+#define MUX_EN_GSCL 0x0300
+#define MUX_STAT_GSCL 0x0400
+#define MUX_IGNORE_GSCL 0x0500
+#define DIV_GSCL 0x0600
+#define DIV_STAT_GSCL 0x0700
+#define EN_ACLK_GSCL 0x0800
+#define EN_ACLK_GSCL_FIMC 0x0804
+#define EN_ACLK_GSCL_SECURE_SMMU_GSCL0 0x0808
+#define EN_ACLK_GSCL_SECURE_SMMU_GSCL1 0x080c
+#define EN_ACLK_GSCL_SECURE_SMMU_MSCL0 0x0810
+#define EN_ACLK_GSCL_SECURE_SMMU_MSCL1 0x0814
+#define EN_PCLK_GSCL 0x0900
+#define EN_PCLK_GSCL_FIMC 0x0904
+#define EN_PCLK_GSCL_SECURE_SMMU_GSCL0 0x0908
+#define EN_PCLK_GSCL_SECURE_SMMU_GSCL1 0x090c
+#define EN_PCLK_GSCL_SECURE_SMMU_MSCL0 0x0910
+#define EN_PCLK_GSCL_SECURE_SMMU_MSCL1 0x0914
+#define EN_SCLK_GSCL 0x0a00
+#define EN_SCLK_GSCL_FIMC 0x0a04
+#define EN_IP_GSCL 0x0b00
+#define EN_IP_GSCL_FIMC 0x0b04
+#define EN_IP_GSCL_SECURE_SMMU_GSCL0 0x0b08
+#define EN_IP_GSCL_SECURE_SMMU_GSCL1 0x0b0c
+#define EN_IP_GSCL_SECURE_SMMU_MSCL0 0x0b10
+#define EN_IP_GSCL_SECURE_SMMU_MSCL1 0x0b14
+
+/*
+*Registers for CMU_ISP
+*/
+#define MUX_SEL_ISP0 0x0200
+#define MUX_SEL_ISP1 0x0204
+#define MUX_ENABLE_ISP0 0x0300
+#define MUX_ENABLE_ISP1 0x0304
+#define MUX_STAT_ISP0 0x0400
+#define MUX_STAT_ISP1 0x0404
+#define MUX_IGNORE_ISP0 0x0500
+#define MUX_IGNORE_ISP1 0x0504
+#define DIV_ISP 0x0600
+#define DIV_STAT_ISP 0x0700
+#define EN_ACLK_ISP0 0x0800
+#define EN_ACLK_ISP1 0x0804
+#define EN_PCLK_ISP0 0x0900
+#define EN_PCLK_ISP1 0x0904
+#define EN_SCLK_ISP 0x0a00
+#define EN_IP_ISP0 0x0b00
+#define EN_IP_ISP1 0x0b04
+
+/*
+*Registers for CMU_KFC
+*/
+#define KFC_PLL_LOCK 0x0000
+#define KFC_PLL_CON0 0x0100
+#define KFC_PLL_CON1 0x0104
+#define KFC_PLL_FDET 0x010c
+#define MUX_SEL_KFC0 0x0200
+#define MUX_SEL_KFC2 0x0208
+#define MUX_ENABLE_KFC0 0x0300
+#define MUX_ENABLE_KFC2 0x0308
+#define MUX_STAT_KFC0 0x0400
+#define MUX_STAT_KFC2 0x0408
+#define DIV_KFC 0x0600
+#define DIV_KFC_PLL_FDET 0x0604
+#define DIV_STAT_KFC 0x0700
+#define DIV_STAT_KFC_PLL_FDET 0x0704
+#define EN_ACLK_KFC 0x0800
+#define EN_PCLK_KFC 0x0900
+#define EN_SCLK_KFC 0x0a00
+#define EN_IP_KFC 0x0b00
+#define CLKOUT_CMU_KFC 0x0c00
+#define CLKOUT_CMU_KFC_DIV_STAT 0x0c04
+#define ARMCLK_STOPCTRL_KFC 0x1000
+#define ARM_EMA_CTRL 0x1008
+#define ARM_EMA_STATUS 0x100c
+#define PWR_CTRL_KFC 0x1020
+#define PWR_CTRL2_KFC 0x1024
+#define CLKSTOP_CTRL_KFC 0x1028
+#define INTR_SPREAD_ENABLE_KFC 0x1080
+#define INTR_SPREAD_USE_STANDBYWFI_KFC 0x1084
+#define INTR_SPREAD_BLOCKING_DURATION_KFC 0x1088
+#define CMU_KFC_SPARE0 0x2000
+#define CMU_KFC_SPARE1 0x2004
+#define CMU_KFC_SPARE2 0x2008
+#define CMU_KFC_SPARE3 0x200c
+#define CMU_KFC_SPARE4 0x2010
+
+/*
+*Registers for CMU_MFC
+*/
+#define MUX_SEL_MFC 0x0200
+#define MUX_ENABLE_MFC 0x0300
+#define MUX_STAT_MFC 0x0400
+#define DIV_MFC 0x0600
+#define DIV_STAT_MFC 0x0700
+#define EN_ACLK_MFC 0x0800
+#define EN_ACLK_SECURE_SMMU2_MFC 0x0804
+#define EN_PCLK_MFC 0x0900
+#define EN_PCLK_SECURE_SMMU2_MFC 0x0904
+#define EN_IP_MFC 0x0b00
+#define EN_IP_MFC_SECURE_SMMU2_MFC 0x0b04
+
+/*
+*Registers for CMU_MIF
+*/
+#define MEM_PLL_LOCK 0x0000
+#define BUS_PLL_LOCK 0x0004
+#define MEDIA_PLL_LOCK 0x0008
+#define MEM_PLL_CON0 0x0100
+#define MEM_PLL_CON1 0x0104
+#define MEM_PLL_FDET 0x010c
+#define BUS_PLL_CON0 0x0110
+#define BUS_PLL_CON1 0x0114
+#define BUS_PLL_FDET 0x011c
+#define MEDIA_PLL_CON0 0x0120
+#define MEDIA_PLL_CON1 0x0124
+#define MEDIA_PLL_FDET 0x012c
+#define MUX_SEL_MIF 0x0200
+#define MUX_ENABLE_MIF 0x0300
+#define MUX_STAT_MIF 0x0400
+#define MUX_IGNORE_MIF 0x0500
+#define DIV_MIF 0x0600
+#define DIV_MIF_PLL_FDET 0x0604
+#define DIV_STAT_MIF 0x0700
+#define DIV_STAT_MIF_PLL_FDET 0x0704
+#define EN_ACLK_MIF 0x0800
+#define EN_ACLK_MIF_SECURE_DREX1_TZ 0x0804
+#define EN_ACLK_MIF_SECURE_DREX0_TZ 0x0808
+#define EN_ACLK_MIF_SECURE_INTMEM 0x080c
+#define EN_PCLK_MIF 0x0900
+#define EN_PCLK_MIF_SECURE_MONOCNT 0x0904
+#define EN_PCLK_MIF_SECURE_RTC_APBIF 0x0908
+#define EN_PCLK_MIF_SECURE_DREX1_TZ 0x090c
+#define EN_PCLK_MIF_SECURE_DREX0_TZ 0x0910
+#define EN_SCLK_MIF 0x0a00
+#define EN_IP_MIF 0x0b00
+#define EN_IP_MIF_SECURE_MONOCNT 0x0b04
+#define EN_IP_MIF_SECURE_RTC_APBIF 0x0b08
+#define EN_IP_MIF_SECURE_DREX1_TZ 0x0b0c
+#define EN_IP_MIF_SECURE_DREX0_TZ 0x0b10
+#define EN_IP_MIF_SECURE_INTEMEM 0x0b14
+#define CLKOUT_CMU_MIF_DIV_STAT 0x0c04
+#define DREX_FREQ_CTRL 0x1000
+#define PAUSE 0x1004
+#define DDRPHY_LOCK_CTRL 0x1008
+#define CLKOUT_CMU_MIF 0xcb00
+
+/*
+*Registers for CMU_PERI
+*/
+#define MUX_SEL_PERI 0x0200
+#define MUX_SEL_PERI1 0x0204
+#define MUX_ENABLE_PERI 0x0300
+#define MUX_ENABLE_PERI1 0x0304
+#define MUX_STAT_PERI 0x0400
+#define MUX_STAT_PERI1 0x0404
+#define MUX_IGNORE_PERI 0x0500
+#define MUX_IGNORE_PERI1 0x0504
+#define DIV_PERI 0x0600
+#define DIV_STAT_PERI 0x0700
+#define EN_PCLK_PERI0 0x0800
+#define EN_PCLK_PERI1 0x0804
+#define EN_PCLK_PERI2 0x0808
+#define EN_PCLK_PERI3 0x080c
+#define EN_PCLK_PERI_SECURE_CHIPID 0x0810
+#define EN_PCLK_PERI_SECURE_PROVKEY0 0x0814
+#define EN_PCLK_PERI_SECURE_PROVKEY1 0x0818
+#define EN_PCLK_PERI_SECURE_SECKEY 0x081c
+#define EN_PCLK_PERI_SECURE_ANTIRBKCNT 0x0820
+#define EN_PCLK_PERI_SECURE_TOP_RTC 0x0824
+#define EN_PCLK_PERI_SECURE_TZPC 0x0828
+#define EN_SCLK_PERI 0x0a00
+#define EN_SCLK_PERI_SECURE_TOP_RTC 0x0a04
+#define EN_IP_PERI0 0x0b00
+#define EN_IP_PERI1 0x0b04
+#define EN_IP_PERI2 0x0b08
+#define EN_IP_PERI_SECURE_CHIPID 0x0b0c
+#define EN_IP_PERI_SECURE_PROVKEY0 0x0b10
+#define EN_IP_PERI_SECURE_PROVKEY1 0x0b14
+#define EN_IP_PERI_SECURE_SECKEY 0x0b18
+#define EN_IP_PERI_SECURE_ANTIRBKCNT 0x0b1c
+#define EN_IP_PERI_SECURE_TOP_RTC 0x0b20
+#define EN_IP_PERI_SECURE_TZPC 0x0b24
+
+/*
+*Registers for CMU_TOP
+*/
+#define DISP_PLL_LOCK 0x0000
+#define AUD_PLL_LOCK 0x0004
+#define DISP_PLL_CON0 0x0100
+#define DISP_PLL_CON1 0x0104
+#define DISP_PLL_FDET 0x0108
+#define AUD_PLL_CON0 0x0110
+#define AUD_PLL_CON1 0x0114
+#define AUD_PLL_CON2 0x0118
+#define AUD_PLL_FDET 0x011c
+#define MUX_SEL_TOP_PLL0 0x0200
+#define MUX_SEL_TOP_MFC 0x0204
+#define MUX_SEL_TOP_G2D 0x0208
+#define MUX_SEL_TOP_GSCL 0x020c
+#define MUX_SEL_TOP_ISP10 0x0214
+#define MUX_SEL_TOP_ISP11 0x0218
+#define MUX_SEL_TOP_DISP0 0x021c
+#define MUX_SEL_TOP_DISP1 0x0220
+#define MUX_SEL_TOP_BUS 0x0224
+#define MUX_SEL_TOP_PERI0 0x0228
+#define MUX_SEL_TOP_PERI1 0x022c
+#define MUX_SEL_TOP_FSYS 0x0230
+#define MUX_ENABLE_TOP_PLL0 0x0300
+#define MUX_ENABLE_TOP_MFC 0x0304
+#define MUX_ENABLE_TOP_G2D 0x0308
+#define MUX_ENABLE_TOP_GSCL 0x030c
+#define MUX_ENABLE_TOP_ISP10 0x0314
+#define MUX_ENABLE_TOP_ISP11 0x0318
+#define MUX_ENABLE_TOP_DISP0 0x031c
+#define MUX_ENABLE_TOP_DISP1 0x0320
+#define MUX_ENABLE_TOP_BUS 0x0324
+#define MUX_ENABLE_TOP_PERI0 0x0328
+#define MUX_ENABLE_TOP_PERI1 0x032c
+#define MUX_ENABLE_TOP_FSYS 0x0330
+#define MUX_STAT_TOP_PLL0 0x0400
+#define MUX_STAT_TOP_MFC 0x0404
+#define MUX_STAT_TOP_G2D 0x0408
+#define MUX_STAT_TOP_GSCL 0x040c
+#define MUX_STAT_TOP_ISP10 0x0414
+#define MUX_STAT_TOP_ISP11 0x0418
+#define MUX_STAT_TOP_DISP0 0x041c
+#define MUX_STAT_TOP_DISP1 0x0420
+#define MUX_STAT_TOP_BUS 0x0424
+#define MUX_STAT_TOP_PERI0 0x0428
+#define MUX_STAT_TOP_PERI1 0x042c
+#define MUX_STAT_TOP_FSYS 0x0430
+#define MUX_IGNORE_TOP_PLL0 0x0500
+#define MUX_IGNORE_TOP_MFC 0x0504
+#define MUX_IGNORE_TOP_G2D 0x0508
+#define MUX_IGNORE_TOP_GSCL 0x050c
+#define MUX_IGNORE_TOP_ISP10 0x0514
+#define MUX_IGNORE_TOP_ISP11 0x0518
+#define MUX_IGNORE_TOP_DISP0 0x051c
+#define MUX_IGNORE_TOP_DISP1 0x0520
+#define MUX_IGNORE_TOP_BUS 0x0524
+#define MUX_IGNORE_TOP_PERI0 0x0528
+#define MUX_IGNORE_TOP_PERI1 0x052c
+#define MUX_IGNORE_TOP_FSYS 0x0530
+#define DIV_TOP_G2D_MFC 0x0600
+#define DIV_TOP_GSCL_ISP0 0x0604
+#define DIV_TOP_ISP10 0x0608
+#define DIV_TOP_ISP11 0x060c
+#define DIV_TOP_DISP 0x0610
+#define DIV_TOP_BUS 0x0614
+#define DIV_TOP_PERI0 0x0618
+#define DIV_TOP_PERI1 0x061c
+#define DIV_TOP_PERI2 0x0620
+#define DIV_TOP_FSYS0 0x0624
+#define DIV_TOP_FSYS1 0x0628
+#define DIV_TOP_HPM 0x062c
+#define DIV_TOP_PLL_FDET 0x0630
+#define DIV_STAT_TOP_G2D_MFC 0x0700
+#define DIV_STAT_TOP_GSCL_ISP0 0x0704
+#define DIV_STAT_TOP_ISP10 0x0708
+#define DIV_STAT_TOP_ISP11 0x070c
+#define DIV_STAT_TOP_DISP 0x0710
+#define DIV_STAT_TOP_BUS 0x0714
+#define DIV_STAT_TOP_PERI0 0x0718
+#define DIV_STAT_TOP_PERI1 0x071c
+#define DIV_STAT_TOP_PERI2 0x0720
+#define DIV_STAT_TOP_FSYS0 0x0724
+#define DIV_STAT_TOP_FSYS1 0x0728
+#define DIV_STAT_TOP_HPM 0x072c
+#define DIV_STAT_TOP_PLL_FDET 0x0730
+#define EN_ACLK_TOP 0x0800
+#define EN_SCLK_TOP 0x0a00
+#define EN_IP_TOP 0x0b00
+#define CLKOUT_CMU_TOP 0x0c00
+#define CLKOUT_CMU_TOP_DIV_STAT 0x0c04
+
+#endif /*__CLK_EXYNOS5260_H */
+
diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c
new file mode 100644
index 000000000000..c9505ab9ee70
--- /dev/null
+++ b/drivers/clk/samsung/clk-exynos5410.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Author: Tarek Dakhran <t.dakhran@samsung.com>
+ *
+ * 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.
+ *
+ * Common Clock Framework support for Exynos5410 SoC.
+*/
+
+#include <dt-bindings/clock/exynos5410.h>
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "clk.h"
+
+#define APLL_LOCK 0x0
+#define APLL_CON0 0x100
+#define CPLL_LOCK 0x10020
+#define CPLL_CON0 0x10120
+#define MPLL_LOCK 0x4000
+#define MPLL_CON0 0x4100
+#define BPLL_LOCK 0x20010
+#define BPLL_CON0 0x20110
+#define KPLL_LOCK 0x28000
+#define KPLL_CON0 0x28100
+
+#define SRC_CPU 0x200
+#define DIV_CPU0 0x500
+#define SRC_CPERI1 0x4204
+#define DIV_TOP0 0x10510
+#define DIV_TOP1 0x10514
+#define DIV_FSYS1 0x1054c
+#define DIV_FSYS2 0x10550
+#define DIV_PERIC0 0x10558
+#define SRC_TOP0 0x10210
+#define SRC_TOP1 0x10214
+#define SRC_TOP2 0x10218
+#define SRC_FSYS 0x10244
+#define SRC_PERIC0 0x10250
+#define SRC_MASK_FSYS 0x10340
+#define SRC_MASK_PERIC0 0x10350
+#define GATE_BUS_FSYS0 0x10740
+#define GATE_IP_FSYS 0x10944
+#define GATE_IP_PERIC 0x10950
+#define GATE_IP_PERIS 0x10960
+#define SRC_CDREX 0x20200
+#define SRC_KFC 0x28200
+#define DIV_KFC0 0x28500
+
+/* list of PLLs */
+enum exynos5410_plls {
+ apll, cpll, mpll,
+ bpll, kpll,
+ nr_plls /* number of PLLs */
+};
+
+/* list of all parent clocks */
+PNAME(apll_p) = { "fin_pll", "fout_apll", };
+PNAME(bpll_p) = { "fin_pll", "fout_bpll", };
+PNAME(cpll_p) = { "fin_pll", "fout_cpll" };
+PNAME(mpll_p) = { "fin_pll", "fout_mpll", };
+PNAME(kpll_p) = { "fin_pll", "fout_kpll", };
+
+PNAME(mout_cpu_p) = { "mout_apll", "sclk_mpll", };
+PNAME(mout_kfc_p) = { "mout_kpll", "sclk_mpll", };
+
+PNAME(mpll_user_p) = { "fin_pll", "sclk_mpll", };
+PNAME(bpll_user_p) = { "fin_pll", "sclk_bpll", };
+PNAME(mpll_bpll_p) = { "sclk_mpll_muxed", "sclk_bpll_muxed", };
+
+PNAME(group2_p) = { "fin_pll", "fin_pll", "none", "none",
+ "none", "none", "sclk_mpll_bpll",
+ "none", "none", "sclk_cpll" };
+
+static struct samsung_mux_clock exynos5410_mux_clks[] __initdata = {
+ MUX(0, "mout_apll", apll_p, SRC_CPU, 0, 1),
+ MUX(0, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1),
+
+ MUX(0, "mout_kpll", kpll_p, SRC_KFC, 0, 1),
+ MUX(0, "mout_kfc", mout_kfc_p, SRC_KFC, 16, 1),
+
+ MUX(0, "sclk_mpll", mpll_p, SRC_CPERI1, 8, 1),
+ MUX(0, "sclk_mpll_muxed", mpll_user_p, SRC_TOP2, 20, 1),
+
+ MUX(0, "sclk_bpll", bpll_p, SRC_CDREX, 0, 1),
+ MUX(0, "sclk_bpll_muxed", bpll_user_p, SRC_TOP2, 24, 1),
+
+ MUX(0, "sclk_cpll", cpll_p, SRC_TOP2, 8, 1),
+
+ MUX(0, "sclk_mpll_bpll", mpll_bpll_p, SRC_TOP1, 20, 1),
+
+ MUX(0, "mout_mmc0", group2_p, SRC_FSYS, 0, 4),
+ MUX(0, "mout_mmc1", group2_p, SRC_FSYS, 4, 4),
+ MUX(0, "mout_mmc2", group2_p, SRC_FSYS, 8, 4),
+
+ MUX(0, "mout_uart0", group2_p, SRC_PERIC0, 0, 4),
+ MUX(0, "mout_uart1", group2_p, SRC_PERIC0, 4, 4),
+ MUX(0, "mout_uart2", group2_p, SRC_PERIC0, 8, 4),
+
+ MUX(0, "mout_aclk200", mpll_bpll_p, SRC_TOP0, 12, 1),
+ MUX(0, "mout_aclk400", mpll_bpll_p, SRC_TOP0, 20, 1),
+};
+
+static struct samsung_div_clock exynos5410_div_clks[] __initdata = {
+ DIV(0, "div_arm", "mout_cpu", DIV_CPU0, 0, 3),
+ DIV(0, "div_arm2", "div_arm", DIV_CPU0, 28, 3),
+
+ DIV(0, "div_acp", "div_arm2", DIV_CPU0, 8, 3),
+ DIV(0, "div_cpud", "div_arm2", DIV_CPU0, 4, 3),
+ DIV(0, "div_atb", "div_arm2", DIV_CPU0, 16, 3),
+ DIV(0, "pclk_dbg", "div_arm2", DIV_CPU0, 20, 3),
+
+ DIV(0, "div_kfc", "mout_kfc", DIV_KFC0, 0, 3),
+ DIV(0, "div_aclk", "div_kfc", DIV_KFC0, 4, 3),
+ DIV(0, "div_pclk", "div_kfc", DIV_KFC0, 20, 3),
+
+ DIV(0, "aclk66_pre", "sclk_mpll_muxed", DIV_TOP1, 24, 3),
+ DIV(0, "aclk66", "aclk66_pre", DIV_TOP0, 0, 3),
+
+ DIV(0, "div_mmc0", "mout_mmc0", DIV_FSYS1, 0, 4),
+ DIV(0, "div_mmc1", "mout_mmc1", DIV_FSYS1, 16, 4),
+ DIV(0, "div_mmc2", "mout_mmc2", DIV_FSYS2, 0, 4),
+
+ DIV_F(0, "div_mmc_pre0", "div_mmc0",
+ DIV_FSYS1, 8, 8, CLK_SET_RATE_PARENT, 0),
+ DIV_F(0, "div_mmc_pre1", "div_mmc1",
+ DIV_FSYS1, 24, 8, CLK_SET_RATE_PARENT, 0),
+ DIV_F(0, "div_mmc_pre2", "div_mmc2",
+ DIV_FSYS2, 8, 8, CLK_SET_RATE_PARENT, 0),
+
+ DIV(0, "div_uart0", "mout_uart0", DIV_PERIC0, 0, 4),
+ DIV(0, "div_uart1", "mout_uart1", DIV_PERIC0, 4, 4),
+ DIV(0, "div_uart2", "mout_uart2", DIV_PERIC0, 8, 4),
+ DIV(0, "div_uart3", "mout_uart3", DIV_PERIC0, 12, 4),
+
+ DIV(0, "aclk200", "mout_aclk200", DIV_TOP0, 12, 3),
+ DIV(0, "aclk400", "mout_aclk400", DIV_TOP0, 24, 3),
+};
+
+static struct samsung_gate_clock exynos5410_gate_clks[] __initdata = {
+ GATE(CLK_MCT, "mct", "aclk66", GATE_IP_PERIS, 18, 0, 0),
+
+ GATE(CLK_SCLK_MMC0, "sclk_mmc0", "div_mmc_pre0",
+ SRC_MASK_FSYS, 0, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_MMC1, "sclk_mmc1", "div_mmc_pre1",
+ SRC_MASK_FSYS, 4, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_MMC2, "sclk_mmc2", "div_mmc_pre2",
+ SRC_MASK_FSYS, 8, CLK_SET_RATE_PARENT, 0),
+
+ GATE(CLK_MMC0, "sdmmc0", "aclk200", GATE_BUS_FSYS0, 12, 0, 0),
+ GATE(CLK_MMC1, "sdmmc1", "aclk200", GATE_BUS_FSYS0, 13, 0, 0),
+ GATE(CLK_MMC2, "sdmmc2", "aclk200", GATE_BUS_FSYS0, 14, 0, 0),
+
+ GATE(CLK_UART0, "uart0", "aclk66", GATE_IP_PERIC, 0, 0, 0),
+ GATE(CLK_UART1, "uart1", "aclk66", GATE_IP_PERIC, 1, 0, 0),
+ GATE(CLK_UART2, "uart2", "aclk66", GATE_IP_PERIC, 2, 0, 0),
+
+ GATE(CLK_SCLK_UART0, "sclk_uart0", "div_uart0",
+ SRC_MASK_PERIC0, 0, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_UART1, "sclk_uart1", "div_uart1",
+ SRC_MASK_PERIC0, 4, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_UART2, "sclk_uart2", "div_uart2",
+ SRC_MASK_PERIC0, 8, CLK_SET_RATE_PARENT, 0),
+};
+
+static struct samsung_pll_clock exynos5410_plls[nr_plls] __initdata = {
+ [apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll", APLL_LOCK,
+ APLL_CON0, NULL),
+ [cpll] = PLL(pll_35xx, CLK_FOUT_CPLL, "fout_cpll", "fin_pll", CPLL_LOCK,
+ CPLL_CON0, NULL),
+ [mpll] = PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll", MPLL_LOCK,
+ MPLL_CON0, NULL),
+ [bpll] = PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll", BPLL_LOCK,
+ BPLL_CON0, NULL),
+ [kpll] = PLL(pll_35xx, CLK_FOUT_KPLL, "fout_kpll", "fin_pll", KPLL_LOCK,
+ KPLL_CON0, NULL),
+};
+
+/* register exynos5410 clocks */
+static void __init exynos5410_clk_init(struct device_node *np)
+{
+ struct samsung_clk_provider *ctx;
+ void __iomem *reg_base;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base)
+ panic("%s: failed to map registers\n", __func__);
+
+ ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
+
+ samsung_clk_register_pll(ctx, exynos5410_plls,
+ ARRAY_SIZE(exynos5410_plls), reg_base);
+
+ samsung_clk_register_mux(ctx, exynos5410_mux_clks,
+ ARRAY_SIZE(exynos5410_mux_clks));
+ samsung_clk_register_div(ctx, exynos5410_div_clks,
+ ARRAY_SIZE(exynos5410_div_clks));
+ samsung_clk_register_gate(ctx, exynos5410_gate_clks,
+ ARRAY_SIZE(exynos5410_gate_clks));
+
+ pr_debug("Exynos5410: clock setup completed.\n");
+}
+CLK_OF_DECLARE(exynos5410_clk, "samsung,exynos5410-clock", exynos5410_clk_init);
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index 60b26819bed5..a4e6cc782e5c 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -27,18 +27,24 @@
#define DIV_CPU1 0x504
#define GATE_BUS_CPU 0x700
#define GATE_SCLK_CPU 0x800
+#define CLKOUT_CMU_CPU 0xa00
+#define GATE_IP_G2D 0x8800
#define CPLL_LOCK 0x10020
#define DPLL_LOCK 0x10030
#define EPLL_LOCK 0x10040
#define RPLL_LOCK 0x10050
#define IPLL_LOCK 0x10060
#define SPLL_LOCK 0x10070
-#define VPLL_LOCK 0x10070
+#define VPLL_LOCK 0x10080
#define MPLL_LOCK 0x10090
#define CPLL_CON0 0x10120
#define DPLL_CON0 0x10128
#define EPLL_CON0 0x10130
+#define EPLL_CON1 0x10134
+#define EPLL_CON2 0x10138
#define RPLL_CON0 0x10140
+#define RPLL_CON1 0x10144
+#define RPLL_CON2 0x10148
#define IPLL_CON0 0x10150
#define SPLL_CON0 0x10160
#define VPLL_CON0 0x10170
@@ -51,21 +57,31 @@
#define SRC_TOP5 0x10214
#define SRC_TOP6 0x10218
#define SRC_TOP7 0x1021c
+#define SRC_TOP8 0x10220 /* 5800 specific */
+#define SRC_TOP9 0x10224 /* 5800 specific */
#define SRC_DISP10 0x1022c
#define SRC_MAU 0x10240
#define SRC_FSYS 0x10244
#define SRC_PERIC0 0x10250
#define SRC_PERIC1 0x10254
+#define SRC_ISP 0x10270
+#define SRC_CAM 0x10274 /* 5800 specific */
#define SRC_TOP10 0x10280
#define SRC_TOP11 0x10284
#define SRC_TOP12 0x10288
-#define SRC_MASK_DISP10 0x1032c
+#define SRC_TOP13 0x1028c /* 5800 specific */
+#define SRC_MASK_TOP2 0x10308
+#define SRC_MASK_TOP7 0x1031c
+#define SRC_MASK_DISP10 0x1032c
+#define SRC_MASK_MAU 0x10334
#define SRC_MASK_FSYS 0x10340
#define SRC_MASK_PERIC0 0x10350
#define SRC_MASK_PERIC1 0x10354
#define DIV_TOP0 0x10500
#define DIV_TOP1 0x10504
#define DIV_TOP2 0x10508
+#define DIV_TOP8 0x10520 /* 5800 specific */
+#define DIV_TOP9 0x10524 /* 5800 specific */
#define DIV_DISP10 0x1052c
#define DIV_MAU 0x10544
#define DIV_FSYS0 0x10548
@@ -76,54 +92,82 @@
#define DIV_PERIC2 0x10560
#define DIV_PERIC3 0x10564
#define DIV_PERIC4 0x10568
+#define DIV_CAM 0x10574 /* 5800 specific */
+#define SCLK_DIV_ISP0 0x10580
+#define SCLK_DIV_ISP1 0x10584
+#define DIV2_RATIO0 0x10590
+#define DIV4_RATIO 0x105a0
#define GATE_BUS_TOP 0x10700
+#define GATE_BUS_GEN 0x1073c
#define GATE_BUS_FSYS0 0x10740
+#define GATE_BUS_FSYS2 0x10748
#define GATE_BUS_PERIC 0x10750
#define GATE_BUS_PERIC1 0x10754
#define GATE_BUS_PERIS0 0x10760
#define GATE_BUS_PERIS1 0x10764
+#define GATE_BUS_NOC 0x10770
+#define GATE_TOP_SCLK_ISP 0x10870
#define GATE_IP_GSCL0 0x10910
#define GATE_IP_GSCL1 0x10920
+#define GATE_IP_CAM 0x10924 /* 5800 specific */
#define GATE_IP_MFC 0x1092c
#define GATE_IP_DISP1 0x10928
#define GATE_IP_G3D 0x10930
#define GATE_IP_GEN 0x10934
+#define GATE_IP_FSYS 0x10944
+#define GATE_IP_PERIC 0x10950
+#define GATE_IP_PERIS 0x10960
#define GATE_IP_MSCL 0x10970
#define GATE_TOP_SCLK_GSCL 0x10820
#define GATE_TOP_SCLK_DISP1 0x10828
#define GATE_TOP_SCLK_MAU 0x1083c
#define GATE_TOP_SCLK_FSYS 0x10840
#define GATE_TOP_SCLK_PERIC 0x10850
+#define TOP_SPARE2 0x10b08
#define BPLL_LOCK 0x20010
#define BPLL_CON0 0x20110
-#define SRC_CDREX 0x20200
#define KPLL_LOCK 0x28000
#define KPLL_CON0 0x28100
#define SRC_KFC 0x28200
#define DIV_KFC0 0x28500
+/* Exynos5x SoC type */
+enum exynos5x_soc {
+ EXYNOS5420,
+ EXYNOS5800,
+};
+
/* list of PLLs */
-enum exynos5420_plls {
+enum exynos5x_plls {
apll, cpll, dpll, epll, rpll, ipll, spll, vpll, mpll,
bpll, kpll,
nr_plls /* number of PLLs */
};
static void __iomem *reg_base;
+static enum exynos5x_soc exynos5x_soc;
#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos5420_save;
+static struct samsung_clk_reg_dump *exynos5x_save;
+static struct samsung_clk_reg_dump *exynos5800_save;
/*
* list of controller registers to be saved and restored during a
* suspend/resume cycle.
*/
-static unsigned long exynos5420_clk_regs[] __initdata = {
+static unsigned long exynos5x_clk_regs[] __initdata = {
SRC_CPU,
DIV_CPU0,
DIV_CPU1,
GATE_BUS_CPU,
GATE_SCLK_CPU,
+ CLKOUT_CMU_CPU,
+ EPLL_CON0,
+ EPLL_CON1,
+ EPLL_CON2,
+ RPLL_CON0,
+ RPLL_CON1,
+ RPLL_CON2,
SRC_TOP0,
SRC_TOP1,
SRC_TOP2,
@@ -140,10 +184,13 @@ static unsigned long exynos5420_clk_regs[] __initdata = {
SRC_TOP10,
SRC_TOP11,
SRC_TOP12,
+ SRC_MASK_TOP2,
+ SRC_MASK_TOP7,
SRC_MASK_DISP10,
SRC_MASK_FSYS,
SRC_MASK_PERIC0,
SRC_MASK_PERIC1,
+ SRC_ISP,
DIV_TOP0,
DIV_TOP1,
DIV_TOP2,
@@ -157,41 +204,71 @@ static unsigned long exynos5420_clk_regs[] __initdata = {
DIV_PERIC2,
DIV_PERIC3,
DIV_PERIC4,
+ SCLK_DIV_ISP0,
+ SCLK_DIV_ISP1,
+ DIV2_RATIO0,
+ DIV4_RATIO,
GATE_BUS_TOP,
+ GATE_BUS_GEN,
GATE_BUS_FSYS0,
+ GATE_BUS_FSYS2,
GATE_BUS_PERIC,
GATE_BUS_PERIC1,
GATE_BUS_PERIS0,
GATE_BUS_PERIS1,
+ GATE_BUS_NOC,
+ GATE_TOP_SCLK_ISP,
GATE_IP_GSCL0,
GATE_IP_GSCL1,
GATE_IP_MFC,
GATE_IP_DISP1,
GATE_IP_G3D,
GATE_IP_GEN,
+ GATE_IP_FSYS,
+ GATE_IP_PERIC,
+ GATE_IP_PERIS,
GATE_IP_MSCL,
GATE_TOP_SCLK_GSCL,
GATE_TOP_SCLK_DISP1,
GATE_TOP_SCLK_MAU,
GATE_TOP_SCLK_FSYS,
GATE_TOP_SCLK_PERIC,
- SRC_CDREX,
+ TOP_SPARE2,
SRC_KFC,
DIV_KFC0,
};
+static unsigned long exynos5800_clk_regs[] __initdata = {
+ SRC_TOP8,
+ SRC_TOP9,
+ SRC_CAM,
+ SRC_TOP1,
+ DIV_TOP8,
+ DIV_TOP9,
+ DIV_CAM,
+ GATE_IP_CAM,
+};
+
static int exynos5420_clk_suspend(void)
{
- samsung_clk_save(reg_base, exynos5420_save,
- ARRAY_SIZE(exynos5420_clk_regs));
+ samsung_clk_save(reg_base, exynos5x_save,
+ ARRAY_SIZE(exynos5x_clk_regs));
+
+ if (exynos5x_soc == EXYNOS5800)
+ samsung_clk_save(reg_base, exynos5800_save,
+ ARRAY_SIZE(exynos5800_clk_regs));
return 0;
}
static void exynos5420_clk_resume(void)
{
- samsung_clk_restore(reg_base, exynos5420_save,
- ARRAY_SIZE(exynos5420_clk_regs));
+ samsung_clk_restore(reg_base, exynos5x_save,
+ ARRAY_SIZE(exynos5x_clk_regs));
+
+ if (exynos5x_soc == EXYNOS5800)
+ samsung_clk_restore(reg_base, exynos5800_save,
+ ARRAY_SIZE(exynos5800_clk_regs));
}
static struct syscore_ops exynos5420_clk_syscore_ops = {
@@ -201,108 +278,183 @@ static struct syscore_ops exynos5420_clk_syscore_ops = {
static void exynos5420_clk_sleep_init(void)
{
- exynos5420_save = samsung_clk_alloc_reg_dump(exynos5420_clk_regs,
- ARRAY_SIZE(exynos5420_clk_regs));
- if (!exynos5420_save) {
+ exynos5x_save = samsung_clk_alloc_reg_dump(exynos5x_clk_regs,
+ ARRAY_SIZE(exynos5x_clk_regs));
+ if (!exynos5x_save) {
pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
__func__);
return;
}
+ if (exynos5x_soc == EXYNOS5800) {
+ exynos5800_save =
+ samsung_clk_alloc_reg_dump(exynos5800_clk_regs,
+ ARRAY_SIZE(exynos5800_clk_regs));
+ if (!exynos5800_save)
+ goto err_soc;
+ }
+
register_syscore_ops(&exynos5420_clk_syscore_ops);
+ return;
+err_soc:
+ kfree(exynos5x_save);
+ pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
+ __func__);
+ return;
}
#else
static void exynos5420_clk_sleep_init(void) {}
#endif
/* list of all parent clocks */
-PNAME(mspll_cpu_p) = { "sclk_cpll", "sclk_dpll",
- "sclk_mpll", "sclk_spll" };
-PNAME(cpu_p) = { "mout_apll" , "mout_mspll_cpu" };
-PNAME(kfc_p) = { "mout_kpll" , "mout_mspll_kfc" };
-PNAME(apll_p) = { "fin_pll", "fout_apll", };
-PNAME(bpll_p) = { "fin_pll", "fout_bpll", };
-PNAME(cpll_p) = { "fin_pll", "fout_cpll", };
-PNAME(dpll_p) = { "fin_pll", "fout_dpll", };
-PNAME(epll_p) = { "fin_pll", "fout_epll", };
-PNAME(ipll_p) = { "fin_pll", "fout_ipll", };
-PNAME(kpll_p) = { "fin_pll", "fout_kpll", };
-PNAME(mpll_p) = { "fin_pll", "fout_mpll", };
-PNAME(rpll_p) = { "fin_pll", "fout_rpll", };
-PNAME(spll_p) = { "fin_pll", "fout_spll", };
-PNAME(vpll_p) = { "fin_pll", "fout_vpll", };
-
-PNAME(group1_p) = { "sclk_cpll", "sclk_dpll", "sclk_mpll" };
-PNAME(group2_p) = { "fin_pll", "sclk_cpll", "sclk_dpll", "sclk_mpll",
- "sclk_spll", "sclk_ipll", "sclk_epll", "sclk_rpll" };
-PNAME(group3_p) = { "sclk_rpll", "sclk_spll" };
-PNAME(group4_p) = { "sclk_ipll", "sclk_dpll", "sclk_mpll" };
-PNAME(group5_p) = { "sclk_vpll", "sclk_dpll" };
-
-PNAME(sw_aclk66_p) = { "dout_aclk66", "sclk_spll" };
-PNAME(aclk66_peric_p) = { "fin_pll", "mout_sw_aclk66" };
-
-PNAME(sw_aclk200_fsys_p) = { "dout_aclk200_fsys", "sclk_spll"};
-PNAME(user_aclk200_fsys_p) = { "fin_pll", "mout_sw_aclk200_fsys" };
-
-PNAME(sw_aclk200_fsys2_p) = { "dout_aclk200_fsys2", "sclk_spll"};
-PNAME(user_aclk200_fsys2_p) = { "fin_pll", "mout_sw_aclk200_fsys2" };
-
-PNAME(sw_aclk200_p) = { "dout_aclk200", "sclk_spll"};
-PNAME(aclk200_disp1_p) = { "fin_pll", "mout_sw_aclk200" };
-
-PNAME(sw_aclk400_mscl_p) = { "dout_aclk400_mscl", "sclk_spll"};
-PNAME(user_aclk400_mscl_p) = { "fin_pll", "mout_sw_aclk400_mscl" };
-
-PNAME(sw_aclk333_p) = { "dout_aclk333", "sclk_spll"};
-PNAME(user_aclk333_p) = { "fin_pll", "mout_sw_aclk333" };
-
-PNAME(sw_aclk166_p) = { "dout_aclk166", "sclk_spll"};
-PNAME(user_aclk166_p) = { "fin_pll", "mout_sw_aclk166" };
-
-PNAME(sw_aclk266_p) = { "dout_aclk266", "sclk_spll"};
-PNAME(user_aclk266_p) = { "fin_pll", "mout_sw_aclk266" };
-
-PNAME(sw_aclk333_432_gscl_p) = { "dout_aclk333_432_gscl", "sclk_spll"};
-PNAME(user_aclk333_432_gscl_p) = { "fin_pll", "mout_sw_aclk333_432_gscl" };
-
-PNAME(sw_aclk300_gscl_p) = { "dout_aclk300_gscl", "sclk_spll"};
-PNAME(user_aclk300_gscl_p) = { "fin_pll", "mout_sw_aclk300_gscl" };
-
-PNAME(sw_aclk300_disp1_p) = { "dout_aclk300_disp1", "sclk_spll"};
-PNAME(user_aclk300_disp1_p) = { "fin_pll", "mout_sw_aclk300_disp1" };
-
-PNAME(sw_aclk300_jpeg_p) = { "dout_aclk300_jpeg", "sclk_spll"};
-PNAME(user_aclk300_jpeg_p) = { "fin_pll", "mout_sw_aclk300_jpeg" };
-
-PNAME(sw_aclk_g3d_p) = { "dout_aclk_g3d", "sclk_spll"};
-PNAME(user_aclk_g3d_p) = { "fin_pll", "mout_sw_aclk_g3d" };
-
-PNAME(sw_aclk266_g2d_p) = { "dout_aclk266_g2d", "sclk_spll"};
-PNAME(user_aclk266_g2d_p) = { "fin_pll", "mout_sw_aclk266_g2d" };
-
-PNAME(sw_aclk333_g2d_p) = { "dout_aclk333_g2d", "sclk_spll"};
-PNAME(user_aclk333_g2d_p) = { "fin_pll", "mout_sw_aclk333_g2d" };
-
-PNAME(audio0_p) = { "fin_pll", "cdclk0", "sclk_dpll", "sclk_mpll",
- "sclk_spll", "sclk_ipll", "sclk_epll", "sclk_rpll" };
-PNAME(audio1_p) = { "fin_pll", "cdclk1", "sclk_dpll", "sclk_mpll",
- "sclk_spll", "sclk_ipll", "sclk_epll", "sclk_rpll" };
-PNAME(audio2_p) = { "fin_pll", "cdclk2", "sclk_dpll", "sclk_mpll",
- "sclk_spll", "sclk_ipll", "sclk_epll", "sclk_rpll" };
-PNAME(spdif_p) = { "fin_pll", "dout_audio0", "dout_audio1", "dout_audio2",
- "spdif_extclk", "sclk_ipll", "sclk_epll", "sclk_rpll" };
-PNAME(hdmi_p) = { "dout_hdmi_pixel", "sclk_hdmiphy" };
-PNAME(maudio0_p) = { "fin_pll", "maudio_clk", "sclk_dpll", "sclk_mpll",
- "sclk_spll", "sclk_ipll", "sclk_epll", "sclk_rpll" };
+PNAME(mout_mspll_cpu_p) = {"mout_sclk_cpll", "mout_sclk_dpll",
+ "mout_sclk_mpll", "mout_sclk_spll"};
+PNAME(mout_cpu_p) = {"mout_apll" , "mout_mspll_cpu"};
+PNAME(mout_kfc_p) = {"mout_kpll" , "mout_mspll_kfc"};
+PNAME(mout_apll_p) = {"fin_pll", "fout_apll"};
+PNAME(mout_bpll_p) = {"fin_pll", "fout_bpll"};
+PNAME(mout_cpll_p) = {"fin_pll", "fout_cpll"};
+PNAME(mout_dpll_p) = {"fin_pll", "fout_dpll"};
+PNAME(mout_epll_p) = {"fin_pll", "fout_epll"};
+PNAME(mout_ipll_p) = {"fin_pll", "fout_ipll"};
+PNAME(mout_kpll_p) = {"fin_pll", "fout_kpll"};
+PNAME(mout_mpll_p) = {"fin_pll", "fout_mpll"};
+PNAME(mout_rpll_p) = {"fin_pll", "fout_rpll"};
+PNAME(mout_spll_p) = {"fin_pll", "fout_spll"};
+PNAME(mout_vpll_p) = {"fin_pll", "fout_vpll"};
+
+PNAME(mout_group1_p) = {"mout_sclk_cpll", "mout_sclk_dpll",
+ "mout_sclk_mpll"};
+PNAME(mout_group2_p) = {"fin_pll", "mout_sclk_cpll",
+ "mout_sclk_dpll", "mout_sclk_mpll", "mout_sclk_spll",
+ "mout_sclk_ipll", "mout_sclk_epll", "mout_sclk_rpll"};
+PNAME(mout_group3_p) = {"mout_sclk_rpll", "mout_sclk_spll"};
+PNAME(mout_group4_p) = {"mout_sclk_ipll", "mout_sclk_dpll", "mout_sclk_mpll"};
+PNAME(mout_group5_p) = {"mout_sclk_vpll", "mout_sclk_dpll"};
+
+PNAME(mout_fimd1_final_p) = {"mout_fimd1", "mout_fimd1_opt"};
+PNAME(mout_sw_aclk66_p) = {"dout_aclk66", "mout_sclk_spll"};
+PNAME(mout_user_aclk66_peric_p) = { "fin_pll", "mout_sw_aclk66"};
+PNAME(mout_user_pclk66_gpio_p) = {"mout_sw_aclk66", "ff_sw_aclk66"};
+
+PNAME(mout_sw_aclk200_fsys_p) = {"dout_aclk200_fsys", "mout_sclk_spll"};
+PNAME(mout_sw_pclk200_fsys_p) = {"dout_pclk200_fsys", "mout_sclk_spll"};
+PNAME(mout_user_pclk200_fsys_p) = {"fin_pll", "mout_sw_pclk200_fsys"};
+PNAME(mout_user_aclk200_fsys_p) = {"fin_pll", "mout_sw_aclk200_fsys"};
+
+PNAME(mout_sw_aclk200_fsys2_p) = {"dout_aclk200_fsys2", "mout_sclk_spll"};
+PNAME(mout_user_aclk200_fsys2_p) = {"fin_pll", "mout_sw_aclk200_fsys2"};
+PNAME(mout_sw_aclk100_noc_p) = {"dout_aclk100_noc", "mout_sclk_spll"};
+PNAME(mout_user_aclk100_noc_p) = {"fin_pll", "mout_sw_aclk100_noc"};
+
+PNAME(mout_sw_aclk400_wcore_p) = {"dout_aclk400_wcore", "mout_sclk_spll"};
+PNAME(mout_aclk400_wcore_bpll_p) = {"mout_aclk400_wcore", "sclk_bpll"};
+PNAME(mout_user_aclk400_wcore_p) = {"fin_pll", "mout_sw_aclk400_wcore"};
+
+PNAME(mout_sw_aclk400_isp_p) = {"dout_aclk400_isp", "mout_sclk_spll"};
+PNAME(mout_user_aclk400_isp_p) = {"fin_pll", "mout_sw_aclk400_isp"};
+
+PNAME(mout_sw_aclk333_432_isp0_p) = {"dout_aclk333_432_isp0",
+ "mout_sclk_spll"};
+PNAME(mout_user_aclk333_432_isp0_p) = {"fin_pll", "mout_sw_aclk333_432_isp0"};
+
+PNAME(mout_sw_aclk333_432_isp_p) = {"dout_aclk333_432_isp", "mout_sclk_spll"};
+PNAME(mout_user_aclk333_432_isp_p) = {"fin_pll", "mout_sw_aclk333_432_isp"};
+
+PNAME(mout_sw_aclk200_p) = {"dout_aclk200", "mout_sclk_spll"};
+PNAME(mout_user_aclk200_disp1_p) = {"fin_pll", "mout_sw_aclk200"};
+
+PNAME(mout_sw_aclk400_mscl_p) = {"dout_aclk400_mscl", "mout_sclk_spll"};
+PNAME(mout_user_aclk400_mscl_p) = {"fin_pll", "mout_sw_aclk400_mscl"};
+
+PNAME(mout_sw_aclk333_p) = {"dout_aclk333", "mout_sclk_spll"};
+PNAME(mout_user_aclk333_p) = {"fin_pll", "mout_sw_aclk333"};
+
+PNAME(mout_sw_aclk166_p) = {"dout_aclk166", "mout_sclk_spll"};
+PNAME(mout_user_aclk166_p) = {"fin_pll", "mout_sw_aclk166"};
+
+PNAME(mout_sw_aclk266_p) = {"dout_aclk266", "mout_sclk_spll"};
+PNAME(mout_user_aclk266_p) = {"fin_pll", "mout_sw_aclk266"};
+PNAME(mout_user_aclk266_isp_p) = {"fin_pll", "mout_sw_aclk266"};
+
+PNAME(mout_sw_aclk333_432_gscl_p) = {"dout_aclk333_432_gscl", "mout_sclk_spll"};
+PNAME(mout_user_aclk333_432_gscl_p) = {"fin_pll", "mout_sw_aclk333_432_gscl"};
+
+PNAME(mout_sw_aclk300_gscl_p) = {"dout_aclk300_gscl", "mout_sclk_spll"};
+PNAME(mout_user_aclk300_gscl_p) = {"fin_pll", "mout_sw_aclk300_gscl"};
+
+PNAME(mout_sw_aclk300_disp1_p) = {"dout_aclk300_disp1", "mout_sclk_spll"};
+PNAME(mout_sw_aclk400_disp1_p) = {"dout_aclk400_disp1", "mout_sclk_spll"};
+PNAME(mout_user_aclk300_disp1_p) = {"fin_pll", "mout_sw_aclk300_disp1"};
+PNAME(mout_user_aclk400_disp1_p) = {"fin_pll", "mout_sw_aclk400_disp1"};
+
+PNAME(mout_sw_aclk300_jpeg_p) = {"dout_aclk300_jpeg", "mout_sclk_spll"};
+PNAME(mout_user_aclk300_jpeg_p) = {"fin_pll", "mout_sw_aclk300_jpeg"};
+
+PNAME(mout_sw_aclk_g3d_p) = {"dout_aclk_g3d", "mout_sclk_spll"};
+PNAME(mout_user_aclk_g3d_p) = {"fin_pll", "mout_sw_aclk_g3d"};
+
+PNAME(mout_sw_aclk266_g2d_p) = {"dout_aclk266_g2d", "mout_sclk_spll"};
+PNAME(mout_user_aclk266_g2d_p) = {"fin_pll", "mout_sw_aclk266_g2d"};
+
+PNAME(mout_sw_aclk333_g2d_p) = {"dout_aclk333_g2d", "mout_sclk_spll"};
+PNAME(mout_user_aclk333_g2d_p) = {"fin_pll", "mout_sw_aclk333_g2d"};
+
+PNAME(mout_audio0_p) = {"fin_pll", "cdclk0", "mout_sclk_dpll",
+ "mout_sclk_mpll", "mout_sclk_spll", "mout_sclk_ipll",
+ "mout_sclk_epll", "mout_sclk_rpll"};
+PNAME(mout_audio1_p) = {"fin_pll", "cdclk1", "mout_sclk_dpll",
+ "mout_sclk_mpll", "mout_sclk_spll", "mout_sclk_ipll",
+ "mout_sclk_epll", "mout_sclk_rpll"};
+PNAME(mout_audio2_p) = {"fin_pll", "cdclk2", "mout_sclk_dpll",
+ "mout_sclk_mpll", "mout_sclk_spll", "mout_sclk_ipll",
+ "mout_sclk_epll", "mout_sclk_rpll"};
+PNAME(mout_spdif_p) = {"fin_pll", "dout_audio0", "dout_audio1",
+ "dout_audio2", "spdif_extclk", "mout_sclk_ipll",
+ "mout_sclk_epll", "mout_sclk_rpll"};
+PNAME(mout_hdmi_p) = {"dout_hdmi_pixel", "sclk_hdmiphy"};
+PNAME(mout_maudio0_p) = {"fin_pll", "maudio_clk", "mout_sclk_dpll",
+ "mout_sclk_mpll", "mout_sclk_spll", "mout_sclk_ipll",
+ "mout_sclk_epll", "mout_sclk_rpll"};
+PNAME(mout_mau_epll_clk_p) = {"mout_sclk_epll", "mout_sclk_dpll",
+ "mout_sclk_mpll", "mout_sclk_spll"};
+/* List of parents specific to exynos5800 */
+PNAME(mout_epll2_5800_p) = { "mout_sclk_epll", "ff_dout_epll2" };
+PNAME(mout_group1_5800_p) = { "mout_sclk_cpll", "mout_sclk_dpll",
+ "mout_sclk_mpll", "ff_dout_spll2" };
+PNAME(mout_group2_5800_p) = { "mout_sclk_cpll", "mout_sclk_dpll",
+ "mout_sclk_mpll", "ff_dout_spll2",
+ "mout_epll2", "mout_sclk_ipll" };
+PNAME(mout_group3_5800_p) = { "mout_sclk_cpll", "mout_sclk_dpll",
+ "mout_sclk_mpll", "ff_dout_spll2",
+ "mout_epll2" };
+PNAME(mout_group5_5800_p) = { "mout_sclk_cpll", "mout_sclk_dpll",
+ "mout_sclk_mpll", "mout_sclk_spll" };
+PNAME(mout_group6_5800_p) = { "mout_sclk_ipll", "mout_sclk_dpll",
+ "mout_sclk_mpll", "ff_dout_spll2" };
+PNAME(mout_group7_5800_p) = { "mout_sclk_cpll", "mout_sclk_dpll",
+ "mout_sclk_mpll", "mout_sclk_spll",
+ "mout_epll2", "mout_sclk_ipll" };
+PNAME(mout_mau_epll_clk_5800_p) = { "mout_sclk_epll", "mout_sclk_dpll",
+ "mout_sclk_mpll",
+ "ff_dout_spll2" };
+PNAME(mout_group8_5800_p) = { "dout_aclk432_scaler", "dout_sclk_sw" };
+PNAME(mout_group9_5800_p) = { "dout_osc_div", "mout_sw_aclk432_scaler" };
+PNAME(mout_group10_5800_p) = { "dout_aclk432_cam", "dout_sclk_sw" };
+PNAME(mout_group11_5800_p) = { "dout_osc_div", "mout_sw_aclk432_cam" };
+PNAME(mout_group12_5800_p) = { "dout_aclkfl1_550_cam", "dout_sclk_sw" };
+PNAME(mout_group13_5800_p) = { "dout_osc_div", "mout_sw_aclkfl1_550_cam" };
+PNAME(mout_group14_5800_p) = { "dout_aclk550_cam", "dout_sclk_sw" };
+PNAME(mout_group15_5800_p) = { "dout_osc_div", "mout_sw_aclk550_cam" };
/* fixed rate clocks generated outside the soc */
-static struct samsung_fixed_rate_clock exynos5420_fixed_rate_ext_clks[] __initdata = {
+static struct samsung_fixed_rate_clock
+ exynos5x_fixed_rate_ext_clks[] __initdata = {
FRATE(CLK_FIN_PLL, "fin_pll", NULL, CLK_IS_ROOT, 0),
};
/* fixed rate clocks generated inside the soc */
-static struct samsung_fixed_rate_clock exynos5420_fixed_rate_clks[] __initdata = {
+static struct samsung_fixed_rate_clock exynos5x_fixed_rate_clks[] __initdata = {
FRATE(CLK_SCLK_HDMIPHY, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 24000000),
FRATE(0, "sclk_pwi", NULL, CLK_IS_ROOT, 24000000),
FRATE(0, "sclk_usbh20", NULL, CLK_IS_ROOT, 48000000),
@@ -310,146 +462,311 @@ static struct samsung_fixed_rate_clock exynos5420_fixed_rate_clks[] __initdata =
FRATE(0, "sclk_usbh20_scan_clk", NULL, CLK_IS_ROOT, 480000000),
};
-static struct samsung_fixed_factor_clock exynos5420_fixed_factor_clks[] __initdata = {
- FFACTOR(0, "sclk_hsic_12m", "fin_pll", 1, 2, 0),
+static struct samsung_fixed_factor_clock
+ exynos5x_fixed_factor_clks[] __initdata = {
+ FFACTOR(0, "ff_hsic_12m", "fin_pll", 1, 2, 0),
+ FFACTOR(0, "ff_sw_aclk66", "mout_sw_aclk66", 1, 2, 0),
+};
+
+static struct samsung_fixed_factor_clock
+ exynos5800_fixed_factor_clks[] __initdata = {
+ FFACTOR(0, "ff_dout_epll2", "mout_sclk_epll", 1, 2, 0),
+ FFACTOR(0, "ff_dout_spll2", "mout_sclk_spll", 1, 2, 0),
+};
+
+struct samsung_mux_clock exynos5800_mux_clks[] __initdata = {
+ MUX(0, "mout_aclk400_isp", mout_group3_5800_p, SRC_TOP0, 0, 3),
+ MUX(0, "mout_aclk400_mscl", mout_group3_5800_p, SRC_TOP0, 4, 3),
+ MUX(0, "mout_aclk400_wcore", mout_group2_5800_p, SRC_TOP0, 16, 3),
+ MUX(0, "mout_aclk100_noc", mout_group1_5800_p, SRC_TOP0, 20, 2),
+
+ MUX(0, "mout_aclk333_432_gscl", mout_group6_5800_p, SRC_TOP1, 0, 2),
+ MUX(0, "mout_aclk333_432_isp", mout_group6_5800_p, SRC_TOP1, 4, 2),
+ MUX(0, "mout_aclk333_432_isp0", mout_group6_5800_p, SRC_TOP1, 12, 2),
+ MUX(0, "mout_aclk266", mout_group5_5800_p, SRC_TOP1, 20, 2),
+ MUX(0, "mout_aclk333", mout_group1_5800_p, SRC_TOP1, 28, 2),
+
+ MUX(0, "mout_aclk400_disp1", mout_group7_5800_p, SRC_TOP2, 4, 3),
+ MUX(0, "mout_aclk333_g2d", mout_group5_5800_p, SRC_TOP2, 8, 2),
+ MUX(0, "mout_aclk266_g2d", mout_group5_5800_p, SRC_TOP2, 12, 2),
+ MUX(0, "mout_aclk300_jpeg", mout_group5_5800_p, SRC_TOP2, 20, 2),
+ MUX(0, "mout_aclk300_disp1", mout_group5_5800_p, SRC_TOP2, 24, 2),
+ MUX(0, "mout_aclk300_gscl", mout_group5_5800_p, SRC_TOP2, 28, 2),
+
+ MUX(0, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p, SRC_TOP7,
+ 20, 2),
+ MUX(0, "sclk_bpll", mout_bpll_p, SRC_TOP7, 24, 1),
+ MUX(0, "mout_epll2", mout_epll2_5800_p, SRC_TOP7, 28, 1),
+
+ MUX(0, "mout_aclk550_cam", mout_group3_5800_p, SRC_TOP8, 16, 3),
+ MUX(0, "mout_aclkfl1_550_cam", mout_group3_5800_p, SRC_TOP8, 20, 3),
+ MUX(0, "mout_aclk432_cam", mout_group6_5800_p, SRC_TOP8, 24, 2),
+ MUX(0, "mout_aclk432_scaler", mout_group6_5800_p, SRC_TOP8, 28, 2),
+
+ MUX(0, "mout_user_aclk550_cam", mout_group15_5800_p,
+ SRC_TOP9, 16, 1),
+ MUX(0, "mout_user_aclkfl1_550_cam", mout_group13_5800_p,
+ SRC_TOP9, 20, 1),
+ MUX(0, "mout_user_aclk432_cam", mout_group11_5800_p,
+ SRC_TOP9, 24, 1),
+ MUX(0, "mout_user_aclk432_scaler", mout_group9_5800_p,
+ SRC_TOP9, 28, 1),
+
+ MUX(0, "mout_sw_aclk550_cam", mout_group14_5800_p, SRC_TOP13, 16, 1),
+ MUX(0, "mout_sw_aclkfl1_550_cam", mout_group12_5800_p,
+ SRC_TOP13, 20, 1),
+ MUX(0, "mout_sw_aclk432_cam", mout_group10_5800_p,
+ SRC_TOP13, 24, 1),
+ MUX(0, "mout_sw_aclk432_scaler", mout_group8_5800_p,
+ SRC_TOP13, 28, 1),
+
+ MUX(0, "mout_fimd1", mout_group2_p, SRC_DISP10, 4, 3),
+};
+
+struct samsung_div_clock exynos5800_div_clks[] __initdata = {
+ DIV(0, "dout_aclk400_wcore", "mout_aclk400_wcore", DIV_TOP0, 16, 3),
+
+ DIV(0, "dout_aclk550_cam", "mout_aclk550_cam",
+ DIV_TOP8, 16, 3),
+ DIV(0, "dout_aclkfl1_550_cam", "mout_aclkfl1_550_cam",
+ DIV_TOP8, 20, 3),
+ DIV(0, "dout_aclk432_cam", "mout_aclk432_cam",
+ DIV_TOP8, 24, 3),
+ DIV(0, "dout_aclk432_scaler", "mout_aclk432_scaler",
+ DIV_TOP8, 28, 3),
+
+ DIV(0, "dout_osc_div", "fin_pll", DIV_TOP9, 20, 3),
+ DIV(0, "dout_sclk_sw", "sclk_spll", DIV_TOP9, 24, 6),
+};
+
+struct samsung_gate_clock exynos5800_gate_clks[] __initdata = {
+ GATE(CLK_ACLK550_CAM, "aclk550_cam", "mout_user_aclk550_cam",
+ GATE_BUS_TOP, 24, 0, 0),
+ GATE(CLK_ACLK432_SCALER, "aclk432_scaler", "mout_user_aclk432_scaler",
+ GATE_BUS_TOP, 27, 0, 0),
};
-static struct samsung_mux_clock exynos5420_mux_clks[] __initdata = {
- MUX(0, "mout_mspll_kfc", mspll_cpu_p, SRC_TOP7, 8, 2),
- MUX(0, "mout_mspll_cpu", mspll_cpu_p, SRC_TOP7, 12, 2),
- MUX(0, "mout_apll", apll_p, SRC_CPU, 0, 1),
- MUX(0, "mout_cpu", cpu_p, SRC_CPU, 16, 1),
- MUX(0, "mout_kpll", kpll_p, SRC_KFC, 0, 1),
- MUX(0, "mout_cpu_kfc", kfc_p, SRC_KFC, 16, 1),
-
- MUX(0, "sclk_bpll", bpll_p, SRC_CDREX, 0, 1),
-
- MUX_A(0, "mout_aclk400_mscl", group1_p,
- SRC_TOP0, 4, 2, "aclk400_mscl"),
- MUX(0, "mout_aclk200", group1_p, SRC_TOP0, 8, 2),
- MUX(0, "mout_aclk200_fsys2", group1_p, SRC_TOP0, 12, 2),
- MUX(0, "mout_aclk200_fsys", group1_p, SRC_TOP0, 28, 2),
-
- MUX(0, "mout_aclk333_432_gscl", group4_p, SRC_TOP1, 0, 2),
- MUX(0, "mout_aclk66", group1_p, SRC_TOP1, 8, 2),
- MUX(0, "mout_aclk266", group1_p, SRC_TOP1, 20, 2),
- MUX(0, "mout_aclk166", group1_p, SRC_TOP1, 24, 2),
- MUX(0, "mout_aclk333", group1_p, SRC_TOP1, 28, 2),
-
- MUX(0, "mout_aclk333_g2d", group1_p, SRC_TOP2, 8, 2),
- MUX(0, "mout_aclk266_g2d", group1_p, SRC_TOP2, 12, 2),
- MUX(0, "mout_aclk_g3d", group5_p, SRC_TOP2, 16, 1),
- MUX(0, "mout_aclk300_jpeg", group1_p, SRC_TOP2, 20, 2),
- MUX(0, "mout_aclk300_disp1", group1_p, SRC_TOP2, 24, 2),
- MUX(0, "mout_aclk300_gscl", group1_p, SRC_TOP2, 28, 2),
-
- MUX(0, "mout_user_aclk400_mscl", user_aclk400_mscl_p,
+struct samsung_mux_clock exynos5420_mux_clks[] __initdata = {
+ MUX(0, "sclk_bpll", mout_bpll_p, TOP_SPARE2, 0, 1),
+ MUX(0, "mout_aclk400_wcore_bpll", mout_aclk400_wcore_bpll_p,
+ TOP_SPARE2, 4, 1),
+
+ MUX(0, "mout_aclk400_isp", mout_group1_p, SRC_TOP0, 0, 2),
+ MUX_A(0, "mout_aclk400_mscl", mout_group1_p,
+ SRC_TOP0, 4, 2, "aclk400_mscl"),
+ MUX(0, "mout_aclk400_wcore", mout_group1_p, SRC_TOP0, 16, 2),
+ MUX(0, "mout_aclk100_noc", mout_group1_p, SRC_TOP0, 20, 2),
+
+ MUX(0, "mout_aclk333_432_gscl", mout_group4_p, SRC_TOP1, 0, 2),
+ MUX(0, "mout_aclk333_432_isp", mout_group4_p,
+ SRC_TOP1, 4, 2),
+ MUX(0, "mout_aclk333_432_isp0", mout_group4_p, SRC_TOP1, 12, 2),
+ MUX(0, "mout_aclk266", mout_group1_p, SRC_TOP1, 20, 2),
+ MUX(0, "mout_aclk333", mout_group1_p, SRC_TOP1, 28, 2),
+
+ MUX(0, "mout_aclk400_disp1", mout_group1_p, SRC_TOP2, 4, 2),
+ MUX(0, "mout_aclk333_g2d", mout_group1_p, SRC_TOP2, 8, 2),
+ MUX(0, "mout_aclk266_g2d", mout_group1_p, SRC_TOP2, 12, 2),
+ MUX(0, "mout_aclk300_jpeg", mout_group1_p, SRC_TOP2, 20, 2),
+ MUX(0, "mout_aclk300_disp1", mout_group1_p, SRC_TOP2, 24, 2),
+ MUX(0, "mout_aclk300_gscl", mout_group1_p, SRC_TOP2, 28, 2),
+
+ MUX(0, "mout_mau_epll_clk", mout_mau_epll_clk_p, SRC_TOP7, 20, 2),
+
+ MUX(0, "mout_fimd1", mout_group3_p, SRC_DISP10, 4, 1),
+};
+
+struct samsung_div_clock exynos5420_div_clks[] __initdata = {
+ DIV(0, "dout_aclk400_wcore", "mout_aclk400_wcore_bpll",
+ DIV_TOP0, 16, 3),
+};
+
+static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
+ MUX(0, "mout_user_pclk66_gpio", mout_user_pclk66_gpio_p,
+ SRC_TOP7, 4, 1),
+ MUX(0, "mout_mspll_kfc", mout_mspll_cpu_p, SRC_TOP7, 8, 2),
+ MUX(0, "mout_mspll_cpu", mout_mspll_cpu_p, SRC_TOP7, 12, 2),
+
+ MUX(0, "mout_apll", mout_apll_p, SRC_CPU, 0, 1),
+ MUX(0, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1),
+ MUX(0, "mout_kpll", mout_kpll_p, SRC_KFC, 0, 1),
+ MUX(0, "mout_kfc", mout_kfc_p, SRC_KFC, 16, 1),
+
+ MUX(0, "mout_aclk200", mout_group1_p, SRC_TOP0, 8, 2),
+ MUX(0, "mout_aclk200_fsys2", mout_group1_p, SRC_TOP0, 12, 2),
+ MUX(0, "mout_pclk200_fsys", mout_group1_p, SRC_TOP0, 24, 2),
+ MUX(0, "mout_aclk200_fsys", mout_group1_p, SRC_TOP0, 28, 2),
+
+ MUX(0, "mout_aclk66", mout_group1_p, SRC_TOP1, 8, 2),
+ MUX(0, "mout_aclk166", mout_group1_p, SRC_TOP1, 24, 2),
+
+ MUX(0, "mout_aclk_g3d", mout_group5_p, SRC_TOP2, 16, 1),
+
+ MUX(0, "mout_user_aclk400_isp", mout_user_aclk400_isp_p,
+ SRC_TOP3, 0, 1),
+ MUX(0, "mout_user_aclk400_mscl", mout_user_aclk400_mscl_p,
SRC_TOP3, 4, 1),
- MUX_A(0, "mout_aclk200_disp1", aclk200_disp1_p,
- SRC_TOP3, 8, 1, "aclk200_disp1"),
- MUX(0, "mout_user_aclk200_fsys2", user_aclk200_fsys2_p,
+ MUX(0, "mout_user_aclk200_disp1", mout_user_aclk200_disp1_p,
+ SRC_TOP3, 8, 1),
+ MUX(0, "mout_user_aclk200_fsys2", mout_user_aclk200_fsys2_p,
SRC_TOP3, 12, 1),
- MUX(0, "mout_user_aclk200_fsys", user_aclk200_fsys_p,
+ MUX(0, "mout_user_aclk400_wcore", mout_user_aclk400_wcore_p,
+ SRC_TOP3, 16, 1),
+ MUX(0, "mout_user_aclk100_noc", mout_user_aclk100_noc_p,
+ SRC_TOP3, 20, 1),
+ MUX(0, "mout_user_pclk200_fsys", mout_user_pclk200_fsys_p,
+ SRC_TOP3, 24, 1),
+ MUX(0, "mout_user_aclk200_fsys", mout_user_aclk200_fsys_p,
SRC_TOP3, 28, 1),
- MUX(0, "mout_user_aclk333_432_gscl", user_aclk333_432_gscl_p,
+ MUX(0, "mout_user_aclk333_432_gscl", mout_user_aclk333_432_gscl_p,
SRC_TOP4, 0, 1),
- MUX(0, "mout_aclk66_peric", aclk66_peric_p, SRC_TOP4, 8, 1),
- MUX(0, "mout_user_aclk266", user_aclk266_p, SRC_TOP4, 20, 1),
- MUX(0, "mout_user_aclk166", user_aclk166_p, SRC_TOP4, 24, 1),
- MUX(0, "mout_user_aclk333", user_aclk333_p, SRC_TOP4, 28, 1),
-
- MUX(0, "mout_aclk66_psgen", aclk66_peric_p, SRC_TOP5, 4, 1),
- MUX(0, "mout_user_aclk333_g2d", user_aclk333_g2d_p, SRC_TOP5, 8, 1),
- MUX(0, "mout_user_aclk266_g2d", user_aclk266_g2d_p, SRC_TOP5, 12, 1),
- MUX_A(0, "mout_user_aclk_g3d", user_aclk_g3d_p,
- SRC_TOP5, 16, 1, "aclkg3d"),
- MUX(0, "mout_user_aclk300_jpeg", user_aclk300_jpeg_p,
+ MUX(0, "mout_user_aclk333_432_isp", mout_user_aclk333_432_isp_p,
+ SRC_TOP4, 4, 1),
+ MUX(0, "mout_user_aclk66_peric", mout_user_aclk66_peric_p,
+ SRC_TOP4, 8, 1),
+ MUX(0, "mout_user_aclk333_432_isp0", mout_user_aclk333_432_isp0_p,
+ SRC_TOP4, 12, 1),
+ MUX(0, "mout_user_aclk266_isp", mout_user_aclk266_isp_p,
+ SRC_TOP4, 16, 1),
+ MUX(0, "mout_user_aclk266", mout_user_aclk266_p, SRC_TOP4, 20, 1),
+ MUX(0, "mout_user_aclk166", mout_user_aclk166_p, SRC_TOP4, 24, 1),
+ MUX(CLK_MOUT_USER_ACLK333, "mout_user_aclk333", mout_user_aclk333_p,
+ SRC_TOP4, 28, 1),
+
+ MUX(0, "mout_user_aclk400_disp1", mout_user_aclk400_disp1_p,
+ SRC_TOP5, 0, 1),
+ MUX(0, "mout_user_aclk66_psgen", mout_user_aclk66_peric_p,
+ SRC_TOP5, 4, 1),
+ MUX(0, "mout_user_aclk333_g2d", mout_user_aclk333_g2d_p,
+ SRC_TOP5, 8, 1),
+ MUX(0, "mout_user_aclk266_g2d", mout_user_aclk266_g2d_p,
+ SRC_TOP5, 12, 1),
+ MUX(CLK_MOUT_G3D, "mout_user_aclk_g3d", mout_user_aclk_g3d_p,
+ SRC_TOP5, 16, 1),
+ MUX(0, "mout_user_aclk300_jpeg", mout_user_aclk300_jpeg_p,
SRC_TOP5, 20, 1),
- MUX(0, "mout_user_aclk300_disp1", user_aclk300_disp1_p,
+ MUX(0, "mout_user_aclk300_disp1", mout_user_aclk300_disp1_p,
SRC_TOP5, 24, 1),
- MUX(0, "mout_user_aclk300_gscl", user_aclk300_gscl_p,
+ MUX(0, "mout_user_aclk300_gscl", mout_user_aclk300_gscl_p,
SRC_TOP5, 28, 1),
- MUX(0, "sclk_mpll", mpll_p, SRC_TOP6, 0, 1),
- MUX(0, "sclk_vpll", vpll_p, SRC_TOP6, 4, 1),
- MUX(0, "sclk_spll", spll_p, SRC_TOP6, 8, 1),
- MUX(0, "sclk_ipll", ipll_p, SRC_TOP6, 12, 1),
- MUX(0, "sclk_rpll", rpll_p, SRC_TOP6, 16, 1),
- MUX(0, "sclk_epll", epll_p, SRC_TOP6, 20, 1),
- MUX(0, "sclk_dpll", dpll_p, SRC_TOP6, 24, 1),
- MUX(0, "sclk_cpll", cpll_p, SRC_TOP6, 28, 1),
-
- MUX(0, "mout_sw_aclk400_mscl", sw_aclk400_mscl_p, SRC_TOP10, 4, 1),
- MUX(0, "mout_sw_aclk200", sw_aclk200_p, SRC_TOP10, 8, 1),
- MUX(0, "mout_sw_aclk200_fsys2", sw_aclk200_fsys2_p,
+ MUX(0, "mout_sclk_mpll", mout_mpll_p, SRC_TOP6, 0, 1),
+ MUX(CLK_MOUT_VPLL, "mout_sclk_vpll", mout_vpll_p, SRC_TOP6, 4, 1),
+ MUX(0, "mout_sclk_spll", mout_spll_p, SRC_TOP6, 8, 1),
+ MUX(0, "mout_sclk_ipll", mout_ipll_p, SRC_TOP6, 12, 1),
+ MUX(0, "mout_sclk_rpll", mout_rpll_p, SRC_TOP6, 16, 1),
+ MUX(0, "mout_sclk_epll", mout_epll_p, SRC_TOP6, 20, 1),
+ MUX(0, "mout_sclk_dpll", mout_dpll_p, SRC_TOP6, 24, 1),
+ MUX(0, "mout_sclk_cpll", mout_cpll_p, SRC_TOP6, 28, 1),
+
+ MUX(0, "mout_sw_aclk400_isp", mout_sw_aclk400_isp_p,
+ SRC_TOP10, 0, 1),
+ MUX(0, "mout_sw_aclk400_mscl", mout_sw_aclk400_mscl_p,
+ SRC_TOP10, 4, 1),
+ MUX(0, "mout_sw_aclk200", mout_sw_aclk200_p, SRC_TOP10, 8, 1),
+ MUX(0, "mout_sw_aclk200_fsys2", mout_sw_aclk200_fsys2_p,
SRC_TOP10, 12, 1),
- MUX(0, "mout_sw_aclk200_fsys", sw_aclk200_fsys_p, SRC_TOP10, 28, 1),
-
- MUX(0, "mout_sw_aclk333_432_gscl", sw_aclk333_432_gscl_p,
+ MUX(0, "mout_sw_aclk400_wcore", mout_sw_aclk400_wcore_p,
+ SRC_TOP10, 16, 1),
+ MUX(0, "mout_sw_aclk100_noc", mout_sw_aclk100_noc_p,
+ SRC_TOP10, 20, 1),
+ MUX(0, "mout_sw_pclk200_fsys", mout_sw_pclk200_fsys_p,
+ SRC_TOP10, 24, 1),
+ MUX(0, "mout_sw_aclk200_fsys", mout_sw_aclk200_fsys_p,
+ SRC_TOP10, 28, 1),
+
+ MUX(0, "mout_sw_aclk333_432_gscl", mout_sw_aclk333_432_gscl_p,
SRC_TOP11, 0, 1),
- MUX(0, "mout_sw_aclk66", sw_aclk66_p, SRC_TOP11, 8, 1),
- MUX(0, "mout_sw_aclk266", sw_aclk266_p, SRC_TOP11, 20, 1),
- MUX(0, "mout_sw_aclk166", sw_aclk166_p, SRC_TOP11, 24, 1),
- MUX(0, "mout_sw_aclk333", sw_aclk333_p, SRC_TOP11, 28, 1),
-
- MUX(0, "mout_sw_aclk333_g2d", sw_aclk333_g2d_p, SRC_TOP12, 8, 1),
- MUX(0, "mout_sw_aclk266_g2d", sw_aclk266_g2d_p, SRC_TOP12, 12, 1),
- MUX(0, "mout_sw_aclk_g3d", sw_aclk_g3d_p, SRC_TOP12, 16, 1),
- MUX(0, "mout_sw_aclk300_jpeg", sw_aclk300_jpeg_p, SRC_TOP12, 20, 1),
- MUX(0, "mout_sw_aclk300_disp1", sw_aclk300_disp1_p,
+ MUX(0, "mout_sw_aclk333_432_isp", mout_sw_aclk333_432_isp_p,
+ SRC_TOP11, 4, 1),
+ MUX(0, "mout_sw_aclk66", mout_sw_aclk66_p, SRC_TOP11, 8, 1),
+ MUX(0, "mout_sw_aclk333_432_isp0", mout_sw_aclk333_432_isp0_p,
+ SRC_TOP11, 12, 1),
+ MUX(0, "mout_sw_aclk266", mout_sw_aclk266_p, SRC_TOP11, 20, 1),
+ MUX(0, "mout_sw_aclk166", mout_sw_aclk166_p, SRC_TOP11, 24, 1),
+ MUX(CLK_MOUT_SW_ACLK333, "mout_sw_aclk333", mout_sw_aclk333_p,
+ SRC_TOP11, 28, 1),
+
+ MUX(0, "mout_sw_aclk400_disp1", mout_sw_aclk400_disp1_p,
+ SRC_TOP12, 4, 1),
+ MUX(0, "mout_sw_aclk333_g2d", mout_sw_aclk333_g2d_p,
+ SRC_TOP12, 8, 1),
+ MUX(0, "mout_sw_aclk266_g2d", mout_sw_aclk266_g2d_p,
+ SRC_TOP12, 12, 1),
+ MUX(0, "mout_sw_aclk_g3d", mout_sw_aclk_g3d_p, SRC_TOP12, 16, 1),
+ MUX(0, "mout_sw_aclk300_jpeg", mout_sw_aclk300_jpeg_p,
+ SRC_TOP12, 20, 1),
+ MUX(0, "mout_sw_aclk300_disp1", mout_sw_aclk300_disp1_p,
SRC_TOP12, 24, 1),
- MUX(0, "mout_sw_aclk300_gscl", sw_aclk300_gscl_p, SRC_TOP12, 28, 1),
+ MUX(0, "mout_sw_aclk300_gscl", mout_sw_aclk300_gscl_p,
+ SRC_TOP12, 28, 1),
/* DISP1 Block */
- MUX(0, "mout_fimd1", group3_p, SRC_DISP10, 4, 1),
- MUX(0, "mout_mipi1", group2_p, SRC_DISP10, 16, 3),
- MUX(0, "mout_dp1", group2_p, SRC_DISP10, 20, 3),
- MUX(0, "mout_pixel", group2_p, SRC_DISP10, 24, 3),
- MUX(CLK_MOUT_HDMI, "mout_hdmi", hdmi_p, SRC_DISP10, 28, 1),
+ MUX(0, "mout_mipi1", mout_group2_p, SRC_DISP10, 16, 3),
+ MUX(0, "mout_dp1", mout_group2_p, SRC_DISP10, 20, 3),
+ MUX(0, "mout_pixel", mout_group2_p, SRC_DISP10, 24, 3),
+ MUX(CLK_MOUT_HDMI, "mout_hdmi", mout_hdmi_p, SRC_DISP10, 28, 1),
+ MUX(0, "mout_fimd1_opt", mout_group2_p, SRC_DISP10, 8, 3),
+
+ MUX(0, "mout_fimd1_final", mout_fimd1_final_p, TOP_SPARE2, 8, 1),
/* MAU Block */
- MUX(0, "mout_maudio0", maudio0_p, SRC_MAU, 28, 3),
+ MUX(CLK_MOUT_MAUDIO0, "mout_maudio0", mout_maudio0_p, SRC_MAU, 28, 3),
/* FSYS Block */
- MUX(0, "mout_usbd301", group2_p, SRC_FSYS, 4, 3),
- MUX(0, "mout_mmc0", group2_p, SRC_FSYS, 8, 3),
- MUX(0, "mout_mmc1", group2_p, SRC_FSYS, 12, 3),
- MUX(0, "mout_mmc2", group2_p, SRC_FSYS, 16, 3),
- MUX(0, "mout_usbd300", group2_p, SRC_FSYS, 20, 3),
- MUX(0, "mout_unipro", group2_p, SRC_FSYS, 24, 3),
+ MUX(0, "mout_usbd301", mout_group2_p, SRC_FSYS, 4, 3),
+ MUX(0, "mout_mmc0", mout_group2_p, SRC_FSYS, 8, 3),
+ MUX(0, "mout_mmc1", mout_group2_p, SRC_FSYS, 12, 3),
+ MUX(0, "mout_mmc2", mout_group2_p, SRC_FSYS, 16, 3),
+ MUX(0, "mout_usbd300", mout_group2_p, SRC_FSYS, 20, 3),
+ MUX(0, "mout_unipro", mout_group2_p, SRC_FSYS, 24, 3),
+ MUX(0, "mout_mphy_refclk", mout_group2_p, SRC_FSYS, 28, 3),
/* PERIC Block */
- MUX(0, "mout_uart0", group2_p, SRC_PERIC0, 4, 3),
- MUX(0, "mout_uart1", group2_p, SRC_PERIC0, 8, 3),
- MUX(0, "mout_uart2", group2_p, SRC_PERIC0, 12, 3),
- MUX(0, "mout_uart3", group2_p, SRC_PERIC0, 16, 3),
- MUX(0, "mout_pwm", group2_p, SRC_PERIC0, 24, 3),
- MUX(0, "mout_spdif", spdif_p, SRC_PERIC0, 28, 3),
- MUX(0, "mout_audio0", audio0_p, SRC_PERIC1, 8, 3),
- MUX(0, "mout_audio1", audio1_p, SRC_PERIC1, 12, 3),
- MUX(0, "mout_audio2", audio2_p, SRC_PERIC1, 16, 3),
- MUX(0, "mout_spi0", group2_p, SRC_PERIC1, 20, 3),
- MUX(0, "mout_spi1", group2_p, SRC_PERIC1, 24, 3),
- MUX(0, "mout_spi2", group2_p, SRC_PERIC1, 28, 3),
+ MUX(0, "mout_uart0", mout_group2_p, SRC_PERIC0, 4, 3),
+ MUX(0, "mout_uart1", mout_group2_p, SRC_PERIC0, 8, 3),
+ MUX(0, "mout_uart2", mout_group2_p, SRC_PERIC0, 12, 3),
+ MUX(0, "mout_uart3", mout_group2_p, SRC_PERIC0, 16, 3),
+ MUX(0, "mout_pwm", mout_group2_p, SRC_PERIC0, 24, 3),
+ MUX(0, "mout_spdif", mout_spdif_p, SRC_PERIC0, 28, 3),
+ MUX(0, "mout_audio0", mout_audio0_p, SRC_PERIC1, 8, 3),
+ MUX(0, "mout_audio1", mout_audio1_p, SRC_PERIC1, 12, 3),
+ MUX(0, "mout_audio2", mout_audio2_p, SRC_PERIC1, 16, 3),
+ MUX(0, "mout_spi0", mout_group2_p, SRC_PERIC1, 20, 3),
+ MUX(0, "mout_spi1", mout_group2_p, SRC_PERIC1, 24, 3),
+ MUX(0, "mout_spi2", mout_group2_p, SRC_PERIC1, 28, 3),
+
+ /* ISP Block */
+ MUX(0, "mout_pwm_isp", mout_group2_p, SRC_ISP, 24, 3),
+ MUX(0, "mout_uart_isp", mout_group2_p, SRC_ISP, 20, 3),
+ MUX(0, "mout_spi0_isp", mout_group2_p, SRC_ISP, 12, 3),
+ MUX(0, "mout_spi1_isp", mout_group2_p, SRC_ISP, 16, 3),
+ MUX(0, "mout_isp_sensor", mout_group2_p, SRC_ISP, 28, 3),
};
-static struct samsung_div_clock exynos5420_div_clks[] __initdata = {
+static struct samsung_div_clock exynos5x_div_clks[] __initdata = {
DIV(0, "div_arm", "mout_cpu", DIV_CPU0, 0, 3),
DIV(0, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3),
DIV(0, "armclk2", "div_arm", DIV_CPU0, 28, 3),
- DIV(0, "div_kfc", "mout_cpu_kfc", DIV_KFC0, 0, 3),
+ DIV(0, "div_kfc", "mout_kfc", DIV_KFC0, 0, 3),
DIV(0, "sclk_kpll", "mout_kpll", DIV_KFC0, 24, 3),
+ DIV(0, "dout_aclk400_isp", "mout_aclk400_isp", DIV_TOP0, 0, 3),
DIV(0, "dout_aclk400_mscl", "mout_aclk400_mscl", DIV_TOP0, 4, 3),
DIV(0, "dout_aclk200", "mout_aclk200", DIV_TOP0, 8, 3),
DIV(0, "dout_aclk200_fsys2", "mout_aclk200_fsys2", DIV_TOP0, 12, 3),
+ DIV(0, "dout_aclk100_noc", "mout_aclk100_noc", DIV_TOP0, 20, 3),
DIV(0, "dout_pclk200_fsys", "mout_pclk200_fsys", DIV_TOP0, 24, 3),
DIV(0, "dout_aclk200_fsys", "mout_aclk200_fsys", DIV_TOP0, 28, 3),
DIV(0, "dout_aclk333_432_gscl", "mout_aclk333_432_gscl",
DIV_TOP1, 0, 3),
+ DIV(0, "dout_aclk333_432_isp", "mout_aclk333_432_isp",
+ DIV_TOP1, 4, 3),
DIV(0, "dout_aclk66", "mout_aclk66", DIV_TOP1, 8, 6),
+ DIV(0, "dout_aclk333_432_isp0", "mout_aclk333_432_isp0",
+ DIV_TOP1, 16, 3),
DIV(0, "dout_aclk266", "mout_aclk266", DIV_TOP1, 20, 3),
DIV(0, "dout_aclk166", "mout_aclk166", DIV_TOP1, 24, 3),
DIV(0, "dout_aclk333", "mout_aclk333", DIV_TOP1, 28, 3),
@@ -458,15 +775,16 @@ static struct samsung_div_clock exynos5420_div_clks[] __initdata = {
DIV(0, "dout_aclk266_g2d", "mout_aclk266_g2d", DIV_TOP2, 12, 3),
DIV(0, "dout_aclk_g3d", "mout_aclk_g3d", DIV_TOP2, 16, 3),
DIV(0, "dout_aclk300_jpeg", "mout_aclk300_jpeg", DIV_TOP2, 20, 3),
- DIV_A(0, "dout_aclk300_disp1", "mout_aclk300_disp1",
- DIV_TOP2, 24, 3, "aclk300_disp1"),
+ DIV(0, "dout_aclk300_disp1", "mout_aclk300_disp1", DIV_TOP2, 24, 3),
DIV(0, "dout_aclk300_gscl", "mout_aclk300_gscl", DIV_TOP2, 28, 3),
/* DISP1 Block */
- DIV(0, "dout_fimd1", "mout_fimd1", DIV_DISP10, 0, 4),
+ DIV(0, "dout_fimd1", "mout_fimd1_final", DIV_DISP10, 0, 4),
DIV(0, "dout_mipi1", "mout_mipi1", DIV_DISP10, 16, 8),
DIV(0, "dout_dp1", "mout_dp1", DIV_DISP10, 24, 4),
DIV(CLK_DOUT_PIXEL, "dout_hdmi_pixel", "mout_pixel", DIV_DISP10, 28, 4),
+ DIV(0, "dout_disp1_blk", "aclk200_disp1", DIV2_RATIO0, 16, 2),
+ DIV(0, "dout_aclk400_disp1", "mout_aclk400_disp1", DIV_TOP2, 4, 3),
/* Audio Block */
DIV(0, "dout_maudio0", "mout_maudio0", DIV_MAU, 20, 4),
@@ -484,6 +802,7 @@ static struct samsung_div_clock exynos5420_div_clks[] __initdata = {
DIV(0, "dout_mmc2", "mout_mmc2", DIV_FSYS1, 20, 10),
DIV(0, "dout_unipro", "mout_unipro", DIV_FSYS2, 24, 8),
+ DIV(0, "dout_mphy_refclk", "mout_mphy_refclk", DIV_FSYS2, 16, 8),
/* UART and PWM */
DIV(0, "dout_uart0", "mout_uart0", DIV_PERIC0, 8, 4),
@@ -497,6 +816,9 @@ static struct samsung_div_clock exynos5420_div_clks[] __initdata = {
DIV(0, "dout_spi1", "mout_spi1", DIV_PERIC1, 24, 4),
DIV(0, "dout_spi2", "mout_spi2", DIV_PERIC1, 28, 4),
+ /* Mfc Block */
+ DIV(0, "dout_mfc_blk", "mout_user_aclk333", DIV4_RATIO, 0, 2),
+
/* PCM */
DIV(0, "dout_pcm1", "dout_audio1", DIV_PERIC2, 16, 8),
DIV(0, "dout_pcm2", "dout_audio2", DIV_PERIC2, 24, 8),
@@ -509,15 +831,43 @@ static struct samsung_div_clock exynos5420_div_clks[] __initdata = {
DIV(0, "dout_audio2", "mout_audio2", DIV_PERIC3, 28, 4),
/* SPI Pre-Ratio */
- DIV(0, "dout_pre_spi0", "dout_spi0", DIV_PERIC4, 8, 8),
- DIV(0, "dout_pre_spi1", "dout_spi1", DIV_PERIC4, 16, 8),
- DIV(0, "dout_pre_spi2", "dout_spi2", DIV_PERIC4, 24, 8),
+ DIV(0, "dout_spi0_pre", "dout_spi0", DIV_PERIC4, 8, 8),
+ DIV(0, "dout_spi1_pre", "dout_spi1", DIV_PERIC4, 16, 8),
+ DIV(0, "dout_spi2_pre", "dout_spi2", DIV_PERIC4, 24, 8),
+
+ /* GSCL Block */
+ DIV(0, "dout_gscl_blk_300", "mout_user_aclk300_gscl",
+ DIV2_RATIO0, 4, 2),
+ DIV(0, "dout_gscl_blk_333", "aclk333_432_gscl", DIV2_RATIO0, 6, 2),
+
+ /* MSCL Block */
+ DIV(0, "dout_mscl_blk", "aclk400_mscl", DIV2_RATIO0, 28, 2),
+
+ /* PSGEN */
+ DIV(0, "dout_gen_blk", "mout_user_aclk266", DIV2_RATIO0, 8, 1),
+ DIV(0, "dout_jpg_blk", "aclk166", DIV2_RATIO0, 20, 1),
+
+ /* ISP Block */
+ DIV(0, "dout_isp_sensor0", "mout_isp_sensor", SCLK_DIV_ISP0, 8, 8),
+ DIV(0, "dout_isp_sensor1", "mout_isp_sensor", SCLK_DIV_ISP0, 16, 8),
+ DIV(0, "dout_isp_sensor2", "mout_isp_sensor", SCLK_DIV_ISP0, 24, 8),
+ DIV(0, "dout_pwm_isp", "mout_pwm_isp", SCLK_DIV_ISP1, 28, 4),
+ DIV(0, "dout_uart_isp", "mout_uart_isp", SCLK_DIV_ISP1, 24, 4),
+ DIV(0, "dout_spi0_isp", "mout_spi0_isp", SCLK_DIV_ISP1, 16, 4),
+ DIV(0, "dout_spi1_isp", "mout_spi1_isp", SCLK_DIV_ISP1, 20, 4),
+ DIV_F(0, "dout_spi0_isp_pre", "dout_spi0_isp", SCLK_DIV_ISP1, 0, 8,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(0, "dout_spi1_isp_pre", "dout_spi1_isp", SCLK_DIV_ISP1, 8, 8,
+ CLK_SET_RATE_PARENT, 0),
};
-static struct samsung_gate_clock exynos5420_gate_clks[] __initdata = {
- /* TODO: Re-verify the CG bits for all the gate clocks */
- GATE_A(CLK_MCT, "pclk_st", "aclk66_psgen", GATE_BUS_PERIS1, 2, 0, 0,
- "mct"),
+static struct samsung_gate_clock exynos5x_gate_clks[] __initdata = {
+ /* G2D */
+ GATE(CLK_MDMA0, "mdma0", "aclk266_g2d", GATE_IP_G2D, 1, 0, 0),
+ GATE(CLK_SSS, "sss", "aclk266_g2d", GATE_IP_G2D, 2, 0, 0),
+ GATE(CLK_G2D, "g2d", "aclk333_g2d", GATE_IP_G2D, 3, 0, 0),
+ GATE(CLK_SMMU_MDMA0, "smmu_mdma0", "aclk266_g2d", GATE_IP_G2D, 5, 0, 0),
+ GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk333_g2d", GATE_IP_G2D, 7, 0, 0),
GATE(0, "aclk200_fsys", "mout_user_aclk200_fsys",
GATE_BUS_FSYS0, 9, CLK_IGNORE_UNUSED, 0),
@@ -530,20 +880,40 @@ static struct samsung_gate_clock exynos5420_gate_clks[] __initdata = {
GATE_BUS_TOP, 1, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk300_jpeg", "mout_user_aclk300_jpeg",
GATE_BUS_TOP, 4, CLK_IGNORE_UNUSED, 0),
+ GATE(0, "aclk333_432_isp0", "mout_user_aclk333_432_isp0",
+ GATE_BUS_TOP, 5, 0, 0),
GATE(0, "aclk300_gscl", "mout_user_aclk300_gscl",
GATE_BUS_TOP, 6, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk333_432_gscl", "mout_user_aclk333_432_gscl",
GATE_BUS_TOP, 7, CLK_IGNORE_UNUSED, 0),
- GATE(0, "pclk66_gpio", "mout_sw_aclk66",
+ GATE(0, "aclk333_432_isp", "mout_user_aclk333_432_isp",
+ GATE_BUS_TOP, 8, 0, 0),
+ GATE(CLK_PCLK66_GPIO, "pclk66_gpio", "mout_user_pclk66_gpio",
GATE_BUS_TOP, 9, CLK_IGNORE_UNUSED, 0),
- GATE(0, "aclk66_psgen", "mout_aclk66_psgen",
+ GATE(0, "aclk66_psgen", "mout_user_aclk66_psgen",
GATE_BUS_TOP, 10, CLK_IGNORE_UNUSED, 0),
- GATE(0, "aclk66_peric", "mout_aclk66_peric",
- GATE_BUS_TOP, 11, 0, 0),
+ GATE(0, "aclk266_isp", "mout_user_aclk266_isp",
+ GATE_BUS_TOP, 13, 0, 0),
GATE(0, "aclk166", "mout_user_aclk166",
GATE_BUS_TOP, 14, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk333", "mout_aclk333",
GATE_BUS_TOP, 15, CLK_IGNORE_UNUSED, 0),
+ GATE(0, "aclk400_isp", "mout_user_aclk400_isp",
+ GATE_BUS_TOP, 16, 0, 0),
+ GATE(0, "aclk400_mscl", "mout_user_aclk400_mscl",
+ GATE_BUS_TOP, 17, 0, 0),
+ GATE(0, "aclk200_disp1", "mout_user_aclk200_disp1",
+ GATE_BUS_TOP, 18, 0, 0),
+ GATE(CLK_SCLK_MPHY_IXTAL24, "sclk_mphy_ixtal24", "mphy_refclk_ixtal24",
+ GATE_BUS_TOP, 28, 0, 0),
+ GATE(CLK_SCLK_HSIC_12M, "sclk_hsic_12m", "ff_hsic_12m",
+ GATE_BUS_TOP, 29, 0, 0),
+
+ GATE(0, "aclk300_disp1", "mout_user_aclk300_disp1",
+ SRC_MASK_TOP2, 24, 0, 0),
+
+ GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk",
+ SRC_MASK_TOP7, 20, 0, 0),
/* sclk */
GATE(CLK_SCLK_UART0, "sclk_uart0", "dout_uart0",
@@ -554,11 +924,11 @@ static struct samsung_gate_clock exynos5420_gate_clks[] __initdata = {
GATE_TOP_SCLK_PERIC, 2, CLK_SET_RATE_PARENT, 0),
GATE(CLK_SCLK_UART3, "sclk_uart3", "dout_uart3",
GATE_TOP_SCLK_PERIC, 3, CLK_SET_RATE_PARENT, 0),
- GATE(CLK_SCLK_SPI0, "sclk_spi0", "dout_pre_spi0",
+ GATE(CLK_SCLK_SPI0, "sclk_spi0", "dout_spi0_pre",
GATE_TOP_SCLK_PERIC, 6, CLK_SET_RATE_PARENT, 0),
- GATE(CLK_SCLK_SPI1, "sclk_spi1", "dout_pre_spi1",
+ GATE(CLK_SCLK_SPI1, "sclk_spi1", "dout_spi1_pre",
GATE_TOP_SCLK_PERIC, 7, CLK_SET_RATE_PARENT, 0),
- GATE(CLK_SCLK_SPI2, "sclk_spi2", "dout_pre_spi2",
+ GATE(CLK_SCLK_SPI2, "sclk_spi2", "dout_spi2_pre",
GATE_TOP_SCLK_PERIC, 8, CLK_SET_RATE_PARENT, 0),
GATE(CLK_SCLK_SPDIF, "sclk_spdif", "mout_spdif",
GATE_TOP_SCLK_PERIC, 9, CLK_SET_RATE_PARENT, 0),
@@ -588,164 +958,218 @@ static struct samsung_gate_clock exynos5420_gate_clks[] __initdata = {
GATE(CLK_SCLK_USBD301, "sclk_usbd301", "dout_usbd301",
GATE_TOP_SCLK_FSYS, 10, CLK_SET_RATE_PARENT, 0),
- GATE(CLK_SCLK_USBD301, "sclk_unipro", "dout_unipro",
- SRC_MASK_FSYS, 24, CLK_SET_RATE_PARENT, 0),
-
- GATE(CLK_SCLK_GSCL_WA, "sclk_gscl_wa", "aclK333_432_gscl",
- GATE_TOP_SCLK_GSCL, 6, CLK_SET_RATE_PARENT, 0),
- GATE(CLK_SCLK_GSCL_WB, "sclk_gscl_wb", "aclk333_432_gscl",
- GATE_TOP_SCLK_GSCL, 7, CLK_SET_RATE_PARENT, 0),
-
/* Display */
GATE(CLK_SCLK_FIMD1, "sclk_fimd1", "dout_fimd1",
- GATE_TOP_SCLK_DISP1, 0, CLK_SET_RATE_PARENT, 0),
+ GATE_TOP_SCLK_DISP1, 0, CLK_SET_RATE_PARENT, 0),
GATE(CLK_SCLK_MIPI1, "sclk_mipi1", "dout_mipi1",
- GATE_TOP_SCLK_DISP1, 3, CLK_SET_RATE_PARENT, 0),
+ GATE_TOP_SCLK_DISP1, 3, CLK_SET_RATE_PARENT, 0),
GATE(CLK_SCLK_HDMI, "sclk_hdmi", "mout_hdmi",
- GATE_TOP_SCLK_DISP1, 9, CLK_SET_RATE_PARENT, 0),
+ GATE_TOP_SCLK_DISP1, 9, 0, 0),
GATE(CLK_SCLK_PIXEL, "sclk_pixel", "dout_hdmi_pixel",
- GATE_TOP_SCLK_DISP1, 10, CLK_SET_RATE_PARENT, 0),
+ GATE_TOP_SCLK_DISP1, 10, CLK_SET_RATE_PARENT, 0),
GATE(CLK_SCLK_DP1, "sclk_dp1", "dout_dp1",
- GATE_TOP_SCLK_DISP1, 20, CLK_SET_RATE_PARENT, 0),
+ GATE_TOP_SCLK_DISP1, 20, CLK_SET_RATE_PARENT, 0),
/* Maudio Block */
GATE(CLK_SCLK_MAUDIO0, "sclk_maudio0", "dout_maudio0",
GATE_TOP_SCLK_MAU, 0, CLK_SET_RATE_PARENT, 0),
GATE(CLK_SCLK_MAUPCM0, "sclk_maupcm0", "dout_maupcm0",
GATE_TOP_SCLK_MAU, 1, CLK_SET_RATE_PARENT, 0),
- /* FSYS */
+
+ /* FSYS Block */
GATE(CLK_TSI, "tsi", "aclk200_fsys", GATE_BUS_FSYS0, 0, 0, 0),
GATE(CLK_PDMA0, "pdma0", "aclk200_fsys", GATE_BUS_FSYS0, 1, 0, 0),
GATE(CLK_PDMA1, "pdma1", "aclk200_fsys", GATE_BUS_FSYS0, 2, 0, 0),
GATE(CLK_UFS, "ufs", "aclk200_fsys2", GATE_BUS_FSYS0, 3, 0, 0),
- GATE(CLK_RTIC, "rtic", "aclk200_fsys", GATE_BUS_FSYS0, 5, 0, 0),
- GATE(CLK_MMC0, "mmc0", "aclk200_fsys2", GATE_BUS_FSYS0, 12, 0, 0),
- GATE(CLK_MMC1, "mmc1", "aclk200_fsys2", GATE_BUS_FSYS0, 13, 0, 0),
- GATE(CLK_MMC2, "mmc2", "aclk200_fsys2", GATE_BUS_FSYS0, 14, 0, 0),
+ GATE(CLK_RTIC, "rtic", "aclk200_fsys", GATE_IP_FSYS, 9, 0, 0),
+ GATE(CLK_MMC0, "mmc0", "aclk200_fsys2", GATE_IP_FSYS, 12, 0, 0),
+ GATE(CLK_MMC1, "mmc1", "aclk200_fsys2", GATE_IP_FSYS, 13, 0, 0),
+ GATE(CLK_MMC2, "mmc2", "aclk200_fsys2", GATE_IP_FSYS, 14, 0, 0),
GATE(CLK_SROMC, "sromc", "aclk200_fsys2",
- GATE_BUS_FSYS0, 19, CLK_IGNORE_UNUSED, 0),
- GATE(CLK_USBH20, "usbh20", "aclk200_fsys", GATE_BUS_FSYS0, 20, 0, 0),
- GATE(CLK_USBD300, "usbd300", "aclk200_fsys", GATE_BUS_FSYS0, 21, 0, 0),
- GATE(CLK_USBD301, "usbd301", "aclk200_fsys", GATE_BUS_FSYS0, 28, 0, 0),
-
- /* UART */
- GATE(CLK_UART0, "uart0", "aclk66_peric", GATE_BUS_PERIC, 4, 0, 0),
- GATE(CLK_UART1, "uart1", "aclk66_peric", GATE_BUS_PERIC, 5, 0, 0),
- GATE_A(CLK_UART2, "uart2", "aclk66_peric",
- GATE_BUS_PERIC, 6, CLK_IGNORE_UNUSED, 0, "uart2"),
- GATE(CLK_UART3, "uart3", "aclk66_peric", GATE_BUS_PERIC, 7, 0, 0),
- /* I2C */
- GATE(CLK_I2C0, "i2c0", "aclk66_peric", GATE_BUS_PERIC, 9, 0, 0),
- GATE(CLK_I2C1, "i2c1", "aclk66_peric", GATE_BUS_PERIC, 10, 0, 0),
- GATE(CLK_I2C2, "i2c2", "aclk66_peric", GATE_BUS_PERIC, 11, 0, 0),
- GATE(CLK_I2C3, "i2c3", "aclk66_peric", GATE_BUS_PERIC, 12, 0, 0),
- GATE(CLK_I2C4, "i2c4", "aclk66_peric", GATE_BUS_PERIC, 13, 0, 0),
- GATE(CLK_I2C5, "i2c5", "aclk66_peric", GATE_BUS_PERIC, 14, 0, 0),
- GATE(CLK_I2C6, "i2c6", "aclk66_peric", GATE_BUS_PERIC, 15, 0, 0),
- GATE(CLK_I2C7, "i2c7", "aclk66_peric", GATE_BUS_PERIC, 16, 0, 0),
- GATE(CLK_I2C_HDMI, "i2c_hdmi", "aclk66_peric", GATE_BUS_PERIC, 17, 0,
- 0),
- GATE(CLK_TSADC, "tsadc", "aclk66_peric", GATE_BUS_PERIC, 18, 0, 0),
- /* SPI */
- GATE(CLK_SPI0, "spi0", "aclk66_peric", GATE_BUS_PERIC, 19, 0, 0),
- GATE(CLK_SPI1, "spi1", "aclk66_peric", GATE_BUS_PERIC, 20, 0, 0),
- GATE(CLK_SPI2, "spi2", "aclk66_peric", GATE_BUS_PERIC, 21, 0, 0),
- GATE(CLK_KEYIF, "keyif", "aclk66_peric", GATE_BUS_PERIC, 22, 0, 0),
- /* I2S */
- GATE(CLK_I2S1, "i2s1", "aclk66_peric", GATE_BUS_PERIC, 23, 0, 0),
- GATE(CLK_I2S2, "i2s2", "aclk66_peric", GATE_BUS_PERIC, 24, 0, 0),
- /* PCM */
- GATE(CLK_PCM1, "pcm1", "aclk66_peric", GATE_BUS_PERIC, 25, 0, 0),
- GATE(CLK_PCM2, "pcm2", "aclk66_peric", GATE_BUS_PERIC, 26, 0, 0),
- /* PWM */
- GATE(CLK_PWM, "pwm", "aclk66_peric", GATE_BUS_PERIC, 27, 0, 0),
- /* SPDIF */
- GATE(CLK_SPDIF, "spdif", "aclk66_peric", GATE_BUS_PERIC, 29, 0, 0),
-
- GATE(CLK_I2C8, "i2c8", "aclk66_peric", GATE_BUS_PERIC1, 0, 0, 0),
- GATE(CLK_I2C9, "i2c9", "aclk66_peric", GATE_BUS_PERIC1, 1, 0, 0),
- GATE(CLK_I2C10, "i2c10", "aclk66_peric", GATE_BUS_PERIC1, 2, 0, 0),
+ GATE_IP_FSYS, 17, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_USBH20, "usbh20", "aclk200_fsys", GATE_IP_FSYS, 18, 0, 0),
+ GATE(CLK_USBD300, "usbd300", "aclk200_fsys", GATE_IP_FSYS, 19, 0, 0),
+ GATE(CLK_USBD301, "usbd301", "aclk200_fsys", GATE_IP_FSYS, 20, 0, 0),
+ GATE(CLK_SCLK_UNIPRO, "sclk_unipro", "dout_unipro",
+ SRC_MASK_FSYS, 24, CLK_SET_RATE_PARENT, 0),
+ /* PERIC Block */
+ GATE(CLK_UART0, "uart0", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 0, 0, 0),
+ GATE(CLK_UART1, "uart1", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 1, 0, 0),
+ GATE(CLK_UART2, "uart2", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 2, 0, 0),
+ GATE(CLK_UART3, "uart3", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 3, 0, 0),
+ GATE(CLK_I2C0, "i2c0", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 6, 0, 0),
+ GATE(CLK_I2C1, "i2c1", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 7, 0, 0),
+ GATE(CLK_I2C2, "i2c2", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 8, 0, 0),
+ GATE(CLK_I2C3, "i2c3", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 9, 0, 0),
+ GATE(CLK_USI0, "usi0", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 10, 0, 0),
+ GATE(CLK_USI1, "usi1", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 11, 0, 0),
+ GATE(CLK_USI2, "usi2", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 12, 0, 0),
+ GATE(CLK_USI3, "usi3", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 13, 0, 0),
+ GATE(CLK_I2C_HDMI, "i2c_hdmi", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 14, 0, 0),
+ GATE(CLK_TSADC, "tsadc", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 15, 0, 0),
+ GATE(CLK_SPI0, "spi0", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 16, 0, 0),
+ GATE(CLK_SPI1, "spi1", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 17, 0, 0),
+ GATE(CLK_SPI2, "spi2", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 18, 0, 0),
+ GATE(CLK_I2S1, "i2s1", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 20, 0, 0),
+ GATE(CLK_I2S2, "i2s2", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 21, 0, 0),
+ GATE(CLK_PCM1, "pcm1", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 22, 0, 0),
+ GATE(CLK_PCM2, "pcm2", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 23, 0, 0),
+ GATE(CLK_PWM, "pwm", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 24, 0, 0),
+ GATE(CLK_SPDIF, "spdif", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 26, 0, 0),
+ GATE(CLK_USI4, "usi4", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 28, 0, 0),
+ GATE(CLK_USI5, "usi5", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 30, 0, 0),
+ GATE(CLK_USI6, "usi6", "mout_user_aclk66_peric",
+ GATE_IP_PERIC, 31, 0, 0),
+
+ GATE(CLK_KEYIF, "keyif", "mout_user_aclk66_peric",
+ GATE_BUS_PERIC, 22, 0, 0),
+
+ /* PERIS Block */
GATE(CLK_CHIPID, "chipid", "aclk66_psgen",
- GATE_BUS_PERIS0, 12, CLK_IGNORE_UNUSED, 0),
+ GATE_IP_PERIS, 0, CLK_IGNORE_UNUSED, 0),
GATE(CLK_SYSREG, "sysreg", "aclk66_psgen",
- GATE_BUS_PERIS0, 13, CLK_IGNORE_UNUSED, 0),
- GATE(CLK_TZPC0, "tzpc0", "aclk66_psgen", GATE_BUS_PERIS0, 18, 0, 0),
- GATE(CLK_TZPC1, "tzpc1", "aclk66_psgen", GATE_BUS_PERIS0, 19, 0, 0),
- GATE(CLK_TZPC2, "tzpc2", "aclk66_psgen", GATE_BUS_PERIS0, 20, 0, 0),
- GATE(CLK_TZPC3, "tzpc3", "aclk66_psgen", GATE_BUS_PERIS0, 21, 0, 0),
- GATE(CLK_TZPC4, "tzpc4", "aclk66_psgen", GATE_BUS_PERIS0, 22, 0, 0),
- GATE(CLK_TZPC5, "tzpc5", "aclk66_psgen", GATE_BUS_PERIS0, 23, 0, 0),
- GATE(CLK_TZPC6, "tzpc6", "aclk66_psgen", GATE_BUS_PERIS0, 24, 0, 0),
- GATE(CLK_TZPC7, "tzpc7", "aclk66_psgen", GATE_BUS_PERIS0, 25, 0, 0),
- GATE(CLK_TZPC8, "tzpc8", "aclk66_psgen", GATE_BUS_PERIS0, 26, 0, 0),
- GATE(CLK_TZPC9, "tzpc9", "aclk66_psgen", GATE_BUS_PERIS0, 27, 0, 0),
-
- GATE(CLK_HDMI_CEC, "hdmi_cec", "aclk66_psgen", GATE_BUS_PERIS1, 0, 0,
- 0),
+ GATE_IP_PERIS, 1, CLK_IGNORE_UNUSED, 0),
+ GATE(CLK_TZPC0, "tzpc0", "aclk66_psgen", GATE_IP_PERIS, 6, 0, 0),
+ GATE(CLK_TZPC1, "tzpc1", "aclk66_psgen", GATE_IP_PERIS, 7, 0, 0),
+ GATE(CLK_TZPC2, "tzpc2", "aclk66_psgen", GATE_IP_PERIS, 8, 0, 0),
+ GATE(CLK_TZPC3, "tzpc3", "aclk66_psgen", GATE_IP_PERIS, 9, 0, 0),
+ GATE(CLK_TZPC4, "tzpc4", "aclk66_psgen", GATE_IP_PERIS, 10, 0, 0),
+ GATE(CLK_TZPC5, "tzpc5", "aclk66_psgen", GATE_IP_PERIS, 11, 0, 0),
+ GATE(CLK_TZPC6, "tzpc6", "aclk66_psgen", GATE_IP_PERIS, 12, 0, 0),
+ GATE(CLK_TZPC7, "tzpc7", "aclk66_psgen", GATE_IP_PERIS, 13, 0, 0),
+ GATE(CLK_TZPC8, "tzpc8", "aclk66_psgen", GATE_IP_PERIS, 14, 0, 0),
+ GATE(CLK_TZPC9, "tzpc9", "aclk66_psgen", GATE_IP_PERIS, 15, 0, 0),
+ GATE(CLK_HDMI_CEC, "hdmi_cec", "aclk66_psgen", GATE_IP_PERIS, 16, 0, 0),
+ GATE(CLK_MCT, "mct", "aclk66_psgen", GATE_IP_PERIS, 18, 0, 0),
+ GATE(CLK_WDT, "wdt", "aclk66_psgen", GATE_IP_PERIS, 19, 0, 0),
+ GATE(CLK_RTC, "rtc", "aclk66_psgen", GATE_IP_PERIS, 20, 0, 0),
+ GATE(CLK_TMU, "tmu", "aclk66_psgen", GATE_IP_PERIS, 21, 0, 0),
+ GATE(CLK_TMU_GPU, "tmu_gpu", "aclk66_psgen", GATE_IP_PERIS, 22, 0, 0),
+
GATE(CLK_SECKEY, "seckey", "aclk66_psgen", GATE_BUS_PERIS1, 1, 0, 0),
- GATE(CLK_WDT, "wdt", "aclk66_psgen", GATE_BUS_PERIS1, 3, 0, 0),
- GATE(CLK_RTC, "rtc", "aclk66_psgen", GATE_BUS_PERIS1, 4, 0, 0),
- GATE(CLK_TMU, "tmu", "aclk66_psgen", GATE_BUS_PERIS1, 5, 0, 0),
- GATE(CLK_TMU_GPU, "tmu_gpu", "aclk66_psgen", GATE_BUS_PERIS1, 6, 0, 0),
+
+ /* GEN Block */
+ GATE(CLK_ROTATOR, "rotator", "mout_user_aclk266", GATE_IP_GEN, 1, 0, 0),
+ GATE(CLK_JPEG, "jpeg", "aclk300_jpeg", GATE_IP_GEN, 2, 0, 0),
+ GATE(CLK_JPEG2, "jpeg2", "aclk300_jpeg", GATE_IP_GEN, 3, 0, 0),
+ GATE(CLK_MDMA1, "mdma1", "mout_user_aclk266", GATE_IP_GEN, 4, 0, 0),
+ GATE(CLK_TOP_RTC, "top_rtc", "aclk66_psgen", GATE_IP_GEN, 5, 0, 0),
+ GATE(CLK_SMMU_ROTATOR, "smmu_rotator", "dout_gen_blk",
+ GATE_IP_GEN, 6, 0, 0),
+ GATE(CLK_SMMU_JPEG, "smmu_jpeg", "dout_jpg_blk", GATE_IP_GEN, 7, 0, 0),
+ GATE(CLK_SMMU_MDMA1, "smmu_mdma1", "dout_gen_blk",
+ GATE_IP_GEN, 9, 0, 0),
+
+ /* GATE_IP_GEN doesn't list gates for smmu_jpeg2 and mc */
+ GATE(CLK_SMMU_JPEG2, "smmu_jpeg2", "dout_jpg_blk",
+ GATE_BUS_GEN, 28, 0, 0),
+ GATE(CLK_MC, "mc", "aclk66_psgen", GATE_BUS_GEN, 12, 0, 0),
+
+ /* GSCL Block */
+ GATE(CLK_SCLK_GSCL_WA, "sclk_gscl_wa", "mout_user_aclk333_432_gscl",
+ GATE_TOP_SCLK_GSCL, 6, 0, 0),
+ GATE(CLK_SCLK_GSCL_WB, "sclk_gscl_wb", "mout_user_aclk333_432_gscl",
+ GATE_TOP_SCLK_GSCL, 7, 0, 0),
GATE(CLK_GSCL0, "gscl0", "aclk300_gscl", GATE_IP_GSCL0, 0, 0, 0),
GATE(CLK_GSCL1, "gscl1", "aclk300_gscl", GATE_IP_GSCL0, 1, 0, 0),
- GATE(CLK_CLK_3AA, "clk_3aa", "aclk300_gscl", GATE_IP_GSCL0, 4, 0, 0),
-
- GATE(CLK_SMMU_3AA, "smmu_3aa", "aclk333_432_gscl", GATE_IP_GSCL1, 2, 0,
- 0),
- GATE(CLK_SMMU_FIMCL0, "smmu_fimcl0", "aclk333_432_gscl",
+ GATE(CLK_FIMC_3AA, "fimc_3aa", "aclk333_432_gscl",
+ GATE_IP_GSCL0, 4, 0, 0),
+ GATE(CLK_FIMC_LITE0, "fimc_lite0", "aclk333_432_gscl",
+ GATE_IP_GSCL0, 5, 0, 0),
+ GATE(CLK_FIMC_LITE1, "fimc_lite1", "aclk333_432_gscl",
+ GATE_IP_GSCL0, 6, 0, 0),
+
+ GATE(CLK_SMMU_3AA, "smmu_3aa", "dout_gscl_blk_333",
+ GATE_IP_GSCL1, 2, 0, 0),
+ GATE(CLK_SMMU_FIMCL0, "smmu_fimcl0", "dout_gscl_blk_333",
GATE_IP_GSCL1, 3, 0, 0),
- GATE(CLK_SMMU_FIMCL1, "smmu_fimcl1", "aclk333_432_gscl",
+ GATE(CLK_SMMU_FIMCL1, "smmu_fimcl1", "dout_gscl_blk_333",
GATE_IP_GSCL1, 4, 0, 0),
- GATE(CLK_SMMU_GSCL0, "smmu_gscl0", "aclk300_gscl", GATE_IP_GSCL1, 6, 0,
- 0),
- GATE(CLK_SMMU_GSCL1, "smmu_gscl1", "aclk300_gscl", GATE_IP_GSCL1, 7, 0,
- 0),
- GATE(CLK_GSCL_WA, "gscl_wa", "aclk300_gscl", GATE_IP_GSCL1, 12, 0, 0),
- GATE(CLK_GSCL_WB, "gscl_wb", "aclk300_gscl", GATE_IP_GSCL1, 13, 0, 0),
- GATE(CLK_SMMU_FIMCL3, "smmu_fimcl3,", "aclk333_432_gscl",
+ GATE(CLK_SMMU_GSCL0, "smmu_gscl0", "dout_gscl_blk_300",
+ GATE_IP_GSCL1, 6, 0, 0),
+ GATE(CLK_SMMU_GSCL1, "smmu_gscl1", "dout_gscl_blk_300",
+ GATE_IP_GSCL1, 7, 0, 0),
+ GATE(CLK_GSCL_WA, "gscl_wa", "sclk_gscl_wa", GATE_IP_GSCL1, 12, 0, 0),
+ GATE(CLK_GSCL_WB, "gscl_wb", "sclk_gscl_wb", GATE_IP_GSCL1, 13, 0, 0),
+ GATE(CLK_SMMU_FIMCL3, "smmu_fimcl3,", "dout_gscl_blk_333",
GATE_IP_GSCL1, 16, 0, 0),
GATE(CLK_FIMC_LITE3, "fimc_lite3", "aclk333_432_gscl",
GATE_IP_GSCL1, 17, 0, 0),
+ /* MSCL Block */
+ GATE(CLK_MSCL0, "mscl0", "aclk400_mscl", GATE_IP_MSCL, 0, 0, 0),
+ GATE(CLK_MSCL1, "mscl1", "aclk400_mscl", GATE_IP_MSCL, 1, 0, 0),
+ GATE(CLK_MSCL2, "mscl2", "aclk400_mscl", GATE_IP_MSCL, 2, 0, 0),
+ GATE(CLK_SMMU_MSCL0, "smmu_mscl0", "dout_mscl_blk",
+ GATE_IP_MSCL, 8, 0, 0),
+ GATE(CLK_SMMU_MSCL1, "smmu_mscl1", "dout_mscl_blk",
+ GATE_IP_MSCL, 9, 0, 0),
+ GATE(CLK_SMMU_MSCL2, "smmu_mscl2", "dout_mscl_blk",
+ GATE_IP_MSCL, 10, 0, 0),
+
GATE(CLK_FIMD1, "fimd1", "aclk300_disp1", GATE_IP_DISP1, 0, 0, 0),
GATE(CLK_DSIM1, "dsim1", "aclk200_disp1", GATE_IP_DISP1, 3, 0, 0),
GATE(CLK_DP1, "dp1", "aclk200_disp1", GATE_IP_DISP1, 4, 0, 0),
- GATE(CLK_MIXER, "mixer", "aclk166", GATE_IP_DISP1, 5, 0, 0),
+ GATE(CLK_MIXER, "mixer", "aclk200_disp1", GATE_IP_DISP1, 5, 0, 0),
GATE(CLK_HDMI, "hdmi", "aclk200_disp1", GATE_IP_DISP1, 6, 0, 0),
- GATE(CLK_SMMU_FIMD1, "smmu_fimd1", "aclk300_disp1", GATE_IP_DISP1, 8, 0,
- 0),
+ GATE(CLK_SMMU_FIMD1M0, "smmu_fimd1m0", "dout_disp1_blk",
+ GATE_IP_DISP1, 7, 0, 0),
+ GATE(CLK_SMMU_FIMD1M1, "smmu_fimd1m1", "dout_disp1_blk",
+ GATE_IP_DISP1, 8, 0, 0),
+ GATE(CLK_SMMU_MIXER, "smmu_mixer", "aclk200_disp1",
+ GATE_IP_DISP1, 9, 0, 0),
+
+ /* ISP */
+ GATE(CLK_SCLK_UART_ISP, "sclk_uart_isp", "dout_uart_isp",
+ GATE_TOP_SCLK_ISP, 0, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_SPI0_ISP, "sclk_spi0_isp", "dout_spi0_isp_pre",
+ GATE_TOP_SCLK_ISP, 1, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_SPI1_ISP, "sclk_spi1_isp", "dout_spi1_isp_pre",
+ GATE_TOP_SCLK_ISP, 2, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_PWM_ISP, "sclk_pwm_isp", "dout_pwm_isp",
+ GATE_TOP_SCLK_ISP, 3, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_ISP_SENSOR0, "sclk_isp_sensor0", "dout_isp_sensor0",
+ GATE_TOP_SCLK_ISP, 4, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_ISP_SENSOR1, "sclk_isp_sensor1", "dout_isp_sensor1",
+ GATE_TOP_SCLK_ISP, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_ISP_SENSOR2, "sclk_isp_sensor2", "dout_isp_sensor2",
+ GATE_TOP_SCLK_ISP, 12, CLK_SET_RATE_PARENT, 0),
GATE(CLK_MFC, "mfc", "aclk333", GATE_IP_MFC, 0, 0, 0),
- GATE(CLK_SMMU_MFCL, "smmu_mfcl", "aclk333", GATE_IP_MFC, 1, 0, 0),
- GATE(CLK_SMMU_MFCR, "smmu_mfcr", "aclk333", GATE_IP_MFC, 2, 0, 0),
-
- GATE(CLK_G3D, "g3d", "aclkg3d", GATE_IP_G3D, 9, 0, 0),
-
- GATE(CLK_ROTATOR, "rotator", "aclk266", GATE_IP_GEN, 1, 0, 0),
- GATE(CLK_JPEG, "jpeg", "aclk300_jpeg", GATE_IP_GEN, 2, 0, 0),
- GATE(CLK_JPEG2, "jpeg2", "aclk300_jpeg", GATE_IP_GEN, 3, 0, 0),
- GATE(CLK_MDMA1, "mdma1", "aclk266", GATE_IP_GEN, 4, 0, 0),
- GATE(CLK_SMMU_ROTATOR, "smmu_rotator", "aclk266", GATE_IP_GEN, 6, 0, 0),
- GATE(CLK_SMMU_JPEG, "smmu_jpeg", "aclk300_jpeg", GATE_IP_GEN, 7, 0, 0),
- GATE(CLK_SMMU_MDMA1, "smmu_mdma1", "aclk266", GATE_IP_GEN, 9, 0, 0),
+ GATE(CLK_SMMU_MFCL, "smmu_mfcl", "dout_mfc_blk", GATE_IP_MFC, 1, 0, 0),
+ GATE(CLK_SMMU_MFCR, "smmu_mfcr", "dout_mfc_blk", GATE_IP_MFC, 2, 0, 0),
- GATE(CLK_MSCL0, "mscl0", "aclk400_mscl", GATE_IP_MSCL, 0, 0, 0),
- GATE(CLK_MSCL1, "mscl1", "aclk400_mscl", GATE_IP_MSCL, 1, 0, 0),
- GATE(CLK_MSCL2, "mscl2", "aclk400_mscl", GATE_IP_MSCL, 2, 0, 0),
- GATE(CLK_SMMU_MSCL0, "smmu_mscl0", "aclk400_mscl", GATE_IP_MSCL, 8, 0,
- 0),
- GATE(CLK_SMMU_MSCL1, "smmu_mscl1", "aclk400_mscl", GATE_IP_MSCL, 9, 0,
- 0),
- GATE(CLK_SMMU_MSCL2, "smmu_mscl2", "aclk400_mscl", GATE_IP_MSCL, 10, 0,
- 0),
- GATE(CLK_SMMU_MIXER, "smmu_mixer", "aclk200_disp1", GATE_IP_DISP1, 9, 0,
- 0),
+ GATE(CLK_G3D, "g3d", "mout_user_aclk_g3d", GATE_IP_G3D, 9, 0, 0),
};
-static struct samsung_pll_clock exynos5420_plls[nr_plls] __initdata = {
+static struct samsung_pll_clock exynos5x_plls[nr_plls] __initdata = {
[apll] = PLL(pll_2550, CLK_FOUT_APLL, "fout_apll", "fin_pll", APLL_LOCK,
APLL_CON0, NULL),
[cpll] = PLL(pll_2550, CLK_FOUT_CPLL, "fout_cpll", "fin_pll", CPLL_LOCK,
@@ -776,8 +1200,11 @@ static struct of_device_id ext_clk_match[] __initdata = {
};
/* register exynos5420 clocks */
-static void __init exynos5420_clk_init(struct device_node *np)
+static void __init exynos5x_clk_init(struct device_node *np,
+ enum exynos5x_soc soc)
{
+ struct samsung_clk_provider *ctx;
+
if (np) {
reg_base = of_iomap(np, 0);
if (!reg_base)
@@ -786,23 +1213,56 @@ static void __init exynos5420_clk_init(struct device_node *np)
panic("%s: unable to determine soc\n", __func__);
}
- samsung_clk_init(np, reg_base, CLK_NR_CLKS);
- samsung_clk_of_register_fixed_ext(exynos5420_fixed_rate_ext_clks,
- ARRAY_SIZE(exynos5420_fixed_rate_ext_clks),
+ exynos5x_soc = soc;
+
+ ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
+ if (!ctx)
+ panic("%s: unable to allocate context.\n", __func__);
+
+ samsung_clk_of_register_fixed_ext(ctx, exynos5x_fixed_rate_ext_clks,
+ ARRAY_SIZE(exynos5x_fixed_rate_ext_clks),
ext_clk_match);
- samsung_clk_register_pll(exynos5420_plls, ARRAY_SIZE(exynos5420_plls),
+ samsung_clk_register_pll(ctx, exynos5x_plls, ARRAY_SIZE(exynos5x_plls),
reg_base);
- samsung_clk_register_fixed_rate(exynos5420_fixed_rate_clks,
- ARRAY_SIZE(exynos5420_fixed_rate_clks));
- samsung_clk_register_fixed_factor(exynos5420_fixed_factor_clks,
- ARRAY_SIZE(exynos5420_fixed_factor_clks));
- samsung_clk_register_mux(exynos5420_mux_clks,
- ARRAY_SIZE(exynos5420_mux_clks));
- samsung_clk_register_div(exynos5420_div_clks,
- ARRAY_SIZE(exynos5420_div_clks));
- samsung_clk_register_gate(exynos5420_gate_clks,
- ARRAY_SIZE(exynos5420_gate_clks));
+ samsung_clk_register_fixed_rate(ctx, exynos5x_fixed_rate_clks,
+ ARRAY_SIZE(exynos5x_fixed_rate_clks));
+ samsung_clk_register_fixed_factor(ctx, exynos5x_fixed_factor_clks,
+ ARRAY_SIZE(exynos5x_fixed_factor_clks));
+ samsung_clk_register_mux(ctx, exynos5x_mux_clks,
+ ARRAY_SIZE(exynos5x_mux_clks));
+ samsung_clk_register_div(ctx, exynos5x_div_clks,
+ ARRAY_SIZE(exynos5x_div_clks));
+ samsung_clk_register_gate(ctx, exynos5x_gate_clks,
+ ARRAY_SIZE(exynos5x_gate_clks));
+
+ if (soc == EXYNOS5420) {
+ samsung_clk_register_mux(ctx, exynos5420_mux_clks,
+ ARRAY_SIZE(exynos5420_mux_clks));
+ samsung_clk_register_div(ctx, exynos5420_div_clks,
+ ARRAY_SIZE(exynos5420_div_clks));
+ } else {
+ samsung_clk_register_fixed_factor(
+ ctx, exynos5800_fixed_factor_clks,
+ ARRAY_SIZE(exynos5800_fixed_factor_clks));
+ samsung_clk_register_mux(ctx, exynos5800_mux_clks,
+ ARRAY_SIZE(exynos5800_mux_clks));
+ samsung_clk_register_div(ctx, exynos5800_div_clks,
+ ARRAY_SIZE(exynos5800_div_clks));
+ samsung_clk_register_gate(ctx, exynos5800_gate_clks,
+ ARRAY_SIZE(exynos5800_gate_clks));
+ }
exynos5420_clk_sleep_init();
}
+
+static void __init exynos5420_clk_init(struct device_node *np)
+{
+ exynos5x_clk_init(np, EXYNOS5420);
+}
CLK_OF_DECLARE(exynos5420_clk, "samsung,exynos5420-clock", exynos5420_clk_init);
+
+static void __init exynos5800_clk_init(struct device_node *np)
+{
+ exynos5x_clk_init(np, EXYNOS5800);
+}
+CLK_OF_DECLARE(exynos5800_clk, "samsung,exynos5800-clock", exynos5800_clk_init);
diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c
index 2bfad5a993d0..647f1440aa6a 100644
--- a/drivers/clk/samsung/clk-exynos5440.c
+++ b/drivers/clk/samsung/clk-exynos5440.c
@@ -93,6 +93,7 @@ static struct of_device_id ext_clk_match[] __initdata = {
static void __init exynos5440_clk_init(struct device_node *np)
{
void __iomem *reg_base;
+ struct samsung_clk_provider *ctx;
reg_base = of_iomap(np, 0);
if (!reg_base) {
@@ -101,22 +102,25 @@ static void __init exynos5440_clk_init(struct device_node *np)
return;
}
- samsung_clk_init(np, reg_base, CLK_NR_CLKS);
- samsung_clk_of_register_fixed_ext(exynos5440_fixed_rate_ext_clks,
+ ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
+ if (!ctx)
+ panic("%s: unable to allocate context.\n", __func__);
+
+ samsung_clk_of_register_fixed_ext(ctx, exynos5440_fixed_rate_ext_clks,
ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match);
samsung_clk_register_pll2550x("cplla", "xtal", reg_base + 0x1c, 0x10);
samsung_clk_register_pll2550x("cpllb", "xtal", reg_base + 0x20, 0x10);
- samsung_clk_register_fixed_rate(exynos5440_fixed_rate_clks,
+ samsung_clk_register_fixed_rate(ctx, exynos5440_fixed_rate_clks,
ARRAY_SIZE(exynos5440_fixed_rate_clks));
- samsung_clk_register_fixed_factor(exynos5440_fixed_factor_clks,
+ samsung_clk_register_fixed_factor(ctx, exynos5440_fixed_factor_clks,
ARRAY_SIZE(exynos5440_fixed_factor_clks));
- samsung_clk_register_mux(exynos5440_mux_clks,
+ samsung_clk_register_mux(ctx, exynos5440_mux_clks,
ARRAY_SIZE(exynos5440_mux_clks));
- samsung_clk_register_div(exynos5440_div_clks,
+ samsung_clk_register_div(ctx, exynos5440_div_clks,
ARRAY_SIZE(exynos5440_div_clks));
- samsung_clk_register_gate(exynos5440_gate_clks,
+ samsung_clk_register_gate(ctx, exynos5440_gate_clks,
ARRAY_SIZE(exynos5440_gate_clks));
pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("arm_clk"));
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index 81e6d2f49aa0..b07fad2a9167 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/hrtimer.h>
+#include <linux/delay.h>
#include "clk.h"
#include "clk-pll.h"
@@ -59,6 +60,72 @@ static long samsung_pll_round_rate(struct clk_hw *hw,
}
/*
+ * PLL2126 Clock Type
+ */
+
+#define PLL2126_MDIV_MASK (0xff)
+#define PLL2126_PDIV_MASK (0x3f)
+#define PLL2126_SDIV_MASK (0x3)
+#define PLL2126_MDIV_SHIFT (16)
+#define PLL2126_PDIV_SHIFT (8)
+#define PLL2126_SDIV_SHIFT (0)
+
+static unsigned long samsung_pll2126_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ u32 pll_con, mdiv, pdiv, sdiv;
+ u64 fvco = parent_rate;
+
+ pll_con = __raw_readl(pll->con_reg);
+ mdiv = (pll_con >> PLL2126_MDIV_SHIFT) & PLL2126_MDIV_MASK;
+ pdiv = (pll_con >> PLL2126_PDIV_SHIFT) & PLL2126_PDIV_MASK;
+ sdiv = (pll_con >> PLL2126_SDIV_SHIFT) & PLL2126_SDIV_MASK;
+
+ fvco *= (mdiv + 8);
+ do_div(fvco, (pdiv + 2) << sdiv);
+
+ return (unsigned long)fvco;
+}
+
+static const struct clk_ops samsung_pll2126_clk_ops = {
+ .recalc_rate = samsung_pll2126_recalc_rate,
+};
+
+/*
+ * PLL3000 Clock Type
+ */
+
+#define PLL3000_MDIV_MASK (0xff)
+#define PLL3000_PDIV_MASK (0x3)
+#define PLL3000_SDIV_MASK (0x3)
+#define PLL3000_MDIV_SHIFT (16)
+#define PLL3000_PDIV_SHIFT (8)
+#define PLL3000_SDIV_SHIFT (0)
+
+static unsigned long samsung_pll3000_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ u32 pll_con, mdiv, pdiv, sdiv;
+ u64 fvco = parent_rate;
+
+ pll_con = __raw_readl(pll->con_reg);
+ mdiv = (pll_con >> PLL3000_MDIV_SHIFT) & PLL3000_MDIV_MASK;
+ pdiv = (pll_con >> PLL3000_PDIV_SHIFT) & PLL3000_PDIV_MASK;
+ sdiv = (pll_con >> PLL3000_SDIV_SHIFT) & PLL3000_SDIV_MASK;
+
+ fvco *= (2 * (mdiv + 8));
+ do_div(fvco, pdiv << sdiv);
+
+ return (unsigned long)fvco;
+}
+
+static const struct clk_ops samsung_pll3000_clk_ops = {
+ .recalc_rate = samsung_pll3000_recalc_rate,
+};
+
+/*
* PLL35xx Clock Type
*/
/* Maximum lock time can be 270 * PDIV cycles */
@@ -564,7 +631,9 @@ static const struct clk_ops samsung_pll46xx_clk_min_ops = {
#define PLL6552_PDIV_MASK 0x3f
#define PLL6552_SDIV_MASK 0x7
#define PLL6552_MDIV_SHIFT 16
+#define PLL6552_MDIV_SHIFT_2416 14
#define PLL6552_PDIV_SHIFT 8
+#define PLL6552_PDIV_SHIFT_2416 5
#define PLL6552_SDIV_SHIFT 0
static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
@@ -575,8 +644,13 @@ static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
u64 fvco = parent_rate;
pll_con = __raw_readl(pll->con_reg);
- mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK;
- pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK;
+ if (pll->type == pll_6552_s3c2416) {
+ mdiv = (pll_con >> PLL6552_MDIV_SHIFT_2416) & PLL6552_MDIV_MASK;
+ pdiv = (pll_con >> PLL6552_PDIV_SHIFT_2416) & PLL6552_PDIV_MASK;
+ } else {
+ mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK;
+ pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK;
+ }
sdiv = (pll_con >> PLL6552_SDIV_SHIFT) & PLL6552_SDIV_MASK;
fvco *= mdiv;
@@ -628,6 +702,169 @@ static const struct clk_ops samsung_pll6553_clk_ops = {
};
/*
+ * PLL Clock Type of S3C24XX before S3C2443
+ */
+
+#define PLLS3C2410_MDIV_MASK (0xff)
+#define PLLS3C2410_PDIV_MASK (0x1f)
+#define PLLS3C2410_SDIV_MASK (0x3)
+#define PLLS3C2410_MDIV_SHIFT (12)
+#define PLLS3C2410_PDIV_SHIFT (4)
+#define PLLS3C2410_SDIV_SHIFT (0)
+
+#define PLLS3C2410_ENABLE_REG_OFFSET 0x10
+
+static unsigned long samsung_s3c2410_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ u32 pll_con, mdiv, pdiv, sdiv;
+ u64 fvco = parent_rate;
+
+ pll_con = __raw_readl(pll->con_reg);
+ mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
+ pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
+ sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
+
+ fvco *= (mdiv + 8);
+ do_div(fvco, (pdiv + 2) << sdiv);
+
+ return (unsigned int)fvco;
+}
+
+static unsigned long samsung_s3c2440_mpll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ u32 pll_con, mdiv, pdiv, sdiv;
+ u64 fvco = parent_rate;
+
+ pll_con = __raw_readl(pll->con_reg);
+ mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
+ pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
+ sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
+
+ fvco *= (2 * (mdiv + 8));
+ do_div(fvco, (pdiv + 2) << sdiv);
+
+ return (unsigned int)fvco;
+}
+
+static int samsung_s3c2410_pll_set_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long prate)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ const struct samsung_pll_rate_table *rate;
+ u32 tmp;
+
+ /* Get required rate settings from table */
+ rate = samsung_get_pll_settings(pll, drate);
+ if (!rate) {
+ pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+ drate, __clk_get_name(hw->clk));
+ return -EINVAL;
+ }
+
+ tmp = __raw_readl(pll->con_reg);
+
+ /* Change PLL PMS values */
+ tmp &= ~((PLLS3C2410_MDIV_MASK << PLLS3C2410_MDIV_SHIFT) |
+ (PLLS3C2410_PDIV_MASK << PLLS3C2410_PDIV_SHIFT) |
+ (PLLS3C2410_SDIV_MASK << PLLS3C2410_SDIV_SHIFT));
+ tmp |= (rate->mdiv << PLLS3C2410_MDIV_SHIFT) |
+ (rate->pdiv << PLLS3C2410_PDIV_SHIFT) |
+ (rate->sdiv << PLLS3C2410_SDIV_SHIFT);
+ __raw_writel(tmp, pll->con_reg);
+
+ /* Time to settle according to the manual */
+ udelay(300);
+
+ return 0;
+}
+
+static int samsung_s3c2410_pll_enable(struct clk_hw *hw, int bit, bool enable)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ u32 pll_en = __raw_readl(pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
+ u32 pll_en_orig = pll_en;
+
+ if (enable)
+ pll_en &= ~BIT(bit);
+ else
+ pll_en |= BIT(bit);
+
+ __raw_writel(pll_en, pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
+
+ /* if we started the UPLL, then allow to settle */
+ if (enable && (pll_en_orig & BIT(bit)))
+ udelay(300);
+
+ return 0;
+}
+
+static int samsung_s3c2410_mpll_enable(struct clk_hw *hw)
+{
+ return samsung_s3c2410_pll_enable(hw, 5, true);
+}
+
+static void samsung_s3c2410_mpll_disable(struct clk_hw *hw)
+{
+ samsung_s3c2410_pll_enable(hw, 5, false);
+}
+
+static int samsung_s3c2410_upll_enable(struct clk_hw *hw)
+{
+ return samsung_s3c2410_pll_enable(hw, 7, true);
+}
+
+static void samsung_s3c2410_upll_disable(struct clk_hw *hw)
+{
+ samsung_s3c2410_pll_enable(hw, 7, false);
+}
+
+static const struct clk_ops samsung_s3c2410_mpll_clk_min_ops = {
+ .recalc_rate = samsung_s3c2410_pll_recalc_rate,
+ .enable = samsung_s3c2410_mpll_enable,
+ .disable = samsung_s3c2410_mpll_disable,
+};
+
+static const struct clk_ops samsung_s3c2410_upll_clk_min_ops = {
+ .recalc_rate = samsung_s3c2410_pll_recalc_rate,
+ .enable = samsung_s3c2410_upll_enable,
+ .disable = samsung_s3c2410_upll_disable,
+};
+
+static const struct clk_ops samsung_s3c2440_mpll_clk_min_ops = {
+ .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
+ .enable = samsung_s3c2410_mpll_enable,
+ .disable = samsung_s3c2410_mpll_disable,
+};
+
+static const struct clk_ops samsung_s3c2410_mpll_clk_ops = {
+ .recalc_rate = samsung_s3c2410_pll_recalc_rate,
+ .enable = samsung_s3c2410_mpll_enable,
+ .disable = samsung_s3c2410_mpll_disable,
+ .round_rate = samsung_pll_round_rate,
+ .set_rate = samsung_s3c2410_pll_set_rate,
+};
+
+static const struct clk_ops samsung_s3c2410_upll_clk_ops = {
+ .recalc_rate = samsung_s3c2410_pll_recalc_rate,
+ .enable = samsung_s3c2410_upll_enable,
+ .disable = samsung_s3c2410_upll_disable,
+ .round_rate = samsung_pll_round_rate,
+ .set_rate = samsung_s3c2410_pll_set_rate,
+};
+
+static const struct clk_ops samsung_s3c2440_mpll_clk_ops = {
+ .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
+ .enable = samsung_s3c2410_mpll_enable,
+ .disable = samsung_s3c2410_mpll_disable,
+ .round_rate = samsung_pll_round_rate,
+ .set_rate = samsung_s3c2410_pll_set_rate,
+};
+
+/*
* PLL2550x Clock Type
*/
@@ -710,8 +947,206 @@ struct clk * __init samsung_clk_register_pll2550x(const char *name,
return clk;
}
-static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
- void __iomem *base)
+/*
+ * PLL2550xx Clock Type
+ */
+
+/* Maximum lock time can be 270 * PDIV cycles */
+#define PLL2550XX_LOCK_FACTOR 270
+
+#define PLL2550XX_M_MASK 0x3FF
+#define PLL2550XX_P_MASK 0x3F
+#define PLL2550XX_S_MASK 0x7
+#define PLL2550XX_LOCK_STAT_MASK 0x1
+#define PLL2550XX_M_SHIFT 9
+#define PLL2550XX_P_SHIFT 3
+#define PLL2550XX_S_SHIFT 0
+#define PLL2550XX_LOCK_STAT_SHIFT 21
+
+static unsigned long samsung_pll2550xx_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ u32 mdiv, pdiv, sdiv, pll_con;
+ u64 fvco = parent_rate;
+
+ pll_con = __raw_readl(pll->con_reg);
+ mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
+ pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
+ sdiv = (pll_con >> PLL2550XX_S_SHIFT) & PLL2550XX_S_MASK;
+
+ fvco *= mdiv;
+ do_div(fvco, (pdiv << sdiv));
+
+ return (unsigned long)fvco;
+}
+
+static inline bool samsung_pll2550xx_mp_change(u32 mdiv, u32 pdiv, u32 pll_con)
+{
+ u32 old_mdiv, old_pdiv;
+
+ old_mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
+ old_pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
+
+ return mdiv != old_mdiv || pdiv != old_pdiv;
+}
+
+static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long prate)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ const struct samsung_pll_rate_table *rate;
+ u32 tmp;
+
+ /* Get required rate settings from table */
+ rate = samsung_get_pll_settings(pll, drate);
+ if (!rate) {
+ pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+ drate, __clk_get_name(hw->clk));
+ return -EINVAL;
+ }
+
+ tmp = __raw_readl(pll->con_reg);
+
+ if (!(samsung_pll2550xx_mp_change(rate->mdiv, rate->pdiv, tmp))) {
+ /* If only s change, change just s value only*/
+ tmp &= ~(PLL2550XX_S_MASK << PLL2550XX_S_SHIFT);
+ tmp |= rate->sdiv << PLL2550XX_S_SHIFT;
+ __raw_writel(tmp, pll->con_reg);
+
+ return 0;
+ }
+
+ /* Set PLL lock time. */
+ __raw_writel(rate->pdiv * PLL2550XX_LOCK_FACTOR, pll->lock_reg);
+
+ /* Change PLL PMS values */
+ tmp &= ~((PLL2550XX_M_MASK << PLL2550XX_M_SHIFT) |
+ (PLL2550XX_P_MASK << PLL2550XX_P_SHIFT) |
+ (PLL2550XX_S_MASK << PLL2550XX_S_SHIFT));
+ tmp |= (rate->mdiv << PLL2550XX_M_SHIFT) |
+ (rate->pdiv << PLL2550XX_P_SHIFT) |
+ (rate->sdiv << PLL2550XX_S_SHIFT);
+ __raw_writel(tmp, pll->con_reg);
+
+ /* wait_lock_time */
+ do {
+ cpu_relax();
+ tmp = __raw_readl(pll->con_reg);
+ } while (!(tmp & (PLL2550XX_LOCK_STAT_MASK
+ << PLL2550XX_LOCK_STAT_SHIFT)));
+
+ return 0;
+}
+
+static const struct clk_ops samsung_pll2550xx_clk_ops = {
+ .recalc_rate = samsung_pll2550xx_recalc_rate,
+ .round_rate = samsung_pll_round_rate,
+ .set_rate = samsung_pll2550xx_set_rate,
+};
+
+static const struct clk_ops samsung_pll2550xx_clk_min_ops = {
+ .recalc_rate = samsung_pll2550xx_recalc_rate,
+};
+
+/*
+ * PLL2650XX Clock Type
+ */
+
+/* Maximum lock time can be 3000 * PDIV cycles */
+#define PLL2650XX_LOCK_FACTOR 3000
+
+#define PLL2650XX_MDIV_SHIFT 9
+#define PLL2650XX_PDIV_SHIFT 3
+#define PLL2650XX_SDIV_SHIFT 0
+#define PLL2650XX_KDIV_SHIFT 0
+#define PLL2650XX_MDIV_MASK 0x1ff
+#define PLL2650XX_PDIV_MASK 0x3f
+#define PLL2650XX_SDIV_MASK 0x7
+#define PLL2650XX_KDIV_MASK 0xffff
+#define PLL2650XX_PLL_ENABLE_SHIFT 23
+#define PLL2650XX_PLL_LOCKTIME_SHIFT 21
+#define PLL2650XX_PLL_FOUTMASK_SHIFT 31
+
+static unsigned long samsung_pll2650xx_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ u32 mdiv, pdiv, sdiv, pll_con0, pll_con2;
+ s16 kdiv;
+ u64 fvco = parent_rate;
+
+ pll_con0 = __raw_readl(pll->con_reg);
+ pll_con2 = __raw_readl(pll->con_reg + 8);
+ mdiv = (pll_con0 >> PLL2650XX_MDIV_SHIFT) & PLL2650XX_MDIV_MASK;
+ pdiv = (pll_con0 >> PLL2650XX_PDIV_SHIFT) & PLL2650XX_PDIV_MASK;
+ sdiv = (pll_con0 >> PLL2650XX_SDIV_SHIFT) & PLL2650XX_SDIV_MASK;
+ kdiv = (s16)(pll_con2 & PLL2650XX_KDIV_MASK);
+
+ fvco *= (mdiv << 16) + kdiv;
+ do_div(fvco, (pdiv << sdiv));
+ fvco >>= 16;
+
+ return (unsigned long)fvco;
+}
+
+static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll *pll = to_clk_pll(hw);
+ u32 tmp, pll_con0, pll_con2;
+ const struct samsung_pll_rate_table *rate;
+
+ rate = samsung_get_pll_settings(pll, drate);
+ if (!rate) {
+ pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+ drate, __clk_get_name(hw->clk));
+ return -EINVAL;
+ }
+
+ pll_con0 = __raw_readl(pll->con_reg);
+ pll_con2 = __raw_readl(pll->con_reg + 8);
+
+ /* Change PLL PMS values */
+ pll_con0 &= ~(PLL2650XX_MDIV_MASK << PLL2650XX_MDIV_SHIFT |
+ PLL2650XX_PDIV_MASK << PLL2650XX_PDIV_SHIFT |
+ PLL2650XX_SDIV_MASK << PLL2650XX_SDIV_SHIFT);
+ pll_con0 |= rate->mdiv << PLL2650XX_MDIV_SHIFT;
+ pll_con0 |= rate->pdiv << PLL2650XX_PDIV_SHIFT;
+ pll_con0 |= rate->sdiv << PLL2650XX_SDIV_SHIFT;
+ pll_con0 |= 1 << PLL2650XX_PLL_ENABLE_SHIFT;
+ pll_con0 |= 1 << PLL2650XX_PLL_FOUTMASK_SHIFT;
+
+ pll_con2 &= ~(PLL2650XX_KDIV_MASK << PLL2650XX_KDIV_SHIFT);
+ pll_con2 |= ((~(rate->kdiv) + 1) & PLL2650XX_KDIV_MASK)
+ << PLL2650XX_KDIV_SHIFT;
+
+ /* Set PLL lock time. */
+ __raw_writel(PLL2650XX_LOCK_FACTOR * rate->pdiv, pll->lock_reg);
+
+ __raw_writel(pll_con0, pll->con_reg);
+ __raw_writel(pll_con2, pll->con_reg + 8);
+
+ do {
+ tmp = __raw_readl(pll->con_reg);
+ } while (!(tmp & (0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT)));
+
+ return 0;
+}
+
+static const struct clk_ops samsung_pll2650xx_clk_ops = {
+ .recalc_rate = samsung_pll2650xx_recalc_rate,
+ .set_rate = samsung_pll2650xx_set_rate,
+ .round_rate = samsung_pll_round_rate,
+};
+
+static const struct clk_ops samsung_pll2650xx_clk_min_ops = {
+ .recalc_rate = samsung_pll2650xx_recalc_rate,
+};
+
+static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
+ struct samsung_pll_clock *pll_clk,
+ void __iomem *base)
{
struct samsung_clk_pll *pll;
struct clk *clk;
@@ -746,6 +1181,12 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
}
switch (pll_clk->type) {
+ case pll_2126:
+ init.ops = &samsung_pll2126_clk_ops;
+ break;
+ case pll_3000:
+ init.ops = &samsung_pll3000_clk_ops;
+ break;
/* clk_ops for 35xx and 2550 are similar */
case pll_35xx:
case pll_2550:
@@ -773,6 +1214,7 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
init.ops = &samsung_pll36xx_clk_ops;
break;
case pll_6552:
+ case pll_6552_s3c2416:
init.ops = &samsung_pll6552_clk_ops;
break;
case pll_6553:
@@ -786,6 +1228,36 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
else
init.ops = &samsung_pll46xx_clk_ops;
break;
+ case pll_s3c2410_mpll:
+ if (!pll->rate_table)
+ init.ops = &samsung_s3c2410_mpll_clk_min_ops;
+ else
+ init.ops = &samsung_s3c2410_mpll_clk_ops;
+ break;
+ case pll_s3c2410_upll:
+ if (!pll->rate_table)
+ init.ops = &samsung_s3c2410_upll_clk_min_ops;
+ else
+ init.ops = &samsung_s3c2410_upll_clk_ops;
+ break;
+ case pll_s3c2440_mpll:
+ if (!pll->rate_table)
+ init.ops = &samsung_s3c2440_mpll_clk_min_ops;
+ else
+ init.ops = &samsung_s3c2440_mpll_clk_ops;
+ break;
+ case pll_2550xx:
+ if (!pll->rate_table)
+ init.ops = &samsung_pll2550xx_clk_min_ops;
+ else
+ init.ops = &samsung_pll2550xx_clk_ops;
+ break;
+ case pll_2650xx:
+ if (!pll->rate_table)
+ init.ops = &samsung_pll2650xx_clk_min_ops;
+ else
+ init.ops = &samsung_pll2650xx_clk_ops;
+ break;
default:
pr_warn("%s: Unknown pll type for pll clk %s\n",
__func__, pll_clk->name);
@@ -804,7 +1276,7 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
return;
}
- samsung_clk_add_lookup(clk, pll_clk->id);
+ samsung_clk_add_lookup(ctx, clk, pll_clk->id);
if (!pll_clk->alias)
return;
@@ -815,11 +1287,12 @@ static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
__func__, pll_clk->name, ret);
}
-void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
- unsigned int nr_pll, void __iomem *base)
+void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx,
+ struct samsung_pll_clock *pll_list,
+ unsigned int nr_pll, void __iomem *base)
{
int cnt;
for (cnt = 0; cnt < nr_pll; cnt++)
- _samsung_clk_register_pll(&pll_list[cnt], base);
+ _samsung_clk_register_pll(ctx, &pll_list[cnt], base);
}
diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h
index 6c39030080fb..c0ed4d41fd90 100644
--- a/drivers/clk/samsung/clk-pll.h
+++ b/drivers/clk/samsung/clk-pll.h
@@ -13,6 +13,8 @@
#define __SAMSUNG_CLK_PLL_H
enum samsung_pll_type {
+ pll_2126,
+ pll_3000,
pll_35xx,
pll_36xx,
pll_2550,
@@ -24,7 +26,13 @@ enum samsung_pll_type {
pll_4650,
pll_4650c,
pll_6552,
+ pll_6552_s3c2416,
pll_6553,
+ pll_s3c2410_mpll,
+ pll_s3c2410_upll,
+ pll_s3c2440_mpll,
+ pll_2550xx,
+ pll_2650xx,
};
#define PLL_35XX_RATE(_rate, _m, _p, _s) \
diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c
new file mode 100644
index 000000000000..0449cc0458ed
--- /dev/null
+++ b/drivers/clk/samsung/clk-s3c2410-dclk.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * Common Clock Framework support for s3c24xx external clock output.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include "clk.h"
+
+/* legacy access to misccr, until dt conversion is finished */
+#include <mach/hardware.h>
+#include <mach/regs-gpio.h>
+
+#define MUX_DCLK0 0
+#define MUX_DCLK1 1
+#define DIV_DCLK0 2
+#define DIV_DCLK1 3
+#define GATE_DCLK0 4
+#define GATE_DCLK1 5
+#define MUX_CLKOUT0 6
+#define MUX_CLKOUT1 7
+#define DCLK_MAX_CLKS (MUX_CLKOUT1 + 1)
+
+enum supported_socs {
+ S3C2410,
+ S3C2412,
+ S3C2440,
+ S3C2443,
+};
+
+struct s3c24xx_dclk_drv_data {
+ const char **clkout0_parent_names;
+ int clkout0_num_parents;
+ const char **clkout1_parent_names;
+ int clkout1_num_parents;
+ const char **mux_parent_names;
+ int mux_num_parents;
+};
+
+/*
+ * Clock for output-parent selection in misccr
+ */
+
+struct s3c24xx_clkout {
+ struct clk_hw hw;
+ u32 mask;
+ u8 shift;
+};
+
+#define to_s3c24xx_clkout(_hw) container_of(_hw, struct s3c24xx_clkout, hw)
+
+static u8 s3c24xx_clkout_get_parent(struct clk_hw *hw)
+{
+ struct s3c24xx_clkout *clkout = to_s3c24xx_clkout(hw);
+ int num_parents = __clk_get_num_parents(hw->clk);
+ u32 val;
+
+ val = readl_relaxed(S3C24XX_MISCCR) >> clkout->shift;
+ val >>= clkout->shift;
+ val &= clkout->mask;
+
+ if (val >= num_parents)
+ return -EINVAL;
+
+ return val;
+}
+
+static int s3c24xx_clkout_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct s3c24xx_clkout *clkout = to_s3c24xx_clkout(hw);
+ int ret = 0;
+
+ s3c2410_modify_misccr((clkout->mask << clkout->shift),
+ (index << clkout->shift));
+
+ return ret;
+}
+
+const struct clk_ops s3c24xx_clkout_ops = {
+ .get_parent = s3c24xx_clkout_get_parent,
+ .set_parent = s3c24xx_clkout_set_parent,
+ .determine_rate = __clk_mux_determine_rate,
+};
+
+struct clk *s3c24xx_register_clkout(struct device *dev, const char *name,
+ const char **parent_names, u8 num_parents,
+ u8 shift, u32 mask)
+{
+ struct s3c24xx_clkout *clkout;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ /* allocate the clkout */
+ clkout = kzalloc(sizeof(*clkout), GFP_KERNEL);
+ if (!clkout)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &s3c24xx_clkout_ops;
+ init.flags = CLK_IS_BASIC;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+
+ clkout->shift = shift;
+ clkout->mask = mask;
+ clkout->hw.init = &init;
+
+ clk = clk_register(dev, &clkout->hw);
+
+ return clk;
+}
+
+/*
+ * dclk and clkout init
+ */
+
+struct s3c24xx_dclk {
+ struct device *dev;
+ void __iomem *base;
+ struct clk_onecell_data clk_data;
+ struct notifier_block dclk0_div_change_nb;
+ struct notifier_block dclk1_div_change_nb;
+ spinlock_t dclk_lock;
+ unsigned long reg_save;
+};
+
+#define to_s3c24xx_dclk0(x) \
+ container_of(x, struct s3c24xx_dclk, dclk0_div_change_nb)
+
+#define to_s3c24xx_dclk1(x) \
+ container_of(x, struct s3c24xx_dclk, dclk1_div_change_nb)
+
+static const char *dclk_s3c2410_p[] = { "pclk", "uclk" };
+static const char *clkout0_s3c2410_p[] = { "mpll", "upll", "fclk", "hclk", "pclk",
+ "gate_dclk0" };
+static const char *clkout1_s3c2410_p[] = { "mpll", "upll", "fclk", "hclk", "pclk",
+ "gate_dclk1" };
+
+static const char *clkout0_s3c2412_p[] = { "mpll", "upll", "rtc_clkout",
+ "hclk", "pclk", "gate_dclk0" };
+static const char *clkout1_s3c2412_p[] = { "xti", "upll", "fclk", "hclk", "pclk",
+ "gate_dclk1" };
+
+static const char *clkout0_s3c2440_p[] = { "xti", "upll", "fclk", "hclk", "pclk",
+ "gate_dclk0" };
+static const char *clkout1_s3c2440_p[] = { "mpll", "upll", "rtc_clkout",
+ "hclk", "pclk", "gate_dclk1" };
+
+static const char *dclk_s3c2443_p[] = { "pclk", "epll" };
+static const char *clkout0_s3c2443_p[] = { "xti", "epll", "armclk", "hclk", "pclk",
+ "gate_dclk0" };
+static const char *clkout1_s3c2443_p[] = { "dummy", "epll", "rtc_clkout",
+ "hclk", "pclk", "gate_dclk1" };
+
+#define DCLKCON_DCLK_DIV_MASK 0xf
+#define DCLKCON_DCLK0_DIV_SHIFT 4
+#define DCLKCON_DCLK0_CMP_SHIFT 8
+#define DCLKCON_DCLK1_DIV_SHIFT 20
+#define DCLKCON_DCLK1_CMP_SHIFT 24
+
+static void s3c24xx_dclk_update_cmp(struct s3c24xx_dclk *s3c24xx_dclk,
+ int div_shift, int cmp_shift)
+{
+ unsigned long flags = 0;
+ u32 dclk_con, div, cmp;
+
+ spin_lock_irqsave(&s3c24xx_dclk->dclk_lock, flags);
+
+ dclk_con = readl_relaxed(s3c24xx_dclk->base);
+
+ div = ((dclk_con >> div_shift) & DCLKCON_DCLK_DIV_MASK) + 1;
+ cmp = ((div + 1) / 2) - 1;
+
+ dclk_con &= ~(DCLKCON_DCLK_DIV_MASK << cmp_shift);
+ dclk_con |= (cmp << cmp_shift);
+
+ writel_relaxed(dclk_con, s3c24xx_dclk->base);
+
+ spin_unlock_irqrestore(&s3c24xx_dclk->dclk_lock, flags);
+}
+
+static int s3c24xx_dclk0_div_notify(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct s3c24xx_dclk *s3c24xx_dclk = to_s3c24xx_dclk0(nb);
+
+ if (event == POST_RATE_CHANGE) {
+ s3c24xx_dclk_update_cmp(s3c24xx_dclk,
+ DCLKCON_DCLK0_DIV_SHIFT, DCLKCON_DCLK0_CMP_SHIFT);
+ }
+
+ return NOTIFY_DONE;
+}
+
+static int s3c24xx_dclk1_div_notify(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct s3c24xx_dclk *s3c24xx_dclk = to_s3c24xx_dclk1(nb);
+
+ if (event == POST_RATE_CHANGE) {
+ s3c24xx_dclk_update_cmp(s3c24xx_dclk,
+ DCLKCON_DCLK1_DIV_SHIFT, DCLKCON_DCLK1_CMP_SHIFT);
+ }
+
+ return NOTIFY_DONE;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int s3c24xx_dclk_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s3c24xx_dclk *s3c24xx_dclk = platform_get_drvdata(pdev);
+
+ s3c24xx_dclk->reg_save = readl_relaxed(s3c24xx_dclk->base);
+ return 0;
+}
+
+static int s3c24xx_dclk_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s3c24xx_dclk *s3c24xx_dclk = platform_get_drvdata(pdev);
+
+ writel_relaxed(s3c24xx_dclk->reg_save, s3c24xx_dclk->base);
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(s3c24xx_dclk_pm_ops,
+ s3c24xx_dclk_suspend, s3c24xx_dclk_resume);
+
+static int s3c24xx_dclk_probe(struct platform_device *pdev)
+{
+ struct s3c24xx_dclk *s3c24xx_dclk;
+ struct resource *mem;
+ struct clk **clk_table;
+ struct s3c24xx_dclk_drv_data *dclk_variant;
+ int ret, i;
+
+ s3c24xx_dclk = devm_kzalloc(&pdev->dev, sizeof(*s3c24xx_dclk),
+ GFP_KERNEL);
+ if (!s3c24xx_dclk)
+ return -ENOMEM;
+
+ s3c24xx_dclk->dev = &pdev->dev;
+ platform_set_drvdata(pdev, s3c24xx_dclk);
+ spin_lock_init(&s3c24xx_dclk->dclk_lock);
+
+ clk_table = devm_kzalloc(&pdev->dev,
+ sizeof(struct clk *) * DCLK_MAX_CLKS,
+ GFP_KERNEL);
+ if (!clk_table)
+ return -ENOMEM;
+
+ s3c24xx_dclk->clk_data.clks = clk_table;
+ s3c24xx_dclk->clk_data.clk_num = DCLK_MAX_CLKS;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ s3c24xx_dclk->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(s3c24xx_dclk->base))
+ return PTR_ERR(s3c24xx_dclk->base);
+
+ dclk_variant = (struct s3c24xx_dclk_drv_data *)
+ platform_get_device_id(pdev)->driver_data;
+
+
+ clk_table[MUX_DCLK0] = clk_register_mux(&pdev->dev, "mux_dclk0",
+ dclk_variant->mux_parent_names,
+ dclk_variant->mux_num_parents, 0,
+ s3c24xx_dclk->base, 1, 1, 0,
+ &s3c24xx_dclk->dclk_lock);
+ clk_table[MUX_DCLK1] = clk_register_mux(&pdev->dev, "mux_dclk1",
+ dclk_variant->mux_parent_names,
+ dclk_variant->mux_num_parents, 0,
+ s3c24xx_dclk->base, 17, 1, 0,
+ &s3c24xx_dclk->dclk_lock);
+
+ clk_table[DIV_DCLK0] = clk_register_divider(&pdev->dev, "div_dclk0",
+ "mux_dclk0", 0, s3c24xx_dclk->base,
+ 4, 4, 0, &s3c24xx_dclk->dclk_lock);
+ clk_table[DIV_DCLK1] = clk_register_divider(&pdev->dev, "div_dclk1",
+ "mux_dclk1", 0, s3c24xx_dclk->base,
+ 20, 4, 0, &s3c24xx_dclk->dclk_lock);
+
+ clk_table[GATE_DCLK0] = clk_register_gate(&pdev->dev, "gate_dclk0",
+ "div_dclk0", CLK_SET_RATE_PARENT,
+ s3c24xx_dclk->base, 0, 0,
+ &s3c24xx_dclk->dclk_lock);
+ clk_table[GATE_DCLK1] = clk_register_gate(&pdev->dev, "gate_dclk1",
+ "div_dclk1", CLK_SET_RATE_PARENT,
+ s3c24xx_dclk->base, 16, 0,
+ &s3c24xx_dclk->dclk_lock);
+
+ clk_table[MUX_CLKOUT0] = s3c24xx_register_clkout(&pdev->dev,
+ "clkout0", dclk_variant->clkout0_parent_names,
+ dclk_variant->clkout0_num_parents, 4, 7);
+ clk_table[MUX_CLKOUT1] = s3c24xx_register_clkout(&pdev->dev,
+ "clkout1", dclk_variant->clkout1_parent_names,
+ dclk_variant->clkout1_num_parents, 8, 7);
+
+ for (i = 0; i < DCLK_MAX_CLKS; i++)
+ if (IS_ERR(clk_table[i])) {
+ dev_err(&pdev->dev, "clock %d failed to register\n", i);
+ ret = PTR_ERR(clk_table[i]);
+ goto err_clk_register;
+ }
+
+ ret = clk_register_clkdev(clk_table[MUX_DCLK0], "dclk0", NULL);
+ if (!ret)
+ ret = clk_register_clkdev(clk_table[MUX_DCLK1], "dclk1", NULL);
+ if (!ret)
+ ret = clk_register_clkdev(clk_table[MUX_CLKOUT0],
+ "clkout0", NULL);
+ if (!ret)
+ ret = clk_register_clkdev(clk_table[MUX_CLKOUT1],
+ "clkout1", NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register aliases, %d\n", ret);
+ goto err_clk_register;
+ }
+
+ s3c24xx_dclk->dclk0_div_change_nb.notifier_call =
+ s3c24xx_dclk0_div_notify;
+
+ s3c24xx_dclk->dclk1_div_change_nb.notifier_call =
+ s3c24xx_dclk1_div_notify;
+
+ ret = clk_notifier_register(clk_table[DIV_DCLK0],
+ &s3c24xx_dclk->dclk0_div_change_nb);
+ if (ret)
+ goto err_clk_register;
+
+ ret = clk_notifier_register(clk_table[DIV_DCLK1],
+ &s3c24xx_dclk->dclk1_div_change_nb);
+ if (ret)
+ goto err_dclk_notify;
+
+ return 0;
+
+err_dclk_notify:
+ clk_notifier_unregister(clk_table[DIV_DCLK0],
+ &s3c24xx_dclk->dclk0_div_change_nb);
+err_clk_register:
+ for (i = 0; i < DCLK_MAX_CLKS; i++)
+ if (clk_table[i] && !IS_ERR(clk_table[i]))
+ clk_unregister(clk_table[i]);
+
+ return ret;
+}
+
+static int s3c24xx_dclk_remove(struct platform_device *pdev)
+{
+ struct s3c24xx_dclk *s3c24xx_dclk = platform_get_drvdata(pdev);
+ struct clk **clk_table = s3c24xx_dclk->clk_data.clks;
+ int i;
+
+ clk_notifier_unregister(clk_table[DIV_DCLK1],
+ &s3c24xx_dclk->dclk1_div_change_nb);
+ clk_notifier_unregister(clk_table[DIV_DCLK0],
+ &s3c24xx_dclk->dclk0_div_change_nb);
+
+ for (i = 0; i < DCLK_MAX_CLKS; i++)
+ clk_unregister(clk_table[i]);
+
+ return 0;
+}
+
+static struct s3c24xx_dclk_drv_data dclk_variants[] = {
+ [S3C2410] = {
+ .clkout0_parent_names = clkout0_s3c2410_p,
+ .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2410_p),
+ .clkout1_parent_names = clkout1_s3c2410_p,
+ .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2410_p),
+ .mux_parent_names = dclk_s3c2410_p,
+ .mux_num_parents = ARRAY_SIZE(dclk_s3c2410_p),
+ },
+ [S3C2412] = {
+ .clkout0_parent_names = clkout0_s3c2412_p,
+ .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2412_p),
+ .clkout1_parent_names = clkout1_s3c2412_p,
+ .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2412_p),
+ .mux_parent_names = dclk_s3c2410_p,
+ .mux_num_parents = ARRAY_SIZE(dclk_s3c2410_p),
+ },
+ [S3C2440] = {
+ .clkout0_parent_names = clkout0_s3c2440_p,
+ .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2440_p),
+ .clkout1_parent_names = clkout1_s3c2440_p,
+ .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2440_p),
+ .mux_parent_names = dclk_s3c2410_p,
+ .mux_num_parents = ARRAY_SIZE(dclk_s3c2410_p),
+ },
+ [S3C2443] = {
+ .clkout0_parent_names = clkout0_s3c2443_p,
+ .clkout0_num_parents = ARRAY_SIZE(clkout0_s3c2443_p),
+ .clkout1_parent_names = clkout1_s3c2443_p,
+ .clkout1_num_parents = ARRAY_SIZE(clkout1_s3c2443_p),
+ .mux_parent_names = dclk_s3c2443_p,
+ .mux_num_parents = ARRAY_SIZE(dclk_s3c2443_p),
+ },
+};
+
+static struct platform_device_id s3c24xx_dclk_driver_ids[] = {
+ {
+ .name = "s3c2410-dclk",
+ .driver_data = (kernel_ulong_t)&dclk_variants[S3C2410],
+ }, {
+ .name = "s3c2412-dclk",
+ .driver_data = (kernel_ulong_t)&dclk_variants[S3C2412],
+ }, {
+ .name = "s3c2440-dclk",
+ .driver_data = (kernel_ulong_t)&dclk_variants[S3C2440],
+ }, {
+ .name = "s3c2443-dclk",
+ .driver_data = (kernel_ulong_t)&dclk_variants[S3C2443],
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(platform, s3c24xx_dclk_driver_ids);
+
+static struct platform_driver s3c24xx_dclk_driver = {
+ .driver = {
+ .name = "s3c24xx-dclk",
+ .owner = THIS_MODULE,
+ .pm = &s3c24xx_dclk_pm_ops,
+ },
+ .probe = s3c24xx_dclk_probe,
+ .remove = s3c24xx_dclk_remove,
+ .id_table = s3c24xx_dclk_driver_ids,
+};
+module_platform_driver(s3c24xx_dclk_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_DESCRIPTION("Driver for the S3C24XX external clock outputs");
diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c
new file mode 100644
index 000000000000..140f4733c02e
--- /dev/null
+++ b/drivers/clk/samsung/clk-s3c2410.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * Common Clock Framework support for S3C2410 and following SoCs.
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+
+#include <dt-bindings/clock/s3c2410.h>
+
+#include "clk.h"
+#include "clk-pll.h"
+
+#define LOCKTIME 0x00
+#define MPLLCON 0x04
+#define UPLLCON 0x08
+#define CLKCON 0x0c
+#define CLKSLOW 0x10
+#define CLKDIVN 0x14
+#define CAMDIVN 0x18
+
+/* the soc types */
+enum supported_socs {
+ S3C2410,
+ S3C2440,
+ S3C2442,
+};
+
+/* list of PLLs to be registered */
+enum s3c2410_plls {
+ mpll, upll,
+};
+
+static void __iomem *reg_base;
+
+#ifdef CONFIG_PM_SLEEP
+static struct samsung_clk_reg_dump *s3c2410_save;
+
+/*
+ * list of controller registers to be saved and restored during a
+ * suspend/resume cycle.
+ */
+static unsigned long s3c2410_clk_regs[] __initdata = {
+ LOCKTIME,
+ MPLLCON,
+ UPLLCON,
+ CLKCON,
+ CLKSLOW,
+ CLKDIVN,
+ CAMDIVN,
+};
+
+static int s3c2410_clk_suspend(void)
+{
+ samsung_clk_save(reg_base, s3c2410_save,
+ ARRAY_SIZE(s3c2410_clk_regs));
+
+ return 0;
+}
+
+static void s3c2410_clk_resume(void)
+{
+ samsung_clk_restore(reg_base, s3c2410_save,
+ ARRAY_SIZE(s3c2410_clk_regs));
+}
+
+static struct syscore_ops s3c2410_clk_syscore_ops = {
+ .suspend = s3c2410_clk_suspend,
+ .resume = s3c2410_clk_resume,
+};
+
+static void s3c2410_clk_sleep_init(void)
+{
+ s3c2410_save = samsung_clk_alloc_reg_dump(s3c2410_clk_regs,
+ ARRAY_SIZE(s3c2410_clk_regs));
+ if (!s3c2410_save) {
+ pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
+ __func__);
+ return;
+ }
+
+ register_syscore_ops(&s3c2410_clk_syscore_ops);
+ return;
+}
+#else
+static void s3c2410_clk_sleep_init(void) {}
+#endif
+
+PNAME(fclk_p) = { "mpll", "div_slow" };
+
+struct samsung_mux_clock s3c2410_common_muxes[] __initdata = {
+ MUX(FCLK, "fclk", fclk_p, CLKSLOW, 4, 1),
+};
+
+static struct clk_div_table divslow_d[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 2, .div = 4 },
+ { .val = 3, .div = 6 },
+ { .val = 4, .div = 8 },
+ { .val = 5, .div = 10 },
+ { .val = 6, .div = 12 },
+ { .val = 7, .div = 14 },
+ { /* sentinel */ },
+};
+
+struct samsung_div_clock s3c2410_common_dividers[] __initdata = {
+ DIV_T(0, "div_slow", "xti", CLKSLOW, 0, 3, divslow_d),
+ DIV(PCLK, "pclk", "hclk", CLKDIVN, 0, 1),
+};
+
+struct samsung_gate_clock s3c2410_common_gates[] __initdata = {
+ GATE(PCLK_SPI, "spi", "pclk", CLKCON, 18, 0, 0),
+ GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 17, 0, 0),
+ GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 16, 0, 0),
+ GATE(PCLK_ADC, "adc", "pclk", CLKCON, 15, 0, 0),
+ GATE(PCLK_RTC, "rtc", "pclk", CLKCON, 14, 0, 0),
+ GATE(PCLK_GPIO, "gpio", "pclk", CLKCON, 13, CLK_IGNORE_UNUSED, 0),
+ GATE(PCLK_UART2, "uart2", "pclk", CLKCON, 12, 0, 0),
+ GATE(PCLK_UART1, "uart1", "pclk", CLKCON, 11, 0, 0),
+ GATE(PCLK_UART0, "uart0", "pclk", CLKCON, 10, 0, 0),
+ GATE(PCLK_SDI, "sdi", "pclk", CLKCON, 9, 0, 0),
+ GATE(PCLK_PWM, "pwm", "pclk", CLKCON, 8, 0, 0),
+ GATE(HCLK_USBD, "usb-device", "hclk", CLKCON, 7, 0, 0),
+ GATE(HCLK_USBH, "usb-host", "hclk", CLKCON, 6, 0, 0),
+ GATE(HCLK_LCD, "lcd", "hclk", CLKCON, 5, 0, 0),
+ GATE(HCLK_NAND, "nand", "hclk", CLKCON, 4, 0, 0),
+};
+
+/* should be added _after_ the soc-specific clocks are created */
+struct samsung_clock_alias s3c2410_common_aliases[] __initdata = {
+ ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"),
+ ALIAS(PCLK_ADC, NULL, "adc"),
+ ALIAS(PCLK_RTC, NULL, "rtc"),
+ ALIAS(PCLK_PWM, NULL, "timers"),
+ ALIAS(HCLK_LCD, NULL, "lcd"),
+ ALIAS(HCLK_USBD, NULL, "usb-device"),
+ ALIAS(HCLK_USBH, NULL, "usb-host"),
+ ALIAS(UCLK, NULL, "usb-bus-host"),
+ ALIAS(UCLK, NULL, "usb-bus-gadget"),
+ ALIAS(ARMCLK, NULL, "armclk"),
+ ALIAS(UCLK, NULL, "uclk"),
+ ALIAS(HCLK, NULL, "hclk"),
+ ALIAS(MPLL, NULL, "mpll"),
+ ALIAS(FCLK, NULL, "fclk"),
+ ALIAS(PCLK, NULL, "watchdog"),
+ ALIAS(PCLK_SDI, NULL, "sdi"),
+ ALIAS(HCLK_NAND, NULL, "nand"),
+ ALIAS(PCLK_I2S, NULL, "iis"),
+ ALIAS(PCLK_I2C, NULL, "i2c"),
+};
+
+/* S3C2410 specific clocks */
+
+static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = {
+ /* sorted in descending order */
+ /* 2410A extras */
+ PLL_35XX_RATE(270000000, 127, 1, 1),
+ PLL_35XX_RATE(268000000, 126, 1, 1),
+ PLL_35XX_RATE(266000000, 125, 1, 1),
+ PLL_35XX_RATE(226000000, 105, 1, 1),
+ PLL_35XX_RATE(210000000, 132, 2, 1),
+ /* 2410 common */
+ PLL_35XX_RATE(203000000, 161, 3, 1),
+ PLL_35XX_RATE(192000000, 88, 1, 1),
+ PLL_35XX_RATE(186000000, 85, 1, 1),
+ PLL_35XX_RATE(180000000, 82, 1, 1),
+ PLL_35XX_RATE(170000000, 77, 1, 1),
+ PLL_35XX_RATE(158000000, 71, 1, 1),
+ PLL_35XX_RATE(152000000, 68, 1, 1),
+ PLL_35XX_RATE(147000000, 90, 2, 1),
+ PLL_35XX_RATE(135000000, 82, 2, 1),
+ PLL_35XX_RATE(124000000, 116, 1, 2),
+ PLL_35XX_RATE(118000000, 150, 2, 2),
+ PLL_35XX_RATE(113000000, 105, 1, 2),
+ PLL_35XX_RATE(101000000, 127, 2, 2),
+ PLL_35XX_RATE(90000000, 112, 2, 2),
+ PLL_35XX_RATE(85000000, 105, 2, 2),
+ PLL_35XX_RATE(79000000, 71, 1, 2),
+ PLL_35XX_RATE(68000000, 82, 2, 2),
+ PLL_35XX_RATE(56000000, 142, 2, 3),
+ PLL_35XX_RATE(48000000, 120, 2, 3),
+ PLL_35XX_RATE(51000000, 161, 3, 3),
+ PLL_35XX_RATE(45000000, 82, 1, 3),
+ PLL_35XX_RATE(34000000, 82, 2, 3),
+ { /* sentinel */ },
+};
+
+static struct samsung_pll_clock s3c2410_plls[] __initdata = {
+ [mpll] = PLL(pll_s3c2410_mpll, MPLL, "mpll", "xti",
+ LOCKTIME, MPLLCON, NULL),
+ [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "xti",
+ LOCKTIME, UPLLCON, NULL),
+};
+
+struct samsung_div_clock s3c2410_dividers[] __initdata = {
+ DIV(HCLK, "hclk", "mpll", CLKDIVN, 1, 1),
+};
+
+struct samsung_fixed_factor_clock s3c2410_ffactor[] __initdata = {
+ /*
+ * armclk is directly supplied by the fclk, without
+ * switching possibility like on the s3c244x below.
+ */
+ FFACTOR(ARMCLK, "armclk", "fclk", 1, 1, 0),
+
+ /* uclk is fed from the unmodified upll */
+ FFACTOR(UCLK, "uclk", "upll", 1, 1, 0),
+};
+
+struct samsung_clock_alias s3c2410_aliases[] __initdata = {
+ ALIAS(PCLK_UART0, "s3c2410-uart.0", "uart"),
+ ALIAS(PCLK_UART1, "s3c2410-uart.1", "uart"),
+ ALIAS(PCLK_UART2, "s3c2410-uart.2", "uart"),
+ ALIAS(PCLK_UART0, "s3c2410-uart.0", "clk_uart_baud0"),
+ ALIAS(PCLK_UART1, "s3c2410-uart.1", "clk_uart_baud0"),
+ ALIAS(PCLK_UART2, "s3c2410-uart.2", "clk_uart_baud0"),
+ ALIAS(UCLK, NULL, "clk_uart_baud1"),
+};
+
+/* S3C244x specific clocks */
+
+static struct samsung_pll_rate_table pll_s3c244x_12mhz_tbl[] __initdata = {
+ /* sorted in descending order */
+ PLL_35XX_RATE(400000000, 0x5c, 1, 1),
+ PLL_35XX_RATE(390000000, 0x7a, 2, 1),
+ PLL_35XX_RATE(380000000, 0x57, 1, 1),
+ PLL_35XX_RATE(370000000, 0xb1, 4, 1),
+ PLL_35XX_RATE(360000000, 0x70, 2, 1),
+ PLL_35XX_RATE(350000000, 0xa7, 4, 1),
+ PLL_35XX_RATE(340000000, 0x4d, 1, 1),
+ PLL_35XX_RATE(330000000, 0x66, 2, 1),
+ PLL_35XX_RATE(320000000, 0x98, 4, 1),
+ PLL_35XX_RATE(310000000, 0x93, 4, 1),
+ PLL_35XX_RATE(300000000, 0x75, 3, 1),
+ PLL_35XX_RATE(240000000, 0x70, 1, 2),
+ PLL_35XX_RATE(230000000, 0x6b, 1, 2),
+ PLL_35XX_RATE(220000000, 0x66, 1, 2),
+ PLL_35XX_RATE(210000000, 0x84, 2, 2),
+ PLL_35XX_RATE(200000000, 0x5c, 1, 2),
+ PLL_35XX_RATE(190000000, 0x57, 1, 2),
+ PLL_35XX_RATE(180000000, 0x70, 2, 2),
+ PLL_35XX_RATE(170000000, 0x4d, 1, 2),
+ PLL_35XX_RATE(160000000, 0x98, 4, 2),
+ PLL_35XX_RATE(150000000, 0x75, 3, 2),
+ PLL_35XX_RATE(120000000, 0x70, 1, 3),
+ PLL_35XX_RATE(110000000, 0x66, 1, 3),
+ PLL_35XX_RATE(100000000, 0x5c, 1, 3),
+ PLL_35XX_RATE(90000000, 0x70, 2, 3),
+ PLL_35XX_RATE(80000000, 0x98, 4, 3),
+ PLL_35XX_RATE(75000000, 0x75, 3, 3),
+ { /* sentinel */ },
+};
+
+static struct samsung_pll_clock s3c244x_common_plls[] __initdata = {
+ [mpll] = PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti",
+ LOCKTIME, MPLLCON, NULL),
+ [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "xti",
+ LOCKTIME, UPLLCON, NULL),
+};
+
+PNAME(hclk_p) = { "fclk", "div_hclk_2", "div_hclk_4", "div_hclk_3" };
+PNAME(armclk_p) = { "fclk", "hclk" };
+
+struct samsung_mux_clock s3c244x_common_muxes[] __initdata = {
+ MUX(HCLK, "hclk", hclk_p, CLKDIVN, 1, 2),
+ MUX(ARMCLK, "armclk", armclk_p, CAMDIVN, 12, 1),
+};
+
+struct samsung_fixed_factor_clock s3c244x_common_ffactor[] __initdata = {
+ FFACTOR(0, "div_hclk_2", "fclk", 1, 2, 0),
+ FFACTOR(0, "ff_cam", "div_cam", 2, 1, CLK_SET_RATE_PARENT),
+};
+
+static struct clk_div_table div_hclk_4_d[] = {
+ { .val = 0, .div = 4 },
+ { .val = 1, .div = 8 },
+ { /* sentinel */ },
+};
+
+static struct clk_div_table div_hclk_3_d[] = {
+ { .val = 0, .div = 3 },
+ { .val = 1, .div = 6 },
+ { /* sentinel */ },
+};
+
+struct samsung_div_clock s3c244x_common_dividers[] __initdata = {
+ DIV(UCLK, "uclk", "upll", CLKDIVN, 3, 1),
+ DIV(0, "div_hclk", "fclk", CLKDIVN, 1, 1),
+ DIV_T(0, "div_hclk_4", "fclk", CAMDIVN, 9, 1, div_hclk_4_d),
+ DIV_T(0, "div_hclk_3", "fclk", CAMDIVN, 8, 1, div_hclk_3_d),
+ DIV(0, "div_cam", "upll", CAMDIVN, 0, 3),
+};
+
+struct samsung_gate_clock s3c244x_common_gates[] __initdata = {
+ GATE(HCLK_CAM, "cam", "hclk", CLKCON, 19, 0, 0),
+};
+
+struct samsung_clock_alias s3c244x_common_aliases[] __initdata = {
+ ALIAS(PCLK_UART0, "s3c2440-uart.0", "uart"),
+ ALIAS(PCLK_UART1, "s3c2440-uart.1", "uart"),
+ ALIAS(PCLK_UART2, "s3c2440-uart.2", "uart"),
+ ALIAS(PCLK_UART0, "s3c2440-uart.0", "clk_uart_baud2"),
+ ALIAS(PCLK_UART1, "s3c2440-uart.1", "clk_uart_baud2"),
+ ALIAS(PCLK_UART2, "s3c2440-uart.2", "clk_uart_baud2"),
+ ALIAS(HCLK_CAM, NULL, "camif"),
+ ALIAS(CAMIF, NULL, "camif-upll"),
+};
+
+/* S3C2440 specific clocks */
+
+PNAME(s3c2440_camif_p) = { "upll", "ff_cam" };
+
+struct samsung_mux_clock s3c2440_muxes[] __initdata = {
+ MUX(CAMIF, "camif", s3c2440_camif_p, CAMDIVN, 4, 1),
+};
+
+struct samsung_gate_clock s3c2440_gates[] __initdata = {
+ GATE(PCLK_AC97, "ac97", "pclk", CLKCON, 20, 0, 0),
+};
+
+/* S3C2442 specific clocks */
+
+struct samsung_fixed_factor_clock s3c2442_ffactor[] __initdata = {
+ FFACTOR(0, "upll_3", "upll", 1, 3, 0),
+};
+
+PNAME(s3c2442_camif_p) = { "upll", "ff_cam", "upll", "upll_3" };
+
+struct samsung_mux_clock s3c2442_muxes[] __initdata = {
+ MUX(CAMIF, "camif", s3c2442_camif_p, CAMDIVN, 4, 2),
+};
+
+/*
+ * fixed rate clocks generated outside the soc
+ * Only necessary until the devicetree-move is complete
+ */
+#define XTI 1
+struct samsung_fixed_rate_clock s3c2410_common_frate_clks[] __initdata = {
+ FRATE(XTI, "xti", NULL, CLK_IS_ROOT, 0),
+};
+
+static void __init s3c2410_common_clk_register_fixed_ext(
+ struct samsung_clk_provider *ctx,
+ unsigned long xti_f)
+{
+ struct samsung_clock_alias xti_alias = ALIAS(XTI, NULL, "xtal");
+
+ s3c2410_common_frate_clks[0].fixed_rate = xti_f;
+ samsung_clk_register_fixed_rate(ctx, s3c2410_common_frate_clks,
+ ARRAY_SIZE(s3c2410_common_frate_clks));
+
+ samsung_clk_register_alias(ctx, &xti_alias, 1);
+}
+
+void __init s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f,
+ int current_soc,
+ void __iomem *base)
+{
+ struct samsung_clk_provider *ctx;
+ reg_base = base;
+
+ if (np) {
+ reg_base = of_iomap(np, 0);
+ if (!reg_base)
+ panic("%s: failed to map registers\n", __func__);
+ }
+
+ ctx = samsung_clk_init(np, reg_base, NR_CLKS);
+ if (!ctx)
+ panic("%s: unable to allocate context.\n", __func__);
+
+ /* Register external clocks only in non-dt cases */
+ if (!np)
+ s3c2410_common_clk_register_fixed_ext(ctx, xti_f);
+
+ if (current_soc == S3C2410) {
+ if (_get_rate("xti") == 12 * MHZ) {
+ s3c2410_plls[mpll].rate_table = pll_s3c2410_12mhz_tbl;
+ s3c2410_plls[upll].rate_table = pll_s3c2410_12mhz_tbl;
+ }
+
+ /* Register PLLs. */
+ samsung_clk_register_pll(ctx, s3c2410_plls,
+ ARRAY_SIZE(s3c2410_plls), reg_base);
+
+ } else { /* S3C2440, S3C2442 */
+ if (_get_rate("xti") == 12 * MHZ) {
+ /*
+ * plls follow different calculation schemes, with the
+ * upll following the same scheme as the s3c2410 plls
+ */
+ s3c244x_common_plls[mpll].rate_table =
+ pll_s3c244x_12mhz_tbl;
+ s3c244x_common_plls[upll].rate_table =
+ pll_s3c2410_12mhz_tbl;
+ }
+
+ /* Register PLLs. */
+ samsung_clk_register_pll(ctx, s3c244x_common_plls,
+ ARRAY_SIZE(s3c244x_common_plls), reg_base);
+ }
+
+ /* Register common internal clocks. */
+ samsung_clk_register_mux(ctx, s3c2410_common_muxes,
+ ARRAY_SIZE(s3c2410_common_muxes));
+ samsung_clk_register_div(ctx, s3c2410_common_dividers,
+ ARRAY_SIZE(s3c2410_common_dividers));
+ samsung_clk_register_gate(ctx, s3c2410_common_gates,
+ ARRAY_SIZE(s3c2410_common_gates));
+
+ if (current_soc == S3C2440 || current_soc == S3C2442) {
+ samsung_clk_register_div(ctx, s3c244x_common_dividers,
+ ARRAY_SIZE(s3c244x_common_dividers));
+ samsung_clk_register_gate(ctx, s3c244x_common_gates,
+ ARRAY_SIZE(s3c244x_common_gates));
+ samsung_clk_register_mux(ctx, s3c244x_common_muxes,
+ ARRAY_SIZE(s3c244x_common_muxes));
+ samsung_clk_register_fixed_factor(ctx, s3c244x_common_ffactor,
+ ARRAY_SIZE(s3c244x_common_ffactor));
+ }
+
+ /* Register SoC-specific clocks. */
+ switch (current_soc) {
+ case S3C2410:
+ samsung_clk_register_div(ctx, s3c2410_dividers,
+ ARRAY_SIZE(s3c2410_dividers));
+ samsung_clk_register_fixed_factor(ctx, s3c2410_ffactor,
+ ARRAY_SIZE(s3c2410_ffactor));
+ samsung_clk_register_alias(ctx, s3c2410_aliases,
+ ARRAY_SIZE(s3c2410_aliases));
+ break;
+ case S3C2440:
+ samsung_clk_register_mux(ctx, s3c2440_muxes,
+ ARRAY_SIZE(s3c2440_muxes));
+ samsung_clk_register_gate(ctx, s3c2440_gates,
+ ARRAY_SIZE(s3c2440_gates));
+ break;
+ case S3C2442:
+ samsung_clk_register_mux(ctx, s3c2442_muxes,
+ ARRAY_SIZE(s3c2442_muxes));
+ samsung_clk_register_fixed_factor(ctx, s3c2442_ffactor,
+ ARRAY_SIZE(s3c2442_ffactor));
+ break;
+ }
+
+ /*
+ * Register common aliases at the end, as some of the aliased clocks
+ * are SoC specific.
+ */
+ samsung_clk_register_alias(ctx, s3c2410_common_aliases,
+ ARRAY_SIZE(s3c2410_common_aliases));
+
+ if (current_soc == S3C2440 || current_soc == S3C2442) {
+ samsung_clk_register_alias(ctx, s3c244x_common_aliases,
+ ARRAY_SIZE(s3c244x_common_aliases));
+ }
+
+ s3c2410_clk_sleep_init();
+}
+
+static void __init s3c2410_clk_init(struct device_node *np)
+{
+ s3c2410_common_clk_init(np, 0, S3C2410, 0);
+}
+CLK_OF_DECLARE(s3c2410_clk, "samsung,s3c2410-clock", s3c2410_clk_init);
+
+static void __init s3c2440_clk_init(struct device_node *np)
+{
+ s3c2410_common_clk_init(np, 0, S3C2440, 0);
+}
+CLK_OF_DECLARE(s3c2440_clk, "samsung,s3c2440-clock", s3c2440_clk_init);
+
+static void __init s3c2442_clk_init(struct device_node *np)
+{
+ s3c2410_common_clk_init(np, 0, S3C2442, 0);
+}
+CLK_OF_DECLARE(s3c2442_clk, "samsung,s3c2442-clock", s3c2442_clk_init);
diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c
new file mode 100644
index 000000000000..23e4313f625e
--- /dev/null
+++ b/drivers/clk/samsung/clk-s3c2412.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * Common Clock Framework support for S3C2412 and S3C2413.
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+
+#include <dt-bindings/clock/s3c2412.h>
+
+#include "clk.h"
+#include "clk-pll.h"
+
+#define LOCKTIME 0x00
+#define MPLLCON 0x04
+#define UPLLCON 0x08
+#define CLKCON 0x0c
+#define CLKDIVN 0x14
+#define CLKSRC 0x1c
+
+/* list of PLLs to be registered */
+enum s3c2412_plls {
+ mpll, upll,
+};
+
+static void __iomem *reg_base;
+
+#ifdef CONFIG_PM_SLEEP
+static struct samsung_clk_reg_dump *s3c2412_save;
+
+/*
+ * list of controller registers to be saved and restored during a
+ * suspend/resume cycle.
+ */
+static unsigned long s3c2412_clk_regs[] __initdata = {
+ LOCKTIME,
+ MPLLCON,
+ UPLLCON,
+ CLKCON,
+ CLKDIVN,
+ CLKSRC,
+};
+
+static int s3c2412_clk_suspend(void)
+{
+ samsung_clk_save(reg_base, s3c2412_save,
+ ARRAY_SIZE(s3c2412_clk_regs));
+
+ return 0;
+}
+
+static void s3c2412_clk_resume(void)
+{
+ samsung_clk_restore(reg_base, s3c2412_save,
+ ARRAY_SIZE(s3c2412_clk_regs));
+}
+
+static struct syscore_ops s3c2412_clk_syscore_ops = {
+ .suspend = s3c2412_clk_suspend,
+ .resume = s3c2412_clk_resume,
+};
+
+static void s3c2412_clk_sleep_init(void)
+{
+ s3c2412_save = samsung_clk_alloc_reg_dump(s3c2412_clk_regs,
+ ARRAY_SIZE(s3c2412_clk_regs));
+ if (!s3c2412_save) {
+ pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
+ __func__);
+ return;
+ }
+
+ register_syscore_ops(&s3c2412_clk_syscore_ops);
+ return;
+}
+#else
+static void s3c2412_clk_sleep_init(void) {}
+#endif
+
+static struct clk_div_table divxti_d[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 2, .div = 4 },
+ { .val = 3, .div = 6 },
+ { .val = 4, .div = 8 },
+ { .val = 5, .div = 10 },
+ { .val = 6, .div = 12 },
+ { .val = 7, .div = 14 },
+ { /* sentinel */ },
+};
+
+struct samsung_div_clock s3c2412_dividers[] __initdata = {
+ DIV_T(0, "div_xti", "xti", CLKSRC, 0, 3, divxti_d),
+ DIV(0, "div_cam", "mux_cam", CLKDIVN, 16, 4),
+ DIV(0, "div_i2s", "mux_i2s", CLKDIVN, 12, 4),
+ DIV(0, "div_uart", "mux_uart", CLKDIVN, 8, 4),
+ DIV(0, "div_usb", "mux_usb", CLKDIVN, 6, 1),
+ DIV(0, "div_hclk_half", "hclk", CLKDIVN, 5, 1),
+ DIV(ARMDIV, "armdiv", "msysclk", CLKDIVN, 3, 1),
+ DIV(PCLK, "pclk", "hclk", CLKDIVN, 2, 1),
+ DIV(HCLK, "hclk", "armdiv", CLKDIVN, 0, 2),
+};
+
+struct samsung_fixed_factor_clock s3c2412_ffactor[] __initdata = {
+ FFACTOR(0, "ff_hclk", "hclk", 2, 1, CLK_SET_RATE_PARENT),
+};
+
+/*
+ * The first two use the OM[4] setting, which is not readable from
+ * software, so assume it is set to xti.
+ */
+PNAME(erefclk_p) = { "xti", "xti", "xti", "ext" };
+PNAME(urefclk_p) = { "xti", "xti", "xti", "ext" };
+
+PNAME(camclk_p) = { "usysclk", "hclk" };
+PNAME(usbclk_p) = { "usysclk", "hclk" };
+PNAME(i2sclk_p) = { "erefclk", "mpll" };
+PNAME(uartclk_p) = { "erefclk", "mpll" };
+PNAME(usysclk_p) = { "urefclk", "upll" };
+PNAME(msysclk_p) = { "mdivclk", "mpll" };
+PNAME(mdivclk_p) = { "xti", "div_xti" };
+PNAME(armclk_p) = { "armdiv", "hclk" };
+
+struct samsung_mux_clock s3c2412_muxes[] __initdata = {
+ MUX(0, "erefclk", erefclk_p, CLKSRC, 14, 2),
+ MUX(0, "urefclk", urefclk_p, CLKSRC, 12, 2),
+ MUX(0, "mux_cam", camclk_p, CLKSRC, 11, 1),
+ MUX(0, "mux_usb", usbclk_p, CLKSRC, 10, 1),
+ MUX(0, "mux_i2s", i2sclk_p, CLKSRC, 9, 1),
+ MUX(0, "mux_uart", uartclk_p, CLKSRC, 8, 1),
+ MUX(USYSCLK, "usysclk", usysclk_p, CLKSRC, 5, 1),
+ MUX(MSYSCLK, "msysclk", msysclk_p, CLKSRC, 4, 1),
+ MUX(MDIVCLK, "mdivclk", mdivclk_p, CLKSRC, 3, 1),
+ MUX(ARMCLK, "armclk", armclk_p, CLKDIVN, 4, 1),
+};
+
+static struct samsung_pll_clock s3c2412_plls[] __initdata = {
+ [mpll] = PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti",
+ LOCKTIME, MPLLCON, NULL),
+ [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk",
+ LOCKTIME, UPLLCON, NULL),
+};
+
+struct samsung_gate_clock s3c2412_gates[] __initdata = {
+ GATE(PCLK_WDT, "wdt", "pclk", CLKCON, 28, 0, 0),
+ GATE(PCLK_SPI, "spi", "pclk", CLKCON, 27, 0, 0),
+ GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 26, 0, 0),
+ GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 25, 0, 0),
+ GATE(PCLK_ADC, "adc", "pclk", CLKCON, 24, 0, 0),
+ GATE(PCLK_RTC, "rtc", "pclk", CLKCON, 23, 0, 0),
+ GATE(PCLK_GPIO, "gpio", "pclk", CLKCON, 22, CLK_IGNORE_UNUSED, 0),
+ GATE(PCLK_UART2, "uart2", "pclk", CLKCON, 21, 0, 0),
+ GATE(PCLK_UART1, "uart1", "pclk", CLKCON, 20, 0, 0),
+ GATE(PCLK_UART0, "uart0", "pclk", CLKCON, 19, 0, 0),
+ GATE(PCLK_SDI, "sdi", "pclk", CLKCON, 18, 0, 0),
+ GATE(PCLK_PWM, "pwm", "pclk", CLKCON, 17, 0, 0),
+ GATE(PCLK_USBD, "usb-device", "pclk", CLKCON, 16, 0, 0),
+ GATE(SCLK_CAM, "sclk_cam", "div_cam", CLKCON, 15, 0, 0),
+ GATE(SCLK_UART, "sclk_uart", "div_uart", CLKCON, 14, 0, 0),
+ GATE(SCLK_I2S, "sclk_i2s", "div_i2s", CLKCON, 13, 0, 0),
+ GATE(SCLK_USBH, "sclk_usbh", "div_usb", CLKCON, 12, 0, 0),
+ GATE(SCLK_USBD, "sclk_usbd", "div_usb", CLKCON, 11, 0, 0),
+ GATE(HCLK_HALF, "hclk_half", "div_hclk_half", CLKCON, 10, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_X2, "hclkx2", "ff_hclk", CLKCON, 9, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_SDRAM, "sdram", "hclk", CLKCON, 8, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_USBH, "usb-host", "hclk", CLKCON, 6, 0, 0),
+ GATE(HCLK_LCD, "lcd", "hclk", CLKCON, 5, 0, 0),
+ GATE(HCLK_NAND, "nand", "hclk", CLKCON, 4, 0, 0),
+ GATE(HCLK_DMA3, "dma3", "hclk", CLKCON, 3, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_DMA2, "dma2", "hclk", CLKCON, 2, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_DMA1, "dma1", "hclk", CLKCON, 1, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_DMA0, "dma0", "hclk", CLKCON, 0, CLK_IGNORE_UNUSED, 0),
+};
+
+struct samsung_clock_alias s3c2412_aliases[] __initdata = {
+ ALIAS(PCLK_UART0, "s3c2412-uart.0", "uart"),
+ ALIAS(PCLK_UART1, "s3c2412-uart.1", "uart"),
+ ALIAS(PCLK_UART2, "s3c2412-uart.2", "uart"),
+ ALIAS(PCLK_UART0, "s3c2412-uart.0", "clk_uart_baud2"),
+ ALIAS(PCLK_UART1, "s3c2412-uart.1", "clk_uart_baud2"),
+ ALIAS(PCLK_UART2, "s3c2412-uart.2", "clk_uart_baud2"),
+ ALIAS(SCLK_UART, NULL, "clk_uart_baud3"),
+ ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"),
+ ALIAS(PCLK_ADC, NULL, "adc"),
+ ALIAS(PCLK_RTC, NULL, "rtc"),
+ ALIAS(PCLK_PWM, NULL, "timers"),
+ ALIAS(HCLK_LCD, NULL, "lcd"),
+ ALIAS(PCLK_USBD, NULL, "usb-device"),
+ ALIAS(SCLK_USBD, NULL, "usb-bus-gadget"),
+ ALIAS(HCLK_USBH, NULL, "usb-host"),
+ ALIAS(SCLK_USBH, NULL, "usb-bus-host"),
+ ALIAS(ARMCLK, NULL, "armclk"),
+ ALIAS(HCLK, NULL, "hclk"),
+ ALIAS(MPLL, NULL, "mpll"),
+ ALIAS(MSYSCLK, NULL, "fclk"),
+};
+
+/*
+ * fixed rate clocks generated outside the soc
+ * Only necessary until the devicetree-move is complete
+ */
+#define XTI 1
+struct samsung_fixed_rate_clock s3c2412_common_frate_clks[] __initdata = {
+ FRATE(XTI, "xti", NULL, CLK_IS_ROOT, 0),
+ FRATE(0, "ext", NULL, CLK_IS_ROOT, 0),
+};
+
+static void __init s3c2412_common_clk_register_fixed_ext(
+ struct samsung_clk_provider *ctx,
+ unsigned long xti_f, unsigned long ext_f)
+{
+ /* xtal alias is necessary for the current cpufreq driver */
+ struct samsung_clock_alias xti_alias = ALIAS(XTI, NULL, "xtal");
+
+ s3c2412_common_frate_clks[0].fixed_rate = xti_f;
+ s3c2412_common_frate_clks[1].fixed_rate = ext_f;
+ samsung_clk_register_fixed_rate(ctx, s3c2412_common_frate_clks,
+ ARRAY_SIZE(s3c2412_common_frate_clks));
+
+ samsung_clk_register_alias(ctx, &xti_alias, 1);
+}
+
+void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f,
+ unsigned long ext_f, void __iomem *base)
+{
+ struct samsung_clk_provider *ctx;
+ reg_base = base;
+
+ if (np) {
+ reg_base = of_iomap(np, 0);
+ if (!reg_base)
+ panic("%s: failed to map registers\n", __func__);
+ }
+
+ ctx = samsung_clk_init(np, reg_base, NR_CLKS);
+ if (!ctx)
+ panic("%s: unable to allocate context.\n", __func__);
+
+ /* Register external clocks only in non-dt cases */
+ if (!np)
+ s3c2412_common_clk_register_fixed_ext(ctx, xti_f, ext_f);
+
+ /* Register PLLs. */
+ samsung_clk_register_pll(ctx, s3c2412_plls, ARRAY_SIZE(s3c2412_plls),
+ reg_base);
+
+ /* Register common internal clocks. */
+ samsung_clk_register_mux(ctx, s3c2412_muxes, ARRAY_SIZE(s3c2412_muxes));
+ samsung_clk_register_div(ctx, s3c2412_dividers,
+ ARRAY_SIZE(s3c2412_dividers));
+ samsung_clk_register_gate(ctx, s3c2412_gates,
+ ARRAY_SIZE(s3c2412_gates));
+ samsung_clk_register_fixed_factor(ctx, s3c2412_ffactor,
+ ARRAY_SIZE(s3c2412_ffactor));
+ samsung_clk_register_alias(ctx, s3c2412_aliases,
+ ARRAY_SIZE(s3c2412_aliases));
+
+ s3c2412_clk_sleep_init();
+}
+
+static void __init s3c2412_clk_init(struct device_node *np)
+{
+ s3c2412_common_clk_init(np, 0, 0, 0);
+}
+CLK_OF_DECLARE(s3c2412_clk, "samsung,s3c2412-clock", s3c2412_clk_init);
diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c
new file mode 100644
index 000000000000..c4bbdabebaa4
--- /dev/null
+++ b/drivers/clk/samsung/clk-s3c2443.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * Common Clock Framework support for S3C2443 and following SoCs.
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+
+#include <dt-bindings/clock/s3c2443.h>
+
+#include "clk.h"
+#include "clk-pll.h"
+
+/* S3C2416 clock controller register offsets */
+#define LOCKCON0 0x00
+#define LOCKCON1 0x04
+#define MPLLCON 0x10
+#define EPLLCON 0x18
+#define EPLLCON_K 0x1C
+#define CLKSRC 0x20
+#define CLKDIV0 0x24
+#define CLKDIV1 0x28
+#define CLKDIV2 0x2C
+#define HCLKCON 0x30
+#define PCLKCON 0x34
+#define SCLKCON 0x38
+
+/* the soc types */
+enum supported_socs {
+ S3C2416,
+ S3C2443,
+ S3C2450,
+};
+
+/* list of PLLs to be registered */
+enum s3c2443_plls {
+ mpll, epll,
+};
+
+static void __iomem *reg_base;
+
+#ifdef CONFIG_PM_SLEEP
+static struct samsung_clk_reg_dump *s3c2443_save;
+
+/*
+ * list of controller registers to be saved and restored during a
+ * suspend/resume cycle.
+ */
+static unsigned long s3c2443_clk_regs[] __initdata = {
+ LOCKCON0,
+ LOCKCON1,
+ MPLLCON,
+ EPLLCON,
+ EPLLCON_K,
+ CLKSRC,
+ CLKDIV0,
+ CLKDIV1,
+ CLKDIV2,
+ PCLKCON,
+ HCLKCON,
+ SCLKCON,
+};
+
+static int s3c2443_clk_suspend(void)
+{
+ samsung_clk_save(reg_base, s3c2443_save,
+ ARRAY_SIZE(s3c2443_clk_regs));
+
+ return 0;
+}
+
+static void s3c2443_clk_resume(void)
+{
+ samsung_clk_restore(reg_base, s3c2443_save,
+ ARRAY_SIZE(s3c2443_clk_regs));
+}
+
+static struct syscore_ops s3c2443_clk_syscore_ops = {
+ .suspend = s3c2443_clk_suspend,
+ .resume = s3c2443_clk_resume,
+};
+
+static void s3c2443_clk_sleep_init(void)
+{
+ s3c2443_save = samsung_clk_alloc_reg_dump(s3c2443_clk_regs,
+ ARRAY_SIZE(s3c2443_clk_regs));
+ if (!s3c2443_save) {
+ pr_warn("%s: failed to allocate sleep save data, no sleep support!\n",
+ __func__);
+ return;
+ }
+
+ register_syscore_ops(&s3c2443_clk_syscore_ops);
+ return;
+}
+#else
+static void s3c2443_clk_sleep_init(void) {}
+#endif
+
+PNAME(epllref_p) = { "mpllref", "mpllref", "xti", "ext" };
+PNAME(esysclk_p) = { "epllref", "epll" };
+PNAME(mpllref_p) = { "xti", "mdivclk" };
+PNAME(msysclk_p) = { "mpllref", "mpll" };
+PNAME(armclk_p) = { "armdiv" , "hclk" };
+PNAME(i2s0_p) = { "div_i2s0", "ext_i2s", "epllref", "epllref" };
+
+struct samsung_mux_clock s3c2443_common_muxes[] __initdata = {
+ MUX(0, "epllref", epllref_p, CLKSRC, 7, 2),
+ MUX(ESYSCLK, "esysclk", esysclk_p, CLKSRC, 6, 1),
+ MUX(0, "mpllref", mpllref_p, CLKSRC, 3, 1),
+ MUX_A(MSYSCLK, "msysclk", msysclk_p, CLKSRC, 4, 1, "msysclk"),
+ MUX_A(ARMCLK, "armclk", armclk_p, CLKDIV0, 13, 1, "armclk"),
+ MUX(0, "mux_i2s0", i2s0_p, CLKSRC, 14, 2),
+};
+
+static struct clk_div_table hclk_d[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 3, .div = 4 },
+ { /* sentinel */ },
+};
+
+static struct clk_div_table mdivclk_d[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 3 },
+ { .val = 2, .div = 5 },
+ { .val = 3, .div = 7 },
+ { .val = 4, .div = 9 },
+ { .val = 5, .div = 11 },
+ { .val = 6, .div = 13 },
+ { .val = 7, .div = 15 },
+ { /* sentinel */ },
+};
+
+struct samsung_div_clock s3c2443_common_dividers[] __initdata = {
+ DIV_T(0, "mdivclk", "xti", CLKDIV0, 6, 3, mdivclk_d),
+ DIV(0, "prediv", "msysclk", CLKDIV0, 4, 2),
+ DIV_T(HCLK, "hclk", "prediv", CLKDIV0, 0, 2, hclk_d),
+ DIV(PCLK, "pclk", "hclk", CLKDIV0, 2, 1),
+ DIV(0, "div_hsspi0_epll", "esysclk", CLKDIV1, 24, 2),
+ DIV(0, "div_fimd", "esysclk", CLKDIV1, 16, 8),
+ DIV(0, "div_i2s0", "esysclk", CLKDIV1, 12, 4),
+ DIV(0, "div_uart", "esysclk", CLKDIV1, 8, 4),
+ DIV(0, "div_hsmmc1", "esysclk", CLKDIV1, 6, 2),
+ DIV(0, "div_usbhost", "esysclk", CLKDIV1, 4, 2),
+};
+
+struct samsung_gate_clock s3c2443_common_gates[] __initdata = {
+ GATE(SCLK_HSMMC_EXT, "sclk_hsmmcext", "ext", SCLKCON, 13, 0, 0),
+ GATE(SCLK_HSMMC1, "sclk_hsmmc1", "div_hsmmc1", SCLKCON, 12, 0, 0),
+ GATE(SCLK_FIMD, "sclk_fimd", "div_fimd", SCLKCON, 10, 0, 0),
+ GATE(SCLK_I2S0, "sclk_i2s0", "mux_i2s0", SCLKCON, 9, 0, 0),
+ GATE(SCLK_UART, "sclk_uart", "div_uart", SCLKCON, 8, 0, 0),
+ GATE(SCLK_USBH, "sclk_usbhost", "div_usbhost", SCLKCON, 1, 0, 0),
+ GATE(HCLK_DRAM, "dram", "hclk", HCLKCON, 19, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_SSMC, "ssmc", "hclk", HCLKCON, 18, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_HSMMC1, "hsmmc1", "hclk", HCLKCON, 16, 0, 0),
+ GATE(HCLK_USBD, "usb-device", "hclk", HCLKCON, 12, 0, 0),
+ GATE(HCLK_USBH, "usb-host", "hclk", HCLKCON, 11, 0, 0),
+ GATE(HCLK_LCD, "lcd", "hclk", HCLKCON, 9, 0, 0),
+ GATE(HCLK_DMA5, "dma5", "hclk", HCLKCON, 5, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_DMA4, "dma4", "hclk", HCLKCON, 4, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_DMA3, "dma3", "hclk", HCLKCON, 3, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_DMA2, "dma2", "hclk", HCLKCON, 2, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_DMA1, "dma1", "hclk", HCLKCON, 1, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_DMA0, "dma0", "hclk", HCLKCON, 0, CLK_IGNORE_UNUSED, 0),
+ GATE(PCLK_GPIO, "gpio", "pclk", PCLKCON, 13, CLK_IGNORE_UNUSED, 0),
+ GATE(PCLK_RTC, "rtc", "pclk", PCLKCON, 12, 0, 0),
+ GATE(PCLK_WDT, "wdt", "pclk", PCLKCON, 11, 0, 0),
+ GATE(PCLK_PWM, "pwm", "pclk", PCLKCON, 10, 0, 0),
+ GATE(PCLK_I2S0, "i2s0", "pclk", PCLKCON, 9, 0, 0),
+ GATE(PCLK_AC97, "ac97", "pclk", PCLKCON, 8, 0, 0),
+ GATE(PCLK_ADC, "adc", "pclk", PCLKCON, 7, 0, 0),
+ GATE(PCLK_SPI0, "spi0", "pclk", PCLKCON, 6, 0, 0),
+ GATE(PCLK_I2C0, "i2c0", "pclk", PCLKCON, 4, 0, 0),
+ GATE(PCLK_UART3, "uart3", "pclk", PCLKCON, 3, 0, 0),
+ GATE(PCLK_UART2, "uart2", "pclk", PCLKCON, 2, 0, 0),
+ GATE(PCLK_UART1, "uart1", "pclk", PCLKCON, 1, 0, 0),
+ GATE(PCLK_UART0, "uart0", "pclk", PCLKCON, 0, 0, 0),
+};
+
+struct samsung_clock_alias s3c2443_common_aliases[] __initdata = {
+ ALIAS(HCLK, NULL, "hclk"),
+ ALIAS(HCLK_SSMC, NULL, "nand"),
+ ALIAS(PCLK_UART0, "s3c2440-uart.0", "uart"),
+ ALIAS(PCLK_UART1, "s3c2440-uart.1", "uart"),
+ ALIAS(PCLK_UART2, "s3c2440-uart.2", "uart"),
+ ALIAS(PCLK_UART3, "s3c2440-uart.3", "uart"),
+ ALIAS(PCLK_UART0, "s3c2440-uart.0", "clk_uart_baud2"),
+ ALIAS(PCLK_UART1, "s3c2440-uart.1", "clk_uart_baud2"),
+ ALIAS(PCLK_UART2, "s3c2440-uart.2", "clk_uart_baud2"),
+ ALIAS(PCLK_UART3, "s3c2440-uart.3", "clk_uart_baud2"),
+ ALIAS(SCLK_UART, NULL, "clk_uart_baud3"),
+ ALIAS(PCLK_PWM, NULL, "timers"),
+ ALIAS(PCLK_RTC, NULL, "rtc"),
+ ALIAS(PCLK_WDT, NULL, "watchdog"),
+ ALIAS(PCLK_ADC, NULL, "adc"),
+ ALIAS(PCLK_I2C0, "s3c2410-i2c.0", "i2c"),
+ ALIAS(HCLK_USBD, NULL, "usb-device"),
+ ALIAS(HCLK_USBH, NULL, "usb-host"),
+ ALIAS(SCLK_USBH, NULL, "usb-bus-host"),
+ ALIAS(PCLK_SPI0, "s3c2443-spi.0", "spi"),
+ ALIAS(PCLK_SPI0, "s3c2443-spi.0", "spi_busclk0"),
+ ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "hsmmc"),
+ ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"),
+ ALIAS(PCLK_I2S0, "samsung-i2s.0", "iis"),
+ ALIAS(SCLK_I2S0, NULL, "i2s-if"),
+ ALIAS(HCLK_LCD, NULL, "lcd"),
+ ALIAS(SCLK_FIMD, NULL, "sclk_fimd"),
+};
+
+/* S3C2416 specific clocks */
+
+static struct samsung_pll_clock s3c2416_pll_clks[] __initdata = {
+ [mpll] = PLL(pll_6552_s3c2416, 0, "mpll", "mpllref",
+ LOCKCON0, MPLLCON, NULL),
+ [epll] = PLL(pll_6553, 0, "epll", "epllref",
+ LOCKCON1, EPLLCON, NULL),
+};
+
+PNAME(s3c2416_hsmmc0_p) = { "sclk_hsmmc0", "sclk_hsmmcext" };
+PNAME(s3c2416_hsmmc1_p) = { "sclk_hsmmc1", "sclk_hsmmcext" };
+PNAME(s3c2416_hsspi0_p) = { "hsspi0_epll", "hsspi0_mpll" };
+
+static struct clk_div_table armdiv_s3c2416_d[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 2, .div = 3 },
+ { .val = 3, .div = 4 },
+ { .val = 5, .div = 6 },
+ { .val = 7, .div = 8 },
+ { /* sentinel */ },
+};
+
+struct samsung_div_clock s3c2416_dividers[] __initdata = {
+ DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 3, armdiv_s3c2416_d),
+ DIV(0, "div_hsspi0_mpll", "msysclk", CLKDIV2, 0, 4),
+ DIV(0, "div_hsmmc0", "esysclk", CLKDIV2, 6, 2),
+};
+
+struct samsung_mux_clock s3c2416_muxes[] __initdata = {
+ MUX(MUX_HSMMC0, "mux_hsmmc0", s3c2416_hsmmc0_p, CLKSRC, 16, 1),
+ MUX(MUX_HSMMC1, "mux_hsmmc1", s3c2416_hsmmc1_p, CLKSRC, 17, 1),
+ MUX(MUX_HSSPI0, "mux_hsspi0", s3c2416_hsspi0_p, CLKSRC, 18, 1),
+};
+
+struct samsung_gate_clock s3c2416_gates[] __initdata = {
+ GATE(0, "hsspi0_mpll", "div_hsspi0_mpll", SCLKCON, 19, 0, 0),
+ GATE(0, "hsspi0_epll", "div_hsspi0_epll", SCLKCON, 14, 0, 0),
+ GATE(0, "sclk_hsmmc0", "div_hsmmc0", SCLKCON, 6, 0, 0),
+ GATE(HCLK_2D, "2d", "hclk", HCLKCON, 20, 0, 0),
+ GATE(HCLK_HSMMC0, "hsmmc0", "hclk", HCLKCON, 15, 0, 0),
+ GATE(HCLK_IROM, "irom", "hclk", HCLKCON, 13, CLK_IGNORE_UNUSED, 0),
+ GATE(PCLK_PCM, "pcm", "pclk", PCLKCON, 19, 0, 0),
+};
+
+struct samsung_clock_alias s3c2416_aliases[] __initdata = {
+ ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"),
+ ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"),
+ ALIAS(MUX_HSMMC0, "s3c-sdhci.0", "mmc_busclk.2"),
+ ALIAS(MUX_HSMMC1, "s3c-sdhci.1", "mmc_busclk.2"),
+ ALIAS(MUX_HSSPI0, "s3c2443-spi.0", "spi_busclk2"),
+ ALIAS(ARMDIV, NULL, "armdiv"),
+};
+
+/* S3C2443 specific clocks */
+
+static struct samsung_pll_clock s3c2443_pll_clks[] __initdata = {
+ [mpll] = PLL(pll_3000, 0, "mpll", "mpllref",
+ LOCKCON0, MPLLCON, NULL),
+ [epll] = PLL(pll_2126, 0, "epll", "epllref",
+ LOCKCON1, EPLLCON, NULL),
+};
+
+static struct clk_div_table armdiv_s3c2443_d[] = {
+ { .val = 0, .div = 1 },
+ { .val = 8, .div = 2 },
+ { .val = 2, .div = 3 },
+ { .val = 9, .div = 4 },
+ { .val = 10, .div = 6 },
+ { .val = 11, .div = 8 },
+ { .val = 13, .div = 12 },
+ { .val = 15, .div = 16 },
+ { /* sentinel */ },
+};
+
+struct samsung_div_clock s3c2443_dividers[] __initdata = {
+ DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 4, armdiv_s3c2443_d),
+ DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4),
+};
+
+struct samsung_gate_clock s3c2443_gates[] __initdata = {
+ GATE(SCLK_HSSPI0, "sclk_hsspi0", "div_hsspi0_epll", SCLKCON, 14, 0, 0),
+ GATE(SCLK_CAM, "sclk_cam", "div_cam", SCLKCON, 11, 0, 0),
+ GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_CAM, "cam", "hclk", HCLKCON, 8, 0, 0),
+ GATE(PCLK_SPI1, "spi1", "pclk", PCLKCON, 15, 0, 0),
+ GATE(PCLK_SDI, "sdi", "pclk", PCLKCON, 5, 0, 0),
+};
+
+struct samsung_clock_alias s3c2443_aliases[] __initdata = {
+ ALIAS(SCLK_HSSPI0, "s3c2443-spi.0", "spi_busclk2"),
+ ALIAS(SCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.2"),
+ ALIAS(SCLK_CAM, NULL, "camif-upll"),
+ ALIAS(PCLK_SPI1, "s3c2410-spi.0", "spi"),
+ ALIAS(PCLK_SDI, NULL, "sdi"),
+ ALIAS(HCLK_CFC, NULL, "cfc"),
+ ALIAS(ARMDIV, NULL, "armdiv"),
+};
+
+/* S3C2450 specific clocks */
+
+PNAME(s3c2450_cam_p) = { "div_cam", "hclk" };
+PNAME(s3c2450_hsspi1_p) = { "hsspi1_epll", "hsspi1_mpll" };
+PNAME(i2s1_p) = { "div_i2s1", "ext_i2s", "epllref", "epllref" };
+
+struct samsung_div_clock s3c2450_dividers[] __initdata = {
+ DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4),
+ DIV(0, "div_hsspi1_epll", "esysclk", CLKDIV2, 24, 2),
+ DIV(0, "div_hsspi1_mpll", "msysclk", CLKDIV2, 16, 4),
+ DIV(0, "div_i2s1", "esysclk", CLKDIV2, 12, 4),
+};
+
+struct samsung_mux_clock s3c2450_muxes[] __initdata = {
+ MUX(0, "mux_cam", s3c2450_cam_p, CLKSRC, 20, 1),
+ MUX(MUX_HSSPI1, "mux_hsspi1", s3c2450_hsspi1_p, CLKSRC, 19, 1),
+ MUX(0, "mux_i2s1", i2s1_p, CLKSRC, 12, 2),
+};
+
+struct samsung_gate_clock s3c2450_gates[] __initdata = {
+ GATE(SCLK_I2S1, "sclk_i2s1", "div_i2s1", SCLKCON, 5, 0, 0),
+ GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, 0, 0),
+ GATE(HCLK_CAM, "cam", "hclk", HCLKCON, 8, 0, 0),
+ GATE(HCLK_DMA7, "dma7", "hclk", HCLKCON, 7, CLK_IGNORE_UNUSED, 0),
+ GATE(HCLK_DMA6, "dma6", "hclk", HCLKCON, 6, CLK_IGNORE_UNUSED, 0),
+ GATE(PCLK_I2S1, "i2s1", "pclk", PCLKCON, 17, 0, 0),
+ GATE(PCLK_I2C1, "i2c1", "pclk", PCLKCON, 16, 0, 0),
+ GATE(PCLK_SPI1, "spi1", "pclk", PCLKCON, 14, 0, 0),
+};
+
+struct samsung_clock_alias s3c2450_aliases[] __initdata = {
+ ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi"),
+ ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi_busclk0"),
+ ALIAS(MUX_HSSPI1, "s3c2443-spi.1", "spi_busclk2"),
+ ALIAS(PCLK_I2C1, "s3c2410-i2c.1", "i2c"),
+};
+
+/*
+ * fixed rate clocks generated outside the soc
+ * Only necessary until the devicetree-move is complete
+ */
+struct samsung_fixed_rate_clock s3c2443_common_frate_clks[] __initdata = {
+ FRATE(0, "xti", NULL, CLK_IS_ROOT, 0),
+ FRATE(0, "ext", NULL, CLK_IS_ROOT, 0),
+ FRATE(0, "ext_i2s", NULL, CLK_IS_ROOT, 0),
+ FRATE(0, "ext_uart", NULL, CLK_IS_ROOT, 0),
+};
+
+static void __init s3c2443_common_clk_register_fixed_ext(
+ struct samsung_clk_provider *ctx, unsigned long xti_f)
+{
+ s3c2443_common_frate_clks[0].fixed_rate = xti_f;
+ samsung_clk_register_fixed_rate(ctx, s3c2443_common_frate_clks,
+ ARRAY_SIZE(s3c2443_common_frate_clks));
+}
+
+void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f,
+ int current_soc,
+ void __iomem *base)
+{
+ struct samsung_clk_provider *ctx;
+ reg_base = base;
+
+ if (np) {
+ reg_base = of_iomap(np, 0);
+ if (!reg_base)
+ panic("%s: failed to map registers\n", __func__);
+ }
+
+ ctx = samsung_clk_init(np, reg_base, NR_CLKS);
+ if (!ctx)
+ panic("%s: unable to allocate context.\n", __func__);
+
+ /* Register external clocks only in non-dt cases */
+ if (!np)
+ s3c2443_common_clk_register_fixed_ext(ctx, xti_f);
+
+ /* Register PLLs. */
+ if (current_soc == S3C2416 || current_soc == S3C2450)
+ samsung_clk_register_pll(ctx, s3c2416_pll_clks,
+ ARRAY_SIZE(s3c2416_pll_clks), reg_base);
+ else
+ samsung_clk_register_pll(ctx, s3c2443_pll_clks,
+ ARRAY_SIZE(s3c2443_pll_clks), reg_base);
+
+ /* Register common internal clocks. */
+ samsung_clk_register_mux(ctx, s3c2443_common_muxes,
+ ARRAY_SIZE(s3c2443_common_muxes));
+ samsung_clk_register_div(ctx, s3c2443_common_dividers,
+ ARRAY_SIZE(s3c2443_common_dividers));
+ samsung_clk_register_gate(ctx, s3c2443_common_gates,
+ ARRAY_SIZE(s3c2443_common_gates));
+ samsung_clk_register_alias(ctx, s3c2443_common_aliases,
+ ARRAY_SIZE(s3c2443_common_aliases));
+
+ /* Register SoC-specific clocks. */
+ switch (current_soc) {
+ case S3C2450:
+ samsung_clk_register_div(ctx, s3c2450_dividers,
+ ARRAY_SIZE(s3c2450_dividers));
+ samsung_clk_register_mux(ctx, s3c2450_muxes,
+ ARRAY_SIZE(s3c2450_muxes));
+ samsung_clk_register_gate(ctx, s3c2450_gates,
+ ARRAY_SIZE(s3c2450_gates));
+ samsung_clk_register_alias(ctx, s3c2450_aliases,
+ ARRAY_SIZE(s3c2450_aliases));
+ /* fall through, as s3c2450 extends the s3c2416 clocks */
+ case S3C2416:
+ samsung_clk_register_div(ctx, s3c2416_dividers,
+ ARRAY_SIZE(s3c2416_dividers));
+ samsung_clk_register_mux(ctx, s3c2416_muxes,
+ ARRAY_SIZE(s3c2416_muxes));
+ samsung_clk_register_gate(ctx, s3c2416_gates,
+ ARRAY_SIZE(s3c2416_gates));
+ samsung_clk_register_alias(ctx, s3c2416_aliases,
+ ARRAY_SIZE(s3c2416_aliases));
+ break;
+ case S3C2443:
+ samsung_clk_register_div(ctx, s3c2443_dividers,
+ ARRAY_SIZE(s3c2443_dividers));
+ samsung_clk_register_gate(ctx, s3c2443_gates,
+ ARRAY_SIZE(s3c2443_gates));
+ samsung_clk_register_alias(ctx, s3c2443_aliases,
+ ARRAY_SIZE(s3c2443_aliases));
+ break;
+ }
+
+ s3c2443_clk_sleep_init();
+}
+
+static void __init s3c2416_clk_init(struct device_node *np)
+{
+ s3c2443_common_clk_init(np, 0, S3C2416, 0);
+}
+CLK_OF_DECLARE(s3c2416_clk, "samsung,s3c2416-clock", s3c2416_clk_init);
+
+static void __init s3c2443_clk_init(struct device_node *np)
+{
+ s3c2443_common_clk_init(np, 0, S3C2443, 0);
+}
+CLK_OF_DECLARE(s3c2443_clk, "samsung,s3c2443-clock", s3c2443_clk_init);
+
+static void __init s3c2450_clk_init(struct device_node *np)
+{
+ s3c2443_common_clk_init(np, 0, S3C2450, 0);
+}
+CLK_OF_DECLARE(s3c2450_clk, "samsung,s3c2450-clock", s3c2450_clk_init);
diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c
index 8bda658137a8..8889ff1c10fc 100644
--- a/drivers/clk/samsung/clk-s3c64xx.c
+++ b/drivers/clk/samsung/clk-s3c64xx.c
@@ -418,8 +418,10 @@ static struct samsung_clock_alias s3c64xx_clock_aliases[] = {
ALIAS(SCLK_MMC2, "s3c-sdhci.2", "mmc_busclk.2"),
ALIAS(SCLK_MMC1, "s3c-sdhci.1", "mmc_busclk.2"),
ALIAS(SCLK_MMC0, "s3c-sdhci.0", "mmc_busclk.2"),
- ALIAS(SCLK_SPI1, "s3c6410-spi.1", "spi-bus"),
- ALIAS(SCLK_SPI0, "s3c6410-spi.0", "spi-bus"),
+ ALIAS(PCLK_SPI1, "s3c6410-spi.1", "spi_busclk0"),
+ ALIAS(SCLK_SPI1, "s3c6410-spi.1", "spi_busclk2"),
+ ALIAS(PCLK_SPI0, "s3c6410-spi.0", "spi_busclk0"),
+ ALIAS(SCLK_SPI0, "s3c6410-spi.0", "spi_busclk2"),
ALIAS(SCLK_AUDIO1, "samsung-pcm.1", "audio-bus"),
ALIAS(SCLK_AUDIO1, "samsung-i2s.1", "audio-bus"),
ALIAS(SCLK_AUDIO0, "samsung-pcm.0", "audio-bus"),
@@ -442,12 +444,14 @@ static struct samsung_clock_alias s3c6410_clock_aliases[] = {
ALIAS(MEM0_SROM, NULL, "srom"),
};
-static void __init s3c64xx_clk_register_fixed_ext(unsigned long fin_pll_f,
- unsigned long xusbxti_f)
+static void __init s3c64xx_clk_register_fixed_ext(
+ struct samsung_clk_provider *ctx,
+ unsigned long fin_pll_f,
+ unsigned long xusbxti_f)
{
s3c64xx_fixed_rate_ext_clks[0].fixed_rate = fin_pll_f;
s3c64xx_fixed_rate_ext_clks[1].fixed_rate = xusbxti_f;
- samsung_clk_register_fixed_rate(s3c64xx_fixed_rate_ext_clks,
+ samsung_clk_register_fixed_rate(ctx, s3c64xx_fixed_rate_ext_clks,
ARRAY_SIZE(s3c64xx_fixed_rate_ext_clks));
}
@@ -456,6 +460,8 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
unsigned long xusbxti_f, bool s3c6400,
void __iomem *base)
{
+ struct samsung_clk_provider *ctx;
+
reg_base = base;
is_s3c6400 = s3c6400;
@@ -465,48 +471,50 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
panic("%s: failed to map registers\n", __func__);
}
- samsung_clk_init(np, reg_base, NR_CLKS);
+ ctx = samsung_clk_init(np, reg_base, NR_CLKS);
+ if (!ctx)
+ panic("%s: unable to allocate context.\n", __func__);
/* Register external clocks. */
if (!np)
- s3c64xx_clk_register_fixed_ext(xtal_f, xusbxti_f);
+ s3c64xx_clk_register_fixed_ext(ctx, xtal_f, xusbxti_f);
/* Register PLLs. */
- samsung_clk_register_pll(s3c64xx_pll_clks,
+ samsung_clk_register_pll(ctx, s3c64xx_pll_clks,
ARRAY_SIZE(s3c64xx_pll_clks), reg_base);
/* Register common internal clocks. */
- samsung_clk_register_fixed_rate(s3c64xx_fixed_rate_clks,
+ samsung_clk_register_fixed_rate(ctx, s3c64xx_fixed_rate_clks,
ARRAY_SIZE(s3c64xx_fixed_rate_clks));
- samsung_clk_register_mux(s3c64xx_mux_clks,
+ samsung_clk_register_mux(ctx, s3c64xx_mux_clks,
ARRAY_SIZE(s3c64xx_mux_clks));
- samsung_clk_register_div(s3c64xx_div_clks,
+ samsung_clk_register_div(ctx, s3c64xx_div_clks,
ARRAY_SIZE(s3c64xx_div_clks));
- samsung_clk_register_gate(s3c64xx_gate_clks,
+ samsung_clk_register_gate(ctx, s3c64xx_gate_clks,
ARRAY_SIZE(s3c64xx_gate_clks));
/* Register SoC-specific clocks. */
if (is_s3c6400) {
- samsung_clk_register_mux(s3c6400_mux_clks,
+ samsung_clk_register_mux(ctx, s3c6400_mux_clks,
ARRAY_SIZE(s3c6400_mux_clks));
- samsung_clk_register_div(s3c6400_div_clks,
+ samsung_clk_register_div(ctx, s3c6400_div_clks,
ARRAY_SIZE(s3c6400_div_clks));
- samsung_clk_register_gate(s3c6400_gate_clks,
+ samsung_clk_register_gate(ctx, s3c6400_gate_clks,
ARRAY_SIZE(s3c6400_gate_clks));
- samsung_clk_register_alias(s3c6400_clock_aliases,
+ samsung_clk_register_alias(ctx, s3c6400_clock_aliases,
ARRAY_SIZE(s3c6400_clock_aliases));
} else {
- samsung_clk_register_mux(s3c6410_mux_clks,
+ samsung_clk_register_mux(ctx, s3c6410_mux_clks,
ARRAY_SIZE(s3c6410_mux_clks));
- samsung_clk_register_div(s3c6410_div_clks,
+ samsung_clk_register_div(ctx, s3c6410_div_clks,
ARRAY_SIZE(s3c6410_div_clks));
- samsung_clk_register_gate(s3c6410_gate_clks,
+ samsung_clk_register_gate(ctx, s3c6410_gate_clks,
ARRAY_SIZE(s3c6410_gate_clks));
- samsung_clk_register_alias(s3c6410_clock_aliases,
+ samsung_clk_register_alias(ctx, s3c6410_clock_aliases,
ARRAY_SIZE(s3c6410_clock_aliases));
}
- samsung_clk_register_alias(s3c64xx_clock_aliases,
+ samsung_clk_register_alias(ctx, s3c64xx_clock_aliases,
ARRAY_SIZE(s3c64xx_clock_aliases));
s3c64xx_clk_sleep_init();
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index 91bec3ebdc8f..49629c71c9e7 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -14,13 +14,6 @@
#include <linux/syscore_ops.h>
#include "clk.h"
-static DEFINE_SPINLOCK(lock);
-static struct clk **clk_table;
-static void __iomem *reg_base;
-#ifdef CONFIG_OF
-static struct clk_onecell_data clk_data;
-#endif
-
void samsung_clk_save(void __iomem *base,
struct samsung_clk_reg_dump *rd,
unsigned int num_regs)
@@ -55,40 +48,58 @@ struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
}
/* setup the essentials required to support clock lookup using ccf */
-void __init samsung_clk_init(struct device_node *np, void __iomem *base,
- unsigned long nr_clks)
+struct samsung_clk_provider *__init samsung_clk_init(struct device_node *np,
+ void __iomem *base, unsigned long nr_clks)
{
- reg_base = base;
+ struct samsung_clk_provider *ctx;
+ struct clk **clk_table;
+ int ret;
+ int i;
- clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
+ ctx = kzalloc(sizeof(struct samsung_clk_provider), GFP_KERNEL);
+ if (!ctx)
+ panic("could not allocate clock provider context.\n");
+
+ clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
if (!clk_table)
panic("could not allocate clock lookup table\n");
+ for (i = 0; i < nr_clks; ++i)
+ clk_table[i] = ERR_PTR(-ENOENT);
+
+ ctx->reg_base = base;
+ ctx->clk_data.clks = clk_table;
+ ctx->clk_data.clk_num = nr_clks;
+ spin_lock_init(&ctx->lock);
+
if (!np)
- return;
+ return ctx;
-#ifdef CONFIG_OF
- clk_data.clks = clk_table;
- clk_data.clk_num = nr_clks;
- of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
-#endif
+ ret = of_clk_add_provider(np, of_clk_src_onecell_get,
+ &ctx->clk_data);
+ if (ret)
+ panic("could not register clock provide\n");
+
+ return ctx;
}
/* add a clock instance to the clock lookup table used for dt based lookup */
-void samsung_clk_add_lookup(struct clk *clk, unsigned int id)
+void samsung_clk_add_lookup(struct samsung_clk_provider *ctx, struct clk *clk,
+ unsigned int id)
{
- if (clk_table && id)
- clk_table[id] = clk;
+ if (ctx->clk_data.clks && id)
+ ctx->clk_data.clks[id] = clk;
}
/* register a list of aliases */
-void __init samsung_clk_register_alias(struct samsung_clock_alias *list,
- unsigned int nr_clk)
+void __init samsung_clk_register_alias(struct samsung_clk_provider *ctx,
+ struct samsung_clock_alias *list,
+ unsigned int nr_clk)
{
struct clk *clk;
unsigned int idx, ret;
- if (!clk_table) {
+ if (!ctx->clk_data.clks) {
pr_err("%s: clock table missing\n", __func__);
return;
}
@@ -100,7 +111,7 @@ void __init samsung_clk_register_alias(struct samsung_clock_alias *list,
continue;
}
- clk = clk_table[list->id];
+ clk = ctx->clk_data.clks[list->id];
if (!clk) {
pr_err("%s: failed to find clock %d\n", __func__,
list->id);
@@ -115,7 +126,7 @@ void __init samsung_clk_register_alias(struct samsung_clock_alias *list,
}
/* register a list of fixed clocks */
-void __init samsung_clk_register_fixed_rate(
+void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
struct samsung_fixed_rate_clock *list, unsigned int nr_clk)
{
struct clk *clk;
@@ -130,7 +141,7 @@ void __init samsung_clk_register_fixed_rate(
continue;
}
- samsung_clk_add_lookup(clk, list->id);
+ samsung_clk_add_lookup(ctx, clk, list->id);
/*
* Unconditionally add a clock lookup for the fixed rate clocks.
@@ -144,7 +155,7 @@ void __init samsung_clk_register_fixed_rate(
}
/* register a list of fixed factor clocks */
-void __init samsung_clk_register_fixed_factor(
+void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx,
struct samsung_fixed_factor_clock *list, unsigned int nr_clk)
{
struct clk *clk;
@@ -159,28 +170,30 @@ void __init samsung_clk_register_fixed_factor(
continue;
}
- samsung_clk_add_lookup(clk, list->id);
+ samsung_clk_add_lookup(ctx, clk, list->id);
}
}
/* register a list of mux clocks */
-void __init samsung_clk_register_mux(struct samsung_mux_clock *list,
- unsigned int nr_clk)
+void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
+ struct samsung_mux_clock *list,
+ unsigned int nr_clk)
{
struct clk *clk;
unsigned int idx, ret;
for (idx = 0; idx < nr_clk; idx++, list++) {
clk = clk_register_mux(NULL, list->name, list->parent_names,
- list->num_parents, list->flags, reg_base + list->offset,
- list->shift, list->width, list->mux_flags, &lock);
+ list->num_parents, list->flags,
+ ctx->reg_base + list->offset,
+ list->shift, list->width, list->mux_flags, &ctx->lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n", __func__,
list->name);
continue;
}
- samsung_clk_add_lookup(clk, list->id);
+ samsung_clk_add_lookup(ctx, clk, list->id);
/* register a clock lookup only if a clock alias is specified */
if (list->alias) {
@@ -194,8 +207,9 @@ void __init samsung_clk_register_mux(struct samsung_mux_clock *list,
}
/* register a list of div clocks */
-void __init samsung_clk_register_div(struct samsung_div_clock *list,
- unsigned int nr_clk)
+void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
+ struct samsung_div_clock *list,
+ unsigned int nr_clk)
{
struct clk *clk;
unsigned int idx, ret;
@@ -203,22 +217,22 @@ void __init samsung_clk_register_div(struct samsung_div_clock *list,
for (idx = 0; idx < nr_clk; idx++, list++) {
if (list->table)
clk = clk_register_divider_table(NULL, list->name,
- list->parent_name, list->flags,
- reg_base + list->offset, list->shift,
- list->width, list->div_flags,
- list->table, &lock);
+ list->parent_name, list->flags,
+ ctx->reg_base + list->offset,
+ list->shift, list->width, list->div_flags,
+ list->table, &ctx->lock);
else
clk = clk_register_divider(NULL, list->name,
- list->parent_name, list->flags,
- reg_base + list->offset, list->shift,
- list->width, list->div_flags, &lock);
+ list->parent_name, list->flags,
+ ctx->reg_base + list->offset, list->shift,
+ list->width, list->div_flags, &ctx->lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n", __func__,
list->name);
continue;
}
- samsung_clk_add_lookup(clk, list->id);
+ samsung_clk_add_lookup(ctx, clk, list->id);
/* register a clock lookup only if a clock alias is specified */
if (list->alias) {
@@ -232,16 +246,17 @@ void __init samsung_clk_register_div(struct samsung_div_clock *list,
}
/* register a list of gate clocks */
-void __init samsung_clk_register_gate(struct samsung_gate_clock *list,
- unsigned int nr_clk)
+void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
+ struct samsung_gate_clock *list,
+ unsigned int nr_clk)
{
struct clk *clk;
unsigned int idx, ret;
for (idx = 0; idx < nr_clk; idx++, list++) {
clk = clk_register_gate(NULL, list->name, list->parent_name,
- list->flags, reg_base + list->offset,
- list->bit_idx, list->gate_flags, &lock);
+ list->flags, ctx->reg_base + list->offset,
+ list->bit_idx, list->gate_flags, &ctx->lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n", __func__,
list->name);
@@ -257,7 +272,7 @@ void __init samsung_clk_register_gate(struct samsung_gate_clock *list,
__func__, list->alias);
}
- samsung_clk_add_lookup(clk, list->id);
+ samsung_clk_add_lookup(ctx, clk, list->id);
}
}
@@ -266,21 +281,21 @@ void __init samsung_clk_register_gate(struct samsung_gate_clock *list,
* tree and register it
*/
#ifdef CONFIG_OF
-void __init samsung_clk_of_register_fixed_ext(
+void __init samsung_clk_of_register_fixed_ext(struct samsung_clk_provider *ctx,
struct samsung_fixed_rate_clock *fixed_rate_clk,
unsigned int nr_fixed_rate_clk,
struct of_device_id *clk_matches)
{
const struct of_device_id *match;
- struct device_node *np;
+ struct device_node *clk_np;
u32 freq;
- for_each_matching_node_and_match(np, clk_matches, &match) {
- if (of_property_read_u32(np, "clock-frequency", &freq))
+ for_each_matching_node_and_match(clk_np, clk_matches, &match) {
+ if (of_property_read_u32(clk_np, "clock-frequency", &freq))
continue;
- fixed_rate_clk[(u32)match->data].fixed_rate = freq;
+ fixed_rate_clk[(unsigned long)match->data].fixed_rate = freq;
}
- samsung_clk_register_fixed_rate(fixed_rate_clk, nr_fixed_rate_clk);
+ samsung_clk_register_fixed_rate(ctx, fixed_rate_clk, nr_fixed_rate_clk);
}
#endif
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index c7141ba826e0..9693b80d924f 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -22,6 +22,18 @@
#include "clk-pll.h"
/**
+ * struct samsung_clk_provider: information about clock provider
+ * @reg_base: virtual address for the register base.
+ * @clk_data: holds clock related data like clk* and number of clocks.
+ * @lock: maintains exclusion bwtween callbacks for a given clock-provider.
+ */
+struct samsung_clk_provider {
+ void __iomem *reg_base;
+ struct clk_onecell_data clk_data;
+ spinlock_t lock;
+};
+
+/**
* struct samsung_clock_alias: information about mux clock
* @id: platform specific id of the clock.
* @dev_name: name of the device to which this clock belongs.
@@ -312,40 +324,52 @@ struct samsung_pll_clock {
__PLL(_typ, _id, NULL, _name, _pname, CLK_GET_RATE_NOCACHE, \
_lock, _con, _rtable, _alias)
-extern void __init samsung_clk_init(struct device_node *np, void __iomem *base,
- unsigned long nr_clks);
+extern struct samsung_clk_provider *__init samsung_clk_init(
+ struct device_node *np, void __iomem *base,
+ unsigned long nr_clks);
extern void __init samsung_clk_of_register_fixed_ext(
- struct samsung_fixed_rate_clock *fixed_rate_clk,
- unsigned int nr_fixed_rate_clk,
- struct of_device_id *clk_matches);
+ struct samsung_clk_provider *ctx,
+ struct samsung_fixed_rate_clock *fixed_rate_clk,
+ unsigned int nr_fixed_rate_clk,
+ struct of_device_id *clk_matches);
-extern void samsung_clk_add_lookup(struct clk *clk, unsigned int id);
+extern void samsung_clk_add_lookup(struct samsung_clk_provider *ctx,
+ struct clk *clk, unsigned int id);
-extern void samsung_clk_register_alias(struct samsung_clock_alias *list,
- unsigned int nr_clk);
+extern void samsung_clk_register_alias(struct samsung_clk_provider *ctx,
+ struct samsung_clock_alias *list,
+ unsigned int nr_clk);
extern void __init samsung_clk_register_fixed_rate(
- struct samsung_fixed_rate_clock *clk_list, unsigned int nr_clk);
+ struct samsung_clk_provider *ctx,
+ struct samsung_fixed_rate_clock *clk_list,
+ unsigned int nr_clk);
extern void __init samsung_clk_register_fixed_factor(
- struct samsung_fixed_factor_clock *list, unsigned int nr_clk);
-extern void __init samsung_clk_register_mux(struct samsung_mux_clock *clk_list,
- unsigned int nr_clk);
-extern void __init samsung_clk_register_div(struct samsung_div_clock *clk_list,
- unsigned int nr_clk);
-extern void __init samsung_clk_register_gate(
- struct samsung_gate_clock *clk_list, unsigned int nr_clk);
-extern void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
- unsigned int nr_clk, void __iomem *base);
+ struct samsung_clk_provider *ctx,
+ struct samsung_fixed_factor_clock *list,
+ unsigned int nr_clk);
+extern void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
+ struct samsung_mux_clock *clk_list,
+ unsigned int nr_clk);
+extern void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
+ struct samsung_div_clock *clk_list,
+ unsigned int nr_clk);
+extern void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
+ struct samsung_gate_clock *clk_list,
+ unsigned int nr_clk);
+extern void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx,
+ struct samsung_pll_clock *pll_list,
+ unsigned int nr_clk, void __iomem *base);
extern unsigned long _get_rate(const char *clk_name);
extern void samsung_clk_save(void __iomem *base,
- struct samsung_clk_reg_dump *rd,
- unsigned int num_regs);
+ struct samsung_clk_reg_dump *rd,
+ unsigned int num_regs);
extern void samsung_clk_restore(void __iomem *base,
- const struct samsung_clk_reg_dump *rd,
- unsigned int num_regs);
+ const struct samsung_clk_reg_dump *rd,
+ unsigned int num_regs);
extern struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
- const unsigned long *rdump,
- unsigned long nr_rdump);
+ const unsigned long *rdump,
+ unsigned long nr_rdump);
#endif /* __SAMSUNG_CLK_H */
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index 5404cb931ebf..e0029237827a 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -1,5 +1,7 @@
obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o
+obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o
+obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o
obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o
diff --git a/drivers/clk/shmobile/clk-mstp.c b/drivers/clk/shmobile/clk-mstp.c
index 1f6324e29a80..2d2fe773ac81 100644
--- a/drivers/clk/shmobile/clk-mstp.c
+++ b/drivers/clk/shmobile/clk-mstp.c
@@ -112,7 +112,7 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
else
value = clk_readl(group->smstpcr);
- return !!(value & BIT(clock->bit_index));
+ return !(value & BIT(clock->bit_index));
}
static const struct clk_ops cpg_mstp_clock_ops = {
diff --git a/drivers/clk/shmobile/clk-r8a7740.c b/drivers/clk/shmobile/clk-r8a7740.c
new file mode 100644
index 000000000000..1e2eaae21e01
--- /dev/null
+++ b/drivers/clk/shmobile/clk-r8a7740.c
@@ -0,0 +1,199 @@
+/*
+ * r8a7740 Core CPG Clocks
+ *
+ * Copyright (C) 2014 Ulrich Hecht
+ *
+ * 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; version 2 of the License.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/shmobile.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spinlock.h>
+
+struct r8a7740_cpg {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+#define CPG_FRQCRA 0x00
+#define CPG_FRQCRB 0x04
+#define CPG_PLLC2CR 0x2c
+#define CPG_USBCKCR 0x8c
+#define CPG_FRQCRC 0xe0
+
+#define CLK_ENABLE_ON_INIT BIT(0)
+
+struct div4_clk {
+ const char *name;
+ unsigned int reg;
+ unsigned int shift;
+ int flags;
+};
+
+static struct div4_clk div4_clks[] = {
+ { "i", CPG_FRQCRA, 20, CLK_ENABLE_ON_INIT },
+ { "zg", CPG_FRQCRA, 16, CLK_ENABLE_ON_INIT },
+ { "b", CPG_FRQCRA, 8, CLK_ENABLE_ON_INIT },
+ { "m1", CPG_FRQCRA, 4, CLK_ENABLE_ON_INIT },
+ { "hp", CPG_FRQCRB, 4, 0 },
+ { "hpp", CPG_FRQCRC, 20, 0 },
+ { "usbp", CPG_FRQCRC, 16, 0 },
+ { "s", CPG_FRQCRC, 12, 0 },
+ { "zb", CPG_FRQCRC, 8, 0 },
+ { "m3", CPG_FRQCRC, 4, 0 },
+ { "cp", CPG_FRQCRC, 0, 0 },
+ { NULL, 0, 0, 0 },
+};
+
+static const struct clk_div_table div4_div_table[] = {
+ { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 },
+ { 6, 16 }, { 7, 18 }, { 8, 24 }, { 9, 32 }, { 10, 36 }, { 11, 48 },
+ { 13, 72 }, { 14, 96 }, { 0, 0 }
+};
+
+static u32 cpg_mode __initdata;
+
+static struct clk * __init
+r8a7740_cpg_register_clock(struct device_node *np, struct r8a7740_cpg *cpg,
+ const char *name)
+{
+ const struct clk_div_table *table = NULL;
+ const char *parent_name;
+ unsigned int shift, reg;
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+ if (!strcmp(name, "r")) {
+ switch (cpg_mode & (BIT(2) | BIT(1))) {
+ case BIT(1) | BIT(2):
+ /* extal1 */
+ parent_name = of_clk_get_parent_name(np, 0);
+ div = 2048;
+ break;
+ case BIT(2):
+ /* extal1 */
+ parent_name = of_clk_get_parent_name(np, 0);
+ div = 1024;
+ break;
+ default:
+ /* extalr */
+ parent_name = of_clk_get_parent_name(np, 2);
+ break;
+ }
+ } else if (!strcmp(name, "system")) {
+ parent_name = of_clk_get_parent_name(np, 0);
+ if (cpg_mode & BIT(1))
+ div = 2;
+ } else if (!strcmp(name, "pllc0")) {
+ /* PLLC0/1 are configurable multiplier clocks. Register them as
+ * fixed factor clocks for now as there's no generic multiplier
+ * clock implementation and we currently have no need to change
+ * the multiplier value.
+ */
+ u32 value = clk_readl(cpg->reg + CPG_FRQCRC);
+ parent_name = "system";
+ mult = ((value >> 24) & 0x7f) + 1;
+ } else if (!strcmp(name, "pllc1")) {
+ u32 value = clk_readl(cpg->reg + CPG_FRQCRA);
+ parent_name = "system";
+ mult = ((value >> 24) & 0x7f) + 1;
+ div = 2;
+ } else if (!strcmp(name, "pllc2")) {
+ u32 value = clk_readl(cpg->reg + CPG_PLLC2CR);
+ parent_name = "system";
+ mult = ((value >> 24) & 0x3f) + 1;
+ } else if (!strcmp(name, "usb24s")) {
+ u32 value = clk_readl(cpg->reg + CPG_USBCKCR);
+ if (value & BIT(7))
+ /* extal2 */
+ parent_name = of_clk_get_parent_name(np, 1);
+ else
+ parent_name = "system";
+ if (!(value & BIT(6)))
+ div = 2;
+ } else {
+ struct div4_clk *c;
+ for (c = div4_clks; c->name; c++) {
+ if (!strcmp(name, c->name)) {
+ parent_name = "pllc1";
+ table = div4_div_table;
+ reg = c->reg;
+ shift = c->shift;
+ break;
+ }
+ }
+ if (!c->name)
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!table) {
+ return clk_register_fixed_factor(NULL, name, parent_name, 0,
+ mult, div);
+ } else {
+ return clk_register_divider_table(NULL, name, parent_name, 0,
+ cpg->reg + reg, shift, 4, 0,
+ table, &cpg->lock);
+ }
+}
+
+static void __init r8a7740_cpg_clocks_init(struct device_node *np)
+{
+ struct r8a7740_cpg *cpg;
+ struct clk **clks;
+ unsigned int i;
+ int num_clks;
+
+ if (of_property_read_u32(np, "renesas,mode", &cpg_mode))
+ pr_warn("%s: missing renesas,mode property\n", __func__);
+
+ num_clks = of_property_count_strings(np, "clock-output-names");
+ if (num_clks < 0) {
+ pr_err("%s: failed to count clocks\n", __func__);
+ return;
+ }
+
+ cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+ clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL);
+ if (cpg == NULL || clks == NULL) {
+ /* We're leaking memory on purpose, there's no point in cleaning
+ * up as the system won't boot anyway.
+ */
+ return;
+ }
+
+ spin_lock_init(&cpg->lock);
+
+ cpg->data.clks = clks;
+ cpg->data.clk_num = num_clks;
+
+ cpg->reg = of_iomap(np, 0);
+ if (WARN_ON(cpg->reg == NULL))
+ return;
+
+ for (i = 0; i < num_clks; ++i) {
+ const char *name;
+ struct clk *clk;
+
+ of_property_read_string_index(np, "clock-output-names", i,
+ &name);
+
+ clk = r8a7740_cpg_register_clock(np, cpg, name);
+ if (IS_ERR(clk))
+ pr_err("%s: failed to register %s %s clock (%ld)\n",
+ __func__, np->name, name, PTR_ERR(clk));
+ else
+ cpg->data.clks[i] = clk;
+ }
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+}
+CLK_OF_DECLARE(r8a7740_cpg_clks, "renesas,r8a7740-cpg-clocks",
+ r8a7740_cpg_clocks_init);
diff --git a/drivers/clk/shmobile/clk-r8a7779.c b/drivers/clk/shmobile/clk-r8a7779.c
new file mode 100644
index 000000000000..652ecacb6daf
--- /dev/null
+++ b/drivers/clk/shmobile/clk-r8a7779.c
@@ -0,0 +1,180 @@
+/*
+ * r8a7779 Core CPG Clocks
+ *
+ * Copyright (C) 2013, 2014 Horms Solutions Ltd.
+ *
+ * Contact: Simon Horman <horms@verge.net.au>
+ *
+ * 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; version 2 of the License.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/shmobile.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spinlock.h>
+
+#include <dt-bindings/clock/r8a7779-clock.h>
+
+#define CPG_NUM_CLOCKS (R8A7779_CLK_OUT + 1)
+
+struct r8a7779_cpg {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+/* -----------------------------------------------------------------------------
+ * CPG Clock Data
+ */
+
+/*
+ * MD1 = 1 MD1 = 0
+ * (PLLA = 1500) (PLLA = 1600)
+ * (MHz) (MHz)
+ *------------------------------------------------+--------------------
+ * clkz 1000 (2/3) 800 (1/2)
+ * clkzs 250 (1/6) 200 (1/8)
+ * clki 750 (1/2) 800 (1/2)
+ * clks 250 (1/6) 200 (1/8)
+ * clks1 125 (1/12) 100 (1/16)
+ * clks3 187.5 (1/8) 200 (1/8)
+ * clks4 93.7 (1/16) 100 (1/16)
+ * clkp 62.5 (1/24) 50 (1/32)
+ * clkg 62.5 (1/24) 66.6 (1/24)
+ * clkb, CLKOUT
+ * (MD2 = 0) 62.5 (1/24) 66.6 (1/24)
+ * (MD2 = 1) 41.6 (1/36) 50 (1/32)
+ */
+
+#define CPG_CLK_CONFIG_INDEX(md) (((md) & (BIT(2)|BIT(1))) >> 1)
+
+struct cpg_clk_config {
+ unsigned int z_mult;
+ unsigned int z_div;
+ unsigned int zs_and_s_div;
+ unsigned int s1_div;
+ unsigned int p_div;
+ unsigned int b_and_out_div;
+};
+
+static const struct cpg_clk_config cpg_clk_configs[4] __initconst = {
+ { 1, 2, 8, 16, 32, 24 },
+ { 2, 3, 6, 12, 24, 24 },
+ { 1, 2, 8, 16, 32, 32 },
+ { 2, 3, 6, 12, 24, 36 },
+};
+
+/*
+ * MD PLLA Ratio
+ * 12 11
+ *------------------------
+ * 0 0 x42
+ * 0 1 x48
+ * 1 0 x56
+ * 1 1 x64
+ */
+
+#define CPG_PLLA_MULT_INDEX(md) (((md) & (BIT(12)|BIT(11))) >> 11)
+
+static const unsigned int cpg_plla_mult[4] __initconst = { 42, 48, 56, 64 };
+
+/* -----------------------------------------------------------------------------
+ * Initialization
+ */
+
+static u32 cpg_mode __initdata;
+
+static struct clk * __init
+r8a7779_cpg_register_clock(struct device_node *np, struct r8a7779_cpg *cpg,
+ const struct cpg_clk_config *config,
+ unsigned int plla_mult, const char *name)
+{
+ const char *parent_name = "plla";
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+ if (!strcmp(name, "plla")) {
+ parent_name = of_clk_get_parent_name(np, 0);
+ mult = plla_mult;
+ } else if (!strcmp(name, "z")) {
+ div = config->z_div;
+ mult = config->z_mult;
+ } else if (!strcmp(name, "zs") || !strcmp(name, "s")) {
+ div = config->zs_and_s_div;
+ } else if (!strcmp(name, "s1")) {
+ div = config->s1_div;
+ } else if (!strcmp(name, "p")) {
+ div = config->p_div;
+ } else if (!strcmp(name, "b") || !strcmp(name, "out")) {
+ div = config->b_and_out_div;
+ } else {
+ return ERR_PTR(-EINVAL);
+ }
+
+ return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, div);
+}
+
+static void __init r8a7779_cpg_clocks_init(struct device_node *np)
+{
+ const struct cpg_clk_config *config;
+ struct r8a7779_cpg *cpg;
+ struct clk **clks;
+ unsigned int i, plla_mult;
+ int num_clks;
+
+ num_clks = of_property_count_strings(np, "clock-output-names");
+ if (num_clks < 0) {
+ pr_err("%s: failed to count clocks\n", __func__);
+ return;
+ }
+
+ cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+ clks = kzalloc(CPG_NUM_CLOCKS * sizeof(*clks), GFP_KERNEL);
+ if (cpg == NULL || clks == NULL) {
+ /* We're leaking memory on purpose, there's no point in cleaning
+ * up as the system won't boot anyway.
+ */
+ return;
+ }
+
+ spin_lock_init(&cpg->lock);
+
+ cpg->data.clks = clks;
+ cpg->data.clk_num = num_clks;
+
+ config = &cpg_clk_configs[CPG_CLK_CONFIG_INDEX(cpg_mode)];
+ plla_mult = cpg_plla_mult[CPG_PLLA_MULT_INDEX(cpg_mode)];
+
+ for (i = 0; i < num_clks; ++i) {
+ const char *name;
+ struct clk *clk;
+
+ of_property_read_string_index(np, "clock-output-names", i,
+ &name);
+
+ clk = r8a7779_cpg_register_clock(np, cpg, config,
+ plla_mult, name);
+ if (IS_ERR(clk))
+ pr_err("%s: failed to register %s %s clock (%ld)\n",
+ __func__, np->name, name, PTR_ERR(clk));
+ else
+ cpg->data.clks[i] = clk;
+ }
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+}
+CLK_OF_DECLARE(r8a7779_cpg_clks, "renesas,r8a7779-cpg-clocks",
+ r8a7779_cpg_clocks_init);
+
+void __init r8a7779_clocks_init(u32 mode)
+{
+ cpg_mode = mode;
+
+ of_clk_init(NULL);
+}
diff --git a/drivers/clk/socfpga/clk-gate.c b/drivers/clk/socfpga/clk-gate.c
index 501d513bf890..dd3a78c64795 100644
--- a/drivers/clk/socfpga/clk-gate.c
+++ b/drivers/clk/socfpga/clk-gate.c
@@ -32,7 +32,6 @@
#define SOCFPGA_MMC_CLK "sdmmc_clk"
#define SOCFPGA_GPIO_DB_CLK_OFFSET 0xA8
-#define div_mask(width) ((1 << (width)) - 1)
#define streq(a, b) (strcmp((a), (b)) == 0)
#define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw)
diff --git a/drivers/clk/socfpga/clk-periph.c b/drivers/clk/socfpga/clk-periph.c
index 81623a3736f9..46531c34ec9b 100644
--- a/drivers/clk/socfpga/clk-periph.c
+++ b/drivers/clk/socfpga/clk-periph.c
@@ -29,12 +29,18 @@ static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
struct socfpga_periph_clk *socfpgaclk = to_socfpga_periph_clk(hwclk);
- u32 div;
+ u32 div, val;
- if (socfpgaclk->fixed_div)
+ if (socfpgaclk->fixed_div) {
div = socfpgaclk->fixed_div;
- else
+ } else {
+ if (socfpgaclk->div_reg) {
+ val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
+ val &= div_mask(socfpgaclk->width);
+ parent_rate /= (val + 1);
+ }
div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1);
+ }
return parent_rate / div;
}
@@ -54,6 +60,7 @@ static __init void __socfpga_periph_init(struct device_node *node,
struct clk_init_data init;
int rc;
u32 fixed_div;
+ u32 div_reg[3];
of_property_read_u32(node, "reg", &reg);
@@ -63,6 +70,15 @@ static __init void __socfpga_periph_init(struct device_node *node,
periph_clk->hw.reg = clk_mgr_base_addr + reg;
+ rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
+ if (!rc) {
+ periph_clk->div_reg = clk_mgr_base_addr + div_reg[0];
+ periph_clk->shift = div_reg[1];
+ periph_clk->width = div_reg[2];
+ } else {
+ periph_clk->div_reg = 0;
+ }
+
rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
if (rc)
periph_clk->fixed_div = 0;
diff --git a/drivers/clk/socfpga/clk.h b/drivers/clk/socfpga/clk.h
index d2e54019c94f..d291f60c46e1 100644
--- a/drivers/clk/socfpga/clk.h
+++ b/drivers/clk/socfpga/clk.h
@@ -27,6 +27,7 @@
#define CLKMGR_PERPLL_SRC 0xAC
#define SOCFPGA_MAX_PARENTS 3
+#define div_mask(width) ((1 << (width)) - 1)
extern void __iomem *clk_mgr_base_addr;
@@ -52,6 +53,9 @@ struct socfpga_periph_clk {
struct clk_gate hw;
char *parent_name;
u32 fixed_div;
+ void __iomem *div_reg;
+ u32 width; /* only valid if div_reg != 0 */
+ u32 shift; /* only valid if div_reg != 0 */
};
#endif /* SOCFPGA_CLK_H */
diff --git a/drivers/clk/spear/spear3xx_clock.c b/drivers/clk/spear/spear3xx_clock.c
index c2d204315546..bb5f387774e2 100644
--- a/drivers/clk/spear/spear3xx_clock.c
+++ b/drivers/clk/spear/spear3xx_clock.c
@@ -211,7 +211,7 @@ static inline void spear310_clk_init(void) { }
/* array of all spear 320 clock lookups */
#ifdef CONFIG_MACH_SPEAR320
-#define SPEAR320_CONTROL_REG (soc_config_base + 0x0000)
+#define SPEAR320_CONTROL_REG (soc_config_base + 0x0010)
#define SPEAR320_EXT_CTRL_REG (soc_config_base + 0x0018)
#define SPEAR320_UARTX_PCLK_MASK 0x1
@@ -245,7 +245,8 @@ static const char *smii0_parents[] = { "smii_125m_pad", "ras_pll2_clk",
"ras_syn0_gclk", };
static const char *uartx_parents[] = { "ras_syn1_gclk", "ras_apb_clk", };
-static void __init spear320_clk_init(void __iomem *soc_config_base)
+static void __init spear320_clk_init(void __iomem *soc_config_base,
+ struct clk *ras_apb_clk)
{
struct clk *clk;
@@ -342,6 +343,8 @@ static void __init spear320_clk_init(void __iomem *soc_config_base)
SPEAR320_CONTROL_REG, UART1_PCLK_SHIFT, UART1_PCLK_MASK,
0, &_lock);
clk_register_clkdev(clk, NULL, "a3000000.serial");
+ /* Enforce ras_apb_clk */
+ clk_set_parent(clk, ras_apb_clk);
clk = clk_register_mux(NULL, "uart2_clk", uartx_parents,
ARRAY_SIZE(uartx_parents),
@@ -349,6 +352,8 @@ static void __init spear320_clk_init(void __iomem *soc_config_base)
SPEAR320_EXT_CTRL_REG, SPEAR320_UART2_PCLK_SHIFT,
SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "a4000000.serial");
+ /* Enforce ras_apb_clk */
+ clk_set_parent(clk, ras_apb_clk);
clk = clk_register_mux(NULL, "uart3_clk", uartx_parents,
ARRAY_SIZE(uartx_parents),
@@ -379,12 +384,12 @@ static void __init spear320_clk_init(void __iomem *soc_config_base)
clk_register_clkdev(clk, NULL, "60100000.serial");
}
#else
-static inline void spear320_clk_init(void __iomem *soc_config_base) { }
+static inline void spear320_clk_init(void __iomem *sb, struct clk *rc) { }
#endif
void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_base)
{
- struct clk *clk, *clk1;
+ struct clk *clk, *clk1, *ras_apb_clk;
clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT,
32000);
@@ -613,6 +618,7 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
clk = clk_register_gate(NULL, "ras_apb_clk", "apb_clk", 0, RAS_CLK_ENB,
RAS_APB_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, "ras_apb_clk", NULL);
+ ras_apb_clk = clk;
clk = clk_register_gate(NULL, "ras_32k_clk", "osc_32k_clk", 0,
RAS_CLK_ENB, RAS_32K_CLK_ENB, 0, &_lock);
@@ -659,5 +665,5 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
else if (of_machine_is_compatible("st,spear310"))
spear310_clk_init();
else if (of_machine_is_compatible("st,spear320"))
- spear320_clk_init(soc_config_base);
+ spear320_clk_init(soc_config_base, ras_apb_clk);
}
diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c
index a886702f7c8b..d8b9b1a2aeda 100644
--- a/drivers/clk/st/clkgen-pll.c
+++ b/drivers/clk/st/clkgen-pll.c
@@ -655,6 +655,7 @@ static struct of_device_id c32_gpu_pll_of_match[] = {
.compatible = "st,stih416-gpu-pll-c32",
.data = &st_pll1200c32_gpu_416,
},
+ {}
};
static void __init clkgengpu_c32_pll_setup(struct device_node *np)
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index b5bac917612c..762fd64dbd1f 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -3,3 +3,7 @@
#
obj-y += clk-sunxi.o clk-factors.o
+obj-y += clk-a10-hosc.o
+obj-y += clk-a20-gmac.o
+
+obj-$(CONFIG_MFD_SUN6I_PRCM) += clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
diff --git a/drivers/clk/sunxi/clk-a10-hosc.c b/drivers/clk/sunxi/clk-a10-hosc.c
new file mode 100644
index 000000000000..0481d5d673d6
--- /dev/null
+++ b/drivers/clk/sunxi/clk-a10-hosc.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2013 Emilio López
+ *
+ * Emilio López <emilio@elopez.com.ar>
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#define SUNXI_OSC24M_GATE 0
+
+static DEFINE_SPINLOCK(hosc_lock);
+
+static void __init sun4i_osc_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ struct clk_fixed_rate *fixed;
+ struct clk_gate *gate;
+ const char *clk_name = node->name;
+ u32 rate;
+
+ if (of_property_read_u32(node, "clock-frequency", &rate))
+ return;
+
+ /* allocate fixed-rate and gate clock structs */
+ fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
+ if (!fixed)
+ return;
+ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+ if (!gate)
+ goto err_free_fixed;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ /* set up gate and fixed rate properties */
+ gate->reg = of_iomap(node, 0);
+ gate->bit_idx = SUNXI_OSC24M_GATE;
+ gate->lock = &hosc_lock;
+ fixed->fixed_rate = rate;
+
+ clk = clk_register_composite(NULL, clk_name,
+ NULL, 0,
+ NULL, NULL,
+ &fixed->hw, &clk_fixed_rate_ops,
+ &gate->hw, &clk_gate_ops,
+ CLK_IS_ROOT);
+
+ if (IS_ERR(clk))
+ goto err_free_gate;
+
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ clk_register_clkdev(clk, clk_name, NULL);
+
+ return;
+
+err_free_gate:
+ kfree(gate);
+err_free_fixed:
+ kfree(fixed);
+}
+CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-a10-osc-clk", sun4i_osc_clk_setup);
diff --git a/drivers/clk/sunxi/clk-a20-gmac.c b/drivers/clk/sunxi/clk-a20-gmac.c
new file mode 100644
index 000000000000..633ddc4389ef
--- /dev/null
+++ b/drivers/clk/sunxi/clk-a20-gmac.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2013 Emilio López
+ * Emilio López <emilio@elopez.com.ar>
+ *
+ * Copyright 2013 Chen-Yu Tsai
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+static DEFINE_SPINLOCK(gmac_lock);
+
+/**
+ * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module
+ *
+ * This clock looks something like this
+ * ________________________
+ * MII TX clock from PHY >-----|___________ _________|----> to GMAC core
+ * GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY
+ * Ext. 125MHz RGMII TX clk >--|__divider__/ |
+ * |________________________|
+ *
+ * The external 125 MHz reference is optional, i.e. GMAC can use its
+ * internal TX clock just fine. The A31 GMAC clock module does not have
+ * the divider controls for the external reference.
+ *
+ * To keep it simple, let the GMAC use either the MII TX clock for MII mode,
+ * and its internal TX clock for GMII and RGMII modes. The GMAC driver should
+ * select the appropriate source and gate/ungate the output to the PHY.
+ *
+ * Only the GMAC should use this clock. Altering the clock so that it doesn't
+ * match the GMAC's operation parameters will result in the GMAC not being
+ * able to send traffic out. The GMAC driver should set the clock rate and
+ * enable/disable this clock to configure the required state. The clock
+ * driver then responds by auto-reparenting the clock.
+ */
+
+#define SUN7I_A20_GMAC_GPIT 2
+#define SUN7I_A20_GMAC_MASK 0x3
+#define SUN7I_A20_GMAC_PARENTS 2
+
+static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ struct clk_mux *mux;
+ struct clk_gate *gate;
+ const char *clk_name = node->name;
+ const char *parents[SUN7I_A20_GMAC_PARENTS];
+ void *reg;
+
+ if (of_property_read_string(node, "clock-output-names", &clk_name))
+ return;
+
+ /* allocate mux and gate clock structs */
+ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
+ if (!mux)
+ return;
+
+ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+ if (!gate)
+ goto free_mux;
+
+ /* gmac clock requires exactly 2 parents */
+ parents[0] = of_clk_get_parent_name(node, 0);
+ parents[1] = of_clk_get_parent_name(node, 1);
+ if (!parents[0] || !parents[1])
+ goto free_gate;
+
+ reg = of_iomap(node, 0);
+ if (!reg)
+ goto free_gate;
+
+ /* set up gate and fixed rate properties */
+ gate->reg = reg;
+ gate->bit_idx = SUN7I_A20_GMAC_GPIT;
+ gate->lock = &gmac_lock;
+ mux->reg = reg;
+ mux->mask = SUN7I_A20_GMAC_MASK;
+ mux->flags = CLK_MUX_INDEX_BIT;
+ mux->lock = &gmac_lock;
+
+ clk = clk_register_composite(NULL, clk_name,
+ parents, SUN7I_A20_GMAC_PARENTS,
+ &mux->hw, &clk_mux_ops,
+ NULL, NULL,
+ &gate->hw, &clk_gate_ops,
+ 0);
+
+ if (IS_ERR(clk))
+ goto iounmap_reg;
+
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ clk_register_clkdev(clk, clk_name, NULL);
+
+ return;
+
+iounmap_reg:
+ iounmap(reg);
+free_gate:
+ kfree(gate);
+free_mux:
+ kfree(mux);
+}
+CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk",
+ sun7i_a20_gmac_clk_setup);
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index 9e232644f07e..3806d97e529b 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -77,6 +77,41 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
return rate;
}
+static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_p)
+{
+ struct clk *clk = hw->clk, *parent, *best_parent = NULL;
+ int i, num_parents;
+ unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
+
+ /* find the parent that can help provide the fastest rate <= rate */
+ num_parents = __clk_get_num_parents(clk);
+ for (i = 0; i < num_parents; i++) {
+ parent = clk_get_parent_by_index(clk, i);
+ if (!parent)
+ continue;
+ if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT)
+ parent_rate = __clk_round_rate(parent, rate);
+ else
+ parent_rate = __clk_get_rate(parent);
+
+ child_rate = clk_factors_round_rate(hw, rate, &parent_rate);
+
+ if (child_rate <= rate && child_rate > best_child_rate) {
+ best_parent = parent;
+ best = parent_rate;
+ best_child_rate = child_rate;
+ }
+ }
+
+ if (best_parent)
+ *best_parent_p = best_parent;
+ *best_parent_rate = best;
+
+ return best_child_rate;
+}
+
static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
@@ -113,6 +148,7 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
}
const struct clk_ops clk_factors_ops = {
+ .determine_rate = clk_factors_determine_rate,
.recalc_rate = clk_factors_recalc_rate,
.round_rate = clk_factors_round_rate,
.set_rate = clk_factors_set_rate,
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c
new file mode 100644
index 000000000000..670f90d629d7
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
+ *
+ * Allwinner A31 APB0 clock gates driver
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define SUN6I_APB0_GATES_MAX_SIZE 32
+
+static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct clk_onecell_data *clk_data;
+ const char *clk_parent;
+ const char *clk_name;
+ struct resource *r;
+ void __iomem *reg;
+ int gate_id;
+ int ngates;
+ int i;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ clk_parent = of_clk_get_parent_name(np, 0);
+ if (!clk_parent)
+ return -EINVAL;
+
+ ngates = of_property_count_strings(np, "clock-output-names");
+ if (ngates < 0)
+ return ngates;
+
+ if (!ngates || ngates > SUN6I_APB0_GATES_MAX_SIZE)
+ return -EINVAL;
+
+ clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->clks = devm_kzalloc(&pdev->dev,
+ SUN6I_APB0_GATES_MAX_SIZE *
+ sizeof(struct clk *),
+ GFP_KERNEL);
+ if (!clk_data->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < ngates; i++) {
+ of_property_read_string_index(np, "clock-output-names",
+ i, &clk_name);
+
+ gate_id = i;
+ of_property_read_u32_index(np, "clock-indices", i, &gate_id);
+
+ WARN_ON(gate_id >= SUN6I_APB0_GATES_MAX_SIZE);
+ if (gate_id >= SUN6I_APB0_GATES_MAX_SIZE)
+ continue;
+
+ clk_data->clks[gate_id] = clk_register_gate(&pdev->dev,
+ clk_name,
+ clk_parent, 0,
+ reg, gate_id,
+ 0, NULL);
+ WARN_ON(IS_ERR(clk_data->clks[gate_id]));
+ }
+
+ clk_data->clk_num = ngates;
+
+ return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+}
+
+const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = {
+ { .compatible = "allwinner,sun6i-a31-apb0-gates-clk" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sun6i_a31_apb0_gates_clk_driver = {
+ .driver = {
+ .name = "sun6i-a31-apb0-gates-clk",
+ .owner = THIS_MODULE,
+ .of_match_table = sun6i_a31_apb0_gates_clk_dt_ids,
+ },
+ .probe = sun6i_a31_apb0_gates_clk_probe,
+};
+module_platform_driver(sun6i_a31_apb0_gates_clk_driver);
+
+MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A31 APB0 gate clocks driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0.c b/drivers/clk/sunxi/clk-sun6i-apb0.c
new file mode 100644
index 000000000000..11f17c34c2ae
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun6i-apb0.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
+ *
+ * Allwinner A31 APB0 clock driver
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+/*
+ * The APB0 clk has a configurable divisor.
+ *
+ * We must use a clk_div_table and not a regular power of 2
+ * divisor here, because the first 2 values divide the clock
+ * by 2.
+ */
+static const struct clk_div_table sun6i_a31_apb0_divs[] = {
+ { .val = 0, .div = 2, },
+ { .val = 1, .div = 2, },
+ { .val = 2, .div = 4, },
+ { .val = 3, .div = 8, },
+ { /* sentinel */ },
+};
+
+static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const char *clk_name = np->name;
+ const char *clk_parent;
+ struct resource *r;
+ void __iomem *reg;
+ struct clk *clk;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ clk_parent = of_clk_get_parent_name(np, 0);
+ if (!clk_parent)
+ return -EINVAL;
+
+ of_property_read_string(np, "clock-output-names", &clk_name);
+
+ clk = clk_register_divider_table(&pdev->dev, clk_name, clk_parent,
+ 0, reg, 0, 2, 0, sun6i_a31_apb0_divs,
+ NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = {
+ { .compatible = "allwinner,sun6i-a31-apb0-clk" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sun6i_a31_apb0_clk_driver = {
+ .driver = {
+ .name = "sun6i-a31-apb0-clk",
+ .owner = THIS_MODULE,
+ .of_match_table = sun6i_a31_apb0_clk_dt_ids,
+ },
+ .probe = sun6i_a31_apb0_clk_probe,
+};
+module_platform_driver(sun6i_a31_apb0_clk_driver);
+
+MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A31 APB0 clock Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c
new file mode 100644
index 000000000000..f73cc051f0dd
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun6i-ar100.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
+ *
+ * Allwinner A31 AR100 clock driver
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define SUN6I_AR100_MAX_PARENTS 4
+#define SUN6I_AR100_SHIFT_MASK 0x3
+#define SUN6I_AR100_SHIFT_MAX SUN6I_AR100_SHIFT_MASK
+#define SUN6I_AR100_SHIFT_SHIFT 4
+#define SUN6I_AR100_DIV_MASK 0x1f
+#define SUN6I_AR100_DIV_MAX (SUN6I_AR100_DIV_MASK + 1)
+#define SUN6I_AR100_DIV_SHIFT 8
+#define SUN6I_AR100_MUX_MASK 0x3
+#define SUN6I_AR100_MUX_SHIFT 16
+
+struct ar100_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+};
+
+static inline struct ar100_clk *to_ar100_clk(struct clk_hw *hw)
+{
+ return container_of(hw, struct ar100_clk, hw);
+}
+
+static unsigned long ar100_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct ar100_clk *clk = to_ar100_clk(hw);
+ u32 val = readl(clk->reg);
+ int shift = (val >> SUN6I_AR100_SHIFT_SHIFT) & SUN6I_AR100_SHIFT_MASK;
+ int div = (val >> SUN6I_AR100_DIV_SHIFT) & SUN6I_AR100_DIV_MASK;
+
+ return (parent_rate >> shift) / (div + 1);
+}
+
+static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_clk)
+{
+ int nparents = __clk_get_num_parents(hw->clk);
+ long best_rate = -EINVAL;
+ int i;
+
+ *best_parent_clk = NULL;
+
+ for (i = 0; i < nparents; i++) {
+ unsigned long parent_rate;
+ unsigned long tmp_rate;
+ struct clk *parent;
+ unsigned long div;
+ int shift;
+
+ parent = clk_get_parent_by_index(hw->clk, i);
+ parent_rate = __clk_get_rate(parent);
+ div = DIV_ROUND_UP(parent_rate, rate);
+
+ /*
+ * The AR100 clk contains 2 divisors:
+ * - one power of 2 divisor
+ * - one regular divisor
+ *
+ * First check if we can safely shift (or divide by a power
+ * of 2) without losing precision on the requested rate.
+ */
+ shift = ffs(div) - 1;
+ if (shift > SUN6I_AR100_SHIFT_MAX)
+ shift = SUN6I_AR100_SHIFT_MAX;
+
+ div >>= shift;
+
+ /*
+ * Then if the divisor is still bigger than what the HW
+ * actually supports, use a bigger shift (or power of 2
+ * divider) value and accept to lose some precision.
+ */
+ while (div > SUN6I_AR100_DIV_MAX) {
+ shift++;
+ div >>= 1;
+ if (shift > SUN6I_AR100_SHIFT_MAX)
+ break;
+ }
+
+ /*
+ * If the shift value (or power of 2 divider) is bigger
+ * than what the HW actually support, skip this parent.
+ */
+ if (shift > SUN6I_AR100_SHIFT_MAX)
+ continue;
+
+ tmp_rate = (parent_rate >> shift) / div;
+ if (!*best_parent_clk || tmp_rate > best_rate) {
+ *best_parent_clk = parent;
+ *best_parent_rate = parent_rate;
+ best_rate = tmp_rate;
+ }
+ }
+
+ return best_rate;
+}
+
+static int ar100_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct ar100_clk *clk = to_ar100_clk(hw);
+ u32 val = readl(clk->reg);
+
+ if (index >= SUN6I_AR100_MAX_PARENTS)
+ return -EINVAL;
+
+ val &= ~(SUN6I_AR100_MUX_MASK << SUN6I_AR100_MUX_SHIFT);
+ val |= (index << SUN6I_AR100_MUX_SHIFT);
+ writel(val, clk->reg);
+
+ return 0;
+}
+
+static u8 ar100_get_parent(struct clk_hw *hw)
+{
+ struct ar100_clk *clk = to_ar100_clk(hw);
+ return (readl(clk->reg) >> SUN6I_AR100_MUX_SHIFT) &
+ SUN6I_AR100_MUX_MASK;
+}
+
+static int ar100_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ unsigned long div = parent_rate / rate;
+ struct ar100_clk *clk = to_ar100_clk(hw);
+ u32 val = readl(clk->reg);
+ int shift;
+
+ if (parent_rate % rate)
+ return -EINVAL;
+
+ shift = ffs(div) - 1;
+ if (shift > SUN6I_AR100_SHIFT_MAX)
+ shift = SUN6I_AR100_SHIFT_MAX;
+
+ div >>= shift;
+
+ if (div > SUN6I_AR100_DIV_MAX)
+ return -EINVAL;
+
+ val &= ~((SUN6I_AR100_SHIFT_MASK << SUN6I_AR100_SHIFT_SHIFT) |
+ (SUN6I_AR100_DIV_MASK << SUN6I_AR100_DIV_SHIFT));
+ val |= (shift << SUN6I_AR100_SHIFT_SHIFT) |
+ (div << SUN6I_AR100_DIV_SHIFT);
+ writel(val, clk->reg);
+
+ return 0;
+}
+
+struct clk_ops ar100_ops = {
+ .recalc_rate = ar100_recalc_rate,
+ .determine_rate = ar100_determine_rate,
+ .set_parent = ar100_set_parent,
+ .get_parent = ar100_get_parent,
+ .set_rate = ar100_set_rate,
+};
+
+static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev)
+{
+ const char *parents[SUN6I_AR100_MAX_PARENTS];
+ struct device_node *np = pdev->dev.of_node;
+ const char *clk_name = np->name;
+ struct clk_init_data init;
+ struct ar100_clk *ar100;
+ struct resource *r;
+ struct clk *clk;
+ int nparents;
+ int i;
+
+ ar100 = devm_kzalloc(&pdev->dev, sizeof(*ar100), GFP_KERNEL);
+ if (!ar100)
+ return -ENOMEM;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ar100->reg = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(ar100->reg))
+ return PTR_ERR(ar100->reg);
+
+ nparents = of_clk_get_parent_count(np);
+ if (nparents > SUN6I_AR100_MAX_PARENTS)
+ nparents = SUN6I_AR100_MAX_PARENTS;
+
+ for (i = 0; i < nparents; i++)
+ parents[i] = of_clk_get_parent_name(np, i);
+
+ of_property_read_string(np, "clock-output-names", &clk_name);
+
+ init.name = clk_name;
+ init.ops = &ar100_ops;
+ init.parent_names = parents;
+ init.num_parents = nparents;
+ init.flags = 0;
+
+ ar100->hw.init = &init;
+
+ clk = clk_register(&pdev->dev, &ar100->hw);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+const struct of_device_id sun6i_a31_ar100_clk_dt_ids[] = {
+ { .compatible = "allwinner,sun6i-a31-ar100-clk" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sun6i_a31_ar100_clk_driver = {
+ .driver = {
+ .name = "sun6i-a31-ar100-clk",
+ .owner = THIS_MODULE,
+ .of_match_table = sun6i_a31_ar100_clk_dt_ids,
+ },
+ .probe = sun6i_a31_ar100_clk_probe,
+};
+module_platform_driver(sun6i_a31_ar100_clk_driver);
+
+MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A31 AR100 clock Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index bd7dc733c1ca..fb2ce8440f0e 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -28,63 +28,6 @@ static DEFINE_SPINLOCK(clk_lock);
#define SUNXI_MAX_PARENTS 5
/**
- * sun4i_osc_clk_setup() - Setup function for gatable oscillator
- */
-
-#define SUNXI_OSC24M_GATE 0
-
-static void __init sun4i_osc_clk_setup(struct device_node *node)
-{
- struct clk *clk;
- struct clk_fixed_rate *fixed;
- struct clk_gate *gate;
- const char *clk_name = node->name;
- u32 rate;
-
- if (of_property_read_u32(node, "clock-frequency", &rate))
- return;
-
- /* allocate fixed-rate and gate clock structs */
- fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
- if (!fixed)
- return;
- gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
- if (!gate)
- goto err_free_fixed;
-
- of_property_read_string(node, "clock-output-names", &clk_name);
-
- /* set up gate and fixed rate properties */
- gate->reg = of_iomap(node, 0);
- gate->bit_idx = SUNXI_OSC24M_GATE;
- gate->lock = &clk_lock;
- fixed->fixed_rate = rate;
-
- clk = clk_register_composite(NULL, clk_name,
- NULL, 0,
- NULL, NULL,
- &fixed->hw, &clk_fixed_rate_ops,
- &gate->hw, &clk_gate_ops,
- CLK_IS_ROOT);
-
- if (IS_ERR(clk))
- goto err_free_gate;
-
- of_clk_add_provider(node, of_clk_src_simple_get, clk);
- clk_register_clkdev(clk, clk_name, NULL);
-
- return;
-
-err_free_gate:
- kfree(gate);
-err_free_fixed:
- kfree(fixed);
-}
-CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-a10-osc-clk", sun4i_osc_clk_setup);
-
-
-
-/**
* sun4i_get_pll1_factors() - calculates n, k, m, p factors for PLL1
* PLL1 rate is calculated as follows
* rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
@@ -408,102 +351,41 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate,
*p = calcp;
}
-
-
/**
- * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module
- *
- * This clock looks something like this
- * ________________________
- * MII TX clock from PHY >-----|___________ _________|----> to GMAC core
- * GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY
- * Ext. 125MHz RGMII TX clk >--|__divider__/ |
- * |________________________|
- *
- * The external 125 MHz reference is optional, i.e. GMAC can use its
- * internal TX clock just fine. The A31 GMAC clock module does not have
- * the divider controls for the external reference.
- *
- * To keep it simple, let the GMAC use either the MII TX clock for MII mode,
- * and its internal TX clock for GMII and RGMII modes. The GMAC driver should
- * select the appropriate source and gate/ungate the output to the PHY.
- *
- * Only the GMAC should use this clock. Altering the clock so that it doesn't
- * match the GMAC's operation parameters will result in the GMAC not being
- * able to send traffic out. The GMAC driver should set the clock rate and
- * enable/disable this clock to configure the required state. The clock
- * driver then responds by auto-reparenting the clock.
+ * clk_sunxi_mmc_phase_control() - configures MMC clock phase control
*/
-#define SUN7I_A20_GMAC_GPIT 2
-#define SUN7I_A20_GMAC_MASK 0x3
-#define SUN7I_A20_GMAC_PARENTS 2
-
-static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
+void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output)
{
- struct clk *clk;
- struct clk_mux *mux;
- struct clk_gate *gate;
- const char *clk_name = node->name;
- const char *parents[SUN7I_A20_GMAC_PARENTS];
- void *reg;
-
- if (of_property_read_string(node, "clock-output-names", &clk_name))
- return;
-
- /* allocate mux and gate clock structs */
- mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
- if (!mux)
- return;
-
- gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
- if (!gate)
- goto free_mux;
+ #define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
+ #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
+
+ struct clk_hw *hw = __clk_get_hw(clk);
+ struct clk_composite *composite = to_clk_composite(hw);
+ struct clk_hw *rate_hw = composite->rate_hw;
+ struct clk_factors *factors = to_clk_factors(rate_hw);
+ unsigned long flags = 0;
+ u32 reg;
- /* gmac clock requires exactly 2 parents */
- parents[0] = of_clk_get_parent_name(node, 0);
- parents[1] = of_clk_get_parent_name(node, 1);
- if (!parents[0] || !parents[1])
- goto free_gate;
+ if (factors->lock)
+ spin_lock_irqsave(factors->lock, flags);
- reg = of_iomap(node, 0);
- if (!reg)
- goto free_gate;
-
- /* set up gate and fixed rate properties */
- gate->reg = reg;
- gate->bit_idx = SUN7I_A20_GMAC_GPIT;
- gate->lock = &clk_lock;
- mux->reg = reg;
- mux->mask = SUN7I_A20_GMAC_MASK;
- mux->flags = CLK_MUX_INDEX_BIT;
- mux->lock = &clk_lock;
-
- clk = clk_register_composite(NULL, clk_name,
- parents, SUN7I_A20_GMAC_PARENTS,
- &mux->hw, &clk_mux_ops,
- NULL, NULL,
- &gate->hw, &clk_gate_ops,
- 0);
+ reg = readl(factors->reg);
- if (IS_ERR(clk))
- goto iounmap_reg;
+ /* set sample clock phase control */
+ reg &= ~(0x7 << 20);
+ reg |= ((sample & 0x7) << 20);
- of_clk_add_provider(node, of_clk_src_simple_get, clk);
- clk_register_clkdev(clk, clk_name, NULL);
+ /* set output clock phase control */
+ reg &= ~(0x7 << 8);
+ reg |= ((output & 0x7) << 8);
- return;
+ writel(reg, factors->reg);
-iounmap_reg:
- iounmap(reg);
-free_gate:
- kfree(gate);
-free_mux:
- kfree(mux);
+ if (factors->lock)
+ spin_unlock_irqrestore(factors->lock, flags);
}
-CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk",
- sun7i_a20_gmac_clk_setup);
-
+EXPORT_SYMBOL(clk_sunxi_mmc_phase_control);
/**
@@ -972,6 +854,11 @@ static const struct gates_data sun5i_a13_usb_gates_data __initconst = {
.reset_mask = 0x03,
};
+static const struct gates_data sun6i_a31_usb_gates_data __initconst = {
+ .mask = { BIT(18) | BIT(17) | BIT(16) | BIT(10) | BIT(9) | BIT(8) },
+ .reset_mask = BIT(2) | BIT(1) | BIT(0),
+};
+
static void __init sunxi_gates_clk_setup(struct device_node *node,
struct gates_data *data)
{
@@ -1267,6 +1154,7 @@ static const struct of_device_id clk_gates_match[] __initconst = {
{.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
{.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,},
{.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,},
+ {.compatible = "allwinner,sun6i-a31-usb-clk", .data = &sun6i_a31_usb_gates_data,},
{}
};
@@ -1278,40 +1166,16 @@ static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_mat
const struct of_device_id *match;
void (*setup_function)(struct device_node *, const void *) = function;
- for_each_matching_node(np, clk_match) {
- match = of_match_node(clk_match, np);
+ for_each_matching_node_and_match(np, clk_match, &match) {
data = match->data;
setup_function(np, data);
}
}
-/**
- * System clock protection
- *
- * By enabling these critical clocks, we prevent their accidental gating
- * by the framework
- */
-static void __init sunxi_clock_protect(void)
+static void __init sunxi_init_clocks(const char *clocks[], int nclocks)
{
- struct clk *clk;
-
- /* memory bus clock - sun5i+ */
- clk = clk_get(NULL, "mbus");
- if (!IS_ERR(clk)) {
- clk_prepare_enable(clk);
- clk_put(clk);
- }
-
- /* DDR clock - sun4i+ */
- clk = clk_get(NULL, "pll5_ddr");
- if (!IS_ERR(clk)) {
- clk_prepare_enable(clk);
- clk_put(clk);
- }
-}
+ unsigned int i;
-static void __init sunxi_init_clocks(void)
-{
/* Register factor clocks */
of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup);
@@ -1327,11 +1191,48 @@ static void __init sunxi_init_clocks(void)
/* Register gate clocks */
of_sunxi_table_clock_setup(clk_gates_match, sunxi_gates_clk_setup);
- /* Enable core system clocks */
- sunxi_clock_protect();
+ /* Protect the clocks that needs to stay on */
+ for (i = 0; i < nclocks; i++) {
+ struct clk *clk = clk_get(NULL, clocks[i]);
+
+ if (!IS_ERR(clk))
+ clk_prepare_enable(clk);
+ }
+}
+
+static const char *sun4i_a10_critical_clocks[] __initdata = {
+ "pll5_ddr",
+};
+
+static void __init sun4i_a10_init_clocks(struct device_node *node)
+{
+ sunxi_init_clocks(sun4i_a10_critical_clocks,
+ ARRAY_SIZE(sun4i_a10_critical_clocks));
+}
+CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks);
+
+static const char *sun5i_critical_clocks[] __initdata = {
+ "mbus",
+ "pll5_ddr",
+};
+
+static void __init sun5i_init_clocks(struct device_node *node)
+{
+ sunxi_init_clocks(sun5i_critical_clocks,
+ ARRAY_SIZE(sun5i_critical_clocks));
+}
+CLK_OF_DECLARE(sun5i_a10s_clk_init, "allwinner,sun5i-a10s", sun5i_init_clocks);
+CLK_OF_DECLARE(sun5i_a13_clk_init, "allwinner,sun5i-a13", sun5i_init_clocks);
+CLK_OF_DECLARE(sun7i_a20_clk_init, "allwinner,sun7i-a20", sun5i_init_clocks);
+
+static const char *sun6i_critical_clocks[] __initdata = {
+ "cpu",
+ "ahb1_sdram",
+};
+
+static void __init sun6i_init_clocks(struct device_node *node)
+{
+ sunxi_init_clocks(sun6i_critical_clocks,
+ ARRAY_SIZE(sun6i_critical_clocks));
}
-CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sunxi_init_clocks);
-CLK_OF_DECLARE(sun5i_a10s_clk_init, "allwinner,sun5i-a10s", sunxi_init_clocks);
-CLK_OF_DECLARE(sun5i_a13_clk_init, "allwinner,sun5i-a13", sunxi_init_clocks);
-CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sunxi_init_clocks);
-CLK_OF_DECLARE(sun7i_a20_clk_init, "allwinner,sun7i-a20", sunxi_init_clocks);
+CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks);
diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index c39613c519af..0011d547a9f7 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -233,6 +233,7 @@ enum clk_id {
tegra_clk_xusb_hs_src,
tegra_clk_xusb_ss,
tegra_clk_xusb_ss_src,
+ tegra_clk_xusb_ss_div2,
tegra_clk_max,
};
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 6aad8abc69a2..637b62ccc91e 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -96,10 +96,20 @@
(PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL)
#define PLLE_AUX_PLLP_SEL BIT(2)
+#define PLLE_AUX_USE_LOCKDET BIT(3)
#define PLLE_AUX_ENABLE_SWCTL BIT(4)
+#define PLLE_AUX_SS_SWCTL BIT(6)
#define PLLE_AUX_SEQ_ENABLE BIT(24)
+#define PLLE_AUX_SEQ_START_STATE BIT(25)
#define PLLE_AUX_PLLRE_SEL BIT(28)
+#define XUSBIO_PLL_CFG0 0x51c
+#define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL BIT(0)
+#define XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL BIT(2)
+#define XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET BIT(6)
+#define XUSBIO_PLL_CFG0_SEQ_ENABLE BIT(24)
+#define XUSBIO_PLL_CFG0_SEQ_START_STATE BIT(25)
+
#define PLLE_MISC_PLLE_PTS BIT(8)
#define PLLE_MISC_IDDQ_SW_VALUE BIT(13)
#define PLLE_MISC_IDDQ_SW_CTRL BIT(14)
@@ -1328,7 +1338,28 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
pll_writel(val, PLLE_SS_CTRL, pll);
udelay(1);
- /* TODO: enable hw control of xusb brick pll */
+ /* Enable hw control of xusb brick pll */
+ val = pll_readl_misc(pll);
+ val &= ~PLLE_MISC_IDDQ_SW_CTRL;
+ pll_writel_misc(val, pll);
+
+ val = pll_readl(pll->params->aux_reg, pll);
+ val |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SEQ_START_STATE);
+ val &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL);
+ pll_writel(val, pll->params->aux_reg, pll);
+ udelay(1);
+ val |= PLLE_AUX_SEQ_ENABLE;
+ pll_writel(val, pll->params->aux_reg, pll);
+
+ val = pll_readl(XUSBIO_PLL_CFG0, pll);
+ val |= (XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET |
+ XUSBIO_PLL_CFG0_SEQ_START_STATE);
+ val &= ~(XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL |
+ XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL);
+ pll_writel(val, XUSBIO_PLL_CFG0, pll);
+ udelay(1);
+ val |= XUSBIO_PLL_CFG0_SEQ_ENABLE;
+ pll_writel(val, XUSBIO_PLL_CFG0, pll);
out:
if (pll->lock)
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index 1fa5c3f33b20..adf6b814b5bc 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -329,7 +329,9 @@ static u32 mux_clkm_pllp_pllc_pllre_idx[] = {
static const char *mux_clkm_48M_pllp_480M[] = {
"clk_m", "pll_u_48M", "pll_p", "pll_u_480M"
};
-#define mux_clkm_48M_pllp_480M_idx NULL
+static u32 mux_clkm_48M_pllp_480M_idx[] = {
+ [0] = 0, [1] = 2, [2] = 4, [3] = 6,
+};
static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = {
"clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref"
@@ -338,6 +340,11 @@ static u32 mux_clkm_pllre_clk32_480M_pllc_ref_idx[] = {
[0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7,
};
+static const char *mux_ss_60M[] = {
+ "xusb_ss_div2", "pll_u_60M"
+};
+#define mux_ss_60M_idx NULL
+
static const char *mux_d_audio_clk[] = {
"pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync",
"i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync",
@@ -499,6 +506,7 @@ static struct tegra_periph_init_data periph_clks[] = {
XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src),
XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src),
XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src),
+ NODIV("xusb_hs_src", mux_ss_60M, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src, NULL),
XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src),
};
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 80431f0fb268..b9c8ba258ef0 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -142,7 +142,6 @@
#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0)
#define CLK_SOURCE_CSITE 0x1d4
-#define CLK_SOURCE_XUSB_SS_SRC 0x610
#define CLK_SOURCE_EMC 0x19c
/* PLLM override registers */
@@ -834,6 +833,7 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
[tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA114_CLK_XUSB_FALCON_SRC, .present = true },
[tegra_clk_xusb_fs_src] = { .dt_id = TEGRA114_CLK_XUSB_FS_SRC, .present = true },
[tegra_clk_xusb_ss_src] = { .dt_id = TEGRA114_CLK_XUSB_SS_SRC, .present = true },
+ [tegra_clk_xusb_ss_div2] = { .dt_id = TEGRA114_CLK_XUSB_SS_DIV2, .present = true},
[tegra_clk_xusb_dev_src] = { .dt_id = TEGRA114_CLK_XUSB_DEV_SRC, .present = true },
[tegra_clk_xusb_dev] = { .dt_id = TEGRA114_CLK_XUSB_DEV, .present = true },
[tegra_clk_xusb_hs_src] = { .dt_id = TEGRA114_CLK_XUSB_HS_SRC, .present = true },
@@ -1182,16 +1182,11 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base,
void __iomem *pmc_base)
{
struct clk *clk;
- u32 val;
-
- /* xusb_hs_src */
- val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC);
- val |= BIT(25); /* always select PLLU_60M */
- writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC);
- clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0,
- 1, 1);
- clks[TEGRA114_CLK_XUSB_HS_SRC] = clk;
+ /* xusb_ss_div2 */
+ clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0,
+ 1, 2);
+ clks[TEGRA114_CLK_XUSB_SS_DIV2] = clk;
/* dsia mux */
clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0,
@@ -1301,7 +1296,12 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{TEGRA114_CLK_GR3D, TEGRA114_CLK_PLL_C2, 300000000, 0},
{TEGRA114_CLK_DSIALP, TEGRA114_CLK_PLL_P, 68000000, 0},
{TEGRA114_CLK_DSIBLP, TEGRA114_CLK_PLL_P, 68000000, 0},
-
+ {TEGRA114_CLK_PLL_RE_VCO, TEGRA114_CLK_CLK_MAX, 612000000, 0},
+ {TEGRA114_CLK_XUSB_SS_SRC, TEGRA114_CLK_PLL_RE_OUT, 122400000, 0},
+ {TEGRA114_CLK_XUSB_FS_SRC, TEGRA114_CLK_PLL_U_48M, 48000000, 0},
+ {TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0},
+ {TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0},
+ {TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0},
/* This MUST be the last entry. */
{TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0},
};
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index cc37c342c4cb..80efe51fdcdf 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -30,7 +30,6 @@
#define CLK_SOURCE_CSITE 0x1d4
#define CLK_SOURCE_EMC 0x19c
-#define CLK_SOURCE_XUSB_SS_SRC 0x610
#define PLLC_BASE 0x80
#define PLLC_OUT 0x84
@@ -925,6 +924,7 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
[tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA124_CLK_XUSB_FALCON_SRC, .present = true },
[tegra_clk_xusb_fs_src] = { .dt_id = TEGRA124_CLK_XUSB_FS_SRC, .present = true },
[tegra_clk_xusb_ss_src] = { .dt_id = TEGRA124_CLK_XUSB_SS_SRC, .present = true },
+ [tegra_clk_xusb_ss_div2] = { .dt_id = TEGRA124_CLK_XUSB_SS_DIV2, .present = true },
[tegra_clk_xusb_dev_src] = { .dt_id = TEGRA124_CLK_XUSB_DEV_SRC, .present = true },
[tegra_clk_xusb_dev] = { .dt_id = TEGRA124_CLK_XUSB_DEV, .present = true },
[tegra_clk_xusb_hs_src] = { .dt_id = TEGRA124_CLK_XUSB_HS_SRC, .present = true },
@@ -1105,16 +1105,11 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base,
void __iomem *pmc_base)
{
struct clk *clk;
- u32 val;
-
- /* xusb_hs_src */
- val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC);
- val |= BIT(25); /* always select PLLU_60M */
- writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC);
- clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0,
- 1, 1);
- clks[TEGRA124_CLK_XUSB_HS_SRC] = clk;
+ /* xusb_ss_div2 */
+ clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0,
+ 1, 2);
+ clks[TEGRA124_CLK_XUSB_SS_DIV2] = clk;
/* dsia mux */
clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0,
@@ -1368,6 +1363,12 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1},
{TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0},
{TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0},
+ {TEGRA124_CLK_PLL_RE_VCO, TEGRA124_CLK_CLK_MAX, 672000000, 0},
+ {TEGRA124_CLK_XUSB_SS_SRC, TEGRA124_CLK_PLL_U_480M, 120000000, 0},
+ {TEGRA124_CLK_XUSB_FS_SRC, TEGRA124_CLK_PLL_U_48M, 48000000, 0},
+ {TEGRA124_CLK_XUSB_HS_SRC, TEGRA124_CLK_PLL_U_60M, 60000000, 0},
+ {TEGRA124_CLK_XUSB_FALCON_SRC, TEGRA124_CLK_PLL_RE_OUT, 224000000, 0},
+ {TEGRA124_CLK_XUSB_HOST_SRC, TEGRA124_CLK_PLL_RE_OUT, 112000000, 0},
/* This MUST be the last entry. */
{TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
};
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile
index 4319d4031aa3..ed4d0aaf8916 100644
--- a/drivers/clk/ti/Makefile
+++ b/drivers/clk/ti/Makefile
@@ -3,9 +3,11 @@ obj-y += clk.o autoidle.o clockdomain.o
clk-common = dpll.o composite.o divider.o gate.o \
fixed-factor.o mux.o apll.o
obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o
+obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o
obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o clk-3xxx.o
obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o
obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o
-obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o
+obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \
+ clk-dra7-atl.o
obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o
endif
diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c
index b986f61f5a77..72d97279eae1 100644
--- a/drivers/clk/ti/apll.c
+++ b/drivers/clk/ti/apll.c
@@ -77,13 +77,11 @@ static int dra7_apll_enable(struct clk_hw *hw)
if (i == MAX_APLL_WAIT_TRIES) {
pr_warn("clock: %s failed transition to '%s'\n",
clk_name, (state) ? "locked" : "bypassed");
- } else {
+ r = -EBUSY;
+ } else
pr_debug("clock: %s transition to '%s' in %d loops\n",
clk_name, (state) ? "locked" : "bypassed", i);
- r = 0;
- }
-
return r;
}
@@ -221,3 +219,184 @@ cleanup:
kfree(init);
}
CLK_OF_DECLARE(dra7_apll_clock, "ti,dra7-apll-clock", of_dra7_apll_setup);
+
+#define OMAP2_EN_APLL_LOCKED 0x3
+#define OMAP2_EN_APLL_STOPPED 0x0
+
+static int omap2_apll_is_enabled(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ struct dpll_data *ad = clk->dpll_data;
+ u32 v;
+
+ v = ti_clk_ll_ops->clk_readl(ad->control_reg);
+ v &= ad->enable_mask;
+
+ v >>= __ffs(ad->enable_mask);
+
+ return v == OMAP2_EN_APLL_LOCKED ? 1 : 0;
+}
+
+static unsigned long omap2_apll_recalc(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+
+ if (omap2_apll_is_enabled(hw))
+ return clk->fixed_rate;
+
+ return 0;
+}
+
+static int omap2_apll_enable(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ struct dpll_data *ad = clk->dpll_data;
+ u32 v;
+ int i = 0;
+
+ v = ti_clk_ll_ops->clk_readl(ad->control_reg);
+ v &= ~ad->enable_mask;
+ v |= OMAP2_EN_APLL_LOCKED << __ffs(ad->enable_mask);
+ ti_clk_ll_ops->clk_writel(v, ad->control_reg);
+
+ while (1) {
+ v = ti_clk_ll_ops->clk_readl(ad->idlest_reg);
+ if (v & ad->idlest_mask)
+ break;
+ if (i > MAX_APLL_WAIT_TRIES)
+ break;
+ i++;
+ udelay(1);
+ }
+
+ if (i == MAX_APLL_WAIT_TRIES) {
+ pr_warn("%s failed to transition to locked\n",
+ __clk_get_name(clk->hw.clk));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static void omap2_apll_disable(struct clk_hw *hw)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ struct dpll_data *ad = clk->dpll_data;
+ u32 v;
+
+ v = ti_clk_ll_ops->clk_readl(ad->control_reg);
+ v &= ~ad->enable_mask;
+ v |= OMAP2_EN_APLL_STOPPED << __ffs(ad->enable_mask);
+ ti_clk_ll_ops->clk_writel(v, ad->control_reg);
+}
+
+static struct clk_ops omap2_apll_ops = {
+ .enable = &omap2_apll_enable,
+ .disable = &omap2_apll_disable,
+ .is_enabled = &omap2_apll_is_enabled,
+ .recalc_rate = &omap2_apll_recalc,
+};
+
+static void omap2_apll_set_autoidle(struct clk_hw_omap *clk, u32 val)
+{
+ struct dpll_data *ad = clk->dpll_data;
+ u32 v;
+
+ v = ti_clk_ll_ops->clk_readl(ad->autoidle_reg);
+ v &= ~ad->autoidle_mask;
+ v |= val << __ffs(ad->autoidle_mask);
+ ti_clk_ll_ops->clk_writel(v, ad->control_reg);
+}
+
+#define OMAP2_APLL_AUTOIDLE_LOW_POWER_STOP 0x3
+#define OMAP2_APLL_AUTOIDLE_DISABLE 0x0
+
+static void omap2_apll_allow_idle(struct clk_hw_omap *clk)
+{
+ omap2_apll_set_autoidle(clk, OMAP2_APLL_AUTOIDLE_LOW_POWER_STOP);
+}
+
+static void omap2_apll_deny_idle(struct clk_hw_omap *clk)
+{
+ omap2_apll_set_autoidle(clk, OMAP2_APLL_AUTOIDLE_DISABLE);
+}
+
+static struct clk_hw_omap_ops omap2_apll_hwops = {
+ .allow_idle = &omap2_apll_allow_idle,
+ .deny_idle = &omap2_apll_deny_idle,
+};
+
+static void __init of_omap2_apll_setup(struct device_node *node)
+{
+ struct dpll_data *ad = NULL;
+ struct clk_hw_omap *clk_hw = NULL;
+ struct clk_init_data *init = NULL;
+ struct clk *clk;
+ const char *parent_name;
+ u32 val;
+
+ ad = kzalloc(sizeof(*ad), GFP_KERNEL);
+ clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
+ init = kzalloc(sizeof(*init), GFP_KERNEL);
+
+ if (!ad || !clk_hw || !init)
+ goto cleanup;
+
+ clk_hw->dpll_data = ad;
+ clk_hw->hw.init = init;
+ init->ops = &omap2_apll_ops;
+ init->name = node->name;
+ clk_hw->ops = &omap2_apll_hwops;
+
+ init->num_parents = of_clk_get_parent_count(node);
+ if (init->num_parents != 1) {
+ pr_err("%s must have one parent\n", node->name);
+ goto cleanup;
+ }
+
+ parent_name = of_clk_get_parent_name(node, 0);
+ init->parent_names = &parent_name;
+
+ if (of_property_read_u32(node, "ti,clock-frequency", &val)) {
+ pr_err("%s missing clock-frequency\n", node->name);
+ goto cleanup;
+ }
+ clk_hw->fixed_rate = val;
+
+ if (of_property_read_u32(node, "ti,bit-shift", &val)) {
+ pr_err("%s missing bit-shift\n", node->name);
+ goto cleanup;
+ }
+
+ clk_hw->enable_bit = val;
+ ad->enable_mask = 0x3 << val;
+ ad->autoidle_mask = 0x3 << val;
+
+ if (of_property_read_u32(node, "ti,idlest-shift", &val)) {
+ pr_err("%s missing idlest-shift\n", node->name);
+ goto cleanup;
+ }
+
+ ad->idlest_mask = 1 << val;
+
+ ad->control_reg = ti_clk_get_reg_addr(node, 0);
+ ad->autoidle_reg = ti_clk_get_reg_addr(node, 1);
+ ad->idlest_reg = ti_clk_get_reg_addr(node, 2);
+
+ if (!ad->control_reg || !ad->autoidle_reg || !ad->idlest_reg)
+ goto cleanup;
+
+ clk = clk_register(NULL, &clk_hw->hw);
+ if (!IS_ERR(clk)) {
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ kfree(init);
+ return;
+ }
+cleanup:
+ kfree(ad);
+ kfree(clk_hw);
+ kfree(init);
+}
+CLK_OF_DECLARE(omap2_apll_clock, "ti,omap2-apll-clock",
+ of_omap2_apll_setup);
diff --git a/drivers/clk/ti/clk-2xxx.c b/drivers/clk/ti/clk-2xxx.c
new file mode 100644
index 000000000000..c808ab3d2bb2
--- /dev/null
+++ b/drivers/clk/ti/clk-2xxx.c
@@ -0,0 +1,256 @@
+/*
+ * OMAP2 Clock init
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc
+ * Tero Kristo (t-kristo@ti.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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
+
+static struct ti_dt_clk omap2xxx_clks[] = {
+ DT_CLK(NULL, "func_32k_ck", "func_32k_ck"),
+ DT_CLK(NULL, "secure_32k_ck", "secure_32k_ck"),
+ DT_CLK(NULL, "virt_12m_ck", "virt_12m_ck"),
+ DT_CLK(NULL, "virt_13m_ck", "virt_13m_ck"),
+ DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"),
+ DT_CLK(NULL, "virt_26m_ck", "virt_26m_ck"),
+ DT_CLK(NULL, "aplls_clkin_ck", "aplls_clkin_ck"),
+ DT_CLK(NULL, "aplls_clkin_x2_ck", "aplls_clkin_x2_ck"),
+ DT_CLK(NULL, "osc_ck", "osc_ck"),
+ DT_CLK(NULL, "sys_ck", "sys_ck"),
+ DT_CLK(NULL, "alt_ck", "alt_ck"),
+ DT_CLK(NULL, "mcbsp_clks", "mcbsp_clks"),
+ DT_CLK(NULL, "dpll_ck", "dpll_ck"),
+ DT_CLK(NULL, "apll96_ck", "apll96_ck"),
+ DT_CLK(NULL, "apll54_ck", "apll54_ck"),
+ DT_CLK(NULL, "func_54m_ck", "func_54m_ck"),
+ DT_CLK(NULL, "core_ck", "core_ck"),
+ DT_CLK(NULL, "func_96m_ck", "func_96m_ck"),
+ DT_CLK(NULL, "func_48m_ck", "func_48m_ck"),
+ DT_CLK(NULL, "func_12m_ck", "func_12m_ck"),
+ DT_CLK(NULL, "sys_clkout_src", "sys_clkout_src"),
+ DT_CLK(NULL, "sys_clkout", "sys_clkout"),
+ DT_CLK(NULL, "emul_ck", "emul_ck"),
+ DT_CLK(NULL, "mpu_ck", "mpu_ck"),
+ DT_CLK(NULL, "dsp_fck", "dsp_fck"),
+ DT_CLK(NULL, "gfx_3d_fck", "gfx_3d_fck"),
+ DT_CLK(NULL, "gfx_2d_fck", "gfx_2d_fck"),
+ DT_CLK(NULL, "gfx_ick", "gfx_ick"),
+ DT_CLK("omapdss_dss", "ick", "dss_ick"),
+ DT_CLK(NULL, "dss_ick", "dss_ick"),
+ DT_CLK(NULL, "dss1_fck", "dss1_fck"),
+ DT_CLK(NULL, "dss2_fck", "dss2_fck"),
+ DT_CLK(NULL, "dss_54m_fck", "dss_54m_fck"),
+ DT_CLK(NULL, "core_l3_ck", "core_l3_ck"),
+ DT_CLK(NULL, "ssi_fck", "ssi_ssr_sst_fck"),
+ DT_CLK(NULL, "usb_l4_ick", "usb_l4_ick"),
+ DT_CLK(NULL, "l4_ck", "l4_ck"),
+ DT_CLK(NULL, "ssi_l4_ick", "ssi_l4_ick"),
+ DT_CLK(NULL, "gpt1_ick", "gpt1_ick"),
+ DT_CLK(NULL, "gpt1_fck", "gpt1_fck"),
+ DT_CLK(NULL, "gpt2_ick", "gpt2_ick"),
+ DT_CLK(NULL, "gpt2_fck", "gpt2_fck"),
+ DT_CLK(NULL, "gpt3_ick", "gpt3_ick"),
+ DT_CLK(NULL, "gpt3_fck", "gpt3_fck"),
+ DT_CLK(NULL, "gpt4_ick", "gpt4_ick"),
+ DT_CLK(NULL, "gpt4_fck", "gpt4_fck"),
+ DT_CLK(NULL, "gpt5_ick", "gpt5_ick"),
+ DT_CLK(NULL, "gpt5_fck", "gpt5_fck"),
+ DT_CLK(NULL, "gpt6_ick", "gpt6_ick"),
+ DT_CLK(NULL, "gpt6_fck", "gpt6_fck"),
+ DT_CLK(NULL, "gpt7_ick", "gpt7_ick"),
+ DT_CLK(NULL, "gpt7_fck", "gpt7_fck"),
+ DT_CLK(NULL, "gpt8_ick", "gpt8_ick"),
+ DT_CLK(NULL, "gpt8_fck", "gpt8_fck"),
+ DT_CLK(NULL, "gpt9_ick", "gpt9_ick"),
+ DT_CLK(NULL, "gpt9_fck", "gpt9_fck"),
+ DT_CLK(NULL, "gpt10_ick", "gpt10_ick"),
+ DT_CLK(NULL, "gpt10_fck", "gpt10_fck"),
+ DT_CLK(NULL, "gpt11_ick", "gpt11_ick"),
+ DT_CLK(NULL, "gpt11_fck", "gpt11_fck"),
+ DT_CLK(NULL, "gpt12_ick", "gpt12_ick"),
+ DT_CLK(NULL, "gpt12_fck", "gpt12_fck"),
+ DT_CLK("omap-mcbsp.1", "ick", "mcbsp1_ick"),
+ DT_CLK(NULL, "mcbsp1_ick", "mcbsp1_ick"),
+ DT_CLK(NULL, "mcbsp1_fck", "mcbsp1_fck"),
+ DT_CLK("omap-mcbsp.2", "ick", "mcbsp2_ick"),
+ DT_CLK(NULL, "mcbsp2_ick", "mcbsp2_ick"),
+ DT_CLK(NULL, "mcbsp2_fck", "mcbsp2_fck"),
+ DT_CLK("omap2_mcspi.1", "ick", "mcspi1_ick"),
+ DT_CLK(NULL, "mcspi1_ick", "mcspi1_ick"),
+ DT_CLK(NULL, "mcspi1_fck", "mcspi1_fck"),
+ DT_CLK("omap2_mcspi.2", "ick", "mcspi2_ick"),
+ DT_CLK(NULL, "mcspi2_ick", "mcspi2_ick"),
+ DT_CLK(NULL, "mcspi2_fck", "mcspi2_fck"),
+ DT_CLK(NULL, "uart1_ick", "uart1_ick"),
+ DT_CLK(NULL, "uart1_fck", "uart1_fck"),
+ DT_CLK(NULL, "uart2_ick", "uart2_ick"),
+ DT_CLK(NULL, "uart2_fck", "uart2_fck"),
+ DT_CLK(NULL, "uart3_ick", "uart3_ick"),
+ DT_CLK(NULL, "uart3_fck", "uart3_fck"),
+ DT_CLK(NULL, "gpios_ick", "gpios_ick"),
+ DT_CLK(NULL, "gpios_fck", "gpios_fck"),
+ DT_CLK("omap_wdt", "ick", "mpu_wdt_ick"),
+ DT_CLK(NULL, "mpu_wdt_ick", "mpu_wdt_ick"),
+ DT_CLK(NULL, "mpu_wdt_fck", "mpu_wdt_fck"),
+ DT_CLK(NULL, "sync_32k_ick", "sync_32k_ick"),
+ DT_CLK(NULL, "wdt1_ick", "wdt1_ick"),
+ DT_CLK(NULL, "omapctrl_ick", "omapctrl_ick"),
+ DT_CLK("omap24xxcam", "fck", "cam_fck"),
+ DT_CLK(NULL, "cam_fck", "cam_fck"),
+ DT_CLK("omap24xxcam", "ick", "cam_ick"),
+ DT_CLK(NULL, "cam_ick", "cam_ick"),
+ DT_CLK(NULL, "mailboxes_ick", "mailboxes_ick"),
+ DT_CLK(NULL, "wdt4_ick", "wdt4_ick"),
+ DT_CLK(NULL, "wdt4_fck", "wdt4_fck"),
+ DT_CLK(NULL, "mspro_ick", "mspro_ick"),
+ DT_CLK(NULL, "mspro_fck", "mspro_fck"),
+ DT_CLK(NULL, "fac_ick", "fac_ick"),
+ DT_CLK(NULL, "fac_fck", "fac_fck"),
+ DT_CLK("omap_hdq.0", "ick", "hdq_ick"),
+ DT_CLK(NULL, "hdq_ick", "hdq_ick"),
+ DT_CLK("omap_hdq.0", "fck", "hdq_fck"),
+ DT_CLK(NULL, "hdq_fck", "hdq_fck"),
+ DT_CLK("omap_i2c.1", "ick", "i2c1_ick"),
+ DT_CLK(NULL, "i2c1_ick", "i2c1_ick"),
+ DT_CLK("omap_i2c.2", "ick", "i2c2_ick"),
+ DT_CLK(NULL, "i2c2_ick", "i2c2_ick"),
+ DT_CLK(NULL, "gpmc_fck", "gpmc_fck"),
+ DT_CLK(NULL, "sdma_fck", "sdma_fck"),
+ DT_CLK(NULL, "sdma_ick", "sdma_ick"),
+ DT_CLK(NULL, "sdrc_ick", "sdrc_ick"),
+ DT_CLK(NULL, "des_ick", "des_ick"),
+ DT_CLK("omap-sham", "ick", "sha_ick"),
+ DT_CLK(NULL, "sha_ick", "sha_ick"),
+ DT_CLK("omap_rng", "ick", "rng_ick"),
+ DT_CLK(NULL, "rng_ick", "rng_ick"),
+ DT_CLK("omap-aes", "ick", "aes_ick"),
+ DT_CLK(NULL, "aes_ick", "aes_ick"),
+ DT_CLK(NULL, "pka_ick", "pka_ick"),
+ DT_CLK(NULL, "usb_fck", "usb_fck"),
+ DT_CLK(NULL, "timer_32k_ck", "func_32k_ck"),
+ DT_CLK(NULL, "timer_sys_ck", "sys_ck"),
+ DT_CLK(NULL, "timer_ext_ck", "alt_ck"),
+ { .node_name = NULL },
+};
+
+static struct ti_dt_clk omap2420_clks[] = {
+ DT_CLK(NULL, "sys_clkout2_src", "sys_clkout2_src"),
+ DT_CLK(NULL, "sys_clkout2", "sys_clkout2"),
+ DT_CLK(NULL, "dsp_ick", "dsp_ick"),
+ DT_CLK(NULL, "iva1_ifck", "iva1_ifck"),
+ DT_CLK(NULL, "iva1_mpu_int_ifck", "iva1_mpu_int_ifck"),
+ DT_CLK(NULL, "wdt3_ick", "wdt3_ick"),
+ DT_CLK(NULL, "wdt3_fck", "wdt3_fck"),
+ DT_CLK("mmci-omap.0", "ick", "mmc_ick"),
+ DT_CLK(NULL, "mmc_ick", "mmc_ick"),
+ DT_CLK("mmci-omap.0", "fck", "mmc_fck"),
+ DT_CLK(NULL, "mmc_fck", "mmc_fck"),
+ DT_CLK(NULL, "eac_ick", "eac_ick"),
+ DT_CLK(NULL, "eac_fck", "eac_fck"),
+ DT_CLK(NULL, "i2c1_fck", "i2c1_fck"),
+ DT_CLK(NULL, "i2c2_fck", "i2c2_fck"),
+ DT_CLK(NULL, "vlynq_ick", "vlynq_ick"),
+ DT_CLK(NULL, "vlynq_fck", "vlynq_fck"),
+ DT_CLK("musb-hdrc", "fck", "osc_ck"),
+ { .node_name = NULL },
+};
+
+static struct ti_dt_clk omap2430_clks[] = {
+ DT_CLK("twl", "fck", "osc_ck"),
+ DT_CLK(NULL, "iva2_1_ick", "iva2_1_ick"),
+ DT_CLK(NULL, "mdm_ick", "mdm_ick"),
+ DT_CLK(NULL, "mdm_osc_ck", "mdm_osc_ck"),
+ DT_CLK("omap-mcbsp.3", "ick", "mcbsp3_ick"),
+ DT_CLK(NULL, "mcbsp3_ick", "mcbsp3_ick"),
+ DT_CLK(NULL, "mcbsp3_fck", "mcbsp3_fck"),
+ DT_CLK("omap-mcbsp.4", "ick", "mcbsp4_ick"),
+ DT_CLK(NULL, "mcbsp4_ick", "mcbsp4_ick"),
+ DT_CLK(NULL, "mcbsp4_fck", "mcbsp4_fck"),
+ DT_CLK("omap-mcbsp.5", "ick", "mcbsp5_ick"),
+ DT_CLK(NULL, "mcbsp5_ick", "mcbsp5_ick"),
+ DT_CLK(NULL, "mcbsp5_fck", "mcbsp5_fck"),
+ DT_CLK("omap2_mcspi.3", "ick", "mcspi3_ick"),
+ DT_CLK(NULL, "mcspi3_ick", "mcspi3_ick"),
+ DT_CLK(NULL, "mcspi3_fck", "mcspi3_fck"),
+ DT_CLK(NULL, "icr_ick", "icr_ick"),
+ DT_CLK(NULL, "i2chs1_fck", "i2chs1_fck"),
+ DT_CLK(NULL, "i2chs2_fck", "i2chs2_fck"),
+ DT_CLK("musb-omap2430", "ick", "usbhs_ick"),
+ DT_CLK(NULL, "usbhs_ick", "usbhs_ick"),
+ DT_CLK("omap_hsmmc.0", "ick", "mmchs1_ick"),
+ DT_CLK(NULL, "mmchs1_ick", "mmchs1_ick"),
+ DT_CLK(NULL, "mmchs1_fck", "mmchs1_fck"),
+ DT_CLK("omap_hsmmc.1", "ick", "mmchs2_ick"),
+ DT_CLK(NULL, "mmchs2_ick", "mmchs2_ick"),
+ DT_CLK(NULL, "mmchs2_fck", "mmchs2_fck"),
+ DT_CLK(NULL, "gpio5_ick", "gpio5_ick"),
+ DT_CLK(NULL, "gpio5_fck", "gpio5_fck"),
+ DT_CLK(NULL, "mdm_intc_ick", "mdm_intc_ick"),
+ DT_CLK("omap_hsmmc.0", "mmchsdb_fck", "mmchsdb1_fck"),
+ DT_CLK(NULL, "mmchsdb1_fck", "mmchsdb1_fck"),
+ DT_CLK("omap_hsmmc.1", "mmchsdb_fck", "mmchsdb2_fck"),
+ DT_CLK(NULL, "mmchsdb2_fck", "mmchsdb2_fck"),
+ { .node_name = NULL },
+};
+
+static const char *enable_init_clks[] = {
+ "apll96_ck",
+ "apll54_ck",
+ "sync_32k_ick",
+ "omapctrl_ick",
+ "gpmc_fck",
+ "sdrc_ick",
+};
+
+enum {
+ OMAP2_SOC_OMAP2420,
+ OMAP2_SOC_OMAP2430,
+};
+
+static int __init omap2xxx_dt_clk_init(int soc_type)
+{
+ ti_dt_clocks_register(omap2xxx_clks);
+
+ if (soc_type == OMAP2_SOC_OMAP2420)
+ ti_dt_clocks_register(omap2420_clks);
+ else
+ ti_dt_clocks_register(omap2430_clks);
+
+ omap2xxx_clkt_vps_init();
+
+ omap2_clk_disable_autoidle_all();
+
+ omap2_clk_enable_init_clocks(enable_init_clks,
+ ARRAY_SIZE(enable_init_clks));
+
+ pr_info("Clocking rate (Crystal/DPLL/MPU): %ld.%01ld/%ld/%ld MHz\n",
+ (clk_get_rate(clk_get_sys(NULL, "sys_ck")) / 1000000),
+ (clk_get_rate(clk_get_sys(NULL, "sys_ck")) / 100000) % 10,
+ (clk_get_rate(clk_get_sys(NULL, "dpll_ck")) / 1000000),
+ (clk_get_rate(clk_get_sys(NULL, "mpu_ck")) / 1000000));
+
+ return 0;
+}
+
+int __init omap2420_dt_clk_init(void)
+{
+ return omap2xxx_dt_clk_init(OMAP2_SOC_OMAP2420);
+}
+
+int __init omap2430_dt_clk_init(void)
+{
+ return omap2xxx_dt_clk_init(OMAP2_SOC_OMAP2430);
+}
diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c
index 67c8de572c50..3795fce8a830 100644
--- a/drivers/clk/ti/clk-43xx.c
+++ b/drivers/clk/ti/clk-43xx.c
@@ -105,14 +105,36 @@ static struct ti_dt_clk am43xx_clks[] = {
DT_CLK(NULL, "func_12m_clk", "func_12m_clk"),
DT_CLK(NULL, "vtp_clk_div", "vtp_clk_div"),
DT_CLK(NULL, "usbphy_32khz_clkmux", "usbphy_32khz_clkmux"),
+ DT_CLK("48300200.ehrpwm", "tbclk", "ehrpwm0_tbclk"),
+ DT_CLK("48302200.ehrpwm", "tbclk", "ehrpwm1_tbclk"),
+ DT_CLK("48304200.ehrpwm", "tbclk", "ehrpwm2_tbclk"),
+ DT_CLK("48306200.ehrpwm", "tbclk", "ehrpwm3_tbclk"),
+ DT_CLK("48308200.ehrpwm", "tbclk", "ehrpwm4_tbclk"),
+ DT_CLK("4830a200.ehrpwm", "tbclk", "ehrpwm5_tbclk"),
{ .node_name = NULL },
};
int __init am43xx_dt_clk_init(void)
{
+ struct clk *clk1, *clk2;
+
ti_dt_clocks_register(am43xx_clks);
omap2_clk_disable_autoidle_all();
+ /*
+ * cpsw_cpts_rft_clk has got the choice of 3 clocksources
+ * dpll_core_m4_ck, dpll_core_m5_ck and dpll_disp_m2_ck.
+ * By default dpll_core_m4_ck is selected, witn this as clock
+ * source the CPTS doesnot work properly. It gives clockcheck errors
+ * while running PTP.
+ * clockcheck: clock jumped backward or running slower than expected!
+ * By selecting dpll_core_m5_ck as the clocksource fixes this issue.
+ * In AM335x dpll_core_m5_ck is the default clocksource.
+ */
+ clk1 = clk_get_sys(NULL, "cpsw_cpts_rft_clk");
+ clk2 = clk_get_sys(NULL, "dpll_core_m5_ck");
+ clk_set_parent(clk1, clk2);
+
return 0;
}
diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c
index 08f3d1b915b3..5e183993e3ec 100644
--- a/drivers/clk/ti/clk-54xx.c
+++ b/drivers/clk/ti/clk-54xx.c
@@ -240,6 +240,12 @@ int __init omap5xxx_dt_clk_init(void)
if (rc)
pr_err("%s: failed to configure ABE DPLL!\n", __func__);
+ abe_dpll = clk_get_sys(NULL, "dpll_abe_m2x2_ck");
+ if (!rc)
+ rc = clk_set_rate(abe_dpll, OMAP5_DPLL_ABE_DEFFREQ * 2);
+ if (rc)
+ pr_err("%s: failed to configure ABE m2x2 DPLL!\n", __func__);
+
usb_dpll = clk_get_sys(NULL, "dpll_usb_ck");
rc = clk_set_rate(usb_dpll, OMAP5_DPLL_USB_DEFFREQ);
if (rc)
diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c
index f7e40734c819..e1581335937d 100644
--- a/drivers/clk/ti/clk-7xx.c
+++ b/drivers/clk/ti/clk-7xx.c
@@ -24,7 +24,7 @@ static struct ti_dt_clk dra7xx_clks[] = {
DT_CLK(NULL, "atl_clkin0_ck", "atl_clkin0_ck"),
DT_CLK(NULL, "atl_clkin1_ck", "atl_clkin1_ck"),
DT_CLK(NULL, "atl_clkin2_ck", "atl_clkin2_ck"),
- DT_CLK(NULL, "atlclkin3_ck", "atlclkin3_ck"),
+ DT_CLK(NULL, "atl_clkin3_ck", "atl_clkin3_ck"),
DT_CLK(NULL, "hdmi_clkin_ck", "hdmi_clkin_ck"),
DT_CLK(NULL, "mlb_clkin_ck", "mlb_clkin_ck"),
DT_CLK(NULL, "mlbp_clkin_ck", "mlbp_clkin_ck"),
diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c
new file mode 100644
index 000000000000..4a65b410e4d5
--- /dev/null
+++ b/drivers/clk/ti/clk-dra7-atl.c
@@ -0,0 +1,312 @@
+/*
+ * DRA7 ATL (Audio Tracking Logic) clock driver
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#define DRA7_ATL_INSTANCES 4
+
+#define DRA7_ATL_PPMR_REG(id) (0x200 + (id * 0x80))
+#define DRA7_ATL_BBSR_REG(id) (0x204 + (id * 0x80))
+#define DRA7_ATL_ATLCR_REG(id) (0x208 + (id * 0x80))
+#define DRA7_ATL_SWEN_REG(id) (0x210 + (id * 0x80))
+#define DRA7_ATL_BWSMUX_REG(id) (0x214 + (id * 0x80))
+#define DRA7_ATL_AWSMUX_REG(id) (0x218 + (id * 0x80))
+#define DRA7_ATL_PCLKMUX_REG(id) (0x21c + (id * 0x80))
+
+#define DRA7_ATL_SWEN BIT(0)
+#define DRA7_ATL_DIVIDER_MASK (0x1f)
+#define DRA7_ATL_PCLKMUX BIT(0)
+struct dra7_atl_clock_info;
+
+struct dra7_atl_desc {
+ struct clk *clk;
+ struct clk_hw hw;
+ struct dra7_atl_clock_info *cinfo;
+ int id;
+
+ bool probed; /* the driver for the IP has been loaded */
+ bool valid; /* configured */
+ bool enabled;
+ u32 bws; /* Baseband Word Select Mux */
+ u32 aws; /* Audio Word Select Mux */
+ u32 divider; /* Cached divider value */
+};
+
+struct dra7_atl_clock_info {
+ struct device *dev;
+ void __iomem *iobase;
+
+ struct dra7_atl_desc *cdesc;
+};
+
+#define to_atl_desc(_hw) container_of(_hw, struct dra7_atl_desc, hw)
+
+static inline void atl_write(struct dra7_atl_clock_info *cinfo, u32 reg,
+ u32 val)
+{
+ __raw_writel(val, cinfo->iobase + reg);
+}
+
+static inline int atl_read(struct dra7_atl_clock_info *cinfo, u32 reg)
+{
+ return __raw_readl(cinfo->iobase + reg);
+}
+
+static int atl_clk_enable(struct clk_hw *hw)
+{
+ struct dra7_atl_desc *cdesc = to_atl_desc(hw);
+
+ if (!cdesc->probed)
+ goto out;
+
+ if (unlikely(!cdesc->valid))
+ dev_warn(cdesc->cinfo->dev, "atl%d has not been configured\n",
+ cdesc->id);
+ pm_runtime_get_sync(cdesc->cinfo->dev);
+
+ atl_write(cdesc->cinfo, DRA7_ATL_ATLCR_REG(cdesc->id),
+ cdesc->divider - 1);
+ atl_write(cdesc->cinfo, DRA7_ATL_SWEN_REG(cdesc->id), DRA7_ATL_SWEN);
+
+out:
+ cdesc->enabled = true;
+
+ return 0;
+}
+
+static void atl_clk_disable(struct clk_hw *hw)
+{
+ struct dra7_atl_desc *cdesc = to_atl_desc(hw);
+
+ if (!cdesc->probed)
+ goto out;
+
+ atl_write(cdesc->cinfo, DRA7_ATL_SWEN_REG(cdesc->id), 0);
+ pm_runtime_put_sync(cdesc->cinfo->dev);
+
+out:
+ cdesc->enabled = false;
+}
+
+static int atl_clk_is_enabled(struct clk_hw *hw)
+{
+ struct dra7_atl_desc *cdesc = to_atl_desc(hw);
+
+ return cdesc->enabled;
+}
+
+static unsigned long atl_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct dra7_atl_desc *cdesc = to_atl_desc(hw);
+
+ return parent_rate / cdesc->divider;
+}
+
+static long atl_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ unsigned divider;
+
+ divider = (*parent_rate + rate / 2) / rate;
+ if (divider > DRA7_ATL_DIVIDER_MASK + 1)
+ divider = DRA7_ATL_DIVIDER_MASK + 1;
+
+ return *parent_rate / divider;
+}
+
+static int atl_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct dra7_atl_desc *cdesc = to_atl_desc(hw);
+ u32 divider;
+
+ divider = ((parent_rate + rate / 2) / rate) - 1;
+ if (divider > DRA7_ATL_DIVIDER_MASK)
+ divider = DRA7_ATL_DIVIDER_MASK;
+
+ cdesc->divider = divider + 1;
+
+ return 0;
+}
+
+const struct clk_ops atl_clk_ops = {
+ .enable = atl_clk_enable,
+ .disable = atl_clk_disable,
+ .is_enabled = atl_clk_is_enabled,
+ .recalc_rate = atl_clk_recalc_rate,
+ .round_rate = atl_clk_round_rate,
+ .set_rate = atl_clk_set_rate,
+};
+
+static void __init of_dra7_atl_clock_setup(struct device_node *node)
+{
+ struct dra7_atl_desc *clk_hw = NULL;
+ struct clk_init_data init = { 0 };
+ const char **parent_names = NULL;
+ struct clk *clk;
+
+ clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
+ if (!clk_hw) {
+ pr_err("%s: could not allocate dra7_atl_desc\n", __func__);
+ return;
+ }
+
+ clk_hw->hw.init = &init;
+ clk_hw->divider = 1;
+ init.name = node->name;
+ init.ops = &atl_clk_ops;
+ init.flags = CLK_IGNORE_UNUSED;
+ init.num_parents = of_clk_get_parent_count(node);
+
+ if (init.num_parents != 1) {
+ pr_err("%s: atl clock %s must have 1 parent\n", __func__,
+ node->name);
+ goto cleanup;
+ }
+
+ parent_names = kzalloc(sizeof(char *), GFP_KERNEL);
+
+ if (!parent_names)
+ goto cleanup;
+
+ parent_names[0] = of_clk_get_parent_name(node, 0);
+
+ init.parent_names = parent_names;
+
+ clk = clk_register(NULL, &clk_hw->hw);
+
+ if (!IS_ERR(clk)) {
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ return;
+ }
+cleanup:
+ kfree(parent_names);
+ kfree(clk_hw);
+}
+CLK_OF_DECLARE(dra7_atl_clock, "ti,dra7-atl-clock", of_dra7_atl_clock_setup);
+
+static int of_dra7_atl_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct dra7_atl_clock_info *cinfo;
+ int i;
+ int ret = 0;
+
+ if (!node)
+ return -ENODEV;
+
+ cinfo = devm_kzalloc(&pdev->dev, sizeof(*cinfo), GFP_KERNEL);
+ if (!cinfo)
+ return -ENOMEM;
+
+ cinfo->iobase = of_iomap(node, 0);
+ cinfo->dev = &pdev->dev;
+ pm_runtime_enable(cinfo->dev);
+
+ pm_runtime_get_sync(cinfo->dev);
+ atl_write(cinfo, DRA7_ATL_PCLKMUX_REG(0), DRA7_ATL_PCLKMUX);
+
+ for (i = 0; i < DRA7_ATL_INSTANCES; i++) {
+ struct device_node *cfg_node;
+ char prop[5];
+ struct dra7_atl_desc *cdesc;
+ struct of_phandle_args clkspec;
+ struct clk *clk;
+ int rc;
+
+ rc = of_parse_phandle_with_args(node, "ti,provided-clocks",
+ NULL, i, &clkspec);
+
+ if (rc) {
+ pr_err("%s: failed to lookup atl clock %d\n", __func__,
+ i);
+ return -EINVAL;
+ }
+
+ clk = of_clk_get_from_provider(&clkspec);
+
+ cdesc = to_atl_desc(__clk_get_hw(clk));
+ cdesc->cinfo = cinfo;
+ cdesc->id = i;
+
+ /* Get configuration for the ATL instances */
+ snprintf(prop, sizeof(prop), "atl%u", i);
+ cfg_node = of_find_node_by_name(node, prop);
+ if (cfg_node) {
+ ret = of_property_read_u32(cfg_node, "bws",
+ &cdesc->bws);
+ ret |= of_property_read_u32(cfg_node, "aws",
+ &cdesc->aws);
+ if (!ret) {
+ cdesc->valid = true;
+ atl_write(cinfo, DRA7_ATL_BWSMUX_REG(i),
+ cdesc->bws);
+ atl_write(cinfo, DRA7_ATL_AWSMUX_REG(i),
+ cdesc->aws);
+ }
+ }
+
+ cdesc->probed = true;
+ /*
+ * Enable the clock if it has been asked prior to loading the
+ * hw driver
+ */
+ if (cdesc->enabled)
+ atl_clk_enable(__clk_get_hw(clk));
+ }
+ pm_runtime_put_sync(cinfo->dev);
+
+ return ret;
+}
+
+static int of_dra7_atl_clk_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static struct of_device_id of_dra7_atl_clk_match_tbl[] = {
+ { .compatible = "ti,dra7-atl", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_dra7_atl_clk_match_tbl);
+
+static struct platform_driver dra7_atl_clk_driver = {
+ .driver = {
+ .name = "dra7-atl",
+ .owner = THIS_MODULE,
+ .of_match_table = of_dra7_atl_clk_match_tbl,
+ },
+ .probe = of_dra7_atl_clk_probe,
+ .remove = of_dra7_atl_clk_remove,
+};
+
+module_platform_driver(dra7_atl_clk_driver);
+
+MODULE_DESCRIPTION("Clock driver for DRA7 Audio Tracking Logic");
+MODULE_ALIAS("platform:dra7-atl-clock");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c
index 7e498a44f97d..79791e1bf282 100644
--- a/drivers/clk/ti/dpll.c
+++ b/drivers/clk/ti/dpll.c
@@ -25,8 +25,6 @@
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
-#define DPLL_HAS_AUTOIDLE 0x1
-
#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
defined(CONFIG_SOC_DRA7XX)
static const struct clk_ops dpll_m4xen_ck_ops = {
@@ -37,21 +35,18 @@ static const struct clk_ops dpll_m4xen_ck_ops = {
.set_rate = &omap3_noncore_dpll_set_rate,
.get_parent = &omap2_init_dpll_parent,
};
+#else
+static const struct clk_ops dpll_m4xen_ck_ops = {};
#endif
+#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) || \
+ defined(CONFIG_SOC_OMAP5) || defined(CONFIG_SOC_DRA7XX) || \
+ defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
static const struct clk_ops dpll_core_ck_ops = {
.recalc_rate = &omap3_dpll_recalc,
.get_parent = &omap2_init_dpll_parent,
};
-#ifdef CONFIG_ARCH_OMAP3
-static const struct clk_ops omap3_dpll_core_ck_ops = {
- .get_parent = &omap2_init_dpll_parent,
- .recalc_rate = &omap3_dpll_recalc,
- .round_rate = &omap2_dpll_round_rate,
-};
-#endif
-
static const struct clk_ops dpll_ck_ops = {
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
@@ -67,6 +62,33 @@ static const struct clk_ops dpll_no_gate_ck_ops = {
.round_rate = &omap2_dpll_round_rate,
.set_rate = &omap3_noncore_dpll_set_rate,
};
+#else
+static const struct clk_ops dpll_core_ck_ops = {};
+static const struct clk_ops dpll_ck_ops = {};
+static const struct clk_ops dpll_no_gate_ck_ops = {};
+const struct clk_hw_omap_ops clkhwops_omap3_dpll = {};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2
+static const struct clk_ops omap2_dpll_core_ck_ops = {
+ .get_parent = &omap2_init_dpll_parent,
+ .recalc_rate = &omap2_dpllcore_recalc,
+ .round_rate = &omap2_dpll_round_rate,
+ .set_rate = &omap2_reprogram_dpllcore,
+};
+#else
+static const struct clk_ops omap2_dpll_core_ck_ops = {};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static const struct clk_ops omap3_dpll_core_ck_ops = {
+ .get_parent = &omap2_init_dpll_parent,
+ .recalc_rate = &omap3_dpll_recalc,
+ .round_rate = &omap2_dpll_round_rate,
+};
+#else
+static const struct clk_ops omap3_dpll_core_ck_ops = {};
+#endif
#ifdef CONFIG_ARCH_OMAP3
static const struct clk_ops omap3_dpll_ck_ops = {
@@ -139,7 +161,8 @@ cleanup:
}
#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
- defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX)
+ defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX) || \
+ defined(CONFIG_SOC_AM43XX)
/**
* ti_clk_register_dpll_x2 - Registers a DPLLx2 clock
* @node: device node for this clock
@@ -193,14 +216,12 @@ static void ti_clk_register_dpll_x2(struct device_node *node,
* @node: device node containing the DPLL info
* @ops: ops for the DPLL
* @ddt: DPLL data template to use
- * @init_flags: flags for controlling init types
*
* Initializes a DPLL clock from device tree data.
*/
static void __init of_ti_dpll_setup(struct device_node *node,
const struct clk_ops *ops,
- const struct dpll_data *ddt,
- u8 init_flags)
+ const struct dpll_data *ddt)
{
struct clk_hw_omap *clk_hw = NULL;
struct clk_init_data *init = NULL;
@@ -241,13 +262,30 @@ static void __init of_ti_dpll_setup(struct device_node *node,
init->parent_names = parent_names;
dd->control_reg = ti_clk_get_reg_addr(node, 0);
- dd->idlest_reg = ti_clk_get_reg_addr(node, 1);
- dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2);
- if (!dd->control_reg || !dd->idlest_reg || !dd->mult_div1_reg)
+ /*
+ * Special case for OMAP2 DPLL, register order is different due to
+ * missing idlest_reg, also clkhwops is different. Detected from
+ * missing idlest_mask.
+ */
+ if (!dd->idlest_mask) {
+ dd->mult_div1_reg = ti_clk_get_reg_addr(node, 1);
+#ifdef CONFIG_ARCH_OMAP2
+ clk_hw->ops = &clkhwops_omap2xxx_dpll;
+ omap2xxx_clkt_dpllcore_init(&clk_hw->hw);
+#endif
+ } else {
+ dd->idlest_reg = ti_clk_get_reg_addr(node, 1);
+ if (!dd->idlest_reg)
+ goto cleanup;
+
+ dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2);
+ }
+
+ if (!dd->control_reg || !dd->mult_div1_reg)
goto cleanup;
- if (init_flags & DPLL_HAS_AUTOIDLE) {
+ if (dd->autoidle_mask) {
dd->autoidle_reg = ti_clk_get_reg_addr(node, 3);
if (!dd->autoidle_reg)
goto cleanup;
@@ -285,7 +323,7 @@ CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock",
of_ti_omap4_dpll_x2_setup);
#endif
-#ifdef CONFIG_SOC_AM33XX
+#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
static void __init of_ti_am3_dpll_x2_setup(struct device_node *node)
{
ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, NULL);
@@ -310,7 +348,7 @@ static void __init of_ti_omap3_dpll_setup(struct device_node *node)
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
};
- of_ti_dpll_setup(node, &omap3_dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+ of_ti_dpll_setup(node, &omap3_dpll_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_omap3_dpll_clock, "ti,omap3-dpll-clock",
of_ti_omap3_dpll_setup);
@@ -329,7 +367,7 @@ static void __init of_ti_omap3_core_dpll_setup(struct device_node *node)
.freqsel_mask = 0xf0,
};
- of_ti_dpll_setup(node, &omap3_dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+ of_ti_dpll_setup(node, &omap3_dpll_core_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_omap3_core_dpll_clock, "ti,omap3-dpll-core-clock",
of_ti_omap3_core_dpll_setup);
@@ -349,7 +387,7 @@ static void __init of_ti_omap3_per_dpll_setup(struct device_node *node)
.modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED),
};
- of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+ of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_omap3_per_dpll_clock, "ti,omap3-dpll-per-clock",
of_ti_omap3_per_dpll_setup);
@@ -371,7 +409,7 @@ static void __init of_ti_omap3_per_jtype_dpll_setup(struct device_node *node)
.modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED),
};
- of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+ of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_omap3_per_jtype_dpll_clock, "ti,omap3-dpll-per-j-type-clock",
of_ti_omap3_per_jtype_dpll_setup);
@@ -391,11 +429,32 @@ static void __init of_ti_omap4_dpll_setup(struct device_node *node)
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
};
- of_ti_dpll_setup(node, &dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+ of_ti_dpll_setup(node, &dpll_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_omap4_dpll_clock, "ti,omap4-dpll-clock",
of_ti_omap4_dpll_setup);
+static void __init of_ti_omap5_mpu_dpll_setup(struct device_node *node)
+{
+ const struct dpll_data dd = {
+ .idlest_mask = 0x1,
+ .enable_mask = 0x7,
+ .autoidle_mask = 0x7,
+ .mult_mask = 0x7ff << 8,
+ .div1_mask = 0x7f,
+ .max_multiplier = 2047,
+ .max_divider = 128,
+ .dcc_mask = BIT(22),
+ .dcc_rate = 1400000000, /* DCC beyond 1.4GHz */
+ .min_divider = 1,
+ .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
+ };
+
+ of_ti_dpll_setup(node, &dpll_ck_ops, &dd);
+}
+CLK_OF_DECLARE(of_ti_omap5_mpu_dpll_clock, "ti,omap5-mpu-dpll-clock",
+ of_ti_omap5_mpu_dpll_setup);
+
static void __init of_ti_omap4_core_dpll_setup(struct device_node *node)
{
const struct dpll_data dd = {
@@ -410,7 +469,7 @@ static void __init of_ti_omap4_core_dpll_setup(struct device_node *node)
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
};
- of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+ of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_omap4_core_dpll_clock, "ti,omap4-dpll-core-clock",
of_ti_omap4_core_dpll_setup);
@@ -433,7 +492,7 @@ static void __init of_ti_omap4_m4xen_dpll_setup(struct device_node *node)
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
};
- of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+ of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_omap4_m4xen_dpll_clock, "ti,omap4-dpll-m4xen-clock",
of_ti_omap4_m4xen_dpll_setup);
@@ -454,7 +513,7 @@ static void __init of_ti_omap4_jtype_dpll_setup(struct device_node *node)
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
};
- of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+ of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_omap4_jtype_dpll_clock, "ti,omap4-dpll-j-type-clock",
of_ti_omap4_jtype_dpll_setup);
@@ -465,7 +524,6 @@ static void __init of_ti_am3_no_gate_dpll_setup(struct device_node *node)
const struct dpll_data dd = {
.idlest_mask = 0x1,
.enable_mask = 0x7,
- .autoidle_mask = 0x7,
.mult_mask = 0x7ff << 8,
.div1_mask = 0x7f,
.max_multiplier = 2047,
@@ -474,7 +532,7 @@ static void __init of_ti_am3_no_gate_dpll_setup(struct device_node *node)
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
};
- of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0);
+ of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_am3_no_gate_dpll_clock, "ti,am3-dpll-no-gate-clock",
of_ti_am3_no_gate_dpll_setup);
@@ -484,7 +542,6 @@ static void __init of_ti_am3_jtype_dpll_setup(struct device_node *node)
const struct dpll_data dd = {
.idlest_mask = 0x1,
.enable_mask = 0x7,
- .autoidle_mask = 0x7,
.mult_mask = 0x7ff << 8,
.div1_mask = 0x7f,
.max_multiplier = 4095,
@@ -494,7 +551,7 @@ static void __init of_ti_am3_jtype_dpll_setup(struct device_node *node)
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
};
- of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0);
+ of_ti_dpll_setup(node, &dpll_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_am3_jtype_dpll_clock, "ti,am3-dpll-j-type-clock",
of_ti_am3_jtype_dpll_setup);
@@ -504,7 +561,6 @@ static void __init of_ti_am3_no_gate_jtype_dpll_setup(struct device_node *node)
const struct dpll_data dd = {
.idlest_mask = 0x1,
.enable_mask = 0x7,
- .autoidle_mask = 0x7,
.mult_mask = 0x7ff << 8,
.div1_mask = 0x7f,
.max_multiplier = 2047,
@@ -514,7 +570,7 @@ static void __init of_ti_am3_no_gate_jtype_dpll_setup(struct device_node *node)
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
};
- of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0);
+ of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_am3_no_gate_jtype_dpll_clock,
"ti,am3-dpll-no-gate-j-type-clock",
@@ -525,7 +581,6 @@ static void __init of_ti_am3_dpll_setup(struct device_node *node)
const struct dpll_data dd = {
.idlest_mask = 0x1,
.enable_mask = 0x7,
- .autoidle_mask = 0x7,
.mult_mask = 0x7ff << 8,
.div1_mask = 0x7f,
.max_multiplier = 2047,
@@ -534,7 +589,7 @@ static void __init of_ti_am3_dpll_setup(struct device_node *node)
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
};
- of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0);
+ of_ti_dpll_setup(node, &dpll_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_am3_dpll_clock, "ti,am3-dpll-clock", of_ti_am3_dpll_setup);
@@ -543,7 +598,6 @@ static void __init of_ti_am3_core_dpll_setup(struct device_node *node)
const struct dpll_data dd = {
.idlest_mask = 0x1,
.enable_mask = 0x7,
- .autoidle_mask = 0x7,
.mult_mask = 0x7ff << 8,
.div1_mask = 0x7f,
.max_multiplier = 2047,
@@ -552,7 +606,22 @@ static void __init of_ti_am3_core_dpll_setup(struct device_node *node)
.modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
};
- of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, 0);
+ of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd);
}
CLK_OF_DECLARE(ti_am3_core_dpll_clock, "ti,am3-dpll-core-clock",
of_ti_am3_core_dpll_setup);
+
+static void __init of_ti_omap2_core_dpll_setup(struct device_node *node)
+{
+ const struct dpll_data dd = {
+ .enable_mask = 0x3,
+ .mult_mask = 0x3ff << 12,
+ .div1_mask = 0xf << 8,
+ .max_divider = 16,
+ .min_divider = 1,
+ };
+
+ of_ti_dpll_setup(node, &omap2_dpll_core_ck_ops, &dd);
+}
+CLK_OF_DECLARE(ti_omap2_core_dpll_clock, "ti,omap2-dpll-core-clock",
+ of_ti_omap2_core_dpll_setup);
diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c
index 3e2999d11d15..b326d2797feb 100644
--- a/drivers/clk/ti/gate.c
+++ b/drivers/clk/ti/gate.c
@@ -185,7 +185,7 @@ of_ti_composite_no_wait_gate_clk_setup(struct device_node *node)
CLK_OF_DECLARE(ti_composite_no_wait_gate_clk, "ti,composite-no-wait-gate-clock",
of_ti_composite_no_wait_gate_clk_setup);
-#ifdef CONFIG_ARCH_OMAP3
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
static void __init of_ti_composite_interface_clk_setup(struct device_node *node)
{
_of_ti_composite_gate_clk_setup(node, &clkhwops_iclk_wait);
@@ -221,7 +221,7 @@ static void __init of_ti_gate_clk_setup(struct device_node *node)
{
_of_ti_gate_clk_setup(node, &omap_gate_clk_ops, NULL);
}
-CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup)
+CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup);
static void __init of_ti_wait_gate_clk_setup(struct device_node *node)
{
diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c
index 320a2b168bb2..9c3e8c4aaa40 100644
--- a/drivers/clk/ti/interface.c
+++ b/drivers/clk/ti/interface.c
@@ -94,6 +94,7 @@ static void __init of_ti_no_wait_interface_clk_setup(struct device_node *node)
CLK_OF_DECLARE(ti_no_wait_interface_clk, "ti,omap3-no-wait-interface-clock",
of_ti_no_wait_interface_clk_setup);
+#ifdef CONFIG_ARCH_OMAP3
static void __init of_ti_hsotgusb_interface_clk_setup(struct device_node *node)
{
_of_ti_interface_clk_setup(node,
@@ -123,3 +124,13 @@ static void __init of_ti_am35xx_interface_clk_setup(struct device_node *node)
}
CLK_OF_DECLARE(ti_am35xx_interface_clk, "ti,am35xx-interface-clock",
of_ti_am35xx_interface_clk_setup);
+#endif
+
+#ifdef CONFIG_SOC_OMAP2430
+static void __init of_ti_omap2430_interface_clk_setup(struct device_node *node)
+{
+ _of_ti_interface_clk_setup(node, &clkhwops_omap2430_i2chs_wait);
+}
+CLK_OF_DECLARE(ti_omap2430_interface_clk, "ti,omap2430-interface-clock",
+ of_ti_omap2430_interface_clk_setup);
+#endif
diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c
index 0197a478720c..e9d650e51287 100644
--- a/drivers/clk/ti/mux.c
+++ b/drivers/clk/ti/mux.c
@@ -160,7 +160,7 @@ static void of_mux_clk_setup(struct device_node *node)
u8 clk_mux_flags = 0;
u32 mask = 0;
u32 shift = 0;
- u32 flags = 0;
+ u32 flags = CLK_SET_RATE_NO_REPARENT;
num_parents = of_clk_get_parent_count(node);
if (num_parents < 2) {
diff --git a/drivers/clk/versatile/Kconfig b/drivers/clk/versatile/Kconfig
new file mode 100644
index 000000000000..1530c9352a76
--- /dev/null
+++ b/drivers/clk/versatile/Kconfig
@@ -0,0 +1,26 @@
+config COMMON_CLK_VERSATILE
+ bool "Clock driver for ARM Reference designs"
+ depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS || ARM64
+ ---help---
+ Supports clocking on ARM Reference designs:
+ - Integrator/AP and Integrator/CP
+ - RealView PB1176, EB, PB11MP and PBX
+ - Versatile Express
+
+config CLK_SP810
+ bool "Clock driver for ARM SP810 System Controller"
+ depends on COMMON_CLK_VERSATILE
+ default y if ARCH_VEXPRESS
+ ---help---
+ Supports clock muxing (REFCLK/TIMCLK to TIMERCLKEN0-3) capabilities
+ of the ARM SP810 System Controller cell.
+
+config CLK_VEXPRESS_OSC
+ bool "Clock driver for Versatile Express OSC clock generators"
+ depends on COMMON_CLK_VERSATILE
+ depends on VEXPRESS_CONFIG
+ default y if ARCH_VEXPRESS
+ ---help---
+ Simple regmap-based driver driving clock generators on Versatile
+ Express platforms hidden behind its configuration infrastructure,
+ commonly known as OSCs.
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile
index c16ca787170a..fd449f9b006d 100644
--- a/drivers/clk/versatile/Makefile
+++ b/drivers/clk/versatile/Makefile
@@ -3,5 +3,6 @@ obj-$(CONFIG_ICST) += clk-icst.o
obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o
obj-$(CONFIG_INTEGRATOR_IMPD1) += clk-impd1.o
obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o
-obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o clk-sp810.o
-obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o
+obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o
+obj-$(CONFIG_CLK_SP810) += clk-sp810.o
+obj-$(CONFIG_CLK_VEXPRESS_OSC) += clk-vexpress-osc.o
diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c
index a820b0cfcf57..bc96f103bd7c 100644
--- a/drivers/clk/versatile/clk-icst.c
+++ b/drivers/clk/versatile/clk-icst.c
@@ -140,6 +140,7 @@ struct clk *icst_clk_register(struct device *dev,
pclone = kmemdup(desc->params, sizeof(*pclone), GFP_KERNEL);
if (!pclone) {
+ kfree(icst);
pr_err("could not clone ICST params\n");
return ERR_PTR(-ENOMEM);
}
@@ -160,3 +161,4 @@ struct clk *icst_clk_register(struct device *dev,
return clk;
}
+EXPORT_SYMBOL_GPL(icst_clk_register);
diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c
index 31b44f025f9e..1cc1330dc570 100644
--- a/drivers/clk/versatile/clk-impd1.c
+++ b/drivers/clk/versatile/clk-impd1.c
@@ -20,6 +20,8 @@
#define IMPD1_LOCK 0x08
struct impd1_clk {
+ char *pclkname;
+ struct clk *pclk;
char *vco1name;
struct clk *vco1clk;
char *vco2name;
@@ -31,7 +33,7 @@ struct impd1_clk {
struct clk *spiclk;
char *scname;
struct clk *scclk;
- struct clk_lookup *clks[6];
+ struct clk_lookup *clks[15];
};
/* One entry for each connected IM-PD1 LM */
@@ -86,6 +88,7 @@ void integrator_impd1_clk_init(void __iomem *base, unsigned int id)
{
struct impd1_clk *imc;
struct clk *clk;
+ struct clk *pclk;
int i;
if (id > 3) {
@@ -94,11 +97,18 @@ void integrator_impd1_clk_init(void __iomem *base, unsigned int id)
}
imc = &impd1_clks[id];
+ /* Register the fixed rate PCLK */
+ imc->pclkname = kasprintf(GFP_KERNEL, "lm%x-pclk", id);
+ pclk = clk_register_fixed_rate(NULL, imc->pclkname, NULL,
+ CLK_IS_ROOT, 0);
+ imc->pclk = pclk;
+
imc->vco1name = kasprintf(GFP_KERNEL, "lm%x-vco1", id);
clk = icst_clk_register(NULL, &impd1_icst1_desc, imc->vco1name, NULL,
base);
imc->vco1clk = clk;
- imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id);
+ imc->clks[0] = clkdev_alloc(pclk, "apb_pclk", "lm%x:01000", id);
+ imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:01000", id);
/* VCO2 is also called "CLK2" */
imc->vco2name = kasprintf(GFP_KERNEL, "lm%x-vco2", id);
@@ -107,32 +117,43 @@ void integrator_impd1_clk_init(void __iomem *base, unsigned int id)
imc->vco2clk = clk;
/* MMCI uses CLK2 right off */
- imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:00700", id);
+ imc->clks[2] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00700", id);
+ imc->clks[3] = clkdev_alloc(clk, NULL, "lm%x:00700", id);
/* UART reference clock divides CLK2 by a fixed factor 4 */
imc->uartname = kasprintf(GFP_KERNEL, "lm%x-uartclk", id);
clk = clk_register_fixed_factor(NULL, imc->uartname, imc->vco2name,
CLK_IGNORE_UNUSED, 1, 4);
imc->uartclk = clk;
- imc->clks[2] = clkdev_alloc(clk, NULL, "lm%x:00100", id);
- imc->clks[3] = clkdev_alloc(clk, NULL, "lm%x:00200", id);
+ imc->clks[4] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00100", id);
+ imc->clks[5] = clkdev_alloc(clk, NULL, "lm%x:00100", id);
+ imc->clks[6] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00200", id);
+ imc->clks[7] = clkdev_alloc(clk, NULL, "lm%x:00200", id);
/* SPI PL022 clock divides CLK2 by a fixed factor 64 */
imc->spiname = kasprintf(GFP_KERNEL, "lm%x-spiclk", id);
clk = clk_register_fixed_factor(NULL, imc->spiname, imc->vco2name,
CLK_IGNORE_UNUSED, 1, 64);
- imc->clks[4] = clkdev_alloc(clk, NULL, "lm%x:00300", id);
+ imc->clks[8] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00300", id);
+ imc->clks[9] = clkdev_alloc(clk, NULL, "lm%x:00300", id);
+
+ /* The GPIO blocks and AACI have only PCLK */
+ imc->clks[10] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00400", id);
+ imc->clks[11] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00500", id);
+ imc->clks[12] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00800", id);
/* Smart Card clock divides CLK2 by a fixed factor 4 */
imc->scname = kasprintf(GFP_KERNEL, "lm%x-scclk", id);
clk = clk_register_fixed_factor(NULL, imc->scname, imc->vco2name,
CLK_IGNORE_UNUSED, 1, 4);
imc->scclk = clk;
- imc->clks[5] = clkdev_alloc(clk, NULL, "lm%x:00600", id);
+ imc->clks[13] = clkdev_alloc(pclk, "apb_pclk", "lm%x:00600", id);
+ imc->clks[14] = clkdev_alloc(clk, NULL, "lm%x:00600", id);
for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
clkdev_add(imc->clks[i]);
}
+EXPORT_SYMBOL_GPL(integrator_impd1_clk_init);
void integrator_impd1_clk_exit(unsigned int id)
{
@@ -149,9 +170,12 @@ void integrator_impd1_clk_exit(unsigned int id)
clk_unregister(imc->uartclk);
clk_unregister(imc->vco2clk);
clk_unregister(imc->vco1clk);
+ clk_unregister(imc->pclk);
kfree(imc->scname);
kfree(imc->spiname);
kfree(imc->uartname);
kfree(imc->vco2name);
kfree(imc->vco1name);
+ kfree(imc->pclkname);
}
+EXPORT_SYMBOL_GPL(integrator_impd1_clk_exit);
diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c
index 422391242b39..529a59c0fbfa 100644
--- a/drivers/clk/versatile/clk-vexpress-osc.c
+++ b/drivers/clk/versatile/clk-vexpress-osc.c
@@ -11,8 +11,6 @@
* Copyright (C) 2012 ARM Limited
*/
-#define pr_fmt(fmt) "vexpress-osc: " fmt
-
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
@@ -22,7 +20,7 @@
#include <linux/vexpress.h>
struct vexpress_osc {
- struct vexpress_config_func *func;
+ struct regmap *reg;
struct clk_hw hw;
unsigned long rate_min;
unsigned long rate_max;
@@ -36,7 +34,7 @@ static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw,
struct vexpress_osc *osc = to_vexpress_osc(hw);
u32 rate;
- vexpress_config_read(osc->func, 0, &rate);
+ regmap_read(osc->reg, 0, &rate);
return rate;
}
@@ -60,7 +58,7 @@ static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct vexpress_osc *osc = to_vexpress_osc(hw);
- return vexpress_config_write(osc->func, 0, rate);
+ return regmap_write(osc->reg, 0, rate);
}
static struct clk_ops vexpress_osc_ops = {
@@ -70,58 +68,31 @@ static struct clk_ops vexpress_osc_ops = {
};
-struct clk * __init vexpress_osc_setup(struct device *dev)
-{
- struct clk_init_data init;
- struct vexpress_osc *osc = kzalloc(sizeof(*osc), GFP_KERNEL);
-
- if (!osc)
- return NULL;
-
- osc->func = vexpress_config_func_get_by_dev(dev);
- if (!osc->func) {
- kfree(osc);
- return NULL;
- }
-
- init.name = dev_name(dev);
- init.ops = &vexpress_osc_ops;
- init.flags = CLK_IS_ROOT;
- init.num_parents = 0;
- osc->hw.init = &init;
-
- return clk_register(NULL, &osc->hw);
-}
-
-void __init vexpress_osc_of_setup(struct device_node *node)
+static int vexpress_osc_probe(struct platform_device *pdev)
{
+ struct clk_lookup *cl = pdev->dev.platform_data; /* Non-DT lookup */
struct clk_init_data init;
struct vexpress_osc *osc;
struct clk *clk;
u32 range[2];
- vexpress_sysreg_of_early_init();
-
- osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+ osc = devm_kzalloc(&pdev->dev, sizeof(*osc), GFP_KERNEL);
if (!osc)
- return;
+ return -ENOMEM;
- osc->func = vexpress_config_func_get_by_node(node);
- if (!osc->func) {
- pr_err("Failed to obtain config func for node '%s'!\n",
- node->full_name);
- goto error;
- }
+ osc->reg = devm_regmap_init_vexpress_config(&pdev->dev);
+ if (IS_ERR(osc->reg))
+ return PTR_ERR(osc->reg);
- if (of_property_read_u32_array(node, "freq-range", range,
+ if (of_property_read_u32_array(pdev->dev.of_node, "freq-range", range,
ARRAY_SIZE(range)) == 0) {
osc->rate_min = range[0];
osc->rate_max = range[1];
}
- of_property_read_string(node, "clock-output-names", &init.name);
- if (!init.name)
- init.name = node->full_name;
+ if (of_property_read_string(pdev->dev.of_node, "clock-output-names",
+ &init.name) != 0)
+ init.name = dev_name(&pdev->dev);
init.ops = &vexpress_osc_ops;
init.flags = CLK_IS_ROOT;
@@ -130,20 +101,37 @@ void __init vexpress_osc_of_setup(struct device_node *node)
osc->hw.init = &init;
clk = clk_register(NULL, &osc->hw);
- if (IS_ERR(clk)) {
- pr_err("Failed to register clock '%s'!\n", init.name);
- goto error;
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, clk);
+
+ /* Only happens for non-DT cases */
+ if (cl) {
+ cl->clk = clk;
+ clkdev_add(cl);
}
- of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ dev_dbg(&pdev->dev, "Registered clock '%s'\n", init.name);
+
+ return 0;
+}
- pr_debug("Registered clock '%s'\n", init.name);
+static struct of_device_id vexpress_osc_of_match[] = {
+ { .compatible = "arm,vexpress-osc", },
+ {}
+};
- return;
+static struct platform_driver vexpress_osc_driver = {
+ .driver = {
+ .name = "vexpress-osc",
+ .of_match_table = vexpress_osc_of_match,
+ },
+ .probe = vexpress_osc_probe,
+};
-error:
- if (osc->func)
- vexpress_config_func_put(osc->func);
- kfree(osc);
+static int __init vexpress_osc_init(void)
+{
+ return platform_driver_register(&vexpress_osc_driver);
}
-CLK_OF_DECLARE(vexpress_soc, "arm,vexpress-osc", vexpress_osc_of_setup);
+core_initcall(vexpress_osc_init);
diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c
index 52c09afdcfb7..246cf1226eaa 100644
--- a/drivers/clk/zynq/clkc.c
+++ b/drivers/clk/zynq/clkc.c
@@ -53,6 +53,9 @@ static void __iomem *zynq_clkc_base;
#define NUM_MIO_PINS 54
+#define DBG_CLK_CTRL_CLKACT_TRC BIT(0)
+#define DBG_CLK_CTRL_CPU_1XCLKACT BIT(1)
+
enum zynq_clk {
armpll, ddrpll, iopll,
cpu_6or4x, cpu_3or2x, cpu_2x, cpu_1x,
@@ -499,6 +502,15 @@ static void __init zynq_clk_setup(struct device_node *np)
clk_output_name[cpu_1x], 0, SLCR_DBG_CLK_CTRL, 1, 0,
&dbgclk_lock);
+ /* leave debug clocks in the state the bootloader set them up to */
+ tmp = clk_readl(SLCR_DBG_CLK_CTRL);
+ if (tmp & DBG_CLK_CTRL_CLKACT_TRC)
+ if (clk_prepare_enable(clks[dbg_trc]))
+ pr_warn("%s: trace clk enable failed\n", __func__);
+ if (tmp & DBG_CLK_CTRL_CPU_1XCLKACT)
+ if (clk_prepare_enable(clks[dbg_apb]))
+ pr_warn("%s: debug APB clk enable failed\n", __func__);
+
/* One gated clock for all APER clocks. */
clks[dma] = clk_register_gate(NULL, clk_output_name[dma],
clk_output_name[cpu_2x], 0, SLCR_APER_CLK_CTRL, 0, 0,