clk: mvebu: refactor corediv driver to support more SoC
authorThomas Petazzoni <thomas.petazzoni@free-electrons.com>
Fri, 14 Feb 2014 20:15:02 +0000 (17:15 -0300)
committerJason Cooper <jason@lakedaemon.net>
Mon, 17 Feb 2014 02:33:57 +0000 (02:33 +0000)
This commit refactors the corediv clock driver so that it is capable
of handling various SOCs that have slightly different corediv clock
registers and capabilities.

It introduces a clk_corediv_soc_desc structure that encapsulates all
the SoC specific details.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
drivers/clk/mvebu/clk-corediv.c

index 59db71df86a830c547eb8040fb5089d954749284..f9e8a120f22bfebe9821ff7ae142614b1d7409ab 100644 (file)
@@ -18,9 +18,6 @@
 #include "common.h"
 
 #define CORE_CLK_DIV_RATIO_MASK                0xff
-#define CORE_CLK_DIV_RATIO_RELOAD      BIT(8)
-#define CORE_CLK_DIV_ENABLE_OFFSET     24
-#define CORE_CLK_DIV_RATIO_OFFSET      0x8
 
 /*
  * This structure describes the hardware details (bit offset and mask)
@@ -35,6 +32,21 @@ struct clk_corediv_desc {
        unsigned int fieldbit;
 };
 
+/*
+ * This structure describes the hardware details to configure the core
+ * divider clocks on a given SoC. Amongst others, it points to the
+ * array of core divider clock descriptors for this SoC, as well as
+ * the corresponding operations to manipulate them.
+ */
+struct clk_corediv_soc_desc {
+       const struct clk_corediv_desc *descs;
+       unsigned int ndescs;
+       const struct clk_ops ops;
+       u32 ratio_reload;
+       u32 enable_bit_offset;
+       u32 ratio_offset;
+};
+
 /*
  * This structure represents one core divider clock for the clock
  * framework, and is dynamically allocated for each core divider clock
@@ -44,6 +56,7 @@ struct clk_corediv {
        struct clk_hw hw;
        void __iomem *reg;
        const struct clk_corediv_desc *desc;
+       const struct clk_corediv_soc_desc *soc_desc;
        spinlock_t lock;
 };
 
@@ -63,8 +76,9 @@ static const struct clk_corediv_desc mvebu_corediv_desc[] = {
 static int clk_corediv_is_enabled(struct clk_hw *hwclk)
 {
        struct clk_corediv *corediv = to_corediv_clk(hwclk);
+       const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
        const struct clk_corediv_desc *desc = corediv->desc;
-       u32 enable_mask = BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET;
+       u32 enable_mask = BIT(desc->fieldbit) << soc_desc->enable_bit_offset;
 
        return !!(readl(corediv->reg) & enable_mask);
 }
@@ -72,6 +86,7 @@ static int clk_corediv_is_enabled(struct clk_hw *hwclk)
 static int clk_corediv_enable(struct clk_hw *hwclk)
 {
        struct clk_corediv *corediv = to_corediv_clk(hwclk);
+       const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
        const struct clk_corediv_desc *desc = corediv->desc;
        unsigned long flags = 0;
        u32 reg;
@@ -79,7 +94,7 @@ static int clk_corediv_enable(struct clk_hw *hwclk)
        spin_lock_irqsave(&corediv->lock, flags);
 
        reg = readl(corediv->reg);
-       reg |= (BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET);
+       reg |= (BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
        writel(reg, corediv->reg);
 
        spin_unlock_irqrestore(&corediv->lock, flags);
@@ -90,6 +105,7 @@ static int clk_corediv_enable(struct clk_hw *hwclk)
 static void clk_corediv_disable(struct clk_hw *hwclk)
 {
        struct clk_corediv *corediv = to_corediv_clk(hwclk);
+       const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
        const struct clk_corediv_desc *desc = corediv->desc;
        unsigned long flags = 0;
        u32 reg;
@@ -97,7 +113,7 @@ static void clk_corediv_disable(struct clk_hw *hwclk)
        spin_lock_irqsave(&corediv->lock, flags);
 
        reg = readl(corediv->reg);
-       reg &= ~(BIT(desc->fieldbit) << CORE_CLK_DIV_ENABLE_OFFSET);
+       reg &= ~(BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
        writel(reg, corediv->reg);
 
        spin_unlock_irqrestore(&corediv->lock, flags);
@@ -107,10 +123,11 @@ static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk,
                                         unsigned long parent_rate)
 {
        struct clk_corediv *corediv = to_corediv_clk(hwclk);
+       const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
        const struct clk_corediv_desc *desc = corediv->desc;
        u32 reg, div;
 
-       reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET);
+       reg = readl(corediv->reg + soc_desc->ratio_offset);
        div = (reg >> desc->offset) & desc->mask;
        return parent_rate / div;
 }
@@ -134,6 +151,7 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
                            unsigned long parent_rate)
 {
        struct clk_corediv *corediv = to_corediv_clk(hwclk);
+       const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
        const struct clk_corediv_desc *desc = corediv->desc;
        unsigned long flags = 0;
        u32 reg, div;
@@ -143,17 +161,17 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
        spin_lock_irqsave(&corediv->lock, flags);
 
        /* Write new divider to the divider ratio register */
