Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  1/*
  2 * Copyright 2013 Freescale Semiconductor, Inc.
  3 *
  4 * This program is free software; you can redistribute it and/or modify
  5 * it under the terms of the GNU General Public License version 2 as
  6 * published by the Free Software Foundation.
  7 *
  8 * clock driver for Freescale PowerPC corenet SoCs.
  9 */
 10#include <linux/clk-provider.h>
 11#include <linux/io.h>
 12#include <linux/kernel.h>
 13#include <linux/module.h>
 14#include <linux/of_address.h>
 15#include <linux/of_platform.h>
 16#include <linux/of.h>
 17#include <linux/slab.h>
 18
 19struct cmux_clk {
 20	struct clk_hw hw;
 21	void __iomem *reg;
 22	u32 flags;
 23};
 24
 25#define PLL_KILL			BIT(31)
 26#define	CLKSEL_SHIFT		27
 27#define CLKSEL_ADJUST		BIT(0)
 28#define to_cmux_clk(p)		container_of(p, struct cmux_clk, hw)
 29
 30static unsigned int clocks_per_pll;
 31
 32static int cmux_set_parent(struct clk_hw *hw, u8 idx)
 33{
 34	struct cmux_clk *clk = to_cmux_clk(hw);
 35	u32 clksel;
 36
 37	clksel = ((idx / clocks_per_pll) << 2) + idx % clocks_per_pll;
 38	if (clk->flags & CLKSEL_ADJUST)
 39		clksel += 8;
 40	clksel = (clksel & 0xf) << CLKSEL_SHIFT;
 41	iowrite32be(clksel, clk->reg);
 42
 43	return 0;
 44}
 45
 46static u8 cmux_get_parent(struct clk_hw *hw)
 47{
 48	struct cmux_clk *clk = to_cmux_clk(hw);
 49	u32 clksel;
 50
 51	clksel = ioread32be(clk->reg);
 52	clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
 53	if (clk->flags & CLKSEL_ADJUST)
 54		clksel -= 8;
 55	clksel = (clksel >> 2) * clocks_per_pll + clksel % 4;
 56
 57	return clksel;
 58}
 59
 60const struct clk_ops cmux_ops = {
 61	.get_parent = cmux_get_parent,
 62	.set_parent = cmux_set_parent,
 63};
 64
 65static void __init core_mux_init(struct device_node *np)
 66{
 67	struct clk *clk;
 68	struct clk_init_data init;
 69	struct cmux_clk *cmux_clk;
 70	struct device_node *node;
 71	int rc, count, i;
 72	u32	offset;
 73	const char *clk_name;
 74	const char **parent_names;
 75
 76	rc = of_property_read_u32(np, "reg", &offset);
 77	if (rc) {
 78		pr_err("%s: could not get reg property\n", np->name);
 79		return;
 80	}
 81
 82	/* get the input clock source count */
 83	count = of_property_count_strings(np, "clock-names");
 84	if (count < 0) {
 85		pr_err("%s: get clock count error\n", np->name);
 86		return;
 87	}
 88	parent_names = kzalloc((sizeof(char *) * count), GFP_KERNEL);
 89	if (!parent_names) {
 90		pr_err("%s: could not allocate parent_names\n", __func__);
 91		return;
 92	}
 93
 94	for (i = 0; i < count; i++)
 95		parent_names[i] = of_clk_get_parent_name(np, i);
 96
 97	cmux_clk = kzalloc(sizeof(struct cmux_clk), GFP_KERNEL);
 98	if (!cmux_clk) {
 99		pr_err("%s: could not allocate cmux_clk\n", __func__);
100		goto err_name;
101	}
102	cmux_clk->reg = of_iomap(np, 0);
103	if (!cmux_clk->reg) {
104		pr_err("%s: could not map register\n", __func__);
105		goto err_clk;
106	}
107
108	node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
109	if (node && (offset >= 0x80))
110		cmux_clk->flags = CLKSEL_ADJUST;
111
112	rc = of_property_read_string_index(np, "clock-output-names",
113			0, &clk_name);
114	if (rc) {
115		pr_err("%s: read clock names error\n", np->name);
116		goto err_clk;
117	}
118
119	init.name = clk_name;
120	init.ops = &cmux_ops;
121	init.parent_names = parent_names;
122	init.num_parents = count;
123	init.flags = 0;
124	cmux_clk->hw.init = &init;
125
126	clk = clk_register(NULL, &cmux_clk->hw);
127	if (IS_ERR(clk)) {
128		pr_err("%s: could not register clock\n", clk_name);
129		goto err_clk;
130	}
131
132	rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
133	if (rc) {
134		pr_err("Could not register clock provider for node:%s\n",
135			 np->name);
136		goto err_clk;
137	}
138	goto err_name;
139
140err_clk:
141	kfree(cmux_clk);
142err_name:
143	/* free *_names because they are reallocated when registered */
144	kfree(parent_names);
145}
146
147static void __init core_pll_init(struct device_node *np)
148{
149	u32 mult;
150	int i, rc, count;
151	const char *clk_name, *parent_name;
152	struct clk_onecell_data *onecell_data;
153	struct clk      **subclks;
154	void __iomem *base;
155
156	base = of_iomap(np, 0);
157	if (!base) {
158		pr_err("clk-ppc: iomap error\n");
159		return;
160	}
161
162	/* get the multiple of PLL */
163	mult = ioread32be(base);
164
165	/* check if this PLL is disabled */
166	if (mult & PLL_KILL) {
167		pr_debug("PLL:%s is disabled\n", np->name);
168		goto err_map;
169	}
170	mult = (mult >> 1) & 0x3f;
171
172	parent_name = of_clk_get_parent_name(np, 0);
173	if (!parent_name) {
174		pr_err("PLL: %s must have a parent\n", np->name);
175		goto err_map;
176	}
177
178	count = of_property_count_strings(np, "clock-output-names");
179	if (count < 0 || count > 4) {
180		pr_err("%s: clock is not supported\n", np->name);
181		goto err_map;
182	}
183
184	/* output clock number per PLL */
185	clocks_per_pll = count;
186
187	subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
188	if (!subclks) {
189		pr_err("%s: could not allocate subclks\n", __func__);
190		goto err_map;
191	}
192
193	onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
194	if (!onecell_data) {
195		pr_err("%s: could not allocate onecell_data\n", __func__);
196		goto err_clks;
197	}
198
199	for (i = 0; i < count; i++) {
200		rc = of_property_read_string_index(np, "clock-output-names",
201				i, &clk_name);
202		if (rc) {
203			pr_err("%s: could not get clock names\n", np->name);
204			goto err_cell;
205		}
206
207		/*
208		 * when count == 4, there are 4 output clocks:
209		 * /1, /2, /3, /4 respectively
210		 * when count < 4, there are at least 2 output clocks:
211		 * /1, /2, (/4, if count == 3) respectively.
212		 */
213		if (count == 4)
214			subclks[i] = clk_register_fixed_factor(NULL, clk_name,
215					parent_name, 0, mult, 1 + i);
216		else
217
218			subclks[i] = clk_register_fixed_factor(NULL, clk_name,
219					parent_name, 0, mult, 1 << i);
220
221		if (IS_ERR(subclks[i])) {
222			pr_err("%s: could not register clock\n", clk_name);
223			goto err_cell;
224		}
225	}
226
227	onecell_data->clks = subclks;
228	onecell_data->clk_num = count;
229
230	rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
231	if (rc) {
232		pr_err("Could not register clk provider for node:%s\n",
233			 np->name);
234		goto err_cell;
235	}
236
237	iounmap(base);
238	return;
239err_cell:
240	kfree(onecell_data);
241err_clks:
242	kfree(subclks);
243err_map:
244	iounmap(base);
245}
246
247static void __init sysclk_init(struct device_node *node)
248{
249	struct clk *clk;
250	const char *clk_name = node->name;
251	struct device_node *np = of_get_parent(node);
252	u32 rate;
253
254	if (!np) {
255		pr_err("ppc-clk: could not get parent node\n");
256		return;
257	}
258
259	if (of_property_read_u32(np, "clock-frequency", &rate)) {
260		of_node_put(node);
261		return;
262	}
263
264	of_property_read_string(np, "clock-output-names", &clk_name);
265
266	clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
267	if (!IS_ERR(clk))
268		of_clk_add_provider(np, of_clk_src_simple_get, clk);
269}
270
271static const struct of_device_id clk_match[] __initconst = {
272	{ .compatible = "fsl,qoriq-sysclk-1.0", .data = sysclk_init, },
273	{ .compatible = "fsl,qoriq-sysclk-2.0", .data = sysclk_init, },
274	{ .compatible = "fsl,qoriq-core-pll-1.0", .data = core_pll_init, },
275	{ .compatible = "fsl,qoriq-core-pll-2.0", .data = core_pll_init, },
276	{ .compatible = "fsl,qoriq-core-mux-1.0", .data = core_mux_init, },
277	{ .compatible = "fsl,qoriq-core-mux-2.0", .data = core_mux_init, },
278	{}
279};
280
281static int __init ppc_corenet_clk_probe(struct platform_device *pdev)
282{
283	of_clk_init(clk_match);
284
285	return 0;
286}
287
288static const struct of_device_id ppc_clk_ids[] __initconst = {
289	{ .compatible = "fsl,qoriq-clockgen-1.0", },
290	{ .compatible = "fsl,qoriq-clockgen-2.0", },
291	{}
292};
293
294static struct platform_driver ppc_corenet_clk_driver = {
295	.driver = {
296		.name = "ppc_corenet_clock",
297		.owner = THIS_MODULE,
298		.of_match_table = ppc_clk_ids,
299	},
300	.probe = ppc_corenet_clk_probe,
301};
302
303static int __init ppc_corenet_clk_init(void)
304{
305	return platform_driver_register(&ppc_corenet_clk_driver);
306}
307subsys_initcall(ppc_corenet_clk_init);