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 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
);
22 unsigned long div
= 1;
25 val
= readl(socfpgaclk
->hw
.reg
);
26 val
&= GENMASK(SWCTRLBTCLKSEN_SHIFT
- 1, 0);
29 return parent_rate
/ div
;
32 static unsigned long clk_peri_cnt_clk_recalc_rate(struct clk_hw
*hwclk
,
33 unsigned long parent_rate
)
35 struct socfpga_periph_clk
*socfpgaclk
= to_periph_clk(hwclk
);
36 unsigned long div
= 1;
38 if (socfpgaclk
->fixed_div
) {
39 div
= socfpgaclk
->fixed_div
;
41 if (socfpgaclk
->hw
.reg
)
42 div
= ((readl(socfpgaclk
->hw
.reg
) & 0x7ff) + 1);
45 return parent_rate
/ div
;
48 static u8
clk_periclk_get_parent(struct clk_hw
*hwclk
)
50 struct socfpga_periph_clk
*socfpgaclk
= to_periph_clk(hwclk
);
54 if (socfpgaclk
->bypass_reg
) {
55 mask
= (0x1 << socfpgaclk
->bypass_shift
);
56 parent
= ((readl(socfpgaclk
->bypass_reg
) & mask
) >>
57 socfpgaclk
->bypass_shift
);
59 clk_src
= readl(socfpgaclk
->hw
.reg
);
60 parent
= (clk_src
>> CLK_MGR_FREE_SHIFT
) &
66 static const struct clk_ops peri_c_clk_ops
= {
67 .recalc_rate
= clk_peri_c_clk_recalc_rate
,
68 .get_parent
= clk_periclk_get_parent
,
71 static const struct clk_ops peri_cnt_clk_ops
= {
72 .recalc_rate
= clk_peri_cnt_clk_recalc_rate
,
73 .get_parent
= clk_periclk_get_parent
,
76 struct clk
*s10_register_periph(const struct stratix10_perip_c_clock
*clks
,
80 struct socfpga_periph_clk
*periph_clk
;
81 struct clk_init_data init
;
82 const char *name
= clks
->name
;
83 const char *parent_name
= clks
->parent_name
;
85 periph_clk
= kzalloc(sizeof(*periph_clk
), GFP_KERNEL
);
86 if (WARN_ON(!periph_clk
))
89 periph_clk
->hw
.reg
= reg
+ clks
->offset
;
92 init
.ops
= &peri_c_clk_ops
;
93 init
.flags
= clks
->flags
;
95 init
.num_parents
= clks
->num_parents
;
96 init
.parent_names
= parent_name
? &parent_name
: NULL
;
97 if (init
.parent_names
== NULL
)
98 init
.parent_data
= clks
->parent_data
;
100 periph_clk
->hw
.hw
.init
= &init
;
102 clk
= clk_register(NULL
, &periph_clk
->hw
.hw
);
103 if (WARN_ON(IS_ERR(clk
))) {
110 struct clk
*s10_register_cnt_periph(const struct stratix10_perip_cnt_clock
*clks
,
111 void __iomem
*regbase
)
114 struct socfpga_periph_clk
*periph_clk
;
115 struct clk_init_data init
;
116 const char *name
= clks
->name
;
117 const char *parent_name
= clks
->parent_name
;
119 periph_clk
= kzalloc(sizeof(*periph_clk
), GFP_KERNEL
);
120 if (WARN_ON(!periph_clk
))
124 periph_clk
->hw
.reg
= regbase
+ clks
->offset
;
126 periph_clk
->hw
.reg
= NULL
;
128 if (clks
->bypass_reg
)
129 periph_clk
->bypass_reg
= regbase
+ clks
->bypass_reg
;
131 periph_clk
->bypass_reg
= NULL
;
132 periph_clk
->bypass_shift
= clks
->bypass_shift
;
133 periph_clk
->fixed_div
= clks
->fixed_divider
;
136 init
.ops
= &peri_cnt_clk_ops
;
137 init
.flags
= clks
->flags
;
139 init
.num_parents
= clks
->num_parents
;
140 init
.parent_names
= parent_name
? &parent_name
: NULL
;
141 if (init
.parent_names
== NULL
)
142 init
.parent_data
= clks
->parent_data
;
144 periph_clk
->hw
.hw
.init
= &init
;
146 clk
= clk_register(NULL
, &periph_clk
->hw
.hw
);
147 if (WARN_ON(IS_ERR(clk
))) {