These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / clk / at91 / clk-programmable.c
index 86c8a07..bc0be62 100644 (file)
 #include <linux/clkdev.h>
 #include <linux/clk/at91_pmc.h>
 #include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/io.h>
-#include <linux/wait.h>
-#include <linux/sched.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 #include "pmc.h"
 
@@ -24,6 +22,7 @@
 
 #define PROG_STATUS_MASK(id)   (1 << ((id) + 8))
 #define PROG_PRES_MASK         0x7
+#define PROG_PRES(layout, pckr)        ((pckr >> layout->pres_shift) & PROG_PRES_MASK)
 #define PROG_MAX_RM9200_CSS    3
 
 struct clk_programmable_layout {
@@ -34,7 +33,7 @@ struct clk_programmable_layout {
 
 struct clk_programmable {
        struct clk_hw hw;
-       struct at91_pmc *pmc;
+       struct regmap *regmap;
        u8 id;
        const struct clk_programmable_layout *layout;
 };
@@ -44,92 +43,91 @@ struct clk_programmable {
 static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
                                                  unsigned long parent_rate)
 {
-       u32 pres;
        struct clk_programmable *prog = to_clk_programmable(hw);
-       struct at91_pmc *pmc = prog->pmc;
-       const struct clk_programmable_layout *layout = prog->layout;
+       unsigned int pckr;
+
+       regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
 
-       pres = (pmc_read(pmc, AT91_PMC_PCKR(prog->id)) >> layout->pres_shift) &
-              PROG_PRES_MASK;
-       return parent_rate >> pres;
+       return parent_rate >> PROG_PRES(prog->layout, pckr);
 }
 
-static long clk_programmable_determine_rate(struct clk_hw *hw,
-                                           unsigned long rate,
-                                           unsigned long min_rate,
-                                           unsigned long max_rate,
-                                           unsigned long *best_parent_rate,
-                                           struct clk_hw **best_parent_hw)
+static int clk_programmable_determine_rate(struct clk_hw *hw,
+                                          struct clk_rate_request *req)
 {
-       struct clk *parent = NULL;
+       struct clk_hw *parent;
        long best_rate = -EINVAL;
        unsigned long parent_rate;
        unsigned long tmp_rate;
        int shift;
        int i;
 
-       for (i = 0; i < __clk_get_num_parents(hw->clk); i++) {
-               parent = clk_get_parent_by_index(hw->clk, i);
+       for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
+               parent = clk_hw_get_parent_by_index(hw, i);
                if (!parent)
                        continue;
 
-               parent_rate = __clk_get_rate(parent);
+               parent_rate = clk_hw_get_rate(parent);
                for (shift = 0; shift < PROG_PRES_MASK; shift++) {
                        tmp_rate = parent_rate >> shift;
-                       if (tmp_rate <= rate)
+                       if (tmp_rate <= req->rate)
                                break;
                }
 
-               if (tmp_rate > rate)
+               if (tmp_rate > req->rate)
                        continue;
 
-               if (best_rate < 0 || (rate - tmp_rate) < (rate - best_rate)) {
+               if (best_rate < 0 ||
+                   (req->rate - tmp_rate) < (req->rate - best_rate)) {
                        best_rate = tmp_rate;
-                       *best_parent_rate = parent_rate;
-                       *best_parent_hw = __clk_get_hw(parent);
+                       req->best_parent_rate = parent_rate;
+                       req->best_parent_hw = parent;
                }
 
                if (!best_rate)
                        break;
        }
 
-       return best_rate;
+       if (best_rate < 0)
+               return best_rate;
+
+       req->rate = best_rate;
+       return 0;
 }
 
 static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
 {
        struct clk_programmable *prog = to_clk_programmable(hw);
        const struct clk_programmable_layout *layout = prog->layout;
-       struct at91_pmc *pmc = prog->pmc;
-       u32 tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)) & ~layout->css_mask;
+       unsigned int mask = layout->css_mask;
+       unsigned int pckr = 0;
 
        if (layout->have_slck_mck)
-               tmp &= AT91_PMC_CSSMCK_MCK;
+               mask |= AT91_PMC_CSSMCK_MCK;
 
        if (index > layout->css_mask) {
-               if (index > PROG_MAX_RM9200_CSS && layout->have_slck_mck) {
-                       tmp |= AT91_PMC_CSSMCK_MCK;
-                       return 0;
-               } else {
+               if (index > PROG_MAX_RM9200_CSS && !layout->have_slck_mck)
                        return -EINVAL;
-               }
+
+               pckr |= AT91_PMC_CSSMCK_MCK;
        }
 
-       pmc_write(pmc, AT91_PMC_PCKR(prog->id), tmp | index);
+       regmap_update_bits(prog->regmap, AT91_PMC_PCKR(prog->id), mask, pckr);
+
        return 0;
 }
 
 static u8 clk_programmable_get_parent(struct clk_hw *hw)
 {
-       u32 tmp;
-       u8 ret;
        struct clk_programmable *prog = to_clk_programmable(hw);
-       struct at91_pmc *pmc = prog->pmc;
        const struct clk_programmable_layout *layout = prog->layout;
+       unsigned int pckr;
+       u8 ret;
+
+       regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
 
-       tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
-       ret = tmp & layout->css_mask;
-       if (layout->have_slck_mck && (tmp & AT91_PMC_CSSMCK_MCK) && !ret)
+       ret = pckr & layout->css_mask;
+
+       if (layout->have_slck_mck && (pckr & AT91_PMC_CSSMCK_MCK) && !ret)
                ret = PROG_MAX_RM9200_CSS + 1;
 
        return ret;
@@ -139,26 +137,27 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
                                     unsigned long parent_rate)
 {
        struct clk_programmable *prog = to_clk_programmable(hw);
-       struct at91_pmc *pmc = prog->pmc;
        const struct clk_programmable_layout *layout = prog->layout;
        unsigned long div = parent_rate / rate;
+       unsigned int pckr;
        int shift = 0;
-       u32 tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)) &
-                 ~(PROG_PRES_MASK << layout->pres_shift);
+
+       regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
 
        if (!div)
                return -EINVAL;
 
        shift = fls(div) - 1;
 
