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
;
84 const char * const *parent_names
= clks
->parent_names
;
86 periph_clk
= kzalloc(sizeof(*periph_clk
), GFP_KERNEL
);
87 if (WARN_ON(!periph_clk
))
90 periph_clk
->hw
.reg
= reg
+ clks
->offset
;
93 init
.ops
= &peri_c_clk_ops
;
94 init
.flags
= clks
->flags
;
96 init
.num_parents
= clks
->num_parents
;
97 init
.parent_names
= parent_names
? parent_names
: &parent_name
;
99 periph_clk
->hw
.hw
.init
= &init
;
101 clk
= clk_register(NULL
, &periph_clk
->hw
.hw
);
102 if (WARN_ON(IS_ERR(clk
))) {
109 struct clk
*s10_register_cnt_periph(const struct stratix10_perip_cnt_clock
*clks
,
110 void __iomem
*regbase
)
113 struct socfpga_periph_clk
*periph_clk
;
114 struct clk_init_data init
;
115 const char *name
= clks
->name
;
116 const char *parent_name
= clks
->parent_name
;
117 const char * const *parent_names
= clks
->parent_names
;
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_names
? parent_names
: &parent_name
;
142 periph_clk
->hw
.hw
.init
= &init
;
144 clk
= clk_register(NULL
, &periph_clk
->hw
.hw
);
145 if (WARN_ON(IS_ERR(clk
))) {