Merge tag 'nios2-v4.2' of git://git.rocketboards.org/linux-socfpga-next
[firefly-linux-kernel-4.4.55.git] / drivers / clk / meson / clkc.c
1 /*
2  * Copyright (c) 2015 Endless Mobile, Inc.
3  * Author: Carlo Caione <carlo@endlessm.com>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <linux/clk.h>
19 #include <linux/clk-provider.h>
20 #include <linux/mfd/syscon.h>
21 #include <linux/slab.h>
22
23 #include "clkc.h"
24
25 static DEFINE_SPINLOCK(clk_lock);
26
27 static struct clk **clks;
28 static struct clk_onecell_data clk_data;
29
30 struct clk ** __init meson_clk_init(struct device_node *np,
31                                    unsigned long nr_clks)
32 {
33         clks = kcalloc(nr_clks, sizeof(*clks), GFP_KERNEL);
34         if (!clks)
35                 return ERR_PTR(-ENOMEM);
36
37         clk_data.clks = clks;
38         clk_data.clk_num = nr_clks;
39         of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
40
41         return clks;
42 }
43
44 static void meson_clk_add_lookup(struct clk *clk, unsigned int id)
45 {
46         if (clks && id)
47                 clks[id] = clk;
48 }
49
50 static struct clk * __init
51 meson_clk_register_composite(const struct clk_conf *clk_conf,
52                              void __iomem *clk_base)
53 {
54         struct clk *clk;
55         struct clk_mux *mux = NULL;
56         struct clk_divider *div = NULL;
57         struct clk_gate *gate = NULL;
58         const struct clk_ops *mux_ops = NULL;
59         const struct composite_conf *composite_conf;
60
61         composite_conf = clk_conf->conf.composite;
62
63         if (clk_conf->num_parents > 1) {
64                 mux = kzalloc(sizeof(*mux), GFP_KERNEL);
65                 if (!mux)
66                         return ERR_PTR(-ENOMEM);
67
68                 mux->reg = clk_base + clk_conf->reg_off
69                                 + composite_conf->mux_parm.reg_off;
70                 mux->shift = composite_conf->mux_parm.shift;
71                 mux->mask = BIT(composite_conf->mux_parm.width) - 1;
72                 mux->flags = composite_conf->mux_flags;
73                 mux->lock = &clk_lock;
74                 mux->table = composite_conf->mux_table;
75                 mux_ops = (composite_conf->mux_flags & CLK_MUX_READ_ONLY) ?
76                           &clk_mux_ro_ops : &clk_mux_ops;
77         }
78
79         if (MESON_PARM_APPLICABLE(&composite_conf->div_parm)) {
80                 div = kzalloc(sizeof(*div), GFP_KERNEL);
81                 if (!div) {
82                         clk = ERR_PTR(-ENOMEM);
83                         goto error;
84                 }
85
86                 div->reg = clk_base + clk_conf->reg_off
87                                 + composite_conf->div_parm.reg_off;
88                 div->shift = composite_conf->div_parm.shift;
89                 div->width = composite_conf->div_parm.width;
90                 div->lock = &clk_lock;
91                 div->flags = composite_conf->div_flags;
92                 div->table = composite_conf->div_table;
93         }
94
95         if (MESON_PARM_APPLICABLE(&composite_conf->gate_parm)) {
96                 gate = kzalloc(sizeof(*gate), GFP_KERNEL);
97                 if (!gate) {
98                         clk = ERR_PTR(-ENOMEM);
99                         goto error;
100                 }
101
102                 gate->reg = clk_base + clk_conf->reg_off
103                                 + composite_conf->div_parm.reg_off;
104                 gate->bit_idx = composite_conf->gate_parm.shift;
105                 gate->flags = composite_conf->gate_flags;
106                 gate->lock = &clk_lock;
107         }
108
109         clk = clk_register_composite(NULL, clk_conf->clk_name,
110                                     clk_conf->clks_parent,
111                                     clk_conf->num_parents,
112                                     mux ? &mux->hw : NULL, mux_ops,
113                                     div ? &div->hw : NULL, &clk_divider_ops,
114                                     gate ? &gate->hw : NULL, &clk_gate_ops,
115                                     clk_conf->flags);
116         if (IS_ERR(clk))
117                 goto error;
118
119         return clk;
120
121 error:
122         kfree(gate);
123         kfree(div);
124         kfree(mux);
125
126         return clk;
127 }
128
129 static struct clk * __init
130 meson_clk_register_fixed_factor(const struct clk_conf *clk_conf,
131                                 void __iomem *clk_base)
132 {
133         struct clk *clk;
134         const struct fixed_fact_conf *fixed_fact_conf;
135         const struct parm *p;
136         unsigned int mult, div;
137         u32 reg;
138
139         fixed_fact_conf = &clk_conf->conf.fixed_fact;
140
141         mult = clk_conf->conf.fixed_fact.mult;
142         div = clk_conf->conf.fixed_fact.div;
143
144         if (!mult) {
145                 mult = 1;
146                 p = &fixed_fact_conf->mult_parm;
147                 if (MESON_PARM_APPLICABLE(p)) {
148                         reg = readl(clk_base + clk_conf->reg_off + p->reg_off);
149                         mult = PARM_GET(p->width, p->shift, reg);
150                 }
151         }
152
153         if (!div) {
154                 div = 1;
155                 p = &fixed_fact_conf->div_parm;
156                 if (MESON_PARM_APPLICABLE(p)) {
157                         reg = readl(clk_base + clk_conf->reg_off + p->reg_off);
158                         mult = PARM_GET(p->width, p->shift, reg);
159                 }
160         }
161
162         clk = clk_register_fixed_factor(NULL,
163                         clk_conf->clk_name,
164                         clk_conf->clks_parent[0],
165                         clk_conf->flags,
166                         mult, div);
167
168         return clk;
169 }
170
171 static struct clk * __init
172 meson_clk_register_fixed_rate(const struct clk_conf *clk_conf,
173                               void __iomem *clk_base)
174 {
175         struct clk *clk;
176         const struct fixed_rate_conf *fixed_rate_conf;
177         const struct parm *r;
178         unsigned long rate;
179         u32 reg;
180
181         fixed_rate_conf = &clk_conf->conf.fixed_rate;
182         rate = fixed_rate_conf->rate;
183
184         if (!rate) {
185                 r = &fixed_rate_conf->rate_parm;
186                 reg = readl(clk_base + clk_conf->reg_off + r->reg_off);
187                 rate = PARM_GET(r->width, r->shift, reg);
188         }
189
190         rate *= 1000000;
191
192         clk = clk_register_fixed_rate(NULL,
193                         clk_conf->clk_name,
194                         clk_conf->num_parents
195                                 ? clk_conf->clks_parent[0] : NULL,
196                         clk_conf->flags, rate);
197
198         return clk;
199 }
200
201 void __init meson_clk_register_clks(const struct clk_conf *clk_confs,
202                                     size_t nr_confs,
203                                     void __iomem *clk_base)
204 {
205         unsigned int i;
206         struct clk *clk = NULL;
207
208         for (i = 0; i < nr_confs; i++) {
209                 const struct clk_conf *clk_conf = &clk_confs[i];
210
211                 switch (clk_conf->clk_type) {
212                 case CLK_FIXED_RATE:
213                         clk = meson_clk_register_fixed_rate(clk_conf,
214                                                             clk_base);
215                         break;
216                 case CLK_FIXED_FACTOR:
217                         clk = meson_clk_register_fixed_factor(clk_conf,
218                                                               clk_base);
219                         break;
220                 case CLK_COMPOSITE:
221                         clk = meson_clk_register_composite(clk_conf,
222                                                            clk_base);
223                         break;
224                 case CLK_CPU:
225                         clk = meson_clk_register_cpu(clk_conf, clk_base,
226                                                      &clk_lock);
227                         break;
228                 case CLK_PLL:
229                         clk = meson_clk_register_pll(clk_conf, clk_base,
230                                                      &clk_lock);
231                         break;
232                 default:
233                         clk = NULL;
234                 }
235
236                 if (!clk) {
237                         pr_err("%s: unknown clock type %d\n", __func__,
238                                clk_conf->clk_type);
239                         continue;
240                 }
241
242                 if (IS_ERR(clk)) {
243                         pr_warn("%s: Unable to create %s clock\n", __func__,
244                                 clk_conf->clk_name);
245                         continue;
246                 }
247
248                 meson_clk_add_lookup(clk, clk_conf->clk_id);
249         }
250 }