linux/drivers/clk/ti/composite.c
<<
>>
Prefs
   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
 119#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
 120struct clk *ti_clk_register_composite(struct ti_clk *setup)
 121{
 122        struct ti_clk_composite *comp;
 123        struct clk_hw *gate;
 124        struct clk_hw *mux;
 125        struct clk_hw *div;
 126        int num_parents = 1;
 127        const char **parent_names = NULL;
 128        struct clk *clk;
 129
 130        comp = setup->data;
 131
 132        div = ti_clk_build_component_div(comp->divider);
 133        gate = ti_clk_build_component_gate(comp->gate);
 134        mux = ti_clk_build_component_mux(comp->mux);
 135
 136        if (div)
 137                parent_names = &comp->divider->parent;
 138
 139        if (gate)
 140                parent_names = &comp->gate->parent;
 141
 142        if (mux) {
 143                num_parents = comp->mux->num_parents;
 144                parent_names = comp->mux->parents;
 145        }
 146
 147        clk = clk_register_composite(NULL, setup->name,
 148                                     parent_names, num_parents, mux,
 149                                     &ti_clk_mux_ops, div,
 150                                     &ti_composite_divider_ops, gate,
 151                                     &ti_composite_gate_ops, 0);
 152
 153        return clk;
 154}
 155#endif
 156
 157static void __init _register_composite(struct clk_hw *hw,
 158                                       struct device_node *node)
 159{
 160        struct clk *clk;
 161        struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw);
 162        struct component_clk *comp;
 163        int num_parents = 0;
 164        const char **parent_names = NULL;
 165        int i;
 166
 167        /* Check for presence of each component clock */
 168        for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) {
 169                if (!cclk->comp_nodes[i])
 170                        continue;
 171
 172                comp = _lookup_component(cclk->comp_nodes[i]);
 173                if (!comp) {
 174                        pr_debug("component %s not ready for %s, retry\n",
 175                                 cclk->comp_nodes[i]->name, node->name);
 176                        if (!ti_clk_retry_init(node, hw,
 177                                               _register_composite))
 178                                return;
 179
 180                        goto cleanup;
 181                }
 182                if (cclk->comp_clks[comp->type] != NULL) {
 183                        pr_err("duplicate component types for %s (%s)!\n",
 184                               node->name, component_clk_types[comp->type]);
 185                        goto cleanup;
 186                }
 187
 188                cclk->comp_clks[comp->type] = comp;
 189
 190                /* Mark this node as found */
 191                cclk->comp_nodes[i] = NULL;
 192        }
 193
 194        /* All components exists, proceed with registration */
 195        for (i = CLK_COMPONENT_TYPE_MAX - 1; i >= 0; i--) {
 196                comp = cclk->comp_clks[i];
 197                if (!comp)
 198                        continue;
 199                if (comp->num_parents) {
 200                        num_parents = comp->num_parents;
 201                        parent_names = comp->parent_names;
 202                        break;
 203                }
 204        }
 205
 206        if (!num_parents) {
 207                pr_err("%s: no parents found for %s!\n", __func__, node->name);
 208                goto cleanup;
 209        }
 210
 211        clk = clk_register_composite(NULL, node->name,
 212                                     parent_names, num_parents,
 213                                     _get_hw(cclk, CLK_COMPONENT_TYPE_MUX),
 214                                     &ti_clk_mux_ops,
 215                                     _get_hw(cclk, CLK_COMPONENT_TYPE_DIVIDER),
 216                                     &ti_composite_divider_ops,
 217                                     _get_hw(cclk, CLK_COMPONENT_TYPE_GATE),
 218                                     &ti_composite_gate_ops, 0);
 219
 220        if (!IS_ERR(clk))
 221                of_clk_add_provider(node, of_clk_src_simple_get, clk);
 222
 223cleanup:
 224        /* Free component clock list entries */
 225        for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) {
 226                if (!cclk->comp_clks[i])
 227                        continue;
 228                list_del(&cclk->comp_clks[i]->link);
 229                kfree(cclk->comp_clks[i]);
 230        }
 231
 232        kfree(cclk);
 233}
 234
 235static void __init of_ti_composite_clk_setup(struct device_node *node)
 236{
 237        unsigned int num_clks;
 238        int i;
 239        struct clk_hw_omap_comp *cclk;
 240
 241        /* Number of component clocks to be put inside this clock */
 242        num_clks = of_clk_get_parent_count(node);
 243
 244        if (!num_clks) {
 245                pr_err("composite clk %s must have component(s)\n", node->name);
 246                return;
 247        }
 248
 249        cclk = kzalloc(sizeof(*cclk), GFP_KERNEL);
 250        if (!cclk)
 251                return;
 252
 253        /* Get device node pointers for each component clock */
 254        for (i = 0; i < num_clks; i++)
 255                cclk->comp_nodes[i] = _get_component_node(node, i);
 256
 257        _register_composite(&cclk->hw, node);
 258}
 259CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock",
 260               of_ti_composite_clk_setup);
 261
 262/**
 263 * ti_clk_add_component - add a component clock to the pool
 264 * @node: device node of the component clock
 265 * @hw: hardware clock definition for the component clock
 266 * @type: type of the component clock
 267 *
 268 * Adds a component clock to the list of available components, so that
 269 * it can be registered by a composite clock.
 270 */
 271int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw,
 272                                int type)
 273{
 274        unsigned int num_parents;
 275        const char **parent_names;
 276        struct component_clk *clk;
 277
 278        num_parents = of_clk_get_parent_count(node);
 279
 280        if (!num_parents) {
 281                pr_err("component-clock %s must have parent(s)\n", node->name);
 282                return -EINVAL;
 283        }
 284
 285        parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
 286        if (!parent_names)
 287                return -ENOMEM;
 288
 289        of_clk_parent_fill(node, parent_names, num_parents);
 290
 291        clk = kzalloc(sizeof(*clk), GFP_KERNEL);
 292        if (!clk) {
 293                kfree(parent_names);
 294                return -ENOMEM;
 295        }
 296
 297        clk->num_parents = num_parents;
 298        clk->parent_names = parent_names;
 299        clk->hw = hw;
 300        clk->node = node;
 301        clk->type = type;
 302        list_add(&clk->link, &component_clks);
 303
 304        return 0;
 305}
 306