root/drivers/clk/ti/composite.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ti_composite_recalc_rate
  2. ti_composite_round_rate
  3. ti_composite_set_rate
  4. _get_component_node
  5. _lookup_component
  6. _get_hw
  7. _register_composite
  8. of_ti_composite_clk_setup
  9. ti_clk_add_component

   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 
  31 static 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 
  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 * const component_clk_types[] __initconst = {
  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 _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 
 193 cleanup:
 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 
 205 static 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 }
 229 CLK_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  */
 241 int __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 }

/* [<][>][^][v][top][bottom][index][help] */