diff options
Diffstat (limited to 'drivers/clk/ti')
-rw-r--r-- | drivers/clk/ti/Makefile | 11 | ||||
-rw-r--r-- | drivers/clk/ti/apll.c | 223 | ||||
-rw-r--r-- | drivers/clk/ti/autoidle.c | 133 | ||||
-rw-r--r-- | drivers/clk/ti/clk-33xx.c | 161 | ||||
-rw-r--r-- | drivers/clk/ti/clk-3xxx.c | 401 | ||||
-rw-r--r-- | drivers/clk/ti/clk-43xx.c | 118 | ||||
-rw-r--r-- | drivers/clk/ti/clk-44xx.c | 316 | ||||
-rw-r--r-- | drivers/clk/ti/clk-54xx.c | 255 | ||||
-rw-r--r-- | drivers/clk/ti/clk-7xx.c | 332 | ||||
-rw-r--r-- | drivers/clk/ti/clk.c | 167 | ||||
-rw-r--r-- | drivers/clk/ti/clockdomain.c | 70 | ||||
-rw-r--r-- | drivers/clk/ti/composite.c | 269 | ||||
-rw-r--r-- | drivers/clk/ti/divider.c | 487 | ||||
-rw-r--r-- | drivers/clk/ti/dpll.c | 558 | ||||
-rw-r--r-- | drivers/clk/ti/fixed-factor.c | 66 | ||||
-rw-r--r-- | drivers/clk/ti/gate.c | 249 | ||||
-rw-r--r-- | drivers/clk/ti/interface.c | 125 | ||||
-rw-r--r-- | drivers/clk/ti/mux.c | 246 |
18 files changed, 4187 insertions, 0 deletions
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile new file mode 100644 index 000000000000..4319d4031aa3 --- /dev/null +++ b/drivers/clk/ti/Makefile @@ -0,0 +1,11 @@ +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_ARCH_OMAP3) += $(clk-common) interface.o clk-3xxx.o +obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o +obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o +obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o +obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o +endif diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c new file mode 100644 index 000000000000..b986f61f5a77 --- /dev/null +++ b/drivers/clk/ti/apll.c @@ -0,0 +1,223 @@ +/* + * OMAP APLL clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * J Keerthy <j-keerthy@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/string.h> +#include <linux/log2.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> +#include <linux/delay.h> + +#define APLL_FORCE_LOCK 0x1 +#define APLL_AUTO_IDLE 0x2 +#define MAX_APLL_WAIT_TRIES 1000000 + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static int dra7_apll_enable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + int r = 0, i = 0; + struct dpll_data *ad; + const char *clk_name; + u8 state = 1; + u32 v; + + ad = clk->dpll_data; + if (!ad) + return -EINVAL; + + clk_name = __clk_get_name(clk->hw.clk); + + state <<= __ffs(ad->idlest_mask); + + /* Check is already locked */ + v = ti_clk_ll_ops->clk_readl(ad->idlest_reg); + + if ((v & ad->idlest_mask) == state) + return r; + + v = ti_clk_ll_ops->clk_readl(ad->control_reg); + v &= ~ad->enable_mask; + v |= APLL_FORCE_LOCK << __ffs(ad->enable_mask); + ti_clk_ll_ops->clk_writel(v, ad->control_reg); + + state <<= __ffs(ad->idlest_mask); + + while (1) { + v = ti_clk_ll_ops->clk_readl(ad->idlest_reg); + if ((v & ad->idlest_mask) == state) + break; + if (i > MAX_APLL_WAIT_TRIES) + break; + i++; + udelay(1); + } + + if (i == MAX_APLL_WAIT_TRIES) { + pr_warn("clock: %s failed transition to '%s'\n", + clk_name, (state) ? "locked" : "bypassed"); + } else { + pr_debug("clock: %s transition to '%s' in %d loops\n", + clk_name, (state) ? "locked" : "bypassed", i); + + r = 0; + } + + return r; +} + +static void dra7_apll_disable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *ad; + u8 state = 1; + u32 v; + + ad = clk->dpll_data; + + state <<= __ffs(ad->idlest_mask); + + v = ti_clk_ll_ops->clk_readl(ad->control_reg); + v &= ~ad->enable_mask; + v |= APLL_AUTO_IDLE << __ffs(ad->enable_mask); + ti_clk_ll_ops->clk_writel(v, ad->control_reg); +} + +static int dra7_apll_is_enabled(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *ad; + u32 v; + + ad = clk->dpll_data; + + v = ti_clk_ll_ops->clk_readl(ad->control_reg); + v &= ad->enable_mask; + + v >>= __ffs(ad->enable_mask); + + return v == APLL_AUTO_IDLE ? 0 : 1; +} + +static u8 dra7_init_apll_parent(struct clk_hw *hw) +{ + return 0; +} + +static const struct clk_ops apll_ck_ops = { + .enable = &dra7_apll_enable, + .disable = &dra7_apll_disable, + .is_enabled = &dra7_apll_is_enabled, + .get_parent = &dra7_init_apll_parent, +}; + +static void __init omap_clk_register_apll(struct clk_hw *hw, + struct device_node *node) +{ + struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw); + struct dpll_data *ad = clk_hw->dpll_data; + struct clk *clk; + + ad->clk_ref = of_clk_get(node, 0); + ad->clk_bypass = of_clk_get(node, 1); + + if (IS_ERR(ad->clk_ref) || IS_ERR(ad->clk_bypass)) { + pr_debug("clk-ref or clk-bypass for %s not ready, retry\n", + node->name); + if (!ti_clk_retry_init(node, hw, omap_clk_register_apll)) + return; + + goto cleanup; + } + + clk = clk_register(NULL, &clk_hw->hw); + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + kfree(clk_hw->hw.init->parent_names); + kfree(clk_hw->hw.init); + return; + } + +cleanup: + kfree(clk_hw->dpll_data); + kfree(clk_hw->hw.init->parent_names); + kfree(clk_hw->hw.init); + kfree(clk_hw); +} + +static void __init of_dra7_apll_setup(struct device_node *node) +{ + struct dpll_data *ad = NULL; + struct clk_hw_omap *clk_hw = NULL; + struct clk_init_data *init = NULL; + const char **parent_names = NULL; + int i; + + ad = kzalloc(sizeof(*ad), GFP_KERNEL); + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + init = kzalloc(sizeof(*init), GFP_KERNEL); + if (!ad || !clk_hw || !init) + goto cleanup; + + clk_hw->dpll_data = ad; + clk_hw->hw.init = init; + clk_hw->flags = MEMMAP_ADDRESSING; + + init->name = node->name; + init->ops = &apll_ck_ops; + + init->num_parents = of_clk_get_parent_count(node); + if (init->num_parents < 1) { + pr_err("dra7 apll %s must have parent(s)\n", node->name); + goto cleanup; + } + + parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL); + if (!parent_names) + goto cleanup; + + for (i = 0; i < init->num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + init->parent_names = parent_names; + + ad->control_reg = ti_clk_get_reg_addr(node, 0); + ad->idlest_reg = ti_clk_get_reg_addr(node, 1); + + if (!ad->control_reg || !ad->idlest_reg) + goto cleanup; + + ad->idlest_mask = 0x1; + ad->enable_mask = 0x3; + + omap_clk_register_apll(&clk_hw->hw, node); + return; + +cleanup: + kfree(parent_names); + kfree(ad); + kfree(clk_hw); + kfree(init); +} +CLK_OF_DECLARE(dra7_apll_clock, "ti,dra7-apll-clock", of_dra7_apll_setup); diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c new file mode 100644 index 000000000000..8912ff80af34 --- /dev/null +++ b/drivers/clk/ti/autoidle.c @@ -0,0 +1,133 @@ +/* + * TI clock autoidle support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +struct clk_ti_autoidle { + void __iomem *reg; + u8 shift; + u8 flags; + const char *name; + struct list_head node; +}; + +#define AUTOIDLE_LOW 0x1 + +static LIST_HEAD(autoidle_clks); + +static void ti_allow_autoidle(struct clk_ti_autoidle *clk) +{ + u32 val; + + val = ti_clk_ll_ops->clk_readl(clk->reg); + + if (clk->flags & AUTOIDLE_LOW) + val &= ~(1 << clk->shift); + else + val |= (1 << clk->shift); + + ti_clk_ll_ops->clk_writel(val, clk->reg); +} + +static void ti_deny_autoidle(struct clk_ti_autoidle *clk) +{ + u32 val; + + val = ti_clk_ll_ops->clk_readl(clk->reg); + + if (clk->flags & AUTOIDLE_LOW) + val |= (1 << clk->shift); + else + val &= ~(1 << clk->shift); + + ti_clk_ll_ops->clk_writel(val, clk->reg); +} + +/** + * of_ti_clk_allow_autoidle_all - enable autoidle for all clocks + * + * Enables hardware autoidle for all registered DT clocks, which have + * the feature. + */ +void of_ti_clk_allow_autoidle_all(void) +{ + struct clk_ti_autoidle *c; + + list_for_each_entry(c, &autoidle_clks, node) + ti_allow_autoidle(c); +} + +/** + * of_ti_clk_deny_autoidle_all - disable autoidle for all clocks + * + * Disables hardware autoidle for all registered DT clocks, which have + * the feature. + */ +void of_ti_clk_deny_autoidle_all(void) +{ + struct clk_ti_autoidle *c; + + list_for_each_entry(c, &autoidle_clks, node) + ti_deny_autoidle(c); +} + +/** + * of_ti_clk_autoidle_setup - sets up hardware autoidle for a clock + * @node: pointer to the clock device node + * + * Checks if a clock has hardware autoidle support or not (check + * for presence of 'ti,autoidle-shift' property in the device tree + * node) and sets up the hardware autoidle feature for the clock + * if available. If autoidle is available, the clock is also added + * to the autoidle list for later processing. Returns 0 on success, + * negative error value on failure. + */ +int __init of_ti_clk_autoidle_setup(struct device_node *node) +{ + u32 shift; + struct clk_ti_autoidle *clk; + + /* Check if this clock has autoidle support or not */ + if (of_property_read_u32(node, "ti,autoidle-shift", &shift)) + return 0; + + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + + if (!clk) + return -ENOMEM; + + clk->shift = shift; + clk->name = node->name; + clk->reg = ti_clk_get_reg_addr(node, 0); + + if (!clk->reg) { + kfree(clk); + return -EINVAL; + } + + if (of_property_read_bool(node, "ti,invert-autoidle-bit")) + clk->flags |= AUTOIDLE_LOW; + + list_add(&clk->node, &autoidle_clks); + + return 0; +} diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c new file mode 100644 index 000000000000..776ee4594bd4 --- /dev/null +++ b/drivers/clk/ti/clk-33xx.c @@ -0,0 +1,161 @@ +/* + * AM33XX Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/clk-provider.h> +#include <linux/clk/ti.h> + +static struct ti_dt_clk am33xx_clks[] = { + DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), + DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_24000000_ck", "virt_24000000_ck"), + DT_CLK(NULL, "virt_25000000_ck", "virt_25000000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"), + DT_CLK(NULL, "tclkin_ck", "tclkin_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_m4_ck", "dpll_core_m4_ck"), + DT_CLK(NULL, "dpll_core_m5_ck", "dpll_core_m5_ck"), + DT_CLK(NULL, "dpll_core_m6_ck", "dpll_core_m6_ck"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK("cpu0", NULL, "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"), + DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"), + DT_CLK(NULL, "dpll_ddr_m2_div2_ck", "dpll_ddr_m2_div2_ck"), + DT_CLK(NULL, "dpll_disp_ck", "dpll_disp_ck"), + DT_CLK(NULL, "dpll_disp_m2_ck", "dpll_disp_m2_ck"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "dpll_per_m2_div4_wkupdm_ck", "dpll_per_m2_div4_wkupdm_ck"), + DT_CLK(NULL, "dpll_per_m2_div4_ck", "dpll_per_m2_div4_ck"), + DT_CLK(NULL, "adc_tsc_fck", "adc_tsc_fck"), + DT_CLK(NULL, "cefuse_fck", "cefuse_fck"), + DT_CLK(NULL, "clkdiv32k_ck", "clkdiv32k_ck"), + DT_CLK(NULL, "clkdiv32k_ick", "clkdiv32k_ick"), + DT_CLK(NULL, "dcan0_fck", "dcan0_fck"), + DT_CLK("481cc000.d_can", NULL, "dcan0_fck"), + DT_CLK(NULL, "dcan1_fck", "dcan1_fck"), + DT_CLK("481d0000.d_can", NULL, "dcan1_fck"), + DT_CLK(NULL, "pruss_ocp_gclk", "pruss_ocp_gclk"), + DT_CLK(NULL, "mcasp0_fck", "mcasp0_fck"), + DT_CLK(NULL, "mcasp1_fck", "mcasp1_fck"), + DT_CLK(NULL, "mmu_fck", "mmu_fck"), + DT_CLK(NULL, "smartreflex0_fck", "smartreflex0_fck"), + DT_CLK(NULL, "smartreflex1_fck", "smartreflex1_fck"), + DT_CLK(NULL, "sha0_fck", "sha0_fck"), + DT_CLK(NULL, "aes0_fck", "aes0_fck"), + DT_CLK(NULL, "rng_fck", "rng_fck"), + 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, "usbotg_fck", "usbotg_fck"), + DT_CLK(NULL, "ieee5000_fck", "ieee5000_fck"), + DT_CLK(NULL, "wdt1_fck", "wdt1_fck"), + DT_CLK(NULL, "l4_rtc_gclk", "l4_rtc_gclk"), + DT_CLK(NULL, "l3_gclk", "l3_gclk"), + DT_CLK(NULL, "dpll_core_m4_div2_ck", "dpll_core_m4_div2_ck"), + DT_CLK(NULL, "l4hs_gclk", "l4hs_gclk"), + DT_CLK(NULL, "l3s_gclk", "l3s_gclk"), + DT_CLK(NULL, "l4fw_gclk", "l4fw_gclk"), + DT_CLK(NULL, "l4ls_gclk", "l4ls_gclk"), + DT_CLK(NULL, "clk_24mhz", "clk_24mhz"), + DT_CLK(NULL, "sysclk_div_ck", "sysclk_div_ck"), + DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"), + DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"), + DT_CLK(NULL, "gpio0_dbclk_mux_ck", "gpio0_dbclk_mux_ck"), + DT_CLK(NULL, "gpio0_dbclk", "gpio0_dbclk"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "lcd_gclk", "lcd_gclk"), + DT_CLK(NULL, "mmc_clk", "mmc_clk"), + DT_CLK(NULL, "gfx_fclk_clksel_ck", "gfx_fclk_clksel_ck"), + DT_CLK(NULL, "gfx_fck_div_ck", "gfx_fck_div_ck"), + DT_CLK(NULL, "sysclkout_pre_ck", "sysclkout_pre_ck"), + DT_CLK(NULL, "clkout2_div_ck", "clkout2_div_ck"), + DT_CLK(NULL, "timer_32k_ck", "clkdiv32k_ick"), + DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"), + DT_CLK(NULL, "dbg_sysclk_ck", "dbg_sysclk_ck"), + DT_CLK(NULL, "dbg_clka_ck", "dbg_clka_ck"), + DT_CLK(NULL, "stm_pmd_clock_mux_ck", "stm_pmd_clock_mux_ck"), + DT_CLK(NULL, "trace_pmd_clk_mux_ck", "trace_pmd_clk_mux_ck"), + DT_CLK(NULL, "stm_clk_div_ck", "stm_clk_div_ck"), + DT_CLK(NULL, "trace_clk_div_ck", "trace_clk_div_ck"), + DT_CLK(NULL, "clkout2_ck", "clkout2_ck"), + DT_CLK("48300200.ehrpwm", "tbclk", "ehrpwm0_tbclk"), + DT_CLK("48302200.ehrpwm", "tbclk", "ehrpwm1_tbclk"), + DT_CLK("48304200.ehrpwm", "tbclk", "ehrpwm2_tbclk"), + { .node_name = NULL }, +}; + +static const char *enable_init_clks[] = { + "dpll_ddr_m2_ck", + "dpll_mpu_m2_ck", + "l3_gclk", + "l4hs_gclk", + "l4fw_gclk", + "l4ls_gclk", + /* Required for external peripherals like, Audio codecs */ + "clkout2_ck", +}; + +int __init am33xx_dt_clk_init(void) +{ + struct clk *clk1, *clk2; + + ti_dt_clocks_register(am33xx_clks); + + omap2_clk_disable_autoidle_all(); + + omap2_clk_enable_init_clocks(enable_init_clks, + ARRAY_SIZE(enable_init_clks)); + + /* TRM ERRATA: Timer 3 & 6 default parent (TCLKIN) may not be always + * physically present, in such a case HWMOD enabling of + * clock would be failure with default parent. And timer + * probe thinks clock is already enabled, this leads to + * crash upon accessing timer 3 & 6 registers in probe. + * Fix by setting parent of both these timers to master + * oscillator clock. + */ + + clk1 = clk_get_sys(NULL, "sys_clkin_ck"); + clk2 = clk_get_sys(NULL, "timer3_fck"); + clk_set_parent(clk2, clk1); + + clk2 = clk_get_sys(NULL, "timer6_fck"); + clk_set_parent(clk2, clk1); + /* + * The On-Chip 32K RC Osc clock is not an accurate clock-source as per + * the design/spec, so as a result, for example, timer which supposed + * to get expired @60Sec, but will expire somewhere ~@40Sec, which is + * not expected by any use-case, so change WDT1 clock source to PRCM + * 32KHz clock. + */ + clk1 = clk_get_sys(NULL, "wdt1_fck"); + clk2 = clk_get_sys(NULL, "clkdiv32k_ick"); + clk_set_parent(clk1, clk2); + + return 0; +} diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c new file mode 100644 index 000000000000..d3230234f07b --- /dev/null +++ b/drivers/clk/ti/clk-3xxx.c @@ -0,0 +1,401 @@ +/* + * OMAP3 Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/clk-provider.h> +#include <linux/clk/ti.h> + + +static struct ti_dt_clk omap3xxx_clks[] = { + DT_CLK(NULL, "apb_pclk", "dummy_apb_pclk"), + DT_CLK(NULL, "omap_32k_fck", "omap_32k_fck"), + DT_CLK(NULL, "virt_12m_ck", "virt_12m_ck"), + DT_CLK(NULL, "virt_13m_ck", "virt_13m_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "virt_38_4m_ck", "virt_38_4m_ck"), + DT_CLK(NULL, "osc_sys_ck", "osc_sys_ck"), + DT_CLK("twl", "fck", "osc_sys_ck"), + DT_CLK(NULL, "sys_ck", "sys_ck"), + DT_CLK(NULL, "omap_96m_alwon_fck", "omap_96m_alwon_fck"), + DT_CLK("etb", "emu_core_alwon_ck", "emu_core_alwon_ck"), + DT_CLK(NULL, "sys_altclk", "sys_altclk"), + DT_CLK(NULL, "mcbsp_clks", "mcbsp_clks"), + DT_CLK(NULL, "sys_clkout1", "sys_clkout1"), + DT_CLK(NULL, "dpll1_ck", "dpll1_ck"), + DT_CLK(NULL, "dpll1_x2_ck", "dpll1_x2_ck"), + DT_CLK(NULL, "dpll1_x2m2_ck", "dpll1_x2m2_ck"), + DT_CLK(NULL, "dpll3_ck", "dpll3_ck"), + DT_CLK(NULL, "core_ck", "core_ck"), + DT_CLK(NULL, "dpll3_x2_ck", "dpll3_x2_ck"), + DT_CLK(NULL, "dpll3_m2_ck", "dpll3_m2_ck"), + DT_CLK(NULL, "dpll3_m2x2_ck", "dpll3_m2x2_ck"), + DT_CLK(NULL, "dpll3_m3_ck", "dpll3_m3_ck"), + DT_CLK(NULL, "dpll3_m3x2_ck", "dpll3_m3x2_ck"), + DT_CLK(NULL, "dpll4_ck", "dpll4_ck"), + DT_CLK(NULL, "dpll4_x2_ck", "dpll4_x2_ck"), + DT_CLK(NULL, "omap_96m_fck", "omap_96m_fck"), + DT_CLK(NULL, "cm_96m_fck", "cm_96m_fck"), + DT_CLK(NULL, "omap_54m_fck", "omap_54m_fck"), + DT_CLK(NULL, "omap_48m_fck", "omap_48m_fck"), + DT_CLK(NULL, "omap_12m_fck", "omap_12m_fck"), + DT_CLK(NULL, "dpll4_m2_ck", "dpll4_m2_ck"), + DT_CLK(NULL, "dpll4_m2x2_ck", "dpll4_m2x2_ck"), + DT_CLK(NULL, "dpll4_m3_ck", "dpll4_m3_ck"), + DT_CLK(NULL, "dpll4_m3x2_ck", "dpll4_m3x2_ck"), + DT_CLK(NULL, "dpll4_m4_ck", "dpll4_m4_ck"), + DT_CLK(NULL, "dpll4_m4x2_ck", "dpll4_m4x2_ck"), + DT_CLK(NULL, "dpll4_m5_ck", "dpll4_m5_ck"), + DT_CLK(NULL, "dpll4_m5x2_ck", "dpll4_m5x2_ck"), + DT_CLK(NULL, "dpll4_m6_ck", "dpll4_m6_ck"), + DT_CLK(NULL, "dpll4_m6x2_ck", "dpll4_m6x2_ck"), + DT_CLK("etb", "emu_per_alwon_ck", "emu_per_alwon_ck"), + DT_CLK(NULL, "clkout2_src_ck", "clkout2_src_ck"), + DT_CLK(NULL, "sys_clkout2", "sys_clkout2"), + DT_CLK(NULL, "corex2_fck", "corex2_fck"), + DT_CLK(NULL, "dpll1_fck", "dpll1_fck"), + DT_CLK(NULL, "mpu_ck", "mpu_ck"), + DT_CLK(NULL, "arm_fck", "arm_fck"), + DT_CLK("etb", "emu_mpu_alwon_ck", "emu_mpu_alwon_ck"), + DT_CLK(NULL, "l3_ick", "l3_ick"), + DT_CLK(NULL, "l4_ick", "l4_ick"), + DT_CLK(NULL, "rm_ick", "rm_ick"), + DT_CLK(NULL, "gpt10_fck", "gpt10_fck"), + DT_CLK(NULL, "gpt11_fck", "gpt11_fck"), + DT_CLK(NULL, "core_96m_fck", "core_96m_fck"), + DT_CLK(NULL, "mmchs2_fck", "mmchs2_fck"), + DT_CLK(NULL, "mmchs1_fck", "mmchs1_fck"), + DT_CLK(NULL, "i2c3_fck", "i2c3_fck"), + DT_CLK(NULL, "i2c2_fck", "i2c2_fck"), + DT_CLK(NULL, "i2c1_fck", "i2c1_fck"), + DT_CLK(NULL, "mcbsp5_fck", "mcbsp5_fck"), + DT_CLK(NULL, "mcbsp1_fck", "mcbsp1_fck"), + DT_CLK(NULL, "core_48m_fck", "core_48m_fck"), + DT_CLK(NULL, "mcspi4_fck", "mcspi4_fck"), + DT_CLK(NULL, "mcspi3_fck", "mcspi3_fck"), + DT_CLK(NULL, "mcspi2_fck", "mcspi2_fck"), + DT_CLK(NULL, "mcspi1_fck", "mcspi1_fck"), + DT_CLK(NULL, "uart2_fck", "uart2_fck"), + DT_CLK(NULL, "uart1_fck", "uart1_fck"), + DT_CLK(NULL, "core_12m_fck", "core_12m_fck"), + DT_CLK("omap_hdq.0", "fck", "hdq_fck"), + DT_CLK(NULL, "hdq_fck", "hdq_fck"), + DT_CLK(NULL, "core_l3_ick", "core_l3_ick"), + DT_CLK(NULL, "sdrc_ick", "sdrc_ick"), + DT_CLK(NULL, "gpmc_fck", "gpmc_fck"), + DT_CLK(NULL, "core_l4_ick", "core_l4_ick"), + DT_CLK("omap_hsmmc.1", "ick", "mmchs2_ick"), + DT_CLK("omap_hsmmc.0", "ick", "mmchs1_ick"), + DT_CLK(NULL, "mmchs2_ick", "mmchs2_ick"), + DT_CLK(NULL, "mmchs1_ick", "mmchs1_ick"), + DT_CLK("omap_hdq.0", "ick", "hdq_ick"), + DT_CLK(NULL, "hdq_ick", "hdq_ick"), + DT_CLK("omap2_mcspi.4", "ick", "mcspi4_ick"), + DT_CLK("omap2_mcspi.3", "ick", "mcspi3_ick"), + DT_CLK("omap2_mcspi.2", "ick", "mcspi2_ick"), + DT_CLK("omap2_mcspi.1", "ick", "mcspi1_ick"), + DT_CLK(NULL, "mcspi4_ick", "mcspi4_ick"), + DT_CLK(NULL, "mcspi3_ick", "mcspi3_ick"), + DT_CLK(NULL, "mcspi2_ick", "mcspi2_ick"), + DT_CLK(NULL, "mcspi1_ick", "mcspi1_ick"), + DT_CLK("omap_i2c.3", "ick", "i2c3_ick"), + DT_CLK("omap_i2c.2", "ick", "i2c2_ick"), + DT_CLK("omap_i2c.1", "ick", "i2c1_ick"), + DT_CLK(NULL, "i2c3_ick", "i2c3_ick"), + DT_CLK(NULL, "i2c2_ick", "i2c2_ick"), + DT_CLK(NULL, "i2c1_ick", "i2c1_ick"), + DT_CLK(NULL, "uart2_ick", "uart2_ick"), + DT_CLK(NULL, "uart1_ick", "uart1_ick"), + DT_CLK(NULL, "gpt11_ick", "gpt11_ick"), + DT_CLK(NULL, "gpt10_ick", "gpt10_ick"), + DT_CLK("omap-mcbsp.5", "ick", "mcbsp5_ick"), + DT_CLK("omap-mcbsp.1", "ick", "mcbsp1_ick"), + DT_CLK(NULL, "mcbsp5_ick", "mcbsp5_ick"), + DT_CLK(NULL, "mcbsp1_ick", "mcbsp1_ick"), + DT_CLK(NULL, "omapctrl_ick", "omapctrl_ick"), + DT_CLK(NULL, "dss_tv_fck", "dss_tv_fck"), + DT_CLK(NULL, "dss_96m_fck", "dss_96m_fck"), + DT_CLK(NULL, "dss2_alwon_fck", "dss2_alwon_fck"), + DT_CLK(NULL, "utmi_p1_gfclk", "dummy_ck"), + DT_CLK(NULL, "utmi_p2_gfclk", "dummy_ck"), + DT_CLK(NULL, "xclk60mhsp1_ck", "dummy_ck"), + DT_CLK(NULL, "xclk60mhsp2_ck", "dummy_ck"), + DT_CLK(NULL, "init_60m_fclk", "dummy_ck"), + DT_CLK(NULL, "gpt1_fck", "gpt1_fck"), + DT_CLK(NULL, "aes2_ick", "aes2_ick"), + DT_CLK(NULL, "wkup_32k_fck", "wkup_32k_fck"), + DT_CLK(NULL, "gpio1_dbck", "gpio1_dbck"), + DT_CLK(NULL, "sha12_ick", "sha12_ick"), + DT_CLK(NULL, "wdt2_fck", "wdt2_fck"), + DT_CLK("omap_wdt", "ick", "wdt2_ick"), + DT_CLK(NULL, "wdt2_ick", "wdt2_ick"), + DT_CLK(NULL, "wdt1_ick", "wdt1_ick"), + DT_CLK(NULL, "gpio1_ick", "gpio1_ick"), + DT_CLK(NULL, "omap_32ksync_ick", "omap_32ksync_ick"), + DT_CLK(NULL, "gpt12_ick", "gpt12_ick"), + DT_CLK(NULL, "gpt1_ick", "gpt1_ick"), + DT_CLK(NULL, "per_96m_fck", "per_96m_fck"), + DT_CLK(NULL, "per_48m_fck", "per_48m_fck"), + DT_CLK(NULL, "uart3_fck", "uart3_fck"), + DT_CLK(NULL, "gpt2_fck", "gpt2_fck"), + DT_CLK(NULL, "gpt3_fck", "gpt3_fck"), + DT_CLK(NULL, "gpt4_fck", "gpt4_fck"), + DT_CLK(NULL, "gpt5_fck", "gpt5_fck"), + DT_CLK(NULL, "gpt6_fck", "gpt6_fck"), + DT_CLK(NULL, "gpt7_fck", "gpt7_fck"), + DT_CLK(NULL, "gpt8_fck", "gpt8_fck"), + DT_CLK(NULL, "gpt9_fck", "gpt9_fck"), + DT_CLK(NULL, "per_32k_alwon_fck", "per_32k_alwon_fck"), + DT_CLK(NULL, "gpio6_dbck", "gpio6_dbck"), + DT_CLK(NULL, "gpio5_dbck", "gpio5_dbck"), + DT_CLK(NULL, "gpio4_dbck", "gpio4_dbck"), + DT_CLK(NULL, "gpio3_dbck", "gpio3_dbck"), + DT_CLK(NULL, "gpio2_dbck", "gpio2_dbck"), + DT_CLK(NULL, "wdt3_fck", "wdt3_fck"), + DT_CLK(NULL, "per_l4_ick", "per_l4_ick"), + DT_CLK(NULL, "gpio6_ick", "gpio6_ick"), + DT_CLK(NULL, "gpio5_ick", "gpio5_ick"), + DT_CLK(NULL, "gpio4_ick", "gpio4_ick"), + DT_CLK(NULL, "gpio3_ick", "gpio3_ick"), + DT_CLK(NULL, "gpio2_ick", "gpio2_ick"), + DT_CLK(NULL, "wdt3_ick", "wdt3_ick"), + DT_CLK(NULL, "uart3_ick", "uart3_ick"), + DT_CLK(NULL, "uart4_ick", "uart4_ick"), + DT_CLK(NULL, "gpt9_ick", "gpt9_ick"), + DT_CLK(NULL, "gpt8_ick", "gpt8_ick"), + DT_CLK(NULL, "gpt7_ick", "gpt7_ick"), + DT_CLK(NULL, "gpt6_ick", "gpt6_ick"), + DT_CLK(NULL, "gpt5_ick", "gpt5_ick"), + DT_CLK(NULL, "gpt4_ick", "gpt4_ick"), + DT_CLK(NULL, "gpt3_ick", "gpt3_ick"), + DT_CLK(NULL, "gpt2_ick", "gpt2_ick"), + DT_CLK("omap-mcbsp.2", "ick", "mcbsp2_ick"), + DT_CLK("omap-mcbsp.3", "ick", "mcbsp3_ick"), + DT_CLK("omap-mcbsp.4", "ick", "mcbsp4_ick"), + DT_CLK(NULL, "mcbsp4_ick", "mcbsp2_ick"), + DT_CLK(NULL, "mcbsp3_ick", "mcbsp3_ick"), + DT_CLK(NULL, "mcbsp2_ick", "mcbsp4_ick"), + DT_CLK(NULL, "mcbsp2_fck", "mcbsp2_fck"), + DT_CLK(NULL, "mcbsp3_fck", "mcbsp3_fck"), + DT_CLK(NULL, "mcbsp4_fck", "mcbsp4_fck"), + DT_CLK("etb", "emu_src_ck", "emu_src_ck"), + DT_CLK(NULL, "emu_src_ck", "emu_src_ck"), + DT_CLK(NULL, "pclk_fck", "pclk_fck"), + DT_CLK(NULL, "pclkx2_fck", "pclkx2_fck"), + DT_CLK(NULL, "atclk_fck", "atclk_fck"), + DT_CLK(NULL, "traceclk_src_fck", "traceclk_src_fck"), + DT_CLK(NULL, "traceclk_fck", "traceclk_fck"), + DT_CLK(NULL, "secure_32k_fck", "secure_32k_fck"), + DT_CLK(NULL, "gpt12_fck", "gpt12_fck"), + DT_CLK(NULL, "wdt1_fck", "wdt1_fck"), + DT_CLK(NULL, "timer_32k_ck", "omap_32k_fck"), + DT_CLK(NULL, "timer_sys_ck", "sys_ck"), + DT_CLK(NULL, "cpufreq_ck", "dpll1_ck"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap34xx_omap36xx_clks[] = { + DT_CLK(NULL, "aes1_ick", "aes1_ick"), + DT_CLK("omap_rng", "ick", "rng_ick"), + DT_CLK("omap3-rom-rng", "ick", "rng_ick"), + DT_CLK(NULL, "sha11_ick", "sha11_ick"), + DT_CLK(NULL, "des1_ick", "des1_ick"), + DT_CLK(NULL, "cam_mclk", "cam_mclk"), + DT_CLK(NULL, "cam_ick", "cam_ick"), + DT_CLK(NULL, "csi2_96m_fck", "csi2_96m_fck"), + DT_CLK(NULL, "security_l3_ick", "security_l3_ick"), + DT_CLK(NULL, "pka_ick", "pka_ick"), + DT_CLK(NULL, "icr_ick", "icr_ick"), + DT_CLK("omap-aes", "ick", "aes2_ick"), + DT_CLK("omap-sham", "ick", "sha12_ick"), + DT_CLK(NULL, "des2_ick", "des2_ick"), + DT_CLK(NULL, "mspro_ick", "mspro_ick"), + DT_CLK(NULL, "mailboxes_ick", "mailboxes_ick"), + DT_CLK(NULL, "ssi_l4_ick", "ssi_l4_ick"), + DT_CLK(NULL, "sr1_fck", "sr1_fck"), + DT_CLK(NULL, "sr2_fck", "sr2_fck"), + DT_CLK(NULL, "sr_l4_ick", "sr_l4_ick"), + DT_CLK(NULL, "security_l4_ick2", "security_l4_ick2"), + DT_CLK(NULL, "wkup_l4_ick", "wkup_l4_ick"), + DT_CLK(NULL, "dpll2_fck", "dpll2_fck"), + DT_CLK(NULL, "iva2_ck", "iva2_ck"), + DT_CLK(NULL, "modem_fck", "modem_fck"), + DT_CLK(NULL, "sad2d_ick", "sad2d_ick"), + DT_CLK(NULL, "mad2d_ick", "mad2d_ick"), + DT_CLK(NULL, "mspro_fck", "mspro_fck"), + DT_CLK(NULL, "dpll2_ck", "dpll2_ck"), + DT_CLK(NULL, "dpll2_m2_ck", "dpll2_m2_ck"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap36xx_omap3430es2plus_clks[] = { + DT_CLK(NULL, "ssi_ssr_fck", "ssi_ssr_fck_3430es2"), + DT_CLK(NULL, "ssi_sst_fck", "ssi_sst_fck_3430es2"), + DT_CLK("musb-omap2430", "ick", "hsotgusb_ick_3430es2"), + DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_3430es2"), + DT_CLK(NULL, "ssi_ick", "ssi_ick_3430es2"), + DT_CLK(NULL, "usim_fck", "usim_fck"), + DT_CLK(NULL, "usim_ick", "usim_ick"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap3430es1_clks[] = { + DT_CLK(NULL, "gfx_l3_ck", "gfx_l3_ck"), + DT_CLK(NULL, "gfx_l3_fck", "gfx_l3_fck"), + DT_CLK(NULL, "gfx_l3_ick", "gfx_l3_ick"), + DT_CLK(NULL, "gfx_cg1_ck", "gfx_cg1_ck"), + DT_CLK(NULL, "gfx_cg2_ck", "gfx_cg2_ck"), + DT_CLK(NULL, "d2d_26m_fck", "d2d_26m_fck"), + DT_CLK(NULL, "fshostusb_fck", "fshostusb_fck"), + DT_CLK(NULL, "ssi_ssr_fck", "ssi_ssr_fck_3430es1"), + DT_CLK(NULL, "ssi_sst_fck", "ssi_sst_fck_3430es1"), + DT_CLK("musb-omap2430", "ick", "hsotgusb_ick_3430es1"), + DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_3430es1"), + DT_CLK(NULL, "fac_ick", "fac_ick"), + DT_CLK(NULL, "ssi_ick", "ssi_ick_3430es1"), + DT_CLK(NULL, "usb_l4_ick", "usb_l4_ick"), + DT_CLK(NULL, "dss1_alwon_fck", "dss1_alwon_fck_3430es1"), + DT_CLK("omapdss_dss", "ick", "dss_ick_3430es1"), + DT_CLK(NULL, "dss_ick", "dss_ick_3430es1"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap36xx_am35xx_omap3430es2plus_clks[] = { + DT_CLK(NULL, "virt_16_8m_ck", "virt_16_8m_ck"), + DT_CLK(NULL, "dpll5_ck", "dpll5_ck"), + DT_CLK(NULL, "dpll5_m2_ck", "dpll5_m2_ck"), + DT_CLK(NULL, "sgx_fck", "sgx_fck"), + DT_CLK(NULL, "sgx_ick", "sgx_ick"), + DT_CLK(NULL, "cpefuse_fck", "cpefuse_fck"), + DT_CLK(NULL, "ts_fck", "ts_fck"), + DT_CLK(NULL, "usbtll_fck", "usbtll_fck"), + DT_CLK(NULL, "usbtll_ick", "usbtll_ick"), + DT_CLK("omap_hsmmc.2", "ick", "mmchs3_ick"), + DT_CLK(NULL, "mmchs3_ick", "mmchs3_ick"), + DT_CLK(NULL, "mmchs3_fck", "mmchs3_fck"), + DT_CLK(NULL, "dss1_alwon_fck", "dss1_alwon_fck_3430es2"), + DT_CLK("omapdss_dss", "ick", "dss_ick_3430es2"), + DT_CLK(NULL, "dss_ick", "dss_ick_3430es2"), + DT_CLK(NULL, "usbhost_120m_fck", "usbhost_120m_fck"), + DT_CLK(NULL, "usbhost_48m_fck", "usbhost_48m_fck"), + DT_CLK(NULL, "usbhost_ick", "usbhost_ick"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk am35xx_clks[] = { + DT_CLK(NULL, "ipss_ick", "ipss_ick"), + DT_CLK(NULL, "rmii_ck", "rmii_ck"), + DT_CLK(NULL, "pclk_ck", "pclk_ck"), + DT_CLK(NULL, "emac_ick", "emac_ick"), + DT_CLK(NULL, "emac_fck", "emac_fck"), + DT_CLK("davinci_emac.0", NULL, "emac_ick"), + DT_CLK("davinci_mdio.0", NULL, "emac_fck"), + DT_CLK("vpfe-capture", "master", "vpfe_ick"), + DT_CLK("vpfe-capture", "slave", "vpfe_fck"), + DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_am35xx"), + DT_CLK(NULL, "hsotgusb_fck", "hsotgusb_fck_am35xx"), + DT_CLK(NULL, "hecc_ck", "hecc_ck"), + DT_CLK(NULL, "uart4_ick", "uart4_ick_am35xx"), + DT_CLK(NULL, "uart4_fck", "uart4_fck_am35xx"), + { .node_name = NULL }, +}; + +static struct ti_dt_clk omap36xx_clks[] = { + DT_CLK(NULL, "omap_192m_alwon_fck", "omap_192m_alwon_fck"), + DT_CLK(NULL, "uart4_fck", "uart4_fck"), + { .node_name = NULL }, +}; + +static const char *enable_init_clks[] = { + "sdrc_ick", + "gpmc_fck", + "omapctrl_ick", +}; + +enum { + OMAP3_SOC_AM35XX, + 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) +{ + if (soc_type == OMAP3_SOC_AM35XX || soc_type == OMAP3_SOC_OMAP3630 || + soc_type == OMAP3_SOC_OMAP3430_ES1 || + soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS) + ti_dt_clocks_register(omap3xxx_clks); + + if (soc_type == OMAP3_SOC_AM35XX) + ti_dt_clocks_register(am35xx_clks); + + if (soc_type == OMAP3_SOC_OMAP3630 || soc_type == OMAP3_SOC_AM35XX || + soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS) + ti_dt_clocks_register(omap36xx_am35xx_omap3430es2plus_clks); + + if (soc_type == OMAP3_SOC_OMAP3430_ES1) + ti_dt_clocks_register(omap3430es1_clks); + + if (soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS || + soc_type == OMAP3_SOC_OMAP3630) + ti_dt_clocks_register(omap36xx_omap3430es2plus_clks); + + if (soc_type == OMAP3_SOC_OMAP3430_ES1 || + soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS || + soc_type == OMAP3_SOC_OMAP3630) + ti_dt_clocks_register(omap34xx_omap36xx_clks); + + if (soc_type == OMAP3_SOC_OMAP3630) + ti_dt_clocks_register(omap36xx_clks); + + 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(clk_get_sys(NULL, "osc_sys_ck")) / 1000000), + (clk_get_rate(clk_get_sys(NULL, "osc_sys_ck")) / 100000) % 10, + (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) + omap3_clk_lock_dpll5(); + + return 0; +} + +int __init omap3430_dt_clk_init(void) +{ + return omap3xxx_dt_clk_init(OMAP3_SOC_OMAP3430_ES2_PLUS); +} + +int __init omap3630_dt_clk_init(void) +{ + return omap3xxx_dt_clk_init(OMAP3_SOC_OMAP3630); +} + +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-43xx.c b/drivers/clk/ti/clk-43xx.c new file mode 100644 index 000000000000..67c8de572c50 --- /dev/null +++ b/drivers/clk/ti/clk-43xx.c @@ -0,0 +1,118 @@ +/* + * AM43XX Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/clk-provider.h> +#include <linux/clk/ti.h> + +static struct ti_dt_clk am43xx_clks[] = { + DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), + DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_24000000_ck", "virt_24000000_ck"), + DT_CLK(NULL, "virt_25000000_ck", "virt_25000000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"), + DT_CLK(NULL, "tclkin_ck", "tclkin_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_m4_ck", "dpll_core_m4_ck"), + DT_CLK(NULL, "dpll_core_m5_ck", "dpll_core_m5_ck"), + DT_CLK(NULL, "dpll_core_m6_ck", "dpll_core_m6_ck"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"), + DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"), + DT_CLK(NULL, "dpll_disp_ck", "dpll_disp_ck"), + DT_CLK(NULL, "dpll_disp_m2_ck", "dpll_disp_m2_ck"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "dpll_per_m2_div4_wkupdm_ck", "dpll_per_m2_div4_wkupdm_ck"), + DT_CLK(NULL, "dpll_per_m2_div4_ck", "dpll_per_m2_div4_ck"), + DT_CLK(NULL, "adc_tsc_fck", "adc_tsc_fck"), + DT_CLK(NULL, "clkdiv32k_ck", "clkdiv32k_ck"), + DT_CLK(NULL, "clkdiv32k_ick", "clkdiv32k_ick"), + DT_CLK(NULL, "dcan0_fck", "dcan0_fck"), + DT_CLK(NULL, "dcan1_fck", "dcan1_fck"), + DT_CLK(NULL, "pruss_ocp_gclk", "pruss_ocp_gclk"), + DT_CLK(NULL, "mcasp0_fck", "mcasp0_fck"), + DT_CLK(NULL, "mcasp1_fck", "mcasp1_fck"), + DT_CLK(NULL, "smartreflex0_fck", "smartreflex0_fck"), + DT_CLK(NULL, "smartreflex1_fck", "smartreflex1_fck"), + DT_CLK(NULL, "sha0_fck", "sha0_fck"), + DT_CLK(NULL, "aes0_fck", "aes0_fck"), + 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, "wdt1_fck", "wdt1_fck"), + DT_CLK(NULL, "l3_gclk", "l3_gclk"), + DT_CLK(NULL, "dpll_core_m4_div2_ck", "dpll_core_m4_div2_ck"), + DT_CLK(NULL, "l4hs_gclk", "l4hs_gclk"), + DT_CLK(NULL, "l3s_gclk", "l3s_gclk"), + DT_CLK(NULL, "l4ls_gclk", "l4ls_gclk"), + DT_CLK(NULL, "clk_24mhz", "clk_24mhz"), + DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"), + DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"), + DT_CLK(NULL, "gpio0_dbclk_mux_ck", "gpio0_dbclk_mux_ck"), + DT_CLK(NULL, "gpio0_dbclk", "gpio0_dbclk"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), + DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), + DT_CLK(NULL, "mmc_clk", "mmc_clk"), + DT_CLK(NULL, "gfx_fclk_clksel_ck", "gfx_fclk_clksel_ck"), + DT_CLK(NULL, "gfx_fck_div_ck", "gfx_fck_div_ck"), + DT_CLK(NULL, "timer_32k_ck", "clkdiv32k_ick"), + DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"), + DT_CLK(NULL, "sysclk_div", "sysclk_div"), + DT_CLK(NULL, "disp_clk", "disp_clk"), + DT_CLK(NULL, "clk_32k_mosc_ck", "clk_32k_mosc_ck"), + DT_CLK(NULL, "clk_32k_tpm_ck", "clk_32k_tpm_ck"), + DT_CLK(NULL, "dpll_extdev_ck", "dpll_extdev_ck"), + DT_CLK(NULL, "dpll_extdev_m2_ck", "dpll_extdev_m2_ck"), + DT_CLK(NULL, "mux_synctimer32k_ck", "mux_synctimer32k_ck"), + DT_CLK(NULL, "synctimer_32kclk", "synctimer_32kclk"), + DT_CLK(NULL, "timer8_fck", "timer8_fck"), + DT_CLK(NULL, "timer9_fck", "timer9_fck"), + DT_CLK(NULL, "timer10_fck", "timer10_fck"), + DT_CLK(NULL, "timer11_fck", "timer11_fck"), + DT_CLK(NULL, "cpsw_50m_clkdiv", "cpsw_50m_clkdiv"), + DT_CLK(NULL, "cpsw_5m_clkdiv", "cpsw_5m_clkdiv"), + DT_CLK(NULL, "dpll_ddr_x2_ck", "dpll_ddr_x2_ck"), + DT_CLK(NULL, "dpll_ddr_m4_ck", "dpll_ddr_m4_ck"), + DT_CLK(NULL, "dpll_per_clkdcoldo", "dpll_per_clkdcoldo"), + DT_CLK(NULL, "dll_aging_clk_div", "dll_aging_clk_div"), + DT_CLK(NULL, "div_core_25m_ck", "div_core_25m_ck"), + DT_CLK(NULL, "func_12m_clk", "func_12m_clk"), + DT_CLK(NULL, "vtp_clk_div", "vtp_clk_div"), + DT_CLK(NULL, "usbphy_32khz_clkmux", "usbphy_32khz_clkmux"), + { .node_name = NULL }, +}; + +int __init am43xx_dt_clk_init(void) +{ + ti_dt_clocks_register(am43xx_clks); + + omap2_clk_disable_autoidle_all(); + + return 0; +} diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c new file mode 100644 index 000000000000..ae00218b5da3 --- /dev/null +++ b/drivers/clk/ti/clk-44xx.c @@ -0,0 +1,316 @@ +/* + * OMAP4 Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/clk-private.h> +#include <linux/clkdev.h> +#include <linux/clk/ti.h> + +/* + * OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section + * "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK + * must be set to 196.608 MHz" and hence, the DPLL locked frequency is + * half of this value. + */ +#define OMAP4_DPLL_ABE_DEFFREQ 98304000 + +/* + * OMAP4 USB DPLL default frequency. In OMAP4430 TRM version V, section + * "3.6.3.9.5 DPLL_USB Preferred Settings" shows that the preferred + * locked frequency for the USB DPLL is 960MHz. + */ +#define OMAP4_DPLL_USB_DEFFREQ 960000000 + +static struct ti_dt_clk omap44xx_clks[] = { + DT_CLK(NULL, "extalt_clkin_ck", "extalt_clkin_ck"), + DT_CLK(NULL, "pad_clks_src_ck", "pad_clks_src_ck"), + DT_CLK(NULL, "pad_clks_ck", "pad_clks_ck"), + DT_CLK(NULL, "pad_slimbus_core_clks_ck", "pad_slimbus_core_clks_ck"), + DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"), + DT_CLK(NULL, "slimbus_src_clk", "slimbus_src_clk"), + DT_CLK(NULL, "slimbus_clk", "slimbus_clk"), + DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"), + DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"), + DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"), + DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"), + DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"), + DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"), + DT_CLK(NULL, "tie_low_clock_ck", "tie_low_clock_ck"), + DT_CLK(NULL, "utmi_phy_clkout_ck", "utmi_phy_clkout_ck"), + DT_CLK(NULL, "xclk60mhsp1_ck", "xclk60mhsp1_ck"), + DT_CLK(NULL, "xclk60mhsp2_ck", "xclk60mhsp2_ck"), + DT_CLK(NULL, "xclk60motg_ck", "xclk60motg_ck"), + DT_CLK(NULL, "abe_dpll_bypass_clk_mux_ck", "abe_dpll_bypass_clk_mux_ck"), + DT_CLK(NULL, "abe_dpll_refclk_mux_ck", "abe_dpll_refclk_mux_ck"), + DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"), + DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"), + DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"), + DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"), + DT_CLK(NULL, "abe_clk", "abe_clk"), + DT_CLK(NULL, "aess_fclk", "aess_fclk"), + DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"), + DT_CLK(NULL, "core_hsd_byp_clk_mux_ck", "core_hsd_byp_clk_mux_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_m6x2_ck", "dpll_core_m6x2_ck"), + DT_CLK(NULL, "dbgclk_mux_ck", "dbgclk_mux_ck"), + DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"), + DT_CLK(NULL, "ddrphy_ck", "ddrphy_ck"), + DT_CLK(NULL, "dpll_core_m5x2_ck", "dpll_core_m5x2_ck"), + DT_CLK(NULL, "div_core_ck", "div_core_ck"), + DT_CLK(NULL, "div_iva_hs_clk", "div_iva_hs_clk"), + DT_CLK(NULL, "div_mpu_hs_clk", "div_mpu_hs_clk"), + DT_CLK(NULL, "dpll_core_m4x2_ck", "dpll_core_m4x2_ck"), + DT_CLK(NULL, "dll_clk_div_ck", "dll_clk_div_ck"), + DT_CLK(NULL, "dpll_abe_m2_ck", "dpll_abe_m2_ck"), + DT_CLK(NULL, "dpll_core_m3x2_ck", "dpll_core_m3x2_ck"), + DT_CLK(NULL, "dpll_core_m7x2_ck", "dpll_core_m7x2_ck"), + DT_CLK(NULL, "iva_hsd_byp_clk_mux_ck", "iva_hsd_byp_clk_mux_ck"), + DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"), + DT_CLK(NULL, "dpll_iva_x2_ck", "dpll_iva_x2_ck"), + DT_CLK(NULL, "dpll_iva_m4x2_ck", "dpll_iva_m4x2_ck"), + DT_CLK(NULL, "dpll_iva_m5x2_ck", "dpll_iva_m5x2_ck"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "per_hs_clk_div_ck", "per_hs_clk_div_ck"), + DT_CLK(NULL, "per_hsd_byp_clk_mux_ck", "per_hsd_byp_clk_mux_ck"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"), + DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"), + DT_CLK(NULL, "dpll_per_m3x2_ck", "dpll_per_m3x2_ck"), + DT_CLK(NULL, "dpll_per_m4x2_ck", "dpll_per_m4x2_ck"), + DT_CLK(NULL, "dpll_per_m5x2_ck", "dpll_per_m5x2_ck"), + DT_CLK(NULL, "dpll_per_m6x2_ck", "dpll_per_m6x2_ck"), + DT_CLK(NULL, "dpll_per_m7x2_ck", "dpll_per_m7x2_ck"), + DT_CLK(NULL, "usb_hs_clk_div_ck", "usb_hs_clk_div_ck"), + DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"), + DT_CLK(NULL, "dpll_usb_clkdcoldo_ck", "dpll_usb_clkdcoldo_ck"), + DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"), + DT_CLK(NULL, "ducati_clk_mux_ck", "ducati_clk_mux_ck"), + DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"), + DT_CLK(NULL, "func_24m_clk", "func_24m_clk"), + DT_CLK(NULL, "func_24mc_fclk", "func_24mc_fclk"), + DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"), + DT_CLK(NULL, "func_48mc_fclk", "func_48mc_fclk"), + DT_CLK(NULL, "func_64m_fclk", "func_64m_fclk"), + DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"), + DT_CLK(NULL, "init_60m_fclk", "init_60m_fclk"), + DT_CLK(NULL, "l3_div_ck", "l3_div_ck"), + DT_CLK(NULL, "l4_div_ck", "l4_div_ck"), + DT_CLK(NULL, "lp_clk_div_ck", "lp_clk_div_ck"), + DT_CLK(NULL, "l4_wkup_clk_mux_ck", "l4_wkup_clk_mux_ck"), + DT_CLK("smp_twd", NULL, "mpu_periphclk"), + DT_CLK(NULL, "ocp_abe_iclk", "ocp_abe_iclk"), + DT_CLK(NULL, "per_abe_24m_fclk", "per_abe_24m_fclk"), + DT_CLK(NULL, "per_abe_nc_fclk", "per_abe_nc_fclk"), + DT_CLK(NULL, "syc_clk_div_ck", "syc_clk_div_ck"), + DT_CLK(NULL, "aes1_fck", "aes1_fck"), + DT_CLK(NULL, "aes2_fck", "aes2_fck"), + DT_CLK(NULL, "dmic_sync_mux_ck", "dmic_sync_mux_ck"), + DT_CLK(NULL, "func_dmic_abe_gfclk", "func_dmic_abe_gfclk"), + DT_CLK(NULL, "dss_sys_clk", "dss_sys_clk"), + DT_CLK(NULL, "dss_tv_clk", "dss_tv_clk"), + DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"), + DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"), + DT_CLK(NULL, "dss_fck", "dss_fck"), + DT_CLK("omapdss_dss", "ick", "dss_fck"), + DT_CLK(NULL, "fdif_fck", "fdif_fck"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), + DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), + DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"), + DT_CLK(NULL, "sgx_clk_mux", "sgx_clk_mux"), + DT_CLK(NULL, "hsi_fck", "hsi_fck"), + DT_CLK(NULL, "iss_ctrlclk", "iss_ctrlclk"), + DT_CLK(NULL, "mcasp_sync_mux_ck", "mcasp_sync_mux_ck"), + DT_CLK(NULL, "func_mcasp_abe_gfclk", "func_mcasp_abe_gfclk"), + DT_CLK(NULL, "mcbsp1_sync_mux_ck", "mcbsp1_sync_mux_ck"), + DT_CLK(NULL, "func_mcbsp1_gfclk", "func_mcbsp1_gfclk"), + DT_CLK(NULL, "mcbsp2_sync_mux_ck", "mcbsp2_sync_mux_ck"), + DT_CLK(NULL, "func_mcbsp2_gfclk", "func_mcbsp2_gfclk"), + DT_CLK(NULL, "mcbsp3_sync_mux_ck", "mcbsp3_sync_mux_ck"), + DT_CLK(NULL, "func_mcbsp3_gfclk", "func_mcbsp3_gfclk"), + DT_CLK(NULL, "mcbsp4_sync_mux_ck", "mcbsp4_sync_mux_ck"), + DT_CLK(NULL, "per_mcbsp4_gfclk", "per_mcbsp4_gfclk"), + DT_CLK(NULL, "hsmmc1_fclk", "hsmmc1_fclk"), + DT_CLK(NULL, "hsmmc2_fclk", "hsmmc2_fclk"), + DT_CLK(NULL, "ocp2scp_usb_phy_phy_48m", "ocp2scp_usb_phy_phy_48m"), + DT_CLK(NULL, "sha2md5_fck", "sha2md5_fck"), + DT_CLK(NULL, "slimbus1_fclk_1", "slimbus1_fclk_1"), + DT_CLK(NULL, "slimbus1_fclk_0", "slimbus1_fclk_0"), + DT_CLK(NULL, "slimbus1_fclk_2", "slimbus1_fclk_2"), + DT_CLK(NULL, "slimbus1_slimbus_clk", "slimbus1_slimbus_clk"), + DT_CLK(NULL, "slimbus2_fclk_1", "slimbus2_fclk_1"), + DT_CLK(NULL, "slimbus2_fclk_0", "slimbus2_fclk_0"), + DT_CLK(NULL, "slimbus2_slimbus_clk", "slimbus2_slimbus_clk"), + DT_CLK(NULL, "smartreflex_core_fck", "smartreflex_core_fck"), + DT_CLK(NULL, "smartreflex_iva_fck", "smartreflex_iva_fck"), + DT_CLK(NULL, "smartreflex_mpu_fck", "smartreflex_mpu_fck"), + DT_CLK(NULL, "dmt1_clk_mux", "dmt1_clk_mux"), + DT_CLK(NULL, "cm2_dm10_mux", "cm2_dm10_mux"), + DT_CLK(NULL, "cm2_dm11_mux", "cm2_dm11_mux"), + DT_CLK(NULL, "cm2_dm2_mux", "cm2_dm2_mux"), + DT_CLK(NULL, "cm2_dm3_mux", "cm2_dm3_mux"), + DT_CLK(NULL, "cm2_dm4_mux", "cm2_dm4_mux"), + DT_CLK(NULL, "timer5_sync_mux", "timer5_sync_mux"), + DT_CLK(NULL, "timer6_sync_mux", "timer6_sync_mux"), + DT_CLK(NULL, "timer7_sync_mux", "timer7_sync_mux"), + DT_CLK(NULL, "timer8_sync_mux", "timer8_sync_mux"), + DT_CLK(NULL, "cm2_dm9_mux", "cm2_dm9_mux"), + DT_CLK(NULL, "usb_host_fs_fck", "usb_host_fs_fck"), + DT_CLK("usbhs_omap", "fs_fck", "usb_host_fs_fck"), + DT_CLK(NULL, "utmi_p1_gfclk", "utmi_p1_gfclk"), + DT_CLK(NULL, "usb_host_hs_utmi_p1_clk", "usb_host_hs_utmi_p1_clk"), + DT_CLK(NULL, "utmi_p2_gfclk", "utmi_p2_gfclk"), + DT_CLK(NULL, "usb_host_hs_utmi_p2_clk", "usb_host_hs_utmi_p2_clk"), + DT_CLK(NULL, "usb_host_hs_utmi_p3_clk", "usb_host_hs_utmi_p3_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p1_clk", "usb_host_hs_hsic480m_p1_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p1_clk", "usb_host_hs_hsic60m_p1_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p2_clk", "usb_host_hs_hsic60m_p2_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p2_clk", "usb_host_hs_hsic480m_p2_clk"), + DT_CLK(NULL, "usb_host_hs_func48mclk", "usb_host_hs_func48mclk"), + DT_CLK(NULL, "usb_host_hs_fck", "usb_host_hs_fck"), + DT_CLK("usbhs_omap", "hs_fck", "usb_host_hs_fck"), + DT_CLK(NULL, "otg_60m_gfclk", "otg_60m_gfclk"), + DT_CLK(NULL, "usb_otg_hs_xclk", "usb_otg_hs_xclk"), + DT_CLK(NULL, "usb_otg_hs_ick", "usb_otg_hs_ick"), + DT_CLK("musb-omap2430", "ick", "usb_otg_hs_ick"), + DT_CLK(NULL, "usb_phy_cm_clk32k", "usb_phy_cm_clk32k"), + DT_CLK(NULL, "usb_tll_hs_usb_ch2_clk", "usb_tll_hs_usb_ch2_clk"), + DT_CLK(NULL, "usb_tll_hs_usb_ch0_clk", "usb_tll_hs_usb_ch0_clk"), + DT_CLK(NULL, "usb_tll_hs_usb_ch1_clk", "usb_tll_hs_usb_ch1_clk"), + DT_CLK(NULL, "usb_tll_hs_ick", "usb_tll_hs_ick"), + DT_CLK("usbhs_omap", "usbtll_ick", "usb_tll_hs_ick"), + DT_CLK("usbhs_tll", "usbtll_ick", "usb_tll_hs_ick"), + DT_CLK(NULL, "usim_ck", "usim_ck"), + DT_CLK(NULL, "usim_fclk", "usim_fclk"), + DT_CLK(NULL, "pmd_stm_clock_mux_ck", "pmd_stm_clock_mux_ck"), + DT_CLK(NULL, "pmd_trace_clk_mux_ck", "pmd_trace_clk_mux_ck"), + DT_CLK(NULL, "stm_clk_div_ck", "stm_clk_div_ck"), + DT_CLK(NULL, "trace_clk_div_ck", "trace_clk_div_ck"), + DT_CLK(NULL, "auxclk0_src_ck", "auxclk0_src_ck"), + DT_CLK(NULL, "auxclk0_ck", "auxclk0_ck"), + DT_CLK(NULL, "auxclkreq0_ck", "auxclkreq0_ck"), + DT_CLK(NULL, "auxclk1_src_ck", "auxclk1_src_ck"), + DT_CLK(NULL, "auxclk1_ck", "auxclk1_ck"), + DT_CLK(NULL, "auxclkreq1_ck", "auxclkreq1_ck"), + DT_CLK(NULL, "auxclk2_src_ck", "auxclk2_src_ck"), + DT_CLK(NULL, "auxclk2_ck", "auxclk2_ck"), + DT_CLK(NULL, "auxclkreq2_ck", "auxclkreq2_ck"), + DT_CLK(NULL, "auxclk3_src_ck", "auxclk3_src_ck"), + DT_CLK(NULL, "auxclk3_ck", "auxclk3_ck"), + DT_CLK(NULL, "auxclkreq3_ck", "auxclkreq3_ck"), + DT_CLK(NULL, "auxclk4_src_ck", "auxclk4_src_ck"), + DT_CLK(NULL, "auxclk4_ck", "auxclk4_ck"), + DT_CLK(NULL, "auxclkreq4_ck", "auxclkreq4_ck"), + DT_CLK(NULL, "auxclk5_src_ck", "auxclk5_src_ck"), + DT_CLK(NULL, "auxclk5_ck", "auxclk5_ck"), + DT_CLK(NULL, "auxclkreq5_ck", "auxclkreq5_ck"), + DT_CLK("50000000.gpmc", "fck", "dummy_ck"), + DT_CLK("omap_i2c.1", "ick", "dummy_ck"), + DT_CLK("omap_i2c.2", "ick", "dummy_ck"), + DT_CLK("omap_i2c.3", "ick", "dummy_ck"), + DT_CLK("omap_i2c.4", "ick", "dummy_ck"), + DT_CLK(NULL, "mailboxes_ick", "dummy_ck"), + DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"), + DT_CLK(NULL, "uart1_ick", "dummy_ck"), + DT_CLK(NULL, "uart2_ick", "dummy_ck"), + DT_CLK(NULL, "uart3_ick", "dummy_ck"), + DT_CLK(NULL, "uart4_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), + DT_CLK("usbhs_tll", "usbtll_fck", "dummy_ck"), + DT_CLK("omap_wdt", "ick", "dummy_ck"), + DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), + DT_CLK("omap_timer.1", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.2", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.3", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.4", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.9", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.10", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.11", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("omap_timer.5", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("omap_timer.6", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("omap_timer.7", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("omap_timer.8", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("4a318000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48036000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("4803e000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48086000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("48088000.timer", "timer_sys_ck", "sys_clkin_ck"), + DT_CLK("40138000.timer", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("4013a000.timer", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("4013c000.timer", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK("4013e000.timer", "timer_sys_ck", "syc_clk_div_ck"), + DT_CLK(NULL, "cpufreq_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "bandgap_fclk", "bandgap_fclk"), + DT_CLK(NULL, "div_ts_ck", "div_ts_ck"), + DT_CLK(NULL, "bandgap_ts_fclk", "bandgap_ts_fclk"), + { .node_name = NULL }, +}; + +int __init omap4xxx_dt_clk_init(void) +{ + int rc; + struct clk *abe_dpll_ref, *abe_dpll, *sys_32k_ck, *usb_dpll; + + ti_dt_clocks_register(omap44xx_clks); + + omap2_clk_disable_autoidle_all(); + + /* + * Lock USB DPLL on OMAP4 devices so that the L3INIT power + * domain can transition to retention state when not in use. + */ + usb_dpll = clk_get_sys(NULL, "dpll_usb_ck"); + rc = clk_set_rate(usb_dpll, OMAP4_DPLL_USB_DEFFREQ); + if (rc) + pr_err("%s: failed to configure USB DPLL!\n", __func__); + + /* + * On OMAP4460 the ABE DPLL fails to turn on if in idle low-power + * state when turning the ABE clock domain. Workaround this by + * locking the ABE DPLL on boot. + * Lock the ABE DPLL in any case to avoid issues with audio. + */ + abe_dpll_ref = clk_get_sys(NULL, "abe_dpll_refclk_mux_ck"); + sys_32k_ck = clk_get_sys(NULL, "sys_32k_ck"); + rc = clk_set_parent(abe_dpll_ref, sys_32k_ck); + abe_dpll = clk_get_sys(NULL, "dpll_abe_ck"); + if (!rc) + rc = clk_set_rate(abe_dpll, OMAP4_DPLL_ABE_DEFFREQ); + if (rc) + pr_err("%s: failed to configure ABE DPLL!\n", __func__); + + return 0; +} diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c new file mode 100644 index 000000000000..0ef9f581286b --- /dev/null +++ b/drivers/clk/ti/clk-54xx.c @@ -0,0 +1,255 @@ +/* + * OMAP5 Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/clk-private.h> +#include <linux/clkdev.h> +#include <linux/io.h> +#include <linux/clk/ti.h> + +#define OMAP5_DPLL_ABE_DEFFREQ 98304000 + +/* + * OMAP543x TRM, section "3.6.3.9.5 DPLL_USB Preferred Settings" + * states it must be at 960MHz + */ +#define OMAP5_DPLL_USB_DEFFREQ 960000000 + +static struct ti_dt_clk omap54xx_clks[] = { + DT_CLK(NULL, "pad_clks_src_ck", "pad_clks_src_ck"), + DT_CLK(NULL, "pad_clks_ck", "pad_clks_ck"), + DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"), + DT_CLK(NULL, "slimbus_src_clk", "slimbus_src_clk"), + DT_CLK(NULL, "slimbus_clk", "slimbus_clk"), + DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"), + DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"), + DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"), + DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"), + DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"), + DT_CLK(NULL, "sys_clkin", "sys_clkin"), + DT_CLK(NULL, "xclk60mhsp1_ck", "xclk60mhsp1_ck"), + DT_CLK(NULL, "xclk60mhsp2_ck", "xclk60mhsp2_ck"), + DT_CLK(NULL, "abe_dpll_bypass_clk_mux", "abe_dpll_bypass_clk_mux"), + DT_CLK(NULL, "abe_dpll_clk_mux", "abe_dpll_clk_mux"), + DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"), + DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"), + DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"), + DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"), + DT_CLK(NULL, "abe_clk", "abe_clk"), + DT_CLK(NULL, "abe_iclk", "abe_iclk"), + DT_CLK(NULL, "abe_lp_clk_div", "abe_lp_clk_div"), + DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_h21x2_ck", "dpll_core_h21x2_ck"), + DT_CLK(NULL, "c2c_fclk", "c2c_fclk"), + DT_CLK(NULL, "c2c_iclk", "c2c_iclk"), + DT_CLK(NULL, "custefuse_sys_gfclk_div", "custefuse_sys_gfclk_div"), + DT_CLK(NULL, "dpll_core_h11x2_ck", "dpll_core_h11x2_ck"), + DT_CLK(NULL, "dpll_core_h12x2_ck", "dpll_core_h12x2_ck"), + DT_CLK(NULL, "dpll_core_h13x2_ck", "dpll_core_h13x2_ck"), + DT_CLK(NULL, "dpll_core_h14x2_ck", "dpll_core_h14x2_ck"), + DT_CLK(NULL, "dpll_core_h22x2_ck", "dpll_core_h22x2_ck"), + DT_CLK(NULL, "dpll_core_h23x2_ck", "dpll_core_h23x2_ck"), + DT_CLK(NULL, "dpll_core_h24x2_ck", "dpll_core_h24x2_ck"), + DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"), + DT_CLK(NULL, "dpll_core_m3x2_ck", "dpll_core_m3x2_ck"), + DT_CLK(NULL, "iva_dpll_hs_clk_div", "iva_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"), + DT_CLK(NULL, "dpll_iva_x2_ck", "dpll_iva_x2_ck"), + DT_CLK(NULL, "dpll_iva_h11x2_ck", "dpll_iva_h11x2_ck"), + DT_CLK(NULL, "dpll_iva_h12x2_ck", "dpll_iva_h12x2_ck"), + DT_CLK(NULL, "mpu_dpll_hs_clk_div", "mpu_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "per_dpll_hs_clk_div", "per_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"), + DT_CLK(NULL, "dpll_per_h11x2_ck", "dpll_per_h11x2_ck"), + DT_CLK(NULL, "dpll_per_h12x2_ck", "dpll_per_h12x2_ck"), + DT_CLK(NULL, "dpll_per_h14x2_ck", "dpll_per_h14x2_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"), + DT_CLK(NULL, "dpll_per_m3x2_ck", "dpll_per_m3x2_ck"), + DT_CLK(NULL, "dpll_unipro1_ck", "dpll_unipro1_ck"), + DT_CLK(NULL, "dpll_unipro1_clkdcoldo", "dpll_unipro1_clkdcoldo"), + DT_CLK(NULL, "dpll_unipro1_m2_ck", "dpll_unipro1_m2_ck"), + DT_CLK(NULL, "dpll_unipro2_ck", "dpll_unipro2_ck"), + DT_CLK(NULL, "dpll_unipro2_clkdcoldo", "dpll_unipro2_clkdcoldo"), + DT_CLK(NULL, "dpll_unipro2_m2_ck", "dpll_unipro2_m2_ck"), + DT_CLK(NULL, "usb_dpll_hs_clk_div", "usb_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"), + DT_CLK(NULL, "dpll_usb_clkdcoldo", "dpll_usb_clkdcoldo"), + DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"), + DT_CLK(NULL, "dss_syc_gfclk_div", "dss_syc_gfclk_div"), + DT_CLK(NULL, "func_128m_clk", "func_128m_clk"), + DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"), + DT_CLK(NULL, "func_24m_clk", "func_24m_clk"), + DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"), + DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"), + DT_CLK(NULL, "l3_iclk_div", "l3_iclk_div"), + DT_CLK(NULL, "gpu_l3_iclk", "gpu_l3_iclk"), + DT_CLK(NULL, "l3init_60m_fclk", "l3init_60m_fclk"), + DT_CLK(NULL, "wkupaon_iclk_mux", "wkupaon_iclk_mux"), + DT_CLK(NULL, "l3instr_ts_gclk_div", "l3instr_ts_gclk_div"), + DT_CLK(NULL, "l4_root_clk_div", "l4_root_clk_div"), + DT_CLK(NULL, "dss_32khz_clk", "dss_32khz_clk"), + DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"), + DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"), + DT_CLK(NULL, "dss_sys_clk", "dss_sys_clk"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), + DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), + DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"), + DT_CLK(NULL, "gpio7_dbclk", "gpio7_dbclk"), + DT_CLK(NULL, "gpio8_dbclk", "gpio8_dbclk"), + DT_CLK(NULL, "iss_ctrlclk", "iss_ctrlclk"), + DT_CLK(NULL, "lli_txphy_clk", "lli_txphy_clk"), + DT_CLK(NULL, "lli_txphy_ls_clk", "lli_txphy_ls_clk"), + DT_CLK(NULL, "mmc1_32khz_clk", "mmc1_32khz_clk"), + DT_CLK(NULL, "sata_ref_clk", "sata_ref_clk"), + DT_CLK(NULL, "slimbus1_slimbus_clk", "slimbus1_slimbus_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p1_clk", "usb_host_hs_hsic480m_p1_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p2_clk", "usb_host_hs_hsic480m_p2_clk"), + DT_CLK(NULL, "usb_host_hs_hsic480m_p3_clk", "usb_host_hs_hsic480m_p3_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p1_clk", "usb_host_hs_hsic60m_p1_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p2_clk", "usb_host_hs_hsic60m_p2_clk"), + DT_CLK(NULL, "usb_host_hs_hsic60m_p3_clk", "usb_host_hs_hsic60m_p3_clk"), + DT_CLK(NULL, "usb_host_hs_utmi_p1_clk", "usb_host_hs_utmi_p1_clk"), + DT_CLK(NULL, "usb_host_hs_utmi_p2_clk", "usb_host_hs_utmi_p2_clk"), + DT_CLK(NULL, "usb_host_hs_utmi_p3_clk", "usb_host_hs_utmi_p3_clk"), + DT_CLK(NULL, "usb_otg_ss_refclk960m", "usb_otg_ss_refclk960m"), + DT_CLK(NULL, "usb_phy_cm_clk32k", "usb_phy_cm_clk32k"), + DT_CLK(NULL, "usb_tll_hs_usb_ch0_clk", "usb_tll_hs_usb_ch0_clk"), + DT_CLK(NULL, "usb_tll_hs_usb_ch1_clk", "usb_tll_hs_usb_ch1_clk"), + DT_CLK(NULL, "usb_tll_hs_usb_ch2_clk", "usb_tll_hs_usb_ch2_clk"), + DT_CLK(NULL, "aess_fclk", "aess_fclk"), + DT_CLK(NULL, "dmic_sync_mux_ck", "dmic_sync_mux_ck"), + DT_CLK(NULL, "dmic_gfclk", "dmic_gfclk"), + DT_CLK(NULL, "fdif_fclk", "fdif_fclk"), + DT_CLK(NULL, "gpu_core_gclk_mux", "gpu_core_gclk_mux"), + DT_CLK(NULL, "gpu_hyd_gclk_mux", "gpu_hyd_gclk_mux"), + DT_CLK(NULL, "hsi_fclk", "hsi_fclk"), + DT_CLK(NULL, "mcasp_sync_mux_ck", "mcasp_sync_mux_ck"), + DT_CLK(NULL, "mcasp_gfclk", "mcasp_gfclk"), + DT_CLK(NULL, "mcbsp1_sync_mux_ck", "mcbsp1_sync_mux_ck"), + DT_CLK(NULL, "mcbsp1_gfclk", "mcbsp1_gfclk"), + DT_CLK(NULL, "mcbsp2_sync_mux_ck", "mcbsp2_sync_mux_ck"), + DT_CLK(NULL, "mcbsp2_gfclk", "mcbsp2_gfclk"), + DT_CLK(NULL, "mcbsp3_sync_mux_ck", "mcbsp3_sync_mux_ck"), + DT_CLK(NULL, "mcbsp3_gfclk", "mcbsp3_gfclk"), + DT_CLK(NULL, "mmc1_fclk_mux", "mmc1_fclk_mux"), + DT_CLK(NULL, "mmc1_fclk", "mmc1_fclk"), + DT_CLK(NULL, "mmc2_fclk_mux", "mmc2_fclk_mux"), + DT_CLK(NULL, "mmc2_fclk", "mmc2_fclk"), + DT_CLK(NULL, "timer10_gfclk_mux", "timer10_gfclk_mux"), + DT_CLK(NULL, "timer11_gfclk_mux", "timer11_gfclk_mux"), + DT_CLK(NULL, "timer1_gfclk_mux", "timer1_gfclk_mux"), + DT_CLK(NULL, "timer2_gfclk_mux", "timer2_gfclk_mux"), + DT_CLK(NULL, "timer3_gfclk_mux", "timer3_gfclk_mux"), + DT_CLK(NULL, "timer4_gfclk_mux", "timer4_gfclk_mux"), + DT_CLK(NULL, "timer5_gfclk_mux", "timer5_gfclk_mux"), + DT_CLK(NULL, "timer6_gfclk_mux", "timer6_gfclk_mux"), + DT_CLK(NULL, "timer7_gfclk_mux", "timer7_gfclk_mux"), + DT_CLK(NULL, "timer8_gfclk_mux", "timer8_gfclk_mux"), + DT_CLK(NULL, "timer9_gfclk_mux", "timer9_gfclk_mux"), + DT_CLK(NULL, "utmi_p1_gfclk", "utmi_p1_gfclk"), + DT_CLK(NULL, "utmi_p2_gfclk", "utmi_p2_gfclk"), + DT_CLK(NULL, "auxclk0_src_ck", "auxclk0_src_ck"), + DT_CLK(NULL, "auxclk0_ck", "auxclk0_ck"), + DT_CLK(NULL, "auxclkreq0_ck", "auxclkreq0_ck"), + DT_CLK(NULL, "auxclk1_src_ck", "auxclk1_src_ck"), + DT_CLK(NULL, "auxclk1_ck", "auxclk1_ck"), + DT_CLK(NULL, "auxclkreq1_ck", "auxclkreq1_ck"), + DT_CLK(NULL, "auxclk2_src_ck", "auxclk2_src_ck"), + DT_CLK(NULL, "auxclk2_ck", "auxclk2_ck"), + DT_CLK(NULL, "auxclkreq2_ck", "auxclkreq2_ck"), + DT_CLK(NULL, "auxclk3_src_ck", "auxclk3_src_ck"), + DT_CLK(NULL, "auxclk3_ck", "auxclk3_ck"), + DT_CLK(NULL, "auxclkreq3_ck", "auxclkreq3_ck"), + DT_CLK(NULL, "gpmc_ck", "dummy_ck"), + DT_CLK("omap_i2c.1", "ick", "dummy_ck"), + DT_CLK("omap_i2c.2", "ick", "dummy_ck"), + DT_CLK("omap_i2c.3", "ick", "dummy_ck"), + DT_CLK("omap_i2c.4", "ick", "dummy_ck"), + DT_CLK(NULL, "mailboxes_ick", "dummy_ck"), + DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"), + DT_CLK(NULL, "uart1_ick", "dummy_ck"), + DT_CLK(NULL, "uart2_ick", "dummy_ck"), + DT_CLK(NULL, "uart3_ick", "dummy_ck"), + DT_CLK(NULL, "uart4_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), + DT_CLK("omap_wdt", "ick", "dummy_ck"), + DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), + DT_CLK("omap_timer.1", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.2", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.3", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.4", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.9", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.10", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.11", "sys_ck", "sys_clkin"), + DT_CLK("omap_timer.5", "sys_ck", "dss_syc_gfclk_div"), + DT_CLK("omap_timer.6", "sys_ck", "dss_syc_gfclk_div"), + DT_CLK("omap_timer.7", "sys_ck", "dss_syc_gfclk_div"), + DT_CLK("omap_timer.8", "sys_ck", "dss_syc_gfclk_div"), + { .node_name = NULL }, +}; + +int __init omap5xxx_dt_clk_init(void) +{ + int rc; + struct clk *abe_dpll_ref, *abe_dpll, *sys_32k_ck, *usb_dpll; + + ti_dt_clocks_register(omap54xx_clks); + + omap2_clk_disable_autoidle_all(); + + abe_dpll_ref = clk_get_sys(NULL, "abe_dpll_clk_mux"); + sys_32k_ck = clk_get_sys(NULL, "sys_32k_ck"); + rc = clk_set_parent(abe_dpll_ref, sys_32k_ck); + abe_dpll = clk_get_sys(NULL, "dpll_abe_ck"); + if (!rc) + rc = clk_set_rate(abe_dpll, OMAP5_DPLL_ABE_DEFFREQ); + if (rc) + pr_err("%s: failed to configure ABE DPLL!\n", __func__); + + usb_dpll = clk_get_sys(NULL, "dpll_usb_ck"); + rc = clk_set_rate(usb_dpll, OMAP5_DPLL_USB_DEFFREQ); + if (rc) + pr_err("%s: failed to configure USB DPLL!\n", __func__); + + usb_dpll = clk_get_sys(NULL, "dpll_usb_m2_ck"); + rc = clk_set_rate(usb_dpll, OMAP5_DPLL_USB_DEFFREQ/2); + if (rc) + pr_err("%s: failed to set USB_DPLL M2 OUT\n", __func__); + + return 0; +} diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c new file mode 100644 index 000000000000..9977653f2d63 --- /dev/null +++ b/drivers/clk/ti/clk-7xx.c @@ -0,0 +1,332 @@ +/* + * DRA7 Clock init + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/clk-private.h> +#include <linux/clkdev.h> +#include <linux/clk/ti.h> + +#define DRA7_DPLL_ABE_DEFFREQ 361267200 +#define DRA7_DPLL_GMAC_DEFFREQ 1000000000 + + +static struct ti_dt_clk dra7xx_clks[] = { + DT_CLK(NULL, "atl_clkin0_ck", "atl_clkin0_ck"), + DT_CLK(NULL, "atl_clkin1_ck", "atl_clkin1_ck"), + DT_CLK(NULL, "atl_clkin2_ck", "atl_clkin2_ck"), + DT_CLK(NULL, "atlclkin3_ck", "atlclkin3_ck"), + DT_CLK(NULL, "hdmi_clkin_ck", "hdmi_clkin_ck"), + DT_CLK(NULL, "mlb_clkin_ck", "mlb_clkin_ck"), + DT_CLK(NULL, "mlbp_clkin_ck", "mlbp_clkin_ck"), + DT_CLK(NULL, "pciesref_acs_clk_ck", "pciesref_acs_clk_ck"), + DT_CLK(NULL, "ref_clkin0_ck", "ref_clkin0_ck"), + DT_CLK(NULL, "ref_clkin1_ck", "ref_clkin1_ck"), + DT_CLK(NULL, "ref_clkin2_ck", "ref_clkin2_ck"), + DT_CLK(NULL, "ref_clkin3_ck", "ref_clkin3_ck"), + DT_CLK(NULL, "rmii_clk_ck", "rmii_clk_ck"), + DT_CLK(NULL, "sdvenc_clkin_ck", "sdvenc_clkin_ck"), + DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"), + DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"), + DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"), + DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"), + DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"), + DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"), + DT_CLK(NULL, "virt_20000000_ck", "virt_20000000_ck"), + DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"), + DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"), + DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"), + DT_CLK(NULL, "sys_clkin1", "sys_clkin1"), + DT_CLK(NULL, "sys_clkin2", "sys_clkin2"), + DT_CLK(NULL, "usb_otg_clkin_ck", "usb_otg_clkin_ck"), + DT_CLK(NULL, "video1_clkin_ck", "video1_clkin_ck"), + DT_CLK(NULL, "video1_m2_clkin_ck", "video1_m2_clkin_ck"), + DT_CLK(NULL, "video2_clkin_ck", "video2_clkin_ck"), + DT_CLK(NULL, "video2_m2_clkin_ck", "video2_m2_clkin_ck"), + DT_CLK(NULL, "abe_dpll_sys_clk_mux", "abe_dpll_sys_clk_mux"), + DT_CLK(NULL, "abe_dpll_bypass_clk_mux", "abe_dpll_bypass_clk_mux"), + DT_CLK(NULL, "abe_dpll_clk_mux", "abe_dpll_clk_mux"), + DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"), + DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"), + DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"), + DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"), + DT_CLK(NULL, "abe_clk", "abe_clk"), + DT_CLK(NULL, "aess_fclk", "aess_fclk"), + DT_CLK(NULL, "abe_giclk_div", "abe_giclk_div"), + DT_CLK(NULL, "abe_lp_clk_div", "abe_lp_clk_div"), + DT_CLK(NULL, "abe_sys_clk_div", "abe_sys_clk_div"), + DT_CLK(NULL, "adc_gfclk_mux", "adc_gfclk_mux"), + DT_CLK(NULL, "dpll_pcie_ref_ck", "dpll_pcie_ref_ck"), + DT_CLK(NULL, "dpll_pcie_ref_m2ldo_ck", "dpll_pcie_ref_m2ldo_ck"), + DT_CLK(NULL, "apll_pcie_ck", "apll_pcie_ck"), + DT_CLK(NULL, "apll_pcie_clkvcoldo", "apll_pcie_clkvcoldo"), + DT_CLK(NULL, "apll_pcie_clkvcoldo_div", "apll_pcie_clkvcoldo_div"), + DT_CLK(NULL, "apll_pcie_m2_ck", "apll_pcie_m2_ck"), + DT_CLK(NULL, "sys_clk1_dclk_div", "sys_clk1_dclk_div"), + DT_CLK(NULL, "sys_clk2_dclk_div", "sys_clk2_dclk_div"), + DT_CLK(NULL, "dpll_abe_m2_ck", "dpll_abe_m2_ck"), + DT_CLK(NULL, "per_abe_x1_dclk_div", "per_abe_x1_dclk_div"), + DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"), + DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"), + DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"), + DT_CLK(NULL, "dpll_core_h12x2_ck", "dpll_core_h12x2_ck"), + DT_CLK(NULL, "mpu_dpll_hs_clk_div", "mpu_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"), + DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"), + DT_CLK(NULL, "mpu_dclk_div", "mpu_dclk_div"), + DT_CLK(NULL, "dsp_dpll_hs_clk_div", "dsp_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_dsp_ck", "dpll_dsp_ck"), + DT_CLK(NULL, "dpll_dsp_m2_ck", "dpll_dsp_m2_ck"), + DT_CLK(NULL, "dsp_gclk_div", "dsp_gclk_div"), + DT_CLK(NULL, "iva_dpll_hs_clk_div", "iva_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"), + DT_CLK(NULL, "dpll_iva_m2_ck", "dpll_iva_m2_ck"), + DT_CLK(NULL, "iva_dclk", "iva_dclk"), + DT_CLK(NULL, "dpll_gpu_ck", "dpll_gpu_ck"), + DT_CLK(NULL, "dpll_gpu_m2_ck", "dpll_gpu_m2_ck"), + DT_CLK(NULL, "gpu_dclk", "gpu_dclk"), + DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"), + DT_CLK(NULL, "core_dpll_out_dclk_div", "core_dpll_out_dclk_div"), + DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"), + DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"), + DT_CLK(NULL, "emif_phy_dclk_div", "emif_phy_dclk_div"), + DT_CLK(NULL, "dpll_gmac_ck", "dpll_gmac_ck"), + DT_CLK(NULL, "dpll_gmac_m2_ck", "dpll_gmac_m2_ck"), + DT_CLK(NULL, "gmac_250m_dclk_div", "gmac_250m_dclk_div"), + DT_CLK(NULL, "video2_dclk_div", "video2_dclk_div"), + DT_CLK(NULL, "video1_dclk_div", "video1_dclk_div"), + DT_CLK(NULL, "hdmi_dclk_div", "hdmi_dclk_div"), + DT_CLK(NULL, "per_dpll_hs_clk_div", "per_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"), + DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"), + DT_CLK(NULL, "func_96m_aon_dclk_div", "func_96m_aon_dclk_div"), + DT_CLK(NULL, "usb_dpll_hs_clk_div", "usb_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"), + DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"), + DT_CLK(NULL, "l3init_480m_dclk_div", "l3init_480m_dclk_div"), + DT_CLK(NULL, "usb_otg_dclk_div", "usb_otg_dclk_div"), + DT_CLK(NULL, "sata_dclk_div", "sata_dclk_div"), + DT_CLK(NULL, "dpll_pcie_ref_m2_ck", "dpll_pcie_ref_m2_ck"), + DT_CLK(NULL, "pcie2_dclk_div", "pcie2_dclk_div"), + DT_CLK(NULL, "pcie_dclk_div", "pcie_dclk_div"), + DT_CLK(NULL, "emu_dclk_div", "emu_dclk_div"), + DT_CLK(NULL, "secure_32k_dclk_div", "secure_32k_dclk_div"), + DT_CLK(NULL, "eve_dpll_hs_clk_div", "eve_dpll_hs_clk_div"), + DT_CLK(NULL, "dpll_eve_ck", "dpll_eve_ck"), + DT_CLK(NULL, "dpll_eve_m2_ck", "dpll_eve_m2_ck"), + DT_CLK(NULL, "eve_dclk_div", "eve_dclk_div"), + DT_CLK(NULL, "clkoutmux0_clk_mux", "clkoutmux0_clk_mux"), + DT_CLK(NULL, "clkoutmux1_clk_mux", "clkoutmux1_clk_mux"), + DT_CLK(NULL, "clkoutmux2_clk_mux", "clkoutmux2_clk_mux"), + DT_CLK(NULL, "custefuse_sys_gfclk_div", "custefuse_sys_gfclk_div"), + DT_CLK(NULL, "dpll_core_h13x2_ck", "dpll_core_h13x2_ck"), + DT_CLK(NULL, "dpll_core_h14x2_ck", "dpll_core_h14x2_ck"), + DT_CLK(NULL, "dpll_core_h22x2_ck", "dpll_core_h22x2_ck"), + DT_CLK(NULL, "dpll_core_h23x2_ck", "dpll_core_h23x2_ck"), + DT_CLK(NULL, "dpll_core_h24x2_ck", "dpll_core_h24x2_ck"), + DT_CLK(NULL, "dpll_ddr_x2_ck", "dpll_ddr_x2_ck"), + DT_CLK(NULL, "dpll_ddr_h11x2_ck", "dpll_ddr_h11x2_ck"), + DT_CLK(NULL, "dpll_dsp_x2_ck", "dpll_dsp_x2_ck"), + DT_CLK(NULL, "dpll_dsp_m3x2_ck", "dpll_dsp_m3x2_ck"), + DT_CLK(NULL, "dpll_gmac_x2_ck", "dpll_gmac_x2_ck"), + DT_CLK(NULL, "dpll_gmac_h11x2_ck", "dpll_gmac_h11x2_ck"), + DT_CLK(NULL, "dpll_gmac_h12x2_ck", "dpll_gmac_h12x2_ck"), + DT_CLK(NULL, "dpll_gmac_h13x2_ck", "dpll_gmac_h13x2_ck"), + DT_CLK(NULL, "dpll_gmac_m3x2_ck", "dpll_gmac_m3x2_ck"), + DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"), + DT_CLK(NULL, "dpll_per_h11x2_ck", "dpll_per_h11x2_ck"), + DT_CLK(NULL, "dpll_per_h12x2_ck", "dpll_per_h12x2_ck"), + DT_CLK(NULL, "dpll_per_h13x2_ck", "dpll_per_h13x2_ck"), + DT_CLK(NULL, "dpll_per_h14x2_ck", "dpll_per_h14x2_ck"), + DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"), + DT_CLK(NULL, "dpll_usb_clkdcoldo", "dpll_usb_clkdcoldo"), + DT_CLK(NULL, "eve_clk", "eve_clk"), + DT_CLK(NULL, "func_128m_clk", "func_128m_clk"), + DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"), + DT_CLK(NULL, "func_24m_clk", "func_24m_clk"), + DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"), + DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"), + DT_CLK(NULL, "gmii_m_clk_div", "gmii_m_clk_div"), + DT_CLK(NULL, "hdmi_clk2_div", "hdmi_clk2_div"), + DT_CLK(NULL, "hdmi_div_clk", "hdmi_div_clk"), + DT_CLK(NULL, "hdmi_dpll_clk_mux", "hdmi_dpll_clk_mux"), + DT_CLK(NULL, "l3_iclk_div", "l3_iclk_div"), + DT_CLK(NULL, "l3init_60m_fclk", "l3init_60m_fclk"), + DT_CLK(NULL, "l4_root_clk_div", "l4_root_clk_div"), + DT_CLK(NULL, "mlb_clk", "mlb_clk"), + DT_CLK(NULL, "mlbp_clk", "mlbp_clk"), + DT_CLK(NULL, "per_abe_x1_gfclk2_div", "per_abe_x1_gfclk2_div"), + DT_CLK(NULL, "timer_sys_clk_div", "timer_sys_clk_div"), + DT_CLK(NULL, "video1_clk2_div", "video1_clk2_div"), + DT_CLK(NULL, "video1_div_clk", "video1_div_clk"), + DT_CLK(NULL, "video1_dpll_clk_mux", "video1_dpll_clk_mux"), + DT_CLK(NULL, "video2_clk2_div", "video2_clk2_div"), + DT_CLK(NULL, "video2_div_clk", "video2_div_clk"), + DT_CLK(NULL, "video2_dpll_clk_mux", "video2_dpll_clk_mux"), + DT_CLK(NULL, "wkupaon_iclk_mux", "wkupaon_iclk_mux"), + DT_CLK(NULL, "dss_32khz_clk", "dss_32khz_clk"), + DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"), + DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"), + DT_CLK(NULL, "dss_hdmi_clk", "dss_hdmi_clk"), + DT_CLK(NULL, "dss_video1_clk", "dss_video1_clk"), + DT_CLK(NULL, "dss_video2_clk", "dss_video2_clk"), + DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), + DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"), + DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"), + DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"), + DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"), + DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"), + DT_CLK(NULL, "gpio7_dbclk", "gpio7_dbclk"), + DT_CLK(NULL, "gpio8_dbclk", "gpio8_dbclk"), + DT_CLK(NULL, "mmc1_clk32k", "mmc1_clk32k"), + DT_CLK(NULL, "mmc2_clk32k", "mmc2_clk32k"), + DT_CLK(NULL, "mmc3_clk32k", "mmc3_clk32k"), + DT_CLK(NULL, "mmc4_clk32k", "mmc4_clk32k"), + DT_CLK(NULL, "sata_ref_clk", "sata_ref_clk"), + DT_CLK(NULL, "usb_otg_ss1_refclk960m", "usb_otg_ss1_refclk960m"), + DT_CLK(NULL, "usb_otg_ss2_refclk960m", "usb_otg_ss2_refclk960m"), + DT_CLK(NULL, "usb_phy1_always_on_clk32k", "usb_phy1_always_on_clk32k"), + DT_CLK(NULL, "usb_phy2_always_on_clk32k", "usb_phy2_always_on_clk32k"), + DT_CLK(NULL, "usb_phy3_always_on_clk32k", "usb_phy3_always_on_clk32k"), + DT_CLK(NULL, "atl_dpll_clk_mux", "atl_dpll_clk_mux"), + DT_CLK(NULL, "atl_gfclk_mux", "atl_gfclk_mux"), + DT_CLK(NULL, "dcan1_sys_clk_mux", "dcan1_sys_clk_mux"), + DT_CLK(NULL, "gmac_gmii_ref_clk_div", "gmac_gmii_ref_clk_div"), + DT_CLK(NULL, "gmac_rft_clk_mux", "gmac_rft_clk_mux"), + DT_CLK(NULL, "gpu_core_gclk_mux", "gpu_core_gclk_mux"), + DT_CLK(NULL, "gpu_hyd_gclk_mux", "gpu_hyd_gclk_mux"), + DT_CLK(NULL, "ipu1_gfclk_mux", "ipu1_gfclk_mux"), + DT_CLK(NULL, "l3instr_ts_gclk_div", "l3instr_ts_gclk_div"), + DT_CLK(NULL, "mcasp1_ahclkr_mux", "mcasp1_ahclkr_mux"), + DT_CLK(NULL, "mcasp1_ahclkx_mux", "mcasp1_ahclkx_mux"), + DT_CLK(NULL, "mcasp1_aux_gfclk_mux", "mcasp1_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp2_ahclkr_mux", "mcasp2_ahclkr_mux"), + DT_CLK(NULL, "mcasp2_ahclkx_mux", "mcasp2_ahclkx_mux"), + DT_CLK(NULL, "mcasp2_aux_gfclk_mux", "mcasp2_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp3_ahclkx_mux", "mcasp3_ahclkx_mux"), + DT_CLK(NULL, "mcasp3_aux_gfclk_mux", "mcasp3_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp4_ahclkx_mux", "mcasp4_ahclkx_mux"), + DT_CLK(NULL, "mcasp4_aux_gfclk_mux", "mcasp4_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp5_ahclkx_mux", "mcasp5_ahclkx_mux"), + DT_CLK(NULL, "mcasp5_aux_gfclk_mux", "mcasp5_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp6_ahclkx_mux", "mcasp6_ahclkx_mux"), + DT_CLK(NULL, "mcasp6_aux_gfclk_mux", "mcasp6_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp7_ahclkx_mux", "mcasp7_ahclkx_mux"), + DT_CLK(NULL, "mcasp7_aux_gfclk_mux", "mcasp7_aux_gfclk_mux"), + DT_CLK(NULL, "mcasp8_ahclk_mux", "mcasp8_ahclk_mux"), + DT_CLK(NULL, "mcasp8_aux_gfclk_mux", "mcasp8_aux_gfclk_mux"), + DT_CLK(NULL, "mmc1_fclk_mux", "mmc1_fclk_mux"), + DT_CLK(NULL, "mmc1_fclk_div", "mmc1_fclk_div"), + DT_CLK(NULL, "mmc2_fclk_mux", "mmc2_fclk_mux"), + DT_CLK(NULL, "mmc2_fclk_div", "mmc2_fclk_div"), + DT_CLK(NULL, "mmc3_gfclk_mux", "mmc3_gfclk_mux"), + DT_CLK(NULL, "mmc3_gfclk_div", "mmc3_gfclk_div"), + DT_CLK(NULL, "mmc4_gfclk_mux", "mmc4_gfclk_mux"), + DT_CLK(NULL, "mmc4_gfclk_div", "mmc4_gfclk_div"), + DT_CLK(NULL, "qspi_gfclk_mux", "qspi_gfclk_mux"), + DT_CLK(NULL, "qspi_gfclk_div", "qspi_gfclk_div"), + DT_CLK(NULL, "timer10_gfclk_mux", "timer10_gfclk_mux"), + DT_CLK(NULL, "timer11_gfclk_mux", "timer11_gfclk_mux"), + DT_CLK(NULL, "timer13_gfclk_mux", "timer13_gfclk_mux"), + DT_CLK(NULL, "timer14_gfclk_mux", "timer14_gfclk_mux"), + DT_CLK(NULL, "timer15_gfclk_mux", "timer15_gfclk_mux"), + DT_CLK(NULL, "timer16_gfclk_mux", "timer16_gfclk_mux"), + DT_CLK(NULL, "timer1_gfclk_mux", "timer1_gfclk_mux"), + DT_CLK(NULL, "timer2_gfclk_mux", "timer2_gfclk_mux"), + DT_CLK(NULL, "timer3_gfclk_mux", "timer3_gfclk_mux"), + DT_CLK(NULL, "timer4_gfclk_mux", "timer4_gfclk_mux"), + DT_CLK(NULL, "timer5_gfclk_mux", "timer5_gfclk_mux"), + DT_CLK(NULL, "timer6_gfclk_mux", "timer6_gfclk_mux"), + DT_CLK(NULL, "timer7_gfclk_mux", "timer7_gfclk_mux"), + DT_CLK(NULL, "timer8_gfclk_mux", "timer8_gfclk_mux"), + DT_CLK(NULL, "timer9_gfclk_mux", "timer9_gfclk_mux"), + DT_CLK(NULL, "uart10_gfclk_mux", "uart10_gfclk_mux"), + DT_CLK(NULL, "uart1_gfclk_mux", "uart1_gfclk_mux"), + DT_CLK(NULL, "uart2_gfclk_mux", "uart2_gfclk_mux"), + DT_CLK(NULL, "uart3_gfclk_mux", "uart3_gfclk_mux"), + DT_CLK(NULL, "uart4_gfclk_mux", "uart4_gfclk_mux"), + DT_CLK(NULL, "uart5_gfclk_mux", "uart5_gfclk_mux"), + DT_CLK(NULL, "uart6_gfclk_mux", "uart6_gfclk_mux"), + DT_CLK(NULL, "uart7_gfclk_mux", "uart7_gfclk_mux"), + DT_CLK(NULL, "uart8_gfclk_mux", "uart8_gfclk_mux"), + DT_CLK(NULL, "uart9_gfclk_mux", "uart9_gfclk_mux"), + DT_CLK(NULL, "vip1_gclk_mux", "vip1_gclk_mux"), + DT_CLK(NULL, "vip2_gclk_mux", "vip2_gclk_mux"), + DT_CLK(NULL, "vip3_gclk_mux", "vip3_gclk_mux"), + DT_CLK(NULL, "gpmc_ck", "dummy_ck"), + DT_CLK("omap_i2c.1", "ick", "dummy_ck"), + DT_CLK("omap_i2c.2", "ick", "dummy_ck"), + DT_CLK("omap_i2c.3", "ick", "dummy_ck"), + DT_CLK("omap_i2c.4", "ick", "dummy_ck"), + DT_CLK(NULL, "mailboxes_ick", "dummy_ck"), + DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"), + DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"), + DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"), + DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"), + DT_CLK(NULL, "uart1_ick", "dummy_ck"), + DT_CLK(NULL, "uart2_ick", "dummy_ck"), + DT_CLK(NULL, "uart3_ick", "dummy_ck"), + DT_CLK(NULL, "uart4_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"), + DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"), + DT_CLK("omap_wdt", "ick", "dummy_ck"), + DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"), + DT_CLK("4ae18000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48036000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("4803e000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48086000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48088000.timer", "timer_sys_ck", "sys_clkin2"), + DT_CLK("48820000.timer", "timer_sys_ck", "timer_sys_clk_div"), + DT_CLK("48822000.timer", "timer_sys_ck", "timer_sys_clk_div"), + DT_CLK("48824000.timer", "timer_sys_ck", "timer_sys_clk_div"), + DT_CLK("48826000.timer", "timer_sys_ck", "timer_sys_clk_div"), + DT_CLK(NULL, "sys_clkin", "sys_clkin1"), + { .node_name = NULL }, +}; + +int __init dra7xx_dt_clk_init(void) +{ + int rc; + struct clk *abe_dpll_mux, *sys_clkin2, *dpll_ck; + + ti_dt_clocks_register(dra7xx_clks); + + omap2_clk_disable_autoidle_all(); + + abe_dpll_mux = clk_get_sys(NULL, "abe_dpll_sys_clk_mux"); + sys_clkin2 = clk_get_sys(NULL, "sys_clkin2"); + dpll_ck = clk_get_sys(NULL, "dpll_abe_ck"); + + rc = clk_set_parent(abe_dpll_mux, sys_clkin2); + if (!rc) + rc = clk_set_rate(dpll_ck, DRA7_DPLL_ABE_DEFFREQ); + if (rc) + pr_err("%s: failed to configure ABE DPLL!\n", __func__); + + dpll_ck = clk_get_sys(NULL, "dpll_gmac_ck"); + rc = clk_set_rate(dpll_ck, DRA7_DPLL_GMAC_DEFFREQ); + if (rc) + pr_err("%s: failed to configure GMAC DPLL!\n", __func__); + + return rc; +} diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c new file mode 100644 index 000000000000..b1a6f7144f3f --- /dev/null +++ b/drivers/clk/ti/clk.c @@ -0,0 +1,167 @@ +/* + * TI clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk/ti.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/list.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static int ti_dt_clk_memmap_index; +struct ti_clk_ll_ops *ti_clk_ll_ops; + +/** + * ti_dt_clocks_register - register DT alias clocks during boot + * @oclks: list of clocks to register + * + * Register alias or non-standard DT clock entries during boot. By + * default, DT clocks are found based on their node name. If any + * additional con-id / dev-id -> clock mapping is required, use this + * function to list these. + */ +void __init ti_dt_clocks_register(struct ti_dt_clk oclks[]) +{ + struct ti_dt_clk *c; + struct device_node *node; + struct clk *clk; + struct of_phandle_args clkspec; + + for (c = oclks; c->node_name != NULL; c++) { + node = of_find_node_by_name(NULL, c->node_name); + clkspec.np = node; + clk = of_clk_get_from_provider(&clkspec); + + if (!IS_ERR(clk)) { + c->lk.clk = clk; + clkdev_add(&c->lk); + } else { + pr_warn("failed to lookup clock node %s\n", + c->node_name); + } + } +} + +struct clk_init_item { + struct device_node *node; + struct clk_hw *hw; + ti_of_clk_init_cb_t func; + struct list_head link; +}; + +static LIST_HEAD(retry_list); + +/** + * ti_clk_retry_init - retries a failed clock init at later phase + * @node: device not for the clock + * @hw: partially initialized clk_hw struct for the clock + * @func: init function to be called for the clock + * + * Adds a failed clock init to the retry list. The retry list is parsed + * once all the other clocks have been initialized. + */ +int __init ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, + ti_of_clk_init_cb_t func) +{ + struct clk_init_item *retry; + + pr_debug("%s: adding to retry list...\n", node->name); + retry = kzalloc(sizeof(*retry), GFP_KERNEL); + if (!retry) + return -ENOMEM; + + retry->node = node; + retry->func = func; + retry->hw = hw; + list_add(&retry->link, &retry_list); + + return 0; +} + +/** + * ti_clk_get_reg_addr - get register address for a clock register + * @node: device node for the clock + * @index: register index from the clock node + * + * Builds clock register address from device tree information. This + * is a struct of type clk_omap_reg. + */ +void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) +{ + struct clk_omap_reg *reg; + u32 val; + u32 tmp; + + reg = (struct clk_omap_reg *)&tmp; + reg->index = ti_dt_clk_memmap_index; + + if (of_property_read_u32_index(node, "reg", index, &val)) { + pr_err("%s must have reg[%d]!\n", node->name, index); + return NULL; + } + + reg->offset = val; + + return (void __iomem *)tmp; +} + +/** + * ti_dt_clk_init_provider - init master clock provider + * @parent: master node + * @index: internal index for clk_reg_ops + * + * Initializes a master clock IP block and its child clock nodes. + * Regmap is provided for accessing the register space for the + * IP block and all the clocks under it. + */ +void ti_dt_clk_init_provider(struct device_node *parent, int index) +{ + const struct of_device_id *match; + struct device_node *np; + struct device_node *clocks; + of_clk_init_cb_t clk_init_cb; + struct clk_init_item *retry; + struct clk_init_item *tmp; + + ti_dt_clk_memmap_index = index; + + /* get clocks for this parent */ + clocks = of_get_child_by_name(parent, "clocks"); + if (!clocks) { + pr_err("%s missing 'clocks' child node.\n", parent->name); + return; + } + + for_each_child_of_node(clocks, np) { + match = of_match_node(&__clk_of_table, np); + if (!match) + continue; + clk_init_cb = (of_clk_init_cb_t)match->data; + pr_debug("%s: initializing: %s\n", __func__, np->name); + clk_init_cb(np); + } + + list_for_each_entry_safe(retry, tmp, &retry_list, link) { + pr_debug("retry-init: %s\n", retry->node->name); + retry->func(retry->hw, retry->node); + list_del(&retry->link); + kfree(retry); + } +} diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c new file mode 100644 index 000000000000..f1e0038d76ac --- /dev/null +++ b/drivers/clk/ti/clockdomain.c @@ -0,0 +1,70 @@ +/* + * OMAP clockdomain support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static void __init of_ti_clockdomain_setup(struct device_node *node) +{ + struct clk *clk; + struct clk_hw *clk_hw; + const char *clkdm_name = node->name; + int i; + int num_clks; + + num_clks = of_count_phandle_with_args(node, "clocks", "#clock-cells"); + + for (i = 0; i < num_clks; i++) { + clk = of_clk_get(node, i); + if (__clk_get_flags(clk) & CLK_IS_BASIC) { + pr_warn("can't setup clkdm for basic clk %s\n", + __clk_get_name(clk)); + continue; + } + clk_hw = __clk_get_hw(clk); + to_clk_hw_omap(clk_hw)->clkdm_name = clkdm_name; + omap2_init_clk_clkdm(clk_hw); + } +} + +static struct of_device_id ti_clkdm_match_table[] __initdata = { + { .compatible = "ti,clockdomain" }, + { } +}; + +/** + * ti_dt_clockdomains_setup - setup device tree clockdomains + * + * Initializes clockdomain nodes for a SoC. This parses through all the + * nodes with compatible = "ti,clockdomain", and add the clockdomain + * info for all the clocks listed under these. This function shall be + * called after rest of the DT clock init has completed and all + * clock nodes have been registered. + */ +void __init ti_dt_clockdomains_setup(void) +{ + struct device_node *np; + for_each_matching_node(np, ti_clkdm_match_table) { + of_ti_clockdomain_setup(np); + } +} diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c new file mode 100644 index 000000000000..19d8980ba458 --- /dev/null +++ b/drivers/clk/ti/composite.c @@ -0,0 +1,269 @@ +/* + * TI composite clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> +#include <linux/list.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) + +static unsigned long ti_composite_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return ti_clk_divider_ops.recalc_rate(hw, parent_rate); +} + +static long ti_composite_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + return -EINVAL; +} + +static int ti_composite_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return -EINVAL; +} + +static const struct clk_ops ti_composite_divider_ops = { + .recalc_rate = &ti_composite_recalc_rate, + .round_rate = &ti_composite_round_rate, + .set_rate = &ti_composite_set_rate, +}; + +static const struct clk_ops ti_composite_gate_ops = { + .enable = &omap2_dflt_clk_enable, + .disable = &omap2_dflt_clk_disable, + .is_enabled = &omap2_dflt_clk_is_enabled, +}; + +struct component_clk { + int num_parents; + const char **parent_names; + struct device_node *node; + int type; + struct clk_hw *hw; + struct list_head link; +}; + +static const char * __initconst component_clk_types[] = { + "gate", "divider", "mux" +}; + +static LIST_HEAD(component_clks); + +static struct device_node *_get_component_node(struct device_node *node, int i) +{ + int rc; + struct of_phandle_args clkspec; + + rc = of_parse_phandle_with_args(node, "clocks", "#clock-cells", i, + &clkspec); + if (rc) + return NULL; + + return clkspec.np; +} + +static struct component_clk *_lookup_component(struct device_node *node) +{ + struct component_clk *comp; + + list_for_each_entry(comp, &component_clks, link) { + if (comp->node == node) + return comp; + } + return NULL; +} + +struct clk_hw_omap_comp { + struct clk_hw hw; + struct device_node *comp_nodes[CLK_COMPONENT_TYPE_MAX]; + struct component_clk *comp_clks[CLK_COMPONENT_TYPE_MAX]; +}; + +static inline struct clk_hw *_get_hw(struct clk_hw_omap_comp *clk, int idx) +{ + if (!clk) + return NULL; + + if (!clk->comp_clks[idx]) + return NULL; + + return clk->comp_clks[idx]->hw; +} + +#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) +{ + struct clk *clk; + struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw); + struct component_clk *comp; + int num_parents = 0; + const char **parent_names = NULL; + int i; + + /* Check for presence of each component clock */ + for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) { + if (!cclk->comp_nodes[i]) + continue; + + comp = _lookup_component(cclk->comp_nodes[i]); + if (!comp) { + 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)) + return; + + goto cleanup; + } + if (cclk->comp_clks[comp->type] != NULL) { + pr_err("duplicate component types for %s (%s)!\n", + node->name, component_clk_types[comp->type]); + goto cleanup; + } + + cclk->comp_clks[comp->type] = comp; + + /* Mark this node as found */ + cclk->comp_nodes[i] = NULL; + } + + /* All components exists, proceed with registration */ + for (i = CLK_COMPONENT_TYPE_MAX - 1; i >= 0; i--) { + comp = cclk->comp_clks[i]; + if (!comp) + continue; + if (comp->num_parents) { + num_parents = comp->num_parents; + parent_names = comp->parent_names; + break; + } + } + + if (!num_parents) { + pr_err("%s: no parents found for %s!\n", __func__, node->name); + goto cleanup; + } + + clk = clk_register_composite(NULL, node->name, + parent_names, num_parents, + _get_hw(cclk, CLK_COMPONENT_TYPE_MUX), + &ti_clk_mux_ops, + _get_hw(cclk, CLK_COMPONENT_TYPE_DIVIDER), + &ti_composite_divider_ops, + _get_hw(cclk, CLK_COMPONENT_TYPE_GATE), + &ti_composite_gate_ops, 0); + + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + +cleanup: + /* Free component clock list entries */ + for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) { + if (!cclk->comp_clks[i]) + continue; + list_del(&cclk->comp_clks[i]->link); + kfree(cclk->comp_clks[i]); + } + + kfree(cclk); +} + +static void __init of_ti_composite_clk_setup(struct device_node *node) +{ + int num_clks; + int i; + struct clk_hw_omap_comp *cclk; + + /* Number of component clocks to be put inside this clock */ + num_clks = of_clk_get_parent_count(node); + + if (num_clks < 1) { + pr_err("composite clk %s must have component(s)\n", node->name); + return; + } + + cclk = kzalloc(sizeof(*cclk), GFP_KERNEL); + if (!cclk) + return; + + /* Get device node pointers for each component clock */ + for (i = 0; i < num_clks; i++) + cclk->comp_nodes[i] = _get_component_node(node, i); + + ti_clk_register_composite(&cclk->hw, node); +} +CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock", + of_ti_composite_clk_setup); + +/** + * ti_clk_add_component - add a component clock to the pool + * @node: device node of the component clock + * @hw: hardware clock definition for the component clock + * @type: type of the component clock + * + * Adds a component clock to the list of available components, so that + * it can be registered by a composite clock. + */ +int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw, + int type) +{ + int num_parents; + const char **parent_names; + struct component_clk *clk; + int i; + + num_parents = of_clk_get_parent_count(node); + + if (num_parents < 1) { + pr_err("component-clock %s must have parent(s)\n", node->name); + return -EINVAL; + } + + parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL); + if (!parent_names) + return -ENOMEM; + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + if (!clk) { + kfree(parent_names); + return -ENOMEM; + } + + clk->num_parents = num_parents; + clk->parent_names = parent_names; + clk->hw = hw; + clk->node = node; + clk->type = type; + list_add(&clk->link, &component_clks); + + return 0; +} diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c new file mode 100644 index 000000000000..a15e445570b2 --- /dev/null +++ b/drivers/clk/ti/divider.c @@ -0,0 +1,487 @@ +/* + * TI Divider Clock + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) + +#define div_mask(d) ((1 << ((d)->width)) - 1) + +static unsigned int _get_table_maxdiv(const struct clk_div_table *table) +{ + unsigned int maxdiv = 0; + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div > maxdiv) + maxdiv = clkt->div; + return maxdiv; +} + +static unsigned int _get_maxdiv(struct clk_divider *divider) +{ + 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; +} + +static unsigned int _get_table_div(const struct clk_div_table *table, + unsigned int val) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->val == val) + return clkt->div; + return 0; +} + +static unsigned int _get_div(struct clk_divider *divider, unsigned int val) +{ + if (divider->flags & CLK_DIVIDER_ONE_BASED) + return val; + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) + return 1 << val; + if (divider->table) + return _get_table_div(divider->table, val); + return val + 1; +} + +static unsigned int _get_table_val(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return clkt->val; + return 0; +} + +static unsigned int _get_val(struct clk_divider *divider, u8 div) +{ + if (divider->flags & CLK_DIVIDER_ONE_BASED) + return div; + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) + return __ffs(div); + if (divider->table) + return _get_table_val(divider->table, div); + return div - 1; +} + +static unsigned long ti_clk_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned int div, val; + + val = ti_clk_ll_ops->clk_readl(divider->reg) >> divider->shift; + val &= div_mask(divider); + + div = _get_div(divider, val); + if (!div) { + WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO), + "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", + __clk_get_name(hw->clk)); + return parent_rate; + } + + return parent_rate / div; +} + +/* + * The reverse of DIV_ROUND_UP: The maximum number which + * divided by m is r + */ +#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) + +static bool _is_valid_table_div(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return true; + return false; +} + +static bool _is_valid_div(struct clk_divider *divider, unsigned int div) +{ + if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) + return is_power_of_2(div); + if (divider->table) + return _is_valid_table_div(divider->table, div); + return true; +} + +static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate) +{ + 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; + + if (!rate) + rate = 1; + + maxdiv = _get_maxdiv(divider); + + if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { + parent_rate = *best_parent_rate; + bestdiv = DIV_ROUND_UP(parent_rate, rate); + bestdiv = bestdiv == 0 ? 1 : bestdiv; + bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; + return bestdiv; + } + + /* + * The maximum divider we can use without overflowing + * unsigned long in rate * i below + */ + maxdiv = min(ULONG_MAX / rate, maxdiv); + + for (i = 1; i <= maxdiv; i++) { + if (!_is_valid_div(divider, i)) + continue; + if (rate * i == parent_rate_saved) { + /* + * It's the most ideal case if the requested rate can be + * divided from parent clock without needing to change + * parent rate, so return the divider immediately. + */ + *best_parent_rate = parent_rate_saved; + return i; + } + parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), + MULT_ROUND_UP(rate, i)); + now = parent_rate / i; + if (now <= rate && now > best) { + bestdiv = i; + best = now; + *best_parent_rate = parent_rate; + } + } + + if (!bestdiv) { + bestdiv = _get_maxdiv(divider); + *best_parent_rate = + __clk_round_rate(__clk_get_parent(hw->clk), 1); + } + + return bestdiv; +} + +static long ti_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int div; + div = ti_clk_divider_bestdiv(hw, rate, prate); + + return *prate / div; +} + +static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned int div, value; + unsigned long flags = 0; + u32 val; + + div = parent_rate / rate; + value = _get_val(divider, div); + + if (value > div_mask(divider)) + value = div_mask(divider); + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + + if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { + val = div_mask(divider) << (divider->shift + 16); + } else { + val = ti_clk_ll_ops->clk_readl(divider->reg); + val &= ~(div_mask(divider) << divider->shift); + } + val |= value << divider->shift; + ti_clk_ll_ops->clk_writel(val, divider->reg); + + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + + return 0; +} + +const struct clk_ops ti_clk_divider_ops = { + .recalc_rate = ti_clk_divider_recalc_rate, + .round_rate = ti_clk_divider_round_rate, + .set_rate = ti_clk_divider_set_rate, +}; + +static struct clk *_register_divider(struct device *dev, const char *name, + const char *parent_name, + unsigned long flags, void __iomem *reg, + u8 shift, u8 width, u8 clk_divider_flags, + const struct clk_div_table *table, + spinlock_t *lock) +{ + struct clk_divider *div; + struct clk *clk; + struct clk_init_data init; + + if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { + if (width + shift > 16) { + pr_warn("divider value exceeds LOWORD field\n"); + return ERR_PTR(-EINVAL); + } + } + + /* allocate the divider */ + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) { + pr_err("%s: could not allocate divider clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &ti_clk_divider_ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + /* struct clk_divider assignments */ + div->reg = reg; + div->shift = shift; + div->width = width; + div->flags = clk_divider_flags; + div->lock = lock; + div->hw.init = &init; + div->table = table; + + /* register the clock */ + clk = clk_register(dev, &div->hw); + + if (IS_ERR(clk)) + kfree(div); + + return clk; +} + +static struct clk_div_table +__init *ti_clk_get_div_table(struct device_node *node) +{ + struct clk_div_table *table; + const __be32 *divspec; + u32 val; + u32 num_div; + u32 valid_div; + int i; + + divspec = of_get_property(node, "ti,dividers", &num_div); + + if (!divspec) + return NULL; + + num_div /= 4; + + valid_div = 0; + + /* Determine required size for divider table */ + for (i = 0; i < num_div; i++) { + of_property_read_u32_index(node, "ti,dividers", i, &val); + if (val) + valid_div++; + } + + if (!valid_div) { + pr_err("no valid dividers for %s table\n", node->name); + return ERR_PTR(-EINVAL); + } + + table = kzalloc(sizeof(*table) * (valid_div + 1), GFP_KERNEL); + + if (!table) + return ERR_PTR(-ENOMEM); + + valid_div = 0; + + for (i = 0; i < num_div; i++) { + of_property_read_u32_index(node, "ti,dividers", i, &val); + if (val) { + table[valid_div].div = val; + table[valid_div].val = i; + valid_div++; + } + } + + return table; +} + +static int _get_divider_width(struct device_node *node, + const struct clk_div_table *table, + u8 flags) +{ + u32 min_div; + u32 max_div; + u32 val = 0; + u32 div; + + if (!table) { + /* Clk divider table not provided, determine min/max divs */ + if (of_property_read_u32(node, "ti,min-div", &min_div)) + min_div = 1; + + if (of_property_read_u32(node, "ti,max-div", &max_div)) { + pr_err("no max-div for %s!\n", node->name); + return -EINVAL; + } + + /* Determine bit width for the field */ + if (flags & CLK_DIVIDER_ONE_BASED) + val = 1; + + div = min_div; + + while (div < max_div) { + if (flags & CLK_DIVIDER_POWER_OF_TWO) + div <<= 1; + else + div++; + val++; + } + } else { + div = 0; + + while (table[div].div) { + val = table[div].val; + div++; + } + } + + return fls(val); +} + +static int __init ti_clk_divider_populate(struct device_node *node, + void __iomem **reg, const struct clk_div_table **table, + u32 *flags, u8 *div_flags, u8 *width, u8 *shift) +{ + u32 val; + + *reg = ti_clk_get_reg_addr(node, 0); + if (!*reg) + return -EINVAL; + + if (!of_property_read_u32(node, "ti,bit-shift", &val)) + *shift = val; + else + *shift = 0; + + *flags = 0; + *div_flags = 0; + + if (of_property_read_bool(node, "ti,index-starts-at-one")) + *div_flags |= CLK_DIVIDER_ONE_BASED; + + if (of_property_read_bool(node, "ti,index-power-of-two")) + *div_flags |= CLK_DIVIDER_POWER_OF_TWO; + + if (of_property_read_bool(node, "ti,set-rate-parent")) + *flags |= CLK_SET_RATE_PARENT; + + *table = ti_clk_get_div_table(node); + + if (IS_ERR(*table)) + return PTR_ERR(*table); + + *width = _get_divider_width(node, *table, *div_flags); + + return 0; +} + +/** + * of_ti_divider_clk_setup - Setup function for simple div rate clock + * @node: device node for this clock + * + * Sets up a basic divider clock. + */ +static void __init of_ti_divider_clk_setup(struct device_node *node) +{ + struct clk *clk; + const char *parent_name; + void __iomem *reg; + u8 clk_divider_flags = 0; + u8 width = 0; + u8 shift = 0; + const struct clk_div_table *table = NULL; + u32 flags = 0; + + parent_name = of_clk_get_parent_name(node, 0); + + if (ti_clk_divider_populate(node, ®, &table, &flags, + &clk_divider_flags, &width, &shift)) + goto cleanup; + + clk = _register_divider(NULL, node->name, parent_name, flags, reg, + shift, width, clk_divider_flags, table, NULL); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + of_ti_clk_autoidle_setup(node); + return; + } + +cleanup: + kfree(table); +} +CLK_OF_DECLARE(divider_clk, "ti,divider-clock", of_ti_divider_clk_setup); + +static void __init of_ti_composite_divider_clk_setup(struct device_node *node) +{ + struct clk_divider *div; + u32 val; + + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) + return; + + if (ti_clk_divider_populate(node, &div->reg, &div->table, &val, + &div->flags, &div->width, &div->shift) < 0) + goto cleanup; + + if (!ti_clk_add_component(node, &div->hw, CLK_COMPONENT_TYPE_DIVIDER)) + return; + +cleanup: + kfree(div->table); + kfree(div); +} +CLK_OF_DECLARE(ti_composite_divider_clk, "ti,composite-divider-clock", + of_ti_composite_divider_clk_setup); diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c new file mode 100644 index 000000000000..7e498a44f97d --- /dev/null +++ b/drivers/clk/ti/dpll.c @@ -0,0 +1,558 @@ +/* + * OMAP DPLL clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#define DPLL_HAS_AUTOIDLE 0x1 + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ + defined(CONFIG_SOC_DRA7XX) +static const struct clk_ops dpll_m4xen_ck_ops = { + .enable = &omap3_noncore_dpll_enable, + .disable = &omap3_noncore_dpll_disable, + .recalc_rate = &omap4_dpll_regm4xen_recalc, + .round_rate = &omap4_dpll_regm4xen_round_rate, + .set_rate = &omap3_noncore_dpll_set_rate, + .get_parent = &omap2_init_dpll_parent, +}; +#endif + +static const struct clk_ops dpll_core_ck_ops = { + .recalc_rate = &omap3_dpll_recalc, + .get_parent = &omap2_init_dpll_parent, +}; + +#ifdef CONFIG_ARCH_OMAP3 +static const struct clk_ops omap3_dpll_core_ck_ops = { + .get_parent = &omap2_init_dpll_parent, + .recalc_rate = &omap3_dpll_recalc, + .round_rate = &omap2_dpll_round_rate, +}; +#endif + +static const struct clk_ops dpll_ck_ops = { + .enable = &omap3_noncore_dpll_enable, + .disable = &omap3_noncore_dpll_disable, + .recalc_rate = &omap3_dpll_recalc, + .round_rate = &omap2_dpll_round_rate, + .set_rate = &omap3_noncore_dpll_set_rate, + .get_parent = &omap2_init_dpll_parent, +}; + +static const struct clk_ops dpll_no_gate_ck_ops = { + .recalc_rate = &omap3_dpll_recalc, + .get_parent = &omap2_init_dpll_parent, + .round_rate = &omap2_dpll_round_rate, + .set_rate = &omap3_noncore_dpll_set_rate, +}; + +#ifdef CONFIG_ARCH_OMAP3 +static const struct clk_ops omap3_dpll_ck_ops = { + .enable = &omap3_noncore_dpll_enable, + .disable = &omap3_noncore_dpll_disable, + .get_parent = &omap2_init_dpll_parent, + .recalc_rate = &omap3_dpll_recalc, + .set_rate = &omap3_noncore_dpll_set_rate, + .round_rate = &omap2_dpll_round_rate, +}; + +static const struct clk_ops omap3_dpll_per_ck_ops = { + .enable = &omap3_noncore_dpll_enable, + .disable = &omap3_noncore_dpll_disable, + .get_parent = &omap2_init_dpll_parent, + .recalc_rate = &omap3_dpll_recalc, + .set_rate = &omap3_dpll4_set_rate, + .round_rate = &omap2_dpll_round_rate, +}; +#endif + +static const struct clk_ops dpll_x2_ck_ops = { + .recalc_rate = &omap3_clkoutx2_recalc, +}; + +/** + * ti_clk_register_dpll - low level registration of a DPLL clock + * @hw: hardware clock definition for the clock + * @node: device node for the clock + * + * Finalizes DPLL registration process. In case a failure (clk-ref or + * 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) +{ + struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw); + struct dpll_data *dd = clk_hw->dpll_data; + struct clk *clk; + + dd->clk_ref = of_clk_get(node, 0); + dd->clk_bypass = of_clk_get(node, 1); + + 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)) + return; + + goto cleanup; + } + + /* register the clock */ + clk = clk_register(NULL, &clk_hw->hw); + + if (!IS_ERR(clk)) { + omap2_init_clk_hw_omap_clocks(clk); + of_clk_add_provider(node, of_clk_src_simple_get, clk); + kfree(clk_hw->hw.init->parent_names); + kfree(clk_hw->hw.init); + return; + } + +cleanup: + kfree(clk_hw->dpll_data); + kfree(clk_hw->hw.init->parent_names); + kfree(clk_hw->hw.init); + kfree(clk_hw); +} + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ + defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX) +/** + * ti_clk_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) +{ + struct clk *clk; + struct clk_init_data init = { NULL }; + struct clk_hw_omap *clk_hw; + const char *name = node->name; + const char *parent_name; + + parent_name = of_clk_get_parent_name(node, 0); + if (!parent_name) { + pr_err("%s must have parent\n", node->name); + return; + } + + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + if (!clk_hw) + return; + + clk_hw->ops = hw_ops; + clk_hw->hw.init = &init; + + init.name = name; + init.ops = ops; + init.parent_names = &parent_name; + init.num_parents = 1; + + /* register the clock */ + clk = clk_register(NULL, &clk_hw->hw); + + if (IS_ERR(clk)) { + kfree(clk_hw); + } else { + omap2_init_clk_hw_omap_clocks(clk); + of_clk_add_provider(node, of_clk_src_simple_get, clk); + } +} +#endif + +/** + * of_ti_dpll_setup - Setup function for OMAP DPLL clocks + * @node: device node containing the DPLL info + * @ops: ops for the DPLL + * @ddt: DPLL data template to use + * @init_flags: flags for controlling init types + * + * Initializes a DPLL clock from device tree data. + */ +static void __init of_ti_dpll_setup(struct device_node *node, + const struct clk_ops *ops, + const struct dpll_data *ddt, + u8 init_flags) +{ + struct clk_hw_omap *clk_hw = NULL; + struct clk_init_data *init = NULL; + const char **parent_names = NULL; + struct dpll_data *dd = NULL; + int i; + u8 dpll_mode = 0; + + dd = kzalloc(sizeof(*dd), GFP_KERNEL); + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + init = kzalloc(sizeof(*init), GFP_KERNEL); + if (!dd || !clk_hw || !init) + goto cleanup; + + memcpy(dd, ddt, sizeof(*dd)); + + clk_hw->dpll_data = dd; + clk_hw->ops = &clkhwops_omap3_dpll; + clk_hw->hw.init = init; + clk_hw->flags = MEMMAP_ADDRESSING; + + init->name = node->name; + init->ops = ops; + + init->num_parents = of_clk_get_parent_count(node); + if (init->num_parents < 1) { + pr_err("%s must have parent(s)\n", node->name); + goto cleanup; + } + + parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL); + if (!parent_names) + goto cleanup; + + for (i = 0; i < init->num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + init->parent_names = parent_names; + + dd->control_reg = ti_clk_get_reg_addr(node, 0); + dd->idlest_reg = ti_clk_get_reg_addr(node, 1); + dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2); + + if (!dd->control_reg || !dd->idlest_reg || !dd->mult_div1_reg) + goto cleanup; + + if (init_flags & DPLL_HAS_AUTOIDLE) { + dd->autoidle_reg = ti_clk_get_reg_addr(node, 3); + if (!dd->autoidle_reg) + goto cleanup; + } + + if (of_property_read_bool(node, "ti,low-power-stop")) + dpll_mode |= 1 << DPLL_LOW_POWER_STOP; + + if (of_property_read_bool(node, "ti,low-power-bypass")) + dpll_mode |= 1 << DPLL_LOW_POWER_BYPASS; + + if (of_property_read_bool(node, "ti,lock")) + dpll_mode |= 1 << DPLL_LOCKED; + + if (dpll_mode) + dd->modes = dpll_mode; + + ti_clk_register_dpll(&clk_hw->hw, node); + return; + +cleanup: + kfree(dd); + kfree(parent_names); + kfree(init); + kfree(clk_hw); +} + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ + 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); +} +CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock", + of_ti_omap4_dpll_x2_setup); +#endif + +#ifdef CONFIG_SOC_AM33XX +static void __init of_ti_am3_dpll_x2_setup(struct device_node *node) +{ + ti_clk_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); +#endif + +#ifdef CONFIG_ARCH_OMAP3 +static void __init of_ti_omap3_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .freqsel_mask = 0xf0, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &omap3_dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap3_dpll_clock, "ti,omap3-dpll-clock", + of_ti_omap3_dpll_setup); + +static void __init of_ti_omap3_core_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 16, + .div1_mask = 0x7f << 8, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .freqsel_mask = 0xf0, + }; + + of_ti_dpll_setup(node, &omap3_dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap3_core_dpll_clock, "ti,omap3-dpll-core-clock", + of_ti_omap3_core_dpll_setup); + +static void __init of_ti_omap3_per_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1 << 1, + .enable_mask = 0x7 << 16, + .autoidle_mask = 0x7 << 3, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .freqsel_mask = 0xf00000, + .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap3_per_dpll_clock, "ti,omap3-dpll-per-clock", + of_ti_omap3_per_dpll_setup); + +static void __init of_ti_omap3_per_jtype_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1 << 1, + .enable_mask = 0x7 << 16, + .autoidle_mask = 0x7 << 3, + .mult_mask = 0xfff << 8, + .div1_mask = 0x7f, + .max_multiplier = 4095, + .max_divider = 128, + .min_divider = 1, + .sddiv_mask = 0xff << 24, + .dco_mask = 0xe << 20, + .flags = DPLL_J_TYPE, + .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap3_per_jtype_dpll_clock, "ti,omap3-dpll-per-j-type-clock", + of_ti_omap3_per_jtype_dpll_setup); +#endif + +static void __init of_ti_omap4_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap4_dpll_clock, "ti,omap4-dpll-clock", + of_ti_omap4_dpll_setup); + +static void __init of_ti_omap4_core_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap4_core_dpll_clock, "ti,omap4-dpll-core-clock", + of_ti_omap4_core_dpll_setup); + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ + defined(CONFIG_SOC_DRA7XX) +static void __init of_ti_omap4_m4xen_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .m4xen_mask = 0x800, + .lpmode_mask = 1 << 10, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap4_m4xen_dpll_clock, "ti,omap4-dpll-m4xen-clock", + of_ti_omap4_m4xen_dpll_setup); + +static void __init of_ti_omap4_jtype_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0xfff << 8, + .div1_mask = 0xff, + .max_multiplier = 4095, + .max_divider = 256, + .min_divider = 1, + .sddiv_mask = 0xff << 24, + .flags = DPLL_J_TYPE, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE); +} +CLK_OF_DECLARE(ti_omap4_jtype_dpll_clock, "ti,omap4-dpll-j-type-clock", + of_ti_omap4_jtype_dpll_setup); +#endif + +static void __init of_ti_am3_no_gate_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_no_gate_dpll_clock, "ti,am3-dpll-no-gate-clock", + of_ti_am3_no_gate_dpll_setup); + +static void __init of_ti_am3_jtype_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 4095, + .max_divider = 256, + .min_divider = 2, + .flags = DPLL_J_TYPE, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_jtype_dpll_clock, "ti,am3-dpll-j-type-clock", + of_ti_am3_jtype_dpll_setup); + +static void __init of_ti_am3_no_gate_jtype_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .flags = DPLL_J_TYPE, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_no_gate_jtype_dpll_clock, + "ti,am3-dpll-no-gate-j-type-clock", + of_ti_am3_no_gate_jtype_dpll_setup); + +static void __init of_ti_am3_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_dpll_clock, "ti,am3-dpll-clock", of_ti_am3_dpll_setup); + +static void __init of_ti_am3_core_dpll_setup(struct device_node *node) +{ + const struct dpll_data dd = { + .idlest_mask = 0x1, + .enable_mask = 0x7, + .autoidle_mask = 0x7, + .mult_mask = 0x7ff << 8, + .div1_mask = 0x7f, + .max_multiplier = 2047, + .max_divider = 128, + .min_divider = 1, + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + }; + + of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, 0); +} +CLK_OF_DECLARE(ti_am3_core_dpll_clock, "ti,am3-dpll-core-clock", + of_ti_am3_core_dpll_setup); diff --git a/drivers/clk/ti/fixed-factor.c b/drivers/clk/ti/fixed-factor.c new file mode 100644 index 000000000000..c2c8a287408c --- /dev/null +++ b/drivers/clk/ti/fixed-factor.c @@ -0,0 +1,66 @@ +/* + * TI Fixed Factor Clock + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +/** + * of_ti_fixed_factor_clk_setup - Setup function for TI fixed factor clock + * @node: device node for this clock + * + * Sets up a simple fixed factor clock based on device tree info. + */ +static void __init of_ti_fixed_factor_clk_setup(struct device_node *node) +{ + struct clk *clk; + const char *clk_name = node->name; + const char *parent_name; + u32 div, mult; + u32 flags = 0; + + if (of_property_read_u32(node, "ti,clock-div", &div)) { + pr_err("%s must have a clock-div property\n", node->name); + return; + } + + if (of_property_read_u32(node, "ti,clock-mult", &mult)) { + pr_err("%s must have a clock-mult property\n", node->name); + return; + } + + if (of_property_read_bool(node, "ti,set-rate-parent")) + flags |= CLK_SET_RATE_PARENT; + + parent_name = of_clk_get_parent_name(node, 0); + + clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags, + mult, div); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + of_ti_clk_autoidle_setup(node); + } +} +CLK_OF_DECLARE(ti_fixed_factor_clk, "ti,fixed-factor-clock", + of_ti_fixed_factor_clk_setup); diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c new file mode 100644 index 000000000000..3e2999d11d15 --- /dev/null +++ b/drivers/clk/ti/gate.c @@ -0,0 +1,249 @@ +/* + * OMAP gate clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk); + +static const struct clk_ops omap_gate_clkdm_clk_ops = { + .init = &omap2_init_clk_clkdm, + .enable = &omap2_clkops_enable_clkdm, + .disable = &omap2_clkops_disable_clkdm, +}; + +static const struct clk_ops omap_gate_clk_ops = { + .init = &omap2_init_clk_clkdm, + .enable = &omap2_dflt_clk_enable, + .disable = &omap2_dflt_clk_disable, + .is_enabled = &omap2_dflt_clk_is_enabled, +}; + +static const struct clk_ops omap_gate_clk_hsdiv_restore_ops = { + .init = &omap2_init_clk_clkdm, + .enable = &omap36xx_gate_clk_enable_with_hsdiv_restore, + .disable = &omap2_dflt_clk_disable, + .is_enabled = &omap2_dflt_clk_is_enabled, +}; + +/** + * omap36xx_gate_clk_enable_with_hsdiv_restore - enable clocks suffering + * from HSDivider PWRDN problem Implements Errata ID: i556. + * @clk: DPLL output struct clk + * + * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck, + * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset + * valueafter their respective PWRDN bits are set. Any dummy write + * (Any other value different from the Read value) to the + * corresponding CM_CLKSEL register will refresh the dividers. + */ +static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk) +{ + struct clk_divider *parent; + struct clk_hw *parent_hw; + u32 dummy_v, orig_v; + int ret; + + /* Clear PWRDN bit of HSDIVIDER */ + ret = omap2_dflt_clk_enable(clk); + + /* Parent is the x2 node, get parent of parent for the m2 div */ + parent_hw = __clk_get_hw(__clk_get_parent(__clk_get_parent(clk->clk))); + parent = to_clk_divider(parent_hw); + + /* Restore the dividers */ + if (!ret) { + orig_v = ti_clk_ll_ops->clk_readl(parent->reg); + dummy_v = orig_v; + + /* Write any other value different from the Read value */ + dummy_v ^= (1 << parent->shift); + ti_clk_ll_ops->clk_writel(dummy_v, parent->reg); + + /* Write the original divider */ + ti_clk_ll_ops->clk_writel(orig_v, parent->reg); + } + + 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) +{ + 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; + + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + if (!clk_hw) + return; + + clk_hw->hw.init = &init; + + init.name = clk_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; + + if (!of_property_read_u32(node, "ti,bit-shift", &val)) + clk_hw->enable_bit = val; + } + + clk_hw->ops = hw_ops; + + clk_hw->flags = MEMMAP_ADDRESSING; + + if (of_clk_get_parent_count(node) != 1) { + pr_err("%s must have 1 parent\n", clk_name); + goto cleanup; + } + + 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; + + if (of_property_read_bool(node, "ti,set-bit-to-disable")) + clk_hw->flags |= INVERT_ENABLE; + + clk = clk_register(NULL, &clk_hw->hw); + + if (!IS_ERR(clk)) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + return; + } + +cleanup: + kfree(clk_hw); +} + +static void __init +_of_ti_composite_gate_clk_setup(struct device_node *node, + const struct clk_hw_omap_ops *hw_ops) +{ + struct clk_hw_omap *gate; + u32 val = 0; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return; + + gate->enable_reg = ti_clk_get_reg_addr(node, 0); + if (!gate->enable_reg) + goto cleanup; + + of_property_read_u32(node, "ti,bit-shift", &val); + + gate->enable_bit = val; + gate->ops = hw_ops; + gate->flags = MEMMAP_ADDRESSING; + + if (!ti_clk_add_component(node, &gate->hw, CLK_COMPONENT_TYPE_GATE)) + return; + +cleanup: + kfree(gate); +} + +static void __init +of_ti_composite_no_wait_gate_clk_setup(struct device_node *node) +{ + _of_ti_composite_gate_clk_setup(node, NULL); +} +CLK_OF_DECLARE(ti_composite_no_wait_gate_clk, "ti,composite-no-wait-gate-clock", + of_ti_composite_no_wait_gate_clk_setup); + +#ifdef CONFIG_ARCH_OMAP3 +static void __init of_ti_composite_interface_clk_setup(struct device_node *node) +{ + _of_ti_composite_gate_clk_setup(node, &clkhwops_iclk_wait); +} +CLK_OF_DECLARE(ti_composite_interface_clk, "ti,composite-interface-clock", + of_ti_composite_interface_clk_setup); +#endif + +static void __init of_ti_composite_gate_clk_setup(struct device_node *node) +{ + _of_ti_composite_gate_clk_setup(node, &clkhwops_wait); +} +CLK_OF_DECLARE(ti_composite_gate_clk, "ti,composite-gate-clock", + of_ti_composite_gate_clk_setup); + + +static void __init of_ti_clkdm_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clkdm_clk_ops, NULL); +} +CLK_OF_DECLARE(ti_clkdm_gate_clk, "ti,clkdm-gate-clock", + of_ti_clkdm_gate_clk_setup); + +static void __init of_ti_hsdiv_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_hsdiv_restore_ops, + &clkhwops_wait); +} +CLK_OF_DECLARE(ti_hsdiv_gate_clk, "ti,hsdiv-gate-clock", + of_ti_hsdiv_gate_clk_setup); + +static void __init of_ti_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, NULL); +} +CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup) + +static void __init of_ti_wait_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, &clkhwops_wait); +} +CLK_OF_DECLARE(ti_wait_gate_clk, "ti,wait-gate-clock", + of_ti_wait_gate_clk_setup); + +#ifdef CONFIG_ARCH_OMAP3 +static void __init of_ti_am35xx_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, + &clkhwops_am35xx_ipss_module_wait); +} +CLK_OF_DECLARE(ti_am35xx_gate_clk, "ti,am35xx-gate-clock", + of_ti_am35xx_gate_clk_setup); + +static void __init of_ti_dss_gate_clk_setup(struct device_node *node) +{ + _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, + &clkhwops_omap3430es2_dss_usbhost_wait); +} +CLK_OF_DECLARE(ti_dss_gate_clk, "ti,dss-gate-clock", + of_ti_dss_gate_clk_setup); +#endif diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c new file mode 100644 index 000000000000..320a2b168bb2 --- /dev/null +++ b/drivers/clk/ti/interface.c @@ -0,0 +1,125 @@ +/* + * OMAP interface clock support + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +static const struct clk_ops ti_interface_clk_ops = { + .init = &omap2_init_clk_clkdm, + .enable = &omap2_dflt_clk_enable, + .disable = &omap2_dflt_clk_disable, + .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) +{ + struct clk *clk; + struct clk_init_data init = { NULL }; + struct clk_hw_omap *clk_hw; + const char *parent_name; + u32 val; + + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + if (!clk_hw) + return; + + clk_hw->hw.init = &init; + clk_hw->ops = ops; + clk_hw->flags = MEMMAP_ADDRESSING; + + 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.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); + omap2_init_clk_hw_omap_clocks(clk); + return; + } + +cleanup: + kfree(clk_hw); +} + +static void __init of_ti_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, &clkhwops_iclk_wait); +} +CLK_OF_DECLARE(ti_interface_clk, "ti,omap3-interface-clock", + of_ti_interface_clk_setup); + +static void __init of_ti_no_wait_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, &clkhwops_iclk); +} +CLK_OF_DECLARE(ti_no_wait_interface_clk, "ti,omap3-no-wait-interface-clock", + of_ti_no_wait_interface_clk_setup); + +static void __init of_ti_hsotgusb_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, + &clkhwops_omap3430es2_iclk_hsotgusb_wait); +} +CLK_OF_DECLARE(ti_hsotgusb_interface_clk, "ti,omap3-hsotgusb-interface-clock", + of_ti_hsotgusb_interface_clk_setup); + +static void __init of_ti_dss_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, + &clkhwops_omap3430es2_iclk_dss_usbhost_wait); +} +CLK_OF_DECLARE(ti_dss_interface_clk, "ti,omap3-dss-interface-clock", + of_ti_dss_interface_clk_setup); + +static void __init of_ti_ssi_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, &clkhwops_omap3430es2_iclk_ssi_wait); +} +CLK_OF_DECLARE(ti_ssi_interface_clk, "ti,omap3-ssi-interface-clock", + of_ti_ssi_interface_clk_setup); + +static void __init of_ti_am35xx_interface_clk_setup(struct device_node *node) +{ + _of_ti_interface_clk_setup(node, &clkhwops_am35xx_ipss_wait); +} +CLK_OF_DECLARE(ti_am35xx_interface_clk, "ti,am35xx-interface-clock", + of_ti_am35xx_interface_clk_setup); diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c new file mode 100644 index 000000000000..0197a478720c --- /dev/null +++ b/drivers/clk/ti/mux.c @@ -0,0 +1,246 @@ +/* + * TI Multiplexer Clock + * + * Copyright (C) 2013 Texas Instruments, Inc. + * + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/clk/ti.h> + +#undef pr_fmt +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) + +static u8 ti_clk_mux_get_parent(struct clk_hw *hw) +{ + struct clk_mux *mux = to_clk_mux(hw); + int num_parents = __clk_get_num_parents(hw->clk); + u32 val; + + /* + * FIXME need a mux-specific flag to determine if val is bitwise or + * numeric. e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges + * from 0x1 to 0x7 (index starts at one) + * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so + * val = 0x4 really means "bit 2, index starts at bit 0" + */ + val = ti_clk_ll_ops->clk_readl(mux->reg) >> mux->shift; + val &= mux->mask; + + if (mux->table) { + int i; + + for (i = 0; i < num_parents; i++) + if (mux->table[i] == val) + return i; + return -EINVAL; + } + + if (val && (mux->flags & CLK_MUX_INDEX_BIT)) + val = ffs(val) - 1; + + if (val && (mux->flags & CLK_MUX_INDEX_ONE)) + val--; + + if (val >= num_parents) + return -EINVAL; + + return val; +} + +static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_mux *mux = to_clk_mux(hw); + u32 val; + unsigned long flags = 0; + + if (mux->table) { + index = mux->table[index]; + } else { + if (mux->flags & CLK_MUX_INDEX_BIT) + index = (1 << ffs(index)); + + if (mux->flags & CLK_MUX_INDEX_ONE) + index++; + } + + if (mux->lock) + spin_lock_irqsave(mux->lock, flags); + + if (mux->flags & CLK_MUX_HIWORD_MASK) { + val = mux->mask << (mux->shift + 16); + } else { + val = ti_clk_ll_ops->clk_readl(mux->reg); + val &= ~(mux->mask << mux->shift); + } + val |= index << mux->shift; + ti_clk_ll_ops->clk_writel(val, mux->reg); + + if (mux->lock) + spin_unlock_irqrestore(mux->lock, flags); + + return 0; +} + +const struct clk_ops ti_clk_mux_ops = { + .get_parent = ti_clk_mux_get_parent, + .set_parent = ti_clk_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +static struct clk *_register_mux(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, + unsigned long flags, void __iomem *reg, + u8 shift, u32 mask, u8 clk_mux_flags, + u32 *table, spinlock_t *lock) +{ + struct clk_mux *mux; + struct clk *clk; + struct clk_init_data init; + + /* allocate the mux */ + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) { + pr_err("%s: could not allocate mux clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &ti_clk_mux_ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = parent_names; + init.num_parents = num_parents; + + /* struct clk_mux assignments */ + mux->reg = reg; + mux->shift = shift; + mux->mask = mask; + mux->flags = clk_mux_flags; + mux->lock = lock; + mux->table = table; + mux->hw.init = &init; + + clk = clk_register(dev, &mux->hw); + + if (IS_ERR(clk)) + kfree(mux); + + return clk; +} + +/** + * of_mux_clk_setup - Setup function for simple mux rate clock + * @node: DT node for the clock + * + * Sets up a basic clock multiplexer. + */ +static void of_mux_clk_setup(struct device_node *node) +{ + struct clk *clk; + void __iomem *reg; + int num_parents; + const char **parent_names; + int i; + u8 clk_mux_flags = 0; + u32 mask = 0; + u32 shift = 0; + u32 flags = 0; + + num_parents = of_clk_get_parent_count(node); + if (num_parents < 2) { + pr_err("mux-clock %s must have parents\n", node->name); + return; + } + parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL); + if (!parent_names) + goto cleanup; + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + reg = ti_clk_get_reg_addr(node, 0); + + if (!reg) + goto cleanup; + + of_property_read_u32(node, "ti,bit-shift", &shift); + + if (of_property_read_bool(node, "ti,index-starts-at-one")) + clk_mux_flags |= CLK_MUX_INDEX_ONE; + + if (of_property_read_bool(node, "ti,set-rate-parent")) + flags |= CLK_SET_RATE_PARENT; + + /* Generate bit-mask based on parent info */ + mask = num_parents; + if (!(clk_mux_flags & CLK_MUX_INDEX_ONE)) + mask--; + + mask = (1 << fls(mask)) - 1; + + 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); + +cleanup: + kfree(parent_names); +} +CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup); + +static void __init of_ti_composite_mux_clk_setup(struct device_node *node) +{ + struct clk_mux *mux; + int num_parents; + u32 val; + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return; + + mux->reg = ti_clk_get_reg_addr(node, 0); + + if (!mux->reg) + goto cleanup; + + if (!of_property_read_u32(node, "ti,bit-shift", &val)) + mux->shift = val; + + if (of_property_read_bool(node, "ti,index-starts-at-one")) + mux->flags |= CLK_MUX_INDEX_ONE; + + num_parents = of_clk_get_parent_count(node); + + if (num_parents < 2) { + pr_err("%s must have parents\n", node->name); + goto cleanup; + } + + mux->mask = num_parents - 1; + mux->mask = (1 << fls(mux->mask)) - 1; + + if (!ti_clk_add_component(node, &mux->hw, CLK_COMPONENT_TYPE_MUX)) + return; + +cleanup: + kfree(mux); +} +CLK_OF_DECLARE(ti_composite_mux_clk_setup, "ti,composite-mux-clock", + of_ti_composite_mux_clk_setup); |