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

Configure Feed

Select the types of activity you want to include in your feed.

at v5.2-rc3 275 lines 6.7 kB view raw
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#include "clock.h" 27 28#undef pr_fmt 29#define pr_fmt(fmt) "%s: " fmt, __func__ 30 31static unsigned long ti_composite_recalc_rate(struct clk_hw *hw, 32 unsigned long parent_rate) 33{ 34 return ti_clk_divider_ops.recalc_rate(hw, parent_rate); 35} 36 37static long ti_composite_round_rate(struct clk_hw *hw, unsigned long rate, 38 unsigned long *prate) 39{ 40 return -EINVAL; 41} 42 43static int ti_composite_set_rate(struct clk_hw *hw, unsigned long rate, 44 unsigned long parent_rate) 45{ 46 return -EINVAL; 47} 48 49static 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 55static 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 61struct 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 70static const char * const component_clk_types[] __initconst = { 71 "gate", "divider", "mux" 72}; 73 74static LIST_HEAD(component_clks); 75 76static 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 89static 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 100struct 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 106static 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 119static void __init _register_composite(void *user, 120 struct device_node *node) 121{ 122 struct clk_hw *hw = user; 123 struct clk *clk; 124 struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw); 125 struct component_clk *comp; 126 int num_parents = 0; 127 const char **parent_names = NULL; 128 int i; 129 int ret; 130 131 /* Check for presence of each component clock */ 132 for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) { 133 if (!cclk->comp_nodes[i]) 134 continue; 135 136 comp = _lookup_component(cclk->comp_nodes[i]); 137 if (!comp) { 138 pr_debug("component %s not ready for %pOFn, retry\n", 139 cclk->comp_nodes[i]->name, node); 140 if (!ti_clk_retry_init(node, hw, 141 _register_composite)) 142 return; 143 144 goto cleanup; 145 } 146 if (cclk->comp_clks[comp->type] != NULL) { 147 pr_err("duplicate component types for %pOFn (%s)!\n", 148 node, component_clk_types[comp->type]); 149 goto cleanup; 150 } 151 152 cclk->comp_clks[comp->type] = comp; 153 154 /* Mark this node as found */ 155 cclk->comp_nodes[i] = NULL; 156 } 157 158 /* All components exists, proceed with registration */ 159 for (i = CLK_COMPONENT_TYPE_MAX - 1; i >= 0; i--) { 160 comp = cclk->comp_clks[i]; 161 if (!comp) 162 continue; 163 if (comp->num_parents) { 164 num_parents = comp->num_parents; 165 parent_names = comp->parent_names; 166 break; 167 } 168 } 169 170 if (!num_parents) { 171 pr_err("%s: no parents found for %pOFn!\n", __func__, node); 172 goto cleanup; 173 } 174 175 clk = clk_register_composite(NULL, node->name, 176 parent_names, num_parents, 177 _get_hw(cclk, CLK_COMPONENT_TYPE_MUX), 178 &ti_clk_mux_ops, 179 _get_hw(cclk, CLK_COMPONENT_TYPE_DIVIDER), 180 &ti_composite_divider_ops, 181 _get_hw(cclk, CLK_COMPONENT_TYPE_GATE), 182 &ti_composite_gate_ops, 0); 183 184 if (!IS_ERR(clk)) { 185 ret = ti_clk_add_alias(NULL, clk, node->name); 186 if (ret) { 187 clk_unregister(clk); 188 goto cleanup; 189 } 190 of_clk_add_provider(node, of_clk_src_simple_get, clk); 191 } 192 193cleanup: 194 /* Free component clock list entries */ 195 for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) { 196 if (!cclk->comp_clks[i]) 197 continue; 198 list_del(&cclk->comp_clks[i]->link); 199 kfree(cclk->comp_clks[i]); 200 } 201 202 kfree(cclk); 203} 204 205static void __init of_ti_composite_clk_setup(struct device_node *node) 206{ 207 unsigned int num_clks; 208 int i; 209 struct clk_hw_omap_comp *cclk; 210 211 /* Number of component clocks to be put inside this clock */ 212 num_clks = of_clk_get_parent_count(node); 213 214 if (!num_clks) { 215 pr_err("composite clk %pOFn must have component(s)\n", node); 216 return; 217 } 218 219 cclk = kzalloc(sizeof(*cclk), GFP_KERNEL); 220 if (!cclk) 221 return; 222 223 /* Get device node pointers for each component clock */ 224 for (i = 0; i < num_clks; i++) 225 cclk->comp_nodes[i] = _get_component_node(node, i); 226 227 _register_composite(&cclk->hw, node); 228} 229CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock", 230 of_ti_composite_clk_setup); 231 232/** 233 * ti_clk_add_component - add a component clock to the pool 234 * @node: device node of the component clock 235 * @hw: hardware clock definition for the component clock 236 * @type: type of the component clock 237 * 238 * Adds a component clock to the list of available components, so that 239 * it can be registered by a composite clock. 240 */ 241int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw, 242 int type) 243{ 244 unsigned int num_parents; 245 const char **parent_names; 246 struct component_clk *clk; 247 248 num_parents = of_clk_get_parent_count(node); 249 250 if (!num_parents) { 251 pr_err("component-clock %pOFn must have parent(s)\n", node); 252 return -EINVAL; 253 } 254 255 parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL); 256 if (!parent_names) 257 return -ENOMEM; 258 259 of_clk_parent_fill(node, parent_names, num_parents); 260 261 clk = kzalloc(sizeof(*clk), GFP_KERNEL); 262 if (!clk) { 263 kfree(parent_names); 264 return -ENOMEM; 265 } 266 267 clk->num_parents = num_parents; 268 clk->parent_names = parent_names; 269 clk->hw = hw; 270 clk->node = node; 271 clk->type = type; 272 list_add(&clk->link, &component_clks); 273 274 return 0; 275}