-       if (div != (1<<shift))
+       if (div != (1 << shift))
                return -EINVAL;
 
        if (shift >= PROG_PRES_MASK)
                return -EINVAL;
 
-       pmc_write(pmc, AT91_PMC_PCKR(prog->id),
-                 tmp | (shift << layout->pres_shift));
+       regmap_update_bits(prog->regmap, AT91_PMC_PCKR(prog->id),
+                          PROG_PRES_MASK << layout->pres_shift,
+                          shift << layout->pres_shift);
 
        return 0;
 }
@@ -172,7 +171,7 @@ static const struct clk_ops programmable_ops = {
 };
 
 static struct clk * __init
-at91_clk_register_programmable(struct at91_pmc *pmc,
+at91_clk_register_programmable(struct regmap *regmap,
                               const char *name, const char **parent_names,
                               u8 num_parents, u8 id,
                               const struct clk_programmable_layout *layout)
@@ -197,7 +196,7 @@ at91_clk_register_programmable(struct at91_pmc *pmc,
        prog->id = id;
        prog->layout = layout;
        prog->hw.init = &init;
-       prog->pmc = pmc;
+       prog->regmap = regmap;
 
        clk = clk_register(NULL, &prog->hw);
        if (IS_ERR(clk))
@@ -225,32 +224,32 @@ static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
 };
 
 static void __init
-of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
+of_at91_clk_prog_setup(struct device_node *np,
                       const struct clk_programmable_layout *layout)
 {
        int num;
        u32 id;
-       int i;
        struct clk *clk;
        int num_parents;
        const char *parent_names[PROG_SOURCE_MAX];
        const char *name;
        struct device_node *progclknp;
+       struct regmap *regmap;
 
-       num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+       num_parents = of_clk_get_parent_count(np);
        if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX)
                return;
 
-       for (i = 0; i < num_parents; ++i) {
-               parent_names[i] = of_clk_get_parent_name(np, i);
-               if (!parent_names[i])
-                       return;
-       }
+       of_clk_parent_fill(np, parent_names, num_parents);
 
        num = of_get_child_count(np);
        if (!num || num > (PROG_ID_MAX + 1))
                return;
 
+       regmap = syscon_node_to_regmap(of_get_parent(np));
+       if (IS_ERR(regmap))
+               return;
+
        for_each_child_of_node(np, progclknp) {
                if (of_property_read_u32(progclknp, "reg", &id))
                        continue;
@@ -258,7 +257,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
                if (of_property_read_string(np, "clock-output-names", &name))
                        name = progclknp->name;
 
-               clk = at91_clk_register_programmable(pmc, name,
+               clk = at91_clk_register_programmable(regmap, name,
                                                     parent_names, num_parents,
                                                     id, layout);
                if (IS_ERR(clk))
@@ -269,20 +268,23 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
 }
 
 
-void __init of_at91rm9200_clk_prog_setup(struct device_node *np,
-                                        struct at91_pmc *pmc)
+static void __init of_at91rm9200_clk_prog_setup(struct device_node *np)
 {
-       of_at91_clk_prog_setup(np, pmc, &at91rm9200_programmable_layout);
+       of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout);
 }
+CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable",
+              of_at91rm9200_clk_prog_setup);
 
-void __init of_at91sam9g45_clk_prog_setup(struct device_node *np,
-                                         struct at91_pmc *pmc)
+static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np)
 {
-       of_at91_clk_prog_setup(np, pmc, &at91sam9g45_programmable_layout);
+       of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout);
 }
+CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable",
+              of_at91sam9g45_clk_prog_setup);
 
-void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
-                                        struct at91_pmc *pmc)
+static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
 {
-       of_at91_clk_prog_setup(np, pmc, &at91sam9x5_programmable_layout);
+       of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout);
 }
+CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable",
+              of_at91sam9x5_clk_prog_setup);