1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2015 Altera Corporation. All rights reserved
5 #include <linux/slab.h>
6 #include <linux/clk-provider.h>
9 #include <linux/of_address.h>
13 /* Clock Manager offsets */
14 #define CLK_MGR_PLL_CLK_SRC_SHIFT 8
15 #define CLK_MGR_PLL_CLK_SRC_MASK 0x3
17 /* Clock bypass bits */
18 #define SOCFPGA_PLL_BG_PWRDWN 0
19 #define SOCFPGA_PLL_PWR_DOWN 1
20 #define SOCFPGA_PLL_EXT_ENA 2
21 #define SOCFPGA_PLL_DIVF_MASK 0x00001FFF
22 #define SOCFPGA_PLL_DIVF_SHIFT 0
23 #define SOCFPGA_PLL_DIVQ_MASK 0x003F0000
24 #define SOCFPGA_PLL_DIVQ_SHIFT 16
25 #define SOCFGPA_MAX_PARENTS 5
27 #define SOCFPGA_MAIN_PLL_CLK "main_pll"
28 #define SOCFPGA_PERIP_PLL_CLK "periph_pll"
30 #define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
32 void __iomem
*clk_mgr_a10_base_addr
;
34 static unsigned long clk_pll_recalc_rate(struct clk_hw
*hwclk
,
35 unsigned long parent_rate
)
37 struct socfpga_pll
*socfpgaclk
= to_socfpga_clk(hwclk
);
38 unsigned long divf
, divq
, reg
;
39 unsigned long long vco_freq
;
41 /* read VCO1 reg for numerator and denominator */
42 reg
= readl(socfpgaclk
->hw
.reg
+ 0x4);
43 divf
= (reg
& SOCFPGA_PLL_DIVF_MASK
) >> SOCFPGA_PLL_DIVF_SHIFT
;
44 divq
= (reg
& SOCFPGA_PLL_DIVQ_MASK
) >> SOCFPGA_PLL_DIVQ_SHIFT
;
45 vco_freq
= (unsigned long long)parent_rate
* (divf
+ 1);
46 do_div(vco_freq
, (1 + divq
));
47 return (unsigned long)vco_freq
;
50 static u8
clk_pll_get_parent(struct clk_hw
*hwclk
)
52 struct socfpga_pll
*socfpgaclk
= to_socfpga_clk(hwclk
);
55 pll_src
= readl(socfpgaclk
->hw
.reg
);
57 return (pll_src
>> CLK_MGR_PLL_CLK_SRC_SHIFT
) &
58 CLK_MGR_PLL_CLK_SRC_MASK
;
61 static const struct clk_ops clk_pll_ops
= {
62 .recalc_rate
= clk_pll_recalc_rate
,
63 .get_parent
= clk_pll_get_parent
,
66 static struct clk
* __init
__socfpga_pll_init(struct device_node
*node
,
67 const struct clk_ops
*ops
)
71 struct socfpga_pll
*pll_clk
;
72 const char *clk_name
= node
->name
;
73 const char *parent_name
[SOCFGPA_MAX_PARENTS
];
74 struct clk_init_data init
;
75 struct device_node
*clkmgr_np
;
79 of_property_read_u32(node
, "reg", ®
);
81 pll_clk
= kzalloc(sizeof(*pll_clk
), GFP_KERNEL
);
82 if (WARN_ON(!pll_clk
))
85 clkmgr_np
= of_find_compatible_node(NULL
, NULL
, "altr,clk-mgr");
86 clk_mgr_a10_base_addr
= of_iomap(clkmgr_np
, 0);
87 of_node_put(clkmgr_np
);
88 BUG_ON(!clk_mgr_a10_base_addr
);
89 pll_clk
->hw
.reg
= clk_mgr_a10_base_addr
+ reg
;
91 of_property_read_string(node
, "clock-output-names", &clk_name
);
97 while (i
< SOCFGPA_MAX_PARENTS
&& (parent_name
[i
] =
98 of_clk_get_parent_name(node
, i
)) != NULL
)
100 init
.num_parents
= i
;
101 init
.parent_names
= parent_name
;
102 pll_clk
->hw
.hw
.init
= &init
;
104 pll_clk
->hw
.bit_idx
= SOCFPGA_PLL_EXT_ENA
;
106 clk
= clk_register(NULL
, &pll_clk
->hw
.hw
);
107 if (WARN_ON(IS_ERR(clk
))) {
111 rc
= of_clk_add_provider(node
, of_clk_src_simple_get
, clk
);
115 void __init
socfpga_a10_pll_init(struct device_node
*node
)
117 __socfpga_pll_init(node
, &clk_pll_ops
);