diff options
151 files changed, 8310 insertions, 14193 deletions
diff --git a/Documentation/devicetree/bindings/arm/spear-timer.txt b/Documentation/devicetree/bindings/arm/spear-timer.txt new file mode 100644 index 000000000000..c0017221cf55 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/spear-timer.txt @@ -0,0 +1,18 @@ +* SPEAr ARM Timer + +** Timer node required properties: + +- compatible : Should be: + "st,spear-timer" +- reg: Address range of the timer registers +- interrupt-parent: Should be the phandle for the interrupt controller + that services interrupts for this device +- interrupt: Should contain the timer interrupt number + +Example: + + timer@f0000000 { + compatible = "st,spear-timer"; + reg = <0xf0000000 0x400>; + interrupts = <2>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 150a29f3cd33..64ec55559d73 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1905,6 +1905,16 @@ F: Documentation/filesystems/coda.txt F: fs/coda/ F: include/linux/coda*.h +COMMON CLK FRAMEWORK +M: Mike Turquette <mturquette@ti.com> +M: Mike Turquette <mturquette@linaro.org> +L: linux-arm-kernel@lists.infradead.org (same as CLK API & CLKDEV) +T: git git://git.linaro.org/people/mturquette/linux.git +S: Maintained +F: drivers/clk/clk.c +F: drivers/clk/clk-* +F: include/linux/clk-pr* + COMMON INTERNET FILE SYSTEM (CIFS) M: Steve French <sfrench@samba.org> L: linux-cifs@vger.kernel.org @@ -6368,9 +6378,7 @@ L: spear-devel@list.st.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) W: http://www.st.com/spear S: Maintained -F: arch/arm/mach-spear*/clock.c -F: arch/arm/plat-spear/clock.c -F: arch/arm/plat-spear/include/plat/clock.h +F: drivers/clk/spear/ SPI SUBSYSTEM M: Grant Likely <grant.likely@secretlab.ca> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4c3e10cc9511..515c8c85cbbb 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -456,6 +456,7 @@ config ARCH_MXS select ARCH_REQUIRE_GPIOLIB select CLKDEV_LOOKUP select CLKSRC_MMIO + select COMMON_CLK select HAVE_CLK_PREPARE select PINCTRL help @@ -947,6 +948,7 @@ config PLAT_SPEAR select ARM_AMBA select ARCH_REQUIRE_GPIOLIB select CLKDEV_LOOKUP + select COMMON_CLK select CLKSRC_MMIO select GENERIC_CLOCKEVENTS select HAVE_CLK @@ -1101,6 +1103,7 @@ config PLAT_ORION bool select CLKSRC_MMIO select GENERIC_IRQ_CHIP + select COMMON_CLK config PLAT_PXA bool diff --git a/arch/arm/boot/dts/spear300-evb.dts b/arch/arm/boot/dts/spear300-evb.dts index 910e264b87c0..fc82b1a26458 100644 --- a/arch/arm/boot/dts/spear300-evb.dts +++ b/arch/arm/boot/dts/spear300-evb.dts @@ -87,6 +87,31 @@ smi: flash@fc000000 { status = "okay"; + clock-rate=<50000000>; + + flash@f8000000 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xf8000000 0x800000>; + st,smi-fast-mode; + + partition@0 { + label = "xloader"; + reg = <0x0 0x10000>; + }; + partition@10000 { + label = "u-boot"; + reg = <0x10000 0x40000>; + }; + partition@50000 { + label = "linux"; + reg = <0x50000 0x2c0000>; + }; + partition@310000 { + label = "rootfs"; + reg = <0x310000 0x4f0000>; + }; + }; }; spi0: spi@d0100000 { diff --git a/arch/arm/boot/dts/spear310-evb.dts b/arch/arm/boot/dts/spear310-evb.dts index 6d95317100ad..dc5e2d445a93 100644 --- a/arch/arm/boot/dts/spear310-evb.dts +++ b/arch/arm/boot/dts/spear310-evb.dts @@ -103,11 +103,27 @@ clock-rate=<50000000>; flash@f8000000 { - label = "m25p64"; - reg = <0xf8000000 0x800000>; #address-cells = <1>; #size-cells = <1>; + reg = <0xf8000000 0x800000>; st,smi-fast-mode; + + partition@0 { + label = "xloader"; + reg = <0x0 0x10000>; + }; + partition@10000 { + label = "u-boot"; + reg = <0x10000 0x40000>; + }; + partition@50000 { + label = "linux"; + reg = <0x50000 0x2c0000>; + }; + partition@310000 { + label = "rootfs"; + reg = <0x310000 0x4f0000>; + }; }; }; diff --git a/arch/arm/boot/dts/spear320-evb.dts b/arch/arm/boot/dts/spear320-evb.dts index 0c6463b71a37..6308fa3bec1e 100644 --- a/arch/arm/boot/dts/spear320-evb.dts +++ b/arch/arm/boot/dts/spear320-evb.dts @@ -110,6 +110,31 @@ smi: flash@fc000000 { status = "okay"; + clock-rate=<50000000>; + + flash@f8000000 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xf8000000 0x800000>; + st,smi-fast-mode; + + partition@0 { + label = "xloader"; + reg = <0x0 0x10000>; + }; + partition@10000 { + label = "u-boot"; + reg = <0x10000 0x40000>; + }; + partition@50000 { + label = "linux"; + reg = <0x50000 0x2c0000>; + }; + partition@310000 { + label = "rootfs"; + reg = <0x310000 0x4f0000>; + }; + }; }; spi0: spi@d0100000 { diff --git a/arch/arm/boot/dts/spear3xx.dtsi b/arch/arm/boot/dts/spear3xx.dtsi index 0ae7c8e86311..91072553963f 100644 --- a/arch/arm/boot/dts/spear3xx.dtsi +++ b/arch/arm/boot/dts/spear3xx.dtsi @@ -139,6 +139,12 @@ interrupts = <12>; status = "disabled"; }; + + timer@f0000000 { + compatible = "st,spear-timer"; + reg = <0xf0000000 0x400>; + interrupts = <2>; + }; }; }; }; diff --git a/arch/arm/boot/dts/spear600-evb.dts b/arch/arm/boot/dts/spear600-evb.dts index 790a7a8a5ccd..1119c22c9a82 100644 --- a/arch/arm/boot/dts/spear600-evb.dts +++ b/arch/arm/boot/dts/spear600-evb.dts @@ -33,6 +33,35 @@ status = "okay"; }; + smi: flash@fc000000 { + status = "okay"; + clock-rate=<50000000>; + + flash@f8000000 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xf8000000 0x800000>; + st,smi-fast-mode; + + partition@0 { + label = "xloader"; + reg = <0x0 0x10000>; + }; + partition@10000 { + label = "u-boot"; + reg = <0x10000 0x40000>; + }; + partition@50000 { + label = "linux"; + reg = <0x50000 0x2c0000>; + }; + partition@310000 { + label = "rootfs"; + reg = <0x310000 0x4f0000>; + }; + }; + }; + apb { serial@d0000000 { status = "okay"; diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi index d777e3a6f178..089f0a42c50e 100644 --- a/arch/arm/boot/dts/spear600.dtsi +++ b/arch/arm/boot/dts/spear600.dtsi @@ -177,6 +177,12 @@ interrupts = <28>; status = "disabled"; }; + + timer@f0000000 { + compatible = "st,spear-timer"; + reg = <0xf0000000 0x400>; + interrupts = <16>; + }; }; }; }; diff --git a/arch/arm/configs/spear3xx_defconfig b/arch/arm/configs/spear3xx_defconfig index 7ed42912d69a..865980c5f212 100644 --- a/arch/arm/configs/spear3xx_defconfig +++ b/arch/arm/configs/spear3xx_defconfig @@ -14,6 +14,9 @@ CONFIG_BINFMT_MISC=y CONFIG_NET=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y +CONFIG_MTD_OF_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSMC=y CONFIG_BLK_DEV_RAM=y @@ -73,6 +76,7 @@ CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m CONFIG_FAT_DEFAULT_IOCHARSET="ascii" CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=m diff --git a/arch/arm/configs/spear6xx_defconfig b/arch/arm/configs/spear6xx_defconfig index cf94bc73a0e0..a2a1265f86b6 100644 --- a/arch/arm/configs/spear6xx_defconfig +++ b/arch/arm/configs/spear6xx_defconfig @@ -8,11 +8,13 @@ CONFIG_MODVERSIONS=y CONFIG_PARTITION_ADVANCED=y CONFIG_PLAT_SPEAR=y CONFIG_ARCH_SPEAR6XX=y -CONFIG_BOARD_SPEAR600_DT=y CONFIG_BINFMT_MISC=y CONFIG_NET=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y +CONFIG_MTD_OF_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSMC=y CONFIG_BLK_DEV_RAM=y @@ -64,6 +66,7 @@ CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m CONFIG_FAT_DEFAULT_IOCHARSET="ascii" CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=m diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c index 42ab1e7c4ecc..9493076fc594 100644 --- a/arch/arm/mach-dove/common.c +++ b/arch/arm/mach-dove/common.c @@ -13,7 +13,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/pci.h> -#include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/ata_platform.h> #include <linux/gpio.h> #include <asm/page.h> @@ -68,6 +68,19 @@ void __init dove_map_io(void) } /***************************************************************************** + * CLK tree + ****************************************************************************/ +static struct clk *tclk; + +static void __init clk_init(void) +{ + tclk = clk_register_fixed_rate(NULL, "tclk", NULL, CLK_IS_ROOT, + get_tclk()); + + orion_clkdev_init(tclk); +} + +/***************************************************************************** * EHCI0 ****************************************************************************/ void __init dove_ehci0_init(void) @@ -89,8 +102,7 @@ void __init dove_ehci1_init(void) void __init dove_ge00_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge00_init(eth_data, - DOVE_GE00_PHYS_BASE, IRQ_DOVE_GE00_SUM, - 0, get_tclk()); + DOVE_GE00_PHYS_BASE, IRQ_DOVE_GE00_SUM, 0); } /***************************************************************************** @@ -116,7 +128,7 @@ void __init dove_sata_init(struct mv_sata_platform_data *sata_data) void __init dove_uart0_init(void) { orion_uart0_init(DOVE_UART0_VIRT_BASE, DOVE_UART0_PHYS_BASE, - IRQ_DOVE_UART_0, get_tclk()); + IRQ_DOVE_UART_0, tclk); } /***************************************************************************** @@ -125,7 +137,7 @@ void __init dove_uart0_init(void) void __init dove_uart1_init(void) { orion_uart1_init(DOVE_UART1_VIRT_BASE, DOVE_UART1_PHYS_BASE, - IRQ_DOVE_UART_1, get_tclk()); + IRQ_DOVE_UART_1, tclk); } /***************************************************************************** @@ -134,7 +146,7 @@ void __init dove_uart1_init(void) void __init dove_uart2_init(void) { orion_uart2_init(DOVE_UART2_VIRT_BASE, DOVE_UART2_PHYS_BASE, - IRQ_DOVE_UART_2, get_tclk()); + IRQ_DOVE_UART_2, tclk); } /***************************************************************************** @@ -143,7 +155,7 @@ void __init dove_uart2_init(void) void __init dove_uart3_init(void) { orion_uart3_init(DOVE_UART3_VIRT_BASE, DOVE_UART3_PHYS_BASE, - IRQ_DOVE_UART_3, get_tclk()); + IRQ_DOVE_UART_3, tclk); } /***************************************************************************** @@ -151,12 +163,12 @@ void __init dove_uart3_init(void) ****************************************************************************/ void __init dove_spi0_init(void) { - orion_spi_init(DOVE_SPI0_PHYS_BASE, get_tclk()); + orion_spi_init(DOVE_SPI0_PHYS_BASE); } void __init dove_spi1_init(void) { - orion_spi_1_init(DOVE_SPI1_PHYS_BASE, get_tclk()); + orion_spi_1_init(DOVE_SPI1_PHYS_BASE); } /***************************************************************************** @@ -272,18 +284,17 @@ void __init dove_sdio1_init(void) void __init dove_init(void) { - int tclk; - - tclk = get_tclk(); - printk(KERN_INFO "Dove 88AP510 SoC, "); - printk(KERN_INFO "TCLK = %dMHz\n", (tclk + 499999) / 1000000); + printk(KERN_INFO "TCLK = %dMHz\n", (get_tclk() + 499999) / 1000000); #ifdef CONFIG_CACHE_TAUROS2 tauros2_init(); #endif dove_setup_cpu_mbus(); + /* Setup root of clk tree */ + clk_init(); + /* internal devices that every board has */ dove_rtc_init(); dove_xor0_init(); diff --git a/arch/arm/mach-dove/dove-db-setup.c b/arch/arm/mach-dove/dove-db-setup.c index ea77ae430b2d..bc2867f11346 100644 --- a/arch/arm/mach-dove/dove-db-setup.c +++ b/arch/arm/mach-dove/dove-db-setup.c @@ -20,7 +20,6 @@ #include <linux/i2c.h> #include <linux/pci.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <linux/spi/flash.h> #include <linux/gpio.h> #include <asm/mach-types.h> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index cca8c0c74794..0021f726b153 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -34,6 +34,7 @@ config ARCH_MX53 config SOC_IMX1 bool select ARCH_MX1 + select COMMON_CLK select CPU_ARM920T select IMX_HAVE_IOMUX_V1 select MXC_AVIC @@ -42,12 +43,14 @@ config SOC_IMX21 bool select MACH_MX21 select CPU_ARM926T + select COMMON_CLK select IMX_HAVE_IOMUX_V1 select MXC_AVIC config SOC_IMX25 bool select ARCH_MX25 + select COMMON_CLK select CPU_ARM926T select ARCH_MXC_IOMUX_V3 select MXC_AVIC @@ -56,6 +59,7 @@ config SOC_IMX27 bool select MACH_MX27 select CPU_ARM926T + select COMMON_CLK select IMX_HAVE_IOMUX_V1 select MXC_AVIC @@ -64,12 +68,14 @@ config SOC_IMX31 select CPU_V6 select IMX_HAVE_PLATFORM_MXC_RNGA select MXC_AVIC + select COMMON_CLK select SMP_ON_UP if SMP config SOC_IMX35 bool select CPU_V6 select ARCH_MXC_IOMUX_V3 + select COMMON_CLK select HAVE_EPIT select MXC_AVIC select SMP_ON_UP if SMP @@ -77,6 +83,7 @@ config SOC_IMX35 config SOC_IMX5 select CPU_V7 select MXC_TZIC + select COMMON_CLK select ARCH_MXC_IOMUX_V3 select ARCH_HAS_CPUFREQ select ARCH_MX5 @@ -815,6 +822,7 @@ config SOC_IMX6Q bool "i.MX6 Quad support" select ARM_CPU_SUSPEND if PM select ARM_GIC + select COMMON_CLK select CPU_V7 select HAVE_ARM_SCU select HAVE_IMX_GPC diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 4937c070a57e..ff29421414f2 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -1,15 +1,18 @@ -obj-$(CONFIG_SOC_IMX1) += clock-imx1.o mm-imx1.o -obj-$(CONFIG_SOC_IMX21) += clock-imx21.o mm-imx21.o +obj-$(CONFIG_SOC_IMX1) += clk-imx1.o mm-imx1.o +obj-$(CONFIG_SOC_IMX21) += clk-imx21.o mm-imx21.o -obj-$(CONFIG_SOC_IMX25) += clock-imx25.o mm-imx25.o ehci-imx25.o cpu-imx25.o +obj-$(CONFIG_SOC_IMX25) += clk-imx25.o mm-imx25.o ehci-imx25.o cpu-imx25.o obj-$(CONFIG_SOC_IMX27) += cpu-imx27.o pm-imx27.o -obj-$(CONFIG_SOC_IMX27) += clock-imx27.o mm-imx27.o ehci-imx27.o +obj-$(CONFIG_SOC_IMX27) += clk-imx27.o mm-imx27.o ehci-imx27.o -obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o pm-imx3.o -obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clock-imx35.o ehci-imx35.o pm-imx3.o +obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clk-imx31.o iomux-imx31.o ehci-imx31.o pm-imx3.o +obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o -obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clock-mx51-mx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o +obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clk-imx51-imx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o + +obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ + clk-pfd.o clk-busy.o # Support for CMOS sensor interface obj-$(CONFIG_MX1_VIDEO) += mx1-camera-fiq.o mx1-camera-fiq-ksym.o @@ -70,7 +73,7 @@ obj-$(CONFIG_CPU_V7) += head-v7.o AFLAGS_head-v7.o :=-Wa,-march=armv7-a obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o +obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o ifeq ($(CONFIG_PM),y) obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o diff --git a/arch/arm/mach-imx/clk-busy.c b/arch/arm/mach-imx/clk-busy.c new file mode 100644 index 000000000000..1a7a8dd045a1 --- /dev/null +++ b/arch/arm/mach-imx/clk-busy.c @@ -0,0 +1,189 @@ +/* + * 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 <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/err.h> +#include "clk.h" + +static int clk_busy_wait(void __iomem *reg, u8 shift) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(10); + + while (readl_relaxed(reg) & (1 << shift)) + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + + return 0; +} + +struct clk_busy_divider { + struct clk_divider div; + const struct clk_ops *div_ops; + void __iomem *reg; + u8 shift; +}; + +static inline struct clk_busy_divider *to_clk_busy_divider(struct clk_hw *hw) +{ + struct clk_divider *div = container_of(hw, struct clk_divider, hw); + + return container_of(div, struct clk_busy_divider, div); +} + +static unsigned long clk_busy_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_busy_divider *busy = to_clk_busy_divider(hw); + + return busy->div_ops->recalc_rate(&busy->div.hw, parent_rate); +} + +static long clk_busy_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_busy_divider *busy = to_clk_busy_divider(hw); + + return busy->div_ops->round_rate(&busy->div.hw, rate, prate); +} + +static int clk_busy_divider_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_busy_divider *busy = to_clk_busy_divider(hw); + int ret; + + ret = busy->div_ops->set_rate(&busy->div.hw, rate, parent_rate); + if (!ret) + ret = clk_busy_wait(busy->reg, busy->shift); + + return ret; +} + +static struct clk_ops clk_busy_divider_ops = { + .recalc_rate = clk_busy_divider_recalc_rate, + .round_rate = clk_busy_divider_round_rate, + .set_rate = clk_busy_divider_set_rate, +}; + +struct clk *imx_clk_busy_divider(const char *name, const char *parent_name, + void __iomem *reg, u8 shift, u8 width, + void __iomem *busy_reg, u8 busy_shift) +{ + struct clk_busy_divider *busy; + struct clk *clk; + struct clk_init_data init; + + busy = kzalloc(sizeof(*busy), GFP_KERNEL); + if (!busy) + return ERR_PTR(-ENOMEM); + + busy->reg = busy_reg; + busy->shift = busy_shift; + + busy->div.reg = reg; + busy->div.shift = shift; + busy->div.width = width; + busy->div.lock = &imx_ccm_lock; + busy->div_ops = &clk_divider_ops; + + init.name = name; + init.ops = &clk_busy_divider_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = &parent_name; + init.num_parents = 1; + + busy->div.hw.init = &init; + + clk = clk_register(NULL, &busy->div.hw); + if (!clk) + kfree(busy); + + return clk; +} + +struct clk_busy_mux { + struct clk_mux mux; + const struct clk_ops *mux_ops; + void __iomem *reg; + u8 shift; +}; + +static inline struct clk_busy_mux *to_clk_busy_mux(struct clk_hw *hw) +{ + struct clk_mux *mux = container_of(hw, struct clk_mux, hw); + + return container_of(mux, struct clk_busy_mux, mux); +} + +static u8 clk_busy_mux_get_parent(struct clk_hw *hw) +{ + struct clk_busy_mux *busy = to_clk_busy_mux(hw); + + return busy->mux_ops->get_parent(&busy->mux.hw); +} + +static int clk_busy_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_busy_mux *busy = to_clk_busy_mux(hw); + int ret; + + ret = busy->mux_ops->set_parent(&busy->mux.hw, index); + if (!ret) + ret = clk_busy_wait(busy->reg, busy->shift); + + return ret; +} + +struct clk_ops clk_busy_mux_ops = { + .get_parent = clk_busy_mux_get_parent, + .set_parent = clk_busy_mux_set_parent, +}; + +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 **parent_names, int num_parents) +{ + struct clk_busy_mux *busy; + struct clk *clk; + struct clk_init_data init; + + busy = kzalloc(sizeof(*busy), GFP_KERNEL); + if (!busy) + return ERR_PTR(-ENOMEM); + + busy->reg = busy_reg; + busy->shift = busy_shift; + + busy->mux.reg = reg; + busy->mux.shift = shift; + busy->mux.width = width; + busy->mux.lock = &imx_ccm_lock; + busy->mux_ops = &clk_mux_ops; + + init.name = name; + init.ops = &clk_busy_mux_ops; + init.flags = 0; + init.parent_names = parent_names; + init.num_parents = num_parents; + + busy->mux.hw.init = &init; + + clk = clk_register(NULL, &busy->mux.hw); + if (IS_ERR(clk)) + kfree(busy); + + return clk; +} diff --git a/arch/arm/mach-imx/clk-gate2.c b/arch/arm/mach-imx/clk-gate2.c new file mode 100644 index 000000000000..3c1b8ff9a0a6 --- /dev/null +++ b/arch/arm/mach-imx/clk-gate2.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com> + * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> + * + * 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. + * + * Gated clock implementation + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/string.h> + +/** + * DOC: basic gatable clock which can gate and ungate it's ouput + * + * Traits of this clock: + * prepare - clk_(un)prepare only ensures parent is (un)prepared + * enable - clk_enable and clk_disable are functional & control gating + * rate - inherits rate from parent. No clk_set_rate support + * parent - fixed parent. No clk_set_parent support + */ + +#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) + +static int clk_gate2_enable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + u32 reg; + unsigned long flags = 0; + + if (gate->lock) + spin_lock_irqsave(gate->lock, flags); + + reg = readl(gate->reg); + reg |= 3 << gate->bit_idx; + writel(reg, gate->reg); + + if (gate->lock) + spin_unlock_irqrestore(gate->lock, flags); + + return 0; +} + +static void clk_gate2_disable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + u32 reg; + unsigned long flags = 0; + + if (gate->lock) + spin_lock_irqsave(gate->lock, flags); + + reg = readl(gate->reg); + reg &= ~(3 << gate->bit_idx); + writel(reg, gate->reg); + + if (gate->lock) + spin_unlock_irqrestore(gate->lock, flags); +} + +static int clk_gate2_is_enabled(struct clk_hw *hw) +{ + u32 reg; + struct clk_gate *gate = to_clk_gate(hw); + + reg = readl(gate->reg); + + if (((reg >> gate->bit_idx) & 3) == 3) + return 1; + + return 0; +} + +static struct clk_ops clk_gate2_ops = { + .enable = clk_gate2_enable, + .disable = clk_gate2_disable, + .is_enabled = clk_gate2_is_enabled, +}; + +struct clk *clk_register_gate2(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate2_flags, spinlock_t *lock) +{ + struct clk_gate *gate; + struct clk *clk; + struct clk_init_data init; + + gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + /* struct clk_gate assignments */ + gate->reg = reg; + gate->bit_idx = bit_idx; + gate->flags = clk_gate2_flags; + gate->lock = lock; + + init.name = name; + init.ops = &clk_gate2_ops; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + gate->hw.init = &init; + + clk = clk_register(dev, &gate->hw); + if (IS_ERR(clk)) + kfree(clk); + + return clk; +} diff --git a/arch/arm/mach-imx/clk-imx1.c b/arch/arm/mach-imx/clk-imx1.c new file mode 100644 index 000000000000..0f0beb580b73 --- /dev/null +++ b/arch/arm/mach-imx/clk-imx1.c @@ -0,0 +1,115 @@ +/* + * 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 <linux/kernel.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include "clk.h" + +/* CCM register addresses */ +#define IO_ADDR_CCM(off) (MX1_IO_ADDRESS(MX1_CCM_BASE_ADDR + (off))) + +#define CCM_CSCR IO_ADDR_CCM(0x0) +#define CCM_MPCTL0 IO_ADDR_CCM(0x4) +#define CCM_SPCTL0 IO_ADDR_CCM(0xc) +#define CCM_PCDR IO_ADDR_CCM(0x20) + +/* SCM register addresses */ +#define IO_ADDR_SCM(off) (MX1_IO_ADDRESS(MX1_SCM_BASE_ADDR + (off))) + +#define SCM_GCCR IO_ADDR_SCM(0xc) + +static const char *prem_sel_clks[] = { "clk32_premult", "clk16m", }; +static const char *clko_sel_clks[] = { "per1", "hclk", "clk48m", "clk16m", "prem", + "fclk", }; +enum imx1_clks { + dummy, clk32, clk16m_ext, 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 *clk[clk_max]; + +int __init mx1_clocks_init(unsigned long fref) +{ + int i; + + clk[dummy] = imx_clk_fixed("dummy", 0); + clk[clk32] = imx_clk_fixed("clk32", fref); + clk[clk16m_ext] = imx_clk_fixed("clk16m_ext", 16000000); + clk[clk16m] = imx_clk_gate("clk16m", "clk16m_ext", CCM_CSCR, 17); + clk[clk32_premult] = imx_clk_fixed_factor("clk32_premult", "clk32", 512, 1); + clk[prem] = imx_clk_mux("prem", CCM_CSCR, 16, 1, prem_sel_clks, + ARRAY_SIZE(prem_sel_clks)); + clk[mpll] = imx_clk_pllv1("mpll", "clk32_premult", CCM_MPCTL0); + clk[spll] = imx_clk_pllv1("spll", "prem", CCM_SPCTL0); + clk[mcu] = imx_clk_divider("mcu", "clk32_premult", CCM_CSCR, 15, 1); + clk[fclk] = imx_clk_divider("fclk", "mpll", CCM_CSCR, 15, 1); + clk[hclk] = imx_clk_divider("hclk", "spll", CCM_CSCR, 10, 4); + clk[clk48m] = imx_clk_divider("clk48m", "spll", CCM_CSCR, 26, 3); + clk[per1] = imx_clk_divider("per1", "spll", CCM_PCDR, 0, 4); + clk[per2] = imx_clk_divider("per2", "spll", CCM_PCDR, 4, 4); + clk[per3] = imx_clk_divider("per3", "spll", CCM_PCDR, 16, 7); + clk[clko] = imx_clk_mux("clko", CCM_CSCR, 29, 3, clko_sel_clks, + ARRAY_SIZE(clko_sel_clks)); + clk[dma_gate] = imx_clk_gate("dma_gate", "hclk", SCM_GCCR, 4); + clk[csi_gate] = imx_clk_gate("csi_gate", "hclk", SCM_GCCR, 2); + clk[mma_gate] = imx_clk_gate("mma_gate", "hclk", SCM_GCCR, 1); + clk[usbd_gate] = imx_clk_gate("usbd_gate", "clk48m", SCM_GCCR, 0); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("imx1 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + clk_register_clkdev(clk[dma_gate], "ahb", "imx-dma"); + clk_register_clkdev(clk[csi_gate], NULL, "mx1-camera.0"); + clk_register_clkdev(clk[mma_gate], "mma", NULL); + clk_register_clkdev(clk[usbd_gate], NULL, "imx_udc.0"); + clk_register_clkdev(clk[per1], "per", "imx-gpt.0"); + clk_register_clkdev(clk[hclk], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[per1], "per", "imx1-uart.0"); + clk_register_clkdev(clk[hclk], "ipg", "imx1-uart.0"); + clk_register_clkdev(clk[per1], "per", "imx1-uart.1"); + clk_register_clkdev(clk[hclk], "ipg", "imx1-uart.1"); + clk_register_clkdev(clk[per1], "per", "imx1-uart.2"); + clk_register_clkdev(clk[hclk], "ipg", "imx1-uart.2"); + clk_register_clkdev(clk[hclk], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[per2], "per", "imx1-cspi.0"); + clk_register_clkdev(clk[dummy], "ipg", "imx1-cspi.0"); + clk_register_clkdev(clk[per2], "per", "imx1-cspi.1"); + clk_register_clkdev(clk[dummy], "ipg", "imx1-cspi.1"); + clk_register_clkdev(clk[per2], NULL, "imx-mmc.0"); + clk_register_clkdev(clk[per2], "per", "imx-fb.0"); + clk_register_clkdev(clk[dummy], "ipg", "imx-fb.0"); + clk_register_clkdev(clk[dummy], "ahb", "imx-fb.0"); + clk_register_clkdev(clk[hclk], "mshc", NULL); + clk_register_clkdev(clk[per3], "ssi", NULL); + clk_register_clkdev(clk[clk32], NULL, "mxc_rtc.0"); + clk_register_clkdev(clk[clko], "clko", NULL); + + mxc_timer_init(NULL, MX1_IO_ADDRESS(MX1_TIM1_BASE_ADDR), + MX1_TIM1_INT); + + return 0; +} diff --git a/arch/arm/mach-imx/clk-imx21.c b/arch/arm/mach-imx/clk-imx21.c new file mode 100644 index 000000000000..4e4f384ee8dd --- /dev/null +++ b/arch/arm/mach-imx/clk-imx21.c @@ -0,0 +1,186 @@ +/* + * 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 <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/clkdev.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include "clk.h" + +#define IO_ADDR_CCM(off) (MX21_IO_ADDRESS(MX21_CCM_BASE_ADDR + (off))) + +/* Register offsets */ +#define CCM_CSCR IO_ADDR_CCM(0x0) +#define CCM_MPCTL0 IO_ADDR_CCM(0x4) +#define CCM_MPCTL1 IO_ADDR_CCM(0x8) +#define CCM_SPCTL0 IO_ADDR_CCM(0xc) +#define CCM_SPCTL1 IO_ADDR_CCM(0x10) +#define CCM_OSC26MCTL IO_ADDR_CCM(0x14) +#define CCM_PCDR0 IO_ADDR_CCM(0x18) +#define CCM_PCDR1 IO_ADDR_CCM(0x1c) +#define CCM_PCCR0 IO_ADDR_CCM(0x20) +#define CCM_PCCR1 IO_ADDR_CCM(0x24) +#define CCM_CCSR IO_ADDR_CCM(0x28) +#define CCM_PMCTL IO_ADDR_CCM(0x2c) +#define CCM_PMCOUNT IO_ADDR_CCM(0x30) +#define CCM_WKGDCTL IO_ADDR_CCM(0x34) + +static const char *mpll_sel_clks[] = { "fpm", "ckih", }; +static const char *spll_sel_clks[] = { "fpm", "ckih", }; + +enum imx21_clks { + ckil, ckih, fpm, mpll_sel, spll_sel, mpll, spll, fclk, hclk, ipg, per1, + per2, per3, per4, uart1_ipg_gate, uart2_ipg_gate, uart3_ipg_gate, + uart4_ipg_gate, gpt1_ipg_gate, gpt2_ipg_gate, gpt3_ipg_gate, + pwm_ipg_gate, sdhc1_ipg_gate, sdhc2_ipg_gate, lcdc_ipg_gate, + lcdc_hclk_gate, cspi3_ipg_gate, cspi2_ipg_gate, cspi1_ipg_gate, + per4_gate, csi_hclk_gate, usb_div, usb_gate, usb_hclk_gate, ssi1_gate, + ssi2_gate, nfc_div, nfc_gate, dma_gate, dma_hclk_gate, brom_gate, + emma_gate, emma_hclk_gate, slcdc_gate, slcdc_hclk_gate, wdog_gate, + gpio_gate, i2c_gate, kpp_gate, owire_gate, rtc_gate, clk_max +}; + +static struct clk *clk[clk_max]; + +/* + * must be called very early to get information about the + * available clock rate when the timer framework starts + */ +int __init mx21_clocks_init(unsigned long lref, unsigned long href) +{ + int i; + + clk[ckil] = imx_clk_fixed("ckil", lref); + clk[ckih] = imx_clk_fixed("ckih", href); + clk[fpm] = imx_clk_fixed_factor("fpm", "ckil", 512, 1); + clk[mpll_sel] = imx_clk_mux("mpll_sel", CCM_CSCR, 16, 1, mpll_sel_clks, + ARRAY_SIZE(mpll_sel_clks)); + clk[spll_sel] = imx_clk_mux("spll_sel", CCM_CSCR, 17, 1, spll_sel_clks, + ARRAY_SIZE(spll_sel_clks)); + clk[mpll] = imx_clk_pllv1("mpll", "mpll_sel", CCM_MPCTL0); + clk[spll] = imx_clk_pllv1("spll", "spll_sel", CCM_SPCTL0); + clk[fclk] = imx_clk_divider("fclk", "mpll", CCM_CSCR, 29, 3); + clk[hclk] = imx_clk_divider("hclk", "fclk", CCM_CSCR, 10, 4); + clk[ipg] = imx_clk_divider("ipg", "hclk", CCM_CSCR, 9, 1); + clk[per1] = imx_clk_divider("per1", "mpll", CCM_PCDR1, 0, 6); + clk[per2] = imx_clk_divider("per2", "mpll", CCM_PCDR1, 8, 6); + clk[per3] = imx_clk_divider("per3", "mpll", CCM_PCDR1, 16, 6); + clk[per4] = imx_clk_divider("per4", "mpll", CCM_PCDR1, 24, 6); + clk[uart1_ipg_gate] = imx_clk_gate("uart1_ipg_gate", "ipg", CCM_PCCR0, 0); + clk[uart2_ipg_gate] = imx_clk_gate("uart2_ipg_gate", "ipg", CCM_PCCR0, 1); + clk[uart3_ipg_gate] = imx_clk_gate("uart3_ipg_gate", "ipg", CCM_PCCR0, 2); + clk[uart4_ipg_gate] = imx_clk_gate("uart4_ipg_gate", "ipg", CCM_PCCR0, 3); + clk[gpt1_ipg_gate] = imx_clk_gate("gpt1_ipg_gate", "ipg", CCM_PCCR1, 25); + clk[gpt2_ipg_gate] = imx_clk_gate("gpt2_ipg_gate", "ipg", CCM_PCCR1, 26); + clk[gpt3_ipg_gate] = imx_clk_gate("gpt3_ipg_gate", "ipg", CCM_PCCR1, 27); + clk[pwm_ipg_gate] = imx_clk_gate("pwm_ipg_gate", "ipg", CCM_PCCR1, 28); + clk[sdhc1_ipg_gate] = imx_clk_gate("sdhc1_ipg_gate", "ipg", CCM_PCCR0, 9); + clk[sdhc2_ipg_gate] = imx_clk_gate("sdhc2_ipg_gate", "ipg", CCM_PCCR0, 10); + clk[lcdc_ipg_gate] = imx_clk_gate("lcdc_ipg_gate", "ipg", CCM_PCCR0, 18); + clk[lcdc_hclk_gate] = imx_clk_gate("lcdc_hclk_gate", "hclk", CCM_PCCR0, 26); + clk[cspi3_ipg_gate] = imx_clk_gate("cspi3_ipg_gate", "ipg", CCM_PCCR1, 23); + clk[cspi2_ipg_gate] = imx_clk_gate("cspi2_ipg_gate", "ipg", CCM_PCCR0, 5); + clk[cspi1_ipg_gate] = imx_clk_gate("cspi1_ipg_gate", "ipg", CCM_PCCR0, 4); + clk[per4_gate] = imx_clk_gate("per4_gate", "per4", CCM_PCCR0, 22); + clk[csi_hclk_gate] = imx_clk_gate("csi_hclk_gate", "hclk", CCM_PCCR0, 31); + clk[usb_div] = imx_clk_divider("usb_div", "spll", CCM_CSCR, 26, 3); + clk[usb_gate] = imx_clk_gate("usb_gate", "usb_div", CCM_PCCR0, 14); + clk[usb_hclk_gate] = imx_clk_gate("usb_hclk_gate", "hclk", CCM_PCCR0, 24); + clk[ssi1_gate] = imx_clk_gate("ssi1_gate", "ipg", CCM_PCCR0, 6); + clk[ssi2_gate] = imx_clk_gate("ssi2_gate", "ipg", CCM_PCCR0, 7); + clk[nfc_div] = imx_clk_divider("nfc_div", "ipg", CCM_PCDR0, 12, 4); + clk[nfc_gate] = imx_clk_gate("nfc_gate", "nfc_div", CCM_PCCR0, 19); + clk[dma_gate] = imx_clk_gate("dma_gate", "ipg", CCM_PCCR0, 13); + clk[dma_hclk_gate] = imx_clk_gate("dma_hclk_gate", "hclk", CCM_PCCR0, 30); + clk[brom_gate] = imx_clk_gate("brom_gate", "hclk", CCM_PCCR0, 28); + clk[emma_gate] = imx_clk_gate("emma_gate", "ipg", CCM_PCCR0, 15); + clk[emma_hclk_gate] = imx_clk_gate("emma_hclk_gate", "hclk", CCM_PCCR0, 27); + clk[slcdc_gate] = imx_clk_gate("slcdc_gate", "ipg", CCM_PCCR0, 25); + clk[slcdc_hclk_gate] = imx_clk_gate("slcdc_hclk_gate", "hclk", CCM_PCCR0, 21); + clk[wdog_gate] = imx_clk_gate("wdog_gate", "ipg", CCM_PCCR1, 24); + clk[gpio_gate] = imx_clk_gate("gpio_gate", "ipg", CCM_PCCR0, 11); + clk[i2c_gate] = imx_clk_gate("i2c_gate", "ipg", CCM_PCCR0, 12); + clk[kpp_gate] = imx_clk_gate("kpp_gate", "ipg", CCM_PCCR1, 30); + clk[owire_gate] = imx_clk_gate("owire_gate", "ipg", CCM_PCCR1, 31); + clk[rtc_gate] = imx_clk_gate("rtc_gate", "ipg", CCM_PCCR1, 29); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX21 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + clk_register_clkdev(clk[per1], "per1", NULL); + clk_register_clkdev(clk[per2], "per2", NULL); + clk_register_clkdev(clk[per3], "per3", NULL); + clk_register_clkdev(clk[per4], "per4", NULL); + clk_register_clkdev(clk[per1], "per", "imx21-uart.0"); + clk_register_clkdev(clk[uart1_ipg_gate], "ipg", "imx21-uart.0"); + clk_register_clkdev(clk[per1], "per", "imx21-uart.1"); + clk_register_clkdev(clk[uart2_ipg_gate], "ipg", "imx21-uart.1"); + clk_register_clkdev(clk[per1], "per", "imx21-uart.2"); + clk_register_clkdev(clk[uart3_ipg_gate], "ipg", "imx21-uart.2"); + clk_register_clkdev(clk[per1], "per", "imx21-uart.3"); + clk_register_clkdev(clk[uart4_ipg_gate], "ipg", "imx21-uart.3"); + clk_register_clkdev(clk[gpt1_ipg_gate], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[per1], "per", "imx-gpt.0"); + clk_register_clkdev(clk[gpt2_ipg_gate], "ipg", "imx-gpt.1"); + clk_register_clkdev(clk[per1], "per", "imx-gpt.1"); + clk_register_clkdev(clk[gpt3_ipg_gate], "ipg", "imx-gpt.2"); + clk_register_clkdev(clk[per1], "per", "imx-gpt.2"); + clk_register_clkdev(clk[pwm_ipg_gate], "pwm", "mxc_pwm.0"); + clk_register_clkdev(clk[per2], "per", "imx21-cspi.0"); + clk_register_clkdev(clk[cspi1_ipg_gate], "ipg", "imx21-cspi.0"); + clk_register_clkdev(clk[per2], "per", "imx21-cspi.1"); + clk_register_clkdev(clk[cspi2_ipg_gate], "ipg", "imx21-cspi.1"); + clk_register_clkdev(clk[per2], "per", "imx21-cspi.2"); + clk_register_clkdev(clk[cspi3_ipg_gate], "ipg", "imx21-cspi.2"); + clk_register_clkdev(clk[per3], "per", "imx-fb.0"); + clk_register_clkdev(clk[lcdc_ipg_gate], "ipg", "imx-fb.0"); + clk_register_clkdev(clk[lcdc_hclk_gate], "ahb", "imx-fb.0"); + clk_register_clkdev(clk[usb_gate], "per", "imx21-hcd.0"); + clk_register_clkdev(clk[usb_hclk_gate], "ahb", "imx21-hcd.0"); + clk_register_clkdev(clk[nfc_gate], NULL, "mxc_nand.0"); + clk_register_clkdev(clk[dma_hclk_gate], "ahb", "imx-dma"); + clk_register_clkdev(clk[dma_gate], "ipg", "imx-dma"); + clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); + clk_register_clkdev(clk[i2c_gate], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[kpp_gate], NULL, "mxc-keypad"); + clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1.0"); + clk_register_clkdev(clk[brom_gate], "brom", NULL); + clk_register_clkdev(clk[emma_gate], "emma", NULL); + clk_register_clkdev(clk[slcdc_gate], "slcdc", NULL); + clk_register_clkdev(clk[gpio_gate], "gpio", NULL); + clk_register_clkdev(clk[rtc_gate], "rtc", NULL); + clk_register_clkdev(clk[csi_hclk_gate], "csi", NULL); + clk_register_clkdev(clk[ssi1_gate], "ssi1", NULL); + clk_register_clkdev(clk[ssi2_gate], "ssi2", NULL); + clk_register_clkdev(clk[sdhc1_ipg_gate], "sdhc1", NULL); + clk_register_clkdev(clk[sdhc2_ipg_gate], "sdhc2", NULL); + + mxc_timer_init(NULL, MX21_IO_ADDRESS(MX21_GPT1_BASE_ADDR), + MX21_INT_GPT1); + return 0; +} diff --git a/arch/arm/mach-imx/clk-imx25.c b/arch/arm/mach-imx/clk-imx25.c new file mode 100644 index 000000000000..d9833bb5fd61 --- /dev/null +++ b/arch/arm/mach-imx/clk-imx25.c @@ -0,0 +1,248 @@ +/* + * 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 <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/mx25.h> +#include "clk.h" + +#define CRM_BASE MX25_IO_ADDRESS(MX25_CRM_BASE_ADDR) + +#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 + +#define ccm(x) (CRM_BASE + (x)) + +static const char *cpu_sel_clks[] = { "mpll", "mpll_cpu_3_4", }; +static const char *per_sel_clks[] = { "ahb", "upll", }; + +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, esdhc1_ipg_per, esdhc2_ipg_per, gpt_ipg_per, i2c_ipg_per, + lcdc_ipg_per, nfc_ipg_per, ssi1_ipg_per, ssi2_ipg_per, uart_ipg_per, + csi_ahb, esdhc1_ahb, esdhc2_ahb, fec_ahb, lcdc_ahb, sdma_ahb, + usbotg_ahb, can1_ipg, can2_ipg, csi_ipg, cspi1_ipg, cspi2_ipg, + cspi3_ipg, dryice_ipg, esdhc1_ipg, esdhc2_ipg, fec_ipg, iim_ipg, + kpp_ipg, lcdc_ipg, pwm1_ipg, pwm2_ipg, pwm3_ipg, pwm4_ipg, sdma_ipg, + ssi1_ipg, ssi2_ipg, tsc_ipg, uart1_ipg, uart2_ipg, uart3_ipg, + uart4_ipg, uart5_ipg, wdt_ipg, clk_max +}; + +static struct clk *clk[clk_max]; + +int __init mx25_clocks_init(void) +{ + int i; + + clk[dummy] = imx_clk_fixed("dummy", 0); + clk[osc] = imx_clk_fixed("osc", 24000000); + clk[mpll] = imx_clk_pllv1("mpll", "osc", ccm(CCM_MPCTL)); + clk[upll] = imx_clk_pllv1("upll", "osc", ccm(CCM_UPCTL)); + clk[mpll_cpu_3_4] = imx_clk_fixed_factor("mpll_cpu_3_4", "mpll", 3, 4); + clk[cpu_sel] = imx_clk_mux("cpu_sel", ccm(CCM_CCTL), 14, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks)); + clk[cpu] = imx_clk_divider("cpu", "cpu_sel", ccm(CCM_CCTL), 30, 2); + clk[ahb] = imx_clk_divider("ahb", "cpu", ccm(CCM_CCTL), 28, 2); + clk[usb_div] = imx_clk_divider("usb_div", "upll", ccm(CCM_CCTL), 16, 6); + clk[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2); + clk[per0_sel] = imx_clk_mux("per0_sel", ccm(CCM_MCR), 0, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per1_sel] = imx_clk_mux("per1_sel", ccm(CCM_MCR), 1, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per2_sel] = imx_clk_mux("per2_sel", ccm(CCM_MCR), 2, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per3_sel] = imx_clk_mux("per3_sel", ccm(CCM_MCR), 3, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per4_sel] = imx_clk_mux("per4_sel", ccm(CCM_MCR), 4, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per5_sel] = imx_clk_mux("per5_sel", ccm(CCM_MCR), 5, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per6_sel] = imx_clk_mux("per6_sel", ccm(CCM_MCR), 6, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per7_sel] = imx_clk_mux("per7_sel", ccm(CCM_MCR), 7, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per8_sel] = imx_clk_mux("per8_sel", ccm(CCM_MCR), 8, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per9_sel] = imx_clk_mux("per9_sel", ccm(CCM_MCR), 9, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per10_sel] = imx_clk_mux("per10_sel", ccm(CCM_MCR), 10, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per11_sel] = imx_clk_mux("per11_sel", ccm(CCM_MCR), 11, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per12_sel] = imx_clk_mux("per12_sel", ccm(CCM_MCR), 12, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per13_sel] = imx_clk_mux("per13_sel", ccm(CCM_MCR), 13, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per14_sel] = imx_clk_mux("per14_sel", ccm(CCM_MCR), 14, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per15_sel] = imx_clk_mux("per15_sel", ccm(CCM_MCR), 15, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per0] = imx_clk_divider("per0", "per0_sel", ccm(CCM_PCDR0), 0, 6); + clk[per1] = imx_clk_divider("per1", "per1_sel", ccm(CCM_PCDR0), 8, 6); + clk[per2] = imx_clk_divider("per2", "per2_sel", ccm(CCM_PCDR0), 16, 6); + clk[per3] = imx_clk_divider("per3", "per3_sel", ccm(CCM_PCDR0), 24, 6); + clk[per4] = imx_clk_divider("per4", "per4_sel", ccm(CCM_PCDR1), 0, 6); + clk[per5] = imx_clk_divider("per5", "per5_sel", ccm(CCM_PCDR1), 8, 6); + clk[per6] = imx_clk_divider("per6", "per6_sel", ccm(CCM_PCDR1), 16, 6); + clk[per7] = imx_clk_divider("per7", "per7_sel", ccm(CCM_PCDR1), 24, 6); + clk[per8] = imx_clk_divider("per8", "per8_sel", ccm(CCM_PCDR2), 0, 6); + clk[per9] = imx_clk_divider("per9", "per9_sel", ccm(CCM_PCDR2), 8, 6); + clk[per10] = imx_clk_divider("per10", "per10_sel", ccm(CCM_PCDR2), 16, 6); + clk[per11] = imx_clk_divider("per11", "per11_sel", ccm(CCM_PCDR2), 24, 6); + clk[per12] = imx_clk_divider("per12", "per12_sel", ccm(CCM_PCDR3), 0, 6); + clk[per13] = imx_clk_divider("per13", "per13_sel", ccm(CCM_PCDR3), 8, 6); + clk[per14] = imx_clk_divider("per14", "per14_sel", ccm(CCM_PCDR3), 16, 6); + clk[per15] = imx_clk_divider("per15", "per15_sel", ccm(CCM_PCDR3), 24, 6); + clk[csi_ipg_per] = imx_clk_gate("csi_ipg_per", "per0", ccm(CCM_CGCR0), 0); + clk[esdhc1_ipg_per] = imx_clk_gate("esdhc1_ipg_per", "per3", ccm(CCM_CGCR0), 3); + clk[esdhc2_ipg_per] = imx_clk_gate("esdhc2_ipg_per", "per4", ccm(CCM_CGCR0), 4); + clk[gpt_ipg_per] = imx_clk_gate("gpt_ipg_per", "per5", ccm(CCM_CGCR0), 5); + clk[i2c_ipg_per] = imx_clk_gate("i2c_ipg_per", "per6", ccm(CCM_CGCR0), 6); + clk[lcdc_ipg_per] = imx_clk_gate("lcdc_ipg_per", "per8", ccm(CCM_CGCR0), 7); + clk[nfc_ipg_per] = imx_clk_gate("nfc_ipg_per", "ipg_per", ccm(CCM_CGCR0), 8); + clk[ssi1_ipg_per] = imx_clk_gate("ssi1_ipg_per", "per13", ccm(CCM_CGCR0), 13); + clk[ssi2_ipg_per] = imx_clk_gate("ssi2_ipg_per", "per14", ccm(CCM_CGCR0), 14); + clk[uart_ipg_per] = imx_clk_gate("uart_ipg_per", "per15", ccm(CCM_CGCR0), 15); + clk[csi_ahb] = imx_clk_gate("csi_ahb", "ahb", ccm(CCM_CGCR0), 18); + clk[esdhc1_ahb] = imx_clk_gate("esdhc1_ahb", "ahb", ccm(CCM_CGCR0), 21); + clk[esdhc2_ahb] = imx_clk_gate("esdhc2_ahb", "ahb", ccm(CCM_CGCR0), 22); + clk[fec_ahb] = imx_clk_gate("fec_ahb", "ahb", ccm(CCM_CGCR0), 23); + clk[lcdc_ahb] = imx_clk_gate("lcdc_ahb", "ahb", ccm(CCM_CGCR0), 24); + clk[sdma_ahb] = imx_clk_gate("sdma_ahb", "ahb", ccm(CCM_CGCR0), 26); + clk[usbotg_ahb] = imx_clk_gate("usbotg_ahb", "ahb", ccm(CCM_CGCR0), 28); + clk[can1_ipg] = imx_clk_gate("can1_ipg", "ipg", ccm(CCM_CGCR1), 2); + clk[can2_ipg] = imx_clk_gate("can2_ipg", "ipg", ccm(CCM_CGCR1), 3); + clk[csi_ipg] = imx_clk_gate("csi_ipg", "ipg", ccm(CCM_CGCR1), 4); + clk[cspi1_ipg] = imx_clk_gate("cspi1_ipg", "ipg", ccm(CCM_CGCR1), 5); + clk[cspi2_ipg] = imx_clk_gate("cspi2_ipg", "ipg", ccm(CCM_CGCR1), 6); + clk[cspi3_ipg] = imx_clk_gate("cspi3_ipg", "ipg", ccm(CCM_CGCR1), 7); + clk[dryice_ipg] = imx_clk_gate("dryice_ipg", "ipg", ccm(CCM_CGCR1), 8); + clk[esdhc1_ipg] = imx_clk_gate("esdhc1_ipg", "ipg", ccm(CCM_CGCR1), 13); + clk[esdhc2_ipg] = imx_clk_gate("esdhc2_ipg", "ipg", ccm(CCM_CGCR1), 14); + clk[fec_ipg] = imx_clk_gate("fec_ipg", "ipg", ccm(CCM_CGCR1), 15); + clk[iim_ipg] = imx_clk_gate("iim_ipg", "ipg", ccm(CCM_CGCR1), 26); + clk[kpp_ipg] = imx_clk_gate("kpp_ipg", "ipg", ccm(CCM_CGCR1), 28); + clk[lcdc_ipg] = imx_clk_gate("lcdc_ipg", "ipg", ccm(CCM_CGCR1), 29); + clk[pwm1_ipg] = imx_clk_gate("pwm1_ipg", "ipg", ccm(CCM_CGCR1), 31); + clk[pwm2_ipg] = imx_clk_gate("pwm2_ipg", "ipg", ccm(CCM_CGCR2), 0); + clk[pwm3_ipg] = imx_clk_gate("pwm3_ipg", "ipg", ccm(CCM_CGCR2), 1); + clk[pwm4_ipg] = imx_clk_gate("pwm4_ipg", "ipg", ccm(CCM_CGCR2), 2); + clk[sdma_ipg] = imx_clk_gate("sdma_ipg", "ipg", ccm(CCM_CGCR2), 6); + clk[ssi1_ipg] = imx_clk_gate("ssi1_ipg", "ipg", ccm(CCM_CGCR2), 11); + clk[ssi2_ipg] = imx_clk_gate("ssi2_ipg", "ipg", ccm(CCM_CGCR2), 12); + clk[tsc_ipg] = imx_clk_gate("tsc_ipg", "ipg", ccm(CCM_CGCR2), 13); + clk[uart1_ipg] = imx_clk_gate("uart1_ipg", "ipg", ccm(CCM_CGCR2), 14); + clk[uart2_ipg] = imx_clk_gate("uart2_ipg", "ipg", ccm(CCM_CGCR2), 15); + clk[uart3_ipg] = imx_clk_gate("uart3_ipg", "ipg", ccm(CCM_CGCR2), 16); + clk[uart4_ipg] = imx_clk_gate("uart4_ipg", "ipg", ccm(CCM_CGCR2), 17); + clk[uart5_ipg] = imx_clk_gate("uart5_ipg", "ipg", ccm(CCM_CGCR2), 18); + clk[wdt_ipg] = imx_clk_gate("wdt_ipg", "ipg", ccm(CCM_CGCR2), 19); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX25 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + /* i.mx25 has the i.mx21 type uart */ + clk_register_clkdev(clk[uart1_ipg], "ipg", "imx21-uart.0"); + clk_register_clkdev(clk[uart_ipg_per], "per", "imx21-uart.0"); + clk_register_clkdev(clk[uart2_ipg], "ipg", "imx21-uart.1"); + clk_register_clkdev(clk[uart_ipg_per], "per", "imx21-uart.1"); + clk_register_clkdev(clk[uart3_ipg], "ipg", "imx21-uart.2"); + clk_register_clkdev(clk[uart_ipg_per], "per", "imx21-uart.2"); + clk_register_clkdev(clk[uart4_ipg], "ipg", "imx21-uart.3"); + clk_register_clkdev(clk[uart_ipg_per], "per", "imx21-uart.3"); + clk_register_clkdev(clk[uart5_ipg], "ipg", "imx21-uart.4"); + clk_register_clkdev(clk[uart_ipg_per], "per", "imx21-uart.4"); + clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[gpt_ipg_per], "per", "imx-gpt.0"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0"); + clk_register_clkdev(clk[usbotg_ahb], "ahb", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.0"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.1"); + clk_register_clkdev(clk[usbotg_ahb], "ahb", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.1"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2"); + clk_register_clkdev(clk[usbotg_ahb], "ahb", "mxc-ehci.2"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.2"); + clk_register_clkdev(clk[ipg], "ipg", "fsl-usb2-udc"); + clk_register_clkdev(clk[usbotg_ahb], "ahb", "fsl-usb2-udc"); + clk_register_clkdev(clk[usb_div], "per", "fsl-usb2-udc"); + clk_register_clkdev(clk[nfc_ipg_per], NULL, "mxc_nand.0"); + /* i.mx25 has the i.mx35 type cspi */ + clk_register_clkdev(clk[cspi1_ipg], NULL, "imx35-cspi.0"); + clk_register_clkdev(clk[cspi2_ipg], NULL, "imx35-cspi.1"); + clk_register_clkdev(clk[cspi3_ipg], NULL, "imx35-cspi.2"); + clk_register_clkdev(clk[pwm1_ipg], "ipg", "mxc_pwm.0"); + clk_register_clkdev(clk[per10], "per", "mxc_pwm.0"); + clk_register_clkdev(clk[pwm1_ipg], "ipg", "mxc_pwm.1"); + clk_register_clkdev(clk[per10], "per", "mxc_pwm.1"); + clk_register_clkdev(clk[pwm1_ipg], "ipg", "mxc_pwm.2"); + clk_register_clkdev(clk[per10], "per", "mxc_pwm.2"); + clk_register_clkdev(clk[pwm1_ipg], "ipg", "mxc_pwm.3"); + clk_register_clkdev(clk[per10], "per", "mxc_pwm.3"); + clk_register_clkdev(clk[kpp_ipg], NULL, "imx-keypad"); + clk_register_clkdev(clk[tsc_ipg], NULL, "mx25-adc"); + clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx-i2c.1"); + clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[fec_ipg], "ipg", "imx25-fec.0"); + clk_register_clkdev(clk[fec_ahb], "ahb", "imx25-fec.0"); + clk_register_clkdev(clk[dryice_ipg], NULL, "imxdi_rtc.0"); + clk_register_clkdev(clk[lcdc_ipg_per], "per", "imx-fb.0"); + clk_register_clkdev(clk[lcdc_ipg], "ipg", "imx-fb.0"); + clk_register_clkdev(clk[lcdc_ahb], "ahb", "imx-fb.0"); + clk_register_clkdev(clk[wdt_ipg], NULL, "imx2-wdt.0"); + clk_register_clkdev(clk[ssi1_ipg_per], "per", "imx-ssi.0"); + clk_register_clkdev(clk[ssi1_ipg], "ipg", "imx-ssi.0"); + clk_register_clkdev(clk[ssi2_ipg_per], "per", "imx-ssi.1"); + clk_register_clkdev(clk[ssi2_ipg], "ipg", "imx-ssi.1"); + clk_register_clkdev(clk[esdhc1_ipg_per], "per", "sdhci-esdhc-imx25.0"); + clk_register_clkdev(clk[esdhc1_ipg], "ipg", "sdhci-esdhc-imx25.0"); + clk_register_clkdev(clk[esdhc1_ahb], "ahb", "sdhci-esdhc-imx25.0"); + clk_register_clkdev(clk[esdhc2_ipg_per], "per", "sdhci-esdhc-imx25.1"); + clk_register_clkdev(clk[esdhc2_ipg], "ipg", "sdhci-esdhc-imx25.1"); + clk_register_clkdev(clk[esdhc2_ahb], "ahb", "sdhci-esdhc-imx25.1"); + clk_register_clkdev(clk[csi_ipg_per], "per", "mx2-camera.0"); + clk_register_clkdev(clk[csi_ipg], "ipg", "mx2-camera.0"); + clk_register_clkdev(clk[csi_ahb], "ahb", "mx2-camera.0"); + clk_register_clkdev(clk[dummy], "audmux", NULL); + clk_register_clkdev(clk[can1_ipg], NULL, "flexcan.0"); + clk_register_clkdev(clk[can2_ipg], NULL, "flexcan.1"); + /* i.mx25 has the i.mx35 type sdma */ + clk_register_clkdev(clk[sdma_ipg], "ipg", "imx35-sdma"); + clk_register_clkdev(clk[sdma_ahb], "ahb", "imx35-sdma"); + clk_register_clkdev(clk[iim_ipg], "iim", NULL); + + mxc_timer_init(NULL, MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54); + return 0; +} diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c new file mode 100644 index 000000000000..50a7ebd8d1b2 --- /dev/null +++ b/arch/arm/mach-imx/clk-imx27.c @@ -0,0 +1,290 @@ +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/clkdev.h> +#include <linux/err.h> +#include <linux/clk-provider.h> +#include <linux/of.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include "clk.h" + +#define IO_ADDR_CCM(off) (MX27_IO_ADDRESS(MX27_CCM_BASE_ADDR + (off))) + +/* Register offsets */ +#define CCM_CSCR IO_ADDR_CCM(0x0) +#define CCM_MPCTL0 IO_ADDR_CCM(0x4) +#define CCM_MPCTL1 IO_ADDR_CCM(0x8) +#define CCM_SPCTL0 IO_ADDR_CCM(0xc) +#define CCM_SPCTL1 IO_ADDR_CCM(0x10) +#define CCM_OSC26MCTL IO_ADDR_CCM(0x14) +#define CCM_PCDR0 IO_ADDR_CCM(0x18) +#define CCM_PCDR1 IO_ADDR_CCM(0x1c) +#define CCM_PCCR0 IO_ADDR_CCM(0x20) +#define CCM_PCCR1 IO_ADDR_CCM(0x24) +#define CCM_CCSR IO_ADDR_CCM(0x28) +#define CCM_PMCTL IO_ADDR_CCM(0x2c) +#define CCM_PMCOUNT IO_ADDR_CCM(0x30) +#define CCM_WKGDCTL IO_ADDR_CCM(0x34) + +#define CCM_CSCR_UPDATE_DIS (1 << 31) +#define CCM_CSCR_SSI2 (1 << 23) +#define CCM_CSCR_SSI1 (1 << 22) +#define CCM_CSCR_VPU (1 << 21) +#define CCM_CSCR_MSHC (1 << 20) +#define CCM_CSCR_SPLLRES (1 << 19) +#define CCM_CSCR_MPLLRES (1 << 18) +#define CCM_CSCR_SP (1 << 17) +#define CCM_CSCR_MCU (1 << 16) +#define CCM_CSCR_OSC26MDIV (1 << 4) +#define CCM_CSCR_OSC26M (1 << 3) +#define CCM_CSCR_FPM (1 << 2) +#define CCM_CSCR_SPEN (1 << 1) +#define CCM_CSCR_MPEN (1 << 0) + +/* i.MX27 TO 2+ */ +#define CCM_CSCR_ARM_SRC (1 << 15) + +#define CCM_SPCTL1_LF (1 << 15) +#define CCM_SPCTL1_BRMO (1 << 6) + +static const char *vpu_sel_clks[] = { "spll", "mpll_main2", }; +static const char *cpu_sel_clks[] = { "mpll_main2", "mpll", }; +static const char *clko_sel_clks[] = { + "ckil", "prem", "ckih", "ckih", + "ckih", "mpll", "spll", "cpu_div", + "ahb", "ipg", "per1_div", "per2_div", + "per3_div", "per4_div", "ssi1_div", "ssi2_div", + "nfc_div", "mshc_div", "vpu_div", "60m", + "32k", "usb_div", "dptc", +}; + +static const char *ssi_sel_clks[] = { "spll", "mpll", }; + +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, clk_max +}; + +static struct clk *clk[clk_max]; + +int __init mx27_clocks_init(unsigned long fref) +{ + int i; + + clk[dummy] = imx_clk_fixed("dummy", 0); + clk[ckih] = imx_clk_fixed("ckih", fref); + clk[ckil] = imx_clk_fixed("ckil", 32768); + clk[mpll] = imx_clk_pllv1("mpll", "ckih", CCM_MPCTL0); + clk[spll] = imx_clk_pllv1("spll", "ckih", CCM_SPCTL0); + clk[mpll_main2] = imx_clk_fixed_factor("mpll_main2", "mpll", 2, 3); + + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { + clk[ahb] = imx_clk_divider("ahb", "mpll_main2", CCM_CSCR, 8, 2); + clk[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2); + } else { + clk[ahb] = imx_clk_divider("ahb", "mpll_main2", CCM_CSCR, 9, 4); + clk[ipg] = imx_clk_divider("ipg", "ahb", CCM_CSCR, 8, 1); + } + + clk[nfc_div] = imx_clk_divider("nfc_div", "ahb", CCM_PCDR0, 6, 4); + clk[per1_div] = imx_clk_divider("per1_div", "mpll_main2", CCM_PCDR1, 0, 6); + clk[per2_div] = imx_clk_divider("per2_div", "mpll_main2", CCM_PCDR1, 8, 6); + clk[per3_div] = imx_clk_divider("per3_div", "mpll_main2", CCM_PCDR1, 16, 6); + clk[per4_div] = imx_clk_divider("per4_div", "mpll_main2", CCM_PCDR1, 24, 6); + clk[vpu_sel] = imx_clk_mux("vpu_sel", CCM_CSCR, 21, 1, vpu_sel_clks, ARRAY_SIZE(vpu_sel_clks)); + clk[vpu_div] = imx_clk_divider("vpu_div", "vpu_sel", CCM_PCDR0, 10, 3); + clk[usb_div] = imx_clk_divider("usb_div", "spll", CCM_CSCR, 28, 3); + clk[cpu_sel] = imx_clk_mux("cpu_sel", CCM_CSCR, 15, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks)); + clk[clko_sel] = imx_clk_mux("clko_sel", CCM_CCSR, 0, 5, clko_sel_clks, ARRAY_SIZE(clko_sel_clks)); + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) + clk[cpu_div] = imx_clk_divider("cpu_div", "cpu_sel", CCM_CSCR, 12, 2); + else + clk[cpu_div] = imx_clk_divider("cpu_div", "cpu_sel", CCM_CSCR, 13, 3); + clk[clko_div] = imx_clk_divider("clko_div", "clko_sel", CCM_PCDR0, 22, 3); + clk[ssi1_sel] = imx_clk_mux("ssi1_sel", CCM_CSCR, 22, 1, ssi_sel_clks, ARRAY_SIZE(ssi_sel_clks)); + clk[ssi2_sel] = imx_clk_mux("ssi2_sel", CCM_CSCR, 23, 1, ssi_sel_clks, ARRAY_SIZE(ssi_sel_clks)); + clk[ssi1_div] = imx_clk_divider("ssi1_div", "ssi1_sel", CCM_PCDR0, 16, 6); + clk[ssi2_div] = imx_clk_divider("ssi2_div", "ssi2_sel", CCM_PCDR0, 26, 3); + clk[clko_en] = imx_clk_gate("clko_en", "clko_div", CCM_PCCR0, 0); + clk[ssi2_ipg_gate] = imx_clk_gate("ssi2_ipg_gate", "ipg", CCM_PCCR0, 0); + clk[ssi1_ipg_gate] = imx_clk_gate("ssi1_ipg_gate", "ipg", CCM_PCCR0, 1); + clk[slcdc_ipg_gate] = imx_clk_gate("slcdc_ipg_gate", "ipg", CCM_PCCR0, 2); + clk[sdhc3_ipg_gate] = imx_clk_gate("sdhc3_ipg_gate", "ipg", CCM_PCCR0, 3); + clk[sdhc2_ipg_gate] = imx_clk_gate("sdhc2_ipg_gate", "ipg", CCM_PCCR0, 4); + clk[sdhc1_ipg_gate] = imx_clk_gate("sdhc1_ipg_gate", "ipg", CCM_PCCR0, 5); + clk[scc_ipg_gate] = imx_clk_gate("scc_ipg_gate", "ipg", CCM_PCCR0, 6); + clk[sahara_ipg_gate] = imx_clk_gate("sahara_ipg_gate", "ipg", CCM_PCCR0, 7); + clk[rtc_ipg_gate] = imx_clk_gate("rtc_ipg_gate", "ipg", CCM_PCCR0, 9); + clk[pwm_ipg_gate] = imx_clk_gate("pwm_ipg_gate", "ipg", CCM_PCCR0, 11); + clk[owire_ipg_gate] = imx_clk_gate("owire_ipg_gate", "ipg", CCM_PCCR0, 12); + clk[lcdc_ipg_gate] = imx_clk_gate("lcdc_ipg_gate", "ipg", CCM_PCCR0, 14); + clk[kpp_ipg_gate] = imx_clk_gate("kpp_ipg_gate", "ipg", CCM_PCCR0, 15); + clk[iim_ipg_gate] = imx_clk_gate("iim_ipg_gate", "ipg", CCM_PCCR0, 16); + clk[i2c2_ipg_gate] = imx_clk_gate("i2c2_ipg_gate", "ipg", CCM_PCCR0, 17); + clk[i2c1_ipg_gate] = imx_clk_gate("i2c1_ipg_gate", "ipg", CCM_PCCR0, 18); + clk[gpt6_ipg_gate] = imx_clk_gate("gpt6_ipg_gate", "ipg", CCM_PCCR0, 19); + clk[gpt5_ipg_gate] = imx_clk_gate("gpt5_ipg_gate", "ipg", CCM_PCCR0, 20); + clk[gpt4_ipg_gate] = imx_clk_gate("gpt4_ipg_gate", "ipg", CCM_PCCR0, 21); + clk[gpt3_ipg_gate] = imx_clk_gate("gpt3_ipg_gate", "ipg", CCM_PCCR0, 22); + clk[gpt2_ipg_gate] = imx_clk_gate("gpt2_ipg_gate", "ipg", CCM_PCCR0, 23); + clk[gpt1_ipg_gate] = imx_clk_gate("gpt1_ipg_gate", "ipg", CCM_PCCR0, 24); + clk[gpio_ipg_gate] = imx_clk_gate("gpio_ipg_gate", "ipg", CCM_PCCR0, 25); + clk[fec_ipg_gate] = imx_clk_gate("fec_ipg_gate", "ipg", CCM_PCCR0, 26); + clk[emma_ipg_gate] = imx_clk_gate("emma_ipg_gate", "ipg", CCM_PCCR0, 27); + clk[dma_ipg_gate] = imx_clk_gate("dma_ipg_gate", "ipg", CCM_PCCR0, 28); + clk[cspi3_ipg_gate] = imx_clk_gate("cspi3_ipg_gate", "ipg", CCM_PCCR0, 29); + clk[cspi2_ipg_gate] = imx_clk_gate("cspi2_ipg_gate", "ipg", CCM_PCCR0, 30); + clk[cspi1_ipg_gate] = imx_clk_gate("cspi1_ipg_gate", "ipg", CCM_PCCR0, 31); + clk[nfc_baud_gate] = imx_clk_gate("nfc_baud_gate", "nfc_div", CCM_PCCR1, 3); + clk[ssi2_baud_gate] = imx_clk_gate("ssi2_baud_gate", "ssi2_div", CCM_PCCR1, 4); + clk[ssi1_baud_gate] = imx_clk_gate("ssi1_baud_gate", "ssi1_div", CCM_PCCR1, 5); + clk[vpu_baud_gate] = imx_clk_gate("vpu_baud_gate", "vpu_div", CCM_PCCR1, 6); + clk[per4_gate] = imx_clk_gate("per4_gate", "per4_div", CCM_PCCR1, 7); + clk[per3_gate] = imx_clk_gate("per3_gate", "per3_div", CCM_PCCR1, 8); + clk[per2_gate] = imx_clk_gate("per2_gate", "per2_div", CCM_PCCR1, 9); + clk[per1_gate] = imx_clk_gate("per1_gate", "per1_div", CCM_PCCR1, 10); + clk[usb_ahb_gate] = imx_clk_gate("usb_ahb_gate", "ahb", CCM_PCCR1, 11); + clk[slcdc_ahb_gate] = imx_clk_gate("slcdc_ahb_gate", "ahb", CCM_PCCR1, 12); + clk[sahara_ahb_gate] = imx_clk_gate("sahara_ahb_gate", "ahb", CCM_PCCR1, 13); + clk[lcdc_ahb_gate] = imx_clk_gate("lcdc_ahb_gate", "ahb", CCM_PCCR1, 15); + clk[vpu_ahb_gate] = imx_clk_gate("vpu_ahb_gate", "ahb", CCM_PCCR1, 16); + clk[fec_ahb_gate] = imx_clk_gate("fec_ahb_gate", "ahb", CCM_PCCR1, 17); + clk[emma_ahb_gate] = imx_clk_gate("emma_ahb_gate", "ahb", CCM_PCCR1, 18); + clk[emi_ahb_gate] = imx_clk_gate("emi_ahb_gate", "ahb", CCM_PCCR1, 19); + clk[dma_ahb_gate] = imx_clk_gate("dma_ahb_gate", "ahb", CCM_PCCR1, 20); + clk[csi_ahb_gate] = imx_clk_gate("csi_ahb_gate", "ahb", CCM_PCCR1, 21); + clk[brom_ahb_gate] = imx_clk_gate("brom_ahb_gate", "ahb", CCM_PCCR1, 22); + clk[ata_ahb_gate] = imx_clk_gate("ata_ahb_gate", "ahb", CCM_PCCR1, 23); + clk[wdog_ipg_gate] = imx_clk_gate("wdog_ipg_gate", "ipg", CCM_PCCR1, 24); + clk[usb_ipg_gate] = imx_clk_gate("usb_ipg_gate", "ipg", CCM_PCCR1, 25); + clk[uart6_ipg_gate] = imx_clk_gate("uart6_ipg_gate", "ipg", CCM_PCCR1, 26); + clk[uart5_ipg_gate] = imx_clk_gate("uart5_ipg_gate", "ipg", CCM_PCCR1, 27); + clk[uart4_ipg_gate] = imx_clk_gate("uart4_ipg_gate", "ipg", CCM_PCCR1, 28); + clk[uart3_ipg_gate] = imx_clk_gate("uart3_ipg_gate", "ipg", CCM_PCCR1, 29); + clk[uart2_ipg_gate] = imx_clk_gate("uart2_ipg_gate", "ipg", CCM_PCCR1, 30); + clk[uart1_ipg_gate] = imx_clk_gate("uart1_ipg_gate", "ipg", CCM_PCCR1, 31); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX27 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + clk_register_clkdev(clk[uart1_ipg_gate], "ipg", "imx21-uart.0"); + clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.0"); + clk_register_clkdev(clk[uart2_ipg_gate], "ipg", "imx21-uart.1"); + clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.1"); + clk_register_clkdev(clk[uart3_ipg_gate], "ipg", "imx21-uart.2"); + clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.2"); + clk_register_clkdev(clk[uart4_ipg_gate], "ipg", "imx21-uart.3"); + clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.3"); + clk_register_clkdev(clk[uart5_ipg_gate], "ipg", "imx21-uart.4"); + clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.4"); + clk_register_clkdev(clk[uart6_ipg_gate], "ipg", "imx21-uart.5"); + clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.5"); + clk_register_clkdev(clk[gpt1_ipg_gate], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.0"); + clk_register_clkdev(clk[gpt2_ipg_gate], "ipg", "imx-gpt.1"); + clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.1"); + clk_register_clkdev(clk[gpt3_ipg_gate], "ipg", "imx-gpt.2"); + clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.2"); + clk_register_clkdev(clk[gpt4_ipg_gate], "ipg", "imx-gpt.3"); + clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.3"); + clk_register_clkdev(clk[gpt5_ipg_gate], "ipg", "imx-gpt.4"); + clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.4"); + clk_register_clkdev(clk[gpt6_ipg_gate], "ipg", "imx-gpt.5"); + clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.5"); + clk_register_clkdev(clk[pwm_ipg_gate], NULL, "mxc_pwm.0"); + clk_register_clkdev(clk[per2_gate], "per", "mxc-mmc.0"); + clk_register_clkdev(clk[sdhc1_ipg_gate], "ipg", "mxc-mmc.0"); + clk_register_clkdev(clk[per2_gate], "per", "mxc-mmc.1"); + clk_register_clkdev(clk[sdhc2_ipg_gate], "ipg", "mxc-mmc.1"); + clk_register_clkdev(clk[per2_gate], "per", "mxc-mmc.2"); + clk_register_clkdev(clk[sdhc2_ipg_gate], "ipg", "mxc-mmc.2"); + clk_register_clkdev(clk[cspi1_ipg_gate], NULL, "imx27-cspi.0"); + clk_register_clkdev(clk[cspi2_ipg_gate], NULL, "imx27-cspi.1"); + clk_register_clkdev(clk[cspi3_ipg_gate], NULL, "imx27-cspi.2"); + clk_register_clkdev(clk[per3_gate], "per", "imx-fb.0"); + clk_register_clkdev(clk[lcdc_ipg_gate], "ipg", "imx-fb.0"); + clk_register_clkdev(clk[lcdc_ahb_gate], "ahb", "imx-fb.0"); + clk_register_clkdev(clk[csi_ahb_gate], NULL, "mx2-camera.0"); + clk_register_clkdev(clk[usb_div], "per", "fsl-usb2-udc"); + clk_register_clkdev(clk[usb_ipg_gate], "ipg", "fsl-usb2-udc"); + clk_register_clkdev(clk[usb_ahb_gate], "ahb", "fsl-usb2-udc"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_ipg_gate], "ipg", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_ahb_gate], "ahb", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_ipg_gate], "ipg", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_ahb_gate], "ahb", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.2"); + clk_register_clkdev(clk[usb_ipg_gate], "ipg", "mxc-ehci.2"); + clk_register_clkdev(clk[usb_ahb_gate], "ahb", "mxc-ehci.2"); + clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "imx-ssi.0"); + clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "imx-ssi.1"); + clk_register_clkdev(clk[nfc_baud_gate], NULL, "mxc_nand.0"); + clk_register_clkdev(clk[vpu_baud_gate], "per", "imx-vpu"); + clk_register_clkdev(clk[vpu_ahb_gate], "ahb", "imx-vpu"); + clk_register_clkdev(clk[dma_ahb_gate], "ahb", "imx-dma"); + clk_register_clkdev(clk[dma_ipg_gate], "ipg", "imx-dma"); + clk_register_clkdev(clk[fec_ipg_gate], "ipg", "imx27-fec.0"); + clk_register_clkdev(clk[fec_ahb_gate], "ahb", "imx27-fec.0"); + clk_register_clkdev(clk[wdog_ipg_gate], NULL, "imx2-wdt.0"); + clk_register_clkdev(clk[i2c1_ipg_gate], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[i2c2_ipg_gate], NULL, "imx-i2c.1"); + clk_register_clkdev(clk[owire_ipg_gate], NULL, "mxc_w1.0"); + clk_register_clkdev(clk[kpp_ipg_gate], NULL, "imx-keypad"); + clk_register_clkdev(clk[emma_ahb_gate], "ahb", "imx-emma"); + clk_register_clkdev(clk[emma_ipg_gate], "ipg", "imx-emma"); + clk_register_clkdev(clk[iim_ipg_gate], "iim", NULL); + clk_register_clkdev(clk[gpio_ipg_gate], "gpio", NULL); + clk_register_clkdev(clk[brom_ahb_gate], "brom", NULL); + clk_register_clkdev(clk[ata_ahb_gate], "ata", NULL); + clk_register_clkdev(clk[rtc_ipg_gate], "rtc", NULL); + clk_register_clkdev(clk[scc_ipg_gate], "scc", NULL); + clk_register_clkdev(clk[cpu_div], "cpu", NULL); + clk_register_clkdev(clk[emi_ahb_gate], "emi_ahb" , NULL); + clk_register_clkdev(clk[ssi1_baud_gate], "bitrate" , "imx-ssi.0"); + clk_register_clkdev(clk[ssi2_baud_gate], "bitrate" , "imx-ssi.1"); + + mxc_timer_init(NULL, MX27_IO_ADDRESS(MX27_GPT1_BASE_ADDR), + MX27_INT_GPT1); + + clk_prepare_enable(clk[emi_ahb_gate]); + + return 0; +} + +#ifdef CONFIG_OF +int __init mx27_clocks_init_dt(void) +{ + struct device_node *np; + u32 fref = 26000000; /* default */ + + for_each_compatible_node(np, NULL, "fixed-clock") { + if (!of_device_is_compatible(np, "fsl,imx-osc26m")) + continue; + + if (!of_property_read_u32(np, "clock-frequency", &fref)) + break; + } + + return mx27_clocks_init(fref); +} +#endif diff --git a/arch/arm/mach-imx/clk-imx31.c b/arch/arm/mach-imx/clk-imx31.c new file mode 100644 index 000000000000..a854b9cae5ea --- /dev/null +++ b/arch/arm/mach-imx/clk-imx31.c @@ -0,0 +1,182 @@ +/* + * 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 <linux/module.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/io.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <mach/mx31.h> +#include <mach/common.h> + +#include "clk.h" +#include "crmregs-imx3.h" + +static const char *mcu_main_sel[] = { "spll", "mpll", }; +static const char *per_sel[] = { "per_div", "ipg", }; +static const char *csi_sel[] = { "upll", "spll", }; +static const char *fir_sel[] = { "mcu_main", "upll", "spll" }; + +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 *clk[clk_max]; + +int __init mx31_clocks_init(unsigned long fref) +{ + void __iomem *base = MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR); + int i; + + clk[ckih] = imx_clk_fixed("ckih", fref); + clk[ckil] = imx_clk_fixed("ckil", 32768); + clk[mpll] = imx_clk_pllv1("mpll", "ckih", base + MXC_CCM_MPCTL); + clk[spll] = imx_clk_pllv1("spll", "ckih", base + MXC_CCM_SRPCTL); + clk[upll] = imx_clk_pllv1("upll", "ckih", base + MXC_CCM_UPCTL); + clk[mcu_main] = imx_clk_mux("mcu_main", base + MXC_CCM_PMCR0, 31, 1, mcu_main_sel, ARRAY_SIZE(mcu_main_sel)); + clk[hsp] = imx_clk_divider("hsp", "mcu_main", base + MXC_CCM_PDR0, 11, 3); + clk[ahb] = imx_clk_divider("ahb", "mcu_main", base + MXC_CCM_PDR0, 3, 3); + clk[nfc] = imx_clk_divider("nfc", "ahb", base + MXC_CCM_PDR0, 8, 3); + clk[ipg] = imx_clk_divider("ipg", "ahb", base + MXC_CCM_PDR0, 6, 2); + clk[per_div] = imx_clk_divider("per_div", "upll", base + MXC_CCM_PDR0, 16, 5); + clk[per] = imx_clk_mux("per", base + MXC_CCM_CCMR, 24, 1, per_sel, ARRAY_SIZE(per_sel)); + clk[csi] = imx_clk_mux("csi_sel", base + MXC_CCM_CCMR, 25, 1, csi_sel, ARRAY_SIZE(csi_sel)); + clk[fir] = imx_clk_mux("fir_sel", base + MXC_CCM_CCMR, 11, 2, fir_sel, ARRAY_SIZE(fir_sel)); + clk[csi_div] = imx_clk_divider("csi_div", "csi_sel", base + MXC_CCM_PDR0, 23, 9); + clk[usb_div_pre] = imx_clk_divider("usb_div_pre", "upll", base + MXC_CCM_PDR1, 30, 2); + clk[usb_div_post] = imx_clk_divider("usb_div_post", "usb_div_pre", base + MXC_CCM_PDR1, 27, 3); + clk[fir_div_pre] = imx_clk_divider("fir_div_pre", "fir_sel", base + MXC_CCM_PDR1, 24, 3); + clk[fir_div_post] = imx_clk_divider("fir_div_post", "fir_div_pre", base + MXC_CCM_PDR1, 23, 6); + clk[sdhc1_gate] = imx_clk_gate2("sdhc1_gate", "per", base + MXC_CCM_CGR0, 0); + clk[sdhc2_gate] = imx_clk_gate2("sdhc2_gate", "per", base + MXC_CCM_CGR0, 2); + clk[gpt_gate] = imx_clk_gate2("gpt_gate", "per", base + MXC_CCM_CGR0, 4); + clk[epit1_gate] = imx_clk_gate2("epit1_gate", "per", base + MXC_CCM_CGR0, 6); + clk[epit2_gate] = imx_clk_gate2("epit2_gate", "per", base + MXC_CCM_CGR0, 8); + clk[iim_gate] = imx_clk_gate2("iim_gate", "ipg", base + MXC_CCM_CGR0, 10); + clk[ata_gate] = imx_clk_gate2("ata_gate", "ipg", base + MXC_CCM_CGR0, 12); + clk[sdma_gate] = imx_clk_gate2("sdma_gate", "ahb", base + MXC_CCM_CGR0, 14); + clk[cspi3_gate] = imx_clk_gate2("cspi3_gate", "ipg", base + MXC_CCM_CGR0, 16); + clk[rng_gate] = imx_clk_gate2("rng_gate", "ipg", base + MXC_CCM_CGR0, 18); + clk[uart1_gate] = imx_clk_gate2("uart1_gate", "per", base + MXC_CCM_CGR0, 20); + clk[uart2_gate] = imx_clk_gate2("uart2_gate", "per", base + MXC_CCM_CGR0, 22); + clk[ssi1_gate] = imx_clk_gate2("ssi1_gate", "spll", base + MXC_CCM_CGR0, 24); + clk[i2c1_gate] = imx_clk_gate2("i2c1_gate", "per", base + MXC_CCM_CGR0, 26); + clk[i2c2_gate] = imx_clk_gate2("i2c2_gate", "per", base + MXC_CCM_CGR0, 28); + clk[i2c3_gate] = imx_clk_gate2("i2c3_gate", "per", base + MXC_CCM_CGR0, 30); + clk[hantro_gate] = imx_clk_gate2("hantro_gate", "per", base + MXC_CCM_CGR1, 0); + clk[mstick1_gate] = imx_clk_gate2("mstick1_gate", "per", base + MXC_CCM_CGR1, 2); + clk[mstick2_gate] = imx_clk_gate2("mstick2_gate", "per", base + MXC_CCM_CGR1, 4); + clk[csi_gate] = imx_clk_gate2("csi_gate", "csi_div", base + MXC_CCM_CGR1, 6); + clk[rtc_gate] = imx_clk_gate2("rtc_gate", "ipg", base + MXC_CCM_CGR1, 8); + clk[wdog_gate] = imx_clk_gate2("wdog_gate", "ipg", base + MXC_CCM_CGR1, 10); + clk[pwm_gate] = imx_clk_gate2("pwm_gate", "per", base + MXC_CCM_CGR1, 12); + clk[sim_gate] = imx_clk_gate2("sim_gate", "per", base + MXC_CCM_CGR1, 14); + clk[ect_gate] = imx_clk_gate2("ect_gate", "per", base + MXC_CCM_CGR1, 16); + clk[usb_gate] = imx_clk_gate2("usb_gate", "ahb", base + MXC_CCM_CGR1, 18); + clk[kpp_gate] = imx_clk_gate2("kpp_gate", "ipg", base + MXC_CCM_CGR1, 20); + clk[ipu_gate] = imx_clk_gate2("ipu_gate", "hsp", base + MXC_CCM_CGR1, 22); + clk[uart3_gate] = imx_clk_gate2("uart3_gate", "per", base + MXC_CCM_CGR1, 24); + clk[uart4_gate] = imx_clk_gate2("uart4_gate", "per", base + MXC_CCM_CGR1, 26); + clk[uart5_gate] = imx_clk_gate2("uart5_gate", "per", base + MXC_CCM_CGR1, 28); + clk[owire_gate] = imx_clk_gate2("owire_gate", "per", base + MXC_CCM_CGR1, 30); + clk[ssi2_gate] = imx_clk_gate2("ssi2_gate", "spll", base + MXC_CCM_CGR2, 0); + clk[cspi1_gate] = imx_clk_gate2("cspi1_gate", "ipg", base + MXC_CCM_CGR2, 2); + clk[cspi2_gate] = imx_clk_gate2("cspi2_gate", "ipg", base + MXC_CCM_CGR2, 4); + clk[gacc_gate] = imx_clk_gate2("gacc_gate", "per", base + MXC_CCM_CGR2, 6); + clk[emi_gate] = imx_clk_gate2("emi_gate", "ahb", base + MXC_CCM_CGR2, 8); + clk[rtic_gate] = imx_clk_gate2("rtic_gate", "ahb", base + MXC_CCM_CGR2, 10); + clk[firi_gate] = imx_clk_gate2("firi_gate", "upll", base+MXC_CCM_CGR2, 12); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("imx31 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0"); + clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[cspi1_gate], NULL, "imx31-cspi.0"); + clk_register_clkdev(clk[cspi2_gate], NULL, "imx31-cspi.1"); + clk_register_clkdev(clk[cspi3_gate], NULL, "imx31-cspi.2"); + clk_register_clkdev(clk[pwm_gate], "pwm", NULL); + clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); + clk_register_clkdev(clk[rtc_gate], "rtc", NULL); + clk_register_clkdev(clk[epit1_gate], "epit", NULL); + clk_register_clkdev(clk[epit2_gate], "epit", NULL); + clk_register_clkdev(clk[nfc], NULL, "mxc_nand.0"); + clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core"); + clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb"); + clk_register_clkdev(clk[kpp_gate], "kpp", NULL); + clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.0"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.1"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.2"); + clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.2"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2"); + clk_register_clkdev(clk[usb_div_post], "per", "fsl-usb2-udc"); + clk_register_clkdev(clk[usb_gate], "ahb", "fsl-usb2-udc"); + clk_register_clkdev(clk[ipg], "ipg", "fsl-usb2-udc"); + clk_register_clkdev(clk[csi_gate], NULL, "mx3-camera.0"); + /* i.mx31 has the i.mx21 type uart */ + clk_register_clkdev(clk[uart1_gate], "per", "imx21-uart.0"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.0"); + clk_register_clkdev(clk[uart2_gate], "per", "imx21-uart.1"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.1"); + clk_register_clkdev(clk[uart3_gate], "per", "imx21-uart.2"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.2"); + clk_register_clkdev(clk[uart4_gate], "per", "imx21-uart.3"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.3"); + clk_register_clkdev(clk[uart5_gate], "per", "imx21-uart.4"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.4"); + clk_register_clkdev(clk[i2c1_gate], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[i2c2_gate], NULL, "imx-i2c.1"); + clk_register_clkdev(clk[i2c3_gate], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1.0"); + clk_register_clkdev(clk[sdhc1_gate], NULL, "mxc-mmc.0"); + clk_register_clkdev(clk[sdhc2_gate], NULL, "mxc-mmc.1"); + clk_register_clkdev(clk[ssi1_gate], NULL, "imx-ssi.0"); + clk_register_clkdev(clk[ssi2_gate], NULL, "imx-ssi.1"); + clk_register_clkdev(clk[firi_gate], "firi", NULL); + clk_register_clkdev(clk[ata_gate], NULL, "pata_imx"); + clk_register_clkdev(clk[rtic_gate], "rtic", NULL); + clk_register_clkdev(clk[rng_gate], "rng", NULL); + clk_register_clkdev(clk[sdma_gate], NULL, "imx31-sdma"); + clk_register_clkdev(clk[iim_gate], "iim", NULL); + + clk_set_parent(clk[csi], clk[upll]); + clk_prepare_enable(clk[emi_gate]); + clk_prepare_enable(clk[iim_gate]); + mx31_revision(); + clk_disable_unprepare(clk[iim_gate]); + + mxc_timer_init(NULL, MX31_IO_ADDRESS(MX31_GPT1_BASE_ADDR), + MX31_INT_GPT); + + return 0; +} diff --git a/arch/arm/mach-imx/clk-imx35.c b/arch/arm/mach-imx/clk-imx35.c new file mode 100644 index 000000000000..a9e60bf7dd75 --- /dev/null +++ b/arch/arm/mach-imx/clk-imx35.c @@ -0,0 +1,278 @@ +/* + * 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 <linux/mm.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <mach/common.h> + +#include "crmregs-imx3.h" +#include "clk.h" + +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 }; + +static const char *std_sel[] = {"ppll", "arm"}; +static const char *ipg_per_sel[] = {"ahb_per_div", "arm_per_div"}; + +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 *clk[clk_max]; + +int __init mx35_clocks_init() +{ + void __iomem *base = MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR); + u32 pdr0, consumer_sel, hsp_sel; + struct arm_ahb_div *aad; + unsigned char *hsp_div; + int i; + + pdr0 = __raw_readl(base + MXC_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]; + } + + clk[ckih] = imx_clk_fixed("ckih", 24000000); + clk[mpll] = imx_clk_pllv1("mpll", "ckih", base + MX35_CCM_MPCTL); + clk[ppll] = imx_clk_pllv1("ppll", "ckih", base + MX35_CCM_PPCTL); + + clk[mpll] = imx_clk_fixed_factor("mpll_075", "mpll", 3, 4); + + if (aad->sel) + clk[arm] = imx_clk_fixed_factor("arm", "mpll_075", 1, aad->arm); + else + clk[arm] = imx_clk_fixed_factor("arm", "mpll", 1, aad->arm); + + if (clk_get_rate(clk[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; + } + + clk[hsp] = imx_clk_fixed_factor("hsp", "arm", 1, hsp_div[hsp_sel]); + + clk[ahb] = imx_clk_fixed_factor("ahb", "arm", 1, aad->ahb); + clk[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2); + + clk[arm_per_div] = imx_clk_divider("arm_per_div", "arm", base + MX35_CCM_PDR4, 16, 6); + clk[ahb_per_div] = imx_clk_divider("ahb_per_div", "ahb", base + MXC_CCM_PDR0, 12, 3); + clk[ipg_per] = imx_clk_mux("ipg_per", base + MXC_CCM_PDR0, 26, 1, ipg_per_sel, ARRAY_SIZE(ipg_per_sel)); + + clk[uart_sel] = imx_clk_mux("uart_sel", base + MX35_CCM_PDR3, 14, 1, std_sel, ARRAY_SIZE(std_sel)); + clk[uart_div] = imx_clk_divider("uart_div", "uart_sel", base + MX35_CCM_PDR4, 10, 6); + + clk[esdhc_sel] = imx_clk_mux("esdhc_sel", base + MX35_CCM_PDR4, 9, 1, std_sel, ARRAY_SIZE(std_sel)); + clk[esdhc1_div] = imx_clk_divider("esdhc1_div", "esdhc_sel", base + MX35_CCM_PDR3, 0, 6); + clk[esdhc2_div] = imx_clk_divider("esdhc2_div", "esdhc_sel", base + MX35_CCM_PDR3, 8, 6); + clk[esdhc3_div] = imx_clk_divider("esdhc3_div", "esdhc_sel", base + MX35_CCM_PDR3, 16, 6); + + clk[spdif_sel] = imx_clk_mux("spdif_sel", base + MX35_CCM_PDR3, 22, 1, std_sel, ARRAY_SIZE(std_sel)); + clk[spdif_div_pre] = imx_clk_divider("spdif_div_pre", "spdif_sel", base + MX35_CCM_PDR3, 29, 3); /* divide by 1 not allowed */ + clk[spdif_div_post] = imx_clk_divider("spdif_div_post", "spdif_div_pre", base + MX35_CCM_PDR3, 23, 6); + + clk[ssi_sel] = imx_clk_mux("ssi_sel", base + MX35_CCM_PDR2, 6, 1, std_sel, ARRAY_SIZE(std_sel)); + clk[ssi1_div_pre] = imx_clk_divider("ssi1_div_pre", "ssi_sel", base + MX35_CCM_PDR2, 24, 3); + clk[ssi1_div_post] = imx_clk_divider("ssi1_div_post", "ssi1_div_pre", base + MX35_CCM_PDR2, 0, 6); + clk[ssi2_div_pre] = imx_clk_divider("ssi2_div_pre", "ssi_sel", base + MX35_CCM_PDR2, 27, 3); + clk[ssi2_div_post] = imx_clk_divider("ssi2_div_post", "ssi2_div_pre", base + MX35_CCM_PDR2, 8, 6); + + clk[usb_sel] = imx_clk_mux("usb_sel", base + MX35_CCM_PDR4, 9, 1, std_sel, ARRAY_SIZE(std_sel)); + clk[usb_div] = imx_clk_divider("usb_div", "usb_sel", base + MX35_CCM_PDR4, 22, 6); + + clk[nfc_div] = imx_clk_divider("nfc_div", "ahb", base + MX35_CCM_PDR4, 28, 4); + + clk[asrc_gate] = imx_clk_gate2("asrc_gate", "ipg", base + MX35_CCM_CGR0, 0); + clk[pata_gate] = imx_clk_gate2("pata_gate", "ipg", base + MX35_CCM_CGR0, 2); + clk[audmux_gate] = imx_clk_gate2("audmux_gate", "ipg", base + MX35_CCM_CGR0, 4); + clk[can1_gate] = imx_clk_gate2("can1_gate", "ipg", base + MX35_CCM_CGR0, 6); + clk[can2_gate] = imx_clk_gate2("can2_gate", "ipg", base + MX35_CCM_CGR0, 8); + clk[cspi1_gate] = imx_clk_gate2("cspi1_gate", "ipg", base + MX35_CCM_CGR0, 10); + clk[cspi2_gate] = imx_clk_gate2("cspi2_gate", "ipg", base + MX35_CCM_CGR0, 12); + clk[ect_gate] = imx_clk_gate2("ect_gate", "ipg", base + MX35_CCM_CGR0, 14); + clk[edio_gate] = imx_clk_gate2("edio_gate", "ipg", base + MX35_CCM_CGR0, 16); + clk[emi_gate] = imx_clk_gate2("emi_gate", "ipg", base + MX35_CCM_CGR0, 18); + clk[epit1_gate] = imx_clk_gate2("epit1_gate", "ipg", base + MX35_CCM_CGR0, 20); + clk[epit2_gate] = imx_clk_gate2("epit2_gate", "ipg", base + MX35_CCM_CGR0, 22); + clk[esai_gate] = imx_clk_gate2("esai_gate", "ipg", base + MX35_CCM_CGR0, 24); + clk[esdhc1_gate] = imx_clk_gate2("esdhc1_gate", "esdhc1_div", base + MX35_CCM_CGR0, 26); + clk[esdhc2_gate] = imx_clk_gate2("esdhc2_gate", "esdhc2_div", base + MX35_CCM_CGR0, 28); + clk[esdhc3_gate] = imx_clk_gate2("esdhc3_gate", "esdhc3_div", base + MX35_CCM_CGR0, 30); + + clk[fec_gate] = imx_clk_gate2("fec_gate", "ipg", base + MX35_CCM_CGR1, 0); + clk[gpio1_gate] = imx_clk_gate2("gpio1_gate", "ipg", base + MX35_CCM_CGR1, 2); + clk[gpio2_gate] = imx_clk_gate2("gpio2_gate", "ipg", base + MX35_CCM_CGR1, 4); + clk[gpio3_gate] = imx_clk_gate2("gpio3_gate", "ipg", base + MX35_CCM_CGR1, 6); + clk[gpt_gate] = imx_clk_gate2("gpt_gate", "ipg", base + MX35_CCM_CGR1, 8); + clk[i2c1_gate] = imx_clk_gate2("i2c1_gate", "ipg_per", base + MX35_CCM_CGR1, 10); + clk[i2c2_gate] = imx_clk_gate2("i2c2_gate", "ipg_per", base + MX35_CCM_CGR1, 12); + clk[i2c3_gate] = imx_clk_gate2("i2c3_gate", "ipg_per", base + MX35_CCM_CGR1, 14); + clk[iomuxc_gate] = imx_clk_gate2("iomuxc_gate", "ipg", base + MX35_CCM_CGR1, 16); + clk[ipu_gate] = imx_clk_gate2("ipu_gate", "hsp", base + MX35_CCM_CGR1, 18); + clk[kpp_gate] = imx_clk_gate2("kpp_gate", "ipg", base + MX35_CCM_CGR1, 20); + clk[mlb_gate] = imx_clk_gate2("mlb_gate", "ahb", base + MX35_CCM_CGR1, 22); + clk[mshc_gate] = imx_clk_gate2("mshc_gate", "dummy", base + MX35_CCM_CGR1, 24); + clk[owire_gate] = imx_clk_gate2("owire_gate", "ipg_per", base + MX35_CCM_CGR1, 26); + clk[pwm_gate] = imx_clk_gate2("pwm_gate", "ipg_per", base + MX35_CCM_CGR1, 28); + clk[rngc_gate] = imx_clk_gate2("rngc_gate", "ipg", base + MX35_CCM_CGR1, 30); + + clk[rtc_gate] = imx_clk_gate2("rtc_gate", "ipg", base + MX35_CCM_CGR2, 0); + clk[rtic_gate] = imx_clk_gate2("rtic_gate", "ahb", base + MX35_CCM_CGR2, 2); + clk[scc_gate] = imx_clk_gate2("scc_gate", "ipg", base + MX35_CCM_CGR2, 4); + clk[sdma_gate] = imx_clk_gate2("sdma_gate", "ahb", base + MX35_CCM_CGR2, 6); + clk[spba_gate] = imx_clk_gate2("spba_gate", "ipg", base + MX35_CCM_CGR2, 8); + clk[spdif_gate] = imx_clk_gate2("spdif_gate", "spdif_div_post", base + MX35_CCM_CGR2, 10); + clk[ssi1_gate] = imx_clk_gate2("ssi1_gate", "ssi1_div_post", base + MX35_CCM_CGR2, 12); + clk[ssi2_gate] = imx_clk_gate2("ssi2_gate", "ssi2_div_post", base + MX35_CCM_CGR2, 14); + clk[uart1_gate] = imx_clk_gate2("uart1_gate", "uart_div", base + MX35_CCM_CGR2, 16); + clk[uart2_gate] = imx_clk_gate2("uart2_gate", "uart_div", base + MX35_CCM_CGR2, 18); + clk[uart3_gate] = imx_clk_gate2("uart3_gate", "uart_div", base + MX35_CCM_CGR2, 20); + clk[usbotg_gate] = imx_clk_gate2("usbotg_gate", "ahb", base + MX35_CCM_CGR2, 22); + clk[wdog_gate] = imx_clk_gate2("wdog_gate", "ipg", base + MX35_CCM_CGR2, 24); + clk[max_gate] = imx_clk_gate2("max_gate", "dummy", base + MX35_CCM_CGR2, 26); + clk[admux_gate] = imx_clk_gate2("admux_gate", "ipg", base + MX35_CCM_CGR2, 30); + + clk[csi_gate] = imx_clk_gate2("csi_gate", "ipg", base + MX35_CCM_CGR3, 0); + clk[iim_gate] = imx_clk_gate2("iim_gate", "ipg", base + MX35_CCM_CGR3, 2); + clk[gpu2d_gate] = imx_clk_gate2("gpu2d_gate", "ahb", base + MX35_CCM_CGR3, 4); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX35 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + + clk_register_clkdev(clk[pata_gate], NULL, "pata_imx"); + clk_register_clkdev(clk[can1_gate], NULL, "flexcan.0"); + clk_register_clkdev(clk[can2_gate], NULL, "flexcan.1"); + clk_register_clkdev(clk[cspi1_gate], "per", "imx35-cspi.0"); + clk_register_clkdev(clk[cspi1_gate], "ipg", "imx35-cspi.0"); + clk_register_clkdev(clk[cspi2_gate], "per", "imx35-cspi.1"); + clk_register_clkdev(clk[cspi2_gate], "ipg", "imx35-cspi.1"); + clk_register_clkdev(clk[epit1_gate], NULL, "imx-epit.0"); + clk_register_clkdev(clk[epit2_gate], NULL, "imx-epit.1"); + clk_register_clkdev(clk[esdhc1_gate], "per", "sdhci-esdhc-imx35.0"); + clk_register_clkdev(clk[ipg], "ipg", "sdhci-esdhc-imx35.0"); + clk_register_clkdev(clk[ahb], "ahb", "sdhci-esdhc-imx35.0"); + clk_register_clkdev(clk[esdhc2_gate], "per", "sdhci-esdhc-imx35.1"); + clk_register_clkdev(clk[ipg], "ipg", "sdhci-esdhc-imx35.1"); + clk_register_clkdev(clk[ahb], "ahb", "sdhci-esdhc-imx35.1"); + clk_register_clkdev(clk[esdhc3_gate], "per", "sdhci-esdhc-imx35.2"); + clk_register_clkdev(clk[ipg], "ipg", "sdhci-esdhc-imx35.2"); + clk_register_clkdev(clk[ahb], "ahb", "sdhci-esdhc-imx35.2"); + /* i.mx35 has the i.mx27 type fec */ + clk_register_clkdev(clk[fec_gate], NULL, "imx27-fec.0"); + clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0"); + clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[i2c1_gate], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[i2c2_gate], NULL, "imx-i2c.1"); + clk_register_clkdev(clk[i2c3_gate], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core"); + clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb"); + clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1"); + clk_register_clkdev(clk[sdma_gate], NULL, "imx35-sdma"); + clk_register_clkdev(clk[ipg], "ipg", "imx-ssi.0"); + clk_register_clkdev(clk[ssi1_div_post], "per", "imx-ssi.0"); + clk_register_clkdev(clk[ipg], "ipg", "imx-ssi.1"); + clk_register_clkdev(clk[ssi2_div_post], "per", "imx-ssi.1"); + /* i.mx35 has the i.mx21 type uart */ + clk_register_clkdev(clk[uart1_gate], "per", "imx21-uart.0"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.0"); + clk_register_clkdev(clk[uart2_gate], "per", "imx21-uart.1"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.1"); + clk_register_clkdev(clk[uart3_gate], "per", "imx21-uart.2"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.2"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.0"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0"); + clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.1"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.1"); + clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.2"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2"); + clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.2"); + clk_register_clkdev(clk[usb_div], "per", "fsl-usb2-udc"); + clk_register_clkdev(clk[ipg], "ipg", "fsl-usb2-udc"); + clk_register_clkdev(clk[usbotg_gate], "ahb", "fsl-usb2-udc"); + clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); + clk_register_clkdev(clk[nfc_div], NULL, "mxc_nand.0"); + + clk_prepare_enable(clk[spba_gate]); + clk_prepare_enable(clk[gpio1_gate]); + clk_prepare_enable(clk[gpio2_gate]); + clk_prepare_enable(clk[gpio3_gate]); + clk_prepare_enable(clk[iim_gate]); + clk_prepare_enable(clk[emi_gate]); + + imx_print_silicon_rev("i.MX35", mx35_revision()); + +#ifdef CONFIG_MXC_USE_EPIT + epit_timer_init(&epit1_clk, + MX35_IO_ADDRESS(MX35_EPIT1_BASE_ADDR), MX35_INT_EPIT1); +#else + mxc_timer_init(NULL, MX35_IO_ADDRESS(MX35_GPT1_BASE_ADDR), + MX35_INT_GPT); +#endif + + return 0; +} diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c new file mode 100644 index 000000000000..b8a382defb23 --- /dev/null +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -0,0 +1,466 @@ +/* + * 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 <linux/mm.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <mach/common.h> + +#include "crm-regs-imx5.h" +#include "clk.h" + +/* Low-power Audio Playback Mode clock */ +static const char *lp_apm_sel[] = { "osc", }; + +/* This is used multiple times */ +static const char *standard_pll_sel[] = { "pll1_sw", "pll2_sw", "pll3_sw", "lp_apm", }; +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 *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", }; +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", }; +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 *tve_sel[] = { "tve_pred", "tve_ext_sel", }; +static const char *ipu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", }; +static const char *vpu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", }; + +enum imx5_clks { + dummy, ckil, osc, ckih1, ckih2, ahb, ipg, axi_a, axi_b, uart_pred, + uart_root, esdhc_a_pred, esdhc_b_pred, esdhc_c_s, esdhc_d_s, + emi_sel, emi_slow_podf, nfc_podf, ecspi_pred, ecspi_podf, usboh3_pred, + usboh3_podf, usb_phy_pred, usb_phy_podf, cpu_podf, di_pred, tve_di, + tve_s, uart1_ipg_gate, uart1_per_gate, uart2_ipg_gate, + uart2_per_gate, uart3_ipg_gate, uart3_per_gate, i2c1_gate, i2c2_gate, + gpt_ipg_gate, pwm1_ipg_gate, pwm1_hf_gate, pwm2_ipg_gate, pwm2_hf_gate, + gpt_gate, fec_gate, usboh3_per_gate, esdhc1_ipg_gate, esdhc2_ipg_gate, + esdhc3_ipg_gate, esdhc4_ipg_gate, ssi1_ipg_gate, ssi2_ipg_gate, + ssi3_ipg_gate, ecspi1_ipg_gate, ecspi1_per_gate, ecspi2_ipg_gate, + ecspi2_per_gate, cspi_ipg_gate, sdma_gate, emi_slow_gate, ipu_s, + ipu_gate, nfc_gate, ipu_di1_gate, vpu_s, vpu_gate, + vpu_reference_gate, uart4_ipg_gate, uart4_per_gate, uart5_ipg_gate, + uart5_per_gate, tve_gate, tve_pred, esdhc1_per_gate, esdhc2_per_gate, + esdhc3_per_gate, esdhc4_per_gate, usb_phy_gate, hsi2c_gate, + mipi_hsc1_gate, mipi_hsc2_gate, mipi_esc_gate, mipi_hsp_gate, + ldb_di1_div_3_5, ldb_di1_div, ldb_di0_div_3_5, ldb_di0_div, + ldb_di1_gate, can2_serial_gate, can2_ipg_gate, i2c3_gate, lp_apm, + periph_apm, main_bus, ahb_max, aips_tz1, aips_tz2, tmax1, tmax2, + tmax3, spba, uart_sel, esdhc_a_sel, esdhc_b_sel, esdhc_a_podf, + esdhc_b_podf, ecspi_sel, usboh3_sel, usb_phy_sel, iim_gate, + usboh3_gate, emi_fast_gate, ipu_di0_gate,gpc_dvfs, pll1_sw, pll2_sw, + pll3_sw, ipu_di0_sel, ipu_di1_sel, tve_ext_sel, mx51_mipi, pll4_sw, + ldb_di1_sel, di_pll4_podf, ldb_di0_sel, ldb_di0_gate, usb_phy1_gate, + usb_phy2_gate, per_lp_apm, per_pred1, per_pred2, per_podf, per_root, + clk_max +}; + +static struct clk *clk[clk_max]; + +static void __init mx5_clocks_common_init(unsigned long rate_ckil, + unsigned long rate_osc, unsigned long rate_ckih1, + unsigned long rate_ckih2) +{ + int i; + + clk[dummy] = imx_clk_fixed("dummy", 0); + clk[ckil] = imx_clk_fixed("ckil", rate_ckil); + clk[osc] = imx_clk_fixed("osc", rate_osc); + clk[ckih1] = imx_clk_fixed("ckih1", rate_ckih1); + clk[ckih2] = imx_clk_fixed("ckih2", rate_ckih2); + + clk[lp_apm] = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 9, 1, + lp_apm_sel, ARRAY_SIZE(lp_apm_sel)); + clk[periph_apm] = imx_clk_mux("periph_apm", MXC_CCM_CBCMR, 12, 2, + periph_apm_sel, ARRAY_SIZE(periph_apm_sel)); + clk[main_bus] = imx_clk_mux("main_bus", MXC_CCM_CBCDR, 25, 1, + main_bus_sel, ARRAY_SIZE(main_bus_sel)); + clk[per_lp_apm] = imx_clk_mux("per_lp_apm", MXC_CCM_CBCDR, 1, 1, + per_lp_apm_sel, ARRAY_SIZE(per_lp_apm_sel)); + clk[per_pred1] = imx_clk_divider("per_pred1", "per_lp_apm", MXC_CCM_CBCDR, 6, 2); + clk[per_pred2] = imx_clk_divider("per_pred2", "per_pred1", MXC_CCM_CBCDR, 3, 3); + clk[per_podf] = imx_clk_divider("per_podf", "per_pred2", MXC_CCM_CBCDR, 0, 3); + clk[per_root] = imx_clk_mux("per_root", MXC_CCM_CBCDR, 1, 0, + per_root_sel, ARRAY_SIZE(per_root_sel)); + clk[ahb] = imx_clk_divider("ahb", "main_bus", MXC_CCM_CBCDR, 10, 3); + clk[ahb_max] = imx_clk_gate2("ahb_max", "ahb", MXC_CCM_CCGR0, 28); + clk[aips_tz1] = imx_clk_gate2("aips_tz1", "ahb", MXC_CCM_CCGR0, 24); + clk[aips_tz2] = imx_clk_gate2("aips_tz2", "ahb", MXC_CCM_CCGR0, 26); + clk[tmax1] = imx_clk_gate2("tmax1", "ahb", MXC_CCM_CCGR1, 0); + clk[tmax2] = imx_clk_gate2("tmax2", "ahb", MXC_CCM_CCGR1, 2); + clk[tmax3] = imx_clk_gate2("tmax3", "ahb", MXC_CCM_CCGR1, 4); + clk[spba] = imx_clk_gate2("spba", "ipg", MXC_CCM_CCGR5, 0); + clk[ipg] = imx_clk_divider("ipg", "ahb", MXC_CCM_CBCDR, 8, 2); + clk[axi_a] = imx_clk_divider("axi_a", "main_bus", MXC_CCM_CBCDR, 16, 3); + clk[axi_b] = imx_clk_divider("axi_b", "main_bus", MXC_CCM_CBCDR, 19, 3); + clk[uart_sel] = imx_clk_mux("uart_sel", MXC_CCM_CSCMR1, 24, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[uart_pred] = imx_clk_divider("uart_pred", "uart_sel", MXC_CCM_CSCDR1, 3, 3); + clk[uart_root] = imx_clk_divider("uart_root", "uart_pred", MXC_CCM_CSCDR1, 0, 3); + + clk[esdhc_a_sel] = imx_clk_mux("esdhc_a_sel", MXC_CCM_CSCMR1, 20, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[esdhc_b_sel] = imx_clk_mux("esdhc_b_sel", MXC_CCM_CSCMR1, 16, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[esdhc_a_pred] = imx_clk_divider("esdhc_a_pred", "esdhc_a_sel", MXC_CCM_CSCDR1, 16, 3); + clk[esdhc_a_podf] = imx_clk_divider("esdhc_a_podf", "esdhc_a_pred", MXC_CCM_CSCDR1, 11, 3); + clk[esdhc_b_pred] = imx_clk_divider("esdhc_b_pred", "esdhc_b_sel", MXC_CCM_CSCDR1, 22, 3); + clk[esdhc_b_podf] = imx_clk_divider("esdhc_b_podf", "esdhc_b_pred", MXC_CCM_CSCDR1, 19, 3); + clk[esdhc_c_s] = imx_clk_mux("esdhc_c_sel", MXC_CCM_CSCMR1, 19, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel)); + clk[esdhc_d_s] = imx_clk_mux("esdhc_d_sel", MXC_CCM_CSCMR1, 18, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel)); + + clk[emi_sel] = imx_clk_mux("emi_sel", MXC_CCM_CBCDR, 26, 1, + emi_slow_sel, ARRAY_SIZE(emi_slow_sel)); + clk[emi_slow_podf] = imx_clk_divider("emi_slow_podf", "emi_sel", MXC_CCM_CBCDR, 22, 3); + clk[nfc_podf] = imx_clk_divider("nfc_podf", "emi_slow_podf", MXC_CCM_CBCDR, 13, 3); + clk[ecspi_sel] = imx_clk_mux("ecspi_sel", MXC_CCM_CSCMR1, 4, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[ecspi_pred] = imx_clk_divider("ecspi_pred", "ecspi_sel", MXC_CCM_CSCDR2, 25, 3); + clk[ecspi_podf] = imx_clk_divider("ecspi_podf", "ecspi_pred", MXC_CCM_CSCDR2, 19, 6); + clk[usboh3_sel] = imx_clk_mux("usboh3_sel", MXC_CCM_CSCMR1, 22, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[usboh3_pred] = imx_clk_divider("usboh3_pred", "usboh3_sel", MXC_CCM_CSCDR1, 8, 3); + clk[usboh3_podf] = imx_clk_divider("usboh3_podf", "usboh3_pred", MXC_CCM_CSCDR1, 6, 2); + clk[usb_phy_pred] = imx_clk_divider("usb_phy_pred", "pll3_sw", MXC_CCM_CDCDR, 3, 3); + clk[usb_phy_podf] = imx_clk_divider("usb_phy_podf", "usb_phy_pred", MXC_CCM_CDCDR, 0, 3); + clk[usb_phy_sel] = imx_clk_mux("usb_phy_sel", MXC_CCM_CSCMR1, 26, 1, + usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str)); + clk[cpu_podf] = imx_clk_divider("cpu_podf", "pll1_sw", MXC_CCM_CACRR, 0, 3); + clk[di_pred] = imx_clk_divider("di_pred", "pll3_sw", MXC_CCM_CDCDR, 6, 3); + clk[tve_di] = imx_clk_fixed("tve_di", 65000000); /* FIXME */ + clk[tve_s] = imx_clk_mux("tve_sel", MXC_CCM_CSCMR1, 7, 1, tve_sel, ARRAY_SIZE(tve_sel)); + clk[iim_gate] = imx_clk_gate2("iim_gate", "ipg", MXC_CCM_CCGR0, 30); + clk[uart1_ipg_gate] = imx_clk_gate2("uart1_ipg_gate", "ipg", MXC_CCM_CCGR1, 6); + clk[uart1_per_gate] = imx_clk_gate2("uart1_per_gate", "uart_root", MXC_CCM_CCGR1, 8); + clk[uart2_ipg_gate] = imx_clk_gate2("uart2_ipg_gate", "ipg", MXC_CCM_CCGR1, 10); + clk[uart2_per_gate] = imx_clk_gate2("uart2_per_gate", "uart_root", MXC_CCM_CCGR1, 12); + clk[uart3_ipg_gate] = imx_clk_gate2("uart3_ipg_gate", "ipg", MXC_CCM_CCGR1, 14); + clk[uart3_per_gate] = imx_clk_gate2("uart3_per_gate", "uart_root", MXC_CCM_CCGR1, 16); + clk[i2c1_gate] = imx_clk_gate2("i2c1_gate", "per_root", MXC_CCM_CCGR1, 18); + clk[i2c2_gate] = imx_clk_gate2("i2c2_gate", "per_root", MXC_CCM_CCGR1, 20); + clk[gpt_ipg_gate] = imx_clk_gate2("gpt_ipg_gate", "ipg", MXC_CCM_CCGR2, 20); + clk[pwm1_ipg_gate] = imx_clk_gate2("pwm1_ipg_gate", "ipg", MXC_CCM_CCGR2, 10); + clk[pwm1_hf_gate] = imx_clk_gate2("pwm1_hf_gate", "ipg", MXC_CCM_CCGR2, 12); + clk[pwm2_ipg_gate] = imx_clk_gate2("pwm2_ipg_gate", "ipg", MXC_CCM_CCGR2, 14); + clk[pwm2_hf_gate] = imx_clk_gate2("pwm2_hf_gate", "ipg", MXC_CCM_CCGR2, 16); + clk[gpt_gate] = imx_clk_gate2("gpt_gate", "ipg", MXC_CCM_CCGR2, 18); + clk[fec_gate] = imx_clk_gate2("fec_gate", "ipg", MXC_CCM_CCGR2, 24); + clk[usboh3_gate] = imx_clk_gate2("usboh3_gate", "ipg", MXC_CCM_CCGR2, 26); + clk[usboh3_per_gate] = imx_clk_gate2("usboh3_per_gate", "usboh3_podf", MXC_CCM_CCGR2, 28); + clk[esdhc1_ipg_gate] = imx_clk_gate2("esdhc1_ipg_gate", "ipg", MXC_CCM_CCGR3, 0); + clk[esdhc2_ipg_gate] = imx_clk_gate2("esdhc2_ipg_gate", "ipg", MXC_CCM_CCGR3, 4); + clk[esdhc3_ipg_gate] = imx_clk_gate2("esdhc3_ipg_gate", "ipg", MXC_CCM_CCGR3, 8); + clk[esdhc4_ipg_gate] = imx_clk_gate2("esdhc4_ipg_gate", "ipg", MXC_CCM_CCGR3, 12); + clk[ssi1_ipg_gate] = imx_clk_gate2("ssi1_ipg_gate", "ipg", MXC_CCM_CCGR3, 16); + clk[ssi2_ipg_gate] = imx_clk_gate2("ssi2_ipg_gate", "ipg", MXC_CCM_CCGR3, 20); + clk[ssi3_ipg_gate] = imx_clk_gate2("ssi3_ipg_gate", "ipg", MXC_CCM_CCGR3, 24); + clk[ecspi1_ipg_gate] = imx_clk_gate2("ecspi1_ipg_gate", "ipg", MXC_CCM_CCGR4, 18); + clk[ecspi1_per_gate] = imx_clk_gate2("ecspi1_per_gate", "ecspi_podf", MXC_CCM_CCGR4, 20); + clk[ecspi2_ipg_gate] = imx_clk_gate2("ecspi2_ipg_gate", "ipg", MXC_CCM_CCGR4, 22); + clk[ecspi2_per_gate] = imx_clk_gate2("ecspi2_per_gate", "ecspi_podf", MXC_CCM_CCGR4, 24); + clk[cspi_ipg_gate] = imx_clk_gate2("cspi_ipg_gate", "ipg", MXC_CCM_CCGR4, 26); + clk[sdma_gate] = imx_clk_gate2("sdma_gate", "ipg", MXC_CCM_CCGR4, 30); + clk[emi_fast_gate] = imx_clk_gate2("emi_fast_gate", "dummy", MXC_CCM_CCGR5, 14); + clk[emi_slow_gate] = imx_clk_gate2("emi_slow_gate", "emi_slow_podf", MXC_CCM_CCGR5, 16); + clk[ipu_s] = imx_clk_mux("ipu_sel", MXC_CCM_CBCMR, 6, 2, ipu_sel, ARRAY_SIZE(ipu_sel)); + clk[ipu_gate] = imx_clk_gate2("ipu_gate", "ipu_sel", MXC_CCM_CCGR5, 10); + clk[nfc_gate] = imx_clk_gate2("nfc_gate", "nfc_podf", MXC_CCM_CCGR5, 20); + clk[ipu_di0_gate] = imx_clk_gate2("ipu_di0_gate", "ipu_di0_sel", MXC_CCM_CCGR6, 10); + clk[ipu_di1_gate] = imx_clk_gate2("ipu_di1_gate", "ipu_di1_sel", MXC_CCM_CCGR6, 12); + clk[vpu_s] = imx_clk_mux("vpu_sel", MXC_CCM_CBCMR, 14, 2, vpu_sel, ARRAY_SIZE(vpu_sel)); + clk[vpu_gate] = imx_clk_gate2("vpu_gate", "vpu_sel", MXC_CCM_CCGR5, 6); + clk[vpu_reference_gate] = imx_clk_gate2("vpu_reference_gate", "osc", MXC_CCM_CCGR5, 8); + clk[uart4_ipg_gate] = imx_clk_gate2("uart4_ipg_gate", "ipg", MXC_CCM_CCGR7, 8); + clk[uart4_per_gate] = imx_clk_gate2("uart4_per_gate", "uart_root", MXC_CCM_CCGR7, 10); + clk[uart5_ipg_gate] = imx_clk_gate2("uart5_ipg_gate", "ipg", MXC_CCM_CCGR7, 12); + clk[uart5_per_gate] = imx_clk_gate2("uart5_per_gate", "uart_root", MXC_CCM_CCGR7, 14); + clk[gpc_dvfs] = imx_clk_gate2("gpc_dvfs", "dummy", MXC_CCM_CCGR5, 24); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX5 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0"); + clk_register_clkdev(clk[gpt_ipg_gate], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[uart1_per_gate], "per", "imx21-uart.0"); + clk_register_clkdev(clk[uart1_ipg_gate], "ipg", "imx21-uart.0"); + clk_register_clkdev(clk[uart2_per_gate], "per", "imx21-uart.1"); + clk_register_clkdev(clk[uart2_ipg_gate], "ipg", "imx21-uart.1"); + clk_register_clkdev(clk[uart3_per_gate], "per", "imx21-uart.2"); + clk_register_clkdev(clk[uart3_ipg_gate], "ipg", "imx21-uart.2"); + clk_register_clkdev(clk[uart4_per_gate], "per", "imx21-uart.3"); + clk_register_clkdev(clk[uart4_ipg_gate], "ipg", "imx21-uart.3"); + clk_register_clkdev(clk[uart5_per_gate], "per", "imx21-uart.4"); + clk_register_clkdev(clk[uart5_ipg_gate], "ipg", "imx21-uart.4"); + clk_register_clkdev(clk[ecspi1_per_gate], "per", "imx51-ecspi.0"); + clk_register_clkdev(clk[ecspi1_ipg_gate], "ipg", "imx51-ecspi.0"); + clk_register_clkdev(clk[ecspi2_per_gate], "per", "imx51-ecspi.1"); + clk_register_clkdev(clk[ecspi2_ipg_gate], "ipg", "imx51-ecspi.1"); + clk_register_clkdev(clk[cspi_ipg_gate], NULL, "imx51-cspi.0"); + clk_register_clkdev(clk[pwm1_ipg_gate], "pwm", "mxc_pwm.0"); + clk_register_clkdev(clk[pwm2_ipg_gate], "pwm", "mxc_pwm.1"); + clk_register_clkdev(clk[i2c1_gate], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[i2c2_gate], NULL, "imx-i2c.1"); + clk_register_clkdev(clk[usboh3_per_gate], "per", "mxc-ehci.0"); + clk_register_clkdev(clk[usboh3_gate], "ipg", "mxc-ehci.0"); + clk_register_clkdev(clk[usboh3_gate], "ahb", "mxc-ehci.0"); + clk_register_clkdev(clk[usboh3_per_gate], "per", "mxc-ehci.1"); + clk_register_clkdev(clk[usboh3_gate], "ipg", "mxc-ehci.1"); + clk_register_clkdev(clk[usboh3_gate], "ahb", "mxc-ehci.1"); + clk_register_clkdev(clk[usboh3_per_gate], "per", "mxc-ehci.2"); + clk_register_clkdev(clk[usboh3_gate], "ipg", "mxc-ehci.2"); + clk_register_clkdev(clk[usboh3_gate], "ahb", "mxc-ehci.2"); + clk_register_clkdev(clk[usboh3_per_gate], "per", "fsl-usb2-udc"); + clk_register_clkdev(clk[usboh3_gate], "ipg", "fsl-usb2-udc"); + clk_register_clkdev(clk[usboh3_gate], "ahb", "fsl-usb2-udc"); + clk_register_clkdev(clk[nfc_gate], NULL, "mxc_nand"); + clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "imx-ssi.0"); + clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "imx-ssi.1"); + clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "imx-ssi.2"); + clk_register_clkdev(clk[sdma_gate], NULL, "imx35-sdma"); + clk_register_clkdev(clk[cpu_podf], "cpu", NULL); + clk_register_clkdev(clk[iim_gate], "iim", NULL); + clk_register_clkdev(clk[dummy], NULL, "imx2-wdt.0"); + clk_register_clkdev(clk[dummy], NULL, "imx2-wdt.1"); + clk_register_clkdev(clk[dummy], NULL, "imx-keypad"); + clk_register_clkdev(clk[tve_gate], NULL, "imx-tve.0"); + clk_register_clkdev(clk[ipu_di1_gate], "di1", "imx-tve.0"); + + /* Set SDHC parents to be PLL2 */ + clk_set_parent(clk[esdhc_a_sel], clk[pll2_sw]); + clk_set_parent(clk[esdhc_b_sel], clk[pll2_sw]); + + /* move usb phy clk to 24MHz */ + clk_set_parent(clk[usb_phy_sel], clk[osc]); + + clk_prepare_enable(clk[gpc_dvfs]); + clk_prepare_enable(clk[ahb_max]); /* esdhc3 */ + clk_prepare_enable(clk[aips_tz1]); + clk_prepare_enable(clk[aips_tz2]); /* fec */ + clk_prepare_enable(clk[spba]); + clk_prepare_enable(clk[emi_fast_gate]); /* fec */ + clk_prepare_enable(clk[tmax1]); + clk_prepare_enable(clk[tmax2]); /* esdhc2, fec */ + clk_prepare_enable(clk[tmax3]); /* esdhc1, esdhc4 */ +} + +int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc, + unsigned long rate_ckih1, unsigned long rate_ckih2) +{ + int i; + + clk[pll1_sw] = imx_clk_pllv2("pll1_sw", "osc", MX51_DPLL1_BASE); + clk[pll2_sw] = imx_clk_pllv2("pll2_sw", "osc", MX51_DPLL2_BASE); + clk[pll3_sw] = imx_clk_pllv2("pll3_sw", "osc", MX51_DPLL3_BASE); + clk[ipu_di0_sel] = imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3, + mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel)); + clk[ipu_di1_sel] = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3, + mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel)); + clk[tve_ext_sel] = imx_clk_mux("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1, + mx51_tve_ext_sel, ARRAY_SIZE(mx51_tve_ext_sel)); + clk[tve_gate] = imx_clk_gate2("tve_gate", "tve_sel", MXC_CCM_CCGR2, 30); + clk[tve_pred] = imx_clk_divider("tve_pred", "pll3_sw", MXC_CCM_CDCDR, 28, 3); + clk[esdhc1_per_gate] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2); + clk[esdhc2_per_gate] = imx_clk_gate2("esdhc2_per_gate", "esdhc_b_podf", MXC_CCM_CCGR3, 6); + clk[esdhc3_per_gate] = imx_clk_gate2("esdhc3_per_gate", "esdhc_c_sel", MXC_CCM_CCGR3, 10); + clk[esdhc4_per_gate] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14); + clk[usb_phy_gate] = imx_clk_gate2("usb_phy_gate", "usb_phy_sel", MXC_CCM_CCGR2, 0); + clk[hsi2c_gate] = imx_clk_gate2("hsi2c_gate", "ipg", MXC_CCM_CCGR1, 22); + clk[mipi_hsc1_gate] = imx_clk_gate2("mipi_hsc1_gate", "ipg", MXC_CCM_CCGR4, 6); + clk[mipi_hsc2_gate] = imx_clk_gate2("mipi_hsc2_gate", "ipg", MXC_CCM_CCGR4, 8); + clk[mipi_esc_gate] = imx_clk_gate2("mipi_esc_gate", "ipg", MXC_CCM_CCGR4, 10); + clk[mipi_hsp_gate] = imx_clk_gate2("mipi_hsp_gate", "ipg", MXC_CCM_CCGR4, 12); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX51 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + mx5_clocks_common_init(rate_ckil, rate_osc, rate_ckih1, rate_ckih2); + + clk_register_clkdev(clk[hsi2c_gate], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[mx51_mipi], "mipi_hsp", NULL); + clk_register_clkdev(clk[vpu_gate], NULL, "imx51-vpu.0"); + clk_register_clkdev(clk[fec_gate], NULL, "imx27-fec.0"); + clk_register_clkdev(clk[gpc_dvfs], "gpc_dvfs", NULL); + clk_register_clkdev(clk[ipu_gate], "bus", "imx51-ipu"); + clk_register_clkdev(clk[ipu_di0_gate], "di0", "imx51-ipu"); + clk_register_clkdev(clk[ipu_di1_gate], "di1", "imx51-ipu"); + clk_register_clkdev(clk[ipu_gate], "hsp", "imx51-ipu"); + clk_register_clkdev(clk[usb_phy_gate], "phy", "mxc-ehci.0"); + clk_register_clkdev(clk[esdhc1_ipg_gate], "ipg", "sdhci-esdhc-imx51.0"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx51.0"); + clk_register_clkdev(clk[esdhc1_per_gate], "per", "sdhci-esdhc-imx51.0"); + clk_register_clkdev(clk[esdhc2_ipg_gate], "ipg", "sdhci-esdhc-imx51.1"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx51.1"); + clk_register_clkdev(clk[esdhc2_per_gate], "per", "sdhci-esdhc-imx51.1"); + clk_register_clkdev(clk[esdhc3_ipg_gate], "ipg", "sdhci-esdhc-imx51.2"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx51.2"); + clk_register_clkdev(clk[esdhc3_per_gate], "per", "sdhci-esdhc-imx51.2"); + clk_register_clkdev(clk[esdhc4_ipg_gate], "ipg", "sdhci-esdhc-imx51.3"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx51.3"); + clk_register_clkdev(clk[esdhc4_per_gate], "per", "sdhci-esdhc-imx51.3"); + + /* set the usboh3 parent to pll2_sw */ + clk_set_parent(clk[usboh3_sel], clk[pll2_sw]); + + /* set SDHC root clock to 166.25MHZ*/ + clk_set_rate(clk[esdhc_a_podf], 166250000); + clk_set_rate(clk[esdhc_b_podf], 166250000); + + /* System timer */ + mxc_timer_init(NULL, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR), + MX51_INT_GPT); + + clk_prepare_enable(clk[iim_gate]); + imx_print_silicon_rev("i.MX51", mx51_revision()); + clk_disable_unprepare(clk[iim_gate]); + + return 0; +} + +int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc, + unsigned long rate_ckih1, unsigned long rate_ckih2) +{ + int i; + unsigned long r; + + clk[pll1_sw] = imx_clk_pllv2("pll1_sw", "osc", MX53_DPLL1_BASE); + clk[pll2_sw] = imx_clk_pllv2("pll2_sw", "osc", MX53_DPLL2_BASE); + clk[pll3_sw] = imx_clk_pllv2("pll3_sw", "osc", MX53_DPLL3_BASE); + clk[pll4_sw] = imx_clk_pllv2("pll4_sw", "osc", MX53_DPLL4_BASE); + + clk[ldb_di1_sel] = imx_clk_mux("ldb_di1_sel", MXC_CCM_CSCMR2, 9, 1, + mx53_ldb_di1_sel, ARRAY_SIZE(mx53_ldb_di1_sel)); + clk[ldb_di1_div_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); + clk[ldb_di1_div] = imx_clk_divider("ldb_di1_div", "ldb_di1_div_3_5", MXC_CCM_CSCMR2, 11, 1); + clk[di_pll4_podf] = imx_clk_divider("di_pll4_podf", "pll4_sw", MXC_CCM_CDCDR, 16, 3); + clk[ldb_di0_sel] = imx_clk_mux("ldb_di0_sel", MXC_CCM_CSCMR2, 8, 1, + mx53_ldb_di0_sel, ARRAY_SIZE(mx53_ldb_di0_sel)); + clk[ldb_di0_div_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); + clk[ldb_di0_div] = imx_clk_divider("ldb_di0_div", "ldb_di0_div_3_5", MXC_CCM_CSCMR2, 10, 1); + clk[ldb_di0_gate] = imx_clk_gate2("ldb_di0_gate", "ldb_di0_div", MXC_CCM_CCGR6, 28); + clk[ldb_di1_gate] = imx_clk_gate2("ldb_di1_gate", "ldb_di1_div", MXC_CCM_CCGR6, 30); + clk[ipu_di0_sel] = imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3, + mx53_ipu_di0_sel, ARRAY_SIZE(mx53_ipu_di0_sel)); + clk[ipu_di1_sel] = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3, + mx53_ipu_di1_sel, ARRAY_SIZE(mx53_ipu_di1_sel)); + clk[tve_ext_sel] = imx_clk_mux("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1, + mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel)); + clk[tve_gate] = imx_clk_gate2("tve_gate", "tve_pred", MXC_CCM_CCGR2, 30); + clk[tve_pred] = imx_clk_divider("tve_pred", "tve_ext_sel", MXC_CCM_CDCDR, 28, 3); + clk[esdhc1_per_gate] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2); + clk[esdhc2_per_gate] = imx_clk_gate2("esdhc2_per_gate", "esdhc_c_sel", MXC_CCM_CCGR3, 6); + clk[esdhc3_per_gate] = imx_clk_gate2("esdhc3_per_gate", "esdhc_b_podf", MXC_CCM_CCGR3, 10); + clk[esdhc4_per_gate] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14); + clk[usb_phy1_gate] = imx_clk_gate2("usb_phy1_gate", "usb_phy_sel", MXC_CCM_CCGR4, 10); + clk[usb_phy2_gate] = imx_clk_gate2("usb_phy2_gate", "usb_phy_sel", MXC_CCM_CCGR4, 12); + clk[can2_serial_gate] = imx_clk_gate2("can2_serial_gate", "ipg", MXC_CCM_CCGR4, 6); + clk[can2_ipg_gate] = imx_clk_gate2("can2_ipg_gate", "ipg", MXC_CCM_CCGR4, 8); + clk[i2c3_gate] = imx_clk_gate2("i2c3_gate", "per_root", MXC_CCM_CCGR1, 22); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX53 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + mx5_clocks_common_init(rate_ckil, rate_osc, rate_ckih1, rate_ckih2); + + clk_register_clkdev(clk[vpu_gate], NULL, "imx53-vpu.0"); + clk_register_clkdev(clk[i2c3_gate], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[fec_gate], NULL, "imx25-fec.0"); + clk_register_clkdev(clk[ipu_gate], "bus", "imx53-ipu"); + clk_register_clkdev(clk[ipu_di0_gate], "di0", "imx53-ipu"); + clk_register_clkdev(clk[ipu_di1_gate], "di1", "imx53-ipu"); + clk_register_clkdev(clk[ipu_gate], "hsp", "imx53-ipu"); + clk_register_clkdev(clk[usb_phy1_gate], "usb_phy1", "mxc-ehci.0"); + clk_register_clkdev(clk[esdhc1_ipg_gate], "ipg", "sdhci-esdhc-imx53.0"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx53.0"); + clk_register_clkdev(clk[esdhc1_per_gate], "per", "sdhci-esdhc-imx53.0"); + clk_register_clkdev(clk[esdhc2_ipg_gate], "ipg", "sdhci-esdhc-imx53.1"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx53.1"); + clk_register_clkdev(clk[esdhc2_per_gate], "per", "sdhci-esdhc-imx53.1"); + clk_register_clkdev(clk[esdhc3_ipg_gate], "ipg", "sdhci-esdhc-imx53.2"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx53.2"); + clk_register_clkdev(clk[esdhc3_per_gate], "per", "sdhci-esdhc-imx53.2"); + clk_register_clkdev(clk[esdhc4_ipg_gate], "ipg", "sdhci-esdhc-imx53.3"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx53.3"); + clk_register_clkdev(clk[esdhc4_per_gate], "per", "sdhci-esdhc-imx53.3"); + + /* set SDHC root clock to 200MHZ*/ + clk_set_rate(clk[esdhc_a_podf], 200000000); + clk_set_rate(clk[esdhc_b_podf], 200000000); + + /* System timer */ + mxc_timer_init(NULL, MX53_IO_ADDRESS(MX53_GPT1_BASE_ADDR), + MX53_INT_GPT); + + clk_prepare_enable(clk[iim_gate]); + imx_print_silicon_rev("i.MX53", mx53_revision()); + clk_disable_unprepare(clk[iim_gate]); + + r = clk_round_rate(clk[usboh3_per_gate], 54000000); + clk_set_rate(clk[usboh3_per_gate], r); + + return 0; +} + +#ifdef CONFIG_OF +static void __init clk_get_freq_dt(unsigned long *ckil, unsigned long *osc, + unsigned long *ckih1, unsigned long *ckih2) +{ + struct device_node *np; + + /* retrieve the freqency of fixed clocks from device tree */ + for_each_compatible_node(np, NULL, "fixed-clock") { + u32 rate; + if (of_property_read_u32(np, "clock-frequency", &rate)) + continue; + + if (of_device_is_compatible(np, "fsl,imx-ckil")) + *ckil = rate; + else if (of_device_is_compatible(np, "fsl,imx-osc")) + *osc = rate; + else if (of_device_is_compatible(np, "fsl,imx-ckih1")) + *ckih1 = rate; + else if (of_device_is_compatible(np, "fsl,imx-ckih2")) + *ckih2 = rate; + } +} + +int __init mx51_clocks_init_dt(void) +{ + unsigned long ckil, osc, ckih1, ckih2; + + clk_get_freq_dt(&ckil, &osc, &ckih1, &ckih2); + return mx51_clocks_init(ckil, osc, ckih1, ckih2); +} + +int __init mx53_clocks_init_dt(void) +{ + unsigned long ckil, osc, ckih1, ckih2; + + clk_get_freq_dt(&ckil, &osc, &ckih1, &ckih2); + return mx53_clocks_init(ckil, osc, ckih1, ckih2); +} +#endif diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c new file mode 100644 index 000000000000..f40a35da2e5c --- /dev/null +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -0,0 +1,439 @@ +/* + * 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 <linux/init.h> +#include <linux/types.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <mach/common.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 void __iomem *ccm_base; + +void __init imx6q_clock_map_io(void) { } + +int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) +{ + u32 val = readl_relaxed(ccm_base + CLPCR); + + val &= ~BM_CLPCR_LPM; + switch (mode) { + case WAIT_CLOCKED: + break; + case WAIT_UNCLOCKED: + val |= 0x1 << BP_CLPCR_LPM; + break; + case STOP_POWER_ON: + val |= 0x2 << BP_CLPCR_LPM; + break; + case WAIT_UNCLOCKED_POWER_OFF: + val |= 0x1 << BP_CLPCR_LPM; + val &= ~BM_CLPCR_VSTBY; + val &= ~BM_CLPCR_SBYOS; + break; + case STOP_POWER_OFF: + val |= 0x2 << BP_CLPCR_LPM; + val |= 0x3 << BP_CLPCR_STBY_COUNT; + val |= BM_CLPCR_VSTBY; + val |= BM_CLPCR_SBYOS; + break; + default: + return -EINVAL; + } + + writel_relaxed(val, ccm_base + CLPCR); + + return 0; +} + +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 *audio_sels[] = { "pll4_audio", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", }; +static const char *gpu_axi_sels[] = { "axi", "ahb", }; +static const char *gpu2d_core_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", }; +static const char *gpu3d_core_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll2_pfd2_396m", }; +static const char *gpu3d_shader_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll2_pfd9_720m", }; +static const char *ipu_sels[] = { "mmdc_ch0_axi", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", }; +static const char *ldb_di_sels[] = { "pll5_video", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", }; +static const char *ipu_di_pre_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll5_video", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", }; +static const char *ipu1_di0_sels[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; +static const char *ipu1_di1_sels[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; +static const char *ipu2_di0_sels[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; +static const char *ipu2_di1_sels[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; +static const char *hsi_tx_sels[] = { "pll3_120m", "pll2_pfd2_396m", }; +static const char *pcie_axi_sels[] = { "axi", "ahb", }; +static const char *ssi_sels[] = { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_audio", }; +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 *emi_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *vdo_axi_sels[] = { "axi", "ahb", }; +static const char *vpu_axi_sels[] = { "axi", "pll2_pfd2_396m", "pll2_pfd0_352m", }; +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 * const clks_init_on[] __initconst = { + "mmdc_ch0_axi", "mmdc_ch1_axi", "usboh3", +}; + +enum mx6q_clks { + dummy, ckil, ckih, osc, pll2_pfd0_352m, pll2_pfd1_594m, pll2_pfd2_396m, + pll3_pfd0_720m, pll3_pfd1_540m, pll3_pfd2_508m, pll3_pfd3_454m, + pll2_198m, pll3_120m, pll3_80m, pll3_60m, twd, step, pll1_sw, + periph_pre, periph2_pre, periph_clk2_sel, periph2_clk2_sel, axi_sel, + esai_sel, asrc_sel, spdif_sel, gpu2d_axi, gpu3d_axi, gpu2d_core_sel, + gpu3d_core_sel, gpu3d_shader_sel, ipu1_sel, ipu2_sel, ldb_di0_sel, + ldb_di1_sel, ipu1_di0_pre_sel, ipu1_di1_pre_sel, ipu2_di0_pre_sel, + ipu2_di1_pre_sel, ipu1_di0_sel, ipu1_di1_sel, ipu2_di0_sel, + ipu2_di1_sel, hsi_tx_sel, pcie_axi_sel, ssi1_sel, ssi2_sel, ssi3_sel, + usdhc1_sel, usdhc2_sel, usdhc3_sel, usdhc4_sel, enfc_sel, emi_sel, + emi_slow_sel, vdo_axi_sel, vpu_axi_sel, cko1_sel, periph, periph2, + periph_clk2, periph2_clk2, ipg, ipg_per, esai_pred, esai_podf, + asrc_pred, asrc_podf, spdif_pred, spdif_podf, can_root, ecspi_root, + gpu2d_core_podf, gpu3d_core_podf, gpu3d_shader, ipu1_podf, ipu2_podf, + ldb_di0_podf, ldb_di1_podf, ipu1_di0_pre, ipu1_di1_pre, ipu2_di0_pre, + ipu2_di1_pre, hsi_tx_podf, ssi1_pred, ssi1_podf, ssi2_pred, ssi2_podf, + ssi3_pred, ssi3_podf, uart_serial_podf, usdhc1_podf, usdhc2_podf, + usdhc3_podf, usdhc4_podf, enfc_pred, enfc_podf, emi_podf, + emi_slow_podf, vpu_axi_podf, cko1_podf, axi, mmdc_ch0_axi_podf, + mmdc_ch1_axi_podf, arm, ahb, apbh_dma, asrc, can1_ipg, can1_serial, + can2_ipg, can2_serial, ecspi1, ecspi2, ecspi3, ecspi4, ecspi5, enet, + esai, gpt_ipg, gpt_ipg_per, gpu2d_core, gpu3d_core, hdmi_iahb, + hdmi_isfr, i2c1, i2c2, i2c3, iim, enfc, ipu1, ipu1_di0, ipu1_di1, ipu2, + ipu2_di0, ldb_di0, ldb_di1, ipu2_di1, hsi_tx, mlb, mmdc_ch0_axi, + mmdc_ch1_axi, ocram, openvg_axi, pcie_axi, pwm1, pwm2, pwm3, pwm4, + gpmi_bch_apb, gpmi_bch, gpmi_io, gpmi_apb, sata, sdma, spba, ssi1, + ssi2, ssi3, uart_ipg, uart_serial, usboh3, usdhc1, usdhc2, usdhc3, + usdhc4, vdo_axi, vpu_axi, cko1, pll1_sys, pll2_bus, pll3_usb_otg, + pll4_audio, pll5_video, pll6_mlb, pll7_usb_host, pll8_enet, clk_max +}; + +static struct clk *clk[clk_max]; + +int __init mx6q_clocks_init(void) +{ + struct device_node *np; + void __iomem *base; + struct clk *c; + int i, irq; + + clk[dummy] = imx_clk_fixed("dummy", 0); + + /* retrieve the freqency of fixed clocks from device tree */ + for_each_compatible_node(np, NULL, "fixed-clock") { + u32 rate; + if (of_property_read_u32(np, "clock-frequency", &rate)) + continue; + + if (of_device_is_compatible(np, "fsl,imx-ckil")) + clk[ckil] = imx_clk_fixed("ckil", rate); + else if (of_device_is_compatible(np, "fsl,imx-ckih1")) + clk[ckih] = imx_clk_fixed("ckih", rate); + else if (of_device_is_compatible(np, "fsl,imx-osc")) + clk[osc] = imx_clk_fixed("osc", rate); + } + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); + base = of_iomap(np, 0); + WARN_ON(!base); + + /* type name parent_name base gate_mask div_mask */ + clk[pll1_sys] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x2000, 0x7f); + clk[pll2_bus] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc", base + 0x30, 0x2000, 0x1); + clk[pll3_usb_otg] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc", base + 0x10, 0x2000, 0x3); + clk[pll4_audio] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4_audio", "osc", base + 0x70, 0x2000, 0x7f); + clk[pll5_video] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "osc", base + 0xa0, 0x2000, 0x7f); + clk[pll6_mlb] = imx_clk_pllv3(IMX_PLLV3_MLB, "pll6_mlb", "osc", base + 0xd0, 0x2000, 0x0); + clk[pll7_usb_host] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_usb_host","osc", base + 0x20, 0x2000, 0x3); + clk[pll8_enet] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll8_enet", "osc", base + 0xe0, 0x182000, 0x3); + + /* name parent_name reg idx */ + clk[pll2_pfd0_352m] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); + clk[pll2_pfd1_594m] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); + clk[pll2_pfd2_396m] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2); + clk[pll3_pfd0_720m] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0); + clk[pll3_pfd1_540m] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1); + clk[pll3_pfd2_508m] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2); + clk[pll3_pfd3_454m] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3); + + /* name parent_name mult div */ + clk[pll2_198m] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2); + clk[pll3_120m] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4); + clk[pll3_80m] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); + clk[pll3_60m] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); + clk[twd] = imx_clk_fixed_factor("twd", "arm", 1, 2); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ccm"); + base = of_iomap(np, 0); + WARN_ON(!base); + ccm_base = base; + + /* name reg shift width parent_names num_parents */ + clk[step] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); + clk[pll1_sw] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); + clk[periph_pre] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); + clk[periph2_pre] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); + clk[periph_clk2_sel] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 1, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); + clk[periph2_clk2_sel] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); + clk[axi_sel] = imx_clk_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_sels)); + clk[esai_sel] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels)); + clk[asrc_sel] = imx_clk_mux("asrc_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels)); + clk[spdif_sel] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels)); + clk[gpu2d_axi] = imx_clk_mux("gpu2d_axi", base + 0x18, 0, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); + clk[gpu3d_axi] = imx_clk_mux("gpu3d_axi", base + 0x18, 1, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); + clk[gpu2d_core_sel] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels)); + clk[gpu3d_core_sel] = imx_clk_mux("gpu3d_core_sel", base + 0x18, 4, 2, gpu3d_core_sels, ARRAY_SIZE(gpu3d_core_sels)); + clk[gpu3d_shader_sel] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels)); + clk[ipu1_sel] = imx_clk_mux("ipu1_sel", base + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); + clk[ipu2_sel] = imx_clk_mux("ipu2_sel", base + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); + clk[ldb_di0_sel] = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); + clk[ldb_di1_sel] = imx_clk_mux("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); + clk[ipu1_di0_pre_sel] = imx_clk_mux("ipu1_di0_pre_sel", base + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clk[ipu1_di1_pre_sel] = imx_clk_mux("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clk[ipu2_di0_pre_sel] = imx_clk_mux("ipu2_di0_pre_sel", base + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clk[ipu2_di1_pre_sel] = imx_clk_mux("ipu2_di1_pre_sel", base + 0x38, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clk[ipu1_di0_sel] = imx_clk_mux("ipu1_di0_sel", base + 0x34, 0, 3, ipu1_di0_sels, ARRAY_SIZE(ipu1_di0_sels)); + clk[ipu1_di1_sel] = imx_clk_mux("ipu1_di1_sel", base + 0x34, 9, 3, ipu1_di1_sels, ARRAY_SIZE(ipu1_di1_sels)); + clk[ipu2_di0_sel] = imx_clk_mux("ipu2_di0_sel", base + 0x38, 0, 3, ipu2_di0_sels, ARRAY_SIZE(ipu2_di0_sels)); + clk[ipu2_di1_sel] = imx_clk_mux("ipu2_di1_sel", base + 0x38, 9, 3, ipu2_di1_sels, ARRAY_SIZE(ipu2_di1_sels)); + clk[hsi_tx_sel] = imx_clk_mux("hsi_tx_sel", base + 0x30, 28, 1, hsi_tx_sels, ARRAY_SIZE(hsi_tx_sels)); + clk[pcie_axi_sel] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels)); + clk[ssi1_sel] = imx_clk_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); + clk[ssi2_sel] = imx_clk_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); + clk[ssi3_sel] = imx_clk_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); + clk[usdhc1_sel] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clk[usdhc2_sel] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clk[usdhc3_sel] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clk[usdhc4_sel] = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clk[enfc_sel] = imx_clk_mux("enfc_sel", base + 0x2c, 16, 2, enfc_sels, ARRAY_SIZE(enfc_sels)); + clk[emi_sel] = imx_clk_mux("emi_sel", base + 0x1c, 27, 2, emi_sels, ARRAY_SIZE(emi_sels)); + clk[emi_slow_sel] = imx_clk_mux("emi_slow_sel", base + 0x1c, 29, 2, emi_sels, ARRAY_SIZE(emi_sels)); + clk[vdo_axi_sel] = imx_clk_mux("vdo_axi_sel", base + 0x18, 11, 1, vdo_axi_sels, ARRAY_SIZE(vdo_axi_sels)); + clk[vpu_axi_sel] = imx_clk_mux("vpu_axi_sel", base + 0x18, 14, 2, vpu_axi_sels, ARRAY_SIZE(vpu_axi_sels)); + clk[cko1_sel] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels)); + + /* name reg shift width busy: reg, shift parent_names num_parents */ + clk[periph] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); + 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 */ + clk[periph_clk2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); + clk[periph2_clk2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); + clk[ipg] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); + clk[ipg_per] = imx_clk_divider("ipg_per", "ipg", base + 0x1c, 0, 6); + clk[esai_pred] = imx_clk_divider("esai_pred", "esai_sel", base + 0x28, 9, 3); + clk[esai_podf] = imx_clk_divider("esai_podf", "esai_pred", base + 0x28, 25, 3); + clk[asrc_pred] = imx_clk_divider("asrc_pred", "asrc_sel", base + 0x30, 12, 3); + clk[asrc_podf] = imx_clk_divider("asrc_podf", "asrc_pred", base + 0x30, 9, 3); + clk[spdif_pred] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3); + clk[spdif_podf] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3); + clk[can_root] = imx_clk_divider("can_root", "pll3_usb_otg", base + 0x20, 2, 6); + clk[ecspi_root] = imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6); + clk[gpu2d_core_podf] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 23, 3); + clk[gpu3d_core_podf] = imx_clk_divider("gpu3d_core_podf", "gpu3d_core_sel", base + 0x18, 26, 3); + clk[gpu3d_shader] = imx_clk_divider("gpu3d_shader", "gpu3d_shader_sel", base + 0x18, 29, 3); + clk[ipu1_podf] = imx_clk_divider("ipu1_podf", "ipu1_sel", base + 0x3c, 11, 3); + clk[ipu2_podf] = imx_clk_divider("ipu2_podf", "ipu2_sel", base + 0x3c, 16, 3); + clk[ldb_di0_podf] = imx_clk_divider("ldb_di0_podf", "ldb_di0_sel", base + 0x20, 10, 1); + clk[ldb_di1_podf] = imx_clk_divider("ldb_di1_podf", "ldb_di1_sel", base + 0x20, 11, 1); + clk[ipu1_di0_pre] = imx_clk_divider("ipu1_di0_pre", "ipu1_di0_pre_sel", base + 0x34, 3, 3); + clk[ipu1_di1_pre] = imx_clk_divider("ipu1_di1_pre", "ipu1_di1_pre_sel", base + 0x34, 12, 3); + clk[ipu2_di0_pre] = imx_clk_divider("ipu2_di0_pre", "ipu2_di0_pre_sel", base + 0x38, 3, 3); + clk[ipu2_di1_pre] = imx_clk_divider("ipu2_di1_pre", "ipu2_di1_pre_sel", base + 0x38, 12, 3); + clk[hsi_tx_podf] = imx_clk_divider("hsi_tx_podf", "hsi_tx_sel", base + 0x30, 29, 3); + clk[ssi1_pred] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3); + clk[ssi1_podf] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6); + clk[ssi2_pred] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3); + clk[ssi2_podf] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6); + clk[ssi3_pred] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3); + clk[ssi3_podf] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6); + clk[uart_serial_podf] = imx_clk_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6); + clk[usdhc1_podf] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); + clk[usdhc2_podf] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); + clk[usdhc3_podf] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3); + clk[usdhc4_podf] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3); + clk[enfc_pred] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3); + clk[enfc_podf] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6); + clk[emi_podf] = imx_clk_divider("emi_podf", "emi_sel", base + 0x1c, 20, 3); + clk[emi_slow_podf] = imx_clk_divider("emi_slow_podf", "emi_slow_sel", base + 0x1c, 23, 3); + clk[vpu_axi_podf] = imx_clk_divider("vpu_axi_podf", "vpu_axi_sel", base + 0x24, 25, 3); + clk[cko1_podf] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3); + + /* name parent_name reg shift width busy: reg, shift */ + clk[axi] = imx_clk_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0); + clk[mmdc_ch0_axi_podf] = imx_clk_busy_divider("mmdc_ch0_axi_podf", "periph", base + 0x14, 19, 3, base + 0x48, 4); + clk[mmdc_ch1_axi_podf] = imx_clk_busy_divider("mmdc_ch1_axi_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2); + clk[arm] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); + clk[ahb] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); + + /* name parent_name reg shift */ + clk[apbh_dma] = imx_clk_gate2("apbh_dma", "ahb", base + 0x68, 4); + clk[asrc] = imx_clk_gate2("asrc", "asrc_podf", base + 0x68, 6); + clk[can1_ipg] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14); + clk[can1_serial] = imx_clk_gate2("can1_serial", "can_root", base + 0x68, 16); + clk[can2_ipg] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18); + clk[can2_serial] = imx_clk_gate2("can2_serial", "can_root", base + 0x68, 20); + clk[ecspi1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0); + clk[ecspi2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2); + clk[ecspi3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4); + clk[ecspi4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6); + clk[ecspi5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8); + clk[enet] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10); + clk[esai] = imx_clk_gate2("esai", "esai_podf", base + 0x6c, 16); + clk[gpt_ipg] = imx_clk_gate2("gpt_ipg", "ipg", base + 0x6c, 20); + clk[gpt_ipg_per] = imx_clk_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22); + clk[gpu2d_core] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24); + clk[gpu3d_core] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26); + clk[hdmi_iahb] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0); + clk[hdmi_isfr] = imx_clk_gate2("hdmi_isfr", "pll3_pfd1_540m", base + 0x70, 4); + clk[i2c1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6); + clk[i2c2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8); + clk[i2c3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10); + clk[iim] = imx_clk_gate2("iim", "ipg", base + 0x70, 12); + clk[enfc] = imx_clk_gate2("enfc", "enfc_podf", base + 0x70, 14); + clk[ipu1] = imx_clk_gate2("ipu1", "ipu1_podf", base + 0x74, 0); + clk[ipu1_di0] = imx_clk_gate2("ipu1_di0", "ipu1_di0_sel", base + 0x74, 2); + clk[ipu1_di1] = imx_clk_gate2("ipu1_di1", "ipu1_di1_sel", base + 0x74, 4); + clk[ipu2] = imx_clk_gate2("ipu2", "ipu2_podf", base + 0x74, 6); + clk[ipu2_di0] = imx_clk_gate2("ipu2_di0", "ipu2_di0_sel", base + 0x74, 8); + clk[ldb_di0] = imx_clk_gate2("ldb_di0", "ldb_di0_podf", base + 0x74, 12); + clk[ldb_di1] = imx_clk_gate2("ldb_di1", "ldb_di1_podf", base + 0x74, 14); + clk[ipu2_di1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", base + 0x74, 10); + clk[hsi_tx] = imx_clk_gate2("hsi_tx", "hsi_tx_podf", base + 0x74, 16); + clk[mlb] = imx_clk_gate2("mlb", "pll6_mlb", base + 0x74, 18); + clk[mmdc_ch0_axi] = imx_clk_gate2("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20); + clk[mmdc_ch1_axi] = imx_clk_gate2("mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22); + clk[ocram] = imx_clk_gate2("ocram", "ahb", base + 0x74, 28); + clk[openvg_axi] = imx_clk_gate2("openvg_axi", "axi", base + 0x74, 30); + clk[pcie_axi] = imx_clk_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0); + clk[pwm1] = imx_clk_gate2("pwm1", "ipg_per", base + 0x78, 16); + clk[pwm2] = imx_clk_gate2("pwm2", "ipg_per", base + 0x78, 18); + clk[pwm3] = imx_clk_gate2("pwm3", "ipg_per", base + 0x78, 20); + clk[pwm4] = imx_clk_gate2("pwm4", "ipg_per", base + 0x78, 22); + clk[gpmi_bch_apb] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24); + clk[gpmi_bch] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26); + clk[gpmi_io] = imx_clk_gate2("gpmi_io", "enfc", base + 0x78, 28); + clk[gpmi_apb] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30); + clk[sata] = imx_clk_gate2("sata", "ipg", base + 0x7c, 4); + clk[sdma] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); + clk[spba] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); + clk[ssi1] = imx_clk_gate2("ssi1", "ssi1_podf", base + 0x7c, 18); + clk[ssi2] = imx_clk_gate2("ssi2", "ssi2_podf", base + 0x7c, 20); + clk[ssi3] = imx_clk_gate2("ssi3", "ssi3_podf", base + 0x7c, 22); + clk[uart_ipg] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24); + clk[uart_serial] = imx_clk_gate2("uart_serial", "uart_serial_podf", base + 0x7c, 26); + clk[usboh3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); + clk[usdhc1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); + clk[usdhc2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); + clk[usdhc3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6); + clk[usdhc4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8); + clk[vdo_axi] = imx_clk_gate2("vdo_axi", "vdo_axi_sel", base + 0x80, 12); + clk[vpu_axi] = imx_clk_gate2("vpu_axi", "vpu_axi_podf", base + 0x80, 14); + clk[cko1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX6q clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + clk_register_clkdev(clk[mmdc_ch0_axi], NULL, "mmdc_ch0_axi"); + clk_register_clkdev(clk[mmdc_ch1_axi], NULL, "mmdc_ch1_axi"); + clk_register_clkdev(clk[gpt_ipg], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[gpt_ipg_per], "per", "imx-gpt.0"); + clk_register_clkdev(clk[twd], NULL, "smp_twd"); + clk_register_clkdev(clk[usboh3], NULL, "usboh3"); + clk_register_clkdev(clk[uart_serial], "per", "2020000.uart"); + clk_register_clkdev(clk[uart_ipg], "ipg", "2020000.uart"); + clk_register_clkdev(clk[uart_serial], "per", "21e8000.uart"); + clk_register_clkdev(clk[uart_ipg], "ipg", "21e8000.uart"); + clk_register_clkdev(clk[uart_serial], "per", "21ec000.uart"); + clk_register_clkdev(clk[uart_ipg], "ipg", "21ec000.uart"); + clk_register_clkdev(clk[uart_serial], "per", "21f0000.uart"); + clk_register_clkdev(clk[uart_ipg], "ipg", "21f0000.uart"); + clk_register_clkdev(clk[uart_serial], "per", "21f4000.uart"); + clk_register_clkdev(clk[uart_ipg], "ipg", "21f4000.uart"); + clk_register_clkdev(clk[enet], NULL, "2188000.enet"); + clk_register_clkdev(clk[usdhc1], NULL, "2190000.usdhc"); + clk_register_clkdev(clk[usdhc2], NULL, "2194000.usdhc"); + clk_register_clkdev(clk[usdhc3], NULL, "2198000.usdhc"); + clk_register_clkdev(clk[usdhc4], NULL, "219c000.usdhc"); + clk_register_clkdev(clk[i2c1], NULL, "21a0000.i2c"); + clk_register_clkdev(clk[i2c2], NULL, "21a4000.i2c"); + clk_register_clkdev(clk[i2c3], NULL, "21a8000.i2c"); + clk_register_clkdev(clk[ecspi1], NULL, "2008000.ecspi"); + clk_register_clkdev(clk[ecspi2], NULL, "200c000.ecspi"); + clk_register_clkdev(clk[ecspi3], NULL, "2010000.ecspi"); + clk_register_clkdev(clk[ecspi4], NULL, "2014000.ecspi"); + clk_register_clkdev(clk[ecspi5], NULL, "2018000.ecspi"); + clk_register_clkdev(clk[sdma], NULL, "20ec000.sdma"); + clk_register_clkdev(clk[dummy], NULL, "20bc000.wdog"); + clk_register_clkdev(clk[dummy], NULL, "20c0000.wdog"); + + for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) { + c = clk_get_sys(clks_init_on[i], NULL); + if (IS_ERR(c)) { + pr_err("%s: failed to get clk %s", __func__, + clks_init_on[i]); + return PTR_ERR(c); + } + clk_prepare_enable(c); + } + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); + base = of_iomap(np, 0); + WARN_ON(!base); + irq = irq_of_parse_and_map(np, 0); + mxc_timer_init(NULL, base, irq); + + return 0; +} diff --git a/arch/arm/mach-imx/clk-pfd.c b/arch/arm/mach-imx/clk-pfd.c new file mode 100644 index 000000000000..e2ed4160f329 --- /dev/null +++ b/arch/arm/mach-imx/clk-pfd.c @@ -0,0 +1,147 @@ +/* + * 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 <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/err.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_hw hw; + void __iomem *reg; + u8 idx; +}; + +#define to_clk_pfd(_hw) container_of(_hw, struct clk_pfd, hw) + +#define SET 0x4 +#define CLR 0x8 +#define OTG 0xc + +static int clk_pfd_enable(struct clk_hw *hw) +{ + struct clk_pfd *pfd = to_clk_pfd(hw); + + writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR); + + return 0; +} + +static void clk_pfd_disable(struct clk_hw *hw) +{ + struct clk_pfd *pfd = to_clk_pfd(hw); + + writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET); +} + +static unsigned long clk_pfd_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pfd *pfd = to_clk_pfd(hw); + u64 tmp = parent_rate; + u8 frac = (readl_relaxed(pfd->reg) >> (pfd->idx * 8)) & 0x3f; + + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static long clk_pfd_round_rate(struct clk_hw *hw, 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_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pfd *pfd = to_clk_pfd(hw); + 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_relaxed(0x3f << (pfd->idx * 8), pfd->reg + CLR); + writel_relaxed(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_name, + void __iomem *reg, u8 idx) +{ + struct clk_pfd *pfd; + struct clk *clk; + struct clk_init_data init; + + pfd = kzalloc(sizeof(*pfd), GFP_KERNEL); + if (!pfd) + return ERR_PTR(-ENOMEM); + + pfd->reg = reg; + pfd->idx = idx; + + init.name = name; + init.ops = &clk_pfd_ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + + pfd->hw.init = &init; + + clk = clk_register(NULL, &pfd->hw); + if (IS_ERR(clk)) + kfree(pfd); + + return clk; +} diff --git a/arch/arm/mach-imx/clk-pllv1.c b/arch/arm/mach-imx/clk-pllv1.c new file mode 100644 index 000000000000..2d856f9ccf59 --- /dev/null +++ b/arch/arm/mach-imx/clk-pllv1.c @@ -0,0 +1,66 @@ +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/err.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/clock.h> +#include "clk.h" + +/** + * pll v1 + * + * @clk_hw clock source + * @parent the parent clock name + * @base base address of pll registers + * + * PLL clock version 1, found on i.MX1/21/25/27/31/35 + */ +struct clk_pllv1 { + struct clk_hw hw; + void __iomem *base; +}; + +#define to_clk_pllv1(clk) (container_of(clk, struct clk_pllv1, clk)) + +static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv1 *pll = to_clk_pllv1(hw); + + return mxc_decode_pll(readl(pll->base), parent_rate); +} + +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; + struct clk *clk; + struct clk_init_data init; + + pll = kmalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + pll->base = base; + + init.name = name; + init.ops = &clk_pllv1_ops; + init.flags = 0; + init.parent_names = &parent; + init.num_parents = 1; + + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} diff --git a/arch/arm/mach-imx/clk-pllv2.c b/arch/arm/mach-imx/clk-pllv2.c new file mode 100644 index 000000000000..4685919deb63 --- /dev/null +++ b/arch/arm/mach-imx/clk-pllv2.c @@ -0,0 +1,249 @@ +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/err.h> + +#include <asm/div64.h> + +#include "clk.h" + +#define to_clk_pllv2(clk) (container_of(clk, struct clk_pllv2, clk)) + +/* 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_hw hw; + void __iomem *base; +}; + +static unsigned long clk_pllv2_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + long mfi, mfn, mfd, pdf, ref_clk, mfn_abs; + unsigned long dp_op, dp_mfd, dp_mfn, dp_ctl, pll_hfsm, dbl; + void __iomem *pllbase; + s64 temp; + struct clk_pllv2 *pll = to_clk_pllv2(hw); + + pllbase = pll->base; + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; + dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN; + + if (pll_hfsm == 0) { + 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); + } else { + dp_op = __raw_readl(pllbase + MXC_PLL_DP_HFS_OP); + dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFD); + dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFN); + } + 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 = -temp; + temp = (ref_clk * mfi) + temp; + + return temp; +} + +static int clk_pllv2_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv2 *pll = to_clk_pllv2(hw); + u32 reg; + void __iomem *pllbase; + long mfi, pdf, mfn, mfd = 999999; + s64 temp64; + unsigned long quad_parent_rate; + unsigned long pll_hfsm, dp_ctl; + + pllbase = pll->base; + + 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; + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + /* use dpdck0_2 */ + __raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL); + pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; + if (pll_hfsm == 0) { + reg = mfi << 4 | pdf; + __raw_writel(reg, pllbase + MXC_PLL_DP_OP); + __raw_writel(mfd, pllbase + MXC_PLL_DP_MFD); + __raw_writel(mfn, pllbase + MXC_PLL_DP_MFN); + } else { + reg = mfi << 4 | pdf; + __raw_writel(reg, pllbase + MXC_PLL_DP_HFS_OP); + __raw_writel(mfd, pllbase + MXC_PLL_DP_HFS_MFD); + __raw_writel(mfn, pllbase + MXC_PLL_DP_HFS_MFN); + } + + return 0; +} + +static long clk_pllv2_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + return rate; +} + +static int clk_pllv2_prepare(struct clk_hw *hw) +{ + struct clk_pllv2 *pll = to_clk_pllv2(hw); + u32 reg; + void __iomem *pllbase; + int i = 0; + + pllbase = pll->base; + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) | MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); + + /* Wait for lock */ + do { + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); + if (reg & MXC_PLL_DP_CTL_LRF) + break; + + udelay(1); + } while (++i < MAX_DPLL_WAIT_TRIES); + + if (i == MAX_DPLL_WAIT_TRIES) { + pr_err("MX5: pll locking failed\n"); + return -EINVAL; + } + + return 0; +} + +static void clk_pllv2_unprepare(struct clk_hw *hw) +{ + struct clk_pllv2 *pll = to_clk_pllv2(hw); + u32 reg; + void __iomem *pllbase; + + pllbase = pll->base; + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) & ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); +} + +struct clk_ops clk_pllv2_ops = { + .prepare = clk_pllv2_prepare, + .unprepare = clk_pllv2_unprepare, + .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; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + pll->base = base; + + init.name = name; + init.ops = &clk_pllv2_ops; + init.flags = 0; + init.parent_names = &parent; + init.num_parents = 1; + + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c new file mode 100644 index 000000000000..36aac947bce1 --- /dev/null +++ b/arch/arm/mach-imx/clk-pllv3.c @@ -0,0 +1,419 @@ +/* + * 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 <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/err.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 - IMX PLL clock version 3 + * @clk_hw: clock source + * @base: base address of PLL registers + * @powerup_set: set POWER bit to power up the PLL + * @gate_mask: mask of gate bits + * @div_mask: mask of divider bits + * + * IMX PLL clock version 3, found on i.MX6 series. Divider for pllv3 + * is actually a multiplier, and always sits at bit 0. + */ +struct clk_pllv3 { + struct clk_hw hw; + void __iomem *base; + bool powerup_set; + u32 gate_mask; + u32 div_mask; +}; + +#define to_clk_pllv3(_hw) container_of(_hw, struct clk_pllv3, hw) + +static int clk_pllv3_prepare(struct clk_hw *hw) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + unsigned long timeout = jiffies + msecs_to_jiffies(10); + u32 val; + + val = readl_relaxed(pll->base); + val &= ~BM_PLL_BYPASS; + if (pll->powerup_set) + val |= BM_PLL_POWER; + else + val &= ~BM_PLL_POWER; + writel_relaxed(val, pll->base); + + /* Wait for PLL to lock */ + while (!(readl_relaxed(pll->base) & BM_PLL_LOCK)) + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + + return 0; +} + +static void clk_pllv3_unprepare(struct clk_hw *hw) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 val; + + val = readl_relaxed(pll->base); + val |= BM_PLL_BYPASS; + if (pll->powerup_set) + val &= ~BM_PLL_POWER; + else + val |= BM_PLL_POWER; + writel_relaxed(val, pll->base); +} + +static int clk_pllv3_enable(struct clk_hw *hw) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 val; + + val = readl_relaxed(pll->base); + val |= pll->gate_mask; + writel_relaxed(val, pll->base); + + return 0; +} + +static void clk_pllv3_disable(struct clk_hw *hw) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 val; + + val = readl_relaxed(pll->base); + val &= ~pll->gate_mask; + writel_relaxed(val, pll->base); +} + +static unsigned long clk_pllv3_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 div = readl_relaxed(pll->base) & pll->div_mask; + + return (div == 1) ? parent_rate * 22 : parent_rate * 20; +} + +static long clk_pllv3_round_rate(struct clk_hw *hw, 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_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 val, div; + + if (rate == parent_rate * 22) + div = 1; + else if (rate == parent_rate * 20) + div = 0; + else + return -EINVAL; + + val = readl_relaxed(pll->base); + val &= ~pll->div_mask; + val |= div; + writel_relaxed(val, pll->base); + + return 0; +} + +static const struct clk_ops clk_pllv3_ops = { + .prepare = clk_pllv3_prepare, + .unprepare = clk_pllv3_unprepare, + .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_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 div = readl_relaxed(pll->base) & pll->div_mask; + + return parent_rate * div / 2; +} + +static long clk_pllv3_sys_round_rate(struct clk_hw *hw, 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_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + 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_relaxed(pll->base); + val &= ~pll->div_mask; + val |= div; + writel_relaxed(val, pll->base); + + return 0; +} + +static const struct clk_ops clk_pllv3_sys_ops = { + .prepare = clk_pllv3_prepare, + .unprepare = clk_pllv3_unprepare, + .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_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 mfn = readl_relaxed(pll->base + PLL_NUM_OFFSET); + u32 mfd = readl_relaxed(pll->base + PLL_DENOM_OFFSET); + u32 div = readl_relaxed(pll->base) & pll->div_mask; + + return (parent_rate * div) + ((parent_rate / mfd) * mfn); +} + +static long clk_pllv3_av_round_rate(struct clk_hw *hw, 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; + s64 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_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + unsigned long min_rate = parent_rate * 27; + unsigned long max_rate = parent_rate * 54; + u32 val, div; + u32 mfn, mfd = 1000000; + s64 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_relaxed(pll->base); + val &= ~pll->div_mask; + val |= div; + writel_relaxed(val, pll->base); + writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET); + writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET); + + return 0; +} + +static const struct clk_ops clk_pllv3_av_ops = { + .prepare = clk_pllv3_prepare, + .unprepare = clk_pllv3_unprepare, + .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_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 div = readl_relaxed(pll->base) & pll->div_mask; + + switch (div) { + case 0: + return 25000000; + case 1: + return 50000000; + case 2: + return 100000000; + case 3: + return 125000000; + } + + return 0; +} + +static long clk_pllv3_enet_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + if (rate >= 125000000) + rate = 125000000; + else if (rate >= 100000000) + rate = 100000000; + else if (rate >= 50000000) + rate = 50000000; + else + rate = 25000000; + return rate; +} + +static int clk_pllv3_enet_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 val, div; + + switch (rate) { + case 25000000: + div = 0; + break; + case 50000000: + div = 1; + break; + case 100000000: + div = 2; + break; + case 125000000: + div = 3; + break; + default: + return -EINVAL; + } + + val = readl_relaxed(pll->base); + val &= ~pll->div_mask; + val |= div; + writel_relaxed(val, pll->base); + + return 0; +} + +static const struct clk_ops clk_pllv3_enet_ops = { + .prepare = clk_pllv3_prepare, + .unprepare = clk_pllv3_unprepare, + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + .recalc_rate = clk_pllv3_enet_recalc_rate, + .round_rate = clk_pllv3_enet_round_rate, + .set_rate = clk_pllv3_enet_set_rate, +}; + +static const struct clk_ops clk_pllv3_mlb_ops = { + .prepare = clk_pllv3_prepare, + .unprepare = clk_pllv3_unprepare, + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, +}; + +struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, + const char *parent_name, void __iomem *base, + u32 gate_mask, u32 div_mask) +{ + struct clk_pllv3 *pll; + const struct clk_ops *ops; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + 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->gate_mask = gate_mask; + pll->div_mask = div_mask; + + init.name = name; + init.ops = ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h new file mode 100644 index 000000000000..1bf64fe2523c --- /dev/null +++ b/arch/arm/mach-imx/clk.h @@ -0,0 +1,83 @@ +#ifndef __MACH_IMX_CLK_H +#define __MACH_IMX_CLK_H + +#include <linux/spinlock.h> +#include <linux/clk-provider.h> +#include <mach/clock.h> + +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_name, void __iomem *base, u32 gate_mask, + u32 div_mask); + +struct clk *clk_register_gate2(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock); + +static inline struct clk *imx_clk_gate2(const char *name, const char *parent, + void __iomem *reg, u8 shift) +{ + return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + shift, 0, &imx_ccm_lock); +} + +struct clk *imx_clk_pfd(const char *name, const char *parent_name, + void __iomem *reg, u8 idx); + +struct clk *imx_clk_busy_divider(const char *name, const char *parent_name, + void __iomem *reg, u8 shift, u8 width, + void __iomem *busy_reg, u8 busy_shift); + +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 **parent_names, int num_parents); + +static inline struct clk *imx_clk_fixed(const char *name, int rate) +{ + return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate); +} + +static inline struct clk *imx_clk_divider(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width) +{ + return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT, + reg, shift, width, 0, &imx_ccm_lock); +} + +static inline struct clk *imx_clk_gate(const char *name, const char *parent, + void __iomem *reg, u8 shift) +{ + return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + shift, 0, &imx_ccm_lock); +} + +static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, + u8 shift, u8 width, const char **parents, int num_parents) +{ + return clk_register_mux(NULL, name, parents, num_parents, 0, reg, shift, + width, 0, &imx_ccm_lock); +} + +static inline struct clk *imx_clk_fixed_factor(const char *name, + const char *parent, unsigned int mult, unsigned int div) +{ + return clk_register_fixed_factor(NULL, name, parent, + CLK_SET_RATE_PARENT, mult, div); +} + +#endif diff --git a/arch/arm/mach-imx/clock-imx1.c b/arch/arm/mach-imx/clock-imx1.c deleted file mode 100644 index 4aabeb241563..000000000000 --- a/arch/arm/mach-imx/clock-imx1.c +++ /dev/null @@ -1,636 +0,0 @@ -/* - * 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 <linux/kernel.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/math64.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/clkdev.h> - -#include <mach/clock.h> -#include <mach/hardware.h> -#include <mach/common.h> - -#define IO_ADDR_CCM(off) (MX1_IO_ADDRESS(MX1_CCM_BASE_ADDR + (off))) - -/* CCM register addresses */ -#define CCM_CSCR IO_ADDR_CCM(0x0) -#define CCM_MPCTL0 IO_ADDR_CCM(0x4) -#define CCM_SPCTL0 IO_ADDR_CCM(0xc) -#define CCM_PCDR IO_ADDR_CCM(0x20) - -#define CCM_CSCR_CLKO_OFFSET 29 -#define CCM_CSCR_CLKO_MASK (0x7 << 29) -#define CCM_CSCR_USB_OFFSET 26 -#define CCM_CSCR_USB_MASK (0x7 << 26) -#define CCM_CSCR_OSC_EN_SHIFT 17 -#define CCM_CSCR_SYSTEM_SEL (1 << 16) -#define CCM_CSCR_BCLK_OFFSET 10 -#define CCM_CSCR_BCLK_MASK (0xf << 10) -#define CCM_CSCR_PRESC (1 << 15) - -#define CCM_PCDR_PCLK3_OFFSET 16 -#define CCM_PCDR_PCLK3_MASK (0x7f << 16) -#define CCM_PCDR_PCLK2_OFFSET 4 -#define CCM_PCDR_PCLK2_MASK (0xf << 4) -#define CCM_PCDR_PCLK1_OFFSET 0 -#define CCM_PCDR_PCLK1_MASK 0xf - -#define IO_ADDR_SCM(off) (MX1_IO_ADDRESS(MX1_SCM_BASE_ADDR + (off))) - -/* SCM register addresses */ -#define SCM_GCCR IO_ADDR_SCM(0xc) - -#define SCM_GCCR_DMA_CLK_EN_OFFSET 3 -#define SCM_GCCR_CSI_CLK_EN_OFFSET 2 -#define SCM_GCCR_MMA_CLK_EN_OFFSET 1 -#define SCM_GCCR_USBD_CLK_EN_OFFSET 0 - -static int _clk_enable(struct clk *clk) -{ - unsigned int reg; - - reg = __raw_readl(clk->enable_reg); - reg |= 1 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - - return 0; -} - -static void _clk_disable(struct clk *clk) -{ - unsigned int reg; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(1 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); -} - -static int _clk_can_use_parent(const struct clk *clk_arr[], unsigned int size, - struct clk *parent) -{ - int i; - - for (i = 0; i < size; i++) - if (parent == clk_arr[i]) - return i; - - return -EINVAL; -} - -static unsigned long -_clk_simple_round_rate(struct clk *clk, unsigned long rate, unsigned int limit) -{ - int div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (parent_rate % rate) - div++; - - if (div > limit) - div = limit; - - return parent_rate / div; -} - -static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate) -{ - return clk->parent->round_rate(clk->parent, rate); -} - -static int _clk_parent_set_rate(struct clk *clk, unsigned long rate) -{ - return clk->parent->set_rate(clk->parent, rate); -} - -static unsigned long clk16m_get_rate(struct clk *clk) -{ - return 16000000; -} - -static struct clk clk16m = { - .get_rate = clk16m_get_rate, - .enable = _clk_enable, - .enable_reg = CCM_CSCR, - .enable_shift = CCM_CSCR_OSC_EN_SHIFT, - .disable = _clk_disable, -}; - -/* in Hz */ -static unsigned long clk32_rate; - -static unsigned long clk32_get_rate(struct clk *clk) -{ - return clk32_rate; -} - -static struct clk clk32 = { - .get_rate = clk32_get_rate, -}; - -static unsigned long clk32_premult_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) * 512; -} - -static struct clk clk32_premult = { - .parent = &clk32, - .get_rate = clk32_premult_get_rate, -}; - -static const struct clk *prem_clk_clocks[] = { - &clk32_premult, - &clk16m, -}; - -static int prem_clk_set_parent(struct clk *clk, struct clk *parent) -{ - int i; - unsigned int reg = __raw_readl(CCM_CSCR); - - i = _clk_can_use_parent(prem_clk_clocks, ARRAY_SIZE(prem_clk_clocks), - parent); - - switch (i) { - case 0: - reg &= ~CCM_CSCR_SYSTEM_SEL; - break; - case 1: - reg |= CCM_CSCR_SYSTEM_SEL; - break; - default: - return i; - } - - __raw_writel(reg, CCM_CSCR); - - return 0; -} - -static struct clk prem_clk = { - .set_parent = prem_clk_set_parent, -}; - -static unsigned long system_clk_get_rate(struct clk *clk) -{ - return mxc_decode_pll(__raw_readl(CCM_SPCTL0), - clk_get_rate(clk->parent)); -} - -static struct clk system_clk = { - .parent = &prem_clk, - .get_rate = system_clk_get_rate, -}; - -static unsigned long mcu_clk_get_rate(struct clk *clk) -{ - return mxc_decode_pll(__raw_readl(CCM_MPCTL0), - clk_get_rate(clk->parent)); -} - -static struct clk mcu_clk = { - .parent = &clk32_premult, - .get_rate = mcu_clk_get_rate, -}; - -static unsigned long fclk_get_rate(struct clk *clk) -{ - unsigned long fclk = clk_get_rate(clk->parent); - - if (__raw_readl(CCM_CSCR) & CCM_CSCR_PRESC) - fclk /= 2; - - return fclk; -} - -static struct clk fclk = { - .parent = &mcu_clk, - .get_rate = fclk_get_rate, -}; - -/* - * get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA ) - */ -static unsigned long hclk_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) & - CCM_CSCR_BCLK_MASK) >> CCM_CSCR_BCLK_OFFSET) + 1); -} - -static unsigned long hclk_round_rate(struct clk *clk, unsigned long rate) -{ - return _clk_simple_round_rate(clk, rate, 16); -} - -static int hclk_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned int div; - unsigned int reg; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 16 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - div--; - - reg = __raw_readl(CCM_CSCR); - reg &= ~CCM_CSCR_BCLK_MASK; - reg |= div << CCM_CSCR_BCLK_OFFSET; - __raw_writel(reg, CCM_CSCR); - - return 0; -} - -static struct clk hclk = { - .parent = &system_clk, - .get_rate = hclk_get_rate, - .round_rate = hclk_round_rate, - .set_rate = hclk_set_rate, -}; - -static unsigned long clk48m_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) & - CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET) + 1); -} - -static unsigned long clk48m_round_rate(struct clk *clk, unsigned long rate) -{ - return _clk_simple_round_rate(clk, rate, 8); -} - -static int clk48m_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned int div; - unsigned int reg; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 8 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - div--; - - reg = __raw_readl(CCM_CSCR); - reg &= ~CCM_CSCR_USB_MASK; - reg |= div << CCM_CSCR_USB_OFFSET; - __raw_writel(reg, CCM_CSCR); - - return 0; -} - -static struct clk clk48m = { - .parent = &system_clk, - .get_rate = clk48m_get_rate, - .round_rate = clk48m_round_rate, - .set_rate = clk48m_set_rate, -}; - -/* - * get peripheral clock 1 ( UART[12], Timer[12], PWM ) - */ -static unsigned long perclk1_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) & - CCM_PCDR_PCLK1_MASK) >> CCM_PCDR_PCLK1_OFFSET) + 1); -} - -static unsigned long perclk1_round_rate(struct clk *clk, unsigned long rate) -{ - return _clk_simple_round_rate(clk, rate, 16); -} - -static int perclk1_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned int div; - unsigned int reg; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 16 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - div--; - - reg = __raw_readl(CCM_PCDR); - reg &= ~CCM_PCDR_PCLK1_MASK; - reg |= div << CCM_PCDR_PCLK1_OFFSET; - __raw_writel(reg, CCM_PCDR); - - return 0; -} - -/* - * get peripheral clock 2 ( LCD, SD, SPI[12] ) - */ -static unsigned long perclk2_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) & - CCM_PCDR_PCLK2_MASK) >> CCM_PCDR_PCLK2_OFFSET) + 1); -} - -static unsigned long perclk2_round_rate(struct clk *clk, unsigned long rate) -{ - return _clk_simple_round_rate(clk, rate, 16); -} - -static int perclk2_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned int div; - unsigned int reg; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 16 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - div--; - - reg = __raw_readl(CCM_PCDR); - reg &= ~CCM_PCDR_PCLK2_MASK; - reg |= div << CCM_PCDR_PCLK2_OFFSET; - __raw_writel(reg, CCM_PCDR); - - return 0; -} - -/* - * get peripheral clock 3 ( SSI ) - */ -static unsigned long perclk3_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) & - CCM_PCDR_PCLK3_MASK) >> CCM_PCDR_PCLK3_OFFSET) + 1); -} - -static unsigned long perclk3_round_rate(struct clk *clk, unsigned long rate) -{ - return _clk_simple_round_rate(clk, rate, 128); -} - -static int perclk3_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned int div; - unsigned int reg; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 128 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - div--; - - reg = __raw_readl(CCM_PCDR); - reg &= ~CCM_PCDR_PCLK3_MASK; - reg |= div << CCM_PCDR_PCLK3_OFFSET; - __raw_writel(reg, CCM_PCDR); - - return 0; -} - -static struct clk perclk[] = { - { - .id = 0, - .parent = &system_clk, - .get_rate = perclk1_get_rate, - .round_rate = perclk1_round_rate, - .set_rate = perclk1_set_rate, - }, { - .id = 1, - .parent = &system_clk, - .get_rate = perclk2_get_rate, - .round_rate = perclk2_round_rate, - .set_rate = perclk2_set_rate, - }, { - .id = 2, - .parent = &system_clk, - .get_rate = perclk3_get_rate, - .round_rate = perclk3_round_rate, - .set_rate = perclk3_set_rate, - } -}; - -static const struct clk *clko_clocks[] = { - &perclk[0], - &hclk, - &clk48m, - &clk16m, - &prem_clk, - &fclk, -}; - -static int clko_set_parent(struct clk *clk, struct clk *parent) -{ - int i; - unsigned int reg; - - i = _clk_can_use_parent(clko_clocks, ARRAY_SIZE(clko_clocks), parent); - if (i < 0) - return i; - - reg = __raw_readl(CCM_CSCR) & ~CCM_CSCR_CLKO_MASK; - reg |= i << CCM_CSCR_CLKO_OFFSET; - __raw_writel(reg, CCM_CSCR); - - if (clko_clocks[i]->set_rate && clko_clocks[i]->round_rate) { - clk->set_rate = _clk_parent_set_rate; - clk->round_rate = _clk_parent_round_rate; - } else { - clk->set_rate = NULL; - clk->round_rate = NULL; - } - - return 0; -} - -static struct clk clko_clk = { - .set_parent = clko_set_parent, -}; - -static struct clk dma_clk = { - .parent = &hclk, - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, - .enable = _clk_enable, - .enable_reg = SCM_GCCR, - .enable_shift = SCM_GCCR_DMA_CLK_EN_OFFSET, - .disable = _clk_disable, -}; - -static struct clk csi_clk = { - .parent = &hclk, - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, - .enable = _clk_enable, - .enable_reg = SCM_GCCR, - .enable_shift = SCM_GCCR_CSI_CLK_EN_OFFSET, - .disable = _clk_disable, -}; - -static struct clk mma_clk = { - .parent = &hclk, - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, - .enable = _clk_enable, - .enable_reg = SCM_GCCR, - .enable_shift = SCM_GCCR_MMA_CLK_EN_OFFSET, - .disable = _clk_disable, -}; - -static struct clk usbd_clk = { - .parent = &clk48m, - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, - .enable = _clk_enable, - .enable_reg = SCM_GCCR, - .enable_shift = SCM_GCCR_USBD_CLK_EN_OFFSET, - .disable = _clk_disable, -}; - -static struct clk gpt_clk = { - .parent = &perclk[0], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk uart_clk = { - .parent = &perclk[0], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk i2c_clk = { - .parent = &hclk, - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk spi_clk = { - .parent = &perclk[1], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk sdhc_clk = { - .parent = &perclk[1], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk lcdc_clk = { - .parent = &perclk[1], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk mshc_clk = { - .parent = &hclk, - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk ssi_clk = { - .parent = &perclk[2], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk rtc_clk = { - .parent = &clk32, -}; - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, -static struct clk_lookup lookups[] __initdata = { - _REGISTER_CLOCK(NULL, "dma", dma_clk) - _REGISTER_CLOCK("mx1-camera.0", NULL, csi_clk) - _REGISTER_CLOCK(NULL, "mma", mma_clk) - _REGISTER_CLOCK("imx_udc.0", NULL, usbd_clk) - _REGISTER_CLOCK(NULL, "gpt", gpt_clk) - _REGISTER_CLOCK("imx1-uart.0", NULL, uart_clk) - _REGISTER_CLOCK("imx1-uart.1", NULL, uart_clk) - _REGISTER_CLOCK("imx1-uart.2", NULL, uart_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk) - _REGISTER_CLOCK("imx1-cspi.0", NULL, spi_clk) - _REGISTER_CLOCK("imx1-cspi.1", NULL, spi_clk) - _REGISTER_CLOCK("imx-mmc.0", NULL, sdhc_clk) - _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk) - _REGISTER_CLOCK(NULL, "mshc", mshc_clk) - _REGISTER_CLOCK(NULL, "ssi", ssi_clk) - _REGISTER_CLOCK("mxc_rtc.0", NULL, rtc_clk) -}; - -int __init mx1_clocks_init(unsigned long fref) -{ - unsigned int reg; - - /* disable clocks we are able to */ - __raw_writel(0, SCM_GCCR); - - clk32_rate = fref; - reg = __raw_readl(CCM_CSCR); - - /* detect clock reference for system PLL */ - if (reg & CCM_CSCR_SYSTEM_SEL) { - prem_clk.parent = &clk16m; - } else { - /* ensure that oscillator is disabled */ - reg &= ~(1 << CCM_CSCR_OSC_EN_SHIFT); - __raw_writel(reg, CCM_CSCR); - prem_clk.parent = &clk32_premult; - } - - /* detect reference for CLKO */ - reg = (reg & CCM_CSCR_CLKO_MASK) >> CCM_CSCR_CLKO_OFFSET; - clko_clk.parent = (struct clk *)clko_clocks[reg]; - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - clk_enable(&hclk); - clk_enable(&fclk); - - mxc_timer_init(&gpt_clk, MX1_IO_ADDRESS(MX1_TIM1_BASE_ADDR), - MX1_TIM1_INT); - - return 0; -} diff --git a/arch/arm/mach-imx/clock-imx21.c b/arch/arm/mach-imx/clock-imx21.c deleted file mode 100644 index ee15d8c9db08..000000000000 --- a/arch/arm/mach-imx/clock-imx21.c +++ /dev/null @@ -1,1239 +0,0 @@ -/* - * 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 <linux/clk.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/clkdev.h> - -#include <mach/clock.h> -#include <mach/hardware.h> -#include <mach/common.h> -#include <asm/div64.h> - -#define IO_ADDR_CCM(off) (MX21_IO_ADDRESS(MX21_CCM_BASE_ADDR + (off))) - -/* Register offsets */ -#define CCM_CSCR IO_ADDR_CCM(0x0) -#define CCM_MPCTL0 IO_ADDR_CCM(0x4) -#define CCM_MPCTL1 IO_ADDR_CCM(0x8) -#define CCM_SPCTL0 IO_ADDR_CCM(0xc) -#define CCM_SPCTL1 IO_ADDR_CCM(0x10) -#define CCM_OSC26MCTL IO_ADDR_CCM(0x14) -#define CCM_PCDR0 IO_ADDR_CCM(0x18) -#define CCM_PCDR1 IO_ADDR_CCM(0x1c) -#define CCM_PCCR0 IO_ADDR_CCM(0x20) -#define CCM_PCCR1 IO_ADDR_CCM(0x24) -#define CCM_CCSR IO_ADDR_CCM(0x28) -#define CCM_PMCTL IO_ADDR_CCM(0x2c) -#define CCM_PMCOUNT IO_ADDR_CCM(0x30) -#define CCM_WKGDCTL IO_ADDR_CCM(0x34) - -#define CCM_CSCR_PRESC_OFFSET 29 -#define CCM_CSCR_PRESC_MASK (0x7 << CCM_CSCR_PRESC_OFFSET) - -#define CCM_CSCR_USB_OFFSET 26 -#define CCM_CSCR_USB_MASK (0x7 << CCM_CSCR_USB_OFFSET) -#define CCM_CSCR_SD_OFFSET 24 -#define CCM_CSCR_SD_MASK (0x3 << CCM_CSCR_SD_OFFSET) -#define CCM_CSCR_SPLLRES (1 << 22) -#define CCM_CSCR_MPLLRES (1 << 21) -#define CCM_CSCR_SSI2_OFFSET 20 -#define CCM_CSCR_SSI2 (1 << CCM_CSCR_SSI2_OFFSET) -#define CCM_CSCR_SSI1_OFFSET 19 -#define CCM_CSCR_SSI1 (1 << CCM_CSCR_SSI1_OFFSET) -#define CCM_CSCR_FIR_OFFSET 18 -#define CCM_CSCR_FIR (1 << CCM_CSCR_FIR_OFFSET) -#define CCM_CSCR_SP (1 << 17) -#define CCM_CSCR_MCU (1 << 16) -#define CCM_CSCR_BCLK_OFFSET 10 -#define CCM_CSCR_BCLK_MASK (0xf << CCM_CSCR_BCLK_OFFSET) -#define CCM_CSCR_IPDIV_OFFSET 9 -#define CCM_CSCR_IPDIV (1 << CCM_CSCR_IPDIV_OFFSET) - -#define CCM_CSCR_OSC26MDIV (1 << 4) -#define CCM_CSCR_OSC26M (1 << 3) -#define CCM_CSCR_FPM (1 << 2) -#define CCM_CSCR_SPEN (1 << 1) -#define CCM_CSCR_MPEN 1 - -#define CCM_MPCTL0_CPLM (1 << 31) -#define CCM_MPCTL0_PD_OFFSET 26 -#define CCM_MPCTL0_PD_MASK (0xf << 26) -#define CCM_MPCTL0_MFD_OFFSET 16 -#define CCM_MPCTL0_MFD_MASK (0x3ff << 16) -#define CCM_MPCTL0_MFI_OFFSET 10 -#define CCM_MPCTL0_MFI_MASK (0xf << 10) -#define CCM_MPCTL0_MFN_OFFSET 0 -#define CCM_MPCTL0_MFN_MASK 0x3ff - -#define CCM_MPCTL1_LF (1 << 15) -#define CCM_MPCTL1_BRMO (1 << 6) - -#define CCM_SPCTL0_CPLM (1 << 31) -#define CCM_SPCTL0_PD_OFFSET 26 -#define CCM_SPCTL0_PD_MASK (0xf << 26) -#define CCM_SPCTL0_MFD_OFFSET 16 -#define CCM_SPCTL0_MFD_MASK (0x3ff << 16) -#define CCM_SPCTL0_MFI_OFFSET 10 -#define CCM_SPCTL0_MFI_MASK (0xf << 10) -#define CCM_SPCTL0_MFN_OFFSET 0 -#define CCM_SPCTL0_MFN_MASK 0x3ff - -#define CCM_SPCTL1_LF (1 << 15) -#define CCM_SPCTL1_BRMO (1 << 6) - -#define CCM_OSC26MCTL_PEAK_OFFSET 16 -#define CCM_OSC26MCTL_PEAK_MASK (0x3 << 16) -#define CCM_OSC26MCTL_AGC_OFFSET 8 -#define CCM_OSC26MCTL_AGC_MASK (0x3f << 8) -#define CCM_OSC26MCTL_ANATEST_OFFSET 0 -#define CCM_OSC26MCTL_ANATEST_MASK 0x3f - -#define CCM_PCDR0_SSI2BAUDDIV_OFFSET 26 -#define CCM_PCDR0_SSI2BAUDDIV_MASK (0x3f << 26) -#define CCM_PCDR0_SSI1BAUDDIV_OFFSET 16 -#define CCM_PCDR0_SSI1BAUDDIV_MASK (0x3f << 16) -#define CCM_PCDR0_NFCDIV_OFFSET 12 -#define CCM_PCDR0_NFCDIV_MASK (0xf << 12) -#define CCM_PCDR0_48MDIV_OFFSET 5 -#define CCM_PCDR0_48MDIV_MASK (0x7 << CCM_PCDR0_48MDIV_OFFSET) -#define CCM_PCDR0_FIRIDIV_OFFSET 0 -#define CCM_PCDR0_FIRIDIV_MASK 0x1f -#define CCM_PCDR1_PERDIV4_OFFSET 24 -#define CCM_PCDR1_PERDIV4_MASK (0x3f << 24) -#define CCM_PCDR1_PERDIV3_OFFSET 16 -#define CCM_PCDR1_PERDIV3_MASK (0x3f << 16) -#define CCM_PCDR1_PERDIV2_OFFSET 8 -#define CCM_PCDR1_PERDIV2_MASK (0x3f << 8) -#define CCM_PCDR1_PERDIV1_OFFSET 0 -#define CCM_PCDR1_PERDIV1_MASK 0x3f - -#define CCM_PCCR_HCLK_CSI_OFFSET 31 -#define CCM_PCCR_HCLK_CSI_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_DMA_OFFSET 30 -#define CCM_PCCR_HCLK_DMA_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_BROM_OFFSET 28 -#define CCM_PCCR_HCLK_BROM_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_EMMA_OFFSET 27 -#define CCM_PCCR_HCLK_EMMA_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_LCDC_OFFSET 26 -#define CCM_PCCR_HCLK_LCDC_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_SLCDC_OFFSET 25 -#define CCM_PCCR_HCLK_SLCDC_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_USBOTG_OFFSET 24 -#define CCM_PCCR_HCLK_USBOTG_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_BMI_OFFSET 23 -#define CCM_PCCR_BMI_MASK (1 << CCM_PCCR_BMI_MASK) -#define CCM_PCCR_HCLK_BMI_REG CCM_PCCR0 -#define CCM_PCCR_PERCLK4_OFFSET 22 -#define CCM_PCCR_PERCLK4_REG CCM_PCCR0 -#define CCM_PCCR_SLCDC_OFFSET 21 -#define CCM_PCCR_SLCDC_REG CCM_PCCR0 -#define CCM_PCCR_FIRI_BAUD_OFFSET 20 -#define CCM_PCCR_FIRI_BAUD_MASK (1 << CCM_PCCR_FIRI_BAUD_MASK) -#define CCM_PCCR_FIRI_BAUD_REG CCM_PCCR0 -#define CCM_PCCR_NFC_OFFSET 19 -#define CCM_PCCR_NFC_REG CCM_PCCR0 -#define CCM_PCCR_LCDC_OFFSET 18 -#define CCM_PCCR_LCDC_REG CCM_PCCR0 -#define CCM_PCCR_SSI1_BAUD_OFFSET 17 -#define CCM_PCCR_SSI1_BAUD_REG CCM_PCCR0 -#define CCM_PCCR_SSI2_BAUD_OFFSET 16 -#define CCM_PCCR_SSI2_BAUD_REG CCM_PCCR0 -#define CCM_PCCR_EMMA_OFFSET 15 -#define CCM_PCCR_EMMA_REG CCM_PCCR0 -#define CCM_PCCR_USBOTG_OFFSET 14 -#define CCM_PCCR_USBOTG_REG CCM_PCCR0 -#define CCM_PCCR_DMA_OFFSET 13 -#define CCM_PCCR_DMA_REG CCM_PCCR0 -#define CCM_PCCR_I2C1_OFFSET 12 -#define CCM_PCCR_I2C1_REG CCM_PCCR0 -#define CCM_PCCR_GPIO_OFFSET 11 -#define CCM_PCCR_GPIO_REG CCM_PCCR0 -#define CCM_PCCR_SDHC2_OFFSET 10 -#define CCM_PCCR_SDHC2_REG CCM_PCCR0 -#define CCM_PCCR_SDHC1_OFFSET 9 -#define CCM_PCCR_SDHC1_REG CCM_PCCR0 -#define CCM_PCCR_FIRI_OFFSET 8 -#define CCM_PCCR_FIRI_MASK (1 << CCM_PCCR_BAUD_MASK) -#define CCM_PCCR_FIRI_REG CCM_PCCR0 -#define CCM_PCCR_SSI2_IPG_OFFSET 7 -#define CCM_PCCR_SSI2_REG CCM_PCCR0 -#define CCM_PCCR_SSI1_IPG_OFFSET 6 -#define CCM_PCCR_SSI1_REG CCM_PCCR0 -#define CCM_PCCR_CSPI2_OFFSET 5 -#define CCM_PCCR_CSPI2_REG CCM_PCCR0 -#define CCM_PCCR_CSPI1_OFFSET 4 -#define CCM_PCCR_CSPI1_REG CCM_PCCR0 -#define CCM_PCCR_UART4_OFFSET 3 -#define CCM_PCCR_UART4_REG CCM_PCCR0 -#define CCM_PCCR_UART3_OFFSET 2 -#define CCM_PCCR_UART3_REG CCM_PCCR0 -#define CCM_PCCR_UART2_OFFSET 1 -#define CCM_PCCR_UART2_REG CCM_PCCR0 -#define CCM_PCCR_UART1_OFFSET 0 -#define CCM_PCCR_UART1_REG CCM_PCCR0 - -#define CCM_PCCR_OWIRE_OFFSET 31 -#define CCM_PCCR_OWIRE_REG CCM_PCCR1 -#define CCM_PCCR_KPP_OFFSET 30 -#define CCM_PCCR_KPP_REG CCM_PCCR1 -#define CCM_PCCR_RTC_OFFSET 29 -#define CCM_PCCR_RTC_REG CCM_PCCR1 -#define CCM_PCCR_PWM_OFFSET 28 -#define CCM_PCCR_PWM_REG CCM_PCCR1 -#define CCM_PCCR_GPT3_OFFSET 27 -#define CCM_PCCR_GPT3_REG CCM_PCCR1 -#define CCM_PCCR_GPT2_OFFSET 26 -#define CCM_PCCR_GPT2_REG CCM_PCCR1 -#define CCM_PCCR_GPT1_OFFSET 25 -#define CCM_PCCR_GPT1_REG CCM_PCCR1 -#define CCM_PCCR_WDT_OFFSET 24 -#define CCM_PCCR_WDT_REG CCM_PCCR1 -#define CCM_PCCR_CSPI3_OFFSET 23 -#define CCM_PCCR_CSPI3_REG CCM_PCCR1 - -#define CCM_PCCR_CSPI1_MASK (1 << CCM_PCCR_CSPI1_OFFSET) -#define CCM_PCCR_CSPI2_MASK (1 << CCM_PCCR_CSPI2_OFFSET) -#define CCM_PCCR_CSPI3_MASK (1 << CCM_PCCR_CSPI3_OFFSET) -#define CCM_PCCR_DMA_MASK (1 << CCM_PCCR_DMA_OFFSET) -#define CCM_PCCR_EMMA_MASK (1 << CCM_PCCR_EMMA_OFFSET) -#define CCM_PCCR_GPIO_MASK (1 << CCM_PCCR_GPIO_OFFSET) -#define CCM_PCCR_GPT1_MASK (1 << CCM_PCCR_GPT1_OFFSET) -#define CCM_PCCR_GPT2_MASK (1 << CCM_PCCR_GPT2_OFFSET) -#define CCM_PCCR_GPT3_MASK (1 << CCM_PCCR_GPT3_OFFSET) -#define CCM_PCCR_HCLK_BROM_MASK (1 << CCM_PCCR_HCLK_BROM_OFFSET) -#define CCM_PCCR_HCLK_CSI_MASK (1 << CCM_PCCR_HCLK_CSI_OFFSET) -#define CCM_PCCR_HCLK_DMA_MASK (1 << CCM_PCCR_HCLK_DMA_OFFSET) -#define CCM_PCCR_HCLK_EMMA_MASK (1 << CCM_PCCR_HCLK_EMMA_OFFSET) -#define CCM_PCCR_HCLK_LCDC_MASK (1 << CCM_PCCR_HCLK_LCDC_OFFSET) -#define CCM_PCCR_HCLK_SLCDC_MASK (1 << CCM_PCCR_HCLK_SLCDC_OFFSET) -#define CCM_PCCR_HCLK_USBOTG_MASK (1 << CCM_PCCR_HCLK_USBOTG_OFFSET) -#define CCM_PCCR_I2C1_MASK (1 << CCM_PCCR_I2C1_OFFSET) -#define CCM_PCCR_KPP_MASK (1 << CCM_PCCR_KPP_OFFSET) -#define CCM_PCCR_LCDC_MASK (1 << CCM_PCCR_LCDC_OFFSET) -#define CCM_PCCR_NFC_MASK (1 << CCM_PCCR_NFC_OFFSET) -#define CCM_PCCR_OWIRE_MASK (1 << CCM_PCCR_OWIRE_OFFSET) -#define CCM_PCCR_PERCLK4_MASK (1 << CCM_PCCR_PERCLK4_OFFSET) -#define CCM_PCCR_PWM_MASK (1 << CCM_PCCR_PWM_OFFSET) -#define CCM_PCCR_RTC_MASK (1 << CCM_PCCR_RTC_OFFSET) -#define CCM_PCCR_SDHC1_MASK (1 << CCM_PCCR_SDHC1_OFFSET) -#define CCM_PCCR_SDHC2_MASK (1 << CCM_PCCR_SDHC2_OFFSET) -#define CCM_PCCR_SLCDC_MASK (1 << CCM_PCCR_SLCDC_OFFSET) -#define CCM_PCCR_SSI1_BAUD_MASK (1 << CCM_PCCR_SSI1_BAUD_OFFSET) -#define CCM_PCCR_SSI1_IPG_MASK (1 << CCM_PCCR_SSI1_IPG_OFFSET) -#define CCM_PCCR_SSI2_BAUD_MASK (1 << CCM_PCCR_SSI2_BAUD_OFFSET) -#define CCM_PCCR_SSI2_IPG_MASK (1 << CCM_PCCR_SSI2_IPG_OFFSET) -#define CCM_PCCR_UART1_MASK (1 << CCM_PCCR_UART1_OFFSET) -#define CCM_PCCR_UART2_MASK (1 << CCM_PCCR_UART2_OFFSET) -#define CCM_PCCR_UART3_MASK (1 << CCM_PCCR_UART3_OFFSET) -#define CCM_PCCR_UART4_MASK (1 << CCM_PCCR_UART4_OFFSET) -#define CCM_PCCR_USBOTG_MASK (1 << CCM_PCCR_USBOTG_OFFSET) -#define CCM_PCCR_WDT_MASK (1 << CCM_PCCR_WDT_OFFSET) - -#define CCM_CCSR_32KSR (1 << 15) - -#define CCM_CCSR_CLKMODE1 (1 << 9) -#define CCM_CCSR_CLKMODE0 (1 << 8) - -#define CCM_CCSR_CLKOSEL_OFFSET 0 -#define CCM_CCSR_CLKOSEL_MASK 0x1f - -#define SYS_FMCR 0x14 /* Functional Muxing Control Reg */ -#define SYS_CHIP_ID 0x00 /* The offset of CHIP ID register */ - -static int _clk_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg |= 1 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - return 0; -} - -static void _clk_disable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(1 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); -} - -static unsigned long _clk_generic_round_rate(struct clk *clk, - unsigned long rate, - u32 max_divisor) -{ - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (parent_rate % rate) - div++; - - if (div > max_divisor) - div = max_divisor; - - return parent_rate / div; -} - -static int _clk_spll_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(CCM_CSCR); - reg |= CCM_CSCR_SPEN; - __raw_writel(reg, CCM_CSCR); - - while ((__raw_readl(CCM_SPCTL1) & CCM_SPCTL1_LF) == 0) - ; - return 0; -} - -static void _clk_spll_disable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(CCM_CSCR); - reg &= ~CCM_CSCR_SPEN; - __raw_writel(reg, CCM_CSCR); -} - - -#define CSCR() (__raw_readl(CCM_CSCR)) -#define PCDR0() (__raw_readl(CCM_PCDR0)) -#define PCDR1() (__raw_readl(CCM_PCDR1)) - -static unsigned long _clk_perclkx_round_rate(struct clk *clk, - unsigned long rate) -{ - return _clk_generic_round_rate(clk, rate, 64); -} - -static int _clk_perclkx_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg; - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->id < 0 || clk->id > 3) - return -EINVAL; - - div = parent_rate / rate; - if (div > 64 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - div--; - - reg = - __raw_readl(CCM_PCDR1) & ~(CCM_PCDR1_PERDIV1_MASK << - (clk->id << 3)); - reg |= div << (clk->id << 3); - __raw_writel(reg, CCM_PCDR1); - - return 0; -} - -static unsigned long _clk_usb_recalc(struct clk *clk) -{ - unsigned long usb_pdf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - usb_pdf = (CSCR() & CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET; - - return parent_rate / (usb_pdf + 1U); -} - -static unsigned long _clk_usb_round_rate(struct clk *clk, - unsigned long rate) -{ - return _clk_generic_round_rate(clk, rate, 8); -} - -static int _clk_usb_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg; - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (div > 8 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - div--; - - reg = CSCR() & ~CCM_CSCR_USB_MASK; - reg |= div << CCM_CSCR_USB_OFFSET; - __raw_writel(reg, CCM_CSCR); - - return 0; -} - -static unsigned long _clk_ssix_recalc(struct clk *clk, unsigned long pdf) -{ - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - pdf = (pdf < 2) ? 124UL : pdf; /* MX21 & MX27 TO1 */ - - return 2UL * parent_rate / pdf; -} - -static unsigned long _clk_ssi1_recalc(struct clk *clk) -{ - return _clk_ssix_recalc(clk, - (PCDR0() & CCM_PCDR0_SSI1BAUDDIV_MASK) - >> CCM_PCDR0_SSI1BAUDDIV_OFFSET); -} - -static unsigned long _clk_ssi2_recalc(struct clk *clk) -{ - return _clk_ssix_recalc(clk, - (PCDR0() & CCM_PCDR0_SSI2BAUDDIV_MASK) >> - CCM_PCDR0_SSI2BAUDDIV_OFFSET); -} - -static unsigned long _clk_nfc_recalc(struct clk *clk) -{ - unsigned long nfc_pdf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - nfc_pdf = (PCDR0() & CCM_PCDR0_NFCDIV_MASK) - >> CCM_PCDR0_NFCDIV_OFFSET; - - return parent_rate / (nfc_pdf + 1); -} - -static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate) -{ - return clk->parent->round_rate(clk->parent, rate); -} - -static int _clk_parent_set_rate(struct clk *clk, unsigned long rate) -{ - return clk->parent->set_rate(clk->parent, rate); -} - -static unsigned long external_high_reference; /* in Hz */ - -static unsigned long get_high_reference_clock_rate(struct clk *clk) -{ - return external_high_reference; -} - -/* - * the high frequency external clock reference - * Default case is 26MHz. - */ -static struct clk ckih_clk = { - .get_rate = get_high_reference_clock_rate, -}; - -static unsigned long external_low_reference; /* in Hz */ - -static unsigned long get_low_reference_clock_rate(struct clk *clk) -{ - return external_low_reference; -} - -/* - * the low frequency external clock reference - * Default case is 32.768kHz. - */ -static struct clk ckil_clk = { - .get_rate = get_low_reference_clock_rate, -}; - - -static unsigned long _clk_fpm_recalc(struct clk *clk) -{ - return clk_get_rate(clk->parent) * 512; -} - -/* Output of frequency pre multiplier */ -static struct clk fpm_clk = { - .parent = &ckil_clk, - .get_rate = _clk_fpm_recalc, -}; - -static unsigned long get_mpll_clk(struct clk *clk) -{ - uint32_t reg; - unsigned long ref_clk; - unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0; - unsigned long long temp; - - ref_clk = clk_get_rate(clk->parent); - - reg = __raw_readl(CCM_MPCTL0); - pdf = (reg & CCM_MPCTL0_PD_MASK) >> CCM_MPCTL0_PD_OFFSET; - mfd = (reg & CCM_MPCTL0_MFD_MASK) >> CCM_MPCTL0_MFD_OFFSET; - mfi = (reg & CCM_MPCTL0_MFI_MASK) >> CCM_MPCTL0_MFI_OFFSET; - mfn = (reg & CCM_MPCTL0_MFN_MASK) >> CCM_MPCTL0_MFN_OFFSET; - - mfi = (mfi <= 5) ? 5 : mfi; - temp = 2LL * ref_clk * mfn; - do_div(temp, mfd + 1); - temp = 2LL * ref_clk * mfi + temp; - do_div(temp, pdf + 1); - - return (unsigned long)temp; -} - -static struct clk mpll_clk = { - .parent = &ckih_clk, - .get_rate = get_mpll_clk, -}; - -static unsigned long _clk_fclk_get_rate(struct clk *clk) -{ - unsigned long parent_rate; - u32 div; - - div = (CSCR() & CCM_CSCR_PRESC_MASK) >> CCM_CSCR_PRESC_OFFSET; - parent_rate = clk_get_rate(clk->parent); - - return parent_rate / (div+1); -} - -static struct clk fclk_clk = { - .parent = &mpll_clk, - .get_rate = _clk_fclk_get_rate -}; - -static unsigned long get_spll_clk(struct clk *clk) -{ - uint32_t reg; - unsigned long ref_clk; - unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0; - unsigned long long temp; - - ref_clk = clk_get_rate(clk->parent); - - reg = __raw_readl(CCM_SPCTL0); - pdf = (reg & CCM_SPCTL0_PD_MASK) >> CCM_SPCTL0_PD_OFFSET; - mfd = (reg & CCM_SPCTL0_MFD_MASK) >> CCM_SPCTL0_MFD_OFFSET; - mfi = (reg & CCM_SPCTL0_MFI_MASK) >> CCM_SPCTL0_MFI_OFFSET; - mfn = (reg & CCM_SPCTL0_MFN_MASK) >> CCM_SPCTL0_MFN_OFFSET; - - mfi = (mfi <= 5) ? 5 : mfi; - temp = 2LL * ref_clk * mfn; - do_div(temp, mfd + 1); - temp = 2LL * ref_clk * mfi + temp; - do_div(temp, pdf + 1); - - return (unsigned long)temp; -} - -static struct clk spll_clk = { - .parent = &ckih_clk, - .get_rate = get_spll_clk, - .enable = _clk_spll_enable, - .disable = _clk_spll_disable, -}; - -static unsigned long get_hclk_clk(struct clk *clk) -{ - unsigned long rate; - unsigned long bclk_pdf; - - bclk_pdf = (CSCR() & CCM_CSCR_BCLK_MASK) - >> CCM_CSCR_BCLK_OFFSET; - - rate = clk_get_rate(clk->parent); - return rate / (bclk_pdf + 1); -} - -static struct clk hclk_clk = { - .parent = &fclk_clk, - .get_rate = get_hclk_clk, -}; - -static unsigned long get_ipg_clk(struct clk *clk) -{ - unsigned long rate; - unsigned long ipg_pdf; - - ipg_pdf = (CSCR() & CCM_CSCR_IPDIV) >> CCM_CSCR_IPDIV_OFFSET; - - rate = clk_get_rate(clk->parent); - return rate / (ipg_pdf + 1); -} - -static struct clk ipg_clk = { - .parent = &hclk_clk, - .get_rate = get_ipg_clk, -}; - -static unsigned long _clk_perclkx_recalc(struct clk *clk) -{ - unsigned long perclk_pdf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->id < 0 || clk->id > 3) - return 0; - - perclk_pdf = (PCDR1() >> (clk->id << 3)) & CCM_PCDR1_PERDIV1_MASK; - - return parent_rate / (perclk_pdf + 1); -} - -static struct clk per_clk[] = { - { - .id = 0, - .parent = &mpll_clk, - .get_rate = _clk_perclkx_recalc, - }, { - .id = 1, - .parent = &mpll_clk, - .get_rate = _clk_perclkx_recalc, - }, { - .id = 2, - .parent = &mpll_clk, - .round_rate = _clk_perclkx_round_rate, - .set_rate = _clk_perclkx_set_rate, - .get_rate = _clk_perclkx_recalc, - /* Enable/Disable done via lcd_clkc[1] */ - }, { - .id = 3, - .parent = &mpll_clk, - .round_rate = _clk_perclkx_round_rate, - .set_rate = _clk_perclkx_set_rate, - .get_rate = _clk_perclkx_recalc, - /* Enable/Disable done via csi_clk[1] */ - }, -}; - -static struct clk uart_ipg_clk[]; - -static struct clk uart_clk[] = { - { - .id = 0, - .parent = &per_clk[0], - .secondary = &uart_ipg_clk[0], - }, { - .id = 1, - .parent = &per_clk[0], - .secondary = &uart_ipg_clk[1], - }, { - .id = 2, - .parent = &per_clk[0], - .secondary = &uart_ipg_clk[2], - }, { - .id = 3, - .parent = &per_clk[0], - .secondary = &uart_ipg_clk[3], - }, -}; - -static struct clk uart_ipg_clk[] = { - { - .id = 0, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_UART1_REG, - .enable_shift = CCM_PCCR_UART1_OFFSET, - .disable = _clk_disable, - }, { - .id = 1, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_UART2_REG, - .enable_shift = CCM_PCCR_UART2_OFFSET, - .disable = _clk_disable, - }, { - .id = 2, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_UART3_REG, - .enable_shift = CCM_PCCR_UART3_OFFSET, - .disable = _clk_disable, - }, { - .id = 3, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_UART4_REG, - .enable_shift = CCM_PCCR_UART4_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk gpt_ipg_clk[]; - -static struct clk gpt_clk[] = { - { - .id = 0, - .parent = &per_clk[0], - .secondary = &gpt_ipg_clk[0], - }, { - .id = 1, - .parent = &per_clk[0], - .secondary = &gpt_ipg_clk[1], - }, { - .id = 2, - .parent = &per_clk[0], - .secondary = &gpt_ipg_clk[2], - }, -}; - -static struct clk gpt_ipg_clk[] = { - { - .id = 0, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_GPT1_REG, - .enable_shift = CCM_PCCR_GPT1_OFFSET, - .disable = _clk_disable, - }, { - .id = 1, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_GPT2_REG, - .enable_shift = CCM_PCCR_GPT2_OFFSET, - .disable = _clk_disable, - }, { - .id = 2, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_GPT3_REG, - .enable_shift = CCM_PCCR_GPT3_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk pwm_clk[] = { - { - .parent = &per_clk[0], - .secondary = &pwm_clk[1], - }, { - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_PWM_REG, - .enable_shift = CCM_PCCR_PWM_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk sdhc_ipg_clk[]; - -static struct clk sdhc_clk[] = { - { - .id = 0, - .parent = &per_clk[1], - .secondary = &sdhc_ipg_clk[0], - }, { - .id = 1, - .parent = &per_clk[1], - .secondary = &sdhc_ipg_clk[1], - }, -}; - -static struct clk sdhc_ipg_clk[] = { - { - .id = 0, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SDHC1_REG, - .enable_shift = CCM_PCCR_SDHC1_OFFSET, - .disable = _clk_disable, - }, { - .id = 1, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SDHC2_REG, - .enable_shift = CCM_PCCR_SDHC2_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk cspi_ipg_clk[]; - -static struct clk cspi_clk[] = { - { - .id = 0, - .parent = &per_clk[1], - .secondary = &cspi_ipg_clk[0], - }, { - .id = 1, - .parent = &per_clk[1], - .secondary = &cspi_ipg_clk[1], - }, { - .id = 2, - .parent = &per_clk[1], - .secondary = &cspi_ipg_clk[2], - }, -}; - -static struct clk cspi_ipg_clk[] = { - { - .id = 0, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_CSPI1_REG, - .enable_shift = CCM_PCCR_CSPI1_OFFSET, - .disable = _clk_disable, - }, { - .id = 1, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_CSPI2_REG, - .enable_shift = CCM_PCCR_CSPI2_OFFSET, - .disable = _clk_disable, - }, { - .id = 3, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_CSPI3_REG, - .enable_shift = CCM_PCCR_CSPI3_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk lcdc_clk[] = { - { - .parent = &per_clk[2], - .secondary = &lcdc_clk[1], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, - }, { - .parent = &ipg_clk, - .secondary = &lcdc_clk[2], - .enable = _clk_enable, - .enable_reg = CCM_PCCR_LCDC_REG, - .enable_shift = CCM_PCCR_LCDC_OFFSET, - .disable = _clk_disable, - }, { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_LCDC_REG, - .enable_shift = CCM_PCCR_HCLK_LCDC_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk csi_clk[] = { - { - .parent = &per_clk[3], - .secondary = &csi_clk[1], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, - }, { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_CSI_REG, - .enable_shift = CCM_PCCR_HCLK_CSI_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk usb_clk[] = { - { - .parent = &spll_clk, - .secondary = &usb_clk[1], - .get_rate = _clk_usb_recalc, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_USBOTG_REG, - .enable_shift = CCM_PCCR_USBOTG_OFFSET, - .disable = _clk_disable, - .round_rate = _clk_usb_round_rate, - .set_rate = _clk_usb_set_rate, - }, { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_USBOTG_REG, - .enable_shift = CCM_PCCR_HCLK_USBOTG_OFFSET, - .disable = _clk_disable, - } -}; - -static struct clk ssi_ipg_clk[]; - -static struct clk ssi_clk[] = { - { - .id = 0, - .parent = &mpll_clk, - .secondary = &ssi_ipg_clk[0], - .get_rate = _clk_ssi1_recalc, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SSI1_BAUD_REG, - .enable_shift = CCM_PCCR_SSI1_BAUD_OFFSET, - .disable = _clk_disable, - }, { - .id = 1, - .parent = &mpll_clk, - .secondary = &ssi_ipg_clk[1], - .get_rate = _clk_ssi2_recalc, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SSI2_BAUD_REG, - .enable_shift = CCM_PCCR_SSI2_BAUD_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk ssi_ipg_clk[] = { - { - .id = 0, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SSI1_REG, - .enable_shift = CCM_PCCR_SSI1_IPG_OFFSET, - .disable = _clk_disable, - }, { - .id = 1, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SSI2_REG, - .enable_shift = CCM_PCCR_SSI2_IPG_OFFSET, - .disable = _clk_disable, - }, -}; - - -static struct clk nfc_clk = { - .parent = &fclk_clk, - .get_rate = _clk_nfc_recalc, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_NFC_REG, - .enable_shift = CCM_PCCR_NFC_OFFSET, - .disable = _clk_disable, -}; - -static struct clk dma_clk[] = { - { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_DMA_REG, - .enable_shift = CCM_PCCR_DMA_OFFSET, - .disable = _clk_disable, - .secondary = &dma_clk[1], - }, { - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_DMA_REG, - .enable_shift = CCM_PCCR_HCLK_DMA_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk brom_clk = { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_BROM_REG, - .enable_shift = CCM_PCCR_HCLK_BROM_OFFSET, - .disable = _clk_disable, -}; - -static struct clk emma_clk[] = { - { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_EMMA_REG, - .enable_shift = CCM_PCCR_EMMA_OFFSET, - .disable = _clk_disable, - .secondary = &emma_clk[1], - }, { - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_EMMA_REG, - .enable_shift = CCM_PCCR_HCLK_EMMA_OFFSET, - .disable = _clk_disable, - } -}; - -static struct clk slcdc_clk[] = { - { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SLCDC_REG, - .enable_shift = CCM_PCCR_SLCDC_OFFSET, - .disable = _clk_disable, - .secondary = &slcdc_clk[1], - }, { - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_SLCDC_REG, - .enable_shift = CCM_PCCR_HCLK_SLCDC_OFFSET, - .disable = _clk_disable, - } -}; - -static struct clk wdog_clk = { - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_WDT_REG, - .enable_shift = CCM_PCCR_WDT_OFFSET, - .disable = _clk_disable, -}; - -static struct clk gpio_clk = { - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_GPIO_REG, - .enable_shift = CCM_PCCR_GPIO_OFFSET, - .disable = _clk_disable, -}; - -static struct clk i2c_clk = { - .id = 0, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_I2C1_REG, - .enable_shift = CCM_PCCR_I2C1_OFFSET, - .disable = _clk_disable, -}; - -static struct clk kpp_clk = { - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_KPP_REG, - .enable_shift = CCM_PCCR_KPP_OFFSET, - .disable = _clk_disable, -}; - -static struct clk owire_clk = { - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_OWIRE_REG, - .enable_shift = CCM_PCCR_OWIRE_OFFSET, - .disable = _clk_disable, -}; - -static struct clk rtc_clk = { - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_RTC_REG, - .enable_shift = CCM_PCCR_RTC_OFFSET, - .disable = _clk_disable, -}; - -static unsigned long _clk_clko_round_rate(struct clk *clk, unsigned long rate) -{ - return _clk_generic_round_rate(clk, rate, 8); -} - -static int _clk_clko_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg; - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 8 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - div--; - - reg = __raw_readl(CCM_PCDR0); - - if (clk->parent == &usb_clk[0]) { - reg &= ~CCM_PCDR0_48MDIV_MASK; - reg |= div << CCM_PCDR0_48MDIV_OFFSET; - } - __raw_writel(reg, CCM_PCDR0); - - return 0; -} - -static unsigned long _clk_clko_recalc(struct clk *clk) -{ - u32 div = 0; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->parent == &usb_clk[0]) /* 48M */ - div = __raw_readl(CCM_PCDR0) & CCM_PCDR0_48MDIV_MASK - >> CCM_PCDR0_48MDIV_OFFSET; - div++; - - return parent_rate / div; -} - -static struct clk clko_clk; - -static int _clk_clko_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(CCM_CCSR) & ~CCM_CCSR_CLKOSEL_MASK; - - if (parent == &ckil_clk) - reg |= 0 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &fpm_clk) - reg |= 1 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &ckih_clk) - reg |= 2 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == mpll_clk.parent) - reg |= 3 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == spll_clk.parent) - reg |= 4 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &mpll_clk) - reg |= 5 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &spll_clk) - reg |= 6 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &fclk_clk) - reg |= 7 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &hclk_clk) - reg |= 8 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &ipg_clk) - reg |= 9 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &per_clk[0]) - reg |= 0xA << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &per_clk[1]) - reg |= 0xB << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &per_clk[2]) - reg |= 0xC << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &per_clk[3]) - reg |= 0xD << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &ssi_clk[0]) - reg |= 0xE << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &ssi_clk[1]) - reg |= 0xF << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &nfc_clk) - reg |= 0x10 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &usb_clk[0]) - reg |= 0x14 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &clko_clk) - reg |= 0x15 << CCM_CCSR_CLKOSEL_OFFSET; - else - return -EINVAL; - - __raw_writel(reg, CCM_CCSR); - - return 0; -} - -static struct clk clko_clk = { - .get_rate = _clk_clko_recalc, - .set_rate = _clk_clko_set_rate, - .round_rate = _clk_clko_round_rate, - .set_parent = _clk_clko_set_parent, -}; - - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, -static struct clk_lookup lookups[] = { -/* It's unlikely that any driver wants one of them directly: - _REGISTER_CLOCK(NULL, "ckih", ckih_clk) - _REGISTER_CLOCK(NULL, "ckil", ckil_clk) - _REGISTER_CLOCK(NULL, "fpm", fpm_clk) - _REGISTER_CLOCK(NULL, "mpll", mpll_clk) - _REGISTER_CLOCK(NULL, "spll", spll_clk) - _REGISTER_CLOCK(NULL, "fclk", fclk_clk) - _REGISTER_CLOCK(NULL, "hclk", hclk_clk) - _REGISTER_CLOCK(NULL, "ipg", ipg_clk) -*/ - _REGISTER_CLOCK(NULL, "perclk1", per_clk[0]) - _REGISTER_CLOCK(NULL, "perclk2", per_clk[1]) - _REGISTER_CLOCK(NULL, "perclk3", per_clk[2]) - _REGISTER_CLOCK(NULL, "perclk4", per_clk[3]) - _REGISTER_CLOCK(NULL, "clko", clko_clk) - _REGISTER_CLOCK("imx21-uart.0", NULL, uart_clk[0]) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart_clk[1]) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart_clk[2]) - _REGISTER_CLOCK("imx21-uart.3", NULL, uart_clk[3]) - _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[0]) - _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[1]) - _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[2]) - _REGISTER_CLOCK(NULL, "pwm", pwm_clk[0]) - _REGISTER_CLOCK(NULL, "sdhc1", sdhc_clk[0]) - _REGISTER_CLOCK(NULL, "sdhc2", sdhc_clk[1]) - _REGISTER_CLOCK("imx21-cspi.0", NULL, cspi_clk[0]) - _REGISTER_CLOCK("imx21-cspi.1", NULL, cspi_clk[1]) - _REGISTER_CLOCK("imx21-cspi.2", NULL, cspi_clk[2]) - _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk[0]) - _REGISTER_CLOCK(NULL, "csi", csi_clk[0]) - _REGISTER_CLOCK("imx21-hcd.0", NULL, usb_clk[0]) - _REGISTER_CLOCK(NULL, "ssi1", ssi_clk[0]) - _REGISTER_CLOCK(NULL, "ssi2", ssi_clk[1]) - _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) - _REGISTER_CLOCK(NULL, "dma", dma_clk[0]) - _REGISTER_CLOCK(NULL, "brom", brom_clk) - _REGISTER_CLOCK(NULL, "emma", emma_clk[0]) - _REGISTER_CLOCK(NULL, "slcdc", slcdc_clk[0]) - _REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk) - _REGISTER_CLOCK(NULL, "gpio", gpio_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk) - _REGISTER_CLOCK("mxc-keypad", NULL, kpp_clk) - _REGISTER_CLOCK(NULL, "owire", owire_clk) - _REGISTER_CLOCK(NULL, "rtc", rtc_clk) -}; - -/* - * must be called very early to get information about the - * available clock rate when the timer framework starts - */ -int __init mx21_clocks_init(unsigned long lref, unsigned long href) -{ - u32 cscr; - - external_low_reference = lref; - external_high_reference = href; - - /* detect clock reference for both system PLL */ - cscr = CSCR(); - if (cscr & CCM_CSCR_MCU) - mpll_clk.parent = &ckih_clk; - else - mpll_clk.parent = &fpm_clk; - - if (cscr & CCM_CSCR_SP) - spll_clk.parent = &ckih_clk; - else - spll_clk.parent = &fpm_clk; - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - /* Turn off all clock gates */ - __raw_writel(0, CCM_PCCR0); - __raw_writel(CCM_PCCR_GPT1_MASK, CCM_PCCR1); - - /* This turns of the serial PLL as well */ - spll_clk.disable(&spll_clk); - - /* This will propagate to all children and init all the clock rates. */ - clk_enable(&per_clk[0]); - clk_enable(&gpio_clk); - -#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) - clk_enable(&uart_clk[0]); -#endif - - mxc_timer_init(&gpt_clk[0], MX21_IO_ADDRESS(MX21_GPT1_BASE_ADDR), - MX21_INT_GPT1); - return 0; -} diff --git a/arch/arm/mach-imx/clock-imx25.c b/arch/arm/mach-imx/clock-imx25.c deleted file mode 100644 index b0fec74c8c91..000000000000 --- a/arch/arm/mach-imx/clock-imx25.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * 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 <linux/kernel.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/clkdev.h> - -#include <mach/clock.h> -#include <mach/hardware.h> -#include <mach/common.h> -#include <mach/mx25.h> - -#define CRM_BASE MX25_IO_ADDRESS(MX25_CRM_BASE_ADDR) - -#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 - -static unsigned long get_rate_mpll(void) -{ - ulong mpctl = __raw_readl(CRM_BASE + CCM_MPCTL); - - return mxc_decode_pll(mpctl, 24000000); -} - -static unsigned long get_rate_upll(void) -{ - ulong mpctl = __raw_readl(CRM_BASE + CCM_UPCTL); - - return mxc_decode_pll(mpctl, 24000000); -} - -unsigned long get_rate_arm(struct clk *clk) -{ - unsigned long cctl = readl(CRM_BASE + CCM_CCTL); - unsigned long rate = get_rate_mpll(); - - if (cctl & (1 << 14)) - rate = (rate * 3) >> 2; - - return rate / ((cctl >> 30) + 1); -} - -static unsigned long get_rate_ahb(struct clk *clk) -{ - unsigned long cctl = readl(CRM_BASE + CCM_CCTL); - - return get_rate_arm(NULL) / (((cctl >> 28) & 0x3) + 1); -} - -static unsigned long get_rate_ipg(struct clk *clk) -{ - return get_rate_ahb(NULL) >> 1; -} - -static unsigned long get_rate_per(int per) -{ - unsigned long ofs = (per & 0x3) * 8; - unsigned long reg = per & ~0x3; - unsigned long val = (readl(CRM_BASE + CCM_PCDR0 + reg) >> ofs) & 0x3f; - unsigned long fref; - - if (readl(CRM_BASE + 0x64) & (1 << per)) - fref = get_rate_upll(); - else - fref = get_rate_ahb(NULL); - - return fref / (val + 1); -} - -static unsigned long get_rate_uart(struct clk *clk) -{ - return get_rate_per(15); -} - -static unsigned long get_rate_ssi2(struct clk *clk) -{ - return get_rate_per(14); -} - -static unsigned long get_rate_ssi1(struct clk *clk) -{ - return get_rate_per(13); -} - -static unsigned long get_rate_i2c(struct clk *clk) -{ - return get_rate_per(6); -} - -static unsigned long get_rate_nfc(struct clk *clk) -{ - return get_rate_per(8); -} - -static unsigned long get_rate_gpt(struct clk *clk) -{ - return get_rate_per(5); -} - -static unsigned long get_rate_lcdc(struct clk *clk) -{ - return get_rate_per(7); -} - -static unsigned long get_rate_esdhc1(struct clk *clk) -{ - return get_rate_per(3); -} - -static unsigned long get_rate_esdhc2(struct clk *clk) -{ - return get_rate_per(4); -} - -static unsigned long get_rate_csi(struct clk *clk) -{ - return get_rate_per(0); -} - -static unsigned long get_rate_otg(struct clk *clk) -{ - unsigned long cctl = readl(CRM_BASE + CCM_CCTL); - unsigned long rate = get_rate_upll(); - - return (cctl & (1 << 23)) ? 0 : rate / ((0x3F & (cctl >> 16)) + 1); -} - -static int clk_cgcr_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg |= 1 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - - return 0; -} - -static void clk_cgcr_disable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(1 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); -} - -#define DEFINE_CLOCK(name, i, er, es, gr, sr, s) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = CRM_BASE + er, \ - .enable_shift = es, \ - .get_rate = gr, \ - .set_rate = sr, \ - .enable = clk_cgcr_enable, \ - .disable = clk_cgcr_disable, \ - .secondary = s, \ - } - -/* - * Note: the following IPG clock gating bits are wrongly marked "Reserved" in - * the i.MX25 Reference Manual Rev 1, table 15-13. The information below is - * taken from the Freescale released BSP. - * - * bit reg offset clock - * - * 0 CGCR1 0 AUDMUX - * 12 CGCR1 12 ESAI - * 16 CGCR1 16 GPIO1 - * 17 CGCR1 17 GPIO2 - * 18 CGCR1 18 GPIO3 - * 23 CGCR1 23 I2C1 - * 24 CGCR1 24 I2C2 - * 25 CGCR1 25 I2C3 - * 27 CGCR1 27 IOMUXC - * 28 CGCR1 28 KPP - * 30 CGCR1 30 OWIRE - * 36 CGCR2 4 RTIC - * 51 CGCR2 19 WDOG - */ - -DEFINE_CLOCK(gpt_clk, 0, CCM_CGCR0, 5, get_rate_gpt, NULL, NULL); -DEFINE_CLOCK(uart_per_clk, 0, CCM_CGCR0, 15, get_rate_uart, NULL, NULL); -DEFINE_CLOCK(ssi1_per_clk, 0, CCM_CGCR0, 13, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(ssi2_per_clk, 0, CCM_CGCR0, 14, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(cspi1_clk, 0, CCM_CGCR1, 5, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(cspi2_clk, 0, CCM_CGCR1, 6, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(cspi3_clk, 0, CCM_CGCR1, 7, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(esdhc1_ahb_clk, 0, CCM_CGCR0, 21, get_rate_esdhc1, NULL, NULL); -DEFINE_CLOCK(esdhc1_per_clk, 0, CCM_CGCR0, 3, get_rate_esdhc1, NULL, - &esdhc1_ahb_clk); -DEFINE_CLOCK(esdhc2_ahb_clk, 0, CCM_CGCR0, 22, get_rate_esdhc2, NULL, NULL); -DEFINE_CLOCK(esdhc2_per_clk, 0, CCM_CGCR0, 4, get_rate_esdhc2, NULL, - &esdhc2_ahb_clk); -DEFINE_CLOCK(sdma_ahb_clk, 0, CCM_CGCR0, 26, NULL, NULL, NULL); -DEFINE_CLOCK(fec_ahb_clk, 0, CCM_CGCR0, 23, NULL, NULL, NULL); -DEFINE_CLOCK(lcdc_ahb_clk, 0, CCM_CGCR0, 24, NULL, NULL, NULL); -DEFINE_CLOCK(lcdc_per_clk, 0, CCM_CGCR0, 7, NULL, NULL, &lcdc_ahb_clk); -DEFINE_CLOCK(csi_ahb_clk, 0, CCM_CGCR0, 18, get_rate_csi, NULL, NULL); -DEFINE_CLOCK(csi_per_clk, 0, CCM_CGCR0, 0, get_rate_csi, NULL, &csi_ahb_clk); -DEFINE_CLOCK(uart1_clk, 0, CCM_CGCR2, 14, get_rate_uart, NULL, &uart_per_clk); -DEFINE_CLOCK(uart2_clk, 0, CCM_CGCR2, 15, get_rate_uart, NULL, &uart_per_clk); -DEFINE_CLOCK(uart3_clk, 0, CCM_CGCR2, 16, get_rate_uart, NULL, &uart_per_clk); -DEFINE_CLOCK(uart4_clk, 0, CCM_CGCR2, 17, get_rate_uart, NULL, &uart_per_clk); -DEFINE_CLOCK(uart5_clk, 0, CCM_CGCR2, 18, get_rate_uart, NULL, &uart_per_clk); -DEFINE_CLOCK(nfc_clk, 0, CCM_CGCR0, 8, get_rate_nfc, NULL, NULL); -DEFINE_CLOCK(usbotg_clk, 0, CCM_CGCR0, 28, get_rate_otg, NULL, NULL); -DEFINE_CLOCK(pwm1_clk, 0, CCM_CGCR1, 31, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(pwm2_clk, 0, CCM_CGCR2, 0, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(pwm3_clk, 0, CCM_CGCR2, 1, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(pwm4_clk, 0, CCM_CGCR2, 2, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(kpp_clk, 0, CCM_CGCR1, 28, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(tsc_clk, 0, CCM_CGCR2, 13, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(i2c_clk, 0, CCM_CGCR0, 6, get_rate_i2c, NULL, NULL); -DEFINE_CLOCK(fec_clk, 0, CCM_CGCR1, 15, get_rate_ipg, NULL, &fec_ahb_clk); -DEFINE_CLOCK(dryice_clk, 0, CCM_CGCR1, 8, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(lcdc_clk, 0, CCM_CGCR1, 29, get_rate_lcdc, NULL, &lcdc_per_clk); -DEFINE_CLOCK(wdt_clk, 0, CCM_CGCR2, 19, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(ssi1_clk, 0, CCM_CGCR2, 11, get_rate_ssi1, NULL, &ssi1_per_clk); -DEFINE_CLOCK(ssi2_clk, 1, CCM_CGCR2, 12, get_rate_ssi2, NULL, &ssi2_per_clk); -DEFINE_CLOCK(sdma_clk, 0, CCM_CGCR2, 6, get_rate_ipg, NULL, &sdma_ahb_clk); -DEFINE_CLOCK(esdhc1_clk, 0, CCM_CGCR1, 13, get_rate_esdhc1, NULL, - &esdhc1_per_clk); -DEFINE_CLOCK(esdhc2_clk, 1, CCM_CGCR1, 14, get_rate_esdhc2, NULL, - &esdhc2_per_clk); -DEFINE_CLOCK(audmux_clk, 0, CCM_CGCR1, 0, NULL, NULL, NULL); -DEFINE_CLOCK(csi_clk, 0, CCM_CGCR1, 4, get_rate_csi, NULL, &csi_per_clk); -DEFINE_CLOCK(can1_clk, 0, CCM_CGCR1, 2, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(can2_clk, 1, CCM_CGCR1, 3, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(iim_clk, 0, CCM_CGCR1, 26, NULL, NULL, NULL); - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup lookups[] = { - /* i.mx25 has the i.mx21 type uart */ - _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk) - _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb", usbotg_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk) - _REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb", usbotg_clk) - _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) - /* i.mx25 has the i.mx35 type cspi */ - _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi1_clk) - _REGISTER_CLOCK("imx35-cspi.1", NULL, cspi2_clk) - _REGISTER_CLOCK("imx35-cspi.2", NULL, cspi3_clk) - _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm1_clk) - _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk) - _REGISTER_CLOCK("mxc_pwm.2", NULL, pwm3_clk) - _REGISTER_CLOCK("mxc_pwm.3", NULL, pwm4_clk) - _REGISTER_CLOCK("imx-keypad", NULL, kpp_clk) - _REGISTER_CLOCK("mx25-adc", NULL, tsc_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk) - _REGISTER_CLOCK("imx-i2c.2", NULL, i2c_clk) - _REGISTER_CLOCK("imx25-fec.0", NULL, fec_clk) - _REGISTER_CLOCK("imxdi_rtc.0", NULL, dryice_clk) - _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, wdt_clk) - _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) - _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx25.0", NULL, esdhc1_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx25.1", NULL, esdhc2_clk) - _REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk) - _REGISTER_CLOCK(NULL, "audmux", audmux_clk) - _REGISTER_CLOCK("flexcan.0", NULL, can1_clk) - _REGISTER_CLOCK("flexcan.1", NULL, can2_clk) - /* i.mx25 has the i.mx35 type sdma */ - _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk) - _REGISTER_CLOCK(NULL, "iim", iim_clk) -}; - -int __init mx25_clocks_init(void) -{ - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - /* Turn off all clocks except the ones we need to survive, namely: - * EMI, GPIO1-3 (CCM_CGCR1[18:16]), GPT1, IOMUXC (CCM_CGCR1[27]), IIM, - * SCC - */ - __raw_writel((1 << 19), CRM_BASE + CCM_CGCR0); - __raw_writel((0xf << 16) | (3 << 26), CRM_BASE + CCM_CGCR1); - __raw_writel((1 << 5), CRM_BASE + CCM_CGCR2); -#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) - clk_enable(&uart1_clk); -#endif - - /* Clock source for lcdc and csi is upll */ - __raw_writel(__raw_readl(CRM_BASE+0x64) | (1 << 7) | (1 << 0), - CRM_BASE + 0x64); - - /* Clock source for gpt is ahb_div */ - __raw_writel(__raw_readl(CRM_BASE+0x64) & ~(1 << 5), CRM_BASE + 0x64); - - clk_enable(&iim_clk); - imx_print_silicon_rev("i.MX25", mx25_revision()); - clk_disable(&iim_clk); - - mxc_timer_init(&gpt_clk, MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54); - - return 0; -} diff --git a/arch/arm/mach-imx/clock-imx27.c b/arch/arm/mach-imx/clock-imx27.c deleted file mode 100644 index 98e04f5a87dd..000000000000 --- a/arch/arm/mach-imx/clock-imx27.c +++ /dev/null @@ -1,785 +0,0 @@ -/* - * 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 <linux/clk.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/clkdev.h> -#include <linux/of.h> - -#include <asm/div64.h> - -#include <mach/clock.h> -#include <mach/common.h> -#include <mach/hardware.h> - -#define IO_ADDR_CCM(off) (MX27_IO_ADDRESS(MX27_CCM_BASE_ADDR + (off))) - -/* Register offsets */ -#define CCM_CSCR IO_ADDR_CCM(0x0) -#define CCM_MPCTL0 IO_ADDR_CCM(0x4) -#define CCM_MPCTL1 IO_ADDR_CCM(0x8) -#define CCM_SPCTL0 IO_ADDR_CCM(0xc) -#define CCM_SPCTL1 IO_ADDR_CCM(0x10) -#define CCM_OSC26MCTL IO_ADDR_CCM(0x14) -#define CCM_PCDR0 IO_ADDR_CCM(0x18) -#define CCM_PCDR1 IO_ADDR_CCM(0x1c) -#define CCM_PCCR0 IO_ADDR_CCM(0x20) -#define CCM_PCCR1 IO_ADDR_CCM(0x24) -#define CCM_CCSR IO_ADDR_CCM(0x28) -#define CCM_PMCTL IO_ADDR_CCM(0x2c) -#define CCM_PMCOUNT IO_ADDR_CCM(0x30) -#define CCM_WKGDCTL IO_ADDR_CCM(0x34) - -#define CCM_CSCR_UPDATE_DIS (1 << 31) -#define CCM_CSCR_SSI2 (1 << 23) -#define CCM_CSCR_SSI1 (1 << 22) -#define CCM_CSCR_VPU (1 << 21) -#define CCM_CSCR_MSHC (1 << 20) -#define CCM_CSCR_SPLLRES (1 << 19) -#define CCM_CSCR_MPLLRES (1 << 18) -#define CCM_CSCR_SP (1 << 17) -#define CCM_CSCR_MCU (1 << 16) -#define CCM_CSCR_OSC26MDIV (1 << 4) -#define CCM_CSCR_OSC26M (1 << 3) -#define CCM_CSCR_FPM (1 << 2) -#define CCM_CSCR_SPEN (1 << 1) -#define CCM_CSCR_MPEN (1 << 0) - -/* i.MX27 TO 2+ */ -#define CCM_CSCR_ARM_SRC (1 << 15) - -#define CCM_SPCTL1_LF (1 << 15) -#define CCM_SPCTL1_BRMO (1 << 6) - -static struct clk mpll_main1_clk, mpll_main2_clk; - -static int clk_pccr_enable(struct clk *clk) -{ - unsigned long reg; - - if (!clk->enable_reg) - return 0; - - reg = __raw_readl(clk->enable_reg); - reg |= 1 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - - return 0; -} - -static void clk_pccr_disable(struct clk *clk) -{ - unsigned long reg; - - if (!clk->enable_reg) - return; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(1 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); -} - -static int clk_spll_enable(struct clk *clk) -{ - unsigned long reg; - - reg = __raw_readl(CCM_CSCR); - reg |= CCM_CSCR_SPEN; - __raw_writel(reg, CCM_CSCR); - - while (!(__raw_readl(CCM_SPCTL1) & CCM_SPCTL1_LF)); - - return 0; -} - -static void clk_spll_disable(struct clk *clk) -{ - unsigned long reg; - - reg = __raw_readl(CCM_CSCR); - reg &= ~CCM_CSCR_SPEN; - __raw_writel(reg, CCM_CSCR); -} - -static int clk_cpu_set_parent(struct clk *clk, struct clk *parent) -{ - int cscr = __raw_readl(CCM_CSCR); - - if (clk->parent == parent) - return 0; - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { - if (parent == &mpll_main1_clk) { - cscr |= CCM_CSCR_ARM_SRC; - } else { - if (parent == &mpll_main2_clk) - cscr &= ~CCM_CSCR_ARM_SRC; - else - return -EINVAL; - } - __raw_writel(cscr, CCM_CSCR); - clk->parent = parent; - return 0; - } - return -ENODEV; -} - -static unsigned long round_rate_cpu(struct clk *clk, unsigned long rate) -{ - int div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (parent_rate % rate) - div++; - - if (div > 4) - div = 4; - - return parent_rate / div; -} - -static int set_rate_cpu(struct clk *clk, unsigned long rate) -{ - unsigned int div; - uint32_t reg; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 4 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - div--; - - reg = __raw_readl(CCM_CSCR); - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { - reg &= ~(3 << 12); - reg |= div << 12; - reg &= ~(CCM_CSCR_FPM | CCM_CSCR_SPEN); - __raw_writel(reg | CCM_CSCR_UPDATE_DIS, CCM_CSCR); - } else { - printk(KERN_ERR "Can't set CPU frequency!\n"); - } - - return 0; -} - -static unsigned long round_rate_per(struct clk *clk, unsigned long rate) -{ - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (parent_rate % rate) - div++; - - if (div > 64) - div = 64; - - return parent_rate / div; -} - -static int set_rate_per(struct clk *clk, unsigned long rate) -{ - u32 reg; - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->id < 0 || clk->id > 3) - return -EINVAL; - - div = parent_rate / rate; - if (div > 64 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - div--; - - reg = __raw_readl(CCM_PCDR1) & ~(0x3f << (clk->id << 3)); - reg |= div << (clk->id << 3); - __raw_writel(reg, CCM_PCDR1); - - return 0; -} - -static unsigned long get_rate_usb(struct clk *clk) -{ - unsigned long usb_pdf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - usb_pdf = (__raw_readl(CCM_CSCR) >> 28) & 0x7; - - return parent_rate / (usb_pdf + 1U); -} - -static unsigned long get_rate_ssix(struct clk *clk, unsigned long pdf) -{ - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) - pdf += 4; /* MX27 TO2+ */ - else - pdf = (pdf < 2) ? 124UL : pdf; /* MX21 & MX27 TO1 */ - - return 2UL * parent_rate / pdf; -} - -static unsigned long get_rate_ssi1(struct clk *clk) -{ - return get_rate_ssix(clk, (__raw_readl(CCM_PCDR0) >> 16) & 0x3f); -} - -static unsigned long get_rate_ssi2(struct clk *clk) -{ - return get_rate_ssix(clk, (__raw_readl(CCM_PCDR0) >> 26) & 0x3f); -} - -static unsigned long get_rate_nfc(struct clk *clk) -{ - unsigned long nfc_pdf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) - nfc_pdf = (__raw_readl(CCM_PCDR0) >> 6) & 0xf; - else - nfc_pdf = (__raw_readl(CCM_PCDR0) >> 12) & 0xf; - - return parent_rate / (nfc_pdf + 1); -} - -static unsigned long get_rate_vpu(struct clk *clk) -{ - unsigned long vpu_pdf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { - vpu_pdf = (__raw_readl(CCM_PCDR0) >> 10) & 0x3f; - vpu_pdf += 4; - } else { - vpu_pdf = (__raw_readl(CCM_PCDR0) >> 8) & 0xf; - vpu_pdf = (vpu_pdf < 2) ? 124 : vpu_pdf; - } - - return 2UL * parent_rate / vpu_pdf; -} - -static unsigned long round_rate_parent(struct clk *clk, unsigned long rate) -{ - return clk->parent->round_rate(clk->parent, rate); -} - -static unsigned long get_rate_parent(struct clk *clk) -{ - return clk_get_rate(clk->parent); -} - -static int set_rate_parent(struct clk *clk, unsigned long rate) -{ - return clk->parent->set_rate(clk->parent, rate); -} - -/* in Hz */ -static unsigned long external_high_reference = 26000000; - -static unsigned long get_rate_high_reference(struct clk *clk) -{ - return external_high_reference; -} - -/* in Hz */ -static unsigned long external_low_reference = 32768; - -static unsigned long get_rate_low_reference(struct clk *clk) -{ - return external_low_reference; -} - -static unsigned long get_rate_fpm(struct clk *clk) -{ - return clk_get_rate(clk->parent) * 1024; -} - -static unsigned long get_rate_mpll(struct clk *clk) -{ - return mxc_decode_pll(__raw_readl(CCM_MPCTL0), - clk_get_rate(clk->parent)); -} - -static unsigned long get_rate_mpll_main(struct clk *clk) -{ - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - /* i.MX27 TO2: - * clk->id == 0: arm clock source path 1 which is from 2 * MPLL / 2 - * clk->id == 1: arm clock source path 2 which is from 2 * MPLL / 3 - */ - if (mx27_revision() >= IMX_CHIP_REVISION_2_0 && clk->id == 1) - return 2UL * parent_rate / 3UL; - - return parent_rate; -} - -static unsigned long get_rate_spll(struct clk *clk) -{ - uint32_t reg; - unsigned long rate; - - rate = clk_get_rate(clk->parent); - - reg = __raw_readl(CCM_SPCTL0); - - /* On TO2 we have to write the value back. Otherwise we - * read 0 from this register the next time. - */ - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) - __raw_writel(reg, CCM_SPCTL0); - - return mxc_decode_pll(reg, rate); -} - -static unsigned long get_rate_cpu(struct clk *clk) -{ - u32 div; - unsigned long rate; - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) - div = (__raw_readl(CCM_CSCR) >> 12) & 0x3; - else - div = (__raw_readl(CCM_CSCR) >> 13) & 0x7; - - rate = clk_get_rate(clk->parent); - return rate / (div + 1); -} - -static unsigned long get_rate_ahb(struct clk *clk) -{ - unsigned long rate, bclk_pdf; - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) - bclk_pdf = (__raw_readl(CCM_CSCR) >> 8) & 0x3; - else - bclk_pdf = (__raw_readl(CCM_CSCR) >> 9) & 0xf; - - rate = clk_get_rate(clk->parent); - return rate / (bclk_pdf + 1); -} - -static unsigned long get_rate_ipg(struct clk *clk) -{ - unsigned long rate, ipg_pdf; - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) - return clk_get_rate(clk->parent); - else - ipg_pdf = (__raw_readl(CCM_CSCR) >> 8) & 1; - - rate = clk_get_rate(clk->parent); - return rate / (ipg_pdf + 1); -} - -static unsigned long get_rate_per(struct clk *clk) -{ - unsigned long perclk_pdf, parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->id < 0 || clk->id > 3) - return 0; - - perclk_pdf = (__raw_readl(CCM_PCDR1) >> (clk->id << 3)) & 0x3f; - - return parent_rate / (perclk_pdf + 1); -} - -/* - * the high frequency external clock reference - * Default case is 26MHz. Could be changed at runtime - * with a call to change_external_high_reference() - */ -static struct clk ckih_clk = { - .get_rate = get_rate_high_reference, -}; - -static struct clk mpll_clk = { - .parent = &ckih_clk, - .get_rate = get_rate_mpll, -}; - -/* For i.MX27 TO2, it is the MPLL path 1 of ARM core - * It provides the clock source whose rate is same as MPLL - */ -static struct clk mpll_main1_clk = { - .id = 0, - .parent = &mpll_clk, - .get_rate = get_rate_mpll_main, -}; - -/* For i.MX27 TO2, it is the MPLL path 2 of ARM core - * It provides the clock source whose rate is same MPLL * 2 / 3 - */ -static struct clk mpll_main2_clk = { - .id = 1, - .parent = &mpll_clk, - .get_rate = get_rate_mpll_main, -}; - -static struct clk ahb_clk = { - .parent = &mpll_main2_clk, - .get_rate = get_rate_ahb, -}; - -static struct clk ipg_clk = { - .parent = &ahb_clk, - .get_rate = get_rate_ipg, -}; - -static struct clk cpu_clk = { - .parent = &mpll_main2_clk, - .set_parent = clk_cpu_set_parent, - .round_rate = round_rate_cpu, - .get_rate = get_rate_cpu, - .set_rate = set_rate_cpu, -}; - -static struct clk spll_clk = { - .parent = &ckih_clk, - .get_rate = get_rate_spll, - .enable = clk_spll_enable, - .disable = clk_spll_disable, -}; - -/* - * the low frequency external clock reference - * Default case is 32.768kHz. - */ -static struct clk ckil_clk = { - .get_rate = get_rate_low_reference, -}; - -/* Output of frequency pre multiplier */ -static struct clk fpm_clk = { - .parent = &ckil_clk, - .get_rate = get_rate_fpm, -}; - -#define PCCR0 CCM_PCCR0 -#define PCCR1 CCM_PCCR1 - -#define DEFINE_CLOCK(name, i, er, es, gr, s, p) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = gr, \ - .enable = clk_pccr_enable, \ - .disable = clk_pccr_disable, \ - .secondary = s, \ - .parent = p, \ - } - -#define DEFINE_CLOCK1(name, i, er, es, getsetround, s, p) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = get_rate_##getsetround, \ - .set_rate = set_rate_##getsetround, \ - .round_rate = round_rate_##getsetround, \ - .enable = clk_pccr_enable, \ - .disable = clk_pccr_disable, \ - .secondary = s, \ - .parent = p, \ - } - -/* Forward declaration to keep the following list in order */ -static struct clk slcdc_clk1, sahara2_clk1, rtic_clk1, fec_clk1, emma_clk1, - dma_clk1, lcdc_clk2, vpu_clk1; - -/* All clocks we can gate through PCCRx in the order of PCCRx bits */ -DEFINE_CLOCK(ssi2_clk1, 1, PCCR0, 0, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(ssi1_clk1, 0, PCCR0, 1, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(slcdc_clk, 0, PCCR0, 2, NULL, &slcdc_clk1, &ahb_clk); -DEFINE_CLOCK(sdhc3_clk1, 0, PCCR0, 3, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(sdhc2_clk1, 0, PCCR0, 4, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(sdhc1_clk1, 0, PCCR0, 5, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(scc_clk, 0, PCCR0, 6, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(sahara2_clk, 0, PCCR0, 7, NULL, &sahara2_clk1, &ahb_clk); -DEFINE_CLOCK(rtic_clk, 0, PCCR0, 8, NULL, &rtic_clk1, &ahb_clk); -DEFINE_CLOCK(rtc_clk, 0, PCCR0, 9, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(pwm_clk1, 0, PCCR0, 11, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(owire_clk, 0, PCCR0, 12, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(mstick_clk1, 0, PCCR0, 13, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(lcdc_clk1, 0, PCCR0, 14, NULL, &lcdc_clk2, &ipg_clk); -DEFINE_CLOCK(kpp_clk, 0, PCCR0, 15, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(iim_clk, 0, PCCR0, 16, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(i2c2_clk, 1, PCCR0, 17, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(i2c1_clk, 0, PCCR0, 18, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpt6_clk1, 0, PCCR0, 29, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpt5_clk1, 0, PCCR0, 20, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpt4_clk1, 0, PCCR0, 21, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpt3_clk1, 0, PCCR0, 22, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpt2_clk1, 0, PCCR0, 23, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpt1_clk1, 0, PCCR0, 24, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpio_clk, 0, PCCR0, 25, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(fec_clk, 0, PCCR0, 26, NULL, &fec_clk1, &ahb_clk); -DEFINE_CLOCK(emma_clk, 0, PCCR0, 27, NULL, &emma_clk1, &ahb_clk); -DEFINE_CLOCK(dma_clk, 0, PCCR0, 28, NULL, &dma_clk1, &ahb_clk); -DEFINE_CLOCK(cspi13_clk1, 0, PCCR0, 29, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(cspi2_clk1, 0, PCCR0, 30, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(cspi1_clk1, 0, PCCR0, 31, NULL, NULL, &ipg_clk); - -DEFINE_CLOCK(mstick_clk, 0, PCCR1, 2, NULL, &mstick_clk1, &ipg_clk); -DEFINE_CLOCK(nfc_clk, 0, PCCR1, 3, get_rate_nfc, NULL, &cpu_clk); -DEFINE_CLOCK(ssi2_clk, 1, PCCR1, 4, get_rate_ssi2, &ssi2_clk1, &mpll_main2_clk); -DEFINE_CLOCK(ssi1_clk, 0, PCCR1, 5, get_rate_ssi1, &ssi1_clk1, &mpll_main2_clk); -DEFINE_CLOCK(vpu_clk, 0, PCCR1, 6, get_rate_vpu, &vpu_clk1, &mpll_main2_clk); -DEFINE_CLOCK1(per4_clk, 3, PCCR1, 7, per, NULL, &mpll_main2_clk); -DEFINE_CLOCK1(per3_clk, 2, PCCR1, 8, per, NULL, &mpll_main2_clk); -DEFINE_CLOCK1(per2_clk, 1, PCCR1, 9, per, NULL, &mpll_main2_clk); -DEFINE_CLOCK1(per1_clk, 0, PCCR1, 10, per, NULL, &mpll_main2_clk); -DEFINE_CLOCK(usb_clk1, 0, PCCR1, 11, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(slcdc_clk1, 0, PCCR1, 12, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(sahara2_clk1, 0, PCCR1, 13, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(rtic_clk1, 0, PCCR1, 14, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(lcdc_clk2, 0, PCCR1, 15, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(vpu_clk1, 0, PCCR1, 16, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(fec_clk1, 0, PCCR1, 17, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(emma_clk1, 0, PCCR1, 18, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(emi_clk, 0, PCCR1, 19, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(dma_clk1, 0, PCCR1, 20, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(csi_clk1, 0, PCCR1, 21, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(brom_clk, 0, PCCR1, 22, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(pata_clk, 0, PCCR1, 23, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(wdog_clk, 0, PCCR1, 24, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(usb_clk, 0, PCCR1, 25, get_rate_usb, &usb_clk1, &spll_clk); -DEFINE_CLOCK(uart6_clk1, 0, PCCR1, 26, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(uart5_clk1, 0, PCCR1, 27, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(uart4_clk1, 0, PCCR1, 28, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(uart3_clk1, 0, PCCR1, 29, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(uart2_clk1, 0, PCCR1, 30, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(uart1_clk1, 0, PCCR1, 31, NULL, NULL, &ipg_clk); - -/* Clocks we cannot directly gate, but drivers need their rates */ -DEFINE_CLOCK(cspi1_clk, 0, NULL, 0, NULL, &cspi1_clk1, &per2_clk); -DEFINE_CLOCK(cspi2_clk, 1, NULL, 0, NULL, &cspi2_clk1, &per2_clk); -DEFINE_CLOCK(cspi3_clk, 2, NULL, 0, NULL, &cspi13_clk1, &per2_clk); -DEFINE_CLOCK(sdhc1_clk, 0, NULL, 0, NULL, &sdhc1_clk1, &per2_clk); -DEFINE_CLOCK(sdhc2_clk, 1, NULL, 0, NULL, &sdhc2_clk1, &per2_clk); -DEFINE_CLOCK(sdhc3_clk, 2, NULL, 0, NULL, &sdhc3_clk1, &per2_clk); -DEFINE_CLOCK(pwm_clk, 0, NULL, 0, NULL, &pwm_clk1, &per1_clk); -DEFINE_CLOCK(gpt1_clk, 0, NULL, 0, NULL, &gpt1_clk1, &per1_clk); -DEFINE_CLOCK(gpt2_clk, 1, NULL, 0, NULL, &gpt2_clk1, &per1_clk); -DEFINE_CLOCK(gpt3_clk, 2, NULL, 0, NULL, &gpt3_clk1, &per1_clk); -DEFINE_CLOCK(gpt4_clk, 3, NULL, 0, NULL, &gpt4_clk1, &per1_clk); -DEFINE_CLOCK(gpt5_clk, 4, NULL, 0, NULL, &gpt5_clk1, &per1_clk); -DEFINE_CLOCK(gpt6_clk, 5, NULL, 0, NULL, &gpt6_clk1, &per1_clk); -DEFINE_CLOCK(uart1_clk, 0, NULL, 0, NULL, &uart1_clk1, &per1_clk); -DEFINE_CLOCK(uart2_clk, 1, NULL, 0, NULL, &uart2_clk1, &per1_clk); -DEFINE_CLOCK(uart3_clk, 2, NULL, 0, NULL, &uart3_clk1, &per1_clk); -DEFINE_CLOCK(uart4_clk, 3, NULL, 0, NULL, &uart4_clk1, &per1_clk); -DEFINE_CLOCK(uart5_clk, 4, NULL, 0, NULL, &uart5_clk1, &per1_clk); -DEFINE_CLOCK(uart6_clk, 5, NULL, 0, NULL, &uart6_clk1, &per1_clk); -DEFINE_CLOCK1(lcdc_clk, 0, NULL, 0, parent, &lcdc_clk1, &per3_clk); -DEFINE_CLOCK1(csi_clk, 0, NULL, 0, parent, &csi_clk1, &per4_clk); - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup lookups[] = { - /* i.mx27 has the i.mx21 type uart */ - _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk) - _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk) - _REGISTER_CLOCK("imx21-uart.5", NULL, uart6_clk) - _REGISTER_CLOCK(NULL, "gpt1", gpt1_clk) - _REGISTER_CLOCK(NULL, "gpt2", gpt2_clk) - _REGISTER_CLOCK(NULL, "gpt3", gpt3_clk) - _REGISTER_CLOCK(NULL, "gpt4", gpt4_clk) - _REGISTER_CLOCK(NULL, "gpt5", gpt5_clk) - _REGISTER_CLOCK(NULL, "gpt6", gpt6_clk) - _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm_clk) - _REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk) - _REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk) - _REGISTER_CLOCK("mxc-mmc.2", NULL, sdhc3_clk) - _REGISTER_CLOCK("imx27-cspi.0", NULL, cspi1_clk) - _REGISTER_CLOCK("imx27-cspi.1", NULL, cspi2_clk) - _REGISTER_CLOCK("imx27-cspi.2", NULL, cspi3_clk) - _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk) - _REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk1) - _REGISTER_CLOCK("mxc-ehci.0", "usb", usb_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_clk1) - _REGISTER_CLOCK("mxc-ehci.1", "usb", usb_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_clk1) - _REGISTER_CLOCK("mxc-ehci.2", "usb", usb_clk) - _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_clk1) - _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) - _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) - _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) - _REGISTER_CLOCK(NULL, "vpu", vpu_clk) - _REGISTER_CLOCK(NULL, "dma", dma_clk) - _REGISTER_CLOCK(NULL, "rtic", rtic_clk) - _REGISTER_CLOCK(NULL, "brom", brom_clk) - _REGISTER_CLOCK(NULL, "emma", emma_clk) - _REGISTER_CLOCK("m2m-emmaprp.0", NULL, emma_clk) - _REGISTER_CLOCK(NULL, "slcdc", slcdc_clk) - _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk) - _REGISTER_CLOCK(NULL, "emi", emi_clk) - _REGISTER_CLOCK(NULL, "sahara2", sahara2_clk) - _REGISTER_CLOCK("pata_imx", NULL, pata_clk) - _REGISTER_CLOCK(NULL, "mstick", mstick_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk) - _REGISTER_CLOCK(NULL, "gpio", gpio_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) - _REGISTER_CLOCK(NULL, "iim", iim_clk) - _REGISTER_CLOCK(NULL, "kpp", kpp_clk) - _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk) - _REGISTER_CLOCK(NULL, "rtc", rtc_clk) - _REGISTER_CLOCK(NULL, "scc", scc_clk) -}; - -/* Adjust the clock path for TO2 and later */ -static void __init to2_adjust_clocks(void) -{ - unsigned long cscr = __raw_readl(CCM_CSCR); - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { - if (cscr & CCM_CSCR_ARM_SRC) - cpu_clk.parent = &mpll_main1_clk; - - if (!(cscr & CCM_CSCR_SSI2)) - ssi1_clk.parent = &spll_clk; - - if (!(cscr & CCM_CSCR_SSI1)) - ssi1_clk.parent = &spll_clk; - - if (!(cscr & CCM_CSCR_VPU)) - vpu_clk.parent = &spll_clk; - } else { - cpu_clk.parent = &mpll_clk; - cpu_clk.set_parent = NULL; - cpu_clk.round_rate = NULL; - cpu_clk.set_rate = NULL; - ahb_clk.parent = &mpll_clk; - - per1_clk.parent = &mpll_clk; - per2_clk.parent = &mpll_clk; - per3_clk.parent = &mpll_clk; - per4_clk.parent = &mpll_clk; - - ssi1_clk.parent = &mpll_clk; - ssi2_clk.parent = &mpll_clk; - - vpu_clk.parent = &mpll_clk; - } -} - -/* - * must be called very early to get information about the - * available clock rate when the timer framework starts - */ -int __init mx27_clocks_init(unsigned long fref) -{ - u32 cscr = __raw_readl(CCM_CSCR); - - external_high_reference = fref; - - /* detect clock reference for both system PLLs */ - if (cscr & CCM_CSCR_MCU) - mpll_clk.parent = &ckih_clk; - else - mpll_clk.parent = &fpm_clk; - - if (cscr & CCM_CSCR_SP) - spll_clk.parent = &ckih_clk; - else - spll_clk.parent = &fpm_clk; - - to2_adjust_clocks(); - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - /* Turn off all clocks we do not need */ - __raw_writel(0, CCM_PCCR0); - __raw_writel((1 << 10) | (1 << 19), CCM_PCCR1); - - spll_clk.disable(&spll_clk); - - /* enable basic clocks */ - clk_enable(&per1_clk); - clk_enable(&gpio_clk); - clk_enable(&emi_clk); - clk_enable(&iim_clk); - imx_print_silicon_rev("i.MX27", mx27_revision()); - clk_disable(&iim_clk); - -#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) - clk_enable(&uart1_clk); -#endif - - mxc_timer_init(&gpt1_clk, MX27_IO_ADDRESS(MX27_GPT1_BASE_ADDR), - MX27_INT_GPT1); - - return 0; -} - -#ifdef CONFIG_OF -int __init mx27_clocks_init_dt(void) -{ - struct device_node *np; - u32 fref = 26000000; /* default */ - - for_each_compatible_node(np, NULL, "fixed-clock") { - if (!of_device_is_compatible(np, "fsl,imx-osc26m")) - continue; - - if (!of_property_read_u32(np, "clock-frequency", &fref)) - break; - } - - return mx27_clocks_init(fref); -} -#endif diff --git a/arch/arm/mach-imx/clock-imx31.c b/arch/arm/mach-imx/clock-imx31.c deleted file mode 100644 index 3a943cd4159f..000000000000 --- a/arch/arm/mach-imx/clock-imx31.c +++ /dev/null @@ -1,630 +0,0 @@ -/* - * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright (C) 2008 by 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, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/clkdev.h> - -#include <asm/div64.h> - -#include <mach/clock.h> -#include <mach/hardware.h> -#include <mach/mx31.h> -#include <mach/common.h> - -#include "crmregs-imx3.h" - -#define PRE_DIV_MIN_FREQ 10000000 /* Minimum Frequency after Predivider */ - -static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post) -{ - u32 min_pre, temp_pre, old_err, err; - - if (div >= 512) { - *pre = 8; - *post = 64; - } else if (div >= 64) { - min_pre = (div - 1) / 64 + 1; - old_err = 8; - for (temp_pre = 8; temp_pre >= min_pre; temp_pre--) { - err = div % temp_pre; - if (err == 0) { - *pre = temp_pre; - break; - } - err = temp_pre - err; - if (err < old_err) { - old_err = err; - *pre = temp_pre; - } - } - *post = (div + *pre - 1) / *pre; - } else if (div <= 8) { - *pre = div; - *post = 1; - } else { - *pre = 1; - *post = div; - } -} - -static struct clk mcu_pll_clk; -static struct clk serial_pll_clk; -static struct clk ipg_clk; -static struct clk ckih_clk; - -static int cgr_enable(struct clk *clk) -{ - u32 reg; - - if (!clk->enable_reg) - return 0; - - reg = __raw_readl(clk->enable_reg); - reg |= 3 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - - return 0; -} - -static void cgr_disable(struct clk *clk) -{ - u32 reg; - - if (!clk->enable_reg) - return; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(3 << clk->enable_shift); - - /* special case for EMI clock */ - if (clk->enable_reg == MXC_CCM_CGR2 && clk->enable_shift == 8) - reg |= (1 << clk->enable_shift); - - __raw_writel(reg, clk->enable_reg); -} - -static unsigned long pll_ref_get_rate(void) -{ - unsigned long ccmr; - unsigned int prcs; - - ccmr = __raw_readl(MXC_CCM_CCMR); - prcs = (ccmr & MXC_CCM_CCMR_PRCS_MASK) >> MXC_CCM_CCMR_PRCS_OFFSET; - if (prcs == 0x1) - return CKIL_CLK_FREQ * 1024; - else - return clk_get_rate(&ckih_clk); -} - -static unsigned long usb_pll_get_rate(struct clk *clk) -{ - unsigned long reg; - - reg = __raw_readl(MXC_CCM_UPCTL); - - return mxc_decode_pll(reg, pll_ref_get_rate()); -} - -static unsigned long serial_pll_get_rate(struct clk *clk) -{ - unsigned long reg; - - reg = __raw_readl(MXC_CCM_SRPCTL); - - return mxc_decode_pll(reg, pll_ref_get_rate()); -} - -static unsigned long mcu_pll_get_rate(struct clk *clk) -{ - unsigned long reg, ccmr; - - ccmr = __raw_readl(MXC_CCM_CCMR); - - if (!(ccmr & MXC_CCM_CCMR_MPE) || (ccmr & MXC_CCM_CCMR_MDS)) - return clk_get_rate(&ckih_clk); - - reg = __raw_readl(MXC_CCM_MPCTL); - - return mxc_decode_pll(reg, pll_ref_get_rate()); -} - -static int usb_pll_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CCMR); - reg |= MXC_CCM_CCMR_UPE; - __raw_writel(reg, MXC_CCM_CCMR); - - /* No lock bit on MX31, so using max time from spec */ - udelay(80); - - return 0; -} - -static void usb_pll_disable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CCMR); - reg &= ~MXC_CCM_CCMR_UPE; - __raw_writel(reg, MXC_CCM_CCMR); -} - -static int serial_pll_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CCMR); - reg |= MXC_CCM_CCMR_SPE; - __raw_writel(reg, MXC_CCM_CCMR); - - /* No lock bit on MX31, so using max time from spec */ - udelay(80); - - return 0; -} - -static void serial_pll_disable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CCMR); - reg &= ~MXC_CCM_CCMR_SPE; - __raw_writel(reg, MXC_CCM_CCMR); -} - -#define PDR0(mask, off) ((__raw_readl(MXC_CCM_PDR0) & mask) >> off) -#define PDR1(mask, off) ((__raw_readl(MXC_CCM_PDR1) & mask) >> off) -#define PDR2(mask, off) ((__raw_readl(MXC_CCM_PDR2) & mask) >> off) - -static unsigned long mcu_main_get_rate(struct clk *clk) -{ - u32 pmcr0 = __raw_readl(MXC_CCM_PMCR0); - - if ((pmcr0 & MXC_CCM_PMCR0_DFSUP1) == MXC_CCM_PMCR0_DFSUP1_SPLL) - return clk_get_rate(&serial_pll_clk); - else - return clk_get_rate(&mcu_pll_clk); -} - -static unsigned long ahb_get_rate(struct clk *clk) -{ - unsigned long max_pdf; - - max_pdf = PDR0(MXC_CCM_PDR0_MAX_PODF_MASK, - MXC_CCM_PDR0_MAX_PODF_OFFSET); - return clk_get_rate(clk->parent) / (max_pdf + 1); -} - -static unsigned long ipg_get_rate(struct clk *clk) -{ - unsigned long ipg_pdf; - - ipg_pdf = PDR0(MXC_CCM_PDR0_IPG_PODF_MASK, - MXC_CCM_PDR0_IPG_PODF_OFFSET); - return clk_get_rate(clk->parent) / (ipg_pdf + 1); -} - -static unsigned long nfc_get_rate(struct clk *clk) -{ - unsigned long nfc_pdf; - - nfc_pdf = PDR0(MXC_CCM_PDR0_NFC_PODF_MASK, - MXC_CCM_PDR0_NFC_PODF_OFFSET); - return clk_get_rate(clk->parent) / (nfc_pdf + 1); -} - -static unsigned long hsp_get_rate(struct clk *clk) -{ - unsigned long hsp_pdf; - - hsp_pdf = PDR0(MXC_CCM_PDR0_HSP_PODF_MASK, - MXC_CCM_PDR0_HSP_PODF_OFFSET); - return clk_get_rate(clk->parent) / (hsp_pdf + 1); -} - -static unsigned long usb_get_rate(struct clk *clk) -{ - unsigned long usb_pdf, usb_prepdf; - - usb_pdf = PDR1(MXC_CCM_PDR1_USB_PODF_MASK, - MXC_CCM_PDR1_USB_PODF_OFFSET); - usb_prepdf = PDR1(MXC_CCM_PDR1_USB_PRDF_MASK, - MXC_CCM_PDR1_USB_PRDF_OFFSET); - return clk_get_rate(clk->parent) / (usb_prepdf + 1) / (usb_pdf + 1); -} - -static unsigned long csi_get_rate(struct clk *clk) -{ - u32 reg, pre, post; - - reg = __raw_readl(MXC_CCM_PDR0); - pre = (reg & MXC_CCM_PDR0_CSI_PRDF_MASK) >> - MXC_CCM_PDR0_CSI_PRDF_OFFSET; - pre++; - post = (reg & MXC_CCM_PDR0_CSI_PODF_MASK) >> - MXC_CCM_PDR0_CSI_PODF_OFFSET; - post++; - return clk_get_rate(clk->parent) / (pre * post); -} - -static unsigned long csi_round_rate(struct clk *clk, unsigned long rate) -{ - u32 pre, post, parent = clk_get_rate(clk->parent); - u32 div = parent / rate; - - if (parent % rate) - div++; - - __calc_pre_post_dividers(div, &pre, &post); - - return parent / (pre * post); -} - -static int csi_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg, div, pre, post, parent = clk_get_rate(clk->parent); - - div = parent / rate; - - if ((parent / div) != rate) - return -EINVAL; - - __calc_pre_post_dividers(div, &pre, &post); - - /* Set CSI clock divider */ - reg = __raw_readl(MXC_CCM_PDR0) & - ~(MXC_CCM_PDR0_CSI_PODF_MASK | MXC_CCM_PDR0_CSI_PRDF_MASK); - reg |= (post - 1) << MXC_CCM_PDR0_CSI_PODF_OFFSET; - reg |= (pre - 1) << MXC_CCM_PDR0_CSI_PRDF_OFFSET; - __raw_writel(reg, MXC_CCM_PDR0); - - return 0; -} - -static unsigned long ssi1_get_rate(struct clk *clk) -{ - unsigned long ssi1_pdf, ssi1_prepdf; - - ssi1_pdf = PDR1(MXC_CCM_PDR1_SSI1_PODF_MASK, - MXC_CCM_PDR1_SSI1_PODF_OFFSET); - ssi1_prepdf = PDR1(MXC_CCM_PDR1_SSI1_PRE_PODF_MASK, - MXC_CCM_PDR1_SSI1_PRE_PODF_OFFSET); - return clk_get_rate(clk->parent) / (ssi1_prepdf + 1) / (ssi1_pdf + 1); -} - -static unsigned long ssi2_get_rate(struct clk *clk) -{ - unsigned long ssi2_pdf, ssi2_prepdf; - - ssi2_pdf = PDR1(MXC_CCM_PDR1_SSI2_PODF_MASK, - MXC_CCM_PDR1_SSI2_PODF_OFFSET); - ssi2_prepdf = PDR1(MXC_CCM_PDR1_SSI2_PRE_PODF_MASK, - MXC_CCM_PDR1_SSI2_PRE_PODF_OFFSET); - return clk_get_rate(clk->parent) / (ssi2_prepdf + 1) / (ssi2_pdf + 1); -} - -static unsigned long firi_get_rate(struct clk *clk) -{ - unsigned long firi_pdf, firi_prepdf; - - firi_pdf = PDR1(MXC_CCM_PDR1_FIRI_PODF_MASK, - MXC_CCM_PDR1_FIRI_PODF_OFFSET); - firi_prepdf = PDR1(MXC_CCM_PDR1_FIRI_PRE_PODF_MASK, - MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET); - return clk_get_rate(clk->parent) / (firi_prepdf + 1) / (firi_pdf + 1); -} - -static unsigned long firi_round_rate(struct clk *clk, unsigned long rate) -{ - u32 pre, post; - u32 parent = clk_get_rate(clk->parent); - u32 div = parent / rate; - - if (parent % rate) - div++; - - __calc_pre_post_dividers(div, &pre, &post); - - return parent / (pre * post); - -} - -static int firi_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg, div, pre, post, parent = clk_get_rate(clk->parent); - - div = parent / rate; - - if ((parent / div) != rate) - return -EINVAL; - - __calc_pre_post_dividers(div, &pre, &post); - - /* Set FIRI clock divider */ - reg = __raw_readl(MXC_CCM_PDR1) & - ~(MXC_CCM_PDR1_FIRI_PODF_MASK | MXC_CCM_PDR1_FIRI_PRE_PODF_MASK); - reg |= (pre - 1) << MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET; - reg |= (post - 1) << MXC_CCM_PDR1_FIRI_PODF_OFFSET; - __raw_writel(reg, MXC_CCM_PDR1); - - return 0; -} - -static unsigned long mbx_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 2; -} - -static unsigned long mstick1_get_rate(struct clk *clk) -{ - unsigned long msti_pdf; - - msti_pdf = PDR2(MXC_CCM_PDR2_MST1_PDF_MASK, - MXC_CCM_PDR2_MST1_PDF_OFFSET); - return clk_get_rate(clk->parent) / (msti_pdf + 1); -} - -static unsigned long mstick2_get_rate(struct clk *clk) -{ - unsigned long msti_pdf; - - msti_pdf = PDR2(MXC_CCM_PDR2_MST2_PDF_MASK, - MXC_CCM_PDR2_MST2_PDF_OFFSET); - return clk_get_rate(clk->parent) / (msti_pdf + 1); -} - -static unsigned long ckih_rate; - -static unsigned long clk_ckih_get_rate(struct clk *clk) -{ - return ckih_rate; -} - -static unsigned long clk_ckil_get_rate(struct clk *clk) -{ - return CKIL_CLK_FREQ; -} - -static struct clk ckih_clk = { - .get_rate = clk_ckih_get_rate, -}; - -static struct clk mcu_pll_clk = { - .parent = &ckih_clk, - .get_rate = mcu_pll_get_rate, -}; - -static struct clk mcu_main_clk = { - .parent = &mcu_pll_clk, - .get_rate = mcu_main_get_rate, -}; - -static struct clk serial_pll_clk = { - .parent = &ckih_clk, - .get_rate = serial_pll_get_rate, - .enable = serial_pll_enable, - .disable = serial_pll_disable, -}; - -static struct clk usb_pll_clk = { - .parent = &ckih_clk, - .get_rate = usb_pll_get_rate, - .enable = usb_pll_enable, - .disable = usb_pll_disable, -}; - -static struct clk ahb_clk = { - .parent = &mcu_main_clk, - .get_rate = ahb_get_rate, -}; - -#define DEFINE_CLOCK(name, i, er, es, gr, s, p) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = gr, \ - .enable = cgr_enable, \ - .disable = cgr_disable, \ - .secondary = s, \ - .parent = p, \ - } - -#define DEFINE_CLOCK1(name, i, er, es, getsetround, s, p) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = getsetround##_get_rate, \ - .set_rate = getsetround##_set_rate, \ - .round_rate = getsetround##_round_rate, \ - .enable = cgr_enable, \ - .disable = cgr_disable, \ - .secondary = s, \ - .parent = p, \ - } - -DEFINE_CLOCK(perclk_clk, 0, NULL, 0, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(ckil_clk, 0, NULL, 0, clk_ckil_get_rate, NULL, NULL); - -DEFINE_CLOCK(sdhc1_clk, 0, MXC_CCM_CGR0, 0, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(sdhc2_clk, 1, MXC_CCM_CGR0, 2, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CGR0, 4, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(epit1_clk, 0, MXC_CCM_CGR0, 6, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(epit2_clk, 1, MXC_CCM_CGR0, 8, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(iim_clk, 0, MXC_CCM_CGR0, 10, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(pata_clk, 0, MXC_CCM_CGR0, 12, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(sdma_clk1, 0, MXC_CCM_CGR0, 14, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(cspi3_clk, 2, MXC_CCM_CGR0, 16, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(rng_clk, 0, MXC_CCM_CGR0, 18, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(uart1_clk, 0, MXC_CCM_CGR0, 20, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(uart2_clk, 1, MXC_CCM_CGR0, 22, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(ssi1_clk, 0, MXC_CCM_CGR0, 24, ssi1_get_rate, NULL, &serial_pll_clk); -DEFINE_CLOCK(i2c1_clk, 0, MXC_CCM_CGR0, 26, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(i2c2_clk, 1, MXC_CCM_CGR0, 28, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(i2c3_clk, 2, MXC_CCM_CGR0, 30, NULL, NULL, &perclk_clk); - -DEFINE_CLOCK(mpeg4_clk, 0, MXC_CCM_CGR1, 0, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(mstick1_clk, 0, MXC_CCM_CGR1, 2, mstick1_get_rate, NULL, &usb_pll_clk); -DEFINE_CLOCK(mstick2_clk, 1, MXC_CCM_CGR1, 4, mstick2_get_rate, NULL, &usb_pll_clk); -DEFINE_CLOCK1(csi_clk, 0, MXC_CCM_CGR1, 6, csi, NULL, &serial_pll_clk); -DEFINE_CLOCK(rtc_clk, 0, MXC_CCM_CGR1, 8, NULL, NULL, &ckil_clk); -DEFINE_CLOCK(wdog_clk, 0, MXC_CCM_CGR1, 10, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(pwm_clk, 0, MXC_CCM_CGR1, 12, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(usb_clk2, 0, MXC_CCM_CGR1, 18, usb_get_rate, NULL, &ahb_clk); -DEFINE_CLOCK(kpp_clk, 0, MXC_CCM_CGR1, 20, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(ipu_clk, 0, MXC_CCM_CGR1, 22, hsp_get_rate, NULL, &mcu_main_clk); -DEFINE_CLOCK(uart3_clk, 2, MXC_CCM_CGR1, 24, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(uart4_clk, 3, MXC_CCM_CGR1, 26, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(uart5_clk, 4, MXC_CCM_CGR1, 28, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(owire_clk, 0, MXC_CCM_CGR1, 30, NULL, NULL, &perclk_clk); - -DEFINE_CLOCK(ssi2_clk, 1, MXC_CCM_CGR2, 0, ssi2_get_rate, NULL, &serial_pll_clk); -DEFINE_CLOCK(cspi1_clk, 0, MXC_CCM_CGR2, 2, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(cspi2_clk, 1, MXC_CCM_CGR2, 4, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(mbx_clk, 0, MXC_CCM_CGR2, 6, mbx_get_rate, NULL, &ahb_clk); -DEFINE_CLOCK(emi_clk, 0, MXC_CCM_CGR2, 8, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(rtic_clk, 0, MXC_CCM_CGR2, 10, NULL, NULL, &ahb_clk); -DEFINE_CLOCK1(firi_clk, 0, MXC_CCM_CGR2, 12, firi, NULL, &usb_pll_clk); - -DEFINE_CLOCK(sdma_clk2, 0, NULL, 0, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(usb_clk1, 0, NULL, 0, usb_get_rate, NULL, &usb_pll_clk); -DEFINE_CLOCK(nfc_clk, 0, NULL, 0, nfc_get_rate, NULL, &ahb_clk); -DEFINE_CLOCK(scc_clk, 0, NULL, 0, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(ipg_clk, 0, NULL, 0, ipg_get_rate, NULL, &ahb_clk); - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup lookups[] = { - _REGISTER_CLOCK(NULL, "emi", emi_clk) - _REGISTER_CLOCK("imx31-cspi.0", NULL, cspi1_clk) - _REGISTER_CLOCK("imx31-cspi.1", NULL, cspi2_clk) - _REGISTER_CLOCK("imx31-cspi.2", NULL, cspi3_clk) - _REGISTER_CLOCK(NULL, "gpt", gpt_clk) - _REGISTER_CLOCK(NULL, "pwm", pwm_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk) - _REGISTER_CLOCK(NULL, "rtc", rtc_clk) - _REGISTER_CLOCK(NULL, "epit", epit1_clk) - _REGISTER_CLOCK(NULL, "epit", epit2_clk) - _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) - _REGISTER_CLOCK("ipu-core", NULL, ipu_clk) - _REGISTER_CLOCK("mx3_sdc_fb", NULL, ipu_clk) - _REGISTER_CLOCK(NULL, "kpp", kpp_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb", usb_clk1) - _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_clk2) - _REGISTER_CLOCK("mxc-ehci.1", "usb", usb_clk1) - _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_clk2) - _REGISTER_CLOCK("mxc-ehci.2", "usb", usb_clk1) - _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_clk2) - _REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk1) - _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk2) - _REGISTER_CLOCK("mx3-camera.0", NULL, csi_clk) - /* i.mx31 has the i.mx21 type uart */ - _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk) - _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) - _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_clk) - _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk) - _REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk) - _REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk) - _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) - _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) - _REGISTER_CLOCK(NULL, "firi", firi_clk) - _REGISTER_CLOCK("pata_imx", NULL, pata_clk) - _REGISTER_CLOCK(NULL, "rtic", rtic_clk) - _REGISTER_CLOCK(NULL, "rng", rng_clk) - _REGISTER_CLOCK("imx31-sdma", NULL, sdma_clk1) - _REGISTER_CLOCK(NULL, "sdma_ipg", sdma_clk2) - _REGISTER_CLOCK(NULL, "mstick", mstick1_clk) - _REGISTER_CLOCK(NULL, "mstick", mstick2_clk) - _REGISTER_CLOCK(NULL, "scc", scc_clk) - _REGISTER_CLOCK(NULL, "iim", iim_clk) - _REGISTER_CLOCK(NULL, "mpeg4", mpeg4_clk) - _REGISTER_CLOCK(NULL, "mbx", mbx_clk) -}; - -int __init mx31_clocks_init(unsigned long fref) -{ - u32 reg; - - ckih_rate = fref; - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - /* change the csi_clk parent if necessary */ - reg = __raw_readl(MXC_CCM_CCMR); - if (!(reg & MXC_CCM_CCMR_CSCS)) - if (clk_set_parent(&csi_clk, &usb_pll_clk)) - pr_err("%s: error changing csi_clk parent\n", __func__); - - - /* Turn off all possible clocks */ - __raw_writel((3 << 4), MXC_CCM_CGR0); - __raw_writel(0, MXC_CCM_CGR1); - __raw_writel((3 << 8) | (3 << 14) | (3 << 16)| - 1 << 27 | 1 << 28, /* Bit 27 and 28 are not defined for - MX32, but still required to be set */ - MXC_CCM_CGR2); - - /* - * Before turning off usb_pll make sure ipg_per_clk is generated - * by ipg_clk and not usb_pll. - */ - __raw_writel(__raw_readl(MXC_CCM_CCMR) | (1 << 24), MXC_CCM_CCMR); - - usb_pll_disable(&usb_pll_clk); - - pr_info("Clock input source is %ld\n", clk_get_rate(&ckih_clk)); - - clk_enable(&gpt_clk); - clk_enable(&emi_clk); - clk_enable(&iim_clk); - mx31_revision(); - clk_disable(&iim_clk); - - clk_enable(&serial_pll_clk); - - if (mx31_revision() >= IMX_CHIP_REVISION_2_0) { - reg = __raw_readl(MXC_CCM_PMCR1); - /* No PLL restart on DVFS switch; enable auto EMI handshake */ - reg |= MXC_CCM_PMCR1_PLLRDIS | MXC_CCM_PMCR1_EMIRQ_EN; - __raw_writel(reg, MXC_CCM_PMCR1); - } - - mxc_timer_init(&ipg_clk, MX31_IO_ADDRESS(MX31_GPT1_BASE_ADDR), - MX31_INT_GPT); - - return 0; -} diff --git a/arch/arm/mach-imx/clock-imx35.c b/arch/arm/mach-imx/clock-imx35.c deleted file mode 100644 index e56c1a83eee3..000000000000 --- a/arch/arm/mach-imx/clock-imx35.c +++ /dev/null @@ -1,536 +0,0 @@ -/* - * 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 <linux/kernel.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/clkdev.h> - -#include <mach/clock.h> -#include <mach/hardware.h> -#include <mach/common.h> - -#include "crmregs-imx3.h" - -#ifdef HAVE_SET_RATE_SUPPORT -static void calc_dividers(u32 div, u32 *pre, u32 *post, u32 maxpost) -{ - u32 min_pre, temp_pre, old_err, err; - - min_pre = (div - 1) / maxpost + 1; - old_err = 8; - - for (temp_pre = 8; temp_pre >= min_pre; temp_pre--) { - if (div > (temp_pre * maxpost)) - break; - - if (div < (temp_pre * temp_pre)) - continue; - - err = div % temp_pre; - - if (err == 0) { - *pre = temp_pre; - break; - } - - err = temp_pre - err; - - if (err < old_err) { - old_err = err; - *pre = temp_pre; - } - } - - *post = (div + *pre - 1) / *pre; -} - -/* get the best values for a 3-bit divider combined with a 6-bit divider */ -static void calc_dividers_3_6(u32 div, u32 *pre, u32 *post) -{ - if (div >= 512) { - *pre = 8; - *post = 64; - } else if (div >= 64) { - calc_dividers(div, pre, post, 64); - } else if (div <= 8) { - *pre = div; - *post = 1; - } else { - *pre = 1; - *post = div; - } -} - -/* get the best values for two cascaded 3-bit dividers */ -static void calc_dividers_3_3(u32 div, u32 *pre, u32 *post) -{ - if (div >= 64) { - *pre = *post = 8; - } else if (div > 8) { - calc_dividers(div, pre, post, 8); - } else { - *pre = 1; - *post = div; - } -} -#endif - -static unsigned long get_rate_mpll(void) -{ - ulong mpctl = __raw_readl(MX35_CCM_MPCTL); - - return mxc_decode_pll(mpctl, 24000000); -} - -static unsigned long get_rate_ppll(void) -{ - ulong ppctl = __raw_readl(MX35_CCM_PPCTL); - - return mxc_decode_pll(ppctl, 24000000); -} - -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 unsigned long get_rate_arm(void) -{ - unsigned long pdr0 = __raw_readl(MXC_CCM_PDR0); - struct arm_ahb_div *aad; - unsigned long fref = get_rate_mpll(); - - aad = &clk_consumer[(pdr0 >> 16) & 0xf]; - if (aad->sel) - fref = fref * 3 / 4; - - return fref / aad->arm; -} - -static unsigned long get_rate_ahb(struct clk *clk) -{ - unsigned long pdr0 = __raw_readl(MXC_CCM_PDR0); - struct arm_ahb_div *aad; - unsigned long fref = get_rate_arm(); - - aad = &clk_consumer[(pdr0 >> 16) & 0xf]; - - return fref / aad->ahb; -} - -static unsigned long get_rate_ipg(struct clk *clk) -{ - return get_rate_ahb(NULL) >> 1; -} - -static unsigned long get_rate_uart(struct clk *clk) -{ - unsigned long pdr3 = __raw_readl(MX35_CCM_PDR3); - unsigned long pdr4 = __raw_readl(MX35_CCM_PDR4); - unsigned long div = ((pdr4 >> 10) & 0x3f) + 1; - - if (pdr3 & (1 << 14)) - return get_rate_arm() / div; - else - return get_rate_ppll() / div; -} - -static unsigned long get_rate_sdhc(struct clk *clk) -{ - unsigned long pdr3 = __raw_readl(MX35_CCM_PDR3); - unsigned long div, rate; - - if (pdr3 & (1 << 6)) - rate = get_rate_arm(); - else - rate = get_rate_ppll(); - - switch (clk->id) { - default: - case 0: - div = pdr3 & 0x3f; - break; - case 1: - div = (pdr3 >> 8) & 0x3f; - break; - case 2: - div = (pdr3 >> 16) & 0x3f; - break; - } - - return rate / (div + 1); -} - -static unsigned long get_rate_mshc(struct clk *clk) -{ - unsigned long pdr1 = __raw_readl(MXC_CCM_PDR1); - unsigned long div1, div2, rate; - - if (pdr1 & (1 << 7)) - rate = get_rate_arm(); - else - rate = get_rate_ppll(); - - div1 = (pdr1 >> 29) & 0x7; - div2 = (pdr1 >> 22) & 0x3f; - - return rate / ((div1 + 1) * (div2 + 1)); -} - -static unsigned long get_rate_ssi(struct clk *clk) -{ - unsigned long pdr2 = __raw_readl(MX35_CCM_PDR2); - unsigned long div1, div2, rate; - - if (pdr2 & (1 << 6)) - rate = get_rate_arm(); - else - rate = get_rate_ppll(); - - switch (clk->id) { - default: - case 0: - div1 = pdr2 & 0x3f; - div2 = (pdr2 >> 24) & 0x7; - break; - case 1: - div1 = (pdr2 >> 8) & 0x3f; - div2 = (pdr2 >> 27) & 0x7; - break; - } - - return rate / ((div1 + 1) * (div2 + 1)); -} - -static unsigned long get_rate_csi(struct clk *clk) -{ - unsigned long pdr2 = __raw_readl(MX35_CCM_PDR2); - unsigned long rate; - - if (pdr2 & (1 << 7)) - rate = get_rate_arm(); - else - rate = get_rate_ppll(); - - return rate / (((pdr2 >> 16) & 0x3f) + 1); -} - -static unsigned long get_rate_otg(struct clk *clk) -{ - unsigned long pdr4 = __raw_readl(MX35_CCM_PDR4); - unsigned long rate; - - if (pdr4 & (1 << 9)) - rate = get_rate_arm(); - else - rate = get_rate_ppll(); - - return rate / (((pdr4 >> 22) & 0x3f) + 1); -} - -static unsigned long get_rate_ipg_per(struct clk *clk) -{ - unsigned long pdr0 = __raw_readl(MXC_CCM_PDR0); - unsigned long pdr4 = __raw_readl(MX35_CCM_PDR4); - unsigned long div; - - if (pdr0 & (1 << 26)) { - div = (pdr4 >> 16) & 0x3f; - return get_rate_arm() / (div + 1); - } else { - div = (pdr0 >> 12) & 0x7; - return get_rate_ahb(NULL) / (div + 1); - } -} - -static unsigned long get_rate_hsp(struct clk *clk) -{ - unsigned long hsp_podf = (__raw_readl(MXC_CCM_PDR0) >> 20) & 0x03; - unsigned long fref = get_rate_mpll(); - - if (fref > 400 * 1000 * 1000) { - switch (hsp_podf) { - case 0: - return fref >> 2; - case 1: - return fref >> 3; - case 2: - return fref / 3; - } - } else { - switch (hsp_podf) { - case 0: - case 2: - return fref / 3; - case 1: - return fref / 6; - } - } - - return 0; -} - -static int clk_cgr_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg |= 3 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - - return 0; -} - -static void clk_cgr_disable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(3 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); -} - -#define DEFINE_CLOCK(name, i, er, es, gr, sr) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = gr, \ - .set_rate = sr, \ - .enable = clk_cgr_enable, \ - .disable = clk_cgr_disable, \ - } - -DEFINE_CLOCK(asrc_clk, 0, MX35_CCM_CGR0, 0, NULL, NULL); -DEFINE_CLOCK(pata_clk, 0, MX35_CCM_CGR0, 2, get_rate_ipg, NULL); -/* DEFINE_CLOCK(audmux_clk, 0, MX35_CCM_CGR0, 4, NULL, NULL); */ -DEFINE_CLOCK(can1_clk, 0, MX35_CCM_CGR0, 6, get_rate_ipg, NULL); -DEFINE_CLOCK(can2_clk, 1, MX35_CCM_CGR0, 8, get_rate_ipg, NULL); -DEFINE_CLOCK(cspi1_clk, 0, MX35_CCM_CGR0, 10, get_rate_ipg, NULL); -DEFINE_CLOCK(cspi2_clk, 1, MX35_CCM_CGR0, 12, get_rate_ipg, NULL); -DEFINE_CLOCK(ect_clk, 0, MX35_CCM_CGR0, 14, get_rate_ipg, NULL); -DEFINE_CLOCK(edio_clk, 0, MX35_CCM_CGR0, 16, NULL, NULL); -DEFINE_CLOCK(emi_clk, 0, MX35_CCM_CGR0, 18, get_rate_ipg, NULL); -DEFINE_CLOCK(epit1_clk, 0, MX35_CCM_CGR0, 20, get_rate_ipg, NULL); -DEFINE_CLOCK(epit2_clk, 1, MX35_CCM_CGR0, 22, get_rate_ipg, NULL); -DEFINE_CLOCK(esai_clk, 0, MX35_CCM_CGR0, 24, NULL, NULL); -DEFINE_CLOCK(esdhc1_clk, 0, MX35_CCM_CGR0, 26, get_rate_sdhc, NULL); -DEFINE_CLOCK(esdhc2_clk, 1, MX35_CCM_CGR0, 28, get_rate_sdhc, NULL); -DEFINE_CLOCK(esdhc3_clk, 2, MX35_CCM_CGR0, 30, get_rate_sdhc, NULL); - -DEFINE_CLOCK(fec_clk, 0, MX35_CCM_CGR1, 0, get_rate_ipg, NULL); -DEFINE_CLOCK(gpio1_clk, 0, MX35_CCM_CGR1, 2, NULL, NULL); -DEFINE_CLOCK(gpio2_clk, 1, MX35_CCM_CGR1, 4, NULL, NULL); -DEFINE_CLOCK(gpio3_clk, 2, MX35_CCM_CGR1, 6, NULL, NULL); -DEFINE_CLOCK(gpt_clk, 0, MX35_CCM_CGR1, 8, get_rate_ipg, NULL); -DEFINE_CLOCK(i2c1_clk, 0, MX35_CCM_CGR1, 10, get_rate_ipg_per, NULL); -DEFINE_CLOCK(i2c2_clk, 1, MX35_CCM_CGR1, 12, get_rate_ipg_per, NULL); -DEFINE_CLOCK(i2c3_clk, 2, MX35_CCM_CGR1, 14, get_rate_ipg_per, NULL); -DEFINE_CLOCK(iomuxc_clk, 0, MX35_CCM_CGR1, 16, NULL, NULL); -DEFINE_CLOCK(ipu_clk, 0, MX35_CCM_CGR1, 18, get_rate_hsp, NULL); -DEFINE_CLOCK(kpp_clk, 0, MX35_CCM_CGR1, 20, get_rate_ipg, NULL); -DEFINE_CLOCK(mlb_clk, 0, MX35_CCM_CGR1, 22, get_rate_ahb, NULL); -DEFINE_CLOCK(mshc_clk, 0, MX35_CCM_CGR1, 24, get_rate_mshc, NULL); -DEFINE_CLOCK(owire_clk, 0, MX35_CCM_CGR1, 26, get_rate_ipg_per, NULL); -DEFINE_CLOCK(pwm_clk, 0, MX35_CCM_CGR1, 28, get_rate_ipg_per, NULL); -DEFINE_CLOCK(rngc_clk, 0, MX35_CCM_CGR1, 30, get_rate_ipg, NULL); - -DEFINE_CLOCK(rtc_clk, 0, MX35_CCM_CGR2, 0, get_rate_ipg, NULL); -DEFINE_CLOCK(rtic_clk, 0, MX35_CCM_CGR2, 2, get_rate_ahb, NULL); -DEFINE_CLOCK(scc_clk, 0, MX35_CCM_CGR2, 4, get_rate_ipg, NULL); -DEFINE_CLOCK(sdma_clk, 0, MX35_CCM_CGR2, 6, NULL, NULL); -DEFINE_CLOCK(spba_clk, 0, MX35_CCM_CGR2, 8, get_rate_ipg, NULL); -DEFINE_CLOCK(spdif_clk, 0, MX35_CCM_CGR2, 10, NULL, NULL); -DEFINE_CLOCK(ssi1_clk, 0, MX35_CCM_CGR2, 12, get_rate_ssi, NULL); -DEFINE_CLOCK(ssi2_clk, 1, MX35_CCM_CGR2, 14, get_rate_ssi, NULL); -DEFINE_CLOCK(uart1_clk, 0, MX35_CCM_CGR2, 16, get_rate_uart, NULL); -DEFINE_CLOCK(uart2_clk, 1, MX35_CCM_CGR2, 18, get_rate_uart, NULL); -DEFINE_CLOCK(uart3_clk, 2, MX35_CCM_CGR2, 20, get_rate_uart, NULL); -DEFINE_CLOCK(usbotg_clk, 0, MX35_CCM_CGR2, 22, get_rate_otg, NULL); -DEFINE_CLOCK(wdog_clk, 0, MX35_CCM_CGR2, 24, NULL, NULL); -DEFINE_CLOCK(max_clk, 0, MX35_CCM_CGR2, 26, NULL, NULL); -DEFINE_CLOCK(audmux_clk, 0, MX35_CCM_CGR2, 30, NULL, NULL); - -DEFINE_CLOCK(csi_clk, 0, MX35_CCM_CGR3, 0, get_rate_csi, NULL); -DEFINE_CLOCK(iim_clk, 0, MX35_CCM_CGR3, 2, NULL, NULL); -DEFINE_CLOCK(gpu2d_clk, 0, MX35_CCM_CGR3, 4, NULL, NULL); - -DEFINE_CLOCK(usbahb_clk, 0, 0, 0, get_rate_ahb, NULL); - -static int clk_dummy_enable(struct clk *clk) -{ - return 0; -} - -static void clk_dummy_disable(struct clk *clk) -{ -} - -static unsigned long get_rate_nfc(struct clk *clk) -{ - unsigned long div1; - - div1 = (__raw_readl(MX35_CCM_PDR4) >> 28) + 1; - - return get_rate_ahb(NULL) / div1; -} - -/* NAND Controller: It seems it can't be disabled */ -static struct clk nfc_clk = { - .id = 0, - .enable_reg = 0, - .enable_shift = 0, - .get_rate = get_rate_nfc, - .set_rate = NULL, /* set_rate_nfc, */ - .enable = clk_dummy_enable, - .disable = clk_dummy_disable -}; - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup lookups[] = { - _REGISTER_CLOCK(NULL, "asrc", asrc_clk) - _REGISTER_CLOCK("pata_imx", NULL, pata_clk) - _REGISTER_CLOCK("flexcan.0", NULL, can1_clk) - _REGISTER_CLOCK("flexcan.1", NULL, can2_clk) - _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi1_clk) - _REGISTER_CLOCK("imx35-cspi.1", NULL, cspi2_clk) - _REGISTER_CLOCK(NULL, "ect", ect_clk) - _REGISTER_CLOCK(NULL, "edio", edio_clk) - _REGISTER_CLOCK(NULL, "emi", emi_clk) - _REGISTER_CLOCK("imx-epit.0", NULL, epit1_clk) - _REGISTER_CLOCK("imx-epit.1", NULL, epit2_clk) - _REGISTER_CLOCK(NULL, "esai", esai_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx35.0", NULL, esdhc1_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx35.1", NULL, esdhc2_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx35.2", NULL, esdhc3_clk) - /* i.mx35 has the i.mx27 type fec */ - _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk) - _REGISTER_CLOCK(NULL, "gpio", gpio1_clk) - _REGISTER_CLOCK(NULL, "gpio", gpio2_clk) - _REGISTER_CLOCK(NULL, "gpio", gpio3_clk) - _REGISTER_CLOCK("gpt.0", NULL, gpt_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) - _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_clk) - _REGISTER_CLOCK(NULL, "iomuxc", iomuxc_clk) - _REGISTER_CLOCK("ipu-core", NULL, ipu_clk) - _REGISTER_CLOCK("mx3_sdc_fb", NULL, ipu_clk) - _REGISTER_CLOCK(NULL, "kpp", kpp_clk) - _REGISTER_CLOCK(NULL, "mlb", mlb_clk) - _REGISTER_CLOCK(NULL, "mshc", mshc_clk) - _REGISTER_CLOCK("mxc_w1", NULL, owire_clk) - _REGISTER_CLOCK(NULL, "pwm", pwm_clk) - _REGISTER_CLOCK(NULL, "rngc", rngc_clk) - _REGISTER_CLOCK(NULL, "rtc", rtc_clk) - _REGISTER_CLOCK(NULL, "rtic", rtic_clk) - _REGISTER_CLOCK(NULL, "scc", scc_clk) - _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk) - _REGISTER_CLOCK(NULL, "spba", spba_clk) - _REGISTER_CLOCK(NULL, "spdif", spdif_clk) - _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) - _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) - /* i.mx35 has the i.mx21 type uart */ - _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb", usbotg_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk) - _REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb", usbotg_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usbahb_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk) - _REGISTER_CLOCK(NULL, "max", max_clk) - _REGISTER_CLOCK(NULL, "audmux", audmux_clk) - _REGISTER_CLOCK("mx3-camera.0", NULL, csi_clk) - _REGISTER_CLOCK(NULL, "iim", iim_clk) - _REGISTER_CLOCK(NULL, "gpu2d", gpu2d_clk) - _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) -}; - -int __init mx35_clocks_init() -{ - unsigned int cgr2 = 3 << 26; - -#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) - cgr2 |= 3 << 16; -#endif - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - /* Turn off all clocks except the ones we need to survive, namely: - * EMI, GPIO1/2/3, GPT, IOMUX, MAX and eventually uart - */ - __raw_writel((3 << 18), MX35_CCM_CGR0); - __raw_writel((3 << 2) | (3 << 4) | (3 << 6) | (3 << 8) | (3 << 16), - MX35_CCM_CGR1); - __raw_writel(cgr2, MX35_CCM_CGR2); - __raw_writel(0, MX35_CCM_CGR3); - - clk_enable(&iim_clk); - imx_print_silicon_rev("i.MX35", mx35_revision()); - clk_disable(&iim_clk); - - /* - * Check if we came up in internal boot mode. If yes, we need some - * extra clocks turned on, otherwise the MX35 boot ROM code will - * hang after a watchdog reset. - */ - if (!(__raw_readl(MX35_CCM_RCSR) & (3 << 10))) { - /* Additionally turn on UART1, SCC, and IIM clocks */ - clk_enable(&iim_clk); - clk_enable(&uart1_clk); - clk_enable(&scc_clk); - } - -#ifdef CONFIG_MXC_USE_EPIT - epit_timer_init(&epit1_clk, - MX35_IO_ADDRESS(MX35_EPIT1_BASE_ADDR), MX35_INT_EPIT1); -#else - mxc_timer_init(&gpt_clk, - MX35_IO_ADDRESS(MX35_GPT1_BASE_ADDR), MX35_INT_GPT); -#endif - - return 0; -} diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c deleted file mode 100644 index 111c328f5420..000000000000 --- a/arch/arm/mach-imx/clock-imx6q.c +++ /dev/null @@ -1,2111 +0,0 @@ -/* - * 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 <linux/init.h> -#include <linux/types.h> -#include <linux/clk.h> -#include <linux/clkdev.h> -#include <linux/io.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <asm/div64.h> -#include <asm/mach/map.h> -#include <mach/clock.h> -#include <mach/common.h> -#include <mach/hardware.h> - -#define PLL_BASE IMX_IO_ADDRESS(MX6Q_ANATOP_BASE_ADDR) -#define PLL1_SYS (PLL_BASE + 0x000) -#define PLL2_BUS (PLL_BASE + 0x030) -#define PLL3_USB_OTG (PLL_BASE + 0x010) -#define PLL4_AUDIO (PLL_BASE + 0x070) -#define PLL5_VIDEO (PLL_BASE + 0x0a0) -#define PLL6_MLB (PLL_BASE + 0x0d0) -#define PLL7_USB_HOST (PLL_BASE + 0x020) -#define PLL8_ENET (PLL_BASE + 0x0e0) -#define PFD_480 (PLL_BASE + 0x0f0) -#define PFD_528 (PLL_BASE + 0x100) -#define PLL_NUM_OFFSET 0x010 -#define PLL_DENOM_OFFSET 0x020 - -#define PFD0 7 -#define PFD1 15 -#define PFD2 23 -#define PFD3 31 -#define PFD_FRAC_MASK 0x3f - -#define BM_PLL_BYPASS (0x1 << 16) -#define BM_PLL_ENABLE (0x1 << 13) -#define BM_PLL_POWER_DOWN (0x1 << 12) -#define BM_PLL_LOCK (0x1 << 31) -#define BP_PLL_SYS_DIV_SELECT 0 -#define BM_PLL_SYS_DIV_SELECT (0x7f << 0) -#define BP_PLL_BUS_DIV_SELECT 0 -#define BM_PLL_BUS_DIV_SELECT (0x1 << 0) -#define BP_PLL_USB_DIV_SELECT 0 -#define BM_PLL_USB_DIV_SELECT (0x3 << 0) -#define BP_PLL_AV_DIV_SELECT 0 -#define BM_PLL_AV_DIV_SELECT (0x7f << 0) -#define BP_PLL_ENET_DIV_SELECT 0 -#define BM_PLL_ENET_DIV_SELECT (0x3 << 0) -#define BM_PLL_ENET_EN_PCIE (0x1 << 19) -#define BM_PLL_ENET_EN_SATA (0x1 << 20) - -#define CCM_BASE IMX_IO_ADDRESS(MX6Q_CCM_BASE_ADDR) -#define CCR (CCM_BASE + 0x00) -#define CCDR (CCM_BASE + 0x04) -#define CSR (CCM_BASE + 0x08) -#define CCSR (CCM_BASE + 0x0c) -#define CACRR (CCM_BASE + 0x10) -#define CBCDR (CCM_BASE + 0x14) -#define CBCMR (CCM_BASE + 0x18) -#define CSCMR1 (CCM_BASE + 0x1c) -#define CSCMR2 (CCM_BASE + 0x20) -#define CSCDR1 (CCM_BASE + 0x24) -#define CS1CDR (CCM_BASE + 0x28) -#define CS2CDR (CCM_BASE + 0x2c) -#define CDCDR (CCM_BASE + 0x30) -#define CHSCCDR (CCM_BASE + 0x34) -#define CSCDR2 (CCM_BASE + 0x38) -#define CSCDR3 (CCM_BASE + 0x3c) -#define CSCDR4 (CCM_BASE + 0x40) -#define CWDR (CCM_BASE + 0x44) -#define CDHIPR (CCM_BASE + 0x48) -#define CDCR (CCM_BASE + 0x4c) -#define CTOR (CCM_BASE + 0x50) -#define CLPCR (CCM_BASE + 0x54) -#define CISR (CCM_BASE + 0x58) -#define CIMR (CCM_BASE + 0x5c) -#define CCOSR (CCM_BASE + 0x60) -#define CGPR (CCM_BASE + 0x64) -#define CCGR0 (CCM_BASE + 0x68) -#define CCGR1 (CCM_BASE + 0x6c) -#define CCGR2 (CCM_BASE + 0x70) -#define CCGR3 (CCM_BASE + 0x74) -#define CCGR4 (CCM_BASE + 0x78) -#define CCGR5 (CCM_BASE + 0x7c) -#define CCGR6 (CCM_BASE + 0x80) -#define CCGR7 (CCM_BASE + 0x84) -#define CMEOR (CCM_BASE + 0x88) - -#define CG0 0 -#define CG1 2 -#define CG2 4 -#define CG3 6 -#define CG4 8 -#define CG5 10 -#define CG6 12 -#define CG7 14 -#define CG8 16 -#define CG9 18 -#define CG10 20 -#define CG11 22 -#define CG12 24 -#define CG13 26 -#define CG14 28 -#define CG15 30 - -#define BM_CCSR_PLL1_SW_SEL (0x1 << 2) -#define BM_CCSR_STEP_SEL (0x1 << 8) - -#define BP_CACRR_ARM_PODF 0 -#define BM_CACRR_ARM_PODF (0x7 << 0) - -#define BP_CBCDR_PERIPH2_CLK2_PODF 0 -#define BM_CBCDR_PERIPH2_CLK2_PODF (0x7 << 0) -#define BP_CBCDR_MMDC_CH1_AXI_PODF 3 -#define BM_CBCDR_MMDC_CH1_AXI_PODF (0x7 << 3) -#define BP_CBCDR_AXI_SEL 6 -#define BM_CBCDR_AXI_SEL (0x3 << 6) -#define BP_CBCDR_IPG_PODF 8 -#define BM_CBCDR_IPG_PODF (0x3 << 8) -#define BP_CBCDR_AHB_PODF 10 -#define BM_CBCDR_AHB_PODF (0x7 << 10) -#define BP_CBCDR_AXI_PODF 16 -#define BM_CBCDR_AXI_PODF (0x7 << 16) -#define BP_CBCDR_MMDC_CH0_AXI_PODF 19 -#define BM_CBCDR_MMDC_CH0_AXI_PODF (0x7 << 19) -#define BP_CBCDR_PERIPH_CLK_SEL 25 -#define BM_CBCDR_PERIPH_CLK_SEL (0x1 << 25) -#define BP_CBCDR_PERIPH2_CLK_SEL 26 -#define BM_CBCDR_PERIPH2_CLK_SEL (0x1 << 26) -#define BP_CBCDR_PERIPH_CLK2_PODF 27 -#define BM_CBCDR_PERIPH_CLK2_PODF (0x7 << 27) - -#define BP_CBCMR_GPU2D_AXI_SEL 0 -#define BM_CBCMR_GPU2D_AXI_SEL (0x1 << 0) -#define BP_CBCMR_GPU3D_AXI_SEL 1 -#define BM_CBCMR_GPU3D_AXI_SEL (0x1 << 1) -#define BP_CBCMR_GPU3D_CORE_SEL 4 -#define BM_CBCMR_GPU3D_CORE_SEL (0x3 << 4) -#define BP_CBCMR_GPU3D_SHADER_SEL 8 -#define BM_CBCMR_GPU3D_SHADER_SEL (0x3 << 8) -#define BP_CBCMR_PCIE_AXI_SEL 10 -#define BM_CBCMR_PCIE_AXI_SEL (0x1 << 10) -#define BP_CBCMR_VDO_AXI_SEL 11 -#define BM_CBCMR_VDO_AXI_SEL (0x1 << 11) -#define BP_CBCMR_PERIPH_CLK2_SEL 12 -#define BM_CBCMR_PERIPH_CLK2_SEL (0x3 << 12) -#define BP_CBCMR_VPU_AXI_SEL 14 -#define BM_CBCMR_VPU_AXI_SEL (0x3 << 14) -#define BP_CBCMR_GPU2D_CORE_SEL 16 -#define BM_CBCMR_GPU2D_CORE_SEL (0x3 << 16) -#define BP_CBCMR_PRE_PERIPH_CLK_SEL 18 -#define BM_CBCMR_PRE_PERIPH_CLK_SEL (0x3 << 18) -#define BP_CBCMR_PERIPH2_CLK2_SEL 20 -#define BM_CBCMR_PERIPH2_CLK2_SEL (0x1 << 20) -#define BP_CBCMR_PRE_PERIPH2_CLK_SEL 21 -#define BM_CBCMR_PRE_PERIPH2_CLK_SEL (0x3 << 21) -#define BP_CBCMR_GPU2D_CORE_PODF 23 -#define BM_CBCMR_GPU2D_CORE_PODF (0x7 << 23) -#define BP_CBCMR_GPU3D_CORE_PODF 26 -#define BM_CBCMR_GPU3D_CORE_PODF (0x7 << 26) -#define BP_CBCMR_GPU3D_SHADER_PODF 29 -#define BM_CBCMR_GPU3D_SHADER_PODF (0x7 << 29) - -#define BP_CSCMR1_PERCLK_PODF 0 -#define BM_CSCMR1_PERCLK_PODF (0x3f << 0) -#define BP_CSCMR1_SSI1_SEL 10 -#define BM_CSCMR1_SSI1_SEL (0x3 << 10) -#define BP_CSCMR1_SSI2_SEL 12 -#define BM_CSCMR1_SSI2_SEL (0x3 << 12) -#define BP_CSCMR1_SSI3_SEL 14 -#define BM_CSCMR1_SSI3_SEL (0x3 << 14) -#define BP_CSCMR1_USDHC1_SEL 16 -#define BM_CSCMR1_USDHC1_SEL (0x1 << 16) -#define BP_CSCMR1_USDHC2_SEL 17 -#define BM_CSCMR1_USDHC2_SEL (0x1 << 17) -#define BP_CSCMR1_USDHC3_SEL 18 -#define BM_CSCMR1_USDHC3_SEL (0x1 << 18) -#define BP_CSCMR1_USDHC4_SEL 19 -#define BM_CSCMR1_USDHC4_SEL (0x1 << 19) -#define BP_CSCMR1_EMI_PODF 20 -#define BM_CSCMR1_EMI_PODF (0x7 << 20) -#define BP_CSCMR1_EMI_SLOW_PODF 23 -#define BM_CSCMR1_EMI_SLOW_PODF (0x7 << 23) -#define BP_CSCMR1_EMI_SEL 27 -#define BM_CSCMR1_EMI_SEL (0x3 << 27) -#define BP_CSCMR1_EMI_SLOW_SEL 29 -#define BM_CSCMR1_EMI_SLOW_SEL (0x3 << 29) - -#define BP_CSCMR2_CAN_PODF 2 -#define BM_CSCMR2_CAN_PODF (0x3f << 2) -#define BM_CSCMR2_LDB_DI0_IPU_DIV (0x1 << 10) -#define BM_CSCMR2_LDB_DI1_IPU_DIV (0x1 << 11) -#define BP_CSCMR2_ESAI_SEL 19 -#define BM_CSCMR2_ESAI_SEL (0x3 << 19) - -#define BP_CSCDR1_UART_PODF 0 -#define BM_CSCDR1_UART_PODF (0x3f << 0) -#define BP_CSCDR1_USDHC1_PODF 11 -#define BM_CSCDR1_USDHC1_PODF (0x7 << 11) -#define BP_CSCDR1_USDHC2_PODF 16 -#define BM_CSCDR1_USDHC2_PODF (0x7 << 16) -#define BP_CSCDR1_USDHC3_PODF 19 -#define BM_CSCDR1_USDHC3_PODF (0x7 << 19) -#define BP_CSCDR1_USDHC4_PODF 22 -#define BM_CSCDR1_USDHC4_PODF (0x7 << 22) -#define BP_CSCDR1_VPU_AXI_PODF 25 -#define BM_CSCDR1_VPU_AXI_PODF (0x7 << 25) - -#define BP_CS1CDR_SSI1_PODF 0 -#define BM_CS1CDR_SSI1_PODF (0x3f << 0) -#define BP_CS1CDR_SSI1_PRED 6 -#define BM_CS1CDR_SSI1_PRED (0x7 << 6) -#define BP_CS1CDR_ESAI_PRED 9 -#define BM_CS1CDR_ESAI_PRED (0x7 << 9) -#define BP_CS1CDR_SSI3_PODF 16 -#define BM_CS1CDR_SSI3_PODF (0x3f << 16) -#define BP_CS1CDR_SSI3_PRED 22 -#define BM_CS1CDR_SSI3_PRED (0x7 << 22) -#define BP_CS1CDR_ESAI_PODF 25 -#define BM_CS1CDR_ESAI_PODF (0x7 << 25) - -#define BP_CS2CDR_SSI2_PODF 0 -#define BM_CS2CDR_SSI2_PODF (0x3f << 0) -#define BP_CS2CDR_SSI2_PRED 6 -#define BM_CS2CDR_SSI2_PRED (0x7 << 6) -#define BP_CS2CDR_LDB_DI0_SEL 9 -#define BM_CS2CDR_LDB_DI0_SEL (0x7 << 9) -#define BP_CS2CDR_LDB_DI1_SEL 12 -#define BM_CS2CDR_LDB_DI1_SEL (0x7 << 12) -#define BP_CS2CDR_ENFC_SEL 16 -#define BM_CS2CDR_ENFC_SEL (0x3 << 16) -#define BP_CS2CDR_ENFC_PRED 18 -#define BM_CS2CDR_ENFC_PRED (0x7 << 18) -#define BP_CS2CDR_ENFC_PODF 21 -#define BM_CS2CDR_ENFC_PODF (0x3f << 21) - -#define BP_CDCDR_ASRC_SERIAL_SEL 7 -#define BM_CDCDR_ASRC_SERIAL_SEL (0x3 << 7) -#define BP_CDCDR_ASRC_SERIAL_PODF 9 -#define BM_CDCDR_ASRC_SERIAL_PODF (0x7 << 9) -#define BP_CDCDR_ASRC_SERIAL_PRED 12 -#define BM_CDCDR_ASRC_SERIAL_PRED (0x7 << 12) -#define BP_CDCDR_SPDIF_SEL 20 -#define BM_CDCDR_SPDIF_SEL (0x3 << 20) -#define BP_CDCDR_SPDIF_PODF 22 -#define BM_CDCDR_SPDIF_PODF (0x7 << 22) -#define BP_CDCDR_SPDIF_PRED 25 -#define BM_CDCDR_SPDIF_PRED (0x7 << 25) -#define BP_CDCDR_HSI_TX_PODF 29 -#define BM_CDCDR_HSI_TX_PODF (0x7 << 29) -#define BP_CDCDR_HSI_TX_SEL 28 -#define BM_CDCDR_HSI_TX_SEL (0x1 << 28) - -#define BP_CHSCCDR_IPU1_DI0_SEL 0 -#define BM_CHSCCDR_IPU1_DI0_SEL (0x7 << 0) -#define BP_CHSCCDR_IPU1_DI0_PRE_PODF 3 -#define BM_CHSCCDR_IPU1_DI0_PRE_PODF (0x7 << 3) -#define BP_CHSCCDR_IPU1_DI0_PRE_SEL 6 -#define BM_CHSCCDR_IPU1_DI0_PRE_SEL (0x7 << 6) -#define BP_CHSCCDR_IPU1_DI1_SEL 9 -#define BM_CHSCCDR_IPU1_DI1_SEL (0x7 << 9) -#define BP_CHSCCDR_IPU1_DI1_PRE_PODF 12 -#define BM_CHSCCDR_IPU1_DI1_PRE_PODF (0x7 << 12) -#define BP_CHSCCDR_IPU1_DI1_PRE_SEL 15 -#define BM_CHSCCDR_IPU1_DI1_PRE_SEL (0x7 << 15) - -#define BP_CSCDR2_IPU2_DI0_SEL 0 -#define BM_CSCDR2_IPU2_DI0_SEL (0x7) -#define BP_CSCDR2_IPU2_DI0_PRE_PODF 3 -#define BM_CSCDR2_IPU2_DI0_PRE_PODF (0x7 << 3) -#define BP_CSCDR2_IPU2_DI0_PRE_SEL 6 -#define BM_CSCDR2_IPU2_DI0_PRE_SEL (0x7 << 6) -#define BP_CSCDR2_IPU2_DI1_SEL 9 -#define BM_CSCDR2_IPU2_DI1_SEL (0x7 << 9) -#define BP_CSCDR2_IPU2_DI1_PRE_PODF 12 -#define BM_CSCDR2_IPU2_DI1_PRE_PODF (0x7 << 12) -#define BP_CSCDR2_IPU2_DI1_PRE_SEL 15 -#define BM_CSCDR2_IPU2_DI1_PRE_SEL (0x7 << 15) -#define BP_CSCDR2_ECSPI_CLK_PODF 19 -#define BM_CSCDR2_ECSPI_CLK_PODF (0x3f << 19) - -#define BP_CSCDR3_IPU1_HSP_SEL 9 -#define BM_CSCDR3_IPU1_HSP_SEL (0x3 << 9) -#define BP_CSCDR3_IPU1_HSP_PODF 11 -#define BM_CSCDR3_IPU1_HSP_PODF (0x7 << 11) -#define BP_CSCDR3_IPU2_HSP_SEL 14 -#define BM_CSCDR3_IPU2_HSP_SEL (0x3 << 14) -#define BP_CSCDR3_IPU2_HSP_PODF 16 -#define BM_CSCDR3_IPU2_HSP_PODF (0x7 << 16) - -#define BM_CDHIPR_AXI_PODF_BUSY (0x1 << 0) -#define BM_CDHIPR_AHB_PODF_BUSY (0x1 << 1) -#define BM_CDHIPR_MMDC_CH1_PODF_BUSY (0x1 << 2) -#define BM_CDHIPR_PERIPH2_SEL_BUSY (0x1 << 3) -#define BM_CDHIPR_MMDC_CH0_PODF_BUSY (0x1 << 4) -#define BM_CDHIPR_PERIPH_SEL_BUSY (0x1 << 5) -#define BM_CDHIPR_ARM_PODF_BUSY (0x1 << 16) - -#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) - -#define BP_CCOSR_CKO1_EN 7 -#define BP_CCOSR_CKO1_PODF 4 -#define BM_CCOSR_CKO1_PODF (0x7 << 4) -#define BP_CCOSR_CKO1_SEL 0 -#define BM_CCOSR_CKO1_SEL (0xf << 0) - -#define FREQ_480M 480000000 -#define FREQ_528M 528000000 -#define FREQ_594M 594000000 -#define FREQ_650M 650000000 -#define FREQ_1300M 1300000000 - -static struct clk pll1_sys; -static struct clk pll2_bus; -static struct clk pll3_usb_otg; -static struct clk pll4_audio; -static struct clk pll5_video; -static struct clk pll6_mlb; -static struct clk pll7_usb_host; -static struct clk pll8_enet; -static struct clk apbh_dma_clk; -static struct clk arm_clk; -static struct clk ipg_clk; -static struct clk ahb_clk; -static struct clk axi_clk; -static struct clk mmdc_ch0_axi_clk; -static struct clk mmdc_ch1_axi_clk; -static struct clk periph_clk; -static struct clk periph_pre_clk; -static struct clk periph_clk2_clk; -static struct clk periph2_clk; -static struct clk periph2_pre_clk; -static struct clk periph2_clk2_clk; -static struct clk gpu2d_core_clk; -static struct clk gpu3d_core_clk; -static struct clk gpu3d_shader_clk; -static struct clk ipg_perclk; -static struct clk emi_clk; -static struct clk emi_slow_clk; -static struct clk can1_clk; -static struct clk uart_clk; -static struct clk usdhc1_clk; -static struct clk usdhc2_clk; -static struct clk usdhc3_clk; -static struct clk usdhc4_clk; -static struct clk vpu_clk; -static struct clk hsi_tx_clk; -static struct clk ipu1_di0_pre_clk; -static struct clk ipu1_di1_pre_clk; -static struct clk ipu2_di0_pre_clk; -static struct clk ipu2_di1_pre_clk; -static struct clk ipu1_clk; -static struct clk ipu2_clk; -static struct clk ssi1_clk; -static struct clk ssi3_clk; -static struct clk esai_clk; -static struct clk ssi2_clk; -static struct clk spdif_clk; -static struct clk asrc_serial_clk; -static struct clk gpu2d_axi_clk; -static struct clk gpu3d_axi_clk; -static struct clk pcie_clk; -static struct clk vdo_axi_clk; -static struct clk ldb_di0_clk; -static struct clk ldb_di1_clk; -static struct clk ipu1_di0_clk; -static struct clk ipu1_di1_clk; -static struct clk ipu2_di0_clk; -static struct clk ipu2_di1_clk; -static struct clk enfc_clk; -static struct clk cko1_clk; -static struct clk dummy_clk = {}; - -static unsigned long external_high_reference; -static unsigned long external_low_reference; -static unsigned long oscillator_reference; - -static unsigned long get_oscillator_reference_clock_rate(struct clk *clk) -{ - return oscillator_reference; -} - -static unsigned long get_high_reference_clock_rate(struct clk *clk) -{ - return external_high_reference; -} - -static unsigned long get_low_reference_clock_rate(struct clk *clk) -{ - return external_low_reference; -} - -static struct clk ckil_clk = { - .get_rate = get_low_reference_clock_rate, -}; - -static struct clk ckih_clk = { - .get_rate = get_high_reference_clock_rate, -}; - -static struct clk osc_clk = { - .get_rate = get_oscillator_reference_clock_rate, -}; - -static inline void __iomem *pll_get_reg_addr(struct clk *pll) -{ - if (pll == &pll1_sys) - return PLL1_SYS; - else if (pll == &pll2_bus) - return PLL2_BUS; - else if (pll == &pll3_usb_otg) - return PLL3_USB_OTG; - else if (pll == &pll4_audio) - return PLL4_AUDIO; - else if (pll == &pll5_video) - return PLL5_VIDEO; - else if (pll == &pll6_mlb) - return PLL6_MLB; - else if (pll == &pll7_usb_host) - return PLL7_USB_HOST; - else if (pll == &pll8_enet) - return PLL8_ENET; - else - BUG(); - - return NULL; -} - -static int pll_enable(struct clk *clk) -{ - int timeout = 0x100000; - void __iomem *reg; - u32 val; - - reg = pll_get_reg_addr(clk); - val = readl_relaxed(reg); - val &= ~BM_PLL_BYPASS; - val &= ~BM_PLL_POWER_DOWN; - /* 480MHz PLLs have the opposite definition for power bit */ - if (clk == &pll3_usb_otg || clk == &pll7_usb_host) - val |= BM_PLL_POWER_DOWN; - writel_relaxed(val, reg); - - /* Wait for PLL to lock */ - while (!(readl_relaxed(reg) & BM_PLL_LOCK) && --timeout) - cpu_relax(); - - if (unlikely(!timeout)) - return -EBUSY; - - /* Enable the PLL output now */ - val = readl_relaxed(reg); - val |= BM_PLL_ENABLE; - writel_relaxed(val, reg); - - return 0; -} - -static void pll_disable(struct clk *clk) -{ - void __iomem *reg; - u32 val; - - reg = pll_get_reg_addr(clk); - val = readl_relaxed(reg); - val &= ~BM_PLL_ENABLE; - val |= BM_PLL_BYPASS; - val |= BM_PLL_POWER_DOWN; - if (clk == &pll3_usb_otg || clk == &pll7_usb_host) - val &= ~BM_PLL_POWER_DOWN; - writel_relaxed(val, reg); -} - -static unsigned long pll1_sys_get_rate(struct clk *clk) -{ - u32 div = (readl_relaxed(PLL1_SYS) & BM_PLL_SYS_DIV_SELECT) >> - BP_PLL_SYS_DIV_SELECT; - - return clk_get_rate(clk->parent) * div / 2; -} - -static int pll1_sys_set_rate(struct clk *clk, unsigned long rate) -{ - u32 val, div; - - if (rate < FREQ_650M || rate > FREQ_1300M) - return -EINVAL; - - div = rate * 2 / clk_get_rate(clk->parent); - val = readl_relaxed(PLL1_SYS); - val &= ~BM_PLL_SYS_DIV_SELECT; - val |= div << BP_PLL_SYS_DIV_SELECT; - writel_relaxed(val, PLL1_SYS); - - return 0; -} - -static unsigned long pll8_enet_get_rate(struct clk *clk) -{ - u32 div = (readl_relaxed(PLL8_ENET) & BM_PLL_ENET_DIV_SELECT) >> - BP_PLL_ENET_DIV_SELECT; - - switch (div) { - case 0: - return 25000000; - case 1: - return 50000000; - case 2: - return 100000000; - case 3: - return 125000000; - } - - return 0; -} - -static int pll8_enet_set_rate(struct clk *clk, unsigned long rate) -{ - u32 val, div; - - switch (rate) { - case 25000000: - div = 0; - break; - case 50000000: - div = 1; - break; - case 100000000: - div = 2; - break; - case 125000000: - div = 3; - break; - default: - return -EINVAL; - } - - val = readl_relaxed(PLL8_ENET); - val &= ~BM_PLL_ENET_DIV_SELECT; - val |= div << BP_PLL_ENET_DIV_SELECT; - writel_relaxed(val, PLL8_ENET); - - return 0; -} - -static unsigned long pll_av_get_rate(struct clk *clk) -{ - void __iomem *reg = (clk == &pll4_audio) ? PLL4_AUDIO : PLL5_VIDEO; - unsigned long parent_rate = clk_get_rate(clk->parent); - u32 mfn = readl_relaxed(reg + PLL_NUM_OFFSET); - u32 mfd = readl_relaxed(reg + PLL_DENOM_OFFSET); - u32 div = (readl_relaxed(reg) & BM_PLL_AV_DIV_SELECT) >> - BP_PLL_AV_DIV_SELECT; - - return (parent_rate * div) + ((parent_rate / mfd) * mfn); -} - -static int pll_av_set_rate(struct clk *clk, unsigned long rate) -{ - void __iomem *reg = (clk == &pll4_audio) ? PLL4_AUDIO : PLL5_VIDEO; - unsigned int parent_rate = clk_get_rate(clk->parent); - u32 val, div; - u32 mfn, mfd = 1000000; - s64 temp64; - - if (rate < FREQ_650M || rate > FREQ_1300M) - return -EINVAL; - - div = rate / parent_rate; - temp64 = (u64) (rate - div * parent_rate); - temp64 *= mfd; - do_div(temp64, parent_rate); - mfn = temp64; - - val = readl_relaxed(reg); - val &= ~BM_PLL_AV_DIV_SELECT; - val |= div << BP_PLL_AV_DIV_SELECT; - writel_relaxed(val, reg); - writel_relaxed(mfn, reg + PLL_NUM_OFFSET); - writel_relaxed(mfd, reg + PLL_DENOM_OFFSET); - - return 0; -} - -static void __iomem *pll_get_div_reg_bit(struct clk *clk, u32 *bp, u32 *bm) -{ - void __iomem *reg; - - if (clk == &pll2_bus) { - reg = PLL2_BUS; - *bp = BP_PLL_BUS_DIV_SELECT; - *bm = BM_PLL_BUS_DIV_SELECT; - } else if (clk == &pll3_usb_otg) { - reg = PLL3_USB_OTG; - *bp = BP_PLL_USB_DIV_SELECT; - *bm = BM_PLL_USB_DIV_SELECT; - } else if (clk == &pll7_usb_host) { - reg = PLL7_USB_HOST; - *bp = BP_PLL_USB_DIV_SELECT; - *bm = BM_PLL_USB_DIV_SELECT; - } else { - BUG(); - } - - return reg; -} - -static unsigned long pll_get_rate(struct clk *clk) -{ - void __iomem *reg; - u32 div, bp, bm; - - reg = pll_get_div_reg_bit(clk, &bp, &bm); - div = (readl_relaxed(reg) & bm) >> bp; - - return (div == 1) ? clk_get_rate(clk->parent) * 22 : - clk_get_rate(clk->parent) * 20; -} - -static int pll_set_rate(struct clk *clk, unsigned long rate) -{ - void __iomem *reg; - u32 val, div, bp, bm; - - if (rate == FREQ_528M) - div = 1; - else if (rate == FREQ_480M) - div = 0; - else - return -EINVAL; - - reg = pll_get_div_reg_bit(clk, &bp, &bm); - val = readl_relaxed(reg); - val &= ~bm; - val |= div << bp; - writel_relaxed(val, reg); - - return 0; -} - -#define pll2_bus_get_rate pll_get_rate -#define pll2_bus_set_rate pll_set_rate -#define pll3_usb_otg_get_rate pll_get_rate -#define pll3_usb_otg_set_rate pll_set_rate -#define pll7_usb_host_get_rate pll_get_rate -#define pll7_usb_host_set_rate pll_set_rate -#define pll4_audio_get_rate pll_av_get_rate -#define pll4_audio_set_rate pll_av_set_rate -#define pll5_video_get_rate pll_av_get_rate -#define pll5_video_set_rate pll_av_set_rate -#define pll6_mlb_get_rate NULL -#define pll6_mlb_set_rate NULL - -#define DEF_PLL(name) \ - static struct clk name = { \ - .enable = pll_enable, \ - .disable = pll_disable, \ - .get_rate = name##_get_rate, \ - .set_rate = name##_set_rate, \ - .parent = &osc_clk, \ - } - -DEF_PLL(pll1_sys); -DEF_PLL(pll2_bus); -DEF_PLL(pll3_usb_otg); -DEF_PLL(pll4_audio); -DEF_PLL(pll5_video); -DEF_PLL(pll6_mlb); -DEF_PLL(pll7_usb_host); -DEF_PLL(pll8_enet); - -static unsigned long pfd_get_rate(struct clk *clk) -{ - u64 tmp = (u64) clk_get_rate(clk->parent) * 18; - u32 frac, bp_frac; - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.enable(&apbh_dma_clk); - - bp_frac = clk->enable_shift - 7; - frac = readl_relaxed(clk->enable_reg) >> bp_frac & PFD_FRAC_MASK; - do_div(tmp, frac); - - return tmp; -} - -static int pfd_set_rate(struct clk *clk, unsigned long rate) -{ - u32 val, frac, bp_frac; - u64 tmp = (u64) clk_get_rate(clk->parent) * 18; - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.enable(&apbh_dma_clk); - - /* - * Round up the divider so that we don't set a rate - * higher than what is requested - */ - tmp += rate / 2; - do_div(tmp, rate); - frac = tmp; - frac = (frac < 12) ? 12 : frac; - frac = (frac > 35) ? 35 : frac; - - /* - * The frac field always starts from 7 bits lower - * position of enable bit - */ - bp_frac = clk->enable_shift - 7; - val = readl_relaxed(clk->enable_reg); - val &= ~(PFD_FRAC_MASK << bp_frac); - val |= frac << bp_frac; - writel_relaxed(val, clk->enable_reg); - - tmp = (u64) clk_get_rate(clk->parent) * 18; - do_div(tmp, frac); - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.disable(&apbh_dma_clk); - - return 0; -} - -static unsigned long pfd_round_rate(struct clk *clk, unsigned long rate) -{ - u32 frac; - u64 tmp; - - tmp = (u64) clk_get_rate(clk->parent) * 18; - tmp += rate / 2; - do_div(tmp, rate); - frac = tmp; - frac = (frac < 12) ? 12 : frac; - frac = (frac > 35) ? 35 : frac; - tmp = (u64) clk_get_rate(clk->parent) * 18; - do_div(tmp, frac); - - return tmp; -} - -static int pfd_enable(struct clk *clk) -{ - u32 val; - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.enable(&apbh_dma_clk); - - val = readl_relaxed(clk->enable_reg); - val &= ~(1 << clk->enable_shift); - writel_relaxed(val, clk->enable_reg); - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.disable(&apbh_dma_clk); - - return 0; -} - -static void pfd_disable(struct clk *clk) -{ - u32 val; - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.enable(&apbh_dma_clk); - - val = readl_relaxed(clk->enable_reg); - val |= 1 << clk->enable_shift; - writel_relaxed(val, clk->enable_reg); - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.disable(&apbh_dma_clk); -} - -#define DEF_PFD(name, er, es, p) \ - static struct clk name = { \ - .enable_reg = er, \ - .enable_shift = es, \ - .enable = pfd_enable, \ - .disable = pfd_disable, \ - .get_rate = pfd_get_rate, \ - .set_rate = pfd_set_rate, \ - .round_rate = pfd_round_rate, \ - .parent = p, \ - } - -DEF_PFD(pll2_pfd_352m, PFD_528, PFD0, &pll2_bus); -DEF_PFD(pll2_pfd_594m, PFD_528, PFD1, &pll2_bus); -DEF_PFD(pll2_pfd_400m, PFD_528, PFD2, &pll2_bus); -DEF_PFD(pll3_pfd_720m, PFD_480, PFD0, &pll3_usb_otg); -DEF_PFD(pll3_pfd_540m, PFD_480, PFD1, &pll3_usb_otg); -DEF_PFD(pll3_pfd_508m, PFD_480, PFD2, &pll3_usb_otg); -DEF_PFD(pll3_pfd_454m, PFD_480, PFD3, &pll3_usb_otg); - -static unsigned long twd_clk_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 2; -} - -static struct clk twd_clk = { - .parent = &arm_clk, - .get_rate = twd_clk_get_rate, -}; - -static unsigned long pll2_200m_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 2; -} - -static struct clk pll2_200m = { - .parent = &pll2_pfd_400m, - .get_rate = pll2_200m_get_rate, -}; - -static unsigned long pll3_120m_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 4; -} - -static struct clk pll3_120m = { - .parent = &pll3_usb_otg, - .get_rate = pll3_120m_get_rate, -}; - -static unsigned long pll3_80m_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 6; -} - -static struct clk pll3_80m = { - .parent = &pll3_usb_otg, - .get_rate = pll3_80m_get_rate, -}; - -static unsigned long pll3_60m_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 8; -} - -static struct clk pll3_60m = { - .parent = &pll3_usb_otg, - .get_rate = pll3_60m_get_rate, -}; - -static int pll1_sw_clk_set_parent(struct clk *clk, struct clk *parent) -{ - u32 val = readl_relaxed(CCSR); - - if (parent == &pll1_sys) { - val &= ~BM_CCSR_PLL1_SW_SEL; - val &= ~BM_CCSR_STEP_SEL; - } else if (parent == &osc_clk) { - val |= BM_CCSR_PLL1_SW_SEL; - val &= ~BM_CCSR_STEP_SEL; - } else if (parent == &pll2_pfd_400m) { - val |= BM_CCSR_PLL1_SW_SEL; - val |= BM_CCSR_STEP_SEL; - } else { - return -EINVAL; - } - - writel_relaxed(val, CCSR); - - return 0; -} - -static struct clk pll1_sw_clk = { - .parent = &pll1_sys, - .set_parent = pll1_sw_clk_set_parent, -}; - -static void calc_pred_podf_dividers(u32 div, u32 *pred, u32 *podf) -{ - u32 min_pred, temp_pred, old_err, err; - - if (div >= 512) { - *pred = 8; - *podf = 64; - } else if (div >= 8) { - min_pred = (div - 1) / 64 + 1; - old_err = 8; - for (temp_pred = 8; temp_pred >= min_pred; temp_pred--) { - err = div % temp_pred; - if (err == 0) { - *pred = temp_pred; - break; - } - err = temp_pred - err; - if (err < old_err) { - old_err = err; - *pred = temp_pred; - } - } - *podf = (div + *pred - 1) / *pred; - } else if (div < 8) { - *pred = div; - *podf = 1; - } -} - -static int _clk_enable(struct clk *clk) -{ - u32 reg; - reg = readl_relaxed(clk->enable_reg); - reg |= 0x3 << clk->enable_shift; - writel_relaxed(reg, clk->enable_reg); - - return 0; -} - -static void _clk_disable(struct clk *clk) -{ - u32 reg; - reg = readl_relaxed(clk->enable_reg); - reg &= ~(0x3 << clk->enable_shift); - writel_relaxed(reg, clk->enable_reg); -} - -static int _clk_enable_1b(struct clk *clk) -{ - u32 reg; - reg = readl_relaxed(clk->enable_reg); - reg |= 0x1 << clk->enable_shift; - writel_relaxed(reg, clk->enable_reg); - - return 0; -} - -static void _clk_disable_1b(struct clk *clk) -{ - u32 reg; - reg = readl_relaxed(clk->enable_reg); - reg &= ~(0x1 << clk->enable_shift); - writel_relaxed(reg, clk->enable_reg); -} - -struct divider { - struct clk *clk; - void __iomem *reg; - u32 bp_pred; - u32 bm_pred; - u32 bp_podf; - u32 bm_podf; -}; - -#define DEF_CLK_DIV1(d, c, r, b) \ - static struct divider d = { \ - .clk = c, \ - .reg = r, \ - .bp_podf = BP_##r##_##b##_PODF, \ - .bm_podf = BM_##r##_##b##_PODF, \ - } - -DEF_CLK_DIV1(arm_div, &arm_clk, CACRR, ARM); -DEF_CLK_DIV1(ipg_div, &ipg_clk, CBCDR, IPG); -DEF_CLK_DIV1(ahb_div, &ahb_clk, CBCDR, AHB); -DEF_CLK_DIV1(axi_div, &axi_clk, CBCDR, AXI); -DEF_CLK_DIV1(mmdc_ch0_axi_div, &mmdc_ch0_axi_clk, CBCDR, MMDC_CH0_AXI); -DEF_CLK_DIV1(mmdc_ch1_axi_div, &mmdc_ch1_axi_clk, CBCDR, MMDC_CH1_AXI); -DEF_CLK_DIV1(periph_clk2_div, &periph_clk2_clk, CBCDR, PERIPH_CLK2); -DEF_CLK_DIV1(periph2_clk2_div, &periph2_clk2_clk, CBCDR, PERIPH2_CLK2); -DEF_CLK_DIV1(gpu2d_core_div, &gpu2d_core_clk, CBCMR, GPU2D_CORE); -DEF_CLK_DIV1(gpu3d_core_div, &gpu3d_core_clk, CBCMR, GPU3D_CORE); -DEF_CLK_DIV1(gpu3d_shader_div, &gpu3d_shader_clk, CBCMR, GPU3D_SHADER); -DEF_CLK_DIV1(ipg_perclk_div, &ipg_perclk, CSCMR1, PERCLK); -DEF_CLK_DIV1(emi_div, &emi_clk, CSCMR1, EMI); -DEF_CLK_DIV1(emi_slow_div, &emi_slow_clk, CSCMR1, EMI_SLOW); -DEF_CLK_DIV1(can_div, &can1_clk, CSCMR2, CAN); -DEF_CLK_DIV1(uart_div, &uart_clk, CSCDR1, UART); -DEF_CLK_DIV1(usdhc1_div, &usdhc1_clk, CSCDR1, USDHC1); -DEF_CLK_DIV1(usdhc2_div, &usdhc2_clk, CSCDR1, USDHC2); -DEF_CLK_DIV1(usdhc3_div, &usdhc3_clk, CSCDR1, USDHC3); -DEF_CLK_DIV1(usdhc4_div, &usdhc4_clk, CSCDR1, USDHC4); -DEF_CLK_DIV1(vpu_div, &vpu_clk, CSCDR1, VPU_AXI); -DEF_CLK_DIV1(hsi_tx_div, &hsi_tx_clk, CDCDR, HSI_TX); -DEF_CLK_DIV1(ipu1_di0_pre_div, &ipu1_di0_pre_clk, CHSCCDR, IPU1_DI0_PRE); -DEF_CLK_DIV1(ipu1_di1_pre_div, &ipu1_di1_pre_clk, CHSCCDR, IPU1_DI1_PRE); -DEF_CLK_DIV1(ipu2_di0_pre_div, &ipu2_di0_pre_clk, CSCDR2, IPU2_DI0_PRE); -DEF_CLK_DIV1(ipu2_di1_pre_div, &ipu2_di1_pre_clk, CSCDR2, IPU2_DI1_PRE); -DEF_CLK_DIV1(ipu1_div, &ipu1_clk, CSCDR3, IPU1_HSP); -DEF_CLK_DIV1(ipu2_div, &ipu2_clk, CSCDR3, IPU2_HSP); -DEF_CLK_DIV1(cko1_div, &cko1_clk, CCOSR, CKO1); - -#define DEF_CLK_DIV2(d, c, r, b) \ - static struct divider d = { \ - .clk = c, \ - .reg = r, \ - .bp_pred = BP_##r##_##b##_PRED, \ - .bm_pred = BM_##r##_##b##_PRED, \ - .bp_podf = BP_##r##_##b##_PODF, \ - .bm_podf = BM_##r##_##b##_PODF, \ - } - -DEF_CLK_DIV2(ssi1_div, &ssi1_clk, CS1CDR, SSI1); -DEF_CLK_DIV2(ssi3_div, &ssi3_clk, CS1CDR, SSI3); -DEF_CLK_DIV2(esai_div, &esai_clk, CS1CDR, ESAI); -DEF_CLK_DIV2(ssi2_div, &ssi2_clk, CS2CDR, SSI2); -DEF_CLK_DIV2(enfc_div, &enfc_clk, CS2CDR, ENFC); -DEF_CLK_DIV2(spdif_div, &spdif_clk, CDCDR, SPDIF); -DEF_CLK_DIV2(asrc_serial_div, &asrc_serial_clk, CDCDR, ASRC_SERIAL); - -static struct divider *dividers[] = { - &arm_div, - &ipg_div, - &ahb_div, - &axi_div, - &mmdc_ch0_axi_div, - &mmdc_ch1_axi_div, - &periph_clk2_div, - &periph2_clk2_div, - &gpu2d_core_div, - &gpu3d_core_div, - &gpu3d_shader_div, - &ipg_perclk_div, - &emi_div, - &emi_slow_div, - &can_div, - &uart_div, - &usdhc1_div, - &usdhc2_div, - &usdhc3_div, - &usdhc4_div, - &vpu_div, - &hsi_tx_div, - &ipu1_di0_pre_div, - &ipu1_di1_pre_div, - &ipu2_di0_pre_div, - &ipu2_di1_pre_div, - &ipu1_div, - &ipu2_div, - &ssi1_div, - &ssi3_div, - &esai_div, - &ssi2_div, - &enfc_div, - &spdif_div, - &asrc_serial_div, - &cko1_div, -}; - -static unsigned long ldb_di_clk_get_rate(struct clk *clk) -{ - u32 val = readl_relaxed(CSCMR2); - - val &= (clk == &ldb_di0_clk) ? BM_CSCMR2_LDB_DI0_IPU_DIV : - BM_CSCMR2_LDB_DI1_IPU_DIV; - if (val) - return clk_get_rate(clk->parent) / 7; - else - return clk_get_rate(clk->parent) * 2 / 7; -} - -static int ldb_di_clk_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - u32 val = readl_relaxed(CSCMR2); - - if (rate * 7 <= parent_rate + parent_rate / 20) - val |= BM_CSCMR2_LDB_DI0_IPU_DIV; - else - val &= ~BM_CSCMR2_LDB_DI0_IPU_DIV; - - writel_relaxed(val, CSCMR2); - - return 0; -} - -static unsigned long ldb_di_clk_round_rate(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - - if (rate * 7 <= parent_rate + parent_rate / 20) - return parent_rate / 7; - else - return 2 * parent_rate / 7; -} - -static unsigned long _clk_get_rate(struct clk *clk) -{ - struct divider *d; - u32 val, pred, podf; - int i, num; - - if (clk == &ldb_di0_clk || clk == &ldb_di1_clk) - return ldb_di_clk_get_rate(clk); - - num = ARRAY_SIZE(dividers); - for (i = 0; i < num; i++) - if (dividers[i]->clk == clk) { - d = dividers[i]; - break; - } - if (i == num) - return clk_get_rate(clk->parent); - - val = readl_relaxed(d->reg); - pred = ((val & d->bm_pred) >> d->bp_pred) + 1; - podf = ((val & d->bm_podf) >> d->bp_podf) + 1; - - return clk_get_rate(clk->parent) / (pred * podf); -} - -static int clk_busy_wait(struct clk *clk) -{ - int timeout = 0x100000; - u32 bm; - - if (clk == &axi_clk) - bm = BM_CDHIPR_AXI_PODF_BUSY; - else if (clk == &ahb_clk) - bm = BM_CDHIPR_AHB_PODF_BUSY; - else if (clk == &mmdc_ch0_axi_clk) - bm = BM_CDHIPR_MMDC_CH0_PODF_BUSY; - else if (clk == &periph_clk) - bm = BM_CDHIPR_PERIPH_SEL_BUSY; - else if (clk == &arm_clk) - bm = BM_CDHIPR_ARM_PODF_BUSY; - else - return -EINVAL; - - while ((readl_relaxed(CDHIPR) & bm) && --timeout) - cpu_relax(); - - if (unlikely(!timeout)) - return -EBUSY; - - return 0; -} - -static int _clk_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - struct divider *d; - u32 val, div, max_div, pred = 0, podf; - int i, num; - - if (clk == &ldb_di0_clk || clk == &ldb_di1_clk) - return ldb_di_clk_set_rate(clk, rate); - - num = ARRAY_SIZE(dividers); - for (i = 0; i < num; i++) - if (dividers[i]->clk == clk) { - d = dividers[i]; - break; - } - if (i == num) - return -EINVAL; - - max_div = ((d->bm_pred >> d->bp_pred) + 1) * - ((d->bm_podf >> d->bp_podf) + 1); - - div = parent_rate / rate; - if (div == 0) - div++; - - if ((parent_rate / div != rate) || div > max_div) - return -EINVAL; - - if (d->bm_pred) { - calc_pred_podf_dividers(div, &pred, &podf); - } else { - pred = 1; - podf = div; - } - - val = readl_relaxed(d->reg); - val &= ~(d->bm_pred | d->bm_podf); - val |= (pred - 1) << d->bp_pred | (podf - 1) << d->bp_podf; - writel_relaxed(val, d->reg); - - if (clk == &axi_clk || clk == &ahb_clk || - clk == &mmdc_ch0_axi_clk || clk == &arm_clk) - return clk_busy_wait(clk); - - return 0; -} - -static unsigned long _clk_round_rate(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - u32 div = parent_rate / rate; - u32 div_max, pred = 0, podf; - struct divider *d; - int i, num; - - if (clk == &ldb_di0_clk || clk == &ldb_di1_clk) - return ldb_di_clk_round_rate(clk, rate); - - num = ARRAY_SIZE(dividers); - for (i = 0; i < num; i++) - if (dividers[i]->clk == clk) { - d = dividers[i]; - break; - } - if (i == num) - return -EINVAL; - - if (div == 0 || parent_rate % rate) - div++; - - if (d->bm_pred) { - calc_pred_podf_dividers(div, &pred, &podf); - div = pred * podf; - } else { - div_max = (d->bm_podf >> d->bp_podf) + 1; - if (div > div_max) - div = div_max; - } - - return parent_rate / div; -} - -struct multiplexer { - struct clk *clk; - void __iomem *reg; - u32 bp; - u32 bm; - int pnum; - struct clk *parents[]; -}; - -static struct multiplexer axi_mux = { - .clk = &axi_clk, - .reg = CBCDR, - .bp = BP_CBCDR_AXI_SEL, - .bm = BM_CBCDR_AXI_SEL, - .parents = { - &periph_clk, - &pll2_pfd_400m, - &pll3_pfd_540m, - NULL - }, -}; - -static struct multiplexer periph_mux = { - .clk = &periph_clk, - .reg = CBCDR, - .bp = BP_CBCDR_PERIPH_CLK_SEL, - .bm = BM_CBCDR_PERIPH_CLK_SEL, - .parents = { - &periph_pre_clk, - &periph_clk2_clk, - NULL - }, -}; - -static struct multiplexer periph_pre_mux = { - .clk = &periph_pre_clk, - .reg = CBCMR, - .bp = BP_CBCMR_PRE_PERIPH_CLK_SEL, - .bm = BM_CBCMR_PRE_PERIPH_CLK_SEL, - .parents = { - &pll2_bus, - &pll2_pfd_400m, - &pll2_pfd_352m, - &pll2_200m, - NULL - }, -}; - -static struct multiplexer periph_clk2_mux = { - .clk = &periph_clk2_clk, - .reg = CBCMR, - .bp = BP_CBCMR_PERIPH_CLK2_SEL, - .bm = BM_CBCMR_PERIPH_CLK2_SEL, - .parents = { - &pll3_usb_otg, - &osc_clk, - NULL - }, -}; - -static struct multiplexer periph2_mux = { - .clk = &periph2_clk, - .reg = CBCDR, - .bp = BP_CBCDR_PERIPH2_CLK_SEL, - .bm = BM_CBCDR_PERIPH2_CLK_SEL, - .parents = { - &periph2_pre_clk, - &periph2_clk2_clk, - NULL - }, -}; - -static struct multiplexer periph2_pre_mux = { - .clk = &periph2_pre_clk, - .reg = CBCMR, - .bp = BP_CBCMR_PRE_PERIPH2_CLK_SEL, - .bm = BM_CBCMR_PRE_PERIPH2_CLK_SEL, - .parents = { - &pll2_bus, - &pll2_pfd_400m, - &pll2_pfd_352m, - &pll2_200m, - NULL - }, -}; - -static struct multiplexer periph2_clk2_mux = { - .clk = &periph2_clk2_clk, - .reg = CBCMR, - .bp = BP_CBCMR_PERIPH2_CLK2_SEL, - .bm = BM_CBCMR_PERIPH2_CLK2_SEL, - .parents = { - &pll3_usb_otg, - &osc_clk, - NULL - }, -}; - -static struct multiplexer gpu2d_axi_mux = { - .clk = &gpu2d_axi_clk, - .reg = CBCMR, - .bp = BP_CBCMR_GPU2D_AXI_SEL, - .bm = BM_CBCMR_GPU2D_AXI_SEL, - .parents = { - &axi_clk, - &ahb_clk, - NULL - }, -}; - -static struct multiplexer gpu3d_axi_mux = { - .clk = &gpu3d_axi_clk, - .reg = CBCMR, - .bp = BP_CBCMR_GPU3D_AXI_SEL, - .bm = BM_CBCMR_GPU3D_AXI_SEL, - .parents = { - &axi_clk, - &ahb_clk, - NULL - }, -}; - -static struct multiplexer gpu3d_core_mux = { - .clk = &gpu3d_core_clk, - .reg = CBCMR, - .bp = BP_CBCMR_GPU3D_CORE_SEL, - .bm = BM_CBCMR_GPU3D_CORE_SEL, - .parents = { - &mmdc_ch0_axi_clk, - &pll3_usb_otg, - &pll2_pfd_594m, - &pll2_pfd_400m, - NULL - }, -}; - -static struct multiplexer gpu3d_shader_mux = { - .clk = &gpu3d_shader_clk, - .reg = CBCMR, - .bp = BP_CBCMR_GPU3D_SHADER_SEL, - .bm = BM_CBCMR_GPU3D_SHADER_SEL, - .parents = { - &mmdc_ch0_axi_clk, - &pll3_usb_otg, - &pll2_pfd_594m, - &pll3_pfd_720m, - NULL - }, -}; - -static struct multiplexer pcie_axi_mux = { - .clk = &pcie_clk, - .reg = CBCMR, - .bp = BP_CBCMR_PCIE_AXI_SEL, - .bm = BM_CBCMR_PCIE_AXI_SEL, - .parents = { - &axi_clk, - &ahb_clk, - NULL - }, -}; - -static struct multiplexer vdo_axi_mux = { - .clk = &vdo_axi_clk, - .reg = CBCMR, - .bp = BP_CBCMR_VDO_AXI_SEL, - .bm = BM_CBCMR_VDO_AXI_SEL, - .parents = { - &axi_clk, - &ahb_clk, - NULL - }, -}; - -static struct multiplexer vpu_axi_mux = { - .clk = &vpu_clk, - .reg = CBCMR, - .bp = BP_CBCMR_VPU_AXI_SEL, - .bm = BM_CBCMR_VPU_AXI_SEL, - .parents = { - &axi_clk, - &pll2_pfd_400m, - &pll2_pfd_352m, - NULL - }, -}; - -static struct multiplexer gpu2d_core_mux = { - .clk = &gpu2d_core_clk, - .reg = CBCMR, - .bp = BP_CBCMR_GPU2D_CORE_SEL, - .bm = BM_CBCMR_GPU2D_CORE_SEL, - .parents = { - &axi_clk, - &pll3_usb_otg, - &pll2_pfd_352m, - &pll2_pfd_400m, - NULL - }, -}; - -#define DEF_SSI_MUX(id) \ - static struct multiplexer ssi##id##_mux = { \ - .clk = &ssi##id##_clk, \ - .reg = CSCMR1, \ - .bp = BP_CSCMR1_SSI##id##_SEL, \ - .bm = BM_CSCMR1_SSI##id##_SEL, \ - .parents = { \ - &pll3_pfd_508m, \ - &pll3_pfd_454m, \ - &pll4_audio, \ - NULL \ - }, \ - } - -DEF_SSI_MUX(1); -DEF_SSI_MUX(2); -DEF_SSI_MUX(3); - -#define DEF_USDHC_MUX(id) \ - static struct multiplexer usdhc##id##_mux = { \ - .clk = &usdhc##id##_clk, \ - .reg = CSCMR1, \ - .bp = BP_CSCMR1_USDHC##id##_SEL, \ - .bm = BM_CSCMR1_USDHC##id##_SEL, \ - .parents = { \ - &pll2_pfd_400m, \ - &pll2_pfd_352m, \ - NULL \ - }, \ - } - -DEF_USDHC_MUX(1); -DEF_USDHC_MUX(2); -DEF_USDHC_MUX(3); -DEF_USDHC_MUX(4); - -static struct multiplexer emi_mux = { - .clk = &emi_clk, - .reg = CSCMR1, - .bp = BP_CSCMR1_EMI_SEL, - .bm = BM_CSCMR1_EMI_SEL, - .parents = { - &axi_clk, - &pll3_usb_otg, - &pll2_pfd_400m, - &pll2_pfd_352m, - NULL - }, -}; - -static struct multiplexer emi_slow_mux = { - .clk = &emi_slow_clk, - .reg = CSCMR1, - .bp = BP_CSCMR1_EMI_SLOW_SEL, - .bm = BM_CSCMR1_EMI_SLOW_SEL, - .parents = { - &axi_clk, - &pll3_usb_otg, - &pll2_pfd_400m, - &pll2_pfd_352m, - NULL - }, -}; - -static struct multiplexer esai_mux = { - .clk = &esai_clk, - .reg = CSCMR2, - .bp = BP_CSCMR2_ESAI_SEL, - .bm = BM_CSCMR2_ESAI_SEL, - .parents = { - &pll4_audio, - &pll3_pfd_508m, - &pll3_pfd_454m, - &pll3_usb_otg, - NULL - }, -}; - -#define DEF_LDB_DI_MUX(id) \ - static struct multiplexer ldb_di##id##_mux = { \ - .clk = &ldb_di##id##_clk, \ - .reg = CS2CDR, \ - .bp = BP_CS2CDR_LDB_DI##id##_SEL, \ - .bm = BM_CS2CDR_LDB_DI##id##_SEL, \ - .parents = { \ - &pll5_video, \ - &pll2_pfd_352m, \ - &pll2_pfd_400m, \ - &pll3_pfd_540m, \ - &pll3_usb_otg, \ - NULL \ - }, \ - } - -DEF_LDB_DI_MUX(0); -DEF_LDB_DI_MUX(1); - -static struct multiplexer enfc_mux = { - .clk = &enfc_clk, - .reg = CS2CDR, - .bp = BP_CS2CDR_ENFC_SEL, - .bm = BM_CS2CDR_ENFC_SEL, - .parents = { - &pll2_pfd_352m, - &pll2_bus, - &pll3_usb_otg, - &pll2_pfd_400m, - NULL - }, -}; - -static struct multiplexer spdif_mux = { - .clk = &spdif_clk, - .reg = CDCDR, - .bp = BP_CDCDR_SPDIF_SEL, - .bm = BM_CDCDR_SPDIF_SEL, - .parents = { - &pll4_audio, - &pll3_pfd_508m, - &pll3_pfd_454m, - &pll3_usb_otg, - NULL - }, -}; - -static struct multiplexer asrc_serial_mux = { - .clk = &asrc_serial_clk, - .reg = CDCDR, - .bp = BP_CDCDR_ASRC_SERIAL_SEL, - .bm = BM_CDCDR_ASRC_SERIAL_SEL, - .parents = { - &pll4_audio, - &pll3_pfd_508m, - &pll3_pfd_454m, - &pll3_usb_otg, - NULL - }, -}; - -static struct multiplexer hsi_tx_mux = { - .clk = &hsi_tx_clk, - .reg = CDCDR, - .bp = BP_CDCDR_HSI_TX_SEL, - .bm = BM_CDCDR_HSI_TX_SEL, - .parents = { - &pll3_120m, - &pll2_pfd_400m, - NULL - }, -}; - -#define DEF_IPU_DI_PRE_MUX(r, i, d) \ - static struct multiplexer ipu##i##_di##d##_pre_mux = { \ - .clk = &ipu##i##_di##d##_pre_clk, \ - .reg = r, \ - .bp = BP_##r##_IPU##i##_DI##d##_PRE_SEL, \ - .bm = BM_##r##_IPU##i##_DI##d##_PRE_SEL, \ - .parents = { \ - &mmdc_ch0_axi_clk, \ - &pll3_usb_otg, \ - &pll5_video, \ - &pll2_pfd_352m, \ - &pll2_pfd_400m, \ - &pll3_pfd_540m, \ - NULL \ - }, \ - } - -DEF_IPU_DI_PRE_MUX(CHSCCDR, 1, 0); -DEF_IPU_DI_PRE_MUX(CHSCCDR, 1, 1); -DEF_IPU_DI_PRE_MUX(CSCDR2, 2, 0); -DEF_IPU_DI_PRE_MUX(CSCDR2, 2, 1); - -#define DEF_IPU_DI_MUX(r, i, d) \ - static struct multiplexer ipu##i##_di##d##_mux = { \ - .clk = &ipu##i##_di##d##_clk, \ - .reg = r, \ - .bp = BP_##r##_IPU##i##_DI##d##_SEL, \ - .bm = BM_##r##_IPU##i##_DI##d##_SEL, \ - .parents = { \ - &ipu##i##_di##d##_pre_clk, \ - &dummy_clk, \ - &dummy_clk, \ - &ldb_di0_clk, \ - &ldb_di1_clk, \ - NULL \ - }, \ - } - -DEF_IPU_DI_MUX(CHSCCDR, 1, 0); -DEF_IPU_DI_MUX(CHSCCDR, 1, 1); -DEF_IPU_DI_MUX(CSCDR2, 2, 0); -DEF_IPU_DI_MUX(CSCDR2, 2, 1); - -#define DEF_IPU_MUX(id) \ - static struct multiplexer ipu##id##_mux = { \ - .clk = &ipu##id##_clk, \ - .reg = CSCDR3, \ - .bp = BP_CSCDR3_IPU##id##_HSP_SEL, \ - .bm = BM_CSCDR3_IPU##id##_HSP_SEL, \ - .parents = { \ - &mmdc_ch0_axi_clk, \ - &pll2_pfd_400m, \ - &pll3_120m, \ - &pll3_pfd_540m, \ - NULL \ - }, \ - } - -DEF_IPU_MUX(1); -DEF_IPU_MUX(2); - -static struct multiplexer cko1_mux = { - .clk = &cko1_clk, - .reg = CCOSR, - .bp = BP_CCOSR_CKO1_SEL, - .bm = BM_CCOSR_CKO1_SEL, - .parents = { - &pll3_usb_otg, - &pll2_bus, - &pll1_sys, - &pll5_video, - &dummy_clk, - &axi_clk, - &enfc_clk, - &ipu1_di0_clk, - &ipu1_di1_clk, - &ipu2_di0_clk, - &ipu2_di1_clk, - &ahb_clk, - &ipg_clk, - &ipg_perclk, - &ckil_clk, - &pll4_audio, - NULL - }, -}; - -static struct multiplexer *multiplexers[] = { - &axi_mux, - &periph_mux, - &periph_pre_mux, - &periph_clk2_mux, - &periph2_mux, - &periph2_pre_mux, - &periph2_clk2_mux, - &gpu2d_axi_mux, - &gpu3d_axi_mux, - &gpu3d_core_mux, - &gpu3d_shader_mux, - &pcie_axi_mux, - &vdo_axi_mux, - &vpu_axi_mux, - &gpu2d_core_mux, - &ssi1_mux, - &ssi2_mux, - &ssi3_mux, - &usdhc1_mux, - &usdhc2_mux, - &usdhc3_mux, - &usdhc4_mux, - &emi_mux, - &emi_slow_mux, - &esai_mux, - &ldb_di0_mux, - &ldb_di1_mux, - &enfc_mux, - &spdif_mux, - &asrc_serial_mux, - &hsi_tx_mux, - &ipu1_di0_pre_mux, - &ipu1_di0_mux, - &ipu1_di1_pre_mux, - &ipu1_di1_mux, - &ipu2_di0_pre_mux, - &ipu2_di0_mux, - &ipu2_di1_pre_mux, - &ipu2_di1_mux, - &ipu1_mux, - &ipu2_mux, - &cko1_mux, -}; - -static int _clk_set_parent(struct clk *clk, struct clk *parent) -{ - struct multiplexer *m; - int i, num; - u32 val; - - num = ARRAY_SIZE(multiplexers); - for (i = 0; i < num; i++) - if (multiplexers[i]->clk == clk) { - m = multiplexers[i]; - break; - } - if (i == num) - return -EINVAL; - - i = 0; - while (m->parents[i]) { - if (parent == m->parents[i]) - break; - i++; - } - if (!m->parents[i] || m->parents[i] == &dummy_clk) - return -EINVAL; - - val = readl_relaxed(m->reg); - val &= ~m->bm; - val |= i << m->bp; - writel_relaxed(val, m->reg); - - if (clk == &periph_clk) - return clk_busy_wait(clk); - - return 0; -} - -#define DEF_NG_CLK(name, p) \ - static struct clk name = { \ - .get_rate = _clk_get_rate, \ - .set_rate = _clk_set_rate, \ - .round_rate = _clk_round_rate, \ - .set_parent = _clk_set_parent, \ - .parent = p, \ - } - -DEF_NG_CLK(periph_clk2_clk, &osc_clk); -DEF_NG_CLK(periph_pre_clk, &pll2_bus); -DEF_NG_CLK(periph_clk, &periph_pre_clk); -DEF_NG_CLK(periph2_clk2_clk, &osc_clk); -DEF_NG_CLK(periph2_pre_clk, &pll2_bus); -DEF_NG_CLK(periph2_clk, &periph2_pre_clk); -DEF_NG_CLK(axi_clk, &periph_clk); -DEF_NG_CLK(emi_clk, &axi_clk); -DEF_NG_CLK(arm_clk, &pll1_sw_clk); -DEF_NG_CLK(ahb_clk, &periph_clk); -DEF_NG_CLK(ipg_clk, &ahb_clk); -DEF_NG_CLK(ipg_perclk, &ipg_clk); -DEF_NG_CLK(ipu1_di0_pre_clk, &pll3_pfd_540m); -DEF_NG_CLK(ipu1_di1_pre_clk, &pll3_pfd_540m); -DEF_NG_CLK(ipu2_di0_pre_clk, &pll3_pfd_540m); -DEF_NG_CLK(ipu2_di1_pre_clk, &pll3_pfd_540m); -DEF_NG_CLK(asrc_serial_clk, &pll3_usb_otg); - -#define DEF_CLK(name, er, es, p, s) \ - static struct clk name = { \ - .enable_reg = er, \ - .enable_shift = es, \ - .enable = _clk_enable, \ - .disable = _clk_disable, \ - .get_rate = _clk_get_rate, \ - .set_rate = _clk_set_rate, \ - .round_rate = _clk_round_rate, \ - .set_parent = _clk_set_parent, \ - .parent = p, \ - .secondary = s, \ - } - -#define DEF_CLK_1B(name, er, es, p, s) \ - static struct clk name = { \ - .enable_reg = er, \ - .enable_shift = es, \ - .enable = _clk_enable_1b, \ - .disable = _clk_disable_1b, \ - .get_rate = _clk_get_rate, \ - .set_rate = _clk_set_rate, \ - .round_rate = _clk_round_rate, \ - .set_parent = _clk_set_parent, \ - .parent = p, \ - .secondary = s, \ - } - -DEF_CLK(aips_tz1_clk, CCGR0, CG0, &ahb_clk, NULL); -DEF_CLK(aips_tz2_clk, CCGR0, CG1, &ahb_clk, NULL); -DEF_CLK(apbh_dma_clk, CCGR0, CG2, &ahb_clk, NULL); -DEF_CLK(asrc_clk, CCGR0, CG3, &pll4_audio, NULL); -DEF_CLK(can1_serial_clk, CCGR0, CG8, &pll3_usb_otg, NULL); -DEF_CLK(can1_clk, CCGR0, CG7, &pll3_usb_otg, &can1_serial_clk); -DEF_CLK(can2_serial_clk, CCGR0, CG10, &pll3_usb_otg, NULL); -DEF_CLK(can2_clk, CCGR0, CG9, &pll3_usb_otg, &can2_serial_clk); -DEF_CLK(ecspi1_clk, CCGR1, CG0, &pll3_60m, NULL); -DEF_CLK(ecspi2_clk, CCGR1, CG1, &pll3_60m, NULL); -DEF_CLK(ecspi3_clk, CCGR1, CG2, &pll3_60m, NULL); -DEF_CLK(ecspi4_clk, CCGR1, CG3, &pll3_60m, NULL); -DEF_CLK(ecspi5_clk, CCGR1, CG4, &pll3_60m, NULL); -DEF_CLK(enet_clk, CCGR1, CG5, &ipg_clk, NULL); -DEF_CLK(esai_clk, CCGR1, CG8, &pll3_usb_otg, NULL); -DEF_CLK(gpt_serial_clk, CCGR1, CG11, &ipg_perclk, NULL); -DEF_CLK(gpt_clk, CCGR1, CG10, &ipg_perclk, &gpt_serial_clk); -DEF_CLK(gpu2d_core_clk, CCGR1, CG12, &pll2_pfd_352m, &gpu2d_axi_clk); -DEF_CLK(gpu3d_core_clk, CCGR1, CG13, &pll2_pfd_594m, &gpu3d_axi_clk); -DEF_CLK(gpu3d_shader_clk, CCGR1, CG13, &pll3_pfd_720m, &gpu3d_axi_clk); -DEF_CLK(hdmi_iahb_clk, CCGR2, CG0, &ahb_clk, NULL); -DEF_CLK(hdmi_isfr_clk, CCGR2, CG2, &pll3_pfd_540m, &hdmi_iahb_clk); -DEF_CLK(i2c1_clk, CCGR2, CG3, &ipg_perclk, NULL); -DEF_CLK(i2c2_clk, CCGR2, CG4, &ipg_perclk, NULL); -DEF_CLK(i2c3_clk, CCGR2, CG5, &ipg_perclk, NULL); -DEF_CLK(iim_clk, CCGR2, CG6, &ipg_clk, NULL); -DEF_CLK(enfc_clk, CCGR2, CG7, &pll2_pfd_352m, NULL); -DEF_CLK(ipu1_clk, CCGR3, CG0, &mmdc_ch0_axi_clk, NULL); -DEF_CLK(ipu1_di0_clk, CCGR3, CG1, &ipu1_di0_pre_clk, NULL); -DEF_CLK(ipu1_di1_clk, CCGR3, CG2, &ipu1_di1_pre_clk, NULL); -DEF_CLK(ipu2_clk, CCGR3, CG3, &mmdc_ch0_axi_clk, NULL); -DEF_CLK(ipu2_di0_clk, CCGR3, CG4, &ipu2_di0_pre_clk, NULL); -DEF_CLK(ipu2_di1_clk, CCGR3, CG5, &ipu2_di1_pre_clk, NULL); -DEF_CLK(ldb_di0_clk, CCGR3, CG6, &pll3_pfd_540m, NULL); -DEF_CLK(ldb_di1_clk, CCGR3, CG7, &pll3_pfd_540m, NULL); -DEF_CLK(hsi_tx_clk, CCGR3, CG8, &pll2_pfd_400m, NULL); -DEF_CLK(mlb_clk, CCGR3, CG9, &pll6_mlb, NULL); -DEF_CLK(mmdc_ch0_ipg_clk, CCGR3, CG12, &ipg_clk, NULL); -DEF_CLK(mmdc_ch0_axi_clk, CCGR3, CG10, &periph_clk, &mmdc_ch0_ipg_clk); -DEF_CLK(mmdc_ch1_ipg_clk, CCGR3, CG13, &ipg_clk, NULL); -DEF_CLK(mmdc_ch1_axi_clk, CCGR3, CG11, &periph2_clk, &mmdc_ch1_ipg_clk); -DEF_CLK(openvg_axi_clk, CCGR3, CG13, &axi_clk, NULL); -DEF_CLK(pwm1_clk, CCGR4, CG8, &ipg_perclk, NULL); -DEF_CLK(pwm2_clk, CCGR4, CG9, &ipg_perclk, NULL); -DEF_CLK(pwm3_clk, CCGR4, CG10, &ipg_perclk, NULL); -DEF_CLK(pwm4_clk, CCGR4, CG11, &ipg_perclk, NULL); -DEF_CLK(gpmi_bch_apb_clk, CCGR4, CG12, &usdhc3_clk, NULL); -DEF_CLK(gpmi_bch_clk, CCGR4, CG13, &usdhc4_clk, &gpmi_bch_apb_clk); -DEF_CLK(gpmi_apb_clk, CCGR4, CG15, &usdhc3_clk, &gpmi_bch_clk); -DEF_CLK(gpmi_io_clk, CCGR4, CG14, &enfc_clk, &gpmi_apb_clk); -DEF_CLK(sdma_clk, CCGR5, CG3, &ahb_clk, NULL); -DEF_CLK(spba_clk, CCGR5, CG6, &ipg_clk, NULL); -DEF_CLK(spdif_clk, CCGR5, CG7, &pll3_usb_otg, &spba_clk); -DEF_CLK(ssi1_clk, CCGR5, CG9, &pll3_pfd_508m, NULL); -DEF_CLK(ssi2_clk, CCGR5, CG10, &pll3_pfd_508m, NULL); -DEF_CLK(ssi3_clk, CCGR5, CG11, &pll3_pfd_508m, NULL); -DEF_CLK(uart_serial_clk, CCGR5, CG13, &pll3_usb_otg, NULL); -DEF_CLK(uart_clk, CCGR5, CG12, &pll3_80m, &uart_serial_clk); -DEF_CLK(usboh3_clk, CCGR6, CG0, &ipg_clk, NULL); -DEF_CLK(usdhc1_clk, CCGR6, CG1, &pll2_pfd_400m, NULL); -DEF_CLK(usdhc2_clk, CCGR6, CG2, &pll2_pfd_400m, NULL); -DEF_CLK(usdhc3_clk, CCGR6, CG3, &pll2_pfd_400m, NULL); -DEF_CLK(usdhc4_clk, CCGR6, CG4, &pll2_pfd_400m, NULL); -DEF_CLK(emi_slow_clk, CCGR6, CG5, &axi_clk, NULL); -DEF_CLK(vdo_axi_clk, CCGR6, CG6, &axi_clk, NULL); -DEF_CLK(vpu_clk, CCGR6, CG7, &axi_clk, NULL); -DEF_CLK_1B(cko1_clk, CCOSR, BP_CCOSR_CKO1_EN, &pll2_bus, NULL); - -static int pcie_clk_enable(struct clk *clk) -{ - u32 val; - - val = readl_relaxed(PLL8_ENET); - val |= BM_PLL_ENET_EN_PCIE; - writel_relaxed(val, PLL8_ENET); - - return _clk_enable(clk); -} - -static void pcie_clk_disable(struct clk *clk) -{ - u32 val; - - _clk_disable(clk); - - val = readl_relaxed(PLL8_ENET); - val &= BM_PLL_ENET_EN_PCIE; - writel_relaxed(val, PLL8_ENET); -} - -static struct clk pcie_clk = { - .enable_reg = CCGR4, - .enable_shift = CG0, - .enable = pcie_clk_enable, - .disable = pcie_clk_disable, - .set_parent = _clk_set_parent, - .parent = &axi_clk, - .secondary = &pll8_enet, -}; - -static int sata_clk_enable(struct clk *clk) -{ - u32 val; - - val = readl_relaxed(PLL8_ENET); - val |= BM_PLL_ENET_EN_SATA; - writel_relaxed(val, PLL8_ENET); - - return _clk_enable(clk); -} - -static void sata_clk_disable(struct clk *clk) -{ - u32 val; - - _clk_disable(clk); - - val = readl_relaxed(PLL8_ENET); - val &= BM_PLL_ENET_EN_SATA; - writel_relaxed(val, PLL8_ENET); -} - -static struct clk sata_clk = { - .enable_reg = CCGR5, - .enable_shift = CG2, - .enable = sata_clk_enable, - .disable = sata_clk_disable, - .parent = &ipg_clk, - .secondary = &pll8_enet, -}; - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - } - -static struct clk_lookup lookups[] = { - _REGISTER_CLOCK("2020000.uart", NULL, uart_clk), - _REGISTER_CLOCK("21e8000.uart", NULL, uart_clk), - _REGISTER_CLOCK("21ec000.uart", NULL, uart_clk), - _REGISTER_CLOCK("21f0000.uart", NULL, uart_clk), - _REGISTER_CLOCK("21f4000.uart", NULL, uart_clk), - _REGISTER_CLOCK("2188000.enet", NULL, enet_clk), - _REGISTER_CLOCK("2190000.usdhc", NULL, usdhc1_clk), - _REGISTER_CLOCK("2194000.usdhc", NULL, usdhc2_clk), - _REGISTER_CLOCK("2198000.usdhc", NULL, usdhc3_clk), - _REGISTER_CLOCK("219c000.usdhc", NULL, usdhc4_clk), - _REGISTER_CLOCK("21a0000.i2c", NULL, i2c1_clk), - _REGISTER_CLOCK("21a4000.i2c", NULL, i2c2_clk), - _REGISTER_CLOCK("21a8000.i2c", NULL, i2c3_clk), - _REGISTER_CLOCK("2008000.ecspi", NULL, ecspi1_clk), - _REGISTER_CLOCK("200c000.ecspi", NULL, ecspi2_clk), - _REGISTER_CLOCK("2010000.ecspi", NULL, ecspi3_clk), - _REGISTER_CLOCK("2014000.ecspi", NULL, ecspi4_clk), - _REGISTER_CLOCK("2018000.ecspi", NULL, ecspi5_clk), - _REGISTER_CLOCK("20ec000.sdma", NULL, sdma_clk), - _REGISTER_CLOCK("20bc000.wdog", NULL, dummy_clk), - _REGISTER_CLOCK("20c0000.wdog", NULL, dummy_clk), - _REGISTER_CLOCK("smp_twd", NULL, twd_clk), - _REGISTER_CLOCK(NULL, "ckih", ckih_clk), - _REGISTER_CLOCK(NULL, "ckil_clk", ckil_clk), - _REGISTER_CLOCK(NULL, "aips_tz1_clk", aips_tz1_clk), - _REGISTER_CLOCK(NULL, "aips_tz2_clk", aips_tz2_clk), - _REGISTER_CLOCK(NULL, "asrc_clk", asrc_clk), - _REGISTER_CLOCK(NULL, "can2_clk", can2_clk), - _REGISTER_CLOCK(NULL, "hdmi_isfr_clk", hdmi_isfr_clk), - _REGISTER_CLOCK(NULL, "iim_clk", iim_clk), - _REGISTER_CLOCK(NULL, "mlb_clk", mlb_clk), - _REGISTER_CLOCK(NULL, "openvg_axi_clk", openvg_axi_clk), - _REGISTER_CLOCK(NULL, "pwm1_clk", pwm1_clk), - _REGISTER_CLOCK(NULL, "pwm2_clk", pwm2_clk), - _REGISTER_CLOCK(NULL, "pwm3_clk", pwm3_clk), - _REGISTER_CLOCK(NULL, "pwm4_clk", pwm4_clk), - _REGISTER_CLOCK(NULL, "gpmi_io_clk", gpmi_io_clk), - _REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk), - _REGISTER_CLOCK(NULL, "sata_clk", sata_clk), - _REGISTER_CLOCK(NULL, "cko1_clk", cko1_clk), -}; - -int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) -{ - u32 val = readl_relaxed(CLPCR); - - val &= ~BM_CLPCR_LPM; - switch (mode) { - case WAIT_CLOCKED: - break; - case WAIT_UNCLOCKED: - val |= 0x1 << BP_CLPCR_LPM; - break; - case STOP_POWER_ON: - val |= 0x2 << BP_CLPCR_LPM; - break; - case WAIT_UNCLOCKED_POWER_OFF: - val |= 0x1 << BP_CLPCR_LPM; - val &= ~BM_CLPCR_VSTBY; - val &= ~BM_CLPCR_SBYOS; - break; - case STOP_POWER_OFF: - val |= 0x2 << BP_CLPCR_LPM; - val |= 0x3 << BP_CLPCR_STBY_COUNT; - val |= BM_CLPCR_VSTBY; - val |= BM_CLPCR_SBYOS; - break; - default: - return -EINVAL; - } - writel_relaxed(val, CLPCR); - - return 0; -} - -static struct map_desc imx6q_clock_desc[] = { - imx_map_entry(MX6Q, CCM, MT_DEVICE), - imx_map_entry(MX6Q, ANATOP, MT_DEVICE), -}; - -void __init imx6q_clock_map_io(void) -{ - iotable_init(imx6q_clock_desc, ARRAY_SIZE(imx6q_clock_desc)); -} - -int __init mx6q_clocks_init(void) -{ - struct device_node *np; - void __iomem *base; - int i, irq; - - /* retrieve the freqency of fixed clocks from device tree */ - for_each_compatible_node(np, NULL, "fixed-clock") { - u32 rate; - if (of_property_read_u32(np, "clock-frequency", &rate)) - continue; - - if (of_device_is_compatible(np, "fsl,imx-ckil")) - external_low_reference = rate; - else if (of_device_is_compatible(np, "fsl,imx-ckih1")) - external_high_reference = rate; - else if (of_device_is_compatible(np, "fsl,imx-osc")) - oscillator_reference = rate; - } - - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); - - /* only keep necessary clocks on */ - writel_relaxed(0x3 << CG0 | 0x3 << CG1 | 0x3 << CG2, CCGR0); - writel_relaxed(0x3 << CG8 | 0x3 << CG9 | 0x3 << CG10, CCGR2); - writel_relaxed(0x3 << CG10 | 0x3 << CG12, CCGR3); - writel_relaxed(0x3 << CG4 | 0x3 << CG6 | 0x3 << CG7, CCGR4); - writel_relaxed(0x3 << CG0, CCGR5); - writel_relaxed(0, CCGR6); - writel_relaxed(0, CCGR7); - - clk_enable(&uart_clk); - clk_enable(&mmdc_ch0_axi_clk); - - clk_set_rate(&pll4_audio, FREQ_650M); - clk_set_rate(&pll5_video, FREQ_650M); - clk_set_parent(&ipu1_di0_clk, &ipu1_di0_pre_clk); - clk_set_parent(&ipu1_di0_pre_clk, &pll5_video); - clk_set_parent(&gpu3d_shader_clk, &pll2_pfd_594m); - clk_set_rate(&gpu3d_shader_clk, FREQ_594M); - clk_set_parent(&gpu3d_core_clk, &mmdc_ch0_axi_clk); - clk_set_rate(&gpu3d_core_clk, FREQ_528M); - clk_set_parent(&asrc_serial_clk, &pll3_usb_otg); - clk_set_rate(&asrc_serial_clk, 1500000); - clk_set_rate(&enfc_clk, 11000000); - - /* - * Before pinctrl API is available, we have to rely on the pad - * configuration set up by bootloader. For usdhc example here, - * u-boot sets up the pads for 49.5 MHz case, and we have to lower - * the usdhc clock from 198 to 49.5 MHz to match the pad configuration. - * - * FIXME: This is should be removed after pinctrl API is available. - * At that time, usdhc driver can call pinctrl API to change pad - * configuration dynamically per different usdhc clock settings. - */ - clk_set_rate(&usdhc1_clk, 49500000); - clk_set_rate(&usdhc2_clk, 49500000); - clk_set_rate(&usdhc3_clk, 49500000); - clk_set_rate(&usdhc4_clk, 49500000); - - clk_set_parent(&cko1_clk, &ahb_clk); - - np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); - base = of_iomap(np, 0); - WARN_ON(!base); - irq = irq_of_parse_and_map(np, 0); - mxc_timer_init(&gpt_clk, base, irq); - - return 0; -} diff --git a/arch/arm/mach-imx/clock-mx51-mx53.c b/arch/arm/mach-imx/clock-mx51-mx53.c deleted file mode 100644 index 08470504a088..000000000000 --- a/arch/arm/mach-imx/clock-mx51-mx53.c +++ /dev/null @@ -1,1675 +0,0 @@ -/* - * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com> - * - * 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 <linux/mm.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/clkdev.h> -#include <linux/of.h> - -#include <asm/div64.h> - -#include <mach/hardware.h> -#include <mach/common.h> -#include <mach/clock.h> - -#include "crm-regs-imx5.h" - -/* External clock values passed-in by the board code */ -static unsigned long external_high_reference, external_low_reference; -static unsigned long oscillator_reference, ckih2_reference; - -static struct clk osc_clk; -static struct clk pll1_main_clk; -static struct clk pll1_sw_clk; -static struct clk pll2_sw_clk; -static struct clk pll3_sw_clk; -static struct clk mx53_pll4_sw_clk; -static struct clk lp_apm_clk; -static struct clk periph_apm_clk; -static struct clk ahb_clk; -static struct clk ipg_clk; -static struct clk usboh3_clk; -static struct clk emi_fast_clk; -static struct clk ipu_clk; -static struct clk mipi_hsc1_clk; -static struct clk esdhc1_clk; -static struct clk esdhc2_clk; -static struct clk esdhc3_mx53_clk; - -#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */ - -/* calculate best pre and post dividers to get the required divider */ -static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post, - u32 max_pre, u32 max_post) -{ - if (div >= max_pre * max_post) { - *pre = max_pre; - *post = max_post; - } else if (div >= max_pre) { - u32 min_pre, temp_pre, old_err, err; - min_pre = DIV_ROUND_UP(div, max_post); - old_err = max_pre; - for (temp_pre = max_pre; temp_pre >= min_pre; temp_pre--) { - err = div % temp_pre; - if (err == 0) { - *pre = temp_pre; - break; - } - err = temp_pre - err; - if (err < old_err) { - old_err = err; - *pre = temp_pre; - } - } - *post = DIV_ROUND_UP(div, *pre); - } else { - *pre = div; - *post = 1; - } -} - -static void _clk_ccgr_setclk(struct clk *clk, unsigned mode) -{ - u32 reg = __raw_readl(clk->enable_reg); - - reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); - reg |= mode << clk->enable_shift; - - __raw_writel(reg, clk->enable_reg); -} - -static int _clk_ccgr_enable(struct clk *clk) -{ - _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_ON); - return 0; -} - -static void _clk_ccgr_disable(struct clk *clk) -{ - _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_OFF); -} - -static int _clk_ccgr_enable_inrun(struct clk *clk) -{ - _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE); - return 0; -} - -static void _clk_ccgr_disable_inwait(struct clk *clk) -{ - _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE); -} - -/* - * For the 4-to-1 muxed input clock - */ -static inline u32 _get_mux(struct clk *parent, struct clk *m0, - struct clk *m1, struct clk *m2, struct clk *m3) -{ - if (parent == m0) - return 0; - else if (parent == m1) - return 1; - else if (parent == m2) - return 2; - else if (parent == m3) - return 3; - else - BUG(); - - return -EINVAL; -} - -static inline void __iomem *_mx51_get_pll_base(struct clk *pll) -{ - if (pll == &pll1_main_clk) - return MX51_DPLL1_BASE; - else if (pll == &pll2_sw_clk) - return MX51_DPLL2_BASE; - else if (pll == &pll3_sw_clk) - return MX51_DPLL3_BASE; - else - BUG(); - - return NULL; -} - -static inline void __iomem *_mx53_get_pll_base(struct clk *pll) -{ - if (pll == &pll1_main_clk) - return MX53_DPLL1_BASE; - else if (pll == &pll2_sw_clk) - return MX53_DPLL2_BASE; - else if (pll == &pll3_sw_clk) - return MX53_DPLL3_BASE; - else if (pll == &mx53_pll4_sw_clk) - return MX53_DPLL4_BASE; - else - BUG(); - - return NULL; -} - -static inline void __iomem *_get_pll_base(struct clk *pll) -{ - if (cpu_is_mx51()) - return _mx51_get_pll_base(pll); - else - return _mx53_get_pll_base(pll); -} - -static unsigned long clk_pll_get_rate(struct clk *clk) -{ - long mfi, mfn, mfd, pdf, ref_clk, mfn_abs; - unsigned long dp_op, dp_mfd, dp_mfn, dp_ctl, pll_hfsm, dbl; - void __iomem *pllbase; - s64 temp; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - pllbase = _get_pll_base(clk); - - dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); - pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; - dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN; - - if (pll_hfsm == 0) { - 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); - } else { - dp_op = __raw_readl(pllbase + MXC_PLL_DP_HFS_OP); - dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFD); - dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFN); - } - 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 = -temp; - temp = (ref_clk * mfi) + temp; - - return temp; -} - -static int _clk_pll_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg; - void __iomem *pllbase; - - long mfi, pdf, mfn, mfd = 999999; - s64 temp64; - unsigned long quad_parent_rate; - unsigned long pll_hfsm, dp_ctl; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - pllbase = _get_pll_base(clk); - - 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; - - dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); - /* use dpdck0_2 */ - __raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL); - pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; - if (pll_hfsm == 0) { - reg = mfi << 4 | pdf; - __raw_writel(reg, pllbase + MXC_PLL_DP_OP); - __raw_writel(mfd, pllbase + MXC_PLL_DP_MFD); - __raw_writel(mfn, pllbase + MXC_PLL_DP_MFN); - } else { - reg = mfi << 4 | pdf; - __raw_writel(reg, pllbase + MXC_PLL_DP_HFS_OP); - __raw_writel(mfd, pllbase + MXC_PLL_DP_HFS_MFD); - __raw_writel(mfn, pllbase + MXC_PLL_DP_HFS_MFN); - } - - return 0; -} - -static int _clk_pll_enable(struct clk *clk) -{ - u32 reg; - void __iomem *pllbase; - int i = 0; - - pllbase = _get_pll_base(clk); - reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); - if (reg & MXC_PLL_DP_CTL_UPEN) - return 0; - - reg |= MXC_PLL_DP_CTL_UPEN; - __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); - - /* Wait for lock */ - do { - reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); - if (reg & MXC_PLL_DP_CTL_LRF) - break; - - udelay(1); - } while (++i < MAX_DPLL_WAIT_TRIES); - - if (i == MAX_DPLL_WAIT_TRIES) { - pr_err("MX5: pll locking failed\n"); - return -EINVAL; - } - - return 0; -} - -static void _clk_pll_disable(struct clk *clk) -{ - u32 reg; - void __iomem *pllbase; - - pllbase = _get_pll_base(clk); - reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) & ~MXC_PLL_DP_CTL_UPEN; - __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); -} - -static int _clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg, step; - - reg = __raw_readl(MXC_CCM_CCSR); - - /* When switching from pll_main_clk to a bypass clock, first select a - * multiplexed clock in 'step_sel', then shift the glitchless mux - * 'pll1_sw_clk_sel'. - * - * When switching back, do it in reverse order - */ - if (parent == &pll1_main_clk) { - /* Switch to pll1_main_clk */ - reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; - __raw_writel(reg, MXC_CCM_CCSR); - /* step_clk mux switched to lp_apm, to save power. */ - reg = __raw_readl(MXC_CCM_CCSR); - reg &= ~MXC_CCM_CCSR_STEP_SEL_MASK; - reg |= (MXC_CCM_CCSR_STEP_SEL_LP_APM << - MXC_CCM_CCSR_STEP_SEL_OFFSET); - } else { - if (parent == &lp_apm_clk) { - step = MXC_CCM_CCSR_STEP_SEL_LP_APM; - } else if (parent == &pll2_sw_clk) { - step = MXC_CCM_CCSR_STEP_SEL_PLL2_DIVIDED; - } else if (parent == &pll3_sw_clk) { - step = MXC_CCM_CCSR_STEP_SEL_PLL3_DIVIDED; - } else - return -EINVAL; - - reg &= ~MXC_CCM_CCSR_STEP_SEL_MASK; - reg |= (step << MXC_CCM_CCSR_STEP_SEL_OFFSET); - - __raw_writel(reg, MXC_CCM_CCSR); - /* Switch to step_clk */ - reg = __raw_readl(MXC_CCM_CCSR); - reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; - } - __raw_writel(reg, MXC_CCM_CCSR); - return 0; -} - -static unsigned long clk_pll1_sw_get_rate(struct clk *clk) -{ - u32 reg, div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - reg = __raw_readl(MXC_CCM_CCSR); - - if (clk->parent == &pll2_sw_clk) { - div = ((reg & MXC_CCM_CCSR_PLL2_PODF_MASK) >> - MXC_CCM_CCSR_PLL2_PODF_OFFSET) + 1; - } else if (clk->parent == &pll3_sw_clk) { - div = ((reg & MXC_CCM_CCSR_PLL3_PODF_MASK) >> - MXC_CCM_CCSR_PLL3_PODF_OFFSET) + 1; - } else - div = 1; - return parent_rate / div; -} - -static int _clk_pll2_sw_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CCSR); - - if (parent == &pll2_sw_clk) - reg &= ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL; - else - reg |= MXC_CCM_CCSR_PLL2_SW_CLK_SEL; - - __raw_writel(reg, MXC_CCM_CCSR); - return 0; -} - -static int _clk_lp_apm_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - if (parent == &osc_clk) - reg = __raw_readl(MXC_CCM_CCSR) & ~MXC_CCM_CCSR_LP_APM_SEL; - else - return -EINVAL; - - __raw_writel(reg, MXC_CCM_CCSR); - - return 0; -} - -static unsigned long clk_cpu_get_rate(struct clk *clk) -{ - u32 cacrr, div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - cacrr = __raw_readl(MXC_CCM_CACRR); - div = (cacrr & MXC_CCM_CACRR_ARM_PODF_MASK) + 1; - - return parent_rate / div; -} - -static int clk_cpu_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg, cpu_podf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - cpu_podf = parent_rate / rate - 1; - /* use post divider to change freq */ - reg = __raw_readl(MXC_CCM_CACRR); - reg &= ~MXC_CCM_CACRR_ARM_PODF_MASK; - reg |= cpu_podf << MXC_CCM_CACRR_ARM_PODF_OFFSET; - __raw_writel(reg, MXC_CCM_CACRR); - - return 0; -} - -static int _clk_periph_apm_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg, mux; - int i = 0; - - mux = _get_mux(parent, &pll1_sw_clk, &pll3_sw_clk, &lp_apm_clk, NULL); - - reg = __raw_readl(MXC_CCM_CBCMR) & ~MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK; - reg |= mux << MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET; - __raw_writel(reg, MXC_CCM_CBCMR); - - /* Wait for lock */ - do { - reg = __raw_readl(MXC_CCM_CDHIPR); - if (!(reg & MXC_CCM_CDHIPR_PERIPH_CLK_SEL_BUSY)) - break; - - udelay(1); - } while (++i < MAX_DPLL_WAIT_TRIES); - - if (i == MAX_DPLL_WAIT_TRIES) { - pr_err("MX5: Set parent for periph_apm clock failed\n"); - return -EINVAL; - } - - return 0; -} - -static int _clk_main_bus_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CBCDR); - - if (parent == &pll2_sw_clk) - reg &= ~MXC_CCM_CBCDR_PERIPH_CLK_SEL; - else if (parent == &periph_apm_clk) - reg |= MXC_CCM_CBCDR_PERIPH_CLK_SEL; - else - return -EINVAL; - - __raw_writel(reg, MXC_CCM_CBCDR); - - return 0; -} - -static struct clk main_bus_clk = { - .parent = &pll2_sw_clk, - .set_parent = _clk_main_bus_set_parent, -}; - -static unsigned long clk_ahb_get_rate(struct clk *clk) -{ - u32 reg, div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - reg = __raw_readl(MXC_CCM_CBCDR); - div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >> - MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1; - return parent_rate / div; -} - - -static int _clk_ahb_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg, div; - unsigned long parent_rate; - int i = 0; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (div > 8 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - reg = __raw_readl(MXC_CCM_CBCDR); - reg &= ~MXC_CCM_CBCDR_AHB_PODF_MASK; - reg |= (div - 1) << MXC_CCM_CBCDR_AHB_PODF_OFFSET; - __raw_writel(reg, MXC_CCM_CBCDR); - - /* Wait for lock */ - do { - reg = __raw_readl(MXC_CCM_CDHIPR); - if (!(reg & MXC_CCM_CDHIPR_AHB_PODF_BUSY)) - break; - - udelay(1); - } while (++i < MAX_DPLL_WAIT_TRIES); - - if (i == MAX_DPLL_WAIT_TRIES) { - pr_err("MX5: clk_ahb_set_rate failed\n"); - return -EINVAL; - } - - return 0; -} - -static unsigned long _clk_ahb_round_rate(struct clk *clk, - unsigned long rate) -{ - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (div > 8) - div = 8; - else if (div == 0) - div++; - return parent_rate / div; -} - - -static int _clk_max_enable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_enable(clk); - - /* Handshake with MAX when LPM is entered. */ - reg = __raw_readl(MXC_CCM_CLPCR); - if (cpu_is_mx51()) - reg &= ~MX51_CCM_CLPCR_BYPASS_MAX_LPM_HS; - else if (cpu_is_mx53()) - reg &= ~MX53_CCM_CLPCR_BYPASS_MAX_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); - - return 0; -} - -static void _clk_max_disable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_disable_inwait(clk); - - /* No Handshake with MAX when LPM is entered as its disabled. */ - reg = __raw_readl(MXC_CCM_CLPCR); - if (cpu_is_mx51()) - reg |= MX51_CCM_CLPCR_BYPASS_MAX_LPM_HS; - else if (cpu_is_mx53()) - reg &= ~MX53_CCM_CLPCR_BYPASS_MAX_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); -} - -static unsigned long clk_ipg_get_rate(struct clk *clk) -{ - u32 reg, div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - reg = __raw_readl(MXC_CCM_CBCDR); - div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >> - MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1; - - return parent_rate / div; -} - -static unsigned long clk_ipg_per_get_rate(struct clk *clk) -{ - u32 reg, prediv1, prediv2, podf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->parent == &main_bus_clk || clk->parent == &lp_apm_clk) { - /* the main_bus_clk is the one before the DVFS engine */ - reg = __raw_readl(MXC_CCM_CBCDR); - prediv1 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >> - MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET) + 1; - prediv2 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >> - MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET) + 1; - podf = ((reg & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >> - MXC_CCM_CBCDR_PERCLK_PODF_OFFSET) + 1; - return parent_rate / (prediv1 * prediv2 * podf); - } else if (clk->parent == &ipg_clk) - return parent_rate; - else - BUG(); -} - -static int _clk_ipg_per_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CBCMR); - - reg &= ~MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; - reg &= ~MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; - - if (parent == &ipg_clk) - reg |= MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; - else if (parent == &lp_apm_clk) - reg |= MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; - else if (parent != &main_bus_clk) - return -EINVAL; - - __raw_writel(reg, MXC_CCM_CBCMR); - - return 0; -} - -#define clk_nfc_set_parent NULL - -static unsigned long clk_nfc_get_rate(struct clk *clk) -{ - unsigned long rate; - u32 reg, div; - - reg = __raw_readl(MXC_CCM_CBCDR); - div = ((reg & MXC_CCM_CBCDR_NFC_PODF_MASK) >> - MXC_CCM_CBCDR_NFC_PODF_OFFSET) + 1; - rate = clk_get_rate(clk->parent) / div; - WARN_ON(rate == 0); - return rate; -} - -static unsigned long clk_nfc_round_rate(struct clk *clk, - unsigned long rate) -{ - u32 div; - unsigned long parent_rate = clk_get_rate(clk->parent); - - if (!rate) - return -EINVAL; - - div = parent_rate / rate; - - if (parent_rate % rate) - div++; - - if (div > 8) - return -EINVAL; - - return parent_rate / div; - -} - -static int clk_nfc_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg, div; - - div = clk_get_rate(clk->parent) / rate; - if (div == 0) - div++; - if (((clk_get_rate(clk->parent) / div) != rate) || (div > 8)) - return -EINVAL; - - reg = __raw_readl(MXC_CCM_CBCDR); - reg &= ~MXC_CCM_CBCDR_NFC_PODF_MASK; - reg |= (div - 1) << MXC_CCM_CBCDR_NFC_PODF_OFFSET; - __raw_writel(reg, MXC_CCM_CBCDR); - - while (__raw_readl(MXC_CCM_CDHIPR) & - MXC_CCM_CDHIPR_NFC_IPG_INT_MEM_PODF_BUSY){ - } - - return 0; -} - -static unsigned long get_high_reference_clock_rate(struct clk *clk) -{ - return external_high_reference; -} - -static unsigned long get_low_reference_clock_rate(struct clk *clk) -{ - return external_low_reference; -} - -static unsigned long get_oscillator_reference_clock_rate(struct clk *clk) -{ - return oscillator_reference; -} - -static unsigned long get_ckih2_reference_clock_rate(struct clk *clk) -{ - return ckih2_reference; -} - -static unsigned long clk_emi_slow_get_rate(struct clk *clk) -{ - u32 reg, div; - - reg = __raw_readl(MXC_CCM_CBCDR); - div = ((reg & MXC_CCM_CBCDR_EMI_PODF_MASK) >> - MXC_CCM_CBCDR_EMI_PODF_OFFSET) + 1; - - return clk_get_rate(clk->parent) / div; -} - -static unsigned long _clk_ddr_hf_get_rate(struct clk *clk) -{ - unsigned long rate; - u32 reg, div; - - reg = __raw_readl(MXC_CCM_CBCDR); - div = ((reg & MXC_CCM_CBCDR_DDR_PODF_MASK) >> - MXC_CCM_CBCDR_DDR_PODF_OFFSET) + 1; - rate = clk_get_rate(clk->parent) / div; - - return rate; -} - -/* External high frequency clock */ -static struct clk ckih_clk = { - .get_rate = get_high_reference_clock_rate, -}; - -static struct clk ckih2_clk = { - .get_rate = get_ckih2_reference_clock_rate, -}; - -static struct clk osc_clk = { - .get_rate = get_oscillator_reference_clock_rate, -}; - -/* External low frequency (32kHz) clock */ -static struct clk ckil_clk = { - .get_rate = get_low_reference_clock_rate, -}; - -static struct clk pll1_main_clk = { - .parent = &osc_clk, - .get_rate = clk_pll_get_rate, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* Clock tree block diagram (WIP): - * CCM: Clock Controller Module - * - * PLL output -> | - * | CCM Switcher -> CCM_CLK_ROOT_GEN -> - * PLL bypass -> | - * - */ - -/* PLL1 SW supplies to ARM core */ -static struct clk pll1_sw_clk = { - .parent = &pll1_main_clk, - .set_parent = _clk_pll1_sw_set_parent, - .get_rate = clk_pll1_sw_get_rate, -}; - -/* PLL2 SW supplies to AXI/AHB/IP buses */ -static struct clk pll2_sw_clk = { - .parent = &osc_clk, - .get_rate = clk_pll_get_rate, - .set_rate = _clk_pll_set_rate, - .set_parent = _clk_pll2_sw_set_parent, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* PLL3 SW supplies to serial clocks like USB, SSI, etc. */ -static struct clk pll3_sw_clk = { - .parent = &osc_clk, - .set_rate = _clk_pll_set_rate, - .get_rate = clk_pll_get_rate, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* PLL4 SW supplies to LVDS Display Bridge(LDB) */ -static struct clk mx53_pll4_sw_clk = { - .parent = &osc_clk, - .set_rate = _clk_pll_set_rate, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* Low-power Audio Playback Mode clock */ -static struct clk lp_apm_clk = { - .parent = &osc_clk, - .set_parent = _clk_lp_apm_set_parent, -}; - -static struct clk periph_apm_clk = { - .parent = &pll1_sw_clk, - .set_parent = _clk_periph_apm_set_parent, -}; - -static struct clk cpu_clk = { - .parent = &pll1_sw_clk, - .get_rate = clk_cpu_get_rate, - .set_rate = clk_cpu_set_rate, -}; - -static struct clk ahb_clk = { - .parent = &main_bus_clk, - .get_rate = clk_ahb_get_rate, - .set_rate = _clk_ahb_set_rate, - .round_rate = _clk_ahb_round_rate, -}; - -static struct clk iim_clk = { - .parent = &ipg_clk, - .enable_reg = MXC_CCM_CCGR0, - .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, -}; - -/* Main IP interface clock for access to registers */ -static struct clk ipg_clk = { - .parent = &ahb_clk, - .get_rate = clk_ipg_get_rate, -}; - -static struct clk ipg_perclk = { - .parent = &lp_apm_clk, - .get_rate = clk_ipg_per_get_rate, - .set_parent = _clk_ipg_per_set_parent, -}; - -static struct clk ahb_max_clk = { - .parent = &ahb_clk, - .enable_reg = MXC_CCM_CCGR0, - .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, -}; - -static struct clk aips_tz1_clk = { - .parent = &ahb_clk, - .secondary = &ahb_max_clk, - .enable_reg = MXC_CCM_CCGR0, - .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, -}; - -static struct clk aips_tz2_clk = { - .parent = &ahb_clk, - .secondary = &ahb_max_clk, - .enable_reg = MXC_CCM_CCGR0, - .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, -}; - -static struct clk gpc_dvfs_clk = { - .enable_reg = MXC_CCM_CCGR5, - .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable, -}; - -static struct clk gpt_32k_clk = { - .id = 0, - .parent = &ckil_clk, -}; - -static struct clk dummy_clk = { - .id = 0, -}; - -static struct clk emi_slow_clk = { - .parent = &pll2_sw_clk, - .enable_reg = MXC_CCM_CCGR5, - .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, - .get_rate = clk_emi_slow_get_rate, -}; - -static int clk_ipu_enable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_enable(clk); - - /* Enable handshake with IPU when certain clock rates are changed */ - reg = __raw_readl(MXC_CCM_CCDR); - reg &= ~MXC_CCM_CCDR_IPU_HS_MASK; - __raw_writel(reg, MXC_CCM_CCDR); - - /* Enable handshake with IPU when LPM is entered */ - reg = __raw_readl(MXC_CCM_CLPCR); - reg &= ~MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); - - return 0; -} - -static void clk_ipu_disable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_disable(clk); - - /* Disable handshake with IPU whe dividers are changed */ - reg = __raw_readl(MXC_CCM_CCDR); - reg |= MXC_CCM_CCDR_IPU_HS_MASK; - __raw_writel(reg, MXC_CCM_CCDR); - - /* Disable handshake with IPU when LPM is entered */ - reg = __raw_readl(MXC_CCM_CLPCR); - reg |= MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); -} - -static struct clk ahbmux1_clk = { - .parent = &ahb_clk, - .secondary = &ahb_max_clk, - .enable_reg = MXC_CCM_CCGR0, - .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, -}; - -static struct clk ipu_sec_clk = { - .parent = &emi_fast_clk, - .secondary = &ahbmux1_clk, -}; - -static struct clk ddr_hf_clk = { - .parent = &pll1_sw_clk, - .get_rate = _clk_ddr_hf_get_rate, -}; - -static struct clk ddr_clk = { - .parent = &ddr_hf_clk, -}; - -/* clock definitions for MIPI HSC unit which has been removed - * from documentation, but not from hardware - */ -static int _clk_hsc_enable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_enable(clk); - /* Handshake with IPU when certain clock rates are changed. */ - reg = __raw_readl(MXC_CCM_CCDR); - reg &= ~MXC_CCM_CCDR_HSC_HS_MASK; - __raw_writel(reg, MXC_CCM_CCDR); - - reg = __raw_readl(MXC_CCM_CLPCR); - reg &= ~MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); - - return 0; -} - -static void _clk_hsc_disable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_disable(clk); - /* No handshake with HSC as its not enabled. */ - reg = __raw_readl(MXC_CCM_CCDR); - reg |= MXC_CCM_CCDR_HSC_HS_MASK; - __raw_writel(reg, MXC_CCM_CCDR); - - reg = __raw_readl(MXC_CCM_CLPCR); - reg |= MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); -} - -static struct clk mipi_hsp_clk = { - .parent = &ipu_clk, - .enable_reg = MXC_CCM_CCGR4, - .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, - .enable = _clk_hsc_enable, - .disable = _clk_hsc_disable, - .secondary = &mipi_hsc1_clk, -}; - -#define DEFINE_CLOCK_CCGR(name, i, er, es, pfx, p, s) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = pfx##_get_rate, \ - .set_rate = pfx##_set_rate, \ - .round_rate = pfx##_round_rate, \ - .set_parent = pfx##_set_parent, \ - .enable = _clk_ccgr_enable, \ - .disable = _clk_ccgr_disable, \ - .parent = p, \ - .secondary = s, \ - } - -#define DEFINE_CLOCK_MAX(name, i, er, es, pfx, p, s) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = pfx##_get_rate, \ - .set_rate = pfx##_set_rate, \ - .set_parent = pfx##_set_parent, \ - .enable = _clk_max_enable, \ - .disable = _clk_max_disable, \ - .parent = p, \ - .secondary = s, \ - } - -#define CLK_GET_RATE(name, nr, bitsname) \ -static unsigned long clk_##name##_get_rate(struct clk *clk) \ -{ \ - u32 reg, pred, podf; \ - \ - reg = __raw_readl(MXC_CCM_CSCDR##nr); \ - pred = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK) \ - >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET; \ - podf = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK) \ - >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET; \ - \ - return DIV_ROUND_CLOSEST(clk_get_rate(clk->parent), \ - (pred + 1) * (podf + 1)); \ -} - -#define CLK_SET_PARENT(name, nr, bitsname) \ -static int clk_##name##_set_parent(struct clk *clk, struct clk *parent) \ -{ \ - u32 reg, mux; \ - \ - mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, \ - &pll3_sw_clk, &lp_apm_clk); \ - reg = __raw_readl(MXC_CCM_CSCMR##nr) & \ - ~MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_MASK; \ - reg |= mux << MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_OFFSET; \ - __raw_writel(reg, MXC_CCM_CSCMR##nr); \ - \ - return 0; \ -} - -#define CLK_SET_RATE(name, nr, bitsname) \ -static int clk_##name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - u32 reg, div, parent_rate; \ - u32 pre = 0, post = 0; \ - \ - parent_rate = clk_get_rate(clk->parent); \ - div = parent_rate / rate; \ - \ - if ((parent_rate / div) != rate) \ - return -EINVAL; \ - \ - __calc_pre_post_dividers(div, &pre, &post, \ - (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK >> \ - MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET) + 1, \ - (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK >> \ - MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET) + 1);\ - \ - /* Set sdhc1 clock divider */ \ - reg = __raw_readl(MXC_CCM_CSCDR##nr) & \ - ~(MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK \ - | MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK); \ - reg |= (post - 1) << \ - MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET; \ - reg |= (pre - 1) << \ - MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET; \ - __raw_writel(reg, MXC_CCM_CSCDR##nr); \ - \ - return 0; \ -} - -/* UART */ -CLK_GET_RATE(uart, 1, UART) -CLK_SET_PARENT(uart, 1, UART) - -static struct clk uart_root_clk = { - .parent = &pll2_sw_clk, - .get_rate = clk_uart_get_rate, - .set_parent = clk_uart_set_parent, -}; - -/* USBOH3 */ -CLK_GET_RATE(usboh3, 1, USBOH3) -CLK_SET_PARENT(usboh3, 1, USBOH3) - -static struct clk usboh3_clk = { - .parent = &pll2_sw_clk, - .get_rate = clk_usboh3_get_rate, - .set_parent = clk_usboh3_set_parent, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable, - .enable_reg = MXC_CCM_CCGR2, - .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, -}; - -static struct clk usb_ahb_clk = { - .parent = &ipg_clk, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable, - .enable_reg = MXC_CCM_CCGR2, - .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, -}; - -static int clk_usb_phy1_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL; - - if (parent == &pll3_sw_clk) - reg |= 1 << MXC_CCM_CSCMR1_USB_PHY_CLK_SEL_OFFSET; - - __raw_writel(reg, MXC_CCM_CSCMR1); - - return 0; -} - -static struct clk usb_phy1_clk = { - .parent = &pll3_sw_clk, - .set_parent = clk_usb_phy1_set_parent, - .enable = _clk_ccgr_enable, - .enable_reg = MXC_CCM_CCGR2, - .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, - .disable = _clk_ccgr_disable, -}; - -/* eCSPI */ -CLK_GET_RATE(ecspi, 2, CSPI) -CLK_SET_PARENT(ecspi, 1, CSPI) - -static struct clk ecspi_main_clk = { - .parent = &pll3_sw_clk, - .get_rate = clk_ecspi_get_rate, - .set_parent = clk_ecspi_set_parent, -}; - -/* eSDHC */ -CLK_GET_RATE(esdhc1, 1, ESDHC1_MSHC1) -CLK_SET_PARENT(esdhc1, 1, ESDHC1_MSHC1) -CLK_SET_RATE(esdhc1, 1, ESDHC1_MSHC1) - -/* mx51 specific */ -CLK_GET_RATE(esdhc2, 1, ESDHC2_MSHC2) -CLK_SET_PARENT(esdhc2, 1, ESDHC2_MSHC2) -CLK_SET_RATE(esdhc2, 1, ESDHC2_MSHC2) - -static int clk_esdhc3_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CSCMR1); - if (parent == &esdhc1_clk) - reg &= ~MXC_CCM_CSCMR1_ESDHC3_CLK_SEL; - else if (parent == &esdhc2_clk) - reg |= MXC_CCM_CSCMR1_ESDHC3_CLK_SEL; - else - return -EINVAL; - __raw_writel(reg, MXC_CCM_CSCMR1); - - return 0; -} - -static int clk_esdhc4_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CSCMR1); - if (parent == &esdhc1_clk) - reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; - else if (parent == &esdhc2_clk) - reg |= MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; - else - return -EINVAL; - __raw_writel(reg, MXC_CCM_CSCMR1); - - return 0; -} - -/* mx53 specific */ -static int clk_esdhc2_mx53_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CSCMR1); - if (parent == &esdhc1_clk) - reg &= ~MXC_CCM_CSCMR1_ESDHC2_MSHC2_MX53_CLK_SEL; - else if (parent == &esdhc3_mx53_clk) - reg |= MXC_CCM_CSCMR1_ESDHC2_MSHC2_MX53_CLK_SEL; - else - return -EINVAL; - __raw_writel(reg, MXC_CCM_CSCMR1); - - return 0; -} - -CLK_GET_RATE(esdhc3_mx53, 1, ESDHC3_MX53) -CLK_SET_PARENT(esdhc3_mx53, 1, ESDHC3_MX53) -CLK_SET_RATE(esdhc3_mx53, 1, ESDHC3_MX53) - -static int clk_esdhc4_mx53_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CSCMR1); - if (parent == &esdhc1_clk) - reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; - else if (parent == &esdhc3_mx53_clk) - reg |= MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; - else - return -EINVAL; - __raw_writel(reg, MXC_CCM_CSCMR1); - - return 0; -} - -#define DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, e, d, p, s) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = gr, \ - .set_rate = sr, \ - .enable = e, \ - .disable = d, \ - .parent = p, \ - .secondary = s, \ - } - -#define DEFINE_CLOCK(name, i, er, es, gr, sr, p, s) \ - DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, _clk_ccgr_enable, _clk_ccgr_disable, p, s) - -/* Shared peripheral bus arbiter */ -DEFINE_CLOCK(spba_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG0_OFFSET, - NULL, NULL, &ipg_clk, NULL); - -/* UART */ -DEFINE_CLOCK(uart1_ipg_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG3_OFFSET, - NULL, NULL, &ipg_clk, &aips_tz1_clk); -DEFINE_CLOCK(uart2_ipg_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG5_OFFSET, - NULL, NULL, &ipg_clk, &aips_tz1_clk); -DEFINE_CLOCK(uart3_ipg_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG7_OFFSET, - NULL, NULL, &ipg_clk, &spba_clk); -DEFINE_CLOCK(uart4_ipg_clk, 3, MXC_CCM_CCGR7, MXC_CCM_CCGRx_CG4_OFFSET, - NULL, NULL, &ipg_clk, &spba_clk); -DEFINE_CLOCK(uart5_ipg_clk, 4, MXC_CCM_CCGR7, MXC_CCM_CCGRx_CG6_OFFSET, - NULL, NULL, &ipg_clk, &spba_clk); -DEFINE_CLOCK(uart1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG4_OFFSET, - NULL, NULL, &uart_root_clk, &uart1_ipg_clk); -DEFINE_CLOCK(uart2_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG6_OFFSET, - NULL, NULL, &uart_root_clk, &uart2_ipg_clk); -DEFINE_CLOCK(uart3_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG8_OFFSET, - NULL, NULL, &uart_root_clk, &uart3_ipg_clk); -DEFINE_CLOCK(uart4_clk, 3, MXC_CCM_CCGR7, MXC_CCM_CCGRx_CG5_OFFSET, - NULL, NULL, &uart_root_clk, &uart4_ipg_clk); -DEFINE_CLOCK(uart5_clk, 4, MXC_CCM_CCGR7, MXC_CCM_CCGRx_CG7_OFFSET, - NULL, NULL, &uart_root_clk, &uart5_ipg_clk); - -/* GPT */ -DEFINE_CLOCK(gpt_ipg_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG10_OFFSET, - NULL, NULL, &ipg_clk, NULL); -DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG9_OFFSET, - NULL, NULL, &ipg_clk, &gpt_ipg_clk); - -DEFINE_CLOCK(pwm1_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG6_OFFSET, - NULL, NULL, &ipg_perclk, NULL); -DEFINE_CLOCK(pwm2_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG8_OFFSET, - NULL, NULL, &ipg_perclk, NULL); - -/* I2C */ -DEFINE_CLOCK(i2c1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG9_OFFSET, - NULL, NULL, &ipg_perclk, NULL); -DEFINE_CLOCK(i2c2_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG10_OFFSET, - NULL, NULL, &ipg_perclk, NULL); -DEFINE_CLOCK(hsi2c_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG11_OFFSET, - NULL, NULL, &ipg_clk, NULL); -DEFINE_CLOCK(i2c3_mx53_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG11_OFFSET, - NULL, NULL, &ipg_perclk, NULL); - -/* FEC */ -DEFINE_CLOCK(fec_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG12_OFFSET, - NULL, NULL, &ipg_clk, NULL); - -/* NFC */ -DEFINE_CLOCK_CCGR(nfc_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG10_OFFSET, - clk_nfc, &emi_slow_clk, NULL); - -/* SSI */ -DEFINE_CLOCK(ssi1_ipg_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG8_OFFSET, - NULL, NULL, &ipg_clk, NULL); -DEFINE_CLOCK(ssi1_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG9_OFFSET, - NULL, NULL, &pll3_sw_clk, &ssi1_ipg_clk); -DEFINE_CLOCK(ssi2_ipg_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG10_OFFSET, - NULL, NULL, &ipg_clk, NULL); -DEFINE_CLOCK(ssi2_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG11_OFFSET, - NULL, NULL, &pll3_sw_clk, &ssi2_ipg_clk); -DEFINE_CLOCK(ssi3_ipg_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG12_OFFSET, - NULL, NULL, &ipg_clk, NULL); -DEFINE_CLOCK(ssi3_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG13_OFFSET, - NULL, NULL, &pll3_sw_clk, &ssi3_ipg_clk); - -/* eCSPI */ -DEFINE_CLOCK_FULL(ecspi1_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG9_OFFSET, - NULL, NULL, _clk_ccgr_enable_inrun, _clk_ccgr_disable, - &ipg_clk, &spba_clk); -DEFINE_CLOCK(ecspi1_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG10_OFFSET, - NULL, NULL, &ecspi_main_clk, &ecspi1_ipg_clk); -DEFINE_CLOCK_FULL(ecspi2_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG11_OFFSET, - NULL, NULL, _clk_ccgr_enable_inrun, _clk_ccgr_disable, - &ipg_clk, &aips_tz2_clk); -DEFINE_CLOCK(ecspi2_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG12_OFFSET, - NULL, NULL, &ecspi_main_clk, &ecspi2_ipg_clk); - -/* CSPI */ -DEFINE_CLOCK(cspi_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG9_OFFSET, - NULL, NULL, &ipg_clk, &aips_tz2_clk); -DEFINE_CLOCK(cspi_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG13_OFFSET, - NULL, NULL, &ipg_clk, &cspi_ipg_clk); - -/* SDMA */ -DEFINE_CLOCK(sdma_clk, 1, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG15_OFFSET, - NULL, NULL, &ahb_clk, NULL); - -/* eSDHC */ -DEFINE_CLOCK_FULL(esdhc1_ipg_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG0_OFFSET, - NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); -DEFINE_CLOCK_MAX(esdhc1_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG1_OFFSET, - clk_esdhc1, &pll2_sw_clk, &esdhc1_ipg_clk); -DEFINE_CLOCK_FULL(esdhc2_ipg_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG2_OFFSET, - NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); -DEFINE_CLOCK_FULL(esdhc3_ipg_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG4_OFFSET, - NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); -DEFINE_CLOCK_FULL(esdhc4_ipg_clk, 3, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG6_OFFSET, - NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); - -/* mx51 specific */ -DEFINE_CLOCK_MAX(esdhc2_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG3_OFFSET, - clk_esdhc2, &pll2_sw_clk, &esdhc2_ipg_clk); - -static struct clk esdhc3_clk = { - .id = 2, - .parent = &esdhc1_clk, - .set_parent = clk_esdhc3_set_parent, - .enable_reg = MXC_CCM_CCGR3, - .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, - .secondary = &esdhc3_ipg_clk, -}; -static struct clk esdhc4_clk = { - .id = 3, - .parent = &esdhc1_clk, - .set_parent = clk_esdhc4_set_parent, - .enable_reg = MXC_CCM_CCGR3, - .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, - .secondary = &esdhc4_ipg_clk, -}; - -/* mx53 specific */ -static struct clk esdhc2_mx53_clk = { - .id = 2, - .parent = &esdhc1_clk, - .set_parent = clk_esdhc2_mx53_set_parent, - .enable_reg = MXC_CCM_CCGR3, - .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, - .secondary = &esdhc3_ipg_clk, -}; - -DEFINE_CLOCK_MAX(esdhc3_mx53_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG5_OFFSET, - clk_esdhc3_mx53, &pll2_sw_clk, &esdhc2_ipg_clk); - -static struct clk esdhc4_mx53_clk = { - .id = 3, - .parent = &esdhc1_clk, - .set_parent = clk_esdhc4_mx53_set_parent, - .enable_reg = MXC_CCM_CCGR3, - .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, - .secondary = &esdhc4_ipg_clk, -}; - -static struct clk sata_clk = { - .parent = &ipg_clk, - .enable = _clk_max_enable, - .enable_reg = MXC_CCM_CCGR4, - .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, - .disable = _clk_max_disable, -}; - -static struct clk ahci_phy_clk = { - .parent = &usb_phy1_clk, -}; - -static struct clk ahci_dma_clk = { - .parent = &ahb_clk, -}; - -DEFINE_CLOCK(mipi_esc_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG5_OFFSET, NULL, NULL, NULL, &pll2_sw_clk); -DEFINE_CLOCK(mipi_hsc2_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG4_OFFSET, NULL, NULL, &mipi_esc_clk, &pll2_sw_clk); -DEFINE_CLOCK(mipi_hsc1_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG3_OFFSET, NULL, NULL, &mipi_hsc2_clk, &pll2_sw_clk); - -/* IPU */ -DEFINE_CLOCK_FULL(ipu_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG5_OFFSET, - NULL, NULL, clk_ipu_enable, clk_ipu_disable, &ahb_clk, &ipu_sec_clk); - -DEFINE_CLOCK_FULL(emi_fast_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG7_OFFSET, - NULL, NULL, _clk_ccgr_enable, _clk_ccgr_disable_inwait, - &ddr_clk, NULL); - -DEFINE_CLOCK(ipu_di0_clk, 0, MXC_CCM_CCGR6, MXC_CCM_CCGRx_CG5_OFFSET, - NULL, NULL, &pll3_sw_clk, NULL); -DEFINE_CLOCK(ipu_di1_clk, 0, MXC_CCM_CCGR6, MXC_CCM_CCGRx_CG6_OFFSET, - NULL, NULL, &pll3_sw_clk, NULL); - -/* PATA */ -DEFINE_CLOCK(pata_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG0_OFFSET, - NULL, NULL, &ipg_clk, &spba_clk); - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup mx51_lookups[] = { - /* i.mx51 has the i.mx21 type uart */ - _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK(NULL, "gpt", gpt_clk) - /* i.mx51 has the i.mx27 type fec */ - _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk) - _REGISTER_CLOCK("mxc_pwm.0", "pwm", pwm1_clk) - _REGISTER_CLOCK("mxc_pwm.1", "pwm", pwm2_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) - _REGISTER_CLOCK("imx-i2c.2", NULL, hsi2c_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb", usboh3_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_ahb_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb_phy1", usb_phy1_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb", usboh3_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_ahb_clk) - _REGISTER_CLOCK("mxc-ehci.2", "usb", usboh3_clk) - _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_ahb_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk) - _REGISTER_CLOCK("imx-keypad", NULL, dummy_clk) - _REGISTER_CLOCK("mxc_nand", NULL, nfc_clk) - _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) - _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) - _REGISTER_CLOCK("imx-ssi.2", NULL, ssi3_clk) - /* i.mx51 has the i.mx35 type sdma */ - _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk) - _REGISTER_CLOCK(NULL, "ckih", ckih_clk) - _REGISTER_CLOCK(NULL, "ckih2", ckih2_clk) - _REGISTER_CLOCK(NULL, "gpt_32k", gpt_32k_clk) - _REGISTER_CLOCK("imx51-ecspi.0", NULL, ecspi1_clk) - _REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk) - /* i.mx51 has the i.mx35 type cspi */ - _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx51.0", NULL, esdhc1_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx51.1", NULL, esdhc2_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx51.2", NULL, esdhc3_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx51.3", NULL, esdhc4_clk) - _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk) - _REGISTER_CLOCK(NULL, "iim_clk", iim_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk) - _REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk) - _REGISTER_CLOCK(NULL, "mipi_hsp", mipi_hsp_clk) - _REGISTER_CLOCK("imx-ipuv3", NULL, ipu_clk) - _REGISTER_CLOCK("imx-ipuv3", "di0", ipu_di0_clk) - _REGISTER_CLOCK("imx-ipuv3", "di1", ipu_di1_clk) - _REGISTER_CLOCK(NULL, "gpc_dvfs", gpc_dvfs_clk) - _REGISTER_CLOCK("pata_imx", NULL, pata_clk) -}; - -static struct clk_lookup mx53_lookups[] = { - /* i.mx53 has the i.mx21 type uart */ - _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk) - _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk) - _REGISTER_CLOCK(NULL, "gpt", gpt_clk) - /* i.mx53 has the i.mx25 type fec */ - _REGISTER_CLOCK("imx25-fec.0", NULL, fec_clk) - _REGISTER_CLOCK(NULL, "iim_clk", iim_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) - _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_mx53_clk) - /* i.mx53 has the i.mx51 type ecspi */ - _REGISTER_CLOCK("imx51-ecspi.0", NULL, ecspi1_clk) - _REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk) - /* i.mx53 has the i.mx25 type cspi */ - _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx53.0", NULL, esdhc1_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx53.1", NULL, esdhc2_mx53_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx53.2", NULL, esdhc3_mx53_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx53.3", NULL, esdhc4_mx53_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk) - _REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk) - /* i.mx53 has the i.mx35 type sdma */ - _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk) - _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) - _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) - _REGISTER_CLOCK("imx-ssi.2", NULL, ssi3_clk) - _REGISTER_CLOCK("imx-keypad", NULL, dummy_clk) - _REGISTER_CLOCK("pata_imx", NULL, pata_clk) - _REGISTER_CLOCK("imx53-ahci.0", "ahci", sata_clk) - _REGISTER_CLOCK("imx53-ahci.0", "ahci_phy", ahci_phy_clk) - _REGISTER_CLOCK("imx53-ahci.0", "ahci_dma", ahci_dma_clk) -}; - -static void clk_tree_init(void) -{ - u32 reg; - - ipg_perclk.set_parent(&ipg_perclk, &lp_apm_clk); - - /* - * Initialise the IPG PER CLK dividers to 3. IPG_PER_CLK should be at - * 8MHz, its derived from lp_apm. - * - * FIXME: Verify if true for all boards - */ - reg = __raw_readl(MXC_CCM_CBCDR); - reg &= ~MXC_CCM_CBCDR_PERCLK_PRED1_MASK; - reg &= ~MXC_CCM_CBCDR_PERCLK_PRED2_MASK; - reg &= ~MXC_CCM_CBCDR_PERCLK_PODF_MASK; - reg |= (2 << MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET); - __raw_writel(reg, MXC_CCM_CBCDR); -} - -int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, - unsigned long ckih1, unsigned long ckih2) -{ - int i; - - external_low_reference = ckil; - external_high_reference = ckih1; - ckih2_reference = ckih2; - oscillator_reference = osc; - - for (i = 0; i < ARRAY_SIZE(mx51_lookups); i++) - clkdev_add(&mx51_lookups[i]); - - clk_tree_init(); - - clk_enable(&cpu_clk); - clk_enable(&main_bus_clk); - - clk_enable(&iim_clk); - imx_print_silicon_rev("i.MX51", mx51_revision()); - clk_disable(&iim_clk); - - /* move usb_phy_clk to 24MHz */ - clk_set_parent(&usb_phy1_clk, &osc_clk); - - /* set the usboh3_clk parent to pll2_sw_clk */ - clk_set_parent(&usboh3_clk, &pll2_sw_clk); - - /* Set SDHC parents to be PLL2 */ - clk_set_parent(&esdhc1_clk, &pll2_sw_clk); - clk_set_parent(&esdhc2_clk, &pll2_sw_clk); - - /* set SDHC root clock as 166.25MHZ*/ - clk_set_rate(&esdhc1_clk, 166250000); - clk_set_rate(&esdhc2_clk, 166250000); - - /* System timer */ - mxc_timer_init(&gpt_clk, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR), - MX51_INT_GPT); - return 0; -} - -int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, - unsigned long ckih1, unsigned long ckih2) -{ - int i; - - external_low_reference = ckil; - external_high_reference = ckih1; - ckih2_reference = ckih2; - oscillator_reference = osc; - - for (i = 0; i < ARRAY_SIZE(mx53_lookups); i++) - clkdev_add(&mx53_lookups[i]); - - clk_tree_init(); - - clk_set_parent(&uart_root_clk, &pll3_sw_clk); - clk_enable(&cpu_clk); - clk_enable(&main_bus_clk); - - clk_enable(&iim_clk); - imx_print_silicon_rev("i.MX53", mx53_revision()); - clk_disable(&iim_clk); - - /* Set SDHC parents to be PLL2 */ - clk_set_parent(&esdhc1_clk, &pll2_sw_clk); - clk_set_parent(&esdhc3_mx53_clk, &pll2_sw_clk); - - /* set SDHC root clock as 200MHZ*/ - clk_set_rate(&esdhc1_clk, 200000000); - clk_set_rate(&esdhc3_mx53_clk, 200000000); - - /* System timer */ - mxc_timer_init(&gpt_clk, MX53_IO_ADDRESS(MX53_GPT1_BASE_ADDR), - MX53_INT_GPT); - return 0; -} - -#ifdef CONFIG_OF -static void __init clk_get_freq_dt(unsigned long *ckil, unsigned long *osc, - unsigned long *ckih1, unsigned long *ckih2) -{ - struct device_node *np; - - /* retrieve the freqency of fixed clocks from device tree */ - for_each_compatible_node(np, NULL, "fixed-clock") { - u32 rate; - if (of_property_read_u32(np, "clock-frequency", &rate)) - continue; - - if (of_device_is_compatible(np, "fsl,imx-ckil")) - *ckil = rate; - else if (of_device_is_compatible(np, "fsl,imx-osc")) - *osc = rate; - else if (of_device_is_compatible(np, "fsl,imx-ckih1")) - *ckih1 = rate; - else if (of_device_is_compatible(np, "fsl,imx-ckih2")) - *ckih2 = rate; - } -} - -int __init mx51_clocks_init_dt(void) -{ - unsigned long ckil, osc, ckih1, ckih2; - - clk_get_freq_dt(&ckil, &osc, &ckih1, &ckih2); - return mx51_clocks_init(ckil, osc, ckih1, ckih2); -} - -int __init mx53_clocks_init_dt(void) -{ - unsigned long ckil, osc, ckih1, ckih2; - - clk_get_freq_dt(&ckil, &osc, &ckih1, &ckih2); - return mx53_clocks_init(ckil, osc, ckih1, ckih2); -} -#endif diff --git a/arch/arm/mach-imx/crmregs-imx3.h b/arch/arm/mach-imx/crmregs-imx3.h index 53141273df45..a1dfde53e335 100644 --- a/arch/arm/mach-imx/crmregs-imx3.h +++ b/arch/arm/mach-imx/crmregs-imx3.h @@ -24,48 +24,47 @@ #define CKIH_CLK_FREQ_27MHZ 27000000 #define CKIL_CLK_FREQ 32768 -#define MXC_CCM_BASE (cpu_is_mx31() ? \ -MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR) : MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR)) +extern void __iomem *mx3_ccm_base; /* Register addresses */ -#define MXC_CCM_CCMR (MXC_CCM_BASE + 0x00) -#define MXC_CCM_PDR0 (MXC_CCM_BASE + 0x04) -#define MXC_CCM_PDR1 (MXC_CCM_BASE + 0x08) -#define MX35_CCM_PDR2 (MXC_CCM_BASE + 0x0C) -#define MXC_CCM_RCSR (MXC_CCM_BASE + 0x0C) -#define MX35_CCM_PDR3 (MXC_CCM_BASE + 0x10) -#define MXC_CCM_MPCTL (MXC_CCM_BASE + 0x10) -#define MX35_CCM_PDR4 (MXC_CCM_BASE + 0x14) -#define MXC_CCM_UPCTL (MXC_CCM_BASE + 0x14) -#define MX35_CCM_RCSR (MXC_CCM_BASE + 0x18) -#define MXC_CCM_SRPCTL (MXC_CCM_BASE + 0x18) -#define MX35_CCM_MPCTL (MXC_CCM_BASE + 0x1C) -#define MXC_CCM_COSR (MXC_CCM_BASE + 0x1C) -#define MX35_CCM_PPCTL (MXC_CCM_BASE + 0x20) -#define MXC_CCM_CGR0 (MXC_CCM_BASE + 0x20) -#define MX35_CCM_ACMR (MXC_CCM_BASE + 0x24) -#define MXC_CCM_CGR1 (MXC_CCM_BASE + 0x24) -#define MX35_CCM_COSR (MXC_CCM_BASE + 0x28) -#define MXC_CCM_CGR2 (MXC_CCM_BASE + 0x28) -#define MX35_CCM_CGR0 (MXC_CCM_BASE + 0x2C) -#define MXC_CCM_WIMR (MXC_CCM_BASE + 0x2C) -#define MX35_CCM_CGR1 (MXC_CCM_BASE + 0x30) -#define MXC_CCM_LDC (MXC_CCM_BASE + 0x30) -#define MX35_CCM_CGR2 (MXC_CCM_BASE + 0x34) -#define MXC_CCM_DCVR0 (MXC_CCM_BASE + 0x34) -#define MX35_CCM_CGR3 (MXC_CCM_BASE + 0x38) -#define MXC_CCM_DCVR1 (MXC_CCM_BASE + 0x38) -#define MXC_CCM_DCVR2 (MXC_CCM_BASE + 0x3C) -#define MXC_CCM_DCVR3 (MXC_CCM_BASE + 0x40) -#define MXC_CCM_LTR0 (MXC_CCM_BASE + 0x44) -#define MXC_CCM_LTR1 (MXC_CCM_BASE + 0x48) -#define MXC_CCM_LTR2 (MXC_CCM_BASE + 0x4C) -#define MXC_CCM_LTR3 (MXC_CCM_BASE + 0x50) -#define MXC_CCM_LTBR0 (MXC_CCM_BASE + 0x54) -#define MXC_CCM_LTBR1 (MXC_CCM_BASE + 0x58) -#define MXC_CCM_PMCR0 (MXC_CCM_BASE + 0x5C) -#define MXC_CCM_PMCR1 (MXC_CCM_BASE + 0x60) -#define MXC_CCM_PDR2 (MXC_CCM_BASE + 0x64) +#define MXC_CCM_CCMR 0x00 +#define MXC_CCM_PDR0 0x04 +#define MXC_CCM_PDR1 0x08 +#define MX35_CCM_PDR2 0x0C +#define MXC_CCM_RCSR 0x0C +#define MX35_CCM_PDR3 0x10 +#define MXC_CCM_MPCTL 0x10 +#define MX35_CCM_PDR4 0x14 +#define MXC_CCM_UPCTL 0x14 +#define MX35_CCM_RCSR 0x18 +#define MXC_CCM_SRPCTL 0x18 +#define MX35_CCM_MPCTL 0x1C +#define MXC_CCM_COSR 0x1C +#define MX35_CCM_PPCTL 0x20 +#define MXC_CCM_CGR0 0x20 +#define MX35_CCM_ACMR 0x24 +#define MXC_CCM_CGR1 0x24 +#define MX35_CCM_COSR 0x28 +#define MXC_CCM_CGR2 0x28 +#define MX35_CCM_CGR0 0x2C +#define MXC_CCM_WIMR 0x2C +#define MX35_CCM_CGR1 0x30 +#define MXC_CCM_LDC 0x30 +#define MX35_CCM_CGR2 0x34 +#define MXC_CCM_DCVR0 0x34 +#define MX35_CCM_CGR3 0x38 +#define MXC_CCM_DCVR1 0x38 +#define MXC_CCM_DCVR2 0x3C +#define MXC_CCM_DCVR3 0x40 +#define MXC_CCM_LTR0 0x44 +#define MXC_CCM_LTR1 0x48 +#define MXC_CCM_LTR2 0x4C +#define MXC_CCM_LTR3 0x50 +#define MXC_CCM_LTBR0 0x54 +#define MXC_CCM_LTBR1 0x58 +#define MXC_CCM_PMCR0 0x5C +#define MXC_CCM_PMCR1 0x60 +#define MXC_CCM_PDR2 0x64 /* Register bit definitions */ #define MXC_CCM_CCMR_WBEN (1 << 27) diff --git a/arch/arm/mach-imx/mm-imx3.c b/arch/arm/mach-imx/mm-imx3.c index 9128d15b1eb7..967ed5b35a45 100644 --- a/arch/arm/mach-imx/mm-imx3.c +++ b/arch/arm/mach-imx/mm-imx3.c @@ -32,6 +32,10 @@ #include <mach/iomux-v3.h> #include <mach/irqs.h> +#include "crmregs-imx3.h" + +void __iomem *mx3_ccm_base; + static void imx3_idle(void) { unsigned long reg = 0; @@ -138,6 +142,7 @@ void __init imx31_init_early(void) mxc_arch_reset_init(MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR)); arch_ioremap_caller = imx3_ioremap_caller; arm_pm_idle = imx3_idle; + mx3_ccm_base = MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR); } void __init mx31_init_irq(void) @@ -211,6 +216,7 @@ void __init imx35_init_early(void) mxc_arch_reset_init(MX35_IO_ADDRESS(MX35_WDOG_BASE_ADDR)); arm_pm_idle = imx3_idle; arch_ioremap_caller = imx3_ioremap_caller; + mx3_ccm_base = MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR); } void __init mx35_init_irq(void) diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c index ba91e6b31cf4..8b4dc20c7c53 100644 --- a/arch/arm/mach-imx/mm-imx5.c +++ b/arch/arm/mach-imx/mm-imx5.c @@ -33,6 +33,7 @@ static void imx5_idle(void) gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs"); if (IS_ERR(gpc_dvfs_clk)) return; + clk_prepare(gpc_dvfs_clk); } clk_enable(gpc_dvfs_clk); mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); diff --git a/arch/arm/mach-imx/pm-imx3.c b/arch/arm/mach-imx/pm-imx3.c index b3752439632e..822103bdb709 100644 --- a/arch/arm/mach-imx/pm-imx3.c +++ b/arch/arm/mach-imx/pm-imx3.c @@ -21,14 +21,14 @@ */ void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode) { - int reg = __raw_readl(MXC_CCM_CCMR); + int reg = __raw_readl(mx3_ccm_base + MXC_CCM_CCMR); reg &= ~MXC_CCM_CCMR_LPM_MASK; switch (mode) { case MX3_WAIT: if (cpu_is_mx35()) reg |= MXC_CCM_CCMR_LPM_WAIT_MX35; - __raw_writel(reg, MXC_CCM_CCMR); + __raw_writel(reg, mx3_ccm_base + MXC_CCM_CCMR); break; default: pr_err("Unknown cpu power mode: %d\n", mode); diff --git a/arch/arm/mach-kirkwood/board-dreamplug.c b/arch/arm/mach-kirkwood/board-dreamplug.c index 985453994dd3..55e357ab2923 100644 --- a/arch/arm/mach-kirkwood/board-dreamplug.c +++ b/arch/arm/mach-kirkwood/board-dreamplug.c @@ -27,7 +27,6 @@ #include <linux/mtd/physmap.h> #include <linux/spi/flash.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c index 10d1969b9e3a..edc3f8a9d45e 100644 --- a/arch/arm/mach-kirkwood/board-dt.c +++ b/arch/arm/mach-kirkwood/board-dt.c @@ -43,6 +43,9 @@ static void __init kirkwood_dt_init(void) kirkwood_l2_init(); #endif + /* Setup root of clk tree */ + kirkwood_clk_init(); + /* internal devices that every board has */ kirkwood_wdt_init(); kirkwood_xor0_init(); diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c index 3ad037385a5e..25fb3fd418ef 100644 --- a/arch/arm/mach-kirkwood/common.c +++ b/arch/arm/mach-kirkwood/common.c @@ -15,7 +15,8 @@ #include <linux/ata_platform.h> #include <linux/mtd/nand.h> #include <linux/dma-mapping.h> -#include <linux/of.h> +#include <linux/clk-provider.h> +#include <linux/spinlock.h> #include <net/dsa.h> #include <asm/page.h> #include <asm/timex.h> @@ -32,6 +33,7 @@ #include <plat/common.h> #include <plat/time.h> #include <plat/addr-map.h> +#include <plat/mv_xor.h> #include "common.h" /***************************************************************************** @@ -61,20 +63,188 @@ void __init kirkwood_map_io(void) iotable_init(kirkwood_io_desc, ARRAY_SIZE(kirkwood_io_desc)); } -/* - * Default clock control bits. Any bit _not_ set in this variable - * will be cleared from the hardware after platform devices have been - * registered. Some reserved bits must be set to 1. - */ -unsigned int kirkwood_clk_ctrl = CGC_DUNIT | CGC_RESERVED; +/***************************************************************************** + * CLK tree + ****************************************************************************/ + +static void disable_sata0(void) +{ + /* Disable PLL and IVREF */ + writel(readl(SATA0_PHY_MODE_2) & ~0xf, SATA0_PHY_MODE_2); + /* Disable PHY */ + writel(readl(SATA0_IF_CTRL) | 0x200, SATA0_IF_CTRL); +} + +static void disable_sata1(void) +{ + /* Disable PLL and IVREF */ + writel(readl(SATA1_PHY_MODE_2) & ~0xf, SATA1_PHY_MODE_2); + /* Disable PHY */ + writel(readl(SATA1_IF_CTRL) | 0x200, SATA1_IF_CTRL); +} + +static void disable_pcie0(void) +{ + writel(readl(PCIE_LINK_CTRL) | 0x10, PCIE_LINK_CTRL); + while (1) + if (readl(PCIE_STATUS) & 0x1) + break; + writel(readl(PCIE_LINK_CTRL) & ~0x10, PCIE_LINK_CTRL); +} + +static void disable_pcie1(void) +{ + u32 dev, rev; + + kirkwood_pcie_id(&dev, &rev); + + if (dev == MV88F6282_DEV_ID) { + writel(readl(PCIE1_LINK_CTRL) | 0x10, PCIE1_LINK_CTRL); + while (1) + if (readl(PCIE1_STATUS) & 0x1) + break; + writel(readl(PCIE1_LINK_CTRL) & ~0x10, PCIE1_LINK_CTRL); + } +} + +/* An extended version of the gated clk. This calls fn() before + * disabling the clock. We use this to turn off PHYs etc. */ +struct clk_gate_fn { + struct clk_gate gate; + void (*fn)(void); +}; + +#define to_clk_gate_fn(_gate) container_of(_gate, struct clk_gate_fn, gate) +#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) + +static void clk_gate_fn_disable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct clk_gate_fn *gate_fn = to_clk_gate_fn(gate); + + if (gate_fn->fn) + gate_fn->fn(); + + clk_gate_ops.disable(hw); +} + +static struct clk_ops clk_gate_fn_ops; + +static struct clk __init *clk_register_gate_fn(struct device *dev, + const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock, + void (*fn)(void)) +{ + struct clk_gate_fn *gate_fn; + struct clk *clk; + struct clk_init_data init; + + gate_fn = kzalloc(sizeof(struct clk_gate_fn), GFP_KERNEL); + if (!gate_fn) { + pr_err("%s: could not allocate gated clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &clk_gate_fn_ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + /* struct clk_gate assignments */ + gate_fn->gate.reg = reg; + gate_fn->gate.bit_idx = bit_idx; + gate_fn->gate.flags = clk_gate_flags; + gate_fn->gate.lock = lock; + gate_fn->gate.hw.init = &init; + + /* ops is the gate ops, but with our disable function */ + if (clk_gate_fn_ops.disable != clk_gate_fn_disable) { + clk_gate_fn_ops = clk_gate_ops; + clk_gate_fn_ops.disable = clk_gate_fn_disable; + } + clk = clk_register(dev, &gate_fn->gate.hw); + + if (IS_ERR(clk)) + kfree(gate_fn); + + return clk; +} + +static DEFINE_SPINLOCK(gating_lock); +static struct clk *tclk; + +static struct clk __init *kirkwood_register_gate(const char *name, u8 bit_idx) +{ + return clk_register_gate(NULL, name, "tclk", 0, + (void __iomem *)CLOCK_GATING_CTRL, + bit_idx, 0, &gating_lock); +} + +static struct clk __init *kirkwood_register_gate_fn(const char *name, + u8 bit_idx, + void (*fn)(void)) +{ + return clk_register_gate_fn(NULL, name, "tclk", 0, + (void __iomem *)CLOCK_GATING_CTRL, + bit_idx, 0, &gating_lock, fn); +} + +void __init kirkwood_clk_init(void) +{ + struct clk *runit, *ge0, *ge1, *sata0, *sata1, *usb0, *sdio; + struct clk *crypto, *xor0, *xor1, *pex0, *pex1, *audio; + + tclk = clk_register_fixed_rate(NULL, "tclk", NULL, + CLK_IS_ROOT, kirkwood_tclk); + + runit = kirkwood_register_gate("runit", CGC_BIT_RUNIT); + ge0 = kirkwood_register_gate("ge0", CGC_BIT_GE0); + ge1 = kirkwood_register_gate("ge1", CGC_BIT_GE1); + sata0 = kirkwood_register_gate_fn("sata0", CGC_BIT_SATA0, + disable_sata0); + sata1 = kirkwood_register_gate_fn("sata1", CGC_BIT_SATA1, + disable_sata1); + usb0 = kirkwood_register_gate("usb0", CGC_BIT_USB0); + sdio = kirkwood_register_gate("sdio", CGC_BIT_SDIO); + crypto = kirkwood_register_gate("crypto", CGC_BIT_CRYPTO); + xor0 = kirkwood_register_gate("xor0", CGC_BIT_XOR0); + xor1 = kirkwood_register_gate("xor1", CGC_BIT_XOR1); + pex0 = kirkwood_register_gate_fn("pex0", CGC_BIT_PEX0, + disable_pcie0); + pex1 = kirkwood_register_gate_fn("pex1", CGC_BIT_PEX1, + disable_pcie1); + audio = kirkwood_register_gate("audio", CGC_BIT_AUDIO); + kirkwood_register_gate("tdm", CGC_BIT_TDM); + kirkwood_register_gate("tsu", CGC_BIT_TSU); + + /* clkdev entries, mapping clks to devices */ + orion_clkdev_add(NULL, "orion_spi.0", runit); + orion_clkdev_add(NULL, "orion_spi.1", runit); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".0", ge0); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".1", ge1); + orion_clkdev_add(NULL, "orion_wdt", tclk); + orion_clkdev_add("0", "sata_mv.0", sata0); + orion_clkdev_add("1", "sata_mv.0", sata1); + orion_clkdev_add(NULL, "orion-ehci.0", usb0); + orion_clkdev_add(NULL, "orion_nand", runit); + orion_clkdev_add(NULL, "mvsdio", sdio); + orion_clkdev_add(NULL, "mv_crypto", crypto); + orion_clkdev_add(NULL, MV_XOR_SHARED_NAME ".0", xor0); + orion_clkdev_add(NULL, MV_XOR_SHARED_NAME ".1", xor1); + orion_clkdev_add("0", "pcie", pex0); + orion_clkdev_add("1", "pcie", pex1); + orion_clkdev_add(NULL, "kirkwood-i2s", audio); +} /***************************************************************************** * EHCI0 ****************************************************************************/ void __init kirkwood_ehci_init(void) { - kirkwood_clk_ctrl |= CGC_USB0; orion_ehci_init(USB_PHYS_BASE, IRQ_KIRKWOOD_USB, EHCI_PHY_NA); } @@ -84,11 +254,9 @@ void __init kirkwood_ehci_init(void) ****************************************************************************/ void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data) { - kirkwood_clk_ctrl |= CGC_GE0; - orion_ge00_init(eth_data, GE00_PHYS_BASE, IRQ_KIRKWOOD_GE00_SUM, - IRQ_KIRKWOOD_GE00_ERR, kirkwood_tclk); + IRQ_KIRKWOOD_GE00_ERR); } @@ -97,12 +265,9 @@ void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data) ****************************************************************************/ void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data) { - - kirkwood_clk_ctrl |= CGC_GE1; - orion_ge01_init(eth_data, GE01_PHYS_BASE, IRQ_KIRKWOOD_GE01_SUM, - IRQ_KIRKWOOD_GE01_ERR, kirkwood_tclk); + IRQ_KIRKWOOD_GE01_ERR); } @@ -144,7 +309,6 @@ static struct platform_device kirkwood_nand_flash = { void __init kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int chip_delay) { - kirkwood_clk_ctrl |= CGC_RUNIT; kirkwood_nand_data.parts = parts; kirkwood_nand_data.nr_parts = nr_parts; kirkwood_nand_data.chip_delay = chip_delay; @@ -154,7 +318,6 @@ void __init kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, void __init kirkwood_nand_init_rnb(struct mtd_partition *parts, int nr_parts, int (*dev_ready)(struct mtd_info *)) { - kirkwood_clk_ctrl |= CGC_RUNIT; kirkwood_nand_data.parts = parts; kirkwood_nand_data.nr_parts = nr_parts; kirkwood_nand_data.dev_ready = dev_ready; @@ -175,10 +338,6 @@ static void __init kirkwood_rtc_init(void) ****************************************************************************/ void __init kirkwood_sata_init(struct mv_sata_platform_data *sata_data) { - kirkwood_clk_ctrl |= CGC_SATA0; - if (sata_data->n_ports > 1) - kirkwood_clk_ctrl |= CGC_SATA1; - orion_sata_init(sata_data, SATA_PHYS_BASE, IRQ_KIRKWOOD_SATA); } @@ -221,7 +380,6 @@ void __init kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data) mvsdio_data->clock = 100000000; else mvsdio_data->clock = 200000000; - kirkwood_clk_ctrl |= CGC_SDIO; kirkwood_sdio.dev.platform_data = mvsdio_data; platform_device_register(&kirkwood_sdio); } @@ -232,8 +390,7 @@ void __init kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data) ****************************************************************************/ void __init kirkwood_spi_init() { - kirkwood_clk_ctrl |= CGC_RUNIT; - orion_spi_init(SPI_PHYS_BASE, kirkwood_tclk); + orion_spi_init(SPI_PHYS_BASE); } @@ -253,7 +410,7 @@ void __init kirkwood_i2c_init(void) void __init kirkwood_uart0_init(void) { orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE, - IRQ_KIRKWOOD_UART_0, kirkwood_tclk); + IRQ_KIRKWOOD_UART_0, tclk); } @@ -263,7 +420,7 @@ void __init kirkwood_uart0_init(void) void __init kirkwood_uart1_init(void) { orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE, - IRQ_KIRKWOOD_UART_1, kirkwood_tclk); + IRQ_KIRKWOOD_UART_1, tclk); } /***************************************************************************** @@ -271,7 +428,6 @@ void __init kirkwood_uart1_init(void) ****************************************************************************/ void __init kirkwood_crypto_init(void) { - kirkwood_clk_ctrl |= CGC_CRYPTO; orion_crypto_init(CRYPTO_PHYS_BASE, KIRKWOOD_SRAM_PHYS_BASE, KIRKWOOD_SRAM_SIZE, IRQ_KIRKWOOD_CRYPTO); } @@ -282,8 +438,6 @@ void __init kirkwood_crypto_init(void) ****************************************************************************/ void __init kirkwood_xor0_init(void) { - kirkwood_clk_ctrl |= CGC_XOR0; - orion_xor0_init(XOR0_PHYS_BASE, XOR0_HIGH_PHYS_BASE, IRQ_KIRKWOOD_XOR_00, IRQ_KIRKWOOD_XOR_01); } @@ -294,8 +448,6 @@ void __init kirkwood_xor0_init(void) ****************************************************************************/ void __init kirkwood_xor1_init(void) { - kirkwood_clk_ctrl |= CGC_XOR1; - orion_xor1_init(XOR1_PHYS_BASE, XOR1_HIGH_PHYS_BASE, IRQ_KIRKWOOD_XOR_10, IRQ_KIRKWOOD_XOR_11); } @@ -306,7 +458,7 @@ void __init kirkwood_xor1_init(void) ****************************************************************************/ void __init kirkwood_wdt_init(void) { - orion_wdt_init(kirkwood_tclk); + orion_wdt_init(); } @@ -382,7 +534,6 @@ static struct platform_device kirkwood_pcm_device = { void __init kirkwood_audio_init(void) { - kirkwood_clk_ctrl |= CGC_AUDIO; platform_device_register(&kirkwood_i2s_device); platform_device_register(&kirkwood_pcm_device); } @@ -466,6 +617,9 @@ void __init kirkwood_init(void) kirkwood_l2_init(); #endif + /* Setup root of clk tree */ + kirkwood_clk_init(); + /* internal devices that every board has */ kirkwood_rtc_init(); kirkwood_wdt_init(); @@ -478,72 +632,6 @@ void __init kirkwood_init(void) #endif } -static int __init kirkwood_clock_gate(void) -{ - unsigned int curr = readl(CLOCK_GATING_CTRL); - u32 dev, rev; - -#ifdef CONFIG_OF - struct device_node *np; -#endif - kirkwood_pcie_id(&dev, &rev); - printk(KERN_DEBUG "Gating clock of unused units\n"); - printk(KERN_DEBUG "before: 0x%08x\n", curr); - - /* Make sure those units are accessible */ - writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0 | CGC_PEX1, CLOCK_GATING_CTRL); - -#ifdef CONFIG_OF - np = of_find_compatible_node(NULL, NULL, "mrvl,orion-nand"); - if (np && of_device_is_available(np)) { - kirkwood_clk_ctrl |= CGC_RUNIT; - of_node_put(np); - } -#endif - - /* For SATA: first shutdown the phy */ - if (!(kirkwood_clk_ctrl & CGC_SATA0)) { - /* Disable PLL and IVREF */ - writel(readl(SATA0_PHY_MODE_2) & ~0xf, SATA0_PHY_MODE_2); - /* Disable PHY */ - writel(readl(SATA0_IF_CTRL) | 0x200, SATA0_IF_CTRL); - } - if (!(kirkwood_clk_ctrl & CGC_SATA1)) { - /* Disable PLL and IVREF */ - writel(readl(SATA1_PHY_MODE_2) & ~0xf, SATA1_PHY_MODE_2); - /* Disable PHY */ - writel(readl(SATA1_IF_CTRL) | 0x200, SATA1_IF_CTRL); - } - - /* For PCIe: first shutdown the phy */ - if (!(kirkwood_clk_ctrl & CGC_PEX0)) { - writel(readl(PCIE_LINK_CTRL) | 0x10, PCIE_LINK_CTRL); - while (1) - if (readl(PCIE_STATUS) & 0x1) - break; - writel(readl(PCIE_LINK_CTRL) & ~0x10, PCIE_LINK_CTRL); - } - - /* For PCIe 1: first shutdown the phy */ - if (dev == MV88F6282_DEV_ID) { - if (!(kirkwood_clk_ctrl & CGC_PEX1)) { - writel(readl(PCIE1_LINK_CTRL) | 0x10, PCIE1_LINK_CTRL); - while (1) - if (readl(PCIE1_STATUS) & 0x1) - break; - writel(readl(PCIE1_LINK_CTRL) & ~0x10, PCIE1_LINK_CTRL); - } - } else /* keep this bit set for devices that don't have PCIe1 */ - kirkwood_clk_ctrl |= CGC_PEX1; - - /* Now gate clock the required units */ - writel(kirkwood_clk_ctrl, CLOCK_GATING_CTRL); - printk(KERN_DEBUG " after: 0x%08x\n", readl(CLOCK_GATING_CTRL)); - - return 0; -} -late_initcall(kirkwood_clock_gate); - void kirkwood_restart(char mode, const char *cmd) { /* diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h index a34c41a5172e..9248fa2c165b 100644 --- a/arch/arm/mach-kirkwood/common.h +++ b/arch/arm/mach-kirkwood/common.h @@ -50,6 +50,7 @@ void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay); void kirkwood_nand_init_rnb(struct mtd_partition *parts, int nr_parts, int (*dev_ready)(struct mtd_info *)); void kirkwood_audio_init(void); void kirkwood_restart(char, const char *); +void kirkwood_clk_init(void); /* board init functions for boards not fully converted to fdt */ #ifdef CONFIG_MACH_DREAMPLUG_DT diff --git a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h index 957bd7997d7e..3eee37a3b501 100644 --- a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h +++ b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h @@ -43,6 +43,22 @@ #define L2_WRITETHROUGH 0x00000010 #define CLOCK_GATING_CTRL (BRIDGE_VIRT_BASE | 0x11c) +#define CGC_BIT_GE0 (0) +#define CGC_BIT_PEX0 (2) +#define CGC_BIT_USB0 (3) +#define CGC_BIT_SDIO (4) +#define CGC_BIT_TSU (5) +#define CGC_BIT_DUNIT (6) +#define CGC_BIT_RUNIT (7) +#define CGC_BIT_XOR0 (8) +#define CGC_BIT_AUDIO (9) +#define CGC_BIT_SATA0 (14) +#define CGC_BIT_SATA1 (15) +#define CGC_BIT_XOR1 (16) +#define CGC_BIT_CRYPTO (17) +#define CGC_BIT_PEX1 (18) +#define CGC_BIT_GE1 (19) +#define CGC_BIT_TDM (20) #define CGC_GE0 (1 << 0) #define CGC_PEX0 (1 << 2) #define CGC_USB0 (1 << 3) diff --git a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c index 85f6169c2484..6d8364a97810 100644 --- a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c +++ b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c @@ -23,7 +23,6 @@ #include <linux/gpio_keys.h> #include <linux/spi/flash.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <net/dsa.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c index de373176ee67..6e8b2efa3c35 100644 --- a/arch/arm/mach-kirkwood/pcie.c +++ b/arch/arm/mach-kirkwood/pcie.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/slab.h> +#include <linux/clk.h> #include <video/vga.h> #include <asm/irq.h> #include <asm/mach/pci.h> @@ -19,6 +20,23 @@ #include <plat/addr-map.h> #include "common.h" +static void kirkwood_enable_pcie_clk(const char *port) +{ + struct clk *clk; + + clk = clk_get_sys("pcie", port); + if (IS_ERR(clk)) { + printk(KERN_ERR "PCIE clock %s missing\n", port); + return; + } + clk_prepare_enable(clk); + clk_put(clk); +} + +/* This function is called very early in the boot when probing the + hardware to determine what we actually are, and what rate tclk is + ticking at. Hence calling kirkwood_enable_pcie_clk() is not + possible since the clk tree has not been created yet. */ void kirkwood_enable_pcie(void) { u32 curr = readl(CLOCK_GATING_CTRL); @@ -26,7 +44,7 @@ void kirkwood_enable_pcie(void) writel(curr | CGC_PEX0, CLOCK_GATING_CTRL); } -void __init kirkwood_pcie_id(u32 *dev, u32 *rev) +void kirkwood_pcie_id(u32 *dev, u32 *rev) { kirkwood_enable_pcie(); *dev = orion_pcie_dev_id((void __iomem *)PCIE_VIRT_BASE); @@ -159,7 +177,6 @@ static void __init pcie1_ioresources_init(struct pcie_port *pp) static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys) { - extern unsigned int kirkwood_clk_ctrl; struct pcie_port *pp; int index; @@ -178,11 +195,11 @@ static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys) switch (index) { case 0: - kirkwood_clk_ctrl |= CGC_PEX0; + kirkwood_enable_pcie_clk("0"); pcie0_ioresources_init(pp); break; case 1: - kirkwood_clk_ctrl |= CGC_PEX1; + kirkwood_enable_pcie_clk("1"); pcie1_ioresources_init(pp); break; default: diff --git a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c index fd2c9c8b6831..f742a66a7045 100644 --- a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c +++ b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c @@ -16,7 +16,6 @@ #include <linux/gpio.h> #include <linux/spi/flash.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <mach/kirkwood.h> diff --git a/arch/arm/mach-kirkwood/t5325-setup.c b/arch/arm/mach-kirkwood/t5325-setup.c index f9d2a11b7f96..bad738e44044 100644 --- a/arch/arm/mach-kirkwood/t5325-setup.c +++ b/arch/arm/mach-kirkwood/t5325-setup.c @@ -16,7 +16,6 @@ #include <linux/mtd/physmap.h> #include <linux/spi/flash.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <linux/i2c.h> #include <linux/mv643xx_eth.h> #include <linux/ata_platform.h> diff --git a/arch/arm/mach-kirkwood/tsx1x-common.c b/arch/arm/mach-kirkwood/tsx1x-common.c index 24294b2bc469..8943ede29b44 100644 --- a/arch/arm/mach-kirkwood/tsx1x-common.c +++ b/arch/arm/mach-kirkwood/tsx1x-common.c @@ -4,7 +4,6 @@ #include <linux/mtd/physmap.h> #include <linux/spi/flash.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <linux/serial_reg.h> #include <mach/kirkwood.h> #include "common.h" diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c index a5dcf766a3f9..b4c53b846c9c 100644 --- a/arch/arm/mach-mv78xx0/common.c +++ b/arch/arm/mach-mv78xx0/common.c @@ -13,6 +13,7 @@ #include <linux/platform_device.h> #include <linux/serial_8250.h> #include <linux/ata_platform.h> +#include <linux/clk-provider.h> #include <linux/ethtool.h> #include <asm/mach/map.h> #include <asm/mach/time.h> @@ -103,24 +104,24 @@ static void get_pclk_l2clk(int hclk, int core_index, int *pclk, int *l2clk) static int get_tclk(void) { - int tclk; + int tclk_freq; /* * TCLK tick rate is configured by DEV_A[2:0] strap pins. */ switch ((readl(SAMPLE_AT_RESET_HIGH) >> 6) & 7) { case 1: - tclk = 166666667; + tclk_freq = 166666667; break; case 3: - tclk = 200000000; + tclk_freq = 200000000; break; default: panic("unknown TCLK PLL setting: %.8x\n", readl(SAMPLE_AT_RESET_HIGH)); } - return tclk; + return tclk_freq; } @@ -166,6 +167,19 @@ void __init mv78xx0_map_io(void) /***************************************************************************** + * CLK tree + ****************************************************************************/ +static struct clk *tclk; + +static void __init clk_init(void) +{ + tclk = clk_register_fixed_rate(NULL, "tclk", NULL, CLK_IS_ROOT, + get_tclk()); + + orion_clkdev_init(tclk); +} + +/***************************************************************************** * EHCI ****************************************************************************/ void __init mv78xx0_ehci0_init(void) @@ -199,7 +213,7 @@ void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge00_init(eth_data, GE00_PHYS_BASE, IRQ_MV78XX0_GE00_SUM, - IRQ_MV78XX0_GE_ERR, get_tclk()); + IRQ_MV78XX0_GE_ERR); } @@ -210,7 +224,7 @@ void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge01_init(eth_data, GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM, - NO_IRQ, get_tclk()); + NO_IRQ); } @@ -234,7 +248,7 @@ void __init mv78xx0_ge10_init(struct mv643xx_eth_platform_data *eth_data) orion_ge10_init(eth_data, GE10_PHYS_BASE, IRQ_MV78XX0_GE10_SUM, - NO_IRQ, get_tclk()); + NO_IRQ); } @@ -258,7 +272,7 @@ void __init mv78xx0_ge11_init(struct mv643xx_eth_platform_data *eth_data) orion_ge11_init(eth_data, GE11_PHYS_BASE, IRQ_MV78XX0_GE11_SUM, - NO_IRQ, get_tclk()); + NO_IRQ); } /***************************************************************************** @@ -285,7 +299,7 @@ void __init mv78xx0_sata_init(struct mv_sata_platform_data *sata_data) void __init mv78xx0_uart0_init(void) { orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE, - IRQ_MV78XX0_UART_0, get_tclk()); + IRQ_MV78XX0_UART_0, tclk); } @@ -295,7 +309,7 @@ void __init mv78xx0_uart0_init(void) void __init mv78xx0_uart1_init(void) { orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE, - IRQ_MV78XX0_UART_1, get_tclk()); + IRQ_MV78XX0_UART_1, tclk); } @@ -305,7 +319,7 @@ void __init mv78xx0_uart1_init(void) void __init mv78xx0_uart2_init(void) { orion_uart2_init(UART2_VIRT_BASE, UART2_PHYS_BASE, - IRQ_MV78XX0_UART_2, get_tclk()); + IRQ_MV78XX0_UART_2, tclk); } /***************************************************************************** @@ -314,7 +328,7 @@ void __init mv78xx0_uart2_init(void) void __init mv78xx0_uart3_init(void) { orion_uart3_init(UART3_VIRT_BASE, UART3_PHYS_BASE, - IRQ_MV78XX0_UART_3, get_tclk()); + IRQ_MV78XX0_UART_3, tclk); } /***************************************************************************** @@ -378,25 +392,26 @@ void __init mv78xx0_init(void) int hclk; int pclk; int l2clk; - int tclk; core_index = mv78xx0_core_index(); hclk = get_hclk(); get_pclk_l2clk(hclk, core_index, &pclk, &l2clk); - tclk = get_tclk(); printk(KERN_INFO "%s ", mv78xx0_id()); printk("core #%d, ", core_index); printk("PCLK = %dMHz, ", (pclk + 499999) / 1000000); printk("L2 = %dMHz, ", (l2clk + 499999) / 1000000); printk("HCLK = %dMHz, ", (hclk + 499999) / 1000000); - printk("TCLK = %dMHz\n", (tclk + 499999) / 1000000); + printk("TCLK = %dMHz\n", (get_tclk() + 499999) / 1000000); mv78xx0_setup_cpu_mbus(); #ifdef CONFIG_CACHE_FEROCEON_L2 feroceon_l2_init(is_l2_writethrough()); #endif + + /* Setup root of clk tree */ + clk_init(); } void mv78xx0_restart(char mode, const char *cmd) diff --git a/arch/arm/mach-mxs/Makefile b/arch/arm/mach-mxs/Makefile index 908bf9a567f1..6ce21a26412e 100644 --- a/arch/arm/mach-mxs/Makefile +++ b/arch/arm/mach-mxs/Makefile @@ -1,12 +1,9 @@ # Common support -obj-y := clock.o devices.o icoll.o iomux.o system.o timer.o mm.o +obj-y := devices.o icoll.o iomux.o system.o timer.o mm.o obj-$(CONFIG_MXS_OCOTP) += ocotp.o obj-$(CONFIG_PM) += pm.o -obj-$(CONFIG_SOC_IMX23) += clock-mx23.o -obj-$(CONFIG_SOC_IMX28) += clock-mx28.o - obj-$(CONFIG_MACH_STMP378X_DEVB) += mach-stmp378x_devb.o obj-$(CONFIG_MACH_MX23EVK) += mach-mx23evk.o obj-$(CONFIG_MACH_MX28EVK) += mach-mx28evk.o diff --git a/arch/arm/mach-mxs/clock-mx23.c b/arch/arm/mach-mxs/clock-mx23.c deleted file mode 100644 index e3ac52c34019..000000000000 --- a/arch/arm/mach-mxs/clock-mx23.c +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * - * 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 <linux/mm.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/jiffies.h> -#include <linux/clkdev.h> - -#include <asm/clkdev.h> -#include <asm/div64.h> - -#include <mach/mx23.h> -#include <mach/common.h> -#include <mach/clock.h> - -#include "regs-clkctrl-mx23.h" - -#define CLKCTRL_BASE_ADDR MX23_IO_ADDRESS(MX23_CLKCTRL_BASE_ADDR) -#define DIGCTRL_BASE_ADDR MX23_IO_ADDRESS(MX23_DIGCTL_BASE_ADDR) - -#define PARENT_RATE_SHIFT 8 - -static int _raw_clk_enable(struct clk *clk) -{ - u32 reg; - - if (clk->enable_reg) { - reg = __raw_readl(clk->enable_reg); - reg &= ~(1 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); - } - - return 0; -} - -static void _raw_clk_disable(struct clk *clk) -{ - u32 reg; - - if (clk->enable_reg) { - reg = __raw_readl(clk->enable_reg); - reg |= 1 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - } -} - -/* - * ref_xtal_clk - */ -static unsigned long ref_xtal_clk_get_rate(struct clk *clk) -{ - return 24000000; -} - -static struct clk ref_xtal_clk = { - .get_rate = ref_xtal_clk_get_rate, -}; - -/* - * pll_clk - */ -static unsigned long pll_clk_get_rate(struct clk *clk) -{ - return 480000000; -} - -static int pll_clk_enable(struct clk *clk) -{ - __raw_writel(BM_CLKCTRL_PLLCTRL0_POWER | - BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_PLLCTRL0_SET); - - /* Only a 10us delay is need. PLLCTRL1 LOCK bitfied is only a timer - * and is incorrect (excessive). Per definition of the PLLCTRL0 - * POWER field, waiting at least 10us. - */ - udelay(10); - - return 0; -} - -static void pll_clk_disable(struct clk *clk) -{ - __raw_writel(BM_CLKCTRL_PLLCTRL0_POWER | - BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_PLLCTRL0_CLR); -} - -static struct clk pll_clk = { - .get_rate = pll_clk_get_rate, - .enable = pll_clk_enable, - .disable = pll_clk_disable, - .parent = &ref_xtal_clk, -}; - -/* - * ref_clk - */ -#define _CLK_GET_RATE_REF(name, sr, ss) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - unsigned long parent_rate; \ - u32 reg, div; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##sr); \ - div = (reg >> BP_CLKCTRL_##sr##_##ss##FRAC) & 0x3f; \ - parent_rate = clk_get_rate(clk->parent); \ - \ - return SH_DIV((parent_rate >> PARENT_RATE_SHIFT) * 18, \ - div, PARENT_RATE_SHIFT); \ -} - -_CLK_GET_RATE_REF(ref_cpu_clk, FRAC, CPU) -_CLK_GET_RATE_REF(ref_emi_clk, FRAC, EMI) -_CLK_GET_RATE_REF(ref_pix_clk, FRAC, PIX) -_CLK_GET_RATE_REF(ref_io_clk, FRAC, IO) - -#define _DEFINE_CLOCK_REF(name, er, es) \ - static struct clk name = { \ - .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_##er, \ - .enable_shift = BP_CLKCTRL_##er##_CLKGATE##es, \ - .get_rate = name##_get_rate, \ - .enable = _raw_clk_enable, \ - .disable = _raw_clk_disable, \ - .parent = &pll_clk, \ - } - -_DEFINE_CLOCK_REF(ref_cpu_clk, FRAC, CPU); -_DEFINE_CLOCK_REF(ref_emi_clk, FRAC, EMI); -_DEFINE_CLOCK_REF(ref_pix_clk, FRAC, PIX); -_DEFINE_CLOCK_REF(ref_io_clk, FRAC, IO); - -/* - * General clocks - * - * clk_get_rate - */ -static unsigned long rtc_clk_get_rate(struct clk *clk) -{ - /* ref_xtal_clk is implemented as the only parent */ - return clk_get_rate(clk->parent) / 768; -} - -static unsigned long clk32k_clk_get_rate(struct clk *clk) -{ - return clk->parent->get_rate(clk->parent) / 750; -} - -#define _CLK_GET_RATE(name, rs) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - u32 reg, div; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ - \ - if (clk->parent == &ref_xtal_clk) \ - div = (reg & BM_CLKCTRL_##rs##_DIV_XTAL) >> \ - BP_CLKCTRL_##rs##_DIV_XTAL; \ - else \ - div = (reg & BM_CLKCTRL_##rs##_DIV_##rs) >> \ - BP_CLKCTRL_##rs##_DIV_##rs; \ - \ - if (!div) \ - return -EINVAL; \ - \ - return clk_get_rate(clk->parent) / div; \ -} - -_CLK_GET_RATE(cpu_clk, CPU) -_CLK_GET_RATE(emi_clk, EMI) - -#define _CLK_GET_RATE1(name, rs) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - u32 reg, div; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ - div = (reg & BM_CLKCTRL_##rs##_DIV) >> BP_CLKCTRL_##rs##_DIV; \ - \ - if (!div) \ - return -EINVAL; \ - \ - return clk_get_rate(clk->parent) / div; \ -} - -_CLK_GET_RATE1(hbus_clk, HBUS) -_CLK_GET_RATE1(xbus_clk, XBUS) -_CLK_GET_RATE1(ssp_clk, SSP) -_CLK_GET_RATE1(gpmi_clk, GPMI) -_CLK_GET_RATE1(lcdif_clk, PIX) - -#define _CLK_GET_RATE_STUB(name) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - return clk_get_rate(clk->parent); \ -} - -_CLK_GET_RATE_STUB(uart_clk) -_CLK_GET_RATE_STUB(audio_clk) -_CLK_GET_RATE_STUB(pwm_clk) - -/* - * clk_set_rate - */ -static int cpu_clk_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg, bm_busy, div_max, d, f, div, frac; - unsigned long diff, parent_rate, calc_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->parent == &ref_xtal_clk) { - div_max = BM_CLKCTRL_CPU_DIV_XTAL >> BP_CLKCTRL_CPU_DIV_XTAL; - bm_busy = BM_CLKCTRL_CPU_BUSY_REF_XTAL; - div = DIV_ROUND_UP(parent_rate, rate); - if (div == 0 || div > div_max) - return -EINVAL; - } else { - div_max = BM_CLKCTRL_CPU_DIV_CPU >> BP_CLKCTRL_CPU_DIV_CPU; - bm_busy = BM_CLKCTRL_CPU_BUSY_REF_CPU; - rate >>= PARENT_RATE_SHIFT; - parent_rate >>= PARENT_RATE_SHIFT; - diff = parent_rate; - div = frac = 1; - for (d = 1; d <= div_max; d++) { - f = parent_rate * 18 / d / rate; - if ((parent_rate * 18 / d) % rate) - f++; - if (f < 18 || f > 35) - continue; - - calc_rate = parent_rate * 18 / f / d; - if (calc_rate > rate) - continue; - - if (rate - calc_rate < diff) { - frac = f; - div = d; - diff = rate - calc_rate; - } - - if (diff == 0) - break; - } - - if (diff == parent_rate) - return -EINVAL; - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); - reg &= ~BM_CLKCTRL_FRAC_CPUFRAC; - reg |= frac; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); - } - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); - reg &= ~BM_CLKCTRL_CPU_DIV_CPU; - reg |= div << BP_CLKCTRL_CPU_DIV_CPU; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); - - mxs_clkctrl_timeout(HW_CLKCTRL_CPU, bm_busy); - - return 0; -} - -#define _CLK_SET_RATE(name, dr) \ -static int name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - u32 reg, div_max, div; \ - unsigned long parent_rate; \ - \ - parent_rate = clk_get_rate(clk->parent); \ - div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ - \ - div = DIV_ROUND_UP(parent_rate, rate); \ - if (div == 0 || div > div_max) \ - return -EINVAL; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ - reg &= ~BM_CLKCTRL_##dr##_DIV; \ - reg |= div << BP_CLKCTRL_##dr##_DIV; \ - if (reg & (1 << clk->enable_shift)) { \ - pr_err("%s: clock is gated\n", __func__); \ - return -EINVAL; \ - } \ - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ - \ - mxs_clkctrl_timeout(HW_CLKCTRL_##dr, BM_CLKCTRL_##dr##_BUSY); \ - return 0; \ -} - -_CLK_SET_RATE(xbus_clk, XBUS) -_CLK_SET_RATE(ssp_clk, SSP) -_CLK_SET_RATE(gpmi_clk, GPMI) -_CLK_SET_RATE(lcdif_clk, PIX) - -#define _CLK_SET_RATE_STUB(name) \ -static int name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - return -EINVAL; \ -} - -_CLK_SET_RATE_STUB(emi_clk) -_CLK_SET_RATE_STUB(uart_clk) -_CLK_SET_RATE_STUB(audio_clk) -_CLK_SET_RATE_STUB(pwm_clk) -_CLK_SET_RATE_STUB(clk32k_clk) - -/* - * clk_set_parent - */ -#define _CLK_SET_PARENT(name, bit) \ -static int name##_set_parent(struct clk *clk, struct clk *parent) \ -{ \ - if (parent != clk->parent) { \ - __raw_writel(BM_CLKCTRL_CLKSEQ_BYPASS_##bit, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ_TOG); \ - clk->parent = parent; \ - } \ - \ - return 0; \ -} - -_CLK_SET_PARENT(cpu_clk, CPU) -_CLK_SET_PARENT(emi_clk, EMI) -_CLK_SET_PARENT(ssp_clk, SSP) -_CLK_SET_PARENT(gpmi_clk, GPMI) -_CLK_SET_PARENT(lcdif_clk, PIX) - -#define _CLK_SET_PARENT_STUB(name) \ -static int name##_set_parent(struct clk *clk, struct clk *parent) \ -{ \ - if (parent != clk->parent) \ - return -EINVAL; \ - else \ - return 0; \ -} - -_CLK_SET_PARENT_STUB(uart_clk) -_CLK_SET_PARENT_STUB(audio_clk) -_CLK_SET_PARENT_STUB(pwm_clk) -_CLK_SET_PARENT_STUB(clk32k_clk) - -/* - * clk definition - */ -static struct clk cpu_clk = { - .get_rate = cpu_clk_get_rate, - .set_rate = cpu_clk_set_rate, - .set_parent = cpu_clk_set_parent, - .parent = &ref_cpu_clk, -}; - -static struct clk hbus_clk = { - .get_rate = hbus_clk_get_rate, - .parent = &cpu_clk, -}; - -static struct clk xbus_clk = { - .get_rate = xbus_clk_get_rate, - .set_rate = xbus_clk_set_rate, - .parent = &ref_xtal_clk, -}; - -static struct clk rtc_clk = { - .get_rate = rtc_clk_get_rate, - .parent = &ref_xtal_clk, -}; - -/* usb_clk gate is controlled in DIGCTRL other than CLKCTRL */ -static struct clk usb_clk = { - .enable_reg = DIGCTRL_BASE_ADDR, - .enable_shift = 2, - .enable = _raw_clk_enable, - .disable = _raw_clk_disable, - .parent = &pll_clk, -}; - -#define _DEFINE_CLOCK(name, er, es, p) \ - static struct clk name = { \ - .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_##er, \ - .enable_shift = BP_CLKCTRL_##er##_##es, \ - .get_rate = name##_get_rate, \ - .set_rate = name##_set_rate, \ - .set_parent = name##_set_parent, \ - .enable = _raw_clk_enable, \ - .disable = _raw_clk_disable, \ - .parent = p, \ - } - -_DEFINE_CLOCK(emi_clk, EMI, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(ssp_clk, SSP, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(gpmi_clk, GPMI, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(lcdif_clk, PIX, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(uart_clk, XTAL, UART_CLK_GATE, &ref_xtal_clk); -_DEFINE_CLOCK(audio_clk, XTAL, FILT_CLK24M_GATE, &ref_xtal_clk); -_DEFINE_CLOCK(pwm_clk, XTAL, PWM_CLK24M_GATE, &ref_xtal_clk); -_DEFINE_CLOCK(clk32k_clk, XTAL, TIMROT_CLK32K_GATE, &ref_xtal_clk); - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup lookups[] = { - /* for amba bus driver */ - _REGISTER_CLOCK("duart", "apb_pclk", xbus_clk) - /* for amba-pl011 driver */ - _REGISTER_CLOCK("duart", NULL, uart_clk) - _REGISTER_CLOCK("mxs-auart.0", NULL, uart_clk) - _REGISTER_CLOCK("rtc", NULL, rtc_clk) - _REGISTER_CLOCK("mxs-dma-apbh", NULL, hbus_clk) - _REGISTER_CLOCK("mxs-dma-apbx", NULL, xbus_clk) - _REGISTER_CLOCK("mxs-mmc.0", NULL, ssp_clk) - _REGISTER_CLOCK("mxs-mmc.1", NULL, ssp_clk) - _REGISTER_CLOCK(NULL, "usb", usb_clk) - _REGISTER_CLOCK(NULL, "audio", audio_clk) - _REGISTER_CLOCK("mxs-pwm.0", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.1", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.2", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.3", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.4", NULL, pwm_clk) - _REGISTER_CLOCK("imx23-fb", NULL, lcdif_clk) - _REGISTER_CLOCK("imx23-gpmi-nand", NULL, gpmi_clk) -}; - -static int clk_misc_init(void) -{ - u32 reg; - int ret; - - /* Fix up parent per register setting */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ); - cpu_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_CPU) ? - &ref_xtal_clk : &ref_cpu_clk; - emi_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_EMI) ? - &ref_xtal_clk : &ref_emi_clk; - ssp_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP) ? - &ref_xtal_clk : &ref_io_clk; - gpmi_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_GPMI) ? - &ref_xtal_clk : &ref_io_clk; - lcdif_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_PIX) ? - &ref_xtal_clk : &ref_pix_clk; - - /* Use int div over frac when both are available */ - __raw_writel(BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_CLR); - __raw_writel(BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_CLR); - __raw_writel(BM_CLKCTRL_HBUS_DIV_FRAC_EN, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS); - reg &= ~BM_CLKCTRL_XBUS_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP); - reg &= ~BM_CLKCTRL_SSP_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI); - reg &= ~BM_CLKCTRL_GPMI_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_PIX); - reg &= ~BM_CLKCTRL_PIX_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_PIX); - - /* - * Set safe hbus clock divider. A divider of 3 ensure that - * the Vddd voltage required for the cpu clock is sufficiently - * high for the hbus clock. - */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - reg &= BM_CLKCTRL_HBUS_DIV; - reg |= 3 << BP_CLKCTRL_HBUS_DIV; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - - ret = mxs_clkctrl_timeout(HW_CLKCTRL_HBUS, BM_CLKCTRL_HBUS_BUSY); - - /* Gate off cpu clock in WFI for power saving */ - __raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_SET); - - /* - * 480 MHz seems too high to be ssp clock source directly, - * so set frac to get a 288 MHz ref_io. - */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); - reg &= ~BM_CLKCTRL_FRAC_IOFRAC; - reg |= 30 << BP_CLKCTRL_FRAC_IOFRAC; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); - - return ret; -} - -int __init mx23_clocks_init(void) -{ - clk_misc_init(); - - /* - * source ssp clock from ref_io than ref_xtal, - * as ref_xtal only provides 24 MHz as maximum. - */ - clk_set_parent(&ssp_clk, &ref_io_clk); - - clk_prepare_enable(&cpu_clk); - clk_prepare_enable(&hbus_clk); - clk_prepare_enable(&xbus_clk); - clk_prepare_enable(&emi_clk); - clk_prepare_enable(&uart_clk); - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - mxs_timer_init(&clk32k_clk, MX23_INT_TIMER0); - - return 0; -} diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c deleted file mode 100644 index cea29c99e214..000000000000 --- a/arch/arm/mach-mxs/clock-mx28.c +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * - * 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 <linux/mm.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/jiffies.h> -#include <linux/clkdev.h> -#include <linux/spinlock.h> - -#include <asm/clkdev.h> -#include <asm/div64.h> - -#include <mach/mx28.h> -#include <mach/common.h> -#include <mach/clock.h> -#include <mach/digctl.h> - -#include "regs-clkctrl-mx28.h" - -#define CLKCTRL_BASE_ADDR MX28_IO_ADDRESS(MX28_CLKCTRL_BASE_ADDR) -#define DIGCTRL_BASE_ADDR MX28_IO_ADDRESS(MX28_DIGCTL_BASE_ADDR) - -#define PARENT_RATE_SHIFT 8 - -static struct clk pll2_clk; -static struct clk cpu_clk; -static struct clk emi_clk; -static struct clk saif0_clk; -static struct clk saif1_clk; -static struct clk clk32k_clk; -static DEFINE_SPINLOCK(clkmux_lock); - -/* - * HW_SAIF_CLKMUX_SEL: - * DIRECT(0x0): SAIF0 clock pins selected for SAIF0 input clocks, and SAIF1 - * clock pins selected for SAIF1 input clocks. - * CROSSINPUT(0x1): SAIF1 clock inputs selected for SAIF0 input clocks, and - * SAIF0 clock inputs selected for SAIF1 input clocks. - * EXTMSTR0(0x2): SAIF0 clock pin selected for both SAIF0 and SAIF1 input - * clocks. - * EXTMSTR1(0x3): SAIF1 clock pin selected for both SAIF0 and SAIF1 input - * clocks. - */ -int mxs_saif_clkmux_select(unsigned int clkmux) -{ - if (clkmux > 0x3) - return -EINVAL; - - spin_lock(&clkmux_lock); - __raw_writel(BM_DIGCTL_CTRL_SAIF_CLKMUX, - DIGCTRL_BASE_ADDR + HW_DIGCTL_CTRL + MXS_CLR_ADDR); - __raw_writel(clkmux << BP_DIGCTL_CTRL_SAIF_CLKMUX, - DIGCTRL_BASE_ADDR + HW_DIGCTL_CTRL + MXS_SET_ADDR); - spin_unlock(&clkmux_lock); - - return 0; -} - -static int _raw_clk_enable(struct clk *clk) -{ - u32 reg; - - if (clk->enable_reg) { - reg = __raw_readl(clk->enable_reg); - reg &= ~(1 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); - } - - return 0; -} - -static void _raw_clk_disable(struct clk *clk) -{ - u32 reg; - - if (clk->enable_reg) { - reg = __raw_readl(clk->enable_reg); - reg |= 1 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - } -} - -/* - * ref_xtal_clk - */ -static unsigned long ref_xtal_clk_get_rate(struct clk *clk) -{ - return 24000000; -} - -static struct clk ref_xtal_clk = { - .get_rate = ref_xtal_clk_get_rate, -}; - -/* - * pll_clk - */ -static unsigned long pll0_clk_get_rate(struct clk *clk) -{ - return 480000000; -} - -static unsigned long pll1_clk_get_rate(struct clk *clk) -{ - return 480000000; -} - -static unsigned long pll2_clk_get_rate(struct clk *clk) -{ - return 50000000; -} - -#define _CLK_ENABLE_PLL(name, r, g) \ -static int name##_enable(struct clk *clk) \ -{ \ - __raw_writel(BM_CLKCTRL_##r##CTRL0_POWER, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_##r##CTRL0_SET); \ - udelay(10); \ - \ - if (clk == &pll2_clk) \ - __raw_writel(BM_CLKCTRL_##r##CTRL0_##g, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_##r##CTRL0_CLR); \ - else \ - __raw_writel(BM_CLKCTRL_##r##CTRL0_##g, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_##r##CTRL0_SET); \ - \ - return 0; \ -} - -_CLK_ENABLE_PLL(pll0_clk, PLL0, EN_USB_CLKS) -_CLK_ENABLE_PLL(pll1_clk, PLL1, EN_USB_CLKS) -_CLK_ENABLE_PLL(pll2_clk, PLL2, CLKGATE) - -#define _CLK_DISABLE_PLL(name, r, g) \ -static void name##_disable(struct clk *clk) \ -{ \ - __raw_writel(BM_CLKCTRL_##r##CTRL0_POWER, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_##r##CTRL0_CLR); \ - \ - if (clk == &pll2_clk) \ - __raw_writel(BM_CLKCTRL_##r##CTRL0_##g, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_##r##CTRL0_SET); \ - else \ - __raw_writel(BM_CLKCTRL_##r##CTRL0_##g, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_##r##CTRL0_CLR); \ - \ -} - -_CLK_DISABLE_PLL(pll0_clk, PLL0, EN_USB_CLKS) -_CLK_DISABLE_PLL(pll1_clk, PLL1, EN_USB_CLKS) -_CLK_DISABLE_PLL(pll2_clk, PLL2, CLKGATE) - -#define _DEFINE_CLOCK_PLL(name) \ - static struct clk name = { \ - .get_rate = name##_get_rate, \ - .enable = name##_enable, \ - .disable = name##_disable, \ - .parent = &ref_xtal_clk, \ - } - -_DEFINE_CLOCK_PLL(pll0_clk); -_DEFINE_CLOCK_PLL(pll1_clk); -_DEFINE_CLOCK_PLL(pll2_clk); - -/* - * ref_clk - */ -#define _CLK_GET_RATE_REF(name, sr, ss) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - unsigned long parent_rate; \ - u32 reg, div; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##sr); \ - div = (reg >> BP_CLKCTRL_##sr##_##ss##FRAC) & 0x3f; \ - parent_rate = clk_get_rate(clk->parent); \ - \ - return SH_DIV((parent_rate >> PARENT_RATE_SHIFT) * 18, \ - div, PARENT_RATE_SHIFT); \ -} - -_CLK_GET_RATE_REF(ref_cpu_clk, FRAC0, CPU) -_CLK_GET_RATE_REF(ref_emi_clk, FRAC0, EMI) -_CLK_GET_RATE_REF(ref_io0_clk, FRAC0, IO0) -_CLK_GET_RATE_REF(ref_io1_clk, FRAC0, IO1) -_CLK_GET_RATE_REF(ref_pix_clk, FRAC1, PIX) -_CLK_GET_RATE_REF(ref_gpmi_clk, FRAC1, GPMI) - -#define _DEFINE_CLOCK_REF(name, er, es) \ - static struct clk name = { \ - .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_##er, \ - .enable_shift = BP_CLKCTRL_##er##_CLKGATE##es, \ - .get_rate = name##_get_rate, \ - .enable = _raw_clk_enable, \ - .disable = _raw_clk_disable, \ - .parent = &pll0_clk, \ - } - -_DEFINE_CLOCK_REF(ref_cpu_clk, FRAC0, CPU); -_DEFINE_CLOCK_REF(ref_emi_clk, FRAC0, EMI); -_DEFINE_CLOCK_REF(ref_io0_clk, FRAC0, IO0); -_DEFINE_CLOCK_REF(ref_io1_clk, FRAC0, IO1); -_DEFINE_CLOCK_REF(ref_pix_clk, FRAC1, PIX); -_DEFINE_CLOCK_REF(ref_gpmi_clk, FRAC1, GPMI); - -/* - * General clocks - * - * clk_get_rate - */ -static unsigned long lradc_clk_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 16; -} - -static unsigned long rtc_clk_get_rate(struct clk *clk) -{ - /* ref_xtal_clk is implemented as the only parent */ - return clk_get_rate(clk->parent) / 768; -} - -static unsigned long clk32k_clk_get_rate(struct clk *clk) -{ - return clk->parent->get_rate(clk->parent) / 750; -} - -static unsigned long spdif_clk_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 4; -} - -#define _CLK_GET_RATE(name, rs) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - u32 reg, div; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ - \ - if (clk->parent == &ref_xtal_clk) \ - div = (reg & BM_CLKCTRL_##rs##_DIV_XTAL) >> \ - BP_CLKCTRL_##rs##_DIV_XTAL; \ - else \ - div = (reg & BM_CLKCTRL_##rs##_DIV_##rs) >> \ - BP_CLKCTRL_##rs##_DIV_##rs; \ - \ - if (!div) \ - return -EINVAL; \ - \ - return clk_get_rate(clk->parent) / div; \ -} - -_CLK_GET_RATE(cpu_clk, CPU) -_CLK_GET_RATE(emi_clk, EMI) - -#define _CLK_GET_RATE1(name, rs) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - u32 reg, div; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ - div = (reg & BM_CLKCTRL_##rs##_DIV) >> BP_CLKCTRL_##rs##_DIV; \ - \ - if (!div) \ - return -EINVAL; \ - \ - if (clk == &saif0_clk || clk == &saif1_clk) \ - return clk_get_rate(clk->parent) >> 16 * div; \ - else \ - return clk_get_rate(clk->parent) / div; \ -} - -_CLK_GET_RATE1(hbus_clk, HBUS) -_CLK_GET_RATE1(xbus_clk, XBUS) -_CLK_GET_RATE1(ssp0_clk, SSP0) -_CLK_GET_RATE1(ssp1_clk, SSP1) -_CLK_GET_RATE1(ssp2_clk, SSP2) -_CLK_GET_RATE1(ssp3_clk, SSP3) -_CLK_GET_RATE1(gpmi_clk, GPMI) -_CLK_GET_RATE1(lcdif_clk, DIS_LCDIF) -_CLK_GET_RATE1(saif0_clk, SAIF0) -_CLK_GET_RATE1(saif1_clk, SAIF1) - -#define _CLK_GET_RATE_STUB(name) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - return clk_get_rate(clk->parent); \ -} - -_CLK_GET_RATE_STUB(uart_clk) -_CLK_GET_RATE_STUB(pwm_clk) -_CLK_GET_RATE_STUB(can0_clk) -_CLK_GET_RATE_STUB(can1_clk) -_CLK_GET_RATE_STUB(fec_clk) - -/* - * clk_set_rate - */ -/* fool compiler */ -#define BM_CLKCTRL_CPU_DIV 0 -#define BP_CLKCTRL_CPU_DIV 0 -#define BM_CLKCTRL_CPU_BUSY 0 - -#define _CLK_SET_RATE(name, dr, fr, fs) \ -static int name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - u32 reg, bm_busy, div_max, d, f, div, frac; \ - unsigned long diff, parent_rate, calc_rate; \ - \ - div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ - bm_busy = BM_CLKCTRL_##dr##_BUSY; \ - \ - if (clk->parent == &ref_xtal_clk) { \ - parent_rate = clk_get_rate(clk->parent); \ - div = DIV_ROUND_UP(parent_rate, rate); \ - if (clk == &cpu_clk) { \ - div_max = BM_CLKCTRL_CPU_DIV_XTAL >> \ - BP_CLKCTRL_CPU_DIV_XTAL; \ - bm_busy = BM_CLKCTRL_CPU_BUSY_REF_XTAL; \ - } \ - if (div == 0 || div > div_max) \ - return -EINVAL; \ - } else { \ - /* \ - * hack alert: this block modifies clk->parent, too, \ - * so the base to use it the grand parent. \ - */ \ - parent_rate = clk_get_rate(clk->parent->parent); \ - rate >>= PARENT_RATE_SHIFT; \ - parent_rate >>= PARENT_RATE_SHIFT; \ - diff = parent_rate; \ - div = frac = 1; \ - if (clk == &cpu_clk) { \ - div_max = BM_CLKCTRL_CPU_DIV_CPU >> \ - BP_CLKCTRL_CPU_DIV_CPU; \ - bm_busy = BM_CLKCTRL_CPU_BUSY_REF_CPU; \ - } \ - for (d = 1; d <= div_max; d++) { \ - f = parent_rate * 18 / d / rate; \ - if ((parent_rate * 18 / d) % rate) \ - f++; \ - if (f < 18 || f > 35) \ - continue; \ - \ - calc_rate = parent_rate * 18 / f / d; \ - if (calc_rate > rate) \ - continue; \ - \ - if (rate - calc_rate < diff) { \ - frac = f; \ - div = d; \ - diff = rate - calc_rate; \ - } \ - \ - if (diff == 0) \ - break; \ - } \ - \ - if (diff == parent_rate) \ - return -EINVAL; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##fr); \ - reg &= ~BM_CLKCTRL_##fr##_##fs##FRAC; \ - reg |= frac << BP_CLKCTRL_##fr##_##fs##FRAC; \ - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##fr); \ - } \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ - if (clk == &cpu_clk) { \ - reg &= ~BM_CLKCTRL_CPU_DIV_CPU; \ - reg |= div << BP_CLKCTRL_CPU_DIV_CPU; \ - } else { \ - reg &= ~BM_CLKCTRL_##dr##_DIV; \ - reg |= div << BP_CLKCTRL_##dr##_DIV; \ - if (reg & (1 << clk->enable_shift)) { \ - pr_err("%s: clock is gated\n", __func__); \ - return -EINVAL; \ - } \ - } \ - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ - \ - return mxs_clkctrl_timeout(HW_CLKCTRL_##dr, bm_busy); \ -} - -_CLK_SET_RATE(cpu_clk, CPU, FRAC0, CPU) -_CLK_SET_RATE(ssp0_clk, SSP0, FRAC0, IO0) -_CLK_SET_RATE(ssp1_clk, SSP1, FRAC0, IO0) -_CLK_SET_RATE(ssp2_clk, SSP2, FRAC0, IO1) -_CLK_SET_RATE(ssp3_clk, SSP3, FRAC0, IO1) -_CLK_SET_RATE(lcdif_clk, DIS_LCDIF, FRAC1, PIX) -_CLK_SET_RATE(gpmi_clk, GPMI, FRAC1, GPMI) - -#define _CLK_SET_RATE1(name, dr) \ -static int name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - u32 reg, div_max, div; \ - unsigned long parent_rate; \ - \ - parent_rate = clk_get_rate(clk->parent); \ - div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ - \ - div = DIV_ROUND_UP(parent_rate, rate); \ - if (div == 0 || div > div_max) \ - return -EINVAL; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ - reg &= ~BM_CLKCTRL_##dr##_DIV; \ - reg |= div << BP_CLKCTRL_##dr##_DIV; \ - if (reg & (1 << clk->enable_shift)) { \ - pr_err("%s: clock is gated\n", __func__); \ - return -EINVAL; \ - } \ - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ - \ - return mxs_clkctrl_timeout(HW_CLKCTRL_##dr, BM_CLKCTRL_##dr##_BUSY);\ -} - -_CLK_SET_RATE1(xbus_clk, XBUS) - -/* saif clock uses 16 bits frac div */ -#define _CLK_SET_RATE_SAIF(name, rs) \ -static int name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - u16 div; \ - u32 reg; \ - u64 lrate; \ - unsigned long parent_rate; \ - \ - parent_rate = clk_get_rate(clk->parent); \ - if (rate > parent_rate) \ - return -EINVAL; \ - \ - lrate = (u64)rate << 16; \ - do_div(lrate, parent_rate); \ - div = (u16)lrate; \ - \ - if (!div) \ - return -EINVAL; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ - reg &= ~BM_CLKCTRL_##rs##_DIV; \ - reg |= div << BP_CLKCTRL_##rs##_DIV; \ - if (reg & (1 << clk->enable_shift)) { \ - pr_err("%s: clock is gated\n", __func__); \ - return -EINVAL; \ - } \ - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ - \ - return mxs_clkctrl_timeout(HW_CLKCTRL_##rs, BM_CLKCTRL_##rs##_BUSY);\ -} - -_CLK_SET_RATE_SAIF(saif0_clk, SAIF0) -_CLK_SET_RATE_SAIF(saif1_clk, SAIF1) - -#define _CLK_SET_RATE_STUB(name) \ -static int name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - return -EINVAL; \ -} - -_CLK_SET_RATE_STUB(emi_clk) -_CLK_SET_RATE_STUB(uart_clk) -_CLK_SET_RATE_STUB(pwm_clk) -_CLK_SET_RATE_STUB(spdif_clk) -_CLK_SET_RATE_STUB(clk32k_clk) -_CLK_SET_RATE_STUB(can0_clk) -_CLK_SET_RATE_STUB(can1_clk) -_CLK_SET_RATE_STUB(fec_clk) - -/* - * clk_set_parent - */ -#define _CLK_SET_PARENT(name, bit) \ -static int name##_set_parent(struct clk *clk, struct clk *parent) \ -{ \ - if (parent != clk->parent) { \ - __raw_writel(BM_CLKCTRL_CLKSEQ_BYPASS_##bit, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ_TOG); \ - clk->parent = parent; \ - } \ - \ - return 0; \ -} - -_CLK_SET_PARENT(cpu_clk, CPU) -_CLK_SET_PARENT(emi_clk, EMI) -_CLK_SET_PARENT(ssp0_clk, SSP0) -_CLK_SET_PARENT(ssp1_clk, SSP1) -_CLK_SET_PARENT(ssp2_clk, SSP2) -_CLK_SET_PARENT(ssp3_clk, SSP3) -_CLK_SET_PARENT(lcdif_clk, DIS_LCDIF) -_CLK_SET_PARENT(gpmi_clk, GPMI) -_CLK_SET_PARENT(saif0_clk, SAIF0) -_CLK_SET_PARENT(saif1_clk, SAIF1) - -#define _CLK_SET_PARENT_STUB(name) \ -static int name##_set_parent(struct clk *clk, struct clk *parent) \ -{ \ - if (parent != clk->parent) \ - return -EINVAL; \ - else \ - return 0; \ -} - -_CLK_SET_PARENT_STUB(pwm_clk) -_CLK_SET_PARENT_STUB(uart_clk) -_CLK_SET_PARENT_STUB(clk32k_clk) -_CLK_SET_PARENT_STUB(spdif_clk) -_CLK_SET_PARENT_STUB(fec_clk) -_CLK_SET_PARENT_STUB(can0_clk) -_CLK_SET_PARENT_STUB(can1_clk) - -/* - * clk definition - */ -static struct clk cpu_clk = { - .get_rate = cpu_clk_get_rate, - .set_rate = cpu_clk_set_rate, - .set_parent = cpu_clk_set_parent, - .parent = &ref_cpu_clk, -}; - -static struct clk hbus_clk = { - .get_rate = hbus_clk_get_rate, - .parent = &cpu_clk, -}; - -static struct clk xbus_clk = { - .get_rate = xbus_clk_get_rate, - .set_rate = xbus_clk_set_rate, - .parent = &ref_xtal_clk, -}; - -static struct clk lradc_clk = { - .get_rate = lradc_clk_get_rate, - .parent = &clk32k_clk, -}; - -static struct clk rtc_clk = { - .get_rate = rtc_clk_get_rate, - .parent = &ref_xtal_clk, -}; - -/* usb_clk gate is controlled in DIGCTRL other than CLKCTRL */ -static struct clk usb0_clk = { - .enable_reg = DIGCTRL_BASE_ADDR, - .enable_shift = 2, - .enable = _raw_clk_enable, - .disable = _raw_clk_disable, - .parent = &pll0_clk, -}; - -static struct clk usb1_clk = { - .enable_reg = DIGCTRL_BASE_ADDR, - .enable_shift = 16, - .enable = _raw_clk_enable, - .disable = _raw_clk_disable, - .parent = &pll1_clk, -}; - -#define _DEFINE_CLOCK(name, er, es, p) \ - static struct clk name = { \ - .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_##er, \ - .enable_shift = BP_CLKCTRL_##er##_##es, \ - .get_rate = name##_get_rate, \ - .set_rate = name##_set_rate, \ - .set_parent = name##_set_parent, \ - .enable = _raw_clk_enable, \ - .disable = _raw_clk_disable, \ - .parent = p, \ - } - -_DEFINE_CLOCK(emi_clk, EMI, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(ssp0_clk, SSP0, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(ssp1_clk, SSP1, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(ssp2_clk, SSP2, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(ssp3_clk, SSP3, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(lcdif_clk, DIS_LCDIF, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(gpmi_clk, GPMI, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(saif0_clk, SAIF0, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(saif1_clk, SAIF1, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(can0_clk, FLEXCAN, STOP_CAN0, &ref_xtal_clk); -_DEFINE_CLOCK(can1_clk, FLEXCAN, STOP_CAN1, &ref_xtal_clk); -_DEFINE_CLOCK(pwm_clk, XTAL, PWM_CLK24M_GATE, &ref_xtal_clk); -_DEFINE_CLOCK(uart_clk, XTAL, UART_CLK_GATE, &ref_xtal_clk); -_DEFINE_CLOCK(clk32k_clk, XTAL, TIMROT_CLK32K_GATE, &ref_xtal_clk); -_DEFINE_CLOCK(spdif_clk, SPDIF, CLKGATE, &pll0_clk); -_DEFINE_CLOCK(fec_clk, ENET, DISABLE, &hbus_clk); - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup lookups[] = { - /* for amba bus driver */ - _REGISTER_CLOCK("duart", "apb_pclk", xbus_clk) - /* for amba-pl011 driver */ - _REGISTER_CLOCK("duart", NULL, uart_clk) - _REGISTER_CLOCK("imx28-fec.0", NULL, fec_clk) - _REGISTER_CLOCK("imx28-fec.1", NULL, fec_clk) - _REGISTER_CLOCK("imx28-gpmi-nand", NULL, gpmi_clk) - _REGISTER_CLOCK("mxs-auart.0", NULL, uart_clk) - _REGISTER_CLOCK("mxs-auart.1", NULL, uart_clk) - _REGISTER_CLOCK("mxs-auart.2", NULL, uart_clk) - _REGISTER_CLOCK("mxs-auart.3", NULL, uart_clk) - _REGISTER_CLOCK("mxs-auart.4", NULL, uart_clk) - _REGISTER_CLOCK("rtc", NULL, rtc_clk) - _REGISTER_CLOCK("pll2", NULL, pll2_clk) - _REGISTER_CLOCK("mxs-dma-apbh", NULL, hbus_clk) - _REGISTER_CLOCK("mxs-dma-apbx", NULL, xbus_clk) - _REGISTER_CLOCK("mxs-mmc.0", NULL, ssp0_clk) - _REGISTER_CLOCK("mxs-mmc.1", NULL, ssp1_clk) - _REGISTER_CLOCK("mxs-mmc.2", NULL, ssp2_clk) - _REGISTER_CLOCK("mxs-mmc.3", NULL, ssp3_clk) - _REGISTER_CLOCK("flexcan.0", NULL, can0_clk) - _REGISTER_CLOCK("flexcan.1", NULL, can1_clk) - _REGISTER_CLOCK(NULL, "usb0", usb0_clk) - _REGISTER_CLOCK(NULL, "usb1", usb1_clk) - _REGISTER_CLOCK("mxs-pwm.0", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.1", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.2", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.3", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.4", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.5", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.6", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.7", NULL, pwm_clk) - _REGISTER_CLOCK(NULL, "lradc", lradc_clk) - _REGISTER_CLOCK(NULL, "spdif", spdif_clk) - _REGISTER_CLOCK("imx28-fb", NULL, lcdif_clk) - _REGISTER_CLOCK("mxs-saif.0", NULL, saif0_clk) - _REGISTER_CLOCK("mxs-saif.1", NULL, saif1_clk) -}; - -static int clk_misc_init(void) -{ - u32 reg; - int ret; - - /* Fix up parent per register setting */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ); - cpu_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_CPU) ? - &ref_xtal_clk : &ref_cpu_clk; - emi_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_EMI) ? - &ref_xtal_clk : &ref_emi_clk; - ssp0_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP0) ? - &ref_xtal_clk : &ref_io0_clk; - ssp1_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP1) ? - &ref_xtal_clk : &ref_io0_clk; - ssp2_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP2) ? - &ref_xtal_clk : &ref_io1_clk; - ssp3_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP3) ? - &ref_xtal_clk : &ref_io1_clk; - lcdif_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF) ? - &ref_xtal_clk : &ref_pix_clk; - gpmi_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_GPMI) ? - &ref_xtal_clk : &ref_gpmi_clk; - saif0_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SAIF0) ? - &ref_xtal_clk : &pll0_clk; - saif1_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SAIF1) ? - &ref_xtal_clk : &pll0_clk; - - /* Use int div over frac when both are available */ - __raw_writel(BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_CLR); - __raw_writel(BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_CLR); - __raw_writel(BM_CLKCTRL_HBUS_DIV_FRAC_EN, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS); - reg &= ~BM_CLKCTRL_XBUS_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP0); - reg &= ~BM_CLKCTRL_SSP0_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP0); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP1); - reg &= ~BM_CLKCTRL_SSP1_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP1); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP2); - reg &= ~BM_CLKCTRL_SSP2_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP2); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP3); - reg &= ~BM_CLKCTRL_SSP3_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP3); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI); - reg &= ~BM_CLKCTRL_GPMI_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_DIS_LCDIF); - reg &= ~BM_CLKCTRL_DIS_LCDIF_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_DIS_LCDIF); - - /* SAIF has to use frac div for functional operation */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF0); - reg |= BM_CLKCTRL_SAIF0_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF0); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF1); - reg |= BM_CLKCTRL_SAIF1_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF1); - - /* - * Set safe hbus clock divider. A divider of 3 ensure that - * the Vddd voltage required for the cpu clock is sufficiently - * high for the hbus clock. - */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - reg &= BM_CLKCTRL_HBUS_DIV; - reg |= 3 << BP_CLKCTRL_HBUS_DIV; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - - ret = mxs_clkctrl_timeout(HW_CLKCTRL_HBUS, BM_CLKCTRL_HBUS_ASM_BUSY); - - /* Gate off cpu clock in WFI for power saving */ - __raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_SET); - - /* - * Extra fec clock setting - * The DENX M28 uses an external clock source - * and the clock output must not be enabled - */ - if (!machine_is_m28evk()) { - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_ENET); - reg &= ~BM_CLKCTRL_ENET_SLEEP; - reg |= BM_CLKCTRL_ENET_CLK_OUT_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_ENET); - } - - /* - * 480 MHz seems too high to be ssp clock source directly, - * so set frac0 to get a 288 MHz ref_io0. - */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0); - reg &= ~BM_CLKCTRL_FRAC0_IO0FRAC; - reg |= 30 << BP_CLKCTRL_FRAC0_IO0FRAC; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0); - - return ret; -} - -int __init mx28_clocks_init(void) -{ - clk_misc_init(); - - /* - * source ssp clock from ref_io0 than ref_xtal, - * as ref_xtal only provides 24 MHz as maximum. - */ - clk_set_parent(&ssp0_clk, &ref_io0_clk); - clk_set_parent(&ssp1_clk, &ref_io0_clk); - clk_set_parent(&ssp2_clk, &ref_io1_clk); - clk_set_parent(&ssp3_clk, &ref_io1_clk); - - clk_prepare_enable(&cpu_clk); - clk_prepare_enable(&hbus_clk); - clk_prepare_enable(&xbus_clk); - clk_prepare_enable(&emi_clk); - clk_prepare_enable(&uart_clk); - - clk_set_parent(&lcdif_clk, &ref_pix_clk); - clk_set_parent(&saif0_clk, &pll0_clk); - clk_set_parent(&saif1_clk, &pll0_clk); - - /* - * Set an initial clock rate for the saif internal logic to work - * properly. This is important when working in EXTMASTER mode that - * uses the other saif's BITCLK&LRCLK but it still needs a basic - * clock which should be fast enough for the internal logic. - */ - clk_set_rate(&saif0_clk, 24000000); - clk_set_rate(&saif1_clk, 24000000); - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - mxs_timer_init(&clk32k_clk, MX28_INT_TIMER0); - - return 0; -} diff --git a/arch/arm/mach-mxs/clock.c b/arch/arm/mach-mxs/clock.c deleted file mode 100644 index 97a6f4acc6cc..000000000000 --- a/arch/arm/mach-mxs/clock.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Based on arch/arm/plat-omap/clock.c - * - * Copyright (C) 2004 - 2005 Nokia corporation - * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> - * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> - * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright 2008 Juergen Beisert, 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, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -/* #define DEBUG */ - -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> -#include <linux/proc_fs.h> -#include <linux/semaphore.h> -#include <linux/string.h> - -#include <mach/clock.h> - -static LIST_HEAD(clocks); -static DEFINE_MUTEX(clocks_mutex); - -/*------------------------------------------------------------------------- - * Standard clock functions defined in include/linux/clk.h - *-------------------------------------------------------------------------*/ - -static void __clk_disable(struct clk *clk) -{ - if (clk == NULL || IS_ERR(clk)) - return; - WARN_ON(!clk->usecount); - - if (!(--clk->usecount)) { - if (clk->disable) - clk->disable(clk); - __clk_disable(clk->parent); - } -} - -static int __clk_enable(struct clk *clk) -{ - if (clk == NULL || IS_ERR(clk)) - return -EINVAL; - - if (clk->usecount++ == 0) { - __clk_enable(clk->parent); - - if (clk->enable) - clk->enable(clk); - } - return 0; -} - -/* - * The clk_enable/clk_disable could be called by drivers in atomic context, - * so they should not really hold mutex. Instead, clk_prepare/clk_unprepare - * can hold a mutex, as the pair will only be called in non-atomic context. - * Before migrating to common clk framework, we can have __clk_enable and - * __clk_disable called in clk_prepare/clk_unprepare with mutex held and - * leave clk_enable/clk_disable as the dummy functions. - */ -int clk_prepare(struct clk *clk) -{ - int ret = 0; - - if (clk == NULL || IS_ERR(clk)) - return -EINVAL; - - mutex_lock(&clocks_mutex); - ret = __clk_enable(clk); - mutex_unlock(&clocks_mutex); - - return ret; -} -EXPORT_SYMBOL(clk_prepare); - -void clk_unprepare(struct clk *clk) -{ - if (clk == NULL || IS_ERR(clk)) - return; - - mutex_lock(&clocks_mutex); - __clk_disable(clk); - mutex_unlock(&clocks_mutex); -} -EXPORT_SYMBOL(clk_unprepare); - -int clk_enable(struct clk *clk) -{ - return 0; -} -EXPORT_SYMBOL(clk_enable); - -void clk_disable(struct clk *clk) -{ - /* nothing to do */ -} -EXPORT_SYMBOL(clk_disable); - -/* Retrieve the *current* clock rate. If the clock itself - * does not provide a special calculation routine, ask - * its parent and so on, until one is able to return - * a valid clock rate - */ -unsigned long clk_get_rate(struct clk *clk) -{ - if (clk == NULL || IS_ERR(clk)) - return 0UL; - - if (clk->get_rate) - return clk->get_rate(clk); - - return clk_get_rate(clk->parent); -} -EXPORT_SYMBOL(clk_get_rate); - -/* Round the requested clock rate to the nearest supported - * rate that is less than or equal to the requested rate. - * This is dependent on the clock's current parent. - */ -long clk_round_rate(struct clk *clk, unsigned long rate) -{ - if (clk == NULL || IS_ERR(clk) || !clk->round_rate) - return 0; - - return clk->round_rate(clk, rate); -} -EXPORT_SYMBOL(clk_round_rate); - -/* Set the clock to the requested clock rate. The rate must - * match a supported rate exactly based on what clk_round_rate returns - */ -int clk_set_rate(struct clk *clk, unsigned long rate) -{ - int ret = -EINVAL; - - if (clk == NULL || IS_ERR(clk) || clk->set_rate == NULL || rate == 0) - return ret; - - mutex_lock(&clocks_mutex); - ret = clk->set_rate(clk, rate); - mutex_unlock(&clocks_mutex); - - return ret; -} -EXPORT_SYMBOL(clk_set_rate); - -/* Set the clock's parent to another clock source */ -int clk_set_parent(struct clk *clk, struct clk *parent) -{ - int ret = -EINVAL; - struct clk *old; - - if (clk == NULL || IS_ERR(clk) || parent == NULL || - IS_ERR(parent) || clk->set_parent == NULL) - return ret; - - if (clk->usecount) - clk_prepare_enable(parent); - - mutex_lock(&clocks_mutex); - ret = clk->set_parent(clk, parent); - if (ret == 0) { - old = clk->parent; - clk->parent = parent; - } else { - old = parent; - } - mutex_unlock(&clocks_mutex); - - if (clk->usecount) - clk_disable(old); - - return ret; -} -EXPORT_SYMBOL(clk_set_parent); - -/* Retrieve the clock's parent clock source */ -struct clk *clk_get_parent(struct clk *clk) -{ - struct clk *ret = NULL; - - if (clk == NULL || IS_ERR(clk)) - return ret; - - return clk->parent; -} -EXPORT_SYMBOL(clk_get_parent); diff --git a/arch/arm/mach-mxs/include/mach/clock.h b/arch/arm/mach-mxs/include/mach/clock.h deleted file mode 100644 index 592c9ab5d760..000000000000 --- a/arch/arm/mach-mxs/include/mach/clock.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright 2008 Juergen Beisert, 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, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#ifndef __MACH_MXS_CLOCK_H__ -#define __MACH_MXS_CLOCK_H__ - -#ifndef __ASSEMBLY__ -#include <linux/list.h> - -struct module; - -struct clk { - int id; - /* Source clock this clk depends on */ - struct clk *parent; - /* Reference count of clock enable/disable */ - __s8 usecount; - /* Register bit position for clock's enable/disable control. */ - u8 enable_shift; - /* Register address for clock's enable/disable control. */ - void __iomem *enable_reg; - u32 flags; - /* get the current clock rate (always a fresh value) */ - unsigned long (*get_rate) (struct clk *); - /* Function ptr to set the clock to a new rate. The rate must match a - supported rate returned from round_rate. Leave blank if clock is not - programmable */ - int (*set_rate) (struct clk *, unsigned long); - /* Function ptr to round the requested clock rate to the nearest - supported rate that is less than or equal to the requested rate. */ - unsigned long (*round_rate) (struct clk *, unsigned long); - /* Function ptr to enable the clock. Leave blank if clock can not - be gated. */ - int (*enable) (struct clk *); - /* Function ptr to disable the clock. Leave blank if clock can not - be gated. */ - void (*disable) (struct clk *); - /* Function ptr to set the parent clock of the clock. */ - int (*set_parent) (struct clk *, struct clk *); -}; - -int clk_register(struct clk *clk); -void clk_unregister(struct clk *clk); - -#endif /* __ASSEMBLY__ */ -#endif /* __MACH_MXS_CLOCK_H__ */ diff --git a/arch/arm/mach-mxs/include/mach/common.h b/arch/arm/mach-mxs/include/mach/common.h index 8d88399b73ef..84af61cf6a62 100644 --- a/arch/arm/mach-mxs/include/mach/common.h +++ b/arch/arm/mach-mxs/include/mach/common.h @@ -11,11 +11,9 @@ #ifndef __MACH_MXS_COMMON_H__ #define __MACH_MXS_COMMON_H__ -struct clk; - extern const u32 *mxs_get_ocotp(void); extern int mxs_reset_block(void __iomem *); -extern void mxs_timer_init(struct clk *, int); +extern void mxs_timer_init(int); extern void mxs_restart(char, const char *); extern int mxs_saif_clkmux_select(unsigned int clkmux); @@ -33,6 +31,4 @@ extern void mx28_init_irq(void); extern void icoll_init_irq(void); -extern int mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask); - #endif /* __MACH_MXS_COMMON_H__ */ diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c index da4610ebe9e6..dafd48e86c8c 100644 --- a/arch/arm/mach-mxs/mach-mx28evk.c +++ b/arch/arm/mach-mxs/mach-mx28evk.c @@ -226,7 +226,7 @@ static void __init mx28evk_fec_reset(void) struct clk *clk; /* Enable fec phy clock */ - clk = clk_get_sys("pll2", NULL); + clk = clk_get_sys("enet_out", NULL); if (!IS_ERR(clk)) clk_prepare_enable(clk); diff --git a/arch/arm/mach-mxs/regs-clkctrl-mx23.h b/arch/arm/mach-mxs/regs-clkctrl-mx23.h deleted file mode 100644 index 0ea5c9d0e2b2..000000000000 --- a/arch/arm/mach-mxs/regs-clkctrl-mx23.h +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Freescale CLKCTRL Register Definitions - * - * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. - * Copyright 2008-2010 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 as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This file is created by xml file. Don't Edit it. - * - * Xml Revision: 1.48 - * Template revision: 26195 - */ - -#ifndef __REGS_CLKCTRL_MX23_H__ -#define __REGS_CLKCTRL_MX23_H__ - - -#define HW_CLKCTRL_PLLCTRL0 (0x00000000) -#define HW_CLKCTRL_PLLCTRL0_SET (0x00000004) -#define HW_CLKCTRL_PLLCTRL0_CLR (0x00000008) -#define HW_CLKCTRL_PLLCTRL0_TOG (0x0000000c) - -#define BP_CLKCTRL_PLLCTRL0_LFR_SEL 28 -#define BM_CLKCTRL_PLLCTRL0_LFR_SEL 0x30000000 -#define BF_CLKCTRL_PLLCTRL0_LFR_SEL(v) \ - (((v) << 28) & BM_CLKCTRL_PLLCTRL0_LFR_SEL) -#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__TIMES_2 0x1 -#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__TIMES_05 0x2 -#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__UNDEFINED 0x3 -#define BP_CLKCTRL_PLLCTRL0_CP_SEL 24 -#define BM_CLKCTRL_PLLCTRL0_CP_SEL 0x03000000 -#define BF_CLKCTRL_PLLCTRL0_CP_SEL(v) \ - (((v) << 24) & BM_CLKCTRL_PLLCTRL0_CP_SEL) -#define BV_CLKCTRL_PLLCTRL0_CP_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLLCTRL0_CP_SEL__TIMES_2 0x1 -#define BV_CLKCTRL_PLLCTRL0_CP_SEL__TIMES_05 0x2 -#define BV_CLKCTRL_PLLCTRL0_CP_SEL__UNDEFINED 0x3 -#define BP_CLKCTRL_PLLCTRL0_DIV_SEL 20 -#define BM_CLKCTRL_PLLCTRL0_DIV_SEL 0x00300000 -#define BF_CLKCTRL_PLLCTRL0_DIV_SEL(v) \ - (((v) << 20) & BM_CLKCTRL_PLLCTRL0_DIV_SEL) -#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__LOWER 0x1 -#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__LOWEST 0x2 -#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__UNDEFINED 0x3 -#define BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS 0x00040000 -#define BM_CLKCTRL_PLLCTRL0_POWER 0x00010000 - -#define HW_CLKCTRL_PLLCTRL1 (0x00000010) - -#define BM_CLKCTRL_PLLCTRL1_LOCK 0x80000000 -#define BM_CLKCTRL_PLLCTRL1_FORCE_LOCK 0x40000000 -#define BP_CLKCTRL_PLLCTRL1_LOCK_COUNT 0 -#define BM_CLKCTRL_PLLCTRL1_LOCK_COUNT 0x0000FFFF -#define BF_CLKCTRL_PLLCTRL1_LOCK_COUNT(v) \ - (((v) << 0) & BM_CLKCTRL_PLLCTRL1_LOCK_COUNT) - -#define HW_CLKCTRL_CPU (0x00000020) -#define HW_CLKCTRL_CPU_SET (0x00000024) -#define HW_CLKCTRL_CPU_CLR (0x00000028) -#define HW_CLKCTRL_CPU_TOG (0x0000002c) - -#define BM_CLKCTRL_CPU_BUSY_REF_XTAL 0x20000000 -#define BM_CLKCTRL_CPU_BUSY_REF_CPU 0x10000000 -#define BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN 0x04000000 -#define BP_CLKCTRL_CPU_DIV_XTAL 16 -#define BM_CLKCTRL_CPU_DIV_XTAL 0x03FF0000 -#define BF_CLKCTRL_CPU_DIV_XTAL(v) \ - (((v) << 16) & BM_CLKCTRL_CPU_DIV_XTAL) -#define BM_CLKCTRL_CPU_INTERRUPT_WAIT 0x00001000 -#define BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN 0x00000400 -#define BP_CLKCTRL_CPU_DIV_CPU 0 -#define BM_CLKCTRL_CPU_DIV_CPU 0x0000003F -#define BF_CLKCTRL_CPU_DIV_CPU(v) \ - (((v) << 0) & BM_CLKCTRL_CPU_DIV_CPU) - -#define HW_CLKCTRL_HBUS (0x00000030) -#define HW_CLKCTRL_HBUS_SET (0x00000034) -#define HW_CLKCTRL_HBUS_CLR (0x00000038) -#define HW_CLKCTRL_HBUS_TOG (0x0000003c) - -#define BM_CLKCTRL_HBUS_BUSY 0x20000000 -#define BM_CLKCTRL_HBUS_DCP_AS_ENABLE 0x10000000 -#define BM_CLKCTRL_HBUS_PXP_AS_ENABLE 0x08000000 -#define BM_CLKCTRL_HBUS_APBHDMA_AS_ENABLE 0x04000000 -#define BM_CLKCTRL_HBUS_APBXDMA_AS_ENABLE 0x02000000 -#define BM_CLKCTRL_HBUS_TRAFFIC_JAM_AS_ENABLE 0x01000000 -#define BM_CLKCTRL_HBUS_TRAFFIC_AS_ENABLE 0x00800000 -#define BM_CLKCTRL_HBUS_CPU_DATA_AS_ENABLE 0x00400000 -#define BM_CLKCTRL_HBUS_CPU_INSTR_AS_ENABLE 0x00200000 -#define BM_CLKCTRL_HBUS_AUTO_SLOW_MODE 0x00100000 -#define BP_CLKCTRL_HBUS_SLOW_DIV 16 -#define BM_CLKCTRL_HBUS_SLOW_DIV 0x00070000 -#define BF_CLKCTRL_HBUS_SLOW_DIV(v) \ - (((v) << 16) & BM_CLKCTRL_HBUS_SLOW_DIV) -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY1 0x0 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY2 0x1 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY4 0x2 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY8 0x3 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY16 0x4 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY32 0x5 -#define BM_CLKCTRL_HBUS_DIV_FRAC_EN 0x00000020 -#define BP_CLKCTRL_HBUS_DIV 0 -#define BM_CLKCTRL_HBUS_DIV 0x0000001F -#define BF_CLKCTRL_HBUS_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_HBUS_DIV) - -#define HW_CLKCTRL_XBUS (0x00000040) - -#define BM_CLKCTRL_XBUS_BUSY 0x80000000 -#define BM_CLKCTRL_XBUS_DIV_FRAC_EN 0x00000400 -#define BP_CLKCTRL_XBUS_DIV 0 -#define BM_CLKCTRL_XBUS_DIV 0x000003FF -#define BF_CLKCTRL_XBUS_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_XBUS_DIV) - -#define HW_CLKCTRL_XTAL (0x00000050) -#define HW_CLKCTRL_XTAL_SET (0x00000054) -#define HW_CLKCTRL_XTAL_CLR (0x00000058) -#define HW_CLKCTRL_XTAL_TOG (0x0000005c) - -#define BP_CLKCTRL_XTAL_UART_CLK_GATE 31 -#define BM_CLKCTRL_XTAL_UART_CLK_GATE 0x80000000 -#define BP_CLKCTRL_XTAL_FILT_CLK24M_GATE 30 -#define BM_CLKCTRL_XTAL_FILT_CLK24M_GATE 0x40000000 -#define BP_CLKCTRL_XTAL_PWM_CLK24M_GATE 29 -#define BM_CLKCTRL_XTAL_PWM_CLK24M_GATE 0x20000000 -#define BM_CLKCTRL_XTAL_DRI_CLK24M_GATE 0x10000000 -#define BM_CLKCTRL_XTAL_DIGCTRL_CLK1M_GATE 0x08000000 -#define BP_CLKCTRL_XTAL_TIMROT_CLK32K_GATE 26 -#define BM_CLKCTRL_XTAL_TIMROT_CLK32K_GATE 0x04000000 -#define BP_CLKCTRL_XTAL_DIV_UART 0 -#define BM_CLKCTRL_XTAL_DIV_UART 0x00000003 -#define BF_CLKCTRL_XTAL_DIV_UART(v) \ - (((v) << 0) & BM_CLKCTRL_XTAL_DIV_UART) - -#define HW_CLKCTRL_PIX (0x00000060) - -#define BP_CLKCTRL_PIX_CLKGATE 31 -#define BM_CLKCTRL_PIX_CLKGATE 0x80000000 -#define BM_CLKCTRL_PIX_BUSY 0x20000000 -#define BM_CLKCTRL_PIX_DIV_FRAC_EN 0x00001000 -#define BP_CLKCTRL_PIX_DIV 0 -#define BM_CLKCTRL_PIX_DIV 0x00000FFF -#define BF_CLKCTRL_PIX_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_PIX_DIV) - -#define HW_CLKCTRL_SSP (0x00000070) - -#define BP_CLKCTRL_SSP_CLKGATE 31 -#define BM_CLKCTRL_SSP_CLKGATE 0x80000000 -#define BM_CLKCTRL_SSP_BUSY 0x20000000 -#define BM_CLKCTRL_SSP_DIV_FRAC_EN 0x00000200 -#define BP_CLKCTRL_SSP_DIV 0 -#define BM_CLKCTRL_SSP_DIV 0x000001FF -#define BF_CLKCTRL_SSP_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SSP_DIV) - -#define HW_CLKCTRL_GPMI (0x00000080) - -#define BP_CLKCTRL_GPMI_CLKGATE 31 -#define BM_CLKCTRL_GPMI_CLKGATE 0x80000000 -#define BM_CLKCTRL_GPMI_BUSY 0x20000000 -#define BM_CLKCTRL_GPMI_DIV_FRAC_EN 0x00000400 -#define BP_CLKCTRL_GPMI_DIV 0 -#define BM_CLKCTRL_GPMI_DIV 0x000003FF -#define BF_CLKCTRL_GPMI_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_GPMI_DIV) - -#define HW_CLKCTRL_SPDIF (0x00000090) - -#define BM_CLKCTRL_SPDIF_CLKGATE 0x80000000 - -#define HW_CLKCTRL_EMI (0x000000a0) - -#define BP_CLKCTRL_EMI_CLKGATE 31 -#define BM_CLKCTRL_EMI_CLKGATE 0x80000000 -#define BM_CLKCTRL_EMI_SYNC_MODE_EN 0x40000000 -#define BM_CLKCTRL_EMI_BUSY_REF_XTAL 0x20000000 -#define BM_CLKCTRL_EMI_BUSY_REF_EMI 0x10000000 -#define BM_CLKCTRL_EMI_BUSY_REF_CPU 0x08000000 -#define BM_CLKCTRL_EMI_BUSY_SYNC_MODE 0x04000000 -#define BM_CLKCTRL_EMI_BUSY_DCC_RESYNC 0x00020000 -#define BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE 0x00010000 -#define BP_CLKCTRL_EMI_DIV_XTAL 8 -#define BM_CLKCTRL_EMI_DIV_XTAL 0x00000F00 -#define BF_CLKCTRL_EMI_DIV_XTAL(v) \ - (((v) << 8) & BM_CLKCTRL_EMI_DIV_XTAL) -#define BP_CLKCTRL_EMI_DIV_EMI 0 -#define BM_CLKCTRL_EMI_DIV_EMI 0x0000003F -#define BF_CLKCTRL_EMI_DIV_EMI(v) \ - (((v) << 0) & BM_CLKCTRL_EMI_DIV_EMI) - -#define HW_CLKCTRL_IR (0x000000b0) - -#define BM_CLKCTRL_IR_CLKGATE 0x80000000 -#define BM_CLKCTRL_IR_AUTO_DIV 0x20000000 -#define BM_CLKCTRL_IR_IR_BUSY 0x10000000 -#define BM_CLKCTRL_IR_IROV_BUSY 0x08000000 -#define BP_CLKCTRL_IR_IROV_DIV 16 -#define BM_CLKCTRL_IR_IROV_DIV 0x01FF0000 -#define BF_CLKCTRL_IR_IROV_DIV(v) \ - (((v) << 16) & BM_CLKCTRL_IR_IROV_DIV) -#define BP_CLKCTRL_IR_IR_DIV 0 -#define BM_CLKCTRL_IR_IR_DIV 0x000003FF -#define BF_CLKCTRL_IR_IR_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_IR_IR_DIV) - -#define HW_CLKCTRL_SAIF (0x000000c0) - -#define BM_CLKCTRL_SAIF_CLKGATE 0x80000000 -#define BM_CLKCTRL_SAIF_BUSY 0x20000000 -#define BM_CLKCTRL_SAIF_DIV_FRAC_EN 0x00010000 -#define BP_CLKCTRL_SAIF_DIV 0 -#define BM_CLKCTRL_SAIF_DIV 0x0000FFFF -#define BF_CLKCTRL_SAIF_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SAIF_DIV) - -#define HW_CLKCTRL_TV (0x000000d0) - -#define BM_CLKCTRL_TV_CLK_TV108M_GATE 0x80000000 -#define BM_CLKCTRL_TV_CLK_TV_GATE 0x40000000 - -#define HW_CLKCTRL_ETM (0x000000e0) - -#define BM_CLKCTRL_ETM_CLKGATE 0x80000000 -#define BM_CLKCTRL_ETM_BUSY 0x20000000 -#define BM_CLKCTRL_ETM_DIV_FRAC_EN 0x00000040 -#define BP_CLKCTRL_ETM_DIV 0 -#define BM_CLKCTRL_ETM_DIV 0x0000003F -#define BF_CLKCTRL_ETM_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_ETM_DIV) - -#define HW_CLKCTRL_FRAC (0x000000f0) -#define HW_CLKCTRL_FRAC_SET (0x000000f4) -#define HW_CLKCTRL_FRAC_CLR (0x000000f8) -#define HW_CLKCTRL_FRAC_TOG (0x000000fc) - -#define BP_CLKCTRL_FRAC_CLKGATEIO 31 -#define BM_CLKCTRL_FRAC_CLKGATEIO 0x80000000 -#define BM_CLKCTRL_FRAC_IO_STABLE 0x40000000 -#define BP_CLKCTRL_FRAC_IOFRAC 24 -#define BM_CLKCTRL_FRAC_IOFRAC 0x3F000000 -#define BF_CLKCTRL_FRAC_IOFRAC(v) \ - (((v) << 24) & BM_CLKCTRL_FRAC_IOFRAC) -#define BP_CLKCTRL_FRAC_CLKGATEPIX 23 -#define BM_CLKCTRL_FRAC_CLKGATEPIX 0x00800000 -#define BM_CLKCTRL_FRAC_PIX_STABLE 0x00400000 -#define BP_CLKCTRL_FRAC_PIXFRAC 16 -#define BM_CLKCTRL_FRAC_PIXFRAC 0x003F0000 -#define BF_CLKCTRL_FRAC_PIXFRAC(v) \ - (((v) << 16) & BM_CLKCTRL_FRAC_PIXFRAC) -#define BP_CLKCTRL_FRAC_CLKGATEEMI 15 -#define BM_CLKCTRL_FRAC_CLKGATEEMI 0x00008000 -#define BM_CLKCTRL_FRAC_EMI_STABLE 0x00004000 -#define BP_CLKCTRL_FRAC_EMIFRAC 8 -#define BM_CLKCTRL_FRAC_EMIFRAC 0x00003F00 -#define BF_CLKCTRL_FRAC_EMIFRAC(v) \ - (((v) << 8) & BM_CLKCTRL_FRAC_EMIFRAC) -#define BP_CLKCTRL_FRAC_CLKGATECPU 7 -#define BM_CLKCTRL_FRAC_CLKGATECPU 0x00000080 -#define BM_CLKCTRL_FRAC_CPU_STABLE 0x00000040 -#define BP_CLKCTRL_FRAC_CPUFRAC 0 -#define BM_CLKCTRL_FRAC_CPUFRAC 0x0000003F -#define BF_CLKCTRL_FRAC_CPUFRAC(v) \ - (((v) << 0) & BM_CLKCTRL_FRAC_CPUFRAC) - -#define HW_CLKCTRL_FRAC1 (0x00000100) -#define HW_CLKCTRL_FRAC1_SET (0x00000104) -#define HW_CLKCTRL_FRAC1_CLR (0x00000108) -#define HW_CLKCTRL_FRAC1_TOG (0x0000010c) - -#define BM_CLKCTRL_FRAC1_CLKGATEVID 0x80000000 -#define BM_CLKCTRL_FRAC1_VID_STABLE 0x40000000 - -#define HW_CLKCTRL_CLKSEQ (0x00000110) -#define HW_CLKCTRL_CLKSEQ_SET (0x00000114) -#define HW_CLKCTRL_CLKSEQ_CLR (0x00000118) -#define HW_CLKCTRL_CLKSEQ_TOG (0x0000011c) - -#define BM_CLKCTRL_CLKSEQ_BYPASS_ETM 0x00000100 -#define BM_CLKCTRL_CLKSEQ_BYPASS_CPU 0x00000080 -#define BM_CLKCTRL_CLKSEQ_BYPASS_EMI 0x00000040 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SSP 0x00000020 -#define BM_CLKCTRL_CLKSEQ_BYPASS_GPMI 0x00000010 -#define BM_CLKCTRL_CLKSEQ_BYPASS_IR 0x00000008 -#define BM_CLKCTRL_CLKSEQ_BYPASS_PIX 0x00000002 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SAIF 0x00000001 - -#define HW_CLKCTRL_RESET (0x00000120) - -#define BM_CLKCTRL_RESET_CHIP 0x00000002 -#define BM_CLKCTRL_RESET_DIG 0x00000001 - -#define HW_CLKCTRL_STATUS (0x00000130) - -#define BP_CLKCTRL_STATUS_CPU_LIMIT 30 -#define BM_CLKCTRL_STATUS_CPU_LIMIT 0xC0000000 -#define BF_CLKCTRL_STATUS_CPU_LIMIT(v) \ - (((v) << 30) & BM_CLKCTRL_STATUS_CPU_LIMIT) - -#define HW_CLKCTRL_VERSION (0x00000140) - -#define BP_CLKCTRL_VERSION_MAJOR 24 -#define BM_CLKCTRL_VERSION_MAJOR 0xFF000000 -#define BF_CLKCTRL_VERSION_MAJOR(v) \ - (((v) << 24) & BM_CLKCTRL_VERSION_MAJOR) -#define BP_CLKCTRL_VERSION_MINOR 16 -#define BM_CLKCTRL_VERSION_MINOR 0x00FF0000 -#define BF_CLKCTRL_VERSION_MINOR(v) \ - (((v) << 16) & BM_CLKCTRL_VERSION_MINOR) -#define BP_CLKCTRL_VERSION_STEP 0 -#define BM_CLKCTRL_VERSION_STEP 0x0000FFFF -#define BF_CLKCTRL_VERSION_STEP(v) \ - (((v) << 0) & BM_CLKCTRL_VERSION_STEP) - -#endif /* __REGS_CLKCTRL_MX23_H__ */ diff --git a/arch/arm/mach-mxs/regs-clkctrl-mx28.h b/arch/arm/mach-mxs/regs-clkctrl-mx28.h deleted file mode 100644 index 7d1b061d7943..000000000000 --- a/arch/arm/mach-mxs/regs-clkctrl-mx28.h +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Freescale CLKCTRL Register Definitions - * - * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This file is created by xml file. Don't Edit it. - * - * Xml Revision: 1.48 - * Template revision: 26195 - */ - -#ifndef __REGS_CLKCTRL_MX28_H__ -#define __REGS_CLKCTRL_MX28_H__ - -#define HW_CLKCTRL_PLL0CTRL0 (0x00000000) -#define HW_CLKCTRL_PLL0CTRL0_SET (0x00000004) -#define HW_CLKCTRL_PLL0CTRL0_CLR (0x00000008) -#define HW_CLKCTRL_PLL0CTRL0_TOG (0x0000000c) - -#define BP_CLKCTRL_PLL0CTRL0_LFR_SEL 28 -#define BM_CLKCTRL_PLL0CTRL0_LFR_SEL 0x30000000 -#define BF_CLKCTRL_PLL0CTRL0_LFR_SEL(v) \ - (((v) << 28) & BM_CLKCTRL_PLL0CTRL0_LFR_SEL) -#define BV_CLKCTRL_PLL0CTRL0_LFR_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLL0CTRL0_LFR_SEL__TIMES_2 0x1 -#define BV_CLKCTRL_PLL0CTRL0_LFR_SEL__TIMES_05 0x2 -#define BV_CLKCTRL_PLL0CTRL0_LFR_SEL__UNDEFINED 0x3 -#define BP_CLKCTRL_PLL0CTRL0_CP_SEL 24 -#define BM_CLKCTRL_PLL0CTRL0_CP_SEL 0x03000000 -#define BF_CLKCTRL_PLL0CTRL0_CP_SEL(v) \ - (((v) << 24) & BM_CLKCTRL_PLL0CTRL0_CP_SEL) -#define BV_CLKCTRL_PLL0CTRL0_CP_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLL0CTRL0_CP_SEL__TIMES_2 0x1 -#define BV_CLKCTRL_PLL0CTRL0_CP_SEL__TIMES_05 0x2 -#define BV_CLKCTRL_PLL0CTRL0_CP_SEL__UNDEFINED 0x3 -#define BP_CLKCTRL_PLL0CTRL0_DIV_SEL 20 -#define BM_CLKCTRL_PLL0CTRL0_DIV_SEL 0x00300000 -#define BF_CLKCTRL_PLL0CTRL0_DIV_SEL(v) \ - (((v) << 20) & BM_CLKCTRL_PLL0CTRL0_DIV_SEL) -#define BV_CLKCTRL_PLL0CTRL0_DIV_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLL0CTRL0_DIV_SEL__LOWER 0x1 -#define BV_CLKCTRL_PLL0CTRL0_DIV_SEL__LOWEST 0x2 -#define BV_CLKCTRL_PLL0CTRL0_DIV_SEL__UNDEFINED 0x3 -#define BM_CLKCTRL_PLL0CTRL0_EN_USB_CLKS 0x00040000 -#define BM_CLKCTRL_PLL0CTRL0_POWER 0x00020000 - -#define HW_CLKCTRL_PLL0CTRL1 (0x00000010) - -#define BM_CLKCTRL_PLL0CTRL1_LOCK 0x80000000 -#define BM_CLKCTRL_PLL0CTRL1_FORCE_LOCK 0x40000000 -#define BP_CLKCTRL_PLL0CTRL1_LOCK_COUNT 0 -#define BM_CLKCTRL_PLL0CTRL1_LOCK_COUNT 0x0000FFFF -#define BF_CLKCTRL_PLL0CTRL1_LOCK_COUNT(v) \ - (((v) << 0) & BM_CLKCTRL_PLL0CTRL1_LOCK_COUNT) - -#define HW_CLKCTRL_PLL1CTRL0 (0x00000020) -#define HW_CLKCTRL_PLL1CTRL0_SET (0x00000024) -#define HW_CLKCTRL_PLL1CTRL0_CLR (0x00000028) -#define HW_CLKCTRL_PLL1CTRL0_TOG (0x0000002c) - -#define BM_CLKCTRL_PLL1CTRL0_CLKGATEEMI 0x80000000 -#define BP_CLKCTRL_PLL1CTRL0_LFR_SEL 28 -#define BM_CLKCTRL_PLL1CTRL0_LFR_SEL 0x30000000 -#define BF_CLKCTRL_PLL1CTRL0_LFR_SEL(v) \ - (((v) << 28) & BM_CLKCTRL_PLL1CTRL0_LFR_SEL) -#define BV_CLKCTRL_PLL1CTRL0_LFR_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLL1CTRL0_LFR_SEL__TIMES_2 0x1 -#define BV_CLKCTRL_PLL1CTRL0_LFR_SEL__TIMES_05 0x2 -#define BV_CLKCTRL_PLL1CTRL0_LFR_SEL__UNDEFINED 0x3 -#define BP_CLKCTRL_PLL1CTRL0_CP_SEL 24 -#define BM_CLKCTRL_PLL1CTRL0_CP_SEL 0x03000000 -#define BF_CLKCTRL_PLL1CTRL0_CP_SEL(v) \ - (((v) << 24) & BM_CLKCTRL_PLL1CTRL0_CP_SEL) -#define BV_CLKCTRL_PLL1CTRL0_CP_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLL1CTRL0_CP_SEL__TIMES_2 0x1 -#define BV_CLKCTRL_PLL1CTRL0_CP_SEL__TIMES_05 0x2 -#define BV_CLKCTRL_PLL1CTRL0_CP_SEL__UNDEFINED 0x3 -#define BP_CLKCTRL_PLL1CTRL0_DIV_SEL 20 -#define BM_CLKCTRL_PLL1CTRL0_DIV_SEL 0x00300000 -#define BF_CLKCTRL_PLL1CTRL0_DIV_SEL(v) \ - (((v) << 20) & BM_CLKCTRL_PLL1CTRL0_DIV_SEL) -#define BV_CLKCTRL_PLL1CTRL0_DIV_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLL1CTRL0_DIV_SEL__LOWER 0x1 -#define BV_CLKCTRL_PLL1CTRL0_DIV_SEL__LOWEST 0x2 -#define BV_CLKCTRL_PLL1CTRL0_DIV_SEL__UNDEFINED 0x3 -#define BM_CLKCTRL_PLL1CTRL0_EN_USB_CLKS 0x00040000 -#define BM_CLKCTRL_PLL1CTRL0_POWER 0x00020000 - -#define HW_CLKCTRL_PLL1CTRL1 (0x00000030) - -#define BM_CLKCTRL_PLL1CTRL1_LOCK 0x80000000 -#define BM_CLKCTRL_PLL1CTRL1_FORCE_LOCK 0x40000000 -#define BP_CLKCTRL_PLL1CTRL1_LOCK_COUNT 0 -#define BM_CLKCTRL_PLL1CTRL1_LOCK_COUNT 0x0000FFFF -#define BF_CLKCTRL_PLL1CTRL1_LOCK_COUNT(v) \ - (((v) << 0) & BM_CLKCTRL_PLL1CTRL1_LOCK_COUNT) - -#define HW_CLKCTRL_PLL2CTRL0 (0x00000040) -#define HW_CLKCTRL_PLL2CTRL0_SET (0x00000044) -#define HW_CLKCTRL_PLL2CTRL0_CLR (0x00000048) -#define HW_CLKCTRL_PLL2CTRL0_TOG (0x0000004c) - -#define BM_CLKCTRL_PLL2CTRL0_CLKGATE 0x80000000 -#define BP_CLKCTRL_PLL2CTRL0_LFR_SEL 28 -#define BM_CLKCTRL_PLL2CTRL0_LFR_SEL 0x30000000 -#define BF_CLKCTRL_PLL2CTRL0_LFR_SEL(v) \ - (((v) << 28) & BM_CLKCTRL_PLL2CTRL0_LFR_SEL) -#define BM_CLKCTRL_PLL2CTRL0_HOLD_RING_OFF_B 0x04000000 -#define BP_CLKCTRL_PLL2CTRL0_CP_SEL 24 -#define BM_CLKCTRL_PLL2CTRL0_CP_SEL 0x03000000 -#define BF_CLKCTRL_PLL2CTRL0_CP_SEL(v) \ - (((v) << 24) & BM_CLKCTRL_PLL2CTRL0_CP_SEL) -#define BM_CLKCTRL_PLL2CTRL0_POWER 0x00800000 - -#define HW_CLKCTRL_CPU (0x00000050) -#define HW_CLKCTRL_CPU_SET (0x00000054) -#define HW_CLKCTRL_CPU_CLR (0x00000058) -#define HW_CLKCTRL_CPU_TOG (0x0000005c) - -#define BM_CLKCTRL_CPU_BUSY_REF_XTAL 0x20000000 -#define BM_CLKCTRL_CPU_BUSY_REF_CPU 0x10000000 -#define BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN 0x04000000 -#define BP_CLKCTRL_CPU_DIV_XTAL 16 -#define BM_CLKCTRL_CPU_DIV_XTAL 0x03FF0000 -#define BF_CLKCTRL_CPU_DIV_XTAL(v) \ - (((v) << 16) & BM_CLKCTRL_CPU_DIV_XTAL) -#define BM_CLKCTRL_CPU_INTERRUPT_WAIT 0x00001000 -#define BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN 0x00000400 -#define BP_CLKCTRL_CPU_DIV_CPU 0 -#define BM_CLKCTRL_CPU_DIV_CPU 0x0000003F -#define BF_CLKCTRL_CPU_DIV_CPU(v) \ - (((v) << 0) & BM_CLKCTRL_CPU_DIV_CPU) - -#define HW_CLKCTRL_HBUS (0x00000060) -#define HW_CLKCTRL_HBUS_SET (0x00000064) -#define HW_CLKCTRL_HBUS_CLR (0x00000068) -#define HW_CLKCTRL_HBUS_TOG (0x0000006c) - -#define BM_CLKCTRL_HBUS_ASM_BUSY 0x80000000 -#define BM_CLKCTRL_HBUS_DCP_AS_ENABLE 0x40000000 -#define BM_CLKCTRL_HBUS_PXP_AS_ENABLE 0x20000000 -#define BM_CLKCTRL_HBUS_ASM_EMIPORT_AS_ENABLE 0x08000000 -#define BM_CLKCTRL_HBUS_APBHDMA_AS_ENABLE 0x04000000 -#define BM_CLKCTRL_HBUS_APBXDMA_AS_ENABLE 0x02000000 -#define BM_CLKCTRL_HBUS_TRAFFIC_JAM_AS_ENABLE 0x01000000 -#define BM_CLKCTRL_HBUS_TRAFFIC_AS_ENABLE 0x00800000 -#define BM_CLKCTRL_HBUS_CPU_DATA_AS_ENABLE 0x00400000 -#define BM_CLKCTRL_HBUS_CPU_INSTR_AS_ENABLE 0x00200000 -#define BM_CLKCTRL_HBUS_ASM_ENABLE 0x00100000 -#define BM_CLKCTRL_HBUS_AUTO_CLEAR_DIV_ENABLE 0x00080000 -#define BP_CLKCTRL_HBUS_SLOW_DIV 16 -#define BM_CLKCTRL_HBUS_SLOW_DIV 0x00070000 -#define BF_CLKCTRL_HBUS_SLOW_DIV(v) \ - (((v) << 16) & BM_CLKCTRL_HBUS_SLOW_DIV) -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY1 0x0 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY2 0x1 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY4 0x2 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY8 0x3 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY16 0x4 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY32 0x5 -#define BM_CLKCTRL_HBUS_DIV_FRAC_EN 0x00000020 -#define BP_CLKCTRL_HBUS_DIV 0 -#define BM_CLKCTRL_HBUS_DIV 0x0000001F -#define BF_CLKCTRL_HBUS_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_HBUS_DIV) - -#define HW_CLKCTRL_XBUS (0x00000070) - -#define BM_CLKCTRL_XBUS_BUSY 0x80000000 -#define BM_CLKCTRL_XBUS_AUTO_CLEAR_DIV_ENABLE 0x00000800 -#define BM_CLKCTRL_XBUS_DIV_FRAC_EN 0x00000400 -#define BP_CLKCTRL_XBUS_DIV 0 -#define BM_CLKCTRL_XBUS_DIV 0x000003FF -#define BF_CLKCTRL_XBUS_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_XBUS_DIV) - -#define HW_CLKCTRL_XTAL (0x00000080) -#define HW_CLKCTRL_XTAL_SET (0x00000084) -#define HW_CLKCTRL_XTAL_CLR (0x00000088) -#define HW_CLKCTRL_XTAL_TOG (0x0000008c) - -#define BP_CLKCTRL_XTAL_UART_CLK_GATE 31 -#define BM_CLKCTRL_XTAL_UART_CLK_GATE 0x80000000 -#define BP_CLKCTRL_XTAL_PWM_CLK24M_GATE 29 -#define BM_CLKCTRL_XTAL_PWM_CLK24M_GATE 0x20000000 -#define BP_CLKCTRL_XTAL_TIMROT_CLK32K_GATE 26 -#define BM_CLKCTRL_XTAL_TIMROT_CLK32K_GATE 0x04000000 -#define BP_CLKCTRL_XTAL_DIV_UART 0 -#define BM_CLKCTRL_XTAL_DIV_UART 0x00000003 -#define BF_CLKCTRL_XTAL_DIV_UART(v) \ - (((v) << 0) & BM_CLKCTRL_XTAL_DIV_UART) - -#define HW_CLKCTRL_SSP0 (0x00000090) - -#define BP_CLKCTRL_SSP0_CLKGATE 31 -#define BM_CLKCTRL_SSP0_CLKGATE 0x80000000 -#define BM_CLKCTRL_SSP0_BUSY 0x20000000 -#define BM_CLKCTRL_SSP0_DIV_FRAC_EN 0x00000200 -#define BP_CLKCTRL_SSP0_DIV 0 -#define BM_CLKCTRL_SSP0_DIV 0x000001FF -#define BF_CLKCTRL_SSP0_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SSP0_DIV) - -#define HW_CLKCTRL_SSP1 (0x000000a0) - -#define BP_CLKCTRL_SSP1_CLKGATE 31 -#define BM_CLKCTRL_SSP1_CLKGATE 0x80000000 -#define BM_CLKCTRL_SSP1_BUSY 0x20000000 -#define BM_CLKCTRL_SSP1_DIV_FRAC_EN 0x00000200 -#define BP_CLKCTRL_SSP1_DIV 0 -#define BM_CLKCTRL_SSP1_DIV 0x000001FF -#define BF_CLKCTRL_SSP1_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SSP1_DIV) - -#define HW_CLKCTRL_SSP2 (0x000000b0) - -#define BP_CLKCTRL_SSP2_CLKGATE 31 -#define BM_CLKCTRL_SSP2_CLKGATE 0x80000000 -#define BM_CLKCTRL_SSP2_BUSY 0x20000000 -#define BM_CLKCTRL_SSP2_DIV_FRAC_EN 0x00000200 -#define BP_CLKCTRL_SSP2_DIV 0 -#define BM_CLKCTRL_SSP2_DIV 0x000001FF -#define BF_CLKCTRL_SSP2_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SSP2_DIV) - -#define HW_CLKCTRL_SSP3 (0x000000c0) - -#define BP_CLKCTRL_SSP3_CLKGATE 31 -#define BM_CLKCTRL_SSP3_CLKGATE 0x80000000 -#define BM_CLKCTRL_SSP3_BUSY 0x20000000 -#define BM_CLKCTRL_SSP3_DIV_FRAC_EN 0x00000200 -#define BP_CLKCTRL_SSP3_DIV 0 -#define BM_CLKCTRL_SSP3_DIV 0x000001FF -#define BF_CLKCTRL_SSP3_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SSP3_DIV) - -#define HW_CLKCTRL_GPMI (0x000000d0) - -#define BP_CLKCTRL_GPMI_CLKGATE 31 -#define BM_CLKCTRL_GPMI_CLKGATE 0x80000000 -#define BM_CLKCTRL_GPMI_BUSY 0x20000000 -#define BM_CLKCTRL_GPMI_DIV_FRAC_EN 0x00000400 -#define BP_CLKCTRL_GPMI_DIV 0 -#define BM_CLKCTRL_GPMI_DIV 0x000003FF -#define BF_CLKCTRL_GPMI_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_GPMI_DIV) - -#define HW_CLKCTRL_SPDIF (0x000000e0) - -#define BP_CLKCTRL_SPDIF_CLKGATE 31 -#define BM_CLKCTRL_SPDIF_CLKGATE 0x80000000 - -#define HW_CLKCTRL_EMI (0x000000f0) - -#define BP_CLKCTRL_EMI_CLKGATE 31 -#define BM_CLKCTRL_EMI_CLKGATE 0x80000000 -#define BM_CLKCTRL_EMI_SYNC_MODE_EN 0x40000000 -#define BM_CLKCTRL_EMI_BUSY_REF_XTAL 0x20000000 -#define BM_CLKCTRL_EMI_BUSY_REF_EMI 0x10000000 -#define BM_CLKCTRL_EMI_BUSY_REF_CPU 0x08000000 -#define BM_CLKCTRL_EMI_BUSY_SYNC_MODE 0x04000000 -#define BM_CLKCTRL_EMI_BUSY_DCC_RESYNC 0x00020000 -#define BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE 0x00010000 -#define BP_CLKCTRL_EMI_DIV_XTAL 8 -#define BM_CLKCTRL_EMI_DIV_XTAL 0x00000F00 -#define BF_CLKCTRL_EMI_DIV_XTAL(v) \ - (((v) << 8) & BM_CLKCTRL_EMI_DIV_XTAL) -#define BP_CLKCTRL_EMI_DIV_EMI 0 -#define BM_CLKCTRL_EMI_DIV_EMI 0x0000003F -#define BF_CLKCTRL_EMI_DIV_EMI(v) \ - (((v) << 0) & BM_CLKCTRL_EMI_DIV_EMI) - -#define HW_CLKCTRL_SAIF0 (0x00000100) - -#define BP_CLKCTRL_SAIF0_CLKGATE 31 -#define BM_CLKCTRL_SAIF0_CLKGATE 0x80000000 -#define BM_CLKCTRL_SAIF0_BUSY 0x20000000 -#define BM_CLKCTRL_SAIF0_DIV_FRAC_EN 0x00010000 -#define BP_CLKCTRL_SAIF0_DIV 0 -#define BM_CLKCTRL_SAIF0_DIV 0x0000FFFF -#define BF_CLKCTRL_SAIF0_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SAIF0_DIV) - -#define HW_CLKCTRL_SAIF1 (0x00000110) - -#define BP_CLKCTRL_SAIF1_CLKGATE 31 -#define BM_CLKCTRL_SAIF1_CLKGATE 0x80000000 -#define BM_CLKCTRL_SAIF1_BUSY 0x20000000 -#define BM_CLKCTRL_SAIF1_DIV_FRAC_EN 0x00010000 -#define BP_CLKCTRL_SAIF1_DIV 0 -#define BM_CLKCTRL_SAIF1_DIV 0x0000FFFF -#define BF_CLKCTRL_SAIF1_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SAIF1_DIV) - -#define HW_CLKCTRL_DIS_LCDIF (0x00000120) - -#define BP_CLKCTRL_DIS_LCDIF_CLKGATE 31 -#define BM_CLKCTRL_DIS_LCDIF_CLKGATE 0x80000000 -#define BM_CLKCTRL_DIS_LCDIF_BUSY 0x20000000 -#define BM_CLKCTRL_DIS_LCDIF_DIV_FRAC_EN 0x00002000 -#define BP_CLKCTRL_DIS_LCDIF_DIV 0 -#define BM_CLKCTRL_DIS_LCDIF_DIV 0x00001FFF -#define BF_CLKCTRL_DIS_LCDIF_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_DIS_LCDIF_DIV) - -#define HW_CLKCTRL_ETM (0x00000130) - -#define BM_CLKCTRL_ETM_CLKGATE 0x80000000 -#define BM_CLKCTRL_ETM_BUSY 0x20000000 -#define BM_CLKCTRL_ETM_DIV_FRAC_EN 0x00000080 -#define BP_CLKCTRL_ETM_DIV 0 -#define BM_CLKCTRL_ETM_DIV 0x0000007F -#define BF_CLKCTRL_ETM_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_ETM_DIV) - -#define HW_CLKCTRL_ENET (0x00000140) - -#define BM_CLKCTRL_ENET_SLEEP 0x80000000 -#define BP_CLKCTRL_ENET_DISABLE 30 -#define BM_CLKCTRL_ENET_DISABLE 0x40000000 -#define BM_CLKCTRL_ENET_STATUS 0x20000000 -#define BM_CLKCTRL_ENET_BUSY_TIME 0x08000000 -#define BP_CLKCTRL_ENET_DIV_TIME 21 -#define BM_CLKCTRL_ENET_DIV_TIME 0x07E00000 -#define BF_CLKCTRL_ENET_DIV_TIME(v) \ - (((v) << 21) & BM_CLKCTRL_ENET_DIV_TIME) -#define BM_CLKCTRL_ENET_BUSY 0x08000000 -#define BP_CLKCTRL_ENET_DIV 21 -#define BM_CLKCTRL_ENET_DIV 0x07E00000 -#define BF_CLKCTRL_ENET_DIV(v) \ - (((v) << 21) & BM_CLKCTRL_ENET_DIV) -#define BP_CLKCTRL_ENET_TIME_SEL 19 -#define BM_CLKCTRL_ENET_TIME_SEL 0x00180000 -#define BF_CLKCTRL_ENET_TIME_SEL(v) \ - (((v) << 19) & BM_CLKCTRL_ENET_TIME_SEL) -#define BV_CLKCTRL_ENET_TIME_SEL__XTAL 0x0 -#define BV_CLKCTRL_ENET_TIME_SEL__PLL 0x1 -#define BV_CLKCTRL_ENET_TIME_SEL__RMII_CLK 0x2 -#define BV_CLKCTRL_ENET_TIME_SEL__UNDEFINED 0x3 -#define BM_CLKCTRL_ENET_CLK_OUT_EN 0x00040000 -#define BM_CLKCTRL_ENET_RESET_BY_SW_CHIP 0x00020000 -#define BM_CLKCTRL_ENET_RESET_BY_SW 0x00010000 - -#define HW_CLKCTRL_HSADC (0x00000150) - -#define BM_CLKCTRL_HSADC_RESETB 0x40000000 -#define BP_CLKCTRL_HSADC_FREQDIV 28 -#define BM_CLKCTRL_HSADC_FREQDIV 0x30000000 -#define BF_CLKCTRL_HSADC_FREQDIV(v) \ - (((v) << 28) & BM_CLKCTRL_HSADC_FREQDIV) - -#define HW_CLKCTRL_FLEXCAN (0x00000160) - -#define BP_CLKCTRL_FLEXCAN_STOP_CAN0 30 -#define BM_CLKCTRL_FLEXCAN_STOP_CAN0 0x40000000 -#define BM_CLKCTRL_FLEXCAN_CAN0_STATUS 0x20000000 -#define BP_CLKCTRL_FLEXCAN_STOP_CAN1 28 -#define BM_CLKCTRL_FLEXCAN_STOP_CAN1 0x10000000 -#define BM_CLKCTRL_FLEXCAN_CAN1_STATUS 0x08000000 - -#define HW_CLKCTRL_FRAC0 (0x000001b0) -#define HW_CLKCTRL_FRAC0_SET (0x000001b4) -#define HW_CLKCTRL_FRAC0_CLR (0x000001b8) -#define HW_CLKCTRL_FRAC0_TOG (0x000001bc) - -#define BP_CLKCTRL_FRAC0_CLKGATEIO0 31 -#define BM_CLKCTRL_FRAC0_CLKGATEIO0 0x80000000 -#define BM_CLKCTRL_FRAC0_IO0_STABLE 0x40000000 -#define BP_CLKCTRL_FRAC0_IO0FRAC 24 -#define BM_CLKCTRL_FRAC0_IO0FRAC 0x3F000000 -#define BF_CLKCTRL_FRAC0_IO0FRAC(v) \ - (((v) << 24) & BM_CLKCTRL_FRAC0_IO0FRAC) -#define BP_CLKCTRL_FRAC0_CLKGATEIO1 23 -#define BM_CLKCTRL_FRAC0_CLKGATEIO1 0x00800000 -#define BM_CLKCTRL_FRAC0_IO1_STABLE 0x00400000 -#define BP_CLKCTRL_FRAC0_IO1FRAC 16 -#define BM_CLKCTRL_FRAC0_IO1FRAC 0x003F0000 -#define BF_CLKCTRL_FRAC0_IO1FRAC(v) \ - (((v) << 16) & BM_CLKCTRL_FRAC0_IO1FRAC) -#define BP_CLKCTRL_FRAC0_CLKGATEEMI 15 -#define BM_CLKCTRL_FRAC0_CLKGATEEMI 0x00008000 -#define BM_CLKCTRL_FRAC0_EMI_STABLE 0x00004000 -#define BP_CLKCTRL_FRAC0_EMIFRAC 8 -#define BM_CLKCTRL_FRAC0_EMIFRAC 0x00003F00 -#define BF_CLKCTRL_FRAC0_EMIFRAC(v) \ - (((v) << 8) & BM_CLKCTRL_FRAC0_EMIFRAC) -#define BP_CLKCTRL_FRAC0_CLKGATECPU 7 -#define BM_CLKCTRL_FRAC0_CLKGATECPU 0x00000080 -#define BM_CLKCTRL_FRAC0_CPU_STABLE 0x00000040 -#define BP_CLKCTRL_FRAC0_CPUFRAC 0 -#define BM_CLKCTRL_FRAC0_CPUFRAC 0x0000003F -#define BF_CLKCTRL_FRAC0_CPUFRAC(v) \ - (((v) << 0) & BM_CLKCTRL_FRAC0_CPUFRAC) - -#define HW_CLKCTRL_FRAC1 (0x000001c0) -#define HW_CLKCTRL_FRAC1_SET (0x000001c4) -#define HW_CLKCTRL_FRAC1_CLR (0x000001c8) -#define HW_CLKCTRL_FRAC1_TOG (0x000001cc) - -#define BP_CLKCTRL_FRAC1_CLKGATEGPMI 23 -#define BM_CLKCTRL_FRAC1_CLKGATEGPMI 0x00800000 -#define BM_CLKCTRL_FRAC1_GPMI_STABLE 0x00400000 -#define BP_CLKCTRL_FRAC1_GPMIFRAC 16 -#define BM_CLKCTRL_FRAC1_GPMIFRAC 0x003F0000 -#define BF_CLKCTRL_FRAC1_GPMIFRAC(v) \ - (((v) << 16) & BM_CLKCTRL_FRAC1_GPMIFRAC) -#define BP_CLKCTRL_FRAC1_CLKGATEHSADC 15 -#define BM_CLKCTRL_FRAC1_CLKGATEHSADC 0x00008000 -#define BM_CLKCTRL_FRAC1_HSADC_STABLE 0x00004000 -#define BP_CLKCTRL_FRAC1_HSADCFRAC 8 -#define BM_CLKCTRL_FRAC1_HSADCFRAC 0x00003F00 -#define BF_CLKCTRL_FRAC1_HSADCFRAC(v) \ - (((v) << 8) & BM_CLKCTRL_FRAC1_HSADCFRAC) -#define BP_CLKCTRL_FRAC1_CLKGATEPIX 7 -#define BM_CLKCTRL_FRAC1_CLKGATEPIX 0x00000080 -#define BM_CLKCTRL_FRAC1_PIX_STABLE 0x00000040 -#define BP_CLKCTRL_FRAC1_PIXFRAC 0 -#define BM_CLKCTRL_FRAC1_PIXFRAC 0x0000003F -#define BF_CLKCTRL_FRAC1_PIXFRAC(v) \ - (((v) << 0) & BM_CLKCTRL_FRAC1_PIXFRAC) - -#define HW_CLKCTRL_CLKSEQ (0x000001d0) -#define HW_CLKCTRL_CLKSEQ_SET (0x000001d4) -#define HW_CLKCTRL_CLKSEQ_CLR (0x000001d8) -#define HW_CLKCTRL_CLKSEQ_TOG (0x000001dc) - -#define BM_CLKCTRL_CLKSEQ_BYPASS_CPU 0x00040000 -#define BM_CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF 0x00004000 -#define BV_CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF__BYPASS 0x1 -#define BV_CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF__PFD 0x0 -#define BM_CLKCTRL_CLKSEQ_BYPASS_ETM 0x00000100 -#define BM_CLKCTRL_CLKSEQ_BYPASS_EMI 0x00000080 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SSP3 0x00000040 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SSP2 0x00000020 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SSP1 0x00000010 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SSP0 0x00000008 -#define BM_CLKCTRL_CLKSEQ_BYPASS_GPMI 0x00000004 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SAIF1 0x00000002 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SAIF0 0x00000001 - -#define HW_CLKCTRL_RESET (0x000001e0) - -#define BM_CLKCTRL_RESET_WDOG_POR_DISABLE 0x00000020 -#define BM_CLKCTRL_RESET_EXTERNAL_RESET_ENABLE 0x00000010 -#define BM_CLKCTRL_RESET_THERMAL_RESET_ENABLE 0x00000008 -#define BM_CLKCTRL_RESET_THERMAL_RESET_DEFAULT 0x00000004 -#define BM_CLKCTRL_RESET_CHIP 0x00000002 -#define BM_CLKCTRL_RESET_DIG 0x00000001 - -#define HW_CLKCTRL_STATUS (0x000001f0) - -#define BP_CLKCTRL_STATUS_CPU_LIMIT 30 -#define BM_CLKCTRL_STATUS_CPU_LIMIT 0xC0000000 -#define BF_CLKCTRL_STATUS_CPU_LIMIT(v) \ - (((v) << 30) & BM_CLKCTRL_STATUS_CPU_LIMIT) - -#define HW_CLKCTRL_VERSION (0x00000200) - -#define BP_CLKCTRL_VERSION_MAJOR 24 -#define BM_CLKCTRL_VERSION_MAJOR 0xFF000000 -#define BF_CLKCTRL_VERSION_MAJOR(v) \ - (((v) << 24) & BM_CLKCTRL_VERSION_MAJOR) -#define BP_CLKCTRL_VERSION_MINOR 16 -#define BM_CLKCTRL_VERSION_MINOR 0x00FF0000 -#define BF_CLKCTRL_VERSION_MINOR(v) \ - (((v) << 16) & BM_CLKCTRL_VERSION_MINOR) -#define BP_CLKCTRL_VERSION_STEP 0 -#define BM_CLKCTRL_VERSION_STEP 0x0000FFFF -#define BF_CLKCTRL_VERSION_STEP(v) \ - (((v) << 0) & BM_CLKCTRL_VERSION_STEP) - -#endif /* __REGS_CLKCTRL_MX28_H__ */ diff --git a/arch/arm/mach-mxs/system.c b/arch/arm/mach-mxs/system.c index 80ac1fca8a00..30042e23bfa7 100644 --- a/arch/arm/mach-mxs/system.c +++ b/arch/arm/mach-mxs/system.c @@ -37,8 +37,6 @@ #define MXS_MODULE_CLKGATE (1 << 30) #define MXS_MODULE_SFTRST (1 << 31) -#define CLKCTRL_TIMEOUT 10 /* 10 ms */ - static void __iomem *mxs_clkctrl_reset_addr; /* @@ -139,17 +137,3 @@ error: return -ETIMEDOUT; } EXPORT_SYMBOL(mxs_reset_block); - -int mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(CLKCTRL_TIMEOUT); - while (readl_relaxed(MXS_IO_ADDRESS(MXS_CLKCTRL_BASE_ADDR) - + reg_offset) & mask) { - if (time_after(jiffies, timeout)) { - pr_err("Timeout at CLKCTRL + 0x%x\n", reg_offset); - return -ETIMEDOUT; - } - } - - return 0; -} diff --git a/arch/arm/mach-mxs/timer.c b/arch/arm/mach-mxs/timer.c index 564a63279f18..02d36de9c4e8 100644 --- a/arch/arm/mach-mxs/timer.c +++ b/arch/arm/mach-mxs/timer.c @@ -20,6 +20,7 @@ * MA 02110-1301, USA. */ +#include <linux/err.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/clockchips.h> @@ -243,8 +244,16 @@ static int __init mxs_clocksource_init(struct clk *timer_clk) return 0; } -void __init mxs_timer_init(struct clk *timer_clk, int irq) +void __init mxs_timer_init(int irq) { + struct clk *timer_clk; + + timer_clk = clk_get_sys("timrot", NULL); + if (IS_ERR(timer_clk)) { + pr_err("%s: failed to get clk\n", __func__); + return; + } + clk_prepare_enable(timer_clk); /* diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c index e2e9db492d0c..9148b229d0de 100644 --- a/arch/arm/mach-orion5x/common.c +++ b/arch/arm/mach-orion5x/common.c @@ -18,6 +18,7 @@ #include <linux/mv643xx_i2c.h> #include <linux/ata_platform.h> #include <linux/delay.h> +#include <linux/clk-provider.h> #include <net/dsa.h> #include <asm/page.h> #include <asm/setup.h> @@ -70,6 +71,19 @@ void __init orion5x_map_io(void) /***************************************************************************** + * CLK tree + ****************************************************************************/ +static struct clk *tclk; + +static void __init clk_init(void) +{ + tclk = clk_register_fixed_rate(NULL, "tclk", NULL, CLK_IS_ROOT, + orion5x_tclk); + + orion_clkdev_init(tclk); +} + +/***************************************************************************** * EHCI0 ****************************************************************************/ void __init orion5x_ehci0_init(void) @@ -95,7 +109,7 @@ void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge00_init(eth_data, ORION5X_ETH_PHYS_BASE, IRQ_ORION5X_ETH_SUM, - IRQ_ORION5X_ETH_ERR, orion5x_tclk); + IRQ_ORION5X_ETH_ERR); } @@ -132,7 +146,7 @@ void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data) ****************************************************************************/ void __init orion5x_spi_init() { - orion_spi_init(SPI_PHYS_BASE, orion5x_tclk); + orion_spi_init(SPI_PHYS_BASE); } @@ -142,7 +156,7 @@ void __init orion5x_spi_init() void __init orion5x_uart0_init(void) { orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE, - IRQ_ORION5X_UART0, orion5x_tclk); + IRQ_ORION5X_UART0, tclk); } /***************************************************************************** @@ -151,7 +165,7 @@ void __init orion5x_uart0_init(void) void __init orion5x_uart1_init(void) { orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE, - IRQ_ORION5X_UART1, orion5x_tclk); + IRQ_ORION5X_UART1, tclk); } /***************************************************************************** @@ -179,7 +193,7 @@ static void __init orion5x_crypto_init(void) ****************************************************************************/ void __init orion5x_wdt_init(void) { - orion_wdt_init(orion5x_tclk); + orion_wdt_init(); } @@ -276,6 +290,9 @@ void __init orion5x_init(void) */ orion5x_setup_cpu_mbus_bridge(); + /* Setup root of clk tree */ + clk_init(); + /* * Don't issue "Wait for Interrupt" instruction if we are * running on D0 5281 silicon. diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c index e91bf0ba4e8e..92df49c1b62a 100644 --- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c +++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c @@ -16,7 +16,6 @@ #include <linux/mtd/physmap.h> #include <linux/mv643xx_eth.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <linux/spi/flash.h> #include <linux/ethtool.h> #include <net/dsa.h> diff --git a/arch/arm/mach-spear3xx/Makefile b/arch/arm/mach-spear3xx/Makefile index 17b5d83cf2d5..8d12faa178fd 100644 --- a/arch/arm/mach-spear3xx/Makefile +++ b/arch/arm/mach-spear3xx/Makefile @@ -3,7 +3,7 @@ # # common files -obj-$(CONFIG_ARCH_SPEAR3XX) += spear3xx.o clock.o +obj-$(CONFIG_ARCH_SPEAR3XX) += spear3xx.o # spear300 specific files obj-$(CONFIG_MACH_SPEAR300) += spear300.o diff --git a/arch/arm/mach-spear3xx/clock.c b/arch/arm/mach-spear3xx/clock.c deleted file mode 100644 index cd6c11099083..000000000000 --- a/arch/arm/mach-spear3xx/clock.c +++ /dev/null @@ -1,892 +0,0 @@ -/* - * arch/arm/mach-spear3xx/clock.c - * - * SPEAr3xx machines clock framework source file - * - * Copyright (C) 2009 ST Microelectronics - * Viresh Kumar<viresh.kumar@st.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/clkdev.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/of_platform.h> -#include <asm/mach-types.h> -#include <plat/clock.h> -#include <mach/misc_regs.h> -#include <mach/spear.h> - -#define PLL1_CTR (MISC_BASE + 0x008) -#define PLL1_FRQ (MISC_BASE + 0x00C) -#define PLL1_MOD (MISC_BASE + 0x010) -#define PLL2_CTR (MISC_BASE + 0x014) -/* PLL_CTR register masks */ -#define PLL_ENABLE 2 -#define PLL_MODE_SHIFT 4 -#define PLL_MODE_MASK 0x3 -#define PLL_MODE_NORMAL 0 -#define PLL_MODE_FRACTION 1 -#define PLL_MODE_DITH_DSB 2 -#define PLL_MODE_DITH_SSB 3 - -#define PLL2_FRQ (MISC_BASE + 0x018) -/* PLL FRQ register masks */ -#define PLL_DIV_N_SHIFT 0 -#define PLL_DIV_N_MASK 0xFF -#define PLL_DIV_P_SHIFT 8 -#define PLL_DIV_P_MASK 0x7 -#define PLL_NORM_FDBK_M_SHIFT 24 -#define PLL_NORM_FDBK_M_MASK 0xFF -#define PLL_DITH_FDBK_M_SHIFT 16 -#define PLL_DITH_FDBK_M_MASK 0xFFFF - -#define PLL2_MOD (MISC_BASE + 0x01C) -#define PLL_CLK_CFG (MISC_BASE + 0x020) -#define CORE_CLK_CFG (MISC_BASE + 0x024) -/* CORE CLK CFG register masks */ -#define PLL_HCLK_RATIO_SHIFT 10 -#define PLL_HCLK_RATIO_MASK 0x3 -#define HCLK_PCLK_RATIO_SHIFT 8 -#define HCLK_PCLK_RATIO_MASK 0x3 - -#define PERIP_CLK_CFG (MISC_BASE + 0x028) -/* PERIP_CLK_CFG register masks */ -#define UART_CLK_SHIFT 4 -#define UART_CLK_MASK 0x1 -#define FIRDA_CLK_SHIFT 5 -#define FIRDA_CLK_MASK 0x3 -#define GPT0_CLK_SHIFT 8 -#define GPT1_CLK_SHIFT 11 -#define GPT2_CLK_SHIFT 12 -#define GPT_CLK_MASK 0x1 -#define AUX_CLK_PLL3_VAL 0 -#define AUX_CLK_PLL1_VAL 1 - -#define PERIP1_CLK_ENB (MISC_BASE + 0x02C) -/* PERIP1_CLK_ENB register masks */ -#define UART_CLK_ENB 3 -#define SSP_CLK_ENB 5 -#define I2C_CLK_ENB 7 -#define JPEG_CLK_ENB 8 -#define FIRDA_CLK_ENB 10 -#define GPT1_CLK_ENB 11 -#define GPT2_CLK_ENB 12 -#define ADC_CLK_ENB 15 -#define RTC_CLK_ENB 17 -#define GPIO_CLK_ENB 18 -#define DMA_CLK_ENB 19 -#define SMI_CLK_ENB 21 -#define GMAC_CLK_ENB 23 -#define USBD_CLK_ENB 24 -#define USBH_CLK_ENB 25 -#define C3_CLK_ENB 31 - -#define RAS_CLK_ENB (MISC_BASE + 0x034) - -#define PRSC1_CLK_CFG (MISC_BASE + 0x044) -#define PRSC2_CLK_CFG (MISC_BASE + 0x048) -#define PRSC3_CLK_CFG (MISC_BASE + 0x04C) -/* gpt synthesizer register masks */ -#define GPT_MSCALE_SHIFT 0 -#define GPT_MSCALE_MASK 0xFFF -#define GPT_NSCALE_SHIFT 12 -#define GPT_NSCALE_MASK 0xF - -#define AMEM_CLK_CFG (MISC_BASE + 0x050) -#define EXPI_CLK_CFG (MISC_BASE + 0x054) -#define CLCD_CLK_SYNT (MISC_BASE + 0x05C) -#define FIRDA_CLK_SYNT (MISC_BASE + 0x060) -#define UART_CLK_SYNT (MISC_BASE + 0x064) -#define GMAC_CLK_SYNT (MISC_BASE + 0x068) -#define RAS1_CLK_SYNT (MISC_BASE + 0x06C) -#define RAS2_CLK_SYNT (MISC_BASE + 0x070) -#define RAS3_CLK_SYNT (MISC_BASE + 0x074) -#define RAS4_CLK_SYNT (MISC_BASE + 0x078) -/* aux clk synthesiser register masks for irda to ras4 */ -#define AUX_SYNT_ENB 31 -#define AUX_EQ_SEL_SHIFT 30 -#define AUX_EQ_SEL_MASK 1 -#define AUX_EQ1_SEL 0 -#define AUX_EQ2_SEL 1 -#define AUX_XSCALE_SHIFT 16 -#define AUX_XSCALE_MASK 0xFFF -#define AUX_YSCALE_SHIFT 0 -#define AUX_YSCALE_MASK 0xFFF - -/* root clks */ -/* 32 KHz oscillator clock */ -static struct clk osc_32k_clk = { - .flags = ALWAYS_ENABLED, - .rate = 32000, -}; - -/* 24 MHz oscillator clock */ -static struct clk osc_24m_clk = { - .flags = ALWAYS_ENABLED, - .rate = 24000000, -}; - -/* clock derived from 32 KHz osc clk */ -/* rtc clock */ -static struct clk rtc_clk = { - .pclk = &osc_32k_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = RTC_CLK_ENB, - .recalc = &follow_parent, -}; - -/* clock derived from 24 MHz osc clk */ -/* pll masks structure */ -static struct pll_clk_masks pll1_masks = { - .mode_mask = PLL_MODE_MASK, - .mode_shift = PLL_MODE_SHIFT, - .norm_fdbk_m_mask = PLL_NORM_FDBK_M_MASK, - .norm_fdbk_m_shift = PLL_NORM_FDBK_M_SHIFT, - .dith_fdbk_m_mask = PLL_DITH_FDBK_M_MASK, - .dith_fdbk_m_shift = PLL_DITH_FDBK_M_SHIFT, - .div_p_mask = PLL_DIV_P_MASK, - .div_p_shift = PLL_DIV_P_SHIFT, - .div_n_mask = PLL_DIV_N_MASK, - .div_n_shift = PLL_DIV_N_SHIFT, -}; - -/* pll1 configuration structure */ -static struct pll_clk_config pll1_config = { - .mode_reg = PLL1_CTR, - .cfg_reg = PLL1_FRQ, - .masks = &pll1_masks, -}; - -/* pll rate configuration table, in ascending order of rates */ -struct pll_rate_tbl pll_rtbl[] = { - {.mode = 0, .m = 0x85, .n = 0x0C, .p = 0x1}, /* 266 MHz */ - {.mode = 0, .m = 0xA6, .n = 0x0C, .p = 0x1}, /* 332 MHz */ -}; - -/* PLL1 clock */ -static struct clk pll1_clk = { - .flags = ENABLED_ON_INIT, - .pclk = &osc_24m_clk, - .en_reg = PLL1_CTR, - .en_reg_bit = PLL_ENABLE, - .calc_rate = &pll_calc_rate, - .recalc = &pll_clk_recalc, - .set_rate = &pll_clk_set_rate, - .rate_config = {pll_rtbl, ARRAY_SIZE(pll_rtbl), 1}, - .private_data = &pll1_config, -}; - -/* PLL3 48 MHz clock */ -static struct clk pll3_48m_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &osc_24m_clk, - .rate = 48000000, -}; - -/* watch dog timer clock */ -static struct clk wdt_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &osc_24m_clk, - .recalc = &follow_parent, -}; - -/* clock derived from pll1 clk */ -/* cpu clock */ -static struct clk cpu_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .recalc = &follow_parent, -}; - -/* ahb masks structure */ -static struct bus_clk_masks ahb_masks = { - .mask = PLL_HCLK_RATIO_MASK, - .shift = PLL_HCLK_RATIO_SHIFT, -}; - -/* ahb configuration structure */ -static struct bus_clk_config ahb_config = { - .reg = CORE_CLK_CFG, - .masks = &ahb_masks, -}; - -/* ahb rate configuration table, in ascending order of rates */ -struct bus_rate_tbl bus_rtbl[] = { - {.div = 3}, /* == parent divided by 4 */ - {.div = 2}, /* == parent divided by 3 */ - {.div = 1}, /* == parent divided by 2 */ - {.div = 0}, /* == parent divided by 1 */ -}; - -/* ahb clock */ -static struct clk ahb_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &bus_calc_rate, - .recalc = &bus_clk_recalc, - .set_rate = &bus_clk_set_rate, - .rate_config = {bus_rtbl, ARRAY_SIZE(bus_rtbl), 2}, - .private_data = &ahb_config, -}; - -/* auxiliary synthesizers masks */ -static struct aux_clk_masks aux_masks = { - .eq_sel_mask = AUX_EQ_SEL_MASK, - .eq_sel_shift = AUX_EQ_SEL_SHIFT, - .eq1_mask = AUX_EQ1_SEL, - .eq2_mask = AUX_EQ2_SEL, - .xscale_sel_mask = AUX_XSCALE_MASK, - .xscale_sel_shift = AUX_XSCALE_SHIFT, - .yscale_sel_mask = AUX_YSCALE_MASK, - .yscale_sel_shift = AUX_YSCALE_SHIFT, -}; - -/* uart synth configurations */ -static struct aux_clk_config uart_synth_config = { - .synth_reg = UART_CLK_SYNT, - .masks = &aux_masks, -}; - -/* aux rate configuration table, in ascending order of rates */ -struct aux_rate_tbl aux_rtbl[] = { - /* For PLL1 = 332 MHz */ - {.xscale = 1, .yscale = 8, .eq = 1}, /* 41.5 MHz */ - {.xscale = 1, .yscale = 4, .eq = 1}, /* 83 MHz */ - {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */ -}; - -/* uart synth clock */ -static struct clk uart_synth_clk = { - .en_reg = UART_CLK_SYNT, - .en_reg_bit = AUX_SYNT_ENB, - .pclk = &pll1_clk, - .calc_rate = &aux_calc_rate, - .recalc = &aux_clk_recalc, - .set_rate = &aux_clk_set_rate, - .rate_config = {aux_rtbl, ARRAY_SIZE(aux_rtbl), 1}, - .private_data = &uart_synth_config, -}; - -/* uart parents */ -static struct pclk_info uart_pclk_info[] = { - { - .pclk = &uart_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* uart parent select structure */ -static struct pclk_sel uart_pclk_sel = { - .pclk_info = uart_pclk_info, - .pclk_count = ARRAY_SIZE(uart_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = UART_CLK_MASK, -}; - -/* uart clock */ -static struct clk uart_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = UART_CLK_ENB, - .pclk_sel = &uart_pclk_sel, - .pclk_sel_shift = UART_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* firda configurations */ -static struct aux_clk_config firda_synth_config = { - .synth_reg = FIRDA_CLK_SYNT, - .masks = &aux_masks, -}; - -/* firda synth clock */ -static struct clk firda_synth_clk = { - .en_reg = FIRDA_CLK_SYNT, - .en_reg_bit = AUX_SYNT_ENB, - .pclk = &pll1_clk, - .calc_rate = &aux_calc_rate, - .recalc = &aux_clk_recalc, - .set_rate = &aux_clk_set_rate, - .rate_config = {aux_rtbl, ARRAY_SIZE(aux_rtbl), 1}, - .private_data = &firda_synth_config, -}; - -/* firda parents */ -static struct pclk_info firda_pclk_info[] = { - { - .pclk = &firda_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* firda parent select structure */ -static struct pclk_sel firda_pclk_sel = { - .pclk_info = firda_pclk_info, - .pclk_count = ARRAY_SIZE(firda_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = FIRDA_CLK_MASK, -}; - -/* firda clock */ -static struct clk firda_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = FIRDA_CLK_ENB, - .pclk_sel = &firda_pclk_sel, - .pclk_sel_shift = FIRDA_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* gpt synthesizer masks */ -static struct gpt_clk_masks gpt_masks = { - .mscale_sel_mask = GPT_MSCALE_MASK, - .mscale_sel_shift = GPT_MSCALE_SHIFT, - .nscale_sel_mask = GPT_NSCALE_MASK, - .nscale_sel_shift = GPT_NSCALE_SHIFT, -}; - -/* gpt rate configuration table, in ascending order of rates */ -struct gpt_rate_tbl gpt_rtbl[] = { - /* For pll1 = 332 MHz */ - {.mscale = 4, .nscale = 0}, /* 41.5 MHz */ - {.mscale = 2, .nscale = 0}, /* 55.3 MHz */ - {.mscale = 1, .nscale = 0}, /* 83 MHz */ -}; - -/* gpt0 synth clk config*/ -static struct gpt_clk_config gpt0_synth_config = { - .synth_reg = PRSC1_CLK_CFG, - .masks = &gpt_masks, -}; - -/* gpt synth clock */ -static struct clk gpt0_synth_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &gpt_calc_rate, - .recalc = &gpt_clk_recalc, - .set_rate = &gpt_clk_set_rate, - .rate_config = {gpt_rtbl, ARRAY_SIZE(gpt_rtbl), 2}, - .private_data = &gpt0_synth_config, -}; - -/* gpt parents */ -static struct pclk_info gpt0_pclk_info[] = { - { - .pclk = &gpt0_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* gpt parent select structure */ -static struct pclk_sel gpt0_pclk_sel = { - .pclk_info = gpt0_pclk_info, - .pclk_count = ARRAY_SIZE(gpt0_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt0 timer clock */ -static struct clk gpt0_clk = { - .flags = ALWAYS_ENABLED, - .pclk_sel = &gpt0_pclk_sel, - .pclk_sel_shift = GPT0_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* gpt1 synth clk configurations */ -static struct gpt_clk_config gpt1_synth_config = { - .synth_reg = PRSC2_CLK_CFG, - .masks = &gpt_masks, -}; - -/* gpt1 synth clock */ -static struct clk gpt1_synth_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &gpt_calc_rate, - .recalc = &gpt_clk_recalc, - .set_rate = &gpt_clk_set_rate, - .rate_config = {gpt_rtbl, ARRAY_SIZE(gpt_rtbl), 2}, - .private_data = &gpt1_synth_config, -}; - -static struct pclk_info gpt1_pclk_info[] = { - { - .pclk = &gpt1_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* gpt parent select structure */ -static struct pclk_sel gpt1_pclk_sel = { - .pclk_info = gpt1_pclk_info, - .pclk_count = ARRAY_SIZE(gpt1_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt1 timer clock */ -static struct clk gpt1_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GPT1_CLK_ENB, - .pclk_sel = &gpt1_pclk_sel, - .pclk_sel_shift = GPT1_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* gpt2 synth clk configurations */ -static struct gpt_clk_config gpt2_synth_config = { - .synth_reg = PRSC3_CLK_CFG, - .masks = &gpt_masks, -}; - -/* gpt1 synth clock */ -static struct clk gpt2_synth_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &gpt_calc_rate, - .recalc = &gpt_clk_recalc, - .set_rate = &gpt_clk_set_rate, - .rate_config = {gpt_rtbl, ARRAY_SIZE(gpt_rtbl), 2}, - .private_data = &gpt2_synth_config, -}; - -static struct pclk_info gpt2_pclk_info[] = { - { - .pclk = &gpt2_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* gpt parent select structure */ -static struct pclk_sel gpt2_pclk_sel = { - .pclk_info = gpt2_pclk_info, - .pclk_count = ARRAY_SIZE(gpt2_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt2 timer clock */ -static struct clk gpt2_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GPT2_CLK_ENB, - .pclk_sel = &gpt2_pclk_sel, - .pclk_sel_shift = GPT2_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* clock derived from pll3 clk */ -/* usbh clock */ -static struct clk usbh_clk = { - .pclk = &pll3_48m_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = USBH_CLK_ENB, - .recalc = &follow_parent, -}; - -/* usbd clock */ -static struct clk usbd_clk = { - .pclk = &pll3_48m_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = USBD_CLK_ENB, - .recalc = &follow_parent, -}; - -/* clock derived from usbh clk */ -/* usbh0 clock */ -static struct clk usbh0_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &usbh_clk, - .recalc = &follow_parent, -}; - -/* usbh1 clock */ -static struct clk usbh1_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &usbh_clk, - .recalc = &follow_parent, -}; - -/* clock derived from ahb clk */ -/* apb masks structure */ -static struct bus_clk_masks apb_masks = { - .mask = HCLK_PCLK_RATIO_MASK, - .shift = HCLK_PCLK_RATIO_SHIFT, -}; - -/* apb configuration structure */ -static struct bus_clk_config apb_config = { - .reg = CORE_CLK_CFG, - .masks = &apb_masks, -}; - -/* apb clock */ -static struct clk apb_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &ahb_clk, - .calc_rate = &bus_calc_rate, - .recalc = &bus_clk_recalc, - .set_rate = &bus_clk_set_rate, - .rate_config = {bus_rtbl, ARRAY_SIZE(bus_rtbl), 2}, - .private_data = &apb_config, -}; - -/* i2c clock */ -static struct clk i2c_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = I2C_CLK_ENB, - .recalc = &follow_parent, -}; - -/* dma clock */ -static struct clk dma_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = DMA_CLK_ENB, - .recalc = &follow_parent, -}; - -/* jpeg clock */ -static struct clk jpeg_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = JPEG_CLK_ENB, - .recalc = &follow_parent, -}; - -/* gmac clock */ -static struct clk gmac_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GMAC_CLK_ENB, - .recalc = &follow_parent, -}; - -/* smi clock */ -static struct clk smi_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = SMI_CLK_ENB, - .recalc = &follow_parent, -}; - -/* c3 clock */ -static struct clk c3_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = C3_CLK_ENB, - .recalc = &follow_parent, -}; - -/* clock derived from apb clk */ -/* adc clock */ -static struct clk adc_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = ADC_CLK_ENB, - .recalc = &follow_parent, -}; - -#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320) -/* emi clock */ -static struct clk emi_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &ahb_clk, - .recalc = &follow_parent, -}; -#endif - -/* ssp clock */ -static struct clk ssp0_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = SSP_CLK_ENB, - .recalc = &follow_parent, -}; - -/* gpio clock */ -static struct clk gpio_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GPIO_CLK_ENB, - .recalc = &follow_parent, -}; - -static struct clk dummy_apb_pclk; - -#if defined(CONFIG_MACH_SPEAR300) || defined(CONFIG_MACH_SPEAR310) || \ - defined(CONFIG_MACH_SPEAR320) -/* fsmc clock */ -static struct clk fsmc_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &ahb_clk, - .recalc = &follow_parent, -}; -#endif - -/* common clocks to spear310 and spear320 */ -#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320) -/* uart1 clock */ -static struct clk uart1_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* uart2 clock */ -static struct clk uart2_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; -#endif /* CONFIG_MACH_SPEAR310 || CONFIG_MACH_SPEAR320 */ - -/* common clocks to spear300 and spear320 */ -#if defined(CONFIG_MACH_SPEAR300) || defined(CONFIG_MACH_SPEAR320) -/* clcd clock */ -static struct clk clcd_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll3_48m_clk, - .recalc = &follow_parent, -}; - -/* sdhci clock */ -static struct clk sdhci_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &ahb_clk, - .recalc = &follow_parent, -}; -#endif /* CONFIG_MACH_SPEAR300 || CONFIG_MACH_SPEAR320 */ - -/* spear300 machine specific clock structures */ -#ifdef CONFIG_MACH_SPEAR300 -/* gpio1 clock */ -static struct clk gpio1_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* keyboard clock */ -static struct clk kbd_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -#endif - -/* spear310 machine specific clock structures */ -#ifdef CONFIG_MACH_SPEAR310 -/* uart3 clock */ -static struct clk uart3_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* uart4 clock */ -static struct clk uart4_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* uart5 clock */ -static struct clk uart5_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; -#endif - -/* spear320 machine specific clock structures */ -#ifdef CONFIG_MACH_SPEAR320 -/* can0 clock */ -static struct clk can0_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* can1 clock */ -static struct clk can1_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* i2c1 clock */ -static struct clk i2c1_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &ahb_clk, - .recalc = &follow_parent, -}; - -/* ssp1 clock */ -static struct clk ssp1_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* ssp2 clock */ -static struct clk ssp2_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* pwm clock */ -static struct clk pwm_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; -#endif - -/* array of all spear 3xx clock lookups */ -static struct clk_lookup spear_clk_lookups[] = { - CLKDEV_INIT(NULL, "apb_pclk", &dummy_apb_pclk), - /* root clks */ - CLKDEV_INIT(NULL, "osc_32k_clk", &osc_32k_clk), - CLKDEV_INIT(NULL, "osc_24m_clk", &osc_24m_clk), - /* clock derived from 32 KHz osc clk */ - CLKDEV_INIT("fc900000.rtc", NULL, &rtc_clk), - /* clock derived from 24 MHz osc clk */ - CLKDEV_INIT(NULL, "pll1_clk", &pll1_clk), - CLKDEV_INIT(NULL, "pll3_48m_clk", &pll3_48m_clk), - CLKDEV_INIT("fc880000.wdt", NULL, &wdt_clk), - /* clock derived from pll1 clk */ - CLKDEV_INIT(NULL, "cpu_clk", &cpu_clk), - CLKDEV_INIT(NULL, "ahb_clk", &ahb_clk), - CLKDEV_INIT(NULL, "uart_synth_clk", &uart_synth_clk), - CLKDEV_INIT(NULL, "firda_synth_clk", &firda_synth_clk), - CLKDEV_INIT(NULL, "gpt0_synth_clk", &gpt0_synth_clk), - CLKDEV_INIT(NULL, "gpt1_synth_clk", &gpt1_synth_clk), - CLKDEV_INIT(NULL, "gpt2_synth_clk", &gpt2_synth_clk), - CLKDEV_INIT("d0000000.serial", NULL, &uart_clk), - CLKDEV_INIT("firda", NULL, &firda_clk), - CLKDEV_INIT("gpt0", NULL, &gpt0_clk), - CLKDEV_INIT("gpt1", NULL, &gpt1_clk), - CLKDEV_INIT("gpt2", NULL, &gpt2_clk), - /* clock derived from pll3 clk */ - CLKDEV_INIT("designware_udc", NULL, &usbd_clk), - CLKDEV_INIT(NULL, "usbh_clk", &usbh_clk), - /* clock derived from usbh clk */ - CLKDEV_INIT(NULL, "usbh.0_clk", &usbh0_clk), - CLKDEV_INIT(NULL, "usbh.1_clk", &usbh1_clk), - /* clock derived from ahb clk */ - CLKDEV_INIT(NULL, "apb_clk", &apb_clk), - CLKDEV_INIT("d0180000.i2c", NULL, &i2c_clk), - CLKDEV_INIT("fc400000.dma", NULL, &dma_clk), - CLKDEV_INIT("jpeg", NULL, &jpeg_clk), - CLKDEV_INIT("e0800000.eth", NULL, &gmac_clk), - CLKDEV_INIT("fc000000.flash", NULL, &smi_clk), - CLKDEV_INIT("c3", NULL, &c3_clk), - /* clock derived from apb clk */ - CLKDEV_INIT("adc", NULL, &adc_clk), - CLKDEV_INIT("d0100000.spi", NULL, &ssp0_clk), - CLKDEV_INIT("fc980000.gpio", NULL, &gpio_clk), -}; - -/* array of all spear 300 clock lookups */ -#ifdef CONFIG_MACH_SPEAR300 -static struct clk_lookup spear300_clk_lookups[] = { - CLKDEV_INIT("60000000.clcd", NULL, &clcd_clk), - CLKDEV_INIT("94000000.flash", NULL, &fsmc_clk), - CLKDEV_INIT("a9000000.gpio", NULL, &gpio1_clk), - CLKDEV_INIT("a0000000.kbd", NULL, &kbd_clk), - CLKDEV_INIT("70000000.sdhci", NULL, &sdhci_clk), -}; - -void __init spear300_clk_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++) - clk_register(&spear_clk_lookups[i]); - - for (i = 0; i < ARRAY_SIZE(spear300_clk_lookups); i++) - clk_register(&spear300_clk_lookups[i]); - - clk_init(); -} -#endif - -/* array of all spear 310 clock lookups */ -#ifdef CONFIG_MACH_SPEAR310 -static struct clk_lookup spear310_clk_lookups[] = { - CLKDEV_INIT("44000000.flash", NULL, &fsmc_clk), - CLKDEV_INIT(NULL, "emi", &emi_clk), - CLKDEV_INIT("b2000000.serial", NULL, &uart1_clk), - CLKDEV_INIT("b2080000.serial", NULL, &uart2_clk), - CLKDEV_INIT("b2100000.serial", NULL, &uart3_clk), - CLKDEV_INIT("b2180000.serial", NULL, &uart4_clk), - CLKDEV_INIT("b2200000.serial", NULL, &uart5_clk), -}; - -void __init spear310_clk_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++) - clk_register(&spear_clk_lookups[i]); - - for (i = 0; i < ARRAY_SIZE(spear310_clk_lookups); i++) - clk_register(&spear310_clk_lookups[i]); - - clk_init(); -} -#endif - -/* array of all spear 320 clock lookups */ -#ifdef CONFIG_MACH_SPEAR320 -static struct clk_lookup spear320_clk_lookups[] = { - CLKDEV_INIT("90000000.clcd", NULL, &clcd_clk), - CLKDEV_INIT("4c000000.flash", NULL, &fsmc_clk), - CLKDEV_INIT("a7000000.i2c", NULL, &i2c1_clk), - CLKDEV_INIT(NULL, "emi", &emi_clk), - CLKDEV_INIT("pwm", NULL, &pwm_clk), - CLKDEV_INIT("70000000.sdhci", NULL, &sdhci_clk), - CLKDEV_INIT("c_can_platform.0", NULL, &can0_clk), - CLKDEV_INIT("c_can_platform.1", NULL, &can1_clk), - CLKDEV_INIT("a5000000.spi", NULL, &ssp1_clk), - CLKDEV_INIT("a6000000.spi", NULL, &ssp2_clk), - CLKDEV_INIT("a3000000.serial", NULL, &uart1_clk), - CLKDEV_INIT("a4000000.serial", NULL, &uart2_clk), -}; - -void __init spear320_clk_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++) - clk_register(&spear_clk_lookups[i]); - - for (i = 0; i < ARRAY_SIZE(spear320_clk_lookups); i++) - clk_register(&spear320_clk_lookups[i]); - - clk_init(); -} -#endif diff --git a/arch/arm/mach-spear3xx/include/mach/generic.h b/arch/arm/mach-spear3xx/include/mach/generic.h index bdb304551caf..4a95b9453c2a 100644 --- a/arch/arm/mach-spear3xx/include/mach/generic.h +++ b/arch/arm/mach-spear3xx/include/mach/generic.h @@ -27,28 +27,11 @@ extern struct pl022_ssp_controller pl022_plat_data; extern struct pl08x_platform_data pl080_plat_data; /* Add spear3xx family function declarations here */ -void __init spear_setup_timer(resource_size_t base, int irq); +void __init spear_setup_of_timer(void); +void __init spear3xx_clk_init(void); void __init spear3xx_map_io(void); void __init spear3xx_dt_init_irq(void); void spear_restart(char, const char *); -/* spear300 declarations */ -#ifdef CONFIG_MACH_SPEAR300 -void __init spear300_clk_init(void); - -#endif /* CONFIG_MACH_SPEAR300 */ - -/* spear310 declarations */ -#ifdef CONFIG_MACH_SPEAR310 -void __init spear310_clk_init(void); - -#endif /* CONFIG_MACH_SPEAR310 */ - -/* spear320 declarations */ -#ifdef CONFIG_MACH_SPEAR320 -void __init spear320_clk_init(void); - -#endif /* CONFIG_MACH_SPEAR320 */ - #endif /* __MACH_GENERIC_H */ diff --git a/arch/arm/mach-spear3xx/include/mach/irqs.h b/arch/arm/mach-spear3xx/include/mach/irqs.h index 319620a1afb4..51bd62a0254c 100644 --- a/arch/arm/mach-spear3xx/include/mach/irqs.h +++ b/arch/arm/mach-spear3xx/include/mach/irqs.h @@ -16,7 +16,6 @@ /* FIXME: probe all these from DT */ #define SPEAR3XX_IRQ_INTRCOMM_RAS_ARM 1 -#define SPEAR3XX_IRQ_CPU_GPT1_1 2 #define SPEAR3XX_IRQ_GEN_RAS_1 28 #define SPEAR3XX_IRQ_GEN_RAS_2 29 #define SPEAR3XX_IRQ_GEN_RAS_3 30 diff --git a/arch/arm/mach-spear3xx/include/mach/misc_regs.h b/arch/arm/mach-spear3xx/include/mach/misc_regs.h index e0ab72e61507..18e2ac576f25 100644 --- a/arch/arm/mach-spear3xx/include/mach/misc_regs.h +++ b/arch/arm/mach-spear3xx/include/mach/misc_regs.h @@ -14,6 +14,8 @@ #ifndef __MACH_MISC_REGS_H #define __MACH_MISC_REGS_H +#include <mach/spear.h> + #define MISC_BASE IOMEM(VA_SPEAR3XX_ICM3_MISC_REG_BASE) #define DMA_CHN_CFG (MISC_BASE + 0x0A0) diff --git a/arch/arm/mach-spear3xx/include/mach/spear.h b/arch/arm/mach-spear3xx/include/mach/spear.h index 6d4dadc67633..51eb953148a9 100644 --- a/arch/arm/mach-spear3xx/include/mach/spear.h +++ b/arch/arm/mach-spear3xx/include/mach/spear.h @@ -26,7 +26,6 @@ /* ML1 - Multi Layer CPU Subsystem */ #define SPEAR3XX_ICM3_ML1_2_BASE UL(0xF0000000) #define VA_SPEAR6XX_ML_CPU_BASE UL(0xF0000000) -#define SPEAR3XX_CPU_TMR_BASE UL(0xF0000000) /* ICM3 - Basic Subsystem */ #define SPEAR3XX_ICM3_SMI_CTRL_BASE UL(0xFC000000) @@ -45,4 +44,17 @@ #define SPEAR_SYS_CTRL_BASE SPEAR3XX_ICM3_SYS_CTRL_BASE #define VA_SPEAR_SYS_CTRL_BASE VA_SPEAR3XX_ICM3_SYS_CTRL_BASE +/* SPEAr320 Macros */ +#define SPEAR320_SOC_CONFIG_BASE UL(0xB3000000) +#define VA_SPEAR320_SOC_CONFIG_BASE UL(0xFE000000) +#define SPEAR320_CONTROL_REG IOMEM(VA_SPEAR320_SOC_CONFIG_BASE) +#define SPEAR320_EXT_CTRL_REG IOMEM(VA_SPEAR320_SOC_CONFIG_BASE + 0x0018) + #define SPEAR320_UARTX_PCLK_MASK 0x1 + #define SPEAR320_UART2_PCLK_SHIFT 8 + #define SPEAR320_UART3_PCLK_SHIFT 9 + #define SPEAR320_UART4_PCLK_SHIFT 10 + #define SPEAR320_UART5_PCLK_SHIFT 11 + #define SPEAR320_UART6_PCLK_SHIFT 12 + #define SPEAR320_RS485_PCLK_SHIFT 13 + #endif /* __MACH_SPEAR3XX_H */ diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c index f75fe25a620c..f74a05bdb829 100644 --- a/arch/arm/mach-spear3xx/spear300.c +++ b/arch/arm/mach-spear3xx/spear300.c @@ -337,7 +337,6 @@ static const char * const spear300_dt_board_compat[] = { static void __init spear300_map_io(void) { spear3xx_map_io(); - spear300_clk_init(); } DT_MACHINE_START(SPEAR300_DT, "ST SPEAr300 SoC with Flattened Device Tree") diff --git a/arch/arm/mach-spear3xx/spear310.c b/arch/arm/mach-spear3xx/spear310.c index f0842a58dc02..84dfb0900747 100644 --- a/arch/arm/mach-spear3xx/spear310.c +++ b/arch/arm/mach-spear3xx/spear310.c @@ -478,7 +478,6 @@ static const char * const spear310_dt_board_compat[] = { static void __init spear310_map_io(void) { spear3xx_map_io(); - spear310_clk_init(); } DT_MACHINE_START(SPEAR310_DT, "ST SPEAr310 SoC with Flattened Device Tree") diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c index e8caeef50a5c..a88fa841d29d 100644 --- a/arch/arm/mach-spear3xx/spear320.c +++ b/arch/arm/mach-spear3xx/spear320.c @@ -27,7 +27,6 @@ #define SPEAR320_UART2_BASE UL(0xA4000000) #define SPEAR320_SSP0_BASE UL(0xA5000000) #define SPEAR320_SSP1_BASE UL(0xA6000000) -#define SPEAR320_SOC_CONFIG_BASE UL(0xB3000000) /* Interrupt registers offsets and masks */ #define SPEAR320_INT_STS_MASK_REG 0x04 @@ -481,10 +480,19 @@ static const char * const spear320_dt_board_compat[] = { NULL, }; +struct map_desc spear320_io_desc[] __initdata = { + { + .virtual = VA_SPEAR320_SOC_CONFIG_BASE, + .pfn = __phys_to_pfn(SPEAR320_SOC_CONFIG_BASE), + .length = SZ_16M, + .type = MT_DEVICE + }, +}; + static void __init spear320_map_io(void) { + iotable_init(spear320_io_desc, ARRAY_SIZE(spear320_io_desc)); spear3xx_map_io(); - spear320_clk_init(); } DT_MACHINE_START(SPEAR320_DT, "ST SPEAr320 SoC with Flattened Device Tree") diff --git a/arch/arm/mach-spear3xx/spear3xx.c b/arch/arm/mach-spear3xx/spear3xx.c index 826ac20ef1e7..f22419ed74a8 100644 --- a/arch/arm/mach-spear3xx/spear3xx.c +++ b/arch/arm/mach-spear3xx/spear3xx.c @@ -90,6 +90,8 @@ static void __init spear3xx_timer_init(void) char pclk_name[] = "pll3_48m_clk"; struct clk *gpt_clk, *pclk; + spear3xx_clk_init(); + /* get the system timer clock */ gpt_clk = clk_get_sys("gpt0", NULL); if (IS_ERR(gpt_clk)) { @@ -109,7 +111,7 @@ static void __init spear3xx_timer_init(void) clk_put(gpt_clk); clk_put(pclk); - spear_setup_timer(SPEAR3XX_CPU_TMR_BASE, SPEAR3XX_IRQ_CPU_GPT1_1); + spear_setup_of_timer(); } struct sys_timer spear3xx_timer = { diff --git a/arch/arm/mach-spear6xx/Makefile b/arch/arm/mach-spear6xx/Makefile index 76e5750552fc..898831d93f37 100644 --- a/arch/arm/mach-spear6xx/Makefile +++ b/arch/arm/mach-spear6xx/Makefile @@ -3,4 +3,4 @@ # # common files -obj-y += clock.o spear6xx.o +obj-y += spear6xx.o diff --git a/arch/arm/mach-spear6xx/clock.c b/arch/arm/mach-spear6xx/clock.c deleted file mode 100644 index bef77d43db87..000000000000 --- a/arch/arm/mach-spear6xx/clock.c +++ /dev/null @@ -1,789 +0,0 @@ -/* - * arch/arm/mach-spear6xx/clock.c - * - * SPEAr6xx machines clock framework source file - * - * Copyright (C) 2009 ST Microelectronics - * Viresh Kumar<viresh.kumar@st.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/init.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <plat/clock.h> -#include <mach/misc_regs.h> -#include <mach/spear.h> - -#define PLL1_CTR (MISC_BASE + 0x008) -#define PLL1_FRQ (MISC_BASE + 0x00C) -#define PLL1_MOD (MISC_BASE + 0x010) -#define PLL2_CTR (MISC_BASE + 0x014) -/* PLL_CTR register masks */ -#define PLL_ENABLE 2 -#define PLL_MODE_SHIFT 4 -#define PLL_MODE_MASK 0x3 -#define PLL_MODE_NORMAL 0 -#define PLL_MODE_FRACTION 1 -#define PLL_MODE_DITH_DSB 2 -#define PLL_MODE_DITH_SSB 3 - -#define PLL2_FRQ (MISC_BASE + 0x018) -/* PLL FRQ register masks */ -#define PLL_DIV_N_SHIFT 0 -#define PLL_DIV_N_MASK 0xFF -#define PLL_DIV_P_SHIFT 8 -#define PLL_DIV_P_MASK 0x7 -#define PLL_NORM_FDBK_M_SHIFT 24 -#define PLL_NORM_FDBK_M_MASK 0xFF -#define PLL_DITH_FDBK_M_SHIFT 16 -#define PLL_DITH_FDBK_M_MASK 0xFFFF - -#define PLL2_MOD (MISC_BASE + 0x01C) -#define PLL_CLK_CFG (MISC_BASE + 0x020) -#define CORE_CLK_CFG (MISC_BASE + 0x024) -/* CORE CLK CFG register masks */ -#define PLL_HCLK_RATIO_SHIFT 10 -#define PLL_HCLK_RATIO_MASK 0x3 -#define HCLK_PCLK_RATIO_SHIFT 8 -#define HCLK_PCLK_RATIO_MASK 0x3 - -#define PERIP_CLK_CFG (MISC_BASE + 0x028) -/* PERIP_CLK_CFG register masks */ -#define CLCD_CLK_SHIFT 2 -#define CLCD_CLK_MASK 0x3 -#define UART_CLK_SHIFT 4 -#define UART_CLK_MASK 0x1 -#define FIRDA_CLK_SHIFT 5 -#define FIRDA_CLK_MASK 0x3 -#define GPT0_CLK_SHIFT 8 -#define GPT1_CLK_SHIFT 10 -#define GPT2_CLK_SHIFT 11 -#define GPT3_CLK_SHIFT 12 -#define GPT_CLK_MASK 0x1 -#define AUX_CLK_PLL3_VAL 0 -#define AUX_CLK_PLL1_VAL 1 - -#define PERIP1_CLK_ENB (MISC_BASE + 0x02C) -/* PERIP1_CLK_ENB register masks */ -#define UART0_CLK_ENB 3 -#define UART1_CLK_ENB 4 -#define SSP0_CLK_ENB 5 -#define SSP1_CLK_ENB 6 -#define I2C_CLK_ENB 7 -#define JPEG_CLK_ENB 8 -#define FSMC_CLK_ENB 9 -#define FIRDA_CLK_ENB 10 -#define GPT2_CLK_ENB 11 -#define GPT3_CLK_ENB 12 -#define GPIO2_CLK_ENB 13 -#define SSP2_CLK_ENB 14 -#define ADC_CLK_ENB 15 -#define GPT1_CLK_ENB 11 -#define RTC_CLK_ENB 17 -#define GPIO1_CLK_ENB 18 -#define DMA_CLK_ENB 19 -#define SMI_CLK_ENB 21 -#define CLCD_CLK_ENB 22 -#define GMAC_CLK_ENB 23 -#define USBD_CLK_ENB 24 -#define USBH0_CLK_ENB 25 -#define USBH1_CLK_ENB 26 - -#define PRSC1_CLK_CFG (MISC_BASE + 0x044) -#define PRSC2_CLK_CFG (MISC_BASE + 0x048) -#define PRSC3_CLK_CFG (MISC_BASE + 0x04C) -/* gpt synthesizer register masks */ -#define GPT_MSCALE_SHIFT 0 -#define GPT_MSCALE_MASK 0xFFF -#define GPT_NSCALE_SHIFT 12 -#define GPT_NSCALE_MASK 0xF - -#define AMEM_CLK_CFG (MISC_BASE + 0x050) -#define EXPI_CLK_CFG (MISC_BASE + 0x054) -#define CLCD_CLK_SYNT (MISC_BASE + 0x05C) -#define FIRDA_CLK_SYNT (MISC_BASE + 0x060) -#define UART_CLK_SYNT (MISC_BASE + 0x064) -#define GMAC_CLK_SYNT (MISC_BASE + 0x068) -#define RAS1_CLK_SYNT (MISC_BASE + 0x06C) -#define RAS2_CLK_SYNT (MISC_BASE + 0x070) -#define RAS3_CLK_SYNT (MISC_BASE + 0x074) -#define RAS4_CLK_SYNT (MISC_BASE + 0x078) -/* aux clk synthesiser register masks for irda to ras4 */ -#define AUX_SYNT_ENB 31 -#define AUX_EQ_SEL_SHIFT 30 -#define AUX_EQ_SEL_MASK 1 -#define AUX_EQ1_SEL 0 -#define AUX_EQ2_SEL 1 -#define AUX_XSCALE_SHIFT 16 -#define AUX_XSCALE_MASK 0xFFF -#define AUX_YSCALE_SHIFT 0 -#define AUX_YSCALE_MASK 0xFFF - -/* root clks */ -/* 32 KHz oscillator clock */ -static struct clk osc_32k_clk = { - .flags = ALWAYS_ENABLED, - .rate = 32000, -}; - -/* 30 MHz oscillator clock */ -static struct clk osc_30m_clk = { - .flags = ALWAYS_ENABLED, - .rate = 30000000, -}; - -/* clock derived from 32 KHz osc clk */ -/* rtc clock */ -static struct clk rtc_clk = { - .pclk = &osc_32k_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = RTC_CLK_ENB, - .recalc = &follow_parent, -}; - -/* clock derived from 30 MHz osc clk */ -/* pll masks structure */ -static struct pll_clk_masks pll1_masks = { - .mode_mask = PLL_MODE_MASK, - .mode_shift = PLL_MODE_SHIFT, - .norm_fdbk_m_mask = PLL_NORM_FDBK_M_MASK, - .norm_fdbk_m_shift = PLL_NORM_FDBK_M_SHIFT, - .dith_fdbk_m_mask = PLL_DITH_FDBK_M_MASK, - .dith_fdbk_m_shift = PLL_DITH_FDBK_M_SHIFT, - .div_p_mask = PLL_DIV_P_MASK, - .div_p_shift = PLL_DIV_P_SHIFT, - .div_n_mask = PLL_DIV_N_MASK, - .div_n_shift = PLL_DIV_N_SHIFT, -}; - -/* pll1 configuration structure */ -static struct pll_clk_config pll1_config = { - .mode_reg = PLL1_CTR, - .cfg_reg = PLL1_FRQ, - .masks = &pll1_masks, -}; - -/* pll rate configuration table, in ascending order of rates */ -struct pll_rate_tbl pll_rtbl[] = { - {.mode = 0, .m = 0x85, .n = 0x0C, .p = 0x1}, /* 266 MHz */ - {.mode = 0, .m = 0xA6, .n = 0x0C, .p = 0x1}, /* 332 MHz */ -}; - -/* PLL1 clock */ -static struct clk pll1_clk = { - .flags = ENABLED_ON_INIT, - .pclk = &osc_30m_clk, - .en_reg = PLL1_CTR, - .en_reg_bit = PLL_ENABLE, - .calc_rate = &pll_calc_rate, - .recalc = &pll_clk_recalc, - .set_rate = &pll_clk_set_rate, - .rate_config = {pll_rtbl, ARRAY_SIZE(pll_rtbl), 1}, - .private_data = &pll1_config, -}; - -/* PLL3 48 MHz clock */ -static struct clk pll3_48m_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &osc_30m_clk, - .rate = 48000000, -}; - -/* watch dog timer clock */ -static struct clk wdt_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &osc_30m_clk, - .recalc = &follow_parent, -}; - -/* clock derived from pll1 clk */ -/* cpu clock */ -static struct clk cpu_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .recalc = &follow_parent, -}; - -/* ahb masks structure */ -static struct bus_clk_masks ahb_masks = { - .mask = PLL_HCLK_RATIO_MASK, - .shift = PLL_HCLK_RATIO_SHIFT, -}; - -/* ahb configuration structure */ -static struct bus_clk_config ahb_config = { - .reg = CORE_CLK_CFG, - .masks = &ahb_masks, -}; - -/* ahb rate configuration table, in ascending order of rates */ -struct bus_rate_tbl bus_rtbl[] = { - {.div = 3}, /* == parent divided by 4 */ - {.div = 2}, /* == parent divided by 3 */ - {.div = 1}, /* == parent divided by 2 */ - {.div = 0}, /* == parent divided by 1 */ -}; - -/* ahb clock */ -static struct clk ahb_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &bus_calc_rate, - .recalc = &bus_clk_recalc, - .set_rate = &bus_clk_set_rate, - .rate_config = {bus_rtbl, ARRAY_SIZE(bus_rtbl), 2}, - .private_data = &ahb_config, -}; - -/* auxiliary synthesizers masks */ -static struct aux_clk_masks aux_masks = { - .eq_sel_mask = AUX_EQ_SEL_MASK, - .eq_sel_shift = AUX_EQ_SEL_SHIFT, - .eq1_mask = AUX_EQ1_SEL, - .eq2_mask = AUX_EQ2_SEL, - .xscale_sel_mask = AUX_XSCALE_MASK, - .xscale_sel_shift = AUX_XSCALE_SHIFT, - .yscale_sel_mask = AUX_YSCALE_MASK, - .yscale_sel_shift = AUX_YSCALE_SHIFT, -}; - -/* uart configurations */ -static struct aux_clk_config uart_synth_config = { - .synth_reg = UART_CLK_SYNT, - .masks = &aux_masks, -}; - -/* aux rate configuration table, in ascending order of rates */ -struct aux_rate_tbl aux_rtbl[] = { - /* For PLL1 = 332 MHz */ - {.xscale = 1, .yscale = 8, .eq = 1}, /* 41.5 MHz */ - {.xscale = 1, .yscale = 4, .eq = 1}, /* 83 MHz */ - {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */ -}; - -/* uart synth clock */ -static struct clk uart_synth_clk = { - .en_reg = UART_CLK_SYNT, - .en_reg_bit = AUX_SYNT_ENB, - .pclk = &pll1_clk, - .calc_rate = &aux_calc_rate, - .recalc = &aux_clk_recalc, - .set_rate = &aux_clk_set_rate, - .rate_config = {aux_rtbl, ARRAY_SIZE(aux_rtbl), 2}, - .private_data = &uart_synth_config, -}; - -/* uart parents */ -static struct pclk_info uart_pclk_info[] = { - { - .pclk = &uart_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* uart parent select structure */ -static struct pclk_sel uart_pclk_sel = { - .pclk_info = uart_pclk_info, - .pclk_count = ARRAY_SIZE(uart_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = UART_CLK_MASK, -}; - -/* uart0 clock */ -static struct clk uart0_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = UART0_CLK_ENB, - .pclk_sel = &uart_pclk_sel, - .pclk_sel_shift = UART_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* uart1 clock */ -static struct clk uart1_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = UART1_CLK_ENB, - .pclk_sel = &uart_pclk_sel, - .pclk_sel_shift = UART_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* firda configurations */ -static struct aux_clk_config firda_synth_config = { - .synth_reg = FIRDA_CLK_SYNT, - .masks = &aux_masks, -}; - -/* firda synth clock */ -static struct clk firda_synth_clk = { - .en_reg = FIRDA_CLK_SYNT, - .en_reg_bit = AUX_SYNT_ENB, - .pclk = &pll1_clk, - .calc_rate = &aux_calc_rate, - .recalc = &aux_clk_recalc, - .set_rate = &aux_clk_set_rate, - .rate_config = {aux_rtbl, ARRAY_SIZE(aux_rtbl), 2}, - .private_data = &firda_synth_config, -}; - -/* firda parents */ -static struct pclk_info firda_pclk_info[] = { - { - .pclk = &firda_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* firda parent select structure */ -static struct pclk_sel firda_pclk_sel = { - .pclk_info = firda_pclk_info, - .pclk_count = ARRAY_SIZE(firda_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = FIRDA_CLK_MASK, -}; - -/* firda clock */ -static struct clk firda_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = FIRDA_CLK_ENB, - .pclk_sel = &firda_pclk_sel, - .pclk_sel_shift = FIRDA_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* clcd configurations */ -static struct aux_clk_config clcd_synth_config = { - .synth_reg = CLCD_CLK_SYNT, - .masks = &aux_masks, -}; - -/* firda synth clock */ -static struct clk clcd_synth_clk = { - .en_reg = CLCD_CLK_SYNT, - .en_reg_bit = AUX_SYNT_ENB, - .pclk = &pll1_clk, - .calc_rate = &aux_calc_rate, - .recalc = &aux_clk_recalc, - .set_rate = &aux_clk_set_rate, - .rate_config = {aux_rtbl, ARRAY_SIZE(aux_rtbl), 2}, - .private_data = &clcd_synth_config, -}; - -/* clcd parents */ -static struct pclk_info clcd_pclk_info[] = { - { - .pclk = &clcd_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* clcd parent select structure */ -static struct pclk_sel clcd_pclk_sel = { - .pclk_info = clcd_pclk_info, - .pclk_count = ARRAY_SIZE(clcd_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = CLCD_CLK_MASK, -}; - -/* clcd clock */ -static struct clk clcd_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = CLCD_CLK_ENB, - .pclk_sel = &clcd_pclk_sel, - .pclk_sel_shift = CLCD_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* gpt synthesizer masks */ -static struct gpt_clk_masks gpt_masks = { - .mscale_sel_mask = GPT_MSCALE_MASK, - .mscale_sel_shift = GPT_MSCALE_SHIFT, - .nscale_sel_mask = GPT_NSCALE_MASK, - .nscale_sel_shift = GPT_NSCALE_SHIFT, -}; - -/* gpt rate configuration table, in ascending order of rates */ -struct gpt_rate_tbl gpt_rtbl[] = { - /* For pll1 = 332 MHz */ - {.mscale = 4, .nscale = 0}, /* 41.5 MHz */ - {.mscale = 2, .nscale = 0}, /* 55.3 MHz */ - {.mscale = 1, .nscale = 0}, /* 83 MHz */ -}; - -/* gpt0 synth clk config*/ -static struct gpt_clk_config gpt0_synth_config = { - .synth_reg = PRSC1_CLK_CFG, - .masks = &gpt_masks, -}; - -/* gpt synth clock */ -static struct clk gpt0_synth_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &gpt_calc_rate, - .recalc = &gpt_clk_recalc, - .set_rate = &gpt_clk_set_rate, - .rate_config = {gpt_rtbl, ARRAY_SIZE(gpt_rtbl), 2}, - .private_data = &gpt0_synth_config, -}; - -/* gpt parents */ -static struct pclk_info gpt0_pclk_info[] = { - { - .pclk = &gpt0_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* gpt parent select structure */ -static struct pclk_sel gpt0_pclk_sel = { - .pclk_info = gpt0_pclk_info, - .pclk_count = ARRAY_SIZE(gpt0_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt0 ARM1 subsystem timer clock */ -static struct clk gpt0_clk = { - .flags = ALWAYS_ENABLED, - .pclk_sel = &gpt0_pclk_sel, - .pclk_sel_shift = GPT0_CLK_SHIFT, - .recalc = &follow_parent, -}; - - -/* Note: gpt0 and gpt1 share same parent clocks */ -/* gpt parent select structure */ -static struct pclk_sel gpt1_pclk_sel = { - .pclk_info = gpt0_pclk_info, - .pclk_count = ARRAY_SIZE(gpt0_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt1 timer clock */ -static struct clk gpt1_clk = { - .flags = ALWAYS_ENABLED, - .pclk_sel = &gpt1_pclk_sel, - .pclk_sel_shift = GPT1_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* gpt2 synth clk config*/ -static struct gpt_clk_config gpt2_synth_config = { - .synth_reg = PRSC2_CLK_CFG, - .masks = &gpt_masks, -}; - -/* gpt synth clock */ -static struct clk gpt2_synth_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &gpt_calc_rate, - .recalc = &gpt_clk_recalc, - .set_rate = &gpt_clk_set_rate, - .rate_config = {gpt_rtbl, ARRAY_SIZE(gpt_rtbl), 2}, - .private_data = &gpt2_synth_config, -}; - -/* gpt parents */ -static struct pclk_info gpt2_pclk_info[] = { - { - .pclk = &gpt2_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* gpt parent select structure */ -static struct pclk_sel gpt2_pclk_sel = { - .pclk_info = gpt2_pclk_info, - .pclk_count = ARRAY_SIZE(gpt2_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt2 timer clock */ -static struct clk gpt2_clk = { - .flags = ALWAYS_ENABLED, - .pclk_sel = &gpt2_pclk_sel, - .pclk_sel_shift = GPT2_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* gpt3 synth clk config*/ -static struct gpt_clk_config gpt3_synth_config = { - .synth_reg = PRSC3_CLK_CFG, - .masks = &gpt_masks, -}; - -/* gpt synth clock */ -static struct clk gpt3_synth_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &gpt_calc_rate, - .recalc = &gpt_clk_recalc, - .set_rate = &gpt_clk_set_rate, - .rate_config = {gpt_rtbl, ARRAY_SIZE(gpt_rtbl), 2}, - .private_data = &gpt3_synth_config, -}; - -/* gpt parents */ -static struct pclk_info gpt3_pclk_info[] = { - { - .pclk = &gpt3_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* gpt parent select structure */ -static struct pclk_sel gpt3_pclk_sel = { - .pclk_info = gpt3_pclk_info, - .pclk_count = ARRAY_SIZE(gpt3_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt3 timer clock */ -static struct clk gpt3_clk = { - .flags = ALWAYS_ENABLED, - .pclk_sel = &gpt3_pclk_sel, - .pclk_sel_shift = GPT3_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* clock derived from pll3 clk */ -/* usbh0 clock */ -static struct clk usbh0_clk = { - .pclk = &pll3_48m_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = USBH0_CLK_ENB, - .recalc = &follow_parent, -}; - -/* usbh1 clock */ -static struct clk usbh1_clk = { - .pclk = &pll3_48m_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = USBH1_CLK_ENB, - .recalc = &follow_parent, -}; - -/* usbd clock */ -static struct clk usbd_clk = { - .pclk = &pll3_48m_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = USBD_CLK_ENB, - .recalc = &follow_parent, -}; - -/* clock derived from ahb clk */ -/* apb masks structure */ -static struct bus_clk_masks apb_masks = { - .mask = HCLK_PCLK_RATIO_MASK, - .shift = HCLK_PCLK_RATIO_SHIFT, -}; - -/* apb configuration structure */ -static struct bus_clk_config apb_config = { - .reg = CORE_CLK_CFG, - .masks = &apb_masks, -}; - -/* apb clock */ -static struct clk apb_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &ahb_clk, - .calc_rate = &bus_calc_rate, - .recalc = &bus_clk_recalc, - .set_rate = &bus_clk_set_rate, - .rate_config = {bus_rtbl, ARRAY_SIZE(bus_rtbl), 2}, - .private_data = &apb_config, -}; - -/* i2c clock */ -static struct clk i2c_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = I2C_CLK_ENB, - .recalc = &follow_parent, -}; - -/* dma clock */ -static struct clk dma_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = DMA_CLK_ENB, - .recalc = &follow_parent, -}; - -/* jpeg clock */ -static struct clk jpeg_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = JPEG_CLK_ENB, - .recalc = &follow_parent, -}; - -/* gmac clock */ -static struct clk gmac_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GMAC_CLK_ENB, - .recalc = &follow_parent, -}; - -/* smi clock */ -static struct clk smi_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = SMI_CLK_ENB, - .recalc = &follow_parent, -}; - -/* fsmc clock */ -static struct clk fsmc_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = FSMC_CLK_ENB, - .recalc = &follow_parent, -}; - -/* clock derived from apb clk */ -/* adc clock */ -static struct clk adc_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = ADC_CLK_ENB, - .recalc = &follow_parent, -}; - -/* ssp0 clock */ -static struct clk ssp0_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = SSP0_CLK_ENB, - .recalc = &follow_parent, -}; - -/* ssp1 clock */ -static struct clk ssp1_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = SSP1_CLK_ENB, - .recalc = &follow_parent, -}; - -/* ssp2 clock */ -static struct clk ssp2_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = SSP2_CLK_ENB, - .recalc = &follow_parent, -}; - -/* gpio0 ARM subsystem clock */ -static struct clk gpio0_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* gpio1 clock */ -static struct clk gpio1_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GPIO1_CLK_ENB, - .recalc = &follow_parent, -}; - -/* gpio2 clock */ -static struct clk gpio2_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GPIO2_CLK_ENB, - .recalc = &follow_parent, -}; - -static struct clk dummy_apb_pclk; - -/* array of all spear 6xx clock lookups */ -static struct clk_lookup spear_clk_lookups[] = { - CLKDEV_INIT(NULL, "apb_pclk", &dummy_apb_pclk), - /* root clks */ - CLKDEV_INIT(NULL, "osc_32k_clk", &osc_32k_clk), - CLKDEV_INIT(NULL, "osc_30m_clk", &osc_30m_clk), - /* clock derived from 32 KHz os clk */ - CLKDEV_INIT("rtc-spear", NULL, &rtc_clk), - /* clock derived from 30 MHz os clk */ - CLKDEV_INIT(NULL, "pll1_clk", &pll1_clk), - CLKDEV_INIT(NULL, "pll3_48m_clk", &pll3_48m_clk), - CLKDEV_INIT("wdt", NULL, &wdt_clk), - /* clock derived from pll1 clk */ - CLKDEV_INIT(NULL, "cpu_clk", &cpu_clk), - CLKDEV_INIT(NULL, "ahb_clk", &ahb_clk), - CLKDEV_INIT(NULL, "uart_synth_clk", &uart_synth_clk), - CLKDEV_INIT(NULL, "firda_synth_clk", &firda_synth_clk), - CLKDEV_INIT(NULL, "clcd_synth_clk", &clcd_synth_clk), - CLKDEV_INIT(NULL, "gpt0_synth_clk", &gpt0_synth_clk), - CLKDEV_INIT(NULL, "gpt2_synth_clk", &gpt2_synth_clk), - CLKDEV_INIT(NULL, "gpt3_synth_clk", &gpt3_synth_clk), - CLKDEV_INIT("d0000000.serial", NULL, &uart0_clk), - CLKDEV_INIT("d0080000.serial", NULL, &uart1_clk), - CLKDEV_INIT("firda", NULL, &firda_clk), - CLKDEV_INIT("clcd", NULL, &clcd_clk), - CLKDEV_INIT("gpt0", NULL, &gpt0_clk), - CLKDEV_INIT("gpt1", NULL, &gpt1_clk), - CLKDEV_INIT("gpt2", NULL, &gpt2_clk), - CLKDEV_INIT("gpt3", NULL, &gpt3_clk), - /* clock derived from pll3 clk */ - CLKDEV_INIT("designware_udc", NULL, &usbd_clk), - CLKDEV_INIT(NULL, "usbh.0_clk", &usbh0_clk), - CLKDEV_INIT(NULL, "usbh.1_clk", &usbh1_clk), - /* clock derived from ahb clk */ - CLKDEV_INIT(NULL, "apb_clk", &apb_clk), - CLKDEV_INIT("d0200000.i2c", NULL, &i2c_clk), - CLKDEV_INIT("fc400000.dma", NULL, &dma_clk), - CLKDEV_INIT("jpeg", NULL, &jpeg_clk), - CLKDEV_INIT("gmac", NULL, &gmac_clk), - CLKDEV_INIT("fc000000.flash", NULL, &smi_clk), - CLKDEV_INIT("d1800000.flash", NULL, &fsmc_clk), - /* clock derived from apb clk */ - CLKDEV_INIT("adc", NULL, &adc_clk), - CLKDEV_INIT("ssp-pl022.0", NULL, &ssp0_clk), - CLKDEV_INIT("ssp-pl022.1", NULL, &ssp1_clk), - CLKDEV_INIT("ssp-pl022.2", NULL, &ssp2_clk), - CLKDEV_INIT("f0100000.gpio", NULL, &gpio0_clk), - CLKDEV_INIT("fc980000.gpio", NULL, &gpio1_clk), - CLKDEV_INIT("d8100000.gpio", NULL, &gpio2_clk), -}; - -void __init spear6xx_clk_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++) - clk_register(&spear_clk_lookups[i]); - - clk_init(); -} diff --git a/arch/arm/mach-spear6xx/include/mach/generic.h b/arch/arm/mach-spear6xx/include/mach/generic.h index 7167fd331d86..65514b159370 100644 --- a/arch/arm/mach-spear6xx/include/mach/generic.h +++ b/arch/arm/mach-spear6xx/include/mach/generic.h @@ -16,7 +16,7 @@ #include <linux/init.h> -void __init spear_setup_timer(resource_size_t base, int irq); +void __init spear_setup_of_timer(void); void spear_restart(char, const char *); void __init spear6xx_clk_init(void); diff --git a/arch/arm/mach-spear6xx/include/mach/irqs.h b/arch/arm/mach-spear6xx/include/mach/irqs.h index 2b735389e74b..37a5c411a866 100644 --- a/arch/arm/mach-spear6xx/include/mach/irqs.h +++ b/arch/arm/mach-spear6xx/include/mach/irqs.h @@ -16,9 +16,6 @@ /* IRQ definitions */ /* VIC 1 */ -/* FIXME: probe this from DT */ -#define IRQ_CPU_GPT1_1 16 - #define IRQ_VIC_END 64 /* GPIO pins virtual irqs */ diff --git a/arch/arm/mach-spear6xx/include/mach/misc_regs.h b/arch/arm/mach-spear6xx/include/mach/misc_regs.h index 2b9aaa6cdd11..179e45774b3a 100644 --- a/arch/arm/mach-spear6xx/include/mach/misc_regs.h +++ b/arch/arm/mach-spear6xx/include/mach/misc_regs.h @@ -14,6 +14,8 @@ #ifndef __MACH_MISC_REGS_H #define __MACH_MISC_REGS_H +#include <mach/spear.h> + #define MISC_BASE IOMEM(VA_SPEAR6XX_ICM3_MISC_REG_BASE) #define DMA_CHN_CFG (MISC_BASE + 0x0A0) diff --git a/arch/arm/mach-spear6xx/include/mach/spear.h b/arch/arm/mach-spear6xx/include/mach/spear.h index d278ed047a53..cb8ed2f4dc85 100644 --- a/arch/arm/mach-spear6xx/include/mach/spear.h +++ b/arch/arm/mach-spear6xx/include/mach/spear.h @@ -25,7 +25,6 @@ /* ML-1, 2 - Multi Layer CPU Subsystem */ #define SPEAR6XX_ML_CPU_BASE UL(0xF0000000) #define VA_SPEAR6XX_ML_CPU_BASE UL(0xF0000000) -#define SPEAR6XX_CPU_TMR_BASE UL(0xF0000000) /* ICM3 - Basic Subsystem */ #define SPEAR6XX_ICM3_SMI_CTRL_BASE UL(0xFC000000) diff --git a/arch/arm/mach-spear6xx/spear6xx.c b/arch/arm/mach-spear6xx/spear6xx.c index de194dbb8371..2e2e3596583e 100644 --- a/arch/arm/mach-spear6xx/spear6xx.c +++ b/arch/arm/mach-spear6xx/spear6xx.c @@ -419,9 +419,6 @@ struct map_desc spear6xx_io_desc[] __initdata = { void __init spear6xx_map_io(void) { iotable_init(spear6xx_io_desc, ARRAY_SIZE(spear6xx_io_desc)); - - /* This will initialize clock framework */ - spear6xx_clk_init(); } static void __init spear6xx_timer_init(void) @@ -429,6 +426,8 @@ static void __init spear6xx_timer_init(void) char pclk_name[] = "pll3_48m_clk"; struct clk *gpt_clk, *pclk; + spear6xx_clk_init(); + /* get the system timer clock */ gpt_clk = clk_get_sys("gpt0", NULL); if (IS_ERR(gpt_clk)) { @@ -448,7 +447,7 @@ static void __init spear6xx_timer_init(void) clk_put(gpt_clk); clk_put(pclk); - spear_setup_timer(SPEAR6XX_CPU_TMR_BASE, IRQ_CPU_GPT1_1); + spear_setup_of_timer(); } struct sys_timer spear6xx_timer = { diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c index 2ed3ab173add..5079787273d2 100644 --- a/arch/arm/plat-mxc/clock.c +++ b/arch/arm/plat-mxc/clock.c @@ -41,6 +41,7 @@ #include <mach/clock.h> #include <mach/hardware.h> +#ifndef CONFIG_COMMON_CLK static LIST_HEAD(clocks); static DEFINE_MUTEX(clocks_mutex); @@ -200,6 +201,16 @@ struct clk *clk_get_parent(struct clk *clk) } EXPORT_SYMBOL(clk_get_parent); +#else + +/* + * Lock to protect the clock module (ccm) registers. Used + * on all i.MXs + */ +DEFINE_SPINLOCK(imx_ccm_lock); + +#endif /* CONFIG_COMMON_CLK */ + /* * Get the resulting clock rate from a PLL register value and the input * frequency. PLLs with this register layout can at least be found on diff --git a/arch/arm/plat-mxc/include/mach/clock.h b/arch/arm/plat-mxc/include/mach/clock.h index 753a5988d85c..bd940c795cbb 100644 --- a/arch/arm/plat-mxc/include/mach/clock.h +++ b/arch/arm/plat-mxc/include/mach/clock.h @@ -23,6 +23,7 @@ #ifndef __ASSEMBLY__ #include <linux/list.h> +#ifndef CONFIG_COMMON_CLK struct module; struct clk { @@ -59,6 +60,9 @@ struct clk { int clk_register(struct clk *clk); void clk_unregister(struct clk *clk); +#endif /* CONFIG_COMMON_CLK */ + +extern spinlock_t imx_ccm_lock; unsigned long mxc_decode_pll(unsigned int pll, u32 f_ref); diff --git a/arch/arm/plat-mxc/time.c b/arch/arm/plat-mxc/time.c index 7daf7c9a413b..99f958ca6cb8 100644 --- a/arch/arm/plat-mxc/time.c +++ b/arch/arm/plat-mxc/time.c @@ -25,6 +25,7 @@ #include <linux/irq.h> #include <linux/clockchips.h> #include <linux/clk.h> +#include <linux/err.h> #include <mach/hardware.h> #include <asm/sched_clock.h> @@ -282,6 +283,19 @@ static int __init mxc_clockevent_init(struct clk *timer_clk) void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq) { uint32_t tctl_val; + struct clk *timer_ipg_clk; + + if (!timer_clk) { + timer_clk = clk_get_sys("imx-gpt.0", "per"); + if (IS_ERR(timer_clk)) { + pr_err("i.MX timer: unable to get clk\n"); + return; + } + + timer_ipg_clk = clk_get_sys("imx-gpt.0", "ipg"); + if (!IS_ERR(timer_ipg_clk)) + clk_prepare_enable(timer_ipg_clk); + } clk_prepare_enable(timer_clk); diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index 74daf5ed1432..61fd837624a8 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -14,15 +14,41 @@ #include <linux/dma-mapping.h> #include <linux/serial_8250.h> #include <linux/ata_platform.h> +#include <linux/clk.h> +#include <linux/clkdev.h> #include <linux/mv643xx_eth.h> #include <linux/mv643xx_i2c.h> #include <net/dsa.h> -#include <linux/spi/orion_spi.h> -#include <plat/orion_wdt.h> #include <plat/mv_xor.h> #include <plat/ehci-orion.h> #include <mach/bridge-regs.h> +/* Create a clkdev entry for a given device/clk */ +void __init orion_clkdev_add(const char *con_id, const char *dev_id, + struct clk *clk) +{ + struct clk_lookup *cl; + + cl = clkdev_alloc(clk, con_id, dev_id); + if (cl) + clkdev_add(cl); +} + +/* Create clkdev entries for all orion platforms except kirkwood. + Kirkwood has gated clocks for some of its peripherals, so creates + its own clkdev entries. For all the other orion devices, create + clkdev entries to the tclk. */ +void __init orion_clkdev_init(struct clk *tclk) +{ + orion_clkdev_add(NULL, "orion_spi.0", tclk); + orion_clkdev_add(NULL, "orion_spi.1", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".0", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".1", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".2", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".3", tclk); + orion_clkdev_add(NULL, "orion_wdt", tclk); +} + /* Fill in the resources structure and link it into the platform device structure. There is always a memory region, and nearly always an interrupt.*/ @@ -49,6 +75,12 @@ static void fill_resources(struct platform_device *device, /***************************************************************************** * UART ****************************************************************************/ +static unsigned long __init uart_get_clk_rate(struct clk *clk) +{ + clk_prepare_enable(clk); + return clk_get_rate(clk); +} + static void __init uart_complete( struct platform_device *orion_uart, struct plat_serial8250_port *data, @@ -56,12 +88,12 @@ static void __init uart_complete( unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk) + struct clk *clk) { data->mapbase = mapbase; data->membase = (void __iomem *)membase; data->irq = irq; - data->uartclk = uartclk; + data->uartclk = uart_get_clk_rate(clk); orion_uart->dev.platform_data = data; fill_resources(orion_uart, resources, mapbase, 0xff, irq); @@ -90,10 +122,10 @@ static struct platform_device orion_uart0 = { void __init orion_uart0_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk) + struct clk *clk) { uart_complete(&orion_uart0, orion_uart0_data, orion_uart0_resources, - membase, mapbase, irq, uartclk); + membase, mapbase, irq, clk); } /***************************************************************************** @@ -118,10 +150,10 @@ static struct platform_device orion_uart1 = { void __init orion_uart1_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk) + struct clk *clk) { uart_complete(&orion_uart1, orion_uart1_data, orion_uart1_resources, - membase, mapbase, irq, uartclk); + membase, mapbase, irq, clk); } /***************************************************************************** @@ -146,10 +178,10 @@ static struct platform_device orion_uart2 = { void __init orion_uart2_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk) + struct clk *clk) { uart_complete(&orion_uart2, orion_uart2_data, orion_uart2_resources, - membase, mapbase, irq, uartclk); + membase, mapbase, irq, clk); } /***************************************************************************** @@ -174,10 +206,10 @@ static struct platform_device orion_uart3 = { void __init orion_uart3_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk) + struct clk *clk) { uart_complete(&orion_uart3, orion_uart3_data, orion_uart3_resources, - membase, mapbase, irq, uartclk); + membase, mapbase, irq, clk); } /***************************************************************************** @@ -203,13 +235,11 @@ void __init orion_rtc_init(unsigned long mapbase, ****************************************************************************/ static __init void ge_complete( struct mv643xx_eth_shared_platform_data *orion_ge_shared_data, - int tclk, struct resource *orion_ge_resource, unsigned long irq, struct platform_device *orion_ge_shared, struct mv643xx_eth_platform_data *eth_data, struct platform_device *orion_ge) { - orion_ge_shared_data->t_clk = tclk; orion_ge_resource->start = irq; orion_ge_resource->end = irq; eth_data->shared = orion_ge_shared; @@ -260,12 +290,11 @@ static struct platform_device orion_ge00 = { void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk) + unsigned long irq_err) { fill_resources(&orion_ge00_shared, orion_ge00_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); - ge_complete(&orion_ge00_shared_data, tclk, + ge_complete(&orion_ge00_shared_data, orion_ge00_resources, irq, &orion_ge00_shared, eth_data, &orion_ge00); } @@ -313,12 +342,11 @@ static struct platform_device orion_ge01 = { void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk) + unsigned long irq_err) { fill_resources(&orion_ge01_shared, orion_ge01_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); - ge_complete(&orion_ge01_shared_data, tclk, + ge_complete(&orion_ge01_shared_data, orion_ge01_resources, irq, &orion_ge01_shared, eth_data, &orion_ge01); } @@ -366,12 +394,11 @@ static struct platform_device orion_ge10 = { void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk) + unsigned long irq_err) { fill_resources(&orion_ge10_shared, orion_ge10_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); - ge_complete(&orion_ge10_shared_data, tclk, + ge_complete(&orion_ge10_shared_data, orion_ge10_resources, irq, &orion_ge10_shared, eth_data, &orion_ge10); } @@ -419,12 +446,11 @@ static struct platform_device orion_ge11 = { void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk) + unsigned long irq_err) { fill_resources(&orion_ge11_shared, orion_ge11_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); - ge_complete(&orion_ge11_shared_data, tclk, + ge_complete(&orion_ge11_shared_data, orion_ge11_resources, irq, &orion_ge11_shared, eth_data, &orion_ge11); } @@ -521,44 +547,32 @@ void __init orion_i2c_1_init(unsigned long mapbase, /***************************************************************************** * SPI ****************************************************************************/ -static struct orion_spi_info orion_spi_plat_data; static struct resource orion_spi_resources; static struct platform_device orion_spi = { .name = "orion_spi", .id = 0, - .dev = { - .platform_data = &orion_spi_plat_data, - }, }; -static struct orion_spi_info orion_spi_1_plat_data; static struct resource orion_spi_1_resources; static struct platform_device orion_spi_1 = { .name = "orion_spi", .id = 1, - .dev = { - .platform_data = &orion_spi_1_plat_data, - }, }; /* Note: The SPI silicon core does have interrupts. However the * current Linux software driver does not use interrupts. */ -void __init orion_spi_init(unsigned long mapbase, - unsigned long tclk) +void __init orion_spi_init(unsigned long mapbase) { - orion_spi_plat_data.tclk = tclk; fill_resources(&orion_spi, &orion_spi_resources, mapbase, SZ_512 - 1, NO_IRQ); platform_device_register(&orion_spi); } -void __init orion_spi_1_init(unsigned long mapbase, - unsigned long tclk) +void __init orion_spi_1_init(unsigned long mapbase) { - orion_spi_1_plat_data.tclk = tclk; fill_resources(&orion_spi_1, &orion_spi_1_resources, mapbase, SZ_512 - 1, NO_IRQ); platform_device_register(&orion_spi_1); @@ -567,24 +581,18 @@ void __init orion_spi_1_init(unsigned long mapbase, /***************************************************************************** * Watchdog ****************************************************************************/ -static struct orion_wdt_platform_data orion_wdt_data; - static struct resource orion_wdt_resource = DEFINE_RES_MEM(TIMER_VIRT_BASE, 0x28); static struct platform_device orion_wdt_device = { .name = "orion_wdt", .id = -1, - .dev = { - .platform_data = &orion_wdt_data, - }, - .resource = &orion_wdt_resource, .num_resources = 1, + .resource = &orion_wdt_resource, }; -void __init orion_wdt_init(unsigned long tclk) +void __init orion_wdt_init(void) { - orion_wdt_data.tclk = tclk; platform_device_register(&orion_wdt_device); } diff --git a/arch/arm/plat-orion/include/plat/common.h b/arch/arm/plat-orion/include/plat/common.h index a7fa005a5a0e..e00fdb213609 100644 --- a/arch/arm/plat-orion/include/plat/common.h +++ b/arch/arm/plat-orion/include/plat/common.h @@ -16,22 +16,22 @@ struct dsa_platform_data; void __init orion_uart0_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk); + struct clk *clk); void __init orion_uart1_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk); + struct clk *clk); void __init orion_uart2_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk); + struct clk *clk); void __init orion_uart3_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk); + struct clk *clk); void __init orion_rtc_init(unsigned long mapbase, unsigned long irq); @@ -39,29 +39,26 @@ void __init orion_rtc_init(unsigned long mapbase, void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk); + unsigned long irq_err); void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk); + unsigned long irq_err); void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk); + unsigned long irq_err); void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk); + unsigned long irq_err); void __init orion_ge00_switch_init(struct dsa_platform_data *d, int irq); + void __init orion_i2c_init(unsigned long mapbase, unsigned long irq, unsigned long freq_m); @@ -70,13 +67,11 @@ void __init orion_i2c_1_init(unsigned long mapbase, unsigned long irq, unsigned long freq_m); -void __init orion_spi_init(unsigned long mapbase, - unsigned long tclk); +void __init orion_spi_init(unsigned long mapbase); -void __init orion_spi_1_init(unsigned long mapbase, - unsigned long tclk); +void __init orion_spi_1_init(unsigned long mapbase); -void __init orion_wdt_init(unsigned long tclk); +void __init orion_wdt_init(void); void __init orion_xor0_init(unsigned long mapbase_low, unsigned long mapbase_high, @@ -106,4 +101,9 @@ void __init orion_crypto_init(unsigned long mapbase, unsigned long srambase, unsigned long sram_size, unsigned long irq); + +void __init orion_clkdev_add(const char *con_id, const char *dev_id, + struct clk *clk); + +void __init orion_clkdev_init(struct clk *tclk); #endif diff --git a/arch/arm/plat-orion/include/plat/orion_wdt.h b/arch/arm/plat-orion/include/plat/orion_wdt.h deleted file mode 100644 index 665c362a2fba..000000000000 --- a/arch/arm/plat-orion/include/plat/orion_wdt.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * arch/arm/plat-orion/include/plat/orion_wdt.h - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __PLAT_ORION_WDT_H -#define __PLAT_ORION_WDT_H - -struct orion_wdt_platform_data { - u32 tclk; /* no <linux/clk.h> support yet */ -}; - - -#endif - diff --git a/arch/arm/plat-orion/pcie.c b/arch/arm/plat-orion/pcie.c index 86dbb5bdb172..f20a321088a2 100644 --- a/arch/arm/plat-orion/pcie.c +++ b/arch/arm/plat-orion/pcie.c @@ -52,12 +52,12 @@ #define PCIE_DEBUG_SOFT_RESET (1<<20) -u32 __init orion_pcie_dev_id(void __iomem *base) +u32 orion_pcie_dev_id(void __iomem *base) { return readl(base + PCIE_DEV_ID_OFF) >> 16; } -u32 __init orion_pcie_rev(void __iomem *base) +u32 orion_pcie_rev(void __iomem *base) { return readl(base + PCIE_DEV_REV_OFF) & 0xff; } diff --git a/arch/arm/plat-spear/Makefile b/arch/arm/plat-spear/Makefile index 7744802c83e7..38f1235f4632 100644 --- a/arch/arm/plat-spear/Makefile +++ b/arch/arm/plat-spear/Makefile @@ -3,6 +3,6 @@ # # Common support -obj-y := clock.o restart.o time.o pl080.o +obj-y := restart.o time.o pl080.o obj-$(CONFIG_ARCH_SPEAR3XX) += shirq.o diff --git a/arch/arm/plat-spear/clock.c b/arch/arm/plat-spear/clock.c deleted file mode 100644 index 67dd00381ea6..000000000000 --- a/arch/arm/plat-spear/clock.c +++ /dev/null @@ -1,1005 +0,0 @@ -/* - * arch/arm/plat-spear/clock.c - * - * Clock framework for SPEAr platform - * - * Copyright (C) 2009 ST Microelectronics - * Viresh Kumar<viresh.kumar@st.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/bug.h> -#include <linux/clk.h> -#include <linux/debugfs.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include <plat/clock.h> - -static DEFINE_SPINLOCK(clocks_lock); -static LIST_HEAD(root_clks); -#ifdef CONFIG_DEBUG_FS -static LIST_HEAD(clocks); -#endif - -static void propagate_rate(struct clk *, int on_init); -#ifdef CONFIG_DEBUG_FS -static int clk_debugfs_reparent(struct clk *); -#endif - -static int generic_clk_enable(struct clk *clk) -{ - unsigned int val; - - if (!clk->en_reg) - return -EFAULT; - - val = readl(clk->en_reg); - if (unlikely(clk->flags & RESET_TO_ENABLE)) - val &= ~(1 << clk->en_reg_bit); - else - val |= 1 << clk->en_reg_bit; - - writel(val, clk->en_reg); - - return 0; -} - -static void generic_clk_disable(struct clk *clk) -{ - unsigned int val; - - if (!clk->en_reg) - return; - - val = readl(clk->en_reg); - if (unlikely(clk->flags & RESET_TO_ENABLE)) - val |= 1 << clk->en_reg_bit; - else - val &= ~(1 << clk->en_reg_bit); - - writel(val, clk->en_reg); -} - -/* generic clk ops */ -static struct clkops generic_clkops = { - .enable = generic_clk_enable, - .disable = generic_clk_disable, -}; - -/* returns current programmed clocks clock info structure */ -static struct pclk_info *pclk_info_get(struct clk *clk) -{ - unsigned int val, i; - struct pclk_info *info = NULL; - - val = (readl(clk->pclk_sel->pclk_sel_reg) >> clk->pclk_sel_shift) - & clk->pclk_sel->pclk_sel_mask; - - for (i = 0; i < clk->pclk_sel->pclk_count; i++) { - if (clk->pclk_sel->pclk_info[i].pclk_val == val) - info = &clk->pclk_sel->pclk_info[i]; - } - - return info; -} - -/* - * Set Update pclk, and pclk_info of clk and add clock sibling node to current - * parents children list - */ -static void clk_reparent(struct clk *clk, struct pclk_info *pclk_info) -{ - unsigned long flags; - - spin_lock_irqsave(&clocks_lock, flags); - list_del(&clk->sibling); - list_add(&clk->sibling, &pclk_info->pclk->children); - - clk->pclk = pclk_info->pclk; - spin_unlock_irqrestore(&clocks_lock, flags); - -#ifdef CONFIG_DEBUG_FS - clk_debugfs_reparent(clk); -#endif -} - -static void do_clk_disable(struct clk *clk) -{ - if (!clk) - return; - - if (!clk->usage_count) { - WARN_ON(1); - return; - } - - clk->usage_count--; - - if (clk->usage_count == 0) { - /* - * Surely, there are no active childrens or direct users - * of this clock - */ - if (clk->pclk) - do_clk_disable(clk->pclk); - - if (clk->ops && clk->ops->disable) - clk->ops->disable(clk); - } -} - -static int do_clk_enable(struct clk *clk) -{ - int ret = 0; - - if (!clk) - return -EFAULT; - - if (clk->usage_count == 0) { - if (clk->pclk) { - ret = do_clk_enable(clk->pclk); - if (ret) - goto err; - } - if (clk->ops && clk->ops->enable) { - ret = clk->ops->enable(clk); - if (ret) { - if (clk->pclk) - do_clk_disable(clk->pclk); - goto err; - } - } - /* - * Since the clock is going to be used for the first - * time please reclac - */ - if (clk->recalc) { - ret = clk->recalc(clk); - if (ret) - goto err; - } - } - clk->usage_count++; -err: - return ret; -} - -/* - * clk_enable - inform the system when the clock source should be running. - * @clk: clock source - * - * If the clock can not be enabled/disabled, this should return success. - * - * Returns success (0) or negative errno. - */ -int clk_enable(struct clk *clk) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&clocks_lock, flags); - ret = do_clk_enable(clk); - spin_unlock_irqrestore(&clocks_lock, flags); - return ret; -} -EXPORT_SYMBOL(clk_enable); - -/* - * clk_disable - inform the system when the clock source is no longer required. - * @clk: clock source - * - * Inform the system that a clock source is no longer required by - * a driver and may be shut down. - * - * Implementation detail: if the clock source is shared between - * multiple drivers, clk_enable() calls must be balanced by the - * same number of clk_disable() calls for the clock source to be - * disabled. - */ -void clk_disable(struct clk *clk) -{ - unsigned long flags; - - spin_lock_irqsave(&clocks_lock, flags); - do_clk_disable(clk); - spin_unlock_irqrestore(&clocks_lock, flags); -} -EXPORT_SYMBOL(clk_disable); - -/** - * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. - * This is only valid once the clock source has been enabled. - * @clk: clock source - */ -unsigned long clk_get_rate(struct clk *clk) -{ - unsigned long flags, rate; - - spin_lock_irqsave(&clocks_lock, flags); - rate = clk->rate; - spin_unlock_irqrestore(&clocks_lock, flags); - - return rate; -} -EXPORT_SYMBOL(clk_get_rate); - -/** - * clk_set_parent - set the parent clock source for this clock - * @clk: clock source - * @parent: parent clock source - * - * Returns success (0) or negative errno. - */ -int clk_set_parent(struct clk *clk, struct clk *parent) -{ - int i, found = 0, val = 0; - unsigned long flags; - - if (!clk || !parent) - return -EFAULT; - if (clk->pclk == parent) - return 0; - if (!clk->pclk_sel) - return -EPERM; - - /* check if requested parent is in clk parent list */ - for (i = 0; i < clk->pclk_sel->pclk_count; i++) { - if (clk->pclk_sel->pclk_info[i].pclk == parent) { - found = 1; - break; - } - } - - if (!found) - return -EINVAL; - - spin_lock_irqsave(&clocks_lock, flags); - /* reflect parent change in hardware */ - val = readl(clk->pclk_sel->pclk_sel_reg); - val &= ~(clk->pclk_sel->pclk_sel_mask << clk->pclk_sel_shift); - val |= clk->pclk_sel->pclk_info[i].pclk_val << clk->pclk_sel_shift; - writel(val, clk->pclk_sel->pclk_sel_reg); - spin_unlock_irqrestore(&clocks_lock, flags); - - /* reflect parent change in software */ - clk_reparent(clk, &clk->pclk_sel->pclk_info[i]); - - propagate_rate(clk, 0); - return 0; -} -EXPORT_SYMBOL(clk_set_parent); - -/** - * clk_set_rate - set the clock rate for a clock source - * @clk: clock source - * @rate: desired clock rate in Hz - * - * Returns success (0) or negative errno. - */ -int clk_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned long flags; - int ret = -EINVAL; - - if (!clk || !rate) - return -EFAULT; - - if (clk->set_rate) { - spin_lock_irqsave(&clocks_lock, flags); - ret = clk->set_rate(clk, rate); - if (!ret) - /* if successful -> propagate */ - propagate_rate(clk, 0); - spin_unlock_irqrestore(&clocks_lock, flags); - } else if (clk->pclk) { - u32 mult = clk->div_factor ? clk->div_factor : 1; - ret = clk_set_rate(clk->pclk, mult * rate); - } - - return ret; -} -EXPORT_SYMBOL(clk_set_rate); - -/* registers clock in platform clock framework */ -void clk_register(struct clk_lookup *cl) -{ - struct clk *clk; - unsigned long flags; - - if (!cl || !cl->clk) - return; - clk = cl->clk; - - spin_lock_irqsave(&clocks_lock, flags); - - INIT_LIST_HEAD(&clk->children); - if (clk->flags & ALWAYS_ENABLED) - clk->ops = NULL; - else if (!clk->ops) - clk->ops = &generic_clkops; - - /* root clock don't have any parents */ - if (!clk->pclk && !clk->pclk_sel) { - list_add(&clk->sibling, &root_clks); - } else if (clk->pclk && !clk->pclk_sel) { - /* add clocks with only one parent to parent's children list */ - list_add(&clk->sibling, &clk->pclk->children); - } else { - /* clocks with more than one parent */ - struct pclk_info *pclk_info; - - pclk_info = pclk_info_get(clk); - if (!pclk_info) { - pr_err("CLKDEV: invalid pclk info of clk with" - " %s dev_id and %s con_id\n", - cl->dev_id, cl->con_id); - } else { - clk->pclk = pclk_info->pclk; - list_add(&clk->sibling, &pclk_info->pclk->children); - } - } - - spin_unlock_irqrestore(&clocks_lock, flags); - - /* debugfs specific */ -#ifdef CONFIG_DEBUG_FS - list_add(&clk->node, &clocks); - clk->cl = cl; -#endif - - /* add clock to arm clockdev framework */ - clkdev_add(cl); -} - -/** - * propagate_rate - recalculate and propagate all clocks to children - * @pclk: parent clock required to be propogated - * @on_init: flag for enabling clocks which are ENABLED_ON_INIT. - * - * Recalculates all children clocks - */ -void propagate_rate(struct clk *pclk, int on_init) -{ - struct clk *clk, *_temp; - int ret = 0; - - list_for_each_entry_safe(clk, _temp, &pclk->children, sibling) { - if (clk->recalc) { - ret = clk->recalc(clk); - /* - * recalc will return error if clk out is not programmed - * In this case configure default rate. - */ - if (ret && clk->set_rate) - clk->set_rate(clk, 0); - } - propagate_rate(clk, on_init); - - if (!on_init) - continue; - - /* Enable clks enabled on init, in software view */ - if (clk->flags & ENABLED_ON_INIT) - do_clk_enable(clk); - } -} - -/** - * round_rate_index - return closest programmable rate index in rate_config tbl - * @clk: ptr to clock structure - * @drate: desired rate - * @rate: final rate will be returned in this variable only. - * - * Finds index in rate_config for highest clk rate which is less than - * requested rate. If there is no clk rate lesser than requested rate then - * -EINVAL is returned. This routine assumes that rate_config is written - * in incrementing order of clk rates. - * If drate passed is zero then default rate is programmed. - */ -static int -round_rate_index(struct clk *clk, unsigned long drate, unsigned long *rate) -{ - unsigned long tmp = 0, prev_rate = 0; - int index; - - if (!clk->calc_rate) - return -EFAULT; - - if (!drate) - return -EINVAL; - - /* - * This loops ends on two conditions: - * - as soon as clk is found with rate greater than requested rate. - * - if all clks in rate_config are smaller than requested rate. - */ - for (index = 0; index < clk->rate_config.count; index++) { - prev_rate = tmp; - tmp = clk->calc_rate(clk, index); - if (drate < tmp) { - index--; - break; - } - } - /* return if can't find suitable clock */ - if (index < 0) { - index = -EINVAL; - *rate = 0; - } else if (index == clk->rate_config.count) { - /* program with highest clk rate possible */ - index = clk->rate_config.count - 1; - *rate = tmp; - } else - *rate = prev_rate; - - return index; -} - -/** - * clk_round_rate - adjust a rate to the exact rate a clock can provide - * @clk: clock source - * @rate: desired clock rate in Hz - * - * Returns rounded clock rate in Hz, or negative errno. - */ -long clk_round_rate(struct clk *clk, unsigned long drate) -{ - long rate = 0; - int index; - - /* - * propagate call to parent who supports calc_rate. Similar approach is - * used in clk_set_rate. - */ - if (!clk->calc_rate) { - u32 mult; - if (!clk->pclk) - return clk->rate; - - mult = clk->div_factor ? clk->div_factor : 1; - return clk_round_rate(clk->pclk, mult * drate) / mult; - } - - index = round_rate_index(clk, drate, &rate); - if (index >= 0) - return rate; - else - return index; -} -EXPORT_SYMBOL(clk_round_rate); - -/*All below functions are called with lock held */ - -/* - * Calculates pll clk rate for specific value of mode, m, n and p - * - * In normal mode - * rate = (2 * M[15:8] * Fin)/(N * 2^P) - * - * In Dithered mode - * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) - */ -unsigned long pll_calc_rate(struct clk *clk, int index) -{ - unsigned long rate = clk->pclk->rate; - struct pll_rate_tbl *tbls = clk->rate_config.tbls; - unsigned int mode; - - mode = tbls[index].mode ? 256 : 1; - return (((2 * rate / 10000) * tbls[index].m) / - (mode * tbls[index].n * (1 << tbls[index].p))) * 10000; -} - -/* - * calculates current programmed rate of pll1 - * - * In normal mode - * rate = (2 * M[15:8] * Fin)/(N * 2^P) - * - * In Dithered mode - * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) - */ -int pll_clk_recalc(struct clk *clk) -{ - struct pll_clk_config *config = clk->private_data; - unsigned int num = 2, den = 0, val, mode = 0; - - mode = (readl(config->mode_reg) >> config->masks->mode_shift) & - config->masks->mode_mask; - - val = readl(config->cfg_reg); - /* calculate denominator */ - den = (val >> config->masks->div_p_shift) & config->masks->div_p_mask; - den = 1 << den; - den *= (val >> config->masks->div_n_shift) & config->masks->div_n_mask; - - /* calculate numerator & denominator */ - if (!mode) { - /* Normal mode */ - num *= (val >> config->masks->norm_fdbk_m_shift) & - config->masks->norm_fdbk_m_mask; - } else { - /* Dithered mode */ - num *= (val >> config->masks->dith_fdbk_m_shift) & - config->masks->dith_fdbk_m_mask; - den *= 256; - } - - if (!den) - return -EINVAL; - - clk->rate = (((clk->pclk->rate/10000) * num) / den) * 10000; - return 0; -} - -/* - * Configures new clock rate of pll - */ -int pll_clk_set_rate(struct clk *clk, unsigned long desired_rate) -{ - struct pll_rate_tbl *tbls = clk->rate_config.tbls; - struct pll_clk_config *config = clk->private_data; - unsigned long val, rate; - int i; - - i = round_rate_index(clk, desired_rate, &rate); - if (i < 0) - return i; - - val = readl(config->mode_reg) & - ~(config->masks->mode_mask << config->masks->mode_shift); - val |= (tbls[i].mode & config->masks->mode_mask) << - config->masks->mode_shift; - writel(val, config->mode_reg); - - val = readl(config->cfg_reg) & - ~(config->masks->div_p_mask << config->masks->div_p_shift); - val |= (tbls[i].p & config->masks->div_p_mask) << - config->masks->div_p_shift; - val &= ~(config->masks->div_n_mask << config->masks->div_n_shift); - val |= (tbls[i].n & config->masks->div_n_mask) << - config->masks->div_n_shift; - val &= ~(config->masks->dith_fdbk_m_mask << - config->masks->dith_fdbk_m_shift); - if (tbls[i].mode) - val |= (tbls[i].m & config->masks->dith_fdbk_m_mask) << - config->masks->dith_fdbk_m_shift; - else - val |= (tbls[i].m & config->masks->norm_fdbk_m_mask) << - config->masks->norm_fdbk_m_shift; - - writel(val, config->cfg_reg); - - clk->rate = rate; - - return 0; -} - -/* - * Calculates ahb, apb clk rate for specific value of div - */ -unsigned long bus_calc_rate(struct clk *clk, int index) -{ - unsigned long rate = clk->pclk->rate; - struct bus_rate_tbl *tbls = clk->rate_config.tbls; - - return rate / (tbls[index].div + 1); -} - -/* calculates current programmed rate of ahb or apb bus */ -int bus_clk_recalc(struct clk *clk) -{ - struct bus_clk_config *config = clk->private_data; - unsigned int div; - - div = ((readl(config->reg) >> config->masks->shift) & - config->masks->mask) + 1; - - if (!div) - return -EINVAL; - - clk->rate = (unsigned long)clk->pclk->rate / div; - return 0; -} - -/* Configures new clock rate of AHB OR APB bus */ -int bus_clk_set_rate(struct clk *clk, unsigned long desired_rate) -{ - struct bus_rate_tbl *tbls = clk->rate_config.tbls; - struct bus_clk_config *config = clk->private_data; - unsigned long val, rate; - int i; - - i = round_rate_index(clk, desired_rate, &rate); - if (i < 0) - return i; - - val = readl(config->reg) & - ~(config->masks->mask << config->masks->shift); - val |= (tbls[i].div & config->masks->mask) << config->masks->shift; - writel(val, config->reg); - - clk->rate = rate; - - return 0; -} - -/* - * gives rate for different values of eq, x and y - * - * Fout from synthesizer can be given from two equations: - * Fout1 = (Fin * X/Y)/2 EQ1 - * Fout2 = Fin * X/Y EQ2 - */ -unsigned long aux_calc_rate(struct clk *clk, int index) -{ - unsigned long rate = clk->pclk->rate; - struct aux_rate_tbl *tbls = clk->rate_config.tbls; - u8 eq = tbls[index].eq ? 1 : 2; - - return (((rate/10000) * tbls[index].xscale) / - (tbls[index].yscale * eq)) * 10000; -} - -/* - * calculates current programmed rate of auxiliary synthesizers - * used by: UART, FIRDA - * - * Fout from synthesizer can be given from two equations: - * Fout1 = (Fin * X/Y)/2 - * Fout2 = Fin * X/Y - * - * Selection of eqn 1 or 2 is programmed in register - */ -int aux_clk_recalc(struct clk *clk) -{ - struct aux_clk_config *config = clk->private_data; - unsigned int num = 1, den = 1, val, eqn; - - val = readl(config->synth_reg); - - eqn = (val >> config->masks->eq_sel_shift) & - config->masks->eq_sel_mask; - if (eqn == config->masks->eq1_mask) - den *= 2; - - /* calculate numerator */ - num = (val >> config->masks->xscale_sel_shift) & - config->masks->xscale_sel_mask; - - /* calculate denominator */ - den *= (val >> config->masks->yscale_sel_shift) & - config->masks->yscale_sel_mask; - - if (!den) - return -EINVAL; - - clk->rate = (((clk->pclk->rate/10000) * num) / den) * 10000; - return 0; -} - -/* Configures new clock rate of auxiliary synthesizers used by: UART, FIRDA*/ -int aux_clk_set_rate(struct clk *clk, unsigned long desired_rate) -{ - struct aux_rate_tbl *tbls = clk->rate_config.tbls; - struct aux_clk_config *config = clk->private_data; - unsigned long val, rate; - int i; - - i = round_rate_index(clk, desired_rate, &rate); - if (i < 0) - return i; - - val = readl(config->synth_reg) & - ~(config->masks->eq_sel_mask << config->masks->eq_sel_shift); - val |= (tbls[i].eq & config->masks->eq_sel_mask) << - config->masks->eq_sel_shift; - val &= ~(config->masks->xscale_sel_mask << - config->masks->xscale_sel_shift); - val |= (tbls[i].xscale & config->masks->xscale_sel_mask) << - config->masks->xscale_sel_shift; - val &= ~(config->masks->yscale_sel_mask << - config->masks->yscale_sel_shift); - val |= (tbls[i].yscale & config->masks->yscale_sel_mask) << - config->masks->yscale_sel_shift; - writel(val, config->synth_reg); - - clk->rate = rate; - - return 0; -} - -/* - * Calculates gpt clk rate for different values of mscale and nscale - * - * Fout= Fin/((2 ^ (N+1)) * (M+1)) - */ -unsigned long gpt_calc_rate(struct clk *clk, int index) -{ - unsigned long rate = clk->pclk->rate; - struct gpt_rate_tbl *tbls = clk->rate_config.tbls; - - return rate / ((1 << (tbls[index].nscale + 1)) * - (tbls[index].mscale + 1)); -} - -/* - * calculates current programmed rate of gpt synthesizers - * Fout from synthesizer can be given from below equations: - * Fout= Fin/((2 ^ (N+1)) * (M+1)) - */ -int gpt_clk_recalc(struct clk *clk) -{ - struct gpt_clk_config *config = clk->private_data; - unsigned int div = 1, val; - - val = readl(config->synth_reg); - div += (val >> config->masks->mscale_sel_shift) & - config->masks->mscale_sel_mask; - div *= 1 << (((val >> config->masks->nscale_sel_shift) & - config->masks->nscale_sel_mask) + 1); - - if (!div) - return -EINVAL; - - clk->rate = (unsigned long)clk->pclk->rate / div; - return 0; -} - -/* Configures new clock rate of gptiliary synthesizers used by: UART, FIRDA*/ -int gpt_clk_set_rate(struct clk *clk, unsigned long desired_rate) -{ - struct gpt_rate_tbl *tbls = clk->rate_config.tbls; - struct gpt_clk_config *config = clk->private_data; - unsigned long val, rate; - int i; - - i = round_rate_index(clk, desired_rate, &rate); - if (i < 0) - return i; - - val = readl(config->synth_reg) & ~(config->masks->mscale_sel_mask << - config->masks->mscale_sel_shift); - val |= (tbls[i].mscale & config->masks->mscale_sel_mask) << - config->masks->mscale_sel_shift; - val &= ~(config->masks->nscale_sel_mask << - config->masks->nscale_sel_shift); - val |= (tbls[i].nscale & config->masks->nscale_sel_mask) << - config->masks->nscale_sel_shift; - writel(val, config->synth_reg); - - clk->rate = rate; - - return 0; -} - -/* - * Calculates clcd clk rate for different values of div - * - * Fout from synthesizer can be given from below equation: - * Fout= Fin/2*div (division factor) - * div is 17 bits:- - * 0-13 (fractional part) - * 14-16 (integer part) - * To calculate Fout we left shift val by 14 bits and divide Fin by - * complete div (including fractional part) and then right shift the - * result by 14 places. - */ -unsigned long clcd_calc_rate(struct clk *clk, int index) -{ - unsigned long rate = clk->pclk->rate; - struct clcd_rate_tbl *tbls = clk->rate_config.tbls; - - rate /= 1000; - rate <<= 12; - rate /= (2 * tbls[index].div); - rate >>= 12; - rate *= 1000; - - return rate; -} - -/* - * calculates current programmed rate of clcd synthesizer - * Fout from synthesizer can be given from below equation: - * Fout= Fin/2*div (division factor) - * div is 17 bits:- - * 0-13 (fractional part) - * 14-16 (integer part) - * To calculate Fout we left shift val by 14 bits and divide Fin by - * complete div (including fractional part) and then right shift the - * result by 14 places. - */ -int clcd_clk_recalc(struct clk *clk) -{ - struct clcd_clk_config *config = clk->private_data; - unsigned int div = 1; - unsigned long prate; - unsigned int val; - - val = readl(config->synth_reg); - div = (val >> config->masks->div_factor_shift) & - config->masks->div_factor_mask; - - if (!div) - return -EINVAL; - - prate = clk->pclk->rate / 1000; /* first level division, make it KHz */ - - clk->rate = (((unsigned long)prate << 12) / (2 * div)) >> 12; - clk->rate *= 1000; - return 0; -} - -/* Configures new clock rate of auxiliary synthesizers used by: UART, FIRDA*/ -int clcd_clk_set_rate(struct clk *clk, unsigned long desired_rate) -{ - struct clcd_rate_tbl *tbls = clk->rate_config.tbls; - struct clcd_clk_config *config = clk->private_data; - unsigned long val, rate; - int i; - - i = round_rate_index(clk, desired_rate, &rate); - if (i < 0) - return i; - - val = readl(config->synth_reg) & ~(config->masks->div_factor_mask << - config->masks->div_factor_shift); - val |= (tbls[i].div & config->masks->div_factor_mask) << - config->masks->div_factor_shift; - writel(val, config->synth_reg); - - clk->rate = rate; - - return 0; -} - -/* - * Used for clocks that always have value as the parent clock divided by a - * fixed divisor - */ -int follow_parent(struct clk *clk) -{ - unsigned int div_factor = (clk->div_factor < 1) ? 1 : clk->div_factor; - - clk->rate = clk->pclk->rate/div_factor; - return 0; -} - -/** - * recalc_root_clocks - recalculate and propagate all root clocks - * - * Recalculates all root clocks (clocks with no parent), which if the - * clock's .recalc is set correctly, should also propagate their rates. - */ -void recalc_root_clocks(void) -{ - struct clk *pclk; - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&clocks_lock, flags); - list_for_each_entry(pclk, &root_clks, sibling) { - if (pclk->recalc) { - ret = pclk->recalc(pclk); - /* - * recalc will return error if clk out is not programmed - * In this case configure default clock. - */ - if (ret && pclk->set_rate) - pclk->set_rate(pclk, 0); - } - propagate_rate(pclk, 1); - /* Enable clks enabled on init, in software view */ - if (pclk->flags & ENABLED_ON_INIT) - do_clk_enable(pclk); - } - spin_unlock_irqrestore(&clocks_lock, flags); -} - -void __init clk_init(void) -{ - recalc_root_clocks(); -} - -#ifdef CONFIG_DEBUG_FS -/* - * debugfs support to trace clock tree hierarchy and attributes - */ -static struct dentry *clk_debugfs_root; -static int clk_debugfs_register_one(struct clk *c) -{ - int err; - struct dentry *d; - struct clk *pa = c->pclk; - char s[255]; - char *p = s; - - if (c) { - if (c->cl->con_id) - p += sprintf(p, "%s", c->cl->con_id); - if (c->cl->dev_id) - p += sprintf(p, "%s", c->cl->dev_id); - } - d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root); - if (!d) - return -ENOMEM; - c->dent = d; - - d = debugfs_create_u32("usage_count", S_IRUGO, c->dent, - (u32 *)&c->usage_count); - if (!d) { - err = -ENOMEM; - goto err_out; - } - d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate); - if (!d) { - err = -ENOMEM; - goto err_out; - } - d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags); - if (!d) { - err = -ENOMEM; - goto err_out; - } - return 0; - -err_out: - debugfs_remove_recursive(c->dent); - return err; -} - -static int clk_debugfs_register(struct clk *c) -{ - int err; - struct clk *pa = c->pclk; - - if (pa && !pa->dent) { - err = clk_debugfs_register(pa); - if (err) - return err; - } - - if (!c->dent) { - err = clk_debugfs_register_one(c); - if (err) - return err; - } - return 0; -} - -static int __init clk_debugfs_init(void) -{ - struct clk *c; - struct dentry *d; - int err; - - d = debugfs_create_dir("clock", NULL); - if (!d) - return -ENOMEM; - clk_debugfs_root = d; - - list_for_each_entry(c, &clocks, node) { - err = clk_debugfs_register(c); - if (err) - goto err_out; - } - return 0; -err_out: - debugfs_remove_recursive(clk_debugfs_root); - return err; -} -late_initcall(clk_debugfs_init); - -static int clk_debugfs_reparent(struct clk *c) -{ - debugfs_remove(c->dent); - return clk_debugfs_register_one(c); -} -#endif /* CONFIG_DEBUG_FS */ diff --git a/arch/arm/plat-spear/include/plat/clock.h b/arch/arm/plat-spear/include/plat/clock.h deleted file mode 100644 index 0062bafef12d..000000000000 --- a/arch/arm/plat-spear/include/plat/clock.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * arch/arm/plat-spear/include/plat/clock.h - * - * Clock framework definitions for SPEAr platform - * - * Copyright (C) 2009 ST Microelectronics - * Viresh Kumar<viresh.kumar@st.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __PLAT_CLOCK_H -#define __PLAT_CLOCK_H - -#include <linux/list.h> -#include <linux/clkdev.h> -#include <linux/types.h> - -/* clk structure flags */ -#define ALWAYS_ENABLED (1 << 0) /* clock always enabled */ -#define RESET_TO_ENABLE (1 << 1) /* reset register bit to enable clk */ -#define ENABLED_ON_INIT (1 << 2) /* clocks enabled at init */ - -/** - * struct clkops - clock operations - * @enable: pointer to clock enable function - * @disable: pointer to clock disable function - */ -struct clkops { - int (*enable) (struct clk *); - void (*disable) (struct clk *); -}; - -/** - * struct pclk_info - parents info - * @pclk: pointer to parent clk - * @pclk_val: value to be written for selecting this parent - */ -struct pclk_info { - struct clk *pclk; - u8 pclk_val; -}; - -/** - * struct pclk_sel - parents selection configuration - * @pclk_info: pointer to array of parent clock info - * @pclk_count: number of parents - * @pclk_sel_reg: register for selecting a parent - * @pclk_sel_mask: mask for selecting parent (can be used to clear bits also) - */ -struct pclk_sel { - struct pclk_info *pclk_info; - u8 pclk_count; - void __iomem *pclk_sel_reg; - unsigned int pclk_sel_mask; -}; - -/** - * struct rate_config - clk rate configurations - * @tbls: array of device specific clk rate tables, in ascending order of rates - * @count: size of tbls array - * @default_index: default setting when originally disabled - */ -struct rate_config { - void *tbls; - u8 count; - u8 default_index; -}; - -/** - * struct clk - clock structure - * @usage_count: num of users who enabled this clock - * @flags: flags for clock properties - * @rate: programmed clock rate in Hz - * @en_reg: clk enable/disable reg - * @en_reg_bit: clk enable/disable bit - * @ops: clk enable/disable ops - generic_clkops selected if NULL - * @recalc: pointer to clock rate recalculate function - * @set_rate: pointer to clock set rate function - * @calc_rate: pointer to clock get rate function for index - * @rate_config: rate configuration information, used by set_rate - * @div_factor: division factor to parent clock. - * @pclk: current parent clk - * @pclk_sel: pointer to parent selection structure - * @pclk_sel_shift: register shift for selecting parent of this clock - * @children: list for childrens or this clock - * @sibling: node for list of clocks having same parents - * @private_data: clock specific private data - * @node: list to maintain clocks linearly - * @cl: clocklook up associated with this clock - * @dent: object for debugfs - */ -struct clk { - unsigned int usage_count; - unsigned int flags; - unsigned long rate; - void __iomem *en_reg; - u8 en_reg_bit; - const struct clkops *ops; - int (*recalc) (struct clk *); - int (*set_rate) (struct clk *, unsigned long rate); - unsigned long (*calc_rate)(struct clk *, int index); - struct rate_config rate_config; - unsigned int div_factor; - - struct clk *pclk; - struct pclk_sel *pclk_sel; - unsigned int pclk_sel_shift; - - struct list_head children; - struct list_head sibling; - void *private_data; -#ifdef CONFIG_DEBUG_FS - struct list_head node; - struct clk_lookup *cl; - struct dentry *dent; -#endif -}; - -/* pll configuration structure */ -struct pll_clk_masks { - u32 mode_mask; - u32 mode_shift; - - u32 norm_fdbk_m_mask; - u32 norm_fdbk_m_shift; - u32 dith_fdbk_m_mask; - u32 dith_fdbk_m_shift; - u32 div_p_mask; - u32 div_p_shift; - u32 div_n_mask; - u32 div_n_shift; -}; - -struct pll_clk_config { - void __iomem *mode_reg; - void __iomem *cfg_reg; - struct pll_clk_masks *masks; -}; - -/* pll clk rate config structure */ -struct pll_rate_tbl { - u8 mode; - u16 m; - u8 n; - u8 p; -}; - -/* ahb and apb bus configuration structure */ -struct bus_clk_masks { - u32 mask; - u32 shift; -}; - -struct bus_clk_config { - void __iomem *reg; - struct bus_clk_masks *masks; -}; - -/* ahb and apb clk bus rate config structure */ -struct bus_rate_tbl { - u8 div; -}; - -/* Aux clk configuration structure: applicable to UART and FIRDA */ -struct aux_clk_masks { - u32 eq_sel_mask; - u32 eq_sel_shift; - u32 eq1_mask; - u32 eq2_mask; - u32 xscale_sel_mask; - u32 xscale_sel_shift; - u32 yscale_sel_mask; - u32 yscale_sel_shift; -}; - -struct aux_clk_config { - void __iomem *synth_reg; - struct aux_clk_masks *masks; -}; - -/* aux clk rate config structure */ -struct aux_rate_tbl { - u16 xscale; - u16 yscale; - u8 eq; -}; - -/* GPT clk configuration structure */ -struct gpt_clk_masks { - u32 mscale_sel_mask; - u32 mscale_sel_shift; - u32 nscale_sel_mask; - u32 nscale_sel_shift; -}; - -struct gpt_clk_config { - void __iomem *synth_reg; - struct gpt_clk_masks *masks; -}; - -/* gpt clk rate config structure */ -struct gpt_rate_tbl { - u16 mscale; - u16 nscale; -}; - -/* clcd clk configuration structure */ -struct clcd_synth_masks { - u32 div_factor_mask; - u32 div_factor_shift; -}; - -struct clcd_clk_config { - void __iomem *synth_reg; - struct clcd_synth_masks *masks; -}; - -/* clcd clk rate config structure */ -struct clcd_rate_tbl { - u16 div; -}; - -/* platform specific clock functions */ -void __init clk_init(void); -void clk_register(struct clk_lookup *cl); -void recalc_root_clocks(void); - -/* clock recalc & set rate functions */ -int follow_parent(struct clk *clk); -unsigned long pll_calc_rate(struct clk *clk, int index); -int pll_clk_recalc(struct clk *clk); -int pll_clk_set_rate(struct clk *clk, unsigned long desired_rate); -unsigned long bus_calc_rate(struct clk *clk, int index); -int bus_clk_recalc(struct clk *clk); -int bus_clk_set_rate(struct clk *clk, unsigned long desired_rate); -unsigned long gpt_calc_rate(struct clk *clk, int index); -int gpt_clk_recalc(struct clk *clk); -int gpt_clk_set_rate(struct clk *clk, unsigned long desired_rate); -unsigned long aux_calc_rate(struct clk *clk, int index); -int aux_clk_recalc(struct clk *clk); -int aux_clk_set_rate(struct clk *clk, unsigned long desired_rate); -unsigned long clcd_calc_rate(struct clk *clk, int index); -int clcd_clk_recalc(struct clk *clk); -int clcd_clk_set_rate(struct clk *clk, unsigned long desired_rate); - -#endif /* __PLAT_CLOCK_H */ diff --git a/arch/arm/plat-spear/time.c b/arch/arm/plat-spear/time.c index a3164d1647fd..03321af5de9f 100644 --- a/arch/arm/plat-spear/time.c +++ b/arch/arm/plat-spear/time.c @@ -18,6 +18,8 @@ #include <linux/ioport.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> #include <linux/time.h> #include <linux/irq.h> #include <asm/mach/time.h> @@ -197,19 +199,32 @@ static void __init spear_clockevent_init(int irq) setup_irq(irq, &spear_timer_irq); } -void __init spear_setup_timer(resource_size_t base, int irq) +const static struct of_device_id timer_of_match[] __initconst = { + { .compatible = "st,spear-timer", }, + { }, +}; + +void __init spear_setup_of_timer(void) { - int ret; + struct device_node *np; + int irq, ret; + + np = of_find_matching_node(NULL, timer_of_match); + if (!np) { + pr_err("%s: No timer passed via DT\n", __func__); + return; + } - if (!request_mem_region(base, SZ_1K, "gpt0")) { - pr_err("%s:cannot get IO addr\n", __func__); + irq = irq_of_parse_and_map(np, 0); + if (!irq) { + pr_err("%s: No irq passed for timer via DT\n", __func__); return; } - gpt_base = ioremap(base, SZ_1K); + gpt_base = of_iomap(np, 0); if (!gpt_base) { - pr_err("%s:ioremap failed for gpt\n", __func__); - goto err_mem; + pr_err("%s: of iomap failed\n", __func__); + return; } gpt_clk = clk_get_sys("gpt0", NULL); @@ -218,10 +233,10 @@ void __init spear_setup_timer(resource_size_t base, int irq) goto err_iomap; } - ret = clk_enable(gpt_clk); + ret = clk_prepare_enable(gpt_clk); if (ret < 0) { - pr_err("%s:couldn't enable gpt clock\n", __func__); - goto err_clk; + pr_err("%s:couldn't prepare-enable gpt clock\n", __func__); + goto err_prepare_enable_clk; } spear_clockevent_init(irq); @@ -229,10 +244,8 @@ void __init spear_setup_timer(resource_size_t base, int irq) return; -err_clk: +err_prepare_enable_clk: clk_put(gpt_clk); err_iomap: iounmap(gpt_base); -err_mem: - release_mem_region(base, SZ_1K); } diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 7336d4a7ab31..24712adf69df 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -553,6 +553,7 @@ struct mv_host_priv { #if defined(CONFIG_HAVE_CLK) struct clk *clk; + struct clk **port_clks; #endif /* * These consistent DMA memory pools give us guaranteed @@ -4027,6 +4028,9 @@ static int mv_platform_probe(struct platform_device *pdev) struct resource *res; int n_ports = 0; int rc; +#if defined(CONFIG_HAVE_CLK) + int port; +#endif ata_print_version_once(&pdev->dev, DRV_VERSION); @@ -4054,6 +4058,13 @@ static int mv_platform_probe(struct platform_device *pdev) if (!host || !hpriv) return -ENOMEM; +#if defined(CONFIG_HAVE_CLK) + hpriv->port_clks = devm_kzalloc(&pdev->dev, + sizeof(struct clk *) * n_ports, + GFP_KERNEL); + if (!hpriv->port_clks) + return -ENOMEM; +#endif host->private_data = hpriv; hpriv->n_ports = n_ports; hpriv->board_idx = chip_soc; @@ -4066,9 +4077,17 @@ static int mv_platform_probe(struct platform_device *pdev) #if defined(CONFIG_HAVE_CLK) hpriv->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(hpriv->clk)) - dev_notice(&pdev->dev, "cannot get clkdev\n"); + dev_notice(&pdev->dev, "cannot get optional clkdev\n"); else - clk_enable(hpriv->clk); + clk_prepare_enable(hpriv->clk); + + for (port = 0; port < n_ports; port++) { + char port_number[16]; + sprintf(port_number, "%d", port); + hpriv->port_clks[port] = clk_get(&pdev->dev, port_number); + if (!IS_ERR(hpriv->port_clks[port])) + clk_prepare_enable(hpriv->port_clks[port]); + } #endif /* @@ -4098,9 +4117,15 @@ static int mv_platform_probe(struct platform_device *pdev) err: #if defined(CONFIG_HAVE_CLK) if (!IS_ERR(hpriv->clk)) { - clk_disable(hpriv->clk); + clk_disable_unprepare(hpriv->clk); clk_put(hpriv->clk); } + for (port = 0; port < n_ports; port++) { + if (!IS_ERR(hpriv->port_clks[port])) { + clk_disable_unprepare(hpriv->port_clks[port]); + clk_put(hpriv->port_clks[port]); + } + } #endif return rc; @@ -4119,14 +4144,21 @@ static int __devexit mv_platform_remove(struct platform_device *pdev) struct ata_host *host = platform_get_drvdata(pdev); #if defined(CONFIG_HAVE_CLK) struct mv_host_priv *hpriv = host->private_data; + int port; #endif ata_host_detach(host); #if defined(CONFIG_HAVE_CLK) if (!IS_ERR(hpriv->clk)) { - clk_disable(hpriv->clk); + clk_disable_unprepare(hpriv->clk); clk_put(hpriv->clk); } + for (port = 0; port < host->n_ports; port++) { + if (!IS_ERR(hpriv->port_clks[port])) { + clk_disable_unprepare(hpriv->port_clks[port]); + clk_put(hpriv->port_clks[port]); + } + } #endif return 0; } diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 165e1febae53..4864407e3fc4 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -12,6 +12,7 @@ config HAVE_MACH_CLKDEV config COMMON_CLK bool select HAVE_CLK_PREPARE + select CLKDEV_LOOKUP ---help--- The common clock framework is a single definition of struct clk, useful across many platforms, as well as an @@ -22,17 +23,6 @@ config COMMON_CLK menu "Common Clock Framework" depends on COMMON_CLK -config COMMON_CLK_DISABLE_UNUSED - bool "Disabled unused clocks at boot" - depends on COMMON_CLK - ---help--- - Traverses the entire clock tree and disables any clocks that are - enabled in hardware but have not been enabled by any device drivers. - This saves power and keeps the software model of the clock in line - with reality. - - If in doubt, say "N". - config COMMON_CLK_DEBUG bool "DebugFS representation of clock tree" depends on COMMON_CLK diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 1f736bc11c4b..b9a5158a30b1 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,4 +1,7 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ - clk-mux.o clk-divider.o + clk-mux.o clk-divider.o clk-fixed-factor.o +# SoCs specific +obj-$(CONFIG_ARCH_MXS) += mxs/ +obj-$(CONFIG_PLAT_SPEAR) += spear/ diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index d5ac6a75ea57..8ea11b444528 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -45,7 +45,6 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, return parent_rate / div; } -EXPORT_SYMBOL_GPL(clk_divider_recalc_rate); /* * The reverse of DIV_ROUND_UP: The maximum number which @@ -68,8 +67,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, if (divider->flags & CLK_DIVIDER_ONE_BASED) maxdiv--; - if (!best_parent_rate) { - parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); + if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { + parent_rate = *best_parent_rate; bestdiv = DIV_ROUND_UP(parent_rate, rate); bestdiv = bestdiv == 0 ? 1 : bestdiv; bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; @@ -109,24 +108,18 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, int div; div = clk_divider_bestdiv(hw, rate, prate); - if (prate) - return *prate / div; - else { - unsigned long r; - r = __clk_get_rate(__clk_get_parent(hw->clk)); - return r / div; - } + return *prate / div; } -EXPORT_SYMBOL_GPL(clk_divider_round_rate); -static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) +static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { struct clk_divider *divider = to_clk_divider(hw); unsigned int div; unsigned long flags = 0; u32 val; - div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate; + div = parent_rate / rate; if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) div--; @@ -147,15 +140,26 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) return 0; } -EXPORT_SYMBOL_GPL(clk_divider_set_rate); -struct clk_ops clk_divider_ops = { +const struct clk_ops clk_divider_ops = { .recalc_rate = clk_divider_recalc_rate, .round_rate = clk_divider_round_rate, .set_rate = clk_divider_set_rate, }; EXPORT_SYMBOL_GPL(clk_divider_ops); +/** + * clk_register_divider - register a divider clock with the clock framework + * @dev: device registering this clock + * @name: name of this clock + * @parent_name: name of clock's parent + * @flags: framework-specific flags + * @reg: register address to adjust divider + * @shift: number of bits to shift the bitfield + * @width: width of the bitfield + * @clk_divider_flags: divider-specific flags for this clock + * @lock: shared register lock for this clock + */ struct clk *clk_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, @@ -163,38 +167,34 @@ struct clk *clk_register_divider(struct device *dev, const char *name, { struct clk_divider *div; struct clk *clk; + struct clk_init_data init; + /* allocate the divider */ div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); - if (!div) { pr_err("%s: could not allocate divider clk\n", __func__); - return NULL; + return ERR_PTR(-ENOMEM); } + init.name = name; + init.ops = &clk_divider_ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name: NULL); + init.num_parents = (parent_name ? 1 : 0); + /* struct clk_divider assignments */ div->reg = reg; div->shift = shift; div->width = width; div->flags = clk_divider_flags; div->lock = lock; + div->hw.init = &init; - if (parent_name) { - div->parent[0] = kstrdup(parent_name, GFP_KERNEL); - if (!div->parent[0]) - goto out; - } - - clk = clk_register(dev, name, - &clk_divider_ops, &div->hw, - div->parent, - (parent_name ? 1 : 0), - flags); - if (clk) - return clk; + /* register the clock */ + clk = clk_register(dev, &div->hw); -out: - kfree(div->parent[0]); - kfree(div); + if (IS_ERR(clk)) + kfree(div); - return NULL; + return clk; } diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c new file mode 100644 index 000000000000..c8c003e217ad --- /dev/null +++ b/drivers/clk/clk-fixed-factor.c @@ -0,0 +1,95 @@ +/* + * 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. + * + * Standard functionality for the common clock API. + */ +#include <linux/module.h> +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/err.h> + +/* + * DOC: basic fixed multiplier and divider clock that cannot gate + * + * Traits of this clock: + * prepare - clk_prepare only ensures that parents are prepared + * enable - clk_enable only ensures that parents are enabled + * rate - rate is fixed. clk->rate = parent->rate / div * mult + * parent - fixed parent. No clk_set_parent support + */ + +#define to_clk_fixed_factor(_hw) container_of(_hw, struct clk_fixed_factor, hw) + +static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); + + return parent_rate * fix->mult / fix->div; +} + +static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); + + if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) { + unsigned long best_parent; + + best_parent = (rate / fix->mult) * fix->div; + *prate = __clk_round_rate(__clk_get_parent(hw->clk), + best_parent); + } + + return (*prate / fix->div) * fix->mult; +} + +static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return 0; +} + +struct clk_ops clk_fixed_factor_ops = { + .round_rate = clk_factor_round_rate, + .set_rate = clk_factor_set_rate, + .recalc_rate = clk_factor_recalc_rate, +}; +EXPORT_SYMBOL_GPL(clk_fixed_factor_ops); + +struct clk *clk_register_fixed_factor(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + unsigned int mult, unsigned int div) +{ + struct clk_fixed_factor *fix; + struct clk_init_data init; + struct clk *clk; + + fix = kmalloc(sizeof(*fix), GFP_KERNEL); + if (!fix) { + pr_err("%s: could not allocate fixed factor clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + /* struct clk_fixed_factor assignments */ + fix->mult = mult; + fix->div = div; + fix->hw.init = &init; + + init.name = name; + init.ops = &clk_fixed_factor_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + clk = clk_register(dev, &fix->hw); + + if (IS_ERR(clk)) + kfree(fix); + + return clk; +} diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index 90c79fb5d1bd..cbd246229786 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -32,51 +32,50 @@ static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw, { return to_clk_fixed_rate(hw)->fixed_rate; } -EXPORT_SYMBOL_GPL(clk_fixed_rate_recalc_rate); -struct clk_ops clk_fixed_rate_ops = { +const struct clk_ops clk_fixed_rate_ops = { .recalc_rate = clk_fixed_rate_recalc_rate, }; EXPORT_SYMBOL_GPL(clk_fixed_rate_ops); +/** + * clk_register_fixed_rate - register fixed-rate clock with the clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_name: name of clock's parent + * @flags: framework-specific flags + * @fixed_rate: non-adjustable clock rate + */ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned long fixed_rate) { struct clk_fixed_rate *fixed; - char **parent_names = NULL; - u8 len; + struct clk *clk; + struct clk_init_data init; + /* allocate fixed-rate clock */ fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); - if (!fixed) { pr_err("%s: could not allocate fixed clk\n", __func__); return ERR_PTR(-ENOMEM); } + init.name = name; + init.ops = &clk_fixed_rate_ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name: NULL); + init.num_parents = (parent_name ? 1 : 0); + /* struct clk_fixed_rate assignments */ fixed->fixed_rate = fixed_rate; + fixed->hw.init = &init; - if (parent_name) { - parent_names = kmalloc(sizeof(char *), GFP_KERNEL); - - if (! parent_names) - goto out; + /* register the clock */ + clk = clk_register(dev, &fixed->hw); - len = sizeof(char) * strlen(parent_name); - - parent_names[0] = kmalloc(len, GFP_KERNEL); - - if (!parent_names[0]) - goto out; - - strncpy(parent_names[0], parent_name, len); - } + if (IS_ERR(clk)) + kfree(fixed); -out: - return clk_register(dev, name, - &clk_fixed_rate_ops, &fixed->hw, - parent_names, - (parent_name ? 1 : 0), - flags); + return clk; } diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index b5902e2ef2fd..578465e04be6 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -28,32 +28,38 @@ #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) -static void clk_gate_set_bit(struct clk_gate *gate) +/* + * It works on following logic: + * + * For enabling clock, enable = 1 + * set2dis = 1 -> clear bit -> set = 0 + * set2dis = 0 -> set bit -> set = 1 + * + * For disabling clock, enable = 0 + * set2dis = 1 -> set bit -> set = 1 + * set2dis = 0 -> clear bit -> set = 0 + * + * So, result is always: enable xor set2dis. + */ +static void clk_gate_endisable(struct clk_hw *hw, int enable) { - u32 reg; + struct clk_gate *gate = to_clk_gate(hw); + int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; unsigned long flags = 0; + u32 reg; + + set ^= enable; if (gate->lock) spin_lock_irqsave(gate->lock, flags); reg = readl(gate->reg); - reg |= BIT(gate->bit_idx); - writel(reg, gate->reg); - - if (gate->lock) - spin_unlock_irqrestore(gate->lock, flags); -} - -static void clk_gate_clear_bit(struct clk_gate *gate) -{ - u32 reg; - unsigned long flags = 0; - if (gate->lock) - spin_lock_irqsave(gate->lock, flags); + if (set) + reg |= BIT(gate->bit_idx); + else + reg &= ~BIT(gate->bit_idx); - reg = readl(gate->reg); - reg &= ~BIT(gate->bit_idx); writel(reg, gate->reg); if (gate->lock) @@ -62,27 +68,15 @@ static void clk_gate_clear_bit(struct clk_gate *gate) static int clk_gate_enable(struct clk_hw *hw) { - struct clk_gate *gate = to_clk_gate(hw); - - if (gate->flags & CLK_GATE_SET_TO_DISABLE) - clk_gate_clear_bit(gate); - else - clk_gate_set_bit(gate); + clk_gate_endisable(hw, 1); return 0; } -EXPORT_SYMBOL_GPL(clk_gate_enable); static void clk_gate_disable(struct clk_hw *hw) { - struct clk_gate *gate = to_clk_gate(hw); - - if (gate->flags & CLK_GATE_SET_TO_DISABLE) - clk_gate_set_bit(gate); - else - clk_gate_clear_bit(gate); + clk_gate_endisable(hw, 0); } -EXPORT_SYMBOL_GPL(clk_gate_disable); static int clk_gate_is_enabled(struct clk_hw *hw) { @@ -99,15 +93,25 @@ static int clk_gate_is_enabled(struct clk_hw *hw) return reg ? 1 : 0; } -EXPORT_SYMBOL_GPL(clk_gate_is_enabled); -struct clk_ops clk_gate_ops = { +const struct clk_ops clk_gate_ops = { .enable = clk_gate_enable, .disable = clk_gate_disable, .is_enabled = clk_gate_is_enabled, }; EXPORT_SYMBOL_GPL(clk_gate_ops); +/** + * clk_register_gate - register a gate clock with the clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_name: name of this clock's parent + * @flags: framework-specific flags for this clock + * @reg: register address to control gating of this clock + * @bit_idx: which bit in the register controls gating of this clock + * @clk_gate_flags: gate-specific flags for this clock + * @lock: shared register lock for this clock + */ struct clk *clk_register_gate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, @@ -115,36 +119,32 @@ struct clk *clk_register_gate(struct device *dev, const char *name, { struct clk_gate *gate; struct clk *clk; + struct clk_init_data init; + /* allocate the gate */ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); - if (!gate) { pr_err("%s: could not allocate gated clk\n", __func__); - return NULL; + return ERR_PTR(-ENOMEM); } + init.name = name; + init.ops = &clk_gate_ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name: NULL); + init.num_parents = (parent_name ? 1 : 0); + /* struct clk_gate assignments */ gate->reg = reg; gate->bit_idx = bit_idx; gate->flags = clk_gate_flags; gate->lock = lock; + gate->hw.init = &init; - if (parent_name) { - gate->parent[0] = kstrdup(parent_name, GFP_KERNEL); - if (!gate->parent[0]) - goto out; - } + clk = clk_register(dev, &gate->hw); + + if (IS_ERR(clk)) + kfree(gate); - clk = clk_register(dev, name, - &clk_gate_ops, &gate->hw, - gate->parent, - (parent_name ? 1 : 0), - flags); - if (clk) - return clk; -out: - kfree(gate->parent[0]); - kfree(gate); - - return NULL; + return clk; } diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index c71ad1f41a97..fd36a8ea73d9 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -55,7 +55,6 @@ static u8 clk_mux_get_parent(struct clk_hw *hw) return val; } -EXPORT_SYMBOL_GPL(clk_mux_get_parent); static int clk_mux_set_parent(struct clk_hw *hw, u8 index) { @@ -82,35 +81,47 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index) return 0; } -EXPORT_SYMBOL_GPL(clk_mux_set_parent); -struct clk_ops clk_mux_ops = { +const struct clk_ops clk_mux_ops = { .get_parent = clk_mux_get_parent, .set_parent = clk_mux_set_parent, }; EXPORT_SYMBOL_GPL(clk_mux_ops); struct clk *clk_register_mux(struct device *dev, const char *name, - char **parent_names, u8 num_parents, unsigned long flags, + const char **parent_names, u8 num_parents, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_mux_flags, spinlock_t *lock) { struct clk_mux *mux; + struct clk *clk; + struct clk_init_data init; - mux = kmalloc(sizeof(struct clk_mux), GFP_KERNEL); - + /* allocate the mux */ + mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); if (!mux) { pr_err("%s: could not allocate mux clk\n", __func__); return ERR_PTR(-ENOMEM); } + init.name = name; + init.ops = &clk_mux_ops; + init.flags = flags; + init.parent_names = parent_names; + init.num_parents = num_parents; + /* struct clk_mux assignments */ mux->reg = reg; mux->shift = shift; mux->width = width; mux->flags = clk_mux_flags; mux->lock = lock; + mux->hw.init = &init; + + clk = clk_register(dev, &mux->hw); + + if (IS_ERR(clk)) + kfree(mux); - return clk_register(dev, name, &clk_mux_ops, &mux->hw, - parent_names, num_parents, flags); + return clk; } diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 9cf6f59e3e19..687b00d67c8a 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -194,9 +194,8 @@ static int __init clk_debug_init(void) late_initcall(clk_debug_init); #else static inline int clk_debug_register(struct clk *clk) { return 0; } -#endif /* CONFIG_COMMON_CLK_DEBUG */ +#endif -#ifdef CONFIG_COMMON_CLK_DISABLE_UNUSED /* caller must hold prepare_lock */ static void clk_disable_unused_subtree(struct clk *clk) { @@ -246,9 +245,6 @@ static int clk_disable_unused(void) return 0; } late_initcall(clk_disable_unused); -#else -static inline int clk_disable_unused(struct clk *clk) { return 0; } -#endif /* CONFIG_COMMON_CLK_DISABLE_UNUSED */ /*** helper functions ***/ @@ -287,7 +283,7 @@ unsigned long __clk_get_rate(struct clk *clk) unsigned long ret; if (!clk) { - ret = -EINVAL; + ret = 0; goto out; } @@ -297,7 +293,7 @@ unsigned long __clk_get_rate(struct clk *clk) goto out; if (!clk->parent) - ret = -ENODEV; + ret = 0; out: return ret; @@ -562,7 +558,7 @@ EXPORT_SYMBOL_GPL(clk_enable); * @clk: the clk whose rate is being returned * * Simply returns the cached rate of the clk. Does not query the hardware. If - * clk is NULL then returns -EINVAL. + * clk is NULL then returns 0. */ unsigned long clk_get_rate(struct clk *clk) { @@ -584,18 +580,22 @@ EXPORT_SYMBOL_GPL(clk_get_rate); */ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) { - unsigned long unused; + unsigned long parent_rate = 0; if (!clk) return -EINVAL; - if (!clk->ops->round_rate) - return clk->rate; + if (!clk->ops->round_rate) { + if (clk->flags & CLK_SET_RATE_PARENT) + return __clk_round_rate(clk->parent, rate); + else + return clk->rate; + } - if (clk->flags & CLK_SET_RATE_PARENT) - return clk->ops->round_rate(clk->hw, rate, &unused); - else - return clk->ops->round_rate(clk->hw, rate, NULL); + if (clk->parent) + parent_rate = clk->parent->rate; + + return clk->ops->round_rate(clk->hw, rate, &parent_rate); } /** @@ -765,25 +765,41 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate) static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate) { struct clk *top = clk; - unsigned long best_parent_rate = clk->parent->rate; + unsigned long best_parent_rate = 0; unsigned long new_rate; - if (!clk->ops->round_rate && !(clk->flags & CLK_SET_RATE_PARENT)) { - clk->new_rate = clk->rate; + /* sanity */ + if (IS_ERR_OR_NULL(clk)) + return NULL; + + /* save parent rate, if it exists */ + if (clk->parent) + best_parent_rate = clk->parent->rate; + + /* never propagate up to the parent */ + if (!(clk->flags & CLK_SET_RATE_PARENT)) { + if (!clk->ops->round_rate) { + clk->new_rate = clk->rate; + return NULL; + } + new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); + goto out; + } + + /* need clk->parent from here on out */ + if (!clk->parent) { + pr_debug("%s: %s has NULL parent\n", __func__, clk->name); return NULL; } - if (!clk->ops->round_rate && (clk->flags & CLK_SET_RATE_PARENT)) { + if (!clk->ops->round_rate) { top = clk_calc_new_rates(clk->parent, rate); - new_rate = clk->new_rate = clk->parent->new_rate; + new_rate = clk->parent->new_rate; goto out; } - if (clk->flags & CLK_SET_RATE_PARENT) - new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); - else - new_rate = clk->ops->round_rate(clk->hw, rate, NULL); + new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); if (best_parent_rate != clk->parent->rate) { top = clk_calc_new_rates(clk->parent, best_parent_rate); @@ -839,7 +855,7 @@ static void clk_change_rate(struct clk *clk) old_rate = clk->rate; if (clk->ops->set_rate) - clk->ops->set_rate(clk->hw, clk->new_rate); + clk->ops->set_rate(clk->hw, clk->new_rate, clk->parent->rate); if (clk->ops->recalc_rate) clk->rate = clk->ops->recalc_rate(clk->hw, @@ -859,38 +875,19 @@ static void clk_change_rate(struct clk *clk) * @clk: the clk whose rate is being changed * @rate: the new rate for clk * - * In the simplest case clk_set_rate will only change the rate of clk. - * - * If clk has the CLK_SET_RATE_GATE flag set and it is enabled this call - * will fail; only when the clk is disabled will it be able to change - * its rate. + * In the simplest case clk_set_rate will only adjust the rate of clk. * - * Setting the CLK_SET_RATE_PARENT flag allows clk_set_rate to - * recursively propagate up to clk's parent; whether or not this happens - * depends on the outcome of clk's .round_rate implementation. If - * *parent_rate is 0 after calling .round_rate then upstream parent - * propagation is ignored. If *parent_rate comes back with a new rate - * for clk's parent then we propagate up to clk's parent and set it's - * rate. Upward propagation will continue until either a clk does not - * support the CLK_SET_RATE_PARENT flag or .round_rate stops requesting - * changes to clk's parent_rate. If there is a failure during upstream - * propagation then clk_set_rate will unwind and restore each clk's rate - * that had been successfully changed. Afterwards a rate change abort - * notification will be propagated downstream, starting from the clk - * that failed. + * Setting the CLK_SET_RATE_PARENT flag allows the rate change operation to + * propagate up to clk's parent; whether or not this happens depends on the + * outcome of clk's .round_rate implementation. If *parent_rate is unchanged + * after calling .round_rate then upstream parent propagation is ignored. If + * *parent_rate comes back with a new rate for clk's parent then we propagate + * up to clk's parent and set it's rate. Upward propagation will continue + * until either a clk does not support the CLK_SET_RATE_PARENT flag or + * .round_rate stops requesting changes to clk's parent_rate. * - * At the end of all of the rate setting, clk_set_rate internally calls - * __clk_recalc_rates and propagates the rate changes downstream, - * starting from the highest clk whose rate was changed. This has the - * added benefit of propagating post-rate change notifiers. - * - * Note that while post-rate change and rate change abort notifications - * are guaranteed to be sent to a clk only once per call to - * clk_set_rate, pre-change notifications will be sent for every clk - * whose rate is changed. Stacking pre-change notifications is noisy - * for the drivers subscribed to them, but this allows drivers to react - * to intermediate clk rate changes up until the point where the final - * rate is achieved at the end of upstream propagation. + * Rate changes are accomplished via tree traversal that also recalculates the + * rates for the clocks and fires off POST_RATE_CHANGE notifiers. * * Returns 0 on success, -EERROR otherwise. */ @@ -906,6 +903,11 @@ int clk_set_rate(struct clk *clk, unsigned long rate) if (rate == clk->rate) goto out; + if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count) { + ret = -EBUSY; + goto out; + } + /* calculate new rates and get the topmost changed clock */ top = clk_calc_new_rates(clk, rate); if (!top) { @@ -1175,40 +1177,41 @@ EXPORT_SYMBOL_GPL(clk_set_parent); * * Initializes the lists in struct clk, queries the hardware for the * parent and rate and sets them both. - * - * Any struct clk passed into __clk_init must have the following members - * populated: - * .name - * .ops - * .hw - * .parent_names - * .num_parents - * .flags - * - * Essentially, everything that would normally be passed into clk_register is - * assumed to be initialized already in __clk_init. The other members may be - * populated, but are optional. - * - * __clk_init is only exposed via clk-private.h and is intended for use with - * very large numbers of clocks that need to be statically initialized. It is - * a layering violation to include clk-private.h from any code which implements - * a clock's .ops; as such any statically initialized clock data MUST be in a - * separate C file from the logic that implements it's operations. */ -void __clk_init(struct device *dev, struct clk *clk) +int __clk_init(struct device *dev, struct clk *clk) { - int i; + int i, ret = 0; struct clk *orphan; struct hlist_node *tmp, *tmp2; if (!clk) - return; + return -EINVAL; mutex_lock(&prepare_lock); /* check to see if a clock with this name is already registered */ - if (__clk_lookup(clk->name)) + if (__clk_lookup(clk->name)) { + pr_debug("%s: clk %s already initialized\n", + __func__, clk->name); + ret = -EEXIST; + goto out; + } + + /* check that clk_ops are sane. See Documentation/clk.txt */ + if (clk->ops->set_rate && + !(clk->ops->round_rate && clk->ops->recalc_rate)) { + pr_warning("%s: %s must implement .round_rate & .recalc_rate\n", + __func__, clk->name); + ret = -EINVAL; + goto out; + } + + if (clk->ops->set_parent && !clk->ops->get_parent) { + pr_warning("%s: %s must implement .get_parent & .set_parent\n", + __func__, clk->name); + ret = -EINVAL; goto out; + } /* throw a WARN if any entries in parent_names are NULL */ for (i = 0; i < clk->num_parents; i++) @@ -1302,48 +1305,130 @@ void __clk_init(struct device *dev, struct clk *clk) out: mutex_unlock(&prepare_lock); - return; + return ret; } /** + * __clk_register - register a clock and return a cookie. + * + * Same as clk_register, except that the .clk field inside hw shall point to a + * preallocated (generally statically allocated) struct clk. None of the fields + * of the struct clk need to be initialized. + * + * The data pointed to by .init and .clk field shall NOT be marked as init + * data. + * + * __clk_register is only exposed via clk-private.h and is intended for use with + * very large numbers of clocks that need to be statically initialized. It is + * a layering violation to include clk-private.h from any code which implements + * a clock's .ops; as such any statically initialized clock data MUST be in a + * separate C file from the logic that implements it's operations. Returns 0 + * on success, otherwise an error code. + */ +struct clk *__clk_register(struct device *dev, struct clk_hw *hw) +{ + int ret; + struct clk *clk; + + clk = hw->clk; + clk->name = hw->init->name; + clk->ops = hw->init->ops; + clk->hw = hw; + clk->flags = hw->init->flags; + clk->parent_names = hw->init->parent_names; + clk->num_parents = hw->init->num_parents; + + ret = __clk_init(dev, clk); + if (ret) + return ERR_PTR(ret); + + return clk; +} +EXPORT_SYMBOL_GPL(__clk_register); + +/** * clk_register - allocate a new clock, register it and return an opaque cookie * @dev: device that is registering this clock - * @name: clock name - * @ops: operations this clock supports * @hw: link to hardware-specific clock data - * @parent_names: array of string names for all possible parents - * @num_parents: number of possible parents - * @flags: framework-level hints and quirks * * clk_register is the primary interface for populating the clock tree with new * clock nodes. It returns a pointer to the newly allocated struct clk which * cannot be dereferenced by driver code but may be used in conjuction with the - * rest of the clock API. + * rest of the clock API. In the event of an error clk_register will return an + * error code; drivers must test for an error code after calling clk_register. */ -struct clk *clk_register(struct device *dev, const char *name, - const struct clk_ops *ops, struct clk_hw *hw, - char **parent_names, u8 num_parents, unsigned long flags) +struct clk *clk_register(struct device *dev, struct clk_hw *hw) { + int i, ret; struct clk *clk; clk = kzalloc(sizeof(*clk), GFP_KERNEL); - if (!clk) - return NULL; + if (!clk) { + pr_err("%s: could not allocate clk\n", __func__); + ret = -ENOMEM; + goto fail_out; + } - clk->name = name; - clk->ops = ops; + clk->name = kstrdup(hw->init->name, GFP_KERNEL); + if (!clk->name) { + pr_err("%s: could not allocate clk->name\n", __func__); + ret = -ENOMEM; + goto fail_name; + } + clk->ops = hw->init->ops; clk->hw = hw; - clk->flags = flags; - clk->parent_names = parent_names; - clk->num_parents = num_parents; + clk->flags = hw->init->flags; + clk->num_parents = hw->init->num_parents; hw->clk = clk; - __clk_init(dev, clk); + /* allocate local copy in case parent_names is __initdata */ + clk->parent_names = kzalloc((sizeof(char*) * clk->num_parents), + GFP_KERNEL); - return clk; + if (!clk->parent_names) { + pr_err("%s: could not allocate clk->parent_names\n", __func__); + ret = -ENOMEM; + goto fail_parent_names; + } + + + /* copy each string name in case parent_names is __initdata */ + for (i = 0; i < clk->num_parents; i++) { + clk->parent_names[i] = kstrdup(hw->init->parent_names[i], + GFP_KERNEL); + if (!clk->parent_names[i]) { + pr_err("%s: could not copy parent_names\n", __func__); + ret = -ENOMEM; + goto fail_parent_names_copy; + } + } + + ret = __clk_init(dev, clk); + if (!ret) + return clk; + +fail_parent_names_copy: + while (--i >= 0) + kfree(clk->parent_names[i]); + kfree(clk->parent_names); +fail_parent_names: + kfree(clk->name); +fail_name: + kfree(clk); +fail_out: + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(clk_register); +/** + * clk_unregister - unregister a currently registered clock + * @clk: clock to unregister + * + * Currently unimplemented. + */ +void clk_unregister(struct clk *clk) {} +EXPORT_SYMBOL_GPL(clk_unregister); + /*** clk rate change notifiers ***/ /** diff --git a/drivers/clk/mxs/Makefile b/drivers/clk/mxs/Makefile new file mode 100644 index 000000000000..7bedeec08524 --- /dev/null +++ b/drivers/clk/mxs/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for mxs specific clk +# + +obj-y += clk.o clk-pll.o clk-ref.o clk-div.o clk-frac.o + +obj-$(CONFIG_SOC_IMX23) += clk-imx23.o +obj-$(CONFIG_SOC_IMX28) += clk-imx28.o diff --git a/drivers/clk/mxs/clk-div.c b/drivers/clk/mxs/clk-div.c new file mode 100644 index 000000000000..90e1da93877e --- /dev/null +++ b/drivers/clk/mxs/clk-div.c @@ -0,0 +1,110 @@ +/* + * Copyright 2012 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 <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/slab.h> +#include "clk.h" + +/** + * struct clk_div - mxs integer divider clock + * @divider: the parent class + * @ops: pointer to clk_ops of parent class + * @reg: register address + * @busy: busy bit shift + * + * The mxs divider clock is a subclass of basic clk_divider with an + * addtional busy bit. + */ +struct clk_div { + struct clk_divider divider; + const struct clk_ops *ops; + void __iomem *reg; + u8 busy; +}; + +static inline struct clk_div *to_clk_div(struct clk_hw *hw) +{ + struct clk_divider *divider = container_of(hw, struct clk_divider, hw); + + return container_of(divider, struct clk_div, divider); +} + +static unsigned long clk_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_div *div = to_clk_div(hw); + + return div->ops->recalc_rate(&div->divider.hw, parent_rate); +} + +static long clk_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_div *div = to_clk_div(hw); + + return div->ops->round_rate(&div->divider.hw, rate, prate); +} + +static int clk_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_div *div = to_clk_div(hw); + int ret; + + ret = div->ops->set_rate(&div->divider.hw, rate, parent_rate); + if (!ret) + ret = mxs_clk_wait(div->reg, div->busy); + + return ret; +} + +static struct clk_ops clk_div_ops = { + .recalc_rate = clk_div_recalc_rate, + .round_rate = clk_div_round_rate, + .set_rate = clk_div_set_rate, +}; + +struct clk *mxs_clk_div(const char *name, const char *parent_name, + void __iomem *reg, u8 shift, u8 width, u8 busy) +{ + struct clk_div *div; + struct clk *clk; + struct clk_init_data init; + + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_div_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = (parent_name ? &parent_name: NULL); + init.num_parents = (parent_name ? 1 : 0); + + div->reg = reg; + div->busy = busy; + + div->divider.reg = reg; + div->divider.shift = shift; + div->divider.width = width; + div->divider.flags = CLK_DIVIDER_ONE_BASED; + div->divider.lock = &mxs_lock; + div->divider.hw.init = &init; + div->ops = &clk_divider_ops; + + clk = clk_register(NULL, &div->divider.hw); + if (IS_ERR(clk)) + kfree(div); + + return clk; +} diff --git a/drivers/clk/mxs/clk-frac.c b/drivers/clk/mxs/clk-frac.c new file mode 100644 index 000000000000..e6aa6b567d68 --- /dev/null +++ b/drivers/clk/mxs/clk-frac.c @@ -0,0 +1,139 @@ +/* + * Copyright 2012 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 <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/slab.h> +#include "clk.h" + +/** + * struct clk_frac - mxs fractional divider clock + * @hw: clk_hw for the fractional divider clock + * @reg: register address + * @shift: the divider bit shift + * @width: the divider bit width + * @busy: busy bit shift + * + * The clock is an adjustable fractional divider with a busy bit to wait + * when the divider is adjusted. + */ +struct clk_frac { + struct clk_hw hw; + void __iomem *reg; + u8 shift; + u8 width; + u8 busy; +}; + +#define to_clk_frac(_hw) container_of(_hw, struct clk_frac, hw) + +static unsigned long clk_frac_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_frac *frac = to_clk_frac(hw); + u32 div; + + div = readl_relaxed(frac->reg) >> frac->shift; + div &= (1 << frac->width) - 1; + + return (parent_rate >> frac->width) * div; +} + +static long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_frac *frac = to_clk_frac(hw); + unsigned long parent_rate = *prate; + u32 div; + u64 tmp; + + if (rate > parent_rate) + return -EINVAL; + + tmp = rate; + tmp <<= frac->width; + do_div(tmp, parent_rate); + div = tmp; + + if (!div) + return -EINVAL; + + return (parent_rate >> frac->width) * div; +} + +static int clk_frac_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_frac *frac = to_clk_frac(hw); + unsigned long flags; + u32 div, val; + u64 tmp; + + if (rate > parent_rate) + return -EINVAL; + + tmp = rate; + tmp <<= frac->width; + do_div(tmp, parent_rate); + div = tmp; + + if (!div) + return -EINVAL; + + spin_lock_irqsave(&mxs_lock, flags); + + val = readl_relaxed(frac->reg); + val &= ~(((1 << frac->width) - 1) << frac->shift); + val |= div << frac->shift; + writel_relaxed(val, frac->reg); + + spin_unlock_irqrestore(&mxs_lock, flags); + + return mxs_clk_wait(frac->reg, frac->busy); +} + +static struct clk_ops clk_frac_ops = { + .recalc_rate = clk_frac_recalc_rate, + .round_rate = clk_frac_round_rate, + .set_rate = clk_frac_set_rate, +}; + +struct clk *mxs_clk_frac(const char *name, const char *parent_name, + void __iomem *reg, u8 shift, u8 width, u8 busy) +{ + struct clk_frac *frac; + struct clk *clk; + struct clk_init_data init; + + frac = kzalloc(sizeof(*frac), GFP_KERNEL); + if (!frac) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_frac_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = (parent_name ? &parent_name: NULL); + init.num_parents = (parent_name ? 1 : 0); + + frac->reg = reg; + frac->shift = shift; + frac->width = width; + frac->busy = busy; + frac->hw.init = &init; + + clk = clk_register(NULL, &frac->hw); + if (IS_ERR(clk)) + kfree(frac); + + return clk; +} diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c new file mode 100644 index 000000000000..dcae11285716 --- /dev/null +++ b/drivers/clk/mxs/clk-imx23.c @@ -0,0 +1,204 @@ +/* + * Copyright 2012 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 <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <mach/common.h> +#include <mach/mx23.h> +#include "clk.h" + +#define DIGCTRL MX23_IO_ADDRESS(MX23_DIGCTL_BASE_ADDR) +#define CLKCTRL MX23_IO_ADDRESS(MX23_CLKCTRL_BASE_ADDR) +#define PLLCTRL0 (CLKCTRL + 0x0000) +#define CPU (CLKCTRL + 0x0020) +#define HBUS (CLKCTRL + 0x0030) +#define XBUS (CLKCTRL + 0x0040) +#define XTAL (CLKCTRL + 0x0050) +#define PIX (CLKCTRL + 0x0060) +#define SSP (CLKCTRL + 0x0070) +#define GPMI (CLKCTRL + 0x0080) +#define SPDIF (CLKCTRL + 0x0090) +#define EMI (CLKCTRL + 0x00a0) +#define SAIF (CLKCTRL + 0x00c0) +#define TV (CLKCTRL + 0x00d0) +#define ETM (CLKCTRL + 0x00e0) +#define FRAC (CLKCTRL + 0x00f0) +#define CLKSEQ (CLKCTRL + 0x0110) + +#define BP_CPU_INTERRUPT_WAIT 12 +#define BP_CLKSEQ_BYPASS_SAIF 0 +#define BP_CLKSEQ_BYPASS_SSP 5 +#define BP_SAIF_DIV_FRAC_EN 16 +#define BP_FRAC_IOFRAC 24 + +static void __init clk_misc_init(void) +{ + u32 val; + + /* Gate off cpu clock in WFI for power saving */ + __mxs_setl(1 << BP_CPU_INTERRUPT_WAIT, CPU); + + /* Clear BYPASS for SAIF */ + __mxs_clrl(1 << BP_CLKSEQ_BYPASS_SAIF, CLKSEQ); + + /* SAIF has to use frac div for functional operation */ + val = readl_relaxed(SAIF); + val |= 1 << BP_SAIF_DIV_FRAC_EN; + writel_relaxed(val, SAIF); + + /* + * Source ssp clock from ref_io than ref_xtal, + * as ref_xtal only provides 24 MHz as maximum. + */ + __mxs_clrl(1 << BP_CLKSEQ_BYPASS_SSP, CLKSEQ); + + /* + * 480 MHz seems too high to be ssp clock source directly, + * so set frac to get a 288 MHz ref_io. + */ + __mxs_clrl(0x3f << BP_FRAC_IOFRAC, FRAC); + __mxs_setl(30 << BP_FRAC_IOFRAC, FRAC); +} + +static struct clk_lookup uart_lookups[] __initdata = { + { .dev_id = "duart", }, + { .dev_id = "mxs-auart.0", }, + { .dev_id = "mxs-auart.1", }, + { .dev_id = "8006c000.serial", }, + { .dev_id = "8006e000.serial", }, + { .dev_id = "80070000.serial", }, +}; + +static struct clk_lookup hbus_lookups[] __initdata = { + { .dev_id = "mxs-dma-apbh", }, + { .dev_id = "80004000.dma-apbh", }, +}; + +static struct clk_lookup xbus_lookups[] __initdata = { + { .dev_id = "duart", .con_id = "apb_pclk"}, + { .dev_id = "mxs-dma-apbx", }, + { .dev_id = "80024000.dma-apbx", }, +}; + +static struct clk_lookup ssp_lookups[] __initdata = { + { .dev_id = "mxs-mmc.0", }, + { .dev_id = "mxs-mmc.1", }, + { .dev_id = "80010000.ssp", }, + { .dev_id = "80034000.ssp", }, +}; + +static struct clk_lookup lcdif_lookups[] __initdata = { + { .dev_id = "imx23-fb", }, + { .dev_id = "80030000.lcdif", }, +}; + +static struct clk_lookup gpmi_lookups[] __initdata = { + { .dev_id = "imx23-gpmi-nand", }, + { .dev_id = "8000c000.gpmi", }, +}; + +static const char *sel_pll[] __initconst = { "pll", "ref_xtal", }; +static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", }; +static const char *sel_pix[] __initconst = { "ref_pix", "ref_xtal", }; +static const char *sel_io[] __initconst = { "ref_io", "ref_xtal", }; +static const char *cpu_sels[] __initconst = { "cpu_pll", "cpu_xtal", }; +static const char *emi_sels[] __initconst = { "emi_pll", "emi_xtal", }; + +enum imx23_clk { + ref_xtal, pll, ref_cpu, ref_emi, ref_pix, ref_io, saif_sel, + lcdif_sel, gpmi_sel, ssp_sel, emi_sel, cpu, etm_sel, cpu_pll, + cpu_xtal, hbus, xbus, lcdif_div, ssp_div, gpmi_div, emi_pll, + emi_xtal, etm_div, saif_div, clk32k_div, rtc, adc, spdif_div, + clk32k, dri, pwm, filt, uart, ssp, gpmi, spdif, emi, saif, + lcdif, etm, usb, usb_pwr, + clk_max +}; + +static struct clk *clks[clk_max]; + +static enum imx23_clk clks_init_on[] __initdata = { + cpu, hbus, xbus, emi, uart, +}; + +int __init mx23_clocks_init(void) +{ + int i; + + clk_misc_init(); + + clks[ref_xtal] = mxs_clk_fixed("ref_xtal", 24000000); + clks[pll] = mxs_clk_pll("pll", "ref_xtal", PLLCTRL0, 16, 480000000); + clks[ref_cpu] = mxs_clk_ref("ref_cpu", "pll", FRAC, 0); + clks[ref_emi] = mxs_clk_ref("ref_emi", "pll", FRAC, 1); + clks[ref_pix] = mxs_clk_ref("ref_pix", "pll", FRAC, 2); + clks[ref_io] = mxs_clk_ref("ref_io", "pll", FRAC, 3); + clks[saif_sel] = mxs_clk_mux("saif_sel", CLKSEQ, 0, 1, sel_pll, ARRAY_SIZE(sel_pll)); + clks[lcdif_sel] = mxs_clk_mux("lcdif_sel", CLKSEQ, 1, 1, sel_pix, ARRAY_SIZE(sel_pix)); + clks[gpmi_sel] = mxs_clk_mux("gpmi_sel", CLKSEQ, 4, 1, sel_io, ARRAY_SIZE(sel_io)); + clks[ssp_sel] = mxs_clk_mux("ssp_sel", CLKSEQ, 5, 1, sel_io, ARRAY_SIZE(sel_io)); + clks[emi_sel] = mxs_clk_mux("emi_sel", CLKSEQ, 6, 1, emi_sels, ARRAY_SIZE(emi_sels)); + clks[cpu] = mxs_clk_mux("cpu", CLKSEQ, 7, 1, cpu_sels, ARRAY_SIZE(cpu_sels)); + clks[etm_sel] = mxs_clk_mux("etm_sel", CLKSEQ, 8, 1, sel_cpu, ARRAY_SIZE(sel_cpu)); + clks[cpu_pll] = mxs_clk_div("cpu_pll", "ref_cpu", CPU, 0, 6, 28); + clks[cpu_xtal] = mxs_clk_div("cpu_xtal", "ref_xtal", CPU, 16, 10, 29); + clks[hbus] = mxs_clk_div("hbus", "cpu", HBUS, 0, 5, 29); + clks[xbus] = mxs_clk_div("xbus", "ref_xtal", XBUS, 0, 10, 31); + clks[lcdif_div] = mxs_clk_div("lcdif_div", "lcdif_sel", PIX, 0, 12, 29); + clks[ssp_div] = mxs_clk_div("ssp_div", "ssp_sel", SSP, 0, 9, 29); + clks[gpmi_div] = mxs_clk_div("gpmi_div", "gpmi_sel", GPMI, 0, 10, 29); + clks[emi_pll] = mxs_clk_div("emi_pll", "ref_emi", EMI, 0, 6, 28); + clks[emi_xtal] = mxs_clk_div("emi_xtal", "ref_xtal", EMI, 8, 4, 29); + clks[etm_div] = mxs_clk_div("etm_div", "etm_sel", ETM, 0, 6, 29); + clks[saif_div] = mxs_clk_frac("saif_div", "saif_sel", SAIF, 0, 16, 29); + clks[clk32k_div] = mxs_clk_fixed_factor("clk32k_div", "ref_xtal", 1, 750); + clks[rtc] = mxs_clk_fixed_factor("rtc", "ref_xtal", 1, 768); + clks[adc] = mxs_clk_fixed_factor("adc", "clk32k", 1, 16); + clks[spdif_div] = mxs_clk_fixed_factor("spdif_div", "pll", 1, 4); + clks[clk32k] = mxs_clk_gate("clk32k", "clk32k_div", XTAL, 26); + clks[dri] = mxs_clk_gate("dri", "ref_xtal", XTAL, 28); + clks[pwm] = mxs_clk_gate("pwm", "ref_xtal", XTAL, 29); + clks[filt] = mxs_clk_gate("filt", "ref_xtal", XTAL, 30); + clks[uart] = mxs_clk_gate("uart", "ref_xtal", XTAL, 31); + clks[ssp] = mxs_clk_gate("ssp", "ssp_div", SSP, 31); + clks[gpmi] = mxs_clk_gate("gpmi", "gpmi_div", GPMI, 31); + clks[spdif] = mxs_clk_gate("spdif", "spdif_div", SPDIF, 31); + clks[emi] = mxs_clk_gate("emi", "emi_sel", EMI, 31); + clks[saif] = mxs_clk_gate("saif", "saif_div", SAIF, 31); + clks[lcdif] = mxs_clk_gate("lcdif", "lcdif_div", PIX, 31); + clks[etm] = mxs_clk_gate("etm", "etm_div", ETM, 31); + clks[usb] = mxs_clk_gate("usb", "usb_pwr", DIGCTRL, 2); + clks[usb_pwr] = clk_register_gate(NULL, "usb_pwr", "pll", 0, PLLCTRL0, 18, 0, &mxs_lock); + + for (i = 0; i < ARRAY_SIZE(clks); i++) + if (IS_ERR(clks[i])) { + pr_err("i.MX23 clk %d: register failed with %ld\n", + i, PTR_ERR(clks[i])); + return PTR_ERR(clks[i]); + } + + clk_register_clkdev(clks[clk32k], NULL, "timrot"); + clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups)); + clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups)); + clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups)); + clk_register_clkdevs(clks[ssp], ssp_lookups, ARRAY_SIZE(ssp_lookups)); + clk_register_clkdevs(clks[gpmi], gpmi_lookups, ARRAY_SIZE(gpmi_lookups)); + clk_register_clkdevs(clks[lcdif], lcdif_lookups, ARRAY_SIZE(lcdif_lookups)); + + for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) + clk_prepare_enable(clks[clks_init_on[i]]); + + mxs_timer_init(MX23_INT_TIMER0); + + return 0; +} diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c new file mode 100644 index 000000000000..b2a3257d4f66 --- /dev/null +++ b/drivers/clk/mxs/clk-imx28.c @@ -0,0 +1,337 @@ +/* + * Copyright 2012 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 <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <mach/common.h> +#include <mach/mx28.h> +#include "clk.h" + +#define CLKCTRL MX28_IO_ADDRESS(MX28_CLKCTRL_BASE_ADDR) +#define PLL0CTRL0 (CLKCTRL + 0x0000) +#define PLL1CTRL0 (CLKCTRL + 0x0020) +#define PLL2CTRL0 (CLKCTRL + 0x0040) +#define CPU (CLKCTRL + 0x0050) +#define HBUS (CLKCTRL + 0x0060) +#define XBUS (CLKCTRL + 0x0070) +#define XTAL (CLKCTRL + 0x0080) +#define SSP0 (CLKCTRL + 0x0090) +#define SSP1 (CLKCTRL + 0x00a0) +#define SSP2 (CLKCTRL + 0x00b0) +#define SSP3 (CLKCTRL + 0x00c0) +#define GPMI (CLKCTRL + 0x00d0) +#define SPDIF (CLKCTRL + 0x00e0) +#define EMI (CLKCTRL + 0x00f0) +#define SAIF0 (CLKCTRL + 0x0100) +#define SAIF1 (CLKCTRL + 0x0110) +#define LCDIF (CLKCTRL + 0x0120) +#define ETM (CLKCTRL + 0x0130) +#define ENET (CLKCTRL + 0x0140) +#define FLEXCAN (CLKCTRL + 0x0160) +#define FRAC0 (CLKCTRL + 0x01b0) +#define FRAC1 (CLKCTRL + 0x01c0) +#define CLKSEQ (CLKCTRL + 0x01d0) + +#define BP_CPU_INTERRUPT_WAIT 12 +#define BP_SAIF_DIV_FRAC_EN 16 +#define BP_ENET_DIV_TIME 21 +#define BP_ENET_SLEEP 31 +#define BP_CLKSEQ_BYPASS_SAIF0 0 +#define BP_CLKSEQ_BYPASS_SSP0 3 +#define BP_FRAC0_IO1FRAC 16 +#define BP_FRAC0_IO0FRAC 24 + +#define DIGCTRL MX28_IO_ADDRESS(MX28_DIGCTL_BASE_ADDR) +#define BP_SAIF_CLKMUX 10 + +/* + * HW_SAIF_CLKMUX_SEL: + * DIRECT(0x0): SAIF0 clock pins selected for SAIF0 input clocks, and SAIF1 + * clock pins selected for SAIF1 input clocks. + * CROSSINPUT(0x1): SAIF1 clock inputs selected for SAIF0 input clocks, and + * SAIF0 clock inputs selected for SAIF1 input clocks. + * EXTMSTR0(0x2): SAIF0 clock pin selected for both SAIF0 and SAIF1 input + * clocks. + * EXTMSTR1(0x3): SAIF1 clock pin selected for both SAIF0 and SAIF1 input + * clocks. + */ +int mxs_saif_clkmux_select(unsigned int clkmux) +{ + if (clkmux > 0x3) + return -EINVAL; + + __mxs_clrl(0x3 << BP_SAIF_CLKMUX, DIGCTRL); + __mxs_setl(clkmux << BP_SAIF_CLKMUX, DIGCTRL); + + return 0; +} + +static void __init clk_misc_init(void) +{ + u32 val; + + /* Gate off cpu clock in WFI for power saving */ + __mxs_setl(1 << BP_CPU_INTERRUPT_WAIT, CPU); + + /* 0 is a bad default value for a divider */ + __mxs_setl(1 << BP_ENET_DIV_TIME, ENET); + + /* Clear BYPASS for SAIF */ + __mxs_clrl(0x3 << BP_CLKSEQ_BYPASS_SAIF0, CLKSEQ); + + /* SAIF has to use frac div for functional operation */ + val = readl_relaxed(SAIF0); + val |= 1 << BP_SAIF_DIV_FRAC_EN; + writel_relaxed(val, SAIF0); + + val = readl_relaxed(SAIF1); + val |= 1 << BP_SAIF_DIV_FRAC_EN; + writel_relaxed(val, SAIF1); + + /* Extra fec clock setting */ + val = readl_relaxed(ENET); + val &= ~(1 << BP_ENET_SLEEP); + writel_relaxed(val, ENET); + + /* + * Source ssp clock from ref_io than ref_xtal, + * as ref_xtal only provides 24 MHz as maximum. + */ + __mxs_clrl(0xf << BP_CLKSEQ_BYPASS_SSP0, CLKSEQ); + + /* + * 480 MHz seems too high to be ssp clock source directly, + * so set frac0 to get a 288 MHz ref_io0. + */ + val = readl_relaxed(FRAC0); + val &= ~(0x3f << BP_FRAC0_IO0FRAC); + val |= 30 << BP_FRAC0_IO0FRAC; + writel_relaxed(val, FRAC0); +} + +static struct clk_lookup uart_lookups[] __initdata = { + { .dev_id = "duart", }, + { .dev_id = "mxs-auart.0", }, + { .dev_id = "mxs-auart.1", }, + { .dev_id = "mxs-auart.2", }, + { .dev_id = "mxs-auart.3", }, + { .dev_id = "mxs-auart.4", }, + { .dev_id = "8006a000.serial", }, + { .dev_id = "8006c000.serial", }, + { .dev_id = "8006e000.serial", }, + { .dev_id = "80070000.serial", }, + { .dev_id = "80072000.serial", }, + { .dev_id = "80074000.serial", }, +}; + +static struct clk_lookup hbus_lookups[] __initdata = { + { .dev_id = "mxs-dma-apbh", }, + { .dev_id = "80004000.dma-apbh", }, +}; + +static struct clk_lookup xbus_lookups[] __initdata = { + { .dev_id = "duart", .con_id = "apb_pclk"}, + { .dev_id = "mxs-dma-apbx", }, + { .dev_id = "80024000.dma-apbx", }, +}; + +static struct clk_lookup ssp0_lookups[] __initdata = { + { .dev_id = "mxs-mmc.0", }, + { .dev_id = "80010000.ssp", }, +}; + +static struct clk_lookup ssp1_lookups[] __initdata = { + { .dev_id = "mxs-mmc.1", }, + { .dev_id = "80012000.ssp", }, +}; + +static struct clk_lookup ssp2_lookups[] __initdata = { + { .dev_id = "mxs-mmc.2", }, + { .dev_id = "80014000.ssp", }, +}; + +static struct clk_lookup ssp3_lookups[] __initdata = { + { .dev_id = "mxs-mmc.3", }, + { .dev_id = "80016000.ssp", }, +}; + +static struct clk_lookup lcdif_lookups[] __initdata = { + { .dev_id = "imx28-fb", }, + { .dev_id = "80030000.lcdif", }, +}; + +static struct clk_lookup gpmi_lookups[] __initdata = { + { .dev_id = "imx28-gpmi-nand", }, + { .dev_id = "8000c000.gpmi", }, +}; + +static struct clk_lookup fec_lookups[] __initdata = { + { .dev_id = "imx28-fec.0", }, + { .dev_id = "imx28-fec.1", }, + { .dev_id = "800f0000.ethernet", }, + { .dev_id = "800f4000.ethernet", }, +}; + +static struct clk_lookup can0_lookups[] __initdata = { + { .dev_id = "flexcan.0", }, + { .dev_id = "80032000.can", }, +}; + +static struct clk_lookup can1_lookups[] __initdata = { + { .dev_id = "flexcan.1", }, + { .dev_id = "80034000.can", }, +}; + +static struct clk_lookup saif0_lookups[] __initdata = { + { .dev_id = "mxs-saif.0", }, + { .dev_id = "80042000.saif", }, +}; + +static struct clk_lookup saif1_lookups[] __initdata = { + { .dev_id = "mxs-saif.1", }, + { .dev_id = "80046000.saif", }, +}; + +static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", }; +static const char *sel_io0[] __initconst = { "ref_io0", "ref_xtal", }; +static const char *sel_io1[] __initconst = { "ref_io1", "ref_xtal", }; +static const char *sel_pix[] __initconst = { "ref_pix", "ref_xtal", }; +static const char *sel_gpmi[] __initconst = { "ref_gpmi", "ref_xtal", }; +static const char *sel_pll0[] __initconst = { "pll0", "ref_xtal", }; +static const char *cpu_sels[] __initconst = { "cpu_pll", "cpu_xtal", }; +static const char *emi_sels[] __initconst = { "emi_pll", "emi_xtal", }; +static const char *ptp_sels[] __initconst = { "ref_xtal", "pll0", }; + +enum imx28_clk { + ref_xtal, pll0, pll1, pll2, ref_cpu, ref_emi, ref_io0, ref_io1, + ref_pix, ref_hsadc, ref_gpmi, saif0_sel, saif1_sel, gpmi_sel, + ssp0_sel, ssp1_sel, ssp2_sel, ssp3_sel, emi_sel, etm_sel, + lcdif_sel, cpu, ptp_sel, cpu_pll, cpu_xtal, hbus, xbus, + ssp0_div, ssp1_div, ssp2_div, ssp3_div, gpmi_div, emi_pll, + emi_xtal, lcdif_div, etm_div, ptp, saif0_div, saif1_div, + clk32k_div, rtc, lradc, spdif_div, clk32k, pwm, uart, ssp0, + ssp1, ssp2, ssp3, gpmi, spdif, emi, saif0, saif1, lcdif, etm, + fec, can0, can1, usb0, usb1, usb0_pwr, usb1_pwr, enet_out, + clk_max +}; + +static struct clk *clks[clk_max]; + +static enum imx28_clk clks_init_on[] __initdata = { + cpu, hbus, xbus, emi, uart, +}; + +int __init mx28_clocks_init(void) +{ + int i; + + clk_misc_init(); + + clks[ref_xtal] = mxs_clk_fixed("ref_xtal", 24000000); + clks[pll0] = mxs_clk_pll("pll0", "ref_xtal", PLL0CTRL0, 17, 480000000); + clks[pll1] = mxs_clk_pll("pll1", "ref_xtal", PLL1CTRL0, 17, 480000000); + clks[pll2] = mxs_clk_pll("pll2", "ref_xtal", PLL2CTRL0, 23, 50000000); + clks[ref_cpu] = mxs_clk_ref("ref_cpu", "pll0", FRAC0, 0); + clks[ref_emi] = mxs_clk_ref("ref_emi", "pll0", FRAC0, 1); + clks[ref_io0] = mxs_clk_ref("ref_io0", "pll0", FRAC0, 2); + clks[ref_io1] = mxs_clk_ref("ref_io1", "pll0", FRAC0, 3); + clks[ref_pix] = mxs_clk_ref("ref_pix", "pll0", FRAC1, 0); + clks[ref_hsadc] = mxs_clk_ref("ref_hsadc", "pll0", FRAC1, 1); + clks[ref_gpmi] = mxs_clk_ref("ref_gpmi", "pll0", FRAC1, 2); + clks[saif0_sel] = mxs_clk_mux("saif0_sel", CLKSEQ, 0, 1, sel_pll0, ARRAY_SIZE(sel_pll0)); + clks[saif1_sel] = mxs_clk_mux("saif1_sel", CLKSEQ, 1, 1, sel_pll0, ARRAY_SIZE(sel_pll0)); + clks[gpmi_sel] = mxs_clk_mux("gpmi_sel", CLKSEQ, 2, 1, sel_gpmi, ARRAY_SIZE(sel_gpmi)); + clks[ssp0_sel] = mxs_clk_mux("ssp0_sel", CLKSEQ, 3, 1, sel_io0, ARRAY_SIZE(sel_io0)); + clks[ssp1_sel] = mxs_clk_mux("ssp1_sel", CLKSEQ, 4, 1, sel_io0, ARRAY_SIZE(sel_io0)); + clks[ssp2_sel] = mxs_clk_mux("ssp2_sel", CLKSEQ, 5, 1, sel_io1, ARRAY_SIZE(sel_io1)); + clks[ssp3_sel] = mxs_clk_mux("ssp3_sel", CLKSEQ, 6, 1, sel_io1, ARRAY_SIZE(sel_io1)); + clks[emi_sel] = mxs_clk_mux("emi_sel", CLKSEQ, 7, 1, emi_sels, ARRAY_SIZE(emi_sels)); + clks[etm_sel] = mxs_clk_mux("etm_sel", CLKSEQ, 8, 1, sel_cpu, ARRAY_SIZE(sel_cpu)); + clks[lcdif_sel] = mxs_clk_mux("lcdif_sel", CLKSEQ, 14, 1, sel_pix, ARRAY_SIZE(sel_pix)); + clks[cpu] = mxs_clk_mux("cpu", CLKSEQ, 18, 1, cpu_sels, ARRAY_SIZE(cpu_sels)); + clks[ptp_sel] = mxs_clk_mux("ptp_sel", ENET, 19, 1, ptp_sels, ARRAY_SIZE(ptp_sels)); + clks[cpu_pll] = mxs_clk_div("cpu_pll", "ref_cpu", CPU, 0, 6, 28); + clks[cpu_xtal] = mxs_clk_div("cpu_xtal", "ref_xtal", CPU, 16, 10, 29); + clks[hbus] = mxs_clk_div("hbus", "cpu", HBUS, 0, 5, 31); + clks[xbus] = mxs_clk_div("xbus", "ref_xtal", XBUS, 0, 10, 31); + clks[ssp0_div] = mxs_clk_div("ssp0_div", "ssp0_sel", SSP0, 0, 9, 29); + clks[ssp1_div] = mxs_clk_div("ssp1_div", "ssp1_sel", SSP1, 0, 9, 29); + clks[ssp2_div] = mxs_clk_div("ssp2_div", "ssp2_sel", SSP2, 0, 9, 29); + clks[ssp3_div] = mxs_clk_div("ssp3_div", "ssp3_sel", SSP3, 0, 9, 29); + clks[gpmi_div] = mxs_clk_div("gpmi_div", "gpmi_sel", GPMI, 0, 10, 29); + clks[emi_pll] = mxs_clk_div("emi_pll", "ref_emi", EMI, 0, 6, 28); + clks[emi_xtal] = mxs_clk_div("emi_xtal", "ref_xtal", EMI, 8, 4, 29); + clks[lcdif_div] = mxs_clk_div("lcdif_div", "lcdif_sel", LCDIF, 0, 13, 29); + clks[etm_div] = mxs_clk_div("etm_div", "etm_sel", ETM, 0, 7, 29); + clks[ptp] = mxs_clk_div("ptp", "ptp_sel", ENET, 21, 6, 27); + clks[saif0_div] = mxs_clk_frac("saif0_div", "saif0_sel", SAIF0, 0, 16, 29); + clks[saif1_div] = mxs_clk_frac("saif1_div", "saif1_sel", SAIF1, 0, 16, 29); + clks[clk32k_div] = mxs_clk_fixed_factor("clk32k_div", "ref_xtal", 1, 750); + clks[rtc] = mxs_clk_fixed_factor("rtc", "ref_xtal", 1, 768); + clks[lradc] = mxs_clk_fixed_factor("lradc", "clk32k", 1, 16); + clks[spdif_div] = mxs_clk_fixed_factor("spdif_div", "pll0", 1, 4); + clks[clk32k] = mxs_clk_gate("clk32k", "clk32k_div", XTAL, 26); + clks[pwm] = mxs_clk_gate("pwm", "ref_xtal", XTAL, 29); + clks[uart] = mxs_clk_gate("uart", "ref_xtal", XTAL, 31); + clks[ssp0] = mxs_clk_gate("ssp0", "ssp0_div", SSP0, 31); + clks[ssp1] = mxs_clk_gate("ssp1", "ssp1_div", SSP1, 31); + clks[ssp2] = mxs_clk_gate("ssp2", "ssp2_div", SSP2, 31); + clks[ssp3] = mxs_clk_gate("ssp3", "ssp3_div", SSP3, 31); + clks[gpmi] = mxs_clk_gate("gpmi", "gpmi_div", GPMI, 31); + clks[spdif] = mxs_clk_gate("spdif", "spdif_div", SPDIF, 31); + clks[emi] = mxs_clk_gate("emi", "emi_sel", EMI, 31); + clks[saif0] = mxs_clk_gate("saif0", "saif0_div", SAIF0, 31); + clks[saif1] = mxs_clk_gate("saif1", "saif1_div", SAIF1, 31); + clks[lcdif] = mxs_clk_gate("lcdif", "lcdif_div", LCDIF, 31); + clks[etm] = mxs_clk_gate("etm", "etm_div", ETM, 31); + clks[fec] = mxs_clk_gate("fec", "hbus", ENET, 30); + clks[can0] = mxs_clk_gate("can0", "ref_xtal", FLEXCAN, 30); + clks[can1] = mxs_clk_gate("can1", "ref_xtal", FLEXCAN, 28); + clks[usb0] = mxs_clk_gate("usb0", "usb0_pwr", DIGCTRL, 2); + clks[usb1] = mxs_clk_gate("usb1", "usb1_pwr", DIGCTRL, 16); + clks[usb0_pwr] = clk_register_gate(NULL, "usb0_pwr", "pll0", 0, PLL0CTRL0, 18, 0, &mxs_lock); + clks[usb1_pwr] = clk_register_gate(NULL, "usb1_pwr", "pll1", 0, PLL1CTRL0, 18, 0, &mxs_lock); + clks[enet_out] = clk_register_gate(NULL, "enet_out", "pll2", 0, ENET, 18, 0, &mxs_lock); + + for (i = 0; i < ARRAY_SIZE(clks); i++) + if (IS_ERR(clks[i])) { + pr_err("i.MX28 clk %d: register failed with %ld\n", + i, PTR_ERR(clks[i])); + return PTR_ERR(clks[i]); + } + + clk_register_clkdev(clks[clk32k], NULL, "timrot"); + clk_register_clkdev(clks[enet_out], NULL, "enet_out"); + clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups)); + clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups)); + clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups)); + clk_register_clkdevs(clks[ssp0], ssp0_lookups, ARRAY_SIZE(ssp0_lookups)); + clk_register_clkdevs(clks[ssp1], ssp1_lookups, ARRAY_SIZE(ssp1_lookups)); + clk_register_clkdevs(clks[ssp2], ssp2_lookups, ARRAY_SIZE(ssp2_lookups)); + clk_register_clkdevs(clks[ssp3], ssp3_lookups, ARRAY_SIZE(ssp3_lookups)); + clk_register_clkdevs(clks[gpmi], gpmi_lookups, ARRAY_SIZE(gpmi_lookups)); + clk_register_clkdevs(clks[saif0], saif0_lookups, ARRAY_SIZE(saif0_lookups)); + clk_register_clkdevs(clks[saif1], saif1_lookups, ARRAY_SIZE(saif1_lookups)); + clk_register_clkdevs(clks[lcdif], lcdif_lookups, ARRAY_SIZE(lcdif_lookups)); + clk_register_clkdevs(clks[fec], fec_lookups, ARRAY_SIZE(fec_lookups)); + clk_register_clkdevs(clks[can0], can0_lookups, ARRAY_SIZE(can0_lookups)); + clk_register_clkdevs(clks[can1], can1_lookups, ARRAY_SIZE(can1_lookups)); + + for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) + clk_prepare_enable(clks[clks_init_on[i]]); + + mxs_timer_init(MX28_INT_TIMER0); + + return 0; +} diff --git a/drivers/clk/mxs/clk-pll.c b/drivers/clk/mxs/clk-pll.c new file mode 100644 index 000000000000..fadae41833ec --- /dev/null +++ b/drivers/clk/mxs/clk-pll.c @@ -0,0 +1,116 @@ +/* + * Copyright 2012 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 <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/slab.h> +#include "clk.h" + +/** + * struct clk_pll - mxs pll clock + * @hw: clk_hw for the pll + * @base: base address of the pll + * @power: the shift of power bit + * @rate: the clock rate of the pll + * + * The mxs pll is a fixed rate clock with power and gate control, + * and the shift of gate bit is always 31. + */ +struct clk_pll { + struct clk_hw hw; + void __iomem *base; + u8 power; + unsigned long rate; +}; + +#define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw) + +static int clk_pll_prepare(struct clk_hw *hw) +{ + struct clk_pll *pll = to_clk_pll(hw); + + writel_relaxed(1 << pll->power, pll->base + SET); + + udelay(10); + + return 0; +} + +static void clk_pll_unprepare(struct clk_hw *hw) +{ + struct clk_pll *pll = to_clk_pll(hw); + + writel_relaxed(1 << pll->power, pll->base + CLR); +} + +static int clk_pll_enable(struct clk_hw *hw) +{ + struct clk_pll *pll = to_clk_pll(hw); + + writel_relaxed(1 << 31, pll->base + CLR); + + return 0; +} + +static void clk_pll_disable(struct clk_hw *hw) +{ + struct clk_pll *pll = to_clk_pll(hw); + + writel_relaxed(1 << 31, pll->base + SET); +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pll *pll = to_clk_pll(hw); + + return pll->rate; +} + +static const struct clk_ops clk_pll_ops = { + .prepare = clk_pll_prepare, + .unprepare = clk_pll_unprepare, + .enable = clk_pll_enable, + .disable = clk_pll_disable, + .recalc_rate = clk_pll_recalc_rate, +}; + +struct clk *mxs_clk_pll(const char *name, const char *parent_name, + void __iomem *base, u8 power, unsigned long rate) +{ + struct clk_pll *pll; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_pll_ops; + init.flags = 0; + init.parent_names = (parent_name ? &parent_name: NULL); + init.num_parents = (parent_name ? 1 : 0); + + pll->base = base; + pll->rate = rate; + pll->power = power; + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} diff --git a/drivers/clk/mxs/clk-ref.c b/drivers/clk/mxs/clk-ref.c new file mode 100644 index 000000000000..4adeed6c2f94 --- /dev/null +++ b/drivers/clk/mxs/clk-ref.c @@ -0,0 +1,154 @@ +/* + * Copyright 2012 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 <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/slab.h> +#include "clk.h" + +/** + * struct clk_ref - mxs reference clock + * @hw: clk_hw for the reference clock + * @reg: register address + * @idx: the index of the reference clock within the same register + * + * The mxs reference clock sources from pll. Every 4 reference clocks share + * one register space, and @idx is used to identify them. Each reference + * clock has a gate control and a fractional * divider. The rate is calculated + * as pll rate * (18 / FRAC), where FRAC = 18 ~ 35. + */ +struct clk_ref { + struct clk_hw hw; + void __iomem *reg; + u8 idx; +}; + +#define to_clk_ref(_hw) container_of(_hw, struct clk_ref, hw) + +static int clk_ref_enable(struct clk_hw *hw) +{ + struct clk_ref *ref = to_clk_ref(hw); + + writel_relaxed(1 << ((ref->idx + 1) * 8 - 1), ref->reg + CLR); + + return 0; +} + +static void clk_ref_disable(struct clk_hw *hw) +{ + struct clk_ref *ref = to_clk_ref(hw); + + writel_relaxed(1 << ((ref->idx + 1) * 8 - 1), ref->reg + SET); +} + +static unsigned long clk_ref_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_ref *ref = to_clk_ref(hw); + u64 tmp = parent_rate; + u8 frac = (readl_relaxed(ref->reg) >> (ref->idx * 8)) & 0x3f; + + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static long clk_ref_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u64 tmp = parent_rate; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + + if (frac < 18) + frac = 18; + else if (frac > 35) + frac = 35; + + tmp = parent_rate; + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static int clk_ref_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_ref *ref = to_clk_ref(hw); + unsigned long flags; + u64 tmp = parent_rate; + u32 val; + u8 frac, shift = ref->idx * 8; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + + if (frac < 18) + frac = 18; + else if (frac > 35) + frac = 35; + + spin_lock_irqsave(&mxs_lock, flags); + + val = readl_relaxed(ref->reg); + val &= ~(0x3f << shift); + val |= frac << shift; + writel_relaxed(val, ref->reg); + + spin_unlock_irqrestore(&mxs_lock, flags); + + return 0; +} + +static const struct clk_ops clk_ref_ops = { + .enable = clk_ref_enable, + .disable = clk_ref_disable, + .recalc_rate = clk_ref_recalc_rate, + .round_rate = clk_ref_round_rate, + .set_rate = clk_ref_set_rate, +}; + +struct clk *mxs_clk_ref(const char *name, const char *parent_name, + void __iomem *reg, u8 idx) +{ + struct clk_ref *ref; + struct clk *clk; + struct clk_init_data init; + + ref = kzalloc(sizeof(*ref), GFP_KERNEL); + if (!ref) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_ref_ops; + init.flags = 0; + init.parent_names = (parent_name ? &parent_name: NULL); + init.num_parents = (parent_name ? 1 : 0); + + ref->reg = reg; + ref->idx = idx; + ref->hw.init = &init; + + clk = clk_register(NULL, &ref->hw); + if (IS_ERR(clk)) + kfree(ref); + + return clk; +} diff --git a/drivers/clk/mxs/clk.c b/drivers/clk/mxs/clk.c new file mode 100644 index 000000000000..b24d56067c80 --- /dev/null +++ b/drivers/clk/mxs/clk.c @@ -0,0 +1,28 @@ +/* + * Copyright 2012 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 <linux/err.h> +#include <linux/io.h> +#include <linux/jiffies.h> +#include <linux/spinlock.h> + +DEFINE_SPINLOCK(mxs_lock); + +int mxs_clk_wait(void __iomem *reg, u8 shift) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(10); + + while (readl_relaxed(reg) & (1 << shift)) + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + + return 0; +} diff --git a/drivers/clk/mxs/clk.h b/drivers/clk/mxs/clk.h new file mode 100644 index 000000000000..81421e28e69c --- /dev/null +++ b/drivers/clk/mxs/clk.h @@ -0,0 +1,66 @@ +/* + * Copyright 2012 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 + */ + +#ifndef __MXS_CLK_H +#define __MXS_CLK_H + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/spinlock.h> + +#define SET 0x4 +#define CLR 0x8 + +extern spinlock_t mxs_lock; + +int mxs_clk_wait(void __iomem *reg, u8 shift); + +struct clk *mxs_clk_pll(const char *name, const char *parent_name, + void __iomem *base, u8 power, unsigned long rate); + +struct clk *mxs_clk_ref(const char *name, const char *parent_name, + void __iomem *reg, u8 idx); + +struct clk *mxs_clk_div(const char *name, const char *parent_name, + void __iomem *reg, u8 shift, u8 width, u8 busy); + +struct clk *mxs_clk_frac(const char *name, const char *parent_name, + void __iomem *reg, u8 shift, u8 width, u8 busy); + +static inline struct clk *mxs_clk_fixed(const char *name, int rate) +{ + return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate); +} + +static inline struct clk *mxs_clk_gate(const char *name, + const char *parent_name, void __iomem *reg, u8 shift) +{ + return clk_register_gate(NULL, name, parent_name, CLK_SET_RATE_PARENT, + reg, shift, CLK_GATE_SET_TO_DISABLE, + &mxs_lock); +} + +static inline struct clk *mxs_clk_mux(const char *name, void __iomem *reg, + u8 shift, u8 width, const char **parent_names, int num_parents) +{ + return clk_register_mux(NULL, name, parent_names, num_parents, + CLK_SET_RATE_PARENT, reg, shift, width, + 0, &mxs_lock); +} + +static inline struct clk *mxs_clk_fixed_factor(const char *name, + const char *parent_name, unsigned int mult, unsigned int div) +{ + return clk_register_fixed_factor(NULL, name, parent_name, + CLK_SET_RATE_PARENT, mult, div); +} + +#endif /* __MXS_CLK_H */ diff --git a/drivers/clk/spear/Makefile b/drivers/clk/spear/Makefile new file mode 100644 index 000000000000..335886049c83 --- /dev/null +++ b/drivers/clk/spear/Makefile @@ -0,0 +1,8 @@ +# +# SPEAr Clock specific Makefile +# + +obj-y += clk.o clk-aux-synth.o clk-frac-synth.o clk-gpt-synth.o clk-vco-pll.o + +obj-$(CONFIG_ARCH_SPEAR3XX) += spear3xx_clock.o +obj-$(CONFIG_ARCH_SPEAR6XX) += spear6xx_clock.o diff --git a/drivers/clk/spear/clk-aux-synth.c b/drivers/clk/spear/clk-aux-synth.c new file mode 100644 index 000000000000..af34074e702b --- /dev/null +++ b/drivers/clk/spear/clk-aux-synth.c @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * Auxiliary Synthesizer clock implementation + */ + +#define pr_fmt(fmt) "clk-aux-synth: " fmt + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include "clk.h" + +/* + * DOC: Auxiliary Synthesizer clock + * + * Aux synth gives rate for different values of eq, x and y + * + * Fout from synthesizer can be given from two equations: + * Fout1 = (Fin * X/Y)/2 EQ1 + * Fout2 = Fin * X/Y EQ2 + */ + +#define to_clk_aux(_hw) container_of(_hw, struct clk_aux, hw) + +static struct aux_clk_masks default_aux_masks = { + .eq_sel_mask = AUX_EQ_SEL_MASK, + .eq_sel_shift = AUX_EQ_SEL_SHIFT, + .eq1_mask = AUX_EQ1_SEL, + .eq2_mask = AUX_EQ2_SEL, + .xscale_sel_mask = AUX_XSCALE_MASK, + .xscale_sel_shift = AUX_XSCALE_SHIFT, + .yscale_sel_mask = AUX_YSCALE_MASK, + .yscale_sel_shift = AUX_YSCALE_SHIFT, + .enable_bit = AUX_SYNT_ENB, +}; + +static unsigned long aux_calc_rate(struct clk_hw *hw, unsigned long prate, + int index) +{ + struct clk_aux *aux = to_clk_aux(hw); + struct aux_rate_tbl *rtbl = aux->rtbl; + u8 eq = rtbl[index].eq ? 1 : 2; + + return (((prate / 10000) * rtbl[index].xscale) / + (rtbl[index].yscale * eq)) * 10000; +} + +static long clk_aux_round_rate(struct clk_hw *hw, unsigned long drate, + unsigned long *prate) +{ + struct clk_aux *aux = to_clk_aux(hw); + int unused; + + return clk_round_rate_index(hw, drate, *prate, aux_calc_rate, + aux->rtbl_cnt, &unused); +} + +static unsigned long clk_aux_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_aux *aux = to_clk_aux(hw); + unsigned int num = 1, den = 1, val, eqn; + unsigned long flags = 0; + + if (aux->lock) + spin_lock_irqsave(aux->lock, flags); + + val = readl_relaxed(aux->reg); + + if (aux->lock) + spin_unlock_irqrestore(aux->lock, flags); + + eqn = (val >> aux->masks->eq_sel_shift) & aux->masks->eq_sel_mask; + if (eqn == aux->masks->eq1_mask) + den = 2; + + /* calculate numerator */ + num = (val >> aux->masks->xscale_sel_shift) & + aux->masks->xscale_sel_mask; + + /* calculate denominator */ + den *= (val >> aux->masks->yscale_sel_shift) & + aux->masks->yscale_sel_mask; + + if (!den) + return 0; + + return (((parent_rate / 10000) * num) / den) * 10000; +} + +/* Configures new clock rate of aux */ +static int clk_aux_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct clk_aux *aux = to_clk_aux(hw); + struct aux_rate_tbl *rtbl = aux->rtbl; + unsigned long val, flags = 0; + int i; + + clk_round_rate_index(hw, drate, prate, aux_calc_rate, aux->rtbl_cnt, + &i); + + if (aux->lock) + spin_lock_irqsave(aux->lock, flags); + + val = readl_relaxed(aux->reg) & + ~(aux->masks->eq_sel_mask << aux->masks->eq_sel_shift); + val |= (rtbl[i].eq & aux->masks->eq_sel_mask) << + aux->masks->eq_sel_shift; + val &= ~(aux->masks->xscale_sel_mask << aux->masks->xscale_sel_shift); + val |= (rtbl[i].xscale & aux->masks->xscale_sel_mask) << + aux->masks->xscale_sel_shift; + val &= ~(aux->masks->yscale_sel_mask << aux->masks->yscale_sel_shift); + val |= (rtbl[i].yscale & aux->masks->yscale_sel_mask) << + aux->masks->yscale_sel_shift; + writel_relaxed(val, aux->reg); + + if (aux->lock) + spin_unlock_irqrestore(aux->lock, flags); + + return 0; +} + +static struct clk_ops clk_aux_ops = { + .recalc_rate = clk_aux_recalc_rate, + .round_rate = clk_aux_round_rate, + .set_rate = clk_aux_set_rate, +}; + +struct clk *clk_register_aux(const char *aux_name, const char *gate_name, + const char *parent_name, unsigned long flags, void __iomem *reg, + struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, + u8 rtbl_cnt, spinlock_t *lock, struct clk **gate_clk) +{ + struct clk_aux *aux; + struct clk_init_data init; + struct clk *clk; + + if (!aux_name || !parent_name || !reg || !rtbl || !rtbl_cnt) { + pr_err("Invalid arguments passed"); + return ERR_PTR(-EINVAL); + } + + aux = kzalloc(sizeof(*aux), GFP_KERNEL); + if (!aux) { + pr_err("could not allocate aux clk\n"); + return ERR_PTR(-ENOMEM); + } + + /* struct clk_aux assignments */ + if (!masks) + aux->masks = &default_aux_masks; + else + aux->masks = masks; + + aux->reg = reg; + aux->rtbl = rtbl; + aux->rtbl_cnt = rtbl_cnt; + aux->lock = lock; + aux->hw.init = &init; + + init.name = aux_name; + init.ops = &clk_aux_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + clk = clk_register(NULL, &aux->hw); + if (IS_ERR_OR_NULL(clk)) + goto free_aux; + + if (gate_name) { + struct clk *tgate_clk; + + tgate_clk = clk_register_gate(NULL, gate_name, aux_name, 0, reg, + aux->masks->enable_bit, 0, lock); + if (IS_ERR_OR_NULL(tgate_clk)) + goto free_aux; + + if (gate_clk) + *gate_clk = tgate_clk; + } + + return clk; + +free_aux: + kfree(aux); + pr_err("clk register failed\n"); + + return NULL; +} diff --git a/drivers/clk/spear/clk-frac-synth.c b/drivers/clk/spear/clk-frac-synth.c new file mode 100644 index 000000000000..4dbdb3fe18e0 --- /dev/null +++ b/drivers/clk/spear/clk-frac-synth.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * Fractional Synthesizer clock implementation + */ + +#define pr_fmt(fmt) "clk-frac-synth: " fmt + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include "clk.h" + +#define DIV_FACTOR_MASK 0x1FFFF + +/* + * DOC: Fractional Synthesizer clock + * + * Fout from synthesizer can be given from below equation: + * + * Fout= Fin/2*div (division factor) + * div is 17 bits:- + * 0-13 (fractional part) + * 14-16 (integer part) + * div is (16-14 bits).(13-0 bits) (in binary) + * + * Fout = Fin/(2 * div) + * Fout = ((Fin / 10000)/(2 * div)) * 10000 + * Fout = (2^14 * (Fin / 10000)/(2^14 * (2 * div))) * 10000 + * Fout = (((Fin / 10000) << 14)/(2 * (div << 14))) * 10000 + * + * div << 14 simply 17 bit value written at register. + * Max error due to scaling down by 10000 is 10 KHz + */ + +#define to_clk_frac(_hw) container_of(_hw, struct clk_frac, hw) + +static unsigned long frac_calc_rate(struct clk_hw *hw, unsigned long prate, + int index) +{ + struct clk_frac *frac = to_clk_frac(hw); + struct frac_rate_tbl *rtbl = frac->rtbl; + + prate /= 10000; + prate <<= 14; + prate /= (2 * rtbl[index].div); + prate *= 10000; + + return prate; +} + +static long clk_frac_round_rate(struct clk_hw *hw, unsigned long drate, + unsigned long *prate) +{ + struct clk_frac *frac = to_clk_frac(hw); + int unused; + + return clk_round_rate_index(hw, drate, *prate, frac_calc_rate, + frac->rtbl_cnt, &unused); +} + +static unsigned long clk_frac_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_frac *frac = to_clk_frac(hw); + unsigned long flags = 0; + unsigned int div = 1, val; + + if (frac->lock) + spin_lock_irqsave(frac->lock, flags); + + val = readl_relaxed(frac->reg); + + if (frac->lock) + spin_unlock_irqrestore(frac->lock, flags); + + div = val & DIV_FACTOR_MASK; + + if (!div) + return 0; + + parent_rate = parent_rate / 10000; + + parent_rate = (parent_rate << 14) / (2 * div); + return parent_rate * 10000; +} + +/* Configures new clock rate of frac */ +static int clk_frac_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct clk_frac *frac = to_clk_frac(hw); + struct frac_rate_tbl *rtbl = frac->rtbl; + unsigned long flags = 0, val; + int i; + + clk_round_rate_index(hw, drate, prate, frac_calc_rate, frac->rtbl_cnt, + &i); + + if (frac->lock) + spin_lock_irqsave(frac->lock, flags); + + val = readl_relaxed(frac->reg) & ~DIV_FACTOR_MASK; + val |= rtbl[i].div & DIV_FACTOR_MASK; + writel_relaxed(val, frac->reg); + + if (frac->lock) + spin_unlock_irqrestore(frac->lock, flags); + + return 0; +} + +struct clk_ops clk_frac_ops = { + .recalc_rate = clk_frac_recalc_rate, + .round_rate = clk_frac_round_rate, + .set_rate = clk_frac_set_rate, +}; + +struct clk *clk_register_frac(const char *name, const char *parent_name, + unsigned long flags, void __iomem *reg, + struct frac_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock) +{ + struct clk_init_data init; + struct clk_frac *frac; + struct clk *clk; + + if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) { + pr_err("Invalid arguments passed"); + return ERR_PTR(-EINVAL); + } + + frac = kzalloc(sizeof(*frac), GFP_KERNEL); + if (!frac) { + pr_err("could not allocate frac clk\n"); + return ERR_PTR(-ENOMEM); + } + + /* struct clk_frac assignments */ + frac->reg = reg; + frac->rtbl = rtbl; + frac->rtbl_cnt = rtbl_cnt; + frac->lock = lock; + frac->hw.init = &init; + + init.name = name; + init.ops = &clk_frac_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + clk = clk_register(NULL, &frac->hw); + if (!IS_ERR_OR_NULL(clk)) + return clk; + + pr_err("clk register failed\n"); + kfree(frac); + + return NULL; +} diff --git a/drivers/clk/spear/clk-gpt-synth.c b/drivers/clk/spear/clk-gpt-synth.c new file mode 100644 index 000000000000..b471c9762a97 --- /dev/null +++ b/drivers/clk/spear/clk-gpt-synth.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * General Purpose Timer Synthesizer clock implementation + */ + +#define pr_fmt(fmt) "clk-gpt-synth: " fmt + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include "clk.h" + +#define GPT_MSCALE_MASK 0xFFF +#define GPT_NSCALE_SHIFT 12 +#define GPT_NSCALE_MASK 0xF + +/* + * DOC: General Purpose Timer Synthesizer clock + * + * Calculates gpt synth clk rate for different values of mscale and nscale + * + * Fout= Fin/((2 ^ (N+1)) * (M+1)) + */ + +#define to_clk_gpt(_hw) container_of(_hw, struct clk_gpt, hw) + +static unsigned long gpt_calc_rate(struct clk_hw *hw, unsigned long prate, + int index) +{ + struct clk_gpt *gpt = to_clk_gpt(hw); + struct gpt_rate_tbl *rtbl = gpt->rtbl; + + prate /= ((1 << (rtbl[index].nscale + 1)) * (rtbl[index].mscale + 1)); + + return prate; +} + +static long clk_gpt_round_rate(struct clk_hw *hw, unsigned long drate, + unsigned long *prate) +{ + struct clk_gpt *gpt = to_clk_gpt(hw); + int unused; + + return clk_round_rate_index(hw, drate, *prate, gpt_calc_rate, + gpt->rtbl_cnt, &unused); +} + +static unsigned long clk_gpt_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_gpt *gpt = to_clk_gpt(hw); + unsigned long flags = 0; + unsigned int div = 1, val; + + if (gpt->lock) + spin_lock_irqsave(gpt->lock, flags); + + val = readl_relaxed(gpt->reg); + + if (gpt->lock) + spin_unlock_irqrestore(gpt->lock, flags); + + div += val & GPT_MSCALE_MASK; + div *= 1 << (((val >> GPT_NSCALE_SHIFT) & GPT_NSCALE_MASK) + 1); + + if (!div) + return 0; + + return parent_rate / div; +} + +/* Configures new clock rate of gpt */ +static int clk_gpt_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct clk_gpt *gpt = to_clk_gpt(hw); + struct gpt_rate_tbl *rtbl = gpt->rtbl; + unsigned long flags = 0, val; + int i; + + clk_round_rate_index(hw, drate, prate, gpt_calc_rate, gpt->rtbl_cnt, + &i); + + if (gpt->lock) + spin_lock_irqsave(gpt->lock, flags); + + val = readl(gpt->reg) & ~GPT_MSCALE_MASK; + val &= ~(GPT_NSCALE_MASK << GPT_NSCALE_SHIFT); + + val |= rtbl[i].mscale & GPT_MSCALE_MASK; + val |= (rtbl[i].nscale & GPT_NSCALE_MASK) << GPT_NSCALE_SHIFT; + + writel_relaxed(val, gpt->reg); + + if (gpt->lock) + spin_unlock_irqrestore(gpt->lock, flags); + + return 0; +} + +static struct clk_ops clk_gpt_ops = { + .recalc_rate = clk_gpt_recalc_rate, + .round_rate = clk_gpt_round_rate, + .set_rate = clk_gpt_set_rate, +}; + +struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned + long flags, void __iomem *reg, struct gpt_rate_tbl *rtbl, u8 + rtbl_cnt, spinlock_t *lock) +{ + struct clk_init_data init; + struct clk_gpt *gpt; + struct clk *clk; + + if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) { + pr_err("Invalid arguments passed"); + return ERR_PTR(-EINVAL); + } + + gpt = kzalloc(sizeof(*gpt), GFP_KERNEL); + if (!gpt) { + pr_err("could not allocate gpt clk\n"); + return ERR_PTR(-ENOMEM); + } + + /* struct clk_gpt assignments */ + gpt->reg = reg; + gpt->rtbl = rtbl; + gpt->rtbl_cnt = rtbl_cnt; + gpt->lock = lock; + gpt->hw.init = &init; + + init.name = name; + init.ops = &clk_gpt_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + clk = clk_register(NULL, &gpt->hw); + if (!IS_ERR_OR_NULL(clk)) + return clk; + + pr_err("clk register failed\n"); + kfree(gpt); + + return NULL; +} diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c new file mode 100644 index 000000000000..dcd4bdf4b0d9 --- /dev/null +++ b/drivers/clk/spear/clk-vco-pll.c @@ -0,0 +1,363 @@ +/* + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * VCO-PLL clock implementation + */ + +#define pr_fmt(fmt) "clk-vco-pll: " fmt + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include "clk.h" + +/* + * DOC: VCO-PLL clock + * + * VCO and PLL rate are derived from following equations: + * + * In normal mode + * vco = (2 * M[15:8] * Fin)/N + * + * In Dithered mode + * vco = (2 * M[15:0] * Fin)/(256 * N) + * + * pll_rate = pll/2^p + * + * vco and pll are very closely bound to each other, "vco needs to program: + * mode, m & n" and "pll needs to program p", both share common enable/disable + * logic. + * + * clk_register_vco_pll() registers instances of both vco & pll. + * CLK_SET_RATE_PARENT flag is forced for pll, as it will always pass its + * set_rate to vco. A single rate table exists for both the clocks, which + * configures m, n and p. + */ + +/* PLL_CTR register masks */ +#define PLL_MODE_NORMAL 0 +#define PLL_MODE_FRACTION 1 +#define PLL_MODE_DITH_DSM 2 +#define PLL_MODE_DITH_SSM 3 +#define PLL_MODE_MASK 3 +#define PLL_MODE_SHIFT 3 +#define PLL_ENABLE 2 + +#define PLL_LOCK_SHIFT 0 +#define PLL_LOCK_MASK 1 + +/* PLL FRQ register masks */ +#define PLL_NORM_FDBK_M_MASK 0xFF +#define PLL_NORM_FDBK_M_SHIFT 24 +#define PLL_DITH_FDBK_M_MASK 0xFFFF +#define PLL_DITH_FDBK_M_SHIFT 16 +#define PLL_DIV_P_MASK 0x7 +#define PLL_DIV_P_SHIFT 8 +#define PLL_DIV_N_MASK 0xFF +#define PLL_DIV_N_SHIFT 0 + +#define to_clk_vco(_hw) container_of(_hw, struct clk_vco, hw) +#define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw) + +/* Calculates pll clk rate for specific value of mode, m, n and p */ +static unsigned long pll_calc_rate(struct pll_rate_tbl *rtbl, + unsigned long prate, int index, unsigned long *pll_rate) +{ + unsigned long rate = prate; + unsigned int mode; + + mode = rtbl[index].mode ? 256 : 1; + rate = (((2 * rate / 10000) * rtbl[index].m) / (mode * rtbl[index].n)); + + if (pll_rate) + *pll_rate = (rate / (1 << rtbl[index].p)) * 10000; + + return rate * 10000; +} + +static long clk_pll_round_rate_index(struct clk_hw *hw, unsigned long drate, + unsigned long *prate, int *index) +{ + struct clk_pll *pll = to_clk_pll(hw); + unsigned long prev_rate, vco_prev_rate, rate = 0; + unsigned long vco_parent_rate = + __clk_get_rate(__clk_get_parent(__clk_get_parent(hw->clk))); + + if (!prate) { + pr_err("%s: prate is must for pll clk\n", __func__); + return -EINVAL; + } + + for (*index = 0; *index < pll->vco->rtbl_cnt; (*index)++) { + prev_rate = rate; + vco_prev_rate = *prate; + *prate = pll_calc_rate(pll->vco->rtbl, vco_parent_rate, *index, + &rate); + if (drate < rate) { + /* previous clock was best */ + if (*index) { + rate = prev_rate; + *prate = vco_prev_rate; + (*index)--; + } + break; + } + } + + return rate; +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long drate, + unsigned long *prate) +{ + int unused; + + return clk_pll_round_rate_index(hw, drate, prate, &unused); +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, unsigned long + parent_rate) +{ + struct clk_pll *pll = to_clk_pll(hw); + unsigned long flags = 0; + unsigned int p; + + if (pll->vco->lock) + spin_lock_irqsave(pll->vco->lock, flags); + + p = readl_relaxed(pll->vco->cfg_reg); + + if (pll->vco->lock) + spin_unlock_irqrestore(pll->vco->lock, flags); + + p = (p >> PLL_DIV_P_SHIFT) & PLL_DIV_P_MASK; + + return parent_rate / (1 << p); +} + +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct clk_pll *pll = to_clk_pll(hw); + struct pll_rate_tbl *rtbl = pll->vco->rtbl; + unsigned long flags = 0, val; + int i; + + clk_pll_round_rate_index(hw, drate, NULL, &i); + + if (pll->vco->lock) + spin_lock_irqsave(pll->vco->lock, flags); + + val = readl_relaxed(pll->vco->cfg_reg); + val &= ~(PLL_DIV_P_MASK << PLL_DIV_P_SHIFT); + val |= (rtbl[i].p & PLL_DIV_P_MASK) << PLL_DIV_P_SHIFT; + writel_relaxed(val, pll->vco->cfg_reg); + + if (pll->vco->lock) + spin_unlock_irqrestore(pll->vco->lock, flags); + + return 0; +} + +static struct clk_ops clk_pll_ops = { + .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_round_rate, + .set_rate = clk_pll_set_rate, +}; + +static inline unsigned long vco_calc_rate(struct clk_hw *hw, + unsigned long prate, int index) +{ + struct clk_vco *vco = to_clk_vco(hw); + + return pll_calc_rate(vco->rtbl, prate, index, NULL); +} + +static long clk_vco_round_rate(struct clk_hw *hw, unsigned long drate, + unsigned long *prate) +{ + struct clk_vco *vco = to_clk_vco(hw); + int unused; + + return clk_round_rate_index(hw, drate, *prate, vco_calc_rate, + vco->rtbl_cnt, &unused); +} + +static unsigned long clk_vco_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_vco *vco = to_clk_vco(hw); + unsigned long flags = 0; + unsigned int num = 2, den = 0, val, mode = 0; + + if (vco->lock) + spin_lock_irqsave(vco->lock, flags); + + mode = (readl_relaxed(vco->mode_reg) >> PLL_MODE_SHIFT) & PLL_MODE_MASK; + + val = readl_relaxed(vco->cfg_reg); + + if (vco->lock) + spin_unlock_irqrestore(vco->lock, flags); + + den = (val >> PLL_DIV_N_SHIFT) & PLL_DIV_N_MASK; + + /* calculate numerator & denominator */ + if (!mode) { + /* Normal mode */ + num *= (val >> PLL_NORM_FDBK_M_SHIFT) & PLL_NORM_FDBK_M_MASK; + } else { + /* Dithered mode */ + num *= (val >> PLL_DITH_FDBK_M_SHIFT) & PLL_DITH_FDBK_M_MASK; + den *= 256; + } + + if (!den) { + WARN(1, "%s: denominator can't be zero\n", __func__); + return 0; + } + + return (((parent_rate / 10000) * num) / den) * 10000; +} + +/* Configures new clock rate of vco */ +static int clk_vco_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct clk_vco *vco = to_clk_vco(hw); + struct pll_rate_tbl *rtbl = vco->rtbl; + unsigned long flags = 0, val; + int i; + + clk_round_rate_index(hw, drate, prate, vco_calc_rate, vco->rtbl_cnt, + &i); + + if (vco->lock) + spin_lock_irqsave(vco->lock, flags); + + val = readl_relaxed(vco->mode_reg); + val &= ~(PLL_MODE_MASK << PLL_MODE_SHIFT); + val |= (rtbl[i].mode & PLL_MODE_MASK) << PLL_MODE_SHIFT; + writel_relaxed(val, vco->mode_reg); + + val = readl_relaxed(vco->cfg_reg); + val &= ~(PLL_DIV_N_MASK << PLL_DIV_N_SHIFT); + val |= (rtbl[i].n & PLL_DIV_N_MASK) << PLL_DIV_N_SHIFT; + + val &= ~(PLL_DITH_FDBK_M_MASK << PLL_DITH_FDBK_M_SHIFT); + if (rtbl[i].mode) + val |= (rtbl[i].m & PLL_DITH_FDBK_M_MASK) << + PLL_DITH_FDBK_M_SHIFT; + else + val |= (rtbl[i].m & PLL_NORM_FDBK_M_MASK) << + PLL_NORM_FDBK_M_SHIFT; + + writel_relaxed(val, vco->cfg_reg); + + if (vco->lock) + spin_unlock_irqrestore(vco->lock, flags); + + return 0; +} + +static struct clk_ops clk_vco_ops = { + .recalc_rate = clk_vco_recalc_rate, + .round_rate = clk_vco_round_rate, + .set_rate = clk_vco_set_rate, +}; + +struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, + const char *vco_gate_name, const char *parent_name, + unsigned long flags, void __iomem *mode_reg, void __iomem + *cfg_reg, struct pll_rate_tbl *rtbl, u8 rtbl_cnt, + spinlock_t *lock, struct clk **pll_clk, + struct clk **vco_gate_clk) +{ + struct clk_vco *vco; + struct clk_pll *pll; + struct clk *vco_clk, *tpll_clk, *tvco_gate_clk; + struct clk_init_data vco_init, pll_init; + const char **vco_parent_name; + + if (!vco_name || !pll_name || !parent_name || !mode_reg || !cfg_reg || + !rtbl || !rtbl_cnt) { + pr_err("Invalid arguments passed"); + return ERR_PTR(-EINVAL); + } + + vco = kzalloc(sizeof(*vco), GFP_KERNEL); + if (!vco) { + pr_err("could not allocate vco clk\n"); + return ERR_PTR(-ENOMEM); + } + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) { + pr_err("could not allocate pll clk\n"); + goto free_vco; + } + + /* struct clk_vco assignments */ + vco->mode_reg = mode_reg; + vco->cfg_reg = cfg_reg; + vco->rtbl = rtbl; + vco->rtbl_cnt = rtbl_cnt; + vco->lock = lock; + vco->hw.init = &vco_init; + + pll->vco = vco; + pll->hw.init = &pll_init; + + if (vco_gate_name) { + tvco_gate_clk = clk_register_gate(NULL, vco_gate_name, + parent_name, 0, mode_reg, PLL_ENABLE, 0, lock); + if (IS_ERR_OR_NULL(tvco_gate_clk)) + goto free_pll; + + if (vco_gate_clk) + *vco_gate_clk = tvco_gate_clk; + vco_parent_name = &vco_gate_name; + } else { + vco_parent_name = &parent_name; + } + + vco_init.name = vco_name; + vco_init.ops = &clk_vco_ops; + vco_init.flags = flags; + vco_init.parent_names = vco_parent_name; + vco_init.num_parents = 1; + + pll_init.name = pll_name; + pll_init.ops = &clk_pll_ops; + pll_init.flags = CLK_SET_RATE_PARENT; + pll_init.parent_names = &vco_name; + pll_init.num_parents = 1; + + vco_clk = clk_register(NULL, &vco->hw); + if (IS_ERR_OR_NULL(vco_clk)) + goto free_pll; + + tpll_clk = clk_register(NULL, &pll->hw); + if (IS_ERR_OR_NULL(tpll_clk)) + goto free_pll; + + if (pll_clk) + *pll_clk = tpll_clk; + + return vco_clk; + +free_pll: + kfree(pll); +free_vco: + kfree(vco); + + pr_err("Failed to register vco pll clock\n"); + + return ERR_PTR(-ENOMEM); +} diff --git a/drivers/clk/spear/clk.c b/drivers/clk/spear/clk.c new file mode 100644 index 000000000000..376d4e5ff326 --- /dev/null +++ b/drivers/clk/spear/clk.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * SPEAr clk - Common routines + */ + +#include <linux/clk-provider.h> +#include <linux/types.h> +#include "clk.h" + +long clk_round_rate_index(struct clk_hw *hw, unsigned long drate, + unsigned long parent_rate, clk_calc_rate calc_rate, u8 rtbl_cnt, + int *index) +{ + unsigned long prev_rate, rate = 0; + + for (*index = 0; *index < rtbl_cnt; (*index)++) { + prev_rate = rate; + rate = calc_rate(hw, parent_rate, *index); + if (drate < rate) { + /* previous clock was best */ + if (*index) { + rate = prev_rate; + (*index)--; + } + break; + } + } + + return rate; +} diff --git a/drivers/clk/spear/clk.h b/drivers/clk/spear/clk.h new file mode 100644 index 000000000000..3321c46a071c --- /dev/null +++ b/drivers/clk/spear/clk.h @@ -0,0 +1,134 @@ +/* + * Clock framework definitions for SPEAr platform + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __SPEAR_CLK_H +#define __SPEAR_CLK_H + +#include <linux/clk-provider.h> +#include <linux/spinlock_types.h> +#include <linux/types.h> + +/* Auxiliary Synth clk */ +/* Default masks */ +#define AUX_EQ_SEL_SHIFT 30 +#define AUX_EQ_SEL_MASK 1 +#define AUX_EQ1_SEL 0 +#define AUX_EQ2_SEL 1 +#define AUX_XSCALE_SHIFT 16 +#define AUX_XSCALE_MASK 0xFFF +#define AUX_YSCALE_SHIFT 0 +#define AUX_YSCALE_MASK 0xFFF +#define AUX_SYNT_ENB 31 + +struct aux_clk_masks { + u32 eq_sel_mask; + u32 eq_sel_shift; + u32 eq1_mask; + u32 eq2_mask; + u32 xscale_sel_mask; + u32 xscale_sel_shift; + u32 yscale_sel_mask; + u32 yscale_sel_shift; + u32 enable_bit; +}; + +struct aux_rate_tbl { + u16 xscale; + u16 yscale; + u8 eq; +}; + +struct clk_aux { + struct clk_hw hw; + void __iomem *reg; + struct aux_clk_masks *masks; + struct aux_rate_tbl *rtbl; + u8 rtbl_cnt; + spinlock_t *lock; +}; + +/* Fractional Synth clk */ +struct frac_rate_tbl { + u32 div; +}; + +struct clk_frac { + struct clk_hw hw; + void __iomem *reg; + struct frac_rate_tbl *rtbl; + u8 rtbl_cnt; + spinlock_t *lock; +}; + +/* GPT clk */ +struct gpt_rate_tbl { + u16 mscale; + u16 nscale; +}; + +struct clk_gpt { + struct clk_hw hw; + void __iomem *reg; + struct gpt_rate_tbl *rtbl; + u8 rtbl_cnt; + spinlock_t *lock; +}; + +/* VCO-PLL clk */ +struct pll_rate_tbl { + u8 mode; + u16 m; + u8 n; + u8 p; +}; + +struct clk_vco { + struct clk_hw hw; + void __iomem *mode_reg; + void __iomem *cfg_reg; + struct pll_rate_tbl *rtbl; + u8 rtbl_cnt; + spinlock_t *lock; +}; + +struct clk_pll { + struct clk_hw hw; + struct clk_vco *vco; + const char *parent[1]; + spinlock_t *lock; +}; + +typedef unsigned long (*clk_calc_rate)(struct clk_hw *hw, unsigned long prate, + int index); + +/* clk register routines */ +struct clk *clk_register_aux(const char *aux_name, const char *gate_name, + const char *parent_name, unsigned long flags, void __iomem *reg, + struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, + u8 rtbl_cnt, spinlock_t *lock, struct clk **gate_clk); +struct clk *clk_register_frac(const char *name, const char *parent_name, + unsigned long flags, void __iomem *reg, + struct frac_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock); +struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned + long flags, void __iomem *reg, struct gpt_rate_tbl *rtbl, u8 + rtbl_cnt, spinlock_t *lock); +struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, + const char *vco_gate_name, const char *parent_name, + unsigned long flags, void __iomem *mode_reg, void __iomem + *cfg_reg, struct pll_rate_tbl *rtbl, u8 rtbl_cnt, + spinlock_t *lock, struct clk **pll_clk, + struct clk **vco_gate_clk); + +long clk_round_rate_index(struct clk_hw *hw, unsigned long drate, + unsigned long parent_rate, clk_calc_rate calc_rate, u8 rtbl_cnt, + int *index); + +#endif /* __SPEAR_CLK_H */ diff --git a/drivers/clk/spear/spear3xx_clock.c b/drivers/clk/spear/spear3xx_clock.c new file mode 100644 index 000000000000..440bb3e4c971 --- /dev/null +++ b/drivers/clk/spear/spear3xx_clock.c @@ -0,0 +1,612 @@ +/* + * SPEAr3xx machines clock framework source file + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of_platform.h> +#include <linux/spinlock_types.h> +#include <mach/misc_regs.h> +#include "clk.h" + +static DEFINE_SPINLOCK(_lock); + +#define PLL1_CTR (MISC_BASE + 0x008) +#define PLL1_FRQ (MISC_BASE + 0x00C) +#define PLL2_CTR (MISC_BASE + 0x014) +#define PLL2_FRQ (MISC_BASE + 0x018) +#define PLL_CLK_CFG (MISC_BASE + 0x020) + /* PLL_CLK_CFG register masks */ + #define MCTR_CLK_SHIFT 28 + #define MCTR_CLK_MASK 3 + +#define CORE_CLK_CFG (MISC_BASE + 0x024) + /* CORE CLK CFG register masks */ + #define GEN_SYNTH2_3_CLK_SHIFT 18 + #define GEN_SYNTH2_3_CLK_MASK 1 + + #define HCLK_RATIO_SHIFT 10 + #define HCLK_RATIO_MASK 2 + #define PCLK_RATIO_SHIFT 8 + #define PCLK_RATIO_MASK 2 + +#define PERIP_CLK_CFG (MISC_BASE + 0x028) + /* PERIP_CLK_CFG register masks */ + #define UART_CLK_SHIFT 4 + #define UART_CLK_MASK 1 + #define FIRDA_CLK_SHIFT 5 + #define FIRDA_CLK_MASK 2 + #define GPT0_CLK_SHIFT 8 + #define GPT1_CLK_SHIFT 11 + #define GPT2_CLK_SHIFT 12 + #define GPT_CLK_MASK 1 + +#define PERIP1_CLK_ENB (MISC_BASE + 0x02C) + /* PERIP1_CLK_ENB register masks */ + #define UART_CLK_ENB 3 + #define SSP_CLK_ENB 5 + #define I2C_CLK_ENB 7 + #define JPEG_CLK_ENB 8 + #define FIRDA_CLK_ENB 10 + #define GPT1_CLK_ENB 11 + #define GPT2_CLK_ENB 12 + #define ADC_CLK_ENB 15 + #define RTC_CLK_ENB 17 + #define GPIO_CLK_ENB 18 + #define DMA_CLK_ENB 19 + #define SMI_CLK_ENB 21 + #define GMAC_CLK_ENB 23 + #define USBD_CLK_ENB 24 + #define USBH_CLK_ENB 25 + #define C3_CLK_ENB 31 + +#define RAS_CLK_ENB (MISC_BASE + 0x034) + #define RAS_AHB_CLK_ENB 0 + #define RAS_PLL1_CLK_ENB 1 + #define RAS_APB_CLK_ENB 2 + #define RAS_32K_CLK_ENB 3 + #define RAS_24M_CLK_ENB 4 + #define RAS_48M_CLK_ENB 5 + #define RAS_PLL2_CLK_ENB 7 + #define RAS_SYNT0_CLK_ENB 8 + #define RAS_SYNT1_CLK_ENB 9 + #define RAS_SYNT2_CLK_ENB 10 + #define RAS_SYNT3_CLK_ENB 11 + +#define PRSC0_CLK_CFG (MISC_BASE + 0x044) +#define PRSC1_CLK_CFG (MISC_BASE + 0x048) +#define PRSC2_CLK_CFG (MISC_BASE + 0x04C) +#define AMEM_CLK_CFG (MISC_BASE + 0x050) + #define AMEM_CLK_ENB 0 + +#define CLCD_CLK_SYNT (MISC_BASE + 0x05C) +#define FIRDA_CLK_SYNT (MISC_BASE + 0x060) +#define UART_CLK_SYNT (MISC_BASE + 0x064) +#define GMAC_CLK_SYNT (MISC_BASE + 0x068) +#define GEN0_CLK_SYNT (MISC_BASE + 0x06C) +#define GEN1_CLK_SYNT (MISC_BASE + 0x070) +#define GEN2_CLK_SYNT (MISC_BASE + 0x074) +#define GEN3_CLK_SYNT (MISC_BASE + 0x078) + +/* pll rate configuration table, in ascending order of rates */ +static struct pll_rate_tbl pll_rtbl[] = { + {.mode = 0, .m = 0x53, .n = 0x0C, .p = 0x1}, /* vco 332 & pll 166 MHz */ + {.mode = 0, .m = 0x85, .n = 0x0C, .p = 0x1}, /* vco 532 & pll 266 MHz */ + {.mode = 0, .m = 0xA6, .n = 0x0C, .p = 0x1}, /* vco 664 & pll 332 MHz */ +}; + +/* aux rate configuration table, in ascending order of rates */ +static struct aux_rate_tbl aux_rtbl[] = { + /* For PLL1 = 332 MHz */ + {.xscale = 2, .yscale = 27, .eq = 0}, /* 12.296 MHz */ + {.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */ + {.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */ + {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */ +}; + +/* gpt rate configuration table, in ascending order of rates */ +static struct gpt_rate_tbl gpt_rtbl[] = { + /* For pll1 = 332 MHz */ + {.mscale = 4, .nscale = 0}, /* 41.5 MHz */ + {.mscale = 2, .nscale = 0}, /* 55.3 MHz */ + {.mscale = 1, .nscale = 0}, /* 83 MHz */ +}; + +/* clock parents */ +static const char *uart0_parents[] = { "pll3_48m_clk", "uart_synth_gate_clk", }; +static const char *firda_parents[] = { "pll3_48m_clk", "firda_synth_gate_clk", +}; +static const char *gpt0_parents[] = { "pll3_48m_clk", "gpt0_synth_clk", }; +static const char *gpt1_parents[] = { "pll3_48m_clk", "gpt1_synth_clk", }; +static const char *gpt2_parents[] = { "pll3_48m_clk", "gpt2_synth_clk", }; +static const char *gen2_3_parents[] = { "pll1_clk", "pll2_clk", }; +static const char *ddr_parents[] = { "ahb_clk", "ahbmult2_clk", "none", + "pll2_clk", }; + +#ifdef CONFIG_MACH_SPEAR300 +static void __init spear300_clk_init(void) +{ + struct clk *clk; + + clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_48m_clk", 0, + 1, 1); + clk_register_clkdev(clk, NULL, "60000000.clcd"); + + clk = clk_register_fixed_factor(NULL, "fsmc_clk", "ras_ahb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "94000000.flash"); + + clk = clk_register_fixed_factor(NULL, "sdhci_clk", "ras_ahb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "70000000.sdhci"); + + clk = clk_register_fixed_factor(NULL, "gpio1_clk", "ras_apb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "a9000000.gpio"); + + clk = clk_register_fixed_factor(NULL, "kbd_clk", "ras_apb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "a0000000.kbd"); +} +#endif + +/* array of all spear 310 clock lookups */ +#ifdef CONFIG_MACH_SPEAR310 +static void __init spear310_clk_init(void) +{ + struct clk *clk; + + clk = clk_register_fixed_factor(NULL, "emi_clk", "ras_ahb_clk", 0, 1, + 1); + clk_register_clkdev(clk, "emi", NULL); + + clk = clk_register_fixed_factor(NULL, "fsmc_clk", "ras_ahb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "44000000.flash"); + + clk = clk_register_fixed_factor(NULL, "tdm_clk", "ras_ahb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "tdm"); + + clk = clk_register_fixed_factor(NULL, "uart1_clk", "ras_apb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "b2000000.serial"); + + clk = clk_register_fixed_factor(NULL, "uart2_clk", "ras_apb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "b2080000.serial"); + + clk = clk_register_fixed_factor(NULL, "uart3_clk", "ras_apb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "b2100000.serial"); + + clk = clk_register_fixed_factor(NULL, "uart4_clk", "ras_apb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "b2180000.serial"); + + clk = clk_register_fixed_factor(NULL, "uart5_clk", "ras_apb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "b2200000.serial"); +} +#endif + +/* array of all spear 320 clock lookups */ +#ifdef CONFIG_MACH_SPEAR320 + #define SMII_PCLK_SHIFT 18 + #define SMII_PCLK_MASK 2 + #define SMII_PCLK_VAL_PAD 0x0 + #define SMII_PCLK_VAL_PLL2 0x1 + #define SMII_PCLK_VAL_SYNTH0 0x2 + #define SDHCI_PCLK_SHIFT 15 + #define SDHCI_PCLK_MASK 1 + #define SDHCI_PCLK_VAL_48M 0x0 + #define SDHCI_PCLK_VAL_SYNTH3 0x1 + #define I2S_REF_PCLK_SHIFT 8 + #define I2S_REF_PCLK_MASK 1 + #define I2S_REF_PCLK_SYNTH_VAL 0x1 + #define I2S_REF_PCLK_PLL2_VAL 0x0 + #define UART1_PCLK_SHIFT 6 + #define UART1_PCLK_MASK 1 + #define SPEAR320_UARTX_PCLK_VAL_SYNTH1 0x0 + #define SPEAR320_UARTX_PCLK_VAL_APB 0x1 + +static const char *i2s_ref_parents[] = { "ras_pll2_clk", + "ras_gen2_synth_gate_clk", }; +static const char *sdhci_parents[] = { "ras_pll3_48m_clk", + "ras_gen3_synth_gate_clk", +}; +static const char *smii0_parents[] = { "smii_125m_pad", "ras_pll2_clk", + "ras_gen0_synth_gate_clk", }; +static const char *uartx_parents[] = { "ras_gen1_synth_gate_clk", "ras_apb_clk", +}; + +static void __init spear320_clk_init(void) +{ + struct clk *clk; + + clk = clk_register_fixed_rate(NULL, "smii_125m_pad_clk", NULL, + CLK_IS_ROOT, 125000000); + clk_register_clkdev(clk, "smii_125m_pad", NULL); + + clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_48m_clk", 0, + 1, 1); + clk_register_clkdev(clk, NULL, "90000000.clcd"); + + clk = clk_register_fixed_factor(NULL, "emi_clk", "ras_ahb_clk", 0, 1, + 1); + clk_register_clkdev(clk, "emi", NULL); + + clk = clk_register_fixed_factor(NULL, "fsmc_clk", "ras_ahb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "4c000000.flash"); + + clk = clk_register_fixed_factor(NULL, "i2c1_clk", "ras_ahb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "a7000000.i2c"); + + clk = clk_register_fixed_factor(NULL, "pwm_clk", "ras_ahb_clk", 0, 1, + 1); + clk_register_clkdev(clk, "pwm", NULL); + + clk = clk_register_fixed_factor(NULL, "ssp1_clk", "ras_ahb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "a5000000.spi"); + + clk = clk_register_fixed_factor(NULL, "ssp2_clk", "ras_ahb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "a6000000.spi"); + + clk = clk_register_fixed_factor(NULL, "can0_clk", "ras_apb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "c_can_platform.0"); + + clk = clk_register_fixed_factor(NULL, "can1_clk", "ras_apb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "c_can_platform.1"); + + clk = clk_register_fixed_factor(NULL, "i2s_clk", "ras_apb_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "i2s"); + + clk = clk_register_mux(NULL, "i2s_ref_clk", i2s_ref_parents, + ARRAY_SIZE(i2s_ref_parents), 0, SPEAR320_CONTROL_REG, + I2S_REF_PCLK_SHIFT, I2S_REF_PCLK_MASK, 0, &_lock); + clk_register_clkdev(clk, "i2s_ref_clk", NULL); + + clk = clk_register_fixed_factor(NULL, "i2s_sclk", "i2s_ref_clk", 0, 1, + 4); + clk_register_clkdev(clk, "i2s_sclk", NULL); + + clk = clk_register_mux(NULL, "rs485_clk", uartx_parents, + ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, + SPEAR320_RS485_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, + &_lock); + clk_register_clkdev(clk, NULL, "a9300000.serial"); + + clk = clk_register_mux(NULL, "sdhci_clk", sdhci_parents, + ARRAY_SIZE(sdhci_parents), 0, SPEAR320_CONTROL_REG, + SDHCI_PCLK_SHIFT, SDHCI_PCLK_MASK, 0, &_lock); + clk_register_clkdev(clk, NULL, "70000000.sdhci"); + + clk = clk_register_mux(NULL, "smii_pclk", smii0_parents, + ARRAY_SIZE(smii0_parents), 0, SPEAR320_CONTROL_REG, + SMII_PCLK_SHIFT, SMII_PCLK_MASK, 0, &_lock); + clk_register_clkdev(clk, NULL, "smii_pclk"); + + clk = clk_register_fixed_factor(NULL, "smii_clk", "smii_pclk", 0, 1, 1); + clk_register_clkdev(clk, NULL, "smii"); + + clk = clk_register_mux(NULL, "uart1_clk", uartx_parents, + ARRAY_SIZE(uartx_parents), 0, SPEAR320_CONTROL_REG, + UART1_PCLK_SHIFT, UART1_PCLK_MASK, 0, &_lock); + clk_register_clkdev(clk, NULL, "a3000000.serial"); + + clk = clk_register_mux(NULL, "uart2_clk", uartx_parents, + ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, + SPEAR320_UART2_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, + &_lock); + clk_register_clkdev(clk, NULL, "a4000000.serial"); + + clk = clk_register_mux(NULL, "uart3_clk", uartx_parents, + ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, + SPEAR320_UART3_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, + &_lock); + clk_register_clkdev(clk, NULL, "a9100000.serial"); + + clk = clk_register_mux(NULL, "uart4_clk", uartx_parents, + ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, + SPEAR320_UART4_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, + &_lock); + clk_register_clkdev(clk, NULL, "a9200000.serial"); + + clk = clk_register_mux(NULL, "uart5_clk", uartx_parents, + ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, + SPEAR320_UART5_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, + &_lock); + clk_register_clkdev(clk, NULL, "60000000.serial"); + + clk = clk_register_mux(NULL, "uart6_clk", uartx_parents, + ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, + SPEAR320_UART6_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, + &_lock); + clk_register_clkdev(clk, NULL, "60100000.serial"); +} +#endif + +void __init spear3xx_clk_init(void) +{ + struct clk *clk, *clk1; + + clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); + clk_register_clkdev(clk, "apb_pclk", NULL); + + clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT, + 32000); + clk_register_clkdev(clk, "osc_32k_clk", NULL); + + clk = clk_register_fixed_rate(NULL, "osc_24m_clk", NULL, CLK_IS_ROOT, + 24000000); + clk_register_clkdev(clk, "osc_24m_clk", NULL); + + /* clock derived from 32 KHz osc clk */ + clk = clk_register_gate(NULL, "rtc-spear", "osc_32k_clk", 0, + PERIP1_CLK_ENB, RTC_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "fc900000.rtc"); + + /* clock derived from 24 MHz osc clk */ + clk = clk_register_fixed_rate(NULL, "pll3_48m_clk", "osc_24m_clk", 0, + 48000000); + clk_register_clkdev(clk, "pll3_48m_clk", NULL); + + clk = clk_register_fixed_factor(NULL, "wdt_clk", "osc_24m_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "fc880000.wdt"); + + clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, + "osc_24m_clk", 0, PLL1_CTR, PLL1_FRQ, pll_rtbl, + ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); + clk_register_clkdev(clk, "vco1_clk", NULL); + clk_register_clkdev(clk1, "pll1_clk", NULL); + + clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, + "osc_24m_clk", 0, PLL2_CTR, PLL2_FRQ, pll_rtbl, + ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); + clk_register_clkdev(clk, "vco2_clk", NULL); + clk_register_clkdev(clk1, "pll2_clk", NULL); + + /* clock derived from pll1 clk */ + clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 1); + clk_register_clkdev(clk, "cpu_clk", NULL); + + clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk", + CLK_SET_RATE_PARENT, CORE_CLK_CFG, HCLK_RATIO_SHIFT, + HCLK_RATIO_MASK, 0, &_lock); + clk_register_clkdev(clk, "ahb_clk", NULL); + + clk = clk_register_aux("uart_synth_clk", "uart_synth_gate_clk", + "pll1_clk", 0, UART_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "uart_synth_clk", NULL); + clk_register_clkdev(clk1, "uart_synth_gate_clk", NULL); + + clk = clk_register_mux(NULL, "uart0_mux_clk", uart0_parents, + ARRAY_SIZE(uart0_parents), 0, PERIP_CLK_CFG, + UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock); + clk_register_clkdev(clk, "uart0_mux_clk", NULL); + + clk = clk_register_gate(NULL, "uart0", "uart0_mux_clk", 0, + PERIP1_CLK_ENB, UART_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "d0000000.serial"); + + clk = clk_register_aux("firda_synth_clk", "firda_synth_gate_clk", + "pll1_clk", 0, FIRDA_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "firda_synth_clk", NULL); + clk_register_clkdev(clk1, "firda_synth_gate_clk", NULL); + + clk = clk_register_mux(NULL, "firda_mux_clk", firda_parents, + ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG, + FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock); + clk_register_clkdev(clk, "firda_mux_clk", NULL); + + clk = clk_register_gate(NULL, "firda_clk", "firda_mux_clk", 0, + PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "firda"); + + /* gpt clocks */ + clk_register_gpt("gpt0_synth_clk", "pll1_clk", 0, PRSC0_CLK_CFG, + gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); + clk = clk_register_mux(NULL, "gpt0_clk", gpt0_parents, + ARRAY_SIZE(gpt0_parents), 0, PERIP_CLK_CFG, + GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); + clk_register_clkdev(clk, NULL, "gpt0"); + + clk_register_gpt("gpt1_synth_clk", "pll1_clk", 0, PRSC1_CLK_CFG, + gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); + clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt1_parents, + ARRAY_SIZE(gpt1_parents), 0, PERIP_CLK_CFG, + GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); + clk_register_clkdev(clk, "gpt1_mux_clk", NULL); + clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0, + PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "gpt1"); + + clk_register_gpt("gpt2_synth_clk", "pll1_clk", 0, PRSC2_CLK_CFG, + gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); + clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt2_parents, + ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG, + GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); + clk_register_clkdev(clk, "gpt2_mux_clk", NULL); + clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0, + PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "gpt2"); + + /* general synths clocks */ + clk = clk_register_aux("gen0_synth_clk", "gen0_synth_gate_clk", + "pll1_clk", 0, GEN0_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "gen0_synth_clk", NULL); + clk_register_clkdev(clk1, "gen0_synth_gate_clk", NULL); + + clk = clk_register_aux("gen1_synth_clk", "gen1_synth_gate_clk", + "pll1_clk", 0, GEN1_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "gen1_synth_clk", NULL); + clk_register_clkdev(clk1, "gen1_synth_gate_clk", NULL); + + clk = clk_register_mux(NULL, "gen2_3_parent_clk", gen2_3_parents, + ARRAY_SIZE(gen2_3_parents), 0, CORE_CLK_CFG, + GEN_SYNTH2_3_CLK_SHIFT, GEN_SYNTH2_3_CLK_MASK, 0, + &_lock); + clk_register_clkdev(clk, "gen2_3_parent_clk", NULL); + + clk = clk_register_aux("gen2_synth_clk", "gen2_synth_gate_clk", + "gen2_3_parent_clk", 0, GEN2_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "gen2_synth_clk", NULL); + clk_register_clkdev(clk1, "gen2_synth_gate_clk", NULL); + + clk = clk_register_aux("gen3_synth_clk", "gen3_synth_gate_clk", + "gen2_3_parent_clk", 0, GEN3_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "gen3_synth_clk", NULL); + clk_register_clkdev(clk1, "gen3_synth_gate_clk", NULL); + + /* clock derived from pll3 clk */ + clk = clk_register_gate(NULL, "usbh_clk", "pll3_48m_clk", 0, + PERIP1_CLK_ENB, USBH_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "usbh_clk", NULL); + + clk = clk_register_fixed_factor(NULL, "usbh.0_clk", "usbh_clk", 0, 1, + 1); + clk_register_clkdev(clk, "usbh.0_clk", NULL); + + clk = clk_register_fixed_factor(NULL, "usbh.1_clk", "usbh_clk", 0, 1, + 1); + clk_register_clkdev(clk, "usbh.1_clk", NULL); + + clk = clk_register_gate(NULL, "usbd_clk", "pll3_48m_clk", 0, + PERIP1_CLK_ENB, USBD_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "designware_udc"); + + /* clock derived from ahb clk */ + clk = clk_register_fixed_factor(NULL, "ahbmult2_clk", "ahb_clk", 0, 2, + 1); + clk_register_clkdev(clk, "ahbmult2_clk", NULL); + + clk = clk_register_mux(NULL, "ddr_clk", ddr_parents, + ARRAY_SIZE(ddr_parents), 0, PLL_CLK_CFG, MCTR_CLK_SHIFT, + MCTR_CLK_MASK, 0, &_lock); + clk_register_clkdev(clk, "ddr_clk", NULL); + + clk = clk_register_divider(NULL, "apb_clk", "ahb_clk", + CLK_SET_RATE_PARENT, CORE_CLK_CFG, PCLK_RATIO_SHIFT, + PCLK_RATIO_MASK, 0, &_lock); + clk_register_clkdev(clk, "apb_clk", NULL); + + clk = clk_register_gate(NULL, "amem_clk", "ahb_clk", 0, AMEM_CLK_CFG, + AMEM_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "amem_clk", NULL); + + clk = clk_register_gate(NULL, "c3_clk", "ahb_clk", 0, PERIP1_CLK_ENB, + C3_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "c3_clk"); + + clk = clk_register_gate(NULL, "dma_clk", "ahb_clk", 0, PERIP1_CLK_ENB, + DMA_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "fc400000.dma"); + + clk = clk_register_gate(NULL, "gmac_clk", "ahb_clk", 0, PERIP1_CLK_ENB, + GMAC_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "e0800000.eth"); + + clk = clk_register_gate(NULL, "i2c0_clk", "ahb_clk", 0, PERIP1_CLK_ENB, + I2C_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "d0180000.i2c"); + + clk = clk_register_gate(NULL, "jpeg_clk", "ahb_clk", 0, PERIP1_CLK_ENB, + JPEG_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "jpeg"); + + clk = clk_register_gate(NULL, "smi_clk", "ahb_clk", 0, PERIP1_CLK_ENB, + SMI_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "fc000000.flash"); + + /* clock derived from apb clk */ + clk = clk_register_gate(NULL, "adc_clk", "apb_clk", 0, PERIP1_CLK_ENB, + ADC_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "adc"); + + clk = clk_register_gate(NULL, "gpio0_clk", "apb_clk", 0, PERIP1_CLK_ENB, + GPIO_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "fc980000.gpio"); + + clk = clk_register_gate(NULL, "ssp0_clk", "apb_clk", 0, PERIP1_CLK_ENB, + SSP_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "d0100000.spi"); + + /* RAS clk enable */ + clk = clk_register_gate(NULL, "ras_ahb_clk", "ahb_clk", 0, RAS_CLK_ENB, + RAS_AHB_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_ahb_clk", NULL); + + clk = clk_register_gate(NULL, "ras_apb_clk", "apb_clk", 0, RAS_CLK_ENB, + RAS_APB_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_apb_clk", NULL); + + clk = clk_register_gate(NULL, "ras_32k_clk", "osc_32k_clk", 0, + RAS_CLK_ENB, RAS_32K_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_32k_clk", NULL); + + clk = clk_register_gate(NULL, "ras_24m_clk", "osc_24m_clk", 0, + RAS_CLK_ENB, RAS_24M_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_24m_clk", NULL); + + clk = clk_register_gate(NULL, "ras_pll1_clk", "pll1_clk", 0, + RAS_CLK_ENB, RAS_PLL1_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_pll1_clk", NULL); + + clk = clk_register_gate(NULL, "ras_pll2_clk", "pll2_clk", 0, + RAS_CLK_ENB, RAS_PLL2_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_pll2_clk", NULL); + + clk = clk_register_gate(NULL, "ras_pll3_48m_clk", "pll3_48m_clk", 0, + RAS_CLK_ENB, RAS_48M_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_pll3_48m_clk", NULL); + + clk = clk_register_gate(NULL, "ras_gen0_synth_gate_clk", + "gen0_synth_gate_clk", 0, RAS_CLK_ENB, + RAS_SYNT0_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_gen0_synth_gate_clk", NULL); + + clk = clk_register_gate(NULL, "ras_gen1_synth_gate_clk", + "gen1_synth_gate_clk", 0, RAS_CLK_ENB, + RAS_SYNT1_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_gen1_synth_gate_clk", NULL); + + clk = clk_register_gate(NULL, "ras_gen2_synth_gate_clk", + "gen2_synth_gate_clk", 0, RAS_CLK_ENB, + RAS_SYNT2_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_gen2_synth_gate_clk", NULL); + + clk = clk_register_gate(NULL, "ras_gen3_synth_gate_clk", + "gen3_synth_gate_clk", 0, RAS_CLK_ENB, + RAS_SYNT3_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, "ras_gen3_synth_gate_clk", NULL); + + if (of_machine_is_compatible("st,spear300")) + spear300_clk_init(); + else if (of_machine_is_compatible("st,spear310")) + spear310_clk_init(); + else if (of_machine_is_compatible("st,spear320")) + spear320_clk_init(); +} diff --git a/drivers/clk/spear/spear6xx_clock.c b/drivers/clk/spear/spear6xx_clock.c new file mode 100644 index 000000000000..f9a20b382304 --- /dev/null +++ b/drivers/clk/spear/spear6xx_clock.c @@ -0,0 +1,342 @@ +/* + * SPEAr6xx machines clock framework source file + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/io.h> +#include <linux/spinlock_types.h> +#include <mach/misc_regs.h> +#include "clk.h" + +static DEFINE_SPINLOCK(_lock); + +#define PLL1_CTR (MISC_BASE + 0x008) +#define PLL1_FRQ (MISC_BASE + 0x00C) +#define PLL2_CTR (MISC_BASE + 0x014) +#define PLL2_FRQ (MISC_BASE + 0x018) +#define PLL_CLK_CFG (MISC_BASE + 0x020) + /* PLL_CLK_CFG register masks */ + #define MCTR_CLK_SHIFT 28 + #define MCTR_CLK_MASK 3 + +#define CORE_CLK_CFG (MISC_BASE + 0x024) + /* CORE CLK CFG register masks */ + #define HCLK_RATIO_SHIFT 10 + #define HCLK_RATIO_MASK 2 + #define PCLK_RATIO_SHIFT 8 + #define PCLK_RATIO_MASK 2 + +#define PERIP_CLK_CFG (MISC_BASE + 0x028) + /* PERIP_CLK_CFG register masks */ + #define CLCD_CLK_SHIFT 2 + #define CLCD_CLK_MASK 2 + #define UART_CLK_SHIFT 4 + #define UART_CLK_MASK 1 + #define FIRDA_CLK_SHIFT 5 + #define FIRDA_CLK_MASK 2 + #define GPT0_CLK_SHIFT 8 + #define GPT1_CLK_SHIFT 10 + #define GPT2_CLK_SHIFT 11 + #define GPT3_CLK_SHIFT 12 + #define GPT_CLK_MASK 1 + +#define PERIP1_CLK_ENB (MISC_BASE + 0x02C) + /* PERIP1_CLK_ENB register masks */ + #define UART0_CLK_ENB 3 + #define UART1_CLK_ENB 4 + #define SSP0_CLK_ENB 5 + #define SSP1_CLK_ENB 6 + #define I2C_CLK_ENB 7 + #define JPEG_CLK_ENB 8 + #define FSMC_CLK_ENB 9 + #define FIRDA_CLK_ENB 10 + #define GPT2_CLK_ENB 11 + #define GPT3_CLK_ENB 12 + #define GPIO2_CLK_ENB 13 + #define SSP2_CLK_ENB 14 + #define ADC_CLK_ENB 15 + #define GPT1_CLK_ENB 11 + #define RTC_CLK_ENB 17 + #define GPIO1_CLK_ENB 18 + #define DMA_CLK_ENB 19 + #define SMI_CLK_ENB 21 + #define CLCD_CLK_ENB 22 + #define GMAC_CLK_ENB 23 + #define USBD_CLK_ENB 24 + #define USBH0_CLK_ENB 25 + #define USBH1_CLK_ENB 26 + +#define PRSC0_CLK_CFG (MISC_BASE + 0x044) +#define PRSC1_CLK_CFG (MISC_BASE + 0x048) +#define PRSC2_CLK_CFG (MISC_BASE + 0x04C) + +#define CLCD_CLK_SYNT (MISC_BASE + 0x05C) +#define FIRDA_CLK_SYNT (MISC_BASE + 0x060) +#define UART_CLK_SYNT (MISC_BASE + 0x064) + +/* vco rate configuration table, in ascending order of rates */ +static struct pll_rate_tbl pll_rtbl[] = { + {.mode = 0, .m = 0x53, .n = 0x0F, .p = 0x1}, /* vco 332 & pll 166 MHz */ + {.mode = 0, .m = 0x85, .n = 0x0F, .p = 0x1}, /* vco 532 & pll 266 MHz */ + {.mode = 0, .m = 0xA6, .n = 0x0F, .p = 0x1}, /* vco 664 & pll 332 MHz */ +}; + +/* aux rate configuration table, in ascending order of rates */ +static struct aux_rate_tbl aux_rtbl[] = { + /* For PLL1 = 332 MHz */ + {.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */ + {.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */ + {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */ +}; + +static const char *clcd_parents[] = { "pll3_48m_clk", "clcd_synth_gate_clk", }; +static const char *firda_parents[] = { "pll3_48m_clk", "firda_synth_gate_clk", +}; +static const char *uart_parents[] = { "pll3_48m_clk", "uart_synth_gate_clk", }; +static const char *gpt0_1_parents[] = { "pll3_48m_clk", "gpt0_1_synth_clk", }; +static const char *gpt2_parents[] = { "pll3_48m_clk", "gpt2_synth_clk", }; +static const char *gpt3_parents[] = { "pll3_48m_clk", "gpt3_synth_clk", }; +static const char *ddr_parents[] = { "ahb_clk", "ahbmult2_clk", "none", + "pll2_clk", }; + +/* gpt rate configuration table, in ascending order of rates */ +static struct gpt_rate_tbl gpt_rtbl[] = { + /* For pll1 = 332 MHz */ + {.mscale = 4, .nscale = 0}, /* 41.5 MHz */ + {.mscale = 2, .nscale = 0}, /* 55.3 MHz */ + {.mscale = 1, .nscale = 0}, /* 83 MHz */ +}; + +void __init spear6xx_clk_init(void) +{ + struct clk *clk, *clk1; + + clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); + clk_register_clkdev(clk, "apb_pclk", NULL); + + clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT, + 32000); + clk_register_clkdev(clk, "osc_32k_clk", NULL); + + clk = clk_register_fixed_rate(NULL, "osc_30m_clk", NULL, CLK_IS_ROOT, + 30000000); + clk_register_clkdev(clk, "osc_30m_clk", NULL); + + /* clock derived from 32 KHz osc clk */ + clk = clk_register_gate(NULL, "rtc_spear", "osc_32k_clk", 0, + PERIP1_CLK_ENB, RTC_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "rtc-spear"); + + /* clock derived from 30 MHz osc clk */ + clk = clk_register_fixed_rate(NULL, "pll3_48m_clk", "osc_24m_clk", 0, + 48000000); + clk_register_clkdev(clk, "pll3_48m_clk", NULL); + + clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "osc_30m_clk", + 0, PLL1_CTR, PLL1_FRQ, pll_rtbl, ARRAY_SIZE(pll_rtbl), + &_lock, &clk1, NULL); + clk_register_clkdev(clk, "vco1_clk", NULL); + clk_register_clkdev(clk1, "pll1_clk", NULL); + + clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, + "osc_30m_clk", 0, PLL2_CTR, PLL2_FRQ, pll_rtbl, + ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL); + clk_register_clkdev(clk, "vco2_clk", NULL); + clk_register_clkdev(clk1, "pll2_clk", NULL); + + clk = clk_register_fixed_factor(NULL, "wdt_clk", "osc_30m_clk", 0, 1, + 1); + clk_register_clkdev(clk, NULL, "wdt"); + + /* clock derived from pll1 clk */ + clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 1); + clk_register_clkdev(clk, "cpu_clk", NULL); + + clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk", + CLK_SET_RATE_PARENT, CORE_CLK_CFG, HCLK_RATIO_SHIFT, + HCLK_RATIO_MASK, 0, &_lock); + clk_register_clkdev(clk, "ahb_clk", NULL); + + clk = clk_register_aux("uart_synth_clk", "uart_synth_gate_clk", + "pll1_clk", 0, UART_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "uart_synth_clk", NULL); + clk_register_clkdev(clk1, "uart_synth_gate_clk", NULL); + + clk = clk_register_mux(NULL, "uart_mux_clk", uart_parents, + ARRAY_SIZE(uart_parents), 0, PERIP_CLK_CFG, + UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock); + clk_register_clkdev(clk, "uart_mux_clk", NULL); + + clk = clk_register_gate(NULL, "uart0", "uart_mux_clk", 0, + PERIP1_CLK_ENB, UART0_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "d0000000.serial"); + + clk = clk_register_gate(NULL, "uart1", "uart_mux_clk", 0, + PERIP1_CLK_ENB, UART1_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "d0080000.serial"); + + clk = clk_register_aux("firda_synth_clk", "firda_synth_gate_clk", + "pll1_clk", 0, FIRDA_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "firda_synth_clk", NULL); + clk_register_clkdev(clk1, "firda_synth_gate_clk", NULL); + + clk = clk_register_mux(NULL, "firda_mux_clk", firda_parents, + ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG, + FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock); + clk_register_clkdev(clk, "firda_mux_clk", NULL); + + clk = clk_register_gate(NULL, "firda_clk", "firda_mux_clk", 0, + PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "firda"); + + clk = clk_register_aux("clcd_synth_clk", "clcd_synth_gate_clk", + "pll1_clk", 0, CLCD_CLK_SYNT, NULL, aux_rtbl, + ARRAY_SIZE(aux_rtbl), &_lock, &clk1); + clk_register_clkdev(clk, "clcd_synth_clk", NULL); + clk_register_clkdev(clk1, "clcd_synth_gate_clk", NULL); + + clk = clk_register_mux(NULL, "clcd_mux_clk", clcd_parents, + ARRAY_SIZE(clcd_parents), 0, PERIP_CLK_CFG, + CLCD_CLK_SHIFT, CLCD_CLK_MASK, 0, &_lock); + clk_register_clkdev(clk, "clcd_mux_clk", NULL); + + clk = clk_register_gate(NULL, "clcd_clk", "clcd_mux_clk", 0, + PERIP1_CLK_ENB, CLCD_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "clcd"); + + /* gpt clocks */ + clk = clk_register_gpt("gpt0_1_synth_clk", "pll1_clk", 0, PRSC0_CLK_CFG, + gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); + clk_register_clkdev(clk, "gpt0_1_synth_clk", NULL); + + clk = clk_register_mux(NULL, "gpt0_mux_clk", gpt0_1_parents, + ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG, + GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); + clk_register_clkdev(clk, NULL, "gpt0"); + + clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt0_1_parents, + ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG, + GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); + clk_register_clkdev(clk, "gpt1_mux_clk", NULL); + + clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0, + PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "gpt1"); + + clk = clk_register_gpt("gpt2_synth_clk", "pll1_clk", 0, PRSC1_CLK_CFG, + gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); + clk_register_clkdev(clk, "gpt2_synth_clk", NULL); + + clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt2_parents, + ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG, + GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); + clk_register_clkdev(clk, "gpt2_mux_clk", NULL); + + clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0, + PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "gpt2"); + + clk = clk_register_gpt("gpt3_synth_clk", "pll1_clk", 0, PRSC2_CLK_CFG, + gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); + clk_register_clkdev(clk, "gpt3_synth_clk", NULL); + + clk = clk_register_mux(NULL, "gpt3_mux_clk", gpt3_parents, + ARRAY_SIZE(gpt3_parents), 0, PERIP_CLK_CFG, + GPT3_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); + clk_register_clkdev(clk, "gpt3_mux_clk", NULL); + + clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mux_clk", 0, + PERIP1_CLK_ENB, GPT3_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "gpt3"); + + /* clock derived from pll3 clk */ + clk = clk_register_gate(NULL, "usbh0_clk", "pll3_48m_clk", 0, + PERIP1_CLK_ENB, USBH0_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "usbh.0_clk"); + + clk = clk_register_gate(NULL, "usbh1_clk", "pll3_48m_clk", 0, + PERIP1_CLK_ENB, USBH1_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "usbh.1_clk"); + + clk = clk_register_gate(NULL, "usbd_clk", "pll3_48m_clk", 0, + PERIP1_CLK_ENB, USBD_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "designware_udc"); + + /* clock derived from ahb clk */ + clk = clk_register_fixed_factor(NULL, "ahbmult2_clk", "ahb_clk", 0, 2, + 1); + clk_register_clkdev(clk, "ahbmult2_clk", NULL); + + clk = clk_register_mux(NULL, "ddr_clk", ddr_parents, + ARRAY_SIZE(ddr_parents), + 0, PLL_CLK_CFG, MCTR_CLK_SHIFT, MCTR_CLK_MASK, 0, + &_lock); + clk_register_clkdev(clk, "ddr_clk", NULL); + + clk = clk_register_divider(NULL, "apb_clk", "ahb_clk", + CLK_SET_RATE_PARENT, CORE_CLK_CFG, PCLK_RATIO_SHIFT, + PCLK_RATIO_MASK, 0, &_lock); + clk_register_clkdev(clk, "apb_clk", NULL); + + clk = clk_register_gate(NULL, "dma_clk", "ahb_clk", 0, PERIP1_CLK_ENB, + DMA_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "fc400000.dma"); + + clk = clk_register_gate(NULL, "fsmc_clk", "ahb_clk", 0, PERIP1_CLK_ENB, + FSMC_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "d1800000.flash"); + + clk = clk_register_gate(NULL, "gmac_clk", "ahb_clk", 0, PERIP1_CLK_ENB, + GMAC_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "gmac"); + + clk = clk_register_gate(NULL, "i2c_clk", "ahb_clk", 0, PERIP1_CLK_ENB, + I2C_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "d0200000.i2c"); + + clk = clk_register_gate(NULL, "jpeg_clk", "ahb_clk", 0, PERIP1_CLK_ENB, + JPEG_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "jpeg"); + + clk = clk_register_gate(NULL, "smi_clk", "ahb_clk", 0, PERIP1_CLK_ENB, + SMI_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "fc000000.flash"); + + /* clock derived from apb clk */ + clk = clk_register_gate(NULL, "adc_clk", "apb_clk", 0, PERIP1_CLK_ENB, + ADC_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "adc"); + + clk = clk_register_fixed_factor(NULL, "gpio0_clk", "apb_clk", 0, 1, 1); + clk_register_clkdev(clk, NULL, "f0100000.gpio"); + + clk = clk_register_gate(NULL, "gpio1_clk", "apb_clk", 0, PERIP1_CLK_ENB, + GPIO1_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "fc980000.gpio"); + + clk = clk_register_gate(NULL, "gpio2_clk", "apb_clk", 0, PERIP1_CLK_ENB, + GPIO2_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "d8100000.gpio"); + + clk = clk_register_gate(NULL, "ssp0_clk", "apb_clk", 0, PERIP1_CLK_ENB, + SSP0_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "ssp-pl022.0"); + + clk = clk_register_gate(NULL, "ssp1_clk", "apb_clk", 0, PERIP1_CLK_ENB, + SSP1_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "ssp-pl022.1"); + + clk = clk_register_gate(NULL, "ssp2_clk", "apb_clk", 0, PERIP1_CLK_ENB, + SSP2_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "ssp-pl022.2"); +} diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index e6ecc5f23943..1cc6b3f3e262 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -16,6 +16,7 @@ #include <linux/scatterlist.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/clk.h> #include <crypto/internal/hash.h> #include <crypto/sha.h> @@ -79,6 +80,7 @@ struct crypto_priv { void __iomem *reg; void __iomem *sram; int irq; + struct clk *clk; struct task_struct *queue_th; /* the lock protects queue and eng_st */ @@ -1053,6 +1055,12 @@ static int mv_probe(struct platform_device *pdev) if (ret) goto err_thread; + /* Not all platforms can gate the clock, so it is not + an error if the clock does not exists. */ + cp->clk = clk_get(&pdev->dev, NULL); + if (!IS_ERR(cp->clk)) + clk_prepare_enable(cp->clk); + writel(SEC_INT_ACCEL0_DONE, cpg->reg + SEC_ACCEL_INT_MASK); writel(SEC_CFG_STOP_DIG_ERR, cpg->reg + SEC_ACCEL_CFG); writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0); @@ -1118,6 +1126,12 @@ static int mv_remove(struct platform_device *pdev) memset(cp->sram, 0, cp->sram_size); iounmap(cp->sram); iounmap(cp->reg); + + if (!IS_ERR(cp->clk)) { + clk_disable_unprepare(cp->clk); + clk_put(cp->clk); + } + kfree(cp); cpg = NULL; return 0; diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index a472a29d8497..fb4f4990f5eb 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -323,7 +323,8 @@ struct sdma_engine { struct sdma_context_data *context; dma_addr_t context_phys; struct dma_device dma_device; - struct clk *clk; + struct clk *clk_ipg; + struct clk *clk_ahb; spinlock_t channel_0_lock; struct sdma_script_start_addrs *script_addrs; }; @@ -867,7 +868,8 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan) sdmac->peripheral_type = data->peripheral_type; sdmac->event_id0 = data->dma_request; - clk_enable(sdmac->sdma->clk); + clk_enable(sdmac->sdma->clk_ipg); + clk_enable(sdmac->sdma->clk_ahb); ret = sdma_request_channel(sdmac); if (ret) @@ -904,7 +906,8 @@ static void sdma_free_chan_resources(struct dma_chan *chan) dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys); - clk_disable(sdma->clk); + clk_disable(sdma->clk_ipg); + clk_disable(sdma->clk_ahb); } static struct dma_async_tx_descriptor *sdma_prep_slave_sg( @@ -1177,12 +1180,14 @@ static void sdma_load_firmware(const struct firmware *fw, void *context) addr = (void *)header + header->script_addrs_start; ram_code = (void *)header + header->ram_code_start; - clk_enable(sdma->clk); + clk_enable(sdma->clk_ipg); + clk_enable(sdma->clk_ahb); /* download the RAM image for SDMA */ sdma_load_script(sdma, ram_code, header->ram_code_size, addr->ram_code_start_addr); - clk_disable(sdma->clk); + clk_disable(sdma->clk_ipg); + clk_disable(sdma->clk_ahb); sdma_add_scripts(sdma, addr); @@ -1224,7 +1229,8 @@ static int __init sdma_init(struct sdma_engine *sdma) return -ENODEV; } - clk_enable(sdma->clk); + clk_enable(sdma->clk_ipg); + clk_enable(sdma->clk_ahb); /* Be sure SDMA has not started yet */ writel_relaxed(0, sdma->regs + SDMA_H_C0PTR); @@ -1277,12 +1283,14 @@ static int __init sdma_init(struct sdma_engine *sdma) /* Initializes channel's priorities */ sdma_set_channel_priority(&sdma->channel[0], 7); - clk_disable(sdma->clk); + clk_disable(sdma->clk_ipg); + clk_disable(sdma->clk_ahb); return 0; err_dma_alloc: - clk_disable(sdma->clk); + clk_disable(sdma->clk_ipg); + clk_disable(sdma->clk_ahb); dev_err(sdma->dev, "initialisation failed with %d\n", ret); return ret; } @@ -1321,12 +1329,21 @@ static int __init sdma_probe(struct platform_device *pdev) goto err_request_region; } - sdma->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(sdma->clk)) { - ret = PTR_ERR(sdma->clk); + sdma->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(sdma->clk_ipg)) { + ret = PTR_ERR(sdma->clk_ipg); goto err_clk; } + sdma->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(sdma->clk_ahb)) { + ret = PTR_ERR(sdma->clk_ahb); + goto err_clk; + } + + clk_prepare(sdma->clk_ipg); + clk_prepare(sdma->clk_ahb); + sdma->regs = ioremap(iores->start, resource_size(iores)); if (!sdma->regs) { ret = -ENOMEM; @@ -1436,7 +1453,6 @@ err_alloc: err_request_irq: iounmap(sdma->regs); err_ioremap: - clk_put(sdma->clk); err_clk: release_mem_region(iores->start, resource_size(iores)); err_request_region: diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index 62e3f8ec2461..5ec72044ea4c 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c @@ -1715,7 +1715,7 @@ static int __init ipu_probe(struct platform_device *pdev) } /* Make sure IPU HSP clock is running */ - clk_enable(ipu_data.ipu_clk); + clk_prepare_enable(ipu_data.ipu_clk); /* Disable all interrupts */ idmac_write_ipureg(&ipu_data, 0, IPU_INT_CTRL_1); @@ -1747,7 +1747,7 @@ static int __init ipu_probe(struct platform_device *pdev) err_idmac_init: err_attach_irq: ipu_irq_detach_irq(&ipu_data, pdev); - clk_disable(ipu_data.ipu_clk); + clk_disable_unprepare(ipu_data.ipu_clk); clk_put(ipu_data.ipu_clk); err_clk_get: iounmap(ipu_data.reg_ic); @@ -1765,7 +1765,7 @@ static int __exit ipu_remove(struct platform_device *pdev) ipu_idmac_exit(ipu); ipu_irq_detach_irq(ipu, pdev); - clk_disable(ipu->ipu_clk); + clk_disable_unprepare(ipu->ipu_clk); clk_put(ipu->ipu_clk); iounmap(ipu->reg_ic); iounmap(ipu->reg_ipu); diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index fa5d55fea46c..0b12e68bf79c 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -25,6 +25,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/memory.h> +#include <linux/clk.h> #include <plat/mv_xor.h> #include "dmaengine.h" @@ -1307,11 +1308,25 @@ static int mv_xor_shared_probe(struct platform_device *pdev) if (dram) mv_xor_conf_mbus_windows(msp, dram); + /* Not all platforms can gate the clock, so it is not + * an error if the clock does not exists. + */ + msp->clk = clk_get(&pdev->dev, NULL); + if (!IS_ERR(msp->clk)) + clk_prepare_enable(msp->clk); + return 0; } static int mv_xor_shared_remove(struct platform_device *pdev) { + struct mv_xor_shared_private *msp = platform_get_drvdata(pdev); + + if (!IS_ERR(msp->clk)) { + clk_disable_unprepare(msp->clk); + clk_put(msp->clk); + } + return 0; } diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h index 654876b7ba1d..a5b422f5a8ab 100644 --- a/drivers/dma/mv_xor.h +++ b/drivers/dma/mv_xor.h @@ -55,6 +55,7 @@ struct mv_xor_shared_private { void __iomem *xor_base; void __iomem *xor_high_base; + struct clk *clk; }; diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index 02d54a057b60..f13643d31353 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -511,7 +511,7 @@ static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam, /* ipu_csi_init_interface() */ csi_reg_write(mx3_cam, conf, CSI_SENS_CONF); - clk_enable(mx3_cam->clk); + clk_prepare_enable(mx3_cam->clk); rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk); dev_dbg(icd->parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate); if (rate) @@ -552,7 +552,7 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd) *ichan = NULL; } - clk_disable(mx3_cam->clk); + clk_disable_unprepare(mx3_cam->clk); mx3_cam->icd = NULL; diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index eeb8cd125b0c..3b9136c1a475 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -19,6 +19,7 @@ #include <linux/dma-mapping.h> #include <linux/scatterlist.h> #include <linux/irq.h> +#include <linux/clk.h> #include <linux/gpio.h> #include <linux/mmc/host.h> @@ -51,6 +52,7 @@ struct mvsd_host { struct device *dev; struct resource *res; int irq; + struct clk *clk; int gpio_card_detect; int gpio_write_protect; }; @@ -770,6 +772,13 @@ static int __init mvsd_probe(struct platform_device *pdev) } else host->irq = irq; + /* Not all platforms can gate the clock, so it is not + an error if the clock does not exists. */ + host->clk = clk_get(&pdev->dev, NULL); + if (!IS_ERR(host->clk)) { + clk_prepare_enable(host->clk); + } + if (mvsd_data->gpio_card_detect) { ret = gpio_request(mvsd_data->gpio_card_detect, DRIVER_NAME " cd"); @@ -854,6 +863,11 @@ static int __exit mvsd_remove(struct platform_device *pdev) mvsd_power_down(host); iounmap(host->base); release_resource(host->res); + + if (!IS_ERR(host->clk)) { + clk_disable_unprepare(host->clk); + clk_put(host->clk); + } mmc_free_host(mmc); } platform_set_drvdata(pdev, NULL); diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index b2058b432320..28ed52d58f7f 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -136,7 +136,8 @@ struct mxcmci_host { u16 rev_no; unsigned int cmdat; - struct clk *clk; + struct clk *clk_ipg; + struct clk *clk_per; int clock; @@ -672,7 +673,7 @@ static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios) { unsigned int divider; int prescaler = 0; - unsigned int clk_in = clk_get_rate(host->clk); + unsigned int clk_in = clk_get_rate(host->clk_per); while (prescaler <= 0x800) { for (divider = 1; divider <= 0xF; divider++) { @@ -900,12 +901,20 @@ static int mxcmci_probe(struct platform_device *pdev) host->res = r; host->irq = irq; - host->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); + host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(host->clk_ipg)) { + ret = PTR_ERR(host->clk_ipg); goto out_iounmap; } - clk_enable(host->clk); + + host->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(host->clk_per)) { + ret = PTR_ERR(host->clk_per); + goto out_iounmap; + } + + clk_prepare_enable(host->clk_per); + clk_prepare_enable(host->clk_ipg); mxcmci_softreset(host); @@ -917,8 +926,8 @@ static int mxcmci_probe(struct platform_device *pdev) goto out_clk_put; } - mmc->f_min = clk_get_rate(host->clk) >> 16; - mmc->f_max = clk_get_rate(host->clk) >> 1; + mmc->f_min = clk_get_rate(host->clk_per) >> 16; + mmc->f_max = clk_get_rate(host->clk_per) >> 1; /* recommended in data sheet */ writew(0x2db4, host->base + MMC_REG_READ_TO); @@ -967,8 +976,8 @@ out_free_dma: if (host->dma) dma_release_channel(host->dma); out_clk_put: - clk_disable(host->clk); - clk_put(host->clk); + clk_disable_unprepare(host->clk_per); + clk_disable_unprepare(host->clk_ipg); out_iounmap: iounmap(host->base); out_free: @@ -999,8 +1008,8 @@ static int mxcmci_remove(struct platform_device *pdev) if (host->dma) dma_release_channel(host->dma); - clk_disable(host->clk); - clk_put(host->clk); + clk_disable_unprepare(host->clk_per); + clk_disable_unprepare(host->clk_ipg); release_mem_region(host->res->start, resource_size(host->res)); @@ -1018,7 +1027,8 @@ static int mxcmci_suspend(struct device *dev) if (mmc) ret = mmc_suspend_host(mmc); - clk_disable(host->clk); + clk_disable_unprepare(host->clk_per); + clk_disable_unprepare(host->clk_ipg); return ret; } @@ -1029,7 +1039,8 @@ static int mxcmci_resume(struct device *dev) struct mxcmci_host *host = mmc_priv(mmc); int ret = 0; - clk_enable(host->clk); + clk_prepare_enable(host->clk_per); + clk_prepare_enable(host->clk_ipg); if (mmc) ret = mmc_resume_host(mmc); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 365b16c230f8..ebbe984e5d00 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -71,6 +71,9 @@ struct pltfm_imx_data { enum imx_esdhc_type devtype; struct pinctrl *pinctrl; struct esdhc_platform_data boarddata; + struct clk *clk_ipg; + struct clk *clk_ahb; + struct clk *clk_per; }; static struct platform_device_id imx_esdhc_devtype[] = { @@ -439,7 +442,6 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host; struct sdhci_host *host; struct esdhc_platform_data *boarddata; - struct clk *clk; int err; struct pltfm_imx_data *imx_data; @@ -460,14 +462,29 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) imx_data->devtype = pdev->id_entry->driver_data; pltfm_host->priv = imx_data; - clk = clk_get(mmc_dev(host->mmc), NULL); - if (IS_ERR(clk)) { - dev_err(mmc_dev(host->mmc), "clk err\n"); - err = PTR_ERR(clk); + imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(imx_data->clk_ipg)) { + err = PTR_ERR(imx_data->clk_ipg); goto err_clk_get; } - clk_prepare_enable(clk); - pltfm_host->clk = clk; + + imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(imx_data->clk_ahb)) { + err = PTR_ERR(imx_data->clk_ahb); + goto err_clk_get; + } + + imx_data->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(imx_data->clk_per)) { + err = PTR_ERR(imx_data->clk_per); + goto err_clk_get; + } + + pltfm_host->clk = imx_data->clk_per; + + clk_prepare_enable(imx_data->clk_per); + clk_prepare_enable(imx_data->clk_ipg); + clk_prepare_enable(imx_data->clk_ahb); imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev); if (IS_ERR(imx_data->pinctrl)) { @@ -567,8 +584,9 @@ no_card_detect_irq: no_card_detect_pin: no_board_data: pin_err: - clk_disable_unprepare(pltfm_host->clk); - clk_put(pltfm_host->clk); + clk_disable_unprepare(imx_data->clk_per); + clk_disable_unprepare(imx_data->clk_ipg); + clk_disable_unprepare(imx_data->clk_ahb); err_clk_get: kfree(imx_data); err_imx_data: @@ -594,8 +612,10 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev) gpio_free(boarddata->cd_gpio); } - clk_disable_unprepare(pltfm_host->clk); - clk_put(pltfm_host->clk); + clk_disable_unprepare(imx_data->clk_per); + clk_disable_unprepare(imx_data->clk_ipg); + clk_disable_unprepare(imx_data->clk_ahb); + kfree(imx_data); sdhci_pltfm_free(pdev); diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index cc0678a967c1..9e374e9bd296 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -690,7 +690,7 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) if (chip == -1) { /* Disable the NFC clock */ if (host->clk_act) { - clk_disable(host->clk); + clk_disable_unprepare(host->clk); host->clk_act = 0; } return; @@ -698,7 +698,7 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) if (!host->clk_act) { /* Enable the NFC clock */ - clk_enable(host->clk); + clk_prepare_enable(host->clk); host->clk_act = 1; } @@ -1078,7 +1078,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) goto eclk; } - clk_enable(host->clk); + clk_prepare_enable(host->clk); host->clk_act = 1; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 0f50ef38b87b..513dc88a05ca 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -17,6 +17,8 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> +#include <linux/clk.h> +#include <linux/err.h> #include <asm/io.h> #include <asm/sizes.h> #include <mach/hardware.h> @@ -79,6 +81,7 @@ static int __init orion_nand_probe(struct platform_device *pdev) struct nand_chip *nc; struct orion_nand_data *board; struct resource *res; + struct clk *clk; void __iomem *io_base; int ret = 0; u32 val = 0; @@ -155,6 +158,14 @@ static int __init orion_nand_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mtd); + /* Not all platforms can gate the clock, so it is not + an error if the clock does not exists. */ + clk = clk_get(&pdev->dev, NULL); + if (!IS_ERR(clk)) { + clk_prepare_enable(clk); + clk_put(clk); + } + if (nand_scan(mtd, 1)) { ret = -ENXIO; goto no_dev; @@ -184,6 +195,7 @@ static int __devexit orion_nand_remove(struct platform_device *pdev) { struct mtd_info *mtd = platform_get_drvdata(pdev); struct nand_chip *nc = mtd->priv; + struct clk *clk; nand_release(mtd); @@ -191,6 +203,12 @@ static int __devexit orion_nand_remove(struct platform_device *pdev) kfree(nc); + clk = clk_get(&pdev->dev, NULL); + if (!IS_ERR(clk)) { + clk_disable_unprepare(clk); + clk_put(clk); + } + return 0; } diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c index 8f2cf8c09e2d..ff7f4c5115a1 100644 --- a/drivers/net/ethernet/freescale/fec.c +++ b/drivers/net/ethernet/freescale/fec.c @@ -207,7 +207,8 @@ struct fec_enet_private { struct net_device *netdev; - struct clk *clk; + struct clk *clk_ipg; + struct clk *clk_ahb; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ unsigned char *tx_bounce[TX_RING_SIZE]; @@ -1065,7 +1066,7 @@ static int fec_enet_mii_init(struct platform_device *pdev) * Reference Manual has an error on this, and gets fixed on i.MX6Q * document. */ - fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000); + fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ahb), 5000000); if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) fep->phy_speed--; fep->phy_speed <<= 1; @@ -1618,12 +1619,20 @@ fec_probe(struct platform_device *pdev) goto failed_pin; } - fep->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(fep->clk)) { - ret = PTR_ERR(fep->clk); + fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(fep->clk_ipg)) { + ret = PTR_ERR(fep->clk_ipg); goto failed_clk; } - clk_prepare_enable(fep->clk); + + fep->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(fep->clk_ahb)) { + ret = PTR_ERR(fep->clk_ahb); + goto failed_clk; + } + + clk_prepare_enable(fep->clk_ahb); + clk_prepare_enable(fep->clk_ipg); ret = fec_enet_init(ndev); if (ret) @@ -1646,8 +1655,8 @@ failed_register: fec_enet_mii_remove(fep); failed_mii_init: failed_init: - clk_disable_unprepare(fep->clk); - clk_put(fep->clk); + clk_disable_unprepare(fep->clk_ahb); + clk_disable_unprepare(fep->clk_ipg); failed_pin: failed_clk: for (i = 0; i < FEC_IRQ_NUM; i++) { @@ -1680,8 +1689,8 @@ fec_drv_remove(struct platform_device *pdev) if (irq > 0) free_irq(irq, ndev); } - clk_disable_unprepare(fep->clk); - clk_put(fep->clk); + clk_disable_unprepare(fep->clk_ahb); + clk_disable_unprepare(fep->clk_ipg); iounmap(fep->hwp); free_netdev(ndev); @@ -1705,7 +1714,8 @@ fec_suspend(struct device *dev) fec_stop(ndev); netif_device_detach(ndev); } - clk_disable_unprepare(fep->clk); + clk_disable_unprepare(fep->clk_ahb); + clk_disable_unprepare(fep->clk_ipg); return 0; } @@ -1716,7 +1726,8 @@ fec_resume(struct device *dev) struct net_device *ndev = dev_get_drvdata(dev); struct fec_enet_private *fep = netdev_priv(ndev); - clk_prepare_enable(fep->clk); + clk_prepare_enable(fep->clk_ahb); + clk_prepare_enable(fep->clk_ipg); if (netif_running(ndev)) { fec_restart(ndev, fep->full_duplex); netif_device_attach(ndev); diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index c8950da60e6b..04d901d0ff63 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -57,6 +57,7 @@ #include <linux/types.h> #include <linux/inet_lro.h> #include <linux/slab.h> +#include <linux/clk.h> static char mv643xx_eth_driver_name[] = "mv643xx_eth"; static char mv643xx_eth_driver_version[] = "1.4"; @@ -289,10 +290,10 @@ struct mv643xx_eth_shared_private { /* * Hardware-specific parameters. */ - unsigned int t_clk; int extended_rx_coal_limit; int tx_bw_control; int tx_csum_limit; + }; #define TX_BW_CONTROL_ABSENT 0 @@ -431,6 +432,12 @@ struct mv643xx_eth_private { int tx_desc_sram_size; int txq_count; struct tx_queue txq[8]; + + /* + * Hardware-specific parameters. + */ + struct clk *clk; + unsigned int t_clk; }; @@ -1010,7 +1017,7 @@ static void tx_set_rate(struct mv643xx_eth_private *mp, int rate, int burst) int mtu; int bucket_size; - token_rate = ((rate / 1000) * 64) / (mp->shared->t_clk / 1000); + token_rate = ((rate / 1000) * 64) / (mp->t_clk / 1000); if (token_rate > 1023) token_rate = 1023; @@ -1042,7 +1049,7 @@ static void txq_set_rate(struct tx_queue *txq, int rate, int burst) int token_rate; int bucket_size; - token_rate = ((rate / 1000) * 64) / (mp->shared->t_clk / 1000); + token_rate = ((rate / 1000) * 64) / (mp->t_clk / 1000); if (token_rate > 1023) token_rate = 1023; @@ -1309,7 +1316,7 @@ static unsigned int get_rx_coal(struct mv643xx_eth_private *mp) temp = (val & 0x003fff00) >> 8; temp *= 64000000; - do_div(temp, mp->shared->t_clk); + do_div(temp, mp->t_clk); return (unsigned int)temp; } @@ -1319,7 +1326,7 @@ static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int usec) u64 temp; u32 val; - temp = (u64)usec * mp->shared->t_clk; + temp = (u64)usec * mp->t_clk; temp += 31999999; do_div(temp, 64000000); @@ -1345,7 +1352,7 @@ static unsigned int get_tx_coal(struct mv643xx_eth_private *mp) temp = (rdlp(mp, TX_FIFO_URGENT_THRESHOLD) & 0x3fff0) >> 4; temp *= 64000000; - do_div(temp, mp->shared->t_clk); + do_div(temp, mp->t_clk); return (unsigned int)temp; } @@ -1354,7 +1361,7 @@ static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int usec) { u64 temp; - temp = (u64)usec * mp->shared->t_clk; + temp = (u64)usec * mp->t_clk; temp += 31999999; do_div(temp, 64000000); @@ -2663,10 +2670,6 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) if (dram) mv643xx_eth_conf_mbus_windows(msp, dram); - /* - * Detect hardware parameters. - */ - msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000; msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ? pd->tx_csum_limit : 9 * 1024; infer_hw_params(msp); @@ -2891,6 +2894,18 @@ static int mv643xx_eth_probe(struct platform_device *pdev) mp->dev = dev; + /* + * Get the clk rate, if there is one, otherwise use the default. + */ + mp->clk = clk_get(&pdev->dev, (pdev->id ? "1" : "0")); + if (!IS_ERR(mp->clk)) { + clk_prepare_enable(mp->clk); + mp->t_clk = clk_get_rate(mp->clk); + } else { + mp->t_clk = 133000000; + printk(KERN_WARNING "Unable to get clock"); + } + set_params(mp, pd); netif_set_real_num_tx_queues(dev, mp->txq_count); netif_set_real_num_rx_queues(dev, mp->rxq_count); @@ -2979,6 +2994,11 @@ static int mv643xx_eth_remove(struct platform_device *pdev) if (mp->phy != NULL) phy_detach(mp->phy); cancel_work_sync(&mp->tx_timeout_task); + + if (!IS_ERR(mp->clk)) { + clk_disable_unprepare(mp->clk); + clk_put(mp->clk); + } free_netdev(mp->dev); platform_set_drvdata(pdev, NULL); diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index d93a9608b1f0..891cd6c61d0a 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -405,7 +405,7 @@ static int dryice_rtc_probe(struct platform_device *pdev) imxdi->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(imxdi->clk)) return PTR_ERR(imxdi->clk); - clk_enable(imxdi->clk); + clk_prepare_enable(imxdi->clk); /* * Initialize dryice hardware @@ -470,7 +470,7 @@ static int dryice_rtc_probe(struct platform_device *pdev) return 0; err: - clk_disable(imxdi->clk); + clk_disable_unprepare(imxdi->clk); clk_put(imxdi->clk); return rc; @@ -487,7 +487,7 @@ static int __devexit dryice_rtc_remove(struct platform_device *pdev) rtc_device_unregister(imxdi->rtc); - clk_disable(imxdi->clk); + clk_disable_unprepare(imxdi->clk); clk_put(imxdi->clk); return 0; diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 69c9a6601f45..47877d687614 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -86,7 +86,8 @@ struct spi_imx_data { struct completion xfer_done; void __iomem *base; int irq; - struct clk *clk; + struct clk *clk_per; + struct clk *clk_ipg; unsigned long spi_clk; unsigned int count; @@ -853,15 +854,22 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) goto out_free_irq; } - spi_imx->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(spi_imx->clk)) { - dev_err(&pdev->dev, "unable to get clock\n"); - ret = PTR_ERR(spi_imx->clk); + spi_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(spi_imx->clk_ipg)) { + ret = PTR_ERR(spi_imx->clk_ipg); goto out_free_irq; } - clk_enable(spi_imx->clk); - spi_imx->spi_clk = clk_get_rate(spi_imx->clk); + spi_imx->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(spi_imx->clk_per)) { + ret = PTR_ERR(spi_imx->clk_per); + goto out_free_irq; + } + + clk_prepare_enable(spi_imx->clk_per); + clk_prepare_enable(spi_imx->clk_ipg); + + spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per); spi_imx->devtype_data->reset(spi_imx); @@ -879,8 +887,8 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) return ret; out_clk_put: - clk_disable(spi_imx->clk); - clk_put(spi_imx->clk); + clk_disable_unprepare(spi_imx->clk_per); + clk_disable_unprepare(spi_imx->clk_ipg); out_free_irq: free_irq(spi_imx->irq, spi_imx); out_iounmap: @@ -908,8 +916,8 @@ static int __devexit spi_imx_remove(struct platform_device *pdev) spi_bitbang_stop(&spi_imx->bitbang); writel(0, spi_imx->base + MXC_CSPICTRL); - clk_disable(spi_imx->clk); - clk_put(spi_imx->clk); + clk_disable_unprepare(spi_imx->clk_per); + clk_disable_unprepare(spi_imx->clk_ipg); free_irq(spi_imx->irq, spi_imx); iounmap(spi_imx->base); diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index e496f799b7a9..dfd04e91fa6d 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -16,8 +16,8 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <linux/module.h> +#include <linux/clk.h> #include <asm/unaligned.h> #define DRIVER_NAME "orion_spi" @@ -46,6 +46,7 @@ struct orion_spi { unsigned int max_speed; unsigned int min_speed; struct orion_spi_info *spi_info; + struct clk *clk; }; static struct workqueue_struct *orion_spi_wq; @@ -104,7 +105,7 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed) orion_spi = spi_master_get_devdata(spi->master); - tclk_hz = orion_spi->spi_info->tclk; + tclk_hz = clk_get_rate(orion_spi->clk); /* * the supported rates are: 4,6,8...30 @@ -450,6 +451,7 @@ static int __init orion_spi_probe(struct platform_device *pdev) struct orion_spi *spi; struct resource *r; struct orion_spi_info *spi_info; + unsigned long tclk_hz; int status = 0; spi_info = pdev->dev.platform_data; @@ -476,19 +478,28 @@ static int __init orion_spi_probe(struct platform_device *pdev) spi->master = master; spi->spi_info = spi_info; - spi->max_speed = DIV_ROUND_UP(spi_info->tclk, 4); - spi->min_speed = DIV_ROUND_UP(spi_info->tclk, 30); + spi->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(spi->clk)) { + status = PTR_ERR(spi->clk); + goto out; + } + + clk_prepare(spi->clk); + clk_enable(spi->clk); + tclk_hz = clk_get_rate(spi->clk); + spi->max_speed = DIV_ROUND_UP(tclk_hz, 4); + spi->min_speed = DIV_ROUND_UP(tclk_hz, 30); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (r == NULL) { status = -ENODEV; - goto out; + goto out_rel_clk; } if (!request_mem_region(r->start, resource_size(r), dev_name(&pdev->dev))) { status = -EBUSY; - goto out; + goto out_rel_clk; } spi->base = ioremap(r->start, SZ_1K); @@ -508,7 +519,9 @@ static int __init orion_spi_probe(struct platform_device *pdev) out_rel_mem: release_mem_region(r->start, resource_size(r)); - +out_rel_clk: + clk_disable_unprepare(spi->clk); + clk_put(spi->clk); out: spi_master_put(master); return status; @@ -526,6 +539,9 @@ static int __exit orion_spi_remove(struct platform_device *pdev) cancel_work_sync(&spi->work); + clk_disable_unprepare(spi->clk); + clk_put(spi->clk); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(r->start, resource_size(r)); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index ec206732f68c..4ef747307ecb 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -205,7 +205,8 @@ struct imx_port { unsigned int irda_inv_rx:1; unsigned int irda_inv_tx:1; unsigned short trcv_delay; /* transceiver delay */ - struct clk *clk; + struct clk *clk_ipg; + struct clk *clk_per; struct imx_uart_data *devdata; }; @@ -673,7 +674,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) * RFDIV is set such way to satisfy requested uartclk value */ val = TXTL << 10 | RXTL; - ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2) + ufcr_rfdiv = (clk_get_rate(sport->clk_per) + sport->port.uartclk / 2) / sport->port.uartclk; if(!ufcr_rfdiv) @@ -1286,7 +1287,7 @@ imx_console_get_options(struct imx_port *sport, int *baud, else ucfr_rfdiv = 6 - ucfr_rfdiv; - uartclk = clk_get_rate(sport->clk); + uartclk = clk_get_rate(sport->clk_per); uartclk /= ucfr_rfdiv; { /* @@ -1511,14 +1512,22 @@ static int serial_imx_probe(struct platform_device *pdev) goto unmap; } - sport->clk = clk_get(&pdev->dev, "uart"); - if (IS_ERR(sport->clk)) { - ret = PTR_ERR(sport->clk); + sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(sport->clk_ipg)) { + ret = PTR_ERR(sport->clk_ipg); goto unmap; } - clk_prepare_enable(sport->clk); - sport->port.uartclk = clk_get_rate(sport->clk); + sport->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(sport->clk_per)) { + ret = PTR_ERR(sport->clk_per); + goto unmap; + } + + clk_prepare_enable(sport->clk_per); + clk_prepare_enable(sport->clk_ipg); + + sport->port.uartclk = clk_get_rate(sport->clk_per); imx_ports[sport->port.line] = sport; @@ -1539,8 +1548,8 @@ deinit: if (pdata && pdata->exit) pdata->exit(pdev); clkput: - clk_disable_unprepare(sport->clk); - clk_put(sport->clk); + clk_disable_unprepare(sport->clk_per); + clk_disable_unprepare(sport->clk_ipg); unmap: iounmap(sport->port.membase); free: @@ -1558,11 +1567,10 @@ static int serial_imx_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - if (sport) { - uart_remove_one_port(&imx_reg, &sport->port); - clk_disable_unprepare(sport->clk); - clk_put(sport->clk); - } + uart_remove_one_port(&imx_reg, &sport->port); + + clk_disable_unprepare(sport->clk_per); + clk_disable_unprepare(sport->clk_ipg); if (pdata && pdata->exit) pdata->exit(pdev); diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index a797d51ecbe8..c778ffe4e4e5 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -32,7 +32,7 @@ #define ULPI_VIEWPORT_OFFSET 0x170 struct ehci_mxc_priv { - struct clk *usbclk, *ahbclk, *phy1clk; + struct clk *usbclk, *ahbclk, *phyclk; struct usb_hcd *hcd; }; @@ -166,31 +166,26 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) } /* enable clocks */ - priv->usbclk = clk_get(dev, "usb"); + priv->usbclk = clk_get(dev, "ipg"); if (IS_ERR(priv->usbclk)) { ret = PTR_ERR(priv->usbclk); goto err_clk; } - clk_enable(priv->usbclk); + clk_prepare_enable(priv->usbclk); - if (!cpu_is_mx35() && !cpu_is_mx25()) { - priv->ahbclk = clk_get(dev, "usb_ahb"); - if (IS_ERR(priv->ahbclk)) { - ret = PTR_ERR(priv->ahbclk); - goto err_clk_ahb; - } - clk_enable(priv->ahbclk); + priv->ahbclk = clk_get(dev, "ahb"); + if (IS_ERR(priv->ahbclk)) { + ret = PTR_ERR(priv->ahbclk); + goto err_clk_ahb; } + clk_prepare_enable(priv->ahbclk); /* "dr" device has its own clock on i.MX51 */ - if (cpu_is_mx51() && (pdev->id == 0)) { - priv->phy1clk = clk_get(dev, "usb_phy1"); - if (IS_ERR(priv->phy1clk)) { - ret = PTR_ERR(priv->phy1clk); - goto err_clk_phy; - } - clk_enable(priv->phy1clk); - } + priv->phyclk = clk_get(dev, "phy"); + if (IS_ERR(priv->phyclk)) + priv->phyclk = NULL; + if (priv->phyclk) + clk_prepare_enable(priv->phyclk); /* call platform specific init function */ @@ -265,17 +260,15 @@ err_add: if (pdata && pdata->exit) pdata->exit(pdev); err_init: - if (priv->phy1clk) { - clk_disable(priv->phy1clk); - clk_put(priv->phy1clk); - } -err_clk_phy: - if (priv->ahbclk) { - clk_disable(priv->ahbclk); - clk_put(priv->ahbclk); + if (priv->phyclk) { + clk_disable_unprepare(priv->phyclk); + clk_put(priv->phyclk); } + + clk_disable_unprepare(priv->ahbclk); + clk_put(priv->ahbclk); err_clk_ahb: - clk_disable(priv->usbclk); + clk_disable_unprepare(priv->usbclk); clk_put(priv->usbclk); err_clk: iounmap(hcd->regs); @@ -307,15 +300,14 @@ static int __exit ehci_mxc_drv_remove(struct platform_device *pdev) usb_put_hcd(hcd); platform_set_drvdata(pdev, NULL); - clk_disable(priv->usbclk); + clk_disable_unprepare(priv->usbclk); clk_put(priv->usbclk); - if (priv->ahbclk) { - clk_disable(priv->ahbclk); - clk_put(priv->ahbclk); - } - if (priv->phy1clk) { - clk_disable(priv->phy1clk); - clk_put(priv->phy1clk); + clk_disable_unprepare(priv->ahbclk); + clk_put(priv->ahbclk); + + if (priv->phyclk) { + clk_disable_unprepare(priv->phyclk); + clk_put(priv->phyclk); } kfree(priv); diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 6c6a5a3b4ea7..82de1073aa52 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/mbus.h> +#include <linux/clk.h> #include <plat/ehci-orion.h> #define rdl(off) __raw_readl(hcd->regs + (off)) @@ -198,6 +199,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev) struct resource *res; struct usb_hcd *hcd; struct ehci_hcd *ehci; + struct clk *clk; void __iomem *regs; int irq, err; @@ -238,6 +240,14 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev) goto err2; } + /* Not all platforms can gate the clock, so it is not + an error if the clock does not exists. */ + clk = clk_get(&pdev->dev, NULL); + if (!IS_ERR(clk)) { + clk_prepare_enable(clk); + clk_put(clk); + } + hcd = usb_create_hcd(&ehci_orion_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { @@ -301,12 +311,18 @@ err1: static int __exit ehci_orion_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct clk *clk; usb_remove_hcd(hcd); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); + clk = clk_get(&pdev->dev, NULL); + if (!IS_ERR(clk)) { + clk_disable_unprepare(clk); + clk_put(clk); + } return 0; } diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index f135dbead07d..caad3689b4e6 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -131,7 +131,9 @@ struct imxfb_rgb { struct imxfb_info { struct platform_device *pdev; void __iomem *regs; - struct clk *clk; + struct clk *clk_ipg; + struct clk *clk_ahb; + struct clk *clk_per; /* * These are the addresses we mapped @@ -340,7 +342,7 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel); - lcd_clk = clk_get_rate(fbi->clk); + lcd_clk = clk_get_rate(fbi->clk_per); tmp = var->pixclock * (unsigned long long)lcd_clk; @@ -455,11 +457,17 @@ static int imxfb_bl_update_status(struct backlight_device *bl) fbi->pwmr = (fbi->pwmr & ~0xFF) | brightness; - if (bl->props.fb_blank != FB_BLANK_UNBLANK) - clk_enable(fbi->clk); + if (bl->props.fb_blank != FB_BLANK_UNBLANK) { + clk_prepare_enable(fbi->clk_ipg); + clk_prepare_enable(fbi->clk_ahb); + clk_prepare_enable(fbi->clk_per); + } writel(fbi->pwmr, fbi->regs + LCDC_PWMR); - if (bl->props.fb_blank != FB_BLANK_UNBLANK) - clk_disable(fbi->clk); + if (bl->props.fb_blank != FB_BLANK_UNBLANK) { + clk_disable_unprepare(fbi->clk_per); + clk_disable_unprepare(fbi->clk_ahb); + clk_disable_unprepare(fbi->clk_ipg); + } return 0; } @@ -522,7 +530,9 @@ static void imxfb_enable_controller(struct imxfb_info *fbi) */ writel(RMCR_LCDC_EN_MX1, fbi->regs + LCDC_RMCR); - clk_enable(fbi->clk); + clk_prepare_enable(fbi->clk_ipg); + clk_prepare_enable(fbi->clk_ahb); + clk_prepare_enable(fbi->clk_per); if (fbi->backlight_power) fbi->backlight_power(1); @@ -539,7 +549,9 @@ static void imxfb_disable_controller(struct imxfb_info *fbi) if (fbi->lcd_power) fbi->lcd_power(0); - clk_disable(fbi->clk); + clk_disable_unprepare(fbi->clk_per); + clk_disable_unprepare(fbi->clk_ipg); + clk_disable_unprepare(fbi->clk_ahb); writel(0, fbi->regs + LCDC_RMCR); } @@ -770,10 +782,21 @@ static int __init imxfb_probe(struct platform_device *pdev) goto failed_req; } - fbi->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(fbi->clk)) { - ret = PTR_ERR(fbi->clk); - dev_err(&pdev->dev, "unable to get clock: %d\n", ret); + fbi->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(fbi->clk_ipg)) { + ret = PTR_ERR(fbi->clk_ipg); + goto failed_getclock; + } + + fbi->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(fbi->clk_ahb)) { + ret = PTR_ERR(fbi->clk_ahb); + goto failed_getclock; + } + + fbi->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(fbi->clk_per)) { + ret = PTR_ERR(fbi->clk_per); goto failed_getclock; } @@ -858,7 +881,6 @@ failed_platform_init: failed_map: iounmap(fbi->regs); failed_ioremap: - clk_put(fbi->clk); failed_getclock: release_mem_region(res->start, resource_size(res)); failed_req: @@ -895,8 +917,6 @@ static int __devexit imxfb_remove(struct platform_device *pdev) iounmap(fbi->regs); release_mem_region(res->start, resource_size(res)); - clk_disable(fbi->clk); - clk_put(fbi->clk); platform_set_drvdata(pdev, NULL); diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index a3b6a74c67a7..1cc61a700fa8 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -138,7 +138,7 @@ static int __devinit mxc_w1_probe(struct platform_device *pdev) goto failed_ioremap; } - clk_enable(mdev->clk); + clk_prepare_enable(mdev->clk); __raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER); mdev->bus_master.data = mdev; @@ -178,7 +178,7 @@ static int __devexit mxc_w1_remove(struct platform_device *pdev) iounmap(mdev->regs); release_mem_region(res->start, resource_size(res)); - clk_disable(mdev->clk); + clk_disable_unprepare(mdev->clk); clk_put(mdev->clk); platform_set_drvdata(pdev, NULL); diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index 7a2b734fcdc7..bcfab2b00ad2 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c @@ -121,7 +121,7 @@ static void imx2_wdt_start(void) { if (!test_and_set_bit(IMX2_WDT_STATUS_STARTED, &imx2_wdt.status)) { /* at our first start we enable clock and do initialisations */ - clk_enable(imx2_wdt.clk); + clk_prepare_enable(imx2_wdt.clk); imx2_wdt_setup(); } else /* delete the timer that pings the watchdog after close */ diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index 788aa158e78c..0f5736949c61 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -24,8 +24,8 @@ #include <linux/uaccess.h> #include <linux/io.h> #include <linux/spinlock.h> +#include <linux/clk.h> #include <mach/bridge-regs.h> -#include <plat/orion_wdt.h> /* * Watchdog timer block registers. @@ -41,6 +41,7 @@ static bool nowayout = WATCHDOG_NOWAYOUT; static int heartbeat = -1; /* module parameter (seconds) */ static unsigned int wdt_max_duration; /* (seconds) */ +static struct clk *clk; static unsigned int wdt_tclk; static void __iomem *wdt_reg; static unsigned long wdt_status; @@ -237,16 +238,16 @@ static struct miscdevice orion_wdt_miscdev = { static int __devinit orion_wdt_probe(struct platform_device *pdev) { - struct orion_wdt_platform_data *pdata = pdev->dev.platform_data; struct resource *res; int ret; - if (pdata) { - wdt_tclk = pdata->tclk; - } else { - pr_err("misses platform data\n"); + clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + printk(KERN_ERR "Orion Watchdog missing clock\n"); return -ENODEV; } + clk_prepare_enable(clk); + wdt_tclk = clk_get_rate(clk); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -282,6 +283,9 @@ static int __devexit orion_wdt_remove(struct platform_device *pdev) if (!ret) orion_wdt_miscdev.parent = NULL; + clk_disable_unprepare(clk); + clk_put(clk); + return ret; } diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 5e4312b6f5cc..eb3f84bc5325 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -30,7 +30,7 @@ struct clk { const struct clk_ops *ops; struct clk_hw *hw; struct clk *parent; - char **parent_names; + const char **parent_names; struct clk **parents; u8 num_parents; unsigned long rate; @@ -55,12 +55,22 @@ struct clk { * alternative macro for static initialization */ -extern struct clk_ops clk_fixed_rate_ops; +#define DEFINE_CLK(_name, _ops, _flags, _parent_names, \ + _parents) \ + static struct clk _name = { \ + .name = #_name, \ + .ops = &_ops, \ + .hw = &_name##_hw.hw, \ + .parent_names = _parent_names, \ + .num_parents = ARRAY_SIZE(_parent_names), \ + .parents = _parents, \ + .flags = _flags, \ + } #define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \ _fixed_rate_flags) \ static struct clk _name; \ - static char *_name##_parent_names[] = {}; \ + static const char *_name##_parent_names[] = {}; \ static struct clk_fixed_rate _name##_hw = { \ .hw = { \ .clk = &_name, \ @@ -68,23 +78,14 @@ extern struct clk_ops clk_fixed_rate_ops; .fixed_rate = _rate, \ .flags = _fixed_rate_flags, \ }; \ - static struct clk _name = { \ - .name = #_name, \ - .ops = &clk_fixed_rate_ops, \ - .hw = &_name##_hw.hw, \ - .parent_names = _name##_parent_names, \ - .num_parents = \ - ARRAY_SIZE(_name##_parent_names), \ - .flags = _flags, \ - }; - -extern struct clk_ops clk_gate_ops; + DEFINE_CLK(_name, clk_fixed_rate_ops, _flags, \ + _name##_parent_names, NULL); #define DEFINE_CLK_GATE(_name, _parent_name, _parent_ptr, \ _flags, _reg, _bit_idx, \ _gate_flags, _lock) \ static struct clk _name; \ - static char *_name##_parent_names[] = { \ + static const char *_name##_parent_names[] = { \ _parent_name, \ }; \ static struct clk *_name##_parents[] = { \ @@ -99,24 +100,14 @@ extern struct clk_ops clk_gate_ops; .flags = _gate_flags, \ .lock = _lock, \ }; \ - static struct clk _name = { \ - .name = #_name, \ - .ops = &clk_gate_ops, \ - .hw = &_name##_hw.hw, \ - .parent_names = _name##_parent_names, \ - .num_parents = \ - ARRAY_SIZE(_name##_parent_names), \ - .parents = _name##_parents, \ - .flags = _flags, \ - }; - -extern struct clk_ops clk_divider_ops; + DEFINE_CLK(_name, clk_gate_ops, _flags, \ + _name##_parent_names, _name##_parents); #define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \ _flags, _reg, _shift, _width, \ _divider_flags, _lock) \ static struct clk _name; \ - static char *_name##_parent_names[] = { \ + static const char *_name##_parent_names[] = { \ _parent_name, \ }; \ static struct clk *_name##_parents[] = { \ @@ -132,18 +123,8 @@ extern struct clk_ops clk_divider_ops; .flags = _divider_flags, \ .lock = _lock, \ }; \ - static struct clk _name = { \ - .name = #_name, \ - .ops = &clk_divider_ops, \ - .hw = &_name##_hw.hw, \ - .parent_names = _name##_parent_names, \ - .num_parents = \ - ARRAY_SIZE(_name##_parent_names), \ - .parents = _name##_parents, \ - .flags = _flags, \ - }; - -extern struct clk_ops clk_mux_ops; + DEFINE_CLK(_name, clk_divider_ops, _flags, \ + _name##_parent_names, _name##_parents); #define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \ _reg, _shift, _width, \ @@ -159,16 +140,28 @@ extern struct clk_ops clk_mux_ops; .flags = _mux_flags, \ .lock = _lock, \ }; \ - static struct clk _name = { \ - .name = #_name, \ - .ops = &clk_mux_ops, \ - .hw = &_name##_hw.hw, \ - .parent_names = _parent_names, \ - .num_parents = \ - ARRAY_SIZE(_parent_names), \ - .parents = _parents, \ - .flags = _flags, \ - }; + DEFINE_CLK(_name, clk_mux_ops, _flags, _parent_names, \ + _parents); + +#define DEFINE_CLK_FIXED_FACTOR(_name, _parent_name, \ + _parent_ptr, _flags, \ + _mult, _div) \ + static struct clk _name; \ + static const char *_name##_parent_names[] = { \ + _parent_name, \ + }; \ + static struct clk *_name##_parents[] = { \ + _parent_ptr, \ + }; \ + static struct clk_fixed_factor _name##_hw = { \ + .hw = { \ + .clk = &_name, \ + }, \ + .mult = _mult, \ + .div = _div, \ + }; \ + DEFINE_CLK(_name, clk_fixed_factor_ops, _flags, \ + _name##_parent_names, _name##_parents); /** * __clk_init - initialize the data structures in a struct clk @@ -189,8 +182,12 @@ extern struct clk_ops clk_mux_ops; * * It is not necessary to call clk_register if __clk_init is used directly with * statically initialized clock data. + * + * Returns 0 on success, otherwise an error code. */ -void __clk_init(struct device *dev, struct clk *clk); +int __clk_init(struct device *dev, struct clk *clk); + +struct clk *__clk_register(struct device *dev, struct clk_hw *hw); #endif /* CONFIG_COMMON_CLK */ #endif /* CLK_PRIVATE_H */ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 5508897ad376..4a0b483986c3 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -15,19 +15,6 @@ #ifdef CONFIG_COMMON_CLK -/** - * struct clk_hw - handle for traversing from a struct clk to its corresponding - * hardware-specific structure. struct clk_hw should be declared within struct - * clk_foo and then referenced by the struct clk instance that uses struct - * clk_foo's clk_ops - * - * clk: pointer to the struct clk instance that points back to this struct - * clk_hw instance - */ -struct clk_hw { - struct clk *clk; -}; - /* * flags used across common struct clk. these flags should only affect the * top-level framework. custom flags for dealing with hardware specifics @@ -39,6 +26,8 @@ struct clk_hw { #define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */ #define CLK_IS_ROOT BIT(4) /* root clk, has no parent */ +struct clk_hw; + /** * struct clk_ops - Callback operations for hardware clocks; these are to * be provided by the clock implementation, and will be called by drivers @@ -88,19 +77,11 @@ struct clk_hw { * array index into the value programmed into the hardware. * Returns 0 on success, -EERROR otherwise. * - * @set_rate: Change the rate of this clock. If this callback returns - * CLK_SET_RATE_PARENT, the rate change will be propagated to the - * parent clock (which may propagate again if the parent clock - * also sets this flag). The requested rate of the parent is - * passed back from the callback in the second 'unsigned long *' - * argument. Note that it is up to the hardware clock's set_rate - * implementation to insure that clocks do not run out of spec - * when propgating the call to set_rate up to the parent. One way - * to do this is to gate the clock (via clk_disable and/or - * clk_unprepare) before calling clk_set_rate, then ungating it - * afterward. If your clock also has the CLK_GATE_SET_RATE flag - * set then this will insure safety. Returns 0 on success, - * -EERROR otherwise. + * @set_rate: Change the rate of this clock. The requested rate is specified + * by the second argument, which should typically be the return + * of .round_rate call. The third argument gives the parent rate + * which is likely helpful for most .set_rate implementation. + * Returns 0 on success, -EERROR otherwise. * * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow * implementations to split any work between atomic (enable) and sleepable @@ -125,10 +106,46 @@ struct clk_ops { unsigned long *); int (*set_parent)(struct clk_hw *hw, u8 index); u8 (*get_parent)(struct clk_hw *hw); - int (*set_rate)(struct clk_hw *hw, unsigned long); + int (*set_rate)(struct clk_hw *hw, unsigned long, + unsigned long); void (*init)(struct clk_hw *hw); }; +/** + * struct clk_init_data - holds init data that's common to all clocks and is + * shared between the clock provider and the common clock framework. + * + * @name: clock name + * @ops: operations this clock supports + * @parent_names: array of string names for all possible parents + * @num_parents: number of possible parents + * @flags: framework-level hints and quirks + */ +struct clk_init_data { + const char *name; + const struct clk_ops *ops; + const char **parent_names; + u8 num_parents; + unsigned long flags; +}; + +/** + * struct clk_hw - handle for traversing from a struct clk to its corresponding + * hardware-specific structure. struct clk_hw should be declared within struct + * clk_foo and then referenced by the struct clk instance that uses struct + * clk_foo's clk_ops + * + * @clk: pointer to the struct clk instance that points back to this struct + * clk_hw instance + * + * @init: pointer to struct clk_init_data that contains the init data shared + * with the common clock framework. + */ +struct clk_hw { + struct clk *clk; + struct clk_init_data *init; +}; + /* * DOC: Basic clock implementations common to many platforms * @@ -149,6 +166,7 @@ struct clk_fixed_rate { u8 flags; }; +extern const struct clk_ops clk_fixed_rate_ops; struct clk *clk_register_fixed_rate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned long fixed_rate); @@ -165,7 +183,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, * Clock which can gate its output. Implements .enable & .disable * * Flags: - * CLK_GATE_SET_DISABLE - by default this clock sets the bit at bit_idx to + * CLK_GATE_SET_TO_DISABLE - by default this clock sets the bit at bit_idx to * enable the clock. Setting this flag does the opposite: setting the bit * disable the clock and clearing it enables the clock */ @@ -175,11 +193,11 @@ struct clk_gate { u8 bit_idx; u8 flags; spinlock_t *lock; - char *parent[1]; }; #define CLK_GATE_SET_TO_DISABLE BIT(0) +extern const struct clk_ops clk_gate_ops; struct clk *clk_register_gate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, @@ -212,12 +230,12 @@ struct clk_divider { u8 width; u8 flags; spinlock_t *lock; - char *parent[1]; }; #define CLK_DIVIDER_ONE_BASED BIT(0) #define CLK_DIVIDER_POWER_OF_TWO BIT(1) +extern const struct clk_ops clk_divider_ops; struct clk *clk_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, @@ -238,7 +256,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name, * * Flags: * CLK_MUX_INDEX_ONE - register index starts at 1, not 0 - * CLK_MUX_INDEX_BITWISE - register index is a single bit (power of two) + * CLK_MUX_INDEX_BIT - register index is a single bit (power of two) */ struct clk_mux { struct clk_hw hw; @@ -252,29 +270,49 @@ struct clk_mux { #define CLK_MUX_INDEX_ONE BIT(0) #define CLK_MUX_INDEX_BIT BIT(1) +extern const struct clk_ops clk_mux_ops; struct clk *clk_register_mux(struct device *dev, const char *name, - char **parent_names, u8 num_parents, unsigned long flags, + const char **parent_names, u8 num_parents, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_mux_flags, spinlock_t *lock); /** + * struct clk_fixed_factor - fixed multiplier and divider clock + * + * @hw: handle between common and hardware-specific interfaces + * @mult: multiplier + * @div: divider + * + * Clock with a fixed multiplier and divider. The output frequency is the + * parent clock rate divided by div and multiplied by mult. + * Implements .recalc_rate, .set_rate and .round_rate + */ + +struct clk_fixed_factor { + struct clk_hw hw; + unsigned int mult; + unsigned int div; +}; + +extern struct clk_ops clk_fixed_factor_ops; +struct clk *clk_register_fixed_factor(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + unsigned int mult, unsigned int div); + +/** * clk_register - allocate a new clock, register it and return an opaque cookie * @dev: device that is registering this clock - * @name: clock name - * @ops: operations this clock supports * @hw: link to hardware-specific clock data - * @parent_names: array of string names for all possible parents - * @num_parents: number of possible parents - * @flags: framework-level hints and quirks * * clk_register is the primary interface for populating the clock tree with new * clock nodes. It returns a pointer to the newly allocated struct clk which * cannot be dereferenced by driver code but may be used in conjuction with the - * rest of the clock API. + * rest of the clock API. In the event of an error clk_register will return an + * error code; drivers must test for an error code after calling clk_register. */ -struct clk *clk_register(struct device *dev, const char *name, - const struct clk_ops *ops, struct clk_hw *hw, - char **parent_names, u8 num_parents, unsigned long flags); +struct clk *clk_register(struct device *dev, struct clk_hw *hw); + +void clk_unregister(struct clk *clk); /* helper functions */ const char *__clk_get_name(struct clk *clk); diff --git a/include/linux/clk.h b/include/linux/clk.h index 70cf722ac3af..ad5c43e8ae8a 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -81,7 +81,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb); int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); -#endif /* !CONFIG_COMMON_CLK */ +#endif /** * clk_get - lookup and obtain a reference to a clock producer. @@ -252,7 +252,7 @@ void devm_clk_put(struct device *dev, struct clk *clk); * Returns rounded clock rate in Hz, or negative errno. */ long clk_round_rate(struct clk *clk, unsigned long rate); - + /** * clk_set_rate - set the clock rate for a clock source * @clk: clock source @@ -261,7 +261,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate); * Returns success (0) or negative errno. */ int clk_set_rate(struct clk *clk, unsigned long rate); - + /** * clk_set_parent - set the parent clock source for this clock * @clk: clock source diff --git a/include/linux/mv643xx_eth.h b/include/linux/mv643xx_eth.h index 30b0c4e78f91..51bf8ada6dc0 100644 --- a/include/linux/mv643xx_eth.h +++ b/include/linux/mv643xx_eth.h @@ -18,7 +18,6 @@ struct mv643xx_eth_shared_platform_data { struct mbus_dram_target_info *dram; struct platform_device *shared_smi; - unsigned int t_clk; /* * Max packet size for Tx IP/Layer 4 checksum, when set to 0, default * limit of 9KiB will be used. diff --git a/include/linux/spi/orion_spi.h b/include/linux/spi/orion_spi.h deleted file mode 100644 index b4d9fa6f797c..000000000000 --- a/include/linux/spi/orion_spi.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * orion_spi.h - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __LINUX_SPI_ORION_SPI_H -#define __LINUX_SPI_ORION_SPI_H - -struct orion_spi_info { - u32 tclk; /* no <linux/clk.h> support yet */ -}; - - -#endif diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 3cb9aa4299d3..fa4556750451 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/mbus.h> #include <linux/delay.h> +#include <linux/clk.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -449,6 +450,14 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev) priv->burst = data->burst; + priv->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "no clock\n"); + err = PTR_ERR(priv->clk); + goto err_ioremap; + } + clk_prepare_enable(priv->clk); + return snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai); err_ioremap: @@ -466,6 +475,10 @@ static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev) struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); + + clk_disable_unprepare(priv->clk); + clk_put(priv->clk); + iounmap(priv->io); release_mem_region(priv->mem->start, SZ_16K); kfree(priv); diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h index 9047436b3937..f9084d83e6bd 100644 --- a/sound/soc/kirkwood/kirkwood.h +++ b/sound/soc/kirkwood/kirkwood.h @@ -123,6 +123,7 @@ struct kirkwood_dma_data { void __iomem *io; int irq; int burst; + struct clk *clk; }; #endif |