xref: /OK3568_Linux_fs/kernel/drivers/clk/imx/clk-lpcg-scu.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright 2018 NXP
4*4882a593Smuzhiyun  *	Dong Aisheng <aisheng.dong@nxp.com>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/bits.h>
8*4882a593Smuzhiyun #include <linux/clk-provider.h>
9*4882a593Smuzhiyun #include <linux/err.h>
10*4882a593Smuzhiyun #include <linux/io.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/spinlock.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include "clk-scu.h"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun static DEFINE_SPINLOCK(imx_lpcg_scu_lock);
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #define CLK_GATE_SCU_LPCG_MASK		0x3
19*4882a593Smuzhiyun #define CLK_GATE_SCU_LPCG_HW_SEL	BIT(0)
20*4882a593Smuzhiyun #define CLK_GATE_SCU_LPCG_SW_SEL	BIT(1)
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun  * struct clk_lpcg_scu - Description of LPCG clock
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  * @hw: clk_hw of this LPCG
26*4882a593Smuzhiyun  * @reg: register of this LPCG clock
27*4882a593Smuzhiyun  * @bit_idx: bit index of this LPCG clock
28*4882a593Smuzhiyun  * @hw_gate: HW auto gate enable
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  * This structure describes one LPCG clock
31*4882a593Smuzhiyun  */
32*4882a593Smuzhiyun struct clk_lpcg_scu {
33*4882a593Smuzhiyun 	struct clk_hw hw;
34*4882a593Smuzhiyun 	void __iomem *reg;
35*4882a593Smuzhiyun 	u8 bit_idx;
36*4882a593Smuzhiyun 	bool hw_gate;
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
40*4882a593Smuzhiyun 
clk_lpcg_scu_enable(struct clk_hw * hw)41*4882a593Smuzhiyun static int clk_lpcg_scu_enable(struct clk_hw *hw)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
44*4882a593Smuzhiyun 	unsigned long flags;
45*4882a593Smuzhiyun 	u32 reg, val;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	reg = readl_relaxed(clk->reg);
50*4882a593Smuzhiyun 	reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	val = CLK_GATE_SCU_LPCG_SW_SEL;
53*4882a593Smuzhiyun 	if (clk->hw_gate)
54*4882a593Smuzhiyun 		val |= CLK_GATE_SCU_LPCG_HW_SEL;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	reg |= val << clk->bit_idx;
57*4882a593Smuzhiyun 	writel(reg, clk->reg);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	return 0;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
clk_lpcg_scu_disable(struct clk_hw * hw)64*4882a593Smuzhiyun static void clk_lpcg_scu_disable(struct clk_hw *hw)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
67*4882a593Smuzhiyun 	unsigned long flags;
68*4882a593Smuzhiyun 	u32 reg;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	reg = readl_relaxed(clk->reg);
73*4882a593Smuzhiyun 	reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
74*4882a593Smuzhiyun 	writel(reg, clk->reg);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun static const struct clk_ops clk_lpcg_scu_ops = {
80*4882a593Smuzhiyun 	.enable = clk_lpcg_scu_enable,
81*4882a593Smuzhiyun 	.disable = clk_lpcg_scu_disable,
82*4882a593Smuzhiyun };
83*4882a593Smuzhiyun 
imx_clk_lpcg_scu(const char * name,const char * parent_name,unsigned long flags,void __iomem * reg,u8 bit_idx,bool hw_gate)84*4882a593Smuzhiyun struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
85*4882a593Smuzhiyun 				unsigned long flags, void __iomem *reg,
86*4882a593Smuzhiyun 				u8 bit_idx, bool hw_gate)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	struct clk_lpcg_scu *clk;
89*4882a593Smuzhiyun 	struct clk_init_data init;
90*4882a593Smuzhiyun 	struct clk_hw *hw;
91*4882a593Smuzhiyun 	int ret;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	clk = kzalloc(sizeof(*clk), GFP_KERNEL);
94*4882a593Smuzhiyun 	if (!clk)
95*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	clk->reg = reg;
98*4882a593Smuzhiyun 	clk->bit_idx = bit_idx;
99*4882a593Smuzhiyun 	clk->hw_gate = hw_gate;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	init.name = name;
102*4882a593Smuzhiyun 	init.ops = &clk_lpcg_scu_ops;
103*4882a593Smuzhiyun 	init.flags = CLK_SET_RATE_PARENT | flags;
104*4882a593Smuzhiyun 	init.parent_names = parent_name ? &parent_name : NULL;
105*4882a593Smuzhiyun 	init.num_parents = parent_name ? 1 : 0;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	clk->hw.init = &init;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	hw = &clk->hw;
110*4882a593Smuzhiyun 	ret = clk_hw_register(NULL, hw);
111*4882a593Smuzhiyun 	if (ret) {
112*4882a593Smuzhiyun 		kfree(clk);
113*4882a593Smuzhiyun 		hw = ERR_PTR(ret);
114*4882a593Smuzhiyun 	}
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	return hw;
117*4882a593Smuzhiyun }
118