[PATCH 11/20] i.MX: Add VF610 clock tree initialization code

Andrey Smirnov andrew.smirnov at gmail.com
Mon Oct 3 07:40:48 PDT 2016


Based on analogous code from Linux kernel

Signed-off-by: Andrey Smirnov <andrew.smirnov at gmail.com>
---
 drivers/clk/imx/Makefile    |    1 +
 drivers/clk/imx/clk-vf610.c | 1224 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1225 insertions(+)
 create mode 100644 drivers/clk/imx/clk-vf610.c

diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index 0303c0b..2665f49 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -1 +1,2 @@
 obj-y += clk.o
+obj-$(CONFIG_ARCH_VF610) += clk-vf610.o
diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c
new file mode 100644
index 0000000..2fbdbb3
--- /dev/null
+++ b/drivers/clk/imx/clk-vf610.c
@@ -0,0 +1,1224 @@
+/*
+ * Copyright (c) 2016 Zodiac Inflight Innovations
+ * Author: Andrey Smirnov <andrew.smirnov at gmail.com>
+ *
+ * Based on analogous code from Linux kernel
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <of.h>
+#include <of_address.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <mfd/syscon.h>
+#include <dt-bindings/clock/vf610-clock.h>
+
+#include "../../../arch/arm/mach-imx/clk.h"
+
+enum {
+	CCM_CCR		= 0x00,
+	CCM_CSR		= 0x04,
+	CCM_CCSR	= 0x08,
+	CCM_CACRR	= 0x0c,
+	CCM_CSCMR1	= 0x10,
+	CCM_CSCDR1	= 0x14,
+	CCM_CSCDR2	= 0x18,
+	CCM_CSCDR3	= 0x1c,
+	CCM_CSCMR2	= 0x20,
+	CCM_CSCDR4	= 0x24,
+	CCM_CLPCR	= 0x2c,
+	CCM_CISR	= 0x30,
+	CCM_CIMR	= 0x34,
+	CCM_CGPR	= 0x3c,
+	CCM_CCGR0	= 0x40,
+	CCM_CCGR1	= 0x44,
+	CCM_CCGR2	= 0x48,
+	CCM_CCGR3	= 0x4c,
+	CCM_CCGR4	= 0x50,
+	CCM_CCGR5	= 0x54,
+	CCM_CCGR6	= 0x58,
+	CCM_CCGR7	= 0x5c,
+	CCM_CCGR8	= 0x60,
+	CCM_CCGR9	= 0x64,
+	CCM_CCGR10	= 0x68,
+	CCM_CCGR11	= 0x6c,
+
+	CCM_CMEOR0	= 0x70,
+	CCM_CMEOR1	= 0x74,
+	CCM_CMEOR2	= 0x78,
+	CCM_CMEOR3	= 0x7c,
+	CCM_CMEOR4	= 0x80,
+	CCM_CMEOR5	= 0x84,
+	CCM_CPPDSR	= 0x88,
+	CCM_CCOWR	= 0x8c,
+	CCM_CCPGR0	= 0x90,
+	CCM_CCPGR1	= 0x94,
+	CCM_CCPGR2	= 0x98,
+	CCM_CCPGR3	= 0x9c,
+};
+
+/* CCM_CCGRx(x)		(CCM_CCGR0 + (x) * 4) */
+
+static int vf610_ccm_ccgrx_cgn(int n) {
+	return n * 2;
+}
+
+
+enum {
+	PFD_PLL1_BASE	= 0x2b0,
+	PFD_PLL2_BASE	= 0x100,
+	PFD_PLL3_BASE	= 0x0f0,
+	ANA_MISC1	= 0x160,
+};
+
+static const unsigned int PLL_CTRL[7] = {
+	0x270,
+	0x030,
+	0x010,
+	0x070,
+	0x0e0,
+	0x0a0,
+	0x020,
+};
+
+
+static struct clk *clk[VF610_CLK_END];
+struct clk_onecell_data clk_data;
+
+static struct clk * __init vf610_get_fixed_clock(struct device_node *np,
+						 const char *name)
+{
+	struct clk *clk = of_clk_get_by_name(np, name);
+
+	/* Backward compatibility if device tree is missing clks assignments */
+	if (IS_ERR(clk))
+		clk = imx_obtain_fixed_clock(name, 0);
+
+	return clk;
+};
+
+static void vf610_ccm_setup_fixed(struct device_node *np,
+				  void __iomem *anatop,
+				  void __iomem *ccm)
+{
+	clk[VF610_CLK_DUMMY]	 = clk_fixed("dummy", 0);
+	clk[VF610_CLK_SIRC_128K] = clk_fixed("sirc_128k", 128000);
+	clk[VF610_CLK_SIRC_32K]  = clk_fixed("sirc_32k", 32000);
+	clk[VF610_CLK_FIRC]	 = clk_fixed("firc", 24000000);
+}
+
+static void vf610_ccm_setup_from_dt(struct device_node *np,
+				    void __iomem *anatop,
+				    void __iomem *ccm)
+{
+	clk[VF610_CLK_SXOSC]     = vf610_get_fixed_clock(np, "sxosc");
+	clk[VF610_CLK_FXOSC]     = vf610_get_fixed_clock(np, "fxosc");
+	clk[VF610_CLK_AUDIO_EXT] = vf610_get_fixed_clock(np, "audio_ext");
+	clk[VF610_CLK_ENET_EXT]  = vf610_get_fixed_clock(np, "enet_ext");
+
+	/* Clock source from external clock via LVDs PAD */
+	clk[VF610_CLK_ANACLK1] = vf610_get_fixed_clock(np, "anaclk1");
+
+	clk[VF610_CLK_FXOSC_HALF] = imx_clk_fixed_factor("fxosc_half",
+							 "fxosc", 1, 2);
+}
+
+static void vf610_ccm_setup_slow_clk(struct device_node *np,
+				     void __iomem *anatop,
+				     void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"sirc_32k",
+		"sxosc",
+	};
+
+	clk[VF610_CLK_SLOW_CLK_SEL] = imx_clk_mux("slow_clk_sel",
+						  ccm + CCM_CCSR,
+						  4, 1,
+						  sources,
+						  ARRAY_SIZE(sources));
+}
+
+static void vf610_ccm_setup_fast_clk(struct device_node *np,
+				     void __iomem *anatop,
+				     void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"firc",
+		"fxosc",
+	};
+
+	clk[VF610_CLK_FASK_CLK_SEL] = imx_clk_mux("fast_clk_sel",
+						  ccm + CCM_CCSR,
+						  5, 1,
+						  sources,
+						  ARRAY_SIZE(sources));
+}
+
+static void vf610_ccm_setup_pll_bypass_srcs(struct device_node *np,
+					    void __iomem *anatop,
+					    void __iomem *ccm)
+{
+	size_t i;
+
+	static const char *parents[] = {
+		"fast_clk_sel",
+		"lvds1_in",
+	};
+
+#define VF610_CLK_PLL_BYPASS_SRC(n)			\
+	{ VF610_CLK_PLL##n##_BYPASS_SRC, "pll" #n "_bypass_src" }
+
+	static const struct {
+		int id;
+		const char *name;
+	} clocks[] = {
+		VF610_CLK_PLL_BYPASS_SRC(1),
+		VF610_CLK_PLL_BYPASS_SRC(2),
+		VF610_CLK_PLL_BYPASS_SRC(3),
+		VF610_CLK_PLL_BYPASS_SRC(4),
+		VF610_CLK_PLL_BYPASS_SRC(5),
+		VF610_CLK_PLL_BYPASS_SRC(6),
+		VF610_CLK_PLL_BYPASS_SRC(7),
+	};
+
+#undef VF610_CLK_PLL_BYPASS_SRC
+
+	for (i = 0; i < ARRAY_SIZE(clocks); i++) {
+		const char *name = clocks[i].name;
+		const int id = clocks[i].id;
+
+		clk[id] = imx_clk_mux(name, anatop + PLL_CTRL[i],
+				      14, 1,
+				      parents, ARRAY_SIZE(parents));
+	}
+}
+
+static void vf610_ccm_setup_plls(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	size_t i;
+
+#define VF610_CLK_PLL(n, type, mask)				   \
+	{ VF610_CLK_PLL##n, type, "pll" #n, "pll" #n "_bypass_src", mask }
+
+	static const struct {
+		int id;
+		int type;
+		const char *name;
+		const char *parent;
+		u32 mask;
+	} clocks[] = {
+		VF610_CLK_PLL(1, IMX_PLLV3_GENERIC,   0x01),
+		VF610_CLK_PLL(2, IMX_PLLV3_GENERIC,   0x01),
+		VF610_CLK_PLL(3, IMX_PLLV3_USB_VF610, 0x02),
+		VF610_CLK_PLL(4, IMX_PLLV3_AV,        0x7f),
+		VF610_CLK_PLL(5, IMX_PLLV3_ENET,      0x03),
+		VF610_CLK_PLL(6, IMX_PLLV3_AV,        0x7f),
+		VF610_CLK_PLL(7, IMX_PLLV3_USB_VF610, 0x02),
+	};
+
+#undef VF610_CLK_PLL
+
+	for (i = 0; i < ARRAY_SIZE(clocks); i++) {
+		const char *name = clocks[i].name;
+		const int id = clocks[i].id;
+
+		clk[id] = imx_clk_pllv3(clocks[i].type,
+					name,
+					clocks[i].parent,
+					anatop + PLL_CTRL[i],
+					clocks[i].mask);
+	}
+}
+
+static void vf610_ccm_setup_pll_bypass(struct device_node *np,
+				       void __iomem *anatop,
+				       void __iomem *ccm)
+{
+	size_t i;
+	static const char *pll_bypass_parents[][2] = {
+		{ "pll1", "pll1_bypass_src" },
+		{ "pll2", "pll2_bypass_src" },
+		{ "pll3", "pll3_bypass_src" },
+		{ "pll4", "pll4_bypass_src" },
+		{ "pll5", "pll5_bypass_src" },
+		{ "pll6", "pll6_bypass_src" },
+		{ "pll7", "pll7_bypass_src" },
+	};
+
+#define VF610_PLL_BYPASS(n)				\
+	{ VF610_PLL##n##_BYPASS, "pll" #n "_bypass" }
+
+	static const struct {
+		int id;
+		const char *name;
+	} clocks[] = {
+		VF610_PLL_BYPASS(1),
+		VF610_PLL_BYPASS(2),
+		VF610_PLL_BYPASS(3),
+		VF610_PLL_BYPASS(4),
+		VF610_PLL_BYPASS(5),
+		VF610_PLL_BYPASS(6),
+		VF610_PLL_BYPASS(7),
+	};
+
+#undef VF610_PLL_BYPASS
+
+	for (i = 0; i < ARRAY_SIZE(clocks); i++) {
+		const char *name = clocks[i].name;
+		const int id = clocks[i].id;
+
+		clk[id] = imx_clk_mux_p(name,
+					anatop + PLL_CTRL[i],
+					16, 1,
+					pll_bypass_parents[i],
+					ARRAY_SIZE(pll_bypass_parents[i]));
+	}
+}
+
+static void vf610_ccm_setup_group1(struct device_node *np,
+				   void __iomem *anatop,
+				   void __iomem *ccm)
+{
+	size_t i;
+
+	static const struct {
+		int id;
+		const char *name;
+		const char *parent;
+		unsigned int reg;
+	} clocks[] = {
+		{ VF610_CLK_PLL1_SYS,      "pll1_sys",      "pll1_bypass" },
+		{ VF610_CLK_PLL2_BUS,      "pll2_bus",      "pll2_bypass" },
+		{ VF610_CLK_PLL3_USB_OTG,  "pll3_usb_otg",  "pll3_bypass" },
+		{ VF610_CLK_PLL4_AUDIO,    "pll4_audio",    "pll4_bypass" },
+		{ VF610_CLK_PLL5_ENET,     "pll5_enet",     "pll5_bypass" },
+		{ VF610_CLK_PLL6_VIDEO,    "pll6_video",    "pll6_bypass" },
+		{ VF610_CLK_PLL7_USB_HOST, "pll7_usb_host", "pll7_bypass" },
+	};
+
+	for (i = 0; i < ARRAY_SIZE(clocks); i++) {
+		const char *name = clocks[i].name;
+		const int id = clocks[i].id;
+
+		clk[id] = imx_clk_gate(name, clocks[i].parent,
+				       anatop + PLL_CTRL[i], 13);
+	}
+}
+
+static void vf610_ccm_setup_pfds(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	size_t i;
+
+#define VF610_CLK_PLL_PFD(n, m)						\
+	{ VF610_CLK_PLL##n##_PFD##m, "pll" #n "_pfd" #m,		\
+	  "pll" #n "_sys", PFD_PLL##n##_BASE, m - 1 }
+
+	const static struct {
+		int id;
+		const char *name;
+		const char *parent;
+		unsigned int reg;
+		u8 idx;
+	} clocks[] = {
+		VF610_CLK_PLL_PFD(1, 1),
+		VF610_CLK_PLL_PFD(1, 2),
+		VF610_CLK_PLL_PFD(1, 3),
+		VF610_CLK_PLL_PFD(1, 4),
+
+		VF610_CLK_PLL_PFD(2, 1),
+		VF610_CLK_PLL_PFD(2, 2),
+		VF610_CLK_PLL_PFD(2, 3),
+		VF610_CLK_PLL_PFD(2, 4),
+
+		VF610_CLK_PLL_PFD(3, 1),
+		VF610_CLK_PLL_PFD(3, 2),
+		VF610_CLK_PLL_PFD(3, 3),
+		VF610_CLK_PLL_PFD(3, 4),
+	};
+
+#undef VF610_CLK_PLL_PFD
+
+	for (i = 0; i < ARRAY_SIZE(clocks); i++) {
+		const char *name = clocks[i].name;
+		const int id = clocks[i].id;
+
+		clk[id] = imx_clk_pfd(name,
+				      clocks[i].parent,
+				      anatop + clocks[i].reg,
+				      clocks[i].idx);
+	}
+}
+
+static void vf610_ccm_setup_pll1_pfd_out(struct device_node *np,
+					 void __iomem *anatop,
+					 void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"pll1_sys",
+		"pll1_pfd1",
+		"pll1_pfd2",
+		"pll1_pfd3",
+		"pll1_pfd4",
+	};
+
+	clk[VF610_CLK_PLL1_PFD_SEL] = imx_clk_mux("pll1_pfd_sel",
+						  ccm + CCM_CCSR,
+						  16, 3,
+						  sources, ARRAY_SIZE(sources));
+}
+
+static void vf610_ccm_setup_pll2_pfd_out(struct device_node *np,
+					 void __iomem *anatop,
+					 void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"pll2_bus",
+		"pll2_pfd1",
+		"pll2_pfd2",
+		"pll2_pfd3",
+		"pll2_pfd4",
+	};
+
+	clk[VF610_CLK_PLL2_PFD_SEL] = imx_clk_mux("pll2_pfd_sel",
+						  ccm + CCM_CCSR,
+						  19, 3,
+						  sources, ARRAY_SIZE(sources));
+}
+
+static void vf610_ccm_setup_sys_out(struct device_node *np,
+				   void __iomem *anatop,
+				   void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"fast_clk_sel",
+		"slow_clk_sel",
+		"pll2_pfd_sel",
+		"pll2_bus",
+		"pll1_pfd_sel",
+		"pll3_usb_otg",
+	};
+
+	clk[VF610_CLK_SYS_SEL] = imx_clk_mux("sys_sel",
+					     ccm + CCM_CCSR,
+					     0, 3,
+					     sources, ARRAY_SIZE(sources));
+}
+
+static void vf610_ccm_setup_ddr_out(struct device_node *np,
+				    void __iomem *anatop,
+				    void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"pll2_pfd2",
+		"sys_sel",
+	};
+
+	clk[VF610_CLK_DDR_SEL] = imx_clk_mux("ddr_sel",
+					     ccm + CCM_CCSR,
+					     6, 1,
+					     sources, ARRAY_SIZE(sources));
+}
+
+static void vf610_ccm_setup_dividers(struct device_node *np,
+				     void __iomem *anatop,
+				     void __iomem *ccm)
+{
+	size_t i;
+
+	static const struct {
+		int id;
+		const char *name;
+		const char *parent;
+		u8 shift;
+		u8 width;
+	} clocks[] = {
+		{
+			.id	= VF610_CLK_SYS_BUS,
+			.name	= "sys_bus",
+			.parent = "sys_sel",
+			.shift	= 0,
+			.width	= 3,
+		},
+		{
+			.id	= VF610_CLK_PLATFORM_BUS,
+			.name	= "platform_bus",
+			.parent = "sys_bus",
+			.shift	= 3,
+			.width	= 3,
+		},
+		{
+			.id	= VF610_CLK_IPG_BUS,
+			.name	= "ipg_bus",
+			.parent = "platform_bus",
+			.shift	= 11,
+			.width	= 2,
+		},
+		{
+			.id	= VF610_CLK_PLL3_MAIN_DIV,
+			.name	= "pll3_usb_otg_div",
+			.parent = "pll3_usb_otg",
+			.shift	= 20,
+			.width	= 1,
+		},
+		{
+			.id	= VF610_CLK_PLL6_MAIN_DIV,
+			.name	= "pll6_video_div",
+			.parent = "pll6_video",
+			.shift	= 21,
+			.width	= 1,
+		},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(clocks); i++)
+		clk[clocks[i].id] = imx_clk_divider(clocks[i].name,
+						    clocks[i].parent,
+						    ccm + CCM_CACRR,
+						    clocks[i].shift,
+						    clocks[i].width);
+}
+
+static void vf610_ccm_setup_pll4_main_div(struct device_node *np,
+					  void __iomem *anatop,
+					  void __iomem *ccm)
+{
+	static const struct clk_div_table div_table[] = {
+		{ .val = 0, .div = 1  },
+		{ .val = 1, .div = 2  },
+		{ .val = 2, .div = 6  },
+		{ .val = 3, .div = 8  },
+		{ .val = 4, .div = 10 },
+		{ .val = 5, .div = 12 },
+		{ .val = 6, .div = 14 },
+		{ .val = 7, .div = 16 },
+		{ }
+	};
+
+	clk[VF610_CLK_PLL4_MAIN_DIV] = clk_divider_table("pll4_audio_div",
+							 "pll4_audio",
+							 ccm +  CCM_CACRR, 6, 3,
+							 div_table, 0);
+}
+
+static void vf610_ccm_setup_ddrmc(struct device_node *np,
+				  void __iomem *anatop,
+				  void __iomem *ccm)
+{
+	clk[VF610_CLK_DDRMC] = imx_clk_gate2_cgr("ddrmc",
+						 "ddr_sel",
+						 ccm + CCM_CCGR6,
+						 vf610_ccm_ccgrx_cgn(14),
+						 0x2);
+}
+
+static void vf610_ccm_setup_wkpu(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	clk[VF610_CLK_WKPU] = imx_clk_gate2_cgr("wkpu",
+						"ipg_bus",
+						ccm + CCM_CCGR4,
+						vf610_ccm_ccgrx_cgn(10),
+						0x2);
+}
+
+static void vf610_ccm_setup_usbphys(struct device_node *np,
+				    void __iomem *anatop,
+				    void __iomem *ccm)
+{
+	clk[VF610_CLK_USBPHY0] = imx_clk_gate("usbphy0", "pll3_usb_otg",
+					      anatop + PLL_CTRL[2], 6);
+	clk[VF610_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll7_usb_host",
+					      anatop + PLL_CTRL[6], 6);
+}
+
+static void vf610_ccm_setup_usbcs(struct device_node *np,
+				  void __iomem *anatop,
+				  void __iomem *ccm)
+
+{
+
+	clk[VF610_CLK_USBC0] = imx_clk_gate2("usbc0", "ipg_bus",
+					     ccm + CCM_CCGR1,
+					     vf610_ccm_ccgrx_cgn(4));
+	clk[VF610_CLK_USBC1] = imx_clk_gate2("usbc1", "ipg_bus",
+					     ccm + CCM_CCGR7,
+					     vf610_ccm_ccgrx_cgn(4));
+
+}
+
+static void vf610_ccm_setup_qspis(struct device_node *np,
+				  void __iomem *anatop,
+				  void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"pll3_usb_otg",
+		"pll3_pfd4",
+		"pll2_pfd4",
+		"pll1_pfd4",
+	};
+
+	clk[VF610_CLK_QSPI0_SEL] = imx_clk_mux("qspi0_sel",
+					       ccm + CCM_CSCMR1,
+					       22, 2,
+					       sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_QSPI0_EN] = imx_clk_gate("qspi0_en", "qspi0_sel",
+					       ccm + CCM_CSCDR3, 4);
+	clk[VF610_CLK_QSPI0_X4_DIV] = imx_clk_divider("qspi0_x4", "qspi0_en",
+						      ccm + CCM_CSCDR3, 0, 2);
+	clk[VF610_CLK_QSPI0_X2_DIV] = imx_clk_divider("qspi0_x2", "qspi0_x4",
+						      ccm + CCM_CSCDR3, 2, 1);
+	clk[VF610_CLK_QSPI0_X1_DIV] = imx_clk_divider("qspi0_x1", "qspi0_x2",
+						      ccm + CCM_CSCDR3, 3, 1);
+	clk[VF610_CLK_QSPI0] = imx_clk_gate2("qspi0", "qspi0_x1",
+					     ccm + CCM_CCGR2,
+					     vf610_ccm_ccgrx_cgn(4));
+
+	clk[VF610_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel",
+					       ccm + CCM_CSCMR1,
+					       24, 2,
+					       sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_QSPI1_EN] = imx_clk_gate("qspi1_en", "qspi1_sel",
+					       ccm + CCM_CSCDR3, 12);
+	clk[VF610_CLK_QSPI1_X4_DIV] = imx_clk_divider("qspi1_x4", "qspi1_en",
+						      ccm + CCM_CSCDR3, 8, 2);
+	clk[VF610_CLK_QSPI1_X2_DIV] = imx_clk_divider("qspi1_x2", "qspi1_x4",
+						      ccm + CCM_CSCDR3, 10, 1);
+	clk[VF610_CLK_QSPI1_X1_DIV] = imx_clk_divider("qspi1_x1", "qspi1_x2",
+						      ccm + CCM_CSCDR3, 11, 1);
+	clk[VF610_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_x1",
+					     ccm + CCM_CCGR8,
+					     vf610_ccm_ccgrx_cgn(4));
+}
+
+static void vf610_ccm_setup_enets(struct device_node *np,
+				  void __iomem *anatop,
+				  void __iomem *ccm)
+{
+	static const char *enet_sels[] = {
+		"enet_ext",
+		"audio_ext",
+		"enet_50m",
+		"enet_25m",
+	};
+
+	static const char *enet_ts_sels[] = {
+		"enet_ext",
+		"fxosc",
+		"audio_ext",
+		"usb",
+		"enet_ts",
+		"enet_25m",
+		"enet_50m",
+	};
+
+	clk[VF610_CLK_ENET_50M] = imx_clk_fixed_factor("enet_50m",
+						       "pll5_enet", 1, 10);
+	clk[VF610_CLK_ENET_25M] = imx_clk_fixed_factor("enet_25m",
+						       "pll5_enet", 1, 20);
+	clk[VF610_CLK_ENET_SEL] = imx_clk_mux("enet_sel",
+					      ccm + CCM_CSCMR2, 4, 2,
+					      enet_sels,
+					      ARRAY_SIZE(enet_sels));
+	clk[VF610_CLK_ENET_TS_SEL] = imx_clk_mux("enet_ts_sel",
+						 ccm + CCM_CSCMR2, 0, 3,
+						 enet_ts_sels,
+						 ARRAY_SIZE(enet_ts_sels));
+	clk[VF610_CLK_ENET] = imx_clk_gate("enet", "enet_sel",
+					   ccm + CCM_CSCDR1, 24);
+	clk[VF610_CLK_ENET_TS] = imx_clk_gate("enet_ts", "enet_ts_sel",
+					      ccm + CCM_CSCDR1, 23);
+	clk[VF610_CLK_ENET0] = imx_clk_gate2("enet0", "ipg_bus",
+					     ccm + CCM_CCGR9,
+					     vf610_ccm_ccgrx_cgn(0));
+	clk[VF610_CLK_ENET1] = imx_clk_gate2("enet1", "ipg_bus",
+					     ccm + CCM_CCGR9,
+					     vf610_ccm_ccgrx_cgn(1));
+}
+
+static void vf610_ccm_setup_pit(struct device_node *np,
+				  void __iomem *anatop,
+				  void __iomem *ccm)
+{
+	clk[VF610_CLK_PIT] = imx_clk_gate2("pit", "ipg_bus",
+					   ccm + CCM_CCGR1,
+					   vf610_ccm_ccgrx_cgn(7));
+}
+
+static void vf610_ccm_setup_uarts(struct device_node *np,
+				  void __iomem *anatop,
+				  void __iomem *ccm)
+{
+	clk[VF610_CLK_UART0] = imx_clk_gate2("uart0", "ipg_bus",
+					     ccm + CCM_CCGR0,
+					     vf610_ccm_ccgrx_cgn(7));
+	clk[VF610_CLK_UART1] = imx_clk_gate2("uart1", "ipg_bus",
+					     ccm + CCM_CCGR0,
+					     vf610_ccm_ccgrx_cgn(8));
+	clk[VF610_CLK_UART2] = imx_clk_gate2("uart2", "ipg_bus",
+					     ccm + CCM_CCGR0,
+					     vf610_ccm_ccgrx_cgn(9));
+	clk[VF610_CLK_UART3] = imx_clk_gate2("uart3", "ipg_bus",
+					     ccm + CCM_CCGR0,
+					     vf610_ccm_ccgrx_cgn(10));
+	clk[VF610_CLK_UART4] = imx_clk_gate2("uart4", "ipg_bus",
+					     ccm + CCM_CCGR6,
+					     vf610_ccm_ccgrx_cgn(9));
+	clk[VF610_CLK_UART5] = imx_clk_gate2("uart5", "ipg_bus",
+					     ccm + CCM_CCGR6,
+					     vf610_ccm_ccgrx_cgn(10));
+}
+
+static void vf610_ccm_setup_i2cs(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+
+{
+	clk[VF610_CLK_I2C0] = imx_clk_gate2("i2c0", "ipg_bus",
+					    ccm + CCM_CCGR4,
+					    vf610_ccm_ccgrx_cgn(6));
+	clk[VF610_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_bus",
+					    ccm + CCM_CCGR4,
+					    vf610_ccm_ccgrx_cgn(7));
+	clk[VF610_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_bus",
+					    ccm + CCM_CCGR10,
+					    vf610_ccm_ccgrx_cgn(6));
+	clk[VF610_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_bus",
+					    ccm + CCM_CCGR10,
+					    vf610_ccm_ccgrx_cgn(7));
+}
+
+static void vf610_ccm_setup_dspis(struct device_node *np,
+				  void __iomem *anatop,
+				  void __iomem *ccm)
+{
+	clk[VF610_CLK_DSPI0] = imx_clk_gate2("dspi0", "ipg_bus",
+					     ccm + CCM_CCGR0,
+					     vf610_ccm_ccgrx_cgn(12));
+	clk[VF610_CLK_DSPI1] = imx_clk_gate2("dspi1", "ipg_bus",
+					     ccm + CCM_CCGR0,
+					     vf610_ccm_ccgrx_cgn(13));
+	clk[VF610_CLK_DSPI2] = imx_clk_gate2("dspi2", "ipg_bus",
+					     ccm + CCM_CCGR6,
+					     vf610_ccm_ccgrx_cgn(12));
+	clk[VF610_CLK_DSPI3] = imx_clk_gate2("dspi3", "ipg_bus",
+					     ccm + CCM_CCGR6,
+					     vf610_ccm_ccgrx_cgn(13));
+}
+
+static void vf610_ccm_setup_wdt(struct device_node *np,
+				void __iomem *anatop,
+				void __iomem *ccm)
+{
+	clk[VF610_CLK_WDT] = imx_clk_gate2("wdt", "ipg_bus",
+					   ccm + CCM_CCGR1,
+					   vf610_ccm_ccgrx_cgn(14));
+}
+
+static void vf610_ccm_setup_esdhcs(struct device_node *np,
+				   void __iomem *anatop,
+				   void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"pll3_usb_otg",
+		"pll3_pfd3",
+		"pll1_pfd3",
+		"platform_bus",
+	};
+
+	clk[VF610_CLK_ESDHC0_SEL] = imx_clk_mux("esdhc0_sel",
+						ccm + CCM_CSCMR1, 16, 2,
+						sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_ESDHC0_EN] = imx_clk_gate("esdhc0_en", "esdhc0_sel",
+						ccm + CCM_CSCDR2, 28);
+	clk[VF610_CLK_ESDHC0_DIV] = imx_clk_divider("esdhc0_div", "esdhc0_en",
+						    ccm +CCM_CSCDR2, 16, 4);
+	clk[VF610_CLK_ESDHC0] = imx_clk_gate2("eshc0", "esdhc0_div",
+					      ccm + CCM_CCGR7,
+					      vf610_ccm_ccgrx_cgn(1));
+
+	clk[VF610_CLK_ESDHC1_SEL] = imx_clk_mux("esdhc1_sel",
+						ccm + CCM_CSCMR1, 18, 2,
+						sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_ESDHC1_EN] = imx_clk_gate("esdhc1_en", "esdhc1_sel",
+						ccm + CCM_CSCDR2, 29);
+	clk[VF610_CLK_ESDHC1_DIV] = imx_clk_divider("esdhc1_div", "esdhc1_en",
+						    ccm + CCM_CSCDR2, 20, 4);
+	clk[VF610_CLK_ESDHC1] = imx_clk_gate2("eshc1", "esdhc1_div",
+					      ccm + CCM_CCGR7,
+					      vf610_ccm_ccgrx_cgn(2));
+}
+
+static void vf610_ccm_setup_ftms(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	/* FTM counter clock source, not module clock */
+	static const char *ftm_ext_sels[] = {
+		"sirc_128k",
+		"sxosc",
+		"fxosc_half",
+		"audio_ext",
+	};
+
+	static const char *ftm_fix_sels[] = {
+		"sxosc",
+		"ipg_bus",
+	};
+
+	/*
+	 * ftm_ext_clk and ftm_fix_clk are FTM timer counter's
+	 * selectable clock sources, both use a common enable bit
+	 * in CCM_CSCDR1, selecting "dummy" clock as parent of
+	 * "ftm0_ext_fix" make it serve only for enable/disable.
+	 */
+	clk[VF610_CLK_FTM0_EXT_SEL] = imx_clk_mux("ftm0_ext_sel",
+						  ccm + CCM_CSCMR2, 6, 2,
+						  ftm_ext_sels,
+						  ARRAY_SIZE(ftm_ext_sels));
+	clk[VF610_CLK_FTM0_FIX_SEL] = imx_clk_mux("ftm0_fix_sel",
+						  ccm + CCM_CSCMR2, 14, 1,
+						  ftm_fix_sels,
+						  ARRAY_SIZE(ftm_fix_sels));
+	clk[VF610_CLK_FTM0_EXT_FIX_EN] = imx_clk_gate("ftm0_ext_fix_en",
+						      "dummy",
+						      ccm + CCM_CSCDR1, 25);
+	clk[VF610_CLK_FTM1_EXT_SEL] = imx_clk_mux("ftm1_ext_sel",
+						  ccm + CCM_CSCMR2, 8, 2,
+						  ftm_ext_sels,
+						  ARRAY_SIZE(ftm_ext_sels));
+	clk[VF610_CLK_FTM1_FIX_SEL] = imx_clk_mux("ftm1_fix_sel",
+						  ccm + CCM_CSCMR2, 15, 1,
+						  ftm_fix_sels,
+						  ARRAY_SIZE(ftm_fix_sels));
+	clk[VF610_CLK_FTM1_EXT_FIX_EN] = imx_clk_gate("ftm1_ext_fix_en",
+						      "dummy",
+						      ccm + CCM_CSCDR1, 26);
+	clk[VF610_CLK_FTM2_EXT_SEL] = imx_clk_mux("ftm2_ext_sel",
+						  ccm + CCM_CSCMR2, 10, 2,
+						  ftm_ext_sels,
+						  ARRAY_SIZE(ftm_ext_sels));
+	clk[VF610_CLK_FTM2_FIX_SEL] = imx_clk_mux("ftm2_fix_sel",
+						  ccm + CCM_CSCMR2, 16, 1,
+						  ftm_fix_sels,
+						  ARRAY_SIZE(ftm_fix_sels));
+	clk[VF610_CLK_FTM2_EXT_FIX_EN] = imx_clk_gate("ftm2_ext_fix_en",
+						      "dummy",
+						      ccm + CCM_CSCDR1, 27);
+	clk[VF610_CLK_FTM3_EXT_SEL] = imx_clk_mux("ftm3_ext_sel",
+						  ccm + CCM_CSCMR2, 12, 2,
+						  ftm_ext_sels,
+						  ARRAY_SIZE(ftm_ext_sels));
+	clk[VF610_CLK_FTM3_FIX_SEL] = imx_clk_mux("ftm3_fix_sel",
+						  ccm + CCM_CSCMR2, 17, 1,
+						  ftm_fix_sels,
+						  ARRAY_SIZE(ftm_fix_sels));
+	clk[VF610_CLK_FTM3_EXT_FIX_EN] = imx_clk_gate("ftm3_ext_fix_en",
+						      "dummy",
+						      ccm + CCM_CSCDR1, 28);
+
+	/* ftm(n)_clk are FTM module operation clock */
+	clk[VF610_CLK_FTM0] = imx_clk_gate2("ftm0", "ipg_bus",
+					    ccm + CCM_CCGR1,
+					    vf610_ccm_ccgrx_cgn(8));
+	clk[VF610_CLK_FTM1] = imx_clk_gate2("ftm1", "ipg_bus",
+					    ccm + CCM_CCGR1,
+					    vf610_ccm_ccgrx_cgn(9));
+	clk[VF610_CLK_FTM2] = imx_clk_gate2("ftm2", "ipg_bus",
+					    ccm + CCM_CCGR7,
+					    vf610_ccm_ccgrx_cgn(8));
+	clk[VF610_CLK_FTM3] = imx_clk_gate2("ftm3", "ipg_bus",
+					    ccm + CCM_CCGR7,
+					    vf610_ccm_ccgrx_cgn(9));
+}
+
+static void vf610_ccm_setup_dcus(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"pll1_pfd2",
+		"pll3_usb_otg",
+	};
+
+	clk[VF610_CLK_DCU0_SEL] = imx_clk_mux("dcu0_sel",
+					      ccm + CCM_CSCMR1, 28, 1,
+					      sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_DCU0_EN] = imx_clk_gate("dcu0_en", "dcu0_sel",
+					      ccm + CCM_CSCDR3, 19);
+	clk[VF610_CLK_DCU0_DIV] = imx_clk_divider("dcu0_div", "dcu0_en",
+						  ccm + CCM_CSCDR3, 16, 3);
+	clk[VF610_CLK_DCU0] = imx_clk_gate2("dcu0", "ipg_bus",
+					    ccm + CCM_CCGR3,
+					    vf610_ccm_ccgrx_cgn(8));
+	clk[VF610_CLK_DCU1_SEL] = imx_clk_mux("dcu1_sel",
+					      ccm + CCM_CSCMR1, 29, 1,
+					      sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_DCU1_EN] = imx_clk_gate("dcu1_en", "dcu1_sel",
+					      ccm + CCM_CSCDR3, 23);
+	clk[VF610_CLK_DCU1_DIV] = imx_clk_divider("dcu1_div", "dcu1_en",
+						  ccm + CCM_CSCDR3, 20, 3);
+	clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "ipg_bus",
+					    ccm + CCM_CCGR9,
+					    vf610_ccm_ccgrx_cgn(8));
+}
+
+static void vf610_ccm_setup_tcons(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	clk[VF610_CLK_TCON0] = imx_clk_gate2("tcon0", "platform_bus",
+					     ccm + CCM_CCGR1,
+					     vf610_ccm_ccgrx_cgn(13));
+	clk[VF610_CLK_TCON1] = imx_clk_gate2("tcon1", "platform_bus",
+					     ccm + CCM_CCGR7,
+					     vf610_ccm_ccgrx_cgn(13));
+}
+
+
+static void vf610_ccm_setup_esai(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"audio_ext",
+		"mlb",
+		"spdif_rx",
+		"pll4_audio_div",
+	};
+
+	clk[VF610_CLK_ESAI_SEL] = imx_clk_mux("esai_sel",
+					      ccm + CCM_CSCMR1, 20, 2,
+					      sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_ESAI_EN] = imx_clk_gate("esai_en", "esai_sel",
+					      ccm + CCM_CSCDR2, 30);
+	clk[VF610_CLK_ESAI_DIV] = imx_clk_divider("esai_div", "esai_en",
+						  ccm + CCM_CSCDR2, 24, 4);
+	clk[VF610_CLK_ESAI] = imx_clk_gate2("esai", "esai_div",
+					    ccm + CCM_CCGR4,
+					    vf610_ccm_ccgrx_cgn(2));
+}
+
+static void vf610_ccm_setup_sais(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"audio_ext",
+		"mlb",
+		"spdif_rx",
+		"pll4_audio_div",
+	};
+
+	clk[VF610_CLK_SAI0_SEL] = imx_clk_mux("sai0_sel",
+					      ccm + CCM_CSCMR1, 0, 2,
+					      sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_SAI0_EN] = imx_clk_gate("sai0_en", "sai0_sel",
+					      ccm + CCM_CSCDR1, 16);
+	clk[VF610_CLK_SAI0_DIV] = imx_clk_divider("sai0_div", "sai0_en",
+						  ccm + CCM_CSCDR1, 0, 4);
+	clk[VF610_CLK_SAI0] = imx_clk_gate2("sai0", "ipg_bus",
+					    ccm + CCM_CCGR0,
+					    vf610_ccm_ccgrx_cgn(15));
+
+	clk[VF610_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel",
+					      ccm + CCM_CSCMR1, 2, 2,
+					      sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_SAI1_EN] = imx_clk_gate("sai1_en", "sai1_sel",
+					      ccm + CCM_CSCDR1, 17);
+	clk[VF610_CLK_SAI1_DIV] = imx_clk_divider("sai1_div", "sai1_en",
+						  ccm + CCM_CSCDR1, 4, 4);
+	clk[VF610_CLK_SAI1] = imx_clk_gate2("sai1", "ipg_bus",
+					    ccm + CCM_CCGR1,
+					    vf610_ccm_ccgrx_cgn(0));
+
+	clk[VF610_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel",
+					      ccm + CCM_CSCMR1, 4, 2,
+					      sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_SAI2_EN] = imx_clk_gate("sai2_en", "sai2_sel",
+					      ccm + CCM_CSCDR1, 18);
+	clk[VF610_CLK_SAI2_DIV] = imx_clk_divider("sai2_div", "sai2_en",
+						  ccm + CCM_CSCDR1, 8, 4);
+	clk[VF610_CLK_SAI2] = imx_clk_gate2("sai2", "ipg_bus",
+					    ccm + CCM_CCGR1,
+					    vf610_ccm_ccgrx_cgn(1));
+
+	clk[VF610_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel",
+					      ccm + CCM_CSCMR1, 6, 2,
+					      sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_SAI3_EN] = imx_clk_gate("sai3_en", "sai3_sel",
+					      ccm + CCM_CSCDR1, 19);
+	clk[VF610_CLK_SAI3_DIV] = imx_clk_divider("sai3_div", "sai3_en",
+						  ccm + CCM_CSCDR1, 12, 4);
+	clk[VF610_CLK_SAI3] = imx_clk_gate2("sai3", "ipg_bus",
+					    ccm + CCM_CCGR1,
+					    vf610_ccm_ccgrx_cgn(2));
+}
+
+static void vf610_ccm_setup_nfc(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"platform_bus",
+		"pll1_pfd1",
+		"pll3_pfd1",
+		"pll3_pfd3",
+	};
+
+	clk[VF610_CLK_NFC_SEL] = imx_clk_mux("nfc_sel",
+					     ccm + CCM_CSCMR1, 12, 2,
+					     sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_NFC_EN] = imx_clk_gate("nfc_en", "nfc_sel",
+					     ccm + CCM_CSCDR2, 9);
+	clk[VF610_CLK_NFC_PRE_DIV] = imx_clk_divider("nfc_pre_div", "nfc_en",
+						     ccm + CCM_CSCDR3, 13, 3);
+	clk[VF610_CLK_NFC_FRAC_DIV] = imx_clk_divider("nfc_frac_div",
+						      "nfc_pre_div",
+						      ccm + CCM_CSCDR2, 4, 4);
+	clk[VF610_CLK_NFC] = imx_clk_gate2("nfc", "nfc_frac_div",
+					   ccm + CCM_CCGR10,
+					   vf610_ccm_ccgrx_cgn(0));
+}
+
+static void vf610_ccm_setup_gpu(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"pll2_pfd2",
+		"pll3_pfd2",
+	};
+
+	clk[VF610_CLK_GPU_SEL] = imx_clk_mux("gpu_sel",
+					     ccm + CCM_CSCMR1, 14, 1,
+					     sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_GPU_EN] = imx_clk_gate("gpu_en", "gpu_sel",
+					     ccm + CCM_CSCDR2, 10);
+	clk[VF610_CLK_GPU2D] = imx_clk_gate2("gpu", "gpu_en",
+					     ccm + CCM_CCGR8,
+					     vf610_ccm_ccgrx_cgn(15));
+}
+
+static void vf610_ccm_setup_vadc(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	static const char *sources[] = {
+		"pll6_video_div",
+		"pll3_usb_otg_div",
+		"pll3_usb_otg",
+	};
+
+	clk[VF610_CLK_VADC_SEL] = imx_clk_mux("vadc_sel",
+					      ccm + CCM_CSCMR1, 8, 2,
+					      sources, ARRAY_SIZE(sources));
+	clk[VF610_CLK_VADC_EN] = imx_clk_gate("vadc_en", "vadc_sel",
+					      ccm + CCM_CSCDR1, 22);
+	clk[VF610_CLK_VADC_DIV] = imx_clk_divider("vadc_div", "vadc_en",
+						  ccm + CCM_CSCDR1, 20, 2);
+	clk[VF610_CLK_VADC_DIV_HALF] = imx_clk_fixed_factor("vadc_div_half",
+							    "vadc_div",
+							    1, 2);
+	clk[VF610_CLK_VADC] = imx_clk_gate2("vadc", "vadc_div",
+					    ccm + CCM_CCGR8,
+					    vf610_ccm_ccgrx_cgn(7));
+}
+
+
+static void vf610_ccm_setup_adcs(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	clk[VF610_CLK_ADC0] = imx_clk_gate2("adc0", "ipg_bus",
+					    ccm + CCM_CCGR1,
+					    vf610_ccm_ccgrx_cgn(11));
+	clk[VF610_CLK_ADC1] = imx_clk_gate2("adc1", "ipg_bus",
+					    ccm + CCM_CCGR7,
+					    vf610_ccm_ccgrx_cgn(11));
+	clk[VF610_CLK_DAC0] = imx_clk_gate2("dac0", "ipg_bus",
+					    ccm + CCM_CCGR8,
+					    vf610_ccm_ccgrx_cgn(12));
+	clk[VF610_CLK_DAC1] = imx_clk_gate2("dac1", "ipg_bus",
+					    ccm + CCM_CCGR8,
+					    vf610_ccm_ccgrx_cgn(13));
+}
+
+static void vf610_ccm_setup_flexcans(struct device_node *np,
+				     void __iomem *anatop,
+				     void __iomem *ccm)
+{
+	clk[VF610_CLK_FLEXCAN0_EN] = imx_clk_gate("flexcan0_en", "ipg_bus",
+						  ccm + CCM_CSCDR2, 11);
+	clk[VF610_CLK_FLEXCAN0] = imx_clk_gate2("flexcan0", "flexcan0_en",
+						ccm + CCM_CCGR0,
+						vf610_ccm_ccgrx_cgn(0));
+	clk[VF610_CLK_FLEXCAN1_EN] = imx_clk_gate("flexcan1_en", "ipg_bus",
+						  ccm + CCM_CSCDR2, 12);
+	clk[VF610_CLK_FLEXCAN1] = imx_clk_gate2("flexcan1", "flexcan1_en",
+						ccm + CCM_CCGR9,
+						vf610_ccm_ccgrx_cgn(4));
+}
+
+static void vf610_ccm_setup_dmas(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	clk[VF610_CLK_DMAMUX0] = imx_clk_gate2("dmamux0", "platform_bus",
+					       ccm + CCM_CCGR0,
+					       vf610_ccm_ccgrx_cgn(4));
+	clk[VF610_CLK_DMAMUX1] = imx_clk_gate2("dmamux1", "platform_bus",
+					       ccm + CCM_CCGR0,
+					       vf610_ccm_ccgrx_cgn(5));
+	clk[VF610_CLK_DMAMUX2] = imx_clk_gate2("dmamux2", "platform_bus",
+					       ccm + CCM_CCGR6,
+					       vf610_ccm_ccgrx_cgn(1));
+	clk[VF610_CLK_DMAMUX3] = imx_clk_gate2("dmamux3", "platform_bus",
+					       ccm + CCM_CCGR6,
+					       vf610_ccm_ccgrx_cgn(2));
+}
+
+static void vf610_ccm_setup_misc(struct device_node *np,
+				 void __iomem *anatop,
+				 void __iomem *ccm)
+{
+	clk[VF610_CLK_ASRC] = imx_clk_gate2("asrc", "ipg_bus",
+					    ccm + CCM_CCGR4,
+					    vf610_ccm_ccgrx_cgn(1));
+	clk[VF610_CLK_SNVS] = imx_clk_gate2("snvs-rtc", "ipg_bus",
+					    ccm + CCM_CCGR6,
+					    vf610_ccm_ccgrx_cgn(7));
+	clk[VF610_CLK_DAP] = imx_clk_gate("dap", "platform_bus",
+					  ccm + CCM_CCSR, 24);
+	clk[VF610_CLK_OCOTP] = imx_clk_gate("ocotp", "ipg_bus",
+					    ccm + CCM_CCGR6,
+					    vf610_ccm_ccgrx_cgn(5));
+
+	clk[VF610_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in",
+							 "anaclk1",
+							 anatop + ANA_MISC1,
+							 12, BIT(10));
+}
+
+typedef void (*vf610_ccm_group_setup_func) (struct device_node *np,
+					    void __iomem *anatop,
+					    void __iomem *ccm);
+
+static void __init vf610_clocks_init(struct device_node *np)
+{
+	size_t i;
+	struct device_node *node;
+	void __iomem *anatop;
+	void __iomem *ccm;
+
+	static const vf610_ccm_group_setup_func group_setup_funcs[] = {
+		vf610_ccm_setup_fixed,
+		vf610_ccm_setup_from_dt,
+		vf610_ccm_setup_slow_clk,
+		vf610_ccm_setup_fast_clk,
+		vf610_ccm_setup_pll_bypass_srcs,
+		vf610_ccm_setup_plls,
+		vf610_ccm_setup_pll_bypass,
+		vf610_ccm_setup_group1,
+		vf610_ccm_setup_pfds,
+		vf610_ccm_setup_pll1_pfd_out,
+		vf610_ccm_setup_pll2_pfd_out,
+		vf610_ccm_setup_sys_out,
+		vf610_ccm_setup_ddr_out,
+		vf610_ccm_setup_dividers,
+		vf610_ccm_setup_pll4_main_div,
+		vf610_ccm_setup_ddrmc,
+		vf610_ccm_setup_wkpu,
+		vf610_ccm_setup_usbphys,
+		vf610_ccm_setup_usbcs,
+		vf610_ccm_setup_qspis,
+		vf610_ccm_setup_enets,
+		vf610_ccm_setup_pit,
+		vf610_ccm_setup_uarts,
+		vf610_ccm_setup_i2cs,
+		vf610_ccm_setup_dspis,
+		vf610_ccm_setup_wdt,
+		vf610_ccm_setup_esdhcs,
+		vf610_ccm_setup_ftms,
+		vf610_ccm_setup_dcus,
+		vf610_ccm_setup_tcons,
+		vf610_ccm_setup_esai,
+		vf610_ccm_setup_sais,
+		vf610_ccm_setup_nfc,
+		vf610_ccm_setup_gpu,
+		vf610_ccm_setup_vadc,
+		vf610_ccm_setup_adcs,
+		vf610_ccm_setup_flexcans,
+		vf610_ccm_setup_dmas,
+		vf610_ccm_setup_misc,
+	};
+
+	ccm = of_iomap(np, 0);
+	BUG_ON(!ccm);
+
+	node = of_find_compatible_node(NULL, NULL, "fsl,vf610-anatop");
+	anatop = of_iomap(node, 0);
+	/* anatop = syscon_base_lookup_by_phandle(np, "fsl,anatop"); */
+	BUG_ON(IS_ERR(anatop));
+
+	for (i = 0; i < ARRAY_SIZE(group_setup_funcs); i++)
+		group_setup_funcs[i](np, anatop, ccm);
+
+	imx_check_clocks(clk, VF610_CLK_END);
+
+	/* Do not bypass PLLs initially */
+
+	clk_set_parent(clk[VF610_PLL1_BYPASS], clk[VF610_CLK_PLL1]);
+	clk_set_parent(clk[VF610_PLL2_BYPASS], clk[VF610_CLK_PLL2]);
+	clk_set_parent(clk[VF610_PLL3_BYPASS], clk[VF610_CLK_PLL3]);
+	clk_set_parent(clk[VF610_PLL4_BYPASS], clk[VF610_CLK_PLL4]);
+	clk_set_parent(clk[VF610_PLL5_BYPASS], clk[VF610_CLK_PLL5]);
+	clk_set_parent(clk[VF610_PLL6_BYPASS], clk[VF610_CLK_PLL6]);
+	clk_set_parent(clk[VF610_PLL7_BYPASS], clk[VF610_CLK_PLL7]);
+
+	clk_set_parent(clk[VF610_CLK_QSPI0_SEL], clk[VF610_CLK_PLL1_PFD4]);
+	clk_set_rate(clk[VF610_CLK_QSPI0_X4_DIV],
+		     clk_get_rate(clk[VF610_CLK_QSPI0_SEL]) / 2);
+	clk_set_rate(clk[VF610_CLK_QSPI0_X2_DIV],
+		     clk_get_rate(clk[VF610_CLK_QSPI0_X4_DIV]) / 2);
+	clk_set_rate(clk[VF610_CLK_QSPI0_X1_DIV],
+		     clk_get_rate(clk[VF610_CLK_QSPI0_X2_DIV]) / 2);
+
+	clk_set_parent(clk[VF610_CLK_QSPI1_SEL], clk[VF610_CLK_PLL1_PFD4]);
+	clk_set_rate(clk[VF610_CLK_QSPI1_X4_DIV],
+		     clk_get_rate(clk[VF610_CLK_QSPI1_SEL]) / 2);
+	clk_set_rate(clk[VF610_CLK_QSPI1_X2_DIV],
+		     clk_get_rate(clk[VF610_CLK_QSPI1_X4_DIV]) / 2);
+	clk_set_rate(clk[VF610_CLK_QSPI1_X1_DIV],
+		     clk_get_rate(clk[VF610_CLK_QSPI1_X2_DIV]) / 2);
+
+	clk_set_parent(clk[VF610_CLK_SAI0_SEL], clk[VF610_CLK_AUDIO_EXT]);
+	clk_set_parent(clk[VF610_CLK_SAI1_SEL], clk[VF610_CLK_AUDIO_EXT]);
+	clk_set_parent(clk[VF610_CLK_SAI2_SEL], clk[VF610_CLK_AUDIO_EXT]);
+	clk_set_parent(clk[VF610_CLK_SAI3_SEL], clk[VF610_CLK_AUDIO_EXT]);
+
+	clk_enable(clk[VF610_CLK_SYS_BUS]);
+	clk_enable(clk[VF610_CLK_DDR_SEL]);
+	clk_enable(clk[VF610_CLK_DAP]);
+	clk_enable(clk[VF610_CLK_DDRMC]);
+	clk_enable(clk[VF610_CLK_WKPU]);
+
+	clk_data.clks = clk;
+	clk_data.clk_num = ARRAY_SIZE(clk);
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+CLK_OF_DECLARE(vf610, "fsl,vf610-ccm", vf610_clocks_init);
-- 
2.5.5




More information about the barebox mailing list