0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/kernel.h>
0013 #include <linux/clk-provider.h>
0014 #include <linux/io.h>
0015 #include <linux/slab.h>
0016
0017 #include "clk.h"
0018
0019
0020 #define CLKGATE_SEPERATED_ENABLE 0x0
0021 #define CLKGATE_SEPERATED_DISABLE 0x4
0022 #define CLKGATE_SEPERATED_STATUS 0x8
0023
0024 struct clkgate_separated {
0025 struct clk_hw hw;
0026 void __iomem *enable;
0027 u8 bit_idx;
0028 u8 flags;
0029 spinlock_t *lock;
0030 };
0031
0032 static int clkgate_separated_enable(struct clk_hw *hw)
0033 {
0034 struct clkgate_separated *sclk;
0035 unsigned long flags = 0;
0036 u32 reg;
0037
0038 sclk = container_of(hw, struct clkgate_separated, hw);
0039 if (sclk->lock)
0040 spin_lock_irqsave(sclk->lock, flags);
0041 reg = BIT(sclk->bit_idx);
0042 writel_relaxed(reg, sclk->enable);
0043 readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS);
0044 if (sclk->lock)
0045 spin_unlock_irqrestore(sclk->lock, flags);
0046 return 0;
0047 }
0048
0049 static void clkgate_separated_disable(struct clk_hw *hw)
0050 {
0051 struct clkgate_separated *sclk;
0052 unsigned long flags = 0;
0053 u32 reg;
0054
0055 sclk = container_of(hw, struct clkgate_separated, hw);
0056 if (sclk->lock)
0057 spin_lock_irqsave(sclk->lock, flags);
0058 reg = BIT(sclk->bit_idx);
0059 writel_relaxed(reg, sclk->enable + CLKGATE_SEPERATED_DISABLE);
0060 readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS);
0061 if (sclk->lock)
0062 spin_unlock_irqrestore(sclk->lock, flags);
0063 }
0064
0065 static int clkgate_separated_is_enabled(struct clk_hw *hw)
0066 {
0067 struct clkgate_separated *sclk;
0068 u32 reg;
0069
0070 sclk = container_of(hw, struct clkgate_separated, hw);
0071 reg = readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS);
0072 reg &= BIT(sclk->bit_idx);
0073
0074 return reg ? 1 : 0;
0075 }
0076
0077 static const struct clk_ops clkgate_separated_ops = {
0078 .enable = clkgate_separated_enable,
0079 .disable = clkgate_separated_disable,
0080 .is_enabled = clkgate_separated_is_enabled,
0081 };
0082
0083 struct clk *hisi_register_clkgate_sep(struct device *dev, const char *name,
0084 const char *parent_name,
0085 unsigned long flags,
0086 void __iomem *reg, u8 bit_idx,
0087 u8 clk_gate_flags, spinlock_t *lock)
0088 {
0089 struct clkgate_separated *sclk;
0090 struct clk *clk;
0091 struct clk_init_data init;
0092
0093 sclk = kzalloc(sizeof(*sclk), GFP_KERNEL);
0094 if (!sclk)
0095 return ERR_PTR(-ENOMEM);
0096
0097 init.name = name;
0098 init.ops = &clkgate_separated_ops;
0099 init.flags = flags;
0100 init.parent_names = (parent_name ? &parent_name : NULL);
0101 init.num_parents = (parent_name ? 1 : 0);
0102
0103 sclk->enable = reg + CLKGATE_SEPERATED_ENABLE;
0104 sclk->bit_idx = bit_idx;
0105 sclk->flags = clk_gate_flags;
0106 sclk->hw.init = &init;
0107 sclk->lock = lock;
0108
0109 clk = clk_register(dev, &sclk->hw);
0110 if (IS_ERR(clk))
0111 kfree(sclk);
0112 return clk;
0113 }