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