2 * Copyright (c) 2015 Endless Mobile, Inc.
3 * Author: Carlo Caione <carlo@endlessm.com>
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.
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
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/>.
18 #include <linux/clk-provider.h>
19 #include <linux/mfd/syscon.h>
20 #include <linux/slab.h>
24 static DEFINE_SPINLOCK(clk_lock
);
26 static struct clk
**clks
;
27 static struct clk_onecell_data clk_data
;
29 struct clk
** __init
meson_clk_init(struct device_node
*np
,
30 unsigned long nr_clks
)
32 clks
= kcalloc(nr_clks
, sizeof(*clks
), GFP_KERNEL
);
34 return ERR_PTR(-ENOMEM
);
37 clk_data
.clk_num
= nr_clks
;
38 of_clk_add_provider(np
, of_clk_src_onecell_get
, &clk_data
);
43 static void meson_clk_add_lookup(struct clk
*clk
, unsigned int id
)
49 static struct clk
* __init
50 meson_clk_register_composite(const struct clk_conf
*clk_conf
,
51 void __iomem
*clk_base
)
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
;
60 composite_conf
= clk_conf
->conf
.composite
;
62 if (clk_conf
->num_parents
> 1) {
63 mux
= kzalloc(sizeof(*mux
), GFP_KERNEL
);
65 return ERR_PTR(-ENOMEM
);
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
;
78 if (MESON_PARM_APPLICABLE(&composite_conf
->div_parm
)) {
79 div
= kzalloc(sizeof(*div
), GFP_KERNEL
);
81 clk
= ERR_PTR(-ENOMEM
);
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
;
94 if (MESON_PARM_APPLICABLE(&composite_conf
->gate_parm
)) {
95 gate
= kzalloc(sizeof(*gate
), GFP_KERNEL
);
97 clk
= ERR_PTR(-ENOMEM
);
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
;
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
,
128 static struct clk
* __init
129 meson_clk_register_fixed_factor(const struct clk_conf
*clk_conf
,
130 void __iomem
*clk_base
)
133 const struct fixed_fact_conf
*fixed_fact_conf
;
134 const struct parm
*p
;
135 unsigned int mult
, div
;
138 fixed_fact_conf
= &clk_conf
->conf
.fixed_fact
;
140 mult
= clk_conf
->conf
.fixed_fact
.mult
;
141 div
= clk_conf
->conf
.fixed_fact
.div
;
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
);
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
);
161 clk
= clk_register_fixed_factor(NULL
,
163 clk_conf
->clks_parent
[0],
170 static struct clk
* __init
171 meson_clk_register_fixed_rate(const struct clk_conf
*clk_conf
,
172 void __iomem
*clk_base
)
175 const struct fixed_rate_conf
*fixed_rate_conf
;
176 const struct parm
*r
;
180 fixed_rate_conf
= &clk_conf
->conf
.fixed_rate
;
181 rate
= fixed_rate_conf
->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
);
191 clk
= clk_register_fixed_rate(NULL
,
193 clk_conf
->num_parents
194 ? clk_conf
->clks_parent
[0] : NULL
,
195 clk_conf
->flags
, rate
);
200 void __init
meson_clk_register_clks(const struct clk_conf
*clk_confs
,
201 unsigned int nr_confs
,
202 void __iomem
*clk_base
)
205 struct clk
*clk
= NULL
;
207 for (i
= 0; i
< nr_confs
; i
++) {
208 const struct clk_conf
*clk_conf
= &clk_confs
[i
];
210 switch (clk_conf
->clk_type
) {
212 clk
= meson_clk_register_fixed_rate(clk_conf
,
215 case CLK_FIXED_FACTOR
:
216 clk
= meson_clk_register_fixed_factor(clk_conf
,
220 clk
= meson_clk_register_composite(clk_conf
,
224 clk
= meson_clk_register_cpu(clk_conf
, clk_base
,
228 clk
= meson_clk_register_pll(clk_conf
, clk_base
,
236 pr_err("%s: unknown clock type %d\n", __func__
,
242 pr_warn("%s: Unable to create %s clock\n", __func__
,
247 meson_clk_add_lookup(clk
, clk_conf
->clk_id
);