These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / 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-provider.h>
19 #include <linux/mfd/syscon.h>
20 #include <linux/slab.h>
21
22 #include "clkc.h"
23
24 static DEFINE_SPINLOCK(clk_lock);
25
26 static struct clk **clks;
27 static struct clk_onecell_data clk_data;
28
29 struct clk ** __init meson_clk_init(struct device_node *np,
30                                    unsigned long nr_clks)
31 {
32         clks = kcalloc(nr_clks, sizeof(*clks), GFP_KERNEL);
33         if (!clks)
34                 return ERR_PTR(-ENOMEM);
35
36         clk_data.clks = clks;
37         clk_data.clk_num = nr_clks;
38         of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
39
40         return clks;
41 }
42
43 static void meson_clk_add_lookup(struct clk *clk, unsigned int id)
44 {
45         if (clks && id)
46                 clks[id] = clk;
47 }
48
49 static struct clk * __init
50 meson_clk_register_composite(const struct clk_conf *clk_conf,
51                              void __iomem *clk_base)
52 {
53         struct clk *clk;
54         struct clk_mux *mux = NULL;
55         struct clk_divider *div = NULL;
56         struct clk_gate *gate = NULL;
57         const struct clk_ops *mux_ops = NULL;
58         const struct composite_conf *composite_conf;
59
60         composite_conf = clk_conf->conf.composite;
61
62         if (clk_conf->num_parents > 1) {
63                 mux = kzalloc(sizeof(*mux), GFP_KERNEL);
64                 if (!mux)
65                         return ERR_PTR(-ENOMEM);
66
67                 mux->reg = clk_base + clk_conf->reg_off
68                                 + composite_conf->mux_parm.reg_off;
69                 mux->shift = composite_conf->mux_parm.shift;
70                 mux->mask = BIT(composite_conf->mux_parm.width) - 1;
71                 mux->flags = composite_conf->mux_flags;
72                 mux->lock = &clk_lock;
73                 mux->table = composite_conf->mux_table;
74                 mux_ops = (composite_conf->mux_flags & CLK_MUX_READ_ONLY) ?
75                           &clk_mux_ro_ops : &clk_mux_ops;
76         }
77
78         if (MESON_PARM_APPLICABLE(&composite_conf->div_parm)) {
79                 div = kzalloc(sizeof(*div), GFP_KERNEL);
80                 if (!div) {
81                         clk = ERR_PTR(-ENOMEM);
82                         goto error;
83                 }
84
85                 div->reg = clk_base + clk_conf->reg_off
86                                 + composite_conf->div_parm.reg_off;
87                 div->shift = composite_conf->div_parm.shift;
88                 div->width = composite_conf->div_parm.width;
89                 div->lock = &clk_lock;
90                 div->flags = composite_conf->div_flags;
91                 div->table = composite_conf->div_table;
92         }
93
94         if (MESON_PARM_APPLICABLE(&composite_conf->gate_parm)) {
95                 gate = kzalloc(sizeof(*gate), GFP_KERNEL);
96                 if (!gate) {
97                         clk = ERR_PTR(-ENOMEM);
98                         goto error;
99                 }
100
101                 gate->reg = clk_base + clk_conf->reg_off
102                                 + composite_conf->div_parm.reg_off;
103                 gate->bit_idx = composite_conf->gate_parm.shift;
104                 gate->flags = composite_conf->gate_flags;
105                 gate->lock = &clk_lock;
106         }
107
108         clk = clk_register_composite(NULL, clk_conf->clk_name,
109                                     clk_conf->clks_parent,
110                                     clk_conf->num_parents,
111                                     mux ? &mux->hw : NULL, mux_ops,
112                                     div ? &div->hw : NULL, &clk_divider_ops,
113                                     gate ? &gate->hw : NULL, &clk_gate_ops,
114                                     clk_conf->flags);
115         if (IS_ERR(clk))
116                 goto error;
117
118         return clk;
119
120 error:
121         kfree(gate);
122         kfree(div);
123         kfree(mux);
124
125         return clk;
126 }
127
128 static struct clk * __init
129 meson_clk_register_fixed_factor(const struct clk_conf *clk_conf,
130                                 void __iomem *clk_base)
131 {
132         struct clk *clk;
133         const struct fixed_fact_conf *fixed_fact_conf;
134         const struct parm *p;
135         unsigned int mult, div;
136         u32 reg;
137
138         fixed_fact_conf = &clk_conf->conf.fixed_fact;
139
140         mult = clk_conf->conf.fixed_fact.mult;
141         div = clk_conf->conf.fixed_fact.div;
142
143         if (!mult) {
144                 mult = 1;
145                 p = &fixed_fact_conf->mult_parm;
146                 if (MESON_PARM_APPLICABLE(p)) {
147                         reg = readl(clk_base + clk_conf->reg_off + p->reg_off);
148                         mult = PARM_GET(p->width, p->shift, reg);
149                 }
150         }
151
152         if (!div) {
153                 div = 1;
154                 p = &fixed_fact_conf->div_parm;
155                 if (MESON_PARM_APPLICABLE(p)) {
156                         reg = readl(clk_base + clk_conf->reg_off + p->reg_off);
157                         mult = PARM_GET(p->width, p->shift, reg);
158                 }
159         }
160
161         clk = clk_register_fixed_factor(NULL,
162                         clk_conf->clk_name,
163                         clk_conf->clks_parent[0],
164                         clk_conf->flags,
165                         mult, div);
166
167         return clk;
168 }
169
170 static struct clk * __init
171 meson_clk_register_fixed_rate(const struct clk_conf *clk_conf,
172                               void __iomem *clk_base)
173 {
174         struct clk *clk;
175         const struct fixed_rate_conf *fixed_rate_conf;
176         const struct parm *r;
177         unsigned long rate;
178         u32 reg;
179
180         fixed_rate_conf = &clk_conf->conf.fixed_rate;
181         rate = fixed_rate_conf->rate;
182
183         if (!rate) {
184                 r = &fixed_rate_conf->rate_parm;
185                 reg = readl(clk_base + clk_conf->reg_off + r->reg_off);
186                 rate = PARM_GET(r->width, r->shift, reg);
187         }
188
189         rate *= 1000000;
190
191         clk = clk_register_fixed_rate(NULL,
192                         clk_conf->clk_name,
193                         clk_conf->num_parents
194                                 ? clk_conf->clks_parent[0] : NULL,
195                         clk_conf->flags, rate);
196
197         return clk;
198 }
199
200 void __init meson_clk_register_clks(const struct clk_conf *clk_confs,
201                                     size_t nr_confs,
202                                     void __iomem *clk_base)
203 {
204         unsigned int i;
205         struct clk *clk = NULL;
206
207         for (i = 0; i < nr_confs; i++) {
208                 const struct clk_conf *clk_conf = &clk_confs[i];
209
210                 switch (clk_conf->clk_type) {
211                 case CLK_FIXED_RATE:
212                         clk = meson_clk_register_fixed_rate(clk_conf,
213                                                             clk_base);
214                         break;
215                 case CLK_FIXED_FACTOR:
216                         clk = meson_clk_register_fixed_factor(clk_conf,
217                                                               clk_base);
218                         break;
219                 case CLK_COMPOSITE:
220                         clk = meson_clk_register_composite(clk_conf,
221                                                            clk_base);
222                         break;
223                 case CLK_CPU:
224                         clk = meson_clk_register_cpu(clk_conf, clk_base,
225                                                      &clk_lock);
226                         break;
227                 case CLK_PLL:
228                         clk = meson_clk_register_pll(clk_conf, clk_base,
229                                                      &clk_lock);
230                         break;
231                 default:
232                         clk = NULL;
233                 }
234
235                 if (!clk) {
236                         pr_err("%s: unknown clock type %d\n", __func__,
237                                clk_conf->clk_type);
238                         continue;
239                 }
240
241                 if (IS_ERR(clk)) {
242                         pr_warn("%s: Unable to create %s clock\n", __func__,
243                                 clk_conf->clk_name);
244                         continue;
245                 }
246
247                 meson_clk_add_lookup(clk, clk_conf->clk_id);
248         }
249 }