Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
[linux-2.6-microblaze.git] / drivers / clk / zynqmp / divider.c
index 4be2cc7..66da02b 100644 (file)
@@ -25,7 +25,8 @@
 #define to_zynqmp_clk_divider(_hw)             \
        container_of(_hw, struct zynqmp_clk_divider, hw)
 
-#define CLK_FRAC       BIT(13) /* has a fractional parent */
+#define CLK_FRAC               BIT(13) /* has a fractional parent */
+#define CUSTOM_FLAG_CLK_FRAC   BIT(0) /* has a fractional parent in custom type flag */
 
 /**
  * struct zynqmp_clk_divider - adjustable divider clock
@@ -83,9 +84,8 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw,
        u32 div_type = divider->div_type;
        u32 div, value;
        int ret;
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
-       ret = eemi_ops->clock_getdivider(clk_id, &div);
+       ret = zynqmp_pm_clock_getdivider(clk_id, &div);
 
        if (ret)
                pr_warn_once("%s() get divider failed for %s, ret = %d\n",
@@ -111,23 +111,30 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw,
 
 static void zynqmp_get_divider2_val(struct clk_hw *hw,
                                    unsigned long rate,
-                                   unsigned long parent_rate,
                                    struct zynqmp_clk_divider *divider,
                                    int *bestdiv)
 {
        int div1;
        int div2;
        long error = LONG_MAX;
-       struct clk_hw *parent_hw = clk_hw_get_parent(hw);
-       struct zynqmp_clk_divider *pdivider = to_zynqmp_clk_divider(parent_hw);
+       unsigned long div1_prate;
+       struct clk_hw *div1_parent_hw;
+       struct clk_hw *div2_parent_hw = clk_hw_get_parent(hw);
+       struct zynqmp_clk_divider *pdivider =
+                               to_zynqmp_clk_divider(div2_parent_hw);
 
        if (!pdivider)
                return;
 
+       div1_parent_hw = clk_hw_get_parent(div2_parent_hw);
+       if (!div1_parent_hw)
+               return;
+
+       div1_prate = clk_hw_get_rate(div1_parent_hw);
        *bestdiv = 1;
        for (div1 = 1; div1 <= pdivider->max_div;) {
                for (div2 = 1; div2 <= divider->max_div;) {
-                       long new_error = ((parent_rate / div1) / div2) - rate;
+                       long new_error = ((div1_prate / div1) / div2) - rate;
 
                        if (abs(new_error) < abs(error)) {
                                *bestdiv = div2;
@@ -163,11 +170,10 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw,
        u32 div_type = divider->div_type;
        u32 bestdiv;
        int ret;
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
        /* if read only, just return current value */
        if (divider->flags & CLK_DIVIDER_READ_ONLY) {
-               ret = eemi_ops->clock_getdivider(clk_id, &bestdiv);
+               ret = zynqmp_pm_clock_getdivider(clk_id, &bestdiv);
 
                if (ret)
                        pr_warn_once("%s() get divider failed for %s, ret = %d\n",
@@ -192,11 +198,13 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw,
         */
        if (div_type == TYPE_DIV2 &&
            (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
-               zynqmp_get_divider2_val(hw, rate, *prate, divider, &bestdiv);
+               zynqmp_get_divider2_val(hw, rate, divider, &bestdiv);
        }
 
        if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && divider->is_frac)
                bestdiv = rate % *prate ? 1 : bestdiv;
+
+       bestdiv = min_t(u32, bestdiv, divider->max_div);
        *prate = rate * bestdiv;
 
        return rate;
@@ -219,7 +227,6 @@ static int zynqmp_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
        u32 div_type = divider->div_type;
        u32 value, div;
        int ret;
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
        value = zynqmp_divider_get_val(parent_rate, rate, divider->flags);
        if (div_type == TYPE_DIV1) {
@@ -233,7 +240,7 @@ static int zynqmp_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
        if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
                div = __ffs(div);
 
-       ret = eemi_ops->clock_setdivider(clk_id, div);
+       ret = zynqmp_pm_clock_setdivider(clk_id, div);
 
        if (ret)
                pr_warn_once("%s() set divider failed for %s, ret = %d\n",
@@ -256,9 +263,8 @@ static const struct clk_ops zynqmp_clk_divider_ops = {
  * Return: Maximum divisor of a clock if query data is successful
  *        U16_MAX in case of query data is not success
  */
-u32 zynqmp_clk_get_max_divisor(u32 clk_id, u32 type)
+static u32 zynqmp_clk_get_max_divisor(u32 clk_id, u32 type)
 {
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
        struct zynqmp_pm_query_data qdata = {0};
        u32 ret_payload[PAYLOAD_ARG_CNT];
        int ret;
@@ -266,7 +272,7 @@ u32 zynqmp_clk_get_max_divisor(u32 clk_id, u32 type)
        qdata.qid = PM_QID_CLOCK_GET_MAX_DIVISOR;
        qdata.arg1 = clk_id;
        qdata.arg2 = type;
-       ret = eemi_ops->query_data(qdata, ret_payload);
+       ret = zynqmp_pm_query_data(qdata, ret_payload);
        /*
         * To maintain backward compatibility return maximum possible value
         * (0xFFFF) if query for max divisor is not successful.
@@ -311,7 +317,8 @@ struct clk_hw *zynqmp_clk_register_divider(const char *name,
        init.num_parents = 1;
 
        /* struct clk_divider assignments */
-       div->is_frac = !!(nodes->flag & CLK_FRAC);
+       div->is_frac = !!((nodes->flag & CLK_FRAC) |
+                         (nodes->custom_type_flag & CUSTOM_FLAG_CLK_FRAC));
        div->flags = nodes->type_flag;
        div->hw.init = &init;
        div->clk_id = clk_id;