module: Convert symbol namespace to string literal
[linux.git] / drivers / clk / meson / a1-pll.c
blob8d7c7b4493c4069bbceb5e04a7f1e312931d119b
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
4 * Author: Jian Hu <jian.hu@amlogic.com>
6 * Copyright (c) 2023, SberDevices. All Rights Reserved.
7 * Author: Dmitry Rokosov <ddrokosov@sberdevices.ru>
8 */
10 #include <linux/clk-provider.h>
11 #include <linux/mod_devicetable.h>
12 #include <linux/platform_device.h>
13 #include "a1-pll.h"
14 #include "clk-regmap.h"
15 #include "meson-clkc-utils.h"
17 #include <dt-bindings/clock/amlogic,a1-pll-clkc.h>
19 static struct clk_regmap fixed_pll_dco = {
20 .data = &(struct meson_clk_pll_data){
21 .en = {
22 .reg_off = ANACTRL_FIXPLL_CTRL0,
23 .shift = 28,
24 .width = 1,
26 .m = {
27 .reg_off = ANACTRL_FIXPLL_CTRL0,
28 .shift = 0,
29 .width = 8,
31 .n = {
32 .reg_off = ANACTRL_FIXPLL_CTRL0,
33 .shift = 10,
34 .width = 5,
36 .frac = {
37 .reg_off = ANACTRL_FIXPLL_CTRL1,
38 .shift = 0,
39 .width = 19,
41 .l = {
42 .reg_off = ANACTRL_FIXPLL_STS,
43 .shift = 31,
44 .width = 1,
46 .rst = {
47 .reg_off = ANACTRL_FIXPLL_CTRL0,
48 .shift = 29,
49 .width = 1,
52 .hw.init = &(struct clk_init_data){
53 .name = "fixed_pll_dco",
54 .ops = &meson_clk_pll_ro_ops,
55 .parent_data = &(const struct clk_parent_data) {
56 .fw_name = "fixpll_in",
58 .num_parents = 1,
62 static struct clk_regmap fixed_pll = {
63 .data = &(struct clk_regmap_gate_data){
64 .offset = ANACTRL_FIXPLL_CTRL0,
65 .bit_idx = 20,
67 .hw.init = &(struct clk_init_data) {
68 .name = "fixed_pll",
69 .ops = &clk_regmap_gate_ops,
70 .parent_hws = (const struct clk_hw *[]) {
71 &fixed_pll_dco.hw
73 .num_parents = 1,
77 static const struct pll_mult_range hifi_pll_mult_range = {
78 .min = 32,
79 .max = 64,
82 static const struct reg_sequence hifi_init_regs[] = {
83 { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 },
84 { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
85 { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 },
86 { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 },
87 { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18000 },
90 static struct clk_regmap hifi_pll = {
91 .data = &(struct meson_clk_pll_data){
92 .en = {
93 .reg_off = ANACTRL_HIFIPLL_CTRL0,
94 .shift = 28,
95 .width = 1,
97 .m = {
98 .reg_off = ANACTRL_HIFIPLL_CTRL0,
99 .shift = 0,
100 .width = 8,
102 .n = {
103 .reg_off = ANACTRL_HIFIPLL_CTRL0,
104 .shift = 10,
105 .width = 5,
107 .frac = {
108 .reg_off = ANACTRL_HIFIPLL_CTRL1,
109 .shift = 0,
110 .width = 19,
112 .l = {
113 .reg_off = ANACTRL_HIFIPLL_STS,
114 .shift = 31,
115 .width = 1,
117 .current_en = {
118 .reg_off = ANACTRL_HIFIPLL_CTRL0,
119 .shift = 26,
120 .width = 1,
122 .l_detect = {
123 .reg_off = ANACTRL_HIFIPLL_CTRL2,
124 .shift = 6,
125 .width = 1,
127 .range = &hifi_pll_mult_range,
128 .init_regs = hifi_init_regs,
129 .init_count = ARRAY_SIZE(hifi_init_regs),
131 .hw.init = &(struct clk_init_data){
132 .name = "hifi_pll",
133 .ops = &meson_clk_pll_ops,
134 .parent_data = &(const struct clk_parent_data) {
135 .fw_name = "hifipll_in",
137 .num_parents = 1,
141 static struct clk_fixed_factor fclk_div2_div = {
142 .mult = 1,
143 .div = 2,
144 .hw.init = &(struct clk_init_data){
145 .name = "fclk_div2_div",
146 .ops = &clk_fixed_factor_ops,
147 .parent_hws = (const struct clk_hw *[]) {
148 &fixed_pll.hw
150 .num_parents = 1,
154 static struct clk_regmap fclk_div2 = {
155 .data = &(struct clk_regmap_gate_data){
156 .offset = ANACTRL_FIXPLL_CTRL0,
157 .bit_idx = 21,
159 .hw.init = &(struct clk_init_data){
160 .name = "fclk_div2",
161 .ops = &clk_regmap_gate_ops,
162 .parent_hws = (const struct clk_hw *[]) {
163 &fclk_div2_div.hw
165 .num_parents = 1,
167 * This clock is used by DDR clock in BL2 firmware
168 * and is required by the platform to operate correctly.
169 * Until the following condition are met, we need this clock to
170 * be marked as critical:
171 * a) Mark the clock used by a firmware resource, if possible
172 * b) CCF has a clock hand-off mechanism to make the sure the
173 * clock stays on until the proper driver comes along
175 .flags = CLK_IS_CRITICAL,
179 static struct clk_fixed_factor fclk_div3_div = {
180 .mult = 1,
181 .div = 3,
182 .hw.init = &(struct clk_init_data){
183 .name = "fclk_div3_div",
184 .ops = &clk_fixed_factor_ops,
185 .parent_hws = (const struct clk_hw *[]) {
186 &fixed_pll.hw
188 .num_parents = 1,
192 static struct clk_regmap fclk_div3 = {
193 .data = &(struct clk_regmap_gate_data){
194 .offset = ANACTRL_FIXPLL_CTRL0,
195 .bit_idx = 22,
197 .hw.init = &(struct clk_init_data){
198 .name = "fclk_div3",
199 .ops = &clk_regmap_gate_ops,
200 .parent_hws = (const struct clk_hw *[]) {
201 &fclk_div3_div.hw
203 .num_parents = 1,
205 * This clock is used by APB bus which is set in boot ROM code
206 * and is required by the platform to operate correctly.
208 .flags = CLK_IS_CRITICAL,
212 static struct clk_fixed_factor fclk_div5_div = {
213 .mult = 1,
214 .div = 5,
215 .hw.init = &(struct clk_init_data){
216 .name = "fclk_div5_div",
217 .ops = &clk_fixed_factor_ops,
218 .parent_hws = (const struct clk_hw *[]) {
219 &fixed_pll.hw
221 .num_parents = 1,
225 static struct clk_regmap fclk_div5 = {
226 .data = &(struct clk_regmap_gate_data){
227 .offset = ANACTRL_FIXPLL_CTRL0,
228 .bit_idx = 23,
230 .hw.init = &(struct clk_init_data){
231 .name = "fclk_div5",
232 .ops = &clk_regmap_gate_ops,
233 .parent_hws = (const struct clk_hw *[]) {
234 &fclk_div5_div.hw
236 .num_parents = 1,
238 * This clock is used by AXI bus which setted in Romcode
239 * and is required by the platform to operate correctly.
241 .flags = CLK_IS_CRITICAL,
245 static struct clk_fixed_factor fclk_div7_div = {
246 .mult = 1,
247 .div = 7,
248 .hw.init = &(struct clk_init_data){
249 .name = "fclk_div7_div",
250 .ops = &clk_fixed_factor_ops,
251 .parent_hws = (const struct clk_hw *[]) {
252 &fixed_pll.hw
254 .num_parents = 1,
258 static struct clk_regmap fclk_div7 = {
259 .data = &(struct clk_regmap_gate_data){
260 .offset = ANACTRL_FIXPLL_CTRL0,
261 .bit_idx = 24,
263 .hw.init = &(struct clk_init_data){
264 .name = "fclk_div7",
265 .ops = &clk_regmap_gate_ops,
266 .parent_hws = (const struct clk_hw *[]) {
267 &fclk_div7_div.hw
269 .num_parents = 1,
273 /* Array of all clocks registered by this provider */
274 static struct clk_hw *a1_pll_hw_clks[] = {
275 [CLKID_FIXED_PLL_DCO] = &fixed_pll_dco.hw,
276 [CLKID_FIXED_PLL] = &fixed_pll.hw,
277 [CLKID_FCLK_DIV2_DIV] = &fclk_div2_div.hw,
278 [CLKID_FCLK_DIV3_DIV] = &fclk_div3_div.hw,
279 [CLKID_FCLK_DIV5_DIV] = &fclk_div5_div.hw,
280 [CLKID_FCLK_DIV7_DIV] = &fclk_div7_div.hw,
281 [CLKID_FCLK_DIV2] = &fclk_div2.hw,
282 [CLKID_FCLK_DIV3] = &fclk_div3.hw,
283 [CLKID_FCLK_DIV5] = &fclk_div5.hw,
284 [CLKID_FCLK_DIV7] = &fclk_div7.hw,
285 [CLKID_HIFI_PLL] = &hifi_pll.hw,
288 static struct clk_regmap *const a1_pll_regmaps[] = {
289 &fixed_pll_dco,
290 &fixed_pll,
291 &fclk_div2,
292 &fclk_div3,
293 &fclk_div5,
294 &fclk_div7,
295 &hifi_pll,
298 static const struct regmap_config a1_pll_regmap_cfg = {
299 .reg_bits = 32,
300 .val_bits = 32,
301 .reg_stride = 4,
302 .max_register = ANACTRL_HIFIPLL_STS,
305 static struct meson_clk_hw_data a1_pll_clks = {
306 .hws = a1_pll_hw_clks,
307 .num = ARRAY_SIZE(a1_pll_hw_clks),
310 static int meson_a1_pll_probe(struct platform_device *pdev)
312 struct device *dev = &pdev->dev;
313 void __iomem *base;
314 struct regmap *map;
315 int clkid, i, err;
317 base = devm_platform_ioremap_resource(pdev, 0);
318 if (IS_ERR(base))
319 return dev_err_probe(dev, PTR_ERR(base),
320 "can't ioremap resource\n");
322 map = devm_regmap_init_mmio(dev, base, &a1_pll_regmap_cfg);
323 if (IS_ERR(map))
324 return dev_err_probe(dev, PTR_ERR(map),
325 "can't init regmap mmio region\n");
327 /* Populate regmap for the regmap backed clocks */
328 for (i = 0; i < ARRAY_SIZE(a1_pll_regmaps); i++)
329 a1_pll_regmaps[i]->map = map;
331 /* Register clocks */
332 for (clkid = 0; clkid < a1_pll_clks.num; clkid++) {
333 err = devm_clk_hw_register(dev, a1_pll_clks.hws[clkid]);
334 if (err)
335 return dev_err_probe(dev, err,
336 "clock[%d] registration failed\n",
337 clkid);
340 return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get,
341 &a1_pll_clks);
344 static const struct of_device_id a1_pll_clkc_match_table[] = {
345 { .compatible = "amlogic,a1-pll-clkc", },
348 MODULE_DEVICE_TABLE(of, a1_pll_clkc_match_table);
350 static struct platform_driver a1_pll_clkc_driver = {
351 .probe = meson_a1_pll_probe,
352 .driver = {
353 .name = "a1-pll-clkc",
354 .of_match_table = a1_pll_clkc_match_table,
357 module_platform_driver(a1_pll_clkc_driver);
359 MODULE_DESCRIPTION("Amlogic S4 PLL Clock Controller driver");
360 MODULE_AUTHOR("Jian Hu <jian.hu@amlogic.com>");
361 MODULE_AUTHOR("Dmitry Rokosov <ddrokosov@sberdevices.ru>");
362 MODULE_LICENSE("GPL");
363 MODULE_IMPORT_NS("CLK_MESON");