]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/clk/at91/clk-programmable.c
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
[mirror_ubuntu-artful-kernel.git] / drivers / clk / at91 / clk-programmable.c
index 14b270b85fec277a6fdea1ad0df260eeee95f27b..10f846cc8db172c5491ddc2508f7084ac5ef5e71 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,14 +43,12 @@ 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 int clk_programmable_determine_rate(struct clk_hw *hw,
@@ -101,36 +98,36 @@ 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);
+
+       ret = pckr & layout->css_mask;
 
-       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)
+       if (layout->have_slck_mck && (pckr & AT91_PMC_CSSMCK_MCK) && !ret)
                ret = PROG_MAX_RM9200_CSS + 1;
 
        return ret;
@@ -140,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;
 }
@@ -173,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)
@@ -198,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))
@@ -226,19 +224,20 @@ 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;
        struct clk *clk;
-       int num_parents;
+       unsigned int num_parents;
        const char *parent_names[PROG_SOURCE_MAX];
        const char *name;
        struct device_node *progclknp;
+       struct regmap *regmap;
 
        num_parents = of_clk_get_parent_count(np);
-       if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX)
+       if (num_parents == 0 || num_parents > PROG_SOURCE_MAX)
                return;
 
        of_clk_parent_fill(np, parent_names, num_parents);
@@ -247,6 +246,10 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
        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;
@@ -254,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))
@@ -265,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);