Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: ti: add composite clock support

This is a multipurpose clock node, which contains support for multiple
sub-clocks. Uses basic composite clock type to implement the actual
functionality, and TI specific gate, mux and divider clocks.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>

authored by

Tero Kristo and committed by
Mike Turquette
975e1548 b1a07b47

+336 -4
+54
Documentation/devicetree/bindings/clock/ti/composite.txt
··· 1 + Binding for TI composite clock. 2 + 3 + Binding status: Unstable - ABI compatibility may be broken in the future 4 + 5 + This binding uses the common clock binding[1]. It assumes a 6 + register-mapped composite clock with multiple different sub-types; 7 + 8 + a multiplexer clock with multiple input clock signals or parents, one 9 + of which can be selected as output, this behaves exactly as [2] 10 + 11 + an adjustable clock rate divider, this behaves exactly as [3] 12 + 13 + a gating function which can be used to enable and disable the output 14 + clock, this behaves exactly as [4] 15 + 16 + The binding must provide a list of the component clocks that shall be 17 + merged to this clock. The component clocks shall be of one of the 18 + "ti,*composite*-clock" types. 19 + 20 + [1] Documentation/devicetree/bindings/clock/clock-bindings.txt 21 + [2] Documentation/devicetree/bindings/clock/ti/mux.txt 22 + [3] Documentation/devicetree/bindings/clock/ti/divider.txt 23 + [4] Documentation/devicetree/bindings/clock/ti/gate.txt 24 + 25 + Required properties: 26 + - compatible : shall be: "ti,composite-clock" 27 + - clocks : link phandles of component clocks 28 + - #clock-cells : from common clock binding; shall be set to 0. 29 + 30 + Examples: 31 + 32 + usb_l4_gate_ick: usb_l4_gate_ick { 33 + #clock-cells = <0>; 34 + compatible = "ti,composite-interface-clock"; 35 + clocks = <&l4_ick>; 36 + ti,bit-shift = <5>; 37 + reg = <0x0a10>; 38 + }; 39 + 40 + usb_l4_div_ick: usb_l4_div_ick { 41 + #clock-cells = <0>; 42 + compatible = "ti,composite-divider-clock"; 43 + clocks = <&l4_ick>; 44 + ti,bit-shift = <4>; 45 + ti,max-div = <1>; 46 + reg = <0x0a40>; 47 + ti,index-starts-at-one; 48 + }; 49 + 50 + usb_l4_ick: usb_l4_ick { 51 + #clock-cells = <0>; 52 + compatible = "ti,composite-clock"; 53 + clocks = <&usb_l4_gate_ick>, <&usb_l4_div_ick>; 54 + };
-3
arch/arm/mach-omap2/clock.h
··· 240 240 241 241 unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); 242 242 243 - int omap2_dflt_clk_enable(struct clk_hw *hw); 244 - void omap2_dflt_clk_disable(struct clk_hw *hw); 245 - int omap2_dflt_clk_is_enabled(struct clk_hw *hw); 246 243 void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, 247 244 void __iomem **other_reg, 248 245 u8 *other_bit);
+1 -1
drivers/clk/ti/Makefile
··· 1 1 ifneq ($(CONFIG_OF),) 2 2 obj-y += clk.o autoidle.o 3 - clk-common = dpll.o 3 + clk-common = dpll.o composite.o 4 4 endif
+269
drivers/clk/ti/composite.c
··· 1 + /* 2 + * TI composite clock support 3 + * 4 + * Copyright (C) 2013 Texas Instruments, Inc. 5 + * 6 + * Tero Kristo <t-kristo@ti.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + * This program is distributed "as is" WITHOUT ANY WARRANTY of any 13 + * kind, whether express or implied; without even the implied warranty 14 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #include <linux/clk-provider.h> 19 + #include <linux/slab.h> 20 + #include <linux/io.h> 21 + #include <linux/of.h> 22 + #include <linux/of_address.h> 23 + #include <linux/clk/ti.h> 24 + #include <linux/list.h> 25 + 26 + #undef pr_fmt 27 + #define pr_fmt(fmt) "%s: " fmt, __func__ 28 + 29 + #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) 30 + 31 + static unsigned long ti_composite_recalc_rate(struct clk_hw *hw, 32 + unsigned long parent_rate) 33 + { 34 + return clk_divider_ops.recalc_rate(hw, parent_rate); 35 + } 36 + 37 + static long ti_composite_round_rate(struct clk_hw *hw, unsigned long rate, 38 + unsigned long *prate) 39 + { 40 + return -EINVAL; 41 + } 42 + 43 + static int ti_composite_set_rate(struct clk_hw *hw, unsigned long rate, 44 + unsigned long parent_rate) 45 + { 46 + return -EINVAL; 47 + } 48 + 49 + static const struct clk_ops ti_composite_divider_ops = { 50 + .recalc_rate = &ti_composite_recalc_rate, 51 + .round_rate = &ti_composite_round_rate, 52 + .set_rate = &ti_composite_set_rate, 53 + }; 54 + 55 + static const struct clk_ops ti_composite_gate_ops = { 56 + .enable = &omap2_dflt_clk_enable, 57 + .disable = &omap2_dflt_clk_disable, 58 + .is_enabled = &omap2_dflt_clk_is_enabled, 59 + }; 60 + 61 + struct component_clk { 62 + int num_parents; 63 + const char **parent_names; 64 + struct device_node *node; 65 + int type; 66 + struct clk_hw *hw; 67 + struct list_head link; 68 + }; 69 + 70 + static const char * __initconst component_clk_types[] = { 71 + "gate", "divider", "mux" 72 + }; 73 + 74 + static LIST_HEAD(component_clks); 75 + 76 + static struct device_node *_get_component_node(struct device_node *node, int i) 77 + { 78 + int rc; 79 + struct of_phandle_args clkspec; 80 + 81 + rc = of_parse_phandle_with_args(node, "clocks", "#clock-cells", i, 82 + &clkspec); 83 + if (rc) 84 + return NULL; 85 + 86 + return clkspec.np; 87 + } 88 + 89 + static struct component_clk *_lookup_component(struct device_node *node) 90 + { 91 + struct component_clk *comp; 92 + 93 + list_for_each_entry(comp, &component_clks, link) { 94 + if (comp->node == node) 95 + return comp; 96 + } 97 + return NULL; 98 + } 99 + 100 + struct clk_hw_omap_comp { 101 + struct clk_hw hw; 102 + struct device_node *comp_nodes[CLK_COMPONENT_TYPE_MAX]; 103 + struct component_clk *comp_clks[CLK_COMPONENT_TYPE_MAX]; 104 + }; 105 + 106 + static inline struct clk_hw *_get_hw(struct clk_hw_omap_comp *clk, int idx) 107 + { 108 + if (!clk) 109 + return NULL; 110 + 111 + if (!clk->comp_clks[idx]) 112 + return NULL; 113 + 114 + return clk->comp_clks[idx]->hw; 115 + } 116 + 117 + #define to_clk_hw_comp(_hw) container_of(_hw, struct clk_hw_omap_comp, hw) 118 + 119 + static void __init ti_clk_register_composite(struct clk_hw *hw, 120 + struct device_node *node) 121 + { 122 + struct clk *clk; 123 + struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw); 124 + struct component_clk *comp; 125 + int num_parents = 0; 126 + const char **parent_names = NULL; 127 + int i; 128 + 129 + /* Check for presence of each component clock */ 130 + for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) { 131 + if (!cclk->comp_nodes[i]) 132 + continue; 133 + 134 + comp = _lookup_component(cclk->comp_nodes[i]); 135 + if (!comp) { 136 + pr_debug("component %s not ready for %s, retry\n", 137 + cclk->comp_nodes[i]->name, node->name); 138 + if (!ti_clk_retry_init(node, hw, 139 + ti_clk_register_composite)) 140 + return; 141 + 142 + goto cleanup; 143 + } 144 + if (cclk->comp_clks[comp->type] != NULL) { 145 + pr_err("duplicate component types for %s (%s)!\n", 146 + node->name, component_clk_types[comp->type]); 147 + goto cleanup; 148 + } 149 + 150 + cclk->comp_clks[comp->type] = comp; 151 + 152 + /* Mark this node as found */ 153 + cclk->comp_nodes[i] = NULL; 154 + } 155 + 156 + /* All components exists, proceed with registration */ 157 + for (i = CLK_COMPONENT_TYPE_MAX - 1; i >= 0; i--) { 158 + comp = cclk->comp_clks[i]; 159 + if (!comp) 160 + continue; 161 + if (comp->num_parents) { 162 + num_parents = comp->num_parents; 163 + parent_names = comp->parent_names; 164 + break; 165 + } 166 + } 167 + 168 + if (!num_parents) { 169 + pr_err("%s: no parents found for %s!\n", __func__, node->name); 170 + goto cleanup; 171 + } 172 + 173 + clk = clk_register_composite(NULL, node->name, 174 + parent_names, num_parents, 175 + _get_hw(cclk, CLK_COMPONENT_TYPE_MUX), 176 + &clk_mux_ops, 177 + _get_hw(cclk, CLK_COMPONENT_TYPE_DIVIDER), 178 + &ti_composite_divider_ops, 179 + _get_hw(cclk, CLK_COMPONENT_TYPE_GATE), 180 + &ti_composite_gate_ops, 0); 181 + 182 + if (!IS_ERR(clk)) 183 + of_clk_add_provider(node, of_clk_src_simple_get, clk); 184 + 185 + cleanup: 186 + /* Free component clock list entries */ 187 + for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) { 188 + if (!cclk->comp_clks[i]) 189 + continue; 190 + list_del(&cclk->comp_clks[i]->link); 191 + kfree(cclk->comp_clks[i]); 192 + } 193 + 194 + kfree(cclk); 195 + } 196 + 197 + static void __init of_ti_composite_clk_setup(struct device_node *node) 198 + { 199 + int num_clks; 200 + int i; 201 + struct clk_hw_omap_comp *cclk; 202 + 203 + /* Number of component clocks to be put inside this clock */ 204 + num_clks = of_clk_get_parent_count(node); 205 + 206 + if (num_clks < 1) { 207 + pr_err("composite clk %s must have component(s)\n", node->name); 208 + return; 209 + } 210 + 211 + cclk = kzalloc(sizeof(*cclk), GFP_KERNEL); 212 + if (!cclk) 213 + return; 214 + 215 + /* Get device node pointers for each component clock */ 216 + for (i = 0; i < num_clks; i++) 217 + cclk->comp_nodes[i] = _get_component_node(node, i); 218 + 219 + ti_clk_register_composite(&cclk->hw, node); 220 + } 221 + CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock", 222 + of_ti_composite_clk_setup); 223 + 224 + /** 225 + * ti_clk_add_component - add a component clock to the pool 226 + * @node: device node of the component clock 227 + * @hw: hardware clock definition for the component clock 228 + * @type: type of the component clock 229 + * 230 + * Adds a component clock to the list of available components, so that 231 + * it can be registered by a composite clock. 232 + */ 233 + int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw, 234 + int type) 235 + { 236 + int num_parents; 237 + const char **parent_names; 238 + struct component_clk *clk; 239 + int i; 240 + 241 + num_parents = of_clk_get_parent_count(node); 242 + 243 + if (num_parents < 1) { 244 + pr_err("component-clock %s must have parent(s)\n", node->name); 245 + return -EINVAL; 246 + } 247 + 248 + parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL); 249 + if (!parent_names) 250 + return -ENOMEM; 251 + 252 + for (i = 0; i < num_parents; i++) 253 + parent_names[i] = of_clk_get_parent_name(node, i); 254 + 255 + clk = kzalloc(sizeof(*clk), GFP_KERNEL); 256 + if (!clk) { 257 + kfree(parent_names); 258 + return -ENOMEM; 259 + } 260 + 261 + clk->num_parents = num_parents; 262 + clk->parent_names = parent_names; 263 + clk->hw = hw; 264 + clk->node = node; 265 + clk->type = type; 266 + list_add(&clk->link, &component_clks); 267 + 268 + return 0; 269 + }
+12
include/linux/clk/ti.h
··· 164 164 /* DPLL Type and DCO Selection Flags */ 165 165 #define DPLL_J_TYPE 0x1 166 166 167 + /* Composite clock component types */ 168 + enum { 169 + CLK_COMPONENT_TYPE_GATE = 0, 170 + CLK_COMPONENT_TYPE_DIVIDER, 171 + CLK_COMPONENT_TYPE_MUX, 172 + CLK_COMPONENT_TYPE_MAX, 173 + }; 174 + 167 175 /** 168 176 * struct ti_dt_clk - OMAP DT clock alias declarations 169 177 * @lk: clock lookup definition ··· 244 236 unsigned long parent_rate); 245 237 int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, 246 238 unsigned long parent_rate); 239 + int omap2_dflt_clk_enable(struct clk_hw *hw); 240 + void omap2_dflt_clk_disable(struct clk_hw *hw); 241 + int omap2_dflt_clk_is_enabled(struct clk_hw *hw); 247 242 248 243 void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); 249 244 void ti_dt_clocks_register(struct ti_dt_clk *oclks); ··· 254 243 int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, 255 244 ti_of_clk_init_cb_t func); 256 245 int of_ti_clk_autoidle_setup(struct device_node *node); 246 + int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type); 257 247 258 248 #ifdef CONFIG_OF 259 249 void of_ti_clk_allow_autoidle_all(void);