Merge tag 'clk-hisi' of https://git.kernel.org/pub/scm/linux/kernel/git/hzhuang1...
authorMike Turquette <mturquette@linaro.org>
Wed, 19 Mar 2014 19:54:03 +0000 (12:54 -0700)
committerMike Turquette <mturquette@linaro.org>
Wed, 19 Mar 2014 19:54:03 +0000 (12:54 -0700)
updating clock drivers for Hisilicon

1  2 
drivers/clk/Makefile
drivers/clk/hisilicon/clk-hi3620.c

Simple merge
@@@ -224,293 -218,16 +218,290 @@@ static void __init hi3620_clk_init(stru
  
        hisi_clk_register_fixed_rate(hi3620_fixed_rate_clks,
                                     ARRAY_SIZE(hi3620_fixed_rate_clks),
-                                    base);
+                                    clk_data);
        hisi_clk_register_fixed_factor(hi3620_fixed_factor_clks,
                                       ARRAY_SIZE(hi3620_fixed_factor_clks),
-                                      base);
+                                      clk_data);
        hisi_clk_register_mux(hi3620_mux_clks, ARRAY_SIZE(hi3620_mux_clks),
-                             base);
+                             clk_data);
        hisi_clk_register_divider(hi3620_div_clks, ARRAY_SIZE(hi3620_div_clks),
-                                 base);
+                                 clk_data);
        hisi_clk_register_gate_sep(hi3620_seperated_gate_clks,
                                   ARRAY_SIZE(hi3620_seperated_gate_clks),
-                                  base);
+                                  clk_data);
  }
  CLK_OF_DECLARE(hi3620_clk, "hisilicon,hi3620-clock", hi3620_clk_init);
 +
 +struct hisi_mmc_clock {
 +      unsigned int            id;
 +      const char              *name;
 +      const char              *parent_name;
 +      unsigned long           flags;
 +      u32                     clken_reg;
 +      u32                     clken_bit;
 +      u32                     div_reg;
 +      u32                     div_off;
 +      u32                     div_bits;
 +      u32                     drv_reg;
 +      u32                     drv_off;
 +      u32                     drv_bits;
 +      u32                     sam_reg;
 +      u32                     sam_off;
 +      u32                     sam_bits;
 +};
 +
 +struct clk_mmc {
 +      struct clk_hw   hw;
 +      u32             id;
 +      void __iomem    *clken_reg;
 +      u32             clken_bit;
 +      void __iomem    *div_reg;
 +      u32             div_off;
 +      u32             div_bits;
 +      void __iomem    *drv_reg;
 +      u32             drv_off;
 +      u32             drv_bits;
 +      void __iomem    *sam_reg;
 +      u32             sam_off;
 +      u32             sam_bits;
 +};
 +
 +#define to_mmc(_hw) container_of(_hw, struct clk_mmc, hw)
 +
 +static struct hisi_mmc_clock hi3620_mmc_clks[] __initdata = {
 +      { HI3620_SD_CIUCLK,     "sd_bclk1", "sd_clk", CLK_SET_RATE_PARENT, 0x1f8, 0, 0x1f8, 1, 3, 0x1f8, 4, 4, 0x1f8, 8, 4},
 +      { HI3620_MMC_CIUCLK1,   "mmc_bclk1", "mmc_clk1", CLK_SET_RATE_PARENT, 0x1f8, 12, 0x1f8, 13, 3, 0x1f8, 16, 4, 0x1f8, 20, 4},
 +      { HI3620_MMC_CIUCLK2,   "mmc_bclk2", "mmc_clk2", CLK_SET_RATE_PARENT, 0x1f8, 24, 0x1f8, 25, 3, 0x1f8, 28, 4, 0x1fc, 0, 4},
 +      { HI3620_MMC_CIUCLK3,   "mmc_bclk3", "mmc_clk3", CLK_SET_RATE_PARENT, 0x1fc, 4, 0x1fc, 5, 3, 0x1fc, 8, 4, 0x1fc, 12, 4},
 +};
 +
 +static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
 +                     unsigned long parent_rate)
 +{
 +      switch (parent_rate) {
 +      case 26000000:
 +              return 13000000;
 +      case 180000000:
 +              return 25000000;
 +      case 360000000:
 +              return 50000000;
 +      case 720000000:
 +              return 100000000;
 +      case 1440000000:
 +              return 180000000;
 +      default:
 +              return parent_rate;
 +      }
 +}
 +
 +static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
 +                            unsigned long *best_parent_rate,
 +                            struct clk **best_parent_p)
 +{
 +      struct clk_mmc *mclk = to_mmc(hw);
 +      unsigned long best = 0;
 +
 +      if ((rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) {
 +              rate = 13000000;
 +              best = 26000000;
 +      } else if (rate <= 26000000) {
 +              rate = 25000000;
 +              best = 180000000;
 +      } else if (rate <= 52000000) {
 +              rate = 50000000;
 +              best = 360000000;
 +      } else if (rate <= 100000000) {
 +              rate = 100000000;
 +              best = 720000000;
 +      } else {
 +              /* max is 180M */
 +              rate = 180000000;
 +              best = 1440000000;
 +      }
 +      *best_parent_rate = best;
 +      return rate;
 +}
 +
 +static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len)
 +{
 +      u32 i;
 +
 +      if (para >= 0) {
 +              for (i = 0; i < len; i++) {
 +                      if (para % 2)
 +                              val |= 1 << (off + i);
 +                      else
 +                              val &= ~(1 << (off + i));
 +                      para = para >> 1;
 +              }
 +      }
 +      return val;
 +}
 +
 +static int mmc_clk_set_timing(struct clk_hw *hw, unsigned long rate)
 +{
 +      struct clk_mmc *mclk = to_mmc(hw);
 +      unsigned long flags;
 +      u32 sam, drv, div, val;
 +      static DEFINE_SPINLOCK(mmc_clk_lock);
 +
 +      switch (rate) {
 +      case 13000000:
 +              sam = 3;
 +              drv = 1;
 +              div = 1;
 +              break;
 +      case 25000000:
 +              sam = 13;
 +              drv = 6;
 +              div = 6;
 +              break;
 +      case 50000000:
 +              sam = 3;
 +              drv = 6;
 +              div = 6;
 +              break;
 +      case 100000000:
 +              sam = 6;
 +              drv = 4;
 +              div = 6;
 +              break;
 +      case 180000000:
 +              sam = 6;
 +              drv = 4;
 +              div = 7;
 +              break;
 +      default:
 +              return -EINVAL;
 +      }
 +
 +      spin_lock_irqsave(&mmc_clk_lock, flags);
 +
 +      val = readl_relaxed(mclk->clken_reg);
 +      val &= ~(1 << mclk->clken_bit);
 +      writel_relaxed(val, mclk->clken_reg);
 +
 +      val = readl_relaxed(mclk->sam_reg);
 +      val = mmc_clk_delay(val, sam, mclk->sam_off, mclk->sam_bits);
 +      writel_relaxed(val, mclk->sam_reg);
 +
 +      val = readl_relaxed(mclk->drv_reg);
 +      val = mmc_clk_delay(val, drv, mclk->drv_off, mclk->drv_bits);
 +      writel_relaxed(val, mclk->drv_reg);
 +
 +      val = readl_relaxed(mclk->div_reg);
 +      val = mmc_clk_delay(val, div, mclk->div_off, mclk->div_bits);
 +      writel_relaxed(val, mclk->div_reg);
 +
 +      val = readl_relaxed(mclk->clken_reg);
 +      val |= 1 << mclk->clken_bit;
 +      writel_relaxed(val, mclk->clken_reg);
 +
 +      spin_unlock_irqrestore(&mmc_clk_lock, flags);
 +
 +      return 0;
 +}
 +
 +static int mmc_clk_prepare(struct clk_hw *hw)
 +{
 +      struct clk_mmc *mclk = to_mmc(hw);
 +      unsigned long rate;
 +
 +      if (mclk->id == HI3620_MMC_CIUCLK1)
 +              rate = 13000000;
 +      else
 +              rate = 25000000;
 +
 +      return mmc_clk_set_timing(hw, rate);
 +}
 +
 +static int mmc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
 +                           unsigned long parent_rate)
 +{
 +      return mmc_clk_set_timing(hw, rate);
 +}
 +
 +static struct clk_ops clk_mmc_ops = {
 +      .prepare = mmc_clk_prepare,
 +      .determine_rate = mmc_clk_determine_rate,
 +      .set_rate = mmc_clk_set_rate,
 +      .recalc_rate = mmc_clk_recalc_rate,
 +};
 +
 +static struct clk *hisi_register_clk_mmc(struct hisi_mmc_clock *mmc_clk,
 +                      void __iomem *base, struct device_node *np)
 +{
 +      struct clk_mmc *mclk;
 +      struct clk *clk;
 +      struct clk_init_data init;
 +
 +      mclk = kzalloc(sizeof(*mclk), GFP_KERNEL);
 +      if (!mclk) {
 +              pr_err("%s: fail to allocate mmc clk\n", __func__);
 +              return ERR_PTR(-ENOMEM);
 +      }
 +
 +      init.name = mmc_clk->name;
 +      init.ops = &clk_mmc_ops;
 +      init.flags = mmc_clk->flags | CLK_IS_BASIC;
 +      init.parent_names = (mmc_clk->parent_name ? &mmc_clk->parent_name : NULL);
 +      init.num_parents = (mmc_clk->parent_name ? 1 : 0);
 +      mclk->hw.init = &init;
 +
 +      mclk->id = mmc_clk->id;
 +      mclk->clken_reg = base + mmc_clk->clken_reg;
 +      mclk->clken_bit = mmc_clk->clken_bit;
 +      mclk->div_reg = base + mmc_clk->div_reg;
 +      mclk->div_off = mmc_clk->div_off;
 +      mclk->div_bits = mmc_clk->div_bits;
 +      mclk->drv_reg = base + mmc_clk->drv_reg;
 +      mclk->drv_off = mmc_clk->drv_off;
 +      mclk->drv_bits = mmc_clk->drv_bits;
 +      mclk->sam_reg = base + mmc_clk->sam_reg;
 +      mclk->sam_off = mmc_clk->sam_off;
 +      mclk->sam_bits = mmc_clk->sam_bits;
 +
 +      clk = clk_register(NULL, &mclk->hw);
 +      if (WARN_ON(IS_ERR(clk)))
 +              kfree(mclk);
 +      return clk;
 +}
 +
 +static void __init hi3620_mmc_clk_init(struct device_node *node)
 +{
 +      void __iomem *base;
 +      int i, num = ARRAY_SIZE(hi3620_mmc_clks);
 +      struct clk_onecell_data *clk_data;
 +
 +      if (!node) {
 +              pr_err("failed to find pctrl node in DTS\n");
 +              return;
 +      }
 +
 +      base = of_iomap(node, 0);
 +      if (!base) {
 +              pr_err("failed to map pctrl\n");
 +              return;
 +      }
 +
 +      clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
 +      if (WARN_ON(!clk_data))
 +              return;
 +
 +      clk_data->clks = kzalloc(sizeof(struct clk *) * num, GFP_KERNEL);
 +      if (!clk_data->clks) {
 +              pr_err("%s: fail to allocate mmc clk\n", __func__);
 +              return;
 +      }
 +
 +      for (i = 0; i < num; i++) {
 +              struct hisi_mmc_clock *mmc_clk = &hi3620_mmc_clks[i];
 +              clk_data->clks[mmc_clk->id] =
 +                      hisi_register_clk_mmc(mmc_clk, base, node);
 +      }
 +
 +      clk_data->clk_num = num;
 +      of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
 +}
 +
 +CLK_OF_DECLARE(hi3620_mmc_clk, "hisilicon,hi3620-mmc-clock", hi3620_mmc_clk_init);