1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2017, Intel Corporation
5 #include <linux/clk-provider.h>
6 #include <linux/slab.h>
7 #include "stratix10-clk.h"
10 #define SOCFPGA_CS_PDBG_CLK "cs_pdbg_clk"
11 #define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw)
13 static unsigned long socfpga_gate_clk_recalc_rate(struct clk_hw
*hwclk
,
14 unsigned long parent_rate
)
16 struct socfpga_gate_clk
*socfpgaclk
= to_socfpga_gate_clk(hwclk
);
19 if (socfpgaclk
->fixed_div
) {
20 div
= socfpgaclk
->fixed_div
;
21 } else if (socfpgaclk
->div_reg
) {
22 val
= readl(socfpgaclk
->div_reg
) >> socfpgaclk
->shift
;
23 val
&= GENMASK(socfpgaclk
->width
- 1, 0);
26 return parent_rate
/ div
;
29 static unsigned long socfpga_dbg_clk_recalc_rate(struct clk_hw
*hwclk
,
30 unsigned long parent_rate
)
32 struct socfpga_gate_clk
*socfpgaclk
= to_socfpga_gate_clk(hwclk
);
35 val
= readl(socfpgaclk
->div_reg
) >> socfpgaclk
->shift
;
36 val
&= GENMASK(socfpgaclk
->width
- 1, 0);
40 return parent_rate
/ div
;
43 static u8
socfpga_gate_get_parent(struct clk_hw
*hwclk
)
45 struct socfpga_gate_clk
*socfpgaclk
= to_socfpga_gate_clk(hwclk
);
49 if (socfpgaclk
->bypass_reg
) {
50 mask
= (0x1 << socfpgaclk
->bypass_shift
);
51 parent
= ((readl(socfpgaclk
->bypass_reg
) & mask
) >>
52 socfpgaclk
->bypass_shift
);
57 static struct clk_ops gateclk_ops
= {
58 .recalc_rate
= socfpga_gate_clk_recalc_rate
,
59 .get_parent
= socfpga_gate_get_parent
,
62 static const struct clk_ops dbgclk_ops
= {
63 .recalc_rate
= socfpga_dbg_clk_recalc_rate
,
64 .get_parent
= socfpga_gate_get_parent
,
67 struct clk
*s10_register_gate(const char *name
, const char *parent_name
,
68 const char * const *parent_names
,
69 u8 num_parents
, unsigned long flags
,
70 void __iomem
*regbase
, unsigned long gate_reg
,
71 unsigned long gate_idx
, unsigned long div_reg
,
72 unsigned long div_offset
, u8 div_width
,
73 unsigned long bypass_reg
, u8 bypass_shift
,
77 struct socfpga_gate_clk
*socfpga_clk
;
78 struct clk_init_data init
;
80 socfpga_clk
= kzalloc(sizeof(*socfpga_clk
), GFP_KERNEL
);
84 socfpga_clk
->hw
.reg
= regbase
+ gate_reg
;
85 socfpga_clk
->hw
.bit_idx
= gate_idx
;
87 gateclk_ops
.enable
= clk_gate_ops
.enable
;
88 gateclk_ops
.disable
= clk_gate_ops
.disable
;
90 socfpga_clk
->fixed_div
= fixed_div
;
93 socfpga_clk
->div_reg
= regbase
+ div_reg
;
95 socfpga_clk
->div_reg
= NULL
;
97 socfpga_clk
->width
= div_width
;
98 socfpga_clk
->shift
= div_offset
;
101 socfpga_clk
->bypass_reg
= regbase
+ bypass_reg
;
103 socfpga_clk
->bypass_reg
= NULL
;
104 socfpga_clk
->bypass_shift
= bypass_shift
;
106 if (streq(name
, "cs_pdbg_clk"))
107 init
.ops
= &dbgclk_ops
;
109 init
.ops
= &gateclk_ops
;
114 init
.num_parents
= num_parents
;
115 init
.parent_names
= parent_names
? parent_names
: &parent_name
;
116 socfpga_clk
->hw
.hw
.init
= &init
;
118 clk
= clk_register(NULL
, &socfpga_clk
->hw
.hw
);
119 if (WARN_ON(IS_ERR(clk
))) {