-       reg = readl(corediv->reg + CORE_CLK_DIV_RATIO_OFFSET);
+       reg = readl(corediv->reg + soc_desc->ratio_offset);
        reg &= ~(desc->mask << desc->offset);
        reg |= (div & desc->mask) << desc->offset;
-       writel(reg, corediv->reg + CORE_CLK_DIV_RATIO_OFFSET);
+       writel(reg, corediv->reg + soc_desc->ratio_offset);
 
        /* Set reload-force for this clock */
        reg = readl(corediv->reg) | BIT(desc->fieldbit);
        writel(reg, corediv->reg);
 
        /* Now trigger the clock update */
-       reg = readl(corediv->reg) | CORE_CLK_DIV_RATIO_RELOAD;
+       reg = readl(corediv->reg) | soc_desc->ratio_reload;
        writel(reg, corediv->reg);
 
        /*
@@ -161,7 +179,7 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
         * ratios request and the reload request.
         */
        udelay(1000);
-       reg &= ~(CORE_CLK_DIV_RATIO_MASK | CORE_CLK_DIV_RATIO_RELOAD);
+       reg &= ~(CORE_CLK_DIV_RATIO_MASK | soc_desc->ratio_reload);
        writel(reg, corediv->reg);
        udelay(1000);
 
@@ -170,16 +188,25 @@ static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
        return 0;
 }
 
-static const struct clk_ops corediv_ops = {
-       .enable = clk_corediv_enable,
-       .disable = clk_corediv_disable,
-       .is_enabled = clk_corediv_is_enabled,
-       .recalc_rate = clk_corediv_recalc_rate,
-       .round_rate = clk_corediv_round_rate,
-       .set_rate = clk_corediv_set_rate,
+static const struct clk_corediv_soc_desc armada370_corediv_soc = {
+       .descs = mvebu_corediv_desc,
+       .ndescs = ARRAY_SIZE(mvebu_corediv_desc),
+       .ops = {
+               .enable = clk_corediv_enable,
+               .disable = clk_corediv_disable,
+               .is_enabled = clk_corediv_is_enabled,
+               .recalc_rate = clk_corediv_recalc_rate,
+               .round_rate = clk_corediv_round_rate,
+               .set_rate = clk_corediv_set_rate,
+       },
+       .ratio_reload = BIT(8),
+       .enable_bit_offset = 24,
+       .ratio_offset = 0x8,
 };
 
-static void __init mvebu_corediv_clk_init(struct device_node *node)
+static void __init
+mvebu_corediv_clk_init(struct device_node *node,
+                      const struct clk_corediv_soc_desc *soc_desc)
 {
        struct clk_init_data init;
        struct clk_corediv *corediv;
@@ -195,7 +222,7 @@ static void __init mvebu_corediv_clk_init(struct device_node *node)
 
        parent_name = of_clk_get_parent_name(node, 0);
 
-       clk_data.clk_num = ARRAY_SIZE(mvebu_corediv_desc);
+       clk_data.clk_num = soc_desc->ndescs;
 
        /* clks holds the clock array */
        clks = kcalloc(clk_data.clk_num, sizeof(struct clk *),
@@ -216,10 +243,11 @@ static void __init mvebu_corediv_clk_init(struct device_node *node)
                init.num_parents = 1;
                init.parent_names = &parent_name;
                init.name = clk_name;
-               init.ops = &corediv_ops;
+               init.ops = &soc_desc->ops;
                init.flags = 0;
 
-               corediv[i].desc = mvebu_corediv_desc + i;
+               corediv[i].soc_desc = soc_desc;
+               corediv[i].desc = soc_desc->descs + i;
                corediv[i].reg = base;
                corediv[i].hw.init = &init;
 
@@ -236,5 +264,10 @@ err_free_clks:
 err_unmap:
        iounmap(base);
 }
-CLK_OF_DECLARE(mvebu_corediv_clk, "marvell,armada-370-corediv-clock",
-              mvebu_corediv_clk_init);
+
+static void __init armada370_corediv_clk_init(struct device_node *node)
+{
+       return mvebu_corediv_clk_init(node, &armada370_corediv_soc);
+}
+CLK_OF_DECLARE(armada370_corediv_clk, "marvell,armada-370-corediv-clock",
+              armada370_corediv_clk_init);
This page took 0.029557 seconds and 5 git commands to generate.