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
 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 %s, retry\n",
 139                                 cclk->comp_nodes[i]->name, node->name);
 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 %s (%s)!\n",
 148                               node->name, 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 %s!\n", __func__, node->name);
 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 %s must have component(s)\n", node->name);
 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 %s must have parent(s)\n", node->name);
 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}
 276