]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/clk/clk-divider.c
Merge tag 'mmc-updates-for-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / drivers / clk / clk-divider.c
index 6d9674160430db7456b58c1697272a801b68ba52..6d55eb2cb959baafc949cae9db15097f38c51c76 100644 (file)
@@ -150,6 +150,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
        struct clk_divider *divider = to_clk_divider(hw);
        int i, bestdiv = 0;
        unsigned long parent_rate, best = 0, now, maxdiv;
+       unsigned long parent_rate_saved = *best_parent_rate;
 
        if (!rate)
                rate = 1;
@@ -173,6 +174,15 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
        for (i = 1; i <= maxdiv; i++) {
                if (!_is_valid_div(divider, i))
                        continue;
+               if (rate * i == parent_rate_saved) {
+                       /*
+                        * It's the most ideal case if the requested rate can be
+                        * divided from parent clock without needing to change
+                        * parent rate, so return the divider immediately.
+                        */
+                       *best_parent_rate = parent_rate_saved;
+                       return i;
+               }
                parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
                                MULT_ROUND_UP(rate, i));
                now = parent_rate / i;
@@ -217,8 +227,12 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
        if (divider->lock)
                spin_lock_irqsave(divider->lock, flags);
 
-       val = readl(divider->reg);
-       val &= ~(div_mask(divider) << divider->shift);
+       if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
+               val = div_mask(divider) << (divider->shift + 16);
+       } else {
+               val = readl(divider->reg);
+               val &= ~(div_mask(divider) << divider->shift);
+       }
        val |= value << divider->shift;
        writel(val, divider->reg);
 
@@ -245,6 +259,13 @@ static struct clk *_register_divider(struct device *dev, const char *name,
        struct clk *clk;
        struct clk_init_data init;
 
+       if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
+               if (width + shift > 16) {
+                       pr_warn("divider value exceeds LOWORD field\n");
+                       return ERR_PTR(-EINVAL);
+               }
+       }
+
        /* allocate the divider */
        div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
        if (!div) {