]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
clk: zynqmp: pll: Enable the fractional mode when needed
authorHyun Kwon <hyun.kwon@xilinx.com>
Fri, 24 Feb 2017 17:38:56 +0000 (09:38 -0800)
committerMichal Simek <michal.simek@xilinx.com>
Mon, 27 Feb 2017 15:00:57 +0000 (16:00 +0100)
Depending on the requested rate and parent rate, if the multiplier
needs to be fractional, enable the fractional mode of the PLL.

Signed-off-by: Hyun Kwon <hyun.kwon@xilinx.com>
Reviewed-by: Shubhrajyoti Datta <Shubhrajyoti.datta@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/clk/zynqmp/pll.c

index ec029036818d6ad1c07025f055eebf523281049a..bac0826d75e0644451675dfd77906802ca16a3fc 100644 (file)
@@ -80,6 +80,27 @@ static inline enum pll_mode pll_frac_get_mode(struct clk_hw *hw)
        return reg ? PLL_MODE_FRAC : PLL_MODE_INT;
 }
 
+/**
+ * pll_frac_set_mode - Set the fractional mode
+ * @hw:                Handle between common and hardware-specific interfaces
+ * @on:                Flag to determine the mode
+ */
+static inline void pll_frac_set_mode(struct clk_hw *hw, bool on)
+{
+       struct zynqmp_pll *clk = to_zynqmp_pll(hw);
+       u32 reg = 0;
+       int ret;
+
+       if (on)
+               reg = PLLFCFG_FRAC_EN;
+
+       ret = zynqmp_pm_mmio_write((u32)(ulong)(clk->pll_ctrl + FRAC_OFFSET),
+                                       PLLFCFG_FRAC_EN, reg);
+       if (ret)
+               pr_warn_once("Write fail pll address: %x\n",
+                               (u32)(ulong)(clk->pll_ctrl + FRAC_OFFSET));
+}
+
 /**
  * zynqmp_pll_round_rate - Round a clock frequency
  * @hw:                Handle between common and hardware-specific interfaces
@@ -92,6 +113,12 @@ static long zynqmp_pll_round_rate(struct clk_hw *hw, unsigned long rate,
                unsigned long *prate)
 {
        u32 fbdiv;
+       long rate_div, f;
+
+       /* Enable the fractional mode if needed */
+       rate_div = ((rate * FRAC_DIV) / *prate);
+       f = rate_div % FRAC_DIV;
+       pll_frac_set_mode(hw, !!f);
 
        if (pll_frac_get_mode(hw) == PLL_MODE_FRAC) {
                if (rate > PS_PLL_VCO_MAX) {
@@ -150,12 +177,12 @@ static int zynqmp_pll_set_rate(struct clk_hw *hw, unsigned long rate,
        long rate_div, frac, m, f;
 
        if (pll_frac_get_mode(hw) == PLL_MODE_FRAC) {
-               rate_div = ((rate*1000000) / parent_rate);
-               m = rate_div / 1000000;
-               f = rate_div % 1000000;
+               rate_div = ((rate * FRAC_DIV) / parent_rate);
+               m = rate_div / FRAC_DIV;
+               f = rate_div % FRAC_DIV;
                m = clamp_t(u32, m, (PLL_FBDIV_MIN), (PLL_FBDIV_MAX));
                rate = parent_rate * m;
-               frac = (parent_rate * f) / 1000000;
+               frac = (parent_rate * f) / FRAC_DIV;
                reg = zynqmp_pm_mmio_readl(clk->pll_ctrl);
                reg &= ~PLLCTRL_FBDIV_MASK;
                reg |= m << PLLCTRL_FBDIV_SHIFT;
@@ -163,7 +190,7 @@ static int zynqmp_pll_set_rate(struct clk_hw *hw, unsigned long rate,
                reg = zynqmp_pm_mmio_readl(clk->pll_ctrl + FRAC_OFFSET);
                reg &= ~0xffff;
 
-               data = (FRAC_DIV * f) / 1000000;
+               data = (FRAC_DIV * f) / FRAC_DIV;
                data = data & 0xffff;
                reg |= data;
                zynqmp_pm_mmio_writel(reg, clk->pll_ctrl + FRAC_OFFSET);