Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * TI composite clock support
0004  *
0005  * Copyright (C) 2013 Texas Instruments, Inc.
0006  *
0007  * Tero Kristo <t-kristo@ti.com>
0008  */
0009 
0010 #include <linux/clk-provider.h>
0011 #include <linux/slab.h>
0012 #include <linux/io.h>
0013 #include <linux/of.h>
0014 #include <linux/of_address.h>
0015 #include <linux/clk/ti.h>
0016 #include <linux/list.h>
0017 
0018 #include "clock.h"
0019 
0020 #undef pr_fmt
0021 #define pr_fmt(fmt) "%s: " fmt, __func__
0022 
0023 static unsigned long ti_composite_recalc_rate(struct clk_hw *hw,
0024                           unsigned long parent_rate)
0025 {
0026     return ti_clk_divider_ops.recalc_rate(hw, parent_rate);
0027 }
0028 
0029 static long ti_composite_round_rate(struct clk_hw *hw, unsigned long rate,
0030                     unsigned long *prate)
0031 {
0032     return -EINVAL;
0033 }
0034 
0035 static int ti_composite_set_rate(struct clk_hw *hw, unsigned long rate,
0036                  unsigned long parent_rate)
0037 {
0038     return -EINVAL;
0039 }
0040 
0041 static const struct clk_ops ti_composite_divider_ops = {
0042     .recalc_rate    = &ti_composite_recalc_rate,
0043     .round_rate = &ti_composite_round_rate,
0044     .set_rate   = &ti_composite_set_rate,
0045 };
0046 
0047 static const struct clk_ops ti_composite_gate_ops = {
0048     .enable     = &omap2_dflt_clk_enable,
0049     .disable    = &omap2_dflt_clk_disable,
0050     .is_enabled = &omap2_dflt_clk_is_enabled,
0051 };
0052 
0053 struct component_clk {
0054     int num_parents;
0055     const char **parent_names;
0056     struct device_node *node;
0057     int type;
0058     struct clk_hw *hw;
0059     struct list_head link;
0060 };
0061 
0062 static const char * const component_clk_types[] __initconst = {
0063     "gate", "divider", "mux"
0064 };
0065 
0066 static LIST_HEAD(component_clks);
0067 
0068 static struct device_node *_get_component_node(struct device_node *node, int i)
0069 {
0070     int rc;
0071     struct of_phandle_args clkspec;
0072 
0073     rc = of_parse_phandle_with_args(node, "clocks", "#clock-cells", i,
0074                     &clkspec);
0075     if (rc)
0076         return NULL;
0077 
0078     return clkspec.np;
0079 }
0080 
0081 static struct component_clk *_lookup_component(struct device_node *node)
0082 {
0083     struct component_clk *comp;
0084 
0085     list_for_each_entry(comp, &component_clks, link) {
0086         if (comp->node == node)
0087             return comp;
0088     }
0089     return NULL;
0090 }
0091 
0092 struct clk_hw_omap_comp {
0093     struct clk_hw hw;
0094     struct device_node *comp_nodes[CLK_COMPONENT_TYPE_MAX];
0095     struct component_clk *comp_clks[CLK_COMPONENT_TYPE_MAX];
0096 };
0097 
0098 static inline struct clk_hw *_get_hw(struct clk_hw_omap_comp *clk, int idx)
0099 {
0100     if (!clk)
0101         return NULL;
0102 
0103     if (!clk->comp_clks[idx])
0104         return NULL;
0105 
0106     return clk->comp_clks[idx]->hw;
0107 }
0108 
0109 #define to_clk_hw_comp(_hw) container_of(_hw, struct clk_hw_omap_comp, hw)
0110 
0111 static void __init _register_composite(void *user,
0112                        struct device_node *node)
0113 {
0114     struct clk_hw *hw = user;
0115     struct clk *clk;
0116     struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw);
0117     struct component_clk *comp;
0118     int num_parents = 0;
0119     const char **parent_names = NULL;
0120     const char *name;
0121     int i;
0122     int ret;
0123 
0124     /* Check for presence of each component clock */
0125     for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) {
0126         if (!cclk->comp_nodes[i])
0127             continue;
0128 
0129         comp = _lookup_component(cclk->comp_nodes[i]);
0130         if (!comp) {
0131             pr_debug("component %s not ready for %pOFn, retry\n",
0132                  cclk->comp_nodes[i]->name, node);
0133             if (!ti_clk_retry_init(node, hw,
0134                            _register_composite))
0135                 return;
0136 
0137             goto cleanup;
0138         }
0139         if (cclk->comp_clks[comp->type] != NULL) {
0140             pr_err("duplicate component types for %pOFn (%s)!\n",
0141                    node, component_clk_types[comp->type]);
0142             goto cleanup;
0143         }
0144 
0145         cclk->comp_clks[comp->type] = comp;
0146 
0147         /* Mark this node as found */
0148         cclk->comp_nodes[i] = NULL;
0149     }
0150 
0151     /* All components exists, proceed with registration */
0152     for (i = CLK_COMPONENT_TYPE_MAX - 1; i >= 0; i--) {
0153         comp = cclk->comp_clks[i];
0154         if (!comp)
0155             continue;
0156         if (comp->num_parents) {
0157             num_parents = comp->num_parents;
0158             parent_names = comp->parent_names;
0159             break;
0160         }
0161     }
0162 
0163     if (!num_parents) {
0164         pr_err("%s: no parents found for %pOFn!\n", __func__, node);
0165         goto cleanup;
0166     }
0167 
0168     name = ti_dt_clk_name(node);
0169     clk = clk_register_composite(NULL, name,
0170                      parent_names, num_parents,
0171                      _get_hw(cclk, CLK_COMPONENT_TYPE_MUX),
0172                      &ti_clk_mux_ops,
0173                      _get_hw(cclk, CLK_COMPONENT_TYPE_DIVIDER),
0174                      &ti_composite_divider_ops,
0175                      _get_hw(cclk, CLK_COMPONENT_TYPE_GATE),
0176                      &ti_composite_gate_ops, 0);
0177 
0178     if (!IS_ERR(clk)) {
0179         ret = ti_clk_add_alias(NULL, clk, name);
0180         if (ret) {
0181             clk_unregister(clk);
0182             goto cleanup;
0183         }
0184         of_clk_add_provider(node, of_clk_src_simple_get, clk);
0185     }
0186 
0187 cleanup:
0188     /* Free component clock list entries */
0189     for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) {
0190         if (!cclk->comp_clks[i])
0191             continue;
0192         list_del(&cclk->comp_clks[i]->link);
0193         kfree(cclk->comp_clks[i]->parent_names);
0194         kfree(cclk->comp_clks[i]);
0195     }
0196 
0197     kfree(cclk);
0198 }
0199 
0200 static void __init of_ti_composite_clk_setup(struct device_node *node)
0201 {
0202     unsigned int num_clks;
0203     int i;
0204     struct clk_hw_omap_comp *cclk;
0205 
0206     /* Number of component clocks to be put inside this clock */
0207     num_clks = of_clk_get_parent_count(node);
0208 
0209     if (!num_clks) {
0210         pr_err("composite clk %pOFn must have component(s)\n", node);
0211         return;
0212     }
0213 
0214     cclk = kzalloc(sizeof(*cclk), GFP_KERNEL);
0215     if (!cclk)
0216         return;
0217 
0218     /* Get device node pointers for each component clock */
0219     for (i = 0; i < num_clks; i++)
0220         cclk->comp_nodes[i] = _get_component_node(node, i);
0221 
0222     _register_composite(&cclk->hw, node);
0223 }
0224 CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock",
0225            of_ti_composite_clk_setup);
0226 
0227 /**
0228  * ti_clk_add_component - add a component clock to the pool
0229  * @node: device node of the component clock
0230  * @hw: hardware clock definition for the component clock
0231  * @type: type of the component clock
0232  *
0233  * Adds a component clock to the list of available components, so that
0234  * it can be registered by a composite clock.
0235  */
0236 int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw,
0237                 int type)
0238 {
0239     unsigned int num_parents;
0240     const char **parent_names;
0241     struct component_clk *clk;
0242 
0243     num_parents = of_clk_get_parent_count(node);
0244 
0245     if (!num_parents) {
0246         pr_err("component-clock %pOFn must have parent(s)\n", node);
0247         return -EINVAL;
0248     }
0249 
0250     parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
0251     if (!parent_names)
0252         return -ENOMEM;
0253 
0254     of_clk_parent_fill(node, parent_names, num_parents);
0255 
0256     clk = kzalloc(sizeof(*clk), GFP_KERNEL);
0257     if (!clk) {
0258         kfree(parent_names);
0259         return -ENOMEM;
0260     }
0261 
0262     clk->num_parents = num_parents;
0263     clk->parent_names = parent_names;
0264     clk->hw = hw;
0265     clk->node = node;
0266     clk->type = type;
0267     list_add(&clk->link, &component_clks);
0268 
0269     return 0;
0270 }