summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-02-21 12:30:30 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-21 12:30:30 -0800
commit18a8d49973667aa016e68826eeb374788b7c63b0 (patch)
treed7f90fcf05087ce50ee931b596e60e4c3c082a29 /drivers
parentc189cb8ef62832f33b6cf757350a0270532a1ad8 (diff)
parentec02ace8ca0a50eef430d3676de5c5fa978b0e29 (diff)
downloadlinux-18a8d49973667aa016e68826eeb374788b7c63b0.tar.bz2
Merge tag 'clk-for-linus-3.20' of git://git.linaro.org/people/mike.turquette/linux
Pull clock framework updates from Mike Turquette: "The clock framework changes contain the usual driver additions, enhancements and fixes mostly for ARM32, ARM64, MIPS and Power-based devices. Additionally the framework core underwent a bit of surgery with two major changes: - The boundary between the clock core and clock providers (e.g clock drivers) is now more well defined with dedicated provider helper functions. struct clk no longer maps 1:1 with the hardware clock but is a true per-user cookie which helps us tracker users of hardware clocks and debug bad behavior. - The addition of rate constraints for clocks. Rate ranges are now supported which are analogous to the voltage ranges in the regulator framework. Unfortunately these changes to the core created some breakeage. We think we fixed it all up but for this reason there are lots of last minute commits trying to undo the damage" * tag 'clk-for-linus-3.20' of git://git.linaro.org/people/mike.turquette/linux: (113 commits) clk: Only recalculate the rate if needed Revert "clk: mxs: Fix invalid 32-bit access to frac registers" clk: qoriq: Add support for the platform PLL powerpc/corenet: Enable CLK_QORIQ clk: Replace explicit clk assignment with __clk_hw_set_clk clk: Add __clk_hw_set_clk helper function clk: Don't dereference parent clock if is NULL MIPS: Alchemy: Remove bogus args from alchemy_clk_fgcs_detr clkdev: Always allocate a struct clk and call __clk_get() w/ CCF clk: shmobile: div6: Avoid division by zero in .round_rate() clk: mxs: Fix invalid 32-bit access to frac registers clk: omap: compile legacy omap3 clocks conditionally clkdev: Export clk_register_clkdev clk: Add rate constraints to clocks clk: remove clk-private.h pci: xgene: do not use clk-private.h arm: omap2+ remove dead clock code clk: Make clk API return per-user struct clk instances clk: tegra: Define PLLD_DSI and remove dsia(b)_mux clk: tegra: Add support for the Tegra132 CAR IP block ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/Kconfig18
-rw-r--r--drivers/clk/Makefile4
-rw-r--r--drivers/clk/at91/clk-programmable.c2
-rw-r--r--drivers/clk/bcm/clk-kona.c2
-rw-r--r--drivers/clk/clk-asm9260.c348
-rw-r--r--drivers/clk/clk-cdce706.c700
-rw-r--r--drivers/clk/clk-composite.c29
-rw-r--r--drivers/clk/clk-divider.c228
-rw-r--r--drivers/clk/clk-gate.c18
-rw-r--r--drivers/clk/clk-mux.c16
-rw-r--r--drivers/clk/clk-qoriq.c (renamed from drivers/clk/clk-ppc-corenet.c)178
-rw-r--r--drivers/clk/clk.c1009
-rw-r--r--drivers/clk/clk.h24
-rw-r--r--drivers/clk/clkdev.c110
-rw-r--r--drivers/clk/hisilicon/clk-hi3620.c2
-rw-r--r--drivers/clk/mmp/clk-mix.c2
-rw-r--r--drivers/clk/pxa/Makefile1
-rw-r--r--drivers/clk/pxa/clk-pxa.c2
-rw-r--r--drivers/clk/pxa/clk-pxa3xx.c364
-rw-r--r--drivers/clk/qcom/Kconfig18
-rw-r--r--drivers/clk/qcom/Makefile4
-rw-r--r--drivers/clk/qcom/clk-pll.c1
-rw-r--r--drivers/clk/qcom/clk-rcg.c10
-rw-r--r--drivers/clk/qcom/clk-rcg2.c6
-rw-r--r--drivers/clk/qcom/clk-regmap-divider.c70
-rw-r--r--drivers/clk/qcom/clk-regmap-divider.h29
-rw-r--r--drivers/clk/qcom/clk-regmap-mux.c59
-rw-r--r--drivers/clk/qcom/clk-regmap-mux.h29
-rw-r--r--drivers/clk/qcom/gcc-ipq806x.c12
-rw-r--r--drivers/clk/qcom/lcc-ipq806x.c473
-rw-r--r--drivers/clk/qcom/lcc-msm8960.c585
-rw-r--r--drivers/clk/rockchip/clk-rk3288.c48
-rw-r--r--drivers/clk/samsung/clk-exynos-audss.c32
-rw-r--r--drivers/clk/samsung/clk-exynos3250.c217
-rw-r--r--drivers/clk/samsung/clk-exynos4.c10
-rw-r--r--drivers/clk/samsung/clk-exynos4415.c216
-rw-r--r--drivers/clk/samsung/clk-exynos7.c408
-rw-r--r--drivers/clk/samsung/clk.c13
-rw-r--r--drivers/clk/samsung/clk.h3
-rw-r--r--drivers/clk/shmobile/Makefile2
-rw-r--r--drivers/clk/shmobile/clk-div6.c18
-rw-r--r--drivers/clk/shmobile/clk-r8a73a4.c241
-rw-r--r--drivers/clk/shmobile/clk-rcar-gen2.c88
-rw-r--r--drivers/clk/st/clk-flexgen.c39
-rw-r--r--drivers/clk/st/clkgen-mux.c14
-rw-r--r--drivers/clk/sunxi/Makefile1
-rw-r--r--drivers/clk/sunxi/clk-factors.c12
-rw-r--r--drivers/clk/sunxi/clk-factors.h7
-rw-r--r--drivers/clk/sunxi/clk-mod0.c224
-rw-r--r--drivers/clk/sunxi/clk-sun6i-ar100.c2
-rw-r--r--drivers/clk/sunxi/clk-sun8i-mbus.c13
-rw-r--r--drivers/clk/sunxi/clk-sun9i-core.c119
-rw-r--r--drivers/clk/sunxi/clk-sun9i-mmc.c219
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c262
-rw-r--r--drivers/clk/tegra/Makefile1
-rw-r--r--drivers/clk/tegra/clk-id.h2
-rw-r--r--drivers/clk/tegra/clk-periph.c14
-rw-r--r--drivers/clk/tegra/clk-pll.c18
-rw-r--r--drivers/clk/tegra/clk-tegra-periph.c18
-rw-r--r--drivers/clk/tegra/clk-tegra114.c10
-rw-r--r--drivers/clk/tegra/clk-tegra124.c168
-rw-r--r--drivers/clk/tegra/clk.c7
-rw-r--r--drivers/clk/ti/Makefile8
-rw-r--r--drivers/clk/ti/clk-3xxx-legacy.c4653
-rw-r--r--drivers/clk/ti/clk-3xxx.c8
-rw-r--r--drivers/clk/ti/clk-44xx.c2
-rw-r--r--drivers/clk/ti/clk-54xx.c2
-rw-r--r--drivers/clk/ti/clk-7xx.c2
-rw-r--r--drivers/clk/ti/clk-816x.c53
-rw-r--r--drivers/clk/ti/clk.c127
-rw-r--r--drivers/clk/ti/clock.h172
-rw-r--r--drivers/clk/ti/composite.c48
-rw-r--r--drivers/clk/ti/divider.c132
-rw-r--r--drivers/clk/ti/dpll.c121
-rw-r--r--drivers/clk/ti/fapll.c410
-rw-r--r--drivers/clk/ti/gate.c163
-rw-r--r--drivers/clk/ti/interface.c98
-rw-r--r--drivers/clk/ti/mux.c70
-rw-r--r--drivers/clk/ux500/clk-prcc.c1
-rw-r--r--drivers/clk/ux500/clk-prcmu.c1
-rw-r--r--drivers/clk/zynq/clkc.c1
-rw-r--r--drivers/cpufreq/Kconfig.powerpc2
-rw-r--r--drivers/mmc/host/sunxi-mmc.c63
83 files changed, 11729 insertions, 1207 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 91f86131bb7a..0b474a04730f 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -102,12 +102,12 @@ config COMMON_CLK_AXI_CLKGEN
Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx
FPGAs. It is commonly used in Analog Devices' reference designs.
-config CLK_PPC_CORENET
- bool "Clock driver for PowerPC corenet platforms"
- depends on PPC_E500MC && OF
+config CLK_QORIQ
+ bool "Clock driver for Freescale QorIQ platforms"
+ depends on (PPC_E500MC || ARM) && OF
---help---
- This adds the clock driver support for Freescale PowerPC corenet
- platforms using common clock framework.
+ This adds the clock driver support for Freescale QorIQ platforms
+ using common clock framework.
config COMMON_CLK_XGENE
bool "Clock driver for APM XGene SoC"
@@ -135,6 +135,14 @@ config COMMON_CLK_PXA
---help---
Sypport for the Marvell PXA SoC.
+config COMMON_CLK_CDCE706
+ tristate "Clock driver for TI CDCE706 clock synthesizer"
+ depends on I2C
+ select REGMAP_I2C
+ select RATIONAL
+ ---help---
+ This driver supports TI CDCE706 programmable 3-PLL clock synthesizer.
+
source "drivers/clk/qcom/Kconfig"
endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index d5fba5bc6e1b..d478ceb69c5f 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -16,9 +16,11 @@ endif
# hardware specific clock types
# please keep this section sorted lexicographically by file/directory path name
+obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
+obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
@@ -30,7 +32,7 @@ obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
-obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o
+obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o
obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
index bbdb1b985c91..86c8a073dcc3 100644
--- a/drivers/clk/at91/clk-programmable.c
+++ b/drivers/clk/at91/clk-programmable.c
@@ -56,6 +56,8 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
static long clk_programmable_determine_rate(struct clk_hw *hw,
unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_hw)
{
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index 1c06f6f3a8c5..05abae89262e 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -1032,6 +1032,8 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate,
}
static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate, struct clk_hw **best_parent)
{
struct kona_clk *bcm_clk = to_kona_clk(hw);
diff --git a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c
new file mode 100644
index 000000000000..88f4ff6916fe
--- /dev/null
+++ b/drivers/clk/clk-asm9260.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2014 Oleksij Rempel <linux@rempel-privat.de>.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <dt-bindings/clock/alphascale,asm9260.h>
+
+#define HW_AHBCLKCTRL0 0x0020
+#define HW_AHBCLKCTRL1 0x0030
+#define HW_SYSPLLCTRL 0x0100
+#define HW_MAINCLKSEL 0x0120
+#define HW_MAINCLKUEN 0x0124
+#define HW_UARTCLKSEL 0x0128
+#define HW_UARTCLKUEN 0x012c
+#define HW_I2S0CLKSEL 0x0130
+#define HW_I2S0CLKUEN 0x0134
+#define HW_I2S1CLKSEL 0x0138
+#define HW_I2S1CLKUEN 0x013c
+#define HW_WDTCLKSEL 0x0160
+#define HW_WDTCLKUEN 0x0164
+#define HW_CLKOUTCLKSEL 0x0170
+#define HW_CLKOUTCLKUEN 0x0174
+#define HW_CPUCLKDIV 0x017c
+#define HW_SYSAHBCLKDIV 0x0180
+#define HW_I2S0MCLKDIV 0x0190
+#define HW_I2S0SCLKDIV 0x0194
+#define HW_I2S1MCLKDIV 0x0188
+#define HW_I2S1SCLKDIV 0x018c
+#define HW_UART0CLKDIV 0x0198
+#define HW_UART1CLKDIV 0x019c
+#define HW_UART2CLKDIV 0x01a0
+#define HW_UART3CLKDIV 0x01a4
+#define HW_UART4CLKDIV 0x01a8
+#define HW_UART5CLKDIV 0x01ac
+#define HW_UART6CLKDIV 0x01b0
+#define HW_UART7CLKDIV 0x01b4
+#define HW_UART8CLKDIV 0x01b8
+#define HW_UART9CLKDIV 0x01bc
+#define HW_SPI0CLKDIV 0x01c0
+#define HW_SPI1CLKDIV 0x01c4
+#define HW_QUADSPICLKDIV 0x01c8
+#define HW_SSP0CLKDIV 0x01d0
+#define HW_NANDCLKDIV 0x01d4
+#define HW_TRACECLKDIV 0x01e0
+#define HW_CAMMCLKDIV 0x01e8
+#define HW_WDTCLKDIV 0x01ec
+#define HW_CLKOUTCLKDIV 0x01f4
+#define HW_MACCLKDIV 0x01f8
+#define HW_LCDCLKDIV 0x01fc
+#define HW_ADCANACLKDIV 0x0200
+
+static struct clk *clks[MAX_CLKS];
+static struct clk_onecell_data clk_data;
+static DEFINE_SPINLOCK(asm9260_clk_lock);
+
+struct asm9260_div_clk {
+ unsigned int idx;
+ const char *name;
+ const char *parent_name;
+ u32 reg;
+};
+
+struct asm9260_gate_data {
+ unsigned int idx;
+ const char *name;
+ const char *parent_name;
+ u32 reg;
+ u8 bit_idx;
+ unsigned long flags;
+};
+
+struct asm9260_mux_clock {
+ u8 mask;
+ u32 *table;
+ const char *name;
+ const char **parent_names;
+ u8 num_parents;
+ unsigned long offset;
+ unsigned long flags;
+};
+
+static void __iomem *base;
+
+static const struct asm9260_div_clk asm9260_div_clks[] __initconst = {
+ { CLKID_SYS_CPU, "cpu_div", "main_gate", HW_CPUCLKDIV },
+ { CLKID_SYS_AHB, "ahb_div", "cpu_div", HW_SYSAHBCLKDIV },
+
+ /* i2s has two deviders: one for only external mclk and internal
+ * devider for all clks. */
+ { CLKID_SYS_I2S0M, "i2s0m_div", "i2s0_mclk", HW_I2S0MCLKDIV },
+ { CLKID_SYS_I2S1M, "i2s1m_div", "i2s1_mclk", HW_I2S1MCLKDIV },
+ { CLKID_SYS_I2S0S, "i2s0s_div", "i2s0_gate", HW_I2S0SCLKDIV },
+ { CLKID_SYS_I2S1S, "i2s1s_div", "i2s0_gate", HW_I2S1SCLKDIV },
+
+ { CLKID_SYS_UART0, "uart0_div", "uart_gate", HW_UART0CLKDIV },
+ { CLKID_SYS_UART1, "uart1_div", "uart_gate", HW_UART1CLKDIV },
+ { CLKID_SYS_UART2, "uart2_div", "uart_gate", HW_UART2CLKDIV },
+ { CLKID_SYS_UART3, "uart3_div", "uart_gate", HW_UART3CLKDIV },
+ { CLKID_SYS_UART4, "uart4_div", "uart_gate", HW_UART4CLKDIV },
+ { CLKID_SYS_UART5, "uart5_div", "uart_gate", HW_UART5CLKDIV },
+ { CLKID_SYS_UART6, "uart6_div", "uart_gate", HW_UART6CLKDIV },
+ { CLKID_SYS_UART7, "uart7_div", "uart_gate", HW_UART7CLKDIV },
+ { CLKID_SYS_UART8, "uart8_div", "uart_gate", HW_UART8CLKDIV },
+ { CLKID_SYS_UART9, "uart9_div", "uart_gate", HW_UART9CLKDIV },
+
+ { CLKID_SYS_SPI0, "spi0_div", "main_gate", HW_SPI0CLKDIV },
+ { CLKID_SYS_SPI1, "spi1_div", "main_gate", HW_SPI1CLKDIV },
+ { CLKID_SYS_QUADSPI, "quadspi_div", "main_gate", HW_QUADSPICLKDIV },
+ { CLKID_SYS_SSP0, "ssp0_div", "main_gate", HW_SSP0CLKDIV },
+ { CLKID_SYS_NAND, "nand_div", "main_gate", HW_NANDCLKDIV },
+ { CLKID_SYS_TRACE, "trace_div", "main_gate", HW_TRACECLKDIV },
+ { CLKID_SYS_CAMM, "camm_div", "main_gate", HW_CAMMCLKDIV },
+ { CLKID_SYS_MAC, "mac_div", "main_gate", HW_MACCLKDIV },
+ { CLKID_SYS_LCD, "lcd_div", "main_gate", HW_LCDCLKDIV },
+ { CLKID_SYS_ADCANA, "adcana_div", "main_gate", HW_ADCANACLKDIV },
+
+ { CLKID_SYS_WDT, "wdt_div", "wdt_gate", HW_WDTCLKDIV },
+ { CLKID_SYS_CLKOUT, "clkout_div", "clkout_gate", HW_CLKOUTCLKDIV },
+};
+
+static const struct asm9260_gate_data asm9260_mux_gates[] __initconst = {
+ { 0, "main_gate", "main_mux", HW_MAINCLKUEN, 0 },
+ { 0, "uart_gate", "uart_mux", HW_UARTCLKUEN, 0 },
+ { 0, "i2s0_gate", "i2s0_mux", HW_I2S0CLKUEN, 0 },
+ { 0, "i2s1_gate", "i2s1_mux", HW_I2S1CLKUEN, 0 },
+ { 0, "wdt_gate", "wdt_mux", HW_WDTCLKUEN, 0 },
+ { 0, "clkout_gate", "clkout_mux", HW_CLKOUTCLKUEN, 0 },
+};
+static const struct asm9260_gate_data asm9260_ahb_gates[] __initconst = {
+ /* ahb gates */
+ { CLKID_AHB_ROM, "rom", "ahb_div",
+ HW_AHBCLKCTRL0, 1, CLK_IGNORE_UNUSED},
+ { CLKID_AHB_RAM, "ram", "ahb_div",
+ HW_AHBCLKCTRL0, 2, CLK_IGNORE_UNUSED},
+ { CLKID_AHB_GPIO, "gpio", "ahb_div",
+ HW_AHBCLKCTRL0, 4 },
+ { CLKID_AHB_MAC, "mac", "ahb_div",
+ HW_AHBCLKCTRL0, 5 },
+ { CLKID_AHB_EMI, "emi", "ahb_div",
+ HW_AHBCLKCTRL0, 6, CLK_IGNORE_UNUSED},
+ { CLKID_AHB_USB0, "usb0", "ahb_div",
+ HW_AHBCLKCTRL0, 7 },
+ { CLKID_AHB_USB1, "usb1", "ahb_div",
+ HW_AHBCLKCTRL0, 8 },
+ { CLKID_AHB_DMA0, "dma0", "ahb_div",
+ HW_AHBCLKCTRL0, 9 },
+ { CLKID_AHB_DMA1, "dma1", "ahb_div",
+ HW_AHBCLKCTRL0, 10 },
+ { CLKID_AHB_UART0, "uart0", "ahb_div",
+ HW_AHBCLKCTRL0, 11 },
+ { CLKID_AHB_UART1, "uart1", "ahb_div",
+ HW_AHBCLKCTRL0, 12 },
+ { CLKID_AHB_UART2, "uart2", "ahb_div",
+ HW_AHBCLKCTRL0, 13 },
+ { CLKID_AHB_UART3, "uart3", "ahb_div",
+ HW_AHBCLKCTRL0, 14 },
+ { CLKID_AHB_UART4, "uart4", "ahb_div",
+ HW_AHBCLKCTRL0, 15 },
+ { CLKID_AHB_UART5, "uart5", "ahb_div",
+ HW_AHBCLKCTRL0, 16 },
+ { CLKID_AHB_UART6, "uart6", "ahb_div",
+ HW_AHBCLKCTRL0, 17 },
+ { CLKID_AHB_UART7, "uart7", "ahb_div",
+ HW_AHBCLKCTRL0, 18 },
+ { CLKID_AHB_UART8, "uart8", "ahb_div",
+ HW_AHBCLKCTRL0, 19 },
+ { CLKID_AHB_UART9, "uart9", "ahb_div",
+ HW_AHBCLKCTRL0, 20 },
+ { CLKID_AHB_I2S0, "i2s0", "ahb_div",
+ HW_AHBCLKCTRL0, 21 },
+ { CLKID_AHB_I2C0, "i2c0", "ahb_div",
+ HW_AHBCLKCTRL0, 22 },
+ { CLKID_AHB_I2C1, "i2c1", "ahb_div",
+ HW_AHBCLKCTRL0, 23 },
+ { CLKID_AHB_SSP0, "ssp0", "ahb_div",
+ HW_AHBCLKCTRL0, 24 },
+ { CLKID_AHB_IOCONFIG, "ioconf", "ahb_div",
+ HW_AHBCLKCTRL0, 25 },
+ { CLKID_AHB_WDT, "wdt", "ahb_div",
+ HW_AHBCLKCTRL0, 26 },
+ { CLKID_AHB_CAN0, "can0", "ahb_div",
+ HW_AHBCLKCTRL0, 27 },
+ { CLKID_AHB_CAN1, "can1", "ahb_div",
+ HW_AHBCLKCTRL0, 28 },
+ { CLKID_AHB_MPWM, "mpwm", "ahb_div",
+ HW_AHBCLKCTRL0, 29 },
+ { CLKID_AHB_SPI0, "spi0", "ahb_div",
+ HW_AHBCLKCTRL0, 30 },
+ { CLKID_AHB_SPI1, "spi1", "ahb_div",
+ HW_AHBCLKCTRL0, 31 },
+
+ { CLKID_AHB_QEI, "qei", "ahb_div",
+ HW_AHBCLKCTRL1, 0 },
+ { CLKID_AHB_QUADSPI0, "quadspi0", "ahb_div",
+ HW_AHBCLKCTRL1, 1 },
+ { CLKID_AHB_CAMIF, "capmif", "ahb_div",
+ HW_AHBCLKCTRL1, 2 },
+ { CLKID_AHB_LCDIF, "lcdif", "ahb_div",
+ HW_AHBCLKCTRL1, 3 },
+ { CLKID_AHB_TIMER0, "timer0", "ahb_div",
+ HW_AHBCLKCTRL1, 4 },
+ { CLKID_AHB_TIMER1, "timer1", "ahb_div",
+ HW_AHBCLKCTRL1, 5 },
+ { CLKID_AHB_TIMER2, "timer2", "ahb_div",
+ HW_AHBCLKCTRL1, 6 },
+ { CLKID_AHB_TIMER3, "timer3", "ahb_div",
+ HW_AHBCLKCTRL1, 7 },
+ { CLKID_AHB_IRQ, "irq", "ahb_div",
+ HW_AHBCLKCTRL1, 8, CLK_IGNORE_UNUSED},
+ { CLKID_AHB_RTC, "rtc", "ahb_div",
+ HW_AHBCLKCTRL1, 9 },
+ { CLKID_AHB_NAND, "nand", "ahb_div",
+ HW_AHBCLKCTRL1, 10 },
+ { CLKID_AHB_ADC0, "adc0", "ahb_div",
+ HW_AHBCLKCTRL1, 11 },
+ { CLKID_AHB_LED, "led", "ahb_div",
+ HW_AHBCLKCTRL1, 12 },
+ { CLKID_AHB_DAC0, "dac0", "ahb_div",
+ HW_AHBCLKCTRL1, 13 },
+ { CLKID_AHB_LCD, "lcd", "ahb_div",
+ HW_AHBCLKCTRL1, 14 },
+ { CLKID_AHB_I2S1, "i2s1", "ahb_div",
+ HW_AHBCLKCTRL1, 15 },
+ { CLKID_AHB_MAC1, "mac1", "ahb_div",
+ HW_AHBCLKCTRL1, 16 },
+};
+
+static const char __initdata *main_mux_p[] = { NULL, NULL };
+static const char __initdata *i2s0_mux_p[] = { NULL, NULL, "i2s0m_div"};
+static const char __initdata *i2s1_mux_p[] = { NULL, NULL, "i2s1m_div"};
+static const char __initdata *clkout_mux_p[] = { NULL, NULL, "rtc"};
+static u32 three_mux_table[] = {0, 1, 3};
+
+static struct asm9260_mux_clock asm9260_mux_clks[] __initdata = {
+ { 1, three_mux_table, "main_mux", main_mux_p,
+ ARRAY_SIZE(main_mux_p), HW_MAINCLKSEL, },
+ { 1, three_mux_table, "uart_mux", main_mux_p,
+ ARRAY_SIZE(main_mux_p), HW_UARTCLKSEL, },
+ { 1, three_mux_table, "wdt_mux", main_mux_p,
+ ARRAY_SIZE(main_mux_p), HW_WDTCLKSEL, },
+ { 3, three_mux_table, "i2s0_mux", i2s0_mux_p,
+ ARRAY_SIZE(i2s0_mux_p), HW_I2S0CLKSEL, },
+ { 3, three_mux_table, "i2s1_mux", i2s1_mux_p,
+ ARRAY_SIZE(i2s1_mux_p), HW_I2S1CLKSEL, },
+ { 3, three_mux_table, "clkout_mux", clkout_mux_p,
+ ARRAY_SIZE(clkout_mux_p), HW_CLKOUTCLKSEL, },
+};
+
+static void __init asm9260_acc_init(struct device_node *np)
+{
+ struct clk *clk;
+ const char *ref_clk, *pll_clk = "pll";
+ u32 rate;
+ int n;
+ u32 accuracy = 0;
+
+ base = of_io_request_and_map(np, 0, np->name);
+ if (!base)
+ panic("%s: unable to map resource", np->name);
+
+ /* register pll */
+ rate = (ioread32(base + HW_SYSPLLCTRL) & 0xffff) * 1000000;
+
+ ref_clk = of_clk_get_parent_name(np, 0);
+ accuracy = clk_get_accuracy(__clk_lookup(ref_clk));
+ clk = clk_register_fixed_rate_with_accuracy(NULL, pll_clk,
+ ref_clk, 0, rate, accuracy);
+
+ if (IS_ERR(clk))
+ panic("%s: can't register REFCLK. Check DT!", np->name);
+
+ for (n = 0; n < ARRAY_SIZE(asm9260_mux_clks); n++) {
+ const struct asm9260_mux_clock *mc = &asm9260_mux_clks[n];
+
+ mc->parent_names[0] = ref_clk;
+ mc->parent_names[1] = pll_clk;
+ clk = clk_register_mux_table(NULL, mc->name, mc->parent_names,
+ mc->num_parents, mc->flags, base + mc->offset,
+ 0, mc->mask, 0, mc->table, &asm9260_clk_lock);
+ }
+
+ /* clock mux gate cells */
+ for (n = 0; n < ARRAY_SIZE(asm9260_mux_gates); n++) {
+ const struct asm9260_gate_data *gd = &asm9260_mux_gates[n];
+
+ clk = clk_register_gate(NULL, gd->name,
+ gd->parent_name, gd->flags | CLK_SET_RATE_PARENT,
+ base + gd->reg, gd->bit_idx, 0, &asm9260_clk_lock);
+ }
+
+ /* clock div cells */
+ for (n = 0; n < ARRAY_SIZE(asm9260_div_clks); n++) {
+ const struct asm9260_div_clk *dc = &asm9260_div_clks[n];
+
+ clks[dc->idx] = clk_register_divider(NULL, dc->name,
+ dc->parent_name, CLK_SET_RATE_PARENT,
+ base + dc->reg, 0, 8, CLK_DIVIDER_ONE_BASED,
+ &asm9260_clk_lock);
+ }
+
+ /* clock ahb gate cells */
+ for (n = 0; n < ARRAY_SIZE(asm9260_ahb_gates); n++) {
+ const struct asm9260_gate_data *gd = &asm9260_ahb_gates[n];
+
+ clks[gd->idx] = clk_register_gate(NULL, gd->name,
+ gd->parent_name, gd->flags, base + gd->reg,
+ gd->bit_idx, 0, &asm9260_clk_lock);
+ }
+
+ /* check for errors on leaf clocks */
+ for (n = 0; n < MAX_CLKS; n++) {
+ if (!IS_ERR(clks[n]))
+ continue;
+
+ pr_err("%s: Unable to register leaf clock %d\n",
+ np->full_name, n);
+ goto fail;
+ }
+
+ /* register clk-provider */
+ clk_data.clks = clks;
+ clk_data.clk_num = MAX_CLKS;
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ return;
+fail:
+ iounmap(base);
+}
+CLK_OF_DECLARE(asm9260_acc, "alphascale,asm9260-clock-controller",
+ asm9260_acc_init);
diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c
new file mode 100644
index 000000000000..c386ad25beb4
--- /dev/null
+++ b/drivers/clk/clk-cdce706.c
@@ -0,0 +1,700 @@
+/*
+ * TI CDCE706 programmable 3-PLL clock synthesizer driver
+ *
+ * Copyright (c) 2014 Cadence Design Systems Inc.
+ *
+ * Reference: http://www.ti.com/lit/ds/symlink/cdce706.pdf
+ *
+ * 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/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/rational.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define CDCE706_CLKIN_CLOCK 10
+#define CDCE706_CLKIN_SOURCE 11
+#define CDCE706_PLL_M_LOW(pll) (1 + 3 * (pll))
+#define CDCE706_PLL_N_LOW(pll) (2 + 3 * (pll))
+#define CDCE706_PLL_HI(pll) (3 + 3 * (pll))
+#define CDCE706_PLL_MUX 3
+#define CDCE706_PLL_FVCO 6
+#define CDCE706_DIVIDER(div) (13 + (div))
+#define CDCE706_CLKOUT(out) (19 + (out))
+
+#define CDCE706_CLKIN_CLOCK_MASK 0x10
+#define CDCE706_CLKIN_SOURCE_SHIFT 6
+#define CDCE706_CLKIN_SOURCE_MASK 0xc0
+#define CDCE706_CLKIN_SOURCE_LVCMOS 0x40
+
+#define CDCE706_PLL_MUX_MASK(pll) (0x80 >> (pll))
+#define CDCE706_PLL_LOW_M_MASK 0xff
+#define CDCE706_PLL_LOW_N_MASK 0xff
+#define CDCE706_PLL_HI_M_MASK 0x1
+#define CDCE706_PLL_HI_N_MASK 0x1e
+#define CDCE706_PLL_HI_N_SHIFT 1
+#define CDCE706_PLL_M_MAX 0x1ff
+#define CDCE706_PLL_N_MAX 0xfff
+#define CDCE706_PLL_FVCO_MASK(pll) (0x80 >> (pll))
+#define CDCE706_PLL_FREQ_MIN 80000000
+#define CDCE706_PLL_FREQ_MAX 300000000
+#define CDCE706_PLL_FREQ_HI 180000000
+
+#define CDCE706_DIVIDER_PLL(div) (9 + (div) - ((div) > 2) - ((div) > 4))
+#define CDCE706_DIVIDER_PLL_SHIFT(div) ((div) < 2 ? 5 : 3 * ((div) & 1))
+#define CDCE706_DIVIDER_PLL_MASK(div) (0x7 << CDCE706_DIVIDER_PLL_SHIFT(div))
+#define CDCE706_DIVIDER_DIVIDER_MASK 0x7f
+#define CDCE706_DIVIDER_DIVIDER_MAX 0x7f
+
+#define CDCE706_CLKOUT_DIVIDER_MASK 0x7
+#define CDCE706_CLKOUT_ENABLE_MASK 0x8
+
+static struct regmap_config cdce706_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .val_format_endian = REGMAP_ENDIAN_NATIVE,
+};
+
+#define to_hw_data(phw) (container_of((phw), struct cdce706_hw_data, hw))
+
+struct cdce706_hw_data {
+ struct cdce706_dev_data *dev_data;
+ unsigned idx;
+ unsigned parent;
+ struct clk *clk;
+ struct clk_hw hw;
+ unsigned div;
+ unsigned mul;
+ unsigned mux;
+};
+
+struct cdce706_dev_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct clk_onecell_data onecell;
+ struct clk *clks[6];
+ struct clk *clkin_clk[2];
+ const char *clkin_name[2];
+ struct cdce706_hw_data clkin[1];
+ struct cdce706_hw_data pll[3];
+ struct cdce706_hw_data divider[6];
+ struct cdce706_hw_data clkout[6];
+};
+
+static const char * const cdce706_source_name[] = {
+ "clk_in0", "clk_in1",
+};
+
+static const char *cdce706_clkin_name[] = {
+ "clk_in",
+};
+
+static const char * const cdce706_pll_name[] = {
+ "pll1", "pll2", "pll3",
+};
+
+static const char *cdce706_divider_parent_name[] = {
+ "clk_in", "pll1", "pll2", "pll2", "pll3",
+};
+
+static const char *cdce706_divider_name[] = {
+ "p0", "p1", "p2", "p3", "p4", "p5",
+};
+
+static const char * const cdce706_clkout_name[] = {
+ "clk_out0", "clk_out1", "clk_out2", "clk_out3", "clk_out4", "clk_out5",
+};
+
+static int cdce706_reg_read(struct cdce706_dev_data *dev_data, unsigned reg,
+ unsigned *val)
+{
+ int rc = regmap_read(dev_data->regmap, reg | 0x80, val);
+
+ if (rc < 0)
+ dev_err(&dev_data->client->dev, "error reading reg %u", reg);
+ return rc;
+}
+
+static int cdce706_reg_write(struct cdce706_dev_data *dev_data, unsigned reg,
+ unsigned val)
+{
+ int rc = regmap_write(dev_data->regmap, reg | 0x80, val);
+
+ if (rc < 0)
+ dev_err(&dev_data->client->dev, "error writing reg %u", reg);
+ return rc;
+}
+
+static int cdce706_reg_update(struct cdce706_dev_data *dev_data, unsigned reg,
+ unsigned mask, unsigned val)
+{
+ int rc = regmap_update_bits(dev_data->regmap, reg | 0x80, mask, val);
+
+ if (rc < 0)
+ dev_err(&dev_data->client->dev, "error updating reg %u", reg);
+ return rc;
+}
+
+static int cdce706_clkin_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ hwd->parent = index;
+ return 0;
+}
+
+static u8 cdce706_clkin_get_parent(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ return hwd->parent;
+}
+
+static const struct clk_ops cdce706_clkin_ops = {
+ .set_parent = cdce706_clkin_set_parent,
+ .get_parent = cdce706_clkin_get_parent,
+};
+
+static unsigned long cdce706_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, pll: %d, mux: %d, mul: %u, div: %u\n",
+ __func__, hwd->idx, hwd->mux, hwd->mul, hwd->div);
+
+ if (!hwd->mux) {
+ if (hwd->div && hwd->mul) {
+ u64 res = (u64)parent_rate * hwd->mul;
+
+ do_div(res, hwd->div);
+ return res;
+ }
+ } else {
+ if (hwd->div)
+ return parent_rate / hwd->div;
+ }
+ return 0;
+}
+
+static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+ unsigned long mul, div;
+ u64 res;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, rate: %lu, parent_rate: %lu\n",
+ __func__, rate, *parent_rate);
+
+ rational_best_approximation(rate, *parent_rate,
+ CDCE706_PLL_N_MAX, CDCE706_PLL_M_MAX,
+ &mul, &div);
+ hwd->mul = mul;
+ hwd->div = div;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, pll: %d, mul: %lu, div: %lu\n",
+ __func__, hwd->idx, mul, div);
+
+ res = (u64)*parent_rate * hwd->mul;
+ do_div(res, hwd->div);
+ return res;
+}
+
+static int cdce706_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+ unsigned long mul = hwd->mul, div = hwd->div;
+ int err;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, pll: %d, mul: %lu, div: %lu\n",
+ __func__, hwd->idx, mul, div);
+
+ err = cdce706_reg_update(hwd->dev_data,
+ CDCE706_PLL_HI(hwd->idx),
+ CDCE706_PLL_HI_M_MASK | CDCE706_PLL_HI_N_MASK,
+ ((div >> 8) & CDCE706_PLL_HI_M_MASK) |
+ ((mul >> (8 - CDCE706_PLL_HI_N_SHIFT)) &
+ CDCE706_PLL_HI_N_MASK));
+ if (err < 0)
+ return err;
+
+ err = cdce706_reg_write(hwd->dev_data,
+ CDCE706_PLL_M_LOW(hwd->idx),
+ div & CDCE706_PLL_LOW_M_MASK);
+ if (err < 0)
+ return err;
+
+ err = cdce706_reg_write(hwd->dev_data,
+ CDCE706_PLL_N_LOW(hwd->idx),
+ mul & CDCE706_PLL_LOW_N_MASK);
+ if (err < 0)
+ return err;
+
+ err = cdce706_reg_update(hwd->dev_data,
+ CDCE706_PLL_FVCO,
+ CDCE706_PLL_FVCO_MASK(hwd->idx),
+ rate > CDCE706_PLL_FREQ_HI ?
+ CDCE706_PLL_FVCO_MASK(hwd->idx) : 0);
+ return err;
+}
+
+static const struct clk_ops cdce706_pll_ops = {
+ .recalc_rate = cdce706_pll_recalc_rate,
+ .round_rate = cdce706_pll_round_rate,
+ .set_rate = cdce706_pll_set_rate,
+};
+
+static int cdce706_divider_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ if (hwd->parent == index)
+ return 0;
+ hwd->parent = index;
+ return cdce706_reg_update(hwd->dev_data,
+ CDCE706_DIVIDER_PLL(hwd->idx),
+ CDCE706_DIVIDER_PLL_MASK(hwd->idx),
+ index << CDCE706_DIVIDER_PLL_SHIFT(hwd->idx));
+}
+
+static u8 cdce706_divider_get_parent(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ return hwd->parent;
+}
+
+static unsigned long cdce706_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, divider: %d, div: %u\n",
+ __func__, hwd->idx, hwd->div);
+ if (hwd->div)
+ return parent_rate / hwd->div;
+ return 0;
+}
+
+static long cdce706_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+ struct cdce706_dev_data *cdce = hwd->dev_data;
+ unsigned long mul, div;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, rate: %lu, parent_rate: %lu\n",
+ __func__, rate, *parent_rate);
+
+ rational_best_approximation(rate, *parent_rate,
+ 1, CDCE706_DIVIDER_DIVIDER_MAX,
+ &mul, &div);
+ if (!mul)
+ div = CDCE706_DIVIDER_DIVIDER_MAX;
+
+ if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+ unsigned long best_diff = rate;
+ unsigned long best_div = 0;
+ struct clk *gp_clk = cdce->clkin_clk[cdce->clkin[0].parent];
+ unsigned long gp_rate = gp_clk ? clk_get_rate(gp_clk) : 0;
+
+ for (div = CDCE706_PLL_FREQ_MIN / rate; best_diff &&
+ div <= CDCE706_PLL_FREQ_MAX / rate; ++div) {
+ unsigned long n, m;
+ unsigned long diff;
+ unsigned long div_rate;
+ u64 div_rate64;
+
+ if (rate * div < CDCE706_PLL_FREQ_MIN)
+ continue;
+
+ rational_best_approximation(rate * div, gp_rate,
+ CDCE706_PLL_N_MAX,
+ CDCE706_PLL_M_MAX,
+ &n, &m);
+ div_rate64 = (u64)gp_rate * n;
+ do_div(div_rate64, m);
+ do_div(div_rate64, div);
+ div_rate = div_rate64;
+ diff = max(div_rate, rate) - min(div_rate, rate);
+
+ if (diff < best_diff) {
+ best_diff = diff;
+ best_div = div;
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, %lu * %lu / %lu / %lu = %lu\n",
+ __func__, gp_rate, n, m, div, div_rate);
+ }
+ }
+
+ div = best_div;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, altering parent rate: %lu -> %lu\n",
+ __func__, *parent_rate, rate * div);
+ *parent_rate = rate * div;
+ }
+ hwd->div = div;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, divider: %d, div: %lu\n",
+ __func__, hwd->idx, div);
+
+ return *parent_rate / div;
+}
+
+static int cdce706_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, divider: %d, div: %u\n",
+ __func__, hwd->idx, hwd->div);
+
+ return cdce706_reg_update(hwd->dev_data,
+ CDCE706_DIVIDER(hwd->idx),
+ CDCE706_DIVIDER_DIVIDER_MASK,
+ hwd->div);
+}
+
+static const struct clk_ops cdce706_divider_ops = {
+ .set_parent = cdce706_divider_set_parent,
+ .get_parent = cdce706_divider_get_parent,
+ .recalc_rate = cdce706_divider_recalc_rate,
+ .round_rate = cdce706_divider_round_rate,
+ .set_rate = cdce706_divider_set_rate,
+};
+
+static int cdce706_clkout_prepare(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ return cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx),
+ CDCE706_CLKOUT_ENABLE_MASK,
+ CDCE706_CLKOUT_ENABLE_MASK);
+}
+
+static void cdce706_clkout_unprepare(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx),
+ CDCE706_CLKOUT_ENABLE_MASK, 0);
+}
+
+static int cdce706_clkout_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ if (hwd->parent == index)
+ return 0;
+ hwd->parent = index;
+ return cdce706_reg_update(hwd->dev_data,
+ CDCE706_CLKOUT(hwd->idx),
+ CDCE706_CLKOUT_ENABLE_MASK, index);
+}
+
+static u8 cdce706_clkout_get_parent(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ return hwd->parent;
+}
+
+static unsigned long cdce706_clkout_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return parent_rate;
+}
+
+static long cdce706_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ *parent_rate = rate;
+ return rate;
+}
+
+static int cdce706_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ return 0;
+}
+
+static const struct clk_ops cdce706_clkout_ops = {
+ .prepare = cdce706_clkout_prepare,
+ .unprepare = cdce706_clkout_unprepare,
+ .set_parent = cdce706_clkout_set_parent,
+ .get_parent = cdce706_clkout_get_parent,
+ .recalc_rate = cdce706_clkout_recalc_rate,
+ .round_rate = cdce706_clkout_round_rate,
+ .set_rate = cdce706_clkout_set_rate,
+};
+
+static int cdce706_register_hw(struct cdce706_dev_data *cdce,
+ struct cdce706_hw_data *hw, unsigned num_hw,
+ const char * const *clk_names,
+ struct clk_init_data *init)
+{
+ unsigned i;
+
+ for (i = 0; i < num_hw; ++i, ++hw) {
+ init->name = clk_names[i];
+ hw->dev_data = cdce;
+ hw->idx = i;
+ hw->hw.init = init;
+ hw->clk = devm_clk_register(&cdce->client->dev,
+ &hw->hw);
+ if (IS_ERR(hw->clk)) {
+ dev_err(&cdce->client->dev, "Failed to register %s\n",
+ clk_names[i]);
+ return PTR_ERR(hw->clk);
+ }
+ }
+ return 0;
+}
+
+static int cdce706_register_clkin(struct cdce706_dev_data *cdce)
+{
+ struct clk_init_data init = {
+ .ops = &cdce706_clkin_ops,
+ .parent_names = cdce->clkin_name,
+ .num_parents = ARRAY_SIZE(cdce->clkin_name),
+ };
+ unsigned i;
+ int ret;
+ unsigned clock, source;
+
+ for (i = 0; i < ARRAY_SIZE(cdce->clkin_name); ++i) {
+ struct clk *parent = devm_clk_get(&cdce->client->dev,
+ cdce706_source_name[i]);
+
+ if (IS_ERR(parent)) {
+ cdce->clkin_name[i] = cdce706_source_name[i];
+ } else {
+ cdce->clkin_name[i] = __clk_get_name(parent);
+ cdce->clkin_clk[i] = parent;
+ }
+ }
+
+ ret = cdce706_reg_read(cdce, CDCE706_CLKIN_SOURCE, &source);
+ if (ret < 0)
+ return ret;
+ if ((source & CDCE706_CLKIN_SOURCE_MASK) ==
+ CDCE706_CLKIN_SOURCE_LVCMOS) {
+ ret = cdce706_reg_read(cdce, CDCE706_CLKIN_CLOCK, &clock);
+ if (ret < 0)
+ return ret;
+ cdce->clkin[0].parent = !!(clock & CDCE706_CLKIN_CLOCK_MASK);
+ }
+
+ ret = cdce706_register_hw(cdce, cdce->clkin,
+ ARRAY_SIZE(cdce->clkin),
+ cdce706_clkin_name, &init);
+ return ret;
+}
+
+static int cdce706_register_plls(struct cdce706_dev_data *cdce)
+{
+ struct clk_init_data init = {
+ .ops = &cdce706_pll_ops,
+ .parent_names = cdce706_clkin_name,
+ .num_parents = ARRAY_SIZE(cdce706_clkin_name),
+ };
+ unsigned i;
+ int ret;
+ unsigned mux;
+
+ ret = cdce706_reg_read(cdce, CDCE706_PLL_MUX, &mux);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(cdce->pll); ++i) {
+ unsigned m, n, v;
+
+ ret = cdce706_reg_read(cdce, CDCE706_PLL_M_LOW(i), &m);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_reg_read(cdce, CDCE706_PLL_N_LOW(i), &n);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_reg_read(cdce, CDCE706_PLL_HI(i), &v);
+ if (ret < 0)
+ return ret;
+ cdce->pll[i].div = m | ((v & CDCE706_PLL_HI_M_MASK) << 8);
+ cdce->pll[i].mul = n | ((v & CDCE706_PLL_HI_N_MASK) <<
+ (8 - CDCE706_PLL_HI_N_SHIFT));
+ cdce->pll[i].mux = mux & CDCE706_PLL_MUX_MASK(i);
+ dev_dbg(&cdce->client->dev,
+ "%s: i: %u, div: %u, mul: %u, mux: %d\n", __func__, i,
+ cdce->pll[i].div, cdce->pll[i].mul, cdce->pll[i].mux);
+ }
+
+ ret = cdce706_register_hw(cdce, cdce->pll,
+ ARRAY_SIZE(cdce->pll),
+ cdce706_pll_name, &init);
+ return ret;
+}
+
+static int cdce706_register_dividers(struct cdce706_dev_data *cdce)
+{
+ struct clk_init_data init = {
+ .ops = &cdce706_divider_ops,
+ .parent_names = cdce706_divider_parent_name,
+ .num_parents = ARRAY_SIZE(cdce706_divider_parent_name),
+ .flags = CLK_SET_RATE_PARENT,
+ };
+ unsigned i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(cdce->divider); ++i) {
+ unsigned val;
+
+ ret = cdce706_reg_read(cdce, CDCE706_DIVIDER_PLL(i), &val);
+ if (ret < 0)
+ return ret;
+ cdce->divider[i].parent =
+ (val & CDCE706_DIVIDER_PLL_MASK(i)) >>
+ CDCE706_DIVIDER_PLL_SHIFT(i);
+
+ ret = cdce706_reg_read(cdce, CDCE706_DIVIDER(i), &val);
+ if (ret < 0)
+ return ret;
+ cdce->divider[i].div = val & CDCE706_DIVIDER_DIVIDER_MASK;
+ dev_dbg(&cdce->client->dev,
+ "%s: i: %u, parent: %u, div: %u\n", __func__, i,
+ cdce->divider[i].parent, cdce->divider[i].div);
+ }
+
+ ret = cdce706_register_hw(cdce, cdce->divider,
+ ARRAY_SIZE(cdce->divider),
+ cdce706_divider_name, &init);
+ return ret;
+}
+
+static int cdce706_register_clkouts(struct cdce706_dev_data *cdce)
+{
+ struct clk_init_data init = {
+ .ops = &cdce706_clkout_ops,
+ .parent_names = cdce706_divider_name,
+ .num_parents = ARRAY_SIZE(cdce706_divider_name),
+ .flags = CLK_SET_RATE_PARENT,
+ };
+ unsigned i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i) {
+ unsigned val;
+
+ ret = cdce706_reg_read(cdce, CDCE706_CLKOUT(i), &val);
+ if (ret < 0)
+ return ret;
+ cdce->clkout[i].parent = val & CDCE706_CLKOUT_DIVIDER_MASK;
+ dev_dbg(&cdce->client->dev,
+ "%s: i: %u, parent: %u\n", __func__, i,
+ cdce->clkout[i].parent);
+ }
+
+ ret = cdce706_register_hw(cdce, cdce->clkout,
+ ARRAY_SIZE(cdce->clkout),
+ cdce706_clkout_name, &init);
+ for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i)
+ cdce->clks[i] = cdce->clkout[i].clk;
+
+ return ret;
+}
+
+static int cdce706_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct cdce706_dev_data *cdce;
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ cdce = devm_kzalloc(&client->dev, sizeof(*cdce), GFP_KERNEL);
+ if (!cdce)
+ return -ENOMEM;
+
+ cdce->client = client;
+ cdce->regmap = devm_regmap_init_i2c(client, &cdce706_regmap_config);
+ if (IS_ERR(cdce->regmap)) {
+ dev_err(&client->dev, "Failed to initialize regmap\n");
+ return -EINVAL;
+ }
+
+ i2c_set_clientdata(client, cdce);
+
+ ret = cdce706_register_clkin(cdce);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_register_plls(cdce);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_register_dividers(cdce);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_register_clkouts(cdce);
+ if (ret < 0)
+ return ret;
+ cdce->onecell.clks = cdce->clks;
+ cdce->onecell.clk_num = ARRAY_SIZE(cdce->clks);
+ ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get,
+ &cdce->onecell);
+
+ return ret;
+}
+
+static int cdce706_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+
+#ifdef CONFIG_OF
+static const struct of_device_id cdce706_dt_match[] = {
+ { .compatible = "ti,cdce706" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, cdce706_dt_match);
+#endif
+
+static const struct i2c_device_id cdce706_id[] = {
+ { "cdce706", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cdce706_id);
+
+static struct i2c_driver cdce706_i2c_driver = {
+ .driver = {
+ .name = "cdce706",
+ .of_match_table = of_match_ptr(cdce706_dt_match),
+ },
+ .probe = cdce706_probe,
+ .remove = cdce706_remove,
+ .id_table = cdce706_id,
+};
+module_i2c_driver(cdce706_i2c_driver);
+
+MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
+MODULE_DESCRIPTION("TI CDCE 706 clock synthesizer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 4386697236a7..956b7e54fa1c 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -27,7 +27,7 @@ static u8 clk_composite_get_parent(struct clk_hw *hw)
const struct clk_ops *mux_ops = composite->mux_ops;
struct clk_hw *mux_hw = composite->mux_hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return mux_ops->get_parent(mux_hw);
}
@@ -38,7 +38,7 @@ static int clk_composite_set_parent(struct clk_hw *hw, u8 index)
const struct clk_ops *mux_ops = composite->mux_ops;
struct clk_hw *mux_hw = composite->mux_hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return mux_ops->set_parent(mux_hw, index);
}
@@ -50,12 +50,14 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
const struct clk_ops *rate_ops = composite->rate_ops;
struct clk_hw *rate_hw = composite->rate_hw;
- rate_hw->clk = hw->clk;
+ __clk_hw_set_clk(rate_hw, hw);
return rate_ops->recalc_rate(rate_hw, parent_rate);
}
static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p)
{
@@ -72,8 +74,10 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
int i;
if (rate_hw && rate_ops && rate_ops->determine_rate) {
- rate_hw->clk = hw->clk;
- return rate_ops->determine_rate(rate_hw, rate, best_parent_rate,
+ __clk_hw_set_clk(rate_hw, hw);
+ return rate_ops->determine_rate(rate_hw, rate, min_rate,
+ max_rate,
+ best_parent_rate,
best_parent_p);
} else if (rate_hw && rate_ops && rate_ops->round_rate &&
mux_hw && mux_ops && mux_ops->set_parent) {
@@ -116,8 +120,9 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
return best_rate;
} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
- mux_hw->clk = hw->clk;
- return mux_ops->determine_rate(mux_hw, rate, best_parent_rate,
+ __clk_hw_set_clk(mux_hw, hw);
+ return mux_ops->determine_rate(mux_hw, rate, min_rate,
+ max_rate, best_parent_rate,
best_parent_p);
} else {
pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n");
@@ -132,7 +137,7 @@ static long clk_composite_round_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops *rate_ops = composite->rate_ops;
struct clk_hw *rate_hw = composite->rate_hw;
- rate_hw->clk = hw->clk;
+ __clk_hw_set_clk(rate_hw, hw);
return rate_ops->round_rate(rate_hw, rate, prate);
}
@@ -144,7 +149,7 @@ static int clk_composite_set_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops *rate_ops = composite->rate_ops;
struct clk_hw *rate_hw = composite->rate_hw;
- rate_hw->clk = hw->clk;
+ __clk_hw_set_clk(rate_hw, hw);
return rate_ops->set_rate(rate_hw, rate, parent_rate);
}
@@ -155,7 +160,7 @@ static int clk_composite_is_enabled(struct clk_hw *hw)
const struct clk_ops *gate_ops = composite->gate_ops;
struct clk_hw *gate_hw = composite->gate_hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
return gate_ops->is_enabled(gate_hw);
}
@@ -166,7 +171,7 @@ static int clk_composite_enable(struct clk_hw *hw)
const struct clk_ops *gate_ops = composite->gate_ops;
struct clk_hw *gate_hw = composite->gate_hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
return gate_ops->enable(gate_hw);
}
@@ -177,7 +182,7 @@ static void clk_composite_disable(struct clk_hw *hw)
const struct clk_ops *gate_ops = composite->gate_ops;
struct clk_hw *gate_hw = composite->gate_hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
gate_ops->disable(gate_hw);
}
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index c0a842b335c5..db7f8bce7467 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -30,7 +30,7 @@
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
-#define div_mask(d) ((1 << ((d)->width)) - 1)
+#define div_mask(width) ((1 << (width)) - 1)
static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
{
@@ -54,15 +54,16 @@ static unsigned int _get_table_mindiv(const struct clk_div_table *table)
return mindiv;
}
-static unsigned int _get_maxdiv(struct clk_divider *divider)
+static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
+ unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
- return div_mask(divider);
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
- return 1 << div_mask(divider);
- if (divider->table)
- return _get_table_maxdiv(divider->table);
- return div_mask(divider) + 1;
+ if (flags & CLK_DIVIDER_ONE_BASED)
+ return div_mask(width);
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
+ return 1 << div_mask(width);
+ if (table)
+ return _get_table_maxdiv(table);
+ return div_mask(width) + 1;
}
static unsigned int _get_table_div(const struct clk_div_table *table,
@@ -76,14 +77,15 @@ static unsigned int _get_table_div(const struct clk_div_table *table,
return 0;
}
-static unsigned int _get_div(struct clk_divider *divider, unsigned int val)
+static unsigned int _get_div(const struct clk_div_table *table,
+ unsigned int val, unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
+ if (flags & CLK_DIVIDER_ONE_BASED)
return val;
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << val;
- if (divider->table)
- return _get_table_div(divider->table, val);
+ if (table)
+ return _get_table_div(table, val);
return val + 1;
}
@@ -98,29 +100,28 @@ static unsigned int _get_table_val(const struct clk_div_table *table,
return 0;
}
-static unsigned int _get_val(struct clk_divider *divider, unsigned int div)
+static unsigned int _get_val(const struct clk_div_table *table,
+ unsigned int div, unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
+ if (flags & CLK_DIVIDER_ONE_BASED)
return div;
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
return __ffs(div);
- if (divider->table)
- return _get_table_val(divider->table, div);
+ if (table)
+ return _get_table_val(table, div);
return div - 1;
}
-static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
+unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
+ unsigned int val,
+ const struct clk_div_table *table,
+ unsigned long flags)
{
- struct clk_divider *divider = to_clk_divider(hw);
- unsigned int div, val;
+ unsigned int div;
- val = clk_readl(divider->reg) >> divider->shift;
- val &= div_mask(divider);
-
- div = _get_div(divider, val);
+ div = _get_div(table, val, flags);
if (!div) {
- WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
+ WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
__clk_get_name(hw->clk));
return parent_rate;
@@ -128,6 +129,20 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
return DIV_ROUND_UP(parent_rate, div);
}
+EXPORT_SYMBOL_GPL(divider_recalc_rate);
+
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ unsigned int val;
+
+ val = clk_readl(divider->reg) >> divider->shift;
+ val &= div_mask(divider->width);
+
+ return divider_recalc_rate(hw, parent_rate, val, divider->table,
+ divider->flags);
+}
/*
* The reverse of DIV_ROUND_UP: The maximum number which
@@ -146,12 +161,13 @@ static bool _is_valid_table_div(const struct clk_div_table *table,
return false;
}
-static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
+static bool _is_valid_div(const struct clk_div_table *table, unsigned int div,
+ unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
return is_power_of_2(div);
- if (divider->table)
- return _is_valid_table_div(divider->table, div);
+ if (table)
+ return _is_valid_table_div(table, div);
return true;
}
@@ -191,71 +207,76 @@ static int _round_down_table(const struct clk_div_table *table, int div)
return down;
}
-static int _div_round_up(struct clk_divider *divider,
- unsigned long parent_rate, unsigned long rate)
+static int _div_round_up(const struct clk_div_table *table,
+ unsigned long parent_rate, unsigned long rate,
+ unsigned long flags)
{
int div = DIV_ROUND_UP(parent_rate, rate);
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
div = __roundup_pow_of_two(div);
- if (divider->table)
- div = _round_up_table(divider->table, div);
+ if (table)
+ div = _round_up_table(table, div);
return div;
}
-static int _div_round_closest(struct clk_divider *divider,
- unsigned long parent_rate, unsigned long rate)
+static int _div_round_closest(const struct clk_div_table *table,
+ unsigned long parent_rate, unsigned long rate,
+ unsigned long flags)
{
int up, down, div;
up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) {
+ if (flags & CLK_DIVIDER_POWER_OF_TWO) {
up = __roundup_pow_of_two(div);
down = __rounddown_pow_of_two(div);
- } else if (divider->table) {
- up = _round_up_table(divider->table, div);
- down = _round_down_table(divider->table, div);
+ } else if (table) {
+ up = _round_up_table(table, div);
+ down = _round_down_table(table, div);
}
return (up - div) <= (div - down) ? up : down;
}
-static int _div_round(struct clk_divider *divider, unsigned long parent_rate,
- unsigned long rate)
+static int _div_round(const struct clk_div_table *table,
+ unsigned long parent_rate, unsigned long rate,
+ unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
- return _div_round_closest(divider, parent_rate, rate);
+ if (flags & CLK_DIVIDER_ROUND_CLOSEST)
+ return _div_round_closest(table, parent_rate, rate, flags);
- return _div_round_up(divider, parent_rate, rate);
+ return _div_round_up(table, parent_rate, rate, flags);
}
-static bool _is_best_div(struct clk_divider *divider,
- unsigned long rate, unsigned long now, unsigned long best)
+static bool _is_best_div(unsigned long rate, unsigned long now,
+ unsigned long best, unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
+ if (flags & CLK_DIVIDER_ROUND_CLOSEST)
return abs(rate - now) < abs(rate - best);
return now <= rate && now > best;
}
-static int _next_div(struct clk_divider *divider, int div)
+static int _next_div(const struct clk_div_table *table, int div,
+ unsigned long flags)
{
div++;
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
return __roundup_pow_of_two(div);
- if (divider->table)
- return _round_up_table(divider->table, div);
+ if (table)
+ return _round_up_table(table, div);
return div;
}
static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
- unsigned long *best_parent_rate)
+ unsigned long *best_parent_rate,
+ const struct clk_div_table *table, u8 width,
+ unsigned long flags)
{
- struct clk_divider *divider = to_clk_divider(hw);
int i, bestdiv = 0;
unsigned long parent_rate, best = 0, now, maxdiv;
unsigned long parent_rate_saved = *best_parent_rate;
@@ -263,19 +284,11 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
if (!rate)
rate = 1;
- /* if read only, just return current value */
- if (divider->flags & CLK_DIVIDER_READ_ONLY) {
- bestdiv = readl(divider->reg) >> divider->shift;
- bestdiv &= div_mask(divider);
- bestdiv = _get_div(divider, bestdiv);
- return bestdiv;
- }
-
- maxdiv = _get_maxdiv(divider);
+ maxdiv = _get_maxdiv(table, width, flags);
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
parent_rate = *best_parent_rate;
- bestdiv = _div_round(divider, parent_rate, rate);
+ bestdiv = _div_round(table, parent_rate, rate, flags);
bestdiv = bestdiv == 0 ? 1 : bestdiv;
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
return bestdiv;
@@ -287,8 +300,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
*/
maxdiv = min(ULONG_MAX / rate, maxdiv);
- for (i = 1; i <= maxdiv; i = _next_div(divider, i)) {
- if (!_is_valid_div(divider, i))
+ for (i = 1; i <= maxdiv; i = _next_div(table, i, flags)) {
+ if (!_is_valid_div(table, i, flags))
continue;
if (rate * i == parent_rate_saved) {
/*
@@ -302,7 +315,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i));
now = DIV_ROUND_UP(parent_rate, i);
- if (_is_best_div(divider, rate, now, best)) {
+ if (_is_best_div(rate, now, best, flags)) {
bestdiv = i;
best = now;
*best_parent_rate = parent_rate;
@@ -310,48 +323,79 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
}
if (!bestdiv) {
- bestdiv = _get_maxdiv(divider);
+ bestdiv = _get_maxdiv(table, width, flags);
*best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
}
return bestdiv;
}
-static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+long divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate, const struct clk_div_table *table,
+ u8 width, unsigned long flags)
{
int div;
- div = clk_divider_bestdiv(hw, rate, prate);
+
+ div = clk_divider_bestdiv(hw, rate, prate, table, width, flags);
return DIV_ROUND_UP(*prate, div);
}
+EXPORT_SYMBOL_GPL(divider_round_rate);
-static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
+static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
{
struct clk_divider *divider = to_clk_divider(hw);
+ int bestdiv;
+
+ /* if read only, just return current value */
+ if (divider->flags & CLK_DIVIDER_READ_ONLY) {
+ bestdiv = readl(divider->reg) >> divider->shift;
+ bestdiv &= div_mask(divider->width);
+ bestdiv = _get_div(divider->table, bestdiv, divider->flags);
+ return bestdiv;
+ }
+
+ return divider_round_rate(hw, rate, prate, divider->table,
+ divider->width, divider->flags);
+}
+
+int divider_get_val(unsigned long rate, unsigned long parent_rate,
+ const struct clk_div_table *table, u8 width,
+ unsigned long flags)
+{
unsigned int div, value;
- unsigned long flags = 0;
- u32 val;
div = DIV_ROUND_UP(parent_rate, rate);
- if (!_is_valid_div(divider, div))
+ if (!_is_valid_div(table, div, flags))
return -EINVAL;
- value = _get_val(divider, div);
+ value = _get_val(table, div, flags);
+
+ return min_t(unsigned int, value, div_mask(width));
+}
+EXPORT_SYMBOL_GPL(divider_get_val);
+
+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 value;
+ unsigned long flags = 0;
+ u32 val;
- if (value > div_mask(divider))
- value = div_mask(divider);
+ value = divider_get_val(rate, parent_rate, divider->table,
+ divider->width, divider->flags);
if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
- val = div_mask(divider) << (divider->shift + 16);
+ val = div_mask(divider->width) << (divider->shift + 16);
} else {
val = clk_readl(divider->reg);
- val &= ~(div_mask(divider) << divider->shift);
+ val &= ~(div_mask(divider->width) << divider->shift);
}
val |= value << divider->shift;
clk_writel(val, divider->reg);
@@ -463,3 +507,19 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
width, clk_divider_flags, table, lock);
}
EXPORT_SYMBOL_GPL(clk_register_divider_table);
+
+void clk_unregister_divider(struct clk *clk)
+{
+ struct clk_divider *div;
+ struct clk_hw *hw;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ div = to_clk_divider(hw);
+
+ clk_unregister(clk);
+ kfree(div);
+}
+EXPORT_SYMBOL_GPL(clk_unregister_divider);
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 51fd87fb7ba6..3f0e4200cb5d 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -128,7 +128,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
struct clk_init_data init;
if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
- if (bit_idx > 16) {
+ if (bit_idx > 15) {
pr_err("gate bit exceeds LOWORD field\n");
return ERR_PTR(-EINVAL);
}
@@ -162,3 +162,19 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
return clk;
}
EXPORT_SYMBOL_GPL(clk_register_gate);
+
+void clk_unregister_gate(struct clk *clk)
+{
+ struct clk_gate *gate;
+ struct clk_hw *hw;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ gate = to_clk_gate(hw);
+
+ clk_unregister(clk);
+ kfree(gate);
+}
+EXPORT_SYMBOL_GPL(clk_unregister_gate);
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 6e1ecf94bf58..69a094c3783d 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -177,3 +177,19 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
NULL, lock);
}
EXPORT_SYMBOL_GPL(clk_register_mux);
+
+void clk_unregister_mux(struct clk *clk)
+{
+ struct clk_mux *mux;
+ struct clk_hw *hw;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ mux = to_clk_mux(hw);
+
+ clk_unregister(clk);
+ kfree(mux);
+}
+EXPORT_SYMBOL_GPL(clk_unregister_mux);
diff --git a/drivers/clk/clk-ppc-corenet.c b/drivers/clk/clk-qoriq.c
index 0a47d6f49cd6..cda90a971e39 100644
--- a/drivers/clk/clk-ppc-corenet.c
+++ b/drivers/clk/clk-qoriq.c
@@ -5,8 +5,11 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * clock driver for Freescale PowerPC corenet SoCs.
+ * clock driver for Freescale QorIQ SoCs.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -19,6 +22,7 @@
struct cmux_clk {
struct clk_hw hw;
void __iomem *reg;
+ unsigned int clk_per_pll;
u32 flags;
};
@@ -27,14 +31,12 @@ struct cmux_clk {
#define CLKSEL_ADJUST BIT(0)
#define to_cmux_clk(p) container_of(p, struct cmux_clk, hw)
-static unsigned int clocks_per_pll;
-
static int cmux_set_parent(struct clk_hw *hw, u8 idx)
{
struct cmux_clk *clk = to_cmux_clk(hw);
u32 clksel;
- clksel = ((idx / clocks_per_pll) << 2) + idx % clocks_per_pll;
+ clksel = ((idx / clk->clk_per_pll) << 2) + idx % clk->clk_per_pll;
if (clk->flags & CLKSEL_ADJUST)
clksel += 8;
clksel = (clksel & 0xf) << CLKSEL_SHIFT;
@@ -52,12 +54,12 @@ static u8 cmux_get_parent(struct clk_hw *hw)
clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
if (clk->flags & CLKSEL_ADJUST)
clksel -= 8;
- clksel = (clksel >> 2) * clocks_per_pll + clksel % 4;
+ clksel = (clksel >> 2) * clk->clk_per_pll + clksel % 4;
return clksel;
}
-const struct clk_ops cmux_ops = {
+static const struct clk_ops cmux_ops = {
.get_parent = cmux_get_parent,
.set_parent = cmux_set_parent,
};
@@ -72,6 +74,7 @@ static void __init core_mux_init(struct device_node *np)
u32 offset;
const char *clk_name;
const char **parent_names;
+ struct of_phandle_args clkspec;
rc = of_property_read_u32(np, "reg", &offset);
if (rc) {
@@ -85,32 +88,40 @@ static void __init core_mux_init(struct device_node *np)
pr_err("%s: get clock count error\n", np->name);
return;
}
- parent_names = kzalloc((sizeof(char *) * count), GFP_KERNEL);
- if (!parent_names) {
- pr_err("%s: could not allocate parent_names\n", __func__);
+ parent_names = kcalloc(count, sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
return;
- }
for (i = 0; i < count; i++)
parent_names[i] = of_clk_get_parent_name(np, i);
- cmux_clk = kzalloc(sizeof(struct cmux_clk), GFP_KERNEL);
- if (!cmux_clk) {
- pr_err("%s: could not allocate cmux_clk\n", __func__);
+ cmux_clk = kzalloc(sizeof(*cmux_clk), GFP_KERNEL);
+ if (!cmux_clk)
goto err_name;
- }
+
cmux_clk->reg = of_iomap(np, 0);
if (!cmux_clk->reg) {
pr_err("%s: could not map register\n", __func__);
goto err_clk;
}
+ rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
+ &clkspec);
+ if (rc) {
+ pr_err("%s: parse clock node error\n", __func__);
+ goto err_clk;
+ }
+
+ cmux_clk->clk_per_pll = of_property_count_strings(clkspec.np,
+ "clock-output-names");
+ of_node_put(clkspec.np);
+
node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
if (node && (offset >= 0x80))
cmux_clk->flags = CLKSEL_ADJUST;
rc = of_property_read_string_index(np, "clock-output-names",
- 0, &clk_name);
+ 0, &clk_name);
if (rc) {
pr_err("%s: read clock names error\n", np->name);
goto err_clk;
@@ -132,7 +143,7 @@ static void __init core_mux_init(struct device_node *np)
rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
if (rc) {
pr_err("Could not register clock provider for node:%s\n",
- np->name);
+ np->name);
goto err_clk;
}
goto err_name;
@@ -155,7 +166,7 @@ static void __init core_pll_init(struct device_node *np)
base = of_iomap(np, 0);
if (!base) {
- pr_err("clk-ppc: iomap error\n");
+ pr_err("iomap error\n");
return;
}
@@ -181,24 +192,17 @@ static void __init core_pll_init(struct device_node *np)
goto err_map;
}
- /* output clock number per PLL */
- clocks_per_pll = count;
-
- subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
- if (!subclks) {
- pr_err("%s: could not allocate subclks\n", __func__);
+ subclks = kcalloc(count, sizeof(struct clk *), GFP_KERNEL);
+ if (!subclks)
goto err_map;
- }
- onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
- if (!onecell_data) {
- pr_err("%s: could not allocate onecell_data\n", __func__);
+ onecell_data = kmalloc(sizeof(*onecell_data), GFP_KERNEL);
+ if (!onecell_data)
goto err_clks;
- }
for (i = 0; i < count; i++) {
rc = of_property_read_string_index(np, "clock-output-names",
- i, &clk_name);
+ i, &clk_name);
if (rc) {
pr_err("%s: could not get clock names\n", np->name);
goto err_cell;
@@ -230,7 +234,7 @@ static void __init core_pll_init(struct device_node *np)
rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
if (rc) {
pr_err("Could not register clk provider for node:%s\n",
- np->name);
+ np->name);
goto err_cell;
}
@@ -252,7 +256,7 @@ static void __init sysclk_init(struct device_node *node)
u32 rate;
if (!np) {
- pr_err("ppc-clk: could not get parent node\n");
+ pr_err("could not get parent node\n");
return;
}
@@ -268,39 +272,91 @@ static void __init sysclk_init(struct device_node *node)
of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
-static const struct of_device_id clk_match[] __initconst = {
- { .compatible = "fsl,qoriq-sysclk-1.0", .data = sysclk_init, },
- { .compatible = "fsl,qoriq-sysclk-2.0", .data = sysclk_init, },
- { .compatible = "fsl,qoriq-core-pll-1.0", .data = core_pll_init, },
- { .compatible = "fsl,qoriq-core-pll-2.0", .data = core_pll_init, },
- { .compatible = "fsl,qoriq-core-mux-1.0", .data = core_mux_init, },
- { .compatible = "fsl,qoriq-core-mux-2.0", .data = core_mux_init, },
- {}
-};
-
-static int __init ppc_corenet_clk_probe(struct platform_device *pdev)
+static void __init pltfrm_pll_init(struct device_node *np)
{
- of_clk_init(clk_match);
+ void __iomem *base;
+ uint32_t mult;
+ const char *parent_name, *clk_name;
+ int i, _errno;
+ struct clk_onecell_data *cod;
- return 0;
-}
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_err("%s(): %s: of_iomap() failed\n", __func__, np->name);
+ return;
+ }
-static const struct of_device_id ppc_clk_ids[] __initconst = {
- { .compatible = "fsl,qoriq-clockgen-1.0", },
- { .compatible = "fsl,qoriq-clockgen-2.0", },
- {}
-};
+ /* Get the multiple of PLL */
+ mult = ioread32be(base);
-static struct platform_driver ppc_corenet_clk_driver = {
- .driver = {
- .name = "ppc_corenet_clock",
- .of_match_table = ppc_clk_ids,
- },
- .probe = ppc_corenet_clk_probe,
-};
+ iounmap(base);
-static int __init ppc_corenet_clk_init(void)
-{
- return platform_driver_register(&ppc_corenet_clk_driver);
+ /* Check if this PLL is disabled */
+ if (mult & PLL_KILL) {
+ pr_debug("%s(): %s: Disabled\n", __func__, np->name);
+ return;
+ }
+ mult = (mult & GENMASK(6, 1)) >> 1;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+ if (!parent_name) {
+ pr_err("%s(): %s: of_clk_get_parent_name() failed\n",
+ __func__, np->name);
+ return;
+ }
+
+ i = of_property_count_strings(np, "clock-output-names");
+ if (i < 0) {
+ pr_err("%s(): %s: of_property_count_strings(clock-output-names) = %d\n",
+ __func__, np->name, i);
+ return;
+ }
+
+ cod = kmalloc(sizeof(*cod) + i * sizeof(struct clk *), GFP_KERNEL);
+ if (!cod)
+ return;
+ cod->clks = (struct clk **)(cod + 1);
+ cod->clk_num = i;
+
+ for (i = 0; i < cod->clk_num; i++) {
+ _errno = of_property_read_string_index(np, "clock-output-names",
+ i, &clk_name);
+ if (_errno < 0) {
+ pr_err("%s(): %s: of_property_read_string_index(clock-output-names) = %d\n",
+ __func__, np->name, _errno);
+ goto return_clk_unregister;
+ }
+
+ cod->clks[i] = clk_register_fixed_factor(NULL, clk_name,
+ parent_name, 0, mult, 1 + i);
+ if (IS_ERR(cod->clks[i])) {
+ pr_err("%s(): %s: clk_register_fixed_factor(%s) = %ld\n",
+ __func__, np->name,
+ clk_name, PTR_ERR(cod->clks[i]));
+ goto return_clk_unregister;
+ }
+ }
+
+ _errno = of_clk_add_provider(np, of_clk_src_onecell_get, cod);
+ if (_errno < 0) {
+ pr_err("%s(): %s: of_clk_add_provider() = %d\n",
+ __func__, np->name, _errno);
+ goto return_clk_unregister;
+ }
+
+ return;
+
+return_clk_unregister:
+ while (--i >= 0)
+ clk_unregister(cod->clks[i]);
+ kfree(cod);
}
-subsys_initcall(ppc_corenet_clk_init);
+
+CLK_OF_DECLARE(qoriq_sysclk_1, "fsl,qoriq-sysclk-1.0", sysclk_init);
+CLK_OF_DECLARE(qoriq_sysclk_2, "fsl,qoriq-sysclk-2.0", sysclk_init);
+CLK_OF_DECLARE(qoriq_core_pll_1, "fsl,qoriq-core-pll-1.0", core_pll_init);
+CLK_OF_DECLARE(qoriq_core_pll_2, "fsl,qoriq-core-pll-2.0", core_pll_init);
+CLK_OF_DECLARE(qoriq_core_mux_1, "fsl,qoriq-core-mux-1.0", core_mux_init);
+CLK_OF_DECLARE(qoriq_core_mux_2, "fsl,qoriq-core-mux-2.0", core_mux_init);
+CLK_OF_DECLARE(qoriq_pltfrm_pll_1, "fsl,qoriq-platform-pll-1.0", pltfrm_pll_init);
+CLK_OF_DECLARE(qoriq_pltfrm_pll_2, "fsl,qoriq-platform-pll-2.0", pltfrm_pll_init);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 642cf37124d3..eb0152961d3c 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -9,7 +9,7 @@
* Standard functionality for the common clock API. See Documentation/clk.txt
*/
-#include <linux/clk-private.h>
+#include <linux/clk-provider.h>
#include <linux/clk/clk-conf.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -37,6 +37,55 @@ static HLIST_HEAD(clk_root_list);
static HLIST_HEAD(clk_orphan_list);
static LIST_HEAD(clk_notifier_list);
+static long clk_core_get_accuracy(struct clk_core *clk);
+static unsigned long clk_core_get_rate(struct clk_core *clk);
+static int clk_core_get_phase(struct clk_core *clk);
+static bool clk_core_is_prepared(struct clk_core *clk);
+static bool clk_core_is_enabled(struct clk_core *clk);
+static struct clk_core *clk_core_lookup(const char *name);
+
+/*** private data structures ***/
+
+struct clk_core {
+ const char *name;
+ const struct clk_ops *ops;
+ struct clk_hw *hw;
+ struct module *owner;
+ struct clk_core *parent;
+ const char **parent_names;
+ struct clk_core **parents;
+ u8 num_parents;
+ u8 new_parent_index;
+ unsigned long rate;
+ unsigned long req_rate;
+ unsigned long new_rate;
+ struct clk_core *new_parent;
+ struct clk_core *new_child;
+ unsigned long flags;
+ unsigned int enable_count;
+ unsigned int prepare_count;
+ unsigned long accuracy;
+ int phase;
+ struct hlist_head children;
+ struct hlist_node child_node;
+ struct hlist_node debug_node;
+ struct hlist_head clks;
+ unsigned int notifier_count;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dentry;
+#endif
+ struct kref ref;
+};
+
+struct clk {
+ struct clk_core *core;
+ const char *dev_id;
+ const char *con_id;
+ unsigned long min_rate;
+ unsigned long max_rate;
+ struct hlist_node child_node;
+};
+
/*** locking ***/
static void clk_prepare_lock(void)
{
@@ -114,7 +163,8 @@ static struct hlist_head *orphan_list[] = {
NULL,
};
-static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
+static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
+ int level)
{
if (!c)
return;
@@ -122,14 +172,14 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n",
level * 3 + 1, "",
30 - level * 3, c->name,
- c->enable_count, c->prepare_count, clk_get_rate(c),
- clk_get_accuracy(c), clk_get_phase(c));
+ c->enable_count, c->prepare_count, clk_core_get_rate(c),
+ clk_core_get_accuracy(c), clk_core_get_phase(c));
}
-static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
+static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
int level)
{
- struct clk *child;
+ struct clk_core *child;
if (!c)
return;
@@ -142,7 +192,7 @@ static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
static int clk_summary_show(struct seq_file *s, void *data)
{
- struct clk *c;
+ struct clk_core *c;
struct hlist_head **lists = (struct hlist_head **)s->private;
seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy phase\n");
@@ -172,7 +222,7 @@ static const struct file_operations clk_summary_fops = {
.release = single_release,
};
-static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
+static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
{
if (!c)
return;
@@ -180,14 +230,14 @@ static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
seq_printf(s, "\"%s\": { ", c->name);
seq_printf(s, "\"enable_count\": %d,", c->enable_count);
seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
- seq_printf(s, "\"rate\": %lu", clk_get_rate(c));
- seq_printf(s, "\"accuracy\": %lu", clk_get_accuracy(c));
- seq_printf(s, "\"phase\": %d", clk_get_phase(c));
+ seq_printf(s, "\"rate\": %lu", clk_core_get_rate(c));
+ seq_printf(s, "\"accuracy\": %lu", clk_core_get_accuracy(c));
+ seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
}
-static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
+static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level)
{
- struct clk *child;
+ struct clk_core *child;
if (!c)
return;
@@ -204,7 +254,7 @@ static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
static int clk_dump(struct seq_file *s, void *data)
{
- struct clk *c;
+ struct clk_core *c;
bool first_node = true;
struct hlist_head **lists = (struct hlist_head **)s->private;
@@ -240,7 +290,7 @@ static const struct file_operations clk_dump_fops = {
.release = single_release,
};
-static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
+static int clk_debug_create_one(struct clk_core *clk, struct dentry *pdentry)
{
struct dentry *d;
int ret = -ENOMEM;
@@ -315,7 +365,7 @@ out:
* initialized. Otherwise it bails out early since the debugfs clk tree
* will be created lazily by clk_debug_init as part of a late_initcall.
*/
-static int clk_debug_register(struct clk *clk)
+static int clk_debug_register(struct clk_core *clk)
{
int ret = 0;
@@ -340,16 +390,12 @@ unlock:
* debugfs clk tree if clk->dentry points to debugfs created by
* clk_debug_register in __clk_init.
*/
-static void clk_debug_unregister(struct clk *clk)
+static void clk_debug_unregister(struct clk_core *clk)
{
mutex_lock(&clk_debug_lock);
- if (!clk->dentry)
- goto out;
-
hlist_del_init(&clk->debug_node);
debugfs_remove_recursive(clk->dentry);
clk->dentry = NULL;
-out:
mutex_unlock(&clk_debug_lock);
}
@@ -358,8 +404,9 @@ struct dentry *clk_debugfs_add_file(struct clk_hw *hw, char *name, umode_t mode,
{
struct dentry *d = NULL;
- if (hw->clk->dentry)
- d = debugfs_create_file(name, mode, hw->clk->dentry, data, fops);
+ if (hw->core->dentry)
+ d = debugfs_create_file(name, mode, hw->core->dentry, data,
+ fops);
return d;
}
@@ -379,7 +426,7 @@ EXPORT_SYMBOL_GPL(clk_debugfs_add_file);
*/
static int __init clk_debug_init(void)
{
- struct clk *clk;
+ struct clk_core *clk;
struct dentry *d;
rootdir = debugfs_create_dir("clk", NULL);
@@ -418,22 +465,20 @@ static int __init clk_debug_init(void)
}
late_initcall(clk_debug_init);
#else
-static inline int clk_debug_register(struct clk *clk) { return 0; }
-static inline void clk_debug_reparent(struct clk *clk, struct clk *new_parent)
+static inline int clk_debug_register(struct clk_core *clk) { return 0; }
+static inline void clk_debug_reparent(struct clk_core *clk,
+ struct clk_core *new_parent)
{
}
-static inline void clk_debug_unregister(struct clk *clk)
+static inline void clk_debug_unregister(struct clk_core *clk)
{
}
#endif
/* caller must hold prepare_lock */
-static void clk_unprepare_unused_subtree(struct clk *clk)
+static void clk_unprepare_unused_subtree(struct clk_core *clk)
{
- struct clk *child;
-
- if (!clk)
- return;
+ struct clk_core *child;
hlist_for_each_entry(child, &clk->children, child_node)
clk_unprepare_unused_subtree(child);
@@ -444,7 +489,7 @@ static void clk_unprepare_unused_subtree(struct clk *clk)
if (clk->flags & CLK_IGNORE_UNUSED)
return;
- if (__clk_is_prepared(clk)) {
+ if (clk_core_is_prepared(clk)) {
if (clk->ops->unprepare_unused)
clk->ops->unprepare_unused(clk->hw);
else if (clk->ops->unprepare)
@@ -453,14 +498,11 @@ static void clk_unprepare_unused_subtree(struct clk *clk)
}
/* caller must hold prepare_lock */
-static void clk_disable_unused_subtree(struct clk *clk)
+static void clk_disable_unused_subtree(struct clk_core *clk)
{
- struct clk *child;
+ struct clk_core *child;
unsigned long flags;
- if (!clk)
- goto out;
-
hlist_for_each_entry(child, &clk->children, child_node)
clk_disable_unused_subtree(child);
@@ -477,7 +519,7 @@ static void clk_disable_unused_subtree(struct clk *clk)
* sequence. call .disable_unused if available, otherwise fall
* back to .disable
*/
- if (__clk_is_enabled(clk)) {
+ if (clk_core_is_enabled(clk)) {
if (clk->ops->disable_unused)
clk->ops->disable_unused(clk->hw);
else if (clk->ops->disable)
@@ -486,9 +528,6 @@ static void clk_disable_unused_subtree(struct clk *clk)
unlock_out:
clk_enable_unlock(flags);
-
-out:
- return;
}
static bool clk_ignore_unused;
@@ -501,7 +540,7 @@ __setup("clk_ignore_unused", clk_ignore_unused_setup);
static int clk_disable_unused(void)
{
- struct clk *clk;
+ struct clk_core *clk;
if (clk_ignore_unused) {
pr_warn("clk: Not disabling unused clocks\n");
@@ -532,48 +571,65 @@ late_initcall_sync(clk_disable_unused);
const char *__clk_get_name(struct clk *clk)
{
- return !clk ? NULL : clk->name;
+ return !clk ? NULL : clk->core->name;
}
EXPORT_SYMBOL_GPL(__clk_get_name);
struct clk_hw *__clk_get_hw(struct clk *clk)
{
- return !clk ? NULL : clk->hw;
+ return !clk ? NULL : clk->core->hw;
}
EXPORT_SYMBOL_GPL(__clk_get_hw);
u8 __clk_get_num_parents(struct clk *clk)
{
- return !clk ? 0 : clk->num_parents;
+ return !clk ? 0 : clk->core->num_parents;
}
EXPORT_SYMBOL_GPL(__clk_get_num_parents);
struct clk *__clk_get_parent(struct clk *clk)
{
- return !clk ? NULL : clk->parent;
+ if (!clk)
+ return NULL;
+
+ /* TODO: Create a per-user clk and change callers to call clk_put */
+ return !clk->core->parent ? NULL : clk->core->parent->hw->clk;
}
EXPORT_SYMBOL_GPL(__clk_get_parent);
-struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
+static struct clk_core *clk_core_get_parent_by_index(struct clk_core *clk,
+ u8 index)
{
if (!clk || index >= clk->num_parents)
return NULL;
else if (!clk->parents)
- return __clk_lookup(clk->parent_names[index]);
+ return clk_core_lookup(clk->parent_names[index]);
else if (!clk->parents[index])
return clk->parents[index] =
- __clk_lookup(clk->parent_names[index]);
+ clk_core_lookup(clk->parent_names[index]);
else
return clk->parents[index];
}
+
+struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
+{
+ struct clk_core *parent;
+
+ if (!clk)
+ return NULL;
+
+ parent = clk_core_get_parent_by_index(clk->core, index);
+
+ return !parent ? NULL : parent->hw->clk;
+}
EXPORT_SYMBOL_GPL(clk_get_parent_by_index);
unsigned int __clk_get_enable_count(struct clk *clk)
{
- return !clk ? 0 : clk->enable_count;
+ return !clk ? 0 : clk->core->enable_count;
}
-unsigned long __clk_get_rate(struct clk *clk)
+static unsigned long clk_core_get_rate_nolock(struct clk_core *clk)
{
unsigned long ret;
@@ -593,9 +649,17 @@ unsigned long __clk_get_rate(struct clk *clk)
out:
return ret;
}
+
+unsigned long __clk_get_rate(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_get_rate_nolock(clk->core);
+}
EXPORT_SYMBOL_GPL(__clk_get_rate);
-static unsigned long __clk_get_accuracy(struct clk *clk)
+static unsigned long __clk_get_accuracy(struct clk_core *clk)
{
if (!clk)
return 0;
@@ -605,11 +669,11 @@ static unsigned long __clk_get_accuracy(struct clk *clk)
unsigned long __clk_get_flags(struct clk *clk)
{
- return !clk ? 0 : clk->flags;
+ return !clk ? 0 : clk->core->flags;
}
EXPORT_SYMBOL_GPL(__clk_get_flags);
-bool __clk_is_prepared(struct clk *clk)
+static bool clk_core_is_prepared(struct clk_core *clk)
{
int ret;
@@ -630,7 +694,15 @@ out:
return !!ret;
}
-bool __clk_is_enabled(struct clk *clk)
+bool __clk_is_prepared(struct clk *clk)
+{
+ if (!clk)
+ return false;
+
+ return clk_core_is_prepared(clk->core);
+}
+
+static bool clk_core_is_enabled(struct clk_core *clk)
{
int ret;
@@ -650,12 +722,21 @@ bool __clk_is_enabled(struct clk *clk)
out:
return !!ret;
}
+
+bool __clk_is_enabled(struct clk *clk)
+{
+ if (!clk)
+ return false;
+
+ return clk_core_is_enabled(clk->core);
+}
EXPORT_SYMBOL_GPL(__clk_is_enabled);
-static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
+static struct clk_core *__clk_lookup_subtree(const char *name,
+ struct clk_core *clk)
{
- struct clk *child;
- struct clk *ret;
+ struct clk_core *child;
+ struct clk_core *ret;
if (!strcmp(clk->name, name))
return clk;
@@ -669,10 +750,10 @@ static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
return NULL;
}
-struct clk *__clk_lookup(const char *name)
+static struct clk_core *clk_core_lookup(const char *name)
{
- struct clk *root_clk;
- struct clk *ret;
+ struct clk_core *root_clk;
+ struct clk_core *ret;
if (!name)
return NULL;
@@ -694,42 +775,53 @@ struct clk *__clk_lookup(const char *name)
return NULL;
}
-/*
- * Helper for finding best parent to provide a given frequency. This can be used
- * directly as a determine_rate callback (e.g. for a mux), or from a more
- * complex clock that may combine a mux with other operations.
- */
-long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_p)
+static bool mux_is_better_rate(unsigned long rate, unsigned long now,
+ unsigned long best, unsigned long flags)
{
- struct clk *clk = hw->clk, *parent, *best_parent = NULL;
+ if (flags & CLK_MUX_ROUND_CLOSEST)
+ return abs(now - rate) < abs(best - rate);
+
+ return now <= rate && now > best;
+}
+
+static long
+clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_p,
+ unsigned long flags)
+{
+ struct clk_core *core = hw->core, *parent, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate, best = 0;
/* if NO_REPARENT flag set, pass through to current parent */
- if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
- parent = clk->parent;
- if (clk->flags & CLK_SET_RATE_PARENT)
- best = __clk_round_rate(parent, rate);
+ if (core->flags & CLK_SET_RATE_NO_REPARENT) {
+ parent = core->parent;
+ if (core->flags & CLK_SET_RATE_PARENT)
+ best = __clk_determine_rate(parent ? parent->hw : NULL,
+ rate, min_rate, max_rate);
else if (parent)
- best = __clk_get_rate(parent);
+ best = clk_core_get_rate_nolock(parent);
else
- best = __clk_get_rate(clk);
+ best = clk_core_get_rate_nolock(core);
goto out;
}
/* find the parent that can provide the fastest rate <= rate */
- num_parents = clk->num_parents;
+ num_parents = core->num_parents;
for (i = 0; i < num_parents; i++) {
- parent = clk_get_parent_by_index(clk, i);
+ parent = clk_core_get_parent_by_index(core, i);
if (!parent)
continue;
- if (clk->flags & CLK_SET_RATE_PARENT)
- parent_rate = __clk_round_rate(parent, rate);
+ if (core->flags & CLK_SET_RATE_PARENT)
+ parent_rate = __clk_determine_rate(parent->hw, rate,
+ min_rate,
+ max_rate);
else
- parent_rate = __clk_get_rate(parent);
- if (parent_rate <= rate && parent_rate > best) {
+ parent_rate = clk_core_get_rate_nolock(parent);
+ if (mux_is_better_rate(rate, parent_rate, best, flags)) {
best_parent = parent;
best = parent_rate;
}
@@ -742,11 +834,63 @@ out:
return best;
}
+
+struct clk *__clk_lookup(const char *name)
+{
+ struct clk_core *core = clk_core_lookup(name);
+
+ return !core ? NULL : core->hw->clk;
+}
+
+static void clk_core_get_boundaries(struct clk_core *clk,
+ unsigned long *min_rate,
+ unsigned long *max_rate)
+{
+ struct clk *clk_user;
+
+ *min_rate = 0;
+ *max_rate = ULONG_MAX;
+
+ hlist_for_each_entry(clk_user, &clk->clks, child_node)
+ *min_rate = max(*min_rate, clk_user->min_rate);
+
+ hlist_for_each_entry(clk_user, &clk->clks, child_node)
+ *max_rate = min(*max_rate, clk_user->max_rate);
+}
+
+/*
+ * Helper for finding best parent to provide a given frequency. This can be used
+ * directly as a determine_rate callback (e.g. for a mux), or from a more
+ * complex clock that may combine a mux with other operations.
+ */
+long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_p)
+{
+ return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
+ best_parent_rate,
+ best_parent_p, 0);
+}
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
+long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_p)
+{
+ return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
+ best_parent_rate,
+ best_parent_p,
+ CLK_MUX_ROUND_CLOSEST);
+}
+EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest);
+
/*** clk api ***/
-void __clk_unprepare(struct clk *clk)
+static void clk_core_unprepare(struct clk_core *clk)
{
if (!clk)
return;
@@ -762,7 +906,7 @@ void __clk_unprepare(struct clk *clk)
if (clk->ops->unprepare)
clk->ops->unprepare(clk->hw);
- __clk_unprepare(clk->parent);
+ clk_core_unprepare(clk->parent);
}
/**
@@ -782,12 +926,12 @@ void clk_unprepare(struct clk *clk)
return;
clk_prepare_lock();
- __clk_unprepare(clk);
+ clk_core_unprepare(clk->core);
clk_prepare_unlock();
}
EXPORT_SYMBOL_GPL(clk_unprepare);
-int __clk_prepare(struct clk *clk)
+static int clk_core_prepare(struct clk_core *clk)
{
int ret = 0;
@@ -795,14 +939,14 @@ int __clk_prepare(struct clk *clk)
return 0;
if (clk->prepare_count == 0) {
- ret = __clk_prepare(clk->parent);
+ ret = clk_core_prepare(clk->parent);
if (ret)
return ret;
if (clk->ops->prepare) {
ret = clk->ops->prepare(clk->hw);
if (ret) {
- __clk_unprepare(clk->parent);
+ clk_core_unprepare(clk->parent);
return ret;
}
}
@@ -829,15 +973,18 @@ int clk_prepare(struct clk *clk)
{
int ret;
+ if (!clk)
+ return 0;
+
clk_prepare_lock();
- ret = __clk_prepare(clk);
+ ret = clk_core_prepare(clk->core);
clk_prepare_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(clk_prepare);
-static void __clk_disable(struct clk *clk)
+static void clk_core_disable(struct clk_core *clk)
{
if (!clk)
return;
@@ -851,7 +998,15 @@ static void __clk_disable(struct clk *clk)
if (clk->ops->disable)
clk->ops->disable(clk->hw);
- __clk_disable(clk->parent);
+ clk_core_disable(clk->parent);
+}
+
+static void __clk_disable(struct clk *clk)
+{
+ if (!clk)
+ return;
+
+ clk_core_disable(clk->core);
}
/**
@@ -879,7 +1034,7 @@ void clk_disable(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_disable);
-static int __clk_enable(struct clk *clk)
+static int clk_core_enable(struct clk_core *clk)
{
int ret = 0;
@@ -890,7 +1045,7 @@ static int __clk_enable(struct clk *clk)
return -ESHUTDOWN;
if (clk->enable_count == 0) {
- ret = __clk_enable(clk->parent);
+ ret = clk_core_enable(clk->parent);
if (ret)
return ret;
@@ -898,7 +1053,7 @@ static int __clk_enable(struct clk *clk)
if (clk->ops->enable) {
ret = clk->ops->enable(clk->hw);
if (ret) {
- __clk_disable(clk->parent);
+ clk_core_disable(clk->parent);
return ret;
}
}
@@ -908,6 +1063,14 @@ static int __clk_enable(struct clk *clk)
return 0;
}
+static int __clk_enable(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_enable(clk->core);
+}
+
/**
* clk_enable - ungate a clock
* @clk: the clk being ungated
@@ -934,17 +1097,13 @@ int clk_enable(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_enable);
-/**
- * __clk_round_rate - round the given rate for a clk
- * @clk: round the rate of this clock
- * @rate: the rate which is to be rounded
- *
- * Caller must hold prepare_lock. Useful for clk_ops such as .set_rate
- */
-unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
+static unsigned long clk_core_round_rate_nolock(struct clk_core *clk,
+ unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate)
{
unsigned long parent_rate = 0;
- struct clk *parent;
+ struct clk_core *parent;
struct clk_hw *parent_hw;
if (!clk)
@@ -956,15 +1115,59 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
if (clk->ops->determine_rate) {
parent_hw = parent ? parent->hw : NULL;
- return clk->ops->determine_rate(clk->hw, rate, &parent_rate,
- &parent_hw);
+ return clk->ops->determine_rate(clk->hw, rate,
+ min_rate, max_rate,
+ &parent_rate, &parent_hw);
} else if (clk->ops->round_rate)
return clk->ops->round_rate(clk->hw, rate, &parent_rate);
else if (clk->flags & CLK_SET_RATE_PARENT)
- return __clk_round_rate(clk->parent, rate);
+ return clk_core_round_rate_nolock(clk->parent, rate, min_rate,
+ max_rate);
else
return clk->rate;
}
+
+/**
+ * __clk_determine_rate - get the closest rate actually supported by a clock
+ * @hw: determine the rate of this clock
+ * @rate: target rate
+ * @min_rate: returned rate must be greater than this rate
+ * @max_rate: returned rate must be less than this rate
+ *
+ * Caller must hold prepare_lock. Useful for clk_ops such as .set_rate and
+ * .determine_rate.
+ */
+unsigned long __clk_determine_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate)
+{
+ if (!hw)
+ return 0;
+
+ return clk_core_round_rate_nolock(hw->core, rate, min_rate, max_rate);
+}
+EXPORT_SYMBOL_GPL(__clk_determine_rate);
+
+/**
+ * __clk_round_rate - round the given rate for a clk
+ * @clk: round the rate of this clock
+ * @rate: the rate which is to be rounded
+ *
+ * Caller must hold prepare_lock. Useful for clk_ops such as .set_rate
+ */
+unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long min_rate;
+ unsigned long max_rate;
+
+ if (!clk)
+ return 0;
+
+ clk_core_get_boundaries(clk->core, &min_rate, &max_rate);
+
+ return clk_core_round_rate_nolock(clk->core, rate, min_rate, max_rate);
+}
EXPORT_SYMBOL_GPL(__clk_round_rate);
/**
@@ -980,6 +1183,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
{
unsigned long ret;
+ if (!clk)
+ return 0;
+
clk_prepare_lock();
ret = __clk_round_rate(clk, rate);
clk_prepare_unlock();
@@ -1002,22 +1208,21 @@ EXPORT_SYMBOL_GPL(clk_round_rate);
* called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if
* a driver returns that.
*/
-static int __clk_notify(struct clk *clk, unsigned long msg,
+static int __clk_notify(struct clk_core *clk, unsigned long msg,
unsigned long old_rate, unsigned long new_rate)
{
struct clk_notifier *cn;
struct clk_notifier_data cnd;
int ret = NOTIFY_DONE;
- cnd.clk = clk;
cnd.old_rate = old_rate;
cnd.new_rate = new_rate;
list_for_each_entry(cn, &clk_notifier_list, node) {
- if (cn->clk == clk) {
+ if (cn->clk->core == clk) {
+ cnd.clk = cn->clk;
ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
&cnd);
- break;
}
}
@@ -1035,10 +1240,10 @@ static int __clk_notify(struct clk *clk, unsigned long msg,
*
* Caller must hold prepare_lock.
*/
-static void __clk_recalc_accuracies(struct clk *clk)
+static void __clk_recalc_accuracies(struct clk_core *clk)
{
unsigned long parent_accuracy = 0;
- struct clk *child;
+ struct clk_core *child;
if (clk->parent)
parent_accuracy = clk->parent->accuracy;
@@ -1053,6 +1258,20 @@ static void __clk_recalc_accuracies(struct clk *clk)
__clk_recalc_accuracies(child);
}
+static long clk_core_get_accuracy(struct clk_core *clk)
+{
+ unsigned long accuracy;
+
+ clk_prepare_lock();
+ if (clk && (clk->flags & CLK_GET_ACCURACY_NOCACHE))
+ __clk_recalc_accuracies(clk);
+
+ accuracy = __clk_get_accuracy(clk);
+ clk_prepare_unlock();
+
+ return accuracy;
+}
+
/**
* clk_get_accuracy - return the accuracy of clk
* @clk: the clk whose accuracy is being returned
@@ -1064,20 +1283,15 @@ static void __clk_recalc_accuracies(struct clk *clk)
*/
long clk_get_accuracy(struct clk *clk)
{
- unsigned long accuracy;
-
- clk_prepare_lock();
- if (clk && (clk->flags & CLK_GET_ACCURACY_NOCACHE))
- __clk_recalc_accuracies(clk);
-
- accuracy = __clk_get_accuracy(clk);
- clk_prepare_unlock();
+ if (!clk)
+ return 0;
- return accuracy;
+ return clk_core_get_accuracy(clk->core);
}
EXPORT_SYMBOL_GPL(clk_get_accuracy);
-static unsigned long clk_recalc(struct clk *clk, unsigned long parent_rate)
+static unsigned long clk_recalc(struct clk_core *clk,
+ unsigned long parent_rate)
{
if (clk->ops->recalc_rate)
return clk->ops->recalc_rate(clk->hw, parent_rate);
@@ -1098,11 +1312,11 @@ static unsigned long clk_recalc(struct clk *clk, unsigned long parent_rate)
*
* Caller must hold prepare_lock.
*/
-static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
+static void __clk_recalc_rates(struct clk_core *clk, unsigned long msg)
{
unsigned long old_rate;
unsigned long parent_rate = 0;
- struct clk *child;
+ struct clk_core *child;
old_rate = clk->rate;
@@ -1122,15 +1336,7 @@ static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
__clk_recalc_rates(child, msg);
}
-/**
- * clk_get_rate - return the rate of clk
- * @clk: the clk whose rate is being returned
- *
- * Simply returns the cached rate of the clk, unless CLK_GET_RATE_NOCACHE flag
- * is set, which means a recalc_rate will be issued.
- * If clk is NULL then returns 0.
- */
-unsigned long clk_get_rate(struct clk *clk)
+static unsigned long clk_core_get_rate(struct clk_core *clk)
{
unsigned long rate;
@@ -1139,14 +1345,32 @@ unsigned long clk_get_rate(struct clk *clk)
if (clk && (clk->flags & CLK_GET_RATE_NOCACHE))
__clk_recalc_rates(clk, 0);
- rate = __clk_get_rate(clk);
+ rate = clk_core_get_rate_nolock(clk);
clk_prepare_unlock();
return rate;
}
+EXPORT_SYMBOL_GPL(clk_core_get_rate);
+
+/**
+ * clk_get_rate - return the rate of clk
+ * @clk: the clk whose rate is being returned
+ *
+ * Simply returns the cached rate of the clk, unless CLK_GET_RATE_NOCACHE flag
+ * is set, which means a recalc_rate will be issued.
+ * If clk is NULL then returns 0.
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_get_rate(clk->core);
+}
EXPORT_SYMBOL_GPL(clk_get_rate);
-static int clk_fetch_parent_index(struct clk *clk, struct clk *parent)
+static int clk_fetch_parent_index(struct clk_core *clk,
+ struct clk_core *parent)
{
int i;
@@ -1160,7 +1384,7 @@ static int clk_fetch_parent_index(struct clk *clk, struct clk *parent)
/*
* find index of new parent clock using cached parent ptrs,
* or if not yet cached, use string name comparison and cache
- * them now to avoid future calls to __clk_lookup.
+ * them now to avoid future calls to clk_core_lookup.
*/
for (i = 0; i < clk->num_parents; i++) {
if (clk->parents[i] == parent)
@@ -1170,7 +1394,7 @@ static int clk_fetch_parent_index(struct clk *clk, struct clk *parent)
continue;
if (!strcmp(clk->parent_names[i], parent->name)) {
- clk->parents[i] = __clk_lookup(parent->name);
+ clk->parents[i] = clk_core_lookup(parent->name);
return i;
}
}
@@ -1178,7 +1402,7 @@ static int clk_fetch_parent_index(struct clk *clk, struct clk *parent)
return -EINVAL;
}
-static void clk_reparent(struct clk *clk, struct clk *new_parent)
+static void clk_reparent(struct clk_core *clk, struct clk_core *new_parent)
{
hlist_del(&clk->child_node);
@@ -1195,10 +1419,11 @@ static void clk_reparent(struct clk *clk, struct clk *new_parent)
clk->parent = new_parent;
}
-static struct clk *__clk_set_parent_before(struct clk *clk, struct clk *parent)
+static struct clk_core *__clk_set_parent_before(struct clk_core *clk,
+ struct clk_core *parent)
{
unsigned long flags;
- struct clk *old_parent = clk->parent;
+ struct clk_core *old_parent = clk->parent;
/*
* Migrate prepare state between parents and prevent race with
@@ -1218,9 +1443,9 @@ static struct clk *__clk_set_parent_before(struct clk *clk, struct clk *parent)
* See also: Comment for clk_set_parent() below.
*/
if (clk->prepare_count) {
- __clk_prepare(parent);
- clk_enable(parent);
- clk_enable(clk);
+ clk_core_prepare(parent);
+ clk_core_enable(parent);
+ clk_core_enable(clk);
}
/* update the clk tree topology */
@@ -1231,25 +1456,27 @@ static struct clk *__clk_set_parent_before(struct clk *clk, struct clk *parent)
return old_parent;
}
-static void __clk_set_parent_after(struct clk *clk, struct clk *parent,
- struct clk *old_parent)
+static void __clk_set_parent_after(struct clk_core *core,
+ struct clk_core *parent,
+ struct clk_core *old_parent)
{
/*
* Finish the migration of prepare state and undo the changes done
* for preventing a race with clk_enable().
*/
- if (clk->prepare_count) {
- clk_disable(clk);
- clk_disable(old_parent);
- __clk_unprepare(old_parent);
+ if (core->prepare_count) {
+ clk_core_disable(core);
+ clk_core_disable(old_parent);
+ clk_core_unprepare(old_parent);
}
}
-static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
+static int __clk_set_parent(struct clk_core *clk, struct clk_core *parent,
+ u8 p_index)
{
unsigned long flags;
int ret = 0;
- struct clk *old_parent;
+ struct clk_core *old_parent;
old_parent = __clk_set_parent_before(clk, parent);
@@ -1263,9 +1490,9 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
clk_enable_unlock(flags);
if (clk->prepare_count) {
- clk_disable(clk);
- clk_disable(parent);
- __clk_unprepare(parent);
+ clk_core_disable(clk);
+ clk_core_disable(parent);
+ clk_core_unprepare(parent);
}
return ret;
}
@@ -1291,9 +1518,10 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
*
* Caller must hold prepare_lock.
*/
-static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
+static int __clk_speculate_rates(struct clk_core *clk,
+ unsigned long parent_rate)
{
- struct clk *child;
+ struct clk_core *child;
unsigned long new_rate;
int ret = NOTIFY_DONE;
@@ -1319,10 +1547,10 @@ out:
return ret;
}
-static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
- struct clk *new_parent, u8 p_index)
+static void clk_calc_subtree(struct clk_core *clk, unsigned long new_rate,
+ struct clk_core *new_parent, u8 p_index)
{
- struct clk *child;
+ struct clk_core *child;
clk->new_rate = new_rate;
clk->new_parent = new_parent;
@@ -1342,13 +1570,16 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
* calculate the new rates returning the topmost clock that has to be
* changed.
*/
-static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
+static struct clk_core *clk_calc_new_rates(struct clk_core *clk,
+ unsigned long rate)
{
- struct clk *top = clk;
- struct clk *old_parent, *parent;
+ struct clk_core *top = clk;
+ struct clk_core *old_parent, *parent;
struct clk_hw *parent_hw;
unsigned long best_parent_rate = 0;
unsigned long new_rate;
+ unsigned long min_rate;
+ unsigned long max_rate;
int p_index = 0;
/* sanity */
@@ -1360,16 +1591,22 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
if (parent)
best_parent_rate = parent->rate;
+ clk_core_get_boundaries(clk, &min_rate, &max_rate);
+
/* find the closest rate and parent clk/rate */
if (clk->ops->determine_rate) {
parent_hw = parent ? parent->hw : NULL;
new_rate = clk->ops->determine_rate(clk->hw, rate,
+ min_rate,
+ max_rate,
&best_parent_rate,
&parent_hw);
- parent = parent_hw ? parent_hw->clk : NULL;
+ parent = parent_hw ? parent_hw->core : NULL;
} else if (clk->ops->round_rate) {
new_rate = clk->ops->round_rate(clk->hw, rate,
&best_parent_rate);
+ if (new_rate < min_rate || new_rate > max_rate)
+ return NULL;
} else if (!parent || !(clk->flags & CLK_SET_RATE_PARENT)) {
/* pass-through clock without adjustable parent */
clk->new_rate = clk->rate;
@@ -1390,7 +1627,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
}
/* try finding the new parent index */
- if (parent) {
+ if (parent && clk->num_parents > 1) {
p_index = clk_fetch_parent_index(clk, parent);
if (p_index < 0) {
pr_debug("%s: clk %s can not be parent of clk %s\n",
@@ -1414,9 +1651,10 @@ out:
* so that in case of an error we can walk down the whole tree again and
* abort the change.
*/
-static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
+static struct clk_core *clk_propagate_rate_change(struct clk_core *clk,
+ unsigned long event)
{
- struct clk *child, *tmp_clk, *fail_clk = NULL;
+ struct clk_core *child, *tmp_clk, *fail_clk = NULL;
int ret = NOTIFY_DONE;
if (clk->rate == clk->new_rate)
@@ -1451,14 +1689,14 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even
* walk down a subtree and set the new rates notifying the rate
* change on the way
*/
-static void clk_change_rate(struct clk *clk)
+static void clk_change_rate(struct clk_core *clk)
{
- struct clk *child;
+ struct clk_core *child;
struct hlist_node *tmp;
unsigned long old_rate;
unsigned long best_parent_rate = 0;
bool skip_set_rate = false;
- struct clk *old_parent;
+ struct clk_core *old_parent;
old_rate = clk->rate;
@@ -1506,6 +1744,45 @@ static void clk_change_rate(struct clk *clk)
clk_change_rate(clk->new_child);
}
+static int clk_core_set_rate_nolock(struct clk_core *clk,
+ unsigned long req_rate)
+{
+ struct clk_core *top, *fail_clk;
+ unsigned long rate = req_rate;
+ int ret = 0;
+
+ if (!clk)
+ return 0;
+
+ /* bail early if nothing to do */
+ if (rate == clk_core_get_rate_nolock(clk))
+ return 0;
+
+ if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count)
+ return -EBUSY;
+
+ /* calculate new rates and get the topmost changed clock */
+ top = clk_calc_new_rates(clk, rate);
+ if (!top)
+ return -EINVAL;
+
+ /* notify that we are about to change rates */
+ fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
+ if (fail_clk) {
+ pr_debug("%s: failed to set %s rate\n", __func__,
+ fail_clk->name);
+ clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
+ return -EBUSY;
+ }
+
+ /* change the rates */
+ clk_change_rate(top);
+
+ clk->req_rate = req_rate;
+
+ return ret;
+}
+
/**
* clk_set_rate - specify a new rate for clk
* @clk: the clk whose rate is being changed
@@ -1529,8 +1806,7 @@ static void clk_change_rate(struct clk *clk)
*/
int clk_set_rate(struct clk *clk, unsigned long rate)
{
- struct clk *top, *fail_clk;
- int ret = 0;
+ int ret;
if (!clk)
return 0;
@@ -1538,41 +1814,81 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
/* prevent racing with updates to the clock topology */
clk_prepare_lock();
- /* bail early if nothing to do */
- if (rate == clk_get_rate(clk))
- goto out;
+ ret = clk_core_set_rate_nolock(clk->core, rate);
- if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count) {
- ret = -EBUSY;
- goto out;
- }
+ clk_prepare_unlock();
- /* calculate new rates and get the topmost changed clock */
- top = clk_calc_new_rates(clk, rate);
- if (!top) {
- ret = -EINVAL;
- goto out;
- }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
- /* notify that we are about to change rates */
- fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
- if (fail_clk) {
- pr_debug("%s: failed to set %s rate\n", __func__,
- fail_clk->name);
- clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
- ret = -EBUSY;
- goto out;
+/**
+ * clk_set_rate_range - set a rate range for a clock source
+ * @clk: clock source
+ * @min: desired minimum clock rate in Hz, inclusive
+ * @max: desired maximum clock rate in Hz, inclusive
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
+{
+ int ret = 0;
+
+ if (!clk)
+ return 0;
+
+ if (min > max) {
+ pr_err("%s: clk %s dev %s con %s: invalid range [%lu, %lu]\n",
+ __func__, clk->core->name, clk->dev_id, clk->con_id,
+ min, max);
+ return -EINVAL;
}
- /* change the rates */
- clk_change_rate(top);
+ clk_prepare_lock();
+
+ if (min != clk->min_rate || max != clk->max_rate) {
+ clk->min_rate = min;
+ clk->max_rate = max;
+ ret = clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
+ }
-out:
clk_prepare_unlock();
return ret;
}
-EXPORT_SYMBOL_GPL(clk_set_rate);
+EXPORT_SYMBOL_GPL(clk_set_rate_range);
+
+/**
+ * clk_set_min_rate - set a minimum clock rate for a clock source
+ * @clk: clock source
+ * @rate: desired minimum clock rate in Hz, inclusive
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_min_rate(struct clk *clk, unsigned long rate)
+{
+ if (!clk)
+ return 0;
+
+ return clk_set_rate_range(clk, rate, clk->max_rate);
+}
+EXPORT_SYMBOL_GPL(clk_set_min_rate);
+
+/**
+ * clk_set_max_rate - set a maximum clock rate for a clock source
+ * @clk: clock source
+ * @rate: desired maximum clock rate in Hz, inclusive
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_max_rate(struct clk *clk, unsigned long rate)
+{
+ if (!clk)
+ return 0;
+
+ return clk_set_rate_range(clk, clk->min_rate, rate);
+}
+EXPORT_SYMBOL_GPL(clk_set_max_rate);
/**
* clk_get_parent - return the parent of a clk
@@ -1599,11 +1915,11 @@ EXPORT_SYMBOL_GPL(clk_get_parent);
*
* For single-parent clocks without .get_parent, first check to see if the
* .parents array exists, and if so use it to avoid an expensive tree
- * traversal. If .parents does not exist then walk the tree with __clk_lookup.
+ * traversal. If .parents does not exist then walk the tree.
*/
-static struct clk *__clk_init_parent(struct clk *clk)
+static struct clk_core *__clk_init_parent(struct clk_core *clk)
{
- struct clk *ret = NULL;
+ struct clk_core *ret = NULL;
u8 index;
/* handle the trivial cases */
@@ -1613,7 +1929,7 @@ static struct clk *__clk_init_parent(struct clk *clk)
if (clk->num_parents == 1) {
if (IS_ERR_OR_NULL(clk->parent))
- clk->parent = __clk_lookup(clk->parent_names[0]);
+ clk->parent = clk_core_lookup(clk->parent_names[0]);
ret = clk->parent;
goto out;
}
@@ -1627,8 +1943,8 @@ static struct clk *__clk_init_parent(struct clk *clk)
/*
* Do our best to cache parent clocks in clk->parents. This prevents
- * unnecessary and expensive calls to __clk_lookup. We don't set
- * clk->parent here; that is done by the calling function
+ * unnecessary and expensive lookups. We don't set clk->parent here;
+ * that is done by the calling function.
*/
index = clk->ops->get_parent(clk->hw);
@@ -1638,13 +1954,14 @@ static struct clk *__clk_init_parent(struct clk *clk)
kcalloc(clk->num_parents, sizeof(struct clk *),
GFP_KERNEL);
- ret = clk_get_parent_by_index(clk, index);
+ ret = clk_core_get_parent_by_index(clk, index);
out:
return ret;
}
-void __clk_reparent(struct clk *clk, struct clk *new_parent)
+static void clk_core_reparent(struct clk_core *clk,
+ struct clk_core *new_parent)
{
clk_reparent(clk, new_parent);
__clk_recalc_accuracies(clk);
@@ -1652,23 +1969,40 @@ void __clk_reparent(struct clk *clk, struct clk *new_parent)
}
/**
- * clk_set_parent - switch the parent of a mux clk
- * @clk: the mux clk whose input we are switching
- * @parent: the new input to clk
+ * clk_has_parent - check if a clock is a possible parent for another
+ * @clk: clock source
+ * @parent: parent clock source
*
- * Re-parent clk to use parent as its new input source. If clk is in
- * prepared state, the clk will get enabled for the duration of this call. If
- * that's not acceptable for a specific clk (Eg: the consumer can't handle
- * that, the reparenting is glitchy in hardware, etc), use the
- * CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared.
- *
- * After successfully changing clk's parent clk_set_parent will update the
- * clk topology, sysfs topology and propagate rate recalculation via
- * __clk_recalc_rates.
+ * This function can be used in drivers that need to check that a clock can be
+ * the parent of another without actually changing the parent.
*
- * Returns 0 on success, -EERROR otherwise.
+ * Returns true if @parent is a possible parent for @clk, false otherwise.
*/
-int clk_set_parent(struct clk *clk, struct clk *parent)
+bool clk_has_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_core *core, *parent_core;
+ unsigned int i;
+
+ /* NULL clocks should be nops, so return success if either is NULL. */
+ if (!clk || !parent)
+ return true;
+
+ core = clk->core;
+ parent_core = parent->core;
+
+ /* Optimize for the case where the parent is already the parent. */
+ if (core->parent == parent_core)
+ return true;
+
+ for (i = 0; i < core->num_parents; i++)
+ if (strcmp(core->parent_names[i], parent_core->name) == 0)
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(clk_has_parent);
+
+static int clk_core_set_parent(struct clk_core *clk, struct clk_core *parent)
{
int ret = 0;
int p_index = 0;
@@ -1728,6 +2062,31 @@ out:
return ret;
}
+
+/**
+ * clk_set_parent - switch the parent of a mux clk
+ * @clk: the mux clk whose input we are switching
+ * @parent: the new input to clk
+ *
+ * Re-parent clk to use parent as its new input source. If clk is in
+ * prepared state, the clk will get enabled for the duration of this call. If
+ * that's not acceptable for a specific clk (Eg: the consumer can't handle
+ * that, the reparenting is glitchy in hardware, etc), use the
+ * CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared.
+ *
+ * After successfully changing clk's parent clk_set_parent will update the
+ * clk topology, sysfs topology and propagate rate recalculation via
+ * __clk_recalc_rates.
+ *
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_set_parent(clk->core, parent ? parent->core : NULL);
+}
EXPORT_SYMBOL_GPL(clk_set_parent);
/**
@@ -1764,13 +2123,13 @@ int clk_set_phase(struct clk *clk, int degrees)
clk_prepare_lock();
- if (!clk->ops->set_phase)
+ if (!clk->core->ops->set_phase)
goto out_unlock;
- ret = clk->ops->set_phase(clk->hw, degrees);
+ ret = clk->core->ops->set_phase(clk->core->hw, degrees);
if (!ret)
- clk->phase = degrees;
+ clk->core->phase = degrees;
out_unlock:
clk_prepare_unlock();
@@ -1778,15 +2137,9 @@ out_unlock:
out:
return ret;
}
+EXPORT_SYMBOL_GPL(clk_set_phase);
-/**
- * clk_get_phase - return the phase shift of a clock signal
- * @clk: clock signal source
- *
- * Returns the phase shift of a clock node in degrees, otherwise returns
- * -EERROR.
- */
-int clk_get_phase(struct clk *clk)
+static int clk_core_get_phase(struct clk_core *clk)
{
int ret = 0;
@@ -1800,28 +2153,48 @@ int clk_get_phase(struct clk *clk)
out:
return ret;
}
+EXPORT_SYMBOL_GPL(clk_get_phase);
+
+/**
+ * clk_get_phase - return the phase shift of a clock signal
+ * @clk: clock signal source
+ *
+ * Returns the phase shift of a clock node in degrees, otherwise returns
+ * -EERROR.
+ */
+int clk_get_phase(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_get_phase(clk->core);
+}
/**
* __clk_init - initialize the data structures in a struct clk
* @dev: device initializing this clk, placeholder for now
* @clk: clk being initialized
*
- * Initializes the lists in struct clk, queries the hardware for the
+ * Initializes the lists in struct clk_core, queries the hardware for the
* parent and rate and sets them both.
*/
-int __clk_init(struct device *dev, struct clk *clk)
+static int __clk_init(struct device *dev, struct clk *clk_user)
{
int i, ret = 0;
- struct clk *orphan;
+ struct clk_core *orphan;
struct hlist_node *tmp2;
+ struct clk_core *clk;
+ unsigned long rate;
- if (!clk)
+ if (!clk_user)
return -EINVAL;
+ clk = clk_user->core;
+
clk_prepare_lock();
/* check to see if a clock with this name is already registered */
- if (__clk_lookup(clk->name)) {
+ if (clk_core_lookup(clk->name)) {
pr_debug("%s: clk %s already initialized\n",
__func__, clk->name);
ret = -EEXIST;
@@ -1873,7 +2246,7 @@ int __clk_init(struct device *dev, struct clk *clk)
clk->parents = kcalloc(clk->num_parents, sizeof(struct clk *),
GFP_KERNEL);
/*
- * __clk_lookup returns NULL for parents that have not been
+ * clk_core_lookup returns NULL for parents that have not been
* clk_init'd; thus any access to clk->parents[] must check
* for a NULL pointer. We can always perform lazy lookups for
* missing parents later on.
@@ -1881,7 +2254,7 @@ int __clk_init(struct device *dev, struct clk *clk)
if (clk->parents)
for (i = 0; i < clk->num_parents; i++)
clk->parents[i] =
- __clk_lookup(clk->parent_names[i]);
+ clk_core_lookup(clk->parent_names[i]);
}
clk->parent = __clk_init_parent(clk);
@@ -1936,12 +2309,13 @@ int __clk_init(struct device *dev, struct clk *clk)
* then rate is set to zero.
*/
if (clk->ops->recalc_rate)
- clk->rate = clk->ops->recalc_rate(clk->hw,
- __clk_get_rate(clk->parent));
+ rate = clk->ops->recalc_rate(clk->hw,
+ clk_core_get_rate_nolock(clk->parent));
else if (clk->parent)
- clk->rate = clk->parent->rate;
+ rate = clk->parent->rate;
else
- clk->rate = 0;
+ rate = 0;
+ clk->rate = clk->req_rate = rate;
/*
* walk the list of orphan clocks and reparent any that are children of
@@ -1951,13 +2325,13 @@ int __clk_init(struct device *dev, struct clk *clk)
if (orphan->num_parents && orphan->ops->get_parent) {
i = orphan->ops->get_parent(orphan->hw);
if (!strcmp(clk->name, orphan->parent_names[i]))
- __clk_reparent(orphan, clk);
+ clk_core_reparent(orphan, clk);
continue;
}
for (i = 0; i < orphan->num_parents; i++)
if (!strcmp(clk->name, orphan->parent_names[i])) {
- __clk_reparent(orphan, clk);
+ clk_core_reparent(orphan, clk);
break;
}
}
@@ -1983,47 +2357,39 @@ out:
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 its operations. Returns 0
- * on success, otherwise an error code.
- */
-struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
+struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
+ const char *con_id)
{
- 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;
- if (dev && dev->driver)
- clk->owner = dev->driver->owner;
- else
- clk->owner = NULL;
+ /* This is to allow this function to be chained to others */
+ if (!hw || IS_ERR(hw))
+ return (struct clk *) hw;
- ret = __clk_init(dev, clk);
- if (ret)
- return ERR_PTR(ret);
+ clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+ if (!clk)
+ return ERR_PTR(-ENOMEM);
+
+ clk->core = hw->core;
+ clk->dev_id = dev_id;
+ clk->con_id = con_id;
+ clk->max_rate = ULONG_MAX;
+
+ clk_prepare_lock();
+ hlist_add_head(&clk->child_node, &hw->core->clks);
+ clk_prepare_unlock();
return clk;
}
-EXPORT_SYMBOL_GPL(__clk_register);
+
+void __clk_free_clk(struct clk *clk)
+{
+ clk_prepare_lock();
+ hlist_del(&clk->child_node);
+ clk_prepare_unlock();
+
+ kfree(clk);
+}
/**
* clk_register - allocate a new clock, register it and return an opaque cookie
@@ -2039,7 +2405,7 @@ EXPORT_SYMBOL_GPL(__clk_register);
struct clk *clk_register(struct device *dev, struct clk_hw *hw)
{
int i, ret;
- struct clk *clk;
+ struct clk_core *clk;
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk) {
@@ -2060,7 +2426,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
clk->hw = hw;
clk->flags = hw->init->flags;
clk->num_parents = hw->init->num_parents;
- hw->clk = clk;
+ hw->core = clk;
/* allocate local copy in case parent_names is __initdata */
clk->parent_names = kcalloc(clk->num_parents, sizeof(char *),
@@ -2084,9 +2450,21 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
}
}
- ret = __clk_init(dev, clk);
+ INIT_HLIST_HEAD(&clk->clks);
+
+ hw->clk = __clk_create_clk(hw, NULL, NULL);
+ if (IS_ERR(hw->clk)) {
+ pr_err("%s: could not allocate per-user clk\n", __func__);
+ ret = PTR_ERR(hw->clk);
+ goto fail_parent_names_copy;
+ }
+
+ ret = __clk_init(dev, hw->clk);
if (!ret)
- return clk;
+ return hw->clk;
+
+ __clk_free_clk(hw->clk);
+ hw->clk = NULL;
fail_parent_names_copy:
while (--i >= 0)
@@ -2107,7 +2485,7 @@ EXPORT_SYMBOL_GPL(clk_register);
*/
static void __clk_release(struct kref *ref)
{
- struct clk *clk = container_of(ref, struct clk, ref);
+ struct clk_core *clk = container_of(ref, struct clk_core, ref);
int i = clk->num_parents;
kfree(clk->parents);
@@ -2165,12 +2543,13 @@ void clk_unregister(struct clk *clk)
if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
return;
- clk_debug_unregister(clk);
+ clk_debug_unregister(clk->core);
clk_prepare_lock();
- if (clk->ops == &clk_nodrv_ops) {
- pr_err("%s: unregistered clock: %s\n", __func__, clk->name);
+ if (clk->core->ops == &clk_nodrv_ops) {
+ pr_err("%s: unregistered clock: %s\n", __func__,
+ clk->core->name);
return;
}
/*
@@ -2178,24 +2557,25 @@ void clk_unregister(struct clk *clk)
* a reference to this clock.
*/
flags = clk_enable_lock();
- clk->ops = &clk_nodrv_ops;
+ clk->core->ops = &clk_nodrv_ops;
clk_enable_unlock(flags);
- if (!hlist_empty(&clk->children)) {
- struct clk *child;
+ if (!hlist_empty(&clk->core->children)) {
+ struct clk_core *child;
struct hlist_node *t;
/* Reparent all children to the orphan list. */
- hlist_for_each_entry_safe(child, t, &clk->children, child_node)
- clk_set_parent(child, NULL);
+ hlist_for_each_entry_safe(child, t, &clk->core->children,
+ child_node)
+ clk_core_set_parent(child, NULL);
}
- hlist_del_init(&clk->child_node);
+ hlist_del_init(&clk->core->child_node);
- if (clk->prepare_count)
+ if (clk->core->prepare_count)
pr_warn("%s: unregistering prepared clock: %s\n",
- __func__, clk->name);
- kref_put(&clk->ref, __clk_release);
+ __func__, clk->core->name);
+ kref_put(&clk->core->ref, __clk_release);
clk_prepare_unlock();
}
@@ -2263,11 +2643,13 @@ EXPORT_SYMBOL_GPL(devm_clk_unregister);
*/
int __clk_get(struct clk *clk)
{
- if (clk) {
- if (!try_module_get(clk->owner))
+ struct clk_core *core = !clk ? NULL : clk->core;
+
+ if (core) {
+ if (!try_module_get(core->owner))
return 0;
- kref_get(&clk->ref);
+ kref_get(&core->ref);
}
return 1;
}
@@ -2280,11 +2662,20 @@ void __clk_put(struct clk *clk)
return;
clk_prepare_lock();
- owner = clk->owner;
- kref_put(&clk->ref, __clk_release);
+
+ hlist_del(&clk->child_node);
+ if (clk->min_rate > clk->core->req_rate ||
+ clk->max_rate < clk->core->req_rate)
+ clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
+
+ owner = clk->core->owner;
+ kref_put(&clk->core->ref, __clk_release);
+
clk_prepare_unlock();
module_put(owner);
+
+ kfree(clk);
}
/*** clk rate change notifiers ***/
@@ -2339,7 +2730,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
ret = srcu_notifier_chain_register(&cn->notifier_head, nb);
- clk->notifier_count++;
+ clk->core->notifier_count++;
out:
clk_prepare_unlock();
@@ -2376,7 +2767,7 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
if (cn->clk == clk) {
ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
- clk->notifier_count--;
+ clk->core->notifier_count--;
/* XXX the notifier code should handle this better */
if (!cn->notifier_head.head) {
@@ -2506,7 +2897,8 @@ void of_clk_del_provider(struct device_node *np)
}
EXPORT_SYMBOL_GPL(of_clk_del_provider);
-struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec)
+struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
+ const char *dev_id, const char *con_id)
{
struct of_clk_provider *provider;
struct clk *clk = ERR_PTR(-EPROBE_DEFER);
@@ -2515,8 +2907,17 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec)
list_for_each_entry(provider, &of_clk_providers, link) {
if (provider->node == clkspec->np)
clk = provider->get(clkspec, provider->data);
- if (!IS_ERR(clk))
+ if (!IS_ERR(clk)) {
+ clk = __clk_create_clk(__clk_get_hw(clk), dev_id,
+ con_id);
+
+ if (!IS_ERR(clk) && !__clk_get(clk)) {
+ __clk_free_clk(clk);
+ clk = ERR_PTR(-ENOENT);
+ }
+
break;
+ }
}
return clk;
@@ -2527,7 +2928,7 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
struct clk *clk;
mutex_lock(&of_clk_mutex);
- clk = __of_clk_get_from_provider(clkspec);
+ clk = __of_clk_get_from_provider(clkspec, NULL, __func__);
mutex_unlock(&of_clk_mutex);
return clk;
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index c798138f023f..ba845408cc3e 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -9,9 +9,31 @@
* published by the Free Software Foundation.
*/
+struct clk_hw;
+
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec);
-struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec);
+struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
+ const char *dev_id, const char *con_id);
void of_clk_lock(void);
void of_clk_unlock(void);
#endif
+
+#ifdef CONFIG_COMMON_CLK
+struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
+ const char *con_id);
+void __clk_free_clk(struct clk *clk);
+#else
+/* All these casts to avoid ifdefs in clkdev... */
+static inline struct clk *
+__clk_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id)
+{
+ return (struct clk *)hw;
+}
+static inline void __clk_free_clk(struct clk *clk) { }
+static struct clk_hw *__clk_get_hw(struct clk *clk)
+{
+ return (struct clk_hw *)clk;
+}
+
+#endif
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index da4bda8b7fc7..043fd3633373 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -19,6 +19,7 @@
#include <linux/mutex.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
#include <linux/of.h>
#include "clk.h"
@@ -28,6 +29,20 @@ static DEFINE_MUTEX(clocks_mutex);
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
+static struct clk *__of_clk_get_by_clkspec(struct of_phandle_args *clkspec,
+ const char *dev_id, const char *con_id)
+{
+ struct clk *clk;
+
+ if (!clkspec)
+ return ERR_PTR(-EINVAL);
+
+ of_clk_lock();
+ clk = __of_clk_get_from_provider(clkspec, dev_id, con_id);
+ of_clk_unlock();
+ return clk;
+}
+
/**
* of_clk_get_by_clkspec() - Lookup a clock form a clock provider
* @clkspec: pointer to a clock specifier data structure
@@ -38,22 +53,11 @@ static DEFINE_MUTEX(clocks_mutex);
*/
struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec)
{
- struct clk *clk;
-
- if (!clkspec)
- return ERR_PTR(-EINVAL);
-
- of_clk_lock();
- clk = __of_clk_get_from_provider(clkspec);
-
- if (!IS_ERR(clk) && !__clk_get(clk))
- clk = ERR_PTR(-ENOENT);
-
- of_clk_unlock();
- return clk;
+ return __of_clk_get_by_clkspec(clkspec, NULL, __func__);
}
-struct clk *of_clk_get(struct device_node *np, int index)
+static struct clk *__of_clk_get(struct device_node *np, int index,
+ const char *dev_id, const char *con_id)
{
struct of_phandle_args clkspec;
struct clk *clk;
@@ -67,22 +71,21 @@ struct clk *of_clk_get(struct device_node *np, int index)
if (rc)
return ERR_PTR(rc);
- clk = of_clk_get_by_clkspec(&clkspec);
+ clk = __of_clk_get_by_clkspec(&clkspec, dev_id, con_id);
of_node_put(clkspec.np);
+
return clk;
}
+
+struct clk *of_clk_get(struct device_node *np, int index)
+{
+ return __of_clk_get(np, index, np->full_name, NULL);
+}
EXPORT_SYMBOL(of_clk_get);
-/**
- * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
- * @np: pointer to clock consumer node
- * @name: name of consumer's clock input, or NULL for the first clock reference
- *
- * This function parses the clocks and clock-names properties,
- * and uses them to look up the struct clk from the registered list of clock
- * providers.
- */
-struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
+static struct clk *__of_clk_get_by_name(struct device_node *np,
+ const char *dev_id,
+ const char *name)
{
struct clk *clk = ERR_PTR(-ENOENT);
@@ -97,10 +100,10 @@ struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
*/
if (name)
index = of_property_match_string(np, "clock-names", name);
- clk = of_clk_get(np, index);
- if (!IS_ERR(clk))
+ clk = __of_clk_get(np, index, dev_id, name);
+ if (!IS_ERR(clk)) {
break;
- else if (name && index >= 0) {
+ } else if (name && index >= 0) {
if (PTR_ERR(clk) != -EPROBE_DEFER)
pr_err("ERROR: could not get clock %s:%s(%i)\n",
np->full_name, name ? name : "", index);
@@ -119,7 +122,33 @@ struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
return clk;
}
+
+/**
+ * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
+ * @np: pointer to clock consumer node
+ * @name: name of consumer's clock input, or NULL for the first clock reference
+ *
+ * This function parses the clocks and clock-names properties,
+ * and uses them to look up the struct clk from the registered list of clock
+ * providers.
+ */
+struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
+{
+ if (!np)
+ return ERR_PTR(-ENOENT);
+
+ return __of_clk_get_by_name(np, np->full_name, name);
+}
EXPORT_SYMBOL(of_clk_get_by_name);
+
+#else /* defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) */
+
+static struct clk *__of_clk_get_by_name(struct device_node *np,
+ const char *dev_id,
+ const char *name)
+{
+ return ERR_PTR(-ENOENT);
+}
#endif
/*
@@ -168,14 +197,28 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
{
struct clk_lookup *cl;
+ struct clk *clk = NULL;
mutex_lock(&clocks_mutex);
+
cl = clk_find(dev_id, con_id);
- if (cl && !__clk_get(cl->clk))
+ if (!cl)
+ goto out;
+
+ clk = __clk_create_clk(__clk_get_hw(cl->clk), dev_id, con_id);
+ if (IS_ERR(clk))
+ goto out;
+
+ if (!__clk_get(clk)) {
+ __clk_free_clk(clk);
cl = NULL;
+ goto out;
+ }
+
+out:
mutex_unlock(&clocks_mutex);
- return cl ? cl->clk : ERR_PTR(-ENOENT);
+ return cl ? clk : ERR_PTR(-ENOENT);
}
EXPORT_SYMBOL(clk_get_sys);
@@ -185,10 +228,8 @@ struct clk *clk_get(struct device *dev, const char *con_id)
struct clk *clk;
if (dev) {
- clk = of_clk_get_by_name(dev->of_node, con_id);
- if (!IS_ERR(clk))
- return clk;
- if (PTR_ERR(clk) == -EPROBE_DEFER)
+ clk = __of_clk_get_by_name(dev->of_node, dev_id, con_id);
+ if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)
return clk;
}
@@ -331,6 +372,7 @@ int clk_register_clkdev(struct clk *clk, const char *con_id,
return 0;
}
+EXPORT_SYMBOL(clk_register_clkdev);
/**
* clk_register_clkdevs - register a set of clk_lookup for a struct clk
diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c
index 007144f81f50..2e4f6d432beb 100644
--- a/drivers/clk/hisilicon/clk-hi3620.c
+++ b/drivers/clk/hisilicon/clk-hi3620.c
@@ -295,6 +295,8 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
}
static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p)
{
diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c
index 48fa53c7ce5e..de6a873175d2 100644
--- a/drivers/clk/mmp/clk-mix.c
+++ b/drivers/clk/mmp/clk-mix.c
@@ -202,6 +202,8 @@ error:
}
static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk)
{
diff --git a/drivers/clk/pxa/Makefile b/drivers/clk/pxa/Makefile
index 38e915344605..38e37bf6b821 100644
--- a/drivers/clk/pxa/Makefile
+++ b/drivers/clk/pxa/Makefile
@@ -1,3 +1,4 @@
obj-y += clk-pxa.o
obj-$(CONFIG_PXA25x) += clk-pxa25x.o
obj-$(CONFIG_PXA27x) += clk-pxa27x.o
+obj-$(CONFIG_PXA3xx) += clk-pxa3xx.o
diff --git a/drivers/clk/pxa/clk-pxa.c b/drivers/clk/pxa/clk-pxa.c
index 4e834753ab09..29cee9e8d4d9 100644
--- a/drivers/clk/pxa/clk-pxa.c
+++ b/drivers/clk/pxa/clk-pxa.c
@@ -46,7 +46,7 @@ static unsigned long cken_recalc_rate(struct clk_hw *hw,
fix = &pclk->lp;
else
fix = &pclk->hp;
- fix->hw.clk = hw->clk;
+ __clk_hw_set_clk(&fix->hw, hw);
return clk_fixed_factor_ops.recalc_rate(&fix->hw, parent_rate);
}
diff --git a/drivers/clk/pxa/clk-pxa3xx.c b/drivers/clk/pxa/clk-pxa3xx.c
new file mode 100644
index 000000000000..39f891bba09a
--- /dev/null
+++ b/drivers/clk/pxa/clk-pxa3xx.c
@@ -0,0 +1,364 @@
+/*
+ * Marvell PXA3xxx family clocks
+ *
+ * Copyright (C) 2014 Robert Jarzmik
+ *
+ * Heavily inspired from former arch/arm/mach-pxa/pxa3xx.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * For non-devicetree platforms. Once pxa is fully converted to devicetree, this
+ * should go away.
+ */
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <mach/smemc.h>
+#include <mach/pxa3xx-regs.h>
+
+#include <dt-bindings/clock/pxa-clock.h>
+#include "clk-pxa.h"
+
+#define KHz 1000
+#define MHz (1000 * 1000)
+
+enum {
+ PXA_CORE_60Mhz = 0,
+ PXA_CORE_RUN,
+ PXA_CORE_TURBO,
+};
+
+enum {
+ PXA_BUS_60Mhz = 0,
+ PXA_BUS_HSS,
+};
+
+/* crystal frequency to HSIO bus frequency multiplier (HSS) */
+static unsigned char hss_mult[4] = { 8, 12, 16, 24 };
+
+/* crystal frequency to static memory controller multiplier (SMCFS) */
+static unsigned int smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
+static unsigned int df_clkdiv[4] = { 1, 2, 4, 1 };
+
+static const char * const get_freq_khz[] = {
+ "core", "ring_osc_60mhz", "run", "cpll", "system_bus"
+};
+
+/*
+ * Get the clock frequency as reflected by ACSR and the turbo flag.
+ * We assume these values have been applied via a fcs.
+ * If info is not 0 we also display the current settings.
+ */
+unsigned int pxa3xx_get_clk_frequency_khz(int info)
+{
+ struct clk *clk;
+ unsigned long clks[5];
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ clk = clk_get(NULL, get_freq_khz[i]);
+ if (IS_ERR(clk)) {
+ clks[i] = 0;
+ } else {
+ clks[i] = clk_get_rate(clk);
+ clk_put(clk);
+ }
+ }
+ if (info) {
+ pr_info("RO Mode clock: %ld.%02ldMHz\n",
+ clks[1] / 1000000, (clks[0] % 1000000) / 10000);
+ pr_info("Run Mode clock: %ld.%02ldMHz\n",
+ clks[2] / 1000000, (clks[1] % 1000000) / 10000);
+ pr_info("Turbo Mode clock: %ld.%02ldMHz\n",
+ clks[3] / 1000000, (clks[2] % 1000000) / 10000);
+ pr_info("System bus clock: %ld.%02ldMHz\n",
+ clks[4] / 1000000, (clks[4] % 1000000) / 10000);
+ }
+ return (unsigned int)clks[0];
+}
+
+static unsigned long clk_pxa3xx_ac97_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long ac97_div, rate;
+
+ ac97_div = AC97_DIV;
+
+ /* This may loose precision for some rates but won't for the
+ * standard 24.576MHz.
+ */
+ rate = parent_rate / 2;
+ rate /= ((ac97_div >> 12) & 0x7fff);
+ rate *= (ac97_div & 0xfff);
+
+ return rate;
+}
+PARENTS(clk_pxa3xx_ac97) = { "spll_624mhz" };
+RATE_RO_OPS(clk_pxa3xx_ac97, "ac97");
+
+static unsigned long clk_pxa3xx_smemc_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long acsr = ACSR;
+ unsigned long memclkcfg = __raw_readl(MEMCLKCFG);
+
+ return (parent_rate / 48) * smcfs_mult[(acsr >> 23) & 0x7] /
+ df_clkdiv[(memclkcfg >> 16) & 0x3];
+}
+PARENTS(clk_pxa3xx_smemc) = { "spll_624mhz" };
+RATE_RO_OPS(clk_pxa3xx_smemc, "smemc");
+
+static bool pxa3xx_is_ring_osc_forced(void)
+{
+ unsigned long acsr = ACSR;
+
+ return acsr & ACCR_D0CS;
+}
+
+PARENTS(pxa3xx_pbus) = { "ring_osc_60mhz", "spll_624mhz" };
+PARENTS(pxa3xx_32Khz_bus) = { "osc_32_768khz", "osc_32_768khz" };
+PARENTS(pxa3xx_13MHz_bus) = { "osc_13mhz", "osc_13mhz" };
+PARENTS(pxa3xx_ac97_bus) = { "ring_osc_60mhz", "ac97" };
+PARENTS(pxa3xx_sbus) = { "ring_osc_60mhz", "system_bus" };
+PARENTS(pxa3xx_smemcbus) = { "ring_osc_60mhz", "smemc" };
+
+#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENA : &CKENB)
+#define PXA3XX_CKEN(dev_id, con_id, parents, mult_lp, div_lp, mult_hp, \
+ div_hp, bit, is_lp, flags) \
+ PXA_CKEN(dev_id, con_id, bit, parents, mult_lp, div_lp, \
+ mult_hp, div_hp, is_lp, CKEN_AB(bit), \
+ (CKEN_ ## bit % 32), flags)
+#define PXA3XX_PBUS_CKEN(dev_id, con_id, bit, mult_lp, div_lp, \
+ mult_hp, div_hp, delay) \
+ PXA3XX_CKEN(dev_id, con_id, pxa3xx_pbus_parents, mult_lp, \
+ div_lp, mult_hp, div_hp, bit, pxa3xx_is_ring_osc_forced, 0)
+#define PXA3XX_CKEN_1RATE(dev_id, con_id, bit, parents) \
+ PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \
+ CKEN_AB(bit), (CKEN_ ## bit % 32), 0)
+
+static struct desc_clk_cken pxa3xx_clocks[] __initdata = {
+ PXA3XX_PBUS_CKEN("pxa2xx-uart.0", NULL, FFUART, 1, 4, 1, 42, 1),
+ PXA3XX_PBUS_CKEN("pxa2xx-uart.1", NULL, BTUART, 1, 4, 1, 42, 1),
+ PXA3XX_PBUS_CKEN("pxa2xx-uart.2", NULL, STUART, 1, 4, 1, 42, 1),
+ PXA3XX_PBUS_CKEN("pxa2xx-i2c.0", NULL, I2C, 2, 5, 1, 19, 0),
+ PXA3XX_PBUS_CKEN("pxa27x-udc", NULL, UDC, 1, 4, 1, 13, 5),
+ PXA3XX_PBUS_CKEN("pxa27x-ohci", NULL, USBH, 1, 4, 1, 13, 0),
+ PXA3XX_PBUS_CKEN("pxa3xx-u2d", NULL, USB2, 1, 4, 1, 13, 0),
+ PXA3XX_PBUS_CKEN("pxa27x-pwm.0", NULL, PWM0, 1, 6, 1, 48, 0),
+ PXA3XX_PBUS_CKEN("pxa27x-pwm.1", NULL, PWM1, 1, 6, 1, 48, 0),
+ PXA3XX_PBUS_CKEN("pxa2xx-mci.0", NULL, MMC1, 1, 4, 1, 24, 0),
+ PXA3XX_PBUS_CKEN("pxa2xx-mci.1", NULL, MMC2, 1, 4, 1, 24, 0),
+ PXA3XX_PBUS_CKEN("pxa2xx-mci.2", NULL, MMC3, 1, 4, 1, 24, 0),
+
+ PXA3XX_CKEN_1RATE("pxa27x-keypad", NULL, KEYPAD,
+ pxa3xx_32Khz_bus_parents),
+ PXA3XX_CKEN_1RATE("pxa3xx-ssp.0", NULL, SSP1, pxa3xx_13MHz_bus_parents),
+ PXA3XX_CKEN_1RATE("pxa3xx-ssp.1", NULL, SSP2, pxa3xx_13MHz_bus_parents),
+ PXA3XX_CKEN_1RATE("pxa3xx-ssp.2", NULL, SSP3, pxa3xx_13MHz_bus_parents),
+ PXA3XX_CKEN_1RATE("pxa3xx-ssp.3", NULL, SSP4, pxa3xx_13MHz_bus_parents),
+
+ PXA3XX_CKEN(NULL, "AC97CLK", pxa3xx_ac97_bus_parents, 1, 4, 1, 1, AC97,
+ pxa3xx_is_ring_osc_forced, 0),
+ PXA3XX_CKEN(NULL, "CAMCLK", pxa3xx_sbus_parents, 1, 2, 1, 1, CAMERA,
+ pxa3xx_is_ring_osc_forced, 0),
+ PXA3XX_CKEN("pxa2xx-fb", NULL, pxa3xx_sbus_parents, 1, 1, 1, 1, LCD,
+ pxa3xx_is_ring_osc_forced, 0),
+ PXA3XX_CKEN("pxa2xx-pcmcia", NULL, pxa3xx_smemcbus_parents, 1, 4,
+ 1, 1, SMC, pxa3xx_is_ring_osc_forced, CLK_IGNORE_UNUSED),
+};
+
+static struct desc_clk_cken pxa300_310_clocks[] __initdata = {
+
+ PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA300_GCU, 1, 1, 1, 1, 0),
+ PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 4, 0),
+ PXA3XX_CKEN_1RATE("pxa3xx-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents),
+};
+
+static struct desc_clk_cken pxa320_clocks[] __initdata = {
+ PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 6, 0),
+ PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA320_GCU, 1, 1, 1, 1, 0),
+ PXA3XX_CKEN_1RATE("pxa3xx-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents),
+};
+
+static struct desc_clk_cken pxa93x_clocks[] __initdata = {
+
+ PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA300_GCU, 1, 1, 1, 1, 0),
+ PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 4, 0),
+ PXA3XX_CKEN_1RATE("pxa93x-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents),
+};
+
+static unsigned long clk_pxa3xx_system_bus_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long acsr = ACSR;
+ unsigned int hss = (acsr >> 14) & 0x3;
+
+ if (pxa3xx_is_ring_osc_forced())
+ return parent_rate;
+ return parent_rate / 48 * hss_mult[hss];
+}
+
+static u8 clk_pxa3xx_system_bus_get_parent(struct clk_hw *hw)
+{
+ if (pxa3xx_is_ring_osc_forced())
+ return PXA_BUS_60Mhz;
+ else
+ return PXA_BUS_HSS;
+}
+
+PARENTS(clk_pxa3xx_system_bus) = { "ring_osc_60mhz", "spll_624mhz" };
+MUX_RO_RATE_RO_OPS(clk_pxa3xx_system_bus, "system_bus");
+
+static unsigned long clk_pxa3xx_core_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return parent_rate;
+}
+
+static u8 clk_pxa3xx_core_get_parent(struct clk_hw *hw)
+{
+ unsigned long xclkcfg;
+ unsigned int t;
+
+ if (pxa3xx_is_ring_osc_forced())
+ return PXA_CORE_60Mhz;
+
+ /* Read XCLKCFG register turbo bit */
+ __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
+ t = xclkcfg & 0x1;
+
+ if (t)
+ return PXA_CORE_TURBO;
+ return PXA_CORE_RUN;
+}
+PARENTS(clk_pxa3xx_core) = { "ring_osc_60mhz", "run", "cpll" };
+MUX_RO_RATE_RO_OPS(clk_pxa3xx_core, "core");
+
+static unsigned long clk_pxa3xx_run_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long acsr = ACSR;
+ unsigned int xn = (acsr & ACCR_XN_MASK) >> 8;
+ unsigned int t, xclkcfg;
+
+ /* Read XCLKCFG register turbo bit */
+ __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
+ t = xclkcfg & 0x1;
+
+ return t ? (parent_rate / xn) * 2 : parent_rate;
+}
+PARENTS(clk_pxa3xx_run) = { "cpll" };
+RATE_RO_OPS(clk_pxa3xx_run, "run");
+
+static unsigned long clk_pxa3xx_cpll_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long acsr = ACSR;
+ unsigned int xn = (acsr & ACCR_XN_MASK) >> 8;
+ unsigned int xl = acsr & ACCR_XL_MASK;
+ unsigned int t, xclkcfg;
+
+ /* Read XCLKCFG register turbo bit */
+ __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
+ t = xclkcfg & 0x1;
+
+ pr_info("RJK: parent_rate=%lu, xl=%u, xn=%u\n", parent_rate, xl, xn);
+ return t ? parent_rate * xl * xn : parent_rate * xl;
+}
+PARENTS(clk_pxa3xx_cpll) = { "osc_13mhz" };
+RATE_RO_OPS(clk_pxa3xx_cpll, "cpll");
+
+static void __init pxa3xx_register_core(void)
+{
+ clk_register_clk_pxa3xx_cpll();
+ clk_register_clk_pxa3xx_run();
+
+ clkdev_pxa_register(CLK_CORE, "core", NULL,
+ clk_register_clk_pxa3xx_core());
+}
+
+static void __init pxa3xx_register_plls(void)
+{
+ clk_register_fixed_rate(NULL, "osc_13mhz", NULL,
+ CLK_GET_RATE_NOCACHE | CLK_IS_ROOT,
+ 13 * MHz);
+ clk_register_fixed_rate(NULL, "osc_32_768khz", NULL,
+ CLK_GET_RATE_NOCACHE | CLK_IS_ROOT,
+ 32768);
+ clk_register_fixed_rate(NULL, "ring_osc_120mhz", NULL,
+ CLK_GET_RATE_NOCACHE | CLK_IS_ROOT,
+ 120 * MHz);
+ clk_register_fixed_rate(NULL, "clk_dummy", NULL, CLK_IS_ROOT, 0);
+ clk_register_fixed_factor(NULL, "spll_624mhz", "osc_13mhz", 0, 48, 1);
+ clk_register_fixed_factor(NULL, "ring_osc_60mhz", "ring_osc_120mhz",
+ 0, 1, 2);
+}
+
+#define DUMMY_CLK(_con_id, _dev_id, _parent) \
+ { .con_id = _con_id, .dev_id = _dev_id, .parent = _parent }
+struct dummy_clk {
+ const char *con_id;
+ const char *dev_id;
+ const char *parent;
+};
+static struct dummy_clk dummy_clks[] __initdata = {
+ DUMMY_CLK(NULL, "pxa93x-gpio", "osc_13mhz"),
+ DUMMY_CLK(NULL, "sa1100-rtc", "osc_32_768khz"),
+ DUMMY_CLK("UARTCLK", "pxa2xx-ir", "STUART"),
+ DUMMY_CLK(NULL, "pxa3xx-pwri2c.1", "osc_13mhz"),
+};
+
+static void __init pxa3xx_dummy_clocks_init(void)
+{
+ struct clk *clk;
+ struct dummy_clk *d;
+ const char *name;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dummy_clks); i++) {
+ d = &dummy_clks[i];
+ name = d->dev_id ? d->dev_id : d->con_id;
+ clk = clk_register_fixed_factor(NULL, name, d->parent, 0, 1, 1);
+ clk_register_clkdev(clk, d->con_id, d->dev_id);
+ }
+}
+
+static void __init pxa3xx_base_clocks_init(void)
+{
+ pxa3xx_register_plls();
+ pxa3xx_register_core();
+ clk_register_clk_pxa3xx_system_bus();
+ clk_register_clk_pxa3xx_ac97();
+ clk_register_clk_pxa3xx_smemc();
+ clk_register_gate(NULL, "CLK_POUT", "osc_13mhz", 0,
+ (void __iomem *)&OSCC, 11, 0, NULL);
+}
+
+int __init pxa3xx_clocks_init(void)
+{
+ int ret;
+
+ pxa3xx_base_clocks_init();
+ pxa3xx_dummy_clocks_init();
+ ret = clk_pxa_cken_init(pxa3xx_clocks, ARRAY_SIZE(pxa3xx_clocks));
+ if (ret)
+ return ret;
+ if (cpu_is_pxa320())
+ return clk_pxa_cken_init(pxa320_clocks,
+ ARRAY_SIZE(pxa320_clocks));
+ if (cpu_is_pxa300() || cpu_is_pxa310())
+ return clk_pxa_cken_init(pxa300_310_clocks,
+ ARRAY_SIZE(pxa300_310_clocks));
+ return clk_pxa_cken_init(pxa93x_clocks, ARRAY_SIZE(pxa93x_clocks));
+}
+
+static void __init pxa3xx_dt_clocks_init(struct device_node *np)
+{
+ pxa3xx_clocks_init();
+ clk_pxa_dt_common_init(np);
+}
+CLK_OF_DECLARE(pxa_clks, "marvell,pxa300-clocks", pxa3xx_dt_clocks_init);
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 1107351ed346..0d7ab52b7ab0 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -29,6 +29,15 @@ config IPQ_GCC_806X
Say Y if you want to use peripheral devices such as UART, SPI,
i2c, USB, SD/eMMC, etc.
+config IPQ_LCC_806X
+ tristate "IPQ806x LPASS Clock Controller"
+ select IPQ_GCC_806X
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the LPASS clock controller on ipq806x devices.
+ Say Y if you want to use audio devices such as i2s, pcm,
+ S/PDIF, etc.
+
config MSM_GCC_8660
tristate "MSM8660 Global Clock Controller"
depends on COMMON_CLK_QCOM
@@ -45,6 +54,15 @@ config MSM_GCC_8960
Say Y if you want to use peripheral devices such as UART, SPI,
i2c, USB, SD/eMMC, SATA, PCIe, etc.
+config MSM_LCC_8960
+ tristate "APQ8064/MSM8960 LPASS Clock Controller"
+ select MSM_GCC_8960
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the LPASS clock controller on apq8064/msm8960 devices.
+ Say Y if you want to use audio devices such as i2s, pcm,
+ SLIMBus, etc.
+
config MSM_MMCC_8960
tristate "MSM8960 Multimedia Clock Controller"
select MSM_GCC_8960
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 783cfb24faa4..617826469595 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -6,13 +6,17 @@ clk-qcom-y += clk-pll.o
clk-qcom-y += clk-rcg.o
clk-qcom-y += clk-rcg2.o
clk-qcom-y += clk-branch.o
+clk-qcom-y += clk-regmap-divider.o
+clk-qcom-y += clk-regmap-mux.o
clk-qcom-y += reset.o
obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
+obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o
obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o
obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o
+obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o
obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c
index 60873a7f45d9..b4325f65a1bf 100644
--- a/drivers/clk/qcom/clk-pll.c
+++ b/drivers/clk/qcom/clk-pll.c
@@ -141,6 +141,7 @@ struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
static long
clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_pll *pll = to_clk_pll(hw);
diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c
index 0b93972c8807..0039bd7d3965 100644
--- a/drivers/clk/qcom/clk-rcg.c
+++ b/drivers/clk/qcom/clk-rcg.c
@@ -368,6 +368,7 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
static long _freq_tbl_determine_rate(struct clk_hw *hw,
const struct freq_tbl *f, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p_hw)
{
unsigned long clk_flags;
@@ -397,22 +398,27 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
}
static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg *rcg = to_clk_rcg(hw);
- return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
+ return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
+ max_rate, p_rate, p);
}
static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
- return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
+ return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
+ max_rate, p_rate, p);
}
static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p_hw)
{
struct clk_rcg *rcg = to_clk_rcg(hw);
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 08b8b3729f53..742acfa18d63 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -208,6 +208,7 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
}
static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
@@ -361,6 +362,8 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw,
}
static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
@@ -412,6 +415,7 @@ const struct clk_ops clk_edp_pixel_ops = {
EXPORT_SYMBOL_GPL(clk_edp_pixel_ops);
static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p_hw)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
@@ -476,6 +480,8 @@ static const struct frac_entry frac_table_pixel[] = {
};
static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c
new file mode 100644
index 000000000000..53484912301e
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-divider.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/export.h>
+
+#include "clk-regmap-divider.h"
+
+static inline struct clk_regmap_div *to_clk_regmap_div(struct clk_hw *hw)
+{
+ return container_of(to_clk_regmap(hw), struct clk_regmap_div, clkr);
+}
+
+static long div_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_regmap_div *divider = to_clk_regmap_div(hw);
+
+ return divider_round_rate(hw, rate, prate, NULL, divider->width,
+ CLK_DIVIDER_ROUND_CLOSEST);
+}
+
+static int div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_regmap_div *divider = to_clk_regmap_div(hw);
+ struct clk_regmap *clkr = &divider->clkr;
+ u32 div;
+
+ div = divider_get_val(rate, parent_rate, NULL, divider->width,
+ CLK_DIVIDER_ROUND_CLOSEST);
+
+ return regmap_update_bits(clkr->regmap, divider->reg,
+ (BIT(divider->width) - 1) << divider->shift,
+ div << divider->shift);
+}
+
+static unsigned long div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_regmap_div *divider = to_clk_regmap_div(hw);
+ struct clk_regmap *clkr = &divider->clkr;
+ u32 div;
+
+ regmap_read(clkr->regmap, divider->reg, &div);
+ div >>= divider->shift;
+ div &= BIT(divider->width) - 1;
+
+ return divider_recalc_rate(hw, parent_rate, div, NULL,
+ CLK_DIVIDER_ROUND_CLOSEST);
+}
+
+const struct clk_ops clk_regmap_div_ops = {
+ .round_rate = div_round_rate,
+ .set_rate = div_set_rate,
+ .recalc_rate = div_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(clk_regmap_div_ops);
diff --git a/drivers/clk/qcom/clk-regmap-divider.h b/drivers/clk/qcom/clk-regmap-divider.h
new file mode 100644
index 000000000000..fc4492e3a827
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-divider.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_CLK_REGMAP_DIVIDER_H__
+#define __QCOM_CLK_REGMAP_DIVIDER_H__
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+struct clk_regmap_div {
+ u32 reg;
+ u32 shift;
+ u32 width;
+ struct clk_regmap clkr;
+};
+
+extern const struct clk_ops clk_regmap_div_ops;
+
+#endif
diff --git a/drivers/clk/qcom/clk-regmap-mux.c b/drivers/clk/qcom/clk-regmap-mux.c
new file mode 100644
index 000000000000..cae3071f384c
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-mux.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/export.h>
+
+#include "clk-regmap-mux.h"
+
+static inline struct clk_regmap_mux *to_clk_regmap_mux(struct clk_hw *hw)
+{
+ return container_of(to_clk_regmap(hw), struct clk_regmap_mux, clkr);
+}
+
+static u8 mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ unsigned int mask = GENMASK(mux->width - 1, 0);
+ unsigned int val;
+
+ regmap_read(clkr->regmap, mux->reg, &val);
+
+ val >>= mux->shift;
+ val &= mask;
+
+ return val;
+}
+
+static int mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift);
+ unsigned int val;
+
+ val = index;
+ val <<= mux->shift;
+
+ return regmap_update_bits(clkr->regmap, mux->reg, mask, val);
+}
+
+const struct clk_ops clk_regmap_mux_closest_ops = {
+ .get_parent = mux_get_parent,
+ .set_parent = mux_set_parent,
+ .determine_rate = __clk_mux_determine_rate_closest,
+};
+EXPORT_SYMBOL_GPL(clk_regmap_mux_closest_ops);
diff --git a/drivers/clk/qcom/clk-regmap-mux.h b/drivers/clk/qcom/clk-regmap-mux.h
new file mode 100644
index 000000000000..5cec76154fda
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-mux.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_CLK_REGMAP_MUX_H__
+#define __QCOM_CLK_REGMAP_MUX_H__
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+struct clk_regmap_mux {
+ u32 reg;
+ u32 shift;
+ u32 width;
+ struct clk_regmap clkr;
+};
+
+extern const struct clk_ops clk_regmap_mux_closest_ops;
+
+#endif
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c
index afed5eb0691e..cbdc31dea7f4 100644
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -75,6 +75,17 @@ static struct clk_pll pll3 = {
},
};
+static struct clk_regmap pll4_vote = {
+ .enable_reg = 0x34c0,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "pll4_vote",
+ .parent_names = (const char *[]){ "pll4" },
+ .num_parents = 1,
+ .ops = &clk_pll_vote_ops,
+ },
+};
+
static struct clk_pll pll8 = {
.l_reg = 0x3144,
.m_reg = 0x3148,
@@ -2163,6 +2174,7 @@ static struct clk_regmap *gcc_ipq806x_clks[] = {
[PLL0] = &pll0.clkr,
[PLL0_VOTE] = &pll0_vote,
[PLL3] = &pll3.clkr,
+ [PLL4_VOTE] = &pll4_vote,
[PLL8] = &pll8.clkr,
[PLL8_VOTE] = &pll8_vote,
[PLL14] = &pll14.clkr,
diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c
new file mode 100644
index 000000000000..121ffde25dc3
--- /dev/null
+++ b/drivers/clk/qcom/lcc-ipq806x.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,lcc-ipq806x.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+
+static struct clk_pll pll4 = {
+ .l_reg = 0x4,
+ .m_reg = 0x8,
+ .n_reg = 0xc,
+ .config_reg = 0x14,
+ .mode_reg = 0x0,
+ .status_reg = 0x18,
+ .status_bit = 16,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pll4",
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+static const struct pll_config pll4_config = {
+ .l = 0xf,
+ .m = 0x91,
+ .n = 0xc7,
+ .vco_val = 0x0,
+ .vco_mask = BIT(17) | BIT(16),
+ .pre_div_val = 0x0,
+ .pre_div_mask = BIT(19),
+ .post_div_val = 0x0,
+ .post_div_mask = BIT(21) | BIT(20),
+ .mn_ena_mask = BIT(22),
+ .main_output_mask = BIT(23),
+};
+
+#define P_PXO 0
+#define P_PLL4 1
+
+static const u8 lcc_pxo_pll4_map[] = {
+ [P_PXO] = 0,
+ [P_PLL4] = 2,
+};
+
+static const char *lcc_pxo_pll4[] = {
+ "pxo",
+ "pll4_vote",
+};
+
+static struct freq_tbl clk_tbl_aif_mi2s[] = {
+ { 1024000, P_PLL4, 4, 1, 96 },
+ { 1411200, P_PLL4, 4, 2, 139 },
+ { 1536000, P_PLL4, 4, 1, 64 },
+ { 2048000, P_PLL4, 4, 1, 48 },
+ { 2116800, P_PLL4, 4, 2, 93 },
+ { 2304000, P_PLL4, 4, 2, 85 },
+ { 2822400, P_PLL4, 4, 6, 209 },
+ { 3072000, P_PLL4, 4, 1, 32 },
+ { 3175200, P_PLL4, 4, 1, 31 },
+ { 4096000, P_PLL4, 4, 1, 24 },
+ { 4233600, P_PLL4, 4, 9, 209 },
+ { 4608000, P_PLL4, 4, 3, 64 },
+ { 5644800, P_PLL4, 4, 12, 209 },
+ { 6144000, P_PLL4, 4, 1, 16 },
+ { 6350400, P_PLL4, 4, 2, 31 },
+ { 8192000, P_PLL4, 4, 1, 12 },
+ { 8467200, P_PLL4, 4, 18, 209 },
+ { 9216000, P_PLL4, 4, 3, 32 },
+ { 11289600, P_PLL4, 4, 24, 209 },
+ { 12288000, P_PLL4, 4, 1, 8 },
+ { 12700800, P_PLL4, 4, 27, 209 },
+ { 13824000, P_PLL4, 4, 9, 64 },
+ { 16384000, P_PLL4, 4, 1, 6 },
+ { 16934400, P_PLL4, 4, 41, 238 },
+ { 18432000, P_PLL4, 4, 3, 16 },
+ { 22579200, P_PLL4, 2, 24, 209 },
+ { 24576000, P_PLL4, 4, 1, 4 },
+ { 27648000, P_PLL4, 4, 9, 32 },
+ { 33868800, P_PLL4, 4, 41, 119 },
+ { 36864000, P_PLL4, 4, 3, 8 },
+ { 45158400, P_PLL4, 1, 24, 209 },
+ { 49152000, P_PLL4, 4, 1, 2 },
+ { 50803200, P_PLL4, 1, 27, 209 },
+ { }
+};
+
+static struct clk_rcg mi2s_osr_src = {
+ .ns_reg = 0x48,
+ .md_reg = 0x4c,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 24,
+ .m_val_shift = 8,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_aif_mi2s,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_osr_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static const char *lcc_mi2s_parents[] = {
+ "mi2s_osr_src",
+};
+
+static struct clk_branch mi2s_osr_clk = {
+ .halt_reg = 0x50,
+ .halt_bit = 1,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(17),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_osr_clk",
+ .parent_names = lcc_mi2s_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_div mi2s_div_clk = {
+ .reg = 0x48,
+ .shift = 10,
+ .width = 4,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_div_clk",
+ .parent_names = lcc_mi2s_parents,
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_branch mi2s_bit_div_clk = {
+ .halt_reg = 0x50,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_bit_div_clk",
+ .parent_names = (const char *[]){ "mi2s_div_clk" },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+
+static struct clk_regmap_mux mi2s_bit_clk = {
+ .reg = 0x48,
+ .shift = 14,
+ .width = 1,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_bit_clk",
+ .parent_names = (const char *[]){
+ "mi2s_bit_div_clk",
+ "mi2s_codec_clk",
+ },
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct freq_tbl clk_tbl_pcm[] = {
+ { 64000, P_PLL4, 4, 1, 1536 },
+ { 128000, P_PLL4, 4, 1, 768 },
+ { 256000, P_PLL4, 4, 1, 384 },
+ { 512000, P_PLL4, 4, 1, 192 },
+ { 1024000, P_PLL4, 4, 1, 96 },
+ { 2048000, P_PLL4, 4, 1, 48 },
+ { },
+};
+
+static struct clk_rcg pcm_src = {
+ .ns_reg = 0x54,
+ .md_reg = 0x58,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 16,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_pcm,
+ .clkr = {
+ .enable_reg = 0x54,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static struct clk_branch pcm_clk_out = {
+ .halt_reg = 0x5c,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x54,
+ .enable_mask = BIT(11),
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_clk_out",
+ .parent_names = (const char *[]){ "pcm_src" },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_mux pcm_clk = {
+ .reg = 0x54,
+ .shift = 10,
+ .width = 1,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_clk",
+ .parent_names = (const char *[]){
+ "pcm_clk_out",
+ "pcm_codec_clk",
+ },
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct freq_tbl clk_tbl_aif_osr[] = {
+ { 22050, P_PLL4, 1, 147, 20480 },
+ { 32000, P_PLL4, 1, 1, 96 },
+ { 44100, P_PLL4, 1, 147, 10240 },
+ { 48000, P_PLL4, 1, 1, 64 },
+ { 88200, P_PLL4, 1, 147, 5120 },
+ { 96000, P_PLL4, 1, 1, 32 },
+ { 176400, P_PLL4, 1, 147, 2560 },
+ { 192000, P_PLL4, 1, 1, 16 },
+ { },
+};
+
+static struct clk_rcg spdif_src = {
+ .ns_reg = 0xcc,
+ .md_reg = 0xd0,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_aif_osr,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "spdif_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static const char *lcc_spdif_parents[] = {
+ "spdif_src",
+};
+
+static struct clk_branch spdif_clk = {
+ .halt_reg = 0xd4,
+ .halt_bit = 1,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(12),
+ .hw.init = &(struct clk_init_data){
+ .name = "spdif_clk",
+ .parent_names = lcc_spdif_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct freq_tbl clk_tbl_ahbix[] = {
+ { 131072, P_PLL4, 1, 1, 3 },
+ { },
+};
+
+static struct clk_rcg ahbix_clk = {
+ .ns_reg = 0x38,
+ .md_reg = 0x3c,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 24,
+ .m_val_shift = 8,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_ahbix,
+ .clkr = {
+ .enable_reg = 0x38,
+ .enable_mask = BIT(10), /* toggle the gfmux to select mn/pxo */
+ .hw.init = &(struct clk_init_data){
+ .name = "ahbix",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static struct clk_regmap *lcc_ipq806x_clks[] = {
+ [PLL4] = &pll4.clkr,
+ [MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
+ [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
+ [MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
+ [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
+ [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
+ [PCM_SRC] = &pcm_src.clkr,
+ [PCM_CLK_OUT] = &pcm_clk_out.clkr,
+ [PCM_CLK] = &pcm_clk.clkr,
+ [SPDIF_SRC] = &spdif_src.clkr,
+ [SPDIF_CLK] = &spdif_clk.clkr,
+ [AHBIX_CLK] = &ahbix_clk.clkr,
+};
+
+static const struct regmap_config lcc_ipq806x_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xfc,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc lcc_ipq806x_desc = {
+ .config = &lcc_ipq806x_regmap_config,
+ .clks = lcc_ipq806x_clks,
+ .num_clks = ARRAY_SIZE(lcc_ipq806x_clks),
+};
+
+static const struct of_device_id lcc_ipq806x_match_table[] = {
+ { .compatible = "qcom,lcc-ipq8064" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lcc_ipq806x_match_table);
+
+static int lcc_ipq806x_probe(struct platform_device *pdev)
+{
+ u32 val;
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &lcc_ipq806x_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Configure the rate of PLL4 if the bootloader hasn't already */
+ val = regmap_read(regmap, 0x0, &val);
+ if (!val)
+ clk_pll_configure_sr(&pll4, regmap, &pll4_config, true);
+ /* Enable PLL4 source on the LPASS Primary PLL Mux */
+ regmap_write(regmap, 0xc4, 0x1);
+
+ return qcom_cc_really_probe(pdev, &lcc_ipq806x_desc, regmap);
+}
+
+static int lcc_ipq806x_remove(struct platform_device *pdev)
+{
+ qcom_cc_remove(pdev);
+ return 0;
+}
+
+static struct platform_driver lcc_ipq806x_driver = {
+ .probe = lcc_ipq806x_probe,
+ .remove = lcc_ipq806x_remove,
+ .driver = {
+ .name = "lcc-ipq806x",
+ .owner = THIS_MODULE,
+ .of_match_table = lcc_ipq806x_match_table,
+ },
+};
+module_platform_driver(lcc_ipq806x_driver);
+
+MODULE_DESCRIPTION("QCOM LCC IPQ806x Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lcc-ipq806x");
diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c
new file mode 100644
index 000000000000..a75a408cfccd
--- /dev/null
+++ b/drivers/clk/qcom/lcc-msm8960.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,lcc-msm8960.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+
+static struct clk_pll pll4 = {
+ .l_reg = 0x4,
+ .m_reg = 0x8,
+ .n_reg = 0xc,
+ .config_reg = 0x14,
+ .mode_reg = 0x0,
+ .status_reg = 0x18,
+ .status_bit = 16,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pll4",
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+#define P_PXO 0
+#define P_PLL4 1
+
+static const u8 lcc_pxo_pll4_map[] = {
+ [P_PXO] = 0,
+ [P_PLL4] = 2,
+};
+
+static const char *lcc_pxo_pll4[] = {
+ "pxo",
+ "pll4_vote",
+};
+
+static struct freq_tbl clk_tbl_aif_osr_492[] = {
+ { 512000, P_PLL4, 4, 1, 240 },
+ { 768000, P_PLL4, 4, 1, 160 },
+ { 1024000, P_PLL4, 4, 1, 120 },
+ { 1536000, P_PLL4, 4, 1, 80 },
+ { 2048000, P_PLL4, 4, 1, 60 },
+ { 3072000, P_PLL4, 4, 1, 40 },
+ { 4096000, P_PLL4, 4, 1, 30 },
+ { 6144000, P_PLL4, 4, 1, 20 },
+ { 8192000, P_PLL4, 4, 1, 15 },
+ { 12288000, P_PLL4, 4, 1, 10 },
+ { 24576000, P_PLL4, 4, 1, 5 },
+ { 27000000, P_PXO, 1, 0, 0 },
+ { }
+};
+
+static struct freq_tbl clk_tbl_aif_osr_393[] = {
+ { 512000, P_PLL4, 4, 1, 192 },
+ { 768000, P_PLL4, 4, 1, 128 },
+ { 1024000, P_PLL4, 4, 1, 96 },
+ { 1536000, P_PLL4, 4, 1, 64 },
+ { 2048000, P_PLL4, 4, 1, 48 },
+ { 3072000, P_PLL4, 4, 1, 32 },
+ { 4096000, P_PLL4, 4, 1, 24 },
+ { 6144000, P_PLL4, 4, 1, 16 },
+ { 8192000, P_PLL4, 4, 1, 12 },
+ { 12288000, P_PLL4, 4, 1, 8 },
+ { 24576000, P_PLL4, 4, 1, 4 },
+ { 27000000, P_PXO, 1, 0, 0 },
+ { }
+};
+
+static struct clk_rcg mi2s_osr_src = {
+ .ns_reg = 0x48,
+ .md_reg = 0x4c,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 24,
+ .m_val_shift = 8,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_aif_osr_393,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_osr_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static const char *lcc_mi2s_parents[] = {
+ "mi2s_osr_src",
+};
+
+static struct clk_branch mi2s_osr_clk = {
+ .halt_reg = 0x50,
+ .halt_bit = 1,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(17),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_osr_clk",
+ .parent_names = lcc_mi2s_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_div mi2s_div_clk = {
+ .reg = 0x48,
+ .shift = 10,
+ .width = 4,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_div_clk",
+ .parent_names = lcc_mi2s_parents,
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_branch mi2s_bit_div_clk = {
+ .halt_reg = 0x50,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_bit_div_clk",
+ .parent_names = (const char *[]){ "mi2s_div_clk" },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_mux mi2s_bit_clk = {
+ .reg = 0x48,
+ .shift = 14,
+ .width = 1,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_bit_clk",
+ .parent_names = (const char *[]){
+ "mi2s_bit_div_clk",
+ "mi2s_codec_clk",
+ },
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+#define CLK_AIF_OSR_DIV(prefix, _ns, _md, hr) \
+static struct clk_rcg prefix##_osr_src = { \
+ .ns_reg = _ns, \
+ .md_reg = _md, \
+ .mn = { \
+ .mnctr_en_bit = 8, \
+ .mnctr_reset_bit = 7, \
+ .mnctr_mode_shift = 5, \
+ .n_val_shift = 24, \
+ .m_val_shift = 8, \
+ .width = 8, \
+ }, \
+ .p = { \
+ .pre_div_shift = 3, \
+ .pre_div_width = 2, \
+ }, \
+ .s = { \
+ .src_sel_shift = 0, \
+ .parent_map = lcc_pxo_pll4_map, \
+ }, \
+ .freq_tbl = clk_tbl_aif_osr_393, \
+ .clkr = { \
+ .enable_reg = _ns, \
+ .enable_mask = BIT(9), \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_osr_src", \
+ .parent_names = lcc_pxo_pll4, \
+ .num_parents = 2, \
+ .ops = &clk_rcg_ops, \
+ .flags = CLK_SET_RATE_GATE, \
+ }, \
+ }, \
+}; \
+ \
+static const char *lcc_##prefix##_parents[] = { \
+ #prefix "_osr_src", \
+}; \
+ \
+static struct clk_branch prefix##_osr_clk = { \
+ .halt_reg = hr, \
+ .halt_bit = 1, \
+ .halt_check = BRANCH_HALT_ENABLE, \
+ .clkr = { \
+ .enable_reg = _ns, \
+ .enable_mask = BIT(21), \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_osr_clk", \
+ .parent_names = lcc_##prefix##_parents, \
+ .num_parents = 1, \
+ .ops = &clk_branch_ops, \
+ .flags = CLK_SET_RATE_PARENT, \
+ }, \
+ }, \
+}; \
+ \
+static struct clk_regmap_div prefix##_div_clk = { \
+ .reg = _ns, \
+ .shift = 10, \
+ .width = 8, \
+ .clkr = { \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_div_clk", \
+ .parent_names = lcc_##prefix##_parents, \
+ .num_parents = 1, \
+ .ops = &clk_regmap_div_ops, \
+ }, \
+ }, \
+}; \
+ \
+static struct clk_branch prefix##_bit_div_clk = { \
+ .halt_reg = hr, \
+ .halt_bit = 0, \
+ .halt_check = BRANCH_HALT_ENABLE, \
+ .clkr = { \
+ .enable_reg = _ns, \
+ .enable_mask = BIT(19), \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_bit_div_clk", \
+ .parent_names = (const char *[]){ \
+ #prefix "_div_clk" \
+ }, \
+ .num_parents = 1, \
+ .ops = &clk_branch_ops, \
+ .flags = CLK_SET_RATE_PARENT, \
+ }, \
+ }, \
+}; \
+ \
+static struct clk_regmap_mux prefix##_bit_clk = { \
+ .reg = _ns, \
+ .shift = 18, \
+ .width = 1, \
+ .clkr = { \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_bit_clk", \
+ .parent_names = (const char *[]){ \
+ #prefix "_bit_div_clk", \
+ #prefix "_codec_clk", \
+ }, \
+ .num_parents = 2, \
+ .ops = &clk_regmap_mux_closest_ops, \
+ .flags = CLK_SET_RATE_PARENT, \
+ }, \
+ }, \
+}
+
+CLK_AIF_OSR_DIV(codec_i2s_mic, 0x60, 0x64, 0x68);
+CLK_AIF_OSR_DIV(spare_i2s_mic, 0x78, 0x7c, 0x80);
+CLK_AIF_OSR_DIV(codec_i2s_spkr, 0x6c, 0x70, 0x74);
+CLK_AIF_OSR_DIV(spare_i2s_spkr, 0x84, 0x88, 0x8c);
+
+static struct freq_tbl clk_tbl_pcm_492[] = {
+ { 256000, P_PLL4, 4, 1, 480 },
+ { 512000, P_PLL4, 4, 1, 240 },
+ { 768000, P_PLL4, 4, 1, 160 },
+ { 1024000, P_PLL4, 4, 1, 120 },
+ { 1536000, P_PLL4, 4, 1, 80 },
+ { 2048000, P_PLL4, 4, 1, 60 },
+ { 3072000, P_PLL4, 4, 1, 40 },
+ { 4096000, P_PLL4, 4, 1, 30 },
+ { 6144000, P_PLL4, 4, 1, 20 },
+ { 8192000, P_PLL4, 4, 1, 15 },
+ { 12288000, P_PLL4, 4, 1, 10 },
+ { 24576000, P_PLL4, 4, 1, 5 },
+ { 27000000, P_PXO, 1, 0, 0 },
+ { }
+};
+
+static struct freq_tbl clk_tbl_pcm_393[] = {
+ { 256000, P_PLL4, 4, 1, 384 },
+ { 512000, P_PLL4, 4, 1, 192 },
+ { 768000, P_PLL4, 4, 1, 128 },
+ { 1024000, P_PLL4, 4, 1, 96 },
+ { 1536000, P_PLL4, 4, 1, 64 },
+ { 2048000, P_PLL4, 4, 1, 48 },
+ { 3072000, P_PLL4, 4, 1, 32 },
+ { 4096000, P_PLL4, 4, 1, 24 },
+ { 6144000, P_PLL4, 4, 1, 16 },
+ { 8192000, P_PLL4, 4, 1, 12 },
+ { 12288000, P_PLL4, 4, 1, 8 },
+ { 24576000, P_PLL4, 4, 1, 4 },
+ { 27000000, P_PXO, 1, 0, 0 },
+ { }
+};
+
+static struct clk_rcg pcm_src = {
+ .ns_reg = 0x54,
+ .md_reg = 0x58,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 16,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_pcm_393,
+ .clkr = {
+ .enable_reg = 0x54,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static struct clk_branch pcm_clk_out = {
+ .halt_reg = 0x5c,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x54,
+ .enable_mask = BIT(11),
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_clk_out",
+ .parent_names = (const char *[]){ "pcm_src" },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_mux pcm_clk = {
+ .reg = 0x54,
+ .shift = 10,
+ .width = 1,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_clk",
+ .parent_names = (const char *[]){
+ "pcm_clk_out",
+ "pcm_codec_clk",
+ },
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_rcg slimbus_src = {
+ .ns_reg = 0xcc,
+ .md_reg = 0xd0,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_aif_osr_393,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "slimbus_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static const char *lcc_slimbus_parents[] = {
+ "slimbus_src",
+};
+
+static struct clk_branch audio_slimbus_clk = {
+ .halt_reg = 0xd4,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(10),
+ .hw.init = &(struct clk_init_data){
+ .name = "audio_slimbus_clk",
+ .parent_names = lcc_slimbus_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_branch sps_slimbus_clk = {
+ .halt_reg = 0xd4,
+ .halt_bit = 1,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(12),
+ .hw.init = &(struct clk_init_data){
+ .name = "sps_slimbus_clk",
+ .parent_names = lcc_slimbus_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap *lcc_msm8960_clks[] = {
+ [PLL4] = &pll4.clkr,
+ [MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
+ [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
+ [MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
+ [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
+ [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
+ [PCM_SRC] = &pcm_src.clkr,
+ [PCM_CLK_OUT] = &pcm_clk_out.clkr,
+ [PCM_CLK] = &pcm_clk.clkr,
+ [SLIMBUS_SRC] = &slimbus_src.clkr,
+ [AUDIO_SLIMBUS_CLK] = &audio_slimbus_clk.clkr,
+ [SPS_SLIMBUS_CLK] = &sps_slimbus_clk.clkr,
+ [CODEC_I2S_MIC_OSR_SRC] = &codec_i2s_mic_osr_src.clkr,
+ [CODEC_I2S_MIC_OSR_CLK] = &codec_i2s_mic_osr_clk.clkr,
+ [CODEC_I2S_MIC_DIV_CLK] = &codec_i2s_mic_div_clk.clkr,
+ [CODEC_I2S_MIC_BIT_DIV_CLK] = &codec_i2s_mic_bit_div_clk.clkr,
+ [CODEC_I2S_MIC_BIT_CLK] = &codec_i2s_mic_bit_clk.clkr,
+ [SPARE_I2S_MIC_OSR_SRC] = &spare_i2s_mic_osr_src.clkr,
+ [SPARE_I2S_MIC_OSR_CLK] = &spare_i2s_mic_osr_clk.clkr,
+ [SPARE_I2S_MIC_DIV_CLK] = &spare_i2s_mic_div_clk.clkr,
+ [SPARE_I2S_MIC_BIT_DIV_CLK] = &spare_i2s_mic_bit_div_clk.clkr,
+ [SPARE_I2S_MIC_BIT_CLK] = &spare_i2s_mic_bit_clk.clkr,
+ [CODEC_I2S_SPKR_OSR_SRC] = &codec_i2s_spkr_osr_src.clkr,
+ [CODEC_I2S_SPKR_OSR_CLK] = &codec_i2s_spkr_osr_clk.clkr,
+ [CODEC_I2S_SPKR_DIV_CLK] = &codec_i2s_spkr_div_clk.clkr,
+ [CODEC_I2S_SPKR_BIT_DIV_CLK] = &codec_i2s_spkr_bit_div_clk.clkr,
+ [CODEC_I2S_SPKR_BIT_CLK] = &codec_i2s_spkr_bit_clk.clkr,
+ [SPARE_I2S_SPKR_OSR_SRC] = &spare_i2s_spkr_osr_src.clkr,
+ [SPARE_I2S_SPKR_OSR_CLK] = &spare_i2s_spkr_osr_clk.clkr,
+ [SPARE_I2S_SPKR_DIV_CLK] = &spare_i2s_spkr_div_clk.clkr,
+ [SPARE_I2S_SPKR_BIT_DIV_CLK] = &spare_i2s_spkr_bit_div_clk.clkr,
+ [SPARE_I2S_SPKR_BIT_CLK] = &spare_i2s_spkr_bit_clk.clkr,
+};
+
+static const struct regmap_config lcc_msm8960_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xfc,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc lcc_msm8960_desc = {
+ .config = &lcc_msm8960_regmap_config,
+ .clks = lcc_msm8960_clks,
+ .num_clks = ARRAY_SIZE(lcc_msm8960_clks),
+};
+
+static const struct of_device_id lcc_msm8960_match_table[] = {
+ { .compatible = "qcom,lcc-msm8960" },
+ { .compatible = "qcom,lcc-apq8064" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lcc_msm8960_match_table);
+
+static int lcc_msm8960_probe(struct platform_device *pdev)
+{
+ u32 val;
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &lcc_msm8960_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Use the correct frequency plan depending on speed of PLL4 */
+ val = regmap_read(regmap, 0x4, &val);
+ if (val == 0x12) {
+ slimbus_src.freq_tbl = clk_tbl_aif_osr_492;
+ mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ pcm_src.freq_tbl = clk_tbl_pcm_492;
+ }
+ /* Enable PLL4 source on the LPASS Primary PLL Mux */
+ regmap_write(regmap, 0xc4, 0x1);
+
+ return qcom_cc_really_probe(pdev, &lcc_msm8960_desc, regmap);
+}
+
+static int lcc_msm8960_remove(struct platform_device *pdev)
+{
+ qcom_cc_remove(pdev);
+ return 0;
+}
+
+static struct platform_driver lcc_msm8960_driver = {
+ .probe = lcc_msm8960_probe,
+ .remove = lcc_msm8960_remove,
+ .driver = {
+ .name = "lcc-msm8960",
+ .owner = THIS_MODULE,
+ .of_match_table = lcc_msm8960_match_table,
+ },
+};
+module_platform_driver(lcc_msm8960_driver);
+
+MODULE_DESCRIPTION("QCOM LCC MSM8960 Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lcc-msm8960");
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index cbcddcc02475..05d7a0bc0599 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -535,44 +535,44 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gll_usb_npll_p, 0,
RK3288_CLKSEL_CON(13), 13, 2, MFLAGS, 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 8, GFLAGS),
- COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", 0,
+ COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(17), 0,
RK3288_CLKGATE_CON(1), 9, GFLAGS),
- MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, 0,
+ MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(13), 8, 2, MFLAGS),
MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(13), 15, 1, MFLAGS),
COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0,
RK3288_CLKSEL_CON(14), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 10, GFLAGS),
- COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", 0,
+ COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(18), 0,
RK3288_CLKGATE_CON(1), 11, GFLAGS),
- MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, 0,
+ MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(14), 8, 2, MFLAGS),
COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0,
RK3288_CLKSEL_CON(15), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 12, GFLAGS),
- COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", 0,
+ COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(19), 0,
RK3288_CLKGATE_CON(1), 13, GFLAGS),
- MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, 0,
+ MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(15), 8, 2, MFLAGS),
COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0,
RK3288_CLKSEL_CON(16), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 14, GFLAGS),
- COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", 0,
+ COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(20), 0,
RK3288_CLKGATE_CON(1), 15, GFLAGS),
- MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, 0,
+ MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(16), 8, 2, MFLAGS),
COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0,
RK3288_CLKSEL_CON(3), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(2), 12, GFLAGS),
- COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", 0,
+ COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(7), 0,
RK3288_CLKGATE_CON(2), 13, GFLAGS),
- MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, 0,
+ MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(3), 8, 2, MFLAGS),
COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
@@ -598,7 +598,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
GATE(0, "jtag", "ext_jtag", 0,
RK3288_CLKGATE_CON(4), 14, GFLAGS),
- COMPOSITE_NODIV(0, "usbphy480m_src", mux_usbphy480m_p, 0,
+ COMPOSITE_NODIV(SCLK_USBPHY480M_SRC, "usbphy480m_src", mux_usbphy480m_p, 0,
RK3288_CLKSEL_CON(13), 11, 2, MFLAGS,
RK3288_CLKGATE_CON(5), 14, GFLAGS),
COMPOSITE_NODIV(SCLK_HSICPHY480M, "sclk_hsicphy480m", mux_hsicphy480m_p, 0,
@@ -704,8 +704,8 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
GATE(SCLK_LCDC_PWM0, "sclk_lcdc_pwm0", "xin24m", 0, RK3288_CLKGATE_CON(13), 10, GFLAGS),
GATE(SCLK_LCDC_PWM1, "sclk_lcdc_pwm1", "xin24m", 0, RK3288_CLKGATE_CON(13), 11, GFLAGS),
- GATE(0, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS),
- GATE(0, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS),
+ GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS),
+ GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS),
GATE(0, "sclk_mipidsi_24m", "xin24m", 0, RK3288_CLKGATE_CON(5), 15, GFLAGS),
/* sclk_gpu gates */
@@ -805,6 +805,20 @@ static int rk3288_clk_suspend(void)
rk3288_saved_cru_regs[i] =
readl_relaxed(rk3288_cru_base + reg_id);
}
+
+ /*
+ * Switch PLLs other than DPLL (for SDRAM) to slow mode to
+ * avoid crashes on resume. The Mask ROM on the system will
+ * put APLL, CPLL, and GPLL into slow mode at resume time
+ * anyway (which is why we restore them), but we might not
+ * even make it to the Mask ROM if this isn't done at suspend
+ * time.
+ *
+ * NOTE: only APLL truly matters here, but we'll do them all.
+ */
+
+ writel_relaxed(0xf3030000, rk3288_cru_base + RK3288_MODE_CON);
+
return 0;
}
@@ -866,6 +880,14 @@ static void __init rk3288_clk_init(struct device_node *np)
pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n",
__func__, PTR_ERR(clk));
+ /* Watchdog pclk is controlled by RK3288_SGRF_SOC_CON0[1]. */
+ clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock pclk_wdt: %ld\n",
+ __func__, PTR_ERR(clk));
+ else
+ rockchip_clk_add_lookup(clk, PCLK_WDT);
+
rockchip_clk_register_plls(rk3288_pll_clks,
ARRAY_SIZE(rk3288_pll_clks),
RK3288_GRF_SOC_STATUS1);
diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c
index f2c2ccce49bb..454b02ae486a 100644
--- a/drivers/clk/samsung/clk-exynos-audss.c
+++ b/drivers/clk/samsung/clk-exynos-audss.c
@@ -82,6 +82,26 @@ static const struct of_device_id exynos_audss_clk_of_match[] = {
{},
};
+static void exynos_audss_clk_teardown(void)
+{
+ int i;
+
+ for (i = EXYNOS_MOUT_AUDSS; i < EXYNOS_DOUT_SRP; i++) {
+ if (!IS_ERR(clk_table[i]))
+ clk_unregister_mux(clk_table[i]);
+ }
+
+ for (; i < EXYNOS_SRP_CLK; i++) {
+ if (!IS_ERR(clk_table[i]))
+ clk_unregister_divider(clk_table[i]);
+ }
+
+ for (; i < clk_data.clk_num; i++) {
+ if (!IS_ERR(clk_table[i]))
+ clk_unregister_gate(clk_table[i]);
+ }
+}
+
/* register exynos_audss clocks */
static int exynos_audss_clk_probe(struct platform_device *pdev)
{
@@ -219,10 +239,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
return 0;
unregister:
- for (i = 0; i < clk_data.clk_num; i++) {
- if (!IS_ERR(clk_table[i]))
- clk_unregister(clk_table[i]);
- }
+ exynos_audss_clk_teardown();
if (!IS_ERR(epll))
clk_disable_unprepare(epll);
@@ -232,18 +249,13 @@ unregister:
static int exynos_audss_clk_remove(struct platform_device *pdev)
{
- int i;
-
#ifdef CONFIG_PM_SLEEP
unregister_syscore_ops(&exynos_audss_clk_syscore_ops);
#endif
of_clk_del_provider(pdev->dev.of_node);
- for (i = 0; i < clk_data.clk_num; i++) {
- if (!IS_ERR(clk_table[i]))
- clk_unregister(clk_table[i]);
- }
+ exynos_audss_clk_teardown();
if (!IS_ERR(epll))
clk_disable_unprepare(epll);
diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c
index 6e6cca392082..cc4c348d8a24 100644
--- a/drivers/clk/samsung/clk-exynos3250.c
+++ b/drivers/clk/samsung/clk-exynos3250.c
@@ -104,27 +104,6 @@
#define PWR_CTRL1_USE_CORE1_WFI (1 << 1)
#define PWR_CTRL1_USE_CORE0_WFI (1 << 0)
-/* list of PLLs to be registered */
-enum exynos3250_plls {
- apll, mpll, vpll, upll,
- nr_plls
-};
-
-/* list of PLLs in DMC block to be registered */
-enum exynos3250_dmc_plls {
- bpll, epll,
- nr_dmc_plls
-};
-
-static void __iomem *reg_base;
-static void __iomem *dmc_reg_base;
-
-/*
- * Support for CMU save/restore across system suspends
- */
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos3250_clk_regs;
-
static unsigned long exynos3250_cmu_clk_regs[] __initdata = {
SRC_LEFTBUS,
DIV_LEFTBUS,
@@ -195,43 +174,6 @@ static unsigned long exynos3250_cmu_clk_regs[] __initdata = {
PWR_CTRL2,
};
-static int exynos3250_clk_suspend(void)
-{
- samsung_clk_save(reg_base, exynos3250_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_clk_regs));
- return 0;
-}
-
-static void exynos3250_clk_resume(void)
-{
- samsung_clk_restore(reg_base, exynos3250_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_clk_regs));
-}
-
-static struct syscore_ops exynos3250_clk_syscore_ops = {
- .suspend = exynos3250_clk_suspend,
- .resume = exynos3250_clk_resume,
-};
-
-static void exynos3250_clk_sleep_init(void)
-{
- exynos3250_clk_regs =
- samsung_clk_alloc_reg_dump(exynos3250_cmu_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_clk_regs));
- if (!exynos3250_clk_regs) {
- pr_warn("%s: Failed to allocate sleep save data\n", __func__);
- goto err;
- }
-
- register_syscore_ops(&exynos3250_clk_syscore_ops);
- return;
-err:
- kfree(exynos3250_clk_regs);
-}
-#else
-static inline void exynos3250_clk_sleep_init(void) { }
-#endif
-
/* list of all parent clock list */
PNAME(mout_vpllsrc_p) = { "fin_pll", };
@@ -782,18 +724,18 @@ static struct samsung_pll_rate_table exynos3250_vpll_rates[] = {
{ /* sentinel */ }
};
-static struct samsung_pll_clock exynos3250_plls[nr_plls] __initdata = {
- [apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
- APLL_LOCK, APLL_CON0, NULL),
- [mpll] = PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll",
- MPLL_LOCK, MPLL_CON0, NULL),
- [vpll] = PLL(pll_36xx, CLK_FOUT_VPLL, "fout_vpll", "fin_pll",
- VPLL_LOCK, VPLL_CON0, NULL),
- [upll] = PLL(pll_35xx, CLK_FOUT_UPLL, "fout_upll", "fin_pll",
- UPLL_LOCK, UPLL_CON0, NULL),
+static struct samsung_pll_clock exynos3250_plls[] __initdata = {
+ PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
+ APLL_LOCK, APLL_CON0, exynos3250_pll_rates),
+ PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll",
+ MPLL_LOCK, MPLL_CON0, exynos3250_pll_rates),
+ PLL(pll_36xx, CLK_FOUT_VPLL, "fout_vpll", "fin_pll",
+ VPLL_LOCK, VPLL_CON0, exynos3250_vpll_rates),
+ PLL(pll_35xx, CLK_FOUT_UPLL, "fout_upll", "fin_pll",
+ UPLL_LOCK, UPLL_CON0, exynos3250_pll_rates),
};
-static void __init exynos3_core_down_clock(void)
+static void __init exynos3_core_down_clock(void __iomem *reg_base)
{
unsigned int tmp;
@@ -814,38 +756,31 @@ static void __init exynos3_core_down_clock(void)
__raw_writel(0x0, reg_base + PWR_CTRL2);
}
+static struct samsung_cmu_info cmu_info __initdata = {
+ .pll_clks = exynos3250_plls,
+ .nr_pll_clks = ARRAY_SIZE(exynos3250_plls),
+ .mux_clks = mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(mux_clks),
+ .div_clks = div_clks,
+ .nr_div_clks = ARRAY_SIZE(div_clks),
+ .gate_clks = gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(gate_clks),
+ .fixed_factor_clks = fixed_factor_clks,
+ .nr_fixed_factor_clks = ARRAY_SIZE(fixed_factor_clks),
+ .nr_clk_ids = CLK_NR_CLKS,
+ .clk_regs = exynos3250_cmu_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(exynos3250_cmu_clk_regs),
+};
+
static void __init exynos3250_cmu_init(struct device_node *np)
{
struct samsung_clk_provider *ctx;
- reg_base = of_iomap(np, 0);
- if (!reg_base)
- panic("%s: failed to map registers\n", __func__);
-
- ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
+ ctx = samsung_cmu_register_one(np, &cmu_info);
if (!ctx)
- panic("%s: unable to allocate context.\n", __func__);
-
- samsung_clk_register_fixed_factor(ctx, fixed_factor_clks,
- ARRAY_SIZE(fixed_factor_clks));
-
- exynos3250_plls[apll].rate_table = exynos3250_pll_rates;
- exynos3250_plls[mpll].rate_table = exynos3250_pll_rates;
- exynos3250_plls[vpll].rate_table = exynos3250_vpll_rates;
- exynos3250_plls[upll].rate_table = exynos3250_pll_rates;
-
- samsung_clk_register_pll(ctx, exynos3250_plls,
- ARRAY_SIZE(exynos3250_plls), reg_base);
-
- samsung_clk_register_mux(ctx, mux_clks, ARRAY_SIZE(mux_clks));
- samsung_clk_register_div(ctx, div_clks, ARRAY_SIZE(div_clks));
- samsung_clk_register_gate(ctx, gate_clks, ARRAY_SIZE(gate_clks));
-
- exynos3_core_down_clock();
+ return;
- exynos3250_clk_sleep_init();
-
- samsung_clk_of_add_provider(np, ctx);
+ exynos3_core_down_clock(ctx->reg_base);
}
CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init);
@@ -872,12 +807,6 @@ CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init);
#define EPLL_CON2 0x111c
#define SRC_EPLL 0x1120
-/*
- * Support for CMU save/restore across system suspends
- */
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos3250_dmc_clk_regs;
-
static unsigned long exynos3250_cmu_dmc_clk_regs[] __initdata = {
BPLL_LOCK,
BPLL_CON0,
@@ -899,43 +828,6 @@ static unsigned long exynos3250_cmu_dmc_clk_regs[] __initdata = {
SRC_EPLL,
};
-static int exynos3250_dmc_clk_suspend(void)
-{
- samsung_clk_save(dmc_reg_base, exynos3250_dmc_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs));
- return 0;
-}
-
-static void exynos3250_dmc_clk_resume(void)
-{
- samsung_clk_restore(dmc_reg_base, exynos3250_dmc_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs));
-}
-
-static struct syscore_ops exynos3250_dmc_clk_syscore_ops = {
- .suspend = exynos3250_dmc_clk_suspend,
- .resume = exynos3250_dmc_clk_resume,
-};
-
-static void exynos3250_dmc_clk_sleep_init(void)
-{
- exynos3250_dmc_clk_regs =
- samsung_clk_alloc_reg_dump(exynos3250_cmu_dmc_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs));
- if (!exynos3250_dmc_clk_regs) {
- pr_warn("%s: Failed to allocate sleep save data\n", __func__);
- goto err;
- }
-
- register_syscore_ops(&exynos3250_dmc_clk_syscore_ops);
- return;
-err:
- kfree(exynos3250_dmc_clk_regs);
-}
-#else
-static inline void exynos3250_dmc_clk_sleep_init(void) { }
-#endif
-
PNAME(mout_epll_p) = { "fin_pll", "fout_epll", };
PNAME(mout_bpll_p) = { "fin_pll", "fout_bpll", };
PNAME(mout_mpll_mif_p) = { "fin_pll", "sclk_mpll_mif", };
@@ -977,43 +869,28 @@ static struct samsung_div_clock dmc_div_clks[] __initdata = {
DIV(CLK_DIV_DMCD, "div_dmcd", "div_dmc", DIV_DMC1, 11, 3),
};
-static struct samsung_pll_clock exynos3250_dmc_plls[nr_dmc_plls] __initdata = {
- [bpll] = PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll",
- BPLL_LOCK, BPLL_CON0, NULL),
- [epll] = PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
- EPLL_LOCK, EPLL_CON0, NULL),
+static struct samsung_pll_clock exynos3250_dmc_plls[] __initdata = {
+ PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll",
+ BPLL_LOCK, BPLL_CON0, exynos3250_pll_rates),
+ PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
+ EPLL_LOCK, EPLL_CON0, exynos3250_epll_rates),
+};
+
+static struct samsung_cmu_info dmc_cmu_info __initdata = {
+ .pll_clks = exynos3250_dmc_plls,
+ .nr_pll_clks = ARRAY_SIZE(exynos3250_dmc_plls),
+ .mux_clks = dmc_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(dmc_mux_clks),
+ .div_clks = dmc_div_clks,
+ .nr_div_clks = ARRAY_SIZE(dmc_div_clks),
+ .nr_clk_ids = NR_CLKS_DMC,
+ .clk_regs = exynos3250_cmu_dmc_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs),
};
static void __init exynos3250_cmu_dmc_init(struct device_node *np)
{
- struct samsung_clk_provider *ctx;
-
- dmc_reg_base = of_iomap(np, 0);
- if (!dmc_reg_base)
- panic("%s: failed to map registers\n", __func__);
-
- ctx = samsung_clk_init(np, dmc_reg_base, NR_CLKS_DMC);
- if (!ctx)
- panic("%s: unable to allocate context.\n", __func__);
-
- exynos3250_dmc_plls[bpll].rate_table = exynos3250_pll_rates;
- exynos3250_dmc_plls[epll].rate_table = exynos3250_epll_rates;
-
- pr_err("CLK registering epll bpll: %d, %d, %d, %d\n",
- exynos3250_dmc_plls[bpll].rate_table[0].rate,
- exynos3250_dmc_plls[bpll].rate_table[0].mdiv,
- exynos3250_dmc_plls[bpll].rate_table[0].pdiv,
- exynos3250_dmc_plls[bpll].rate_table[0].sdiv
- );
- samsung_clk_register_pll(ctx, exynos3250_dmc_plls,
- ARRAY_SIZE(exynos3250_dmc_plls), dmc_reg_base);
-
- samsung_clk_register_mux(ctx, dmc_mux_clks, ARRAY_SIZE(dmc_mux_clks));
- samsung_clk_register_div(ctx, dmc_div_clks, ARRAY_SIZE(dmc_div_clks));
-
- exynos3250_dmc_clk_sleep_init();
-
- samsung_clk_of_add_provider(np, ctx);
+ samsung_cmu_register_one(np, &dmc_cmu_info);
}
CLK_OF_DECLARE(exynos3250_cmu_dmc, "samsung,exynos3250-cmu-dmc",
exynos3250_cmu_dmc_init);
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index 88e8c6bbd77f..51462e85675f 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -703,12 +703,12 @@ static struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
/* list of divider clocks supported in all exynos4 soc's */
static struct samsung_div_clock exynos4_div_clks[] __initdata = {
- DIV(0, "div_gdl", "mout_gdl", DIV_LEFTBUS, 0, 3),
+ DIV(CLK_DIV_GDL, "div_gdl", "mout_gdl", DIV_LEFTBUS, 0, 3),
DIV(0, "div_gpl", "div_gdl", DIV_LEFTBUS, 4, 3),
DIV(0, "div_clkout_leftbus", "mout_clkout_leftbus",
CLKOUT_CMU_LEFTBUS, 8, 6),
- DIV(0, "div_gdr", "mout_gdr", DIV_RIGHTBUS, 0, 3),
+ DIV(CLK_DIV_GDR, "div_gdr", "mout_gdr", DIV_RIGHTBUS, 0, 3),
DIV(0, "div_gpr", "div_gdr", DIV_RIGHTBUS, 4, 3),
DIV(0, "div_clkout_rightbus", "mout_clkout_rightbus",
CLKOUT_CMU_RIGHTBUS, 8, 6),
@@ -781,10 +781,10 @@ static struct samsung_div_clock exynos4_div_clks[] __initdata = {
CLK_SET_RATE_PARENT, 0),
DIV(0, "div_clkout_top", "mout_clkout_top", CLKOUT_CMU_TOP, 8, 6),
- DIV(0, "div_acp", "mout_dmc_bus", DIV_DMC0, 0, 3),
+ DIV(CLK_DIV_ACP, "div_acp", "mout_dmc_bus", DIV_DMC0, 0, 3),
DIV(0, "div_acp_pclk", "div_acp", DIV_DMC0, 4, 3),
DIV(0, "div_dphy", "mout_dphy", DIV_DMC0, 8, 3),
- DIV(0, "div_dmc", "mout_dmc_bus", DIV_DMC0, 12, 3),
+ DIV(CLK_DIV_DMC, "div_dmc", "mout_dmc_bus", DIV_DMC0, 12, 3),
DIV(0, "div_dmcd", "div_dmc", DIV_DMC0, 16, 3),
DIV(0, "div_dmcp", "div_dmcd", DIV_DMC0, 20, 3),
DIV(0, "div_pwi", "mout_pwi", DIV_DMC1, 8, 4),
@@ -829,7 +829,7 @@ static struct samsung_div_clock exynos4x12_div_clks[] __initdata = {
DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1,
8, 3, CLK_GET_RATE_NOCACHE, 0),
DIV(CLK_SCLK_FIMG2D, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4),
- DIV(0, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3),
+ DIV(CLK_DIV_C2C, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3),
DIV(0, "div_c2c_aclk", "div_c2c", DIV_DMC1, 12, 3),
};
diff --git a/drivers/clk/samsung/clk-exynos4415.c b/drivers/clk/samsung/clk-exynos4415.c
index 2123fc251e0f..6c78b09c829f 100644
--- a/drivers/clk/samsung/clk-exynos4415.c
+++ b/drivers/clk/samsung/clk-exynos4415.c
@@ -113,19 +113,6 @@
#define DIV_CPU0 0x14500
#define DIV_CPU1 0x14504
-enum exynos4415_plls {
- apll, epll, g3d_pll, isp_pll, disp_pll,
- nr_plls,
-};
-
-static struct samsung_clk_provider *exynos4415_ctx;
-
-/*
- * Support for CMU save/restore across system suspends
- */
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos4415_clk_regs;
-
static unsigned long exynos4415_cmu_clk_regs[] __initdata = {
SRC_LEFTBUS,
DIV_LEFTBUS,
@@ -219,41 +206,6 @@ static unsigned long exynos4415_cmu_clk_regs[] __initdata = {
DIV_CPU1,
};
-static int exynos4415_clk_suspend(void)
-{
- samsung_clk_save(exynos4415_ctx->reg_base, exynos4415_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_clk_regs));
-
- return 0;
-}
-
-static void exynos4415_clk_resume(void)
-{
- samsung_clk_restore(exynos4415_ctx->reg_base, exynos4415_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_clk_regs));
-}
-
-static struct syscore_ops exynos4415_clk_syscore_ops = {
- .suspend = exynos4415_clk_suspend,
- .resume = exynos4415_clk_resume,
-};
-
-static void exynos4415_clk_sleep_init(void)
-{
- exynos4415_clk_regs =
- samsung_clk_alloc_reg_dump(exynos4415_cmu_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_clk_regs));
- if (!exynos4415_clk_regs) {
- pr_warn("%s: Failed to allocate sleep save data\n", __func__);
- return;
- }
-
- register_syscore_ops(&exynos4415_clk_syscore_ops);
-}
-#else
-static inline void exynos4415_clk_sleep_init(void) { }
-#endif
-
/* list of all parent clock list */
PNAME(mout_g3d_pllsrc_p) = { "fin_pll", };
@@ -959,56 +911,40 @@ static struct samsung_pll_rate_table exynos4415_epll_rates[] = {
{ /* sentinel */ }
};
-static struct samsung_pll_clock exynos4415_plls[nr_plls] __initdata = {
- [apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
- APLL_LOCK, APLL_CON0, NULL),
- [epll] = PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
- EPLL_LOCK, EPLL_CON0, NULL),
- [g3d_pll] = PLL(pll_35xx, CLK_FOUT_G3D_PLL, "fout_g3d_pll",
- "mout_g3d_pllsrc", G3D_PLL_LOCK, G3D_PLL_CON0, NULL),
- [isp_pll] = PLL(pll_35xx, CLK_FOUT_ISP_PLL, "fout_isp_pll", "fin_pll",
- ISP_PLL_LOCK, ISP_PLL_CON0, NULL),
- [disp_pll] = PLL(pll_35xx, CLK_FOUT_DISP_PLL, "fout_disp_pll",
- "fin_pll", DISP_PLL_LOCK, DISP_PLL_CON0, NULL),
+static struct samsung_pll_clock exynos4415_plls[] __initdata = {
+ PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
+ APLL_LOCK, APLL_CON0, exynos4415_pll_rates),
+ PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
+ EPLL_LOCK, EPLL_CON0, exynos4415_epll_rates),
+ PLL(pll_35xx, CLK_FOUT_G3D_PLL, "fout_g3d_pll", "mout_g3d_pllsrc",
+ G3D_PLL_LOCK, G3D_PLL_CON0, exynos4415_pll_rates),
+ PLL(pll_35xx, CLK_FOUT_ISP_PLL, "fout_isp_pll", "fin_pll",
+ ISP_PLL_LOCK, ISP_PLL_CON0, exynos4415_pll_rates),
+ PLL(pll_35xx, CLK_FOUT_DISP_PLL, "fout_disp_pll",
+ "fin_pll", DISP_PLL_LOCK, DISP_PLL_CON0, exynos4415_pll_rates),
+};
+
+static struct samsung_cmu_info cmu_info __initdata = {
+ .pll_clks = exynos4415_plls,
+ .nr_pll_clks = ARRAY_SIZE(exynos4415_plls),
+ .mux_clks = exynos4415_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(exynos4415_mux_clks),
+ .div_clks = exynos4415_div_clks,
+ .nr_div_clks = ARRAY_SIZE(exynos4415_div_clks),
+ .gate_clks = exynos4415_gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(exynos4415_gate_clks),
+ .fixed_clks = exynos4415_fixed_rate_clks,
+ .nr_fixed_clks = ARRAY_SIZE(exynos4415_fixed_rate_clks),
+ .fixed_factor_clks = exynos4415_fixed_factor_clks,
+ .nr_fixed_factor_clks = ARRAY_SIZE(exynos4415_fixed_factor_clks),
+ .nr_clk_ids = CLK_NR_CLKS,
+ .clk_regs = exynos4415_cmu_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(exynos4415_cmu_clk_regs),
};
static void __init exynos4415_cmu_init(struct device_node *np)
{
- void __iomem *reg_base;
-
- reg_base = of_iomap(np, 0);
- if (!reg_base)
- panic("%s: failed to map registers\n", __func__);
-
- exynos4415_ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
- if (!exynos4415_ctx)
- panic("%s: unable to allocate context.\n", __func__);
-
- exynos4415_plls[apll].rate_table = exynos4415_pll_rates;
- exynos4415_plls[epll].rate_table = exynos4415_epll_rates;
- exynos4415_plls[g3d_pll].rate_table = exynos4415_pll_rates;
- exynos4415_plls[isp_pll].rate_table = exynos4415_pll_rates;
- exynos4415_plls[disp_pll].rate_table = exynos4415_pll_rates;
-
- samsung_clk_register_fixed_factor(exynos4415_ctx,
- exynos4415_fixed_factor_clks,
- ARRAY_SIZE(exynos4415_fixed_factor_clks));
- samsung_clk_register_fixed_rate(exynos4415_ctx,
- exynos4415_fixed_rate_clks,
- ARRAY_SIZE(exynos4415_fixed_rate_clks));
-
- samsung_clk_register_pll(exynos4415_ctx, exynos4415_plls,
- ARRAY_SIZE(exynos4415_plls), reg_base);
- samsung_clk_register_mux(exynos4415_ctx, exynos4415_mux_clks,
- ARRAY_SIZE(exynos4415_mux_clks));
- samsung_clk_register_div(exynos4415_ctx, exynos4415_div_clks,
- ARRAY_SIZE(exynos4415_div_clks));
- samsung_clk_register_gate(exynos4415_ctx, exynos4415_gate_clks,
- ARRAY_SIZE(exynos4415_gate_clks));
-
- exynos4415_clk_sleep_init();
-
- samsung_clk_of_add_provider(np, exynos4415_ctx);
+ samsung_cmu_register_one(np, &cmu_info);
}
CLK_OF_DECLARE(exynos4415_cmu, "samsung,exynos4415-cmu", exynos4415_cmu_init);
@@ -1027,16 +963,6 @@ CLK_OF_DECLARE(exynos4415_cmu, "samsung,exynos4415-cmu", exynos4415_cmu_init);
#define SRC_DMC 0x300
#define DIV_DMC1 0x504
-enum exynos4415_dmc_plls {
- mpll, bpll,
- nr_dmc_plls,
-};
-
-static struct samsung_clk_provider *exynos4415_dmc_ctx;
-
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos4415_dmc_clk_regs;
-
static unsigned long exynos4415_cmu_dmc_clk_regs[] __initdata = {
MPLL_LOCK,
MPLL_CON0,
@@ -1050,42 +976,6 @@ static unsigned long exynos4415_cmu_dmc_clk_regs[] __initdata = {
DIV_DMC1,
};
-static int exynos4415_dmc_clk_suspend(void)
-{
- samsung_clk_save(exynos4415_dmc_ctx->reg_base,
- exynos4415_dmc_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs));
- return 0;
-}
-
-static void exynos4415_dmc_clk_resume(void)
-{
- samsung_clk_restore(exynos4415_dmc_ctx->reg_base,
- exynos4415_dmc_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs));
-}
-
-static struct syscore_ops exynos4415_dmc_clk_syscore_ops = {
- .suspend = exynos4415_dmc_clk_suspend,
- .resume = exynos4415_dmc_clk_resume,
-};
-
-static void exynos4415_dmc_clk_sleep_init(void)
-{
- exynos4415_dmc_clk_regs =
- samsung_clk_alloc_reg_dump(exynos4415_cmu_dmc_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs));
- if (!exynos4415_dmc_clk_regs) {
- pr_warn("%s: Failed to allocate sleep save data\n", __func__);
- return;
- }
-
- register_syscore_ops(&exynos4415_dmc_clk_syscore_ops);
-}
-#else
-static inline void exynos4415_dmc_clk_sleep_init(void) { }
-#endif /* CONFIG_PM_SLEEP */
-
PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", };
PNAME(mout_bpll_p) = { "fin_pll", "fout_bpll", };
PNAME(mbpll_p) = { "mout_mpll", "mout_bpll", };
@@ -1107,38 +997,28 @@ static struct samsung_div_clock exynos4415_dmc_div_clks[] __initdata = {
DIV(CLK_DMC_DIV_MPLL_PRE, "div_mpll_pre", "mout_mpll", DIV_DMC1, 8, 2),
};
-static struct samsung_pll_clock exynos4415_dmc_plls[nr_dmc_plls] __initdata = {
- [mpll] = PLL(pll_35xx, CLK_DMC_FOUT_MPLL, "fout_mpll", "fin_pll",
- MPLL_LOCK, MPLL_CON0, NULL),
- [bpll] = PLL(pll_35xx, CLK_DMC_FOUT_BPLL, "fout_bpll", "fin_pll",
- BPLL_LOCK, BPLL_CON0, NULL),
+static struct samsung_pll_clock exynos4415_dmc_plls[] __initdata = {
+ PLL(pll_35xx, CLK_DMC_FOUT_MPLL, "fout_mpll", "fin_pll",
+ MPLL_LOCK, MPLL_CON0, exynos4415_pll_rates),
+ PLL(pll_35xx, CLK_DMC_FOUT_BPLL, "fout_bpll", "fin_pll",
+ BPLL_LOCK, BPLL_CON0, exynos4415_pll_rates),
+};
+
+static struct samsung_cmu_info cmu_dmc_info __initdata = {
+ .pll_clks = exynos4415_dmc_plls,
+ .nr_pll_clks = ARRAY_SIZE(exynos4415_dmc_plls),
+ .mux_clks = exynos4415_dmc_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(exynos4415_dmc_mux_clks),
+ .div_clks = exynos4415_dmc_div_clks,
+ .nr_div_clks = ARRAY_SIZE(exynos4415_dmc_div_clks),
+ .nr_clk_ids = NR_CLKS_DMC,
+ .clk_regs = exynos4415_cmu_dmc_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs),
};
static void __init exynos4415_cmu_dmc_init(struct device_node *np)
{
- void __iomem *reg_base;
-
- reg_base = of_iomap(np, 0);
- if (!reg_base)
- panic("%s: failed to map registers\n", __func__);
-
- exynos4415_dmc_ctx = samsung_clk_init(np, reg_base, NR_CLKS_DMC);
- if (!exynos4415_dmc_ctx)
- panic("%s: unable to allocate context.\n", __func__);
-
- exynos4415_dmc_plls[mpll].rate_table = exynos4415_pll_rates;
- exynos4415_dmc_plls[bpll].rate_table = exynos4415_pll_rates;
-
- samsung_clk_register_pll(exynos4415_dmc_ctx, exynos4415_dmc_plls,
- ARRAY_SIZE(exynos4415_dmc_plls), reg_base);
- samsung_clk_register_mux(exynos4415_dmc_ctx, exynos4415_dmc_mux_clks,
- ARRAY_SIZE(exynos4415_dmc_mux_clks));
- samsung_clk_register_div(exynos4415_dmc_ctx, exynos4415_dmc_div_clks,
- ARRAY_SIZE(exynos4415_dmc_div_clks));
-
- exynos4415_dmc_clk_sleep_init();
-
- samsung_clk_of_add_provider(np, exynos4415_dmc_ctx);
+ samsung_cmu_register_one(np, &cmu_dmc_info);
}
CLK_OF_DECLARE(exynos4415_cmu_dmc, "samsung,exynos4415-cmu-dmc",
exynos4415_cmu_dmc_init);
diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c
index ea4483b8d62e..03d36e847b78 100644
--- a/drivers/clk/samsung/clk-exynos7.c
+++ b/drivers/clk/samsung/clk-exynos7.c
@@ -34,6 +34,7 @@
#define DIV_TOPC0 0x0600
#define DIV_TOPC1 0x0604
#define DIV_TOPC3 0x060C
+#define ENABLE_ACLK_TOPC1 0x0804
static struct samsung_fixed_factor_clock topc_fixed_factor_clks[] __initdata = {
FFACTOR(0, "ffac_topc_bus0_pll_div2", "mout_bus0_pll_ctrl", 1, 2, 0),
@@ -45,6 +46,7 @@ static struct samsung_fixed_factor_clock topc_fixed_factor_clks[] __initdata = {
};
/* List of parent clocks for Muxes in CMU_TOPC */
+PNAME(mout_aud_pll_ctrl_p) = { "fin_pll", "fout_aud_pll" };
PNAME(mout_bus0_pll_ctrl_p) = { "fin_pll", "fout_bus0_pll" };
PNAME(mout_bus1_pll_ctrl_p) = { "fin_pll", "fout_bus1_pll" };
PNAME(mout_cc_pll_ctrl_p) = { "fin_pll", "fout_cc_pll" };
@@ -104,9 +106,11 @@ static struct samsung_mux_clock topc_mux_clks[] __initdata = {
MUX(0, "mout_sclk_bus0_pll_out", mout_sclk_bus0_pll_out_p,
MUX_SEL_TOPC1, 16, 1),
+ MUX(0, "mout_aud_pll_ctrl", mout_aud_pll_ctrl_p, MUX_SEL_TOPC1, 0, 1),
MUX(0, "mout_aclk_ccore_133", mout_topc_group2, MUX_SEL_TOPC2, 4, 2),
+ MUX(0, "mout_aclk_mscl_532", mout_topc_group2, MUX_SEL_TOPC3, 20, 2),
MUX(0, "mout_aclk_peris_66", mout_topc_group2, MUX_SEL_TOPC3, 24, 2),
};
@@ -114,6 +118,8 @@ static struct samsung_div_clock topc_div_clks[] __initdata = {
DIV(DOUT_ACLK_CCORE_133, "dout_aclk_ccore_133", "mout_aclk_ccore_133",
DIV_TOPC0, 4, 4),
+ DIV(DOUT_ACLK_MSCL_532, "dout_aclk_mscl_532", "mout_aclk_mscl_532",
+ DIV_TOPC1, 20, 4),
DIV(DOUT_ACLK_PERIS, "dout_aclk_peris_66", "mout_aclk_peris_66",
DIV_TOPC1, 24, 4),
@@ -125,6 +131,18 @@ static struct samsung_div_clock topc_div_clks[] __initdata = {
DIV_TOPC3, 12, 3),
DIV(DOUT_SCLK_MFC_PLL, "dout_sclk_mfc_pll", "mout_mfc_pll_ctrl",
DIV_TOPC3, 16, 3),
+ DIV(DOUT_SCLK_AUD_PLL, "dout_sclk_aud_pll", "mout_aud_pll_ctrl",
+ DIV_TOPC3, 28, 3),
+};
+
+static struct samsung_pll_rate_table pll1460x_24mhz_tbl[] __initdata = {
+ PLL_36XX_RATE(491520000, 20, 1, 0, 31457),
+ {},
+};
+
+static struct samsung_gate_clock topc_gate_clks[] __initdata = {
+ GATE(ACLK_MSCL_532, "aclk_mscl_532", "dout_aclk_mscl_532",
+ ENABLE_ACLK_TOPC1, 20, 0, 0),
};
static struct samsung_pll_clock topc_pll_clks[] __initdata = {
@@ -136,8 +154,8 @@ static struct samsung_pll_clock topc_pll_clks[] __initdata = {
BUS1_DPLL_CON0, NULL),
PLL(pll_1452x, 0, "fout_mfc_pll", "fin_pll", MFC_PLL_LOCK,
MFC_PLL_CON0, NULL),
- PLL(pll_1460x, 0, "fout_aud_pll", "fin_pll", AUD_PLL_LOCK,
- AUD_PLL_CON0, NULL),
+ PLL(pll_1460x, FOUT_AUD_PLL, "fout_aud_pll", "fin_pll", AUD_PLL_LOCK,
+ AUD_PLL_CON0, pll1460x_24mhz_tbl),
};
static struct samsung_cmu_info topc_cmu_info __initdata = {
@@ -147,6 +165,8 @@ static struct samsung_cmu_info topc_cmu_info __initdata = {
.nr_mux_clks = ARRAY_SIZE(topc_mux_clks),
.div_clks = topc_div_clks,
.nr_div_clks = ARRAY_SIZE(topc_div_clks),
+ .gate_clks = topc_gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(topc_gate_clks),
.fixed_factor_clks = topc_fixed_factor_clks,
.nr_fixed_factor_clks = ARRAY_SIZE(topc_fixed_factor_clks),
.nr_clk_ids = TOPC_NR_CLK,
@@ -166,9 +186,18 @@ CLK_OF_DECLARE(exynos7_clk_topc, "samsung,exynos7-clock-topc",
#define MUX_SEL_TOP00 0x0200
#define MUX_SEL_TOP01 0x0204
#define MUX_SEL_TOP03 0x020C
+#define MUX_SEL_TOP0_PERIC0 0x0230
+#define MUX_SEL_TOP0_PERIC1 0x0234
+#define MUX_SEL_TOP0_PERIC2 0x0238
#define MUX_SEL_TOP0_PERIC3 0x023C
#define DIV_TOP03 0x060C
+#define DIV_TOP0_PERIC0 0x0630
+#define DIV_TOP0_PERIC1 0x0634
+#define DIV_TOP0_PERIC2 0x0638
#define DIV_TOP0_PERIC3 0x063C
+#define ENABLE_SCLK_TOP0_PERIC0 0x0A30
+#define ENABLE_SCLK_TOP0_PERIC1 0x0A34
+#define ENABLE_SCLK_TOP0_PERIC2 0x0A38
#define ENABLE_SCLK_TOP0_PERIC3 0x0A3C
/* List of parent clocks for Muxes in CMU_TOP0 */
@@ -176,6 +205,7 @@ PNAME(mout_bus0_pll_p) = { "fin_pll", "dout_sclk_bus0_pll" };
PNAME(mout_bus1_pll_p) = { "fin_pll", "dout_sclk_bus1_pll" };
PNAME(mout_cc_pll_p) = { "fin_pll", "dout_sclk_cc_pll" };
PNAME(mout_mfc_pll_p) = { "fin_pll", "dout_sclk_mfc_pll" };
+PNAME(mout_aud_pll_p) = { "fin_pll", "dout_sclk_aud_pll" };
PNAME(mout_top0_half_bus0_pll_p) = {"mout_top0_bus0_pll",
"ffac_top0_bus0_pll_div2"};
@@ -189,18 +219,34 @@ PNAME(mout_top0_half_mfc_pll_p) = {"mout_top0_mfc_pll",
PNAME(mout_top0_group1) = {"mout_top0_half_bus0_pll",
"mout_top0_half_bus1_pll", "mout_top0_half_cc_pll",
"mout_top0_half_mfc_pll"};
+PNAME(mout_top0_group3) = {"ioclk_audiocdclk0",
+ "ioclk_audiocdclk1", "ioclk_spdif_extclk",
+ "mout_top0_aud_pll", "mout_top0_half_bus0_pll",
+ "mout_top0_half_bus1_pll"};
+PNAME(mout_top0_group4) = {"ioclk_audiocdclk1", "mout_top0_aud_pll",
+ "mout_top0_half_bus0_pll", "mout_top0_half_bus1_pll"};
static unsigned long top0_clk_regs[] __initdata = {
MUX_SEL_TOP00,
MUX_SEL_TOP01,
MUX_SEL_TOP03,
+ MUX_SEL_TOP0_PERIC0,
+ MUX_SEL_TOP0_PERIC1,
+ MUX_SEL_TOP0_PERIC2,
MUX_SEL_TOP0_PERIC3,
DIV_TOP03,
+ DIV_TOP0_PERIC0,
+ DIV_TOP0_PERIC1,
+ DIV_TOP0_PERIC2,
DIV_TOP0_PERIC3,
+ ENABLE_SCLK_TOP0_PERIC0,
+ ENABLE_SCLK_TOP0_PERIC1,
+ ENABLE_SCLK_TOP0_PERIC2,
ENABLE_SCLK_TOP0_PERIC3,
};
static struct samsung_mux_clock top0_mux_clks[] __initdata = {
+ MUX(0, "mout_top0_aud_pll", mout_aud_pll_p, MUX_SEL_TOP00, 0, 1),
MUX(0, "mout_top0_mfc_pll", mout_mfc_pll_p, MUX_SEL_TOP00, 4, 1),
MUX(0, "mout_top0_cc_pll", mout_cc_pll_p, MUX_SEL_TOP00, 8, 1),
MUX(0, "mout_top0_bus1_pll", mout_bus1_pll_p, MUX_SEL_TOP00, 12, 1),
@@ -218,10 +264,20 @@ static struct samsung_mux_clock top0_mux_clks[] __initdata = {
MUX(0, "mout_aclk_peric1_66", mout_top0_group1, MUX_SEL_TOP03, 12, 2),
MUX(0, "mout_aclk_peric0_66", mout_top0_group1, MUX_SEL_TOP03, 20, 2),
+ MUX(0, "mout_sclk_spdif", mout_top0_group3, MUX_SEL_TOP0_PERIC0, 4, 3),
+ MUX(0, "mout_sclk_pcm1", mout_top0_group4, MUX_SEL_TOP0_PERIC0, 8, 2),
+ MUX(0, "mout_sclk_i2s1", mout_top0_group4, MUX_SEL_TOP0_PERIC0, 20, 2),
+
+ MUX(0, "mout_sclk_spi1", mout_top0_group1, MUX_SEL_TOP0_PERIC1, 8, 2),
+ MUX(0, "mout_sclk_spi0", mout_top0_group1, MUX_SEL_TOP0_PERIC1, 20, 2),
+
+ MUX(0, "mout_sclk_spi3", mout_top0_group1, MUX_SEL_TOP0_PERIC2, 8, 2),
+ MUX(0, "mout_sclk_spi2", mout_top0_group1, MUX_SEL_TOP0_PERIC2, 20, 2),
MUX(0, "mout_sclk_uart3", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 4, 2),
MUX(0, "mout_sclk_uart2", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 8, 2),
MUX(0, "mout_sclk_uart1", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 12, 2),
MUX(0, "mout_sclk_uart0", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 16, 2),
+ MUX(0, "mout_sclk_spi4", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 20, 2),
};
static struct samsung_div_clock top0_div_clks[] __initdata = {
@@ -230,13 +286,40 @@ static struct samsung_div_clock top0_div_clks[] __initdata = {
DIV(DOUT_ACLK_PERIC0, "dout_aclk_peric0_66", "mout_aclk_peric0_66",
DIV_TOP03, 20, 6),
+ DIV(0, "dout_sclk_spdif", "mout_sclk_spdif", DIV_TOP0_PERIC0, 4, 4),
+ DIV(0, "dout_sclk_pcm1", "mout_sclk_pcm1", DIV_TOP0_PERIC0, 8, 12),
+ DIV(0, "dout_sclk_i2s1", "mout_sclk_i2s1", DIV_TOP0_PERIC0, 20, 10),
+
+ DIV(0, "dout_sclk_spi1", "mout_sclk_spi1", DIV_TOP0_PERIC1, 8, 12),
+ DIV(0, "dout_sclk_spi0", "mout_sclk_spi0", DIV_TOP0_PERIC1, 20, 12),
+
+ DIV(0, "dout_sclk_spi3", "mout_sclk_spi3", DIV_TOP0_PERIC2, 8, 12),
+ DIV(0, "dout_sclk_spi2", "mout_sclk_spi2", DIV_TOP0_PERIC2, 20, 12),
+
DIV(0, "dout_sclk_uart3", "mout_sclk_uart3", DIV_TOP0_PERIC3, 4, 4),
DIV(0, "dout_sclk_uart2", "mout_sclk_uart2", DIV_TOP0_PERIC3, 8, 4),
DIV(0, "dout_sclk_uart1", "mout_sclk_uart1", DIV_TOP0_PERIC3, 12, 4),
DIV(0, "dout_sclk_uart0", "mout_sclk_uart0", DIV_TOP0_PERIC3, 16, 4),
+ DIV(0, "dout_sclk_spi4", "mout_sclk_spi4", DIV_TOP0_PERIC3, 20, 12),
};
static struct samsung_gate_clock top0_gate_clks[] __initdata = {
+ GATE(CLK_SCLK_SPDIF, "sclk_spdif", "dout_sclk_spdif",
+ ENABLE_SCLK_TOP0_PERIC0, 4, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_PCM1, "sclk_pcm1", "dout_sclk_pcm1",
+ ENABLE_SCLK_TOP0_PERIC0, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_I2S1, "sclk_i2s1", "dout_sclk_i2s1",
+ ENABLE_SCLK_TOP0_PERIC0, 20, CLK_SET_RATE_PARENT, 0),
+
+ GATE(CLK_SCLK_SPI1, "sclk_spi1", "dout_sclk_spi1",
+ ENABLE_SCLK_TOP0_PERIC1, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_SPI0, "sclk_spi0", "dout_sclk_spi0",
+ ENABLE_SCLK_TOP0_PERIC1, 20, CLK_SET_RATE_PARENT, 0),
+
+ GATE(CLK_SCLK_SPI3, "sclk_spi3", "dout_sclk_spi3",
+ ENABLE_SCLK_TOP0_PERIC2, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_SPI2, "sclk_spi2", "dout_sclk_spi2",
+ ENABLE_SCLK_TOP0_PERIC2, 20, CLK_SET_RATE_PARENT, 0),
GATE(CLK_SCLK_UART3, "sclk_uart3", "dout_sclk_uart3",
ENABLE_SCLK_TOP0_PERIC3, 4, 0, 0),
GATE(CLK_SCLK_UART2, "sclk_uart2", "dout_sclk_uart2",
@@ -245,6 +328,8 @@ static struct samsung_gate_clock top0_gate_clks[] __initdata = {
ENABLE_SCLK_TOP0_PERIC3, 12, 0, 0),
GATE(CLK_SCLK_UART0, "sclk_uart0", "dout_sclk_uart0",
ENABLE_SCLK_TOP0_PERIC3, 16, 0, 0),
+ GATE(CLK_SCLK_SPI4, "sclk_spi4", "dout_sclk_spi4",
+ ENABLE_SCLK_TOP0_PERIC3, 20, CLK_SET_RATE_PARENT, 0),
};
static struct samsung_fixed_factor_clock top0_fixed_factor_clks[] __initdata = {
@@ -343,6 +428,8 @@ static struct samsung_mux_clock top1_mux_clks[] __initdata = {
MUX(0, "mout_aclk_fsys0_200", mout_top1_group1, MUX_SEL_TOP13, 28, 2),
MUX(0, "mout_sclk_mmc2", mout_top1_group1, MUX_SEL_TOP1_FSYS0, 24, 2),
+ MUX(0, "mout_sclk_usbdrd300", mout_top1_group1,
+ MUX_SEL_TOP1_FSYS0, 28, 2),
MUX(0, "mout_sclk_mmc1", mout_top1_group1, MUX_SEL_TOP1_FSYS1, 24, 2),
MUX(0, "mout_sclk_mmc0", mout_top1_group1, MUX_SEL_TOP1_FSYS1, 28, 2),
@@ -356,6 +443,8 @@ static struct samsung_div_clock top1_div_clks[] __initdata = {
DIV(DOUT_SCLK_MMC2, "dout_sclk_mmc2", "mout_sclk_mmc2",
DIV_TOP1_FSYS0, 24, 4),
+ DIV(0, "dout_sclk_usbdrd300", "mout_sclk_usbdrd300",
+ DIV_TOP1_FSYS0, 28, 4),
DIV(DOUT_SCLK_MMC1, "dout_sclk_mmc1", "mout_sclk_mmc1",
DIV_TOP1_FSYS1, 24, 4),
@@ -366,6 +455,8 @@ static struct samsung_div_clock top1_div_clks[] __initdata = {
static struct samsung_gate_clock top1_gate_clks[] __initdata = {
GATE(CLK_SCLK_MMC2, "sclk_mmc2", "dout_sclk_mmc2",
ENABLE_SCLK_TOP1_FSYS0, 24, CLK_SET_RATE_PARENT, 0),
+ GATE(0, "sclk_usbdrd300", "dout_sclk_usbdrd300",
+ ENABLE_SCLK_TOP1_FSYS0, 28, 0, 0),
GATE(CLK_SCLK_MMC1, "sclk_mmc1", "dout_sclk_mmc1",
ENABLE_SCLK_TOP1_FSYS1, 24, CLK_SET_RATE_PARENT, 0),
@@ -514,6 +605,7 @@ static void __init exynos7_clk_peric0_init(struct device_node *np)
/* Register Offset definitions for CMU_PERIC1 (0x14C80000) */
#define MUX_SEL_PERIC10 0x0200
#define MUX_SEL_PERIC11 0x0204
+#define MUX_SEL_PERIC12 0x0208
#define ENABLE_PCLK_PERIC1 0x0900
#define ENABLE_SCLK_PERIC10 0x0A00
@@ -525,10 +617,16 @@ PNAME(mout_aclk_peric1_66_p) = { "fin_pll", "dout_aclk_peric1_66" };
PNAME(mout_sclk_uart1_p) = { "fin_pll", "sclk_uart1" };
PNAME(mout_sclk_uart2_p) = { "fin_pll", "sclk_uart2" };
PNAME(mout_sclk_uart3_p) = { "fin_pll", "sclk_uart3" };
+PNAME(mout_sclk_spi0_p) = { "fin_pll", "sclk_spi0" };
+PNAME(mout_sclk_spi1_p) = { "fin_pll", "sclk_spi1" };
+PNAME(mout_sclk_spi2_p) = { "fin_pll", "sclk_spi2" };
+PNAME(mout_sclk_spi3_p) = { "fin_pll", "sclk_spi3" };
+PNAME(mout_sclk_spi4_p) = { "fin_pll", "sclk_spi4" };
static unsigned long peric1_clk_regs[] __initdata = {
MUX_SEL_PERIC10,
MUX_SEL_PERIC11,
+ MUX_SEL_PERIC12,
ENABLE_PCLK_PERIC1,
ENABLE_SCLK_PERIC10,
};
@@ -537,6 +635,16 @@ static struct samsung_mux_clock peric1_mux_clks[] __initdata = {
MUX(0, "mout_aclk_peric1_66_user", mout_aclk_peric1_66_p,
MUX_SEL_PERIC10, 0, 1),
+ MUX_F(0, "mout_sclk_spi0_user", mout_sclk_spi0_p,
+ MUX_SEL_PERIC11, 0, 1, CLK_SET_RATE_PARENT, 0),
+ MUX_F(0, "mout_sclk_spi1_user", mout_sclk_spi1_p,
+ MUX_SEL_PERIC11, 4, 1, CLK_SET_RATE_PARENT, 0),
+ MUX_F(0, "mout_sclk_spi2_user", mout_sclk_spi2_p,
+ MUX_SEL_PERIC11, 8, 1, CLK_SET_RATE_PARENT, 0),
+ MUX_F(0, "mout_sclk_spi3_user", mout_sclk_spi3_p,
+ MUX_SEL_PERIC11, 12, 1, CLK_SET_RATE_PARENT, 0),
+ MUX_F(0, "mout_sclk_spi4_user", mout_sclk_spi4_p,
+ MUX_SEL_PERIC11, 16, 1, CLK_SET_RATE_PARENT, 0),
MUX(0, "mout_sclk_uart1_user", mout_sclk_uart1_p,
MUX_SEL_PERIC11, 20, 1),
MUX(0, "mout_sclk_uart2_user", mout_sclk_uart2_p,
@@ -562,6 +670,22 @@ static struct samsung_gate_clock peric1_gate_clks[] __initdata = {
ENABLE_PCLK_PERIC1, 10, 0, 0),
GATE(PCLK_UART3, "pclk_uart3", "mout_aclk_peric1_66_user",
ENABLE_PCLK_PERIC1, 11, 0, 0),
+ GATE(PCLK_SPI0, "pclk_spi0", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 12, 0, 0),
+ GATE(PCLK_SPI1, "pclk_spi1", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 13, 0, 0),
+ GATE(PCLK_SPI2, "pclk_spi2", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 14, 0, 0),
+ GATE(PCLK_SPI3, "pclk_spi3", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 15, 0, 0),
+ GATE(PCLK_SPI4, "pclk_spi4", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 16, 0, 0),
+ GATE(PCLK_I2S1, "pclk_i2s1", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 17, CLK_SET_RATE_PARENT, 0),
+ GATE(PCLK_PCM1, "pclk_pcm1", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 18, 0, 0),
+ GATE(PCLK_SPDIF, "pclk_spdif", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 19, 0, 0),
GATE(SCLK_UART1, "sclk_uart1_user", "mout_sclk_uart1_user",
ENABLE_SCLK_PERIC10, 9, 0, 0),
@@ -569,6 +693,22 @@ static struct samsung_gate_clock peric1_gate_clks[] __initdata = {
ENABLE_SCLK_PERIC10, 10, 0, 0),
GATE(SCLK_UART3, "sclk_uart3_user", "mout_sclk_uart3_user",
ENABLE_SCLK_PERIC10, 11, 0, 0),
+ GATE(SCLK_SPI0, "sclk_spi0_user", "mout_sclk_spi0_user",
+ ENABLE_SCLK_PERIC10, 12, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPI1, "sclk_spi1_user", "mout_sclk_spi1_user",
+ ENABLE_SCLK_PERIC10, 13, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPI2, "sclk_spi2_user", "mout_sclk_spi2_user",
+ ENABLE_SCLK_PERIC10, 14, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPI3, "sclk_spi3_user", "mout_sclk_spi3_user",
+ ENABLE_SCLK_PERIC10, 15, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPI4, "sclk_spi4_user", "mout_sclk_spi4_user",
+ ENABLE_SCLK_PERIC10, 16, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_I2S1, "sclk_i2s1_user", "sclk_i2s1",
+ ENABLE_SCLK_PERIC10, 17, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_PCM1, "sclk_pcm1_user", "sclk_pcm1",
+ ENABLE_SCLK_PERIC10, 18, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPDIF, "sclk_spdif_user", "sclk_spdif",
+ ENABLE_SCLK_PERIC10, 19, CLK_SET_RATE_PARENT, 0),
};
static struct samsung_cmu_info peric1_cmu_info __initdata = {
@@ -647,7 +787,12 @@ CLK_OF_DECLARE(exynos7_clk_peris, "samsung,exynos7-clock-peris",
/* Register Offset definitions for CMU_FSYS0 (0x10E90000) */
#define MUX_SEL_FSYS00 0x0200
#define MUX_SEL_FSYS01 0x0204
+#define MUX_SEL_FSYS02 0x0208
+#define ENABLE_ACLK_FSYS00 0x0800
#define ENABLE_ACLK_FSYS01 0x0804
+#define ENABLE_SCLK_FSYS01 0x0A04
+#define ENABLE_SCLK_FSYS02 0x0A08
+#define ENABLE_SCLK_FSYS04 0x0A10
/*
* List of parent clocks for Muxes in CMU_FSYS0
@@ -655,10 +800,29 @@ CLK_OF_DECLARE(exynos7_clk_peris, "samsung,exynos7-clock-peris",
PNAME(mout_aclk_fsys0_200_p) = { "fin_pll", "dout_aclk_fsys0_200" };
PNAME(mout_sclk_mmc2_p) = { "fin_pll", "sclk_mmc2" };
+PNAME(mout_sclk_usbdrd300_p) = { "fin_pll", "sclk_usbdrd300" };
+PNAME(mout_phyclk_usbdrd300_udrd30_phyclk_p) = { "fin_pll",
+ "phyclk_usbdrd300_udrd30_phyclock" };
+PNAME(mout_phyclk_usbdrd300_udrd30_pipe_pclk_p) = { "fin_pll",
+ "phyclk_usbdrd300_udrd30_pipe_pclk" };
+
+/* fixed rate clocks used in the FSYS0 block */
+struct samsung_fixed_rate_clock fixed_rate_clks_fsys0[] __initdata = {
+ FRATE(0, "phyclk_usbdrd300_udrd30_phyclock", NULL,
+ CLK_IS_ROOT, 60000000),
+ FRATE(0, "phyclk_usbdrd300_udrd30_pipe_pclk", NULL,
+ CLK_IS_ROOT, 125000000),
+};
+
static unsigned long fsys0_clk_regs[] __initdata = {
MUX_SEL_FSYS00,
MUX_SEL_FSYS01,
+ MUX_SEL_FSYS02,
+ ENABLE_ACLK_FSYS00,
ENABLE_ACLK_FSYS01,
+ ENABLE_SCLK_FSYS01,
+ ENABLE_SCLK_FSYS02,
+ ENABLE_SCLK_FSYS04,
};
static struct samsung_mux_clock fsys0_mux_clks[] __initdata = {
@@ -666,11 +830,49 @@ static struct samsung_mux_clock fsys0_mux_clks[] __initdata = {
MUX_SEL_FSYS00, 24, 1),
MUX(0, "mout_sclk_mmc2_user", mout_sclk_mmc2_p, MUX_SEL_FSYS01, 24, 1),
+ MUX(0, "mout_sclk_usbdrd300_user", mout_sclk_usbdrd300_p,
+ MUX_SEL_FSYS01, 28, 1),
+
+ MUX(0, "mout_phyclk_usbdrd300_udrd30_pipe_pclk_user",
+ mout_phyclk_usbdrd300_udrd30_pipe_pclk_p,
+ MUX_SEL_FSYS02, 24, 1),
+ MUX(0, "mout_phyclk_usbdrd300_udrd30_phyclk_user",
+ mout_phyclk_usbdrd300_udrd30_phyclk_p,
+ MUX_SEL_FSYS02, 28, 1),
};
static struct samsung_gate_clock fsys0_gate_clks[] __initdata = {
+ GATE(ACLK_AXIUS_USBDRD30X_FSYS0X, "aclk_axius_usbdrd30x_fsys0x",
+ "mout_aclk_fsys0_200_user",
+ ENABLE_ACLK_FSYS00, 19, 0, 0),
+ GATE(ACLK_PDMA1, "aclk_pdma1", "mout_aclk_fsys0_200_user",
+ ENABLE_ACLK_FSYS00, 3, 0, 0),
+ GATE(ACLK_PDMA0, "aclk_pdma0", "mout_aclk_fsys0_200_user",
+ ENABLE_ACLK_FSYS00, 4, 0, 0),
+
+ GATE(ACLK_USBDRD300, "aclk_usbdrd300", "mout_aclk_fsys0_200_user",
+ ENABLE_ACLK_FSYS01, 29, 0, 0),
GATE(ACLK_MMC2, "aclk_mmc2", "mout_aclk_fsys0_200_user",
ENABLE_ACLK_FSYS01, 31, 0, 0),
+
+ GATE(SCLK_USBDRD300_SUSPENDCLK, "sclk_usbdrd300_suspendclk",
+ "mout_sclk_usbdrd300_user",
+ ENABLE_SCLK_FSYS01, 4, 0, 0),
+ GATE(SCLK_USBDRD300_REFCLK, "sclk_usbdrd300_refclk", "fin_pll",
+ ENABLE_SCLK_FSYS01, 8, 0, 0),
+
+ GATE(PHYCLK_USBDRD300_UDRD30_PIPE_PCLK_USER,
+ "phyclk_usbdrd300_udrd30_pipe_pclk_user",
+ "mout_phyclk_usbdrd300_udrd30_pipe_pclk_user",
+ ENABLE_SCLK_FSYS02, 24, 0, 0),
+ GATE(PHYCLK_USBDRD300_UDRD30_PHYCLK_USER,
+ "phyclk_usbdrd300_udrd30_phyclk_user",
+ "mout_phyclk_usbdrd300_udrd30_phyclk_user",
+ ENABLE_SCLK_FSYS02, 28, 0, 0),
+
+ GATE(OSCCLK_PHY_CLKOUT_USB30_PHY, "oscclk_phy_clkout_usb30_phy",
+ "fin_pll",
+ ENABLE_SCLK_FSYS04, 28, 0, 0),
};
static struct samsung_cmu_info fsys0_cmu_info __initdata = {
@@ -741,3 +943,205 @@ static void __init exynos7_clk_fsys1_init(struct device_node *np)
CLK_OF_DECLARE(exynos7_clk_fsys1, "samsung,exynos7-clock-fsys1",
exynos7_clk_fsys1_init);
+
+#define MUX_SEL_MSCL 0x0200
+#define DIV_MSCL 0x0600
+#define ENABLE_ACLK_MSCL 0x0800
+#define ENABLE_PCLK_MSCL 0x0900
+
+/* List of parent clocks for Muxes in CMU_MSCL */
+PNAME(mout_aclk_mscl_532_user_p) = { "fin_pll", "aclk_mscl_532" };
+
+static unsigned long mscl_clk_regs[] __initdata = {
+ MUX_SEL_MSCL,
+ DIV_MSCL,
+ ENABLE_ACLK_MSCL,
+ ENABLE_PCLK_MSCL,
+};
+
+static struct samsung_mux_clock mscl_mux_clks[] __initdata = {
+ MUX(USERMUX_ACLK_MSCL_532, "usermux_aclk_mscl_532",
+ mout_aclk_mscl_532_user_p, MUX_SEL_MSCL, 0, 1),
+};
+static struct samsung_div_clock mscl_div_clks[] __initdata = {
+ DIV(DOUT_PCLK_MSCL, "dout_pclk_mscl", "usermux_aclk_mscl_532",
+ DIV_MSCL, 0, 3),
+};
+static struct samsung_gate_clock mscl_gate_clks[] __initdata = {
+
+ GATE(ACLK_MSCL_0, "aclk_mscl_0", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 31, 0, 0),
+ GATE(ACLK_MSCL_1, "aclk_mscl_1", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 30, 0, 0),
+ GATE(ACLK_JPEG, "aclk_jpeg", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 29, 0, 0),
+ GATE(ACLK_G2D, "aclk_g2d", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 28, 0, 0),
+ GATE(ACLK_LH_ASYNC_SI_MSCL_0, "aclk_lh_async_si_mscl_0",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 27, 0, 0),
+ GATE(ACLK_LH_ASYNC_SI_MSCL_1, "aclk_lh_async_si_mscl_1",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 26, 0, 0),
+ GATE(ACLK_XIU_MSCLX_0, "aclk_xiu_msclx_0", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 25, 0, 0),
+ GATE(ACLK_XIU_MSCLX_1, "aclk_xiu_msclx_1", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 24, 0, 0),
+ GATE(ACLK_AXI2ACEL_BRIDGE, "aclk_axi2acel_bridge",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 23, 0, 0),
+ GATE(ACLK_QE_MSCL_0, "aclk_qe_mscl_0", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 22, 0, 0),
+ GATE(ACLK_QE_MSCL_1, "aclk_qe_mscl_1", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 21, 0, 0),
+ GATE(ACLK_QE_JPEG, "aclk_qe_jpeg", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 20, 0, 0),
+ GATE(ACLK_QE_G2D, "aclk_qe_g2d", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 19, 0, 0),
+ GATE(ACLK_PPMU_MSCL_0, "aclk_ppmu_mscl_0", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 18, 0, 0),
+ GATE(ACLK_PPMU_MSCL_1, "aclk_ppmu_mscl_1", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 17, 0, 0),
+ GATE(ACLK_MSCLNP_133, "aclk_msclnp_133", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 16, 0, 0),
+ GATE(ACLK_AHB2APB_MSCL0P, "aclk_ahb2apb_mscl0p",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 15, 0, 0),
+ GATE(ACLK_AHB2APB_MSCL1P, "aclk_ahb2apb_mscl1p",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 14, 0, 0),
+
+ GATE(PCLK_MSCL_0, "pclk_mscl_0", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 31, 0, 0),
+ GATE(PCLK_MSCL_1, "pclk_mscl_1", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 30, 0, 0),
+ GATE(PCLK_JPEG, "pclk_jpeg", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 29, 0, 0),
+ GATE(PCLK_G2D, "pclk_g2d", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 28, 0, 0),
+ GATE(PCLK_QE_MSCL_0, "pclk_qe_mscl_0", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 27, 0, 0),
+ GATE(PCLK_QE_MSCL_1, "pclk_qe_mscl_1", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 26, 0, 0),
+ GATE(PCLK_QE_JPEG, "pclk_qe_jpeg", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 25, 0, 0),
+ GATE(PCLK_QE_G2D, "pclk_qe_g2d", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 24, 0, 0),
+ GATE(PCLK_PPMU_MSCL_0, "pclk_ppmu_mscl_0", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 23, 0, 0),
+ GATE(PCLK_PPMU_MSCL_1, "pclk_ppmu_mscl_1", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 22, 0, 0),
+ GATE(PCLK_AXI2ACEL_BRIDGE, "pclk_axi2acel_bridge", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 21, 0, 0),
+ GATE(PCLK_PMU_MSCL, "pclk_pmu_mscl", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 20, 0, 0),
+};
+
+static struct samsung_cmu_info mscl_cmu_info __initdata = {
+ .mux_clks = mscl_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(mscl_mux_clks),
+ .div_clks = mscl_div_clks,
+ .nr_div_clks = ARRAY_SIZE(mscl_div_clks),
+ .gate_clks = mscl_gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(mscl_gate_clks),
+ .nr_clk_ids = MSCL_NR_CLK,
+ .clk_regs = mscl_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(mscl_clk_regs),
+};
+
+static void __init exynos7_clk_mscl_init(struct device_node *np)
+{
+ samsung_cmu_register_one(np, &mscl_cmu_info);
+}
+
+CLK_OF_DECLARE(exynos7_clk_mscl, "samsung,exynos7-clock-mscl",
+ exynos7_clk_mscl_init);
+
+/* Register Offset definitions for CMU_AUD (0x114C0000) */
+#define MUX_SEL_AUD 0x0200
+#define DIV_AUD0 0x0600
+#define DIV_AUD1 0x0604
+#define ENABLE_ACLK_AUD 0x0800
+#define ENABLE_PCLK_AUD 0x0900
+#define ENABLE_SCLK_AUD 0x0A00
+
+/*
+ * List of parent clocks for Muxes in CMU_AUD
+ */
+PNAME(mout_aud_pll_user_p) = { "fin_pll", "fout_aud_pll" };
+PNAME(mout_aud_group_p) = { "dout_aud_cdclk", "ioclk_audiocdclk0" };
+
+static unsigned long aud_clk_regs[] __initdata = {
+ MUX_SEL_AUD,
+ DIV_AUD0,
+ DIV_AUD1,
+ ENABLE_ACLK_AUD,
+ ENABLE_PCLK_AUD,
+ ENABLE_SCLK_AUD,
+};
+
+static struct samsung_mux_clock aud_mux_clks[] __initdata = {
+ MUX(0, "mout_sclk_i2s", mout_aud_group_p, MUX_SEL_AUD, 12, 1),
+ MUX(0, "mout_sclk_pcm", mout_aud_group_p, MUX_SEL_AUD, 16, 1),
+ MUX(0, "mout_aud_pll_user", mout_aud_pll_user_p, MUX_SEL_AUD, 20, 1),
+};
+
+static struct samsung_div_clock aud_div_clks[] __initdata = {
+ DIV(0, "dout_aud_ca5", "mout_aud_pll_user", DIV_AUD0, 0, 4),
+ DIV(0, "dout_aclk_aud", "dout_aud_ca5", DIV_AUD0, 4, 4),
+ DIV(0, "dout_aud_pclk_dbg", "dout_aud_ca5", DIV_AUD0, 8, 4),
+
+ DIV(0, "dout_sclk_i2s", "mout_sclk_i2s", DIV_AUD1, 0, 4),
+ DIV(0, "dout_sclk_pcm", "mout_sclk_pcm", DIV_AUD1, 4, 8),
+ DIV(0, "dout_sclk_uart", "dout_aud_cdclk", DIV_AUD1, 12, 4),
+ DIV(0, "dout_sclk_slimbus", "dout_aud_cdclk", DIV_AUD1, 16, 5),
+ DIV(0, "dout_aud_cdclk", "mout_aud_pll_user", DIV_AUD1, 24, 4),
+};
+
+static struct samsung_gate_clock aud_gate_clks[] __initdata = {
+ GATE(SCLK_PCM, "sclk_pcm", "dout_sclk_pcm",
+ ENABLE_SCLK_AUD, 27, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_I2S, "sclk_i2s", "dout_sclk_i2s",
+ ENABLE_SCLK_AUD, 28, CLK_SET_RATE_PARENT, 0),
+ GATE(0, "sclk_uart", "dout_sclk_uart", ENABLE_SCLK_AUD, 29, 0, 0),
+ GATE(0, "sclk_slimbus", "dout_sclk_slimbus",
+ ENABLE_SCLK_AUD, 30, 0, 0),
+
+ GATE(0, "pclk_dbg_aud", "dout_aud_pclk_dbg", ENABLE_PCLK_AUD, 19, 0, 0),
+ GATE(0, "pclk_gpio_aud", "dout_aclk_aud", ENABLE_PCLK_AUD, 20, 0, 0),
+ GATE(0, "pclk_wdt1", "dout_aclk_aud", ENABLE_PCLK_AUD, 22, 0, 0),
+ GATE(0, "pclk_wdt0", "dout_aclk_aud", ENABLE_PCLK_AUD, 23, 0, 0),
+ GATE(0, "pclk_slimbus", "dout_aclk_aud", ENABLE_PCLK_AUD, 24, 0, 0),
+ GATE(0, "pclk_uart", "dout_aclk_aud", ENABLE_PCLK_AUD, 25, 0, 0),
+ GATE(PCLK_PCM, "pclk_pcm", "dout_aclk_aud",
+ ENABLE_PCLK_AUD, 26, CLK_SET_RATE_PARENT, 0),
+ GATE(PCLK_I2S, "pclk_i2s", "dout_aclk_aud",
+ ENABLE_PCLK_AUD, 27, CLK_SET_RATE_PARENT, 0),
+ GATE(0, "pclk_timer", "dout_aclk_aud", ENABLE_PCLK_AUD, 28, 0, 0),
+ GATE(0, "pclk_smmu_aud", "dout_aclk_aud", ENABLE_PCLK_AUD, 31, 0, 0),
+
+ GATE(0, "aclk_smmu_aud", "dout_aclk_aud", ENABLE_ACLK_AUD, 27, 0, 0),
+ GATE(0, "aclk_acel_lh_async_si_top", "dout_aclk_aud",
+ ENABLE_ACLK_AUD, 28, 0, 0),
+ GATE(ACLK_ADMA, "aclk_dmac", "dout_aclk_aud", ENABLE_ACLK_AUD, 31, 0, 0),
+};
+
+static struct samsung_cmu_info aud_cmu_info __initdata = {
+ .mux_clks = aud_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(aud_mux_clks),
+ .div_clks = aud_div_clks,
+ .nr_div_clks = ARRAY_SIZE(aud_div_clks),
+ .gate_clks = aud_gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(aud_gate_clks),
+ .nr_clk_ids = AUD_NR_CLK,
+ .clk_regs = aud_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(aud_clk_regs),
+};
+
+static void __init exynos7_clk_aud_init(struct device_node *np)
+{
+ samsung_cmu_register_one(np, &aud_cmu_info);
+}
+
+CLK_OF_DECLARE(exynos7_clk_aud, "samsung,exynos7-clock-aud",
+ exynos7_clk_aud_init);
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index 4bda54095a16..9e1f88c04fd4 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -374,19 +374,24 @@ static void samsung_clk_sleep_init(void __iomem *reg_base,
* Common function which registers plls, muxes, dividers and gates
* for each CMU. It also add CMU register list to register cache.
*/
-void __init samsung_cmu_register_one(struct device_node *np,
+struct samsung_clk_provider * __init samsung_cmu_register_one(
+ struct device_node *np,
struct samsung_cmu_info *cmu)
{
void __iomem *reg_base;
struct samsung_clk_provider *ctx;
reg_base = of_iomap(np, 0);
- if (!reg_base)
+ if (!reg_base) {
panic("%s: failed to map registers\n", __func__);
+ return NULL;
+ }
ctx = samsung_clk_init(np, reg_base, cmu->nr_clk_ids);
- if (!ctx)
+ if (!ctx) {
panic("%s: unable to alllocate ctx\n", __func__);
+ return ctx;
+ }
if (cmu->pll_clks)
samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks,
@@ -410,4 +415,6 @@ void __init samsung_cmu_register_one(struct device_node *np,
cmu->nr_clk_regs);
samsung_clk_of_add_provider(np, ctx);
+
+ return ctx;
}
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 8acabe1f32c4..e4c75383cea7 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -392,7 +392,8 @@ extern void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx,
struct samsung_pll_clock *pll_list,
unsigned int nr_clk, void __iomem *base);
-extern void __init samsung_cmu_register_one(struct device_node *,
+extern struct samsung_clk_provider __init *samsung_cmu_register_one(
+ struct device_node *,
struct samsung_cmu_info *);
extern unsigned long _get_rate(const char *clk_name);
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index f83980f2b956..0689d7fb2666 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -1,9 +1,11 @@
obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o
+obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o
obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o
obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o
obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o
+obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o
diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c
index 639241e31e03..036a692c7219 100644
--- a/drivers/clk/shmobile/clk-div6.c
+++ b/drivers/clk/shmobile/clk-div6.c
@@ -54,12 +54,19 @@ static int cpg_div6_clock_enable(struct clk_hw *hw)
static void cpg_div6_clock_disable(struct clk_hw *hw)
{
struct div6_clock *clock = to_div6_clock(hw);
+ u32 val;
- /* DIV6 clocks require the divisor field to be non-zero when stopping
- * the clock.
+ val = clk_readl(clock->reg);
+ val |= CPG_DIV6_CKSTP;
+ /*
+ * DIV6 clocks require the divisor field to be non-zero when stopping
+ * the clock. However, some clocks (e.g. ZB on sh73a0) fail to be
+ * re-enabled later if the divisor field is changed when stopping the
+ * clock
*/
- clk_writel(clk_readl(clock->reg) | CPG_DIV6_CKSTP | CPG_DIV6_DIV_MASK,
- clock->reg);
+ if (!(val & CPG_DIV6_DIV_MASK))
+ val |= CPG_DIV6_DIV_MASK;
+ clk_writel(val, clock->reg);
}
static int cpg_div6_clock_is_enabled(struct clk_hw *hw)
@@ -83,6 +90,9 @@ static unsigned int cpg_div6_clock_calc_div(unsigned long rate,
{
unsigned int div;
+ if (!rate)
+ rate = 1;
+
div = DIV_ROUND_CLOSEST(parent_rate, rate);
return clamp_t(unsigned int, div, 1, 64);
}
diff --git a/drivers/clk/shmobile/clk-r8a73a4.c b/drivers/clk/shmobile/clk-r8a73a4.c
new file mode 100644
index 000000000000..29b9a0b0012a
--- /dev/null
+++ b/drivers/clk/shmobile/clk-r8a73a4.c
@@ -0,0 +1,241 @@
+/*
+ * r8a73a4 Core CPG Clocks
+ *
+ * Copyright (C) 2014 Ulrich Hecht
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/shmobile.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spinlock.h>
+
+struct r8a73a4_cpg {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+#define CPG_CKSCR 0xc0
+#define CPG_FRQCRA 0x00
+#define CPG_FRQCRB 0x04
+#define CPG_FRQCRC 0xe0
+#define CPG_PLL0CR 0xd8
+#define CPG_PLL1CR 0x28
+#define CPG_PLL2CR 0x2c
+#define CPG_PLL2HCR 0xe4
+#define CPG_PLL2SCR 0xf4
+
+#define CLK_ENABLE_ON_INIT BIT(0)
+
+struct div4_clk {
+ const char *name;
+ unsigned int reg;
+ unsigned int shift;
+};
+
+static struct div4_clk div4_clks[] = {
+ { "i", CPG_FRQCRA, 20 },
+ { "m3", CPG_FRQCRA, 12 },
+ { "b", CPG_FRQCRA, 8 },
+ { "m1", CPG_FRQCRA, 4 },
+ { "m2", CPG_FRQCRA, 0 },
+ { "zx", CPG_FRQCRB, 12 },
+ { "zs", CPG_FRQCRB, 8 },
+ { "hp", CPG_FRQCRB, 4 },
+ { NULL, 0, 0 },
+};
+
+static const struct clk_div_table div4_div_table[] = {
+ { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 },
+ { 6, 16 }, { 7, 18 }, { 8, 24 }, { 10, 36 }, { 11, 48 },
+ { 12, 10 }, { 0, 0 }
+};
+
+static struct clk * __init
+r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg,
+ const char *name)
+{
+ const struct clk_div_table *table = NULL;
+ const char *parent_name;
+ unsigned int shift, reg;
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+
+ if (!strcmp(name, "main")) {
+ u32 ckscr = clk_readl(cpg->reg + CPG_CKSCR);
+
+ switch ((ckscr >> 28) & 3) {
+ case 0: /* extal1 */
+ parent_name = of_clk_get_parent_name(np, 0);
+ break;
+ case 1: /* extal1 / 2 */
+ parent_name = of_clk_get_parent_name(np, 0);
+ div = 2;
+ break;
+ case 2: /* extal2 */
+ parent_name = of_clk_get_parent_name(np, 1);
+ break;
+ case 3: /* extal2 / 2 */
+ parent_name = of_clk_get_parent_name(np, 1);
+ div = 2;
+ break;
+ }
+ } else if (!strcmp(name, "pll0")) {
+ /* PLL0/1 are configurable multiplier clocks. Register them as
+ * fixed factor clocks for now as there's no generic multiplier
+ * clock implementation and we currently have no need to change
+ * the multiplier value.
+ */
+ u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+
+ parent_name = "main";
+ mult = ((value >> 24) & 0x7f) + 1;
+ if (value & BIT(20))
+ div = 2;
+ } else if (!strcmp(name, "pll1")) {
+ u32 value = clk_readl(cpg->reg + CPG_PLL1CR);
+
+ parent_name = "main";
+ /* XXX: enable bit? */
+ mult = ((value >> 24) & 0x7f) + 1;
+ if (value & BIT(7))
+ div = 2;
+ } else if (!strncmp(name, "pll2", 4)) {
+ u32 value, cr;
+
+ switch (name[4]) {
+ case 0:
+ cr = CPG_PLL2CR;
+ break;
+ case 's':
+ cr = CPG_PLL2SCR;
+ break;
+ case 'h':
+ cr = CPG_PLL2HCR;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ value = clk_readl(cpg->reg + cr);
+ switch ((value >> 5) & 7) {
+ case 0:
+ parent_name = "main";
+ div = 2;
+ break;
+ case 1:
+ parent_name = "extal2";
+ div = 2;
+ break;
+ case 3:
+ parent_name = "extal2";
+ div = 4;
+ break;
+ case 4:
+ parent_name = "main";
+ break;
+ case 5:
+ parent_name = "extal2";
+ break;
+ default:
+ pr_warn("%s: unexpected parent of %s\n", __func__,
+ name);
+ return ERR_PTR(-EINVAL);
+ }
+ /* XXX: enable bit? */
+ mult = ((value >> 24) & 0x7f) + 1;
+ } else if (!strcmp(name, "z") || !strcmp(name, "z2")) {
+ u32 shift = 8;
+
+ parent_name = "pll0";
+ if (name[1] == '2') {
+ div = 2;
+ shift = 0;
+ }
+ div *= 32;
+ mult = 0x20 - ((clk_readl(cpg->reg + CPG_FRQCRC) >> shift)
+ & 0x1f);
+ } else {
+ struct div4_clk *c;
+
+ for (c = div4_clks; c->name; c++) {
+ if (!strcmp(name, c->name))
+ break;
+ }
+ if (!c->name)
+ return ERR_PTR(-EINVAL);
+
+ parent_name = "pll1";
+ table = div4_div_table;
+ reg = c->reg;
+ shift = c->shift;
+ }
+
+ if (!table) {
+ return clk_register_fixed_factor(NULL, name, parent_name, 0,
+ mult, div);
+ } else {
+ return clk_register_divider_table(NULL, name, parent_name, 0,
+ cpg->reg + reg, shift, 4, 0,
+ table, &cpg->lock);
+ }
+}
+
+static void __init r8a73a4_cpg_clocks_init(struct device_node *np)
+{
+ struct r8a73a4_cpg *cpg;
+ struct clk **clks;
+ unsigned int i;
+ int num_clks;
+
+ num_clks = of_property_count_strings(np, "clock-output-names");
+ if (num_clks < 0) {
+ pr_err("%s: failed to count clocks\n", __func__);
+ return;
+ }
+
+ cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+ clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL);
+ if (cpg == NULL || clks == NULL) {
+ /* We're leaking memory on purpose, there's no point in cleaning
+ * up as the system won't boot anyway.
+ */
+ return;
+ }
+
+ spin_lock_init(&cpg->lock);
+
+ cpg->data.clks = clks;
+ cpg->data.clk_num = num_clks;
+
+ cpg->reg = of_iomap(np, 0);
+ if (WARN_ON(cpg->reg == NULL))
+ return;
+
+ for (i = 0; i < num_clks; ++i) {
+ const char *name;
+ struct clk *clk;
+
+ of_property_read_string_index(np, "clock-output-names", i,
+ &name);
+
+ clk = r8a73a4_cpg_register_clock(np, cpg, name);
+ if (IS_ERR(clk))
+ pr_err("%s: failed to register %s %s clock (%ld)\n",
+ __func__, np->name, name, PTR_ERR(clk));
+ else
+ cpg->data.clks[i] = clk;
+ }
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+}
+CLK_OF_DECLARE(r8a73a4_cpg_clks, "renesas,r8a73a4-cpg-clocks",
+ r8a73a4_cpg_clocks_init);
diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c
index e996425d06a9..acfb6d7dbd6b 100644
--- a/drivers/clk/shmobile/clk-rcar-gen2.c
+++ b/drivers/clk/shmobile/clk-rcar-gen2.c
@@ -33,6 +33,8 @@ struct rcar_gen2_cpg {
#define CPG_FRQCRC 0x000000e0
#define CPG_FRQCRC_ZFC_MASK (0x1f << 8)
#define CPG_FRQCRC_ZFC_SHIFT 8
+#define CPG_ADSPCKCR 0x0000025c
+#define CPG_RCANCKCR 0x00000270
/* -----------------------------------------------------------------------------
* Z Clock
@@ -161,6 +163,88 @@ static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
return clk;
}
+static struct clk * __init cpg_rcan_clk_register(struct rcar_gen2_cpg *cpg,
+ struct device_node *np)
+{
+ const char *parent_name = of_clk_get_parent_name(np, 1);
+ struct clk_fixed_factor *fixed;
+ struct clk_gate *gate;
+ struct clk *clk;
+
+ fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
+ if (!fixed)
+ return ERR_PTR(-ENOMEM);
+
+ fixed->mult = 1;
+ fixed->div = 6;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ kfree(fixed);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ gate->reg = cpg->reg + CPG_RCANCKCR;
+ gate->bit_idx = 8;
+ gate->flags = CLK_GATE_SET_TO_DISABLE;
+ gate->lock = &cpg->lock;
+
+ clk = clk_register_composite(NULL, "rcan", &parent_name, 1, NULL, NULL,
+ &fixed->hw, &clk_fixed_factor_ops,
+ &gate->hw, &clk_gate_ops, 0);
+ if (IS_ERR(clk)) {
+ kfree(gate);
+ kfree(fixed);
+ }
+
+ return clk;
+}
+
+/* ADSP divisors */
+static const struct clk_div_table cpg_adsp_div_table[] = {
+ { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 },
+ { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 },
+ { 10, 36 }, { 11, 48 }, { 0, 0 },
+};
+
+static struct clk * __init cpg_adsp_clk_register(struct rcar_gen2_cpg *cpg)
+{
+ const char *parent_name = "pll1";
+ struct clk_divider *div;
+ struct clk_gate *gate;
+ struct clk *clk;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ div->reg = cpg->reg + CPG_ADSPCKCR;
+ div->width = 4;
+ div->table = cpg_adsp_div_table;
+ div->lock = &cpg->lock;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ kfree(div);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ gate->reg = cpg->reg + CPG_ADSPCKCR;
+ gate->bit_idx = 8;
+ gate->flags = CLK_GATE_SET_TO_DISABLE;
+ gate->lock = &cpg->lock;
+
+ clk = clk_register_composite(NULL, "adsp", &parent_name, 1, NULL, NULL,
+ &div->hw, &clk_divider_ops,
+ &gate->hw, &clk_gate_ops, 0);
+ if (IS_ERR(clk)) {
+ kfree(gate);
+ kfree(div);
+ }
+
+ return clk;
+}
+
/* -----------------------------------------------------------------------------
* CPG Clock Data
*/
@@ -263,6 +347,10 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
shift = 0;
} else if (!strcmp(name, "z")) {
return cpg_z_clk_register(cpg);
+ } else if (!strcmp(name, "rcan")) {
+ return cpg_rcan_clk_register(cpg, np);
+ } else if (!strcmp(name, "adsp")) {
+ return cpg_adsp_clk_register(cpg);
} else {
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c
index 2282cef9f2ff..bf12a25eb3a2 100644
--- a/drivers/clk/st/clk-flexgen.c
+++ b/drivers/clk/st/clk-flexgen.c
@@ -37,8 +37,8 @@ static int flexgen_enable(struct clk_hw *hw)
struct clk_hw *pgate_hw = &flexgen->pgate.hw;
struct clk_hw *fgate_hw = &flexgen->fgate.hw;
- pgate_hw->clk = hw->clk;
- fgate_hw->clk = hw->clk;
+ __clk_hw_set_clk(pgate_hw, hw);
+ __clk_hw_set_clk(fgate_hw, hw);
clk_gate_ops.enable(pgate_hw);
@@ -54,7 +54,7 @@ static void flexgen_disable(struct clk_hw *hw)
struct clk_hw *fgate_hw = &flexgen->fgate.hw;
/* disable only the final gate */
- fgate_hw->clk = hw->clk;
+ __clk_hw_set_clk(fgate_hw, hw);
clk_gate_ops.disable(fgate_hw);
@@ -66,7 +66,7 @@ static int flexgen_is_enabled(struct clk_hw *hw)
struct flexgen *flexgen = to_flexgen(hw);
struct clk_hw *fgate_hw = &flexgen->fgate.hw;
- fgate_hw->clk = hw->clk;
+ __clk_hw_set_clk(fgate_hw, hw);
if (!clk_gate_ops.is_enabled(fgate_hw))
return 0;
@@ -79,7 +79,7 @@ static u8 flexgen_get_parent(struct clk_hw *hw)
struct flexgen *flexgen = to_flexgen(hw);
struct clk_hw *mux_hw = &flexgen->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return clk_mux_ops.get_parent(mux_hw);
}
@@ -89,7 +89,7 @@ static int flexgen_set_parent(struct clk_hw *hw, u8 index)
struct flexgen *flexgen = to_flexgen(hw);
struct clk_hw *mux_hw = &flexgen->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return clk_mux_ops.set_parent(mux_hw, index);
}
@@ -124,8 +124,8 @@ unsigned long flexgen_recalc_rate(struct clk_hw *hw,
struct clk_hw *fdiv_hw = &flexgen->fdiv.hw;
unsigned long mid_rate;
- pdiv_hw->clk = hw->clk;
- fdiv_hw->clk = hw->clk;
+ __clk_hw_set_clk(pdiv_hw, hw);
+ __clk_hw_set_clk(fdiv_hw, hw);
mid_rate = clk_divider_ops.recalc_rate(pdiv_hw, parent_rate);
@@ -138,16 +138,27 @@ static int flexgen_set_rate(struct clk_hw *hw, unsigned long rate,
struct flexgen *flexgen = to_flexgen(hw);
struct clk_hw *pdiv_hw = &flexgen->pdiv.hw;
struct clk_hw *fdiv_hw = &flexgen->fdiv.hw;
- unsigned long primary_div = 0;
+ unsigned long div = 0;
int ret = 0;
- pdiv_hw->clk = hw->clk;
- fdiv_hw->clk = hw->clk;
+ __clk_hw_set_clk(pdiv_hw, hw);
+ __clk_hw_set_clk(fdiv_hw, hw);
- primary_div = clk_best_div(parent_rate, rate);
+ div = clk_best_div(parent_rate, rate);
- clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
- ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * primary_div);
+ /*
+ * pdiv is mainly targeted for low freq results, while fdiv
+ * should be used for div <= 64. The other way round can
+ * lead to 'duty cycle' issues.
+ */
+
+ if (div <= 64) {
+ clk_divider_ops.set_rate(pdiv_hw, parent_rate, parent_rate);
+ ret = clk_divider_ops.set_rate(fdiv_hw, rate, rate * div);
+ } else {
+ clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
+ ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * div);
+ }
return ret;
}
diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c
index 79dc40b5cc68..9a15ec344a85 100644
--- a/drivers/clk/st/clkgen-mux.c
+++ b/drivers/clk/st/clkgen-mux.c
@@ -94,7 +94,7 @@ static int clkgena_divmux_enable(struct clk_hw *hw)
unsigned long timeout;
int ret = 0;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
ret = clk_mux_ops.set_parent(mux_hw, genamux->muxsel);
if (ret)
@@ -116,7 +116,7 @@ static void clkgena_divmux_disable(struct clk_hw *hw)
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *mux_hw = &genamux->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
clk_mux_ops.set_parent(mux_hw, CKGAX_CLKOPSRC_SWITCH_OFF);
}
@@ -126,7 +126,7 @@ static int clkgena_divmux_is_enabled(struct clk_hw *hw)
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *mux_hw = &genamux->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return (s8)clk_mux_ops.get_parent(mux_hw) > 0;
}
@@ -136,7 +136,7 @@ u8 clkgena_divmux_get_parent(struct clk_hw *hw)
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *mux_hw = &genamux->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
genamux->muxsel = clk_mux_ops.get_parent(mux_hw);
if ((s8)genamux->muxsel < 0) {
@@ -174,7 +174,7 @@ unsigned long clkgena_divmux_recalc_rate(struct clk_hw *hw,
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return clk_divider_ops.recalc_rate(div_hw, parent_rate);
}
@@ -185,7 +185,7 @@ static int clkgena_divmux_set_rate(struct clk_hw *hw, unsigned long rate,
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return clk_divider_ops.set_rate(div_hw, rate, parent_rate);
}
@@ -196,7 +196,7 @@ static long clkgena_divmux_round_rate(struct clk_hw *hw, unsigned long rate,
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return clk_divider_ops.round_rate(div_hw, rate, prate);
}
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index a66953c0f430..3a5292e3fcf8 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -8,6 +8,7 @@ obj-y += clk-a20-gmac.o
obj-y += clk-mod0.o
obj-y += clk-sun8i-mbus.o
obj-y += clk-sun9i-core.o
+obj-y += clk-sun9i-mmc.o
obj-$(CONFIG_MFD_SUN6I_PRCM) += \
clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index 62e08fb58554..8c20190a3e9f 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -80,6 +80,8 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
}
static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p)
{
@@ -156,9 +158,10 @@ static const struct clk_ops clk_factors_ops = {
.set_rate = clk_factors_set_rate,
};
-struct clk * __init sunxi_factors_register(struct device_node *node,
- const struct factors_data *data,
- spinlock_t *lock)
+struct clk *sunxi_factors_register(struct device_node *node,
+ const struct factors_data *data,
+ spinlock_t *lock,
+ void __iomem *reg)
{
struct clk *clk;
struct clk_factors *factors;
@@ -168,11 +171,8 @@ struct clk * __init sunxi_factors_register(struct device_node *node,
struct clk_hw *mux_hw = NULL;
const char *clk_name = node->name;
const char *parents[FACTORS_MAX_PARENTS];
- void __iomem *reg;
int i = 0;
- reg = of_iomap(node, 0);
-
/* if we have a mux, we will have >1 parents */
while (i < FACTORS_MAX_PARENTS &&
(parents[i] = of_clk_get_parent_name(node, i)) != NULL)
diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h
index 912238fde132..171085ab5513 100644
--- a/drivers/clk/sunxi/clk-factors.h
+++ b/drivers/clk/sunxi/clk-factors.h
@@ -36,8 +36,9 @@ struct clk_factors {
spinlock_t *lock;
};
-struct clk * __init sunxi_factors_register(struct device_node *node,
- const struct factors_data *data,
- spinlock_t *lock);
+struct clk *sunxi_factors_register(struct device_node *node,
+ const struct factors_data *data,
+ spinlock_t *lock,
+ void __iomem *reg);
#endif
diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
index da0524eaee94..ec8f5a1fca09 100644
--- a/drivers/clk/sunxi/clk-mod0.c
+++ b/drivers/clk/sunxi/clk-mod0.c
@@ -17,6 +17,7 @@
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include "clk-factors.h"
@@ -67,7 +68,7 @@ static struct clk_factors_config sun4i_a10_mod0_config = {
.pwidth = 2,
};
-static const struct factors_data sun4i_a10_mod0_data __initconst = {
+static const struct factors_data sun4i_a10_mod0_data = {
.enable = 31,
.mux = 24,
.muxmask = BIT(1) | BIT(0),
@@ -79,15 +80,95 @@ static DEFINE_SPINLOCK(sun4i_a10_mod0_lock);
static void __init sun4i_a10_mod0_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun4i_a10_mod0_lock);
+ void __iomem *reg;
+
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ /*
+ * This happens with mod0 clk nodes instantiated through
+ * mfd, as those do not have their resources assigned at
+ * CLK_OF_DECLARE time yet, so do not print an error.
+ */
+ return;
+ }
+
+ sunxi_factors_register(node, &sun4i_a10_mod0_data,
+ &sun4i_a10_mod0_lock, reg);
}
CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
+static int sun4i_a10_mod0_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *r;
+ void __iomem *reg;
+
+ if (!np)
+ return -ENODEV;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ sunxi_factors_register(np, &sun4i_a10_mod0_data,
+ &sun4i_a10_mod0_lock, reg);
+ return 0;
+}
+
+static const struct of_device_id sun4i_a10_mod0_clk_dt_ids[] = {
+ { .compatible = "allwinner,sun4i-a10-mod0-clk" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sun4i_a10_mod0_clk_driver = {
+ .driver = {
+ .name = "sun4i-a10-mod0-clk",
+ .of_match_table = sun4i_a10_mod0_clk_dt_ids,
+ },
+ .probe = sun4i_a10_mod0_clk_probe,
+};
+module_platform_driver(sun4i_a10_mod0_clk_driver);
+
+static const struct factors_data sun9i_a80_mod0_data __initconst = {
+ .enable = 31,
+ .mux = 24,
+ .muxmask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
+ .table = &sun4i_a10_mod0_config,
+ .getter = sun4i_a10_get_mod0_factors,
+};
+
+static void __init sun9i_a80_mod0_setup(struct device_node *node)
+{
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (IS_ERR(reg)) {
+ pr_err("Could not get registers for mod0-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_mod0_data,
+ &sun4i_a10_mod0_lock, reg);
+}
+CLK_OF_DECLARE(sun9i_a80_mod0, "allwinner,sun9i-a80-mod0-clk", sun9i_a80_mod0_setup);
+
static DEFINE_SPINLOCK(sun5i_a13_mbus_lock);
static void __init sun5i_a13_mbus_setup(struct device_node *node)
{
- struct clk *mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun5i_a13_mbus_lock);
+ struct clk *mbus;
+ void __iomem *reg;
+
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ pr_err("Could not get registers for a13-mbus-clk\n");
+ return;
+ }
+
+ mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data,
+ &sun5i_a13_mbus_lock, reg);
/* The MBUS clocks needs to be always enabled */
__clk_get(mbus);
@@ -95,14 +176,10 @@ static void __init sun5i_a13_mbus_setup(struct device_node *node)
}
CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
-struct mmc_phase_data {
- u8 offset;
-};
-
struct mmc_phase {
struct clk_hw hw;
+ u8 offset;
void __iomem *reg;
- struct mmc_phase_data *data;
spinlock_t *lock;
};
@@ -118,7 +195,7 @@ static int mmc_get_phase(struct clk_hw *hw)
u8 delay;
value = readl(phase->reg);
- delay = (value >> phase->data->offset) & 0x3;
+ delay = (value >> phase->offset) & 0x3;
if (!delay)
return 180;
@@ -206,8 +283,8 @@ static int mmc_set_phase(struct clk_hw *hw, int degrees)
spin_lock_irqsave(phase->lock, flags);
value = readl(phase->reg);
- value &= ~GENMASK(phase->data->offset + 3, phase->data->offset);
- value |= delay << phase->data->offset;
+ value &= ~GENMASK(phase->offset + 3, phase->offset);
+ value |= delay << phase->offset;
writel(value, phase->reg);
spin_unlock_irqrestore(phase->lock, flags);
@@ -219,66 +296,97 @@ static const struct clk_ops mmc_clk_ops = {
.set_phase = mmc_set_phase,
};
-static void __init sun4i_a10_mmc_phase_setup(struct device_node *node,
- struct mmc_phase_data *data)
+/*
+ * sunxi_mmc_setup - Common setup function for mmc module clocks
+ *
+ * The only difference between module clocks on different platforms is the
+ * width of the mux register bits and the valid values, which are passed in
+ * through struct factors_data. The phase clocks parts are identical.
+ */
+static void __init sunxi_mmc_setup(struct device_node *node,
+ const struct factors_data *data,
+ spinlock_t *lock)
{
- const char *parent_names[1] = { of_clk_get_parent_name(node, 0) };
- struct clk_init_data init = {
- .num_parents = 1,
- .parent_names = parent_names,
- .ops = &mmc_clk_ops,
- };
-
- struct mmc_phase *phase;
- struct clk *clk;
-
- phase = kmalloc(sizeof(*phase), GFP_KERNEL);
- if (!phase)
+ struct clk_onecell_data *clk_data;
+ const char *parent;
+ void __iomem *reg;
+ int i;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (IS_ERR(reg)) {
+ pr_err("Couldn't map the %s clock registers\n", node->name);
return;
+ }
- phase->hw.init = &init;
-
- phase->reg = of_iomap(node, 0);
- if (!phase->reg)
- goto err_free;
-
- phase->data = data;
- phase->lock = &sun4i_a10_mod0_lock;
-
- if (of_property_read_string(node, "clock-output-names", &init.name))
- init.name = node->name;
+ clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return;
- clk = clk_register(NULL, &phase->hw);
- if (IS_ERR(clk))
- goto err_unmap;
+ clk_data->clks = kcalloc(3, sizeof(*clk_data->clks), GFP_KERNEL);
+ if (!clk_data->clks)
+ goto err_free_data;
+
+ clk_data->clk_num = 3;
+ clk_data->clks[0] = sunxi_factors_register(node, data, lock, reg);
+ if (!clk_data->clks[0])
+ goto err_free_clks;
+
+ parent = __clk_get_name(clk_data->clks[0]);
+
+ for (i = 1; i < 3; i++) {
+ struct clk_init_data init = {
+ .num_parents = 1,
+ .parent_names = &parent,
+ .ops = &mmc_clk_ops,
+ };
+ struct mmc_phase *phase;
+
+ phase = kmalloc(sizeof(*phase), GFP_KERNEL);
+ if (!phase)
+ continue;
+
+ phase->hw.init = &init;
+ phase->reg = reg;
+ phase->lock = lock;
+
+ if (i == 1)
+ phase->offset = 8;
+ else
+ phase->offset = 20;
+
+ if (of_property_read_string_index(node, "clock-output-names",
+ i, &init.name))
+ init.name = node->name;
+
+ clk_data->clks[i] = clk_register(NULL, &phase->hw);
+ if (IS_ERR(clk_data->clks[i])) {
+ kfree(phase);
+ continue;
+ }
+ }
- of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
return;
-err_unmap:
- iounmap(phase->reg);
-err_free:
- kfree(phase);
+err_free_clks:
+ kfree(clk_data->clks);
+err_free_data:
+ kfree(clk_data);
}
+static DEFINE_SPINLOCK(sun4i_a10_mmc_lock);
-static struct mmc_phase_data mmc_output_clk = {
- .offset = 8,
-};
-
-static struct mmc_phase_data mmc_sample_clk = {
- .offset = 20,
-};
-
-static void __init sun4i_a10_mmc_output_setup(struct device_node *node)
+static void __init sun4i_a10_mmc_setup(struct device_node *node)
{
- sun4i_a10_mmc_phase_setup(node, &mmc_output_clk);
+ sunxi_mmc_setup(node, &sun4i_a10_mod0_data, &sun4i_a10_mmc_lock);
}
-CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup);
+CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);
+
+static DEFINE_SPINLOCK(sun9i_a80_mmc_lock);
-static void __init sun4i_a10_mmc_sample_setup(struct device_node *node)
+static void __init sun9i_a80_mmc_setup(struct device_node *node)
{
- sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk);
+ sunxi_mmc_setup(node, &sun9i_a80_mod0_data, &sun9i_a80_mmc_lock);
}
-CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup);
+CLK_OF_DECLARE(sun9i_a80_mmc, "allwinner,sun9i-a80-mmc-clk", sun9i_a80_mmc_setup);
diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c
index 3d282fb8f85c..63cf149195ae 100644
--- a/drivers/clk/sunxi/clk-sun6i-ar100.c
+++ b/drivers/clk/sunxi/clk-sun6i-ar100.c
@@ -45,6 +45,8 @@ static unsigned long ar100_recalc_rate(struct clk_hw *hw,
}
static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk)
{
diff --git a/drivers/clk/sunxi/clk-sun8i-mbus.c b/drivers/clk/sunxi/clk-sun8i-mbus.c
index ef49786eefd3..14cd026064bf 100644
--- a/drivers/clk/sunxi/clk-sun8i-mbus.c
+++ b/drivers/clk/sunxi/clk-sun8i-mbus.c
@@ -69,8 +69,17 @@ static DEFINE_SPINLOCK(sun8i_a23_mbus_lock);
static void __init sun8i_a23_mbus_setup(struct device_node *node)
{
- struct clk *mbus = sunxi_factors_register(node, &sun8i_a23_mbus_data,
- &sun8i_a23_mbus_lock);
+ struct clk *mbus;
+ void __iomem *reg;
+
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ pr_err("Could not get registers for a23-mbus-clk\n");
+ return;
+ }
+
+ mbus = sunxi_factors_register(node, &sun8i_a23_mbus_data,
+ &sun8i_a23_mbus_lock, reg);
/* The MBUS clocks needs to be always enabled */
__clk_get(mbus);
diff --git a/drivers/clk/sunxi/clk-sun9i-core.c b/drivers/clk/sunxi/clk-sun9i-core.c
index 3cb9036d91bb..d8da77d72861 100644
--- a/drivers/clk/sunxi/clk-sun9i-core.c
+++ b/drivers/clk/sunxi/clk-sun9i-core.c
@@ -24,50 +24,51 @@
/**
- * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL1
+ * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL4
* PLL4 rate is calculated as follows
* rate = (parent_rate * n >> p) / (m + 1);
- * parent_rate is always 24Mhz
+ * parent_rate is always 24MHz
*
* p and m are named div1 and div2 in Allwinner's SDK
*/
static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate,
- u8 *n, u8 *k, u8 *m, u8 *p)
+ u8 *n_ret, u8 *k, u8 *m_ret, u8 *p_ret)
{
- int div;
+ int n;
+ int m = 1;
+ int p = 1;
- /* Normalize value to a 6M multiple */
- div = DIV_ROUND_UP(*freq, 6000000);
+ /* Normalize value to a 6 MHz multiple (24 MHz / 4) */
+ n = DIV_ROUND_UP(*freq, 6000000);
- /* divs above 256 cannot be odd */
- if (div > 256)
- div = round_up(div, 2);
+ /* If n is too large switch to steps of 12 MHz */
+ if (n > 255) {
+ m = 0;
+ n = (n + 1) / 2;
+ }
+
+ /* If n is still too large switch to steps of 24 MHz */
+ if (n > 255) {
+ p = 0;
+ n = (n + 1) / 2;
+ }
- /* divs above 512 must be a multiple of 4 */
- if (div > 512)
- div = round_up(div, 4);
+ /* n must be between 12 and 255 */
+ if (n > 255)
+ n = 255;
+ else if (n < 12)
+ n = 12;
- *freq = 6000000 * div;
+ *freq = ((24000000 * n) >> p) / (m + 1);
/* we were called to round the frequency, we can now return */
- if (n == NULL)
+ if (n_ret == NULL)
return;
- /* p will be 1 for divs under 512 */
- if (div < 512)
- *p = 1;
- else
- *p = 0;
-
- /* m will be 1 if div is odd */
- if (div & 1)
- *m = 1;
- else
- *m = 0;
-
- /* calculate a suitable n based on m and p */
- *n = div / (*p + 1) / (*m + 1);
+ *n_ret = n;
+ *m_ret = m;
+ *p_ret = p;
}
static struct clk_factors_config sun9i_a80_pll4_config = {
@@ -89,7 +90,17 @@ static DEFINE_SPINLOCK(sun9i_a80_pll4_lock);
static void __init sun9i_a80_pll4_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun9i_a80_pll4_data, &sun9i_a80_pll4_lock);
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-pll4-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_pll4_data,
+ &sun9i_a80_pll4_lock, reg);
}
CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup);
@@ -139,8 +150,18 @@ static DEFINE_SPINLOCK(sun9i_a80_gt_lock);
static void __init sun9i_a80_gt_setup(struct device_node *node)
{
- struct clk *gt = sunxi_factors_register(node, &sun9i_a80_gt_data,
- &sun9i_a80_gt_lock);
+ void __iomem *reg;
+ struct clk *gt;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-gt-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ gt = sunxi_factors_register(node, &sun9i_a80_gt_data,
+ &sun9i_a80_gt_lock, reg);
/* The GT bus clock needs to be always enabled */
__clk_get(gt);
@@ -194,7 +215,17 @@ static DEFINE_SPINLOCK(sun9i_a80_ahb_lock);
static void __init sun9i_a80_ahb_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun9i_a80_ahb_data, &sun9i_a80_ahb_lock);
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-ahb-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_ahb_data,
+ &sun9i_a80_ahb_lock, reg);
}
CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup);
@@ -210,7 +241,17 @@ static DEFINE_SPINLOCK(sun9i_a80_apb0_lock);
static void __init sun9i_a80_apb0_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun9i_a80_apb0_data, &sun9i_a80_apb0_lock);
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-apb0-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_apb0_data,
+ &sun9i_a80_apb0_lock, reg);
}
CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup);
@@ -266,6 +307,16 @@ static DEFINE_SPINLOCK(sun9i_a80_apb1_lock);
static void __init sun9i_a80_apb1_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun9i_a80_apb1_data, &sun9i_a80_apb1_lock);
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-apb1-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_apb1_data,
+ &sun9i_a80_apb1_lock, reg);
}
CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup);
diff --git a/drivers/clk/sunxi/clk-sun9i-mmc.c b/drivers/clk/sunxi/clk-sun9i-mmc.c
new file mode 100644
index 000000000000..710c273648d7
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun9i-mmc.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2015 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/reset.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/spinlock.h>
+
+#define SUN9I_MMC_WIDTH 4
+
+#define SUN9I_MMC_GATE_BIT 16
+#define SUN9I_MMC_RESET_BIT 18
+
+struct sun9i_mmc_clk_data {
+ spinlock_t lock;
+ void __iomem *membase;
+ struct clk *clk;
+ struct reset_control *reset;
+ struct clk_onecell_data clk_data;
+ struct reset_controller_dev rcdev;
+};
+
+static int sun9i_mmc_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct sun9i_mmc_clk_data *data = container_of(rcdev,
+ struct sun9i_mmc_clk_data,
+ rcdev);
+ unsigned long flags;
+ void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
+ u32 val;
+
+ clk_prepare_enable(data->clk);
+ spin_lock_irqsave(&data->lock, flags);
+
+ val = readl(reg);
+ writel(val & ~BIT(SUN9I_MMC_RESET_BIT), reg);
+
+ spin_unlock_irqrestore(&data->lock, flags);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static int sun9i_mmc_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct sun9i_mmc_clk_data *data = container_of(rcdev,
+ struct sun9i_mmc_clk_data,
+ rcdev);
+ unsigned long flags;
+ void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
+ u32 val;
+
+ clk_prepare_enable(data->clk);
+ spin_lock_irqsave(&data->lock, flags);
+
+ val = readl(reg);
+ writel(val | BIT(SUN9I_MMC_RESET_BIT), reg);
+
+ spin_unlock_irqrestore(&data->lock, flags);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static struct reset_control_ops sun9i_mmc_reset_ops = {
+ .assert = sun9i_mmc_reset_assert,
+ .deassert = sun9i_mmc_reset_deassert,
+};
+
+static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sun9i_mmc_clk_data *data;
+ struct clk_onecell_data *clk_data;
+ const char *clk_name = np->name;
+ const char *clk_parent;
+ struct resource *r;
+ int count, i, ret;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock_init(&data->lock);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ /* one clock/reset pair per word */
+ count = DIV_ROUND_UP((r->end - r->start + 1), SUN9I_MMC_WIDTH);
+ data->membase = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(data->membase))
+ return PTR_ERR(data->membase);
+
+ clk_data = &data->clk_data;
+ clk_data->clk_num = count;
+ clk_data->clks = devm_kcalloc(&pdev->dev, count, sizeof(struct clk *),
+ GFP_KERNEL);
+ if (!clk_data->clks)
+ return -ENOMEM;
+
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(data->clk)) {
+ dev_err(&pdev->dev, "Could not get clock\n");
+ return PTR_ERR(data->clk);
+ }
+
+ data->reset = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(data->reset)) {
+ dev_err(&pdev->dev, "Could not get reset control\n");
+ return PTR_ERR(data->reset);
+ }
+
+ ret = reset_control_deassert(data->reset);
+ if (ret) {
+ dev_err(&pdev->dev, "Reset deassert err %d\n", ret);
+ return ret;
+ }
+
+ clk_parent = __clk_get_name(data->clk);
+ for (i = 0; i < count; i++) {
+ of_property_read_string_index(np, "clock-output-names",
+ i, &clk_name);
+
+ clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
+ clk_parent, 0,
+ data->membase + SUN9I_MMC_WIDTH * i,
+ SUN9I_MMC_GATE_BIT, 0,
+ &data->lock);
+
+ if (IS_ERR(clk_data->clks[i])) {
+ ret = PTR_ERR(clk_data->clks[i]);
+ goto err_clk_register;
+ }
+ }
+
+ ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+ if (ret)
+ goto err_clk_provider;
+
+ data->rcdev.owner = THIS_MODULE;
+ data->rcdev.nr_resets = count;
+ data->rcdev.ops = &sun9i_mmc_reset_ops;
+ data->rcdev.of_node = pdev->dev.of_node;
+
+ ret = reset_controller_register(&data->rcdev);
+ if (ret)
+ goto err_rc_reg;
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+err_rc_reg:
+ of_clk_del_provider(np);
+
+err_clk_provider:
+ for (i = 0; i < count; i++)
+ clk_unregister(clk_data->clks[i]);
+
+err_clk_register:
+ reset_control_assert(data->reset);
+
+ return ret;
+}
+
+static int sun9i_a80_mmc_config_clk_remove(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sun9i_mmc_clk_data *data = platform_get_drvdata(pdev);
+ struct clk_onecell_data *clk_data = &data->clk_data;
+ int i;
+
+ reset_controller_unregister(&data->rcdev);
+ of_clk_del_provider(np);
+ for (i = 0; i < clk_data->clk_num; i++)
+ clk_unregister(clk_data->clks[i]);
+
+ reset_control_assert(data->reset);
+
+ return 0;
+}
+
+static const struct of_device_id sun9i_a80_mmc_config_clk_dt_ids[] = {
+ { .compatible = "allwinner,sun9i-a80-mmc-config-clk" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sun9i_a80_mmc_config_clk_driver = {
+ .driver = {
+ .name = "sun9i-a80-mmc-config-clk",
+ .of_match_table = sun9i_a80_mmc_config_clk_dt_ids,
+ },
+ .probe = sun9i_a80_mmc_config_clk_probe,
+ .remove = sun9i_a80_mmc_config_clk_remove,
+};
+module_platform_driver(sun9i_a80_mmc_config_clk_driver);
+
+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
+MODULE_DESCRIPTION("Allwinner A80 MMC clock/reset Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 1818f404538d..379324eb5486 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -20,11 +20,221 @@
#include <linux/of_address.h>
#include <linux/reset-controller.h>
#include <linux/spinlock.h>
+#include <linux/log2.h>
#include "clk-factors.h"
static DEFINE_SPINLOCK(clk_lock);
+/**
+ * sun6i_a31_ahb1_clk_setup() - Setup function for a31 ahb1 composite clk
+ */
+
+#define SUN6I_AHB1_MAX_PARENTS 4
+#define SUN6I_AHB1_MUX_PARENT_PLL6 3
+#define SUN6I_AHB1_MUX_SHIFT 12
+/* un-shifted mask is what mux_clk expects */
+#define SUN6I_AHB1_MUX_MASK 0x3
+#define SUN6I_AHB1_MUX_GET_PARENT(reg) ((reg >> SUN6I_AHB1_MUX_SHIFT) & \
+ SUN6I_AHB1_MUX_MASK)
+
+#define SUN6I_AHB1_DIV_SHIFT 4
+#define SUN6I_AHB1_DIV_MASK (0x3 << SUN6I_AHB1_DIV_SHIFT)
+#define SUN6I_AHB1_DIV_GET(reg) ((reg & SUN6I_AHB1_DIV_MASK) >> \
+ SUN6I_AHB1_DIV_SHIFT)
+#define SUN6I_AHB1_DIV_SET(reg, div) ((reg & ~SUN6I_AHB1_DIV_MASK) | \
+ (div << SUN6I_AHB1_DIV_SHIFT))
+#define SUN6I_AHB1_PLL6_DIV_SHIFT 6
+#define SUN6I_AHB1_PLL6_DIV_MASK (0x3 << SUN6I_AHB1_PLL6_DIV_SHIFT)
+#define SUN6I_AHB1_PLL6_DIV_GET(reg) ((reg & SUN6I_AHB1_PLL6_DIV_MASK) >> \
+ SUN6I_AHB1_PLL6_DIV_SHIFT)
+#define SUN6I_AHB1_PLL6_DIV_SET(reg, div) ((reg & ~SUN6I_AHB1_PLL6_DIV_MASK) | \
+ (div << SUN6I_AHB1_PLL6_DIV_SHIFT))
+
+struct sun6i_ahb1_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+};
+
+#define to_sun6i_ahb1_clk(_hw) container_of(_hw, struct sun6i_ahb1_clk, hw)
+
+static unsigned long sun6i_ahb1_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct sun6i_ahb1_clk *ahb1 = to_sun6i_ahb1_clk(hw);
+ unsigned long rate;
+ u32 reg;
+
+ /* Fetch the register value */
+ reg = readl(ahb1->reg);
+
+ /* apply pre-divider first if parent is pll6 */
+ if (SUN6I_AHB1_MUX_GET_PARENT(reg) == SUN6I_AHB1_MUX_PARENT_PLL6)
+ parent_rate /= SUN6I_AHB1_PLL6_DIV_GET(reg) + 1;
+
+ /* clk divider */
+ rate = parent_rate >> SUN6I_AHB1_DIV_GET(reg);
+
+ return rate;
+}
+
+static long sun6i_ahb1_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
+ u8 parent, unsigned long parent_rate)
+{
+ u8 div, calcp, calcm = 1;
+
+ /*
+ * clock can only divide, so we will never be able to achieve
+ * frequencies higher than the parent frequency
+ */
+ if (parent_rate && rate > parent_rate)
+ rate = parent_rate;
+
+ div = DIV_ROUND_UP(parent_rate, rate);
+
+ /* calculate pre-divider if parent is pll6 */
+ if (parent == SUN6I_AHB1_MUX_PARENT_PLL6) {
+ if (div < 4)
+ calcp = 0;
+ else if (div / 2 < 4)
+ calcp = 1;
+ else if (div / 4 < 4)
+ calcp = 2;
+ else
+ calcp = 3;
+
+ calcm = DIV_ROUND_UP(div, 1 << calcp);
+ } else {
+ calcp = __roundup_pow_of_two(div);
+ calcp = calcp > 3 ? 3 : calcp;
+ }
+
+ /* we were asked to pass back divider values */
+ if (divp) {
+ *divp = calcp;
+ *pre_divp = calcm - 1;
+ }
+
+ return (parent_rate / calcm) >> calcp;
+}
+
+static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_clk)
+{
+ struct clk *clk = hw->clk, *parent, *best_parent = NULL;
+ int i, num_parents;
+ unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
+
+ /* find the parent that can help provide the fastest rate <= rate */
+ num_parents = __clk_get_num_parents(clk);
+ for (i = 0; i < num_parents; i++) {
+ parent = clk_get_parent_by_index(clk, i);
+ if (!parent)
+ continue;
+ if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT)
+ parent_rate = __clk_round_rate(parent, rate);
+ else
+ parent_rate = __clk_get_rate(parent);
+
+ child_rate = sun6i_ahb1_clk_round(rate, NULL, NULL, i,
+ parent_rate);
+
+ if (child_rate <= rate && child_rate > best_child_rate) {
+ best_parent = parent;
+ best = parent_rate;
+ best_child_rate = child_rate;
+ }
+ }
+
+ if (best_parent)
+ *best_parent_clk = __clk_get_hw(best_parent);
+ *best_parent_rate = best;
+
+ return best_child_rate;
+}
+
+static int sun6i_ahb1_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct sun6i_ahb1_clk *ahb1 = to_sun6i_ahb1_clk(hw);
+ unsigned long flags;
+ u8 div, pre_div, parent;
+ u32 reg;
+
+ spin_lock_irqsave(&clk_lock, flags);
+
+ reg = readl(ahb1->reg);
+
+ /* need to know which parent is used to apply pre-divider */
+ parent = SUN6I_AHB1_MUX_GET_PARENT(reg);
+ sun6i_ahb1_clk_round(rate, &div, &pre_div, parent, parent_rate);
+
+ reg = SUN6I_AHB1_DIV_SET(reg, div);
+ reg = SUN6I_AHB1_PLL6_DIV_SET(reg, pre_div);
+ writel(reg, ahb1->reg);
+
+ spin_unlock_irqrestore(&clk_lock, flags);
+
+ return 0;
+}
+
+static const struct clk_ops sun6i_ahb1_clk_ops = {
+ .determine_rate = sun6i_ahb1_clk_determine_rate,
+ .recalc_rate = sun6i_ahb1_clk_recalc_rate,
+ .set_rate = sun6i_ahb1_clk_set_rate,
+};
+
+static void __init sun6i_ahb1_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ struct sun6i_ahb1_clk *ahb1;
+ struct clk_mux *mux;
+ const char *clk_name = node->name;
+ const char *parents[SUN6I_AHB1_MAX_PARENTS];
+ void __iomem *reg;
+ int i = 0;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+
+ /* we have a mux, we will have >1 parents */
+ while (i < SUN6I_AHB1_MAX_PARENTS &&
+ (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
+ i++;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ ahb1 = kzalloc(sizeof(struct sun6i_ahb1_clk), GFP_KERNEL);
+ if (!ahb1)
+ return;
+
+ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
+ if (!mux) {
+ kfree(ahb1);
+ return;
+ }
+
+ /* set up clock properties */
+ mux->reg = reg;
+ mux->shift = SUN6I_AHB1_MUX_SHIFT;
+ mux->mask = SUN6I_AHB1_MUX_MASK;
+ mux->lock = &clk_lock;
+ ahb1->reg = reg;
+
+ clk = clk_register_composite(NULL, clk_name, parents, i,
+ &mux->hw, &clk_mux_ops,
+ &ahb1->hw, &sun6i_ahb1_clk_ops,
+ NULL, NULL, 0);
+
+ if (!IS_ERR(clk)) {
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ clk_register_clkdev(clk, clk_name, NULL);
+ }
+}
+CLK_OF_DECLARE(sun6i_a31_ahb1, "allwinner,sun6i-a31-ahb1-clk", sun6i_ahb1_clk_setup);
+
/* Maximum number of parents our clocks have */
#define SUNXI_MAX_PARENTS 5
@@ -355,43 +565,6 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate,
}
/**
- * clk_sunxi_mmc_phase_control() - configures MMC clock phase control
- */
-
-void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output)
-{
- #define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
- #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
-
- struct clk_hw *hw = __clk_get_hw(clk);
- struct clk_composite *composite = to_clk_composite(hw);
- struct clk_hw *rate_hw = composite->rate_hw;
- struct clk_factors *factors = to_clk_factors(rate_hw);
- unsigned long flags = 0;
- u32 reg;
-
- if (factors->lock)
- spin_lock_irqsave(factors->lock, flags);
-
- reg = readl(factors->reg);
-
- /* set sample clock phase control */
- reg &= ~(0x7 << 20);
- reg |= ((sample & 0x7) << 20);
-
- /* set output clock phase control */
- reg &= ~(0x7 << 8);
- reg |= ((output & 0x7) << 8);
-
- writel(reg, factors->reg);
-
- if (factors->lock)
- spin_unlock_irqrestore(factors->lock, flags);
-}
-EXPORT_SYMBOL(clk_sunxi_mmc_phase_control);
-
-
-/**
* sunxi_factors_clk_setup() - Setup function for factor clocks
*/
@@ -413,6 +586,7 @@ static struct clk_factors_config sun6i_a31_pll1_config = {
.kwidth = 2,
.mshift = 0,
.mwidth = 2,
+ .n_start = 1,
};
static struct clk_factors_config sun8i_a23_pll1_config = {
@@ -520,7 +694,16 @@ static const struct factors_data sun7i_a20_out_data __initconst = {
static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
const struct factors_data *data)
{
- return sunxi_factors_register(node, data, &clk_lock);
+ void __iomem *reg;
+
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ pr_err("Could not get registers for factors-clk: %s\n",
+ node->name);
+ return NULL;
+ }
+
+ return sunxi_factors_register(node, data, &clk_lock, reg);
}
@@ -561,7 +744,7 @@ static void __init sunxi_mux_clk_setup(struct device_node *node,
of_property_read_string(node, "clock-output-names", &clk_name);
clk = clk_register_mux(NULL, clk_name, parents, i,
- CLK_SET_RATE_NO_REPARENT, reg,
+ CLK_SET_RATE_PARENT, reg,
data->shift, SUNXI_MUX_GATE_WIDTH,
0, &clk_lock);
@@ -1217,7 +1400,6 @@ CLK_OF_DECLARE(sun7i_a20_clk_init, "allwinner,sun7i-a20", sun5i_init_clocks);
static const char *sun6i_critical_clocks[] __initdata = {
"cpu",
- "ahb1_sdram",
};
static void __init sun6i_init_clocks(struct device_node *node)
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
index f7dfb72884a4..edb8358fa6ce 100644
--- a/drivers/clk/tegra/Makefile
+++ b/drivers/clk/tegra/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o
obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o
+obj-$(CONFIG_ARCH_TEGRA_132_SOC) += clk-tegra124.o
diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index 0011d547a9f7..60738cc954cb 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -64,10 +64,8 @@ enum clk_id {
tegra_clk_disp2,
tegra_clk_dp2,
tegra_clk_dpaux,
- tegra_clk_dsia,
tegra_clk_dsialp,
tegra_clk_dsia_mux,
- tegra_clk_dsib,
tegra_clk_dsiblp,
tegra_clk_dsib_mux,
tegra_clk_dtv,
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
index 9e899c18af86..d84ae49d0e05 100644
--- a/drivers/clk/tegra/clk-periph.c
+++ b/drivers/clk/tegra/clk-periph.c
@@ -28,7 +28,7 @@ static u8 clk_periph_get_parent(struct clk_hw *hw)
const struct clk_ops *mux_ops = periph->mux_ops;
struct clk_hw *mux_hw = &periph->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return mux_ops->get_parent(mux_hw);
}
@@ -39,7 +39,7 @@ static int clk_periph_set_parent(struct clk_hw *hw, u8 index)
const struct clk_ops *mux_ops = periph->mux_ops;
struct clk_hw *mux_hw = &periph->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return mux_ops->set_parent(mux_hw, index);
}
@@ -51,7 +51,7 @@ static unsigned long clk_periph_recalc_rate(struct clk_hw *hw,
const struct clk_ops *div_ops = periph->div_ops;
struct clk_hw *div_hw = &periph->divider.hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return div_ops->recalc_rate(div_hw, parent_rate);
}
@@ -63,7 +63,7 @@ static long clk_periph_round_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops *div_ops = periph->div_ops;
struct clk_hw *div_hw = &periph->divider.hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return div_ops->round_rate(div_hw, rate, prate);
}
@@ -75,7 +75,7 @@ static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops *div_ops = periph->div_ops;
struct clk_hw *div_hw = &periph->divider.hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return div_ops->set_rate(div_hw, rate, parent_rate);
}
@@ -86,7 +86,7 @@ static int clk_periph_is_enabled(struct clk_hw *hw)
const struct clk_ops *gate_ops = periph->gate_ops;
struct clk_hw *gate_hw = &periph->gate.hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
return gate_ops->is_enabled(gate_hw);
}
@@ -97,7 +97,7 @@ static int clk_periph_enable(struct clk_hw *hw)
const struct clk_ops *gate_ops = periph->gate_ops;
struct clk_hw *gate_hw = &periph->gate.hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
return gate_ops->enable(gate_hw);
}
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index c7c6d8fb32fb..bfef9abdf232 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -816,7 +816,9 @@ const struct clk_ops tegra_clk_plle_ops = {
.enable = clk_plle_enable,
};
-#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC)
+#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_124_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_132_SOC)
static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params,
unsigned long parent_rate)
@@ -1505,7 +1507,9 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
return clk;
}
-#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC)
+#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_124_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_132_SOC)
static const struct clk_ops tegra_clk_pllxc_ops = {
.is_enabled = clk_pll_is_enabled,
.enable = clk_pll_iddq_enable,
@@ -1565,7 +1569,7 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
parent = __clk_lookup(parent_name);
if (!parent) {
WARN(1, "parent clk %s of %s must be registered first\n",
- name, parent_name);
+ parent_name, name);
return ERR_PTR(-EINVAL);
}
@@ -1665,7 +1669,7 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
parent = __clk_lookup(parent_name);
if (!parent) {
WARN(1, "parent clk %s of %s must be registered first\n",
- name, parent_name);
+ parent_name, name);
return ERR_PTR(-EINVAL);
}
@@ -1706,7 +1710,7 @@ struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name,
parent = __clk_lookup(parent_name);
if (!parent) {
WARN(1, "parent clk %s of %s must be registered first\n",
- name, parent_name);
+ parent_name, name);
return ERR_PTR(-EINVAL);
}
@@ -1802,7 +1806,7 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name,
}
#endif
-#ifdef CONFIG_ARCH_TEGRA_124_SOC
+#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
static const struct clk_ops tegra_clk_pllss_ops = {
.is_enabled = clk_pll_is_enabled,
.enable = clk_pll_iddq_enable,
@@ -1830,7 +1834,7 @@ struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
parent = __clk_lookup(parent_name);
if (!parent) {
WARN(1, "parent clk %s of %s must be registered first\n",
- name, parent_name);
+ parent_name, name);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index 37f32c49674e..cef0727b9eec 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -434,10 +434,10 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX("hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA, 125, TEGRA_PERIPH_ON_APB, tegra_clk_hda),
MUX("hda2codec_2x", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, TEGRA_PERIPH_ON_APB, tegra_clk_hda2codec_2x),
MUX("vfir", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VFIR, 7, TEGRA_PERIPH_ON_APB, tegra_clk_vfir),
- MUX("sdmmc1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, 0, tegra_clk_sdmmc1),
- MUX("sdmmc2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, 0, tegra_clk_sdmmc2),
- MUX("sdmmc3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, 0, tegra_clk_sdmmc3),
- MUX("sdmmc4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, 0, tegra_clk_sdmmc4),
+ MUX("sdmmc1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1),
+ MUX("sdmmc2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2),
+ MUX("sdmmc3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3),
+ MUX("sdmmc4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4),
MUX("la", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_LA, 76, TEGRA_PERIPH_ON_APB, tegra_clk_la),
MUX("trace", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_TRACE, 77, TEGRA_PERIPH_ON_APB, tegra_clk_trace),
MUX("owr", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_OWR, 71, TEGRA_PERIPH_ON_APB, tegra_clk_owr),
@@ -470,10 +470,10 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1),
MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1),
MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 165, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2),
- MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, 0, tegra_clk_sdmmc1_8),
- MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, 0, tegra_clk_sdmmc2_8),
- MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, 0, tegra_clk_sdmmc3_8),
- MUX8("sdmmc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC4, 15, 0, tegra_clk_sdmmc4_8),
+ MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1_8),
+ MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2_8),
+ MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3_8),
+ MUX8("sdmmc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4_8),
MUX8("sbc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_8),
MUX8("sbc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_8),
MUX8("sbc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_8),
@@ -537,8 +537,6 @@ static struct tegra_periph_init_data gate_clks[] = {
GATE("xusb_host", "xusb_host_src", 89, 0, tegra_clk_xusb_host, 0),
GATE("xusb_ss", "xusb_ss_src", 156, 0, tegra_clk_xusb_ss, 0),
GATE("xusb_dev", "xusb_dev_src", 95, 0, tegra_clk_xusb_dev, 0),
- GATE("dsia", "dsia_mux", 48, 0, tegra_clk_dsia, 0),
- GATE("dsib", "dsib_mux", 82, 0, tegra_clk_dsib, 0),
GATE("emc", "emc_mux", 57, 0, tegra_clk_emc, CLK_IGNORE_UNUSED),
GATE("sata_cold", "clk_m", 129, TEGRA_PERIPH_ON_APB, tegra_clk_sata_cold, 0),
GATE("ispb", "clk_m", 3, 0, tegra_clk_ispb, 0),
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 0b03d2cf7264..d0766423a5d6 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -715,7 +715,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
[tegra_clk_sbc2_8] = { .dt_id = TEGRA114_CLK_SBC2, .present = true },
[tegra_clk_sbc3_8] = { .dt_id = TEGRA114_CLK_SBC3, .present = true },
[tegra_clk_i2c5] = { .dt_id = TEGRA114_CLK_I2C5, .present = true },
- [tegra_clk_dsia] = { .dt_id = TEGRA114_CLK_DSIA, .present = true },
[tegra_clk_mipi] = { .dt_id = TEGRA114_CLK_MIPI, .present = true },
[tegra_clk_hdmi] = { .dt_id = TEGRA114_CLK_HDMI, .present = true },
[tegra_clk_csi] = { .dt_id = TEGRA114_CLK_CSI, .present = true },
@@ -739,7 +738,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
[tegra_clk_dtv] = { .dt_id = TEGRA114_CLK_DTV, .present = true },
[tegra_clk_ndspeed] = { .dt_id = TEGRA114_CLK_NDSPEED, .present = true },
[tegra_clk_i2cslow] = { .dt_id = TEGRA114_CLK_I2CSLOW, .present = true },
- [tegra_clk_dsib] = { .dt_id = TEGRA114_CLK_DSIB, .present = true },
[tegra_clk_tsec] = { .dt_id = TEGRA114_CLK_TSEC, .present = true },
[tegra_clk_xusb_host] = { .dt_id = TEGRA114_CLK_XUSB_HOST, .present = true },
[tegra_clk_msenc] = { .dt_id = TEGRA114_CLK_MSENC, .present = true },
@@ -1224,6 +1222,14 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base,
clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock);
clks[TEGRA114_CLK_DSIB_MUX] = clk;
+ clk = tegra_clk_register_periph_gate("dsia", "dsia_mux", 0, clk_base,
+ 0, 48, periph_clk_enb_refcnt);
+ clks[TEGRA114_CLK_DSIA] = clk;
+
+ clk = tegra_clk_register_periph_gate("dsib", "dsib_mux", 0, clk_base,
+ 0, 82, periph_clk_enb_refcnt);
+ clks[TEGRA114_CLK_DSIB] = clk;
+
/* emc mux */
clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
ARRAY_SIZE(mux_pllmcp_clkm),
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index f5f9baca7bb6..9a893f2fe8e9 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2012-2014 NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -28,6 +28,14 @@
#include "clk.h"
#include "clk-id.h"
+/*
+ * TEGRA124_CAR_BANK_COUNT: the number of peripheral clock register
+ * banks present in the Tegra124/132 CAR IP block. The banks are
+ * identified by single letters, e.g.: L, H, U, V, W, X. See
+ * periph_regs[] in drivers/clk/tegra/clk.c
+ */
+#define TEGRA124_CAR_BANK_COUNT 6
+
#define CLK_SOURCE_CSITE 0x1d4
#define CLK_SOURCE_EMC 0x19c
@@ -128,7 +136,6 @@ static unsigned long osc_freq;
static unsigned long pll_ref_freq;
static DEFINE_SPINLOCK(pll_d_lock);
-static DEFINE_SPINLOCK(pll_d2_lock);
static DEFINE_SPINLOCK(pll_e_lock);
static DEFINE_SPINLOCK(pll_re_lock);
static DEFINE_SPINLOCK(pll_u_lock);
@@ -145,11 +152,6 @@ static unsigned long tegra124_input_freq[] = {
[12] = 260000000,
};
-static const char *mux_plld_out0_plld2_out0[] = {
- "pll_d_out0", "pll_d2_out0",
-};
-#define mux_plld_out0_plld2_out0_idx NULL
-
static const char *mux_pllmcp_clkm[] = {
"pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3",
};
@@ -783,7 +785,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
[tegra_clk_sbc2] = { .dt_id = TEGRA124_CLK_SBC2, .present = true },
[tegra_clk_sbc3] = { .dt_id = TEGRA124_CLK_SBC3, .present = true },
[tegra_clk_i2c5] = { .dt_id = TEGRA124_CLK_I2C5, .present = true },
- [tegra_clk_dsia] = { .dt_id = TEGRA124_CLK_DSIA, .present = true },
[tegra_clk_mipi] = { .dt_id = TEGRA124_CLK_MIPI, .present = true },
[tegra_clk_hdmi] = { .dt_id = TEGRA124_CLK_HDMI, .present = true },
[tegra_clk_csi] = { .dt_id = TEGRA124_CLK_CSI, .present = true },
@@ -809,7 +810,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
[tegra_clk_soc_therm] = { .dt_id = TEGRA124_CLK_SOC_THERM, .present = true },
[tegra_clk_dtv] = { .dt_id = TEGRA124_CLK_DTV, .present = true },
[tegra_clk_i2cslow] = { .dt_id = TEGRA124_CLK_I2CSLOW, .present = true },
- [tegra_clk_dsib] = { .dt_id = TEGRA124_CLK_DSIB, .present = true },
[tegra_clk_tsec] = { .dt_id = TEGRA124_CLK_TSEC, .present = true },
[tegra_clk_xusb_host] = { .dt_id = TEGRA124_CLK_XUSB_HOST, .present = true },
[tegra_clk_msenc] = { .dt_id = TEGRA124_CLK_MSENC, .present = true },
@@ -949,8 +949,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
[tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_1_MUX, .present = true },
[tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_2_MUX, .present = true },
[tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_3_MUX, .present = true },
- [tegra_clk_dsia_mux] = { .dt_id = TEGRA124_CLK_DSIA_MUX, .present = true },
- [tegra_clk_dsib_mux] = { .dt_id = TEGRA124_CLK_DSIB_MUX, .present = true },
};
static struct tegra_devclk devclks[] __initdata = {
@@ -1112,17 +1110,17 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base,
1, 2);
clks[TEGRA124_CLK_XUSB_SS_DIV2] = clk;
- /* dsia mux */
- clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0,
- ARRAY_SIZE(mux_plld_out0_plld2_out0), 0,
- clk_base + PLLD_BASE, 25, 1, 0, &pll_d_lock);
- clks[TEGRA124_CLK_DSIA_MUX] = clk;
+ clk = clk_register_gate(NULL, "plld_dsi", "plld_out0", 0,
+ clk_base + PLLD_MISC, 30, 0, &pll_d_lock);
+ clks[TEGRA124_CLK_PLLD_DSI] = clk;
+
+ clk = tegra_clk_register_periph_gate("dsia", "plld_dsi", 0, clk_base,
+ 0, 48, periph_clk_enb_refcnt);
+ clks[TEGRA124_CLK_DSIA] = clk;
- /* dsib mux */
- clk = clk_register_mux(NULL, "dsib_mux", mux_plld_out0_plld2_out0,
- ARRAY_SIZE(mux_plld_out0_plld2_out0), 0,
- clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock);
- clks[TEGRA124_CLK_DSIB_MUX] = clk;
+ clk = tegra_clk_register_periph_gate("dsib", "plld_dsi", 0, clk_base,
+ 0, 82, periph_clk_enb_refcnt);
+ clks[TEGRA124_CLK_DSIB] = clk;
/* emc mux */
clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
@@ -1351,7 +1349,7 @@ static const struct of_device_id pmc_match[] __initconst = {
{},
};
-static struct tegra_clk_init_table init_table[] __initdata = {
+static struct tegra_clk_init_table common_init_table[] __initdata = {
{TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 408000000, 0},
{TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 408000000, 0},
{TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 408000000, 0},
@@ -1368,6 +1366,8 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0},
{TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1},
+ {TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0},
+ {TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0},
{TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1},
{TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1},
{TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1},
@@ -1385,27 +1385,73 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{TEGRA124_CLK_SATA, TEGRA124_CLK_PLL_P, 104000000, 0},
{TEGRA124_CLK_SATA_OOB, TEGRA124_CLK_PLL_P, 204000000, 0},
{TEGRA124_CLK_EMC, TEGRA124_CLK_CLK_MAX, 0, 1},
- {TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1},
{TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1},
{TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1},
{TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0},
+ /* This MUST be the last entry. */
+ {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
+};
+
+static struct tegra_clk_init_table tegra124_init_table[] __initdata = {
{TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 0},
+ {TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1},
+ /* This MUST be the last entry. */
+ {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
+};
+
+/* Tegra132 requires the SOC_THERM clock to remain active */
+static struct tegra_clk_init_table tegra132_init_table[] __initdata = {
+ {TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 1},
/* This MUST be the last entry. */
{TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
};
+/**
+ * tegra124_clock_apply_init_table - initialize clocks on Tegra124 SoCs
+ *
+ * Program an initial clock rate and enable or disable clocks needed
+ * by the rest of the kernel, for Tegra124 SoCs. It is intended to be
+ * called by assigning a pointer to it to tegra_clk_apply_init_table -
+ * this will be called as an arch_initcall. No return value.
+ */
static void __init tegra124_clock_apply_init_table(void)
{
- tegra_init_from_table(init_table, clks, TEGRA124_CLK_CLK_MAX);
+ tegra_init_from_table(common_init_table, clks, TEGRA124_CLK_CLK_MAX);
+ tegra_init_from_table(tegra124_init_table, clks, TEGRA124_CLK_CLK_MAX);
}
-static void __init tegra124_clock_init(struct device_node *np)
+/**
+ * tegra132_clock_apply_init_table - initialize clocks on Tegra132 SoCs
+ *
+ * Program an initial clock rate and enable or disable clocks needed
+ * by the rest of the kernel, for Tegra132 SoCs. It is intended to be
+ * called by assigning a pointer to it to tegra_clk_apply_init_table -
+ * this will be called as an arch_initcall. No return value.
+ */
+static void __init tegra132_clock_apply_init_table(void)
+{
+ tegra_init_from_table(common_init_table, clks, TEGRA124_CLK_CLK_MAX);
+ tegra_init_from_table(tegra132_init_table, clks, TEGRA124_CLK_CLK_MAX);
+}
+
+/**
+ * tegra124_132_clock_init_pre - clock initialization preamble for T124/T132
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most of the clocks controlled by the CAR IP block, along
+ * with a few clocks controlled by the PMC IP block. Everything in
+ * this function should be common to Tegra124 and Tegra132. XXX The
+ * PMC clock initialization should probably be moved to PMC-specific
+ * driver code. No return value.
+ */
+static void __init tegra124_132_clock_init_pre(struct device_node *np)
{
struct device_node *node;
+ u32 plld_base;
clk_base = of_iomap(np, 0);
if (!clk_base) {
- pr_err("ioremap tegra124 CAR failed\n");
+ pr_err("ioremap tegra124/tegra132 CAR failed\n");
return;
}
@@ -1423,7 +1469,8 @@ static void __init tegra124_clock_init(struct device_node *np)
return;
}
- clks = tegra_clk_init(clk_base, TEGRA124_CLK_CLK_MAX, 6);
+ clks = tegra_clk_init(clk_base, TEGRA124_CLK_CLK_MAX,
+ TEGRA124_CAR_BANK_COUNT);
if (!clks)
return;
@@ -1437,13 +1484,76 @@ static void __init tegra124_clock_init(struct device_node *np)
tegra_audio_clk_init(clk_base, pmc_base, tegra124_clks, &pll_a_params);
tegra_pmc_clk_init(pmc_base, tegra124_clks);
+ /* For Tegra124 & Tegra132, PLLD is the only source for DSIA & DSIB */
+ plld_base = clk_readl(clk_base + PLLD_BASE);
+ plld_base &= ~BIT(25);
+ clk_writel(plld_base, clk_base + PLLD_BASE);
+}
+
+/**
+ * tegra124_132_clock_init_post - clock initialization postamble for T124/T132
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most of the along with a few clocks controlled by the PMC
+ * IP block. Everything in this function should be common to Tegra124
+ * and Tegra132. This function must be called after
+ * tegra124_132_clock_init_pre(), otherwise clk_base and pmc_base will
+ * not be set. No return value.
+ */
+static void __init tegra124_132_clock_init_post(struct device_node *np)
+{
tegra_super_clk_gen4_init(clk_base, pmc_base, tegra124_clks,
- &pll_x_params);
+ &pll_x_params);
tegra_add_of_provider(np);
tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
+ tegra_cpu_car_ops = &tegra124_cpu_car_ops;
+}
+
+/**
+ * tegra124_clock_init - Tegra124-specific clock initialization
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most SoC clocks for the Tegra124 system-on-chip. Most of
+ * this code is shared between the Tegra124 and Tegra132 SoCs,
+ * although some of the initial clock settings and CPU clocks differ.
+ * Intended to be called by the OF init code when a DT node with the
+ * "nvidia,tegra124-car" string is encountered, and declared with
+ * CLK_OF_DECLARE. No return value.
+ */
+static void __init tegra124_clock_init(struct device_node *np)
+{
+ tegra124_132_clock_init_pre(np);
tegra_clk_apply_init_table = tegra124_clock_apply_init_table;
+ tegra124_132_clock_init_post(np);
+}
- tegra_cpu_car_ops = &tegra124_cpu_car_ops;
+/**
+ * tegra132_clock_init - Tegra132-specific clock initialization
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most SoC clocks for the Tegra132 system-on-chip. Most of
+ * this code is shared between the Tegra124 and Tegra132 SoCs,
+ * although some of the initial clock settings and CPU clocks differ.
+ * Intended to be called by the OF init code when a DT node with the
+ * "nvidia,tegra132-car" string is encountered, and declared with
+ * CLK_OF_DECLARE. No return value.
+ */
+static void __init tegra132_clock_init(struct device_node *np)
+{
+ tegra124_132_clock_init_pre(np);
+
+ /*
+ * On Tegra132, these clocks are controlled by the
+ * CLUSTER_clocks IP block, located in the CPU complex
+ */
+ tegra124_clks[tegra_clk_cclk_g].present = false;
+ tegra124_clks[tegra_clk_cclk_lp].present = false;
+ tegra124_clks[tegra_clk_pll_x].present = false;
+ tegra124_clks[tegra_clk_pll_x_out0].present = false;
+
+ tegra_clk_apply_init_table = tegra132_clock_apply_init_table;
+ tegra124_132_clock_init_post(np);
}
CLK_OF_DECLARE(tegra124, "nvidia,tegra124-car", tegra124_clock_init);
+CLK_OF_DECLARE(tegra132, "nvidia,tegra132-car", tegra132_clock_init);
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
index 97dc8595c3cd..9ddb7547cb43 100644
--- a/drivers/clk/tegra/clk.c
+++ b/drivers/clk/tegra/clk.c
@@ -302,10 +302,13 @@ struct clk ** __init tegra_lookup_dt_id(int clk_id,
tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
-void __init tegra_clocks_apply_init_table(void)
+static int __init tegra_clocks_apply_init_table(void)
{
if (!tegra_clk_apply_init_table)
- return;
+ return 0;
tegra_clk_apply_init_table();
+
+ return 0;
}
+arch_initcall(tegra_clocks_apply_init_table);
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile
index ed4d0aaf8916..105ffd0f5e79 100644
--- a/drivers/clk/ti/Makefile
+++ b/drivers/clk/ti/Makefile
@@ -1,13 +1,17 @@
-ifneq ($(CONFIG_OF),)
obj-y += clk.o autoidle.o clockdomain.o
clk-common = dpll.o composite.o divider.o gate.o \
fixed-factor.o mux.o apll.o
obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o
+obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o
obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o
-obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o clk-3xxx.o
+obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o \
+ clk-3xxx.o
obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o
obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o
obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \
clk-dra7-atl.o
obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o
+
+ifdef CONFIG_ATAGS
+obj-$(CONFIG_ARCH_OMAP3) += clk-3xxx-legacy.o
endif
diff --git a/drivers/clk/ti/clk-3xxx-legacy.c b/drivers/clk/ti/clk-3xxx-legacy.c
new file mode 100644
index 000000000000..e0732a4c8f26
--- /dev/null
+++ b/drivers/clk/ti/clk-3xxx-legacy.c
@@ -0,0 +1,4653 @@
+/*
+ * OMAP3 Legacy clock data
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc
+ * Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
+
+#include "clock.h"
+
+static struct ti_clk_fixed virt_12m_ck_data = {
+ .frequency = 12000000,
+};
+
+static struct ti_clk virt_12m_ck = {
+ .name = "virt_12m_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_12m_ck_data,
+};
+
+static struct ti_clk_fixed virt_13m_ck_data = {
+ .frequency = 13000000,
+};
+
+static struct ti_clk virt_13m_ck = {
+ .name = "virt_13m_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_13m_ck_data,
+};
+
+static struct ti_clk_fixed virt_19200000_ck_data = {
+ .frequency = 19200000,
+};
+
+static struct ti_clk virt_19200000_ck = {
+ .name = "virt_19200000_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_19200000_ck_data,
+};
+
+static struct ti_clk_fixed virt_26000000_ck_data = {
+ .frequency = 26000000,
+};
+
+static struct ti_clk virt_26000000_ck = {
+ .name = "virt_26000000_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_26000000_ck_data,
+};
+
+static struct ti_clk_fixed virt_38_4m_ck_data = {
+ .frequency = 38400000,
+};
+
+static struct ti_clk virt_38_4m_ck = {
+ .name = "virt_38_4m_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_38_4m_ck_data,
+};
+
+static struct ti_clk_fixed virt_16_8m_ck_data = {
+ .frequency = 16800000,
+};
+
+static struct ti_clk virt_16_8m_ck = {
+ .name = "virt_16_8m_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_16_8m_ck_data,
+};
+
+static const char *osc_sys_ck_parents[] = {
+ "virt_12m_ck",
+ "virt_13m_ck",
+ "virt_19200000_ck",
+ "virt_26000000_ck",
+ "virt_38_4m_ck",
+ "virt_16_8m_ck",
+};
+
+static struct ti_clk_mux osc_sys_ck_data = {
+ .num_parents = ARRAY_SIZE(osc_sys_ck_parents),
+ .reg = 0xd40,
+ .module = TI_CLKM_PRM,
+ .parents = osc_sys_ck_parents,
+};
+
+static struct ti_clk osc_sys_ck = {
+ .name = "osc_sys_ck",
+ .type = TI_CLK_MUX,
+ .data = &osc_sys_ck_data,
+};
+
+static struct ti_clk_divider sys_ck_data = {
+ .parent = "osc_sys_ck",
+ .bit_shift = 6,
+ .max_div = 3,
+ .reg = 0x1270,
+ .module = TI_CLKM_PRM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk sys_ck = {
+ .name = "sys_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &sys_ck_data,
+};
+
+static const char *dpll3_ck_parents[] = {
+ "sys_ck",
+ "sys_ck",
+};
+
+static struct ti_clk_dpll dpll3_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll3_ck_parents),
+ .control_reg = 0xd00,
+ .idlest_reg = 0xd20,
+ .mult_div1_reg = 0xd40,
+ .autoidle_reg = 0xd30,
+ .module = TI_CLKM_CM,
+ .parents = dpll3_ck_parents,
+ .flags = CLKF_CORE,
+ .freqsel_mask = 0xf0,
+ .div1_mask = 0x7f00,
+ .idlest_mask = 0x1,
+ .auto_recal_bit = 0x3,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x5,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x7,
+ .mult_mask = 0x7ff0000,
+ .recal_st_bit = 0x5,
+ .autoidle_mask = 0x7,
+};
+
+static struct ti_clk dpll3_ck = {
+ .name = "dpll3_ck",
+ .clkdm_name = "dpll3_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll3_ck_data,
+};
+
+static struct ti_clk_divider dpll3_m2_ck_data = {
+ .parent = "dpll3_ck",
+ .bit_shift = 27,
+ .max_div = 31,
+ .reg = 0xd40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll3_m2_ck = {
+ .name = "dpll3_m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll3_m2_ck_data,
+};
+
+static struct ti_clk_fixed_factor core_ck_data = {
+ .parent = "dpll3_m2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_ck = {
+ .name = "core_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_ck_data,
+};
+
+static struct ti_clk_divider l3_ick_data = {
+ .parent = "core_ck",
+ .max_div = 3,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk l3_ick = {
+ .name = "l3_ick",
+ .type = TI_CLK_DIVIDER,
+ .data = &l3_ick_data,
+};
+
+static struct ti_clk_fixed_factor security_l3_ick_data = {
+ .parent = "l3_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk security_l3_ick = {
+ .name = "security_l3_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &security_l3_ick_data,
+};
+
+static struct ti_clk_fixed_factor wkup_l4_ick_data = {
+ .parent = "sys_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk wkup_l4_ick = {
+ .name = "wkup_l4_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &wkup_l4_ick_data,
+};
+
+static struct ti_clk_gate usim_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 9,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk usim_ick = {
+ .name = "usim_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usim_ick_data,
+};
+
+static struct ti_clk_gate dss2_alwon_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 1,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk dss2_alwon_fck = {
+ .name = "dss2_alwon_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss2_alwon_fck_data,
+};
+
+static struct ti_clk_divider l4_ick_data = {
+ .parent = "l3_ick",
+ .bit_shift = 2,
+ .max_div = 3,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk l4_ick = {
+ .name = "l4_ick",
+ .type = TI_CLK_DIVIDER,
+ .data = &l4_ick_data,
+};
+
+static struct ti_clk_fixed_factor core_l4_ick_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_l4_ick = {
+ .name = "core_l4_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_l4_ick_data,
+};
+
+static struct ti_clk_gate mmchs2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 25,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mmchs2_ick = {
+ .name = "mmchs2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs2_ick_data,
+};
+
+static const char *dpll4_ck_parents[] = {
+ "sys_ck",
+ "sys_ck",
+};
+
+static struct ti_clk_dpll dpll4_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll4_ck_parents),
+ .control_reg = 0xd00,
+ .idlest_reg = 0xd20,
+ .mult_div1_reg = 0xd44,
+ .autoidle_reg = 0xd30,
+ .module = TI_CLKM_CM,
+ .parents = dpll4_ck_parents,
+ .flags = CLKF_PER,
+ .freqsel_mask = 0xf00000,
+ .modes = 0x82,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x2,
+ .auto_recal_bit = 0x13,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x6,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x70000,
+ .mult_mask = 0x7ff00,
+ .recal_st_bit = 0x6,
+ .autoidle_mask = 0x38,
+};
+
+static struct ti_clk dpll4_ck = {
+ .name = "dpll4_ck",
+ .clkdm_name = "dpll4_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll4_ck_data,
+};
+
+static struct ti_clk_divider dpll4_m2_ck_data = {
+ .parent = "dpll4_ck",
+ .max_div = 63,
+ .reg = 0xd48,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m2_ck = {
+ .name = "dpll4_m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m2_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_m2x2_mul_ck_data = {
+ .parent = "dpll4_m2_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll4_m2x2_mul_ck = {
+ .name = "dpll4_m2x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m2x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m2x2_ck_data = {
+ .parent = "dpll4_m2x2_mul_ck",
+ .bit_shift = 0x1b,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m2x2_ck = {
+ .name = "dpll4_m2x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m2x2_ck_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_alwon_fck_data = {
+ .parent = "dpll4_m2x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_alwon_fck = {
+ .name = "omap_96m_alwon_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_alwon_fck_data,
+};
+
+static struct ti_clk_fixed_factor cm_96m_fck_data = {
+ .parent = "omap_96m_alwon_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk cm_96m_fck = {
+ .name = "cm_96m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &cm_96m_fck_data,
+};
+
+static const char *omap_96m_fck_parents[] = {
+ "cm_96m_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux omap_96m_fck_data = {
+ .bit_shift = 6,
+ .num_parents = ARRAY_SIZE(omap_96m_fck_parents),
+ .reg = 0xd40,
+ .module = TI_CLKM_CM,
+ .parents = omap_96m_fck_parents,
+};
+
+static struct ti_clk omap_96m_fck = {
+ .name = "omap_96m_fck",
+ .type = TI_CLK_MUX,
+ .data = &omap_96m_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_96m_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_96m_fck = {
+ .name = "core_96m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_96m_fck_data,
+};
+
+static struct ti_clk_gate mspro_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 23,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mspro_fck = {
+ .name = "mspro_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mspro_fck_data,
+};
+
+static struct ti_clk_gate dss_ick_3430es2_data = {
+ .parent = "l4_ick",
+ .bit_shift = 0,
+ .reg = 0xe10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_DSS | CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk dss_ick_3430es2 = {
+ .name = "dss_ick",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss_ick_3430es2_data,
+};
+
+static struct ti_clk_gate uart4_ick_am35xx_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 23,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart4_ick_am35xx = {
+ .name = "uart4_ick_am35xx",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart4_ick_am35xx_data,
+};
+
+static struct ti_clk_fixed_factor security_l4_ick2_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk security_l4_ick2 = {
+ .name = "security_l4_ick2",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &security_l4_ick2_data,
+};
+
+static struct ti_clk_gate aes1_ick_data = {
+ .parent = "security_l4_ick2",
+ .bit_shift = 3,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk aes1_ick = {
+ .name = "aes1_ick",
+ .type = TI_CLK_GATE,
+ .data = &aes1_ick_data,
+};
+
+static const char *dpll5_ck_parents[] = {
+ "sys_ck",
+ "sys_ck",
+};
+
+static struct ti_clk_dpll dpll5_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll5_ck_parents),
+ .control_reg = 0xd04,
+ .idlest_reg = 0xd24,
+ .mult_div1_reg = 0xd4c,
+ .autoidle_reg = 0xd34,
+ .module = TI_CLKM_CM,
+ .parents = dpll5_ck_parents,
+ .freqsel_mask = 0xf0,
+ .modes = 0x82,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x1,
+ .auto_recal_bit = 0x3,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x19,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x7,
+ .mult_mask = 0x7ff00,
+ .recal_st_bit = 0x19,
+ .autoidle_mask = 0x7,
+};
+
+static struct ti_clk dpll5_ck = {
+ .name = "dpll5_ck",
+ .clkdm_name = "dpll5_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll5_ck_data,
+};
+
+static struct ti_clk_divider dpll5_m2_ck_data = {
+ .parent = "dpll5_ck",
+ .max_div = 31,
+ .reg = 0xd50,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll5_m2_ck = {
+ .name = "dpll5_m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll5_m2_ck_data,
+};
+
+static struct ti_clk_gate usbhost_120m_fck_data = {
+ .parent = "dpll5_m2_ck",
+ .bit_shift = 1,
+ .reg = 0x1400,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk usbhost_120m_fck = {
+ .name = "usbhost_120m_fck",
+ .clkdm_name = "usbhost_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbhost_120m_fck_data,
+};
+
+static struct ti_clk_fixed_factor cm_96m_d2_fck_data = {
+ .parent = "cm_96m_fck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk cm_96m_d2_fck = {
+ .name = "cm_96m_d2_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &cm_96m_d2_fck_data,
+};
+
+static struct ti_clk_fixed sys_altclk_data = {
+ .frequency = 0x0,
+};
+
+static struct ti_clk sys_altclk = {
+ .name = "sys_altclk",
+ .type = TI_CLK_FIXED,
+ .data = &sys_altclk_data,
+};
+
+static const char *omap_48m_fck_parents[] = {
+ "cm_96m_d2_fck",
+ "sys_altclk",
+};
+
+static struct ti_clk_mux omap_48m_fck_data = {
+ .bit_shift = 3,
+ .num_parents = ARRAY_SIZE(omap_48m_fck_parents),
+ .reg = 0xd40,
+ .module = TI_CLKM_CM,
+ .parents = omap_48m_fck_parents,
+};
+
+static struct ti_clk omap_48m_fck = {
+ .name = "omap_48m_fck",
+ .type = TI_CLK_MUX,
+ .data = &omap_48m_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_48m_fck_data = {
+ .parent = "omap_48m_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_48m_fck = {
+ .name = "core_48m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_48m_fck_data,
+};
+
+static struct ti_clk_fixed mcbsp_clks_data = {
+ .frequency = 0x0,
+};
+
+static struct ti_clk mcbsp_clks = {
+ .name = "mcbsp_clks",
+ .type = TI_CLK_FIXED,
+ .data = &mcbsp_clks_data,
+};
+
+static struct ti_clk_gate mcbsp2_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 0,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_fixed_factor per_96m_fck_data = {
+ .parent = "omap_96m_alwon_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk per_96m_fck = {
+ .name = "per_96m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &per_96m_fck_data,
+};
+
+static const char *mcbsp2_mux_fck_parents[] = {
+ "per_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp2_mux_fck_data = {
+ .bit_shift = 6,
+ .num_parents = ARRAY_SIZE(mcbsp2_mux_fck_parents),
+ .reg = 0x274,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp2_mux_fck_parents,
+};
+
+static struct ti_clk_composite mcbsp2_fck_data = {
+ .mux = &mcbsp2_mux_fck_data,
+ .gate = &mcbsp2_gate_fck_data,
+};
+
+static struct ti_clk mcbsp2_fck = {
+ .name = "mcbsp2_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp2_fck_data,
+};
+
+static struct ti_clk_fixed_factor dpll3_m2x2_ck_data = {
+ .parent = "dpll3_m2_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll3_m2x2_ck = {
+ .name = "dpll3_m2x2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll3_m2x2_ck_data,
+};
+
+static struct ti_clk_fixed_factor corex2_fck_data = {
+ .parent = "dpll3_m2x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk corex2_fck = {
+ .name = "corex2_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &corex2_fck_data,
+};
+
+static struct ti_clk_gate ssi_ssr_gate_fck_3430es1_data = {
+ .parent = "corex2_fck",
+ .bit_shift = 0,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_NO_WAIT,
+};
+
+static int ssi_ssr_div_fck_3430es1_divs[] = {
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 0,
+ 6,
+ 0,
+ 8,
+};
+
+static struct ti_clk_divider ssi_ssr_div_fck_3430es1_data = {
+ .num_dividers = ARRAY_SIZE(ssi_ssr_div_fck_3430es1_divs),
+ .parent = "corex2_fck",
+ .bit_shift = 8,
+ .dividers = ssi_ssr_div_fck_3430es1_divs,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite ssi_ssr_fck_3430es1_data = {
+ .gate = &ssi_ssr_gate_fck_3430es1_data,
+ .divider = &ssi_ssr_div_fck_3430es1_data,
+};
+
+static struct ti_clk ssi_ssr_fck_3430es1 = {
+ .name = "ssi_ssr_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &ssi_ssr_fck_3430es1_data,
+};
+
+static struct ti_clk_fixed_factor ssi_sst_fck_3430es1_data = {
+ .parent = "ssi_ssr_fck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk ssi_sst_fck_3430es1 = {
+ .name = "ssi_sst_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &ssi_sst_fck_3430es1_data,
+};
+
+static struct ti_clk_fixed omap_32k_fck_data = {
+ .frequency = 32768,
+};
+
+static struct ti_clk omap_32k_fck = {
+ .name = "omap_32k_fck",
+ .type = TI_CLK_FIXED,
+ .data = &omap_32k_fck_data,
+};
+
+static struct ti_clk_fixed_factor per_32k_alwon_fck_data = {
+ .parent = "omap_32k_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk per_32k_alwon_fck = {
+ .name = "per_32k_alwon_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &per_32k_alwon_fck_data,
+};
+
+static struct ti_clk_gate gpio5_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 16,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio5_dbck = {
+ .name = "gpio5_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio5_dbck_data,
+};
+
+static struct ti_clk_gate gpt1_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 0,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt1_ick = {
+ .name = "gpt1_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt1_ick_data,
+};
+
+static struct ti_clk_gate mcspi3_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 20,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mcspi3_fck = {
+ .name = "mcspi3_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi3_fck_data,
+};
+
+static struct ti_clk_gate gpt2_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 3,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt2_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt2_mux_fck_data = {
+ .num_parents = ARRAY_SIZE(gpt2_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt2_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt2_fck_data = {
+ .mux = &gpt2_mux_fck_data,
+ .gate = &gpt2_gate_fck_data,
+};
+
+static struct ti_clk gpt2_fck = {
+ .name = "gpt2_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt2_fck_data,
+};
+
+static struct ti_clk_gate gpt10_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 11,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt10_ick = {
+ .name = "gpt10_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt10_ick_data,
+};
+
+static struct ti_clk_gate uart2_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 14,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart2_fck = {
+ .name = "uart2_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart2_fck_data,
+};
+
+static struct ti_clk_fixed_factor sr_l4_ick_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk sr_l4_ick = {
+ .name = "sr_l4_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &sr_l4_ick_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_d8_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 8,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_d8_fck = {
+ .name = "omap_96m_d8_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_d8_fck_data,
+};
+
+static struct ti_clk_divider dpll4_m5_ck_data = {
+ .parent = "dpll4_ck",
+ .max_div = 63,
+ .reg = 0xf40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m5_ck = {
+ .name = "dpll4_m5_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m5_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_m5x2_mul_ck_data = {
+ .parent = "dpll4_m5_ck",
+ .div = 1,
+ .mult = 2,
+ .flags = CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk dpll4_m5x2_mul_ck = {
+ .name = "dpll4_m5x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m5x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m5x2_ck_data = {
+ .parent = "dpll4_m5x2_mul_ck",
+ .bit_shift = 0x1e,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m5x2_ck = {
+ .name = "dpll4_m5x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m5x2_ck_data,
+};
+
+static struct ti_clk_gate cam_mclk_data = {
+ .parent = "dpll4_m5x2_ck",
+ .bit_shift = 0,
+ .reg = 0xf00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk cam_mclk = {
+ .name = "cam_mclk",
+ .type = TI_CLK_GATE,
+ .data = &cam_mclk_data,
+};
+
+static struct ti_clk_gate mcbsp3_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 1,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *mcbsp3_mux_fck_parents[] = {
+ "per_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp3_mux_fck_data = {
+ .num_parents = ARRAY_SIZE(mcbsp3_mux_fck_parents),
+ .reg = 0x2d8,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp3_mux_fck_parents,
+};
+
+static struct ti_clk_composite mcbsp3_fck_data = {
+ .mux = &mcbsp3_mux_fck_data,
+ .gate = &mcbsp3_gate_fck_data,
+};
+
+static struct ti_clk mcbsp3_fck = {
+ .name = "mcbsp3_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp3_fck_data,
+};
+
+static struct ti_clk_gate csi2_96m_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 1,
+ .reg = 0xf00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk csi2_96m_fck = {
+ .name = "csi2_96m_fck",
+ .clkdm_name = "cam_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &csi2_96m_fck_data,
+};
+
+static struct ti_clk_gate gpt9_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 10,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt9_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt9_mux_fck_data = {
+ .bit_shift = 7,
+ .num_parents = ARRAY_SIZE(gpt9_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt9_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt9_fck_data = {
+ .mux = &gpt9_mux_fck_data,
+ .gate = &gpt9_gate_fck_data,
+};
+
+static struct ti_clk gpt9_fck = {
+ .name = "gpt9_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt9_fck_data,
+};
+
+static struct ti_clk_divider dpll3_m3_ck_data = {
+ .parent = "dpll3_ck",
+ .bit_shift = 16,
+ .max_div = 31,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll3_m3_ck = {
+ .name = "dpll3_m3_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll3_m3_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll3_m3x2_mul_ck_data = {
+ .parent = "dpll3_m3_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll3_m3x2_mul_ck = {
+ .name = "dpll3_m3x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll3_m3x2_mul_ck_data,
+};
+
+static struct ti_clk_gate sr2_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 7,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk sr2_fck = {
+ .name = "sr2_fck",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sr2_fck_data,
+};
+
+static struct ti_clk_fixed pclk_ck_data = {
+ .frequency = 27000000,
+};
+
+static struct ti_clk pclk_ck = {
+ .name = "pclk_ck",
+ .type = TI_CLK_FIXED,
+ .data = &pclk_ck_data,
+};
+
+static struct ti_clk_gate wdt2_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 5,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk wdt2_ick = {
+ .name = "wdt2_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt2_ick_data,
+};
+
+static struct ti_clk_fixed_factor core_l3_ick_data = {
+ .parent = "l3_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_l3_ick = {
+ .name = "core_l3_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_l3_ick_data,
+};
+
+static struct ti_clk_gate mcspi4_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 21,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mcspi4_fck = {
+ .name = "mcspi4_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi4_fck_data,
+};
+
+static struct ti_clk_fixed_factor per_48m_fck_data = {
+ .parent = "omap_48m_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk per_48m_fck = {
+ .name = "per_48m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &per_48m_fck_data,
+};
+
+static struct ti_clk_gate uart4_fck_data = {
+ .parent = "per_48m_fck",
+ .bit_shift = 18,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart4_fck = {
+ .name = "uart4_fck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart4_fck_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_d10_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 10,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_d10_fck = {
+ .name = "omap_96m_d10_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_d10_fck_data,
+};
+
+static struct ti_clk_gate usim_gate_fck_data = {
+ .parent = "omap_96m_fck",
+ .bit_shift = 9,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_fixed_factor per_l4_ick_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk per_l4_ick = {
+ .name = "per_l4_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &per_l4_ick_data,
+};
+
+static struct ti_clk_gate gpt5_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 6,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt5_ick = {
+ .name = "gpt5_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt5_ick_data,
+};
+
+static struct ti_clk_gate mcspi2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 19,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcspi2_ick = {
+ .name = "mcspi2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi2_ick_data,
+};
+
+static struct ti_clk_fixed_factor ssi_l4_ick_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk ssi_l4_ick = {
+ .name = "ssi_l4_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &ssi_l4_ick_data,
+};
+
+static struct ti_clk_gate ssi_ick_3430es1_data = {
+ .parent = "ssi_l4_ick",
+ .bit_shift = 0,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE,
+};
+
+static struct ti_clk ssi_ick_3430es1 = {
+ .name = "ssi_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &ssi_ick_3430es1_data,
+};
+
+static struct ti_clk_gate i2c2_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 16,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk i2c2_fck = {
+ .name = "i2c2_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c2_fck_data,
+};
+
+static struct ti_clk_divider dpll1_fck_data = {
+ .parent = "core_ck",
+ .bit_shift = 19,
+ .max_div = 7,
+ .reg = 0x940,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll1_fck = {
+ .name = "dpll1_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll1_fck_data,
+};
+
+static const char *dpll1_ck_parents[] = {
+ "sys_ck",
+ "dpll1_fck",
+};
+
+static struct ti_clk_dpll dpll1_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll1_ck_parents),
+ .control_reg = 0x904,
+ .idlest_reg = 0x924,
+ .mult_div1_reg = 0x940,
+ .autoidle_reg = 0x934,
+ .module = TI_CLKM_CM,
+ .parents = dpll1_ck_parents,
+ .freqsel_mask = 0xf0,
+ .modes = 0xa0,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x1,
+ .auto_recal_bit = 0x3,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x7,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x7,
+ .mult_mask = 0x7ff00,
+ .recal_st_bit = 0x7,
+ .autoidle_mask = 0x7,
+};
+
+static struct ti_clk dpll1_ck = {
+ .name = "dpll1_ck",
+ .clkdm_name = "dpll1_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll1_ck_data,
+};
+
+static struct ti_clk_fixed secure_32k_fck_data = {
+ .frequency = 32768,
+};
+
+static struct ti_clk secure_32k_fck = {
+ .name = "secure_32k_fck",
+ .type = TI_CLK_FIXED,
+ .data = &secure_32k_fck_data,
+};
+
+static struct ti_clk_gate gpio5_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 16,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio5_ick = {
+ .name = "gpio5_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio5_ick_data,
+};
+
+static struct ti_clk_divider dpll4_m4_ck_data = {
+ .parent = "dpll4_ck",
+ .max_div = 32,
+ .reg = 0xe40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m4_ck = {
+ .name = "dpll4_m4_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m4_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_m4x2_mul_ck_data = {
+ .parent = "dpll4_m4_ck",
+ .div = 1,
+ .mult = 2,
+ .flags = CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk dpll4_m4x2_mul_ck = {
+ .name = "dpll4_m4x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m4x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m4x2_ck_data = {
+ .parent = "dpll4_m4x2_mul_ck",
+ .bit_shift = 0x1d,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_RATE_PARENT | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m4x2_ck = {
+ .name = "dpll4_m4x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m4x2_ck_data,
+};
+
+static struct ti_clk_gate dss1_alwon_fck_3430es2_data = {
+ .parent = "dpll4_m4x2_ck",
+ .bit_shift = 0,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_DSS | CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk dss1_alwon_fck_3430es2 = {
+ .name = "dss1_alwon_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss1_alwon_fck_3430es2_data,
+};
+
+static struct ti_clk_gate uart3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 11,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart3_ick = {
+ .name = "uart3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart3_ick_data,
+};
+
+static struct ti_clk_divider dpll4_m3_ck_data = {
+ .parent = "dpll4_ck",
+ .bit_shift = 8,
+ .max_div = 32,
+ .reg = 0xe40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m3_ck = {
+ .name = "dpll4_m3_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m3_ck_data,
+};
+
+static struct ti_clk_gate mcbsp3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 1,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp3_ick = {
+ .name = "mcbsp3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp3_ick_data,
+};
+
+static struct ti_clk_gate gpio3_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 14,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio3_dbck = {
+ .name = "gpio3_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio3_dbck_data,
+};
+
+static struct ti_clk_gate fac_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 8,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk fac_ick = {
+ .name = "fac_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &fac_ick_data,
+};
+
+static struct ti_clk_gate clkout2_src_gate_ck_data = {
+ .parent = "core_ck",
+ .bit_shift = 7,
+ .reg = 0xd70,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_NO_WAIT,
+};
+
+static struct ti_clk_fixed_factor dpll4_m3x2_mul_ck_data = {
+ .parent = "dpll4_m3_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll4_m3x2_mul_ck = {
+ .name = "dpll4_m3x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m3x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m3x2_ck_data = {
+ .parent = "dpll4_m3x2_mul_ck",
+ .bit_shift = 0x1c,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m3x2_ck = {
+ .name = "dpll4_m3x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m3x2_ck_data,
+};
+
+static const char *omap_54m_fck_parents[] = {
+ "dpll4_m3x2_ck",
+ "sys_altclk",
+};
+
+static struct ti_clk_mux omap_54m_fck_data = {
+ .bit_shift = 5,
+ .num_parents = ARRAY_SIZE(omap_54m_fck_parents),
+ .reg = 0xd40,
+ .module = TI_CLKM_CM,
+ .parents = omap_54m_fck_parents,
+};
+
+static struct ti_clk omap_54m_fck = {
+ .name = "omap_54m_fck",
+ .type = TI_CLK_MUX,
+ .data = &omap_54m_fck_data,
+};
+
+static const char *clkout2_src_mux_ck_parents[] = {
+ "core_ck",
+ "sys_ck",
+ "cm_96m_fck",
+ "omap_54m_fck",
+};
+
+static struct ti_clk_mux clkout2_src_mux_ck_data = {
+ .num_parents = ARRAY_SIZE(clkout2_src_mux_ck_parents),
+ .reg = 0xd70,
+ .module = TI_CLKM_CM,
+ .parents = clkout2_src_mux_ck_parents,
+};
+
+static struct ti_clk_composite clkout2_src_ck_data = {
+ .mux = &clkout2_src_mux_ck_data,
+ .gate = &clkout2_src_gate_ck_data,
+};
+
+static struct ti_clk clkout2_src_ck = {
+ .name = "clkout2_src_ck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &clkout2_src_ck_data,
+};
+
+static struct ti_clk_gate i2c1_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 15,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk i2c1_fck = {
+ .name = "i2c1_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c1_fck_data,
+};
+
+static struct ti_clk_gate wdt3_fck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 12,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk wdt3_fck = {
+ .name = "wdt3_fck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt3_fck_data,
+};
+
+static struct ti_clk_gate gpt7_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 8,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt7_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt7_mux_fck_data = {
+ .bit_shift = 5,
+ .num_parents = ARRAY_SIZE(gpt7_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt7_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt7_fck_data = {
+ .mux = &gpt7_mux_fck_data,
+ .gate = &gpt7_gate_fck_data,
+};
+
+static struct ti_clk gpt7_fck = {
+ .name = "gpt7_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt7_fck_data,
+};
+
+static struct ti_clk_gate usb_l4_gate_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 5,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INTERFACE,
+};
+
+static struct ti_clk_divider usb_l4_div_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 4,
+ .max_div = 1,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk_composite usb_l4_ick_data = {
+ .gate = &usb_l4_gate_ick_data,
+ .divider = &usb_l4_div_ick_data,
+};
+
+static struct ti_clk usb_l4_ick = {
+ .name = "usb_l4_ick",
+ .type = TI_CLK_COMPOSITE,
+ .data = &usb_l4_ick_data,
+};
+
+static struct ti_clk_gate uart4_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 18,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart4_ick = {
+ .name = "uart4_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart4_ick_data,
+};
+
+static struct ti_clk_fixed dummy_ck_data = {
+ .frequency = 0,
+};
+
+static struct ti_clk dummy_ck = {
+ .name = "dummy_ck",
+ .type = TI_CLK_FIXED,
+ .data = &dummy_ck_data,
+};
+
+static const char *gpt3_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt3_mux_fck_data = {
+ .bit_shift = 1,
+ .num_parents = ARRAY_SIZE(gpt3_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt3_mux_fck_parents,
+};
+
+static struct ti_clk_gate gpt9_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 10,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt9_ick = {
+ .name = "gpt9_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt9_ick_data,
+};
+
+static struct ti_clk_gate gpt10_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 11,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate dss_ick_3430es1_data = {
+ .parent = "l4_ick",
+ .bit_shift = 0,
+ .reg = 0xe10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE,
+};
+
+static struct ti_clk dss_ick_3430es1 = {
+ .name = "dss_ick",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss_ick_3430es1_data,
+};
+
+static struct ti_clk_gate gpt11_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 12,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt11_ick = {
+ .name = "gpt11_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt11_ick_data,
+};
+
+static struct ti_clk_divider dpll2_fck_data = {
+ .parent = "core_ck",
+ .bit_shift = 19,
+ .max_div = 7,
+ .reg = 0x40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll2_fck = {
+ .name = "dpll2_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll2_fck_data,
+};
+
+static struct ti_clk_gate uart1_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 13,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart1_fck = {
+ .name = "uart1_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart1_fck_data,
+};
+
+static struct ti_clk_gate hsotgusb_ick_3430es1_data = {
+ .parent = "core_l3_ick",
+ .bit_shift = 4,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE,
+};
+
+static struct ti_clk hsotgusb_ick_3430es1 = {
+ .name = "hsotgusb_ick_3430es1",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hsotgusb_ick_3430es1_data,
+};
+
+static struct ti_clk_gate gpio2_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 13,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio2_ick = {
+ .name = "gpio2_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio2_ick_data,
+};
+
+static struct ti_clk_gate mmchs1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 24,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mmchs1_ick = {
+ .name = "mmchs1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs1_ick_data,
+};
+
+static struct ti_clk_gate modem_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 31,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk modem_fck = {
+ .name = "modem_fck",
+ .clkdm_name = "d2d_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &modem_fck_data,
+};
+
+static struct ti_clk_gate mcbsp4_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 2,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp4_ick = {
+ .name = "mcbsp4_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp4_ick_data,
+};
+
+static struct ti_clk_gate gpio1_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 3,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio1_ick = {
+ .name = "gpio1_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio1_ick_data,
+};
+
+static const char *gpt6_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt6_mux_fck_data = {
+ .bit_shift = 4,
+ .num_parents = ARRAY_SIZE(gpt6_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt6_mux_fck_parents,
+};
+
+static struct ti_clk_fixed_factor dpll1_x2_ck_data = {
+ .parent = "dpll1_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll1_x2_ck = {
+ .name = "dpll1_x2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll1_x2_ck_data,
+};
+
+static struct ti_clk_divider dpll1_x2m2_ck_data = {
+ .parent = "dpll1_x2_ck",
+ .max_div = 31,
+ .reg = 0x944,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll1_x2m2_ck = {
+ .name = "dpll1_x2m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll1_x2m2_ck_data,
+};
+
+static struct ti_clk_fixed_factor mpu_ck_data = {
+ .parent = "dpll1_x2m2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk mpu_ck = {
+ .name = "mpu_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &mpu_ck_data,
+};
+
+static struct ti_clk_divider arm_fck_data = {
+ .parent = "mpu_ck",
+ .max_div = 2,
+ .reg = 0x924,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk arm_fck = {
+ .name = "arm_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &arm_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_d3_ck_data = {
+ .parent = "core_ck",
+ .div = 3,
+ .mult = 1,
+};
+
+static struct ti_clk core_d3_ck = {
+ .name = "core_d3_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_d3_ck_data,
+};
+
+static struct ti_clk_gate gpt11_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 12,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt11_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt11_mux_fck_data = {
+ .bit_shift = 7,
+ .num_parents = ARRAY_SIZE(gpt11_mux_fck_parents),
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .parents = gpt11_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt11_fck_data = {
+ .mux = &gpt11_mux_fck_data,
+ .gate = &gpt11_gate_fck_data,
+};
+
+static struct ti_clk gpt11_fck = {
+ .name = "gpt11_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt11_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_d6_ck_data = {
+ .parent = "core_ck",
+ .div = 6,
+ .mult = 1,
+};
+
+static struct ti_clk core_d6_ck = {
+ .name = "core_d6_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_d6_ck_data,
+};
+
+static struct ti_clk_gate uart4_fck_am35xx_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 23,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart4_fck_am35xx = {
+ .name = "uart4_fck_am35xx",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart4_fck_am35xx_data,
+};
+
+static struct ti_clk_gate dpll3_m3x2_ck_data = {
+ .parent = "dpll3_m3x2_mul_ck",
+ .bit_shift = 0xc,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll3_m3x2_ck = {
+ .name = "dpll3_m3x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll3_m3x2_ck_data,
+};
+
+static struct ti_clk_fixed_factor emu_core_alwon_ck_data = {
+ .parent = "dpll3_m3x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk emu_core_alwon_ck = {
+ .name = "emu_core_alwon_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &emu_core_alwon_ck_data,
+};
+
+static struct ti_clk_divider dpll4_m6_ck_data = {
+ .parent = "dpll4_ck",
+ .bit_shift = 24,
+ .max_div = 63,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m6_ck = {
+ .name = "dpll4_m6_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m6_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_m6x2_mul_ck_data = {
+ .parent = "dpll4_m6_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll4_m6x2_mul_ck = {
+ .name = "dpll4_m6x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m6x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m6x2_ck_data = {
+ .parent = "dpll4_m6x2_mul_ck",
+ .bit_shift = 0x1f,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m6x2_ck = {
+ .name = "dpll4_m6x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m6x2_ck_data,
+};
+
+static struct ti_clk_fixed_factor emu_per_alwon_ck_data = {
+ .parent = "dpll4_m6x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk emu_per_alwon_ck = {
+ .name = "emu_per_alwon_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &emu_per_alwon_ck_data,
+};
+
+static struct ti_clk_fixed_factor emu_mpu_alwon_ck_data = {
+ .parent = "mpu_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk emu_mpu_alwon_ck = {
+ .name = "emu_mpu_alwon_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &emu_mpu_alwon_ck_data,
+};
+
+static const char *emu_src_mux_ck_parents[] = {
+ "sys_ck",
+ "emu_core_alwon_ck",
+ "emu_per_alwon_ck",
+ "emu_mpu_alwon_ck",
+};
+
+static struct ti_clk_mux emu_src_mux_ck_data = {
+ .num_parents = ARRAY_SIZE(emu_src_mux_ck_parents),
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .parents = emu_src_mux_ck_parents,
+};
+
+static struct ti_clk emu_src_mux_ck = {
+ .name = "emu_src_mux_ck",
+ .type = TI_CLK_MUX,
+ .data = &emu_src_mux_ck_data,
+};
+
+static struct ti_clk_gate emu_src_ck_data = {
+ .parent = "emu_src_mux_ck",
+ .flags = CLKF_CLKDM,
+};
+
+static struct ti_clk emu_src_ck = {
+ .name = "emu_src_ck",
+ .clkdm_name = "emu_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &emu_src_ck_data,
+};
+
+static struct ti_clk_divider atclk_fck_data = {
+ .parent = "emu_src_ck",
+ .bit_shift = 4,
+ .max_div = 3,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk atclk_fck = {
+ .name = "atclk_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &atclk_fck_data,
+};
+
+static struct ti_clk_gate ipss_ick_data = {
+ .parent = "core_l3_ick",
+ .bit_shift = 4,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_AM35XX | CLKF_INTERFACE,
+};
+
+static struct ti_clk ipss_ick = {
+ .name = "ipss_ick",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &ipss_ick_data,
+};
+
+static struct ti_clk_gate emac_ick_data = {
+ .parent = "ipss_ick",
+ .bit_shift = 1,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+ .flags = CLKF_AM35XX,
+};
+
+static struct ti_clk emac_ick = {
+ .name = "emac_ick",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &emac_ick_data,
+};
+
+static struct ti_clk_gate vpfe_ick_data = {
+ .parent = "ipss_ick",
+ .bit_shift = 2,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+ .flags = CLKF_AM35XX,
+};
+
+static struct ti_clk vpfe_ick = {
+ .name = "vpfe_ick",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &vpfe_ick_data,
+};
+
+static const char *dpll2_ck_parents[] = {
+ "sys_ck",
+ "dpll2_fck",
+};
+
+static struct ti_clk_dpll dpll2_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll2_ck_parents),
+ .control_reg = 0x4,
+ .idlest_reg = 0x24,
+ .mult_div1_reg = 0x40,
+ .autoidle_reg = 0x34,
+ .module = TI_CLKM_CM,
+ .parents = dpll2_ck_parents,
+ .freqsel_mask = 0xf0,
+ .modes = 0xa2,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x1,
+ .auto_recal_bit = 0x3,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x8,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x7,
+ .mult_mask = 0x7ff00,
+ .recal_st_bit = 0x8,
+ .autoidle_mask = 0x7,
+};
+
+static struct ti_clk dpll2_ck = {
+ .name = "dpll2_ck",
+ .clkdm_name = "dpll2_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll2_ck_data,
+};
+
+static struct ti_clk_divider dpll2_m2_ck_data = {
+ .parent = "dpll2_ck",
+ .max_div = 31,
+ .reg = 0x44,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll2_m2_ck = {
+ .name = "dpll2_m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll2_m2_ck_data,
+};
+
+static const char *mcbsp4_mux_fck_parents[] = {
+ "per_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp4_mux_fck_data = {
+ .bit_shift = 2,
+ .num_parents = ARRAY_SIZE(mcbsp4_mux_fck_parents),
+ .reg = 0x2d8,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp4_mux_fck_parents,
+};
+
+static const char *mcbsp1_mux_fck_parents[] = {
+ "core_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp1_mux_fck_data = {
+ .bit_shift = 2,
+ .num_parents = ARRAY_SIZE(mcbsp1_mux_fck_parents),
+ .reg = 0x274,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp1_mux_fck_parents,
+};
+
+static struct ti_clk_gate gpt8_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 9,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate gpt8_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 9,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt8_ick = {
+ .name = "gpt8_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt8_ick_data,
+};
+
+static const char *gpt10_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt10_mux_fck_data = {
+ .bit_shift = 6,
+ .num_parents = ARRAY_SIZE(gpt10_mux_fck_parents),
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .parents = gpt10_mux_fck_parents,
+};
+
+static struct ti_clk_gate mmchs3_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 30,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mmchs3_ick = {
+ .name = "mmchs3_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs3_ick_data,
+};
+
+static struct ti_clk_gate gpio3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 14,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio3_ick = {
+ .name = "gpio3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio3_ick_data,
+};
+
+static const char *traceclk_src_fck_parents[] = {
+ "sys_ck",
+ "emu_core_alwon_ck",
+ "emu_per_alwon_ck",
+ "emu_mpu_alwon_ck",
+};
+
+static struct ti_clk_mux traceclk_src_fck_data = {
+ .bit_shift = 2,
+ .num_parents = ARRAY_SIZE(traceclk_src_fck_parents),
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .parents = traceclk_src_fck_parents,
+};
+
+static struct ti_clk traceclk_src_fck = {
+ .name = "traceclk_src_fck",
+ .type = TI_CLK_MUX,
+ .data = &traceclk_src_fck_data,
+};
+
+static struct ti_clk_divider traceclk_fck_data = {
+ .parent = "traceclk_src_fck",
+ .bit_shift = 11,
+ .max_div = 7,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk traceclk_fck = {
+ .name = "traceclk_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &traceclk_fck_data,
+};
+
+static struct ti_clk_gate mcbsp5_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 10,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate sad2d_ick_data = {
+ .parent = "l3_ick",
+ .bit_shift = 3,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk sad2d_ick = {
+ .name = "sad2d_ick",
+ .clkdm_name = "d2d_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sad2d_ick_data,
+};
+
+static const char *gpt1_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt1_mux_fck_data = {
+ .num_parents = ARRAY_SIZE(gpt1_mux_fck_parents),
+ .reg = 0xc40,
+ .module = TI_CLKM_CM,
+ .parents = gpt1_mux_fck_parents,
+};
+
+static struct ti_clk_gate hecc_ck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 3,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+ .flags = CLKF_AM35XX,
+};
+
+static struct ti_clk hecc_ck = {
+ .name = "hecc_ck",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hecc_ck_data,
+};
+
+static struct ti_clk_gate gpt1_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 0,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite gpt1_fck_data = {
+ .mux = &gpt1_mux_fck_data,
+ .gate = &gpt1_gate_fck_data,
+};
+
+static struct ti_clk gpt1_fck = {
+ .name = "gpt1_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt1_fck_data,
+};
+
+static struct ti_clk_gate dpll4_m2x2_ck_omap36xx_data = {
+ .parent = "dpll4_m2x2_mul_ck",
+ .bit_shift = 0x1b,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m2x2_ck_omap36xx = {
+ .name = "dpll4_m2x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m2x2_ck_omap36xx_data,
+ .patch = &dpll4_m2x2_ck,
+};
+
+static struct ti_clk_divider gfx_l3_fck_data = {
+ .parent = "l3_ick",
+ .max_div = 7,
+ .reg = 0xb40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk gfx_l3_fck = {
+ .name = "gfx_l3_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &gfx_l3_fck_data,
+};
+
+static struct ti_clk_gate gfx_cg1_ck_data = {
+ .parent = "gfx_l3_fck",
+ .bit_shift = 1,
+ .reg = 0xb00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk gfx_cg1_ck = {
+ .name = "gfx_cg1_ck",
+ .clkdm_name = "gfx_3430es1_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gfx_cg1_ck_data,
+};
+
+static struct ti_clk_gate mailboxes_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 7,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mailboxes_ick = {
+ .name = "mailboxes_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mailboxes_ick_data,
+};
+
+static struct ti_clk_gate sha11_ick_data = {
+ .parent = "security_l4_ick2",
+ .bit_shift = 1,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk sha11_ick = {
+ .name = "sha11_ick",
+ .type = TI_CLK_GATE,
+ .data = &sha11_ick_data,
+};
+
+static struct ti_clk_gate hsotgusb_ick_am35xx_data = {
+ .parent = "ipss_ick",
+ .bit_shift = 0,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+ .flags = CLKF_AM35XX,
+};
+
+static struct ti_clk hsotgusb_ick_am35xx = {
+ .name = "hsotgusb_ick_am35xx",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hsotgusb_ick_am35xx_data,
+};
+
+static struct ti_clk_gate mmchs3_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 30,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mmchs3_fck = {
+ .name = "mmchs3_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs3_fck_data,
+};
+
+static struct ti_clk_divider pclk_fck_data = {
+ .parent = "emu_src_ck",
+ .bit_shift = 8,
+ .max_div = 7,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk pclk_fck = {
+ .name = "pclk_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &pclk_fck_data,
+};
+
+static const char *dpll4_ck_omap36xx_parents[] = {
+ "sys_ck",
+ "sys_ck",
+};
+
+static struct ti_clk_dpll dpll4_ck_omap36xx_data = {
+ .num_parents = ARRAY_SIZE(dpll4_ck_omap36xx_parents),
+ .control_reg = 0xd00,
+ .idlest_reg = 0xd20,
+ .mult_div1_reg = 0xd44,
+ .autoidle_reg = 0xd30,
+ .module = TI_CLKM_CM,
+ .parents = dpll4_ck_omap36xx_parents,
+ .modes = 0x82,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x2,
+ .auto_recal_bit = 0x13,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x6,
+ .max_multiplier = 0xfff,
+ .enable_mask = 0x70000,
+ .mult_mask = 0xfff00,
+ .recal_st_bit = 0x6,
+ .autoidle_mask = 0x38,
+ .sddiv_mask = 0xff000000,
+ .dco_mask = 0xe00000,
+ .flags = CLKF_PER | CLKF_J_TYPE,
+};
+
+static struct ti_clk dpll4_ck_omap36xx = {
+ .name = "dpll4_ck",
+ .type = TI_CLK_DPLL,
+ .data = &dpll4_ck_omap36xx_data,
+ .patch = &dpll4_ck,
+};
+
+static struct ti_clk_gate uart3_fck_data = {
+ .parent = "per_48m_fck",
+ .bit_shift = 11,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart3_fck = {
+ .name = "uart3_fck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart3_fck_data,
+};
+
+static struct ti_clk_fixed_factor wkup_32k_fck_data = {
+ .parent = "omap_32k_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk wkup_32k_fck = {
+ .name = "wkup_32k_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &wkup_32k_fck_data,
+};
+
+static struct ti_clk_gate sys_clkout1_data = {
+ .parent = "osc_sys_ck",
+ .bit_shift = 7,
+ .reg = 0xd70,
+ .module = TI_CLKM_PRM,
+};
+
+static struct ti_clk sys_clkout1 = {
+ .name = "sys_clkout1",
+ .type = TI_CLK_GATE,
+ .data = &sys_clkout1_data,
+};
+
+static struct ti_clk_fixed_factor gpmc_fck_data = {
+ .parent = "core_l3_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk gpmc_fck = {
+ .name = "gpmc_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &gpmc_fck_data,
+};
+
+static struct ti_clk_fixed_factor dpll5_m2_d20_ck_data = {
+ .parent = "dpll5_m2_ck",
+ .div = 20,
+ .mult = 1,
+};
+
+static struct ti_clk dpll5_m2_d20_ck = {
+ .name = "dpll5_m2_d20_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll5_m2_d20_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m5x2_ck_omap36xx_data = {
+ .parent = "dpll4_m5x2_mul_ck",
+ .bit_shift = 0x1e,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_RATE_PARENT | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m5x2_ck_omap36xx = {
+ .name = "dpll4_m5x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m5x2_ck_omap36xx_data,
+ .patch = &dpll4_m5x2_ck,
+};
+
+static struct ti_clk_gate ssi_ssr_gate_fck_3430es2_data = {
+ .parent = "corex2_fck",
+ .bit_shift = 0,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_NO_WAIT,
+};
+
+static struct ti_clk_gate uart1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 13,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart1_ick = {
+ .name = "uart1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart1_ick_data,
+};
+
+static struct ti_clk_gate iva2_ck_data = {
+ .parent = "dpll2_m2_ck",
+ .bit_shift = 0,
+ .reg = 0x0,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk iva2_ck = {
+ .name = "iva2_ck",
+ .clkdm_name = "iva2_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &iva2_ck_data,
+};
+
+static struct ti_clk_gate pka_ick_data = {
+ .parent = "security_l3_ick",
+ .bit_shift = 4,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk pka_ick = {
+ .name = "pka_ick",
+ .type = TI_CLK_GATE,
+ .data = &pka_ick_data,
+};
+
+static struct ti_clk_gate gpt12_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 1,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt12_ick = {
+ .name = "gpt12_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt12_ick_data,
+};
+
+static const char *mcbsp5_mux_fck_parents[] = {
+ "core_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp5_mux_fck_data = {
+ .bit_shift = 4,
+ .num_parents = ARRAY_SIZE(mcbsp5_mux_fck_parents),
+ .reg = 0x2d8,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp5_mux_fck_parents,
+};
+
+static struct ti_clk_composite mcbsp5_fck_data = {
+ .mux = &mcbsp5_mux_fck_data,
+ .gate = &mcbsp5_gate_fck_data,
+};
+
+static struct ti_clk mcbsp5_fck = {
+ .name = "mcbsp5_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp5_fck_data,
+};
+
+static struct ti_clk_gate usbhost_48m_fck_data = {
+ .parent = "omap_48m_fck",
+ .bit_shift = 0,
+ .reg = 0x1400,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_DSS,
+};
+
+static struct ti_clk usbhost_48m_fck = {
+ .name = "usbhost_48m_fck",
+ .clkdm_name = "usbhost_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbhost_48m_fck_data,
+};
+
+static struct ti_clk_gate des1_ick_data = {
+ .parent = "security_l4_ick2",
+ .bit_shift = 0,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk des1_ick = {
+ .name = "des1_ick",
+ .type = TI_CLK_GATE,
+ .data = &des1_ick_data,
+};
+
+static struct ti_clk_gate sgx_gate_fck_data = {
+ .parent = "core_ck",
+ .bit_shift = 1,
+ .reg = 0xb00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_fixed_factor core_d4_ck_data = {
+ .parent = "core_ck",
+ .div = 4,
+ .mult = 1,
+};
+
+static struct ti_clk core_d4_ck = {
+ .name = "core_d4_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_d4_ck_data,
+};
+
+static struct ti_clk_fixed_factor omap_192m_alwon_fck_data = {
+ .parent = "dpll4_m2x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk omap_192m_alwon_fck = {
+ .name = "omap_192m_alwon_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_192m_alwon_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_d2_ck_data = {
+ .parent = "core_ck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk core_d2_ck = {
+ .name = "core_d2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_d2_ck_data,
+};
+
+static struct ti_clk_fixed_factor corex2_d3_fck_data = {
+ .parent = "corex2_fck",
+ .div = 3,
+ .mult = 1,
+};
+
+static struct ti_clk corex2_d3_fck = {
+ .name = "corex2_d3_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &corex2_d3_fck_data,
+};
+
+static struct ti_clk_fixed_factor corex2_d5_fck_data = {
+ .parent = "corex2_fck",
+ .div = 5,
+ .mult = 1,
+};
+
+static struct ti_clk corex2_d5_fck = {
+ .name = "corex2_d5_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &corex2_d5_fck_data,
+};
+
+static const char *sgx_mux_fck_parents[] = {
+ "core_d3_ck",
+ "core_d4_ck",
+ "core_d6_ck",
+ "cm_96m_fck",
+ "omap_192m_alwon_fck",
+ "core_d2_ck",
+ "corex2_d3_fck",
+ "corex2_d5_fck",
+};
+
+static struct ti_clk_mux sgx_mux_fck_data = {
+ .num_parents = ARRAY_SIZE(sgx_mux_fck_parents),
+ .reg = 0xb40,
+ .module = TI_CLKM_CM,
+ .parents = sgx_mux_fck_parents,
+};
+
+static struct ti_clk_composite sgx_fck_data = {
+ .mux = &sgx_mux_fck_data,
+ .gate = &sgx_gate_fck_data,
+};
+
+static struct ti_clk sgx_fck = {
+ .name = "sgx_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &sgx_fck_data,
+};
+
+static struct ti_clk_gate mcspi1_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 18,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mcspi1_fck = {
+ .name = "mcspi1_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi1_fck_data,
+};
+
+static struct ti_clk_gate mmchs2_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 25,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mmchs2_fck = {
+ .name = "mmchs2_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs2_fck_data,
+};
+
+static struct ti_clk_gate mcspi2_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 19,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mcspi2_fck = {
+ .name = "mcspi2_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi2_fck_data,
+};
+
+static struct ti_clk_gate vpfe_fck_data = {
+ .parent = "pclk_ck",
+ .bit_shift = 10,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+};
+
+static struct ti_clk vpfe_fck = {
+ .name = "vpfe_fck",
+ .type = TI_CLK_GATE,
+ .data = &vpfe_fck_data,
+};
+
+static struct ti_clk_gate gpt4_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 5,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate mcbsp1_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 9,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate gpt5_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 6,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt5_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt5_mux_fck_data = {
+ .bit_shift = 3,
+ .num_parents = ARRAY_SIZE(gpt5_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt5_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt5_fck_data = {
+ .mux = &gpt5_mux_fck_data,
+ .gate = &gpt5_gate_fck_data,
+};
+
+static struct ti_clk gpt5_fck = {
+ .name = "gpt5_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt5_fck_data,
+};
+
+static struct ti_clk_gate ts_fck_data = {
+ .parent = "omap_32k_fck",
+ .bit_shift = 1,
+ .reg = 0xa08,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk ts_fck = {
+ .name = "ts_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &ts_fck_data,
+};
+
+static struct ti_clk_fixed_factor wdt1_fck_data = {
+ .parent = "secure_32k_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk wdt1_fck = {
+ .name = "wdt1_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &wdt1_fck_data,
+};
+
+static struct ti_clk_gate dpll4_m6x2_ck_omap36xx_data = {
+ .parent = "dpll4_m6x2_mul_ck",
+ .bit_shift = 0x1f,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m6x2_ck_omap36xx = {
+ .name = "dpll4_m6x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m6x2_ck_omap36xx_data,
+ .patch = &dpll4_m6x2_ck,
+};
+
+static const char *gpt4_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt4_mux_fck_data = {
+ .bit_shift = 2,
+ .num_parents = ARRAY_SIZE(gpt4_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt4_mux_fck_parents,
+};
+
+static struct ti_clk_gate usbhost_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 0,
+ .reg = 0x1410,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_DSS | CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk usbhost_ick = {
+ .name = "usbhost_ick",
+ .clkdm_name = "usbhost_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbhost_ick_data,
+};
+
+static struct ti_clk_gate mcbsp2_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 0,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp2_ick = {
+ .name = "mcbsp2_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp2_ick_data,
+};
+
+static struct ti_clk_gate omapctrl_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 6,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk omapctrl_ick = {
+ .name = "omapctrl_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &omapctrl_ick_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_d4_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 4,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_d4_fck = {
+ .name = "omap_96m_d4_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_d4_fck_data,
+};
+
+static struct ti_clk_gate gpt6_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 7,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt6_ick = {
+ .name = "gpt6_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt6_ick_data,
+};
+
+static struct ti_clk_gate dpll3_m3x2_ck_omap36xx_data = {
+ .parent = "dpll3_m3x2_mul_ck",
+ .bit_shift = 0xc,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll3_m3x2_ck_omap36xx = {
+ .name = "dpll3_m3x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll3_m3x2_ck_omap36xx_data,
+ .patch = &dpll3_m3x2_ck,
+};
+
+static struct ti_clk_gate i2c3_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 17,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk i2c3_ick = {
+ .name = "i2c3_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c3_ick_data,
+};
+
+static struct ti_clk_gate gpio6_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 17,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio6_ick = {
+ .name = "gpio6_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio6_ick_data,
+};
+
+static struct ti_clk_gate mspro_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 23,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mspro_ick = {
+ .name = "mspro_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mspro_ick_data,
+};
+
+static struct ti_clk_composite mcbsp1_fck_data = {
+ .mux = &mcbsp1_mux_fck_data,
+ .gate = &mcbsp1_gate_fck_data,
+};
+
+static struct ti_clk mcbsp1_fck = {
+ .name = "mcbsp1_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp1_fck_data,
+};
+
+static struct ti_clk_gate gpt3_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 4,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_fixed rmii_ck_data = {
+ .frequency = 50000000,
+};
+
+static struct ti_clk rmii_ck = {
+ .name = "rmii_ck",
+ .type = TI_CLK_FIXED,
+ .data = &rmii_ck_data,
+};
+
+static struct ti_clk_gate gpt6_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 7,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite gpt6_fck_data = {
+ .mux = &gpt6_mux_fck_data,
+ .gate = &gpt6_gate_fck_data,
+};
+
+static struct ti_clk gpt6_fck = {
+ .name = "gpt6_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt6_fck_data,
+};
+
+static struct ti_clk_fixed_factor dpll5_m2_d4_ck_data = {
+ .parent = "dpll5_m2_ck",
+ .div = 4,
+ .mult = 1,
+};
+
+static struct ti_clk dpll5_m2_d4_ck = {
+ .name = "dpll5_m2_d4_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll5_m2_d4_ck_data,
+};
+
+static struct ti_clk_fixed_factor sys_d2_ck_data = {
+ .parent = "sys_ck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk sys_d2_ck = {
+ .name = "sys_d2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &sys_d2_ck_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_d2_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_d2_fck = {
+ .name = "omap_96m_d2_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_d2_fck_data,
+};
+
+static struct ti_clk_fixed_factor dpll5_m2_d8_ck_data = {
+ .parent = "dpll5_m2_ck",
+ .div = 8,
+ .mult = 1,
+};
+
+static struct ti_clk dpll5_m2_d8_ck = {
+ .name = "dpll5_m2_d8_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll5_m2_d8_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll5_m2_d16_ck_data = {
+ .parent = "dpll5_m2_ck",
+ .div = 16,
+ .mult = 1,
+};
+
+static struct ti_clk dpll5_m2_d16_ck = {
+ .name = "dpll5_m2_d16_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll5_m2_d16_ck_data,
+};
+
+static const char *usim_mux_fck_parents[] = {
+ "sys_ck",
+ "sys_d2_ck",
+ "omap_96m_d2_fck",
+ "omap_96m_d4_fck",
+ "omap_96m_d8_fck",
+ "omap_96m_d10_fck",
+ "dpll5_m2_d4_ck",
+ "dpll5_m2_d8_ck",
+ "dpll5_m2_d16_ck",
+ "dpll5_m2_d20_ck",
+};
+
+static struct ti_clk_mux usim_mux_fck_data = {
+ .bit_shift = 3,
+ .num_parents = ARRAY_SIZE(usim_mux_fck_parents),
+ .reg = 0xc40,
+ .module = TI_CLKM_CM,
+ .parents = usim_mux_fck_parents,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk_composite usim_fck_data = {
+ .mux = &usim_mux_fck_data,
+ .gate = &usim_gate_fck_data,
+};
+
+static struct ti_clk usim_fck = {
+ .name = "usim_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &usim_fck_data,
+};
+
+static int ssi_ssr_div_fck_3430es2_divs[] = {
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 0,
+ 6,
+ 0,
+ 8,
+};
+
+static struct ti_clk_divider ssi_ssr_div_fck_3430es2_data = {
+ .num_dividers = ARRAY_SIZE(ssi_ssr_div_fck_3430es2_divs),
+ .parent = "corex2_fck",
+ .bit_shift = 8,
+ .dividers = ssi_ssr_div_fck_3430es2_divs,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite ssi_ssr_fck_3430es2_data = {
+ .gate = &ssi_ssr_gate_fck_3430es2_data,
+ .divider = &ssi_ssr_div_fck_3430es2_data,
+};
+
+static struct ti_clk ssi_ssr_fck_3430es2 = {
+ .name = "ssi_ssr_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &ssi_ssr_fck_3430es2_data,
+};
+
+static struct ti_clk_gate dss1_alwon_fck_3430es1_data = {
+ .parent = "dpll4_m4x2_ck",
+ .bit_shift = 0,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk dss1_alwon_fck_3430es1 = {
+ .name = "dss1_alwon_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss1_alwon_fck_3430es1_data,
+};
+
+static struct ti_clk_gate gpt3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 4,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt3_ick = {
+ .name = "gpt3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt3_ick_data,
+};
+
+static struct ti_clk_fixed_factor omap_12m_fck_data = {
+ .parent = "omap_48m_fck",
+ .div = 4,
+ .mult = 1,
+};
+
+static struct ti_clk omap_12m_fck = {
+ .name = "omap_12m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_12m_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_12m_fck_data = {
+ .parent = "omap_12m_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_12m_fck = {
+ .name = "core_12m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_12m_fck_data,
+};
+
+static struct ti_clk_gate hdq_fck_data = {
+ .parent = "core_12m_fck",
+ .bit_shift = 22,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk hdq_fck = {
+ .name = "hdq_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hdq_fck_data,
+};
+
+static struct ti_clk_gate usbtll_fck_data = {
+ .parent = "dpll5_m2_ck",
+ .bit_shift = 2,
+ .reg = 0xa08,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk usbtll_fck = {
+ .name = "usbtll_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbtll_fck_data,
+};
+
+static struct ti_clk_gate hsotgusb_fck_am35xx_data = {
+ .parent = "sys_ck",
+ .bit_shift = 8,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+};
+
+static struct ti_clk hsotgusb_fck_am35xx = {
+ .name = "hsotgusb_fck_am35xx",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hsotgusb_fck_am35xx_data,
+};
+
+static struct ti_clk_gate hsotgusb_ick_3430es2_data = {
+ .parent = "core_l3_ick",
+ .bit_shift = 4,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSOTGUSB | CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk hsotgusb_ick_3430es2 = {
+ .name = "hsotgusb_ick_3430es2",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hsotgusb_ick_3430es2_data,
+};
+
+static struct ti_clk_gate gfx_l3_ck_data = {
+ .parent = "l3_ick",
+ .bit_shift = 0,
+ .reg = 0xb10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk gfx_l3_ck = {
+ .name = "gfx_l3_ck",
+ .clkdm_name = "gfx_3430es1_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gfx_l3_ck_data,
+};
+
+static struct ti_clk_fixed_factor gfx_l3_ick_data = {
+ .parent = "gfx_l3_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk gfx_l3_ick = {
+ .name = "gfx_l3_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &gfx_l3_ick_data,
+};
+
+static struct ti_clk_gate mcbsp1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 9,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp1_ick = {
+ .name = "mcbsp1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp1_ick_data,
+};
+
+static struct ti_clk_fixed_factor gpt12_fck_data = {
+ .parent = "secure_32k_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk gpt12_fck = {
+ .name = "gpt12_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &gpt12_fck_data,
+};
+
+static struct ti_clk_gate gfx_cg2_ck_data = {
+ .parent = "gfx_l3_fck",
+ .bit_shift = 2,
+ .reg = 0xb00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk gfx_cg2_ck = {
+ .name = "gfx_cg2_ck",
+ .clkdm_name = "gfx_3430es1_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gfx_cg2_ck_data,
+};
+
+static struct ti_clk_gate i2c2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 16,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk i2c2_ick = {
+ .name = "i2c2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c2_ick_data,
+};
+
+static struct ti_clk_gate gpio4_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 15,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio4_dbck = {
+ .name = "gpio4_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio4_dbck_data,
+};
+
+static struct ti_clk_gate i2c3_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 17,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk i2c3_fck = {
+ .name = "i2c3_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c3_fck_data,
+};
+
+static struct ti_clk_composite gpt3_fck_data = {
+ .mux = &gpt3_mux_fck_data,
+ .gate = &gpt3_gate_fck_data,
+};
+
+static struct ti_clk gpt3_fck = {
+ .name = "gpt3_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt3_fck_data,
+};
+
+static struct ti_clk_gate i2c1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 15,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk i2c1_ick = {
+ .name = "i2c1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c1_ick_data,
+};
+
+static struct ti_clk_gate omap_32ksync_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 2,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk omap_32ksync_ick = {
+ .name = "omap_32ksync_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &omap_32ksync_ick_data,
+};
+
+static struct ti_clk_gate aes2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 28,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk aes2_ick = {
+ .name = "aes2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &aes2_ick_data,
+};
+
+static const char *gpt8_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt8_mux_fck_data = {
+ .bit_shift = 6,
+ .num_parents = ARRAY_SIZE(gpt8_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt8_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt8_fck_data = {
+ .mux = &gpt8_mux_fck_data,
+ .gate = &gpt8_gate_fck_data,
+};
+
+static struct ti_clk gpt8_fck = {
+ .name = "gpt8_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt8_fck_data,
+};
+
+static struct ti_clk_gate mcbsp4_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 2,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite mcbsp4_fck_data = {
+ .mux = &mcbsp4_mux_fck_data,
+ .gate = &mcbsp4_gate_fck_data,
+};
+
+static struct ti_clk mcbsp4_fck = {
+ .name = "mcbsp4_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp4_fck_data,
+};
+
+static struct ti_clk_gate gpio2_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 13,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio2_dbck = {
+ .name = "gpio2_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio2_dbck_data,
+};
+
+static struct ti_clk_gate usbtll_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 2,
+ .reg = 0xa18,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk usbtll_ick = {
+ .name = "usbtll_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbtll_ick_data,
+};
+
+static struct ti_clk_gate mcspi4_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 21,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcspi4_ick = {
+ .name = "mcspi4_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi4_ick_data,
+};
+
+static struct ti_clk_gate dss_96m_fck_data = {
+ .parent = "omap_96m_fck",
+ .bit_shift = 2,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk dss_96m_fck = {
+ .name = "dss_96m_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss_96m_fck_data,
+};
+
+static struct ti_clk_divider rm_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 1,
+ .max_div = 3,
+ .reg = 0xc40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk rm_ick = {
+ .name = "rm_ick",
+ .type = TI_CLK_DIVIDER,
+ .data = &rm_ick_data,
+};
+
+static struct ti_clk_gate hdq_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 22,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk hdq_ick = {
+ .name = "hdq_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hdq_ick_data,
+};
+
+static struct ti_clk_fixed_factor dpll3_x2_ck_data = {
+ .parent = "dpll3_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll3_x2_ck = {
+ .name = "dpll3_x2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll3_x2_ck_data,
+};
+
+static struct ti_clk_gate mad2d_ick_data = {
+ .parent = "l3_ick",
+ .bit_shift = 3,
+ .reg = 0xa18,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mad2d_ick = {
+ .name = "mad2d_ick",
+ .clkdm_name = "d2d_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mad2d_ick_data,
+};
+
+static struct ti_clk_gate fshostusb_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 5,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk fshostusb_fck = {
+ .name = "fshostusb_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &fshostusb_fck_data,
+};
+
+static struct ti_clk_gate sr1_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 6,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk sr1_fck = {
+ .name = "sr1_fck",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sr1_fck_data,
+};
+
+static struct ti_clk_gate des2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 26,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk des2_ick = {
+ .name = "des2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &des2_ick_data,
+};
+
+static struct ti_clk_gate sdrc_ick_data = {
+ .parent = "core_l3_ick",
+ .bit_shift = 1,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk sdrc_ick = {
+ .name = "sdrc_ick",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sdrc_ick_data,
+};
+
+static struct ti_clk_composite gpt4_fck_data = {
+ .mux = &gpt4_mux_fck_data,
+ .gate = &gpt4_gate_fck_data,
+};
+
+static struct ti_clk gpt4_fck = {
+ .name = "gpt4_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt4_fck_data,
+};
+
+static struct ti_clk_gate dpll4_m3x2_ck_omap36xx_data = {
+ .parent = "dpll4_m3x2_mul_ck",
+ .bit_shift = 0x1c,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m3x2_ck_omap36xx = {
+ .name = "dpll4_m3x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m3x2_ck_omap36xx_data,
+ .patch = &dpll4_m3x2_ck,
+};
+
+static struct ti_clk_gate cpefuse_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 0,
+ .reg = 0xa08,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk cpefuse_fck = {
+ .name = "cpefuse_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &cpefuse_fck_data,
+};
+
+static struct ti_clk_gate mcspi3_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 20,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcspi3_ick = {
+ .name = "mcspi3_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi3_ick_data,
+};
+
+static struct ti_clk_fixed_factor ssi_sst_fck_3430es2_data = {
+ .parent = "ssi_ssr_fck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk ssi_sst_fck_3430es2 = {
+ .name = "ssi_sst_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &ssi_sst_fck_3430es2_data,
+};
+
+static struct ti_clk_gate gpio1_dbck_data = {
+ .parent = "wkup_32k_fck",
+ .bit_shift = 3,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio1_dbck = {
+ .name = "gpio1_dbck",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio1_dbck_data,
+};
+
+static struct ti_clk_gate gpt4_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 5,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt4_ick = {
+ .name = "gpt4_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt4_ick_data,
+};
+
+static struct ti_clk_gate gpt2_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 3,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt2_ick = {
+ .name = "gpt2_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt2_ick_data,
+};
+
+static struct ti_clk_gate mmchs1_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 24,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mmchs1_fck = {
+ .name = "mmchs1_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs1_fck_data,
+};
+
+static struct ti_clk_fixed dummy_apb_pclk_data = {
+ .frequency = 0x0,
+};
+
+static struct ti_clk dummy_apb_pclk = {
+ .name = "dummy_apb_pclk",
+ .type = TI_CLK_FIXED,
+ .data = &dummy_apb_pclk_data,
+};
+
+static struct ti_clk_gate gpio6_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 17,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio6_dbck = {
+ .name = "gpio6_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio6_dbck_data,
+};
+
+static struct ti_clk_gate uart2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 14,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart2_ick = {
+ .name = "uart2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart2_ick_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_x2_ck_data = {
+ .parent = "dpll4_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll4_x2_ck = {
+ .name = "dpll4_x2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_x2_ck_data,
+};
+
+static struct ti_clk_gate gpt7_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 8,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt7_ick = {
+ .name = "gpt7_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt7_ick_data,
+};
+
+static struct ti_clk_gate dss_tv_fck_data = {
+ .parent = "omap_54m_fck",
+ .bit_shift = 2,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk dss_tv_fck = {
+ .name = "dss_tv_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss_tv_fck_data,
+};
+
+static struct ti_clk_gate mcbsp5_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 10,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp5_ick = {
+ .name = "mcbsp5_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp5_ick_data,
+};
+
+static struct ti_clk_gate mcspi1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 18,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcspi1_ick = {
+ .name = "mcspi1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi1_ick_data,
+};
+
+static struct ti_clk_gate d2d_26m_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 3,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk d2d_26m_fck = {
+ .name = "d2d_26m_fck",
+ .clkdm_name = "d2d_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &d2d_26m_fck_data,
+};
+
+static struct ti_clk_gate wdt3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 12,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk wdt3_ick = {
+ .name = "wdt3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt3_ick_data,
+};
+
+static struct ti_clk_divider pclkx2_fck_data = {
+ .parent = "emu_src_ck",
+ .bit_shift = 6,
+ .max_div = 3,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk pclkx2_fck = {
+ .name = "pclkx2_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &pclkx2_fck_data,
+};
+
+static struct ti_clk_gate sha12_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 27,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk sha12_ick = {
+ .name = "sha12_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sha12_ick_data,
+};
+
+static struct ti_clk_gate emac_fck_data = {
+ .parent = "rmii_ck",
+ .bit_shift = 9,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+};
+
+static struct ti_clk emac_fck = {
+ .name = "emac_fck",
+ .type = TI_CLK_GATE,
+ .data = &emac_fck_data,
+};
+
+static struct ti_clk_composite gpt10_fck_data = {
+ .mux = &gpt10_mux_fck_data,
+ .gate = &gpt10_gate_fck_data,
+};
+
+static struct ti_clk gpt10_fck = {
+ .name = "gpt10_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt10_fck_data,
+};
+
+static struct ti_clk_gate wdt2_fck_data = {
+ .parent = "wkup_32k_fck",
+ .bit_shift = 5,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk wdt2_fck = {
+ .name = "wdt2_fck",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt2_fck_data,
+};
+
+static struct ti_clk_gate cam_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 0,
+ .reg = 0xf10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE,
+};
+
+static struct ti_clk cam_ick = {
+ .name = "cam_ick",
+ .clkdm_name = "cam_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &cam_ick_data,
+};
+
+static struct ti_clk_gate ssi_ick_3430es2_data = {
+ .parent = "ssi_l4_ick",
+ .bit_shift = 0,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SSI | CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk ssi_ick_3430es2 = {
+ .name = "ssi_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &ssi_ick_3430es2_data,
+};
+
+static struct ti_clk_gate gpio4_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 15,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio4_ick = {
+ .name = "gpio4_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio4_ick_data,
+};
+
+static struct ti_clk_gate wdt1_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 4,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk wdt1_ick = {
+ .name = "wdt1_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt1_ick_data,
+};
+
+static struct ti_clk_gate rng_ick_data = {
+ .parent = "security_l4_ick2",
+ .bit_shift = 2,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk rng_ick = {
+ .name = "rng_ick",
+ .type = TI_CLK_GATE,
+ .data = &rng_ick_data,
+};
+
+static struct ti_clk_gate icr_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 29,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk icr_ick = {
+ .name = "icr_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &icr_ick_data,
+};
+
+static struct ti_clk_gate sgx_ick_data = {
+ .parent = "l3_ick",
+ .bit_shift = 0,
+ .reg = 0xb10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk sgx_ick = {
+ .name = "sgx_ick",
+ .clkdm_name = "sgx_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sgx_ick_data,
+};
+
+static struct ti_clk_divider sys_clkout2_data = {
+ .parent = "clkout2_src_ck",
+ .bit_shift = 3,
+ .max_div = 64,
+ .reg = 0xd70,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_POWER_OF_TWO,
+};
+
+static struct ti_clk sys_clkout2 = {
+ .name = "sys_clkout2",
+ .type = TI_CLK_DIVIDER,
+ .data = &sys_clkout2_data,
+};
+
+static struct ti_clk_alias omap34xx_omap36xx_clks[] = {
+ CLK(NULL, "security_l4_ick2", &security_l4_ick2),
+ CLK(NULL, "aes1_ick", &aes1_ick),
+ CLK("omap_rng", "ick", &rng_ick),
+ CLK("omap3-rom-rng", "ick", &rng_ick),
+ CLK(NULL, "sha11_ick", &sha11_ick),
+ CLK(NULL, "des1_ick", &des1_ick),
+ CLK(NULL, "cam_mclk", &cam_mclk),
+ CLK(NULL, "cam_ick", &cam_ick),
+ CLK(NULL, "csi2_96m_fck", &csi2_96m_fck),
+ CLK(NULL, "security_l3_ick", &security_l3_ick),
+ CLK(NULL, "pka_ick", &pka_ick),
+ CLK(NULL, "icr_ick", &icr_ick),
+ CLK(NULL, "des2_ick", &des2_ick),
+ CLK(NULL, "mspro_ick", &mspro_ick),
+ CLK(NULL, "mailboxes_ick", &mailboxes_ick),
+ CLK(NULL, "ssi_l4_ick", &ssi_l4_ick),
+ CLK(NULL, "sr1_fck", &sr1_fck),
+ CLK(NULL, "sr2_fck", &sr2_fck),
+ CLK(NULL, "sr_l4_ick", &sr_l4_ick),
+ CLK(NULL, "dpll2_fck", &dpll2_fck),
+ CLK(NULL, "dpll2_ck", &dpll2_ck),
+ CLK(NULL, "dpll2_m2_ck", &dpll2_m2_ck),
+ CLK(NULL, "iva2_ck", &iva2_ck),
+ CLK(NULL, "modem_fck", &modem_fck),
+ CLK(NULL, "sad2d_ick", &sad2d_ick),
+ CLK(NULL, "mad2d_ick", &mad2d_ick),
+ CLK(NULL, "mspro_fck", &mspro_fck),
+ { NULL },
+};
+
+static struct ti_clk_alias omap36xx_omap3430es2plus_clks[] = {
+ CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es2),
+ CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es2),
+ CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es2),
+ CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_3430es2),
+ CLK(NULL, "ssi_ick", &ssi_ick_3430es2),
+ CLK(NULL, "sys_d2_ck", &sys_d2_ck),
+ CLK(NULL, "omap_96m_d2_fck", &omap_96m_d2_fck),
+ CLK(NULL, "omap_96m_d4_fck", &omap_96m_d4_fck),
+ CLK(NULL, "omap_96m_d8_fck", &omap_96m_d8_fck),
+ CLK(NULL, "omap_96m_d10_fck", &omap_96m_d10_fck),
+ CLK(NULL, "dpll5_m2_d4_ck", &dpll5_m2_d4_ck),
+ CLK(NULL, "dpll5_m2_d8_ck", &dpll5_m2_d8_ck),
+ CLK(NULL, "dpll5_m2_d16_ck", &dpll5_m2_d16_ck),
+ CLK(NULL, "dpll5_m2_d20_ck", &dpll5_m2_d20_ck),
+ CLK(NULL, "usim_fck", &usim_fck),
+ CLK(NULL, "usim_ick", &usim_ick),
+ { NULL },
+};
+
+static struct ti_clk_alias omap3xxx_clks[] = {
+ CLK(NULL, "apb_pclk", &dummy_apb_pclk),
+ CLK(NULL, "omap_32k_fck", &omap_32k_fck),
+ CLK(NULL, "virt_12m_ck", &virt_12m_ck),
+ CLK(NULL, "virt_13m_ck", &virt_13m_ck),
+ CLK(NULL, "virt_19200000_ck", &virt_19200000_ck),
+ CLK(NULL, "virt_26000000_ck", &virt_26000000_ck),
+ CLK(NULL, "virt_38_4m_ck", &virt_38_4m_ck),
+ CLK(NULL, "virt_16_8m_ck", &virt_16_8m_ck),
+ CLK(NULL, "osc_sys_ck", &osc_sys_ck),
+ CLK("twl", "fck", &osc_sys_ck),
+ CLK(NULL, "sys_ck", &sys_ck),
+ CLK(NULL, "timer_sys_ck", &sys_ck),
+ CLK(NULL, "dpll4_ck", &dpll4_ck),
+ CLK(NULL, "dpll4_m2_ck", &dpll4_m2_ck),
+ CLK(NULL, "dpll4_m2x2_mul_ck", &dpll4_m2x2_mul_ck),
+ CLK(NULL, "dpll4_m2x2_ck", &dpll4_m2x2_ck),
+ CLK(NULL, "omap_96m_alwon_fck", &omap_96m_alwon_fck),
+ CLK(NULL, "dpll3_ck", &dpll3_ck),
+ CLK(NULL, "dpll3_m3_ck", &dpll3_m3_ck),
+ CLK(NULL, "dpll3_m3x2_mul_ck", &dpll3_m3x2_mul_ck),
+ CLK(NULL, "dpll3_m3x2_ck", &dpll3_m3x2_ck),
+ CLK("etb", "emu_core_alwon_ck", &emu_core_alwon_ck),
+ CLK(NULL, "sys_altclk", &sys_altclk),
+ CLK(NULL, "mcbsp_clks", &mcbsp_clks),
+ CLK(NULL, "sys_clkout1", &sys_clkout1),
+ CLK(NULL, "dpll3_m2_ck", &dpll3_m2_ck),
+ CLK(NULL, "core_ck", &core_ck),
+ CLK(NULL, "dpll1_fck", &dpll1_fck),
+ CLK(NULL, "dpll1_ck", &dpll1_ck),
+ CLK(NULL, "cpufreq_ck", &dpll1_ck),
+ CLK(NULL, "dpll1_x2_ck", &dpll1_x2_ck),
+ CLK(NULL, "dpll1_x2m2_ck", &dpll1_x2m2_ck),
+ CLK(NULL, "dpll3_x2_ck", &dpll3_x2_ck),
+ CLK(NULL, "dpll3_m2x2_ck", &dpll3_m2x2_ck),
+ CLK(NULL, "dpll4_x2_ck", &dpll4_x2_ck),
+ CLK(NULL, "cm_96m_fck", &cm_96m_fck),
+ CLK(NULL, "omap_96m_fck", &omap_96m_fck),
+ CLK(NULL, "dpll4_m3_ck", &dpll4_m3_ck),
+ CLK(NULL, "dpll4_m3x2_mul_ck", &dpll4_m3x2_mul_ck),
+ CLK(NULL, "dpll4_m3x2_ck", &dpll4_m3x2_ck),
+ CLK(NULL, "omap_54m_fck", &omap_54m_fck),
+ CLK(NULL, "cm_96m_d2_fck", &cm_96m_d2_fck),
+ CLK(NULL, "omap_48m_fck", &omap_48m_fck),
+ CLK(NULL, "omap_12m_fck", &omap_12m_fck),
+ CLK(NULL, "dpll4_m4_ck", &dpll4_m4_ck),
+ CLK(NULL, "dpll4_m4x2_mul_ck", &dpll4_m4x2_mul_ck),
+ CLK(NULL, "dpll4_m4x2_ck", &dpll4_m4x2_ck),
+ CLK(NULL, "dpll4_m5_ck", &dpll4_m5_ck),
+ CLK(NULL, "dpll4_m5x2_mul_ck", &dpll4_m5x2_mul_ck),
+ CLK(NULL, "dpll4_m5x2_ck", &dpll4_m5x2_ck),
+ CLK(NULL, "dpll4_m6_ck", &dpll4_m6_ck),
+ CLK(NULL, "dpll4_m6x2_mul_ck", &dpll4_m6x2_mul_ck),
+ CLK(NULL, "dpll4_m6x2_ck", &dpll4_m6x2_ck),
+ CLK("etb", "emu_per_alwon_ck", &emu_per_alwon_ck),
+ CLK(NULL, "clkout2_src_ck", &clkout2_src_ck),
+ CLK(NULL, "sys_clkout2", &sys_clkout2),
+ CLK(NULL, "corex2_fck", &corex2_fck),
+ CLK(NULL, "mpu_ck", &mpu_ck),
+ CLK(NULL, "arm_fck", &arm_fck),
+ CLK("etb", "emu_mpu_alwon_ck", &emu_mpu_alwon_ck),
+ CLK(NULL, "l3_ick", &l3_ick),
+ CLK(NULL, "l4_ick", &l4_ick),
+ CLK(NULL, "rm_ick", &rm_ick),
+ CLK(NULL, "timer_32k_ck", &omap_32k_fck),
+ CLK(NULL, "gpt10_fck", &gpt10_fck),
+ CLK(NULL, "gpt11_fck", &gpt11_fck),
+ CLK(NULL, "core_96m_fck", &core_96m_fck),
+ CLK(NULL, "mmchs2_fck", &mmchs2_fck),
+ CLK(NULL, "mmchs1_fck", &mmchs1_fck),
+ CLK(NULL, "i2c3_fck", &i2c3_fck),
+ CLK(NULL, "i2c2_fck", &i2c2_fck),
+ CLK(NULL, "i2c1_fck", &i2c1_fck),
+ CLK(NULL, "mcbsp5_fck", &mcbsp5_fck),
+ CLK(NULL, "mcbsp1_fck", &mcbsp1_fck),
+ CLK(NULL, "core_48m_fck", &core_48m_fck),
+ CLK(NULL, "mcspi4_fck", &mcspi4_fck),
+ CLK(NULL, "mcspi3_fck", &mcspi3_fck),
+ CLK(NULL, "mcspi2_fck", &mcspi2_fck),
+ CLK(NULL, "mcspi1_fck", &mcspi1_fck),
+ CLK(NULL, "uart2_fck", &uart2_fck),
+ CLK(NULL, "uart1_fck", &uart1_fck),
+ CLK(NULL, "core_12m_fck", &core_12m_fck),
+ CLK("omap_hdq.0", "fck", &hdq_fck),
+ CLK(NULL, "hdq_fck", &hdq_fck),
+ CLK(NULL, "core_l3_ick", &core_l3_ick),
+ CLK(NULL, "sdrc_ick", &sdrc_ick),
+ CLK(NULL, "gpmc_fck", &gpmc_fck),
+ CLK(NULL, "core_l4_ick", &core_l4_ick),
+ CLK("omap_hsmmc.1", "ick", &mmchs2_ick),
+ CLK("omap_hsmmc.0", "ick", &mmchs1_ick),
+ CLK(NULL, "mmchs2_ick", &mmchs2_ick),
+ CLK(NULL, "mmchs1_ick", &mmchs1_ick),
+ CLK("omap_hdq.0", "ick", &hdq_ick),
+ CLK(NULL, "hdq_ick", &hdq_ick),
+ CLK("omap2_mcspi.4", "ick", &mcspi4_ick),
+ CLK("omap2_mcspi.3", "ick", &mcspi3_ick),
+ CLK("omap2_mcspi.2", "ick", &mcspi2_ick),
+ CLK("omap2_mcspi.1", "ick", &mcspi1_ick),
+ CLK(NULL, "mcspi4_ick", &mcspi4_ick),
+ CLK(NULL, "mcspi3_ick", &mcspi3_ick),
+ CLK(NULL, "mcspi2_ick", &mcspi2_ick),
+ CLK(NULL, "mcspi1_ick", &mcspi1_ick),
+ CLK("omap_i2c.3", "ick", &i2c3_ick),
+ CLK("omap_i2c.2", "ick", &i2c2_ick),
+ CLK("omap_i2c.1", "ick", &i2c1_ick),
+ CLK(NULL, "i2c3_ick", &i2c3_ick),
+ CLK(NULL, "i2c2_ick", &i2c2_ick),
+ CLK(NULL, "i2c1_ick", &i2c1_ick),
+ CLK(NULL, "uart2_ick", &uart2_ick),
+ CLK(NULL, "uart1_ick", &uart1_ick),
+ CLK(NULL, "gpt11_ick", &gpt11_ick),
+ CLK(NULL, "gpt10_ick", &gpt10_ick),
+ CLK("omap-mcbsp.5", "ick", &mcbsp5_ick),
+ CLK("omap-mcbsp.1", "ick", &mcbsp1_ick),
+ CLK(NULL, "mcbsp5_ick", &mcbsp5_ick),
+ CLK(NULL, "mcbsp1_ick", &mcbsp1_ick),
+ CLK(NULL, "omapctrl_ick", &omapctrl_ick),
+ CLK(NULL, "dss_tv_fck", &dss_tv_fck),
+ CLK(NULL, "dss_96m_fck", &dss_96m_fck),
+ CLK(NULL, "dss2_alwon_fck", &dss2_alwon_fck),
+ CLK(NULL, "init_60m_fclk", &dummy_ck),
+ CLK(NULL, "gpt1_fck", &gpt1_fck),
+ CLK(NULL, "aes2_ick", &aes2_ick),
+ CLK(NULL, "wkup_32k_fck", &wkup_32k_fck),
+ CLK(NULL, "gpio1_dbck", &gpio1_dbck),
+ CLK(NULL, "sha12_ick", &sha12_ick),
+ CLK(NULL, "wdt2_fck", &wdt2_fck),
+ CLK(NULL, "wkup_l4_ick", &wkup_l4_ick),
+ CLK("omap_wdt", "ick", &wdt2_ick),
+ CLK(NULL, "wdt2_ick", &wdt2_ick),
+ CLK(NULL, "wdt1_ick", &wdt1_ick),
+ CLK(NULL, "gpio1_ick", &gpio1_ick),
+ CLK(NULL, "omap_32ksync_ick", &omap_32ksync_ick),
+ CLK(NULL, "gpt12_ick", &gpt12_ick),
+ CLK(NULL, "gpt1_ick", &gpt1_ick),
+ CLK(NULL, "per_96m_fck", &per_96m_fck),
+ CLK(NULL, "per_48m_fck", &per_48m_fck),
+ CLK(NULL, "uart3_fck", &uart3_fck),
+ CLK(NULL, "gpt2_fck", &gpt2_fck),
+ CLK(NULL, "gpt3_fck", &gpt3_fck),
+ CLK(NULL, "gpt4_fck", &gpt4_fck),
+ CLK(NULL, "gpt5_fck", &gpt5_fck),
+ CLK(NULL, "gpt6_fck", &gpt6_fck),
+ CLK(NULL, "gpt7_fck", &gpt7_fck),
+ CLK(NULL, "gpt8_fck", &gpt8_fck),
+ CLK(NULL, "gpt9_fck", &gpt9_fck),
+ CLK(NULL, "per_32k_alwon_fck", &per_32k_alwon_fck),
+ CLK(NULL, "gpio6_dbck", &gpio6_dbck),
+ CLK(NULL, "gpio5_dbck", &gpio5_dbck),
+ CLK(NULL, "gpio4_dbck", &gpio4_dbck),
+ CLK(NULL, "gpio3_dbck", &gpio3_dbck),
+ CLK(NULL, "gpio2_dbck", &gpio2_dbck),
+ CLK(NULL, "wdt3_fck", &wdt3_fck),
+ CLK(NULL, "per_l4_ick", &per_l4_ick),
+ CLK(NULL, "gpio6_ick", &gpio6_ick),
+ CLK(NULL, "gpio5_ick", &gpio5_ick),
+ CLK(NULL, "gpio4_ick", &gpio4_ick),
+ CLK(NULL, "gpio3_ick", &gpio3_ick),
+ CLK(NULL, "gpio2_ick", &gpio2_ick),
+ CLK(NULL, "wdt3_ick", &wdt3_ick),
+ CLK(NULL, "uart3_ick", &uart3_ick),
+ CLK(NULL, "uart4_ick", &uart4_ick),
+ CLK(NULL, "gpt9_ick", &gpt9_ick),
+ CLK(NULL, "gpt8_ick", &gpt8_ick),
+ CLK(NULL, "gpt7_ick", &gpt7_ick),
+ CLK(NULL, "gpt6_ick", &gpt6_ick),
+ CLK(NULL, "gpt5_ick", &gpt5_ick),
+ CLK(NULL, "gpt4_ick", &gpt4_ick),
+ CLK(NULL, "gpt3_ick", &gpt3_ick),
+ CLK(NULL, "gpt2_ick", &gpt2_ick),
+ CLK("omap-mcbsp.2", "ick", &mcbsp2_ick),
+ CLK("omap-mcbsp.3", "ick", &mcbsp3_ick),
+ CLK("omap-mcbsp.4", "ick", &mcbsp4_ick),
+ CLK(NULL, "mcbsp4_ick", &mcbsp2_ick),
+ CLK(NULL, "mcbsp3_ick", &mcbsp3_ick),
+ CLK(NULL, "mcbsp2_ick", &mcbsp4_ick),
+ CLK(NULL, "mcbsp2_fck", &mcbsp2_fck),
+ CLK(NULL, "mcbsp3_fck", &mcbsp3_fck),
+ CLK(NULL, "mcbsp4_fck", &mcbsp4_fck),
+ CLK(NULL, "emu_src_mux_ck", &emu_src_mux_ck),
+ CLK("etb", "emu_src_ck", &emu_src_ck),
+ CLK(NULL, "emu_src_mux_ck", &emu_src_mux_ck),
+ CLK(NULL, "emu_src_ck", &emu_src_ck),
+ CLK(NULL, "pclk_fck", &pclk_fck),
+ CLK(NULL, "pclkx2_fck", &pclkx2_fck),
+ CLK(NULL, "atclk_fck", &atclk_fck),
+ CLK(NULL, "traceclk_src_fck", &traceclk_src_fck),
+ CLK(NULL, "traceclk_fck", &traceclk_fck),
+ CLK(NULL, "secure_32k_fck", &secure_32k_fck),
+ CLK(NULL, "gpt12_fck", &gpt12_fck),
+ CLK(NULL, "wdt1_fck", &wdt1_fck),
+ { NULL },
+};
+
+static struct ti_clk_alias omap36xx_am35xx_omap3430es2plus_clks[] = {
+ CLK(NULL, "dpll5_ck", &dpll5_ck),
+ CLK(NULL, "dpll5_m2_ck", &dpll5_m2_ck),
+ CLK(NULL, "core_d3_ck", &core_d3_ck),
+ CLK(NULL, "core_d4_ck", &core_d4_ck),
+ CLK(NULL, "core_d6_ck", &core_d6_ck),
+ CLK(NULL, "omap_192m_alwon_fck", &omap_192m_alwon_fck),
+ CLK(NULL, "core_d2_ck", &core_d2_ck),
+ CLK(NULL, "corex2_d3_fck", &corex2_d3_fck),
+ CLK(NULL, "corex2_d5_fck", &corex2_d5_fck),
+ CLK(NULL, "sgx_fck", &sgx_fck),
+ CLK(NULL, "sgx_ick", &sgx_ick),
+ CLK(NULL, "cpefuse_fck", &cpefuse_fck),
+ CLK(NULL, "ts_fck", &ts_fck),
+ CLK(NULL, "usbtll_fck", &usbtll_fck),
+ CLK(NULL, "usbtll_ick", &usbtll_ick),
+ CLK("omap_hsmmc.2", "ick", &mmchs3_ick),
+ CLK(NULL, "mmchs3_ick", &mmchs3_ick),
+ CLK(NULL, "mmchs3_fck", &mmchs3_fck),
+ CLK(NULL, "dss1_alwon_fck", &dss1_alwon_fck_3430es2),
+ CLK("omapdss_dss", "ick", &dss_ick_3430es2),
+ CLK(NULL, "dss_ick", &dss_ick_3430es2),
+ CLK(NULL, "usbhost_120m_fck", &usbhost_120m_fck),
+ CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck),
+ CLK(NULL, "usbhost_ick", &usbhost_ick),
+ { NULL },
+};
+
+static struct ti_clk_alias omap3430es1_clks[] = {
+ CLK(NULL, "gfx_l3_ck", &gfx_l3_ck),
+ CLK(NULL, "gfx_l3_fck", &gfx_l3_fck),
+ CLK(NULL, "gfx_l3_ick", &gfx_l3_ick),
+ CLK(NULL, "gfx_cg1_ck", &gfx_cg1_ck),
+ CLK(NULL, "gfx_cg2_ck", &gfx_cg2_ck),
+ CLK(NULL, "d2d_26m_fck", &d2d_26m_fck),
+ CLK(NULL, "fshostusb_fck", &fshostusb_fck),
+ CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es1),
+ CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es1),
+ CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es1),
+ CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_3430es1),
+ CLK(NULL, "fac_ick", &fac_ick),
+ CLK(NULL, "ssi_ick", &ssi_ick_3430es1),
+ CLK(NULL, "usb_l4_ick", &usb_l4_ick),
+ CLK(NULL, "dss1_alwon_fck", &dss1_alwon_fck_3430es1),
+ CLK("omapdss_dss", "ick", &dss_ick_3430es1),
+ CLK(NULL, "dss_ick", &dss_ick_3430es1),
+ { NULL },
+};
+
+static struct ti_clk_alias omap36xx_clks[] = {
+ CLK(NULL, "uart4_fck", &uart4_fck),
+ { NULL },
+};
+
+static struct ti_clk_alias am35xx_clks[] = {
+ CLK(NULL, "ipss_ick", &ipss_ick),
+ CLK(NULL, "rmii_ck", &rmii_ck),
+ CLK(NULL, "pclk_ck", &pclk_ck),
+ CLK(NULL, "emac_ick", &emac_ick),
+ CLK(NULL, "emac_fck", &emac_fck),
+ CLK("davinci_emac.0", NULL, &emac_ick),
+ CLK("davinci_mdio.0", NULL, &emac_fck),
+ CLK("vpfe-capture", "master", &vpfe_ick),
+ CLK("vpfe-capture", "slave", &vpfe_fck),
+ CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_am35xx),
+ CLK(NULL, "hsotgusb_fck", &hsotgusb_fck_am35xx),
+ CLK(NULL, "hecc_ck", &hecc_ck),
+ CLK(NULL, "uart4_ick", &uart4_ick_am35xx),
+ CLK(NULL, "uart4_fck", &uart4_fck_am35xx),
+ { NULL },
+};
+
+static struct ti_clk *omap36xx_clk_patches[] = {
+ &dpll4_m3x2_ck_omap36xx,
+ &dpll3_m3x2_ck_omap36xx,
+ &dpll4_m6x2_ck_omap36xx,
+ &dpll4_m2x2_ck_omap36xx,
+ &dpll4_m5x2_ck_omap36xx,
+ &dpll4_ck_omap36xx,
+ NULL,
+};
+
+static const char *enable_init_clks[] = {
+ "sdrc_ick",
+ "gpmc_fck",
+ "omapctrl_ick",
+};
+
+static void __init omap3_clk_legacy_common_init(void)
+{
+ omap2_clk_disable_autoidle_all();
+
+ omap2_clk_enable_init_clocks(enable_init_clks,
+ ARRAY_SIZE(enable_init_clks));
+
+ pr_info("Clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n",
+ (clk_get_rate(osc_sys_ck.clk) / 1000000),
+ (clk_get_rate(osc_sys_ck.clk) / 100000) % 10,
+ (clk_get_rate(core_ck.clk) / 1000000),
+ (clk_get_rate(arm_fck.clk) / 1000000));
+}
+
+int __init omap3430es1_clk_legacy_init(void)
+{
+ int r;
+
+ r = ti_clk_register_legacy_clks(omap3430es1_clks);
+ r |= ti_clk_register_legacy_clks(omap34xx_omap36xx_clks);
+ r |= ti_clk_register_legacy_clks(omap3xxx_clks);
+
+ omap3_clk_legacy_common_init();
+
+ return r;
+}
+
+int __init omap3430_clk_legacy_init(void)
+{
+ int r;
+
+ r = ti_clk_register_legacy_clks(omap34xx_omap36xx_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_am35xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap3xxx_clks);
+
+ omap3_clk_legacy_common_init();
+ omap3_clk_lock_dpll5();
+
+ return r;
+}
+
+int __init omap36xx_clk_legacy_init(void)
+{
+ int r;
+
+ ti_clk_patch_legacy_clks(omap36xx_clk_patches);
+ r = ti_clk_register_legacy_clks(omap36xx_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap34xx_omap36xx_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_am35xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap3xxx_clks);
+
+ omap3_clk_legacy_common_init();
+ omap3_clk_lock_dpll5();
+
+ return r;
+}
+
+int __init am35xx_clk_legacy_init(void)
+{
+ int r;
+
+ r = ti_clk_register_legacy_clks(am35xx_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_am35xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap3xxx_clks);
+
+ omap3_clk_legacy_common_init();
+ omap3_clk_lock_dpll5();
+
+ return r;
+}
diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c
index 0d1750a8aea4..383a06e49b09 100644
--- a/drivers/clk/ti/clk-3xxx.c
+++ b/drivers/clk/ti/clk-3xxx.c
@@ -327,7 +327,6 @@ enum {
OMAP3_SOC_OMAP3430_ES1,
OMAP3_SOC_OMAP3430_ES2_PLUS,
OMAP3_SOC_OMAP3630,
- OMAP3_SOC_TI81XX,
};
static int __init omap3xxx_dt_clk_init(int soc_type)
@@ -370,7 +369,7 @@ static int __init omap3xxx_dt_clk_init(int soc_type)
(clk_get_rate(clk_get_sys(NULL, "core_ck")) / 1000000),
(clk_get_rate(clk_get_sys(NULL, "arm_fck")) / 1000000));
- if (soc_type != OMAP3_SOC_TI81XX && soc_type != OMAP3_SOC_OMAP3430_ES1)
+ if (soc_type != OMAP3_SOC_OMAP3430_ES1)
omap3_clk_lock_dpll5();
return 0;
@@ -390,8 +389,3 @@ int __init am35xx_dt_clk_init(void)
{
return omap3xxx_dt_clk_init(OMAP3_SOC_AM35XX);
}
-
-int __init ti81xx_dt_clk_init(void)
-{
- return omap3xxx_dt_clk_init(OMAP3_SOC_TI81XX);
-}
diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c
index 02517a8206bd..4f4c87751db5 100644
--- a/drivers/clk/ti/clk-44xx.c
+++ b/drivers/clk/ti/clk-44xx.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
-#include <linux/clk-private.h>
+#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk/ti.h>
diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c
index 5e183993e3ec..14160b223548 100644
--- a/drivers/clk/ti/clk-54xx.c
+++ b/drivers/clk/ti/clk-54xx.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
-#include <linux/clk-private.h>
+#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/clk/ti.h>
diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c
index 62ac8f6e480c..ee32f4deebf4 100644
--- a/drivers/clk/ti/clk-7xx.c
+++ b/drivers/clk/ti/clk-7xx.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
-#include <linux/clk-private.h>
+#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk/ti.h>
diff --git a/drivers/clk/ti/clk-816x.c b/drivers/clk/ti/clk-816x.c
new file mode 100644
index 000000000000..9451e651a1ff
--- /dev/null
+++ b/drivers/clk/ti/clk-816x.c
@@ -0,0 +1,53 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
+
+static struct ti_dt_clk dm816x_clks[] = {
+ DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"),
+ DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
+ DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"),
+ DT_CLK(NULL, "mpu_ck", "mpu_ck"),
+ DT_CLK(NULL, "timer1_fck", "timer1_fck"),
+ DT_CLK(NULL, "timer2_fck", "timer2_fck"),
+ DT_CLK(NULL, "timer3_fck", "timer3_fck"),
+ DT_CLK(NULL, "timer4_fck", "timer4_fck"),
+ DT_CLK(NULL, "timer5_fck", "timer5_fck"),
+ DT_CLK(NULL, "timer6_fck", "timer6_fck"),
+ DT_CLK(NULL, "timer7_fck", "timer7_fck"),
+ DT_CLK(NULL, "sysclk4_ck", "sysclk4_ck"),
+ DT_CLK(NULL, "sysclk5_ck", "sysclk5_ck"),
+ DT_CLK(NULL, "sysclk6_ck", "sysclk6_ck"),
+ DT_CLK(NULL, "sysclk10_ck", "sysclk10_ck"),
+ DT_CLK(NULL, "sysclk18_ck", "sysclk18_ck"),
+ DT_CLK(NULL, "sysclk24_ck", "sysclk24_ck"),
+ DT_CLK("4a100000.ethernet", "sysclk24_ck", "sysclk24_ck"),
+ { .node_name = NULL },
+};
+
+static const char *enable_init_clks[] = {
+ "ddr_pll_clk1",
+ "ddr_pll_clk2",
+ "ddr_pll_clk3",
+};
+
+int __init ti81xx_dt_clk_init(void)
+{
+ ti_dt_clocks_register(dm816x_clks);
+ omap2_clk_disable_autoidle_all();
+ omap2_clk_enable_init_clocks(enable_init_clks,
+ ARRAY_SIZE(enable_init_clks));
+
+ return 0;
+}
diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c
index 337abe5909e1..e22b95646e09 100644
--- a/drivers/clk/ti/clk.c
+++ b/drivers/clk/ti/clk.c
@@ -22,6 +22,8 @@
#include <linux/of_address.h>
#include <linux/list.h>
+#include "clock.h"
+
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -183,3 +185,128 @@ void ti_dt_clk_init_retry_clks(void)
retries--;
}
}
+
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+void __init ti_clk_patch_legacy_clks(struct ti_clk **patch)
+{
+ while (*patch) {
+ memcpy((*patch)->patch, *patch, sizeof(**patch));
+ patch++;
+ }
+}
+
+struct clk __init *ti_clk_register_clk(struct ti_clk *setup)
+{
+ struct clk *clk;
+ struct ti_clk_fixed *fixed;
+ struct ti_clk_fixed_factor *fixed_factor;
+ struct clk_hw *clk_hw;
+
+ if (setup->clk)
+ return setup->clk;
+
+ switch (setup->type) {
+ case TI_CLK_FIXED:
+ fixed = setup->data;
+
+ clk = clk_register_fixed_rate(NULL, setup->name, NULL,
+ CLK_IS_ROOT, fixed->frequency);
+ break;
+ case TI_CLK_MUX:
+ clk = ti_clk_register_mux(setup);
+ break;
+ case TI_CLK_DIVIDER:
+ clk = ti_clk_register_divider(setup);
+ break;
+ case TI_CLK_COMPOSITE:
+ clk = ti_clk_register_composite(setup);
+ break;
+ case TI_CLK_FIXED_FACTOR:
+ fixed_factor = setup->data;
+
+ clk = clk_register_fixed_factor(NULL, setup->name,
+ fixed_factor->parent,
+ 0, fixed_factor->mult,
+ fixed_factor->div);
+ break;
+ case TI_CLK_GATE:
+ clk = ti_clk_register_gate(setup);
+ break;
+ case TI_CLK_DPLL:
+ clk = ti_clk_register_dpll(setup);
+ break;
+ default:
+ pr_err("bad type for %s!\n", setup->name);
+ clk = ERR_PTR(-EINVAL);
+ }
+
+ if (!IS_ERR(clk)) {
+ setup->clk = clk;
+ if (setup->clkdm_name) {
+ if (__clk_get_flags(clk) & CLK_IS_BASIC) {
+ pr_warn("can't setup clkdm for basic clk %s\n",
+ setup->name);
+ } else {
+ clk_hw = __clk_get_hw(clk);
+ to_clk_hw_omap(clk_hw)->clkdm_name =
+ setup->clkdm_name;
+ omap2_init_clk_clkdm(clk_hw);
+ }
+ }
+ }
+
+ return clk;
+}
+
+int __init ti_clk_register_legacy_clks(struct ti_clk_alias *clks)
+{
+ struct clk *clk;
+ bool retry;
+ struct ti_clk_alias *retry_clk;
+ struct ti_clk_alias *tmp;
+
+ while (clks->clk) {
+ clk = ti_clk_register_clk(clks->clk);
+ if (IS_ERR(clk)) {
+ if (PTR_ERR(clk) == -EAGAIN) {
+ list_add(&clks->link, &retry_list);
+ } else {
+ pr_err("register for %s failed: %ld\n",
+ clks->clk->name, PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+ } else {
+ clks->lk.clk = clk;
+ clkdev_add(&clks->lk);
+ }
+ clks++;
+ }
+
+ retry = true;
+
+ while (!list_empty(&retry_list) && retry) {
+ retry = false;
+ list_for_each_entry_safe(retry_clk, tmp, &retry_list, link) {
+ pr_debug("retry-init: %s\n", retry_clk->clk->name);
+ clk = ti_clk_register_clk(retry_clk->clk);
+ if (IS_ERR(clk)) {
+ if (PTR_ERR(clk) == -EAGAIN) {
+ continue;
+ } else {
+ pr_err("register for %s failed: %ld\n",
+ retry_clk->clk->name,
+ PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+ } else {
+ retry = true;
+ retry_clk->lk.clk = clk;
+ clkdev_add(&retry_clk->lk);
+ list_del(&retry_clk->link);
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h
new file mode 100644
index 000000000000..404158d2d7f8
--- /dev/null
+++ b/drivers/clk/ti/clock.h
@@ -0,0 +1,172 @@
+/*
+ * TI Clock driver internal definitions
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc
+ * Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DRIVERS_CLK_TI_CLOCK__
+#define __DRIVERS_CLK_TI_CLOCK__
+
+enum {
+ TI_CLK_FIXED,
+ TI_CLK_MUX,
+ TI_CLK_DIVIDER,
+ TI_CLK_COMPOSITE,
+ TI_CLK_FIXED_FACTOR,
+ TI_CLK_GATE,
+ TI_CLK_DPLL,
+};
+
+/* Global flags */
+#define CLKF_INDEX_POWER_OF_TWO (1 << 0)
+#define CLKF_INDEX_STARTS_AT_ONE (1 << 1)
+#define CLKF_SET_RATE_PARENT (1 << 2)
+#define CLKF_OMAP3 (1 << 3)
+#define CLKF_AM35XX (1 << 4)
+
+/* Gate flags */
+#define CLKF_SET_BIT_TO_DISABLE (1 << 5)
+#define CLKF_INTERFACE (1 << 6)
+#define CLKF_SSI (1 << 7)
+#define CLKF_DSS (1 << 8)
+#define CLKF_HSOTGUSB (1 << 9)
+#define CLKF_WAIT (1 << 10)
+#define CLKF_NO_WAIT (1 << 11)
+#define CLKF_HSDIV (1 << 12)
+#define CLKF_CLKDM (1 << 13)
+
+/* DPLL flags */
+#define CLKF_LOW_POWER_STOP (1 << 5)
+#define CLKF_LOCK (1 << 6)
+#define CLKF_LOW_POWER_BYPASS (1 << 7)
+#define CLKF_PER (1 << 8)
+#define CLKF_CORE (1 << 9)
+#define CLKF_J_TYPE (1 << 10)
+
+#define CLK(dev, con, ck) \
+ { \
+ .lk = { \
+ .dev_id = dev, \
+ .con_id = con, \
+ }, \
+ .clk = ck, \
+ }
+
+struct ti_clk {
+ const char *name;
+ const char *clkdm_name;
+ int type;
+ void *data;
+ struct ti_clk *patch;
+ struct clk *clk;
+};
+
+struct ti_clk_alias {
+ struct ti_clk *clk;
+ struct clk_lookup lk;
+ struct list_head link;
+};
+
+struct ti_clk_fixed {
+ u32 frequency;
+ u16 flags;
+};
+
+struct ti_clk_mux {
+ u8 bit_shift;
+ int num_parents;
+ u16 reg;
+ u8 module;
+ const char **parents;
+ u16 flags;
+};
+
+struct ti_clk_divider {
+ const char *parent;
+ u8 bit_shift;
+ u16 max_div;
+ u16 reg;
+ u8 module;
+ int *dividers;
+ int num_dividers;
+ u16 flags;
+};
+
+struct ti_clk_fixed_factor {
+ const char *parent;
+ u16 div;
+ u16 mult;
+ u16 flags;
+};
+
+struct ti_clk_gate {
+ const char *parent;
+ u8 bit_shift;
+ u16 reg;
+ u8 module;
+ u16 flags;
+};
+
+struct ti_clk_composite {
+ struct ti_clk_divider *divider;
+ struct ti_clk_mux *mux;
+ struct ti_clk_gate *gate;
+ u16 flags;
+};
+
+struct ti_clk_clkdm_gate {
+ const char *parent;
+ u16 flags;
+};
+
+struct ti_clk_dpll {
+ int num_parents;
+ u16 control_reg;
+ u16 idlest_reg;
+ u16 autoidle_reg;
+ u16 mult_div1_reg;
+ u8 module;
+ const char **parents;
+ u16 flags;
+ u8 modes;
+ u32 mult_mask;
+ u32 div1_mask;
+ u32 enable_mask;
+ u32 autoidle_mask;
+ u32 freqsel_mask;
+ u32 idlest_mask;
+ u32 dco_mask;
+ u32 sddiv_mask;
+ u16 max_multiplier;
+ u16 max_divider;
+ u8 min_divider;
+ u8 auto_recal_bit;
+ u8 recal_en_bit;
+ u8 recal_st_bit;
+};
+
+struct clk *ti_clk_register_gate(struct ti_clk *setup);
+struct clk *ti_clk_register_interface(struct ti_clk *setup);
+struct clk *ti_clk_register_mux(struct ti_clk *setup);
+struct clk *ti_clk_register_divider(struct ti_clk *setup);
+struct clk *ti_clk_register_composite(struct ti_clk *setup);
+struct clk *ti_clk_register_dpll(struct ti_clk *setup);
+
+struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup);
+struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup);
+struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup);
+
+void ti_clk_patch_legacy_clks(struct ti_clk **patch);
+struct clk *ti_clk_register_clk(struct ti_clk *setup);
+int ti_clk_register_legacy_clks(struct ti_clk_alias *clks);
+
+#endif
diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c
index 19d8980ba458..3654f61912eb 100644
--- a/drivers/clk/ti/composite.c
+++ b/drivers/clk/ti/composite.c
@@ -23,6 +23,8 @@
#include <linux/clk/ti.h>
#include <linux/list.h>
+#include "clock.h"
+
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -116,8 +118,46 @@ static inline struct clk_hw *_get_hw(struct clk_hw_omap_comp *clk, int idx)
#define to_clk_hw_comp(_hw) container_of(_hw, struct clk_hw_omap_comp, hw)
-static void __init ti_clk_register_composite(struct clk_hw *hw,
- struct device_node *node)
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+struct clk *ti_clk_register_composite(struct ti_clk *setup)
+{
+ struct ti_clk_composite *comp;
+ struct clk_hw *gate;
+ struct clk_hw *mux;
+ struct clk_hw *div;
+ int num_parents = 1;
+ const char **parent_names = NULL;
+ struct clk *clk;
+
+ comp = setup->data;
+
+ div = ti_clk_build_component_div(comp->divider);
+ gate = ti_clk_build_component_gate(comp->gate);
+ mux = ti_clk_build_component_mux(comp->mux);
+
+ if (div)
+ parent_names = &comp->divider->parent;
+
+ if (gate)
+ parent_names = &comp->gate->parent;
+
+ if (mux) {
+ num_parents = comp->mux->num_parents;
+ parent_names = comp->mux->parents;
+ }
+
+ clk = clk_register_composite(NULL, setup->name,
+ parent_names, num_parents, mux,
+ &ti_clk_mux_ops, div,
+ &ti_composite_divider_ops, gate,
+ &ti_composite_gate_ops, 0);
+
+ return clk;
+}
+#endif
+
+static void __init _register_composite(struct clk_hw *hw,
+ struct device_node *node)
{
struct clk *clk;
struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw);
@@ -136,7 +176,7 @@ static void __init ti_clk_register_composite(struct clk_hw *hw,
pr_debug("component %s not ready for %s, retry\n",
cclk->comp_nodes[i]->name, node->name);
if (!ti_clk_retry_init(node, hw,
- ti_clk_register_composite))
+ _register_composite))
return;
goto cleanup;
@@ -216,7 +256,7 @@ static void __init of_ti_composite_clk_setup(struct device_node *node)
for (i = 0; i < num_clks; i++)
cclk->comp_nodes[i] = _get_component_node(node, i);
- ti_clk_register_composite(&cclk->hw, node);
+ _register_composite(&cclk->hw, node);
}
CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock",
of_ti_composite_clk_setup);
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c
index bff2b5b8ff59..6211893c0980 100644
--- a/drivers/clk/ti/divider.c
+++ b/drivers/clk/ti/divider.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -301,6 +302,134 @@ static struct clk *_register_divider(struct device *dev, const char *name,
}
static struct clk_div_table *
+_get_div_table_from_setup(struct ti_clk_divider *setup, u8 *width)
+{
+ int valid_div = 0;
+ struct clk_div_table *table;
+ int i;
+ int div;
+ u32 val;
+ u8 flags;
+
+ if (!setup->num_dividers) {
+ /* Clk divider table not provided, determine min/max divs */
+ flags = setup->flags;
+
+ if (flags & CLKF_INDEX_STARTS_AT_ONE)
+ val = 1;
+ else
+ val = 0;
+
+ div = 1;
+
+ while (div < setup->max_div) {
+ if (flags & CLKF_INDEX_POWER_OF_TWO)
+ div <<= 1;
+ else
+ div++;
+ val++;
+ }
+
+ *width = fls(val);
+
+ return NULL;
+ }
+
+ for (i = 0; i < setup->num_dividers; i++)
+ if (setup->dividers[i])
+ valid_div++;
+
+ table = kzalloc(sizeof(*table) * (valid_div + 1), GFP_KERNEL);
+ if (!table)
+ return ERR_PTR(-ENOMEM);
+
+ valid_div = 0;
+ *width = 0;
+
+ for (i = 0; i < setup->num_dividers; i++)
+ if (setup->dividers[i]) {
+ table[valid_div].div = setup->dividers[i];
+ table[valid_div].val = i;
+ valid_div++;
+ *width = i;
+ }
+
+ *width = fls(*width);
+
+ return table;
+}
+
+struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup)
+{
+ struct clk_divider *div;
+ struct clk_omap_reg *reg;
+
+ if (!setup)
+ return NULL;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ reg = (struct clk_omap_reg *)&div->reg;
+ reg->index = setup->module;
+ reg->offset = setup->reg;
+
+ if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
+ div->flags |= CLK_DIVIDER_ONE_BASED;
+
+ if (setup->flags & CLKF_INDEX_POWER_OF_TWO)
+ div->flags |= CLK_DIVIDER_POWER_OF_TWO;
+
+ div->table = _get_div_table_from_setup(setup, &div->width);
+
+ div->shift = setup->bit_shift;
+
+ return &div->hw;
+}
+
+struct clk *ti_clk_register_divider(struct ti_clk *setup)
+{
+ struct ti_clk_divider *div;
+ struct clk_omap_reg *reg_setup;
+ u32 reg;
+ u8 width;
+ u32 flags = 0;
+ u8 div_flags = 0;
+ struct clk_div_table *table;
+ struct clk *clk;
+
+ div = setup->data;
+
+ reg_setup = (struct clk_omap_reg *)&reg;
+
+ reg_setup->index = div->module;
+ reg_setup->offset = div->reg;
+
+ if (div->flags & CLKF_INDEX_STARTS_AT_ONE)
+ div_flags |= CLK_DIVIDER_ONE_BASED;
+
+ if (div->flags & CLKF_INDEX_POWER_OF_TWO)
+ div_flags |= CLK_DIVIDER_POWER_OF_TWO;
+
+ if (div->flags & CLKF_SET_RATE_PARENT)
+ flags |= CLK_SET_RATE_PARENT;
+
+ table = _get_div_table_from_setup(div, &width);
+ if (IS_ERR(table))
+ return (struct clk *)table;
+
+ clk = _register_divider(NULL, setup->name, div->parent,
+ flags, (void __iomem *)reg, div->bit_shift,
+ width, div_flags, table, NULL);
+
+ if (IS_ERR(clk))
+ kfree(table);
+
+ return clk;
+}
+
+static struct clk_div_table *
__init ti_clk_get_div_table(struct device_node *node)
{
struct clk_div_table *table;
@@ -455,7 +584,8 @@ static void __init of_ti_divider_clk_setup(struct device_node *node)
goto cleanup;
clk = _register_divider(NULL, node->name, parent_name, flags, reg,
- shift, width, clk_divider_flags, table, NULL);
+ shift, width, clk_divider_flags, table,
+ NULL);
if (!IS_ERR(clk)) {
of_clk_add_provider(node, of_clk_src_simple_get, clk);
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c
index 85ac0dd501de..81dc4698dc41 100644
--- a/drivers/clk/ti/dpll.c
+++ b/drivers/clk/ti/dpll.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -130,7 +131,7 @@ static const struct clk_ops dpll_x2_ck_ops = {
};
/**
- * ti_clk_register_dpll - low level registration of a DPLL clock
+ * _register_dpll - low level registration of a DPLL clock
* @hw: hardware clock definition for the clock
* @node: device node for the clock
*
@@ -138,8 +139,8 @@ static const struct clk_ops dpll_x2_ck_ops = {
* clk-bypass is missing), the clock is added to retry list and
* the initialization is retried on later stage.
*/
-static void __init ti_clk_register_dpll(struct clk_hw *hw,
- struct device_node *node)
+static void __init _register_dpll(struct clk_hw *hw,
+ struct device_node *node)
{
struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw);
struct dpll_data *dd = clk_hw->dpll_data;
@@ -151,7 +152,7 @@ static void __init ti_clk_register_dpll(struct clk_hw *hw,
if (IS_ERR(dd->clk_ref) || IS_ERR(dd->clk_bypass)) {
pr_debug("clk-ref or clk-bypass missing for %s, retry later\n",
node->name);
- if (!ti_clk_retry_init(node, hw, ti_clk_register_dpll))
+ if (!ti_clk_retry_init(node, hw, _register_dpll))
return;
goto cleanup;
@@ -175,20 +176,118 @@ cleanup:
kfree(clk_hw);
}
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+void __iomem *_get_reg(u8 module, u16 offset)
+{
+ u32 reg;
+ struct clk_omap_reg *reg_setup;
+
+ reg_setup = (struct clk_omap_reg *)&reg;
+
+ reg_setup->index = module;
+ reg_setup->offset = offset;
+
+ return (void __iomem *)reg;
+}
+
+struct clk *ti_clk_register_dpll(struct ti_clk *setup)
+{
+ struct clk_hw_omap *clk_hw;
+ struct clk_init_data init = { NULL };
+ struct dpll_data *dd;
+ struct clk *clk;
+ struct ti_clk_dpll *dpll;
+ const struct clk_ops *ops = &omap3_dpll_ck_ops;
+ struct clk *clk_ref;
+ struct clk *clk_bypass;
+
+ dpll = setup->data;
+
+ if (dpll->num_parents < 2)
+ return ERR_PTR(-EINVAL);
+
+ clk_ref = clk_get_sys(NULL, dpll->parents[0]);
+ clk_bypass = clk_get_sys(NULL, dpll->parents[1]);
+
+ if (IS_ERR_OR_NULL(clk_ref) || IS_ERR_OR_NULL(clk_bypass))
+ return ERR_PTR(-EAGAIN);
+
+ dd = kzalloc(sizeof(*dd), GFP_KERNEL);
+ clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
+ if (!dd || !clk_hw) {
+ clk = ERR_PTR(-ENOMEM);
+ goto cleanup;
+ }
+
+ clk_hw->dpll_data = dd;
+ clk_hw->ops = &clkhwops_omap3_dpll;
+ clk_hw->hw.init = &init;
+ clk_hw->flags = MEMMAP_ADDRESSING;
+
+ init.name = setup->name;
+ init.ops = ops;
+
+ init.num_parents = dpll->num_parents;
+ init.parent_names = dpll->parents;
+
+ dd->control_reg = _get_reg(dpll->module, dpll->control_reg);
+ dd->idlest_reg = _get_reg(dpll->module, dpll->idlest_reg);
+ dd->mult_div1_reg = _get_reg(dpll->module, dpll->mult_div1_reg);
+ dd->autoidle_reg = _get_reg(dpll->module, dpll->autoidle_reg);
+
+ dd->modes = dpll->modes;
+ dd->div1_mask = dpll->div1_mask;
+ dd->idlest_mask = dpll->idlest_mask;
+ dd->mult_mask = dpll->mult_mask;
+ dd->autoidle_mask = dpll->autoidle_mask;
+ dd->enable_mask = dpll->enable_mask;
+ dd->sddiv_mask = dpll->sddiv_mask;
+ dd->dco_mask = dpll->dco_mask;
+ dd->max_divider = dpll->max_divider;
+ dd->min_divider = dpll->min_divider;
+ dd->max_multiplier = dpll->max_multiplier;
+ dd->auto_recal_bit = dpll->auto_recal_bit;
+ dd->recal_en_bit = dpll->recal_en_bit;
+ dd->recal_st_bit = dpll->recal_st_bit;
+
+ dd->clk_ref = clk_ref;
+ dd->clk_bypass = clk_bypass;
+
+ if (dpll->flags & CLKF_CORE)
+ ops = &omap3_dpll_core_ck_ops;
+
+ if (dpll->flags & CLKF_PER)
+ ops = &omap3_dpll_per_ck_ops;
+
+ if (dpll->flags & CLKF_J_TYPE)
+ dd->flags |= DPLL_J_TYPE;
+
+ clk = clk_register(NULL, &clk_hw->hw);
+
+ if (!IS_ERR(clk))
+ return clk;
+
+cleanup:
+ kfree(dd);
+ kfree(clk_hw);
+ return clk;
+}
+#endif
+
#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX) || \
defined(CONFIG_SOC_AM43XX)
/**
- * ti_clk_register_dpll_x2 - Registers a DPLLx2 clock
+ * _register_dpll_x2 - Registers a DPLLx2 clock
* @node: device node for this clock
* @ops: clk_ops for this clock
* @hw_ops: clk_hw_ops for this clock
*
* Initializes a DPLL x 2 clock from device tree data.
*/
-static void ti_clk_register_dpll_x2(struct device_node *node,
- const struct clk_ops *ops,
- const struct clk_hw_omap_ops *hw_ops)
+static void _register_dpll_x2(struct device_node *node,
+ const struct clk_ops *ops,
+ const struct clk_hw_omap_ops *hw_ops)
{
struct clk *clk;
struct clk_init_data init = { NULL };
@@ -318,7 +417,7 @@ static void __init of_ti_dpll_setup(struct device_node *node,
if (dpll_mode)
dd->modes = dpll_mode;
- ti_clk_register_dpll(&clk_hw->hw, node);
+ _register_dpll(&clk_hw->hw, node);
return;
cleanup:
@@ -332,7 +431,7 @@ cleanup:
defined(CONFIG_SOC_DRA7XX)
static void __init of_ti_omap4_dpll_x2_setup(struct device_node *node)
{
- ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx);
+ _register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx);
}
CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock",
of_ti_omap4_dpll_x2_setup);
@@ -341,7 +440,7 @@ CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock",
#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
static void __init of_ti_am3_dpll_x2_setup(struct device_node *node)
{
- ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, NULL);
+ _register_dpll_x2(node, &dpll_x2_ck_ops, NULL);
}
CLK_OF_DECLARE(ti_am3_dpll_x2_clock, "ti,am3-dpll-x2-clock",
of_ti_am3_dpll_x2_setup);
diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c
new file mode 100644
index 000000000000..6ef89639a9f6
--- /dev/null
+++ b/drivers/clk/ti/fapll.c
@@ -0,0 +1,410 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+#include <asm/div64.h>
+
+/* FAPLL Control Register PLL_CTRL */
+#define FAPLL_MAIN_LOCK BIT(7)
+#define FAPLL_MAIN_PLLEN BIT(3)
+#define FAPLL_MAIN_BP BIT(2)
+#define FAPLL_MAIN_LOC_CTL BIT(0)
+
+/* FAPLL powerdown register PWD */
+#define FAPLL_PWD_OFFSET 4
+
+#define MAX_FAPLL_OUTPUTS 7
+#define FAPLL_MAX_RETRIES 1000
+
+#define to_fapll(_hw) container_of(_hw, struct fapll_data, hw)
+#define to_synth(_hw) container_of(_hw, struct fapll_synth, hw)
+
+/* The bypass bit is inverted on the ddr_pll.. */
+#define fapll_is_ddr_pll(va) (((u32)(va) & 0xffff) == 0x0440)
+
+/*
+ * The audio_pll_clk1 input is hard wired to the 27MHz bypass clock,
+ * and the audio_pll_clk1 synthesizer is hardwared to 32KiHz output.
+ */
+#define is_ddr_pll_clk1(va) (((u32)(va) & 0xffff) == 0x044c)
+#define is_audio_pll_clk1(va) (((u32)(va) & 0xffff) == 0x04a8)
+
+/* Synthesizer divider register */
+#define SYNTH_LDMDIV1 BIT(8)
+
+/* Synthesizer frequency register */
+#define SYNTH_LDFREQ BIT(31)
+
+struct fapll_data {
+ struct clk_hw hw;
+ void __iomem *base;
+ const char *name;
+ struct clk *clk_ref;
+ struct clk *clk_bypass;
+ struct clk_onecell_data outputs;
+ bool bypass_bit_inverted;
+};
+
+struct fapll_synth {
+ struct clk_hw hw;
+ struct fapll_data *fd;
+ int index;
+ void __iomem *freq;
+ void __iomem *div;
+ const char *name;
+ struct clk *clk_pll;
+};
+
+static bool ti_fapll_clock_is_bypass(struct fapll_data *fd)
+{
+ u32 v = readl_relaxed(fd->base);
+
+ if (fd->bypass_bit_inverted)
+ return !(v & FAPLL_MAIN_BP);
+ else
+ return !!(v & FAPLL_MAIN_BP);
+}
+
+static int ti_fapll_enable(struct clk_hw *hw)
+{
+ struct fapll_data *fd = to_fapll(hw);
+ u32 v = readl_relaxed(fd->base);
+
+ v |= (1 << FAPLL_MAIN_PLLEN);
+ writel_relaxed(v, fd->base);
+
+ return 0;
+}
+
+static void ti_fapll_disable(struct clk_hw *hw)
+{
+ struct fapll_data *fd = to_fapll(hw);
+ u32 v = readl_relaxed(fd->base);
+
+ v &= ~(1 << FAPLL_MAIN_PLLEN);
+ writel_relaxed(v, fd->base);
+}
+
+static int ti_fapll_is_enabled(struct clk_hw *hw)
+{
+ struct fapll_data *fd = to_fapll(hw);
+ u32 v = readl_relaxed(fd->base);
+
+ return v & (1 << FAPLL_MAIN_PLLEN);
+}
+
+static unsigned long ti_fapll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct fapll_data *fd = to_fapll(hw);
+ u32 fapll_n, fapll_p, v;
+ long long rate;
+
+ if (ti_fapll_clock_is_bypass(fd))
+ return parent_rate;
+
+ rate = parent_rate;
+
+ /* PLL pre-divider is P and multiplier is N */
+ v = readl_relaxed(fd->base);
+ fapll_p = (v >> 8) & 0xff;
+ if (fapll_p)
+ do_div(rate, fapll_p);
+ fapll_n = v >> 16;
+ if (fapll_n)
+ rate *= fapll_n;
+
+ return rate;
+}
+
+static u8 ti_fapll_get_parent(struct clk_hw *hw)
+{
+ struct fapll_data *fd = to_fapll(hw);
+
+ if (ti_fapll_clock_is_bypass(fd))
+ return 1;
+
+ return 0;
+}
+
+static struct clk_ops ti_fapll_ops = {
+ .enable = ti_fapll_enable,
+ .disable = ti_fapll_disable,
+ .is_enabled = ti_fapll_is_enabled,
+ .recalc_rate = ti_fapll_recalc_rate,
+ .get_parent = ti_fapll_get_parent,
+};
+
+static int ti_fapll_synth_enable(struct clk_hw *hw)
+{
+ struct fapll_synth *synth = to_synth(hw);
+ u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
+
+ v &= ~(1 << synth->index);
+ writel_relaxed(v, synth->fd->base + FAPLL_PWD_OFFSET);
+
+ return 0;
+}
+
+static void ti_fapll_synth_disable(struct clk_hw *hw)
+{
+ struct fapll_synth *synth = to_synth(hw);
+ u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
+
+ v |= 1 << synth->index;
+ writel_relaxed(v, synth->fd->base + FAPLL_PWD_OFFSET);
+}
+
+static int ti_fapll_synth_is_enabled(struct clk_hw *hw)
+{
+ struct fapll_synth *synth = to_synth(hw);
+ u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
+
+ return !(v & (1 << synth->index));
+}
+
+/*
+ * See dm816x TRM chapter 1.10.3 Flying Adder PLL fore more info
+ */
+static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct fapll_synth *synth = to_synth(hw);
+ u32 synth_div_m;
+ long long rate;
+
+ /* The audio_pll_clk1 is hardwired to produce 32.768KiHz clock */
+ if (!synth->div)
+ return 32768;
+
+ /*
+ * PLL in bypass sets the synths in bypass mode too. The PLL rate
+ * can be also be set to 27MHz, so we can't use parent_rate to
+ * check for bypass mode.
+ */
+ if (ti_fapll_clock_is_bypass(synth->fd))
+ return parent_rate;
+
+ rate = parent_rate;
+
+ /*
+ * Synth frequency integer and fractional divider.
+ * Note that the phase output K is 8, so the result needs
+ * to be multiplied by 8.
+ */
+ if (synth->freq) {
+ u32 v, synth_int_div, synth_frac_div, synth_div_freq;
+
+ v = readl_relaxed(synth->freq);
+ synth_int_div = (v >> 24) & 0xf;
+ synth_frac_div = v & 0xffffff;
+ synth_div_freq = (synth_int_div * 10000000) + synth_frac_div;
+ rate *= 10000000;
+ do_div(rate, synth_div_freq);
+ rate *= 8;
+ }
+
+ /* Synth ost-divider M */
+ synth_div_m = readl_relaxed(synth->div) & 0xff;
+ do_div(rate, synth_div_m);
+
+ return rate;
+}
+
+static struct clk_ops ti_fapll_synt_ops = {
+ .enable = ti_fapll_synth_enable,
+ .disable = ti_fapll_synth_disable,
+ .is_enabled = ti_fapll_synth_is_enabled,
+ .recalc_rate = ti_fapll_synth_recalc_rate,
+};
+
+static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd,
+ void __iomem *freq,
+ void __iomem *div,
+ int index,
+ const char *name,
+ const char *parent,
+ struct clk *pll_clk)
+{
+ struct clk_init_data *init;
+ struct fapll_synth *synth;
+
+ init = kzalloc(sizeof(*init), GFP_KERNEL);
+ if (!init)
+ return ERR_PTR(-ENOMEM);
+
+ init->ops = &ti_fapll_synt_ops;
+ init->name = name;
+ init->parent_names = &parent;
+ init->num_parents = 1;
+
+ synth = kzalloc(sizeof(*synth), GFP_KERNEL);
+ if (!synth)
+ goto free;
+
+ synth->fd = fd;
+ synth->index = index;
+ synth->freq = freq;
+ synth->div = div;
+ synth->name = name;
+ synth->hw.init = init;
+ synth->clk_pll = pll_clk;
+
+ return clk_register(NULL, &synth->hw);
+
+free:
+ kfree(synth);
+ kfree(init);
+
+ return ERR_PTR(-ENOMEM);
+}
+
+static void __init ti_fapll_setup(struct device_node *node)
+{
+ struct fapll_data *fd;
+ struct clk_init_data *init = NULL;
+ const char *parent_name[2];
+ struct clk *pll_clk;
+ int i;
+
+ fd = kzalloc(sizeof(*fd), GFP_KERNEL);
+ if (!fd)
+ return;
+
+ fd->outputs.clks = kzalloc(sizeof(struct clk *) *
+ MAX_FAPLL_OUTPUTS + 1,
+ GFP_KERNEL);
+ if (!fd->outputs.clks)
+ goto free;
+
+ init = kzalloc(sizeof(*init), GFP_KERNEL);
+ if (!init)
+ goto free;
+
+ init->ops = &ti_fapll_ops;
+ init->name = node->name;
+
+ init->num_parents = of_clk_get_parent_count(node);
+ if (init->num_parents != 2) {
+ pr_err("%s must have two parents\n", node->name);
+ goto free;
+ }
+
+ parent_name[0] = of_clk_get_parent_name(node, 0);
+ parent_name[1] = of_clk_get_parent_name(node, 1);
+ init->parent_names = parent_name;
+
+ fd->clk_ref = of_clk_get(node, 0);
+ if (IS_ERR(fd->clk_ref)) {
+ pr_err("%s could not get clk_ref\n", node->name);
+ goto free;
+ }
+
+ fd->clk_bypass = of_clk_get(node, 1);
+ if (IS_ERR(fd->clk_bypass)) {
+ pr_err("%s could not get clk_bypass\n", node->name);
+ goto free;
+ }
+
+ fd->base = of_iomap(node, 0);
+ if (!fd->base) {
+ pr_err("%s could not get IO base\n", node->name);
+ goto free;
+ }
+
+ if (fapll_is_ddr_pll(fd->base))
+ fd->bypass_bit_inverted = true;
+
+ fd->name = node->name;
+ fd->hw.init = init;
+
+ /* Register the parent PLL */
+ pll_clk = clk_register(NULL, &fd->hw);
+ if (IS_ERR(pll_clk))
+ goto unmap;
+
+ fd->outputs.clks[0] = pll_clk;
+ fd->outputs.clk_num++;
+
+ /*
+ * Set up the child synthesizers starting at index 1 as the
+ * PLL output is at index 0. We need to check the clock-indices
+ * for numbering in case there are holes in the synth mapping,
+ * and then probe the synth register to see if it has a FREQ
+ * register available.
+ */
+ for (i = 0; i < MAX_FAPLL_OUTPUTS; i++) {
+ const char *output_name;
+ void __iomem *freq, *div;
+ struct clk *synth_clk;
+ int output_instance;
+ u32 v;
+
+ if (of_property_read_string_index(node, "clock-output-names",
+ i, &output_name))
+ continue;
+
+ if (of_property_read_u32_index(node, "clock-indices", i,
+ &output_instance))
+ output_instance = i;
+
+ freq = fd->base + (output_instance * 8);
+ div = freq + 4;
+
+ /* Check for hardwired audio_pll_clk1 */
+ if (is_audio_pll_clk1(freq)) {
+ freq = 0;
+ div = 0;
+ } else {
+ /* Does the synthesizer have a FREQ register? */
+ v = readl_relaxed(freq);
+ if (!v)
+ freq = 0;
+ }
+ synth_clk = ti_fapll_synth_setup(fd, freq, div, output_instance,
+ output_name, node->name,
+ pll_clk);
+ if (IS_ERR(synth_clk))
+ continue;
+
+ fd->outputs.clks[output_instance] = synth_clk;
+ fd->outputs.clk_num++;
+
+ clk_register_clkdev(synth_clk, output_name, NULL);
+ }
+
+ /* Register the child synthesizers as the FAPLL outputs */
+ of_clk_add_provider(node, of_clk_src_onecell_get, &fd->outputs);
+ /* Add clock alias for the outputs */
+
+ kfree(init);
+
+ return;
+
+unmap:
+ iounmap(fd->base);
+free:
+ if (fd->clk_bypass)
+ clk_put(fd->clk_bypass);
+ if (fd->clk_ref)
+ clk_put(fd->clk_ref);
+ kfree(fd->outputs.clks);
+ kfree(fd);
+ kfree(init);
+}
+
+CLK_OF_DECLARE(ti_fapll_clock, "ti,dm816-fapll-clock", ti_fapll_setup);
diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c
index b326d2797feb..d493307b73f4 100644
--- a/drivers/clk/ti/gate.c
+++ b/drivers/clk/ti/gate.c
@@ -22,6 +22,8 @@
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
#undef pr_fmt
@@ -90,63 +92,164 @@ static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk)
return ret;
}
-static void __init _of_ti_gate_clk_setup(struct device_node *node,
- const struct clk_ops *ops,
- const struct clk_hw_omap_ops *hw_ops)
+static struct clk *_register_gate(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 bit_idx,
+ u8 clk_gate_flags, const struct clk_ops *ops,
+ const struct clk_hw_omap_ops *hw_ops)
{
- struct clk *clk;
struct clk_init_data init = { NULL };
struct clk_hw_omap *clk_hw;
- const char *clk_name = node->name;
- const char *parent_name;
- u32 val;
+ struct clk *clk;
clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
if (!clk_hw)
- return;
+ return ERR_PTR(-ENOMEM);
clk_hw->hw.init = &init;
- init.name = clk_name;
+ init.name = name;
init.ops = ops;
- if (ops != &omap_gate_clkdm_clk_ops) {
- clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0);
- if (!clk_hw->enable_reg)
- goto cleanup;
+ clk_hw->enable_reg = reg;
+ clk_hw->enable_bit = bit_idx;
+ clk_hw->ops = hw_ops;
- if (!of_property_read_u32(node, "ti,bit-shift", &val))
- clk_hw->enable_bit = val;
+ clk_hw->flags = MEMMAP_ADDRESSING | clk_gate_flags;
+
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ init.flags = flags;
+
+ clk = clk_register(NULL, &clk_hw->hw);
+
+ if (IS_ERR(clk))
+ kfree(clk_hw);
+
+ return clk;
+}
+
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+struct clk *ti_clk_register_gate(struct ti_clk *setup)
+{
+ const struct clk_ops *ops = &omap_gate_clk_ops;
+ const struct clk_hw_omap_ops *hw_ops = NULL;
+ u32 reg;
+ struct clk_omap_reg *reg_setup;
+ u32 flags = 0;
+ u8 clk_gate_flags = 0;
+ struct ti_clk_gate *gate;
+
+ gate = setup->data;
+
+ if (gate->flags & CLKF_INTERFACE)
+ return ti_clk_register_interface(setup);
+
+ reg_setup = (struct clk_omap_reg *)&reg;
+
+ if (gate->flags & CLKF_SET_RATE_PARENT)
+ flags |= CLK_SET_RATE_PARENT;
+
+ if (gate->flags & CLKF_SET_BIT_TO_DISABLE)
+ clk_gate_flags |= INVERT_ENABLE;
+
+ if (gate->flags & CLKF_HSDIV) {
+ ops = &omap_gate_clk_hsdiv_restore_ops;
+ hw_ops = &clkhwops_wait;
}
- clk_hw->ops = hw_ops;
+ if (gate->flags & CLKF_DSS)
+ hw_ops = &clkhwops_omap3430es2_dss_usbhost_wait;
+
+ if (gate->flags & CLKF_WAIT)
+ hw_ops = &clkhwops_wait;
+
+ if (gate->flags & CLKF_CLKDM)
+ ops = &omap_gate_clkdm_clk_ops;
+
+ if (gate->flags & CLKF_AM35XX)
+ hw_ops = &clkhwops_am35xx_ipss_module_wait;
- clk_hw->flags = MEMMAP_ADDRESSING;
+ reg_setup->index = gate->module;
+ reg_setup->offset = gate->reg;
+
+ return _register_gate(NULL, setup->name, gate->parent, flags,
+ (void __iomem *)reg, gate->bit_shift,
+ clk_gate_flags, ops, hw_ops);
+}
+
+struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup)
+{
+ struct clk_hw_omap *gate;
+ struct clk_omap_reg *reg;
+ const struct clk_hw_omap_ops *ops = &clkhwops_wait;
+
+ if (!setup)
+ return NULL;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ reg = (struct clk_omap_reg *)&gate->enable_reg;
+ reg->index = setup->module;
+ reg->offset = setup->reg;
+
+ gate->enable_bit = setup->bit_shift;
+
+ if (setup->flags & CLKF_NO_WAIT)
+ ops = NULL;
+
+ if (setup->flags & CLKF_INTERFACE)
+ ops = &clkhwops_iclk_wait;
+
+ gate->ops = ops;
+ gate->flags = MEMMAP_ADDRESSING;
+
+ return &gate->hw;
+}
+#endif
+
+static void __init _of_ti_gate_clk_setup(struct device_node *node,
+ const struct clk_ops *ops,
+ const struct clk_hw_omap_ops *hw_ops)
+{
+ struct clk *clk;
+ const char *parent_name;
+ void __iomem *reg = NULL;
+ u8 enable_bit = 0;
+ u32 val;
+ u32 flags = 0;
+ u8 clk_gate_flags = 0;
+
+ if (ops != &omap_gate_clkdm_clk_ops) {
+ reg = ti_clk_get_reg_addr(node, 0);
+ if (!reg)
+ return;
+
+ if (!of_property_read_u32(node, "ti,bit-shift", &val))
+ enable_bit = val;
+ }
if (of_clk_get_parent_count(node) != 1) {
- pr_err("%s must have 1 parent\n", clk_name);
- goto cleanup;
+ pr_err("%s must have 1 parent\n", node->name);
+ return;
}
parent_name = of_clk_get_parent_name(node, 0);
- init.parent_names = &parent_name;
- init.num_parents = 1;
if (of_property_read_bool(node, "ti,set-rate-parent"))
- init.flags |= CLK_SET_RATE_PARENT;
+ flags |= CLK_SET_RATE_PARENT;
if (of_property_read_bool(node, "ti,set-bit-to-disable"))
- clk_hw->flags |= INVERT_ENABLE;
+ clk_gate_flags |= INVERT_ENABLE;
- clk = clk_register(NULL, &clk_hw->hw);
+ clk = _register_gate(NULL, node->name, parent_name, flags, reg,
+ enable_bit, clk_gate_flags, ops, hw_ops);
- if (!IS_ERR(clk)) {
+ if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
- return;
- }
-
-cleanup:
- kfree(clk_hw);
}
static void __init
diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c
index 9c3e8c4aaa40..265d91f071c5 100644
--- a/drivers/clk/ti/interface.c
+++ b/drivers/clk/ti/interface.c
@@ -20,6 +20,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -31,53 +32,102 @@ static const struct clk_ops ti_interface_clk_ops = {
.is_enabled = &omap2_dflt_clk_is_enabled,
};
-static void __init _of_ti_interface_clk_setup(struct device_node *node,
- const struct clk_hw_omap_ops *ops)
+static struct clk *_register_interface(struct device *dev, const char *name,
+ const char *parent_name,
+ void __iomem *reg, u8 bit_idx,
+ const struct clk_hw_omap_ops *ops)
{
- struct clk *clk;
struct clk_init_data init = { NULL };
struct clk_hw_omap *clk_hw;
- const char *parent_name;
- u32 val;
+ struct clk *clk;
clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
if (!clk_hw)
- return;
+ return ERR_PTR(-ENOMEM);
clk_hw->hw.init = &init;
clk_hw->ops = ops;
clk_hw->flags = MEMMAP_ADDRESSING;
+ clk_hw->enable_reg = reg;
+ clk_hw->enable_bit = bit_idx;
- clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0);
- if (!clk_hw->enable_reg)
- goto cleanup;
-
- if (!of_property_read_u32(node, "ti,bit-shift", &val))
- clk_hw->enable_bit = val;
-
- init.name = node->name;
+ init.name = name;
init.ops = &ti_interface_clk_ops;
init.flags = 0;
- parent_name = of_clk_get_parent_name(node, 0);
- if (!parent_name) {
- pr_err("%s must have a parent\n", node->name);
- goto cleanup;
- }
-
init.num_parents = 1;
init.parent_names = &parent_name;
clk = clk_register(NULL, &clk_hw->hw);
- if (!IS_ERR(clk)) {
- of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ if (IS_ERR(clk))
+ kfree(clk_hw);
+ else
omap2_init_clk_hw_omap_clocks(clk);
+
+ return clk;
+}
+
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+struct clk *ti_clk_register_interface(struct ti_clk *setup)
+{
+ const struct clk_hw_omap_ops *ops = &clkhwops_iclk_wait;
+ u32 reg;
+ struct clk_omap_reg *reg_setup;
+ struct ti_clk_gate *gate;
+
+ gate = setup->data;
+ reg_setup = (struct clk_omap_reg *)&reg;
+ reg_setup->index = gate->module;
+ reg_setup->offset = gate->reg;
+
+ if (gate->flags & CLKF_NO_WAIT)
+ ops = &clkhwops_iclk;
+
+ if (gate->flags & CLKF_HSOTGUSB)
+ ops = &clkhwops_omap3430es2_iclk_hsotgusb_wait;
+
+ if (gate->flags & CLKF_DSS)
+ ops = &clkhwops_omap3430es2_iclk_dss_usbhost_wait;
+
+ if (gate->flags & CLKF_SSI)
+ ops = &clkhwops_omap3430es2_iclk_ssi_wait;
+
+ if (gate->flags & CLKF_AM35XX)
+ ops = &clkhwops_am35xx_ipss_wait;
+
+ return _register_interface(NULL, setup->name, gate->parent,
+ (void __iomem *)reg, gate->bit_shift, ops);
+}
+#endif
+
+static void __init _of_ti_interface_clk_setup(struct device_node *node,
+ const struct clk_hw_omap_ops *ops)
+{
+ struct clk *clk;
+ const char *parent_name;
+ void __iomem *reg;
+ u8 enable_bit = 0;
+ u32 val;
+
+ reg = ti_clk_get_reg_addr(node, 0);
+ if (!reg)
+ return;
+
+ if (!of_property_read_u32(node, "ti,bit-shift", &val))
+ enable_bit = val;
+
+ parent_name = of_clk_get_parent_name(node, 0);
+ if (!parent_name) {
+ pr_err("%s must have a parent\n", node->name);
return;
}
-cleanup:
- kfree(clk_hw);
+ clk = _register_interface(NULL, node->name, parent_name, reg,
+ enable_bit, ops);
+
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
static void __init of_ti_interface_clk_setup(struct device_node *node)
diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c
index e9d650e51287..728e253606bc 100644
--- a/drivers/clk/ti/mux.c
+++ b/drivers/clk/ti/mux.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -144,6 +145,39 @@ static struct clk *_register_mux(struct device *dev, const char *name,
return clk;
}
+struct clk *ti_clk_register_mux(struct ti_clk *setup)
+{
+ struct ti_clk_mux *mux;
+ u32 flags;
+ u8 mux_flags = 0;
+ struct clk_omap_reg *reg_setup;
+ u32 reg;
+ u32 mask;
+
+ reg_setup = (struct clk_omap_reg *)&reg;
+
+ mux = setup->data;
+ flags = CLK_SET_RATE_NO_REPARENT;
+
+ mask = mux->num_parents;
+ if (!(mux->flags & CLKF_INDEX_STARTS_AT_ONE))
+ mask--;
+
+ mask = (1 << fls(mask)) - 1;
+ reg_setup->index = mux->module;
+ reg_setup->offset = mux->reg;
+
+ if (mux->flags & CLKF_INDEX_STARTS_AT_ONE)
+ mux_flags |= CLK_MUX_INDEX_ONE;
+
+ if (mux->flags & CLKF_SET_RATE_PARENT)
+ flags |= CLK_SET_RATE_PARENT;
+
+ return _register_mux(NULL, setup->name, mux->parents, mux->num_parents,
+ flags, (void __iomem *)reg, mux->bit_shift, mask,
+ mux_flags, NULL, NULL);
+}
+
/**
* of_mux_clk_setup - Setup function for simple mux rate clock
* @node: DT node for the clock
@@ -194,8 +228,9 @@ static void of_mux_clk_setup(struct device_node *node)
mask = (1 << fls(mask)) - 1;
- clk = _register_mux(NULL, node->name, parent_names, num_parents, flags,
- reg, shift, mask, clk_mux_flags, NULL, NULL);
+ clk = _register_mux(NULL, node->name, parent_names, num_parents,
+ flags, reg, shift, mask, clk_mux_flags, NULL,
+ NULL);
if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
@@ -205,6 +240,37 @@ cleanup:
}
CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup);
+struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup)
+{
+ struct clk_mux *mux;
+ struct clk_omap_reg *reg;
+ int num_parents;
+
+ if (!setup)
+ return NULL;
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+
+ reg = (struct clk_omap_reg *)&mux->reg;
+
+ mux->shift = setup->bit_shift;
+
+ reg->index = setup->module;
+ reg->offset = setup->reg;
+
+ if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
+ mux->flags |= CLK_MUX_INDEX_ONE;
+
+ num_parents = setup->num_parents;
+
+ mux->mask = num_parents - 1;
+ mux->mask = (1 << fls(mux->mask)) - 1;
+
+ return &mux->hw;
+}
+
static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
{
struct clk_mux *mux;
diff --git a/drivers/clk/ux500/clk-prcc.c b/drivers/clk/ux500/clk-prcc.c
index bd4769a84485..0e950769ed03 100644
--- a/drivers/clk/ux500/clk-prcc.c
+++ b/drivers/clk/ux500/clk-prcc.c
@@ -8,7 +8,6 @@
*/
#include <linux/clk-provider.h>
-#include <linux/clk-private.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c
index e2d63bc47436..bf63c96acb1a 100644
--- a/drivers/clk/ux500/clk-prcmu.c
+++ b/drivers/clk/ux500/clk-prcmu.c
@@ -8,7 +8,6 @@
*/
#include <linux/clk-provider.h>
-#include <linux/clk-private.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/slab.h>
#include <linux/io.h>
diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c
index 9037bebd69f7..f870aad57711 100644
--- a/drivers/clk/zynq/clkc.c
+++ b/drivers/clk/zynq/clkc.c
@@ -303,6 +303,7 @@ static void __init zynq_clk_setup(struct device_node *np)
clks[cpu_2x] = clk_register_gate(NULL, clk_output_name[cpu_2x],
"cpu_2x_div", CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL,
26, 0, &armclk_lock);
+ clk_prepare_enable(clks[cpu_2x]);
clk = clk_register_fixed_factor(NULL, "cpu_1x_div", "cpu_div", 0, 1,
4 + 2 * tmp);
diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
index 72564b701b4a..7ea24413cee6 100644
--- a/drivers/cpufreq/Kconfig.powerpc
+++ b/drivers/cpufreq/Kconfig.powerpc
@@ -26,7 +26,7 @@ config CPU_FREQ_MAPLE
config PPC_CORENET_CPUFREQ
tristate "CPU frequency scaling driver for Freescale E500MC SoCs"
depends on PPC_E500MC && OF && COMMON_CLK
- select CLK_PPC_CORENET
+ select CLK_QORIQ
help
This adds the CPUFreq driver support for Freescale e500mc,
e5500 and e6500 series SoCs which are capable of changing
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index 6af0a28ba37d..e8a4218b5726 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -21,8 +21,6 @@
#include <linux/err.h>
#include <linux/clk.h>
-#include <linux/clk/sunxi.h>
-
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
@@ -229,6 +227,8 @@ struct sunxi_mmc_host {
/* clock management */
struct clk *clk_ahb;
struct clk *clk_mmc;
+ struct clk *clk_sample;
+ struct clk *clk_output;
/* irq */
spinlock_t lock;
@@ -653,26 +653,31 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
/* determine delays */
if (rate <= 400000) {
- oclk_dly = 0;
- sclk_dly = 7;
+ oclk_dly = 180;
+ sclk_dly = 42;
} else if (rate <= 25000000) {
- oclk_dly = 0;
- sclk_dly = 5;
+ oclk_dly = 180;
+ sclk_dly = 75;
} else if (rate <= 50000000) {
if (ios->timing == MMC_TIMING_UHS_DDR50) {
- oclk_dly = 2;
- sclk_dly = 4;
+ oclk_dly = 60;
+ sclk_dly = 120;
} else {
- oclk_dly = 3;
- sclk_dly = 5;
+ oclk_dly = 90;
+ sclk_dly = 150;
}
+ } else if (rate <= 100000000) {
+ oclk_dly = 6;
+ sclk_dly = 24;
+ } else if (rate <= 200000000) {
+ oclk_dly = 3;
+ sclk_dly = 12;
} else {
- /* rate > 50000000 */
- oclk_dly = 2;
- sclk_dly = 4;
+ return -EINVAL;
}
- clk_sunxi_mmc_phase_control(host->clk_mmc, sclk_dly, oclk_dly);
+ clk_set_phase(host->clk_sample, sclk_dly);
+ clk_set_phase(host->clk_output, oclk_dly);
return sunxi_mmc_oclk_onoff(host, 1);
}
@@ -913,6 +918,18 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
return PTR_ERR(host->clk_mmc);
}
+ host->clk_output = devm_clk_get(&pdev->dev, "output");
+ if (IS_ERR(host->clk_output)) {
+ dev_err(&pdev->dev, "Could not get output clock\n");
+ return PTR_ERR(host->clk_output);
+ }
+
+ host->clk_sample = devm_clk_get(&pdev->dev, "sample");
+ if (IS_ERR(host->clk_sample)) {
+ dev_err(&pdev->dev, "Could not get sample clock\n");
+ return PTR_ERR(host->clk_sample);
+ }
+
host->reset = devm_reset_control_get(&pdev->dev, "ahb");
ret = clk_prepare_enable(host->clk_ahb);
@@ -927,11 +944,23 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
goto error_disable_clk_ahb;
}
+ ret = clk_prepare_enable(host->clk_output);
+ if (ret) {
+ dev_err(&pdev->dev, "Enable output clk err %d\n", ret);
+ goto error_disable_clk_mmc;
+ }
+
+ ret = clk_prepare_enable(host->clk_sample);
+ if (ret) {
+ dev_err(&pdev->dev, "Enable sample clk err %d\n", ret);
+ goto error_disable_clk_output;
+ }
+
if (!IS_ERR(host->reset)) {
ret = reset_control_deassert(host->reset);
if (ret) {
dev_err(&pdev->dev, "reset err %d\n", ret);
- goto error_disable_clk_mmc;
+ goto error_disable_clk_sample;
}
}
@@ -950,6 +979,10 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
error_assert_reset:
if (!IS_ERR(host->reset))
reset_control_assert(host->reset);
+error_disable_clk_sample:
+ clk_disable_unprepare(host->clk_sample);
+error_disable_clk_output:
+ clk_disable_unprepare(host->clk_output);
error_disable_clk_mmc:
clk_disable_unprepare(host->clk_mmc);
error_disable_clk_ahb: