xref: /openbmc/linux/drivers/clk/hisilicon/clk.c (revision 0aa0c95f743a06893dbc494b2a75fbf7093330d4)
1*0aa0c95fSHaojian Zhuang /*
2*0aa0c95fSHaojian Zhuang  * Hisilicon clock driver
3*0aa0c95fSHaojian Zhuang  *
4*0aa0c95fSHaojian Zhuang  * Copyright (c) 2012-2013 Hisilicon Limited.
5*0aa0c95fSHaojian Zhuang  * Copyright (c) 2012-2013 Linaro Limited.
6*0aa0c95fSHaojian Zhuang  *
7*0aa0c95fSHaojian Zhuang  * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
8*0aa0c95fSHaojian Zhuang  *	   Xin Li <li.xin@linaro.org>
9*0aa0c95fSHaojian Zhuang  *
10*0aa0c95fSHaojian Zhuang  * This program is free software; you can redistribute it and/or modify
11*0aa0c95fSHaojian Zhuang  * it under the terms of the GNU General Public License as published by
12*0aa0c95fSHaojian Zhuang  * the Free Software Foundation; either version 2 of the License, or
13*0aa0c95fSHaojian Zhuang  * (at your option) any later version.
14*0aa0c95fSHaojian Zhuang  *
15*0aa0c95fSHaojian Zhuang  * This program is distributed in the hope that it will be useful,
16*0aa0c95fSHaojian Zhuang  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*0aa0c95fSHaojian Zhuang  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*0aa0c95fSHaojian Zhuang  * GNU General Public License for more details.
19*0aa0c95fSHaojian Zhuang  *
20*0aa0c95fSHaojian Zhuang  * You should have received a copy of the GNU General Public License along
21*0aa0c95fSHaojian Zhuang  * with this program; if not, write to the Free Software Foundation, Inc.,
22*0aa0c95fSHaojian Zhuang  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23*0aa0c95fSHaojian Zhuang  *
24*0aa0c95fSHaojian Zhuang  */
25*0aa0c95fSHaojian Zhuang 
26*0aa0c95fSHaojian Zhuang #include <linux/kernel.h>
27*0aa0c95fSHaojian Zhuang #include <linux/clk-provider.h>
28*0aa0c95fSHaojian Zhuang #include <linux/clkdev.h>
29*0aa0c95fSHaojian Zhuang #include <linux/delay.h>
30*0aa0c95fSHaojian Zhuang #include <linux/io.h>
31*0aa0c95fSHaojian Zhuang #include <linux/of.h>
32*0aa0c95fSHaojian Zhuang #include <linux/of_address.h>
33*0aa0c95fSHaojian Zhuang #include <linux/of_device.h>
34*0aa0c95fSHaojian Zhuang #include <linux/slab.h>
35*0aa0c95fSHaojian Zhuang #include <linux/clk.h>
36*0aa0c95fSHaojian Zhuang 
37*0aa0c95fSHaojian Zhuang #include "clk.h"
38*0aa0c95fSHaojian Zhuang 
39*0aa0c95fSHaojian Zhuang static DEFINE_SPINLOCK(hisi_clk_lock);
40*0aa0c95fSHaojian Zhuang static struct clk **clk_table;
41*0aa0c95fSHaojian Zhuang static struct clk_onecell_data clk_data;
42*0aa0c95fSHaojian Zhuang 
43*0aa0c95fSHaojian Zhuang void __init hisi_clk_init(struct device_node *np, int nr_clks)
44*0aa0c95fSHaojian Zhuang {
45*0aa0c95fSHaojian Zhuang 	clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
46*0aa0c95fSHaojian Zhuang 	if (!clk_table) {
47*0aa0c95fSHaojian Zhuang 		pr_err("%s: could not allocate clock lookup table\n", __func__);
48*0aa0c95fSHaojian Zhuang 		return;
49*0aa0c95fSHaojian Zhuang 	}
50*0aa0c95fSHaojian Zhuang 	clk_data.clks = clk_table;
51*0aa0c95fSHaojian Zhuang 	clk_data.clk_num = nr_clks;
52*0aa0c95fSHaojian Zhuang 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
53*0aa0c95fSHaojian Zhuang }
54*0aa0c95fSHaojian Zhuang 
55*0aa0c95fSHaojian Zhuang void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks,
56*0aa0c95fSHaojian Zhuang 					 int nums, void __iomem *base)
57*0aa0c95fSHaojian Zhuang {
58*0aa0c95fSHaojian Zhuang 	struct clk *clk;
59*0aa0c95fSHaojian Zhuang 	int i;
60*0aa0c95fSHaojian Zhuang 
61*0aa0c95fSHaojian Zhuang 	for (i = 0; i < nums; i++) {
62*0aa0c95fSHaojian Zhuang 		clk = clk_register_fixed_rate(NULL, clks[i].name,
63*0aa0c95fSHaojian Zhuang 					      clks[i].parent_name,
64*0aa0c95fSHaojian Zhuang 					      clks[i].flags,
65*0aa0c95fSHaojian Zhuang 					      clks[i].fixed_rate);
66*0aa0c95fSHaojian Zhuang 		if (IS_ERR(clk)) {
67*0aa0c95fSHaojian Zhuang 			pr_err("%s: failed to register clock %s\n",
68*0aa0c95fSHaojian Zhuang 			       __func__, clks[i].name);
69*0aa0c95fSHaojian Zhuang 			continue;
70*0aa0c95fSHaojian Zhuang 		}
71*0aa0c95fSHaojian Zhuang 	}
72*0aa0c95fSHaojian Zhuang }
73*0aa0c95fSHaojian Zhuang 
74*0aa0c95fSHaojian Zhuang void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks,
75*0aa0c95fSHaojian Zhuang 					   int nums, void __iomem *base)
76*0aa0c95fSHaojian Zhuang {
77*0aa0c95fSHaojian Zhuang 	struct clk *clk;
78*0aa0c95fSHaojian Zhuang 	int i;
79*0aa0c95fSHaojian Zhuang 
80*0aa0c95fSHaojian Zhuang 	for (i = 0; i < nums; i++) {
81*0aa0c95fSHaojian Zhuang 		clk = clk_register_fixed_factor(NULL, clks[i].name,
82*0aa0c95fSHaojian Zhuang 						clks[i].parent_name,
83*0aa0c95fSHaojian Zhuang 						clks[i].flags, clks[i].mult,
84*0aa0c95fSHaojian Zhuang 						clks[i].div);
85*0aa0c95fSHaojian Zhuang 		if (IS_ERR(clk)) {
86*0aa0c95fSHaojian Zhuang 			pr_err("%s: failed to register clock %s\n",
87*0aa0c95fSHaojian Zhuang 			       __func__, clks[i].name);
88*0aa0c95fSHaojian Zhuang 			continue;
89*0aa0c95fSHaojian Zhuang 		}
90*0aa0c95fSHaojian Zhuang 	}
91*0aa0c95fSHaojian Zhuang }
92*0aa0c95fSHaojian Zhuang 
93*0aa0c95fSHaojian Zhuang void __init hisi_clk_register_mux(struct hisi_mux_clock *clks,
94*0aa0c95fSHaojian Zhuang 				  int nums, void __iomem *base)
95*0aa0c95fSHaojian Zhuang {
96*0aa0c95fSHaojian Zhuang 	struct clk *clk;
97*0aa0c95fSHaojian Zhuang 	int i;
98*0aa0c95fSHaojian Zhuang 
99*0aa0c95fSHaojian Zhuang 	for (i = 0; i < nums; i++) {
100*0aa0c95fSHaojian Zhuang 		clk = clk_register_mux(NULL, clks[i].name, clks[i].parent_names,
101*0aa0c95fSHaojian Zhuang 				       clks[i].num_parents, clks[i].flags,
102*0aa0c95fSHaojian Zhuang 				       base + clks[i].offset, clks[i].shift,
103*0aa0c95fSHaojian Zhuang 				       clks[i].width, clks[i].mux_flags,
104*0aa0c95fSHaojian Zhuang 				       &hisi_clk_lock);
105*0aa0c95fSHaojian Zhuang 		if (IS_ERR(clk)) {
106*0aa0c95fSHaojian Zhuang 			pr_err("%s: failed to register clock %s\n",
107*0aa0c95fSHaojian Zhuang 			       __func__, clks[i].name);
108*0aa0c95fSHaojian Zhuang 			continue;
109*0aa0c95fSHaojian Zhuang 		}
110*0aa0c95fSHaojian Zhuang 
111*0aa0c95fSHaojian Zhuang 		if (clks[i].alias)
112*0aa0c95fSHaojian Zhuang 			clk_register_clkdev(clk, clks[i].alias, NULL);
113*0aa0c95fSHaojian Zhuang 
114*0aa0c95fSHaojian Zhuang 		clk_table[clks[i].id] = clk;
115*0aa0c95fSHaojian Zhuang 	}
116*0aa0c95fSHaojian Zhuang }
117*0aa0c95fSHaojian Zhuang 
118*0aa0c95fSHaojian Zhuang void __init hisi_clk_register_divider(struct hisi_divider_clock *clks,
119*0aa0c95fSHaojian Zhuang 				      int nums, void __iomem *base)
120*0aa0c95fSHaojian Zhuang {
121*0aa0c95fSHaojian Zhuang 	struct clk *clk;
122*0aa0c95fSHaojian Zhuang 	int i;
123*0aa0c95fSHaojian Zhuang 
124*0aa0c95fSHaojian Zhuang 	for (i = 0; i < nums; i++) {
125*0aa0c95fSHaojian Zhuang 		clk = clk_register_divider_table(NULL, clks[i].name,
126*0aa0c95fSHaojian Zhuang 						 clks[i].parent_name,
127*0aa0c95fSHaojian Zhuang 						 clks[i].flags,
128*0aa0c95fSHaojian Zhuang 						 base + clks[i].offset,
129*0aa0c95fSHaojian Zhuang 						 clks[i].shift, clks[i].width,
130*0aa0c95fSHaojian Zhuang 						 clks[i].div_flags,
131*0aa0c95fSHaojian Zhuang 						 clks[i].table,
132*0aa0c95fSHaojian Zhuang 						 &hisi_clk_lock);
133*0aa0c95fSHaojian Zhuang 		if (IS_ERR(clk)) {
134*0aa0c95fSHaojian Zhuang 			pr_err("%s: failed to register clock %s\n",
135*0aa0c95fSHaojian Zhuang 			       __func__, clks[i].name);
136*0aa0c95fSHaojian Zhuang 			continue;
137*0aa0c95fSHaojian Zhuang 		}
138*0aa0c95fSHaojian Zhuang 
139*0aa0c95fSHaojian Zhuang 		if (clks[i].alias)
140*0aa0c95fSHaojian Zhuang 			clk_register_clkdev(clk, clks[i].alias, NULL);
141*0aa0c95fSHaojian Zhuang 
142*0aa0c95fSHaojian Zhuang 		clk_table[clks[i].id] = clk;
143*0aa0c95fSHaojian Zhuang 	}
144*0aa0c95fSHaojian Zhuang }
145*0aa0c95fSHaojian Zhuang 
146*0aa0c95fSHaojian Zhuang void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
147*0aa0c95fSHaojian Zhuang 				       int nums, void __iomem *base)
148*0aa0c95fSHaojian Zhuang {
149*0aa0c95fSHaojian Zhuang 	struct clk *clk;
150*0aa0c95fSHaojian Zhuang 	int i;
151*0aa0c95fSHaojian Zhuang 
152*0aa0c95fSHaojian Zhuang 	for (i = 0; i < nums; i++) {
153*0aa0c95fSHaojian Zhuang 		clk = hisi_register_clkgate_sep(NULL, clks[i].name,
154*0aa0c95fSHaojian Zhuang 						clks[i].parent_name,
155*0aa0c95fSHaojian Zhuang 						clks[i].flags,
156*0aa0c95fSHaojian Zhuang 						base + clks[i].offset,
157*0aa0c95fSHaojian Zhuang 						clks[i].bit_idx,
158*0aa0c95fSHaojian Zhuang 						clks[i].gate_flags,
159*0aa0c95fSHaojian Zhuang 						&hisi_clk_lock);
160*0aa0c95fSHaojian Zhuang 		if (IS_ERR(clk)) {
161*0aa0c95fSHaojian Zhuang 			pr_err("%s: failed to register clock %s\n",
162*0aa0c95fSHaojian Zhuang 			       __func__, clks[i].name);
163*0aa0c95fSHaojian Zhuang 			continue;
164*0aa0c95fSHaojian Zhuang 		}
165*0aa0c95fSHaojian Zhuang 
166*0aa0c95fSHaojian Zhuang 		if (clks[i].alias)
167*0aa0c95fSHaojian Zhuang 			clk_register_clkdev(clk, clks[i].alias, NULL);
168*0aa0c95fSHaojian Zhuang 
169*0aa0c95fSHaojian Zhuang 		clk_table[clks[i].id] = clk;
170*0aa0c95fSHaojian Zhuang 	}
171*0aa0c95fSHaojian Zhuang }
172