2 * Copyright (c) 2014 MediaTek Inc.
3 * Author: James Liao <jamesjj.liao@mediatek.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #include <linux/of_address.h>
17 #include <linux/err.h>
19 #include <linux/slab.h>
20 #include <linux/delay.h>
21 #include <linux/clkdev.h>
22 #include <linux/mfd/syscon.h>
27 struct clk_onecell_data
*mtk_alloc_clk_data(unsigned int clk_num
)
30 struct clk_onecell_data
*clk_data
;
32 clk_data
= kzalloc(sizeof(*clk_data
), GFP_KERNEL
);
36 clk_data
->clks
= kcalloc(clk_num
, sizeof(*clk_data
->clks
), GFP_KERNEL
);
40 clk_data
->clk_num
= clk_num
;
42 for (i
= 0; i
< clk_num
; i
++)
43 clk_data
->clks
[i
] = ERR_PTR(-ENOENT
);
52 void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk
*clks
,
53 int num
, struct clk_onecell_data
*clk_data
)
58 for (i
= 0; i
< num
; i
++) {
59 const struct mtk_fixed_clk
*rc
= &clks
[i
];
61 if (clk_data
&& !IS_ERR_OR_NULL(clk_data
->clks
[rc
->id
]))
64 clk
= clk_register_fixed_rate(NULL
, rc
->name
, rc
->parent
, 0,
68 pr_err("Failed to register clk %s: %ld\n",
69 rc
->name
, PTR_ERR(clk
));
74 clk_data
->clks
[rc
->id
] = clk
;
78 void mtk_clk_register_factors(const struct mtk_fixed_factor
*clks
,
79 int num
, struct clk_onecell_data
*clk_data
)
84 for (i
= 0; i
< num
; i
++) {
85 const struct mtk_fixed_factor
*ff
= &clks
[i
];
87 if (clk_data
&& !IS_ERR_OR_NULL(clk_data
->clks
[ff
->id
]))
90 clk
= clk_register_fixed_factor(NULL
, ff
->name
, ff
->parent_name
,
91 CLK_SET_RATE_PARENT
, ff
->mult
, ff
->div
);
94 pr_err("Failed to register clk %s: %ld\n",
95 ff
->name
, PTR_ERR(clk
));
100 clk_data
->clks
[ff
->id
] = clk
;
104 int mtk_clk_register_gates(struct device_node
*node
,
105 const struct mtk_gate
*clks
,
106 int num
, struct clk_onecell_data
*clk_data
)
110 struct regmap
*regmap
;
115 regmap
= syscon_node_to_regmap(node
);
116 if (IS_ERR(regmap
)) {
117 pr_err("Cannot find regmap for %s: %ld\n", node
->full_name
,
119 return PTR_ERR(regmap
);
122 for (i
= 0; i
< num
; i
++) {
123 const struct mtk_gate
*gate
= &clks
[i
];
125 if (!IS_ERR_OR_NULL(clk_data
->clks
[gate
->id
]))
128 clk
= mtk_clk_register_gate(gate
->name
, gate
->parent_name
,
133 gate
->shift
, gate
->ops
);
136 pr_err("Failed to register clk %s: %ld\n",
137 gate
->name
, PTR_ERR(clk
));
141 clk_data
->clks
[gate
->id
] = clk
;
147 struct clk
*mtk_clk_register_composite(const struct mtk_composite
*mc
,
148 void __iomem
*base
, spinlock_t
*lock
)
151 struct clk_mux
*mux
= NULL
;
152 struct clk_gate
*gate
= NULL
;
153 struct clk_divider
*div
= NULL
;
154 struct clk_hw
*mux_hw
= NULL
, *gate_hw
= NULL
, *div_hw
= NULL
;
155 const struct clk_ops
*mux_ops
= NULL
, *gate_ops
= NULL
, *div_ops
= NULL
;
156 const char * const *parent_names
;
161 if (mc
->mux_shift
>= 0) {
162 mux
= kzalloc(sizeof(*mux
), GFP_KERNEL
);
164 return ERR_PTR(-ENOMEM
);
166 mux
->reg
= base
+ mc
->mux_reg
;
167 mux
->mask
= BIT(mc
->mux_width
) - 1;
168 mux
->shift
= mc
->mux_shift
;
172 mux_ops
= &clk_mux_ops
;
174 parent_names
= mc
->parent_names
;
175 num_parents
= mc
->num_parents
;
178 parent_names
= &parent
;
182 if (mc
->gate_shift
>= 0) {
183 gate
= kzalloc(sizeof(*gate
), GFP_KERNEL
);
189 gate
->reg
= base
+ mc
->gate_reg
;
190 gate
->bit_idx
= mc
->gate_shift
;
191 gate
->flags
= CLK_GATE_SET_TO_DISABLE
;
195 gate_ops
= &clk_gate_ops
;
198 if (mc
->divider_shift
>= 0) {
199 div
= kzalloc(sizeof(*div
), GFP_KERNEL
);
205 div
->reg
= base
+ mc
->divider_reg
;
206 div
->shift
= mc
->divider_shift
;
207 div
->width
= mc
->divider_width
;
211 div_ops
= &clk_divider_ops
;
214 clk
= clk_register_composite(NULL
, mc
->name
, parent_names
, num_parents
,
234 void mtk_clk_register_composites(const struct mtk_composite
*mcs
,
235 int num
, void __iomem
*base
, spinlock_t
*lock
,
236 struct clk_onecell_data
*clk_data
)
241 for (i
= 0; i
< num
; i
++) {
242 const struct mtk_composite
*mc
= &mcs
[i
];
244 if (clk_data
&& !IS_ERR_OR_NULL(clk_data
->clks
[mc
->id
]))
247 clk
= mtk_clk_register_composite(mc
, base
, lock
);
250 pr_err("Failed to register clk %s: %ld\n",
251 mc
->name
, PTR_ERR(clk
));
256 clk_data
->clks
[mc
->id
] = clk
;
260 void mtk_clk_register_dividers(const struct mtk_clk_divider
*mcds
,
261 int num
, void __iomem
*base
, spinlock_t
*lock
,
262 struct clk_onecell_data
*clk_data
)
267 for (i
= 0; i
< num
; i
++) {
268 const struct mtk_clk_divider
*mcd
= &mcds
[i
];
270 if (clk_data
&& !IS_ERR_OR_NULL(clk_data
->clks
[mcd
->id
]))
273 clk
= clk_register_divider(NULL
, mcd
->name
, mcd
->parent_name
,
274 mcd
->flags
, base
+ mcd
->div_reg
, mcd
->div_shift
,
275 mcd
->div_width
, mcd
->clk_divider_flags
, lock
);
278 pr_err("Failed to register clk %s: %ld\n",
279 mcd
->name
, PTR_ERR(clk
));
284 clk_data
->clks
[mcd
->id
] = clk
;