brintos

brintos / linux-shallow public Read only

0
0
Text · 6.2 KiB · b85382c Raw
271 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * TI composite clock support4 *5 * Copyright (C) 2013 Texas Instruments, Inc.6 *7 * Tero Kristo <t-kristo@ti.com>8 */9 10#include <linux/clk-provider.h>11#include <linux/slab.h>12#include <linux/io.h>13#include <linux/of.h>14#include <linux/of_address.h>15#include <linux/clk/ti.h>16#include <linux/list.h>17 18#include "clock.h"19 20#undef pr_fmt21#define pr_fmt(fmt) "%s: " fmt, __func__22 23static unsigned long ti_composite_recalc_rate(struct clk_hw *hw,24					      unsigned long parent_rate)25{26	return ti_clk_divider_ops.recalc_rate(hw, parent_rate);27}28 29static long ti_composite_round_rate(struct clk_hw *hw, unsigned long rate,30				    unsigned long *prate)31{32	return -EINVAL;33}34 35static int ti_composite_set_rate(struct clk_hw *hw, unsigned long rate,36				 unsigned long parent_rate)37{38	return -EINVAL;39}40 41static const struct clk_ops ti_composite_divider_ops = {42	.recalc_rate	= &ti_composite_recalc_rate,43	.round_rate	= &ti_composite_round_rate,44	.set_rate	= &ti_composite_set_rate,45};46 47static const struct clk_ops ti_composite_gate_ops = {48	.enable		= &omap2_dflt_clk_enable,49	.disable	= &omap2_dflt_clk_disable,50	.is_enabled	= &omap2_dflt_clk_is_enabled,51};52 53struct component_clk {54	int num_parents;55	const char **parent_names;56	struct device_node *node;57	int type;58	struct clk_hw *hw;59	struct list_head link;60};61 62static const char * const component_clk_types[] __initconst = {63	"gate", "divider", "mux"64};65 66static LIST_HEAD(component_clks);67 68static struct device_node *_get_component_node(struct device_node *node, int i)69{70	int rc;71	struct of_phandle_args clkspec;72 73	rc = of_parse_phandle_with_args(node, "clocks", "#clock-cells", i,74					&clkspec);75	if (rc)76		return NULL;77 78	return clkspec.np;79}80 81static struct component_clk *_lookup_component(struct device_node *node)82{83	struct component_clk *comp;84 85	list_for_each_entry(comp, &component_clks, link) {86		if (comp->node == node)87			return comp;88	}89	return NULL;90}91 92struct clk_hw_omap_comp {93	struct clk_hw hw;94	struct device_node *comp_nodes[CLK_COMPONENT_TYPE_MAX];95	struct component_clk *comp_clks[CLK_COMPONENT_TYPE_MAX];96};97 98static inline struct clk_hw *_get_hw(struct clk_hw_omap_comp *clk, int idx)99{100	if (!clk)101		return NULL;102 103	if (!clk->comp_clks[idx])104		return NULL;105 106	return clk->comp_clks[idx]->hw;107}108 109#define to_clk_hw_comp(_hw) container_of(_hw, struct clk_hw_omap_comp, hw)110 111static void __init _register_composite(void *user,112				       struct device_node *node)113{114	struct clk_hw *hw = user;115	struct clk *clk;116	struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw);117	struct component_clk *comp;118	int num_parents = 0;119	const char **parent_names = NULL;120	const char *name;121	int i;122	int ret;123 124	/* Check for presence of each component clock */125	for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) {126		if (!cclk->comp_nodes[i])127			continue;128 129		comp = _lookup_component(cclk->comp_nodes[i]);130		if (!comp) {131			pr_debug("component %s not ready for %pOFn, retry\n",132				 cclk->comp_nodes[i]->name, node);133			if (!ti_clk_retry_init(node, hw,134					       _register_composite))135				return;136 137			goto cleanup;138		}139		if (cclk->comp_clks[comp->type] != NULL) {140			pr_err("duplicate component types for %pOFn (%s)!\n",141			       node, component_clk_types[comp->type]);142			goto cleanup;143		}144 145		cclk->comp_clks[comp->type] = comp;146 147		/* Mark this node as found */148		cclk->comp_nodes[i] = NULL;149	}150 151	/* All components exists, proceed with registration */152	for (i = CLK_COMPONENT_TYPE_MAX - 1; i >= 0; i--) {153		comp = cclk->comp_clks[i];154		if (!comp)155			continue;156		if (comp->num_parents) {157			num_parents = comp->num_parents;158			parent_names = comp->parent_names;159			break;160		}161	}162 163	if (!num_parents) {164		pr_err("%s: no parents found for %pOFn!\n", __func__, node);165		goto cleanup;166	}167 168	name = ti_dt_clk_name(node);169	clk = clk_register_composite(NULL, name,170				     parent_names, num_parents,171				     _get_hw(cclk, CLK_COMPONENT_TYPE_MUX),172				     &ti_clk_mux_ops,173				     _get_hw(cclk, CLK_COMPONENT_TYPE_DIVIDER),174				     &ti_composite_divider_ops,175				     _get_hw(cclk, CLK_COMPONENT_TYPE_GATE),176				     &ti_composite_gate_ops, 0);177 178	if (!IS_ERR(clk)) {179		ret = ti_clk_add_alias(clk, name);180		if (ret) {181			clk_unregister(clk);182			goto cleanup;183		}184		of_clk_add_provider(node, of_clk_src_simple_get, clk);185	}186 187cleanup:188	/* Free component clock list entries */189	for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) {190		if (!cclk->comp_clks[i])191			continue;192		list_del(&cclk->comp_clks[i]->link);193		kfree(cclk->comp_clks[i]->parent_names);194		kfree(cclk->comp_clks[i]);195	}196 197	kfree(cclk);198}199 200static void __init of_ti_composite_clk_setup(struct device_node *node)201{202	unsigned int num_clks;203	int i;204	struct clk_hw_omap_comp *cclk;205 206	/* Number of component clocks to be put inside this clock */207	num_clks = of_clk_get_parent_count(node);208 209	if (!num_clks) {210		pr_err("composite clk %pOFn must have component(s)\n", node);211		return;212	}213 214	cclk = kzalloc(sizeof(*cclk), GFP_KERNEL);215	if (!cclk)216		return;217 218	/* Get device node pointers for each component clock */219	for (i = 0; i < num_clks; i++)220		cclk->comp_nodes[i] = _get_component_node(node, i);221 222	_register_composite(&cclk->hw, node);223}224CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock",225	       of_ti_composite_clk_setup);226 227/**228 * ti_clk_add_component - add a component clock to the pool229 * @node: device node of the component clock230 * @hw: hardware clock definition for the component clock231 * @type: type of the component clock232 *233 * Adds a component clock to the list of available components, so that234 * it can be registered by a composite clock.235 */236int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw,237				int type)238{239	unsigned int num_parents;240	const char **parent_names;241	struct component_clk *clk;242 243	num_parents = of_clk_get_parent_count(node);244 245	if (!num_parents) {246		pr_err("component-clock %pOFn must have parent(s)\n", node);247		return -EINVAL;248	}249 250	parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);251	if (!parent_names)252		return -ENOMEM;253 254	of_clk_parent_fill(node, parent_names, num_parents);255 256	clk = kzalloc(sizeof(*clk), GFP_KERNEL);257	if (!clk) {258		kfree(parent_names);259		return -ENOMEM;260	}261 262	clk->num_parents = num_parents;263	clk->parent_names = parent_names;264	clk->hw = hw;265	clk->node = node;266	clk->type = type;267	list_add(&clk->link, &component_clks);268 269	return 0;270}271