1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2017, Intel Corporation
5 #include <linux/clk-provider.h>
7 #include <linux/slab.h>
8 #include "stratix10-clk.h"
11 #define SOCFPGA_CS_PDBG_CLK "cs_pdbg_clk"
12 #define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw)
14 static unsigned long socfpga_gate_clk_recalc_rate(struct clk_hw
*hwclk
,
15 unsigned long parent_rate
)
17 struct socfpga_gate_clk
*socfpgaclk
= to_socfpga_gate_clk(hwclk
);
20 if (socfpgaclk
->fixed_div
) {
21 div
= socfpgaclk
->fixed_div
;
22 } else if (socfpgaclk
->div_reg
) {
23 val
= readl(socfpgaclk
->div_reg
) >> socfpgaclk
->shift
;
24 val
&= GENMASK(socfpgaclk
->width
- 1, 0);
27 return parent_rate
/ div
;
30 static unsigned long socfpga_dbg_clk_recalc_rate(struct clk_hw
*hwclk
,
31 unsigned long parent_rate
)
33 struct socfpga_gate_clk
*socfpgaclk
= to_socfpga_gate_clk(hwclk
);
36 val
= readl(socfpgaclk
->div_reg
) >> socfpgaclk
->shift
;
37 val
&= GENMASK(socfpgaclk
->width
- 1, 0);
41 return parent_rate
/ div
;
44 static u8
socfpga_gate_get_parent(struct clk_hw
*hwclk
)
46 struct socfpga_gate_clk
*socfpgaclk
= to_socfpga_gate_clk(hwclk
);
50 if (socfpgaclk
->bypass_reg
) {
51 mask
= (0x1 << socfpgaclk
->bypass_shift
);
52 parent
= ((readl(socfpgaclk
->bypass_reg
) & mask
) >>
53 socfpgaclk
->bypass_shift
);
58 static struct clk_ops gateclk_ops
= {
59 .recalc_rate
= socfpga_gate_clk_recalc_rate
,
60 .get_parent
= socfpga_gate_get_parent
,
63 static const struct clk_ops dbgclk_ops
= {
64 .recalc_rate
= socfpga_dbg_clk_recalc_rate
,
65 .get_parent
= socfpga_gate_get_parent
,
68 struct clk
*s10_register_gate(const struct stratix10_gate_clock
*clks
, void __iomem
*regbase
)
71 struct socfpga_gate_clk
*socfpga_clk
;
72 struct clk_init_data init
;
73 const char *parent_name
= clks
->parent_name
;
75 socfpga_clk
= kzalloc(sizeof(*socfpga_clk
), GFP_KERNEL
);
79 socfpga_clk
->hw
.reg
= regbase
+ clks
->gate_reg
;
80 socfpga_clk
->hw
.bit_idx
= clks
->gate_idx
;
82 gateclk_ops
.enable
= clk_gate_ops
.enable
;
83 gateclk_ops
.disable
= clk_gate_ops
.disable
;
85 socfpga_clk
->fixed_div
= clks
->fixed_div
;
88 socfpga_clk
->div_reg
= regbase
+ clks
->div_reg
;
90 socfpga_clk
->div_reg
= NULL
;
92 socfpga_clk
->width
= clks
->div_width
;
93 socfpga_clk
->shift
= clks
->div_offset
;
96 socfpga_clk
->bypass_reg
= regbase
+ clks
->bypass_reg
;
98 socfpga_clk
->bypass_reg
= NULL
;
99 socfpga_clk
->bypass_shift
= clks
->bypass_shift
;
101 if (streq(clks
->name
, "cs_pdbg_clk"))
102 init
.ops
= &dbgclk_ops
;
104 init
.ops
= &gateclk_ops
;
106 init
.name
= clks
->name
;
107 init
.flags
= clks
->flags
;
109 init
.num_parents
= clks
->num_parents
;
110 init
.parent_names
= parent_name
? &parent_name
: NULL
;
111 if (init
.parent_names
== NULL
)
112 init
.parent_data
= clks
->parent_data
;
113 socfpga_clk
->hw
.hw
.init
= &init
;
115 clk
= clk_register(NULL
, &socfpga_clk
->hw
.hw
);
116 if (WARN_ON(IS_ERR(clk
))) {