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 char *name
, const char *parent_name
,
69 const char * const *parent_names
,
70 u8 num_parents
, unsigned long flags
,
71 void __iomem
*regbase
, unsigned long gate_reg
,
72 unsigned long gate_idx
, unsigned long div_reg
,
73 unsigned long div_offset
, u8 div_width
,
74 unsigned long bypass_reg
, u8 bypass_shift
,
78 struct socfpga_gate_clk
*socfpga_clk
;
79 struct clk_init_data init
;
81 socfpga_clk
= kzalloc(sizeof(*socfpga_clk
), GFP_KERNEL
);
85 socfpga_clk
->hw
.reg
= regbase
+ gate_reg
;
86 socfpga_clk
->hw
.bit_idx
= gate_idx
;
88 gateclk_ops
.enable
= clk_gate_ops
.enable
;
89 gateclk_ops
.disable
= clk_gate_ops
.disable
;
91 socfpga_clk
->fixed_div
= fixed_div
;
94 socfpga_clk
->div_reg
= regbase
+ div_reg
;
96 socfpga_clk
->div_reg
= NULL
;
98 socfpga_clk
->width
= div_width
;
99 socfpga_clk
->shift
= div_offset
;
102 socfpga_clk
->bypass_reg
= regbase
+ bypass_reg
;
104 socfpga_clk
->bypass_reg
= NULL
;
105 socfpga_clk
->bypass_shift
= bypass_shift
;
107 if (streq(name
, "cs_pdbg_clk"))
108 init
.ops
= &dbgclk_ops
;
110 init
.ops
= &gateclk_ops
;
115 init
.num_parents
= num_parents
;
116 init
.parent_names
= parent_names
? parent_names
: &parent_name
;
117 socfpga_clk
->hw
.hw
.init
= &init
;
119 clk
= clk_register(NULL
, &socfpga_clk
->hw
.hw
);
120 if (WARN_ON(IS_ERR(clk
))) {