1/*
2 * drivers/clk/clk-axm5516.c
3 *
4 * Provides clock implementations for three different types of clock devices on
5 * the Axxia device: PLL clock, a clock divider and a clock mux.
6 *
7 * Copyright (C) 2014 LSI Corporation
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
12 */
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/slab.h>
16#include <linux/platform_device.h>
17#include <linux/of.h>
18#include <linux/of_address.h>
19#include <linux/clk-provider.h>
20#include <linux/regmap.h>
21#include <dt-bindings/clock/lsi,axm5516-clks.h>
22
23
24/**
25 * struct axxia_clk - Common struct to all Axxia clocks.
26 * @hw: clk_hw for the common clk framework
27 * @regmap: Regmap for the clock control registers
28 */
29struct axxia_clk {
30	struct clk_hw hw;
31	struct regmap *regmap;
32};
33#define to_axxia_clk(_hw) container_of(_hw, struct axxia_clk, hw)
34
35/**
36 * struct axxia_pllclk - Axxia PLL generated clock.
37 * @aclk: Common struct
38 * @reg: Offset into regmap for PLL control register
39 */
40struct axxia_pllclk {
41	struct axxia_clk aclk;
42	u32 reg;
43};
44#define to_axxia_pllclk(_aclk) container_of(_aclk, struct axxia_pllclk, aclk)
45
46/**
47 * axxia_pllclk_recalc - Calculate the PLL generated clock rate given the
48 * parent clock rate.
49 */
50static unsigned long
51axxia_pllclk_recalc(struct clk_hw *hw, unsigned long parent_rate)
52{
53	struct axxia_clk *aclk = to_axxia_clk(hw);
54	struct axxia_pllclk *pll = to_axxia_pllclk(aclk);
55	unsigned long rate, fbdiv, refdiv, postdiv;
56	u32 control;
57
58	regmap_read(aclk->regmap, pll->reg, &control);
59	postdiv = ((control >> 0) & 0xf) + 1;
60	fbdiv   = ((control >> 4) & 0xfff) + 3;
61	refdiv  = ((control >> 16) & 0x1f) + 1;
62	rate = (parent_rate / (refdiv * postdiv)) * fbdiv;
63
64	return rate;
65}
66
67static const struct clk_ops axxia_pllclk_ops = {
68	.recalc_rate = axxia_pllclk_recalc,
69};
70
71/**
72 * struct axxia_divclk - Axxia clock divider
73 * @aclk: Common struct
74 * @reg: Offset into regmap for PLL control register
75 * @shift: Bit position for divider value
76 * @width: Number of bits in divider value
77 */
78struct axxia_divclk {
79	struct axxia_clk aclk;
80	u32 reg;
81	u32 shift;
82	u32 width;
83};
84#define to_axxia_divclk(_aclk) container_of(_aclk, struct axxia_divclk, aclk)
85
86/**
87 * axxia_divclk_recalc_rate - Calculate clock divider output rage
88 */
89static unsigned long
90axxia_divclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
91{
92	struct axxia_clk *aclk = to_axxia_clk(hw);
93	struct axxia_divclk *divclk = to_axxia_divclk(aclk);
94	u32 ctrl, div;
95
96	regmap_read(aclk->regmap, divclk->reg, &ctrl);
97	div = 1 + ((ctrl >> divclk->shift) & ((1 << divclk->width)-1));
98
99	return parent_rate / div;
100}
101
102static const struct clk_ops axxia_divclk_ops = {
103	.recalc_rate = axxia_divclk_recalc_rate,
104};
105
106/**
107 * struct axxia_clkmux - Axxia clock mux
108 * @aclk: Common struct
109 * @reg: Offset into regmap for PLL control register
110 * @shift: Bit position for selection value
111 * @width: Number of bits in selection value
112 */
113struct axxia_clkmux {
114	struct axxia_clk aclk;
115	u32 reg;
116	u32 shift;
117	u32 width;
118};
119#define to_axxia_clkmux(_aclk) container_of(_aclk, struct axxia_clkmux, aclk)
120
121/**
122 * axxia_clkmux_get_parent - Return the index of selected parent clock
123 */
124static u8 axxia_clkmux_get_parent(struct clk_hw *hw)
125{
126	struct axxia_clk *aclk = to_axxia_clk(hw);
127	struct axxia_clkmux *mux = to_axxia_clkmux(aclk);
128	u32 ctrl, parent;
129
130	regmap_read(aclk->regmap, mux->reg, &ctrl);
131	parent = (ctrl >> mux->shift) & ((1 << mux->width) - 1);
132
133	return (u8) parent;
134}
135
136static const struct clk_ops axxia_clkmux_ops = {
137	.get_parent = axxia_clkmux_get_parent,
138};
139
140
141/*
142 * PLLs
143 */
144
145static struct axxia_pllclk clk_fab_pll = {
146	.aclk.hw.init = &(struct clk_init_data){
147		.name = "clk_fab_pll",
148		.parent_names = (const char *[]){
149			"clk_ref0"
150		},
151		.num_parents = 1,
152		.ops = &axxia_pllclk_ops,
153	},
154	.reg   = 0x01800,
155};
156
157static struct axxia_pllclk clk_cpu_pll = {
158	.aclk.hw.init = &(struct clk_init_data){
159		.name = "clk_cpu_pll",
160		.parent_names = (const char *[]){
161			"clk_ref0"
162		},
163		.num_parents = 1,
164		.ops = &axxia_pllclk_ops,
165	},
166	.reg   = 0x02000,
167};
168
169static struct axxia_pllclk clk_sys_pll = {
170	.aclk.hw.init = &(struct clk_init_data){
171		.name = "clk_sys_pll",
172		.parent_names = (const char *[]){
173			"clk_ref0"
174		},
175		.num_parents = 1,
176		.ops = &axxia_pllclk_ops,
177	},
178	.reg   = 0x02800,
179};
180
181static struct axxia_pllclk clk_sm0_pll = {
182	.aclk.hw.init = &(struct clk_init_data){
183		.name = "clk_sm0_pll",
184		.parent_names = (const char *[]){
185			"clk_ref2"
186		},
187		.num_parents = 1,
188		.ops = &axxia_pllclk_ops,
189	},
190	.reg   = 0x03000,
191};
192
193static struct axxia_pllclk clk_sm1_pll = {
194	.aclk.hw.init = &(struct clk_init_data){
195		.name = "clk_sm1_pll",
196		.parent_names = (const char *[]){
197			"clk_ref1"
198		},
199		.num_parents = 1,
200		.ops = &axxia_pllclk_ops,
201	},
202	.reg   = 0x03800,
203};
204
205/*
206 * Clock dividers
207 */
208
209static struct axxia_divclk clk_cpu0_div = {
210	.aclk.hw.init = &(struct clk_init_data){
211		.name = "clk_cpu0_div",
212		.parent_names = (const char *[]){
213			"clk_cpu_pll"
214		},
215		.num_parents = 1,
216		.ops = &axxia_divclk_ops,
217	},
218	.reg   = 0x10008,
219	.shift = 0,
220	.width = 4,
221};
222
223static struct axxia_divclk clk_cpu1_div = {
224	.aclk.hw.init = &(struct clk_init_data){
225		.name = "clk_cpu1_div",
226		.parent_names = (const char *[]){
227			"clk_cpu_pll"
228		},
229		.num_parents = 1,
230		.ops = &axxia_divclk_ops,
231	},
232	.reg   = 0x10008,
233	.shift = 4,
234	.width = 4,
235};
236
237static struct axxia_divclk clk_cpu2_div = {
238	.aclk.hw.init = &(struct clk_init_data){
239		.name = "clk_cpu2_div",
240		.parent_names = (const char *[]){
241			"clk_cpu_pll"
242		},
243		.num_parents = 1,
244		.ops = &axxia_divclk_ops,
245	},
246	.reg   = 0x10008,
247	.shift = 8,
248	.width = 4,
249};
250
251static struct axxia_divclk clk_cpu3_div = {
252	.aclk.hw.init = &(struct clk_init_data){
253		.name = "clk_cpu3_div",
254		.parent_names = (const char *[]){
255			"clk_cpu_pll"
256		},
257		.num_parents = 1,
258		.ops = &axxia_divclk_ops,
259	},
260	.reg   = 0x10008,
261	.shift = 12,
262	.width = 4,
263};
264
265static struct axxia_divclk clk_nrcp_div = {
266	.aclk.hw.init = &(struct clk_init_data){
267		.name = "clk_nrcp_div",
268		.parent_names = (const char *[]){
269			"clk_sys_pll"
270		},
271		.num_parents = 1,
272		.ops = &axxia_divclk_ops,
273	},
274	.reg   = 0x1000c,
275	.shift = 0,
276	.width = 4,
277};
278
279static struct axxia_divclk clk_sys_div = {
280	.aclk.hw.init = &(struct clk_init_data){
281		.name = "clk_sys_div",
282		.parent_names = (const char *[]){
283			"clk_sys_pll"
284		},
285		.num_parents = 1,
286		.ops = &axxia_divclk_ops,
287	},
288	.reg   = 0x1000c,
289	.shift = 4,
290	.width = 4,
291};
292
293static struct axxia_divclk clk_fab_div = {
294	.aclk.hw.init = &(struct clk_init_data){
295		.name = "clk_fab_div",
296		.parent_names = (const char *[]){
297			"clk_fab_pll"
298		},
299		.num_parents = 1,
300		.ops = &axxia_divclk_ops,
301	},
302	.reg   = 0x1000c,
303	.shift = 8,
304	.width = 4,
305};
306
307static struct axxia_divclk clk_per_div = {
308	.aclk.hw.init = &(struct clk_init_data){
309		.name = "clk_per_div",
310		.parent_names = (const char *[]){
311			"clk_sm1_pll"
312		},
313		.num_parents = 1,
314		.flags = CLK_IS_BASIC,
315		.ops = &axxia_divclk_ops,
316	},
317	.reg   = 0x1000c,
318	.shift = 12,
319	.width = 4,
320};
321
322static struct axxia_divclk clk_mmc_div = {
323	.aclk.hw.init = &(struct clk_init_data){
324		.name = "clk_mmc_div",
325		.parent_names = (const char *[]){
326			"clk_sm1_pll"
327		},
328		.num_parents = 1,
329		.flags = CLK_IS_BASIC,
330		.ops = &axxia_divclk_ops,
331	},
332	.reg   = 0x1000c,
333	.shift = 16,
334	.width = 4,
335};
336
337/*
338 * Clock MUXes
339 */
340
341static struct axxia_clkmux clk_cpu0_mux = {
342	.aclk.hw.init = &(struct clk_init_data){
343		.name = "clk_cpu0",
344		.parent_names = (const char *[]){
345			"clk_ref0",
346			"clk_cpu_pll",
347			"clk_cpu0_div",
348			"clk_cpu0_div"
349		},
350		.num_parents = 4,
351		.ops = &axxia_clkmux_ops,
352	},
353	.reg   = 0x10000,
354	.shift = 0,
355	.width = 2,
356};
357
358static struct axxia_clkmux clk_cpu1_mux = {
359	.aclk.hw.init = &(struct clk_init_data){
360		.name = "clk_cpu1",
361		.parent_names = (const char *[]){
362			"clk_ref0",
363			"clk_cpu_pll",
364			"clk_cpu1_div",
365			"clk_cpu1_div"
366		},
367		.num_parents = 4,
368		.ops = &axxia_clkmux_ops,
369	},
370	.reg   = 0x10000,
371	.shift = 2,
372	.width = 2,
373};
374
375static struct axxia_clkmux clk_cpu2_mux = {
376	.aclk.hw.init = &(struct clk_init_data){
377		.name = "clk_cpu2",
378		.parent_names = (const char *[]){
379			"clk_ref0",
380			"clk_cpu_pll",
381			"clk_cpu2_div",
382			"clk_cpu2_div"
383		},
384		.num_parents = 4,
385		.ops = &axxia_clkmux_ops,
386	},
387	.reg   = 0x10000,
388	.shift = 4,
389	.width = 2,
390};
391
392static struct axxia_clkmux clk_cpu3_mux = {
393	.aclk.hw.init = &(struct clk_init_data){
394		.name = "clk_cpu3",
395		.parent_names = (const char *[]){
396			"clk_ref0",
397			"clk_cpu_pll",
398			"clk_cpu3_div",
399			"clk_cpu3_div"
400		},
401		.num_parents = 4,
402		.ops = &axxia_clkmux_ops,
403	},
404	.reg   = 0x10000,
405	.shift = 6,
406	.width = 2,
407};
408
409static struct axxia_clkmux clk_nrcp_mux = {
410	.aclk.hw.init = &(struct clk_init_data){
411		.name = "clk_nrcp",
412		.parent_names = (const char *[]){
413			"clk_ref0",
414			"clk_sys_pll",
415			"clk_nrcp_div",
416			"clk_nrcp_div"
417		},
418		.num_parents = 4,
419		.ops = &axxia_clkmux_ops,
420	},
421	.reg   = 0x10004,
422	.shift = 0,
423	.width = 2,
424};
425
426static struct axxia_clkmux clk_sys_mux = {
427	.aclk.hw.init = &(struct clk_init_data){
428		.name = "clk_sys",
429		.parent_names = (const char *[]){
430			"clk_ref0",
431			"clk_sys_pll",
432			"clk_sys_div",
433			"clk_sys_div"
434		},
435		.num_parents = 4,
436		.ops = &axxia_clkmux_ops,
437	},
438	.reg   = 0x10004,
439	.shift = 2,
440	.width = 2,
441};
442
443static struct axxia_clkmux clk_fab_mux = {
444	.aclk.hw.init = &(struct clk_init_data){
445		.name = "clk_fab",
446		.parent_names = (const char *[]){
447			"clk_ref0",
448			"clk_fab_pll",
449			"clk_fab_div",
450			"clk_fab_div"
451		},
452		.num_parents = 4,
453		.ops = &axxia_clkmux_ops,
454	},
455	.reg   = 0x10004,
456	.shift = 4,
457	.width = 2,
458};
459
460static struct axxia_clkmux clk_per_mux = {
461	.aclk.hw.init = &(struct clk_init_data){
462		.name = "clk_per",
463		.parent_names = (const char *[]){
464			"clk_ref1",
465			"clk_per_div"
466		},
467		.num_parents = 2,
468		.ops = &axxia_clkmux_ops,
469	},
470	.reg   = 0x10004,
471	.shift = 6,
472	.width = 1,
473};
474
475static struct axxia_clkmux clk_mmc_mux = {
476	.aclk.hw.init = &(struct clk_init_data){
477		.name = "clk_mmc",
478		.parent_names = (const char *[]){
479			"clk_ref1",
480			"clk_mmc_div"
481		},
482		.num_parents = 2,
483		.ops = &axxia_clkmux_ops,
484	},
485	.reg   = 0x10004,
486	.shift = 9,
487	.width = 1,
488};
489
490/* Table of all supported clocks indexed by the clock identifiers from the
491 * device tree binding
492 */
493static struct axxia_clk *axmclk_clocks[] = {
494	[AXXIA_CLK_FAB_PLL]  = &clk_fab_pll.aclk,
495	[AXXIA_CLK_CPU_PLL]  = &clk_cpu_pll.aclk,
496	[AXXIA_CLK_SYS_PLL]  = &clk_sys_pll.aclk,
497	[AXXIA_CLK_SM0_PLL]  = &clk_sm0_pll.aclk,
498	[AXXIA_CLK_SM1_PLL]  = &clk_sm1_pll.aclk,
499	[AXXIA_CLK_FAB_DIV]  = &clk_fab_div.aclk,
500	[AXXIA_CLK_SYS_DIV]  = &clk_sys_div.aclk,
501	[AXXIA_CLK_NRCP_DIV] = &clk_nrcp_div.aclk,
502	[AXXIA_CLK_CPU0_DIV] = &clk_cpu0_div.aclk,
503	[AXXIA_CLK_CPU1_DIV] = &clk_cpu1_div.aclk,
504	[AXXIA_CLK_CPU2_DIV] = &clk_cpu2_div.aclk,
505	[AXXIA_CLK_CPU3_DIV] = &clk_cpu3_div.aclk,
506	[AXXIA_CLK_PER_DIV]  = &clk_per_div.aclk,
507	[AXXIA_CLK_MMC_DIV]  = &clk_mmc_div.aclk,
508	[AXXIA_CLK_FAB]      = &clk_fab_mux.aclk,
509	[AXXIA_CLK_SYS]      = &clk_sys_mux.aclk,
510	[AXXIA_CLK_NRCP]     = &clk_nrcp_mux.aclk,
511	[AXXIA_CLK_CPU0]     = &clk_cpu0_mux.aclk,
512	[AXXIA_CLK_CPU1]     = &clk_cpu1_mux.aclk,
513	[AXXIA_CLK_CPU2]     = &clk_cpu2_mux.aclk,
514	[AXXIA_CLK_CPU3]     = &clk_cpu3_mux.aclk,
515	[AXXIA_CLK_PER]      = &clk_per_mux.aclk,
516	[AXXIA_CLK_MMC]      = &clk_mmc_mux.aclk,
517};
518
519static const struct regmap_config axmclk_regmap_config = {
520	.reg_bits	= 32,
521	.reg_stride	= 4,
522	.val_bits	= 32,
523	.max_register	= 0x1fffc,
524	.fast_io	= true,
525};
526
527static const struct of_device_id axmclk_match_table[] = {
528	{ .compatible = "lsi,axm5516-clks" },
529	{ }
530};
531MODULE_DEVICE_TABLE(of, axmclk_match_table);
532
533struct axmclk_priv {
534	struct clk_onecell_data onecell;
535	struct clk *clks[];
536};
537
538static int axmclk_probe(struct platform_device *pdev)
539{
540	void __iomem *base;
541	struct resource *res;
542	int i, ret;
543	struct device *dev = &pdev->dev;
544	struct clk *clk;
545	struct regmap *regmap;
546	size_t num_clks;
547	struct axmclk_priv *priv;
548
549	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
550	base = devm_ioremap_resource(dev, res);
551	if (IS_ERR(base))
552		return PTR_ERR(base);
553
554	regmap = devm_regmap_init_mmio(dev, base, &axmclk_regmap_config);
555	if (IS_ERR(regmap))
556		return PTR_ERR(regmap);
557
558	num_clks = ARRAY_SIZE(axmclk_clocks);
559	pr_info("axmclk: supporting %u clocks\n", num_clks);
560	priv = devm_kzalloc(dev, sizeof(*priv) + sizeof(*priv->clks) * num_clks,
561			    GFP_KERNEL);
562	if (!priv)
563		return -ENOMEM;
564
565	priv->onecell.clks = priv->clks;
566	priv->onecell.clk_num = num_clks;
567
568	/* Update each entry with the allocated regmap and register the clock
569	 * with the common clock framework
570	 */
571	for (i = 0; i < num_clks; i++) {
572		axmclk_clocks[i]->regmap = regmap;
573		clk = devm_clk_register(dev, &axmclk_clocks[i]->hw);
574		if (IS_ERR(clk))
575			return PTR_ERR(clk);
576		priv->clks[i] = clk;
577	}
578
579	ret = of_clk_add_provider(dev->of_node,
580				  of_clk_src_onecell_get, &priv->onecell);
581
582	return ret;
583}
584
585static int axmclk_remove(struct platform_device *pdev)
586{
587	of_clk_del_provider(pdev->dev.of_node);
588	return 0;
589}
590
591static struct platform_driver axmclk_driver = {
592	.probe		= axmclk_probe,
593	.remove		= axmclk_remove,
594	.driver		= {
595		.name	= "clk-axm5516",
596		.of_match_table = axmclk_match_table,
597	},
598};
599
600static int __init axmclk_init(void)
601{
602	return platform_driver_register(&axmclk_driver);
603}
604core_initcall(axmclk_init);
605
606static void __exit axmclk_exit(void)
607{
608	platform_driver_unregister(&axmclk_driver);
609}
610module_exit(axmclk_exit);
611
612MODULE_DESCRIPTION("AXM5516 clock driver");
613MODULE_LICENSE("GPL v2");
614MODULE_ALIAS("platform:clk-axm5516");
615