0001
0002
0003
0004
0005
0006
0007 #include <linux/bits.h>
0008 #include <linux/clk-provider.h>
0009 #include <linux/err.h>
0010 #include <linux/io.h>
0011 #include <linux/slab.h>
0012 #include <linux/spinlock.h>
0013
0014 #include "clk-scu.h"
0015
0016 static DEFINE_SPINLOCK(imx_lpcg_scu_lock);
0017
0018 #define CLK_GATE_SCU_LPCG_MASK 0x3
0019 #define CLK_GATE_SCU_LPCG_HW_SEL BIT(0)
0020 #define CLK_GATE_SCU_LPCG_SW_SEL BIT(1)
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 struct clk_lpcg_scu {
0033 struct clk_hw hw;
0034 void __iomem *reg;
0035 u8 bit_idx;
0036 bool hw_gate;
0037
0038
0039 u32 state;
0040 };
0041
0042 #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
0043
0044 static int clk_lpcg_scu_enable(struct clk_hw *hw)
0045 {
0046 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
0047 unsigned long flags;
0048 u32 reg, val;
0049
0050 spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
0051
0052 reg = readl_relaxed(clk->reg);
0053 reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
0054
0055 val = CLK_GATE_SCU_LPCG_SW_SEL;
0056 if (clk->hw_gate)
0057 val |= CLK_GATE_SCU_LPCG_HW_SEL;
0058
0059 reg |= val << clk->bit_idx;
0060 writel(reg, clk->reg);
0061
0062 spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
0063
0064 return 0;
0065 }
0066
0067 static void clk_lpcg_scu_disable(struct clk_hw *hw)
0068 {
0069 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
0070 unsigned long flags;
0071 u32 reg;
0072
0073 spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
0074
0075 reg = readl_relaxed(clk->reg);
0076 reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
0077 writel(reg, clk->reg);
0078
0079 spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
0080 }
0081
0082 static const struct clk_ops clk_lpcg_scu_ops = {
0083 .enable = clk_lpcg_scu_enable,
0084 .disable = clk_lpcg_scu_disable,
0085 };
0086
0087 struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name,
0088 const char *parent_name, unsigned long flags,
0089 void __iomem *reg, u8 bit_idx, bool hw_gate)
0090 {
0091 struct clk_lpcg_scu *clk;
0092 struct clk_init_data init;
0093 struct clk_hw *hw;
0094 int ret;
0095
0096 clk = kzalloc(sizeof(*clk), GFP_KERNEL);
0097 if (!clk)
0098 return ERR_PTR(-ENOMEM);
0099
0100 clk->reg = reg;
0101 clk->bit_idx = bit_idx;
0102 clk->hw_gate = hw_gate;
0103
0104 init.name = name;
0105 init.ops = &clk_lpcg_scu_ops;
0106 init.flags = CLK_SET_RATE_PARENT | flags;
0107 init.parent_names = parent_name ? &parent_name : NULL;
0108 init.num_parents = parent_name ? 1 : 0;
0109
0110 clk->hw.init = &init;
0111
0112 hw = &clk->hw;
0113 ret = clk_hw_register(dev, hw);
0114 if (ret) {
0115 kfree(clk);
0116 hw = ERR_PTR(ret);
0117 return hw;
0118 }
0119
0120 if (dev)
0121 dev_set_drvdata(dev, clk);
0122
0123 return hw;
0124 }
0125
0126 void imx_clk_lpcg_scu_unregister(struct clk_hw *hw)
0127 {
0128 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
0129
0130 clk_hw_unregister(&clk->hw);
0131 kfree(clk);
0132 }
0133
0134 static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev)
0135 {
0136 struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
0137
0138 clk->state = readl_relaxed(clk->reg);
0139 dev_dbg(dev, "save lpcg state 0x%x\n", clk->state);
0140
0141 return 0;
0142 }
0143
0144 static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev)
0145 {
0146 struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
0147
0148
0149
0150
0151
0152
0153 writel(clk->state, clk->reg);
0154 writel(clk->state, clk->reg);
0155 dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state);
0156
0157 return 0;
0158 }
0159
0160 const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops = {
0161 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_lpcg_scu_suspend,
0162 imx_clk_lpcg_scu_resume)
0163 };