1 // SPDX-License-Identifier: GPL-2.0+
4 * Dong Aisheng <aisheng.dong@nxp.com>
7 #include <linux/clk-provider.h>
10 #include <linux/slab.h>
11 #include <linux/spinlock.h>
15 static DEFINE_SPINLOCK(imx_lpcg_scu_lock
);
17 #define CLK_GATE_SCU_LPCG_MASK 0x3
18 #define CLK_GATE_SCU_LPCG_HW_SEL BIT(0)
19 #define CLK_GATE_SCU_LPCG_SW_SEL BIT(1)
22 * struct clk_lpcg_scu - Description of LPCG clock
24 * @hw: clk_hw of this LPCG
25 * @reg: register of this LPCG clock
26 * @bit_idx: bit index of this LPCG clock
27 * @hw_gate: HW auto gate enable
29 * This structure describes one LPCG clock
38 #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
40 static int clk_lpcg_scu_enable(struct clk_hw
*hw
)
42 struct clk_lpcg_scu
*clk
= to_clk_lpcg_scu(hw
);
46 spin_lock_irqsave(&imx_lpcg_scu_lock
, flags
);
48 reg
= readl_relaxed(clk
->reg
);
49 reg
&= ~(CLK_GATE_SCU_LPCG_MASK
<< clk
->bit_idx
);
51 val
= CLK_GATE_SCU_LPCG_SW_SEL
;
53 val
|= CLK_GATE_SCU_LPCG_HW_SEL
;
55 reg
|= val
<< clk
->bit_idx
;
56 writel(reg
, clk
->reg
);
58 spin_unlock_irqrestore(&imx_lpcg_scu_lock
, flags
);
63 static void clk_lpcg_scu_disable(struct clk_hw
*hw
)
65 struct clk_lpcg_scu
*clk
= to_clk_lpcg_scu(hw
);
69 spin_lock_irqsave(&imx_lpcg_scu_lock
, flags
);
71 reg
= readl_relaxed(clk
->reg
);
72 reg
&= ~(CLK_GATE_SCU_LPCG_MASK
<< clk
->bit_idx
);
73 writel(reg
, clk
->reg
);
75 spin_unlock_irqrestore(&imx_lpcg_scu_lock
, flags
);
78 static const struct clk_ops clk_lpcg_scu_ops
= {
79 .enable
= clk_lpcg_scu_enable
,
80 .disable
= clk_lpcg_scu_disable
,
83 struct clk_hw
*imx_clk_lpcg_scu(const char *name
, const char *parent_name
,
84 unsigned long flags
, void __iomem
*reg
,
85 u8 bit_idx
, bool hw_gate
)
87 struct clk_lpcg_scu
*clk
;
88 struct clk_init_data init
;
92 clk
= kzalloc(sizeof(*clk
), GFP_KERNEL
);
94 return ERR_PTR(-ENOMEM
);
97 clk
->bit_idx
= bit_idx
;
98 clk
->hw_gate
= hw_gate
;
101 init
.ops
= &clk_lpcg_scu_ops
;
102 init
.flags
= CLK_SET_RATE_PARENT
| flags
;
103 init
.parent_names
= parent_name
? &parent_name
: NULL
;
104 init
.num_parents
= parent_name
? 1 : 0;
106 clk
->hw
.init
= &init
;
109 ret
= clk_hw_register(NULL
, hw
);