clk: at91: make use of syscon/regmap internally
[cascardo/linux.git] / drivers / clk / at91 / clk-generated.c
index abc8094..5866684 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 #include "pmc.h"
 
@@ -28,8 +30,9 @@
 
 struct clk_generated {
        struct clk_hw hw;
-       struct at91_pmc *pmc;
+       struct regmap *regmap;
        struct clk_range range;
+       spinlock_t *lock;
        u32 id;
        u32 gckdiv;
        u8 parent_id;
@@ -41,49 +44,52 @@ struct clk_generated {
 static int clk_generated_enable(struct clk_hw *hw)
 {
        struct clk_generated *gck = to_clk_generated(hw);
-       struct at91_pmc *pmc = gck->pmc;
-       u32 tmp;
+       unsigned long flags;
 
        pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n",
                 __func__, gck->gckdiv, gck->parent_id);
 
-       pmc_lock(pmc);
-       pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK));
-       tmp = pmc_read(pmc, AT91_PMC_PCR) &
-                       ~(AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK);
-       pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_GCKCSS(gck->parent_id)
-                                        | AT91_PMC_PCR_CMD
-                                        | AT91_PMC_PCR_GCKDIV(gck->gckdiv)
-                                        | AT91_PMC_PCR_GCKEN);
-       pmc_unlock(pmc);
+       spin_lock_irqsave(gck->lock, flags);
+       regmap_write(gck->regmap, AT91_PMC_PCR,
+                    (gck->id & AT91_PMC_PCR_PID_MASK));
+       regmap_update_bits(gck->regmap, AT91_PMC_PCR,
+                          AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK |
+                          AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
+                          AT91_PMC_PCR_GCKCSS(gck->parent_id) |
+                          AT91_PMC_PCR_CMD |
+                          AT91_PMC_PCR_GCKDIV(gck->gckdiv) |
+                          AT91_PMC_PCR_GCKEN);
+       spin_unlock_irqrestore(gck->lock, flags);
        return 0;
 }
 
 static void clk_generated_disable(struct clk_hw *hw)
 {
        struct clk_generated *gck = to_clk_generated(hw);
-       struct at91_pmc *pmc = gck->pmc;
-       u32 tmp;
-
-       pmc_lock(pmc);
-       pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK));
-       tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_GCKEN;
-       pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD);
-       pmc_unlock(pmc);
+       unsigned long flags;
+
+       spin_lock_irqsave(gck->lock, flags);
+       regmap_write(gck->regmap, AT91_PMC_PCR,
+                    (gck->id & AT91_PMC_PCR_PID_MASK));
+       regmap_update_bits(gck->regmap, AT91_PMC_PCR,
+                          AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
+                          AT91_PMC_PCR_CMD);
+       spin_unlock_irqrestore(gck->lock, flags);
 }
 
 static int clk_generated_is_enabled(struct clk_hw *hw)
 {
        struct clk_generated *gck = to_clk_generated(hw);
-       struct at91_pmc *pmc = gck->pmc;
-       int ret;
+       unsigned long flags;
+       unsigned int status;
 
-       pmc_lock(pmc);
-       pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK));
-       ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_GCKEN);
-       pmc_unlock(pmc);
+       spin_lock_irqsave(gck->lock, flags);
+       regmap_write(gck->regmap, AT91_PMC_PCR,
+                    (gck->id & AT91_PMC_PCR_PID_MASK));
+       regmap_read(gck->regmap, AT91_PMC_PCR, &status);
+       spin_unlock_irqrestore(gck->lock, flags);
 
-       return ret;
+       return status & AT91_PMC_PCR_GCKEN ? 1 : 0;
 }
 
 static unsigned long
@@ -214,13 +220,14 @@ static const struct clk_ops generated_ops = {
  */
 static void clk_generated_startup(struct clk_generated *gck)
 {
-       struct at91_pmc *pmc = gck->pmc;
        u32 tmp;
+       unsigned long flags;
 
-       pmc_lock(pmc);
-       pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK));
-       tmp = pmc_read(pmc, AT91_PMC_PCR);
-       pmc_unlock(pmc);
+       spin_lock_irqsave(gck->lock, flags);
+       regmap_write(gck->regmap, AT91_PMC_PCR,
+                    (gck->id & AT91_PMC_PCR_PID_MASK));
+       regmap_read(gck->regmap, AT91_PMC_PCR, &tmp);
+       spin_unlock_irqrestore(gck->lock, flags);
 
        gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK)
                                        >> AT91_PMC_PCR_GCKCSS_OFFSET;
@@ -229,8 +236,8 @@ static void clk_generated_startup(struct clk_generated *gck)
 }
 
 static struct clk * __init
-at91_clk_register_generated(struct at91_pmc *pmc, const char *name,
-                           const char **parent_names, u8 num_parents,
+at91_clk_register_generated(struct regmap *regmap,  spinlock_t *lock, const char
+                           *name, const char **parent_names, u8 num_parents,
                            u8 id, const struct clk_range *range)
 {
        struct clk_generated *gck;
@@ -249,7 +256,8 @@ at91_clk_register_generated(struct at91_pmc *pmc, const char *name,
 
        gck->id = id;
        gck->hw.init = &init;
-       gck->pmc = pmc;
+       gck->regmap = regmap;
+       gck->lock = lock;
        gck->range = *range;
 
        clk = clk_register(NULL, &gck->hw);
@@ -261,8 +269,7 @@ at91_clk_register_generated(struct at91_pmc *pmc, const char *name,
        return clk;
 }
 
-void __init of_sama5d2_clk_generated_setup(struct device_node *np,
-                                          struct at91_pmc *pmc)
+void __init of_sama5d2_clk_generated_setup(struct device_node *np)
 {
        int num;
        u32 id;
@@ -272,6 +279,7 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np,
        const char *parent_names[GENERATED_SOURCE_MAX];
        struct device_node *gcknp;
        struct clk_range range = CLK_RANGE(0, 0);
+       struct regmap *regmap;
 
        num_parents = of_clk_get_parent_count(np);
        if (num_parents <= 0 || num_parents > GENERATED_SOURCE_MAX)
@@ -283,6 +291,10 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np,
        if (!num || num > PERIPHERAL_MAX)
                return;
 
+       regmap = syscon_node_to_regmap(of_get_parent(np));
+       if (IS_ERR(regmap))
+               return;
+
        for_each_child_of_node(np, gcknp) {
                if (of_property_read_u32(gcknp, "reg", &id))
                        continue;
@@ -296,11 +308,14 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np,
                of_at91_get_clk_range(gcknp, "atmel,clk-output-range",
                                      &range);
 
-               clk = at91_clk_register_generated(pmc, name, parent_names,
-                                                 num_parents, id, &range);
+               clk = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
+                                                 parent_names, num_parents,
+                                                 id, &range);
                if (IS_ERR(clk))
                        continue;
 
                of_clk_add_provider(gcknp, of_clk_src_simple_get, clk);
        }
 }
+CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated",
+              of_sama5d2_clk_generated_setup);