Merge branch 'v4.3-topic/clk-samsung' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / drivers / clk / keystone / pll.c
index 0dd8a4b12747b6df0ce1c88f34aaf28781fe85f8..3f553d0ae0b5f885d3cee60c9f673870684f83fc 100644 (file)
@@ -10,7 +10,6 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  */
-#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -37,7 +36,8 @@
  *     Main PLL or any other PLLs in the device such as ARM PLL, DDR PLL
  *     or PA PLL available on keystone2. These PLLs are controlled by
  *     this register. Main PLL is controlled by a PLL controller.
- * @pllm: PLL register map address
+ * @pllm: PLL register map address for multiplier bits
+ * @pllod: PLL register map address for post divider bits
  * @pll_ctl0: PLL controller map address
  * @pllm_lower_mask: multiplier lower mask
  * @pllm_upper_mask: multiplier upper mask
@@ -53,6 +53,7 @@ struct clk_pll_data {
        u32 phy_pllm;
        u32 phy_pll_ctl0;
        void __iomem *pllm;
+       void __iomem *pllod;
        void __iomem *pll_ctl0;
        u32 pllm_lower_mask;
        u32 pllm_upper_mask;
@@ -102,7 +103,11 @@ static unsigned long clk_pllclk_recalc(struct clk_hw *hw,
                /* read post divider from od bits*/
                postdiv = ((val & pll_data->clkod_mask) >>
                                 pll_data->clkod_shift) + 1;
-       else
+       else if (pll_data->pllod) {
+               postdiv = readl(pll_data->pllod);
+               postdiv = ((postdiv & pll_data->clkod_mask) >>
+                               pll_data->clkod_shift) + 1;
+       } else
                postdiv = pll_data->postdiv;
 
        rate /= (prediv + 1);
@@ -172,12 +177,21 @@ static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl)
                /* assume the PLL has output divider register bits */
                pll_data->clkod_mask = CLKOD_MASK;
                pll_data->clkod_shift = CLKOD_SHIFT;
+
+               /*
+                * Check if there is an post-divider register. If not
+                * assume od bits are part of control register.
+                */
+               i = of_property_match_string(node, "reg-names",
+                                            "post-divider");
+               pll_data->pllod = of_iomap(node, i);
        }
 
        i = of_property_match_string(node, "reg-names", "control");
        pll_data->pll_ctl0 = of_iomap(node, i);
        if (!pll_data->pll_ctl0) {
                pr_err("%s: ioremap failed\n", __func__);
+               iounmap(pll_data->pllod);
                goto out;
        }
 
@@ -193,6 +207,7 @@ static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl)
                pll_data->pllm = of_iomap(node, i);
                if (!pll_data->pllm) {
                        iounmap(pll_data->pll_ctl0);
+                       iounmap(pll_data->pllod);
                        goto out;
                }
        }
@@ -293,8 +308,7 @@ static void __init of_pll_mux_clk_init(struct device_node *node)
                return;
        }
 
-       parents[0] = of_clk_get_parent_name(node, 0);
-       parents[1] = of_clk_get_parent_name(node, 1);
+       of_clk_parent_fill(node, parents, 2);
        if (!parents[0] || !parents[1]) {
                pr_err("%s: missing parent clocks\n", __func__);
                return;