[PATCH 04/14] clk: stm32mp1: add MP1 gate for osc hse/hsi/csi oscillators

2018-02-02 Thread gabriel.fernandez
From: Gabriel Fernandez 

MP1 Gate is a gate with a set and a clear register.
This patch also introduces divider and fixed factor clocks.

Signed-off-by: Gabriel Fernandez 
---
 drivers/clk/clk-stm32mp1.c | 186 +
 1 file changed, 186 insertions(+)

diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index 6e39e85..be5a4e5 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -355,6 +355,19 @@ struct gate_cfg {
u8 gate_flags;
 };
 
+struct fixed_factor_cfg {
+   unsigned int mult;
+   unsigned int div;
+};
+
+struct div_cfg {
+   u32 reg_off;
+   u8 shift;
+   u8 width;
+   u8 div_flags;
+   const struct clk_div_table *table;
+};
+
 static struct clk_hw *
 _clk_hw_register_gate(struct device *dev,
  struct clk_hw_onecell_data *clk_data,
@@ -373,6 +386,122 @@ struct gate_cfg {
lock);
 }
 
+static struct clk_hw *
+_clk_hw_register_fixed_factor(struct device *dev,
+ struct clk_hw_onecell_data *clk_data,
+ void __iomem *base, spinlock_t *lock,
+ const struct clock_config *cfg)
+{
+   struct fixed_factor_cfg *ff_cfg = cfg->cfg;
+
+   return clk_hw_register_fixed_factor(dev, cfg->name, cfg->parent_name,
+   cfg->flags, ff_cfg->mult,
+   ff_cfg->div);
+}
+
+static struct clk_hw *
+_clk_hw_register_divider_table(struct device *dev,
+  struct clk_hw_onecell_data *clk_data,
+  void __iomem *base, spinlock_t *lock,
+  const struct clock_config *cfg)
+{
+   struct div_cfg *div_cfg = cfg->cfg;
+
+   return clk_hw_register_divider_table(dev,
+cfg->name,
+cfg->parent_name,
+cfg->flags,
+div_cfg->reg_off + base,
+div_cfg->shift,
+div_cfg->width,
+div_cfg->div_flags,
+div_cfg->table,
+lock);
+}
+
+/* MP1 Gate clock with set & clear registers */
+
+static int mp1_gate_clk_enable(struct clk_hw *hw)
+{
+   if (!clk_gate_ops.is_enabled(hw))
+   clk_gate_ops.enable(hw);
+
+   return 0;
+}
+
+static void mp1_gate_clk_disable(struct clk_hw *hw)
+{
+   struct clk_gate *gate = to_clk_gate(hw);
+   unsigned long flags = 0;
+
+   if (clk_gate_ops.is_enabled(hw)) {
+   spin_lock_irqsave(gate->lock, flags);
+   writel_relaxed(BIT(gate->bit_idx), gate->reg + RCC_CLR);
+   spin_unlock_irqrestore(gate->lock, flags);
+   }
+}
+
+const struct clk_ops mp1_gate_clk_ops = {
+   .enable = mp1_gate_clk_enable,
+   .disable= mp1_gate_clk_disable,
+   .is_enabled = clk_gate_is_enabled,
+};
+
+static struct clk_hw *clk_register_mp1_gate(struct device *dev,
+   const char *name,
+   const char *parent_name,
+   unsigned long flags,
+   void __iomem *reg, u8 bit_idx,
+   u8 clk_gate_flags, spinlock_t *lock)
+{
+   struct clk_init_data init = { NULL };
+   struct clk_gate *gate;
+   int ret;
+   struct clk_hw *hw;
+
+   gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+   if (!gate)
+   return ERR_PTR(-ENOMEM);
+
+   init.name = name;
+   init.ops = _gate_clk_ops;
+   init.parent_names = _name;
+   init.num_parents = 1;
+   init.flags = flags;
+
+   gate->reg = reg;
+   gate->bit_idx = bit_idx;
+   gate->lock = lock;
+
+   gate->hw.init = 
+   hw = >hw;
+
+   ret = clk_hw_register(dev, hw);
+   if (ret) {
+   kfree(gate);
+   hw = ERR_PTR(ret);
+   }
+   return hw;
+}
+
+static struct clk_hw *
+_clk_register_mp1_gate(struct device *dev,
+  struct clk_hw_onecell_data *clk_data,
+  void __iomem *base, spinlock_t *lock,
+  const struct clock_config *cfg)
+{
+   struct gate_cfg *gate_cfg = cfg->cfg;
+
+   return clk_register_mp1_gate(dev,
+cfg->name,
+cfg->parent_name,
+cfg->flags,
+gate_cfg->reg_off + base,
+gate_cfg->bit_idx,
+

[PATCH 04/14] clk: stm32mp1: add MP1 gate for osc hse/hsi/csi oscillators

2018-02-02 Thread gabriel.fernandez
From: Gabriel Fernandez 

MP1 Gate is a gate with a set and a clear register.
This patch also introduces divider and fixed factor clocks.

Signed-off-by: Gabriel Fernandez 
---
 drivers/clk/clk-stm32mp1.c | 186 +
 1 file changed, 186 insertions(+)

diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index 6e39e85..be5a4e5 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -355,6 +355,19 @@ struct gate_cfg {
u8 gate_flags;
 };
 
+struct fixed_factor_cfg {
+   unsigned int mult;
+   unsigned int div;
+};
+
+struct div_cfg {
+   u32 reg_off;
+   u8 shift;
+   u8 width;
+   u8 div_flags;
+   const struct clk_div_table *table;
+};
+
 static struct clk_hw *
 _clk_hw_register_gate(struct device *dev,
  struct clk_hw_onecell_data *clk_data,
@@ -373,6 +386,122 @@ struct gate_cfg {
lock);
 }
 
+static struct clk_hw *
+_clk_hw_register_fixed_factor(struct device *dev,
+ struct clk_hw_onecell_data *clk_data,
+ void __iomem *base, spinlock_t *lock,
+ const struct clock_config *cfg)
+{
+   struct fixed_factor_cfg *ff_cfg = cfg->cfg;
+
+   return clk_hw_register_fixed_factor(dev, cfg->name, cfg->parent_name,
+   cfg->flags, ff_cfg->mult,
+   ff_cfg->div);
+}
+
+static struct clk_hw *
+_clk_hw_register_divider_table(struct device *dev,
+  struct clk_hw_onecell_data *clk_data,
+  void __iomem *base, spinlock_t *lock,
+  const struct clock_config *cfg)
+{
+   struct div_cfg *div_cfg = cfg->cfg;
+
+   return clk_hw_register_divider_table(dev,
+cfg->name,
+cfg->parent_name,
+cfg->flags,
+div_cfg->reg_off + base,
+div_cfg->shift,
+div_cfg->width,
+div_cfg->div_flags,
+div_cfg->table,
+lock);
+}
+
+/* MP1 Gate clock with set & clear registers */
+
+static int mp1_gate_clk_enable(struct clk_hw *hw)
+{
+   if (!clk_gate_ops.is_enabled(hw))
+   clk_gate_ops.enable(hw);
+
+   return 0;
+}
+
+static void mp1_gate_clk_disable(struct clk_hw *hw)
+{
+   struct clk_gate *gate = to_clk_gate(hw);
+   unsigned long flags = 0;
+
+   if (clk_gate_ops.is_enabled(hw)) {
+   spin_lock_irqsave(gate->lock, flags);
+   writel_relaxed(BIT(gate->bit_idx), gate->reg + RCC_CLR);
+   spin_unlock_irqrestore(gate->lock, flags);
+   }
+}
+
+const struct clk_ops mp1_gate_clk_ops = {
+   .enable = mp1_gate_clk_enable,
+   .disable= mp1_gate_clk_disable,
+   .is_enabled = clk_gate_is_enabled,
+};
+
+static struct clk_hw *clk_register_mp1_gate(struct device *dev,
+   const char *name,
+   const char *parent_name,
+   unsigned long flags,
+   void __iomem *reg, u8 bit_idx,
+   u8 clk_gate_flags, spinlock_t *lock)
+{
+   struct clk_init_data init = { NULL };
+   struct clk_gate *gate;
+   int ret;
+   struct clk_hw *hw;
+
+   gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+   if (!gate)
+   return ERR_PTR(-ENOMEM);
+
+   init.name = name;
+   init.ops = _gate_clk_ops;
+   init.parent_names = _name;
+   init.num_parents = 1;
+   init.flags = flags;
+
+   gate->reg = reg;
+   gate->bit_idx = bit_idx;
+   gate->lock = lock;
+
+   gate->hw.init = 
+   hw = >hw;
+
+   ret = clk_hw_register(dev, hw);
+   if (ret) {
+   kfree(gate);
+   hw = ERR_PTR(ret);
+   }
+   return hw;
+}
+
+static struct clk_hw *
+_clk_register_mp1_gate(struct device *dev,
+  struct clk_hw_onecell_data *clk_data,
+  void __iomem *base, spinlock_t *lock,
+  const struct clock_config *cfg)
+{
+   struct gate_cfg *gate_cfg = cfg->cfg;
+
+   return clk_register_mp1_gate(dev,
+cfg->name,
+cfg->parent_name,
+cfg->flags,
+gate_cfg->reg_off + base,
+gate_cfg->bit_idx,
+gate_cfg->gate_flags,
+