From c82f8957b48c628a74bf5dd8ee64e33fc70d7b8f Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 16 Dec 2014 18:20:46 +0200 Subject: clk: ti: add core support for initializing legacy clocks Legacy clock data for OMAP3 is being moved under clock driver, thus base support for this is needed. This patch adds basic definitions for clock init descriptors and core infrastructure for initialization, which will be called from the OMAP3 clock init. Signed-off-by: Tero Kristo Acked-by: Tony Lindgren Signed-off-by: Michael Turquette --- drivers/clk/ti/clock.h | 160 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 drivers/clk/ti/clock.h (limited to 'drivers/clk/ti/clock.h') diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h new file mode 100644 index 000000000000..6ee6c6e43ede --- /dev/null +++ b/drivers/clk/ti/clock.h @@ -0,0 +1,160 @@ +/* + * TI Clock driver internal definitions + * + * Copyright (C) 2014 Texas Instruments, Inc + * Tero Kristo (t-kristo@ti.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __DRIVERS_CLK_TI_CLOCK__ +#define __DRIVERS_CLK_TI_CLOCK__ + +enum { + TI_CLK_FIXED, + TI_CLK_MUX, + TI_CLK_DIVIDER, + TI_CLK_COMPOSITE, + TI_CLK_FIXED_FACTOR, + TI_CLK_GATE, + TI_CLK_DPLL, +}; + +/* Global flags */ +#define CLKF_INDEX_POWER_OF_TWO (1 << 0) +#define CLKF_INDEX_STARTS_AT_ONE (1 << 1) +#define CLKF_SET_RATE_PARENT (1 << 2) +#define CLKF_OMAP3 (1 << 3) +#define CLKF_AM35XX (1 << 4) + +/* Gate flags */ +#define CLKF_SET_BIT_TO_DISABLE (1 << 5) +#define CLKF_INTERFACE (1 << 6) +#define CLKF_SSI (1 << 7) +#define CLKF_DSS (1 << 8) +#define CLKF_HSOTGUSB (1 << 9) +#define CLKF_WAIT (1 << 10) +#define CLKF_NO_WAIT (1 << 11) +#define CLKF_HSDIV (1 << 12) +#define CLKF_CLKDM (1 << 13) + +/* DPLL flags */ +#define CLKF_LOW_POWER_STOP (1 << 5) +#define CLKF_LOCK (1 << 6) +#define CLKF_LOW_POWER_BYPASS (1 << 7) +#define CLKF_PER (1 << 8) +#define CLKF_CORE (1 << 9) +#define CLKF_J_TYPE (1 << 10) + +#define CLK(dev, con, ck) \ + { \ + .lk = { \ + .dev_id = dev, \ + .con_id = con, \ + }, \ + .clk = ck, \ + } + +struct ti_clk { + const char *name; + const char *clkdm_name; + int type; + void *data; + struct ti_clk *patch; + struct clk *clk; +}; + +struct ti_clk_alias { + struct ti_clk *clk; + struct clk_lookup lk; + struct list_head link; +}; + +struct ti_clk_fixed { + u32 frequency; + u16 flags; +}; + +struct ti_clk_mux { + u8 bit_shift; + int num_parents; + u16 reg; + u8 module; + const char **parents; + u16 flags; +}; + +struct ti_clk_divider { + const char *parent; + u8 bit_shift; + u16 max_div; + u16 reg; + u8 module; + int *dividers; + int num_dividers; + u16 flags; +}; + +struct ti_clk_fixed_factor { + const char *parent; + u16 div; + u16 mult; + u16 flags; +}; + +struct ti_clk_gate { + const char *parent; + u8 bit_shift; + u16 reg; + u8 module; + u16 flags; +}; + +struct ti_clk_composite { + struct ti_clk_divider *divider; + struct ti_clk_mux *mux; + struct ti_clk_gate *gate; + u16 flags; +}; + +struct ti_clk_clkdm_gate { + const char *parent; + u16 flags; +}; + +struct ti_clk_dpll { + int num_parents; + u16 control_reg; + u16 idlest_reg; + u16 autoidle_reg; + u16 mult_div1_reg; + u8 module; + const char **parents; + u16 flags; + u8 modes; + u32 mult_mask; + u32 div1_mask; + u32 enable_mask; + u32 autoidle_mask; + u32 freqsel_mask; + u32 idlest_mask; + u32 dco_mask; + u32 sddiv_mask; + u16 max_multiplier; + u16 max_divider; + u8 auto_recal_bit; + u8 recal_en_bit; + u8 recal_st_bit; +}; + +void ti_clk_patch_legacy_clks(struct ti_clk **patch); +struct clk *ti_clk_register_clk(struct ti_clk *setup); +int ti_clk_register_legacy_clks(struct ti_clk_alias *clks); + +#endif -- cgit v1.2.3-59-g8ed1b From 7c18a65cb5295484261274b931dd4a3da88695d2 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 16 Dec 2014 18:20:47 +0200 Subject: clk: ti: mux: add support for legacy mux init Legacy clock data is initialized slightly differently compared to DT clocks, thus add support for this. Signed-off-by: Tero Kristo Acked-by: Tony Lindgren Signed-off-by: Michael Turquette --- drivers/clk/ti/clk.c | 3 +++ drivers/clk/ti/clock.h | 4 +++ drivers/clk/ti/mux.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 75 insertions(+), 2 deletions(-) (limited to 'drivers/clk/ti/clock.h') diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index a8958f1ba8a3..215f681053d0 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -211,6 +211,9 @@ struct clk __init *ti_clk_register_clk(struct ti_clk *setup) clk = clk_register_fixed_rate(NULL, setup->name, NULL, CLK_IS_ROOT, fixed->frequency); break; + case TI_CLK_MUX: + clk = ti_clk_register_mux(setup); + break; case TI_CLK_FIXED_FACTOR: fixed_factor = setup->data; diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 6ee6c6e43ede..c06bbf4c9f95 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -153,6 +153,10 @@ struct ti_clk_dpll { u8 recal_st_bit; }; +struct clk *ti_clk_register_mux(struct ti_clk *setup); + +struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup); + void ti_clk_patch_legacy_clks(struct ti_clk **patch); struct clk *ti_clk_register_clk(struct ti_clk *setup); int ti_clk_register_legacy_clks(struct ti_clk_alias *clks); diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c index e9d650e51287..728e253606bc 100644 --- a/drivers/clk/ti/mux.c +++ b/drivers/clk/ti/mux.c @@ -21,6 +21,7 @@ #include #include #include +#include "clock.h" #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -144,6 +145,39 @@ static struct clk *_register_mux(struct device *dev, const char *name, return clk; } +struct clk *ti_clk_register_mux(struct ti_clk *setup) +{ + struct ti_clk_mux *mux; + u32 flags; + u8 mux_flags = 0; + struct clk_omap_reg *reg_setup; + u32 reg; + u32 mask; + + reg_setup = (struct clk_omap_reg *)® + + mux = setup->data; + flags = CLK_SET_RATE_NO_REPARENT; + + mask = mux->num_parents; + if (!(mux->flags & CLKF_INDEX_STARTS_AT_ONE)) + mask--; + + mask = (1 << fls(mask)) - 1; + reg_setup->index = mux->module; + reg_setup->offset = mux->reg; + + if (mux->flags & CLKF_INDEX_STARTS_AT_ONE) + mux_flags |= CLK_MUX_INDEX_ONE; + + if (mux->flags & CLKF_SET_RATE_PARENT) + flags |= CLK_SET_RATE_PARENT; + + return _register_mux(NULL, setup->name, mux->parents, mux->num_parents, + flags, (void __iomem *)reg, mux->bit_shift, mask, + mux_flags, NULL, NULL); +} + /** * of_mux_clk_setup - Setup function for simple mux rate clock * @node: DT node for the clock @@ -194,8 +228,9 @@ static void of_mux_clk_setup(struct device_node *node) mask = (1 << fls(mask)) - 1; - clk = _register_mux(NULL, node->name, parent_names, num_parents, flags, - reg, shift, mask, clk_mux_flags, NULL, NULL); + clk = _register_mux(NULL, node->name, parent_names, num_parents, + flags, reg, shift, mask, clk_mux_flags, NULL, + NULL); if (!IS_ERR(clk)) of_clk_add_provider(node, of_clk_src_simple_get, clk); @@ -205,6 +240,37 @@ cleanup: } CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup); +struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup) +{ + struct clk_mux *mux; + struct clk_omap_reg *reg; + int num_parents; + + if (!setup) + return NULL; + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + reg = (struct clk_omap_reg *)&mux->reg; + + mux->shift = setup->bit_shift; + + reg->index = setup->module; + reg->offset = setup->reg; + + if (setup->flags & CLKF_INDEX_STARTS_AT_ONE) + mux->flags |= CLK_MUX_INDEX_ONE; + + num_parents = setup->num_parents; + + mux->mask = num_parents - 1; + mux->mask = (1 << fls(mux->mask)) - 1; + + return &mux->hw; +} + static void __init of_ti_composite_mux_clk_setup(struct device_node *node) { struct clk_mux *mux; -- cgit v1.2.3-59-g8ed1b From f187616b36edafff5a18d2b66fe7eed3bbb38bf0 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 16 Dec 2014 18:20:48 +0200 Subject: clk: ti: gate: add support for legacy gate init Legacy clock data is initialialized slightly differently compared to DT clocks, thus add support for this. Signed-off-by: Tero Kristo Acked-by: Tony Lindgren Signed-off-by: Michael Turquette --- drivers/clk/ti/clk.c | 3 + drivers/clk/ti/clock.h | 2 + drivers/clk/ti/gate.c | 158 +++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 133 insertions(+), 30 deletions(-) (limited to 'drivers/clk/ti/clock.h') diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 215f681053d0..676dbf170b31 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -222,6 +222,9 @@ struct clk __init *ti_clk_register_clk(struct ti_clk *setup) 0, fixed_factor->mult, fixed_factor->div); break; + case TI_CLK_GATE: + clk = ti_clk_register_gate(setup); + break; default: pr_err("bad type for %s!\n", setup->name); clk = ERR_PTR(-EINVAL); diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index c06bbf4c9f95..d0715bc029b6 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -153,8 +153,10 @@ struct ti_clk_dpll { u8 recal_st_bit; }; +struct clk *ti_clk_register_gate(struct ti_clk *setup); struct clk *ti_clk_register_mux(struct ti_clk *setup); +struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup); struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup); void ti_clk_patch_legacy_clks(struct ti_clk **patch); diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c index b326d2797feb..ff3380ea3861 100644 --- a/drivers/clk/ti/gate.c +++ b/drivers/clk/ti/gate.c @@ -22,6 +22,8 @@ #include #include +#include "clock.h" + #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) #undef pr_fmt @@ -90,63 +92,159 @@ static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk) return ret; } -static void __init _of_ti_gate_clk_setup(struct device_node *node, - const struct clk_ops *ops, - const struct clk_hw_omap_ops *hw_ops) +static struct clk *_register_gate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, const struct clk_ops *ops, + const struct clk_hw_omap_ops *hw_ops) { - struct clk *clk; struct clk_init_data init = { NULL }; struct clk_hw_omap *clk_hw; - const char *clk_name = node->name; - const char *parent_name; - u32 val; + struct clk *clk; clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); if (!clk_hw) - return; + return ERR_PTR(-ENOMEM); clk_hw->hw.init = &init; - init.name = clk_name; + init.name = name; init.ops = ops; - if (ops != &omap_gate_clkdm_clk_ops) { - clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0); - if (!clk_hw->enable_reg) - goto cleanup; + clk_hw->enable_reg = reg; + clk_hw->enable_bit = bit_idx; + clk_hw->ops = hw_ops; - if (!of_property_read_u32(node, "ti,bit-shift", &val)) - clk_hw->enable_bit = val; + clk_hw->flags = MEMMAP_ADDRESSING | clk_gate_flags; + + init.parent_names = &parent_name; + init.num_parents = 1; + + init.flags = flags; + + clk = clk_register(NULL, &clk_hw->hw); + + if (IS_ERR(clk)) + kfree(clk_hw); + + return clk; +} + +struct clk *ti_clk_register_gate(struct ti_clk *setup) +{ + const struct clk_ops *ops = &omap_gate_clk_ops; + const struct clk_hw_omap_ops *hw_ops = NULL; + u32 reg; + struct clk_omap_reg *reg_setup; + u32 flags = 0; + u8 clk_gate_flags = 0; + struct ti_clk_gate *gate; + + gate = setup->data; + + reg_setup = (struct clk_omap_reg *)® + + if (gate->flags & CLKF_SET_RATE_PARENT) + flags |= CLK_SET_RATE_PARENT; + + if (gate->flags & CLKF_SET_BIT_TO_DISABLE) + clk_gate_flags |= INVERT_ENABLE; + + if (gate->flags & CLKF_HSDIV) { + ops = &omap_gate_clk_hsdiv_restore_ops; + hw_ops = &clkhwops_wait; } - clk_hw->ops = hw_ops; + if (gate->flags & CLKF_DSS) + hw_ops = &clkhwops_omap3430es2_dss_usbhost_wait; + + if (gate->flags & CLKF_WAIT) + hw_ops = &clkhwops_wait; + + if (gate->flags & CLKF_CLKDM) + ops = &omap_gate_clkdm_clk_ops; + + if (gate->flags & CLKF_AM35XX) + hw_ops = &clkhwops_am35xx_ipss_module_wait; - clk_hw->flags = MEMMAP_ADDRESSING; + reg_setup->index = gate->module; + reg_setup->offset = gate->reg; + + return _register_gate(NULL, setup->name, gate->parent, flags, + (void __iomem *)reg, gate->bit_shift, + clk_gate_flags, ops, hw_ops); +} + +struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup) +{ + struct clk_hw_omap *gate; + struct clk_omap_reg *reg; + const struct clk_hw_omap_ops *ops = &clkhwops_wait; + + if (!setup) + return NULL; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + reg = (struct clk_omap_reg *)&gate->enable_reg; + reg->index = setup->module; + reg->offset = setup->reg; + + gate->enable_bit = setup->bit_shift; + + if (setup->flags & CLKF_NO_WAIT) + ops = NULL; + + if (setup->flags & CLKF_INTERFACE) + ops = &clkhwops_iclk_wait; + + gate->ops = ops; + gate->flags = MEMMAP_ADDRESSING; + + return &gate->hw; +} + +static void __init _of_ti_gate_clk_setup(struct device_node *node, + const struct clk_ops *ops, + const struct clk_hw_omap_ops *hw_ops) +{ + struct clk *clk; + const char *parent_name; + void __iomem *reg = NULL; + u8 enable_bit = 0; + u32 val; + u32 flags = 0; + u8 clk_gate_flags = 0; + + if (ops != &omap_gate_clkdm_clk_ops) { + reg = ti_clk_get_reg_addr(node, 0); + if (!reg) + return; + + if (!of_property_read_u32(node, "ti,bit-shift", &val)) + enable_bit = val; + } if (of_clk_get_parent_count(node) != 1) { - pr_err("%s must have 1 parent\n", clk_name); - goto cleanup; + pr_err("%s must have 1 parent\n", node->name); + return; } parent_name = of_clk_get_parent_name(node, 0); - init.parent_names = &parent_name; - init.num_parents = 1; if (of_property_read_bool(node, "ti,set-rate-parent")) - init.flags |= CLK_SET_RATE_PARENT; + flags |= CLK_SET_RATE_PARENT; if (of_property_read_bool(node, "ti,set-bit-to-disable")) - clk_hw->flags |= INVERT_ENABLE; + clk_gate_flags |= INVERT_ENABLE; - clk = clk_register(NULL, &clk_hw->hw); + clk = _register_gate(NULL, node->name, parent_name, flags, reg, + enable_bit, clk_gate_flags, ops, hw_ops); - if (!IS_ERR(clk)) { + if (!IS_ERR(clk)) of_clk_add_provider(node, of_clk_src_simple_get, clk); - return; - } - -cleanup: - kfree(clk_hw); } static void __init -- cgit v1.2.3-59-g8ed1b From 06524fa4289797deb9a66c1a3e681052eed0d83d Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 16 Dec 2014 18:20:49 +0200 Subject: clk: ti: interface: add support for legacy interface clock init Legacy clock data is initialized slightly differently compared to DT clocks, thus add support for this. The interface clock descriptor itself is overloading the gate clock descriptor, thus it needs to be called from the gate setup. Signed-off-by: Tero Kristo Acked-by: Tony Lindgren Signed-off-by: Michael Turquette --- drivers/clk/ti/clock.h | 1 + drivers/clk/ti/gate.c | 3 ++ drivers/clk/ti/interface.c | 96 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 76 insertions(+), 24 deletions(-) (limited to 'drivers/clk/ti/clock.h') diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index d0715bc029b6..9430dc614d3c 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -154,6 +154,7 @@ struct ti_clk_dpll { }; struct clk *ti_clk_register_gate(struct ti_clk *setup); +struct clk *ti_clk_register_interface(struct ti_clk *setup); struct clk *ti_clk_register_mux(struct ti_clk *setup); struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup); diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c index ff3380ea3861..d4f6cb20e16e 100644 --- a/drivers/clk/ti/gate.c +++ b/drivers/clk/ti/gate.c @@ -142,6 +142,9 @@ struct clk *ti_clk_register_gate(struct ti_clk *setup) gate = setup->data; + if (gate->flags & CLKF_INTERFACE) + return ti_clk_register_interface(setup); + reg_setup = (struct clk_omap_reg *)® if (gate->flags & CLKF_SET_RATE_PARENT) diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c index 9c3e8c4aaa40..d71cd9b5de46 100644 --- a/drivers/clk/ti/interface.c +++ b/drivers/clk/ti/interface.c @@ -20,6 +20,7 @@ #include #include #include +#include "clock.h" #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -31,53 +32,100 @@ static const struct clk_ops ti_interface_clk_ops = { .is_enabled = &omap2_dflt_clk_is_enabled, }; -static void __init _of_ti_interface_clk_setup(struct device_node *node, - const struct clk_hw_omap_ops *ops) +static struct clk *_register_interface(struct device *dev, const char *name, + const char *parent_name, + void __iomem *reg, u8 bit_idx, + const struct clk_hw_omap_ops *ops) { - struct clk *clk; struct clk_init_data init = { NULL }; struct clk_hw_omap *clk_hw; - const char *parent_name; - u32 val; + struct clk *clk; clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); if (!clk_hw) - return; + return ERR_PTR(-ENOMEM); clk_hw->hw.init = &init; clk_hw->ops = ops; clk_hw->flags = MEMMAP_ADDRESSING; + clk_hw->enable_reg = reg; + clk_hw->enable_bit = bit_idx; - clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0); - if (!clk_hw->enable_reg) - goto cleanup; - - if (!of_property_read_u32(node, "ti,bit-shift", &val)) - clk_hw->enable_bit = val; - - init.name = node->name; + init.name = name; init.ops = &ti_interface_clk_ops; init.flags = 0; - parent_name = of_clk_get_parent_name(node, 0); - if (!parent_name) { - pr_err("%s must have a parent\n", node->name); - goto cleanup; - } - init.num_parents = 1; init.parent_names = &parent_name; clk = clk_register(NULL, &clk_hw->hw); - if (!IS_ERR(clk)) { - of_clk_add_provider(node, of_clk_src_simple_get, clk); + if (IS_ERR(clk)) + kfree(clk_hw); + else omap2_init_clk_hw_omap_clocks(clk); + + return clk; +} + +struct clk *ti_clk_register_interface(struct ti_clk *setup) +{ + const struct clk_hw_omap_ops *ops = &clkhwops_iclk_wait; + u32 reg; + struct clk_omap_reg *reg_setup; + struct ti_clk_gate *gate; + + gate = setup->data; + reg_setup = (struct clk_omap_reg *)® + reg_setup->index = gate->module; + reg_setup->offset = gate->reg; + + if (gate->flags & CLKF_NO_WAIT) + ops = &clkhwops_iclk; + + if (gate->flags & CLKF_HSOTGUSB) + ops = &clkhwops_omap3430es2_iclk_hsotgusb_wait; + + if (gate->flags & CLKF_DSS) + ops = &clkhwops_omap3430es2_iclk_dss_usbhost_wait; + + if (gate->flags & CLKF_SSI) + ops = &clkhwops_omap3430es2_iclk_ssi_wait; + + if (gate->flags & CLKF_AM35XX) + ops = &clkhwops_am35xx_ipss_wait; + + return _register_interface(NULL, setup->name, gate->parent, + (void __iomem *)reg, gate->bit_shift, ops); +} + +static void __init _of_ti_interface_clk_setup(struct device_node *node, + const struct clk_hw_omap_ops *ops) +{ + struct clk *clk; + const char *parent_name; + void __iomem *reg; + u8 enable_bit = 0; + u32 val; + + reg = ti_clk_get_reg_addr(node, 0); + if (!reg) + return; + + if (!of_property_read_u32(node, "ti,bit-shift", &val)) + enable_bit = val; + + parent_name = of_clk_get_parent_name(node, 0); + if (!parent_name) { + pr_err("%s must have a parent\n", node->name); return; } -cleanup: - kfree(clk_hw); + clk = _register_interface(NULL, node->name, parent_name, reg, + enable_bit, ops); + + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); } static void __init of_ti_interface_clk_setup(struct device_node *node) -- cgit v1.2.3-59-g8ed1b From d96f774b25386a7a71c799bbf55b69c27129e454 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 16 Dec 2014 18:20:50 +0200 Subject: clk: ti: divider: add support for legacy divider init Legacy clock data is initialized slightly differently compared to DT clocks, thus add support for this. Signed-off-by: Tero Kristo Acked-by: Tony Lindgren Signed-off-by: Michael Turquette --- drivers/clk/ti/clk.c | 3 ++ drivers/clk/ti/clock.h | 2 + drivers/clk/ti/divider.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 136 insertions(+), 1 deletion(-) (limited to 'drivers/clk/ti/clock.h') diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 676dbf170b31..a0475e23881d 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -214,6 +214,9 @@ struct clk __init *ti_clk_register_clk(struct ti_clk *setup) case TI_CLK_MUX: clk = ti_clk_register_mux(setup); break; + case TI_CLK_DIVIDER: + clk = ti_clk_register_divider(setup); + break; case TI_CLK_FIXED_FACTOR: fixed_factor = setup->data; diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 9430dc614d3c..fe709412514c 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -156,7 +156,9 @@ struct ti_clk_dpll { struct clk *ti_clk_register_gate(struct ti_clk *setup); struct clk *ti_clk_register_interface(struct ti_clk *setup); struct clk *ti_clk_register_mux(struct ti_clk *setup); +struct clk *ti_clk_register_divider(struct ti_clk *setup); +struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup); struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup); struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup); diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index bff2b5b8ff59..6211893c0980 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -21,6 +21,7 @@ #include #include #include +#include "clock.h" #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -300,6 +301,134 @@ static struct clk *_register_divider(struct device *dev, const char *name, return clk; } +static struct clk_div_table * +_get_div_table_from_setup(struct ti_clk_divider *setup, u8 *width) +{ + int valid_div = 0; + struct clk_div_table *table; + int i; + int div; + u32 val; + u8 flags; + + if (!setup->num_dividers) { + /* Clk divider table not provided, determine min/max divs */ + flags = setup->flags; + + if (flags & CLKF_INDEX_STARTS_AT_ONE) + val = 1; + else + val = 0; + + div = 1; + + while (div < setup->max_div) { + if (flags & CLKF_INDEX_POWER_OF_TWO) + div <<= 1; + else + div++; + val++; + } + + *width = fls(val); + + return NULL; + } + + for (i = 0; i < setup->num_dividers; i++) + if (setup->dividers[i]) + valid_div++; + + table = kzalloc(sizeof(*table) * (valid_div + 1), GFP_KERNEL); + if (!table) + return ERR_PTR(-ENOMEM); + + valid_div = 0; + *width = 0; + + for (i = 0; i < setup->num_dividers; i++) + if (setup->dividers[i]) { + table[valid_div].div = setup->dividers[i]; + table[valid_div].val = i; + valid_div++; + *width = i; + } + + *width = fls(*width); + + return table; +} + +struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup) +{ + struct clk_divider *div; + struct clk_omap_reg *reg; + + if (!setup) + return NULL; + + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) + return ERR_PTR(-ENOMEM); + + reg = (struct clk_omap_reg *)&div->reg; + reg->index = setup->module; + reg->offset = setup->reg; + + if (setup->flags & CLKF_INDEX_STARTS_AT_ONE) + div->flags |= CLK_DIVIDER_ONE_BASED; + + if (setup->flags & CLKF_INDEX_POWER_OF_TWO) + div->flags |= CLK_DIVIDER_POWER_OF_TWO; + + div->table = _get_div_table_from_setup(setup, &div->width); + + div->shift = setup->bit_shift; + + return &div->hw; +} + +struct clk *ti_clk_register_divider(struct ti_clk *setup) +{ + struct ti_clk_divider *div; + struct clk_omap_reg *reg_setup; + u32 reg; + u8 width; + u32 flags = 0; + u8 div_flags = 0; + struct clk_div_table *table; + struct clk *clk; + + div = setup->data; + + reg_setup = (struct clk_omap_reg *)® + + reg_setup->index = div->module; + reg_setup->offset = div->reg; + + if (div->flags & CLKF_INDEX_STARTS_AT_ONE) + div_flags |= CLK_DIVIDER_ONE_BASED; + + if (div->flags & CLKF_INDEX_POWER_OF_TWO) + div_flags |= CLK_DIVIDER_POWER_OF_TWO; + + if (div->flags & CLKF_SET_RATE_PARENT) + flags |= CLK_SET_RATE_PARENT; + + table = _get_div_table_from_setup(div, &width); + if (IS_ERR(table)) + return (struct clk *)table; + + clk = _register_divider(NULL, setup->name, div->parent, + flags, (void __iomem *)reg, div->bit_shift, + width, div_flags, table, NULL); + + if (IS_ERR(clk)) + kfree(table); + + return clk; +} + static struct clk_div_table * __init ti_clk_get_div_table(struct device_node *node) { @@ -455,7 +584,8 @@ static void __init of_ti_divider_clk_setup(struct device_node *node) goto cleanup; clk = _register_divider(NULL, node->name, parent_name, flags, reg, - shift, width, clk_divider_flags, table, NULL); + shift, width, clk_divider_flags, table, + NULL); if (!IS_ERR(clk)) { of_clk_add_provider(node, of_clk_src_simple_get, clk); -- cgit v1.2.3-59-g8ed1b From ed405a2350646a940966f471ae705fa2d81eee65 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Thu, 29 Jan 2015 22:24:28 +0200 Subject: clk: ti: dpll: add support for legacy DPLL init Legacy clock data is initialized slightly differently compared to DT clocks, thus add support for this. Signed-off-by: Tero Kristo Acked-by: Tony Lindgren Signed-off-by: Michael Turquette --- drivers/clk/ti/clk.c | 3 ++ drivers/clk/ti/clock.h | 2 + drivers/clk/ti/dpll.c | 119 ++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 113 insertions(+), 11 deletions(-) (limited to 'drivers/clk/ti/clock.h') diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index a0475e23881d..f41a7576a3ff 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -228,6 +228,9 @@ struct clk __init *ti_clk_register_clk(struct ti_clk *setup) case TI_CLK_GATE: clk = ti_clk_register_gate(setup); break; + case TI_CLK_DPLL: + clk = ti_clk_register_dpll(setup); + break; default: pr_err("bad type for %s!\n", setup->name); clk = ERR_PTR(-EINVAL); diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index fe709412514c..578b73b2edf1 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -148,6 +148,7 @@ struct ti_clk_dpll { u32 sddiv_mask; u16 max_multiplier; u16 max_divider; + u8 min_divider; u8 auto_recal_bit; u8 recal_en_bit; u8 recal_st_bit; @@ -157,6 +158,7 @@ struct clk *ti_clk_register_gate(struct ti_clk *setup); struct clk *ti_clk_register_interface(struct ti_clk *setup); struct clk *ti_clk_register_mux(struct ti_clk *setup); struct clk *ti_clk_register_divider(struct ti_clk *setup); +struct clk *ti_clk_register_dpll(struct ti_clk *setup); struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup); struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup); diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 85ac0dd501de..47ebff772b13 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -21,6 +21,7 @@ #include #include #include +#include "clock.h" #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -130,7 +131,7 @@ static const struct clk_ops dpll_x2_ck_ops = { }; /** - * ti_clk_register_dpll - low level registration of a DPLL clock + * _register_dpll - low level registration of a DPLL clock * @hw: hardware clock definition for the clock * @node: device node for the clock * @@ -138,8 +139,8 @@ static const struct clk_ops dpll_x2_ck_ops = { * clk-bypass is missing), the clock is added to retry list and * the initialization is retried on later stage. */ -static void __init ti_clk_register_dpll(struct clk_hw *hw, - struct device_node *node) +static void __init _register_dpll(struct clk_hw *hw, + struct device_node *node) { struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw); struct dpll_data *dd = clk_hw->dpll_data; @@ -151,7 +152,7 @@ static void __init ti_clk_register_dpll(struct clk_hw *hw, if (IS_ERR(dd->clk_ref) || IS_ERR(dd->clk_bypass)) { pr_debug("clk-ref or clk-bypass missing for %s, retry later\n", node->name); - if (!ti_clk_retry_init(node, hw, ti_clk_register_dpll)) + if (!ti_clk_retry_init(node, hw, _register_dpll)) return; goto cleanup; @@ -175,20 +176,116 @@ cleanup: kfree(clk_hw); } +void __iomem *_get_reg(u8 module, u16 offset) +{ + u32 reg; + struct clk_omap_reg *reg_setup; + + reg_setup = (struct clk_omap_reg *)® + + reg_setup->index = module; + reg_setup->offset = offset; + + return (void __iomem *)reg; +} + +struct clk *ti_clk_register_dpll(struct ti_clk *setup) +{ + struct clk_hw_omap *clk_hw; + struct clk_init_data init = { NULL }; + struct dpll_data *dd; + struct clk *clk; + struct ti_clk_dpll *dpll; + const struct clk_ops *ops = &omap3_dpll_ck_ops; + struct clk *clk_ref; + struct clk *clk_bypass; + + dpll = setup->data; + + if (dpll->num_parents < 2) + return ERR_PTR(-EINVAL); + + clk_ref = clk_get_sys(NULL, dpll->parents[0]); + clk_bypass = clk_get_sys(NULL, dpll->parents[1]); + + if (IS_ERR_OR_NULL(clk_ref) || IS_ERR_OR_NULL(clk_bypass)) + return ERR_PTR(-EAGAIN); + + dd = kzalloc(sizeof(*dd), GFP_KERNEL); + clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); + if (!dd || !clk_hw) { + clk = ERR_PTR(-ENOMEM); + goto cleanup; + } + + clk_hw->dpll_data = dd; + clk_hw->ops = &clkhwops_omap3_dpll; + clk_hw->hw.init = &init; + clk_hw->flags = MEMMAP_ADDRESSING; + + init.name = setup->name; + init.ops = ops; + + init.num_parents = dpll->num_parents; + init.parent_names = dpll->parents; + + dd->control_reg = _get_reg(dpll->module, dpll->control_reg); + dd->idlest_reg = _get_reg(dpll->module, dpll->idlest_reg); + dd->mult_div1_reg = _get_reg(dpll->module, dpll->mult_div1_reg); + dd->autoidle_reg = _get_reg(dpll->module, dpll->autoidle_reg); + + dd->modes = dpll->modes; + dd->div1_mask = dpll->div1_mask; + dd->idlest_mask = dpll->idlest_mask; + dd->mult_mask = dpll->mult_mask; + dd->autoidle_mask = dpll->autoidle_mask; + dd->enable_mask = dpll->enable_mask; + dd->sddiv_mask = dpll->sddiv_mask; + dd->dco_mask = dpll->dco_mask; + dd->max_divider = dpll->max_divider; + dd->min_divider = dpll->min_divider; + dd->max_multiplier = dpll->max_multiplier; + dd->auto_recal_bit = dpll->auto_recal_bit; + dd->recal_en_bit = dpll->recal_en_bit; + dd->recal_st_bit = dpll->recal_st_bit; + + dd->clk_ref = clk_ref; + dd->clk_bypass = clk_bypass; + + if (dpll->flags & CLKF_CORE) + ops = &omap3_dpll_core_ck_ops; + + if (dpll->flags & CLKF_PER) + ops = &omap3_dpll_per_ck_ops; + + if (dpll->flags & CLKF_J_TYPE) + dd->flags |= DPLL_J_TYPE; + + clk = clk_register(NULL, &clk_hw->hw); + + if (!IS_ERR(clk)) + return clk; + +cleanup: + kfree(dd); + kfree(clk_hw); + return clk; +} + #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX) || \ defined(CONFIG_SOC_AM43XX) /** - * ti_clk_register_dpll_x2 - Registers a DPLLx2 clock + * _register_dpll_x2 - Registers a DPLLx2 clock * @node: device node for this clock * @ops: clk_ops for this clock * @hw_ops: clk_hw_ops for this clock * * Initializes a DPLL x 2 clock from device tree data. */ -static void ti_clk_register_dpll_x2(struct device_node *node, - const struct clk_ops *ops, - const struct clk_hw_omap_ops *hw_ops) +static void _register_dpll_x2(struct device_node *node, + const struct clk_ops *ops, + const struct clk_hw_omap_ops *hw_ops) { struct clk *clk; struct clk_init_data init = { NULL }; @@ -318,7 +415,7 @@ static void __init of_ti_dpll_setup(struct device_node *node, if (dpll_mode) dd->modes = dpll_mode; - ti_clk_register_dpll(&clk_hw->hw, node); + _register_dpll(&clk_hw->hw, node); return; cleanup: @@ -332,7 +429,7 @@ cleanup: defined(CONFIG_SOC_DRA7XX) static void __init of_ti_omap4_dpll_x2_setup(struct device_node *node) { - ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx); + _register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx); } CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock", of_ti_omap4_dpll_x2_setup); @@ -341,7 +438,7 @@ CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock", #if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX) static void __init of_ti_am3_dpll_x2_setup(struct device_node *node) { - ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, NULL); + _register_dpll_x2(node, &dpll_x2_ck_ops, NULL); } CLK_OF_DECLARE(ti_am3_dpll_x2_clock, "ti,am3-dpll-x2-clock", of_ti_am3_dpll_x2_setup); -- cgit v1.2.3-59-g8ed1b From b26bcf9be64e26d8a0972d6df1c2105cc5076cf1 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 16 Dec 2014 18:20:52 +0200 Subject: clk: ti: composite: add support for legacy composite clock init Legacy clock data is initialized slightly differently compared to DT clocks, thus add support for this. Signed-off-by: Tero Kristo Acked-by: Tony Lindgren Signed-off-by: Michael Turquette --- drivers/clk/ti/clk.c | 3 +++ drivers/clk/ti/clock.h | 1 + drivers/clk/ti/composite.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 46 insertions(+), 4 deletions(-) (limited to 'drivers/clk/ti/clock.h') diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index f41a7576a3ff..546dae405402 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -217,6 +217,9 @@ struct clk __init *ti_clk_register_clk(struct ti_clk *setup) case TI_CLK_DIVIDER: clk = ti_clk_register_divider(setup); break; + case TI_CLK_COMPOSITE: + clk = ti_clk_register_composite(setup); + break; case TI_CLK_FIXED_FACTOR: fixed_factor = setup->data; diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 578b73b2edf1..404158d2d7f8 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -158,6 +158,7 @@ struct clk *ti_clk_register_gate(struct ti_clk *setup); struct clk *ti_clk_register_interface(struct ti_clk *setup); struct clk *ti_clk_register_mux(struct ti_clk *setup); struct clk *ti_clk_register_divider(struct ti_clk *setup); +struct clk *ti_clk_register_composite(struct ti_clk *setup); struct clk *ti_clk_register_dpll(struct ti_clk *setup); struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup); diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c index 19d8980ba458..3a9665fce041 100644 --- a/drivers/clk/ti/composite.c +++ b/drivers/clk/ti/composite.c @@ -23,6 +23,8 @@ #include #include +#include "clock.h" + #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -116,8 +118,44 @@ static inline struct clk_hw *_get_hw(struct clk_hw_omap_comp *clk, int idx) #define to_clk_hw_comp(_hw) container_of(_hw, struct clk_hw_omap_comp, hw) -static void __init ti_clk_register_composite(struct clk_hw *hw, - struct device_node *node) +struct clk *ti_clk_register_composite(struct ti_clk *setup) +{ + struct ti_clk_composite *comp; + struct clk_hw *gate; + struct clk_hw *mux; + struct clk_hw *div; + int num_parents = 1; + const char **parent_names = NULL; + struct clk *clk; + + comp = setup->data; + + div = ti_clk_build_component_div(comp->divider); + gate = ti_clk_build_component_gate(comp->gate); + mux = ti_clk_build_component_mux(comp->mux); + + if (div) + parent_names = &comp->divider->parent; + + if (gate) + parent_names = &comp->gate->parent; + + if (mux) { + num_parents = comp->mux->num_parents; + parent_names = comp->mux->parents; + } + + clk = clk_register_composite(NULL, setup->name, + parent_names, num_parents, mux, + &ti_clk_mux_ops, div, + &ti_composite_divider_ops, gate, + &ti_composite_gate_ops, 0); + + return clk; +} + +static void __init _register_composite(struct clk_hw *hw, + struct device_node *node) { struct clk *clk; struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw); @@ -136,7 +174,7 @@ static void __init ti_clk_register_composite(struct clk_hw *hw, pr_debug("component %s not ready for %s, retry\n", cclk->comp_nodes[i]->name, node->name); if (!ti_clk_retry_init(node, hw, - ti_clk_register_composite)) + _register_composite)) return; goto cleanup; @@ -216,7 +254,7 @@ static void __init of_ti_composite_clk_setup(struct device_node *node) for (i = 0; i < num_clks; i++) cclk->comp_nodes[i] = _get_component_node(node, i); - ti_clk_register_composite(&cclk->hw, node); + _register_composite(&cclk->hw, node); } CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock", of_ti_composite_clk_setup); -- cgit v1.2.3-59-g8ed1b