1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2017, Intel Corporation
5 #include <linux/slab.h>
6 #include <linux/clk-provider.h>
9 #include "stratix10-clk.h"
12 #define CLK_MGR_FREE_SHIFT 16
13 #define CLK_MGR_FREE_MASK 0x7
14 #define SWCTRLBTCLKSEN_SHIFT 8
16 #define to_periph_clk(p) container_of(p, struct socfpga_periph_clk, hw.hw)
18 static unsigned long n5x_clk_peri_c_clk_recalc_rate(struct clk_hw
*hwclk
,
19 unsigned long parent_rate
)
21 struct socfpga_periph_clk
*socfpgaclk
= to_periph_clk(hwclk
);
23 unsigned long shift
= socfpgaclk
->shift
;
26 val
= readl(socfpgaclk
->hw
.reg
);
27 val
&= (0x1f << shift
);
28 div
= (val
>> shift
) + 1;
30 return parent_rate
/ div
;
33 static unsigned long clk_peri_c_clk_recalc_rate(struct clk_hw
*hwclk
,
34 unsigned long parent_rate
)
36 struct socfpga_periph_clk
*socfpgaclk
= to_periph_clk(hwclk
);
37 unsigned long div
= 1;
40 val
= readl(socfpgaclk
->hw
.reg
);
41 val
&= GENMASK(SWCTRLBTCLKSEN_SHIFT
- 1, 0);
44 return parent_rate
/ div
;
47 static unsigned long clk_peri_cnt_clk_recalc_rate(struct clk_hw
*hwclk
,
48 unsigned long parent_rate
)
50 struct socfpga_periph_clk
*socfpgaclk
= to_periph_clk(hwclk
);
51 unsigned long div
= 1;
53 if (socfpgaclk
->fixed_div
) {
54 div
= socfpgaclk
->fixed_div
;
56 if (socfpgaclk
->hw
.reg
)
57 div
= ((readl(socfpgaclk
->hw
.reg
) & 0x7ff) + 1);
60 return parent_rate
/ div
;
63 static u8
clk_periclk_get_parent(struct clk_hw
*hwclk
)
65 struct socfpga_periph_clk
*socfpgaclk
= to_periph_clk(hwclk
);
69 /* handle the bypass first */
70 if (socfpgaclk
->bypass_reg
) {
71 mask
= (0x1 << socfpgaclk
->bypass_shift
);
72 parent
= ((readl(socfpgaclk
->bypass_reg
) & mask
) >>
73 socfpgaclk
->bypass_shift
);
78 if (socfpgaclk
->hw
.reg
) {
79 clk_src
= readl(socfpgaclk
->hw
.reg
);
80 parent
= (clk_src
>> CLK_MGR_FREE_SHIFT
) &
86 static const struct clk_ops n5x_peri_c_clk_ops
= {
87 .recalc_rate
= n5x_clk_peri_c_clk_recalc_rate
,
88 .get_parent
= clk_periclk_get_parent
,
91 static const struct clk_ops peri_c_clk_ops
= {
92 .recalc_rate
= clk_peri_c_clk_recalc_rate
,
93 .get_parent
= clk_periclk_get_parent
,
96 static const struct clk_ops peri_cnt_clk_ops
= {
97 .recalc_rate
= clk_peri_cnt_clk_recalc_rate
,
98 .get_parent
= clk_periclk_get_parent
,
101 struct clk_hw
*s10_register_periph(const struct stratix10_perip_c_clock
*clks
,
104 struct clk_hw
*hw_clk
;
105 struct socfpga_periph_clk
*periph_clk
;
106 struct clk_init_data init
;
107 const char *name
= clks
->name
;
108 const char *parent_name
= clks
->parent_name
;
111 periph_clk
= kzalloc(sizeof(*periph_clk
), GFP_KERNEL
);
112 if (WARN_ON(!periph_clk
))
115 periph_clk
->hw
.reg
= reg
+ clks
->offset
;
118 init
.ops
= &peri_c_clk_ops
;
119 init
.flags
= clks
->flags
;
121 init
.num_parents
= clks
->num_parents
;
122 init
.parent_names
= parent_name
? &parent_name
: NULL
;
123 if (init
.parent_names
== NULL
)
124 init
.parent_data
= clks
->parent_data
;
126 periph_clk
->hw
.hw
.init
= &init
;
127 hw_clk
= &periph_clk
->hw
.hw
;
129 ret
= clk_hw_register(NULL
, hw_clk
);
137 struct clk_hw
*n5x_register_periph(const struct n5x_perip_c_clock
*clks
,
138 void __iomem
*regbase
)
140 struct clk_hw
*hw_clk
;
141 struct socfpga_periph_clk
*periph_clk
;
142 struct clk_init_data init
;
143 const char *name
= clks
->name
;
144 const char *parent_name
= clks
->parent_name
;
147 periph_clk
= kzalloc(sizeof(*periph_clk
), GFP_KERNEL
);
148 if (WARN_ON(!periph_clk
))
151 periph_clk
->hw
.reg
= regbase
+ clks
->offset
;
152 periph_clk
->shift
= clks
->shift
;
155 init
.ops
= &n5x_peri_c_clk_ops
;
156 init
.flags
= clks
->flags
;
158 init
.num_parents
= clks
->num_parents
;
159 init
.parent_names
= parent_name
? &parent_name
: NULL
;
161 periph_clk
->hw
.hw
.init
= &init
;
162 hw_clk
= &periph_clk
->hw
.hw
;
164 ret
= clk_hw_register(NULL
, hw_clk
);
172 struct clk_hw
*s10_register_cnt_periph(const struct stratix10_perip_cnt_clock
*clks
,
173 void __iomem
*regbase
)
175 struct clk_hw
*hw_clk
;
176 struct socfpga_periph_clk
*periph_clk
;
177 struct clk_init_data init
;
178 const char *name
= clks
->name
;
179 const char *parent_name
= clks
->parent_name
;
182 periph_clk
= kzalloc(sizeof(*periph_clk
), GFP_KERNEL
);
183 if (WARN_ON(!periph_clk
))
187 periph_clk
->hw
.reg
= regbase
+ clks
->offset
;
189 periph_clk
->hw
.reg
= NULL
;
191 if (clks
->bypass_reg
)
192 periph_clk
->bypass_reg
= regbase
+ clks
->bypass_reg
;
194 periph_clk
->bypass_reg
= NULL
;
195 periph_clk
->bypass_shift
= clks
->bypass_shift
;
196 periph_clk
->fixed_div
= clks
->fixed_divider
;
199 init
.ops
= &peri_cnt_clk_ops
;
200 init
.flags
= clks
->flags
;
202 init
.num_parents
= clks
->num_parents
;
203 init
.parent_names
= parent_name
? &parent_name
: NULL
;
204 if (init
.parent_names
== NULL
)
205 init
.parent_data
= clks
->parent_data
;
207 periph_clk
->hw
.hw
.init
= &init
;
208 hw_clk
= &periph_clk
->hw
.hw
;
210 ret
= clk_hw_register(NULL
, hw_clk
);