2 * Copyright (c) 2014 MundoReader S.L.
3 * Author: Heiko Stuebner <heiko@sntech.de>
8 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
9 * Copyright (c) 2013 Linaro Ltd.
10 * Author: Thomas Abraham <thomas.ab@samsung.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
23 #include <linux/slab.h>
24 #include <linux/clk.h>
25 #include <linux/clk-provider.h>
26 #include <linux/mfd/syscon.h>
27 #include <linux/regmap.h>
31 * Register a clock branch.
32 * Most clock branches have a form like
38 * sometimes without one of those components.
40 struct clk
*rockchip_clk_register_branch(const char *name
,
41 const char **parent_names
, u8 num_parents
, void __iomem
*base
,
42 int muxdiv_offset
, u8 mux_shift
, u8 mux_width
, u8 mux_flags
,
43 u8 div_shift
, u8 div_width
, u8 div_flags
,
44 struct clk_div_table
*div_table
, int gate_offset
,
45 u8 gate_shift
, u8 gate_flags
, unsigned long flags
,
49 struct clk_mux
*mux
= NULL
;
50 struct clk_gate
*gate
= NULL
;
51 struct clk_divider
*div
= NULL
;
52 const struct clk_ops
*mux_ops
= NULL
, *div_ops
= NULL
,
55 if (num_parents
> 1) {
56 mux
= kzalloc(sizeof(*mux
), GFP_KERNEL
);
58 return ERR_PTR(-ENOMEM
);
60 mux
->reg
= base
+ muxdiv_offset
;
61 mux
->shift
= mux_shift
;
62 mux
->mask
= BIT(mux_width
) - 1;
63 mux
->flags
= mux_flags
;
65 mux_ops
= (mux_flags
& CLK_MUX_READ_ONLY
) ? &clk_mux_ro_ops
69 if (gate_offset
>= 0) {
70 gate
= kzalloc(sizeof(*gate
), GFP_KERNEL
);
72 return ERR_PTR(-ENOMEM
);
74 gate
->flags
= gate_flags
;
75 gate
->reg
= base
+ gate_offset
;
76 gate
->bit_idx
= gate_shift
;
78 gate_ops
= &clk_gate_ops
;
82 div
= kzalloc(sizeof(*div
), GFP_KERNEL
);
84 return ERR_PTR(-ENOMEM
);
86 div
->flags
= div_flags
;
87 div
->reg
= base
+ muxdiv_offset
;
88 div
->shift
= div_shift
;
89 div
->width
= div_width
;
91 div
->table
= div_table
;
92 div_ops
= (div_flags
& CLK_DIVIDER_READ_ONLY
)
97 clk
= clk_register_composite(NULL
, name
, parent_names
, num_parents
,
98 mux
? &mux
->hw
: NULL
, mux_ops
,
99 div
? &div
->hw
: NULL
, div_ops
,
100 gate
? &gate
->hw
: NULL
, gate_ops
,
106 static DEFINE_SPINLOCK(clk_lock
);
107 static struct clk
**clk_table
;
108 static void __iomem
*reg_base
;
109 static struct clk_onecell_data clk_data
;
110 static struct device_node
*cru_node
;
111 static struct regmap
*grf
;
113 void __init
rockchip_clk_init(struct device_node
*np
, void __iomem
*base
,
114 unsigned long nr_clks
)
118 grf
= ERR_PTR(-EPROBE_DEFER
);
120 clk_table
= kcalloc(nr_clks
, sizeof(struct clk
*), GFP_KERNEL
);
122 pr_err("%s: could not allocate clock lookup table\n", __func__
);
124 clk_data
.clks
= clk_table
;
125 clk_data
.clk_num
= nr_clks
;
126 of_clk_add_provider(np
, of_clk_src_onecell_get
, &clk_data
);
129 struct regmap
*rockchip_clk_get_grf(void)
132 grf
= syscon_regmap_lookup_by_phandle(cru_node
, "rockchip,grf");
136 void rockchip_clk_add_lookup(struct clk
*clk
, unsigned int id
)
142 void __init
rockchip_clk_register_plls(struct rockchip_pll_clock
*list
,
143 unsigned int nr_pll
, int grf_lock_offset
)
148 for (idx
= 0; idx
< nr_pll
; idx
++, list
++) {
149 clk
= rockchip_clk_register_pll(list
->type
, list
->name
,
150 list
->parent_names
, list
->num_parents
,
151 reg_base
, list
->con_offset
, grf_lock_offset
,
152 list
->lock_shift
, list
->mode_offset
,
153 list
->mode_shift
, list
->rate_table
, &clk_lock
);
155 pr_err("%s: failed to register clock %s\n", __func__
,
160 rockchip_clk_add_lookup(clk
, list
->id
);
164 void __init
rockchip_clk_register_branches(
165 struct rockchip_clk_branch
*list
,
168 struct clk
*clk
= NULL
;
172 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
175 /* catch simple muxes */
176 switch (list
->branch_type
) {
178 clk
= clk_register_mux(NULL
, list
->name
,
179 list
->parent_names
, list
->num_parents
,
180 flags
, reg_base
+ list
->muxdiv_offset
,
181 list
->mux_shift
, list
->mux_width
,
182 list
->mux_flags
, &clk_lock
);
186 clk
= clk_register_divider_table(NULL
,
187 list
->name
, list
->parent_names
[0],
188 flags
, reg_base
+ list
->muxdiv_offset
,
189 list
->div_shift
, list
->div_width
,
190 list
->div_flags
, list
->div_table
,
193 clk
= clk_register_divider(NULL
, list
->name
,
194 list
->parent_names
[0], flags
,
195 reg_base
+ list
->muxdiv_offset
,
196 list
->div_shift
, list
->div_width
,
197 list
->div_flags
, &clk_lock
);
199 case branch_fraction_divider
:
204 flags
|= CLK_SET_RATE_PARENT
;
206 /* keep all gates untouched for now */
207 flags
|= CLK_IGNORE_UNUSED
;
209 clk
= clk_register_gate(NULL
, list
->name
,
210 list
->parent_names
[0], flags
,
211 reg_base
+ list
->gate_offset
,
212 list
->gate_shift
, list
->gate_flags
, &clk_lock
);
214 case branch_composite
:
215 /* keep all gates untouched for now */
216 flags
|= CLK_IGNORE_UNUSED
;
218 clk
= rockchip_clk_register_branch(list
->name
,
219 list
->parent_names
, list
->num_parents
,
220 reg_base
, list
->muxdiv_offset
, list
->mux_shift
,
221 list
->mux_width
, list
->mux_flags
,
222 list
->div_shift
, list
->div_width
,
223 list
->div_flags
, list
->div_table
,
224 list
->gate_offset
, list
->gate_shift
,
225 list
->gate_flags
, flags
, &clk_lock
);
229 /* none of the cases above matched */
231 pr_err("%s: unknown clock type %d\n",
232 __func__
, list
->branch_type
);
237 pr_err("%s: failed to register clock %s: %ld\n",
238 __func__
, list
->name
, PTR_ERR(clk
));
242 rockchip_clk_add_lookup(clk
, list
->id
);