summaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/imx/Makefile20
-rw-r--r--drivers/clk/imx/clk-gate-exclusive.c103
-rw-r--r--drivers/clk/imx/clk-gate2.c145
-rw-r--r--drivers/clk/imx/clk-imx1.c121
-rw-r--r--drivers/clk/imx/clk-imx21.c196
-rw-r--r--drivers/clk/imx/clk-imx25.c200
-rw-r--r--drivers/clk/imx/clk-imx27.c270
-rw-r--r--drivers/clk/imx/clk-imx31.c146
-rw-r--r--drivers/clk/imx/clk-imx35.c219
-rw-r--r--drivers/clk/imx/clk-imx5.c533
-rw-r--r--drivers/clk/imx/clk-imx6.c541
-rw-r--r--drivers/clk/imx/clk-imx6sx.c483
-rw-r--r--drivers/clk/imx/clk-pfd.c148
-rw-r--r--drivers/clk/imx/clk-pllv1.c95
-rw-r--r--drivers/clk/imx/clk-pllv2.c230
-rw-r--r--drivers/clk/imx/clk-pllv3.c326
-rw-r--r--drivers/clk/imx/clk.h104
18 files changed, 3881 insertions, 0 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 0fe8f1e200..a4e4ed0241 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_CLK_SOCFPGA) += socfpga.o
obj-$(CONFIG_MACH_MIPS_ATH79) += clk-ar933x.o
+obj-$(CONFIG_ARCH_IMX) += imx/
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
new file mode 100644
index 0000000000..99dbe7d17c
--- /dev/null
+++ b/drivers/clk/imx/Makefile
@@ -0,0 +1,20 @@
+obj-$(CONFIG_COMMON_CLK) += \
+ clk-pllv1.o \
+ clk-pllv2.o \
+ clk-pllv3.o \
+ clk-pfd.o \
+ clk-gate2.o \
+ clk-gate-exclusive.o
+
+obj-$(CONFIG_ARCH_IMX1) += clk-imx1.o
+obj-$(CONFIG_ARCH_IMX25) += clk-imx25.o
+obj-$(CONFIG_ARCH_IMX21) += clk-imx21.o
+obj-$(CONFIG_ARCH_IMX27) += clk-imx27.o
+obj-$(CONFIG_ARCH_IMX31) += clk-imx31.o
+obj-$(CONFIG_ARCH_IMX35) += clk-imx35.o
+obj-$(CONFIG_ARCH_IMX50) += clk-imx5.o
+obj-$(CONFIG_ARCH_IMX51) += clk-imx5.o
+obj-$(CONFIG_ARCH_IMX53) += clk-imx5.o
+obj-$(CONFIG_ARCH_IMX6) += clk-imx6.o
+obj-$(CONFIG_ARCH_IMX6SX) += clk-imx6sx.o
+obj-$(CONFIG_ARCH_IMX6UL) += clk-imx6ul.o
diff --git a/drivers/clk/imx/clk-gate-exclusive.c b/drivers/clk/imx/clk-gate-exclusive.c
new file mode 100644
index 0000000000..db88db0237
--- /dev/null
+++ b/drivers/clk/imx/clk-gate-exclusive.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * 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 <common.h>
+#include <io.h>
+#include <malloc.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include "clk.h"
+
+/**
+ * struct clk_gate_exclusive - i.MX specific gate clock which is mutually
+ * exclusive with other gate clocks
+ *
+ * @gate: the parent class
+ * @exclusive_mask: mask of gate bits which are mutually exclusive to this
+ * gate clock
+ *
+ * The imx exclusive gate clock is a subclass of basic clk_gate
+ * with an addtional mask to indicate which other gate bits in the same
+ * register is mutually exclusive to this gate clock.
+ */
+struct clk_gate_exclusive {
+ struct clk clk;
+ void __iomem *reg;
+ int shift;
+ const char *parent;
+ u32 exclusive_mask;
+};
+
+static int clk_gate_exclusive_enable(struct clk *clk)
+{
+ struct clk_gate_exclusive *exgate = container_of(clk,
+ struct clk_gate_exclusive, clk);
+ u32 val = readl(exgate->reg);
+
+ if (val & exgate->exclusive_mask)
+ return -EBUSY;
+
+ val |= 1 << exgate->shift;
+
+ writel(val, exgate->reg);
+
+ return 0;
+}
+
+static void clk_gate_exclusive_disable(struct clk *clk)
+{
+ struct clk_gate_exclusive *exgate = container_of(clk,
+ struct clk_gate_exclusive, clk);
+ u32 val = readl(exgate->reg);
+
+ val &= ~(1 << exgate->shift);
+
+ writel(val, exgate->reg);
+}
+
+static int clk_gate_exclusive_is_enabled(struct clk *clk)
+{
+ struct clk_gate_exclusive *exgate = container_of(clk,
+ struct clk_gate_exclusive, clk);
+
+ return readl(exgate->reg) & (1 << exgate->shift);
+}
+
+static const struct clk_ops clk_gate_exclusive_ops = {
+ .enable = clk_gate_exclusive_enable,
+ .disable = clk_gate_exclusive_disable,
+ .is_enabled = clk_gate_exclusive_is_enabled,
+};
+
+struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u32 exclusive_mask)
+{
+ struct clk_gate_exclusive *exgate;
+ int ret;
+
+ exgate = xzalloc(sizeof(*exgate));
+ exgate->parent = parent;
+ exgate->clk.name = name;
+ exgate->clk.ops = &clk_gate_exclusive_ops;
+ exgate->clk.flags = CLK_SET_RATE_PARENT;
+ exgate->clk.parent_names = &exgate->parent;
+ exgate->clk.num_parents = 1;
+
+ exgate->reg = reg;
+ exgate->shift = shift;
+ exgate->exclusive_mask = exclusive_mask;
+
+ ret = clk_register(&exgate->clk);
+ if (ret) {
+ free(exgate);
+ return ERR_PTR(ret);
+ }
+
+ return &exgate->clk;
+}
diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
new file mode 100644
index 0000000000..faed6313fb
--- /dev/null
+++ b/drivers/clk/imx/clk-gate2.c
@@ -0,0 +1,145 @@
+/*
+ * clk-gate2.c - barebox 2-bit clock support. Based on Linux clk support
+ *
+ * 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 <common.h>
+#include <io.h>
+#include <malloc.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include "clk.h"
+
+
+struct clk_gate2 {
+ struct clk clk;
+ void __iomem *reg;
+ int shift;
+ const char *parent;
+#define CLK_GATE_INVERTED (1 << 0)
+ unsigned flags;
+};
+
+#define to_clk_gate2(_clk) container_of(_clk, struct clk_gate2, clk)
+
+static int clk_gate2_enable(struct clk *clk)
+{
+ struct clk_gate2 *g = to_clk_gate2(clk);
+ u32 val;
+
+ val = readl(g->reg);
+
+ if (g->flags & CLK_GATE_INVERTED)
+ val &= ~(3 << g->shift);
+ else
+ val |= 3 << g->shift;
+
+ writel(val, g->reg);
+
+ return 0;
+}
+
+static void clk_gate2_disable(struct clk *clk)
+{
+ struct clk_gate2 *g = to_clk_gate2(clk);
+ u32 val;
+
+ val = readl(g->reg);
+
+ if (g->flags & CLK_GATE_INVERTED)
+ val |= 3 << g->shift;
+ else
+ val &= ~(3 << g->shift);
+
+ writel(val, g->reg);
+}
+
+static int clk_gate2_is_enabled(struct clk *clk)
+{
+ struct clk_gate2 *g = to_clk_gate2(clk);
+ u32 val;
+
+ val = readl(g->reg);
+
+ if (val & (1 << g->shift))
+ return g->flags & CLK_GATE_INVERTED ? 0 : 1;
+ else
+ return g->flags & CLK_GATE_INVERTED ? 1 : 0;
+}
+
+static struct clk_ops clk_gate2_ops = {
+ .set_rate = clk_parent_set_rate,
+ .round_rate = clk_parent_round_rate,
+ .enable = clk_gate2_enable,
+ .disable = clk_gate2_disable,
+ .is_enabled = clk_gate2_is_enabled,
+};
+
+struct clk *clk_gate2_alloc(const char *name, const char *parent,
+ void __iomem *reg, u8 shift)
+{
+ struct clk_gate2 *g = xzalloc(sizeof(*g));
+
+ g->parent = parent;
+ g->reg = reg;
+ g->shift = shift;
+ g->clk.ops = &clk_gate2_ops;
+ g->clk.name = name;
+ g->clk.parent_names = &g->parent;
+ g->clk.num_parents = 1;
+ g->clk.flags = CLK_SET_RATE_PARENT;
+
+ return &g->clk;
+}
+
+void clk_gate2_free(struct clk *clk)
+{
+ struct clk_gate2 *g = to_clk_gate2(clk);
+
+ free(g);
+}
+
+struct clk *clk_gate2(const char *name, const char *parent, void __iomem *reg,
+ u8 shift)
+{
+ struct clk *g;
+ int ret;
+
+ g = clk_gate2_alloc(name , parent, reg, shift);
+
+ ret = clk_register(g);
+ if (ret) {
+ free(to_clk_gate2(g));
+ return ERR_PTR(ret);
+ }
+
+ return g;
+}
+
+struct clk *clk_gate2_inverted(const char *name, const char *parent,
+ void __iomem *reg, u8 shift)
+{
+ struct clk *clk;
+ struct clk_gate2 *g;
+
+ clk = clk_gate2(name, parent, reg, shift);
+ if (IS_ERR(clk))
+ return clk;
+
+ g = to_clk_gate2(clk);
+
+ g->flags = CLK_GATE_INVERTED;
+
+ return clk;
+}
diff --git a/drivers/clk/imx/clk-imx1.c b/drivers/clk/imx/clk-imx1.c
new file mode 100644
index 0000000000..5f600a9da3
--- /dev/null
+++ b/drivers/clk/imx/clk-imx1.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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 in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <mach/imx1-regs.h>
+
+#include "clk.h"
+
+#define CCM_CSCR 0x0
+#define CCM_MPCTL0 0x4
+#define CCM_SPCTL0 0xc
+#define CCM_PCDR 0x20
+
+enum imx1_clks {
+ dummy, clk32, clk16m, clk32_premult, prem, mpll, spll, mcu,
+ fclk, hclk, clk48m, per1, per2, per3, clko, dma_gate, csi_gate,
+ mma_gate, usbd_gate, clk_max
+};
+
+static struct clk *clks[clk_max];
+
+static const char *prem_sel_clks[] = {
+ "clk32_premult",
+ "clk16m",
+};
+
+static const char *clko_sel_clks[] = {
+ "per1",
+ "hclk",
+ "clk48m",
+ "clk16m",
+ "prem",
+ "fclk",
+};
+
+int __init mx1_clocks_init(void __iomem *regs, unsigned long fref)
+{
+ clks[dummy] = clk_fixed("dummy", 0);
+ clks[clk32] = clk_fixed("clk32", fref);
+ clks[clk16m] = clk_fixed("clk16m", 16000000);
+ clks[clk32_premult] = imx_clk_fixed_factor("clk32_premult", "clk32", 512, 1);
+ clks[prem] = imx_clk_mux("prem", regs + CCM_CSCR, 16, 1, prem_sel_clks,
+ ARRAY_SIZE(prem_sel_clks));
+ clks[mpll] = imx_clk_pllv1("mpll", "clk32_premult", regs + CCM_MPCTL0);
+ clks[spll] = imx_clk_pllv1("spll", "prem", regs + CCM_SPCTL0);
+ clks[mcu] = imx_clk_divider("mcu", "clk32_premult", regs + CCM_CSCR, 15, 1);
+ clks[fclk] = imx_clk_divider("fclk", "mpll", regs + CCM_CSCR, 15, 1);
+ clks[hclk] = imx_clk_divider("hclk", "spll", regs + CCM_CSCR, 10, 4);
+ clks[clk48m] = imx_clk_divider("clk48m", "spll", regs + CCM_CSCR, 26, 3);
+ clks[per1] = imx_clk_divider("per1", "spll", regs + CCM_PCDR, 0, 4);
+ clks[per2] = imx_clk_divider("per2", "spll", regs + CCM_PCDR, 4, 4);
+ clks[per3] = imx_clk_divider("per3", "spll", regs + CCM_PCDR, 16, 7);
+ clks[clko] = imx_clk_mux("clko", regs + CCM_CSCR, 29, 3, clko_sel_clks,
+ ARRAY_SIZE(clko_sel_clks));
+
+ clkdev_add_physbase(clks[per1], MX1_TIM1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1], MX1_TIM2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per2], MX1_LCDC_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1], MX1_UART1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1], MX1_UART2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per2], MX1_CSPI1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per2], MX1_CSPI2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[hclk], MX1_I2C_BASE_ADDR, NULL);
+
+ return 0;
+}
+
+static int imx1_ccm_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ void __iomem *regs;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ regs = IOMEM(iores->start);
+
+ mx1_clocks_init(regs, 32000);
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id imx1_ccm_dt_ids[] = {
+ {
+ .compatible = "fsl,imx1-ccm",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d imx1_ccm_driver = {
+ .probe = imx1_ccm_probe,
+ .name = "imx1-ccm",
+ .of_compatible = DRV_OF_COMPAT(imx1_ccm_dt_ids),
+};
+
+static int imx1_ccm_init(void)
+{
+ return platform_driver_register(&imx1_ccm_driver);
+}
+core_initcall(imx1_ccm_init);
diff --git a/drivers/clk/imx/clk-imx21.c b/drivers/clk/imx/clk-imx21.c
new file mode 100644
index 0000000000..546461b8ee
--- /dev/null
+++ b/drivers/clk/imx/clk-imx21.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ * Copyright 2008 Martin Fuzzey, mfuzzey@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <mach/imx21-regs.h>
+
+#include "clk.h"
+
+/* Register offsets */
+#define CCM_CSCR 0x0
+#define CCM_MPCTL0 0x4
+#define CCM_MPCTL1 0x8
+#define CCM_SPCTL0 0xc
+#define CCM_SPCTL1 0x10
+#define CCM_OSC26MCTL 0x14
+#define CCM_PCDR0 0x18
+#define CCM_PCDR1 0x1c
+#define CCM_PCCR0 0x20
+#define CCM_PCCR1 0x24
+#define CCM_CCSR 0x28
+#define CCM_PMCTL 0x2c
+#define CCM_PMCOUNT 0x30
+#define CCM_WKGDCTL 0x34
+
+#define PCCR0_UART1_EN (1 << 0)
+#define PCCR0_UART2_EN (1 << 1)
+#define PCCR0_UART3_EN (1 << 2)
+#define PCCR0_UART4_EN (1 << 3)
+#define PCCR0_CSPI1_EN (1 << 4)
+#define PCCR0_CSPI2_EN (1 << 5)
+#define PCCR0_SSI1_EN (1 << 6)
+#define PCCR0_SSI2_EN (1 << 7)
+#define PCCR0_FIRI_EN (1 << 8)
+#define PCCR0_SDHC1_EN (1 << 9)
+#define PCCR0_SDHC2_EN (1 << 10)
+#define PCCR0_GPIO_EN (1 << 11)
+#define PCCR0_I2C_EN (1 << 12)
+#define PCCR0_DMA_EN (1 << 13)
+#define PCCR0_USBOTG_EN (1 << 14)
+#define PCCR0_EMMA_EN (1 << 15)
+#define PCCR0_SSI2_BAUD_EN (1 << 16)
+#define PCCR0_SSI1_BAUD_EN (1 << 17)
+#define PCCR0_PERCLK3_EN (1 << 18)
+#define PCCR0_NFC_EN (1 << 19)
+#define PCCR0_FRI_BAUD_EN (1 << 20)
+#define PCCR0_SLDC_EN (1 << 21)
+#define PCCR0_PERCLK4_EN (1 << 22)
+#define PCCR0_HCLK_BMI_EN (1 << 23)
+#define PCCR0_HCLK_USBOTG_EN (1 << 24)
+#define PCCR0_HCLK_SLCDC_EN (1 << 25)
+#define PCCR0_HCLK_LCDC_EN (1 << 26)
+#define PCCR0_HCLK_EMMA_EN (1 << 27)
+#define PCCR0_HCLK_BROM_EN (1 << 28)
+#define PCCR0_HCLK_DMA_EN (1 << 30)
+#define PCCR0_HCLK_CSI_EN (1 << 31)
+
+#define PCCR1_CSPI3_EN (1 << 23)
+#define PCCR1_WDT_EN (1 << 24)
+#define PCCR1_GPT1_EN (1 << 25)
+#define PCCR1_GPT2_EN (1 << 26)
+#define PCCR1_GPT3_EN (1 << 27)
+#define PCCR1_PWM_EN (1 << 28)
+#define PCCR1_RTC_EN (1 << 29)
+#define PCCR1_KPP_EN (1 << 30)
+#define PCCR1_OWIRE_EN (1 << 31)
+
+enum imx21_clks {
+ ckil, ckih, fpm, mpll_sel, spll_sel, mpll, spll, fclk, hclk, ipg, per1,
+ per2, per3, per4, usb_div, nfc_div, lcdc_per_gate, lcdc_ahb_gate,
+ lcdc_ipg_gate, clk_max
+};
+
+static struct clk *clks[clk_max];
+
+static const char *mpll_sel_clks[] = {
+ "fpm",
+ "ckih",
+};
+
+static const char *spll_sel_clks[] = {
+ "fpm",
+ "ckih",
+};
+
+static int imx21_ccm_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ void __iomem *base;
+ unsigned long lref = 32768;
+ unsigned long href = 26000000;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ base = IOMEM(iores->start);
+
+ writel(PCCR0_UART1_EN | PCCR0_UART2_EN | PCCR0_UART3_EN | PCCR0_UART4_EN |
+ PCCR0_CSPI1_EN | PCCR0_CSPI2_EN | PCCR0_SDHC1_EN |
+ PCCR0_SDHC2_EN | PCCR0_GPIO_EN | PCCR0_I2C_EN | PCCR0_DMA_EN |
+ PCCR0_USBOTG_EN | PCCR0_NFC_EN | PCCR0_PERCLK4_EN |
+ PCCR0_HCLK_USBOTG_EN | PCCR0_HCLK_DMA_EN,
+ base + CCM_PCCR0);
+
+ writel(PCCR1_CSPI3_EN | PCCR1_WDT_EN | PCCR1_GPT1_EN | PCCR1_GPT2_EN |
+ PCCR1_GPT3_EN | PCCR1_PWM_EN | PCCR1_RTC_EN | PCCR1_KPP_EN |
+ PCCR1_OWIRE_EN,
+ base + CCM_PCCR1);
+
+ clks[ckil] = clk_fixed("ckil", lref);
+ clks[ckih] = clk_fixed("ckih", href);
+ clks[fpm] = imx_clk_fixed_factor("fpm", "ckil", 512, 1);
+ clks[mpll_sel] = imx_clk_mux("mpll_sel", base + CCM_CSCR, 16, 1, mpll_sel_clks,
+ ARRAY_SIZE(mpll_sel_clks));
+ clks[spll_sel] = imx_clk_mux("spll_sel", base + CCM_CSCR, 17, 1, spll_sel_clks,
+ ARRAY_SIZE(spll_sel_clks));
+ clks[mpll] = imx_clk_pllv1("mpll", "mpll_sel", base + CCM_MPCTL0);
+ clks[spll] = imx_clk_pllv1("spll", "spll_sel", base + CCM_SPCTL0);
+ clks[fclk] = imx_clk_divider("fclk", "mpll", base + CCM_CSCR, 29, 3);
+ clks[hclk] = imx_clk_divider("hclk", "fclk", base + CCM_CSCR, 10, 4);
+ clks[ipg] = imx_clk_divider("ipg", "hclk", base + CCM_CSCR, 9, 1);
+ clks[per1] = imx_clk_divider("per1", "mpll", base + CCM_PCDR1, 0, 6);
+ clks[per2] = imx_clk_divider("per2", "mpll", base + CCM_PCDR1, 8, 6);
+ clks[per3] = imx_clk_divider("per3", "mpll", base + CCM_PCDR1, 16, 6);
+ clks[per4] = imx_clk_divider("per4", "mpll", base + CCM_PCDR1, 24, 6);
+ clks[usb_div] = imx_clk_divider("usb_div", "spll", base + CCM_CSCR, 26, 3);
+ clks[nfc_div] = imx_clk_divider("nfc_div", "ipg", base + CCM_PCDR0, 12, 4);
+ clks[lcdc_per_gate] = imx_clk_gate("lcdc_per_gate", "per3", base + CCM_PCCR0, 18);
+ clks[lcdc_ahb_gate] = imx_clk_gate("lcdc_ahb_gate", "ahb", base + CCM_PCCR0, 26);
+ /*
+ * i.MX21 doesn't have an IPG clock for the LCD. To avoid even more conditionals
+ * in the framebuffer code, provide a dummy clock.
+ */
+ clks[lcdc_ipg_gate] = clk_fixed("dummy", 0);
+
+ clkdev_add_physbase(clks[per1], MX21_GPT1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1], MX21_GPT2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1], MX21_GPT3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1], MX21_UART1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1], MX21_UART2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1], MX21_UART3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1], MX21_UART4_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per2], MX21_CSPI1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per2], MX21_CSPI2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per2], MX21_CSPI3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX21_I2C_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX21_SDHC1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX21_SDHC2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[lcdc_per_gate], MX21_LCDC_BASE_ADDR, "per");
+ clkdev_add_physbase(clks[lcdc_ahb_gate], MX21_LCDC_BASE_ADDR, "ahb");
+ clkdev_add_physbase(clks[lcdc_ipg_gate], MX21_LCDC_BASE_ADDR, "ipg");
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id imx21_ccm_dt_ids[] = {
+ {
+ .compatible = "fsl,imx21-ccm",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d imx21_ccm_driver = {
+ .probe = imx21_ccm_probe,
+ .name = "imx21-ccm",
+ .of_compatible = DRV_OF_COMPAT(imx21_ccm_dt_ids),
+};
+
+static int imx21_ccm_init(void)
+{
+ return platform_driver_register(&imx21_ccm_driver);
+}
+core_initcall(imx21_ccm_init);
diff --git a/drivers/clk/imx/clk-imx25.c b/drivers/clk/imx/clk-imx25.c
new file mode 100644
index 0000000000..864d06e195
--- /dev/null
+++ b/drivers/clk/imx/clk-imx25.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2009 by Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <mach/imx25-regs.h>
+
+#include "clk.h"
+
+#define CCM_MPCTL 0x00
+#define CCM_UPCTL 0x04
+#define CCM_CCTL 0x08
+#define CCM_CGCR0 0x0C
+#define CCM_CGCR1 0x10
+#define CCM_CGCR2 0x14
+#define CCM_PCDR0 0x18
+#define CCM_PCDR1 0x1C
+#define CCM_PCDR2 0x20
+#define CCM_PCDR3 0x24
+#define CCM_RCSR 0x28
+#define CCM_CRDR 0x2C
+#define CCM_DCVR0 0x30
+#define CCM_DCVR1 0x34
+#define CCM_DCVR2 0x38
+#define CCM_DCVR3 0x3c
+#define CCM_LTR0 0x40
+#define CCM_LTR1 0x44
+#define CCM_LTR2 0x48
+#define CCM_LTR3 0x4c
+#define CCM_MCR 0x64
+
+enum mx25_clks {
+ dummy, osc, mpll, upll, mpll_cpu_3_4, cpu_sel, cpu, ahb, usb_div, ipg,
+ per0_sel, per1_sel, per2_sel, per3_sel, per4_sel, per5_sel, per6_sel,
+ per7_sel, per8_sel, per9_sel, per10_sel, per11_sel, per12_sel,
+ per13_sel, per14_sel, per15_sel, per0, per1, per2, per3, per4, per5,
+ per6, per7, per8, per9, per10, per11, per12, per13, per14, per15,
+ csi_ipg_per, epit_ipg_per, esai_ipg_per, esdhc1_ipg_per, esdhc2_ipg_per,
+ gpt_ipg_per, i2c_ipg_per, lcdc_ipg_per, nfc_ipg_per, owire_ipg_per,
+ pwm_ipg_per, sim1_ipg_per, sim2_ipg_per, ssi1_ipg_per, ssi2_ipg_per,
+ uart_ipg_per, ata_ahb, reserved1, csi_ahb, emi_ahb, esai_ahb, esdhc1_ahb,
+ esdhc2_ahb, fec_ahb, lcdc_ahb, rtic_ahb, sdma_ahb, slcdc_ahb, usbotg_ahb,
+ reserved2, reserved3, reserved4, reserved5, can1_ipg, can2_ipg, csi_ipg,
+ cspi1_ipg, cspi2_ipg, cspi3_ipg, dryice_ipg, ect_ipg, epit1_ipg, epit2_ipg,
+ reserved6, esdhc1_ipg, esdhc2_ipg, fec_ipg, reserved7, reserved8, reserved9,
+ gpt1_ipg, gpt2_ipg, gpt3_ipg, gpt4_ipg, reserved10, reserved11, reserved12,
+ iim_ipg, reserved13, reserved14, kpp_ipg, lcdc_ipg, reserved15, pwm1_ipg,
+ pwm2_ipg, pwm3_ipg, pwm4_ipg, rngb_ipg, reserved16, scc_ipg, sdma_ipg,
+ sim1_ipg, sim2_ipg, slcdc_ipg, spba_ipg, ssi1_ipg, ssi2_ipg, tsc_ipg,
+ uart1_ipg, uart2_ipg, uart3_ipg, uart4_ipg, uart5_ipg, reserved17,
+ wdt_ipg, clk_max
+};
+
+static struct clk *clks[clk_max];
+
+static const char *cpu_sel_clks[] = {
+ "mpll",
+ "mpll_cpu_3_4",
+};
+
+static const char *per_sel_clks[] = {
+ "ahb",
+ "upll",
+};
+
+static int imx25_ccm_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ void __iomem *base;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ base = IOMEM(iores->start);
+
+ writel((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 8) | (1 << 9) |
+ (1 << 10) | (1 << 15) | (1 << 19) | (1 << 21) | (1 << 22) |
+ (1 << 23) | (1 << 24) | (1 << 28),
+ base + CCM_CGCR0);
+
+ writel((1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 13) | (1 << 14) |
+ (1 << 15) | (1 << 19) | (1 << 20) | (1 << 21) | (1 << 22) |
+ (1 << 26) | (1 << 31),
+ base + CCM_CGCR1);
+
+ writel((1 << 0) | (1 << 1) | (1 << 2) | (1 << 10) | (1 << 13) | (1 << 14) |
+ (1 << 15) | (1 << 16) | (1 << 17) | (1 << 18),
+ base + CCM_CGCR2);
+
+ clks[dummy] = clk_fixed("dummy", 0);
+ clks[osc] = clk_fixed("osc", 24000000);
+ clks[mpll] = imx_clk_pllv1("mpll", "osc", base + CCM_MPCTL);
+ clks[upll] = imx_clk_pllv1("upll", "osc", base + CCM_UPCTL);
+ clks[mpll_cpu_3_4] = imx_clk_fixed_factor("mpll_cpu_3_4", "mpll", 3, 4);
+ clks[cpu_sel] = imx_clk_mux("cpu_sel", base + CCM_CCTL, 14, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks));
+ clks[cpu] = imx_clk_divider("cpu", "cpu_sel", base + CCM_CCTL, 30, 2);
+ clks[ahb] = imx_clk_divider("ahb", "cpu", base + CCM_CCTL, 28, 2);
+ clks[usb_div] = imx_clk_divider("usb_div", "upll", base + CCM_CCTL, 16, 6);
+ clks[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2);
+ clks[per0_sel] = imx_clk_mux("per0_sel", base + CCM_MCR, 0, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per1_sel] = imx_clk_mux("per1_sel", base + CCM_MCR, 1, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per2_sel] = imx_clk_mux("per2_sel", base + CCM_MCR, 2, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per3_sel] = imx_clk_mux("per3_sel", base + CCM_MCR, 3, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per4_sel] = imx_clk_mux("per4_sel", base + CCM_MCR, 4, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per5_sel] = imx_clk_mux("per5_sel", base + CCM_MCR, 5, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per6_sel] = imx_clk_mux("per6_sel", base + CCM_MCR, 6, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per7_sel] = imx_clk_mux("per7_sel", base + CCM_MCR, 7, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per8_sel] = imx_clk_mux("per8_sel", base + CCM_MCR, 8, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per9_sel] = imx_clk_mux("per9_sel", base + CCM_MCR, 9, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per10_sel] = imx_clk_mux("per10_sel", base + CCM_MCR, 10, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per11_sel] = imx_clk_mux("per11_sel", base + CCM_MCR, 11, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per12_sel] = imx_clk_mux("per12_sel", base + CCM_MCR, 12, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per13_sel] = imx_clk_mux("per13_sel", base + CCM_MCR, 13, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per14_sel] = imx_clk_mux("per14_sel", base + CCM_MCR, 14, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per15_sel] = imx_clk_mux("per15_sel", base + CCM_MCR, 15, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks));
+ clks[per0] = imx_clk_divider("per0", "per0_sel", base + CCM_PCDR0, 0, 6);
+ clks[per1] = imx_clk_divider("per1", "per1_sel", base + CCM_PCDR0, 8, 6);
+ clks[per2] = imx_clk_divider("per2", "per2_sel", base + CCM_PCDR0, 16, 6);
+ clks[per3] = imx_clk_divider("per3", "per3_sel", base + CCM_PCDR0, 24, 6);
+ clks[per4] = imx_clk_divider("per4", "per4_sel", base + CCM_PCDR1, 0, 6);
+ clks[per5] = imx_clk_divider("per5", "per5_sel", base + CCM_PCDR1, 8, 6);
+ clks[per6] = imx_clk_divider("per6", "per6_sel", base + CCM_PCDR1, 16, 6);
+ clks[per7] = imx_clk_divider("per7", "per7_sel", base + CCM_PCDR1, 24, 6);
+ clks[per8] = imx_clk_divider("per8", "per8_sel", base + CCM_PCDR2, 0, 6);
+ clks[per9] = imx_clk_divider("per9", "per9_sel", base + CCM_PCDR2, 8, 6);
+ clks[per10] = imx_clk_divider("per10", "per10_sel", base + CCM_PCDR2, 16, 6);
+ clks[per11] = imx_clk_divider("per11", "per11_sel", base + CCM_PCDR2, 24, 6);
+ clks[per12] = imx_clk_divider("per12", "per12_sel", base + CCM_PCDR3, 0, 6);
+ clks[per13] = imx_clk_divider("per13", "per13_sel", base + CCM_PCDR3, 8, 6);
+ clks[per14] = imx_clk_divider("per14", "per14_sel", base + CCM_PCDR3, 16, 6);
+ clks[per15] = imx_clk_divider("per15", "per15_sel", base + CCM_PCDR3, 24, 6);
+ clks[lcdc_ahb] = imx_clk_gate("lcdc_ahb", "ahb", base + CCM_CGCR0, 24);
+ clks[lcdc_ipg] = imx_clk_gate("lcdc_ipg", "ipg", base + CCM_CGCR1, 29);
+ clks[lcdc_ipg_per] = imx_clk_gate("lcdc_ipg_per", "per7", base + CCM_CGCR0, 7);
+
+ clkdev_add_physbase(clks[per15], MX25_UART1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per15], MX25_UART2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per15], MX25_UART3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per15], MX25_UART4_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per15], MX25_UART5_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per5], MX25_GPT1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per5], MX25_GPT2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per5], MX25_GPT3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per5], MX25_GPT4_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX25_FEC_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX25_I2C1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX25_I2C2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX25_I2C3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX25_CSPI1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX25_CSPI2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX25_CSPI3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per3], MX25_ESDHC1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per4], MX25_ESDHC2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per8], MX25_NFC_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[lcdc_ipg_per], MX25_LCDC_BASE_ADDR, "per");
+ clkdev_add_physbase(clks[lcdc_ipg], MX25_LCDC_BASE_ADDR, "ipg");
+ clkdev_add_physbase(clks[lcdc_ahb], MX25_LCDC_BASE_ADDR, "ahb");
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id imx25_ccm_dt_ids[] = {
+ {
+ .compatible = "fsl,imx25-ccm",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d imx25_ccm_driver = {
+ .probe = imx25_ccm_probe,
+ .name = "imx25-ccm",
+ .of_compatible = DRV_OF_COMPAT(imx25_ccm_dt_ids),
+};
+
+static int imx25_ccm_init(void)
+{
+ return platform_driver_register(&imx25_ccm_driver);
+}
+core_initcall(imx25_ccm_init);
diff --git a/drivers/clk/imx/clk-imx27.c b/drivers/clk/imx/clk-imx27.c
new file mode 100644
index 0000000000..4b63244211
--- /dev/null
+++ b/drivers/clk/imx/clk-imx27.c
@@ -0,0 +1,270 @@
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <mach/imx27-regs.h>
+#include <mach/generic.h>
+#include <mach/revision.h>
+
+#include "clk.h"
+
+/* Register offsets */
+#define CCM_CSCR 0x0
+#define CCM_MPCTL0 0x4
+#define CCM_MPCTL1 0x8
+#define CCM_SPCTL0 0xc
+#define CCM_SPCTL1 0x10
+#define CCM_OSC26MCTL 0x14
+#define CCM_PCDR0 0x18
+#define CCM_PCDR1 0x1c
+#define CCM_PCCR0 0x20
+#define CCM_PCCR1 0x24
+#define CCM_CCSR 0x28
+#define CCM_PMCTL 0x2c
+#define CCM_PMCOUNT 0x30
+#define CCM_WKGDCTL 0x34
+
+#define PCCR0_SSI2_EN (1 << 0)
+#define PCCR0_SSI1_EN (1 << 1)
+#define PCCR0_SLCDC_EN (1 << 2)
+#define PCCR0_SDHC3_EN (1 << 3)
+#define PCCR0_SDHC2_EN (1 << 4)
+#define PCCR0_SDHC1_EN (1 << 5)
+#define PCCR0_SDC_EN (1 << 6)
+#define PCCR0_SAHARA_EN (1 << 7)
+#define PCCR0_RTIC_EN (1 << 8)
+#define PCCR0_RTC_EN (1 << 9)
+#define PCCR0_PWM_EN (1 << 11)
+#define PCCR0_OWIRE_EN (1 << 12)
+#define PCCR0_MSHC_EN (1 << 13)
+#define PCCR0_LCDC_EN (1 << 14)
+#define PCCR0_KPP_EN (1 << 15)
+#define PCCR0_IIM_EN (1 << 16)
+#define PCCR0_I2C2_EN (1 << 17)
+#define PCCR0_I2C1_EN (1 << 18)
+#define PCCR0_GPT6_EN (1 << 19)
+#define PCCR0_GPT5_EN (1 << 20)
+#define PCCR0_GPT4_EN (1 << 21)
+#define PCCR0_GPT3_EN (1 << 22)
+#define PCCR0_GPT2_EN (1 << 23)
+#define PCCR0_GPT1_EN (1 << 24)
+#define PCCR0_GPIO_EN (1 << 25)
+#define PCCR0_FEC_EN (1 << 26)
+#define PCCR0_EMMA_EN (1 << 27)
+#define PCCR0_DMA_EN (1 << 28)
+#define PCCR0_CSPI3_EN (1 << 29)
+#define PCCR0_CSPI2_EN (1 << 30)
+#define PCCR0_CSPI1_EN (1 << 31)
+
+#define PCCR1_MSHC_BAUDEN (1 << 2)
+#define PCCR1_NFC_BAUDEN (1 << 3)
+#define PCCR1_SSI2_BAUDEN (1 << 4)
+#define PCCR1_SSI1_BAUDEN (1 << 5)
+#define PCCR1_H264_BAUDEN (1 << 6)
+#define PCCR1_PERCLK4_EN (1 << 7)
+#define PCCR1_PERCLK3_EN (1 << 8)
+#define PCCR1_PERCLK2_EN (1 << 9)
+#define PCCR1_PERCLK1_EN (1 << 10)
+#define PCCR1_HCLK_USB (1 << 11)
+#define PCCR1_HCLK_SLCDC (1 << 12)
+#define PCCR1_HCLK_SAHARA (1 << 13)
+#define PCCR1_HCLK_RTIC (1 << 14)
+#define PCCR1_HCLK_LCDC (1 << 15)
+#define PCCR1_HCLK_H264 (1 << 16)
+#define PCCR1_HCLK_FEC (1 << 17)
+#define PCCR1_HCLK_EMMA (1 << 18)
+#define PCCR1_HCLK_EMI (1 << 19)
+#define PCCR1_HCLK_DMA (1 << 20)
+#define PCCR1_HCLK_CSI (1 << 21)
+#define PCCR1_HCLK_BROM (1 << 22)
+#define PCCR1_HCLK_ATA (1 << 23)
+#define PCCR1_WDT_EN (1 << 24)
+#define PCCR1_USB_EN (1 << 25)
+#define PCCR1_UART6_EN (1 << 26)
+#define PCCR1_UART5_EN (1 << 27)
+#define PCCR1_UART4_EN (1 << 28)
+#define PCCR1_UART3_EN (1 << 29)
+#define PCCR1_UART2_EN (1 << 30)
+#define PCCR1_UART1_EN (1 << 31)
+
+enum mx27_clks {
+ dummy, ckih, ckil, mpll, spll, mpll_main2, ahb, ipg, nfc_div, per1_div,
+ per2_div, per3_div, per4_div, vpu_sel, vpu_div, usb_div, cpu_sel,
+ clko_sel, cpu_div, clko_div, ssi1_sel, ssi2_sel, ssi1_div, ssi2_div,
+ clko_en, ssi2_ipg_gate, ssi1_ipg_gate, slcdc_ipg_gate, sdhc3_ipg_gate,
+ sdhc2_ipg_gate, sdhc1_ipg_gate, scc_ipg_gate, sahara_ipg_gate,
+ rtc_ipg_gate, pwm_ipg_gate, owire_ipg_gate, lcdc_ipg_gate,
+ kpp_ipg_gate, iim_ipg_gate, i2c2_ipg_gate, i2c1_ipg_gate,
+ gpt6_ipg_gate, gpt5_ipg_gate, gpt4_ipg_gate, gpt3_ipg_gate,
+ gpt2_ipg_gate, gpt1_ipg_gate, gpio_ipg_gate, fec_ipg_gate,
+ emma_ipg_gate, dma_ipg_gate, cspi3_ipg_gate, cspi2_ipg_gate,
+ cspi1_ipg_gate, nfc_baud_gate, ssi2_baud_gate, ssi1_baud_gate,
+ vpu_baud_gate, per4_gate, per3_gate, per2_gate, per1_gate,
+ usb_ahb_gate, slcdc_ahb_gate, sahara_ahb_gate, lcdc_ahb_gate,
+ vpu_ahb_gate, fec_ahb_gate, emma_ahb_gate, emi_ahb_gate, dma_ahb_gate,
+ csi_ahb_gate, brom_ahb_gate, ata_ahb_gate, wdog_ipg_gate, usb_ipg_gate,
+ uart6_ipg_gate, uart5_ipg_gate, uart4_ipg_gate, uart3_ipg_gate,
+ uart2_ipg_gate, uart1_ipg_gate, ckih_div1p5, fpm, mpll_osc_sel,
+ mpll_sel, spll_gate, clk_max
+};
+
+static struct clk *clks[clk_max];
+
+static const char *cpu_sel_clks[] = {
+ "mpll_main2",
+ "mpll",
+};
+
+static const char *mpll_sel_clks[] = {
+ "fpm",
+ "mpll_osc_sel",
+};
+
+static const char *mpll_osc_sel_clks[] = {
+ "ckih",
+ "ckih_div1p5",
+};
+
+static const char *clko_sel_clks[] = {
+ "ckil",
+ NULL,
+ "ckih",
+ "ckih",
+ "ckih",
+ "mpll",
+ "spll",
+ "cpu_div",
+ "ahb",
+ "ipg",
+ "per1_div",
+ "per2_div",
+ "per3_div",
+ "per4_div",
+ NULL,
+ NULL,
+ "nfc_div",
+ NULL,
+ NULL,
+ NULL,
+ "ckil",
+ "usb_div",
+ NULL,
+};
+
+static int imx27_ccm_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ void __iomem *base;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ base = IOMEM(iores->start);
+
+ writel(PCCR0_SDHC3_EN | PCCR0_SDHC2_EN | PCCR0_SDHC1_EN |
+ PCCR0_PWM_EN | PCCR0_KPP_EN | PCCR0_IIM_EN |
+ PCCR0_I2C2_EN | PCCR0_I2C1_EN | PCCR0_GPT6_EN | PCCR0_GPT5_EN |
+ PCCR0_GPT4_EN | PCCR0_GPT3_EN | PCCR0_GPT2_EN | PCCR0_GPT1_EN |
+ PCCR0_GPIO_EN | PCCR0_FEC_EN | PCCR0_CSPI3_EN | PCCR0_CSPI2_EN |
+ PCCR0_CSPI1_EN,
+ base + CCM_PCCR0);
+
+ writel(PCCR1_NFC_BAUDEN | PCCR1_PERCLK4_EN | PCCR1_PERCLK2_EN | PCCR1_PERCLK1_EN |
+ PCCR1_HCLK_USB | PCCR1_HCLK_FEC | PCCR1_HCLK_EMI | PCCR1_WDT_EN |
+ PCCR1_USB_EN | PCCR1_UART6_EN | PCCR1_UART5_EN | PCCR1_UART4_EN |
+ PCCR1_UART3_EN | PCCR1_UART2_EN | PCCR1_UART1_EN,
+ base + CCM_PCCR1);
+
+ clks[dummy] = clk_fixed("dummy", 0);
+ clks[ckih] = clk_fixed("ckih", 26000000);
+ clks[ckil] = clk_fixed("ckil", 32768);
+ clks[fpm] = imx_clk_fixed_factor("fpm", "ckil", 1024, 1);
+ clks[ckih_div1p5] = imx_clk_fixed_factor("ckih_div1p5", "ckih", 2, 3);
+
+ clks[mpll_osc_sel] = imx_clk_mux("mpll_osc_sel", base + CCM_CSCR, 4, 1,
+ mpll_osc_sel_clks,
+ ARRAY_SIZE(mpll_osc_sel_clks));
+ clks[mpll_sel] = imx_clk_mux("mpll_sel", base + CCM_CSCR, 16, 1, mpll_sel_clks,
+ ARRAY_SIZE(mpll_sel_clks));
+
+ clks[mpll] = imx_clk_pllv1("mpll", "mpll_sel", base + CCM_MPCTL0);
+ clks[spll] = imx_clk_pllv1("spll", "ckih", base + CCM_SPCTL0);
+ clks[mpll_main2] = imx_clk_fixed_factor("mpll_main2", "mpll", 2, 3);
+
+ if (imx_silicon_revision() >= IMX_CHIP_REV_2_0) {
+ clks[ahb] = imx_clk_divider("ahb", "mpll_main2", base + CCM_CSCR, 8, 2);
+ clks[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2);
+ } else {
+ clks[ahb] = imx_clk_divider("ahb", "mpll_main2", base + CCM_CSCR, 9, 4);
+ clks[ipg] = imx_clk_divider("ipg", "ahb", base + CCM_CSCR, 8, 1);
+ }
+
+ clks[nfc_div] = imx_clk_divider("nfc_div", "ahb", base + CCM_PCDR0, 6, 4);
+ clks[per1_div] = imx_clk_divider("per1_div", "mpll_main2", base + CCM_PCDR1, 0, 6);
+ clks[per2_div] = imx_clk_divider("per2_div", "mpll_main2", base + CCM_PCDR1, 8, 6);
+ clks[per3_div] = imx_clk_divider("per3_div", "mpll_main2", base + CCM_PCDR1, 16, 6);
+ clks[per4_div] = imx_clk_divider("per4_div", "mpll_main2", base + CCM_PCDR1, 24, 6);
+ clks[usb_div] = imx_clk_divider("usb_div", "spll", base + CCM_CSCR, 28, 3);
+ clks[cpu_sel] = imx_clk_mux("cpu_sel", base + CCM_CSCR, 15, 1, cpu_sel_clks,
+ ARRAY_SIZE(cpu_sel_clks));
+ clks[clko_sel] = imx_clk_mux("clko_sel", base + CCM_CCSR, 0, 5, clko_sel_clks,
+ ARRAY_SIZE(clko_sel_clks));
+ if (imx_silicon_revision() >= IMX_CHIP_REV_2_0)
+ clks[cpu_div] = imx_clk_divider("cpu_div", "cpu_sel", base + CCM_CSCR, 12, 2);
+ else
+ clks[cpu_div] = imx_clk_divider("cpu_div", "cpu_sel", base + CCM_CSCR, 13, 3);
+ clks[clko_div] = imx_clk_divider("clko_div", "clko_sel", base + CCM_PCDR0, 22, 3);
+ clks[per3_gate] = imx_clk_gate("per3_gate", "per3_div", base + CCM_PCCR1, 8);
+ clks[lcdc_ahb_gate] = imx_clk_gate("lcdc_ahb_gate", "ahb", base + CCM_PCCR1, 15);
+ clks[lcdc_ipg_gate] = imx_clk_gate("lcdc_ipg_gate", "ipg", base + CCM_PCCR0, 14);
+
+ clkdev_add_physbase(clks[per1_div], MX27_GPT1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1_div], MX27_GPT2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1_div], MX27_GPT3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1_div], MX27_GPT4_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1_div], MX27_GPT5_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1_div], MX27_GPT6_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1_div], MX27_UART1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1_div], MX27_UART2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1_div], MX27_UART3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1_div], MX27_UART4_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1_div], MX27_UART5_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per1_div], MX27_UART6_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX27_CSPI1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX27_CSPI2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX27_CSPI3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX27_I2C1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX27_I2C2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per2_div], MX27_SDHC1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per2_div], MX27_SDHC2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per2_div], MX27_SDHC3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per3_gate], MX27_LCDC_BASE_ADDR, "per");
+ clkdev_add_physbase(clks[lcdc_ahb_gate], MX27_LCDC_BASE_ADDR, "ahb");
+ clkdev_add_physbase(clks[lcdc_ipg_gate], MX27_LCDC_BASE_ADDR, "ipg");
+ clkdev_add_physbase(clks[ipg], MX27_FEC_BASE_ADDR, NULL);
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id imx27_ccm_dt_ids[] = {
+ {
+ .compatible = "fsl,imx27-ccm",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d imx27_ccm_driver = {
+ .probe = imx27_ccm_probe,
+ .name = "imx27-ccm",
+ .of_compatible = DRV_OF_COMPAT(imx27_ccm_dt_ids),
+};
+
+static int imx27_ccm_init(void)
+{
+ return platform_driver_register(&imx27_ccm_driver);
+}
+core_initcall(imx27_ccm_init);
diff --git a/drivers/clk/imx/clk-imx31.c b/drivers/clk/imx/clk-imx31.c
new file mode 100644
index 0000000000..8d135c9a1f
--- /dev/null
+++ b/drivers/clk/imx/clk-imx31.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2012 Sascha Hauer <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <mach/imx31-regs.h>
+
+#include "clk.h"
+
+/* Register addresses */
+#define CCM_CCMR 0x00
+#define CCM_PDR0 0x04
+#define CCM_PDR1 0x08
+//#define CCM_RCSR 0x0C
+#define CCM_MPCTL 0x10
+#define CCM_UPCTL 0x14
+#define CCM_SRPCTL 0x18
+#define CCM_COSR 0x1C
+#define CCM_CGR0 0x20
+#define CCM_CGR1 0x24
+#define CCM_CGR2 0x28
+#define CCM_WIMR 0x2C
+#define CCM_LDC 0x30
+#define CCM_DCVR0 0x34
+#define CCM_DCVR1 0x38
+#define CCM_DCVR2 0x3C
+#define CCM_DCVR3 0x40
+#define CCM_LTR0 0x44
+#define CCM_LTR1 0x48
+#define CCM_LTR2 0x4C
+#define CCM_LTR3 0x50
+#define CCM_LTBR0 0x54
+#define CCM_LTBR1 0x58
+#define CCM_PMCR0 0x5C
+#define CCM_PMCR1 0x60
+#define CCM_PDR2 0x64
+
+enum mx31_clks {
+ ckih, ckil, mpll, spll, upll, mcu_main, hsp, ahb, nfc, ipg, per_div,
+ per, csi, fir, csi_div, usb_div_pre, usb_div_post, fir_div_pre,
+ fir_div_post, sdhc1_gate, sdhc2_gate, gpt_gate, epit1_gate, epit2_gate,
+ iim_gate, ata_gate, sdma_gate, cspi3_gate, rng_gate, uart1_gate,
+ uart2_gate, ssi1_gate, i2c1_gate, i2c2_gate, i2c3_gate, hantro_gate,
+ mstick1_gate, mstick2_gate, csi_gate, rtc_gate, wdog_gate, pwm_gate,
+ sim_gate, ect_gate, usb_gate, kpp_gate, ipu_gate, uart3_gate,
+ uart4_gate, uart5_gate, owire_gate, ssi2_gate, cspi1_gate, cspi2_gate,
+ gacc_gate, emi_gate, rtic_gate, firi_gate, clk_max
+};
+
+static struct clk *clks[clk_max];
+
+static const char *mcu_main_sel[] = {
+ "spll",
+ "mpll",
+};
+
+static const char *per_sel[] = {
+ "per_div",
+ "ipg",
+};
+
+static int imx31_ccm_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ void __iomem *base;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ base = IOMEM(iores->start);
+
+ writel(0xffffffff, base + CCM_CGR0);
+ writel(0xffffffff, base + CCM_CGR1);
+ writel(0xffffffff, base + CCM_CGR2);
+
+ clks[ckih] = clk_fixed("ckih", 26000000);
+ clks[ckil] = clk_fixed("ckil", 32768);
+ clks[mpll] = imx_clk_pllv1("mpll", "ckih", base + CCM_MPCTL);
+ clks[spll] = imx_clk_pllv1("spll", "ckih", base + CCM_SRPCTL);
+ clks[upll] = imx_clk_pllv1("upll", "ckih", base + CCM_UPCTL);
+ clks[mcu_main] = imx_clk_mux("mcu_main", base + CCM_PMCR0, 31, 1,
+ mcu_main_sel, ARRAY_SIZE(mcu_main_sel));
+ clks[hsp] = imx_clk_divider("hsp", "mcu_main", base + CCM_PDR0, 11, 3);
+ clks[ahb] = imx_clk_divider("ahb", "mcu_main", base + CCM_PDR0, 3, 3);
+ clks[nfc] = imx_clk_divider("nfc", "ahb", base + CCM_PDR0, 8, 3);
+ clks[ipg] = imx_clk_divider("ipg", "ahb", base + CCM_PDR0, 6, 2);
+ clks[per_div] = imx_clk_divider("per_div", "upll", base + CCM_PDR0, 16, 5);
+ clks[per] = imx_clk_mux("per", base + CCM_CCMR, 24, 1, per_sel, ARRAY_SIZE(per_sel));
+
+ clkdev_add_physbase(clks[per], MX31_UART1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per], MX31_UART2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per], MX31_UART3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per], MX31_UART4_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per], MX31_UART5_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per], MX31_I2C1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per], MX31_I2C2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per], MX31_I2C3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX31_CSPI1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX31_CSPI2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX31_CSPI3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per], MX31_SDHC1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per], MX31_SDHC2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[per], MX31_GPT1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[hsp], MX31_IPU_CTRL_BASE_ADDR, NULL);
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id imx31_ccm_dt_ids[] = {
+ {
+ .compatible = "fsl,imx31-ccm",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d imx31_ccm_driver = {
+ .probe = imx31_ccm_probe,
+ .name = "imx31-ccm",
+ .of_compatible = DRV_OF_COMPAT(imx31_ccm_dt_ids),
+};
+
+static int imx31_ccm_init(void)
+{
+ return platform_driver_register(&imx31_ccm_driver);
+}
+core_initcall(imx31_ccm_init);
diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c
new file mode 100644
index 0000000000..af6c4058d7
--- /dev/null
+++ b/drivers/clk/imx/clk-imx35.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix <s.hauer@pengutronix.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.
+ *
+ */
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <mach/imx35-regs.h>
+#include <reset_source.h>
+
+#include "clk.h"
+
+#define CCM_CCMR 0x00
+#define CCM_PDR0 0x04
+#define CCM_PDR1 0x08
+#define CCM_PDR2 0x0C
+#define CCM_PDR3 0x10
+#define CCM_PDR4 0x14
+#define CCM_RCSR 0x18
+#define CCM_MPCTL 0x1C
+#define CCM_PPCTL 0x20
+#define CCM_ACMR 0x24
+#define CCM_COSR 0x28
+#define CCM_CGR0 0x2C
+#define CCM_CGR1 0x30
+#define CCM_CGR2 0x34
+#define CCM_CGR3 0x38
+
+struct arm_ahb_div {
+ unsigned char arm, ahb, sel;
+};
+
+static struct arm_ahb_div clk_consumer[] = {
+ { .arm = 1, .ahb = 4, .sel = 0},
+ { .arm = 1, .ahb = 3, .sel = 1},
+ { .arm = 2, .ahb = 2, .sel = 0},
+ { .arm = 0, .ahb = 0, .sel = 0},
+ { .arm = 0, .ahb = 0, .sel = 0},
+ { .arm = 0, .ahb = 0, .sel = 0},
+ { .arm = 4, .ahb = 1, .sel = 0},
+ { .arm = 1, .ahb = 5, .sel = 0},
+ { .arm = 1, .ahb = 8, .sel = 0},
+ { .arm = 1, .ahb = 6, .sel = 1},
+ { .arm = 2, .ahb = 4, .sel = 0},
+ { .arm = 0, .ahb = 0, .sel = 0},
+ { .arm = 0, .ahb = 0, .sel = 0},
+ { .arm = 0, .ahb = 0, .sel = 0},
+ { .arm = 4, .ahb = 2, .sel = 0},
+ { .arm = 0, .ahb = 0, .sel = 0},
+};
+
+static char hsp_div_532[] = { 4, 8, 3, 0 };
+static char hsp_div_400[] = { 3, 6, 3, 0 };
+
+enum mx35_clks {
+ ckih, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg,
+ arm_per_div, ahb_per_div, ipg_per, uart_sel, uart_div, esdhc_sel,
+ esdhc1_div, esdhc2_div, esdhc3_div, spdif_sel, spdif_div_pre,
+ spdif_div_post, ssi_sel, ssi1_div_pre, ssi1_div_post, ssi2_div_pre,
+ ssi2_div_post, usb_sel, usb_div, nfc_div, asrc_gate, pata_gate,
+ audmux_gate, can1_gate, can2_gate, cspi1_gate, cspi2_gate, ect_gate,
+ edio_gate, emi_gate, epit1_gate, epit2_gate, esai_gate, esdhc1_gate,
+ esdhc2_gate, esdhc3_gate, fec_gate, gpio1_gate, gpio2_gate, gpio3_gate,
+ gpt_gate, i2c1_gate, i2c2_gate, i2c3_gate, iomuxc_gate, ipu_gate,
+ kpp_gate, mlb_gate, mshc_gate, owire_gate, pwm_gate, rngc_gate,
+ rtc_gate, rtic_gate, scc_gate, sdma_gate, spba_gate, spdif_gate,
+ ssi1_gate, ssi2_gate, uart1_gate, uart2_gate, uart3_gate, usbotg_gate,
+ wdog_gate, max_gate, admux_gate, csi_gate, iim_gate, gpu2d_gate,
+ clk_max
+};
+
+static struct clk *clks[clk_max];
+
+static const char *std_sel[] = {
+ "ppll",
+ "arm",
+};
+
+static const char *ipg_per_sel[] = {
+ "ahb_per_div",
+ "arm_per_div",
+};
+
+static int imx35_ccm_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ u32 pdr0, consumer_sel, hsp_sel;
+ struct arm_ahb_div *aad;
+ unsigned char *hsp_div;
+ void __iomem *base;
+ u32 reg;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ base = IOMEM(iores->start);
+
+ /* Check reset source */
+ reg = readl(base + CCM_RCSR);
+
+ switch (reg & 0x0F) {
+ case 0x00:
+ reset_source_set_priority(RESET_POR, 200);
+ break;
+ case 0x02:
+ reset_source_set_priority(RESET_JTAG, 200);
+ break;
+ case 0x04:
+ reset_source_set_priority(RESET_RST, 200);
+ break;
+ case 0x08:
+ reset_source_set_priority(RESET_WDG, 200);
+ break;
+ }
+
+ writel(0xffffffff, base + CCM_CGR0);
+ writel(0xffffffff, base + CCM_CGR1);
+ writel(0xfbffffff, base + CCM_CGR2);
+ writel(0xffffffff, base + CCM_CGR3);
+
+ pdr0 = __raw_readl(base + CCM_PDR0);
+ consumer_sel = (pdr0 >> 16) & 0xf;
+ aad = &clk_consumer[consumer_sel];
+ if (!aad->arm) {
+ pr_err("i.MX35 clk: illegal consumer mux selection 0x%x\n", consumer_sel);
+ /*
+ * We are basically stuck. Continue with a default entry and hope we
+ * get far enough to actually show the above message
+ */
+ aad = &clk_consumer[0];
+ }
+
+ clks[ckih] = clk_fixed("ckih", 24000000);
+ clks[mpll] = imx_clk_pllv1("mpll", "ckih", base + CCM_MPCTL);
+ clks[ppll] = imx_clk_pllv1("ppll", "ckih", base + CCM_PPCTL);
+
+ clks[mpll_075] = imx_clk_fixed_factor("mpll_075", "mpll", 3, 4);
+
+ if (aad->sel)
+ clks[arm] = imx_clk_fixed_factor("arm", "mpll_075", 1, aad->arm);
+ else
+ clks[arm] = imx_clk_fixed_factor("arm", "mpll", 1, aad->arm);
+
+ if (clk_get_rate(clks[arm]) > 400000000)
+ hsp_div = hsp_div_532;
+ else
+ hsp_div = hsp_div_400;
+
+ hsp_sel = (pdr0 >> 20) & 0x3;
+ if (!hsp_div[hsp_sel]) {
+ pr_err("i.MX35 clk: illegal hsp clk selection 0x%x\n", hsp_sel);
+ hsp_sel = 0;
+ }
+
+ clks[hsp] = imx_clk_fixed_factor("hsp", "arm", 1, hsp_div[hsp_sel]);
+
+ clks[ahb] = imx_clk_fixed_factor("ahb", "arm", 1, aad->ahb);
+ clks[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2);
+
+ clks[arm_per_div] = imx_clk_divider("arm_per_div", "arm", base + CCM_PDR4, 16, 6);
+ clks[ahb_per_div] = imx_clk_divider("ahb_per_div", "ahb", base + CCM_PDR0, 12, 3);
+ clks[ipg_per] = imx_clk_mux("ipg_per", base + CCM_PDR0, 26, 1, ipg_per_sel, ARRAY_SIZE(ipg_per_sel));
+
+ clks[uart_sel] = imx_clk_mux("uart_sel", base + CCM_PDR3, 14, 1, std_sel, ARRAY_SIZE(std_sel));
+ clks[uart_div] = imx_clk_divider("uart_div", "uart_sel", base + CCM_PDR4, 10, 6);
+
+ clks[esdhc_sel] = imx_clk_mux("esdhc_sel", base + CCM_PDR4, 9, 1, std_sel, ARRAY_SIZE(std_sel));
+ clks[esdhc1_div] = imx_clk_divider("esdhc1_div", "esdhc_sel", base + CCM_PDR3, 0, 6);
+ clks[esdhc2_div] = imx_clk_divider("esdhc2_div", "esdhc_sel", base + CCM_PDR3, 8, 6);
+ clks[esdhc3_div] = imx_clk_divider("esdhc3_div", "esdhc_sel", base + CCM_PDR3, 16, 6);
+
+ clks[usb_sel] = imx_clk_mux("usb_sel", base + CCM_PDR4, 9, 1, std_sel, ARRAY_SIZE(std_sel));
+ clks[usb_div] = imx_clk_divider("usb_div", "usb_sel", base + CCM_PDR4, 22, 6);
+
+ clkdev_add_physbase(clks[uart_div], MX35_UART1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[uart_div], MX35_UART2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[uart_div], MX35_UART3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg_per], MX35_I2C1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg_per], MX35_I2C2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg_per], MX35_I2C3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX35_CSPI1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX35_CSPI2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX35_FEC_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[ipg], MX35_GPT1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[esdhc1_div], MX35_ESDHC1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[esdhc2_div], MX35_ESDHC2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[esdhc3_div], MX35_ESDHC3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[hsp], MX35_IPU_CTRL_BASE_ADDR, NULL);
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id imx35_ccm_dt_ids[] = {
+ {
+ .compatible = "fsl,imx35-ccm",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d imx35_ccm_driver = {
+ .probe = imx35_ccm_probe,
+ .name = "imx35-ccm",
+ .of_compatible = DRV_OF_COMPAT(imx35_ccm_dt_ids),
+};
+
+static int imx35_ccm_init(void)
+{
+ return platform_driver_register(&imx35_ccm_driver);
+}
+core_initcall(imx35_ccm_init);
diff --git a/drivers/clk/imx/clk-imx5.c b/drivers/clk/imx/clk-imx5.c
new file mode 100644
index 0000000000..c4c47a6d87
--- /dev/null
+++ b/drivers/clk/imx/clk-imx5.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.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.
+ *
+ */
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <of.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <mach/imx50-regs.h>
+#include <mach/imx51-regs.h>
+#include <mach/imx53-regs.h>
+#include <dt-bindings/clock/imx5-clock.h>
+
+#include "clk.h"
+
+/* Register addresses of CCM*/
+#define CCM_CCR 0x00
+#define CCM_CCDR 0x04
+#define CCM_CSR 0x08
+#define CCM_CCSR 0x0C
+#define CCM_CACRR 0x10
+#define CCM_CBCDR 0x14
+#define CCM_CBCMR 0x18
+#define CCM_CSCMR1 0x1C
+#define CCM_CSCMR2 0x20
+#define CCM_CSCDR1 0x24
+#define CCM_CS1CDR 0x28
+#define CCM_CS2CDR 0x2C
+#define CCM_CDCDR 0x30
+#define CCM_CHSCDR 0x34
+#define CCM_CSCDR2 0x38
+#define CCM_CSCDR3 0x3C
+#define CCM_CSCDR4 0x40
+#define CCM_CWDR 0x44
+#define CCM_CDHIPR 0x48
+#define CCM_CDCR 0x4C
+#define CCM_CTOR 0x50
+#define CCM_CLPCR 0x54
+#define CCM_CISR 0x58
+#define CCM_CIMR 0x5C
+#define CCM_CCOSR 0x60
+#define CCM_CGPR 0x64
+#define CCM_CCGR0 0x68
+#define CCM_CCGR1 0x6C
+#define CCM_CCGR2 0x70
+#define CCM_CCGR3 0x74
+#define CCM_CCGR4 0x78
+#define CCM_CCGR5 0x7C
+#define CCM_CCGR6 0x80
+#define CCM_CCGR7 0x84
+
+#define CCM_CMEOR 0x84
+
+static struct clk *clks[IMX5_CLK_END];
+
+/* This is used multiple times */
+static const char *standard_pll_sel[] = {
+ "pll1_sw",
+ "pll2_sw",
+ "pll3_sw",
+ "lp_apm",
+};
+
+static const char *mx50_3bit_clk_sel[] = {
+ "pll1_sw",
+ "pll2_sw",
+ "pll3_sw",
+ "lp_apm",
+ "pfd0",
+ "pfd1",
+ "pfd4",
+ "osc",
+};
+
+static const char *lp_apm_sel[] = {
+ "osc",
+};
+
+static const char *periph_apm_sel[] = {
+ "pll1_sw",
+ "pll3_sw",
+ "lp_apm",
+};
+
+static const char *main_bus_sel[] = {
+ "pll2_sw",
+ "periph_apm",
+};
+
+static const char *mx50_periph_clk_sel[] = {
+ "pll1_sw",
+ "pll2_sw",
+ "pll3_sw",
+ "lp_apm",
+};
+
+static const char *per_lp_apm_sel[] = {
+ "main_bus",
+ "lp_apm",
+};
+
+static const char *per_root_sel[] = {
+ "per_podf",
+ "ipg",
+};
+
+static const char *esdhc_c_sel[] = {
+ "esdhc_a_podf",
+ "esdhc_b_podf",
+};
+
+static const char *esdhc_d_sel[] = {
+ "esdhc_a_podf",
+ "esdhc_b_podf",
+};
+
+static const char *emi_slow_sel[] = {
+ "main_bus",
+ "ahb",
+};
+
+static const char *usb_phy_sel_str[] = {
+ "osc",
+ "usb_phy_podf",
+};
+
+static const char *mx51_ipu_di0_sel[] = {
+ "di_pred",
+ "osc",
+ "ckih1",
+ "tve_di",
+};
+
+static const char *mx53_ipu_di0_sel[] = {
+ "di_pred",
+ "osc",
+ "ckih1",
+ "di_pll4_podf",
+ "dummy",
+ "ldb_di0_div",
+};
+
+static const char *mx53_ldb_di0_sel[] = {
+ "pll3_sw",
+ "pll4_sw",
+};
+
+static const char *mx51_ipu_di1_sel[] = {
+ "di_pred",
+ "osc",
+ "ckih1",
+ "tve_di",
+ "ipp_di1",
+};
+
+static const char *mx53_ipu_di1_sel[] = {
+ "di_pred",
+ "osc",
+ "ckih1",
+ "tve_di",
+ "ipp_di1",
+ "ldb_di1_div",
+};
+
+static const char *mx53_ldb_di1_sel[] = {
+ "pll3_sw",
+ "pll4_sw",
+};
+
+static const char *mx51_tve_ext_sel[] = {
+ "osc",
+ "ckih1",
+};
+
+static const char *mx53_tve_ext_sel[] = {
+ "pll4_sw",
+ "ckih1",
+};
+
+static const char *mx51_tve_sel[] = {
+ "tve_pred",
+ "tve_ext_sel",
+};
+
+static const char *ipu_sel[] = {
+ "axi_a",
+ "axi_b",
+ "emi_slow_gate",
+ "ahb",
+};
+
+static void __init mx5_clocks_common_init(struct device_d *dev, void __iomem *base)
+{
+ writel(0xffffffff, base + CCM_CCGR0);
+ writel(0xffffffff, base + CCM_CCGR1);
+ writel(0xffffffff, base + CCM_CCGR2);
+ writel(0xffffffff, base + CCM_CCGR3);
+ writel(0xffffffff, base + CCM_CCGR4);
+ writel(0xffffffff, base + CCM_CCGR5);
+ writel(0xffffffff, base + CCM_CCGR6);
+ writel(0xffffffff, base + CCM_CCGR7);
+
+ if (!IS_ENABLED(CONFIG_COMMON_CLK_OF_PROVIDER) || !dev->device_node) {
+ clks[IMX5_CLK_CKIL] = clk_fixed("ckil", 32768);
+ clks[IMX5_CLK_OSC] = clk_fixed("osc", 24000000);
+ }
+
+ clks[IMX5_CLK_PER_LP_APM] = imx_clk_mux("per_lp_apm", base + CCM_CBCMR, 1, 1,
+ per_lp_apm_sel, ARRAY_SIZE(per_lp_apm_sel));
+ clks[IMX5_CLK_PER_PRED1] = imx_clk_divider("per_pred1", "per_lp_apm", base + CCM_CBCDR, 6, 2);
+ clks[IMX5_CLK_PER_PRED2] = imx_clk_divider("per_pred2", "per_pred1", base + CCM_CBCDR, 3, 3);
+ clks[IMX5_CLK_PER_PODF] = imx_clk_divider("per_podf", "per_pred2", base + CCM_CBCDR, 0, 3);
+ clks[IMX5_CLK_PER_ROOT] = imx_clk_mux("per_root", base + CCM_CBCMR, 0, 1,
+ per_root_sel, ARRAY_SIZE(per_root_sel));
+ clks[IMX5_CLK_AHB] = imx_clk_divider("ahb", "main_bus", base + CCM_CBCDR, 10, 3);
+ clks[IMX5_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + CCM_CBCDR, 8, 2);
+ clks[IMX5_CLK_AXI_A] = imx_clk_divider("axi_a", "main_bus", base + CCM_CBCDR, 16, 3);
+ clks[IMX5_CLK_AXI_B] = imx_clk_divider("axi_b", "main_bus", base + CCM_CBCDR, 19, 3);
+ clks[IMX5_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + CCM_CSCMR1, 24, 2,
+ standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
+ clks[IMX5_CLK_UART_PRED] = imx_clk_divider("uart_pred", "uart_sel", base + CCM_CSCDR1, 3, 3);
+ clks[IMX5_CLK_UART_ROOT] = imx_clk_divider("uart_root", "uart_pred", base + CCM_CSCDR1, 0, 3);
+ clks[IMX5_CLK_ESDHC_A_PRED] = imx_clk_divider("esdhc_a_pred",
+ "esdhc_a_sel", base + CCM_CSCDR1, 16, 3);
+ clks[IMX5_CLK_ESDHC_A_PODF] = imx_clk_divider("esdhc_a_podf",
+ "esdhc_a_pred", base + CCM_CSCDR1, 11, 3);
+ clks[IMX5_CLK_ESDHC_B_PRED] = imx_clk_divider("esdhc_b_pred",
+ "esdhc_b_sel", base + CCM_CSCDR1, 22, 3);
+ clks[IMX5_CLK_ESDHC_B_PODF] = imx_clk_divider("esdhc_b_podf",
+ "esdhc_b_pred", base + CCM_CSCDR1, 19, 3);
+ clks[IMX5_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + CCM_CSCMR1,
+ 4, 2, standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
+ clks[IMX5_CLK_ECSPI_PRED] = imx_clk_divider("ecspi_pred",
+ "ecspi_sel", base + CCM_CSCDR2, 25, 3);
+ clks[IMX5_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf",
+ "ecspi_pred", base + CCM_CSCDR2, 19, 6);
+ clks[IMX5_CLK_CPU_PODF] = imx_clk_divider("cpu_podf",
+ "pll1_sw", base + CCM_CACRR, 0, 3);
+}
+
+static void mx5_clocks_mx51_mx53_init(void __iomem *base)
+{
+ clks[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", base + CCM_CCSR, 9, 1,
+ lp_apm_sel, ARRAY_SIZE(lp_apm_sel));
+ clks[IMX5_CLK_PERIPH_APM] = imx_clk_mux("periph_apm", base + CCM_CBCMR, 12, 2,
+ periph_apm_sel, ARRAY_SIZE(periph_apm_sel));
+ clks[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", base + CCM_CBCDR, 25, 1,
+ main_bus_sel, ARRAY_SIZE(main_bus_sel));
+ clks[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", base + CCM_CSCMR1, 20, 2,
+ standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
+ clks[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", base + CCM_CSCMR1, 16, 2,
+ standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
+ clks[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", base + CCM_CSCMR1, 19, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel));
+ clks[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", base + CCM_CSCMR1, 18, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel));
+ clks[IMX5_CLK_EMI_SEL] = imx_clk_mux("emi_sel", base + CCM_CBCDR, 26, 1,
+ emi_slow_sel, ARRAY_SIZE(emi_slow_sel));
+ clks[IMX5_CLK_EMI_SLOW_PODF] = imx_clk_divider("emi_slow_podf", "emi_sel", base + CCM_CBCDR, 22, 3);
+ clks[IMX5_CLK_NFC_PODF] = imx_clk_divider("nfc_podf", "emi_slow_podf", base + CCM_CBCDR, 13, 3);
+ clks[IMX5_CLK_USBOH3_SEL] = imx_clk_mux("usboh3_sel", base + CCM_CSCMR1, 22, 2,
+ standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
+ clks[IMX5_CLK_USBOH3_PRED] = imx_clk_divider("usboh3_pred", "usboh3_sel", base + CCM_CSCDR1, 8, 3);
+ clks[IMX5_CLK_USBOH3_PODF] = imx_clk_divider("usboh3_podf", "usboh3_pred", base + CCM_CSCDR1, 6, 2);
+ clks[IMX5_CLK_USB_PHY_PRED] = imx_clk_divider("usb_phy_pred", "pll3_sw", base + CCM_CDCDR, 3, 3);
+ clks[IMX5_CLK_USB_PHY_PODF] = imx_clk_divider("usb_phy_podf", "usb_phy_pred", base + CCM_CDCDR, 0, 3);
+ clks[IMX5_CLK_USB_PHY_SEL] = imx_clk_mux("usb_phy_sel", base + CCM_CSCMR1, 26, 1,
+ usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str));
+}
+
+static void mx5_clocks_ipu_init(void __iomem *regs)
+{
+ clks[IMX5_CLK_IPU_SEL] = imx_clk_mux("ipu_sel", regs + CCM_CBCMR, 6, 2, ipu_sel, ARRAY_SIZE(ipu_sel));
+}
+
+int __init mx50_clocks_init(struct device_d *dev, void __iomem *regs)
+{
+ clks[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc",
+ (void *)MX50_PLL1_BASE_ADDR);
+ clks[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc",
+ (void *)MX50_PLL2_BASE_ADDR);
+ clks[IMX5_CLK_PLL3_SW] = imx_clk_pllv2("pll3_sw", "osc",
+ (void *)MX50_PLL3_BASE_ADDR);
+
+ mx5_clocks_common_init(dev, regs);
+
+ clks[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", regs + CCM_CCSR, 10, 1, lp_apm_sel, ARRAY_SIZE(lp_apm_sel));
+ clks[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", regs + CCM_CBCDR, 25, 2, mx50_periph_clk_sel, ARRAY_SIZE(mx50_periph_clk_sel));
+ clks[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", regs + CCM_CSCMR1, 21, 2, standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
+ clks[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", regs + CCM_CSCMR1, 16, 3, mx50_3bit_clk_sel, ARRAY_SIZE(mx50_3bit_clk_sel));
+ clks[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", regs + CCM_CSCMR1, 20, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel));
+ clks[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", regs + CCM_CSCMR1, 19, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel));
+ clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX50_UART1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX50_UART2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX50_UART3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_I2C1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_I2C2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_I2C3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_GPT1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_IPG], MX50_CSPI_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX50_ECSPI1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX50_ECSPI2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_IPG], MX50_FEC_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ESDHC_A_PODF], MX50_ESDHC1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ESDHC_C_SEL], MX50_ESDHC2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ESDHC_B_PODF], MX50_ESDHC3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ESDHC_D_SEL], MX50_ESDHC4_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_PWM1_BASE_ADDR, "per");
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX50_PWM2_BASE_ADDR, "per");
+
+ return 0;
+}
+
+static int imx50_ccm_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ void __iomem *regs;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ regs = IOMEM(iores->start);
+
+ mx50_clocks_init(dev, regs);
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id imx50_ccm_dt_ids[] = {
+ {
+ .compatible = "fsl,imx50-ccm",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d imx50_ccm_driver = {
+ .probe = imx50_ccm_probe,
+ .name = "imx50-ccm",
+ .of_compatible = DRV_OF_COMPAT(imx50_ccm_dt_ids),
+};
+
+static void mx51_clocks_ipu_init(void __iomem *regs)
+{
+ clks[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux_p("ipu_di0_sel", regs + CCM_CSCMR2, 26, 3,
+ mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel));
+ clks[IMX5_CLK_IPU_DI1_SEL] = imx_clk_mux_p("ipu_di1_sel", regs + CCM_CSCMR2, 29, 3,
+ mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel));
+ clks[IMX5_CLK_TVE_EXT_SEL] = imx_clk_mux_p("tve_ext_sel", regs + CCM_CSCMR1, 6, 1,
+ mx51_tve_ext_sel, ARRAY_SIZE(mx51_tve_ext_sel));
+ clks[IMX5_CLK_TVE_SEL] = imx_clk_mux("tve_sel", regs + CCM_CSCMR1, 7, 1,
+ mx51_tve_sel, ARRAY_SIZE(mx51_tve_sel));
+ clks[IMX5_CLK_TVE_PRED] = imx_clk_divider("tve_pred", "pll3_sw", regs + CCM_CDCDR, 28, 3);
+
+ mx5_clocks_ipu_init(regs);
+
+ clkdev_add_physbase(clks[IMX5_CLK_IPU_SEL], MX51_IPU_BASE_ADDR, "bus");
+ clkdev_add_physbase(clks[IMX5_CLK_IPU_DI0_SEL], MX51_IPU_BASE_ADDR, "di0");
+ clkdev_add_physbase(clks[IMX5_CLK_IPU_DI1_SEL], MX51_IPU_BASE_ADDR, "di1");
+}
+
+int __init mx51_clocks_init(struct device_d *dev, void __iomem *regs)
+{
+ clks[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", (void *)MX51_PLL1_BASE_ADDR);
+ clks[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", (void *)MX51_PLL2_BASE_ADDR);
+ clks[IMX5_CLK_PLL3_SW] = imx_clk_pllv2("pll3_sw", "osc", (void *)MX51_PLL3_BASE_ADDR);
+
+ mx5_clocks_common_init(dev, regs);
+ mx5_clocks_mx51_mx53_init(regs);
+
+ clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX51_UART1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX51_UART2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX51_UART3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_I2C1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_I2C2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_GPT1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_IPG], MX51_CSPI_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX51_ECSPI1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX51_ECSPI2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_IPG], MX51_MXC_FEC_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ESDHC_A_PODF], MX51_MMC_SDHC1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ESDHC_B_PODF], MX51_MMC_SDHC2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ESDHC_C_SEL], MX51_MMC_SDHC3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ESDHC_D_SEL], MX51_MMC_SDHC4_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_IPG], MX51_ATA_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_PWM1_BASE_ADDR, "per");
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX51_PWM2_BASE_ADDR, "per");
+
+ if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3))
+ mx51_clocks_ipu_init(regs);
+
+ return 0;
+}
+
+static int imx51_ccm_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ void __iomem *regs;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ regs = IOMEM(iores->start);
+
+ mx51_clocks_init(dev, regs);
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id imx51_ccm_dt_ids[] = {
+ {
+ .compatible = "fsl,imx51-ccm",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d imx51_ccm_driver = {
+ .probe = imx51_ccm_probe,
+ .name = "imx51-ccm",
+ .of_compatible = DRV_OF_COMPAT(imx51_ccm_dt_ids),
+};
+
+static void mx53_clocks_ipu_init(void __iomem *regs)
+{
+ clks[IMX5_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+ clks[IMX5_CLK_LDB_DI1_DIV] = imx_clk_divider_np("ldb_di1_div", "ldb_di1_div_3_5", regs + CCM_CSCMR2, 11, 1);
+ clks[IMX5_CLK_LDB_DI1_SEL] = imx_clk_mux_p("ldb_di1_sel", regs + CCM_CSCMR2, 9, 1,
+ mx53_ldb_di1_sel, ARRAY_SIZE(mx53_ldb_di1_sel));
+ clks[IMX5_CLK_DI_PLL4_PODF] = imx_clk_divider("di_pll4_podf", "pll4_sw", regs + CCM_CDCDR, 16, 3);
+ clks[IMX5_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+ clks[IMX5_CLK_LDB_DI0_DIV] = imx_clk_divider("ldb_di0_div", "ldb_di0_div_3_5", regs + CCM_CSCMR2, 10, 1);
+ clks[IMX5_CLK_LDB_DI0_SEL] = imx_clk_mux_p("ldb_di0_sel", regs + CCM_CSCMR2, 8, 1,
+ mx53_ldb_di0_sel, ARRAY_SIZE(mx53_ldb_di0_sel));
+ clks[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux_p("ipu_di0_sel", regs + CCM_CSCMR2, 26, 3,
+ mx53_ipu_di0_sel, ARRAY_SIZE(mx53_ipu_di0_sel));
+ clks[IMX5_CLK_IPU_DI1_SEL] = imx_clk_mux_p("ipu_di1_sel", regs + CCM_CSCMR2, 29, 3,
+ mx53_ipu_di1_sel, ARRAY_SIZE(mx53_ipu_di1_sel));
+ clks[IMX5_CLK_TVE_EXT_SEL] = imx_clk_mux_p("tve_ext_sel", regs + CCM_CSCMR1, 6, 1,
+ mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel));
+ clks[IMX5_CLK_TVE_PRED] = imx_clk_divider("tve_pred", "tve_ext_sel", regs + CCM_CDCDR, 28, 3);
+
+ mx5_clocks_ipu_init(regs);
+
+ clkdev_add_physbase(clks[IMX5_CLK_IPU_SEL], MX53_IPU_BASE_ADDR, "bus");
+ clkdev_add_physbase(clks[IMX5_CLK_IPU_DI0_SEL], MX53_IPU_BASE_ADDR, "di0");
+ clkdev_add_physbase(clks[IMX5_CLK_IPU_DI1_SEL], MX53_IPU_BASE_ADDR, "di1");
+}
+
+int __init mx53_clocks_init(struct device_d *dev, void __iomem *regs)
+{
+ clks[IMX5_CLK_PLL1_SW] = imx_clk_pllv2("pll1_sw", "osc", (void *)MX53_PLL1_BASE_ADDR);
+ clks[IMX5_CLK_PLL2_SW] = imx_clk_pllv2("pll2_sw", "osc", (void *)MX53_PLL2_BASE_ADDR);
+ clks[IMX5_CLK_PLL3_SW] = imx_clk_pllv2("pll3_sw", "osc", (void *)MX53_PLL3_BASE_ADDR);
+ clks[IMX5_CLK_PLL4_SW] = imx_clk_pllv2("pll4_sw", "osc", (void *)MX53_PLL4_BASE_ADDR);
+
+ mx5_clocks_common_init(dev, regs);
+ mx5_clocks_mx51_mx53_init(regs);
+
+ clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART4_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_UART_ROOT], MX53_UART5_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_I2C1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_I2C2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_I2C3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_GPT1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_IPG], MX53_CSPI_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX53_ECSPI1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ECSPI_PODF], MX53_ECSPI2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_IPG], MX53_FEC_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ESDHC_A_PODF], MX53_ESDHC1_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ESDHC_C_SEL], MX53_ESDHC2_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ESDHC_B_PODF], MX53_ESDHC3_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_ESDHC_D_SEL], MX53_ESDHC4_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_AHB], MX53_SATA_BASE_ADDR, NULL);
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_PWM1_BASE_ADDR, "per");
+ clkdev_add_physbase(clks[IMX5_CLK_PER_ROOT], MX53_PWM2_BASE_ADDR, "per");
+
+ if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3))
+ mx53_clocks_ipu_init(regs);
+
+ return 0;
+}
+
+static int imx53_ccm_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ void __iomem *regs;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ regs = IOMEM(iores->start);
+
+ mx53_clocks_init(dev, regs);
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id imx53_ccm_dt_ids[] = {
+ {
+ .compatible = "fsl,imx53-ccm",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d imx53_ccm_driver = {
+ .probe = imx53_ccm_probe,
+ .name = "imx53-ccm",
+ .of_compatible = DRV_OF_COMPAT(imx53_ccm_dt_ids),
+};
+
+static int imx5_ccm_init(void)
+{
+ if (IS_ENABLED(CONFIG_ARCH_IMX50))
+ platform_driver_register(&imx50_ccm_driver);
+ if (IS_ENABLED(CONFIG_ARCH_IMX51))
+ platform_driver_register(&imx51_ccm_driver);
+ if (IS_ENABLED(CONFIG_ARCH_IMX53))
+ platform_driver_register(&imx53_ccm_driver);
+
+ return 0;
+}
+core_initcall(imx5_ccm_init);
diff --git a/drivers/clk/imx/clk-imx6.c b/drivers/clk/imx/clk-imx6.c
new file mode 100644
index 0000000000..8ac43bebb0
--- /dev/null
+++ b/drivers/clk/imx/clk-imx6.c
@@ -0,0 +1,541 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <of.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <mach/imx6-regs.h>
+#include <mach/revision.h>
+#include <mach/imx6.h>
+#include <dt-bindings/clock/imx6qdl-clock.h>
+
+#include "clk.h"
+
+#define CCGR0 0x68
+#define CCGR1 0x6c
+#define CCGR2 0x70
+#define CCGR3 0x74
+#define CCGR4 0x78
+#define CCGR5 0x7c
+#define CCGR6 0x80
+#define CCGR7 0x84
+
+#define CLPCR 0x54
+#define BP_CLPCR_LPM 0
+#define BM_CLPCR_LPM (0x3 << 0)
+#define BM_CLPCR_BYPASS_PMIC_READY (0x1 << 2)
+#define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5)
+#define BM_CLPCR_SBYOS (0x1 << 6)
+#define BM_CLPCR_DIS_REF_OSC (0x1 << 7)
+#define BM_CLPCR_VSTBY (0x1 << 8)
+#define BP_CLPCR_STBY_COUNT 9
+#define BM_CLPCR_STBY_COUNT (0x3 << 9)
+#define BM_CLPCR_COSC_PWRDOWN (0x1 << 11)
+#define BM_CLPCR_WB_PER_AT_LPM (0x1 << 16)
+#define BM_CLPCR_WB_CORE_AT_LPM (0x1 << 17)
+#define BM_CLPCR_BYP_MMDC_CH0_LPM_HS (0x1 << 19)
+#define BM_CLPCR_BYP_MMDC_CH1_LPM_HS (0x1 << 21)
+#define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22)
+#define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23)
+#define BM_CLPCR_MASK_CORE2_WFI (0x1 << 24)
+#define BM_CLPCR_MASK_CORE3_WFI (0x1 << 25)
+#define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26)
+#define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27)
+
+static struct clk *clks[IMX6QDL_CLK_END];
+static struct clk_onecell_data clk_data;
+
+static const char *step_sels[] = {
+ "osc",
+ "pll2_pfd2_396m",
+};
+
+static const char *pll1_sw_sels[] = {
+ "pll1_sys",
+ "step",
+};
+
+static const char *periph_pre_sels[] = {
+ "pll2_bus",
+ "pll2_pfd2_396m",
+ "pll2_pfd0_352m",
+ "pll2_198m",
+};
+
+static const char *periph_clk2_sels[] = {
+ "pll3_usb_otg",
+ "osc",
+};
+
+static const char *periph_sels[] = {
+ "periph_pre",
+ "periph_clk2",
+};
+
+static const char *periph2_sels[] = {
+ "periph2_pre",
+ "periph2_clk2",
+};
+
+static const char *axi_sels[] = {
+ "periph",
+ "pll2_pfd2_396m",
+ "pll3_pfd1_540m",
+};
+
+static const char *usdhc_sels[] = {
+ "pll2_pfd2_396m",
+ "pll2_pfd0_352m",
+};
+
+static const char *enfc_sels[] = {
+ "pll2_pfd0_352m",
+ "pll2_bus",
+ "pll3_usb_otg",
+ "pll2_pfd2_396m",
+};
+
+static const char *eim_sels[] = {
+ "axi",
+ "pll3_usb_otg",
+ "pll2_pfd2_396m",
+ "pll2_pfd0_352m",
+};
+
+static const char *vdo_axi_sels[] = {
+ "axi",
+ "ahb",
+};
+
+static const char *cko_sels[] = {
+ "cko1",
+ "cko2",
+};
+
+static const char *cko1_sels[] = {
+ "pll3_usb_otg",
+ "pll2_bus",
+ "pll1_sys",
+ "pll5_video",
+ "dummy",
+ "axi",
+ "enfc",
+ "ipu1_di0",
+ "ipu1_di1",
+ "ipu2_di0",
+ "ipu2_di1",
+ "ahb",
+ "ipg",
+ "ipg_per",
+ "ckil",
+ "pll4_audio",
+};
+
+static const char *cko2_sels[] = {
+ "mmdc_ch0_axi",
+ "mmdc_ch1_axi",
+ "usdhc4",
+ "usdhc1",
+ "gpu2d_axi",
+ "dummy",
+ "ecspi_root",
+ "gpu3d_axi",
+ "usdhc3",
+ "dummy",
+ "arm",
+ "ipu1",
+ "ipu2",
+ "vdo_axi",
+ "osc",
+ "gpu2d_core",
+ "gpu3d_core",
+ "usdhc2",
+ "ssi1",
+ "ssi2",
+ "ssi3",
+ "gpu3d_shader",
+ "vpu_axi",
+ "can_root",
+ "ldb_di0",
+ "ldb_di1",
+ "esai",
+ "eim_slow",
+ "uart_serial",
+ "spdif",
+ "asrc",
+ "hsi_tx",
+};
+
+static const char *ipu_sels[] = {
+ "mmdc_ch0_axi_podf",
+ "pll2_pfd2_396m",
+ "pll3_120m",
+ "pll3_pfd1_540m",
+};
+
+static const char *ldb_di_sels[] = {
+ "pll5_video_div",
+ "pll2_pfd0_352m",
+ "pll2_pfd2_396m",
+ "mmdc_ch1_axi_podf",
+ "pll3_usb_otg",
+};
+
+static const char *ipu_di_pre_sels[] = {
+ "mmdc_ch0_axi",
+ "pll3_usb_otg",
+ "pll5_video_div",
+ "pll2_pfd0_352m",
+ "pll2_pfd2_396m",
+ "pll3_pfd1_540m",
+};
+
+static const char *ipu1_di0_sels[] = {
+ "ipu1_di0_pre",
+ "dummy",
+ "dummy",
+ "ldb_di0_podf",
+ "ldb_di1_podf",
+};
+
+static const char *ipu1_di1_sels[] = {
+ "ipu1_di1_pre",
+ "dummy",
+ "dummy",
+ "ldb_di0_podf",
+ "ldb_di1_podf",
+};
+
+static const char *ipu2_di0_sels[] = {
+ "ipu2_di0_pre",
+ "dummy",
+ "dummy",
+ "ldb_di0_podf",
+ "ldb_di1_podf",
+};
+
+static const char *ipu2_di1_sels[] = {
+ "ipu2_di1_pre",
+ "dummy",
+ "dummy",
+ "ldb_di0_podf",
+ "ldb_di1_podf",
+};
+
+static const char *lvds_sels[] = {
+ "dummy",
+ "dummy",
+ "dummy",
+ "dummy",
+ "dummy",
+ "dummy",
+ "pll4_audio",
+ "pll5_video",
+ "pll8_mlb",
+ "enet_ref",
+ "pcie_ref_125m",
+ "sata_ref_100m",
+};
+
+static const char *pcie_axi_sels[] = {
+ "axi",
+ "ahb",
+};
+
+static struct clk_div_table clk_enet_ref_table[] = {
+ { .val = 0, .div = 20, },
+ { .val = 1, .div = 10, },
+ { .val = 2, .div = 5, },
+ { .val = 3, .div = 4, },
+ { },
+};
+
+static struct clk_div_table post_div_table[] = {
+ { .val = 2, .div = 1, },
+ { .val = 1, .div = 2, },
+ { .val = 0, .div = 4, },
+ { /* sentinel */ }
+};
+
+static struct clk_div_table video_div_table[] = {
+ { .val = 0, .div = 1, },
+ { .val = 1, .div = 2, },
+ { .val = 2, .div = 1, },
+ { .val = 3, .div = 4, },
+ { /* sentinel */ }
+};
+
+static void imx6_add_video_clks(void __iomem *anab, void __iomem *cb)
+{
+ clks[IMX6QDL_CLK_PLL5_POST_DIV] = imx_clk_divider_table("pll5_post_div", "pll5_video", anab + 0xa0, 19, 2, post_div_table);
+ clks[IMX6QDL_CLK_PLL5_VIDEO_DIV] = imx_clk_divider_table("pll5_video_div", "pll5_post_div", anab + 0x170, 30, 2, video_div_table);
+
+ clks[IMX6QDL_CLK_IPU1_SEL] = imx_clk_mux("ipu1_sel", cb + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels));
+ clks[IMX6QDL_CLK_IPU2_SEL] = imx_clk_mux("ipu2_sel", cb + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels));
+ clks[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_p("ldb_di0_sel", cb + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels));
+ clks[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_p("ldb_di1_sel", cb + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels));
+ clks[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_mux_p("ipu1_di0_pre_sel", cb + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels));
+ clks[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_mux_p("ipu1_di1_pre_sel", cb + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels));
+ clks[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_mux_p("ipu2_di0_pre_sel", cb + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels));
+ clks[IMX6QDL_CLK_IPU2_DI1_PRE_SEL] = imx_clk_mux_p("ipu2_di1_pre_sel", cb + 0x38, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels));
+ clks[IMX6QDL_CLK_IPU1_DI0_SEL] = imx_clk_mux_p("ipu1_di0_sel", cb + 0x34, 0, 3, ipu1_di0_sels, ARRAY_SIZE(ipu1_di0_sels));
+ clks[IMX6QDL_CLK_IPU1_DI1_SEL] = imx_clk_mux_p("ipu1_di1_sel", cb + 0x34, 9, 3, ipu1_di1_sels, ARRAY_SIZE(ipu1_di1_sels));
+ clks[IMX6QDL_CLK_IPU2_DI0_SEL] = imx_clk_mux_p("ipu2_di0_sel", cb + 0x38, 0, 3, ipu2_di0_sels, ARRAY_SIZE(ipu2_di0_sels));
+ clks[IMX6QDL_CLK_IPU2_DI1_SEL] = imx_clk_mux_p("ipu2_di1_sel", cb + 0x38, 9, 3, ipu2_di1_sels, ARRAY_SIZE(ipu2_di1_sels));
+
+ clks[IMX6QDL_CLK_IPU1_PODF] = imx_clk_divider("ipu1_podf", "ipu1_sel", cb + 0x3c, 11, 3);
+ clks[IMX6QDL_CLK_IPU2_PODF] = imx_clk_divider("ipu2_podf", "ipu2_sel", cb + 0x3c, 16, 3);
+ clks[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+ clks[IMX6QDL_CLK_LDB_DI0_PODF] = imx_clk_divider_np("ldb_di0_podf", "ldb_di0_div_3_5", cb + 0x20, 10, 1);
+ clks[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+ clks[IMX6QDL_CLK_LDB_DI1_PODF] = imx_clk_divider_np("ldb_di1_podf", "ldb_di1_div_3_5", cb + 0x20, 11, 1);
+ clks[IMX6QDL_CLK_IPU1_DI0_PRE] = imx_clk_divider("ipu1_di0_pre", "ipu1_di0_pre_sel", cb + 0x34, 3, 3);
+ clks[IMX6QDL_CLK_IPU1_DI1_PRE] = imx_clk_divider("ipu1_di1_pre", "ipu1_di1_pre_sel", cb + 0x34, 12, 3);
+ clks[IMX6QDL_CLK_IPU2_DI0_PRE] = imx_clk_divider("ipu2_di0_pre", "ipu2_di0_pre_sel", cb + 0x38, 3, 3);
+ clks[IMX6QDL_CLK_IPU2_DI1_PRE] = imx_clk_divider("ipu2_di1_pre", "ipu2_di1_pre_sel", cb + 0x38, 12, 3);
+
+ clks[IMX6QDL_CLK_IPU1] = imx_clk_gate2("ipu1", "ipu1_podf", cb + 0x74, 0);
+ clks[IMX6QDL_CLK_IPU1_DI0] = imx_clk_gate2("ipu1_di0", "ipu1_di0_sel", cb + 0x74, 2);
+ clks[IMX6QDL_CLK_IPU1_DI1] = imx_clk_gate2("ipu1_di1", "ipu1_di1_sel", cb + 0x74, 4);
+ clks[IMX6QDL_CLK_IPU2] = imx_clk_gate2("ipu2", "ipu2_podf", cb + 0x74, 6);
+ clks[IMX6QDL_CLK_IPU2_DI0] = imx_clk_gate2("ipu2_di0", "ipu2_di0_sel", cb + 0x74, 8);
+ clks[IMX6QDL_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_podf", cb + 0x74, 12);
+ clks[IMX6QDL_CLK_LDB_DI1] = imx_clk_gate2("ldb_di1", "ldb_di1_podf", cb + 0x74, 14);
+ clks[IMX6QDL_CLK_IPU2_DI1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", cb + 0x74, 10);
+
+ clk_set_parent(clks[IMX6QDL_CLK_IPU1_DI0_SEL], clks[IMX6QDL_CLK_IPU1_DI0_PRE]);
+ clk_set_parent(clks[IMX6QDL_CLK_IPU1_DI1_SEL], clks[IMX6QDL_CLK_IPU1_DI1_PRE]);
+ clk_set_parent(clks[IMX6QDL_CLK_IPU2_DI0_SEL], clks[IMX6QDL_CLK_IPU2_DI0_PRE]);
+ clk_set_parent(clks[IMX6QDL_CLK_IPU2_DI1_SEL], clks[IMX6QDL_CLK_IPU2_DI1_PRE]);
+
+ clk_set_parent(clks[IMX6QDL_CLK_IPU1_DI0_PRE_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
+ clk_set_parent(clks[IMX6QDL_CLK_IPU1_DI1_PRE_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
+ clk_set_parent(clks[IMX6QDL_CLK_IPU2_DI0_PRE_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
+ clk_set_parent(clks[IMX6QDL_CLK_IPU2_DI1_PRE_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
+
+ if ((imx_silicon_revision() != IMX_CHIP_REV_1_0) ||
+ cpu_is_mx6dl()) {
+ clk_set_parent(clks[IMX6QDL_CLK_LDB_DI0_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
+ clk_set_parent(clks[IMX6QDL_CLK_LDB_DI1_SEL], clks[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
+ }
+
+}
+
+static int imx6_ccm_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ void __iomem *base, *anatop_base, *ccm_base;
+
+ anatop_base = (void *)MX6_ANATOP_BASE_ADDR;
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ ccm_base = IOMEM(iores->start);
+
+ base = anatop_base;
+
+ /* type name parent_name base div_mask */
+ clks[IMX6QDL_CLK_PLL1_SYS] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f);
+ clks[IMX6QDL_CLK_PLL2_BUS] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc", base + 0x30, 0x1);
+ clks[IMX6QDL_CLK_PLL3_USB_OTG] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc", base + 0x10, 0x3);
+ clks[IMX6QDL_CLK_PLL4_AUDIO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4_audio", "osc", base + 0x70, 0x7f);
+ clks[IMX6QDL_CLK_PLL5_VIDEO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "osc", base + 0xa0, 0x7f);
+ clks[IMX6QDL_CLK_PLL8_MLB] = imx_clk_pllv3(IMX_PLLV3_MLB, "pll8_mlb", "osc", base + 0xd0, 0x0);
+ clks[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_usb_host","osc", base + 0x20, 0x3);
+ clks[IMX6QDL_CLK_PLL6_ENET] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6_enet", "osc", base + 0xe0, 0x3);
+
+ clks[IMX6QDL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 6);
+ clks[IMX6QDL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 6);
+
+ clks[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5);
+ clks[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
+ clks[IMX6QDL_CLK_SATA_REF_100M] = imx_clk_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20);
+ clks[IMX6QDL_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
+
+ clks[IMX6QDL_CLK_ENET_REF] = imx_clk_divider_table("enet_ref", "pll6_enet", base + 0xe0, 0, 2, clk_enet_ref_table);
+
+ clks[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+ clks[IMX6QDL_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+
+ clks[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12));
+ clks[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13));
+
+ /* name parent_name reg idx */
+ clks[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
+ clks[IMX6QDL_CLK_PLL2_PFD1_594M] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
+ clks[IMX6QDL_CLK_PLL2_PFD2_396M] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
+ clks[IMX6QDL_CLK_PLL3_PFD0_720M] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
+ clks[IMX6QDL_CLK_PLL3_PFD1_540M] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
+ clks[IMX6QDL_CLK_PLL3_PFD2_508M] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
+ clks[IMX6QDL_CLK_PLL3_PFD3_454M] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
+
+ /* name parent_name mult div */
+ clks[IMX6QDL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
+ clks[IMX6QDL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
+ clks[IMX6QDL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
+ clks[IMX6QDL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
+ clks[IMX6QDL_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2);
+
+ base = ccm_base;
+
+ /* name reg shift width parent_names num_parents */
+ clks[IMX6QDL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
+ clks[IMX6QDL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
+ clks[IMX6QDL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+ clks[IMX6QDL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+ clks[IMX6QDL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 1, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ clks[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ clks[IMX6QDL_CLK_AXI_SEL] = imx_clk_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_sels));
+ clks[IMX6QDL_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ clks[IMX6QDL_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ clks[IMX6QDL_CLK_USDHC3_SEL] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ clks[IMX6QDL_CLK_USDHC4_SEL] = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ clks[IMX6QDL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 16, 2, enfc_sels, ARRAY_SIZE(enfc_sels));
+ clks[IMX6QDL_CLK_EIM_SEL] = imx_clk_mux("eim_sel", base + 0x1c, 27, 2, eim_sels, ARRAY_SIZE(eim_sels));
+ clks[IMX6QDL_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_sels, ARRAY_SIZE(eim_sels));
+ clks[IMX6QDL_CLK_VDO_AXI_SEL] = imx_clk_mux("vdo_axi_sel", base + 0x18, 11, 1, vdo_axi_sels, ARRAY_SIZE(vdo_axi_sels));
+ clks[IMX6QDL_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels));
+ clks[IMX6QDL_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
+ clks[IMX6QDL_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
+ clks[IMX6QDL_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels));
+
+ /* name reg shift width busy: reg, shift parent_names num_parents */
+ clks[IMX6QDL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
+ clks[IMX6QDL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
+
+ /* name parent_name reg shift width */
+ clks[IMX6QDL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
+ clks[IMX6QDL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
+ clks[IMX6QDL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
+ clks[IMX6QDL_CLK_IPG_PER] = imx_clk_divider("ipg_per", "ipg", base + 0x1c, 0, 6);
+ clks[IMX6QDL_CLK_CAN_ROOT] = imx_clk_divider("can_root", "pll3_usb_otg", base + 0x20, 2, 6);
+ clks[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6);
+ clks[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6);
+ clks[IMX6QDL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
+ clks[IMX6QDL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
+ clks[IMX6QDL_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
+ clks[IMX6QDL_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3);
+ clks[IMX6QDL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3);
+ clks[IMX6QDL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6);
+ clks[IMX6QDL_CLK_EIM_PODF] = imx_clk_divider("eim_podf", "eim_sel", base + 0x1c, 20, 3);
+ clks[IMX6QDL_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3);
+ clks[IMX6QDL_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3);
+ clks[IMX6QDL_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3);
+
+ /* name parent_name reg shift width busy: reg, shift */
+ clks[IMX6QDL_CLK_AXI] = imx_clk_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0);
+ clks[IMX6QDL_CLK_MMDC_CH0_AXI_PODF] = imx_clk_busy_divider("mmdc_ch0_axi_podf", "periph", base + 0x14, 19, 3, base + 0x48, 4);
+ clks[IMX6QDL_CLK_MMDC_CH1_AXI_PODF] = imx_clk_busy_divider("mmdc_ch1_axi_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
+ clks[IMX6QDL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
+ clks[IMX6QDL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
+
+ /* name parent_name reg shift */
+ clks[IMX6QDL_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4);
+ clks[IMX6QDL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8);
+ clks[IMX6QDL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10);
+ clks[IMX6QDL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12);
+ clks[IMX6QDL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0);
+ clks[IMX6QDL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2);
+ clks[IMX6QDL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4);
+ clks[IMX6QDL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6);
+ if (cpu_is_mx6dl())
+ clks[IMX6DL_CLK_I2C4] = imx_clk_gate2("i2c4", "ipg_per", base + 0x6c, 8);
+ else
+ clks[IMX6Q_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8);
+ clks[IMX6QDL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10);
+ clks[IMX6QDL_CLK_GPT_IPG] = imx_clk_gate2("gpt_ipg", "ipg", base + 0x6c, 20);
+ clks[IMX6QDL_CLK_GPT_IPG_PER] = imx_clk_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22);
+ clks[IMX6QDL_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6);
+ clks[IMX6QDL_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8);
+ clks[IMX6QDL_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10);
+ clks[IMX6QDL_CLK_IIM] = imx_clk_gate2("iim", "ipg", base + 0x70, 12);
+ clks[IMX6QDL_CLK_ENFC] = imx_clk_gate2("enfc", "enfc_podf", base + 0x70, 14);
+ clks[IMX6QDL_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0);
+ clks[IMX6QDL_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12);
+ clks[IMX6QDL_CLK_PWM1] = imx_clk_gate2("pwm1", "ipg_per", base + 0x78, 16);
+ clks[IMX6QDL_CLK_PWM2] = imx_clk_gate2("pwm2", "ipg_per", base + 0x78, 18);
+ clks[IMX6QDL_CLK_PWM3] = imx_clk_gate2("pwm3", "ipg_per", base + 0x78, 20);
+ clks[IMX6QDL_CLK_PWM4] = imx_clk_gate2("pwm4", "ipg_per", base + 0x78, 22);
+ clks[IMX6QDL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24);
+ clks[IMX6QDL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26);
+ clks[IMX6QDL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc", base + 0x78, 28);
+ clks[IMX6QDL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30);
+ clks[IMX6QDL_CLK_SATA] = imx_clk_gate2("sata", "ipg", base + 0x7c, 4);
+ clks[IMX6QDL_CLK_UART_IPG] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24);
+ clks[IMX6QDL_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_serial_podf", base + 0x7c, 26);
+ clks[IMX6QDL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
+ clks[IMX6QDL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
+ clks[IMX6QDL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
+ clks[IMX6QDL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
+ clks[IMX6QDL_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8);
+ clks[IMX6QDL_CLK_EIM_SLOW] = imx_clk_gate2("eim_slow", "eim_slow_podf", base + 0x80, 10);
+ clks[IMX6QDL_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7);
+ clks[IMX6QDL_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24);
+
+ clkdev_add_physbase(clks[IMX6QDL_CLK_IPG], MX6_OCOTP_BASE_ADDR, NULL);
+
+ if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3))
+ imx6_add_video_clks(anatop_base, ccm_base);
+
+ writel(0xffffffff, ccm_base + CCGR0);
+ writel(0xf0ffffff, ccm_base + CCGR1); /* gate GPU3D, GPU2D */
+ writel(0xffffffff, ccm_base + CCGR2);
+ if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3))
+ writel(0x3fffffff, ccm_base + CCGR3); /* gate OpenVG */
+ else
+ writel(0x3fff0000, ccm_base + CCGR3); /* gate OpenVG, LDB, IPU1, IPU2 */
+ if (IS_ENABLED(CONFIG_PCI_IMX6))
+ writel(0xffffffff, ccm_base + CCGR4);
+ else
+ writel(0xfffffffc, ccm_base + CCGR4); /* gate PCIe */
+ writel(0xffffffff, ccm_base + CCGR5);
+ writel(0xffff3fff, ccm_base + CCGR6); /* gate VPU */
+ writel(0xffffffff, ccm_base + CCGR7);
+
+ clk_data.clks = clks;
+ clk_data.clk_num = IMX6QDL_CLK_END;
+ of_clk_add_provider(dev->device_node, of_clk_src_onecell_get, &clk_data);
+
+ clk_enable(clks[IMX6QDL_CLK_MMDC_CH0_AXI_PODF]);
+ clk_enable(clks[IMX6QDL_CLK_PLL6_ENET]);
+ clk_enable(clks[IMX6QDL_CLK_SATA_REF_100M]);
+ clk_enable(clks[IMX6QDL_CLK_ENFC_PODF]);
+
+ clk_set_parent(clks[IMX6QDL_CLK_LVDS1_SEL], clks[IMX6QDL_CLK_SATA_REF_100M]);
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id imx6_ccm_dt_ids[] = {
+ {
+ .compatible = "fsl,imx6q-ccm",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d imx6_ccm_driver = {
+ .probe = imx6_ccm_probe,
+ .name = "imx6-ccm",
+ .of_compatible = DRV_OF_COMPAT(imx6_ccm_dt_ids),
+};
+
+static int imx6_ccm_init(void)
+{
+ return platform_driver_register(&imx6_ccm_driver);
+}
+core_initcall(imx6_ccm_init);
diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c
new file mode 100644
index 0000000000..d758957d4d
--- /dev/null
+++ b/drivers/clk/imx/clk-imx6sx.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <dt-bindings/clock/imx6sx-clock.h>
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <of.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <mach/imx6-regs.h>
+#include <mach/revision.h>
+#include <mach/imx6.h>
+
+#include "clk.h"
+#include "common.h"
+
+#define CCDR 0x4
+#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16)
+
+static const char *step_sels[] = { "osc", "pll2_pfd2_396m", };
+static const char *pll1_sw_sels[] = { "pll1_sys", "step", };
+static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", };
+static const char *periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll4_audio_div", };
+static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", };
+static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "osc", };
+static const char *periph_sels[] = { "periph_pre", "periph_clk2", };
+static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", };
+static const char *ocram_sels[] = { "periph", "pll2_pfd2_396m", "periph", "pll3_pfd1_540m", };
+static const char *gpu_axi_sels[] = { "pll2_pfd2_396m", "pll3_pfd0_720m", "pll3_pfd1_540m", "pll2_bus", };
+static const char *gpu_core_sels[] = { "pll3_pfd1_540m", "pll3_pfd0_720m", "pll2_bus", "pll2_pfd2_396m", };
+static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", };
+static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", };
+static const char *ldb_di0_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_pfd3_594m", "pll2_pfd1_594m", "pll3_pfd3_454m", };
+static const char *ldb_di1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", };
+static const char *pcie_axi_sels[] = { "axi", "ahb", };
+static const char *qspi1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", };
+static const char *perclk_sels[] = { "ipg", "osc", };
+static const char *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
+static const char *vid_sels[] = { "pll3_pfd1_540m", "pll3_usb_otg", "pll3_pfd3_454m", "pll4_audio_div", "pll5_video_div", };
+static const char *uart_sels[] = { "pll3_80m", "osc", };
+static const char *qspi2_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd3_454m", "dummy", "dummy", "dummy", };
+static const char *enet_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", };
+static const char *enet_sels[] = { "enet_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
+static const char *m4_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "osc", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd3_454m", };
+static const char *m4_sels[] = { "m4_pre_sel", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
+static const char *eim_slow_sels[] = { "ocram", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", };
+static const char *ecspi_sels[] = { "pll3_60m", "osc", };
+static const char *lcdif1_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_540m", };
+static const char *lcdif1_sels[] = { "lcdif1_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
+static const char *lcdif2_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd3_594m", "pll3_pfd1_540m", };
+static const char *lcdif2_sels[] = { "lcdif2_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
+static const char *display_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll3_usb_otg", "pll3_pfd1_540m", };
+static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", };
+static const char *cko1_sels[] = {
+ "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div",
+ "dummy", "ocram", "dummy", "pxp_axi", "epdc_axi", "lcdif_pix",
+ "epdc_pix", "ahb", "ipg", "perclk", "ckil", "pll4_audio_div",
+};
+static const char *cko2_sels[] = {
+ "dummy", "mmdc_p0_fast", "usdhc4", "usdhc1", "dummy", "wrck",
+ "ecspi_root", "dummy", "usdhc3", "pcie", "arm", "csi_core",
+ "lcdif_axi", "dummy", "osc", "dummy", "gpu2d_ovg_core",
+ "usdhc2", "ssi1", "ssi2", "ssi3", "gpu2d_core", "dummy",
+ "dummy", "dummy", "dummy", "esai_extal", "eim_slow", "uart_serial",
+ "spdif", "asrc", "dummy",
+};
+static const char *cko_sels[] = { "cko1", "cko2", };
+static const char *lvds_sels[] = {
+ "arm", "pll1_sys", "dummy", "dummy", "dummy", "dummy", "dummy", "pll5_video_div",
+ "dummy", "dummy", "pcie_ref_125m", "dummy", "usbphy1", "usbphy2",
+};
+static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", };
+static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
+static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
+static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
+static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", };
+static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
+static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
+static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
+
+static struct clk *clks[IMX6SX_CLK_CLK_END];
+static struct clk_onecell_data clk_data;
+
+static struct clk_div_table clk_enet_ref_table[] = {
+ { .val = 0, .div = 20, },
+ { .val = 1, .div = 10, },
+ { .val = 2, .div = 5, },
+ { .val = 3, .div = 4, },
+ { }
+};
+
+static struct clk_div_table post_div_table[] = {
+ { .val = 2, .div = 1, },
+ { .val = 1, .div = 2, },
+ { .val = 0, .div = 4, },
+ { }
+};
+
+static struct clk_div_table video_div_table[] = {
+ { .val = 0, .div = 1, },
+ { .val = 1, .div = 2, },
+ { .val = 2, .div = 1, },
+ { .val = 3, .div = 4, },
+ { }
+};
+
+static int imx6sx_ccm_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ void __iomem *base, *anatop_base, *ccm_base;
+ struct device_node *ccm_node = dev->device_node;
+
+ clks[IMX6SX_CLK_DUMMY] = clk_fixed("dummy", 0);
+
+ anatop_base = (void *)MX6_ANATOP_BASE_ADDR;
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ ccm_base = IOMEM(iores->start);
+
+ base = anatop_base;
+
+ clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6SX_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6SX_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6SX_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6SX_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6SX_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+
+ /* type name parent_name base div_mask */
+ clks[IMX6SX_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
+ clks[IMX6SX_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
+ clks[IMX6SX_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
+ clks[IMX6SX_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
+ clks[IMX6SX_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
+ clks[IMX6SX_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
+ clks[IMX6SX_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
+
+ clks[IMX6SX_PLL1_BYPASS] = imx_clk_mux_p("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels));
+ clks[IMX6SX_PLL2_BYPASS] = imx_clk_mux_p("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels));
+ clks[IMX6SX_PLL3_BYPASS] = imx_clk_mux_p("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels));
+ clks[IMX6SX_PLL4_BYPASS] = imx_clk_mux_p("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels));
+ clks[IMX6SX_PLL5_BYPASS] = imx_clk_mux_p("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels));
+ clks[IMX6SX_PLL6_BYPASS] = imx_clk_mux_p("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels));
+ clks[IMX6SX_PLL7_BYPASS] = imx_clk_mux_p("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels));
+
+ /* Do not bypass PLLs initially */
+ clk_set_parent(clks[IMX6SX_PLL1_BYPASS], clks[IMX6SX_CLK_PLL1]);
+ clk_set_parent(clks[IMX6SX_PLL2_BYPASS], clks[IMX6SX_CLK_PLL2]);
+ clk_set_parent(clks[IMX6SX_PLL3_BYPASS], clks[IMX6SX_CLK_PLL3]);
+ clk_set_parent(clks[IMX6SX_PLL4_BYPASS], clks[IMX6SX_CLK_PLL4]);
+ clk_set_parent(clks[IMX6SX_PLL5_BYPASS], clks[IMX6SX_CLK_PLL5]);
+ clk_set_parent(clks[IMX6SX_PLL6_BYPASS], clks[IMX6SX_CLK_PLL6]);
+ clk_set_parent(clks[IMX6SX_PLL7_BYPASS], clks[IMX6SX_CLK_PLL7]);
+
+ clks[IMX6SX_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
+ clks[IMX6SX_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
+ clks[IMX6SX_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
+ clks[IMX6SX_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
+ clks[IMX6SX_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
+ clks[IMX6SX_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
+ clks[IMX6SX_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+
+ /*
+ * Bit 20 is the reserved and read-only bit, we do this only for:
+ * - Do nothing for usbphy clk_enable/disable
+ * - Keep refcount when do usbphy clk_enable/disable, in that case,
+ * the clk framework may need to enable/disable usbphy's parent
+ */
+ clks[IMX6SX_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
+ clks[IMX6SX_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+
+ /*
+ * usbphy*_gate needs to be on after system boots up, and software
+ * never needs to control it anymore.
+ */
+ clks[IMX6SX_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+ clks[IMX6SX_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
+
+ /* FIXME 100Mhz is used for pcie ref for all imx6 pcie, excepted imx6q */
+ clks[IMX6SX_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 5);
+ clks[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
+
+ clks[IMX6SX_CLK_ENET_REF] = imx_clk_divider_table("enet_ref", "pll6_enet",
+ base + 0xe0, 0, 2, clk_enet_ref_table);
+ clks[IMX6SX_CLK_ENET2_REF] = imx_clk_divider_table("enet2_ref", "pll6_enet",
+ base + 0xe0, 2, 2, clk_enet_ref_table);
+ clks[IMX6SX_CLK_ENET2_REF_125M] = imx_clk_gate("enet2_ref_125m", "enet2_ref", base + 0xe0, 20);
+
+ clks[IMX6SX_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
+ clks[IMX6SX_CLK_ENET_PTP] = imx_clk_gate("enet_ptp_25m", "enet_ptp_ref", base + 0xe0, 21);
+
+ /* name parent_name reg idx */
+ clks[IMX6SX_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
+ clks[IMX6SX_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
+ clks[IMX6SX_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
+ clks[IMX6SX_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3);
+ clks[IMX6SX_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
+ clks[IMX6SX_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
+ clks[IMX6SX_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
+ clks[IMX6SX_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
+
+ /* name parent_name mult div */
+ clks[IMX6SX_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
+ clks[IMX6SX_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
+ clks[IMX6SX_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
+ clks[IMX6SX_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
+ clks[IMX6SX_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2);
+ clks[IMX6SX_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
+
+ clks[IMX6SX_CLK_PLL4_POST_DIV] = imx_clk_divider_table("pll4_post_div", "pll4_audio",
+ base + 0x70, 19, 2, post_div_table);
+ clks[IMX6SX_CLK_PLL4_AUDIO_DIV] = imx_clk_divider("pll4_audio_div", "pll4_post_div",
+ base + 0x170, 15, 1);
+ clks[IMX6SX_CLK_PLL5_POST_DIV] = imx_clk_divider_table("pll5_post_div", "pll5_video",
+ base + 0xa0, 19, 2, post_div_table);
+ clks[IMX6SX_CLK_PLL5_VIDEO_DIV] = imx_clk_divider_table("pll5_video_div", "pll5_post_div",
+ base + 0x170, 30, 2, video_div_table);
+
+ /* name reg shift width parent_names num_parents */
+ clks[IMX6SX_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+
+ base = ccm_base;
+
+ /* name reg shift width parent_names num_parents */
+ clks[IMX6SX_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
+ clks[IMX6SX_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
+ clks[IMX6SX_CLK_OCRAM_SEL] = imx_clk_mux("ocram_sel", base + 0x14, 6, 2, ocram_sels, ARRAY_SIZE(ocram_sels));
+ clks[IMX6SX_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+ clks[IMX6SX_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
+ clks[IMX6SX_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ clks[IMX6SX_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+ clks[IMX6SX_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels));
+ clks[IMX6SX_CLK_GPU_AXI_SEL] = imx_clk_mux("gpu_axi_sel", base + 0x18, 8, 2, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels));
+ clks[IMX6SX_CLK_GPU_CORE_SEL] = imx_clk_mux("gpu_core_sel", base + 0x18, 4, 2, gpu_core_sels, ARRAY_SIZE(gpu_core_sels));
+ clks[IMX6SX_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
+ clks[IMX6SX_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ clks[IMX6SX_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ clks[IMX6SX_CLK_USDHC3_SEL] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ clks[IMX6SX_CLK_USDHC4_SEL] = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ clks[IMX6SX_CLK_QSPI1_SEL] = imx_clk_mux_p("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels));
+ clks[IMX6SX_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
+ clks[IMX6SX_CLK_VID_SEL] = imx_clk_mux("vid_sel", base + 0x20, 21, 3, vid_sels, ARRAY_SIZE(vid_sels));
+ clks[IMX6SX_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
+ clks[IMX6SX_CLK_QSPI2_SEL] = imx_clk_mux_p("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels));
+ clks[IMX6SX_CLK_ENET_PRE_SEL] = imx_clk_mux("enet_pre_sel", base + 0x34, 15, 3, enet_pre_sels, ARRAY_SIZE(enet_pre_sels));
+ clks[IMX6SX_CLK_ENET_SEL] = imx_clk_mux("enet_sel", base + 0x34, 9, 3, enet_sels, ARRAY_SIZE(enet_sels));
+ clks[IMX6SX_CLK_M4_PRE_SEL] = imx_clk_mux("m4_pre_sel", base + 0x34, 6, 3, m4_pre_sels, ARRAY_SIZE(m4_pre_sels));
+ clks[IMX6SX_CLK_M4_SEL] = imx_clk_mux("m4_sel", base + 0x34, 0, 3, m4_sels, ARRAY_SIZE(m4_sels));
+ clks[IMX6SX_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
+ clks[IMX6SX_CLK_LCDIF2_PRE_SEL] = imx_clk_mux("lcdif2_pre_sel", base + 0x38, 6, 3, lcdif2_pre_sels, ARRAY_SIZE(lcdif2_pre_sels));
+ clks[IMX6SX_CLK_LCDIF2_SEL] = imx_clk_mux("lcdif2_sel", base + 0x38, 0, 3, lcdif2_sels, ARRAY_SIZE(lcdif2_sels));
+ clks[IMX6SX_CLK_DISPLAY_SEL] = imx_clk_mux("display_sel", base + 0x3c, 14, 2, display_sels, ARRAY_SIZE(display_sels));
+ clks[IMX6SX_CLK_CSI_SEL] = imx_clk_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels));
+ clks[IMX6SX_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels));
+ clks[IMX6SX_CLK_CKO2_SEL] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels));
+ clks[IMX6SX_CLK_CKO] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels));
+
+ clks[IMX6SX_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux_p("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
+ clks[IMX6SX_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux_p("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
+ clks[IMX6SX_CLK_LDB_DI1_SEL] = imx_clk_mux_p("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels));
+ clks[IMX6SX_CLK_LDB_DI0_SEL] = imx_clk_mux_p("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
+ clks[IMX6SX_CLK_LCDIF1_PRE_SEL] = imx_clk_mux_p("lcdif1_pre_sel", base + 0x38, 15, 3, lcdif1_pre_sels, ARRAY_SIZE(lcdif1_pre_sels));
+ clks[IMX6SX_CLK_LCDIF1_SEL] = imx_clk_mux_p("lcdif1_sel", base + 0x38, 9, 3, lcdif1_sels, ARRAY_SIZE(lcdif1_sels));
+
+ /* name parent_name reg shift width */
+ clks[IMX6SX_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
+ clks[IMX6SX_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
+ clks[IMX6SX_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
+ clks[IMX6SX_CLK_GPU_CORE_PODF] = imx_clk_divider("gpu_core_podf", "gpu_core_sel", base + 0x18, 29, 3);
+ clks[IMX6SX_CLK_GPU_AXI_PODF] = imx_clk_divider("gpu_axi_podf", "gpu_axi_sel", base + 0x18, 26, 3);
+ clks[IMX6SX_CLK_LCDIF1_PODF] = imx_clk_divider("lcdif1_podf", "lcdif1_pred", base + 0x18, 23, 3);
+ clks[IMX6SX_CLK_QSPI1_PODF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3);
+ clks[IMX6SX_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3);
+ clks[IMX6SX_CLK_LCDIF2_PODF] = imx_clk_divider("lcdif2_podf", "lcdif2_pred", base + 0x1c, 20, 3);
+ clks[IMX6SX_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6);
+ clks[IMX6SX_CLK_VID_PODF] = imx_clk_divider("vid_podf", "vid_sel", base + 0x20, 24, 2);
+ clks[IMX6SX_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3);
+ clks[IMX6SX_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
+ clks[IMX6SX_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
+ clks[IMX6SX_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
+ clks[IMX6SX_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6);
+ clks[IMX6SX_CLK_QSPI2_PRED] = imx_clk_divider("qspi2_pred", "qspi2_sel", base + 0x2c, 18, 3);
+ clks[IMX6SX_CLK_QSPI2_PODF] = imx_clk_divider("qspi2_podf", "qspi2_pred", base + 0x2c, 21, 6);
+ clks[IMX6SX_CLK_ENET_PODF] = imx_clk_divider("enet_podf", "enet_pre_sel", base + 0x34, 12, 3);
+ clks[IMX6SX_CLK_M4_PODF] = imx_clk_divider("m4_podf", "m4_sel", base + 0x34, 3, 3);
+ clks[IMX6SX_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6);
+ clks[IMX6SX_CLK_LCDIF1_PRED] = imx_clk_divider("lcdif1_pred", "lcdif1_pre_sel", base + 0x38, 12, 3);
+ clks[IMX6SX_CLK_LCDIF2_PRED] = imx_clk_divider("lcdif2_pred", "lcdif2_pre_sel", base + 0x38, 3, 3);
+ clks[IMX6SX_CLK_DISPLAY_PODF] = imx_clk_divider("display_podf", "display_sel", base + 0x3c, 16, 3);
+ clks[IMX6SX_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3);
+ clks[IMX6SX_CLK_CKO1_PODF] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3);
+ clks[IMX6SX_CLK_CKO2_PODF] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3);
+
+ clks[IMX6SX_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+ clks[IMX6SX_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
+ clks[IMX6SX_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+ clks[IMX6SX_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7);
+
+ /* name reg shift width busy: reg, shift parent_names num_parents */
+ clks[IMX6SX_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
+ clks[IMX6SX_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
+ /* name parent_name reg shift width busy: reg, shift */
+ clks[IMX6SX_CLK_OCRAM_PODF] = imx_clk_busy_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3, base + 0x48, 0);
+ clks[IMX6SX_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
+ clks[IMX6SX_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
+ clks[IMX6SX_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
+
+ /* name parent_name reg shift */
+ /* CCGR0 */
+ clks[IMX6SX_CLK_AIPS_TZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0);
+ clks[IMX6SX_CLK_AIPS_TZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2);
+ clks[IMX6SX_CLK_APBH_DMA] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4);
+ clks[IMX6SX_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8);
+ clks[IMX6SX_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10);
+ clks[IMX6SX_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12);
+ clks[IMX6SX_CLK_DCIC1] = imx_clk_gate2("dcic1", "display_podf", base + 0x68, 24);
+ clks[IMX6SX_CLK_DCIC2] = imx_clk_gate2("dcic2", "display_podf", base + 0x68, 26);
+ clks[IMX6SX_CLK_AIPS_TZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30);
+
+ /* CCGR1 */
+ clks[IMX6SX_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
+ clks[IMX6SX_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2);
+ clks[IMX6SX_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4);
+ clks[IMX6SX_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6);
+ clks[IMX6SX_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_podf", base + 0x6c, 8);
+ clks[IMX6SX_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12);
+ clks[IMX6SX_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14);
+ clks[IMX6SX_CLK_WAKEUP] = imx_clk_gate2("wakeup", "ipg", base + 0x6c, 18);
+ clks[IMX6SX_CLK_GPT_BUS] = imx_clk_gate2("gpt_bus", "perclk", base + 0x6c, 20);
+ clks[IMX6SX_CLK_GPT_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x6c, 22);
+ clks[IMX6SX_CLK_GPU] = imx_clk_gate2("gpu", "gpu_core_podf", base + 0x6c, 26);
+
+ /* CCGR2 */
+ clks[IMX6SX_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2);
+ clks[IMX6SX_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6);
+ clks[IMX6SX_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8);
+ clks[IMX6SX_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10);
+ clks[IMX6SX_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12);
+ clks[IMX6SX_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif1_podf", base + 0x70, 14);
+ clks[IMX6SX_CLK_IPMUX1] = imx_clk_gate2("ipmux1", "ahb", base + 0x70, 16);
+ clks[IMX6SX_CLK_IPMUX2] = imx_clk_gate2("ipmux2", "ahb", base + 0x70, 18);
+ clks[IMX6SX_CLK_IPMUX3] = imx_clk_gate2("ipmux3", "ahb", base + 0x70, 20);
+ clks[IMX6SX_CLK_TZASC1] = imx_clk_gate2("tzasc1", "mmdc_podf", base + 0x70, 22);
+ clks[IMX6SX_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "display_podf", base + 0x70, 28);
+ clks[IMX6SX_CLK_PXP_AXI] = imx_clk_gate2("pxp_axi", "display_podf", base + 0x70, 30);
+
+ /* CCGR3 */
+ clks[IMX6SX_CLK_M4] = imx_clk_gate2("m4", "m4_podf", base + 0x74, 2);
+ clks[IMX6SX_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4);
+ clks[IMX6SX_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "enet_sel", base + 0x74, 4);
+ clks[IMX6SX_CLK_DISPLAY_AXI] = imx_clk_gate2("display_axi", "display_podf", base + 0x74, 6);
+ clks[IMX6SX_CLK_LCDIF2_PIX] = imx_clk_gate2("lcdif2_pix", "lcdif2_sel", base + 0x74, 8);
+ clks[IMX6SX_CLK_LCDIF1_PIX] = imx_clk_gate2("lcdif1_pix", "lcdif1_sel", base + 0x74, 10);
+ clks[IMX6SX_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_div_sel", base + 0x74, 12);
+ clks[IMX6SX_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14);
+ clks[IMX6SX_CLK_MLB] = imx_clk_gate2("mlb", "ahb", base + 0x74, 18);
+ clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20);
+ clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24);
+ clks[IMX6SX_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28);
+
+ /* CCGR4 */
+ clks[IMX6SX_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "display_podf", base + 0x78, 0);
+ clks[IMX6SX_CLK_QSPI2] = imx_clk_gate2("qspi2", "qspi2_podf", base + 0x78, 10);
+ clks[IMX6SX_CLK_PER1_BCH] = imx_clk_gate2("per1_bch", "usdhc3", base + 0x78, 12);
+ clks[IMX6SX_CLK_PER2_MAIN] = imx_clk_gate2("per2_main", "ahb", base + 0x78, 14);
+ clks[IMX6SX_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
+ clks[IMX6SX_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
+ clks[IMX6SX_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20);
+ clks[IMX6SX_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22);
+ clks[IMX6SX_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24);
+ clks[IMX6SX_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26);
+ clks[IMX6SX_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "qspi2_podf", base + 0x78, 28);
+ clks[IMX6SX_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30);
+
+ /* CCGR5 */
+ clks[IMX6SX_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0);
+ clks[IMX6SX_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
+ clks[IMX6SX_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
+ clks[IMX6SX_CLK_UART_IPG] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24);
+ clks[IMX6SX_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_podf", base + 0x7c, 26);
+ clks[IMX6SX_CLK_SAI1_IPG] = imx_clk_gate2("sai1_ipg", "ipg", base + 0x7c, 28);
+ clks[IMX6SX_CLK_SAI2_IPG] = imx_clk_gate2("sai2_ipg", "ipg", base + 0x7c, 30);
+
+ /* CCGR6 */
+ clks[IMX6SX_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
+ clks[IMX6SX_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
+ clks[IMX6SX_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
+ clks[IMX6SX_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
+ clks[IMX6SX_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8);
+ clks[IMX6SX_CLK_EIM_SLOW] = imx_clk_gate2("eim_slow", "eim_slow_podf", base + 0x80, 10);
+ clks[IMX6SX_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16);
+ clks[IMX6SX_CLK_VADC] = imx_clk_gate2("vadc", "vid_podf", base + 0x80, 20);
+ clks[IMX6SX_CLK_GIS] = imx_clk_gate2("gis", "display_podf", base + 0x80, 22);
+ clks[IMX6SX_CLK_I2C4] = imx_clk_gate2("i2c4", "perclk", base + 0x80, 24);
+ clks[IMX6SX_CLK_PWM5] = imx_clk_gate2("pwm5", "perclk", base + 0x80, 26);
+ clks[IMX6SX_CLK_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28);
+ clks[IMX6SX_CLK_PWM7] = imx_clk_gate2("pwm7", "perclk", base + 0x80, 30);
+
+ clks[IMX6SX_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7);
+ clks[IMX6SX_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24);
+
+ /* mask handshake of mmdc */
+ writel(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(ccm_node, of_clk_src_onecell_get, &clk_data);
+
+ if (IS_ENABLED(CONFIG_USB_IMX_PHY)) {
+ clk_enable(clks[IMX6SX_CLK_USBPHY1_GATE]);
+ clk_enable(clks[IMX6SX_CLK_USBPHY2_GATE]);
+ }
+
+ return 0;
+};
+
+static int imx6sx_clocks_init(void)
+{
+ if (!of_machine_is_compatible("fsl,imx6sx"))
+ return 0;
+
+ /* Set the default 132MHz for EIM module */
+ clk_set_parent(clks[IMX6SX_CLK_EIM_SLOW_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
+ clk_set_rate(clks[IMX6SX_CLK_EIM_SLOW], 132000000);
+
+ /* set parent clock for LCDIF1 pixel clock */
+ clk_set_parent(clks[IMX6SX_CLK_LCDIF1_PRE_SEL], clks[IMX6SX_CLK_PLL5_VIDEO_DIV]);
+ clk_set_parent(clks[IMX6SX_CLK_LCDIF1_SEL], clks[IMX6SX_CLK_LCDIF1_PODF]);
+
+ /*
+ * Init enet system AHB clock, set to 200Mhz
+ * pll2_pfd2_396m-> ENET_PODF-> ENET_AHB
+ */
+ clk_set_parent(clks[IMX6SX_CLK_ENET_PRE_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
+ clk_set_parent(clks[IMX6SX_CLK_ENET_SEL], clks[IMX6SX_CLK_ENET_PODF]);
+ clk_set_rate(clks[IMX6SX_CLK_ENET_PODF], 200000000);
+ clk_set_rate(clks[IMX6SX_CLK_ENET_REF], 125000000);
+ clk_set_rate(clks[IMX6SX_CLK_ENET2_REF], 125000000);
+
+ /* Set parent clock for vadc */
+ clk_set_parent(clks[IMX6SX_CLK_VID_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]);
+
+ /* Update gpu clock from default 528M to 720M */
+ clk_set_parent(clks[IMX6SX_CLK_GPU_CORE_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
+ clk_set_parent(clks[IMX6SX_CLK_GPU_AXI_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
+
+ return 0;
+}
+coredevice_initcall(imx6sx_clocks_init);
+
+static __maybe_unused struct of_device_id imx6sx_ccm_dt_ids[] = {
+ {
+ .compatible = "fsl,imx6sx-ccm",
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d imx6sx_ccm_driver = {
+ .probe = imx6sx_ccm_probe,
+ .name = "imx6-ccm",
+ .of_compatible = DRV_OF_COMPAT(imx6sx_ccm_dt_ids),
+};
+
+static int imx6sx_ccm_init(void)
+{
+ return platform_driver_register(&imx6sx_ccm_driver);
+}
+core_initcall(imx6sx_ccm_init);
diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c
new file mode 100644
index 0000000000..8f6d5ad7a8
--- /dev/null
+++ b/drivers/clk/imx/clk-pfd.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <malloc.h>
+#include <asm-generic/div64.h>
+
+#include "clk.h"
+
+/**
+ * struct clk_pfd - IMX PFD clock
+ * @clk_hw: clock source
+ * @reg: PFD register address
+ * @idx: the index of PFD encoded in the register
+ *
+ * PFD clock found on i.MX6 series. Each register for PFD has 4 clk_pfd
+ * data encoded, and member idx is used to specify the one. And each
+ * register has SET, CLR and TOG registers at offset 0x4 0x8 and 0xc.
+ */
+struct clk_pfd {
+ struct clk clk;
+ void __iomem *reg;
+ u8 idx;
+ const char *parent;
+};
+
+#define to_clk_pfd(_clk) container_of(_clk, struct clk_pfd, clk)
+
+#define SET 0x4
+#define CLR 0x8
+#define OTG 0xc
+
+static int clk_pfd_enable(struct clk *clk)
+{
+ struct clk_pfd *pfd = to_clk_pfd(clk);
+ writel(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR);
+
+ return 0;
+}
+
+static void clk_pfd_disable(struct clk *clk)
+{
+ struct clk_pfd *pfd = to_clk_pfd(clk);
+
+ writel(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET);
+}
+
+static unsigned long clk_pfd_recalc_rate(struct clk *clk,
+ unsigned long parent_rate)
+{
+ struct clk_pfd *pfd = to_clk_pfd(clk);
+ u64 tmp = parent_rate;
+ u8 frac = (readl(pfd->reg) >> (pfd->idx * 8)) & 0x3f;
+
+ tmp *= 18;
+ do_div(tmp, frac);
+
+ return tmp;
+}
+
+static long clk_pfd_round_rate(struct clk *clk, unsigned long rate,
+ unsigned long *prate)
+{
+ u64 tmp = *prate;
+ u8 frac;
+
+ tmp = tmp * 18 + rate / 2;
+ do_div(tmp, rate);
+ frac = tmp;
+ if (frac < 12)
+ frac = 12;
+ else if (frac > 35)
+ frac = 35;
+ tmp = *prate;
+ tmp *= 18;
+ do_div(tmp, frac);
+
+ return tmp;
+}
+
+static int clk_pfd_set_rate(struct clk *clk, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_pfd *pfd = to_clk_pfd(clk);
+ u64 tmp = parent_rate;
+ u8 frac;
+
+ tmp = tmp * 18 + rate / 2;
+ do_div(tmp, rate);
+ frac = tmp;
+ if (frac < 12)
+ frac = 12;
+ else if (frac > 35)
+ frac = 35;
+
+ writel(0x3f << (pfd->idx * 8), pfd->reg + CLR);
+ writel(frac << (pfd->idx * 8), pfd->reg + SET);
+
+ return 0;
+}
+
+static const struct clk_ops clk_pfd_ops = {
+ .enable = clk_pfd_enable,
+ .disable = clk_pfd_disable,
+ .recalc_rate = clk_pfd_recalc_rate,
+ .round_rate = clk_pfd_round_rate,
+ .set_rate = clk_pfd_set_rate,
+};
+
+struct clk *imx_clk_pfd(const char *name, const char *parent,
+ void __iomem *reg, u8 idx)
+{
+ struct clk_pfd *pfd;
+ int ret;
+
+ pfd = xzalloc(sizeof(*pfd));
+
+ pfd->reg = reg;
+ pfd->idx = idx;
+ pfd->parent = parent;
+ pfd->clk.name = name;
+ pfd->clk.ops = &clk_pfd_ops;
+ pfd->clk.parent_names = &pfd->parent;
+ pfd->clk.num_parents = 1;
+
+ ret = clk_register(&pfd->clk);
+ if (ret) {
+ free(pfd);
+ return ERR_PTR(ret);
+ }
+
+ return &pfd->clk;
+}
diff --git a/drivers/clk/imx/clk-pllv1.c b/drivers/clk/imx/clk-pllv1.c
new file mode 100644
index 0000000000..f992134f7e
--- /dev/null
+++ b/drivers/clk/imx/clk-pllv1.c
@@ -0,0 +1,95 @@
+/*
+ * 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 <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <malloc.h>
+#include <asm-generic/div64.h>
+
+#include "clk.h"
+
+struct clk_pllv1 {
+ struct clk clk;
+ void __iomem *reg;
+ const char *parent;
+};
+
+static unsigned long clk_pllv1_recalc_rate(struct clk *clk,
+ unsigned long parent_rate)
+{
+ struct clk_pllv1 *pll = container_of(clk, struct clk_pllv1, clk);
+ unsigned long long ll;
+ int mfn_abs;
+ unsigned int mfi, mfn, mfd, pd;
+ u32 reg_val = readl(pll->reg);
+ unsigned long freq = parent_rate;
+
+ mfi = (reg_val >> 10) & 0xf;
+ mfn = reg_val & 0x3ff;
+ mfd = (reg_val >> 16) & 0x3ff;
+ pd = (reg_val >> 26) & 0xf;
+
+ mfi = mfi <= 5 ? 5 : mfi;
+
+ mfn_abs = mfn;
+
+#if !defined CONFIG_ARCH_MX1 && !defined CONFIG_ARCH_MX21
+ if (mfn >= 0x200) {
+ mfn |= 0xFFFFFE00;
+ mfn_abs = -mfn;
+ }
+#endif
+
+ freq *= 2;
+ freq /= pd + 1;
+
+ ll = (unsigned long long)freq * mfn_abs;
+
+ do_div(ll, mfd + 1);
+ if (mfn < 0)
+ ll = (freq * mfi) - ll;
+ else
+ ll = (freq * mfi) + ll;
+
+ return ll;
+}
+
+struct clk_ops clk_pllv1_ops = {
+ .recalc_rate = clk_pllv1_recalc_rate,
+};
+
+struct clk *imx_clk_pllv1(const char *name, const char *parent,
+ void __iomem *base)
+{
+ struct clk_pllv1 *pll = xzalloc(sizeof(*pll));
+ int ret;
+
+ pll->parent = parent;
+ pll->reg = base;
+ pll->clk.ops = &clk_pllv1_ops;
+ pll->clk.name = name;
+ pll->clk.parent_names = &pll->parent;
+ pll->clk.num_parents = 1;
+
+ ret = clk_register(&pll->clk);
+ if (ret) {
+ free(pll);
+ return ERR_PTR(ret);
+ }
+
+ return &pll->clk;
+}
diff --git a/drivers/clk/imx/clk-pllv2.c b/drivers/clk/imx/clk-pllv2.c
new file mode 100644
index 0000000000..5ba07fa5e6
--- /dev/null
+++ b/drivers/clk/imx/clk-pllv2.c
@@ -0,0 +1,230 @@
+/*
+ * 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 <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <malloc.h>
+#include <asm-generic/div64.h>
+
+#include "clk.h"
+
+/* PLL Register Offsets */
+#define MXC_PLL_DP_CTL 0x00
+#define MXC_PLL_DP_CONFIG 0x04
+#define MXC_PLL_DP_OP 0x08
+#define MXC_PLL_DP_MFD 0x0C
+#define MXC_PLL_DP_MFN 0x10
+#define MXC_PLL_DP_MFNMINUS 0x14
+#define MXC_PLL_DP_MFNPLUS 0x18
+#define MXC_PLL_DP_HFS_OP 0x1C
+#define MXC_PLL_DP_HFS_MFD 0x20
+#define MXC_PLL_DP_HFS_MFN 0x24
+#define MXC_PLL_DP_MFN_TOGC 0x28
+#define MXC_PLL_DP_DESTAT 0x2c
+
+/* PLL Register Bit definitions */
+#define MXC_PLL_DP_CTL_MUL_CTRL 0x2000
+#define MXC_PLL_DP_CTL_DPDCK0_2_EN 0x1000
+#define MXC_PLL_DP_CTL_DPDCK0_2_OFFSET 12
+#define MXC_PLL_DP_CTL_ADE 0x800
+#define MXC_PLL_DP_CTL_REF_CLK_DIV 0x400
+#define MXC_PLL_DP_CTL_REF_CLK_SEL_MASK (3 << 8)
+#define MXC_PLL_DP_CTL_REF_CLK_SEL_OFFSET 8
+#define MXC_PLL_DP_CTL_HFSM 0x80
+#define MXC_PLL_DP_CTL_PRE 0x40
+#define MXC_PLL_DP_CTL_UPEN 0x20
+#define MXC_PLL_DP_CTL_RST 0x10
+#define MXC_PLL_DP_CTL_RCP 0x8
+#define MXC_PLL_DP_CTL_PLM 0x4
+#define MXC_PLL_DP_CTL_BRM0 0x2
+#define MXC_PLL_DP_CTL_LRF 0x1
+
+#define MXC_PLL_DP_CONFIG_BIST 0x8
+#define MXC_PLL_DP_CONFIG_SJC_CE 0x4
+#define MXC_PLL_DP_CONFIG_AREN 0x2
+#define MXC_PLL_DP_CONFIG_LDREQ 0x1
+
+#define MXC_PLL_DP_OP_MFI_OFFSET 4
+#define MXC_PLL_DP_OP_MFI_MASK (0xF << 4)
+#define MXC_PLL_DP_OP_PDF_OFFSET 0
+#define MXC_PLL_DP_OP_PDF_MASK 0xF
+
+#define MXC_PLL_DP_MFD_OFFSET 0
+#define MXC_PLL_DP_MFD_MASK 0x07FFFFFF
+
+#define MXC_PLL_DP_MFN_OFFSET 0x0
+#define MXC_PLL_DP_MFN_MASK 0x07FFFFFF
+
+#define MXC_PLL_DP_MFN_TOGC_TOG_DIS (1 << 17)
+#define MXC_PLL_DP_MFN_TOGC_TOG_EN (1 << 16)
+#define MXC_PLL_DP_MFN_TOGC_CNT_OFFSET 0x0
+#define MXC_PLL_DP_MFN_TOGC_CNT_MASK 0xFFFF
+
+#define MXC_PLL_DP_DESTAT_TOG_SEL (1 << 31)
+#define MXC_PLL_DP_DESTAT_MFN 0x07FFFFFF
+
+#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */
+
+struct clk_pllv2 {
+ struct clk clk;
+ void __iomem *reg;
+ const char *parent;
+};
+
+static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate,
+ u32 dp_ctl, u32 dp_op, u32 dp_mfd, u32 dp_mfn)
+{
+ long mfi, mfn, mfd, pdf, ref_clk, mfn_abs;
+ unsigned long dbl;
+ uint64_t temp;
+
+ dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN;
+
+ pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK;
+ mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET;
+ mfi = (mfi <= 5) ? 5 : mfi;
+ mfd = dp_mfd & MXC_PLL_DP_MFD_MASK;
+ mfn = mfn_abs = dp_mfn & MXC_PLL_DP_MFN_MASK;
+ /* Sign extend to 32-bits */
+ if (mfn >= 0x04000000) {
+ mfn |= 0xFC000000;
+ mfn_abs = -mfn;
+ }
+
+ ref_clk = 2 * parent_rate;
+ if (dbl != 0)
+ ref_clk *= 2;
+
+ ref_clk /= (pdf + 1);
+ temp = (u64) ref_clk * mfn_abs;
+ do_div(temp, mfd + 1);
+ if (mfn < 0)
+ temp = (ref_clk * mfi) - temp;
+ else
+ temp = (ref_clk * mfi) + temp;
+
+ return temp;
+}
+
+static unsigned long clk_pllv2_recalc_rate(struct clk *clk,
+ unsigned long parent_rate)
+{
+ u32 dp_op, dp_mfd, dp_mfn, dp_ctl;
+ void __iomem *pllbase;
+ struct clk_pllv2 *pll = container_of(clk, struct clk_pllv2, clk);
+
+ pllbase = pll->reg;
+
+ dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL);
+ dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP);
+ dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD);
+ dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN);
+
+ return __clk_pllv2_recalc_rate(parent_rate, dp_ctl, dp_op, dp_mfd, dp_mfn);
+}
+
+static int __clk_pllv2_set_rate(unsigned long rate, unsigned long parent_rate,
+ u32 *dp_op, u32 *dp_mfd, u32 *dp_mfn)
+{
+ u32 reg;
+ long mfi, pdf, mfn, mfd = 999999;
+ u64 temp64;
+ unsigned long quad_parent_rate;
+
+ quad_parent_rate = 4 * parent_rate;
+ pdf = mfi = -1;
+ while (++pdf < 16 && mfi < 5)
+ mfi = rate * (pdf+1) / quad_parent_rate;
+ if (mfi > 15)
+ return -EINVAL;
+ pdf--;
+
+ temp64 = rate * (pdf + 1) - quad_parent_rate * mfi;
+ do_div(temp64, quad_parent_rate / 1000000);
+ mfn = (long)temp64;
+
+ reg = mfi << 4 | pdf;
+
+ *dp_op = reg;
+ *dp_mfd = mfd;
+ *dp_mfn = mfn;
+
+ return 0;
+}
+
+static int clk_pllv2_set_rate(struct clk *clk, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_pllv2 *pll = container_of(clk, struct clk_pllv2, clk);
+ void __iomem *pllbase;
+ u32 dp_ctl, dp_op, dp_mfd, dp_mfn;
+ int ret;
+
+ pllbase = pll->reg;
+
+ ret = __clk_pllv2_set_rate(rate, parent_rate, &dp_op, &dp_mfd, &dp_mfn);
+ if (ret)
+ return ret;
+
+ dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL);
+ /* use dpdck0_2 */
+ __raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL);
+
+ __raw_writel(dp_op, pllbase + MXC_PLL_DP_OP);
+ __raw_writel(dp_mfd, pllbase + MXC_PLL_DP_MFD);
+ __raw_writel(dp_mfn, pllbase + MXC_PLL_DP_MFN);
+
+ return 0;
+}
+
+static long clk_pllv2_round_rate(struct clk *clk, unsigned long rate,
+ unsigned long *prate)
+{
+ u32 dp_op, dp_mfd, dp_mfn;
+
+ __clk_pllv2_set_rate(rate, *prate, &dp_op, &dp_mfd, &dp_mfn);
+ return __clk_pllv2_recalc_rate(*prate, MXC_PLL_DP_CTL_DPDCK0_2_EN,
+ dp_op, dp_mfd, dp_mfn);
+}
+
+struct clk_ops clk_pllv2_ops = {
+ .recalc_rate = clk_pllv2_recalc_rate,
+ .round_rate = clk_pllv2_round_rate,
+ .set_rate = clk_pllv2_set_rate,
+};
+
+struct clk *imx_clk_pllv2(const char *name, const char *parent,
+ void __iomem *base)
+{
+ struct clk_pllv2 *pll = xzalloc(sizeof(*pll));
+ int ret;
+
+ pll->parent = parent;
+ pll->reg = base;
+ pll->clk.ops = &clk_pllv2_ops;
+ pll->clk.name = name;
+ pll->clk.parent_names = &pll->parent;
+ pll->clk.num_parents = 1;
+
+ ret = clk_register(&pll->clk);
+ if (ret) {
+ free(pll);
+ return ERR_PTR(ret);
+ }
+
+ return &pll->clk;
+}
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
new file mode 100644
index 0000000000..e38dcdfdaa
--- /dev/null
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -0,0 +1,326 @@
+/*
+ * 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 <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <malloc.h>
+#include <clock.h>
+#include <asm-generic/div64.h>
+
+#include "clk.h"
+
+#define PLL_NUM_OFFSET 0x10
+#define PLL_DENOM_OFFSET 0x20
+
+#define BM_PLL_POWER (0x1 << 12)
+#define BM_PLL_ENABLE (0x1 << 13)
+#define BM_PLL_BYPASS (0x1 << 16)
+#define BM_PLL_LOCK (0x1 << 31)
+
+struct clk_pllv3 {
+ struct clk clk;
+ void __iomem *base;
+ bool powerup_set;
+ u32 div_mask;
+ const char *parent;
+};
+
+#define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk)
+
+static int clk_pllv3_enable(struct clk *clk)
+{
+ struct clk_pllv3 *pll = to_clk_pllv3(clk);
+ u32 val;
+ int timeout = 10000;
+
+ val = readl(pll->base);
+ val &= ~BM_PLL_BYPASS;
+ if (pll->powerup_set)
+ val |= BM_PLL_POWER;
+ else
+ val &= ~BM_PLL_POWER;
+ writel(val, pll->base);
+
+ /* Wait for PLL to lock */
+ while (timeout--) {
+ if (readl(pll->base) & BM_PLL_LOCK)
+ break;
+ }
+
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ val = readl(pll->base);
+ val |= BM_PLL_ENABLE;
+ writel(val, pll->base);
+
+ return 0;
+}
+
+static void clk_pllv3_disable(struct clk *clk)
+{
+ struct clk_pllv3 *pll = to_clk_pllv3(clk);
+ u32 val;
+
+ val = readl(pll->base);
+ val &= ~BM_PLL_ENABLE;
+ writel(val, pll->base);
+
+ val |= BM_PLL_BYPASS;
+ if (pll->powerup_set)
+ val &= ~BM_PLL_POWER;
+ else
+ val |= BM_PLL_POWER;
+ writel(val, pll->base);
+}
+
+static unsigned long clk_pllv3_recalc_rate(struct clk *clk,
+ unsigned long parent_rate)
+{
+ struct clk_pllv3 *pll = to_clk_pllv3(clk);
+ u32 div = readl(pll->base) & pll->div_mask;
+
+ return (div == 1) ? parent_rate * 22 : parent_rate * 20;
+}
+
+static long clk_pllv3_round_rate(struct clk *clk, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long parent_rate = *prate;
+
+ return (rate >= parent_rate * 22) ? parent_rate * 22 :
+ parent_rate * 20;
+}
+
+static int clk_pllv3_set_rate(struct clk *clk, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_pllv3 *pll = to_clk_pllv3(clk);
+ u32 val, div;
+
+ if (rate == parent_rate * 22)
+ div = 1;
+ else if (rate == parent_rate * 20)
+ div = 0;
+ else
+ return -EINVAL;
+
+ val = readl(pll->base);
+ val &= ~pll->div_mask;
+ val |= div;
+ writel(val, pll->base);
+
+ return 0;
+}
+
+static const struct clk_ops clk_pllv3_ops = {
+ .enable = clk_pllv3_enable,
+ .disable = clk_pllv3_disable,
+ .recalc_rate = clk_pllv3_recalc_rate,
+ .round_rate = clk_pllv3_round_rate,
+ .set_rate = clk_pllv3_set_rate,
+};
+
+static unsigned long clk_pllv3_sys_recalc_rate(struct clk *clk,
+ unsigned long parent_rate)
+{
+ struct clk_pllv3 *pll = to_clk_pllv3(clk);
+ u32 div = readl(pll->base) & pll->div_mask;
+
+ return parent_rate * div / 2;
+}
+
+static long clk_pllv3_sys_round_rate(struct clk *clk, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long parent_rate = *prate;
+ unsigned long min_rate = parent_rate * 54 / 2;
+ unsigned long max_rate = parent_rate * 108 / 2;
+ u32 div;
+
+ if (rate > max_rate)
+ rate = max_rate;
+ else if (rate < min_rate)
+ rate = min_rate;
+ div = rate * 2 / parent_rate;
+
+ return parent_rate * div / 2;
+}
+
+static int clk_pllv3_sys_set_rate(struct clk *clk, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_pllv3 *pll = to_clk_pllv3(clk);
+ unsigned long min_rate = parent_rate * 54 / 2;
+ unsigned long max_rate = parent_rate * 108 / 2;
+ u32 val, div;
+
+ if (rate < min_rate || rate > max_rate)
+ return -EINVAL;
+
+ div = rate * 2 / parent_rate;
+ val = readl(pll->base);
+ val &= ~pll->div_mask;
+ val |= div;
+ writel(val, pll->base);
+
+ return 0;
+}
+
+static const struct clk_ops clk_pllv3_sys_ops = {
+ .enable = clk_pllv3_enable,
+ .disable = clk_pllv3_disable,
+ .recalc_rate = clk_pllv3_sys_recalc_rate,
+ .round_rate = clk_pllv3_sys_round_rate,
+ .set_rate = clk_pllv3_sys_set_rate,
+};
+
+static unsigned long clk_pllv3_av_recalc_rate(struct clk *clk,
+ unsigned long parent_rate)
+{
+ struct clk_pllv3 *pll = to_clk_pllv3(clk);
+ u32 mfn = readl(pll->base + PLL_NUM_OFFSET);
+ u32 mfd = readl(pll->base + PLL_DENOM_OFFSET);
+ u32 div = readl(pll->base) & pll->div_mask;
+
+ return (parent_rate * div) + ((parent_rate / mfd) * mfn);
+}
+
+static long clk_pllv3_av_round_rate(struct clk *clk, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long parent_rate = *prate;
+ unsigned long min_rate = parent_rate * 27;
+ unsigned long max_rate = parent_rate * 54;
+ u32 div;
+ u32 mfn, mfd = 1000000;
+ u64 temp64;
+
+ if (rate > max_rate)
+ rate = max_rate;
+ else if (rate < min_rate)
+ rate = min_rate;
+
+ div = rate / parent_rate;
+ temp64 = (u64) (rate - div * parent_rate);
+ temp64 *= mfd;
+ do_div(temp64, parent_rate);
+ mfn = temp64;
+
+ return parent_rate * div + parent_rate / mfd * mfn;
+}
+
+static int clk_pllv3_av_set_rate(struct clk *clk, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_pllv3 *pll = to_clk_pllv3(clk);
+ unsigned long min_rate = parent_rate * 27;
+ unsigned long max_rate = parent_rate * 54;
+ u32 val, div;
+ u32 mfn, mfd = 1000000;
+ u64 temp64;
+
+ if (rate < min_rate || rate > max_rate)
+ return -EINVAL;
+
+ div = rate / parent_rate;
+ temp64 = (u64) (rate - div * parent_rate);
+ temp64 *= mfd;
+ do_div(temp64, parent_rate);
+ mfn = temp64;
+
+ val = readl(pll->base);
+ val &= ~pll->div_mask;
+ val |= div;
+ writel(val, pll->base);
+ writel(mfn, pll->base + PLL_NUM_OFFSET);
+ writel(mfd, pll->base + PLL_DENOM_OFFSET);
+
+ return 0;
+}
+
+static const struct clk_ops clk_pllv3_av_ops = {
+ .enable = clk_pllv3_enable,
+ .disable = clk_pllv3_disable,
+ .recalc_rate = clk_pllv3_av_recalc_rate,
+ .round_rate = clk_pllv3_av_round_rate,
+ .set_rate = clk_pllv3_av_set_rate,
+};
+
+static unsigned long clk_pllv3_enet_recalc_rate(struct clk *clk,
+ unsigned long parent_rate)
+{
+ return 500000000;
+}
+
+static const struct clk_ops clk_pllv3_enet_ops = {
+ .enable = clk_pllv3_enable,
+ .disable = clk_pllv3_disable,
+ .recalc_rate = clk_pllv3_enet_recalc_rate,
+};
+
+static const struct clk_ops clk_pllv3_mlb_ops = {
+ .enable = clk_pllv3_enable,
+ .disable = clk_pllv3_disable,
+};
+
+struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
+ const char *parent, void __iomem *base,
+ u32 div_mask)
+{
+ struct clk_pllv3 *pll;
+ const struct clk_ops *ops;
+ int ret;
+
+ pll = xzalloc(sizeof(*pll));
+
+ switch (type) {
+ case IMX_PLLV3_SYS:
+ ops = &clk_pllv3_sys_ops;
+ break;
+ case IMX_PLLV3_USB:
+ ops = &clk_pllv3_ops;
+ pll->powerup_set = true;
+ break;
+ case IMX_PLLV3_AV:
+ ops = &clk_pllv3_av_ops;
+ break;
+ case IMX_PLLV3_ENET:
+ ops = &clk_pllv3_enet_ops;
+ break;
+ case IMX_PLLV3_MLB:
+ ops = &clk_pllv3_mlb_ops;
+ break;
+ default:
+ ops = &clk_pllv3_ops;
+ }
+ pll->base = base;
+ pll->div_mask = div_mask;
+ pll->parent = parent;
+ pll->clk.ops = ops;
+ pll->clk.name = name;
+ pll->clk.parent_names = &pll->parent;
+ pll->clk.num_parents = 1;
+
+ ret = clk_register(&pll->clk);
+ if (ret) {
+ free(pll);
+ return ERR_PTR(ret);
+ }
+
+ return &pll->clk;
+}
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
new file mode 100644
index 0000000000..c5913e1879
--- /dev/null
+++ b/drivers/clk/imx/clk.h
@@ -0,0 +1,104 @@
+#ifndef __IMX_CLK_H
+#define __IMX_CLK_H
+
+struct clk *clk_gate2(const char *name, const char *parent, void __iomem *reg,
+ u8 shift);
+
+static inline struct clk *imx_clk_divider(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u8 width)
+{
+ return clk_divider(name, parent, reg, shift, width, CLK_SET_RATE_PARENT);
+}
+
+static inline struct clk *imx_clk_divider_np(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u8 width)
+{
+ return clk_divider(name, parent, reg, shift, width, 0);
+}
+
+static inline struct clk *imx_clk_divider_table(const char *name,
+ const char *parent, void __iomem *reg, u8 shift, u8 width,
+ const struct clk_div_table *table)
+{
+ return clk_divider_table(name, parent, reg, shift, width, table,
+ CLK_SET_RATE_PARENT);
+}
+
+static inline struct clk *imx_clk_fixed_factor(const char *name,
+ const char *parent, unsigned int mult, unsigned int div)
+{
+ return clk_fixed_factor(name, parent, mult, div, CLK_SET_RATE_PARENT);
+}
+
+static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
+ u8 shift, u8 width, const char **parents, u8 num_parents)
+{
+ return clk_mux(name, reg, shift, width, parents, num_parents, 0);
+}
+
+static inline struct clk *imx_clk_mux_p(const char *name, void __iomem *reg,
+ u8 shift, u8 width, const char **parents, u8 num_parents)
+{
+ return clk_mux(name, reg, shift, width, parents, num_parents, CLK_SET_RATE_PARENT);
+}
+
+static inline struct clk *imx_clk_gate(const char *name, const char *parent,
+ void __iomem *reg, u8 shift)
+{
+ return clk_gate(name, parent, reg, shift, CLK_SET_RATE_PARENT, 0);
+}
+
+static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
+ void __iomem *reg, u8 shift)
+{
+ return clk_gate2(name, parent, reg, shift);
+}
+
+struct clk *imx_clk_pllv1(const char *name, const char *parent,
+ void __iomem *base);
+
+struct clk *imx_clk_pllv2(const char *name, const char *parent,
+ void __iomem *base);
+
+enum imx_pllv3_type {
+ IMX_PLLV3_GENERIC,
+ IMX_PLLV3_SYS,
+ IMX_PLLV3_USB,
+ IMX_PLLV3_AV,
+ IMX_PLLV3_ENET,
+ IMX_PLLV3_MLB,
+};
+
+struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
+ const char *parent, void __iomem *base,
+ u32 div_mask);
+
+struct clk *imx_clk_pfd(const char *name, const char *parent,
+ void __iomem *reg, u8 idx);
+
+static inline struct clk *imx_clk_busy_divider(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u8 width,
+ void __iomem *busy_reg, u8 busy_shift)
+{
+ /*
+ * For now we do not support rate setting, so just fall back to
+ * regular divider.
+ */
+ return imx_clk_divider(name, parent, reg, shift, width);
+}
+
+static inline struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
+ u8 width, void __iomem *busy_reg, u8 busy_shift,
+ const char **parents, int num_parents)
+{
+ /*
+ * For now we do not support mux switching, so just fall back to
+ * regular mux.
+ */
+ return imx_clk_mux(name, reg, shift, width, parents, num_parents);
+}
+
+struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u32 exclusive_mask);
+
+#endif /* __IMX_CLK_H */