lkml.org 
[lkml]   [2015]   [Dec]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v3 02/13] clk: at91: make use of syscon/regmap internally
    Date
    From: Boris Brezillon <boris.brezillon@free-electrons.com>

    Use the regmap coming from syscon to access the registers instead of using
    pmc_read/pmc_write. This allows to avoid passing the at91_pmc structure to
    the child nodes of the PMC.

    The final benefit is to have each clock register itself instead of having
    to iterate over the children.

    Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
    Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
    ---
    drivers/clk/at91/clk-generated.c | 95 ++++++++------
    drivers/clk/at91/clk-h32mx.c | 32 +++--
    drivers/clk/at91/clk-main.c | 248 +++++++++++++++++++++++-------------
    drivers/clk/at91/clk-master.c | 68 ++++++----
    drivers/clk/at91/clk-peripheral.c | 135 ++++++++++++--------
    drivers/clk/at91/clk-pll.c | 119 ++++++++++-------
    drivers/clk/at91/clk-plldiv.c | 42 +++---
    drivers/clk/at91/clk-programmable.c | 92 +++++++------
    drivers/clk/at91/clk-slow.c | 27 ++--
    drivers/clk/at91/clk-smd.c | 54 ++++----
    drivers/clk/at91/clk-system.c | 60 +++++----
    drivers/clk/at91/clk-usb.c | 121 ++++++++++--------
    drivers/clk/at91/clk-utmi.c | 53 ++++----
    drivers/clk/at91/pmc.c | 155 ++--------------------
    drivers/clk/at91/pmc.h | 87 -------------
    15 files changed, 694 insertions(+), 694 deletions(-)

    diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c
    index abc80949e1dd..0b9e0aeef346 100644
    --- a/drivers/clk/at91/clk-generated.c
    +++ b/drivers/clk/at91/clk-generated.c
    @@ -17,9 +17,13 @@
    #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"

    +extern spinlock_t pmc_pcr_lock;
    +
    #define PERIPHERAL_MAX 64
    #define PERIPHERAL_ID_MIN 2

    @@ -28,8 +32,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 +46,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 +222,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 +238,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 +258,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 +271,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 +281,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 +293,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 +310,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);
    diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c
    index 61566bcefa53..3fd59b129f92 100644
    --- a/drivers/clk/at91/clk-h32mx.c
    +++ b/drivers/clk/at91/clk-h32mx.c
    @@ -24,6 +24,8 @@
    #include <linux/irq.h>
    #include <linux/sched.h>
    #include <linux/wait.h>
    +#include <linux/regmap.h>
    +#include <linux/mfd/syscon.h>

    #include "pmc.h"

    @@ -31,7 +33,7 @@

    struct clk_sama5d4_h32mx {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    };

    #define to_clk_sama5d4_h32mx(hw) container_of(hw, struct clk_sama5d4_h32mx, hw)
    @@ -40,8 +42,10 @@ static unsigned long clk_sama5d4_h32mx_recalc_rate(struct clk_hw *hw,
    unsigned long parent_rate)
    {
    struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw);
    + unsigned int mckr;

    - if (pmc_read(h32mxclk->pmc, AT91_PMC_MCKR) & AT91_PMC_H32MXDIV)
    + regmap_read(h32mxclk->regmap, AT91_PMC_MCKR, &mckr);
    + if (mckr & AT91_PMC_H32MXDIV)
    return parent_rate / 2;

    if (parent_rate > H32MX_MAX_FREQ)
    @@ -70,18 +74,16 @@ static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate,
    unsigned long parent_rate)
    {
    struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw);
    - struct at91_pmc *pmc = h32mxclk->pmc;
    - u32 tmp;
    + u32 mckr = 0;

    if (parent_rate != rate && (parent_rate / 2) != rate)
    return -EINVAL;

    - pmc_lock(pmc);
    - tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_H32MXDIV;
    if ((parent_rate / 2) == rate)
    - tmp |= AT91_PMC_H32MXDIV;
    - pmc_write(pmc, AT91_PMC_MCKR, tmp);
    - pmc_unlock(pmc);
    + mckr = AT91_PMC_H32MXDIV;
    +
    + regmap_update_bits(h32mxclk->regmap, AT91_PMC_MCKR,
    + AT91_PMC_H32MXDIV, mckr);

    return 0;
    }
    @@ -92,14 +94,18 @@ static const struct clk_ops h32mx_ops = {
    .set_rate = clk_sama5d4_h32mx_set_rate,
    };

    -void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
    {
    struct clk_sama5d4_h32mx *h32mxclk;
    struct clk_init_data init;
    const char *parent_name;
    + struct regmap *regmap;
    struct clk *clk;

    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;
    +
    h32mxclk = kzalloc(sizeof(*h32mxclk), GFP_KERNEL);
    if (!h32mxclk)
    return;
    @@ -113,7 +119,7 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
    init.flags = CLK_SET_RATE_GATE;

    h32mxclk->hw.init = &init;
    - h32mxclk->pmc = pmc;
    + h32mxclk->regmap = regmap;

    clk = clk_register(NULL, &h32mxclk->hw);
    if (!clk) {
    @@ -123,3 +129,5 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,

    of_clk_add_provider(np, of_clk_src_simple_get, clk);
    }
    +CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx",
    + of_sama5d4_clk_h32mx_setup);
    diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
    index fd7247deabdc..c1f119748bdc 100644
    --- a/drivers/clk/at91/clk-main.c
    +++ b/drivers/clk/at91/clk-main.c
    @@ -18,6 +18,8 @@
    #include <linux/io.h>
    #include <linux/interrupt.h>
    #include <linux/irq.h>
    +#include <linux/mfd/syscon.h>
    +#include <linux/regmap.h>
    #include <linux/sched.h>
    #include <linux/wait.h>

    @@ -34,7 +36,7 @@

    struct clk_main_osc {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    unsigned int irq;
    wait_queue_head_t wait;
    };
    @@ -43,7 +45,7 @@ struct clk_main_osc {

    struct clk_main_rc_osc {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    unsigned int irq;
    wait_queue_head_t wait;
    unsigned long frequency;
    @@ -54,14 +56,14 @@ struct clk_main_rc_osc {

    struct clk_rm9200_main {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    };

    #define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw)

    struct clk_sam9x5_main {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    unsigned int irq;
    wait_queue_head_t wait;
    u8 parent;
    @@ -79,25 +81,36 @@ static irqreturn_t clk_main_osc_irq_handler(int irq, void *dev_id)
    return IRQ_HANDLED;
    }

    +static inline bool clk_main_osc_ready(struct regmap *regmap)
    +{
    + unsigned int status;
    +
    + regmap_read(regmap, AT91_PMC_SR, &status);
    +
    + return status & AT91_PMC_MOSCS;
    +}
    +
    static int clk_main_osc_prepare(struct clk_hw *hw)
    {
    struct clk_main_osc *osc = to_clk_main_osc(hw);
    - struct at91_pmc *pmc = osc->pmc;
    + struct regmap *regmap = osc->regmap;
    u32 tmp;

    - tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK;
    + regmap_read(regmap, AT91_CKGR_MOR, &tmp);
    + tmp &= ~MOR_KEY_MASK;
    +
    if (tmp & AT91_PMC_OSCBYPASS)
    return 0;

    if (!(tmp & AT91_PMC_MOSCEN)) {
    tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
    - pmc_write(pmc, AT91_CKGR_MOR, tmp);
    + regmap_write(regmap, AT91_CKGR_MOR, tmp);
    }

    - while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) {
    + while (!clk_main_osc_ready(regmap)) {
    enable_irq(osc->irq);
    wait_event(osc->wait,
    - pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
    + clk_main_osc_ready(regmap));
    }

    return 0;
    @@ -106,9 +119,10 @@ static int clk_main_osc_prepare(struct clk_hw *hw)
    static void clk_main_osc_unprepare(struct clk_hw *hw)
    {
    struct clk_main_osc *osc = to_clk_main_osc(hw);
    - struct at91_pmc *pmc = osc->pmc;
    - u32 tmp = pmc_read(pmc, AT91_CKGR_MOR);
    + struct regmap *regmap = osc->regmap;
    + u32 tmp;

    + regmap_read(regmap, AT91_CKGR_MOR, &tmp);
    if (tmp & AT91_PMC_OSCBYPASS)
    return;

    @@ -116,20 +130,22 @@ static void clk_main_osc_unprepare(struct clk_hw *hw)
    return;

    tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
    - pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
    + regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
    }

    static int clk_main_osc_is_prepared(struct clk_hw *hw)
    {
    struct clk_main_osc *osc = to_clk_main_osc(hw);
    - struct at91_pmc *pmc = osc->pmc;
    - u32 tmp = pmc_read(pmc, AT91_CKGR_MOR);
    + struct regmap *regmap = osc->regmap;
    + u32 tmp, status;

    + regmap_read(regmap, AT91_CKGR_MOR, &tmp);
    if (tmp & AT91_PMC_OSCBYPASS)
    return 1;

    - return !!((pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS) &&
    - (pmc_read(pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCEN));
    + regmap_read(regmap, AT91_PMC_SR, &status);
    +
    + return (status & AT91_PMC_MOSCS) && (tmp & AT91_PMC_MOSCEN);
    }

    static const struct clk_ops main_osc_ops = {
    @@ -139,7 +155,7 @@ static const struct clk_ops main_osc_ops = {
    };

    static struct clk * __init
    -at91_clk_register_main_osc(struct at91_pmc *pmc,
    +at91_clk_register_main_osc(struct regmap *regmap,
    unsigned int irq,
    const char *name,
    const char *parent_name,
    @@ -150,7 +166,7 @@ at91_clk_register_main_osc(struct at91_pmc *pmc,
    struct clk *clk = NULL;
    struct clk_init_data init;

    - if (!pmc || !irq || !name || !parent_name)
    + if (!irq || !name || !parent_name)
    return ERR_PTR(-EINVAL);

    osc = kzalloc(sizeof(*osc), GFP_KERNEL);
    @@ -164,7 +180,7 @@ at91_clk_register_main_osc(struct at91_pmc *pmc,
    init.flags = CLK_IGNORE_UNUSED;

    osc->hw.init = &init;
    - osc->pmc = pmc;
    + osc->regmap = regmap;
    osc->irq = irq;

    init_waitqueue_head(&osc->wait);
    @@ -177,10 +193,10 @@ at91_clk_register_main_osc(struct at91_pmc *pmc,
    }

    if (bypass)
    - pmc_write(pmc, AT91_CKGR_MOR,
    - (pmc_read(pmc, AT91_CKGR_MOR) &
    - ~(MOR_KEY_MASK | AT91_PMC_MOSCEN)) |
    - AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
    + regmap_update_bits(regmap,
    + AT91_CKGR_MOR, MOR_KEY_MASK |
    + AT91_PMC_MOSCEN,
    + AT91_PMC_OSCBYPASS | AT91_PMC_KEY);

    clk = clk_register(NULL, &osc->hw);
    if (IS_ERR(clk)) {
    @@ -191,29 +207,35 @@ at91_clk_register_main_osc(struct at91_pmc *pmc,
    return clk;
    }

    -void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np)
    {
    struct clk *clk;
    unsigned int irq;
    const char *name = np->name;
    const char *parent_name;
    + struct regmap *regmap;
    bool bypass;

    of_property_read_string(np, "clock-output-names", &name);
    bypass = of_property_read_bool(np, "atmel,osc-bypass");
    parent_name = of_clk_get_parent_name(np, 0);

    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;
    +
    irq = irq_of_parse_and_map(np, 0);
    if (!irq)
    return;

    - clk = at91_clk_register_main_osc(pmc, irq, name, parent_name, bypass);
    + clk = at91_clk_register_main_osc(regmap, irq, name, parent_name, bypass);
    if (IS_ERR(clk))
    return;

    of_clk_add_provider(np, of_clk_src_simple_get, clk);
    }
    +CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc",
    + of_at91rm9200_clk_main_osc_setup);

    static irqreturn_t clk_main_rc_osc_irq_handler(int irq, void *dev_id)
    {
    @@ -225,23 +247,32 @@ static irqreturn_t clk_main_rc_osc_irq_handler(int irq, void *dev_id)
    return IRQ_HANDLED;
    }

    +static bool clk_main_rc_osc_ready(struct regmap *regmap)
    +{
    + unsigned int status;
    +
    + regmap_read(regmap, AT91_PMC_SR, &status);
    +
    + return status & AT91_PMC_MOSCRCS;
    +}
    +
    static int clk_main_rc_osc_prepare(struct clk_hw *hw)
    {
    struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
    - struct at91_pmc *pmc = osc->pmc;
    - u32 tmp;
    + struct regmap *regmap = osc->regmap;
    + unsigned int mor;

    - tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK;
    + regmap_read(regmap, AT91_CKGR_MOR, &mor);

    - if (!(tmp & AT91_PMC_MOSCRCEN)) {
    - tmp |= AT91_PMC_MOSCRCEN | AT91_PMC_KEY;
    - pmc_write(pmc, AT91_CKGR_MOR, tmp);
    - }
    + if (!(mor & AT91_PMC_MOSCRCEN))
    + regmap_update_bits(regmap, AT91_CKGR_MOR,
    + MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
    + AT91_PMC_MOSCRCEN | AT91_PMC_KEY);

    - while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS)) {
    + while (!clk_main_rc_osc_ready(regmap)) {
    enable_irq(osc->irq);
    wait_event(osc->wait,
    - pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS);
    + clk_main_rc_osc_ready(regmap));
    }

    return 0;
    @@ -250,23 +281,28 @@ static int clk_main_rc_osc_prepare(struct clk_hw *hw)
    static void clk_main_rc_osc_unprepare(struct clk_hw *hw)
    {
    struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
    - struct at91_pmc *pmc = osc->pmc;
    - u32 tmp = pmc_read(pmc, AT91_CKGR_MOR);
    + struct regmap *regmap = osc->regmap;
    + unsigned int mor;

    - if (!(tmp & AT91_PMC_MOSCRCEN))
    + regmap_read(regmap, AT91_CKGR_MOR, &mor);
    +
    + if (!(mor & AT91_PMC_MOSCRCEN))
    return;

    - tmp &= ~(MOR_KEY_MASK | AT91_PMC_MOSCRCEN);
    - pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
    + regmap_update_bits(regmap, AT91_CKGR_MOR,
    + MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY);
    }

    static int clk_main_rc_osc_is_prepared(struct clk_hw *hw)
    {
    struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
    - struct at91_pmc *pmc = osc->pmc;
    + struct regmap *regmap = osc->regmap;
    + unsigned int mor, status;
    +
    + regmap_read(regmap, AT91_CKGR_MOR, &mor);
    + regmap_read(regmap, AT91_PMC_SR, &status);

    - return !!((pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS) &&
    - (pmc_read(pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCRCEN));
    + return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS);
    }

    static unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw,
    @@ -294,7 +330,7 @@ static const struct clk_ops main_rc_osc_ops = {
    };

    static struct clk * __init
    -at91_clk_register_main_rc_osc(struct at91_pmc *pmc,
    +at91_clk_register_main_rc_osc(struct regmap *regmap,
    unsigned int irq,
    const char *name,
    u32 frequency, u32 accuracy)
    @@ -304,7 +340,7 @@ at91_clk_register_main_rc_osc(struct at91_pmc *pmc,
    struct clk *clk = NULL;
    struct clk_init_data init;

    - if (!pmc || !irq || !name || !frequency)
    + if (!name || !frequency)
    return ERR_PTR(-EINVAL);

    osc = kzalloc(sizeof(*osc), GFP_KERNEL);
    @@ -318,7 +354,7 @@ at91_clk_register_main_rc_osc(struct at91_pmc *pmc,
    init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED;

    osc->hw.init = &init;
    - osc->pmc = pmc;
    + osc->regmap = regmap;
    osc->irq = irq;
    osc->frequency = frequency;
    osc->accuracy = accuracy;
    @@ -339,14 +375,14 @@ at91_clk_register_main_rc_osc(struct at91_pmc *pmc,
    return clk;
    }

    -void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
    {
    struct clk *clk;
    unsigned int irq;
    u32 frequency = 0;
    u32 accuracy = 0;
    const char *name = np->name;
    + struct regmap *regmap;

    of_property_read_string(np, "clock-output-names", &name);
    of_property_read_u32(np, "clock-frequency", &frequency);
    @@ -356,25 +392,31 @@ void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np,
    if (!irq)
    return;

    - clk = at91_clk_register_main_rc_osc(pmc, irq, name, frequency,
    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;
    +
    + clk = at91_clk_register_main_rc_osc(regmap, irq, name, frequency,
    accuracy);
    if (IS_ERR(clk))
    return;

    of_clk_add_provider(np, of_clk_src_simple_get, clk);
    }
    +CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc",
    + of_at91sam9x5_clk_main_rc_osc_setup);


    -static int clk_main_probe_frequency(struct at91_pmc *pmc)
    +static int clk_main_probe_frequency(struct regmap *regmap)
    {
    unsigned long prep_time, timeout;
    - u32 tmp;
    + unsigned int mcfr;

    timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT);
    do {
    prep_time = jiffies;
    - tmp = pmc_read(pmc, AT91_CKGR_MCFR);
    - if (tmp & AT91_PMC_MAINRDY)
    + regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
    + if (mcfr & AT91_PMC_MAINRDY)
    return 0;
    usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
    } while (time_before(prep_time, timeout));
    @@ -382,34 +424,37 @@ static int clk_main_probe_frequency(struct at91_pmc *pmc)
    return -ETIMEDOUT;
    }

    -static unsigned long clk_main_recalc_rate(struct at91_pmc *pmc,
    +static unsigned long clk_main_recalc_rate(struct regmap *regmap,
    unsigned long parent_rate)
    {
    - u32 tmp;
    + unsigned int mcfr;

    if (parent_rate)
    return parent_rate;

    pr_warn("Main crystal frequency not set, using approximate value\n");
    - tmp = pmc_read(pmc, AT91_CKGR_MCFR);
    - if (!(tmp & AT91_PMC_MAINRDY))
    + regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
    + if (!(mcfr & AT91_PMC_MAINRDY))
    return 0;

    - return ((tmp & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
    + return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
    }

    static int clk_rm9200_main_prepare(struct clk_hw *hw)
    {
    struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);

    - return clk_main_probe_frequency(clkmain->pmc);
    + return clk_main_probe_frequency(clkmain->regmap);
    }

    static int clk_rm9200_main_is_prepared(struct clk_hw *hw)
    {
    struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
    + unsigned int status;
    +
    + regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);

    - return !!(pmc_read(clkmain->pmc, AT91_CKGR_MCFR) & AT91_PMC_MAINRDY);
    + return status & AT91_PMC_MAINRDY ? 1 : 0;
    }

    static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
    @@ -417,7 +462,7 @@ static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
    {
    struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);

    - return clk_main_recalc_rate(clkmain->pmc, parent_rate);
    + return clk_main_recalc_rate(clkmain->regmap, parent_rate);
    }

    static const struct clk_ops rm9200_main_ops = {
    @@ -427,7 +472,7 @@ static const struct clk_ops rm9200_main_ops = {
    };

    static struct clk * __init
    -at91_clk_register_rm9200_main(struct at91_pmc *pmc,
    +at91_clk_register_rm9200_main(struct regmap *regmap,
    const char *name,
    const char *parent_name)
    {
    @@ -435,7 +480,7 @@ at91_clk_register_rm9200_main(struct at91_pmc *pmc,
    struct clk *clk = NULL;
    struct clk_init_data init;

    - if (!pmc || !name)
    + if (!name)
    return ERR_PTR(-EINVAL);

    if (!parent_name)
    @@ -452,7 +497,7 @@ at91_clk_register_rm9200_main(struct at91_pmc *pmc,
    init.flags = 0;

    clkmain->hw.init = &init;
    - clkmain->pmc = pmc;
    + clkmain->regmap = regmap;

    clk = clk_register(NULL, &clkmain->hw);
    if (IS_ERR(clk))
    @@ -461,22 +506,28 @@ at91_clk_register_rm9200_main(struct at91_pmc *pmc,
    return clk;
    }

    -void __init of_at91rm9200_clk_main_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91rm9200_clk_main_setup(struct device_node *np)
    {
    struct clk *clk;
    const char *parent_name;
    const char *name = np->name;
    + struct regmap *regmap;

    parent_name = of_clk_get_parent_name(np, 0);
    of_property_read_string(np, "clock-output-names", &name);

    - clk = at91_clk_register_rm9200_main(pmc, name, parent_name);
    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;
    +
    + clk = at91_clk_register_rm9200_main(regmap, name, parent_name);
    if (IS_ERR(clk))
    return;

    of_clk_add_provider(np, of_clk_src_simple_get, clk);
    }
    +CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main",
    + of_at91rm9200_clk_main_setup);

    static irqreturn_t clk_sam9x5_main_irq_handler(int irq, void *dev_id)
    {
    @@ -488,25 +539,34 @@ static irqreturn_t clk_sam9x5_main_irq_handler(int irq, void *dev_id)
    return IRQ_HANDLED;
    }

    +static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
    +{
    + unsigned int status;
    +
    + regmap_read(regmap, AT91_PMC_SR, &status);
    +
    + return status & AT91_PMC_MOSCSELS ? 1 : 0;
    +}
    +
    static int clk_sam9x5_main_prepare(struct clk_hw *hw)
    {
    struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
    - struct at91_pmc *pmc = clkmain->pmc;
    + struct regmap *regmap = clkmain->regmap;

    - while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS)) {
    + while (!clk_sam9x5_main_ready(regmap)) {
    enable_irq(clkmain->irq);
    wait_event(clkmain->wait,
    - pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS);
    + clk_sam9x5_main_ready(regmap));
    }

    - return clk_main_probe_frequency(pmc);
    + return clk_main_probe_frequency(regmap);
    }

    static int clk_sam9x5_main_is_prepared(struct clk_hw *hw)
    {
    struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);

    - return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS);
    + return clk_sam9x5_main_ready(clkmain->regmap);
    }

    static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,
    @@ -514,29 +574,30 @@ static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,
    {
    struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);

    - return clk_main_recalc_rate(clkmain->pmc, parent_rate);
    + return clk_main_recalc_rate(clkmain->regmap, parent_rate);
    }

    static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
    {
    struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
    - struct at91_pmc *pmc = clkmain->pmc;
    - u32 tmp;
    + struct regmap *regmap = clkmain->regmap;
    + unsigned int tmp;

    if (index > 1)
    return -EINVAL;

    - tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK;
    + regmap_read(regmap, AT91_CKGR_MOR, &tmp);
    + tmp &= ~MOR_KEY_MASK;

    if (index && !(tmp & AT91_PMC_MOSCSEL))
    - pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
    + regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
    else if (!index && (tmp & AT91_PMC_MOSCSEL))
    - pmc_write(pmc, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
    + regmap_write(regmap, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);

    - while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS)) {
    + while (!clk_sam9x5_main_ready(regmap)) {
    enable_irq(clkmain->irq);
    wait_event(clkmain->wait,
    - pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS);
    + clk_sam9x5_main_ready(regmap));
    }

    return 0;
    @@ -545,8 +606,11 @@ static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
    static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw)
    {
    struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
    + unsigned int status;

    - return !!(pmc_read(clkmain->pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCEN);
    + regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
    +
    + return status & AT91_PMC_MOSCEN ? 1 : 0;
    }

    static const struct clk_ops sam9x5_main_ops = {
    @@ -558,7 +622,7 @@ static const struct clk_ops sam9x5_main_ops = {
    };

    static struct clk * __init
    -at91_clk_register_sam9x5_main(struct at91_pmc *pmc,
    +at91_clk_register_sam9x5_main(struct regmap *regmap,
    unsigned int irq,
    const char *name,
    const char **parent_names,
    @@ -568,8 +632,9 @@ at91_clk_register_sam9x5_main(struct at91_pmc *pmc,
    struct clk_sam9x5_main *clkmain;
    struct clk *clk = NULL;
    struct clk_init_data init;
    + unsigned int status;

    - if (!pmc || !irq || !name)
    + if (!name)
    return ERR_PTR(-EINVAL);

    if (!parent_names || !num_parents)
    @@ -586,10 +651,10 @@ at91_clk_register_sam9x5_main(struct at91_pmc *pmc,
    init.flags = CLK_SET_PARENT_GATE;

    clkmain->hw.init = &init;
    - clkmain->pmc = pmc;
    + clkmain->regmap = regmap;
    clkmain->irq = irq;
    - clkmain->parent = !!(pmc_read(clkmain->pmc, AT91_CKGR_MOR) &
    - AT91_PMC_MOSCEN);
    + regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
    + clkmain->parent = status & AT91_PMC_MOSCEN ? 1 : 0;
    init_waitqueue_head(&clkmain->wait);
    irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN);
    ret = request_irq(clkmain->irq, clk_sam9x5_main_irq_handler,
    @@ -606,20 +671,23 @@ at91_clk_register_sam9x5_main(struct at91_pmc *pmc,
    return clk;
    }

    -void __init of_at91sam9x5_clk_main_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
    {
    struct clk *clk;
    const char *parent_names[2];
    int num_parents;
    unsigned int irq;
    const char *name = np->name;
    + struct regmap *regmap;

    num_parents = of_clk_get_parent_count(np);
    if (num_parents <= 0 || num_parents > 2)
    return;

    of_clk_parent_fill(np, parent_names, num_parents);
    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;

    of_property_read_string(np, "clock-output-names", &name);

    @@ -627,10 +695,12 @@ void __init of_at91sam9x5_clk_main_setup(struct device_node *np,
    if (!irq)
    return;

    - clk = at91_clk_register_sam9x5_main(pmc, irq, name, parent_names,
    + clk = at91_clk_register_sam9x5_main(regmap, irq, name, parent_names,
    num_parents);
    if (IS_ERR(clk))
    return;

    of_clk_add_provider(np, of_clk_src_simple_get, clk);
    }
    +CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main",
    + of_at91sam9x5_clk_main_setup);
    diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
    index 620ea323356b..8d94ddfc9c72 100644
    --- a/drivers/clk/at91/clk-master.c
    +++ b/drivers/clk/at91/clk-master.c
    @@ -19,6 +19,8 @@
    #include <linux/sched.h>
    #include <linux/interrupt.h>
    #include <linux/irq.h>
    +#include <linux/mfd/syscon.h>
    +#include <linux/regmap.h>

    #include "pmc.h"

    @@ -44,7 +46,7 @@ struct clk_master_layout {

    struct clk_master {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    unsigned int irq;
    wait_queue_head_t wait;
    const struct clk_master_layout *layout;
    @@ -60,15 +62,24 @@ static irqreturn_t clk_master_irq_handler(int irq, void *dev_id)

    return IRQ_HANDLED;
    }
    +
    +static inline bool clk_master_ready(struct regmap *regmap)
    +{
    + unsigned int status;
    +
    + regmap_read(regmap, AT91_PMC_SR, &status);
    +
    + return status & AT91_PMC_MCKRDY ? 1 : 0;
    +}
    +
    static int clk_master_prepare(struct clk_hw *hw)
    {
    struct clk_master *master = to_clk_master(hw);
    - struct at91_pmc *pmc = master->pmc;

    - while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY)) {
    + while (!clk_master_ready(master->regmap)) {
    enable_irq(master->irq);
    wait_event(master->wait,
    - pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY);
    + clk_master_ready(master->regmap));
    }

    return 0;
    @@ -78,7 +89,7 @@ static int clk_master_is_prepared(struct clk_hw *hw)
    {
    struct clk_master *master = to_clk_master(hw);

    - return !!(pmc_read(master->pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY);
    + return clk_master_ready(master->regmap);
    }

    static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
    @@ -88,18 +99,16 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
    u8 div;
    unsigned long rate = parent_rate;
    struct clk_master *master = to_clk_master(hw);
    - struct at91_pmc *pmc = master->pmc;
    const struct clk_master_layout *layout = master->layout;
    const struct clk_master_characteristics *characteristics =
    master->characteristics;
    - u32 tmp;
    + unsigned int mckr;

    - pmc_lock(pmc);
    - tmp = pmc_read(pmc, AT91_PMC_MCKR) & layout->mask;
    - pmc_unlock(pmc);
    + regmap_read(master->regmap, AT91_PMC_MCKR, &mckr);
    + mckr &= layout->mask;

    - pres = (tmp >> layout->pres_shift) & MASTER_PRES_MASK;
    - div = (tmp >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
    + pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;
    + div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;

    if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX)
    rate /= 3;
    @@ -119,9 +128,11 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
    static u8 clk_master_get_parent(struct clk_hw *hw)
    {
    struct clk_master *master = to_clk_master(hw);
    - struct at91_pmc *pmc = master->pmc;
    + unsigned int mckr;
    +
    + regmap_read(master->regmap, AT91_PMC_MCKR, &mckr);

    - return pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_CSS;
    + return mckr & AT91_PMC_CSS;
    }

    static const struct clk_ops master_ops = {
    @@ -132,7 +143,7 @@ static const struct clk_ops master_ops = {
    };

    static struct clk * __init
    -at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq,
    +at91_clk_register_master(struct regmap *regmap, unsigned int irq,
    const char *name, int num_parents,
    const char **parent_names,
    const struct clk_master_layout *layout,
    @@ -143,7 +154,7 @@ at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq,
    struct clk *clk = NULL;
    struct clk_init_data init;

    - if (!pmc || !irq || !name || !num_parents || !parent_names)
    + if (!name || !num_parents || !parent_names)
    return ERR_PTR(-EINVAL);

    master = kzalloc(sizeof(*master), GFP_KERNEL);
    @@ -159,7 +170,7 @@ at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq,
    master->hw.init = &init;
    master->layout = layout;
    master->characteristics = characteristics;
    - master->pmc = pmc;
    + master->regmap = regmap;
    master->irq = irq;
    init_waitqueue_head(&master->wait);
    irq_set_status_flags(master->irq, IRQ_NOAUTOEN);
    @@ -217,7 +228,7 @@ out_free_characteristics:
    }

    static void __init
    -of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
    +of_at91_clk_master_setup(struct device_node *np,
    const struct clk_master_layout *layout)
    {
    struct clk *clk;
    @@ -226,6 +237,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
    const char *parent_names[MASTER_SOURCE_MAX];
    const char *name = np->name;
    struct clk_master_characteristics *characteristics;
    + struct regmap *regmap;

    num_parents = of_clk_get_parent_count(np);
    if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX)
    @@ -239,11 +251,15 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
    if (!characteristics)
    return;

    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;
    +
    irq = irq_of_parse_and_map(np, 0);
    if (!irq)
    goto out_free_characteristics;

    - clk = at91_clk_register_master(pmc, irq, name, num_parents,
    + clk = at91_clk_register_master(regmap, irq, name, num_parents,
    parent_names, layout,
    characteristics);
    if (IS_ERR(clk))
    @@ -256,14 +272,16 @@ out_free_characteristics:
    kfree(characteristics);
    }

    -void __init of_at91rm9200_clk_master_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91rm9200_clk_master_setup(struct device_node *np)
    {
    - of_at91_clk_master_setup(np, pmc, &at91rm9200_master_layout);
    + of_at91_clk_master_setup(np, &at91rm9200_master_layout);
    }
    +CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master",
    + of_at91rm9200_clk_master_setup);

    -void __init of_at91sam9x5_clk_master_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91sam9x5_clk_master_setup(struct device_node *np)
    {
    - of_at91_clk_master_setup(np, pmc, &at91sam9x5_master_layout);
    + of_at91_clk_master_setup(np, &at91sam9x5_master_layout);
    }
    +CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master",
    + of_at91sam9x5_clk_master_setup);
    diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
    index 58f3b568e9cb..33c31d43dd8d 100644
    --- a/drivers/clk/at91/clk-peripheral.c
    +++ b/drivers/clk/at91/clk-peripheral.c
    @@ -14,9 +14,13 @@
    #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"

    +DEFINE_SPINLOCK(pmc_pcr_lock);
    +
    #define PERIPHERAL_MAX 64

    #define PERIPHERAL_AT91RM9200 0
    @@ -33,7 +37,7 @@

    struct clk_peripheral {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    u32 id;
    };

    @@ -41,8 +45,9 @@ struct clk_peripheral {

    struct clk_sam9x5_peripheral {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    struct clk_range range;
    + spinlock_t *lock;
    u32 id;
    u32 div;
    bool auto_div;
    @@ -54,7 +59,6 @@ struct clk_sam9x5_peripheral {
    static int clk_peripheral_enable(struct clk_hw *hw)
    {
    struct clk_peripheral *periph = to_clk_peripheral(hw);
    - struct at91_pmc *pmc = periph->pmc;
    int offset = AT91_PMC_PCER;
    u32 id = periph->id;

    @@ -62,14 +66,14 @@ static int clk_peripheral_enable(struct clk_hw *hw)
    return 0;
    if (id > PERIPHERAL_ID_MAX)
    offset = AT91_PMC_PCER1;
    - pmc_write(pmc, offset, PERIPHERAL_MASK(id));
    + regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id));
    +
    return 0;
    }

    static void clk_peripheral_disable(struct clk_hw *hw)
    {
    struct clk_peripheral *periph = to_clk_peripheral(hw);
    - struct at91_pmc *pmc = periph->pmc;
    int offset = AT91_PMC_PCDR;
    u32 id = periph->id;

    @@ -77,21 +81,23 @@ static void clk_peripheral_disable(struct clk_hw *hw)
    return;
    if (id > PERIPHERAL_ID_MAX)
    offset = AT91_PMC_PCDR1;
    - pmc_write(pmc, offset, PERIPHERAL_MASK(id));
    + regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id));
    }

    static int clk_peripheral_is_enabled(struct clk_hw *hw)
    {
    struct clk_peripheral *periph = to_clk_peripheral(hw);
    - struct at91_pmc *pmc = periph->pmc;
    int offset = AT91_PMC_PCSR;
    + unsigned int status;
    u32 id = periph->id;

    if (id < PERIPHERAL_ID_MIN)
    return 1;
    if (id > PERIPHERAL_ID_MAX)
    offset = AT91_PMC_PCSR1;
    - return !!(pmc_read(pmc, offset) & PERIPHERAL_MASK(id));
    + regmap_read(periph->regmap, offset, &status);
    +
    + return status & PERIPHERAL_MASK(id) ? 1 : 0;
    }

    static const struct clk_ops peripheral_ops = {
    @@ -101,14 +107,14 @@ static const struct clk_ops peripheral_ops = {
    };

    static struct clk * __init
    -at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name,
    +at91_clk_register_peripheral(struct regmap *regmap, const char *name,
    const char *parent_name, u32 id)
    {
    struct clk_peripheral *periph;
    struct clk *clk = NULL;
    struct clk_init_data init;

    - if (!pmc || !name || !parent_name || id > PERIPHERAL_ID_MAX)
    + if (!name || !parent_name || id > PERIPHERAL_ID_MAX)
    return ERR_PTR(-EINVAL);

    periph = kzalloc(sizeof(*periph), GFP_KERNEL);
    @@ -123,7 +129,7 @@ at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name,

    periph->id = id;
    periph->hw.init = &init;
    - periph->pmc = pmc;
    + periph->regmap = regmap;

    clk = clk_register(NULL, &periph->hw);
    if (IS_ERR(clk))
    @@ -160,53 +166,58 @@ static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
    static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
    {
    struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
    - struct at91_pmc *pmc = periph->pmc;
    - u32 tmp;
    + unsigned long flags;

    if (periph->id < PERIPHERAL_ID_MIN)
    return 0;

    - pmc_lock(pmc);
    - pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK));
    - tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_DIV_MASK;
    - pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_DIV(periph->div)
    - | AT91_PMC_PCR_CMD
    - | AT91_PMC_PCR_EN);
    - pmc_unlock(pmc);
    + spin_lock_irqsave(periph->lock, flags);
    + regmap_write(periph->regmap, AT91_PMC_PCR,
    + (periph->id & AT91_PMC_PCR_PID_MASK));
    + regmap_update_bits(periph->regmap, AT91_PMC_PCR,
    + AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD |
    + AT91_PMC_PCR_EN,
    + AT91_PMC_PCR_DIV(periph->div) |
    + AT91_PMC_PCR_CMD |
    + AT91_PMC_PCR_EN);
    + spin_unlock_irqrestore(periph->lock, flags);
    +
    return 0;
    }

    static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
    {
    struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
    - struct at91_pmc *pmc = periph->pmc;
    - u32 tmp;
    + unsigned long flags;

    if (periph->id < PERIPHERAL_ID_MIN)
    return;

    - pmc_lock(pmc);
    - pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK));
    - tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_EN;
    - pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD);
    - pmc_unlock(pmc);
    + spin_lock_irqsave(periph->lock, flags);
    + regmap_write(periph->regmap, AT91_PMC_PCR,
    + (periph->id & AT91_PMC_PCR_PID_MASK));
    + regmap_update_bits(periph->regmap, AT91_PMC_PCR,
    + AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD,
    + AT91_PMC_PCR_CMD);
    + spin_unlock_irqrestore(periph->lock, flags);
    }

    static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
    {
    struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
    - struct at91_pmc *pmc = periph->pmc;
    - int ret;
    + unsigned long flags;
    + unsigned int status;

    if (periph->id < PERIPHERAL_ID_MIN)
    return 1;

    - pmc_lock(pmc);
    - pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK));
    - ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_EN);
    - pmc_unlock(pmc);
    + spin_lock_irqsave(periph->lock, flags);
    + regmap_write(periph->regmap, AT91_PMC_PCR,
    + (periph->id & AT91_PMC_PCR_PID_MASK));
    + regmap_read(periph->regmap, AT91_PMC_PCR, &status);
    + spin_unlock_irqrestore(periph->lock, flags);

    - return ret;
    + return status & AT91_PMC_PCR_EN ? 1 : 0;
    }

    static unsigned long
    @@ -214,19 +225,20 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
    unsigned long parent_rate)
    {
    struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
    - struct at91_pmc *pmc = periph->pmc;
    - u32 tmp;
    + unsigned long flags;
    + unsigned int status;

    if (periph->id < PERIPHERAL_ID_MIN)
    return parent_rate;

    - pmc_lock(pmc);
    - pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK));
    - tmp = pmc_read(pmc, AT91_PMC_PCR);
    - pmc_unlock(pmc);
    + spin_lock_irqsave(periph->lock, flags);
    + regmap_write(periph->regmap, AT91_PMC_PCR,
    + (periph->id & AT91_PMC_PCR_PID_MASK));
    + regmap_read(periph->regmap, AT91_PMC_PCR, &status);
    + spin_unlock_irqrestore(periph->lock, flags);

    - if (tmp & AT91_PMC_PCR_EN) {
    - periph->div = PERIPHERAL_RSHIFT(tmp);
    + if (status & AT91_PMC_PCR_EN) {
    + periph->div = PERIPHERAL_RSHIFT(status);
    periph->auto_div = false;
    } else {
    clk_sam9x5_peripheral_autodiv(periph);
    @@ -318,15 +330,15 @@ static const struct clk_ops sam9x5_peripheral_ops = {
    };

    static struct clk * __init
    -at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name,
    - const char *parent_name, u32 id,
    - const struct clk_range *range)
    +at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
    + const char *name, const char *parent_name,
    + u32 id, const struct clk_range *range)
    {
    struct clk_sam9x5_peripheral *periph;
    struct clk *clk = NULL;
    struct clk_init_data init;

    - if (!pmc || !name || !parent_name)
    + if (!name || !parent_name)
    return ERR_PTR(-EINVAL);

    periph = kzalloc(sizeof(*periph), GFP_KERNEL);
    @@ -342,7 +354,8 @@ at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name,
    periph->id = id;
    periph->hw.init = &init;
    periph->div = 0;
    - periph->pmc = pmc;
    + periph->regmap = regmap;
    + periph->lock = lock;
    periph->auto_div = true;
    periph->range = *range;

    @@ -356,7 +369,7 @@ at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name,
    }

    static void __init
    -of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
    +of_at91_clk_periph_setup(struct device_node *np, u8 type)
    {
    int num;
    u32 id;
    @@ -364,6 +377,7 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
    const char *parent_name;
    const char *name;
    struct device_node *periphclknp;
    + struct regmap *regmap;

    parent_name = of_clk_get_parent_name(np, 0);
    if (!parent_name)
    @@ -373,6 +387,10 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
    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, periphclknp) {
    if (of_property_read_u32(periphclknp, "reg", &id))
    continue;
    @@ -384,7 +402,7 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
    name = periphclknp->name;

    if (type == PERIPHERAL_AT91RM9200) {
    - clk = at91_clk_register_peripheral(pmc, name,
    + clk = at91_clk_register_peripheral(regmap, name,
    parent_name, id);
    } else {
    struct clk_range range = CLK_RANGE(0, 0);
    @@ -393,7 +411,9 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
    "atmel,clk-output-range",
    &range);

    - clk = at91_clk_register_sam9x5_peripheral(pmc, name,
    + clk = at91_clk_register_sam9x5_peripheral(regmap,
    + &pmc_pcr_lock,
    + name,
    parent_name,
    id, &range);
    }
    @@ -405,14 +425,17 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
    }
    }

    -void __init of_at91rm9200_clk_periph_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91rm9200_clk_periph_setup(struct device_node *np)
    {
    - of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91RM9200);
    + of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200);
    }
    +CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral",
    + of_at91rm9200_clk_periph_setup);

    -void __init of_at91sam9x5_clk_periph_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np)
    {
    - of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91SAM9X5);
    + of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5);
    }
    +CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral",
    + of_at91sam9x5_clk_periph_setup);
    +
    diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c
    index 18b60f4895a6..5f4c6ce628e0 100644
    --- a/drivers/clk/at91/clk-pll.c
    +++ b/drivers/clk/at91/clk-pll.c
    @@ -20,6 +20,8 @@
    #include <linux/sched.h>
    #include <linux/interrupt.h>
    #include <linux/irq.h>
    +#include <linux/mfd/syscon.h>
    +#include <linux/regmap.h>

    #include "pmc.h"

    @@ -58,7 +60,7 @@ struct clk_pll_layout {

    struct clk_pll {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    unsigned int irq;
    wait_queue_head_t wait;
    u8 id;
    @@ -79,10 +81,19 @@ static irqreturn_t clk_pll_irq_handler(int irq, void *dev_id)
    return IRQ_HANDLED;
    }

    +static inline bool clk_pll_ready(struct regmap *regmap, int id)
    +{
    + unsigned int status;
    +
    + regmap_read(regmap, AT91_PMC_SR, &status);
    +
    + return status & PLL_STATUS_MASK(id) ? 1 : 0;
    +}
    +
    static int clk_pll_prepare(struct clk_hw *hw)
    {
    struct clk_pll *pll = to_clk_pll(hw);
    - struct at91_pmc *pmc = pll->pmc;
    + struct regmap *regmap = pll->regmap;
    const struct clk_pll_layout *layout = pll->layout;
    const struct clk_pll_characteristics *characteristics =
    pll->characteristics;
    @@ -90,38 +101,36 @@ static int clk_pll_prepare(struct clk_hw *hw)
    u32 mask = PLL_STATUS_MASK(id);
    int offset = PLL_REG(id);
    u8 out = 0;
    - u32 pllr, icpr;
    + unsigned int pllr;
    + unsigned int status;
    u8 div;
    u16 mul;

    - pllr = pmc_read(pmc, offset);
    + regmap_read(regmap, offset, &pllr);
    div = PLL_DIV(pllr);
    mul = PLL_MUL(pllr, layout);

    - if ((pmc_read(pmc, AT91_PMC_SR) & mask) &&
    + regmap_read(regmap, AT91_PMC_SR, &status);
    + if ((status & mask) &&
    (div == pll->div && mul == pll->mul))
    return 0;

    if (characteristics->out)
    out = characteristics->out[pll->range];
    - if (characteristics->icpll) {
    - icpr = pmc_read(pmc, AT91_PMC_PLLICPR) & ~PLL_ICPR_MASK(id);
    - icpr |= (characteristics->icpll[pll->range] <<
    - PLL_ICPR_SHIFT(id));
    - pmc_write(pmc, AT91_PMC_PLLICPR, icpr);
    - }

    - pllr &= ~layout->pllr_mask;
    - pllr |= layout->pllr_mask &
    - (pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) |
    - (out << PLL_OUT_SHIFT) |
    - ((pll->mul & layout->mul_mask) << layout->mul_shift));
    - pmc_write(pmc, offset, pllr);
    + if (characteristics->icpll)
    + regmap_update_bits(regmap, AT91_PMC_PLLICPR, PLL_ICPR_MASK(id),
    + characteristics->icpll[pll->range] << PLL_ICPR_SHIFT(id));

    - while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) {
    + regmap_update_bits(regmap, offset, layout->pllr_mask,
    + pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) |
    + (out << PLL_OUT_SHIFT) |
    + ((pll->mul & layout->mul_mask) << layout->mul_shift));
    +
    + while (!clk_pll_ready(regmap, pll->id)) {
    enable_irq(pll->irq);
    wait_event(pll->wait,
    - pmc_read(pmc, AT91_PMC_SR) & mask);
    + clk_pll_ready(regmap, pll->id));
    }

    return 0;
    @@ -130,32 +139,35 @@ static int clk_pll_prepare(struct clk_hw *hw)
    static int clk_pll_is_prepared(struct clk_hw *hw)
    {
    struct clk_pll *pll = to_clk_pll(hw);
    - struct at91_pmc *pmc = pll->pmc;

    - return !!(pmc_read(pmc, AT91_PMC_SR) &
    - PLL_STATUS_MASK(pll->id));
    + return clk_pll_ready(pll->regmap, pll->id);
    }

    static void clk_pll_unprepare(struct clk_hw *hw)
    {
    struct clk_pll *pll = to_clk_pll(hw);
    - struct at91_pmc *pmc = pll->pmc;
    - const struct clk_pll_layout *layout = pll->layout;
    - int offset = PLL_REG(pll->id);
    - u32 tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask);
    + unsigned int mask = pll->layout->pllr_mask;

    - pmc_write(pmc, offset, tmp);
    + regmap_update_bits(pll->regmap, PLL_REG(pll->id), mask, ~mask);
    }

    static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
    unsigned long parent_rate)
    {
    struct clk_pll *pll = to_clk_pll(hw);
    + unsigned int pllr;
    + u16 mul;
    + u8 div;
    +
    + regmap_read(pll->regmap, PLL_REG(pll->id), &pllr);
    +
    + div = PLL_DIV(pllr);
    + mul = PLL_MUL(pllr, pll->layout);

    - if (!pll->div || !pll->mul)
    + if (!div || !mul)
    return 0;

    - return (parent_rate / pll->div) * (pll->mul + 1);
    + return (parent_rate / div) * (mul + 1);
    }

    static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
    @@ -308,7 +320,7 @@ static const struct clk_ops pll_ops = {
    };

    static struct clk * __init
    -at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
    +at91_clk_register_pll(struct regmap *regmap, unsigned int irq, const char *name,
    const char *parent_name, u8 id,
    const struct clk_pll_layout *layout,
    const struct clk_pll_characteristics *characteristics)
    @@ -318,7 +330,7 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
    struct clk_init_data init;
    int ret;
    int offset = PLL_REG(id);
    - u32 tmp;
    + unsigned int pllr;

    if (id > PLL_MAX_ID)
    return ERR_PTR(-EINVAL);
    @@ -337,11 +349,11 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
    pll->hw.init = &init;
    pll->layout = layout;
    pll->characteristics = characteristics;
    - pll->pmc = pmc;
    + pll->regmap = regmap;
    pll->irq = irq;
    - tmp = pmc_read(pmc, offset) & layout->pllr_mask;
    - pll->div = PLL_DIV(tmp);
    - pll->mul = PLL_MUL(tmp, layout);
    + regmap_read(regmap, offset, &pllr);
    + pll->div = PLL_DIV(pllr);
    + pll->mul = PLL_MUL(pllr, layout);
    init_waitqueue_head(&pll->wait);
    irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
    ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH,
    @@ -483,12 +495,13 @@ out_free_characteristics:
    }

    static void __init
    -of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc,
    +of_at91_clk_pll_setup(struct device_node *np,
    const struct clk_pll_layout *layout)
    {
    u32 id;
    unsigned int irq;
    struct clk *clk;
    + struct regmap *regmap;
    const char *parent_name;
    const char *name = np->name;
    struct clk_pll_characteristics *characteristics;
    @@ -500,6 +513,10 @@ of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc,

    of_property_read_string(np, "clock-output-names", &name);

    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;
    +
    characteristics = of_at91_clk_pll_get_characteristics(np);
    if (!characteristics)
    return;
    @@ -508,7 +525,7 @@ of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc,
    if (!irq)
    return;

    - clk = at91_clk_register_pll(pmc, irq, name, parent_name, id, layout,
    + clk = at91_clk_register_pll(regmap, irq, name, parent_name, id, layout,
    characteristics);
    if (IS_ERR(clk))
    goto out_free_characteristics;
    @@ -520,26 +537,30 @@ out_free_characteristics:
    kfree(characteristics);
    }

    -void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91rm9200_clk_pll_setup(struct device_node *np)
    {
    - of_at91_clk_pll_setup(np, pmc, &at91rm9200_pll_layout);
    + of_at91_clk_pll_setup(np, &at91rm9200_pll_layout);
    }
    +CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll",
    + of_at91rm9200_clk_pll_setup);

    -void __init of_at91sam9g45_clk_pll_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np)
    {
    - of_at91_clk_pll_setup(np, pmc, &at91sam9g45_pll_layout);
    + of_at91_clk_pll_setup(np, &at91sam9g45_pll_layout);
    }
    +CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll",
    + of_at91sam9g45_clk_pll_setup);

    -void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np)
    {
    - of_at91_clk_pll_setup(np, pmc, &at91sam9g20_pllb_layout);
    + of_at91_clk_pll_setup(np, &at91sam9g20_pllb_layout);
    }
    +CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb",
    + of_at91sam9g20_clk_pllb_setup);

    -void __init of_sama5d3_clk_pll_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_sama5d3_clk_pll_setup(struct device_node *np)
    {
    - of_at91_clk_pll_setup(np, pmc, &sama5d3_pll_layout);
    + of_at91_clk_pll_setup(np, &sama5d3_pll_layout);
    }
    +CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll",
    + of_sama5d3_clk_pll_setup);
    diff --git a/drivers/clk/at91/clk-plldiv.c b/drivers/clk/at91/clk-plldiv.c
    index ea226562bb40..f43e93738a99 100644
    --- a/drivers/clk/at91/clk-plldiv.c
    +++ b/drivers/clk/at91/clk-plldiv.c
    @@ -14,6 +14,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"

    @@ -21,16 +23,18 @@

    struct clk_plldiv {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    };

    static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw,
    unsigned long parent_rate)
    {
    struct clk_plldiv *plldiv = to_clk_plldiv(hw);
    - struct at91_pmc *pmc = plldiv->pmc;
    + unsigned int mckr;

    - if (pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_PLLADIV2)
    + regmap_read(plldiv->regmap, AT91_PMC_MCKR, &mckr);
    +
    + if (mckr & AT91_PMC_PLLADIV2)
    return parent_rate / 2;

    return parent_rate;
    @@ -57,18 +61,12 @@ static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate,
    unsigned long parent_rate)
    {
    struct clk_plldiv *plldiv = to_clk_plldiv(hw);
    - struct at91_pmc *pmc = plldiv->pmc;
    - u32 tmp;

    - if (parent_rate != rate && (parent_rate / 2) != rate)
    + if ((parent_rate != rate) && (parent_rate / 2 != rate))
    return -EINVAL;

    - pmc_lock(pmc);
    - tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_PLLADIV2;
    - if ((parent_rate / 2) == rate)
    - tmp |= AT91_PMC_PLLADIV2;
    - pmc_write(pmc, AT91_PMC_MCKR, tmp);
    - pmc_unlock(pmc);
    + regmap_update_bits(plldiv->regmap, AT91_PMC_MCKR, AT91_PMC_PLLADIV2,
    + parent_rate != rate ? AT91_PMC_PLLADIV2 : 0);

    return 0;
    }
    @@ -80,7 +78,7 @@ static const struct clk_ops plldiv_ops = {
    };

    static struct clk * __init
    -at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name,
    +at91_clk_register_plldiv(struct regmap *regmap, const char *name,
    const char *parent_name)
    {
    struct clk_plldiv *plldiv;
    @@ -98,7 +96,7 @@ at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name,
    init.flags = CLK_SET_RATE_GATE;

    plldiv->hw.init = &init;
    - plldiv->pmc = pmc;
    + plldiv->regmap = regmap;

    clk = clk_register(NULL, &plldiv->hw);

    @@ -109,27 +107,27 @@ at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name,
    }

    static void __init
    -of_at91_clk_plldiv_setup(struct device_node *np, struct at91_pmc *pmc)
    +of_at91sam9x5_clk_plldiv_setup(struct device_node *np)
    {
    struct clk *clk;
    const char *parent_name;
    const char *name = np->name;
    + struct regmap *regmap;

    parent_name = of_clk_get_parent_name(np, 0);

    of_property_read_string(np, "clock-output-names", &name);

    - clk = at91_clk_register_plldiv(pmc, name, parent_name);
    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;

    + clk = at91_clk_register_plldiv(regmap, name, parent_name);
    if (IS_ERR(clk))
    return;

    of_clk_add_provider(np, of_clk_src_simple_get, clk);
    return;
    }
    -
    -void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    -{
    - of_at91_clk_plldiv_setup(np, pmc);
    -}
    +CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv",
    + of_at91sam9x5_clk_plldiv_setup);
    diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
    index 14b270b85fec..78814ba448c4 100644
    --- a/drivers/clk/at91/clk-programmable.c
    +++ b/drivers/clk/at91/clk-programmable.c
    @@ -16,6 +16,8 @@
    #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 +26,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 +37,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 +47,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 +102,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 +141,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 +175,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 +200,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,7 +228,7 @@ 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;
    @@ -236,6 +238,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
    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)
    @@ -247,6 +250,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 +261,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 +272,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);
    diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c
    index d0d5076a9b94..d4e3521216fd 100644
    --- a/drivers/clk/at91/clk-slow.c
    +++ b/drivers/clk/at91/clk-slow.c
    @@ -22,6 +22,8 @@
    #include <linux/io.h>
    #include <linux/interrupt.h>
    #include <linux/irq.h>
    +#include <linux/mfd/syscon.h>
    +#include <linux/regmap.h>
    #include <linux/sched.h>
    #include <linux/wait.h>

    @@ -59,7 +61,7 @@ struct clk_slow_rc_osc {

    struct clk_sam9260_slow {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    };

    #define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
    @@ -393,8 +395,11 @@ void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
    static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
    {
    struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
    + unsigned int status;

    - return !!(pmc_read(slowck->pmc, AT91_PMC_SR) & AT91_PMC_OSCSEL);
    + regmap_read(slowck->regmap, AT91_PMC_SR, &status);
    +
    + return status & AT91_PMC_OSCSEL ? 1 : 0;
    }

    static const struct clk_ops sam9260_slow_ops = {
    @@ -402,7 +407,7 @@ static const struct clk_ops sam9260_slow_ops = {
    };

    static struct clk * __init
    -at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
    +at91_clk_register_sam9260_slow(struct regmap *regmap,
    const char *name,
    const char **parent_names,
    int num_parents)
    @@ -411,7 +416,7 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
    struct clk *clk = NULL;
    struct clk_init_data init;

    - if (!pmc || !name)
    + if (!name)
    return ERR_PTR(-EINVAL);

    if (!parent_names || !num_parents)
    @@ -428,7 +433,7 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
    init.flags = 0;

    slowck->hw.init = &init;
    - slowck->pmc = pmc;
    + slowck->regmap = regmap;

    clk = clk_register(NULL, &slowck->hw);
    if (IS_ERR(clk))
    @@ -439,23 +444,26 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
    return clk;
    }

    -void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
    {
    struct clk *clk;
    const char *parent_names[2];
    int num_parents;
    const char *name = np->name;
    + struct regmap *regmap;

    num_parents = of_clk_get_parent_count(np);
    if (num_parents != 2)
    return;

    of_clk_parent_fill(np, parent_names, num_parents);
    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;

    of_property_read_string(np, "clock-output-names", &name);

    - clk = at91_clk_register_sam9260_slow(pmc, name, parent_names,
    + clk = at91_clk_register_sam9260_slow(regmap, name, parent_names,
    num_parents);
    if (IS_ERR(clk))
    return;
    @@ -463,6 +471,9 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
    of_clk_add_provider(np, of_clk_src_simple_get, clk);
    }

    +CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
    + of_at91sam9260_clk_slow_setup);
    +
    /*
    * FIXME: All slow clk users are not properly claiming it (get + prepare +
    * enable) before using it.
    diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c
    index a7f8501cfa05..0f6e8d67e630 100644
    --- a/drivers/clk/at91/clk-smd.c
    +++ b/drivers/clk/at91/clk-smd.c
    @@ -14,6 +14,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"

    @@ -24,7 +26,7 @@

    struct at91sam9x5_clk_smd {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    };

    #define to_at91sam9x5_clk_smd(hw) \
    @@ -33,13 +35,13 @@ struct at91sam9x5_clk_smd {
    static unsigned long at91sam9x5_clk_smd_recalc_rate(struct clk_hw *hw,
    unsigned long parent_rate)
    {
    - u32 tmp;
    - u8 smddiv;
    struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
    - struct at91_pmc *pmc = smd->pmc;
    + unsigned int smdr;
    + u8 smddiv;
    +
    + regmap_read(smd->regmap, AT91_PMC_SMD, &smdr);
    + smddiv = (smdr & AT91_PMC_SMD_DIV) >> SMD_DIV_SHIFT;

    - tmp = pmc_read(pmc, AT91_PMC_SMD);
    - smddiv = (tmp & AT91_PMC_SMD_DIV) >> SMD_DIV_SHIFT;
    return parent_rate / (smddiv + 1);
    }

    @@ -67,40 +69,38 @@ static long at91sam9x5_clk_smd_round_rate(struct clk_hw *hw, unsigned long rate,

    static int at91sam9x5_clk_smd_set_parent(struct clk_hw *hw, u8 index)
    {
    - u32 tmp;
    struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
    - struct at91_pmc *pmc = smd->pmc;

    if (index > 1)
    return -EINVAL;
    - tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMDS;
    - if (index)
    - tmp |= AT91_PMC_SMDS;
    - pmc_write(pmc, AT91_PMC_SMD, tmp);
    +
    + regmap_update_bits(smd->regmap, AT91_PMC_SMD, AT91_PMC_SMDS,
    + index ? AT91_PMC_SMDS : 0);
    +
    return 0;
    }

    static u8 at91sam9x5_clk_smd_get_parent(struct clk_hw *hw)
    {
    struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
    - struct at91_pmc *pmc = smd->pmc;
    + unsigned int smdr;

    - return pmc_read(pmc, AT91_PMC_SMD) & AT91_PMC_SMDS;
    + regmap_read(smd->regmap, AT91_PMC_SMD, &smdr);
    +
    + return smdr & AT91_PMC_SMDS;
    }

    static int at91sam9x5_clk_smd_set_rate(struct clk_hw *hw, unsigned long rate,
    unsigned long parent_rate)
    {
    - u32 tmp;
    struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
    - struct at91_pmc *pmc = smd->pmc;
    unsigned long div = parent_rate / rate;

    if (parent_rate % rate || div < 1 || div > (SMD_MAX_DIV + 1))
    return -EINVAL;
    - tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMD_DIV;
    - tmp |= (div - 1) << SMD_DIV_SHIFT;
    - pmc_write(pmc, AT91_PMC_SMD, tmp);
    +
    + regmap_update_bits(smd->regmap, AT91_PMC_SMD, AT91_PMC_SMD_DIV,
    + (div - 1) << SMD_DIV_SHIFT);

    return 0;
    }
    @@ -114,7 +114,7 @@ static const struct clk_ops at91sam9x5_smd_ops = {
    };

    static struct clk * __init
    -at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name,
    +at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name,
    const char **parent_names, u8 num_parents)
    {
    struct at91sam9x5_clk_smd *smd;
    @@ -132,7 +132,7 @@ at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name,
    init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;

    smd->hw.init = &init;
    - smd->pmc = pmc;
    + smd->regmap = regmap;

    clk = clk_register(NULL, &smd->hw);
    if (IS_ERR(clk))
    @@ -141,13 +141,13 @@ at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name,
    return clk;
    }

    -void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np)
    {
    struct clk *clk;
    int num_parents;
    const char *parent_names[SMD_SOURCE_MAX];
    const char *name = np->name;
    + struct regmap *regmap;

    num_parents = of_clk_get_parent_count(np);
    if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX)
    @@ -157,10 +157,16 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,

    of_property_read_string(np, "clock-output-names", &name);

    - clk = at91sam9x5_clk_register_smd(pmc, name, parent_names,
    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;
    +
    + clk = at91sam9x5_clk_register_smd(regmap, name, parent_names,
    num_parents);
    if (IS_ERR(clk))
    return;

    of_clk_add_provider(np, of_clk_src_simple_get, clk);
    }
    +CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd",
    + of_at91sam9x5_clk_smd_setup);
    diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
    index 3f5314344286..0593adf1bf4b 100644
    --- a/drivers/clk/at91/clk-system.c
    +++ b/drivers/clk/at91/clk-system.c
    @@ -19,6 +19,8 @@
    #include <linux/interrupt.h>
    #include <linux/wait.h>
    #include <linux/sched.h>
    +#include <linux/mfd/syscon.h>
    +#include <linux/regmap.h>

    #include "pmc.h"

    @@ -29,7 +31,7 @@
    #define to_clk_system(hw) container_of(hw, struct clk_system, hw)
    struct clk_system {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    unsigned int irq;
    wait_queue_head_t wait;
    u8 id;
    @@ -49,24 +51,32 @@ static irqreturn_t clk_system_irq_handler(int irq, void *dev_id)
    return IRQ_HANDLED;
    }

    +static inline bool clk_system_ready(struct regmap *regmap, int id)
    +{
    + unsigned int status;
    +
    + regmap_read(regmap, AT91_PMC_SR, &status);
    +
    + return status & (1 << id) ? 1 : 0;
    +}
    +
    static int clk_system_prepare(struct clk_hw *hw)
    {
    struct clk_system *sys = to_clk_system(hw);
    - struct at91_pmc *pmc = sys->pmc;
    - u32 mask = 1 << sys->id;

    - pmc_write(pmc, AT91_PMC_SCER, mask);
    + regmap_write(sys->regmap, AT91_PMC_SCER, 1 << sys->id);

    if (!is_pck(sys->id))
    return 0;

    - while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) {
    + while (!clk_system_ready(sys->regmap, sys->id)) {
    if (sys->irq) {
    enable_irq(sys->irq);
    wait_event(sys->wait,
    - pmc_read(pmc, AT91_PMC_SR) & mask);
    - } else
    + clk_system_ready(sys->regmap, sys->id));
    + } else {
    cpu_relax();
    + }
    }
    return 0;
    }
    @@ -74,23 +84,26 @@ static int clk_system_prepare(struct clk_hw *hw)
    static void clk_system_unprepare(struct clk_hw *hw)
    {
    struct clk_system *sys = to_clk_system(hw);
    - struct at91_pmc *pmc = sys->pmc;

    - pmc_write(pmc, AT91_PMC_SCDR, 1 << sys->id);
    + regmap_write(sys->regmap, AT91_PMC_SCDR, 1 << sys->id);
    }

    static int clk_system_is_prepared(struct clk_hw *hw)
    {
    struct clk_system *sys = to_clk_system(hw);
    - struct at91_pmc *pmc = sys->pmc;
    + unsigned int status;
    +
    + regmap_read(sys->regmap, AT91_PMC_SCSR, &status);

    - if (!(pmc_read(pmc, AT91_PMC_SCSR) & (1 << sys->id)))
    + if (!(status & (1 << sys->id)))
    return 0;

    if (!is_pck(sys->id))
    return 1;

    - return !!(pmc_read(pmc, AT91_PMC_SR) & (1 << sys->id));
    + regmap_read(sys->regmap, AT91_PMC_SR, &status);
    +
    + return status & (1 << sys->id) ? 1 : 0;
    }

    static const struct clk_ops system_ops = {
    @@ -100,7 +113,7 @@ static const struct clk_ops system_ops = {
    };

    static struct clk * __init
    -at91_clk_register_system(struct at91_pmc *pmc, const char *name,
    +at91_clk_register_system(struct regmap *regmap, const char *name,
    const char *parent_name, u8 id, int irq)
    {
    struct clk_system *sys;
    @@ -123,7 +136,7 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name,

    sys->id = id;
    sys->hw.init = &init;
    - sys->pmc = pmc;
    + sys->regmap = regmap;
    sys->irq = irq;
    if (irq) {
    init_waitqueue_head(&sys->wait);
    @@ -146,8 +159,7 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name,
    return clk;
    }

    -static void __init
    -of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc)
    +static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
    {
    int num;
    int irq = 0;
    @@ -156,11 +168,16 @@ of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc)
    const char *name;
    struct device_node *sysclknp;
    const char *parent_name;
    + struct regmap *regmap;

    num = of_get_child_count(np);
    if (num > (SYSTEM_MAX_ID + 1))
    return;

    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;
    +
    for_each_child_of_node(np, sysclknp) {
    if (of_property_read_u32(sysclknp, "reg", &id))
    continue;
    @@ -173,16 +190,13 @@ of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc)

    parent_name = of_clk_get_parent_name(sysclknp, 0);

    - clk = at91_clk_register_system(pmc, name, parent_name, id, irq);
    + clk = at91_clk_register_system(regmap, name, parent_name, id,
    + irq);
    if (IS_ERR(clk))
    continue;

    of_clk_add_provider(sysclknp, of_clk_src_simple_get, clk);
    }
    }
    -
    -void __init of_at91rm9200_clk_sys_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    -{
    - of_at91_clk_sys_setup(np, pmc);
    -}
    +CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system",
    + of_at91rm9200_clk_sys_setup);
    diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
    index 8ab8502778a2..617e24f6ef76 100644
    --- a/drivers/clk/at91/clk-usb.c
    +++ b/drivers/clk/at91/clk-usb.c
    @@ -14,6 +14,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"

    @@ -27,7 +29,7 @@

    struct at91sam9x5_clk_usb {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    };

    #define to_at91sam9x5_clk_usb(hw) \
    @@ -35,7 +37,7 @@ struct at91sam9x5_clk_usb {

    struct at91rm9200_clk_usb {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    u32 divisors[4];
    };

    @@ -45,13 +47,12 @@ struct at91rm9200_clk_usb {
    static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw,
    unsigned long parent_rate)
    {
    - u32 tmp;
    - u8 usbdiv;
    struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
    - struct at91_pmc *pmc = usb->pmc;
    + unsigned int usbr;
    + u8 usbdiv;

    - tmp = pmc_read(pmc, AT91_PMC_USB);
    - usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT;
    + regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
    + usbdiv = (usbr & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT;

    return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1));
    }
    @@ -109,33 +110,31 @@ static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,

    static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
    {
    - u32 tmp;
    struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
    - struct at91_pmc *pmc = usb->pmc;

    if (index > 1)
    return -EINVAL;
    - tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS;
    - if (index)
    - tmp |= AT91_PMC_USBS;
    - pmc_write(pmc, AT91_PMC_USB, tmp);
    +
    + regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS,
    + index ? AT91_PMC_USBS : 0);
    +
    return 0;
    }

    static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw)
    {
    struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
    - struct at91_pmc *pmc = usb->pmc;
    + unsigned int usbr;

    - return pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS;
    + regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
    +
    + return usbr & AT91_PMC_USBS;
    }

    static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
    unsigned long parent_rate)
    {
    - u32 tmp;
    struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
    - struct at91_pmc *pmc = usb->pmc;
    unsigned long div;

    if (!rate)
    @@ -145,9 +144,8 @@ static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
    if (div > SAM9X5_USB_MAX_DIV + 1 || !div)
    return -EINVAL;

    - tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV;
    - tmp |= (div - 1) << SAM9X5_USB_DIV_SHIFT;
    - pmc_write(pmc, AT91_PMC_USB, tmp);
    + regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_OHCIUSBDIV,
    + (div - 1) << SAM9X5_USB_DIV_SHIFT);

    return 0;
    }
    @@ -163,28 +161,28 @@ static const struct clk_ops at91sam9x5_usb_ops = {
    static int at91sam9n12_clk_usb_enable(struct clk_hw *hw)
    {
    struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
    - struct at91_pmc *pmc = usb->pmc;

    - pmc_write(pmc, AT91_PMC_USB,
    - pmc_read(pmc, AT91_PMC_USB) | AT91_PMC_USBS);
    + regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS,
    + AT91_PMC_USBS);
    +
    return 0;
    }

    static void at91sam9n12_clk_usb_disable(struct clk_hw *hw)
    {
    struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
    - struct at91_pmc *pmc = usb->pmc;

    - pmc_write(pmc, AT91_PMC_USB,
    - pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS);
    + regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, 0);
    }

    static int at91sam9n12_clk_usb_is_enabled(struct clk_hw *hw)
    {
    struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
    - struct at91_pmc *pmc = usb->pmc;
    + unsigned int usbr;

    - return !!(pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS);
    + regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
    +
    + return usbr & AT91_PMC_USBS;
    }

    static const struct clk_ops at91sam9n12_usb_ops = {
    @@ -197,7 +195,7 @@ static const struct clk_ops at91sam9n12_usb_ops = {
    };

    static struct clk * __init
    -at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name,
    +at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
    const char **parent_names, u8 num_parents)
    {
    struct at91sam9x5_clk_usb *usb;
    @@ -216,7 +214,7 @@ at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name,
    CLK_SET_RATE_PARENT;

    usb->hw.init = &init;
    - usb->pmc = pmc;
    + usb->regmap = regmap;

    clk = clk_register(NULL, &usb->hw);
    if (IS_ERR(clk))
    @@ -226,7 +224,7 @@ at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name,
    }

    static struct clk * __init
    -at91sam9n12_clk_register_usb(struct at91_pmc *pmc, const char *name,
    +at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
    const char *parent_name)
    {
    struct at91sam9x5_clk_usb *usb;
    @@ -244,7 +242,7 @@ at91sam9n12_clk_register_usb(struct at91_pmc *pmc, const char *name,
    init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT;

    usb->hw.init = &init;
    - usb->pmc = pmc;
    + usb->regmap = regmap;

    clk = clk_register(NULL, &usb->hw);
    if (IS_ERR(clk))
    @@ -257,12 +255,12 @@ static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw,
    unsigned long parent_rate)
    {
    struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
    - struct at91_pmc *pmc = usb->pmc;
    - u32 tmp;
    + unsigned int pllbr;
    u8 usbdiv;

    - tmp = pmc_read(pmc, AT91_CKGR_PLLBR);
    - usbdiv = (tmp & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT;
    + regmap_read(usb->regmap, AT91_CKGR_PLLBR, &pllbr);
    +
    + usbdiv = (pllbr & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT;
    if (usb->divisors[usbdiv])
    return parent_rate / usb->divisors[usbdiv];

    @@ -310,10 +308,8 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
    static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
    unsigned long parent_rate)
    {
    - u32 tmp;
    int i;
    struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
    - struct at91_pmc *pmc = usb->pmc;
    unsigned long div;

    if (!rate)
    @@ -323,10 +319,10 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,

    for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
    if (usb->divisors[i] == div) {
    - tmp = pmc_read(pmc, AT91_CKGR_PLLBR) &
    - ~AT91_PMC_USBDIV;
    - tmp |= i << RM9200_USB_DIV_SHIFT;
    - pmc_write(pmc, AT91_CKGR_PLLBR, tmp);
    + regmap_update_bits(usb->regmap, AT91_CKGR_PLLBR,
    + AT91_PMC_USBDIV,
    + i << RM9200_USB_DIV_SHIFT);
    +
    return 0;
    }
    }
    @@ -341,7 +337,7 @@ static const struct clk_ops at91rm9200_usb_ops = {
    };

    static struct clk * __init
    -at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
    +at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
    const char *parent_name, const u32 *divisors)
    {
    struct at91rm9200_clk_usb *usb;
    @@ -359,7 +355,7 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
    init.flags = CLK_SET_RATE_PARENT;

    usb->hw.init = &init;
    - usb->pmc = pmc;
    + usb->regmap = regmap;
    memcpy(usb->divisors, divisors, sizeof(usb->divisors));

    clk = clk_register(NULL, &usb->hw);
    @@ -369,13 +365,13 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
    return clk;
    }

    -void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np)
    {
    struct clk *clk;
    int num_parents;
    const char *parent_names[USB_SOURCE_MAX];
    const char *name = np->name;
    + struct regmap *regmap;

    num_parents = of_clk_get_parent_count(np);
    if (num_parents <= 0 || num_parents > USB_SOURCE_MAX)
    @@ -385,19 +381,26 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,

    of_property_read_string(np, "clock-output-names", &name);

    - clk = at91sam9x5_clk_register_usb(pmc, name, parent_names, num_parents);
    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;
    +
    + clk = at91sam9x5_clk_register_usb(regmap, name, parent_names,
    + num_parents);
    if (IS_ERR(clk))
    return;

    of_clk_add_provider(np, of_clk_src_simple_get, clk);
    }
    +CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb",
    + of_at91sam9x5_clk_usb_setup);

    -void __init of_at91sam9n12_clk_usb_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np)
    {
    struct clk *clk;
    const char *parent_name;
    const char *name = np->name;
    + struct regmap *regmap;

    parent_name = of_clk_get_parent_name(np, 0);
    if (!parent_name)
    @@ -405,20 +408,26 @@ void __init of_at91sam9n12_clk_usb_setup(struct device_node *np,

    of_property_read_string(np, "clock-output-names", &name);

    - clk = at91sam9n12_clk_register_usb(pmc, name, parent_name);
    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;
    +
    + clk = at91sam9n12_clk_register_usb(regmap, name, parent_name);
    if (IS_ERR(clk))
    return;

    of_clk_add_provider(np, of_clk_src_simple_get, clk);
    }
    +CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb",
    + of_at91sam9n12_clk_usb_setup);

    -void __init of_at91rm9200_clk_usb_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    +static void __init of_at91rm9200_clk_usb_setup(struct device_node *np)
    {
    struct clk *clk;
    const char *parent_name;
    const char *name = np->name;
    u32 divisors[4] = {0, 0, 0, 0};
    + struct regmap *regmap;

    parent_name = of_clk_get_parent_name(np, 0);
    if (!parent_name)
    @@ -430,9 +439,15 @@ void __init of_at91rm9200_clk_usb_setup(struct device_node *np,

    of_property_read_string(np, "clock-output-names", &name);

    - clk = at91rm9200_clk_register_usb(pmc, name, parent_name, divisors);
    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;
    +
    + clk = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors);
    if (IS_ERR(clk))
    return;

    of_clk_add_provider(np, of_clk_src_simple_get, clk);
    }
    +CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb",
    + of_at91rm9200_clk_usb_setup);
    diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c
    index ca561e90a60f..58a310e5768c 100644
    --- a/drivers/clk/at91/clk-utmi.c
    +++ b/drivers/clk/at91/clk-utmi.c
    @@ -19,6 +19,8 @@
    #include <linux/io.h>
    #include <linux/sched.h>
    #include <linux/wait.h>
    +#include <linux/mfd/syscon.h>
    +#include <linux/regmap.h>

    #include "pmc.h"

    @@ -26,7 +28,7 @@

    struct clk_utmi {
    struct clk_hw hw;
    - struct at91_pmc *pmc;
    + struct regmap *regmap;
    unsigned int irq;
    wait_queue_head_t wait;
    };
    @@ -43,19 +45,27 @@ static irqreturn_t clk_utmi_irq_handler(int irq, void *dev_id)
    return IRQ_HANDLED;
    }

    +static inline bool clk_utmi_ready(struct regmap *regmap)
    +{
    + unsigned int status;
    +
    + regmap_read(regmap, AT91_PMC_SR, &status);
    +
    + return status & AT91_PMC_LOCKU;
    +}
    +
    static int clk_utmi_prepare(struct clk_hw *hw)
    {
    struct clk_utmi *utmi = to_clk_utmi(hw);
    - struct at91_pmc *pmc = utmi->pmc;
    - u32 tmp = pmc_read(pmc, AT91_CKGR_UCKR) | AT91_PMC_UPLLEN |
    - AT91_PMC_UPLLCOUNT | AT91_PMC_BIASEN;
    + unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT |
    + AT91_PMC_BIASEN;

    - pmc_write(pmc, AT91_CKGR_UCKR, tmp);
    + regmap_update_bits(utmi->regmap, AT91_CKGR_UCKR, uckr, uckr);

    - while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU)) {
    + while (!clk_utmi_ready(utmi->regmap)) {
    enable_irq(utmi->irq);
    wait_event(utmi->wait,
    - pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU);
    + clk_utmi_ready(utmi->regmap));
    }

    return 0;
    @@ -64,18 +74,15 @@ static int clk_utmi_prepare(struct clk_hw *hw)
    static int clk_utmi_is_prepared(struct clk_hw *hw)
    {
    struct clk_utmi *utmi = to_clk_utmi(hw);
    - struct at91_pmc *pmc = utmi->pmc;

    - return !!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU);
    + return clk_utmi_ready(utmi->regmap);
    }

    static void clk_utmi_unprepare(struct clk_hw *hw)
    {
    struct clk_utmi *utmi = to_clk_utmi(hw);
    - struct at91_pmc *pmc = utmi->pmc;
    - u32 tmp = pmc_read(pmc, AT91_CKGR_UCKR) & ~AT91_PMC_UPLLEN;

    - pmc_write(pmc, AT91_CKGR_UCKR, tmp);
    + regmap_update_bits(utmi->regmap, AT91_CKGR_UCKR, AT91_PMC_UPLLEN, 0);
    }

    static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw,
    @@ -93,7 +100,7 @@ static const struct clk_ops utmi_ops = {
    };

    static struct clk * __init
    -at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq,
    +at91_clk_register_utmi(struct regmap *regmap, unsigned int irq,
    const char *name, const char *parent_name)
    {
    int ret;
    @@ -112,7 +119,7 @@ at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq,
    init.flags = CLK_SET_RATE_GATE;

    utmi->hw.init = &init;
    - utmi->pmc = pmc;
    + utmi->regmap = regmap;
    utmi->irq = irq;
    init_waitqueue_head(&utmi->wait);
    irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN);
    @@ -132,13 +139,13 @@ at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq,
    return clk;
    }

    -static void __init
    -of_at91_clk_utmi_setup(struct device_node *np, struct at91_pmc *pmc)
    +static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
    {
    unsigned int irq;
    struct clk *clk;
    const char *parent_name;
    const char *name = np->name;
    + struct regmap *regmap;

    parent_name = of_clk_get_parent_name(np, 0);

    @@ -148,16 +155,16 @@ of_at91_clk_utmi_setup(struct device_node *np, struct at91_pmc *pmc)
    if (!irq)
    return;

    - clk = at91_clk_register_utmi(pmc, irq, name, parent_name);
    + regmap = syscon_node_to_regmap(of_get_parent(np));
    + if (IS_ERR(regmap))
    + return;
    +
    + clk = at91_clk_register_utmi(regmap, irq, name, parent_name);
    if (IS_ERR(clk))
    return;

    of_clk_add_provider(np, of_clk_src_simple_get, clk);
    return;
    }
    -
    -void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np,
    - struct at91_pmc *pmc)
    -{
    - of_at91_clk_utmi_setup(np, pmc);
    -}
    +CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi",
    + of_at91sam9x5_clk_utmi_setup);
    diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
    index 481146029b2e..295b17b9c689 100644
    --- a/drivers/clk/at91/pmc.c
    +++ b/drivers/clk/at91/pmc.c
    @@ -20,6 +20,7 @@
    #include <linux/irqdomain.h>
    #include <linux/of_irq.h>
    #include <linux/mfd/syscon.h>
    +#include <linux/regmap.h>

    #include <asm/proc-fns.h>

    @@ -70,14 +71,14 @@ static void pmc_irq_mask(struct irq_data *d)
    {
    struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);

    - pmc_write(pmc, AT91_PMC_IDR, 1 << d->hwirq);
    + regmap_write(pmc->regmap, AT91_PMC_IDR, 1 << d->hwirq);
    }

    static void pmc_irq_unmask(struct irq_data *d)
    {
    struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);

    - pmc_write(pmc, AT91_PMC_IER, 1 << d->hwirq);
    + regmap_write(pmc->regmap, AT91_PMC_IER, 1 << d->hwirq);
    }

    static int pmc_irq_set_type(struct irq_data *d, unsigned type)
    @@ -94,15 +95,15 @@ static void pmc_irq_suspend(struct irq_data *d)
    {
    struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);

    - pmc->imr = pmc_read(pmc, AT91_PMC_IMR);
    - pmc_write(pmc, AT91_PMC_IDR, pmc->imr);
    + regmap_read(pmc->regmap, AT91_PMC_IMR, &pmc->imr);
    + regmap_write(pmc->regmap, AT91_PMC_IDR, pmc->imr);
    }

    static void pmc_irq_resume(struct irq_data *d)
    {
    struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);

    - pmc_write(pmc, AT91_PMC_IER, pmc->imr);
    + regmap_write(pmc->regmap, AT91_PMC_IER, pmc->imr);
    }

    static struct irq_chip pmc_irq = {
    @@ -161,10 +162,14 @@ static const struct irq_domain_ops pmc_irq_ops = {
    static irqreturn_t pmc_irq_handler(int irq, void *data)
    {
    struct at91_pmc *pmc = (struct at91_pmc *)data;
    + unsigned int tmpsr, imr;
    unsigned long sr;
    int n;

    - sr = pmc_read(pmc, AT91_PMC_SR) & pmc_read(pmc, AT91_PMC_IMR);
    + regmap_read(pmc->regmap, AT91_PMC_SR, &tmpsr);
    + regmap_read(pmc->regmap, AT91_PMC_IMR, &imr);
    +
    + sr = tmpsr & imr;
    if (!sr)
    return IRQ_NONE;

    @@ -239,17 +244,15 @@ static struct at91_pmc *__init at91_pmc_init(struct device_node *np,
    if (!pmc)
    return NULL;

    - spin_lock_init(&pmc->lock);
    pmc->regmap = regmap;
    pmc->virq = virq;
    pmc->caps = caps;

    pmc->irqdomain = irq_domain_add_linear(np, 32, &pmc_irq_ops, pmc);
    -
    if (!pmc->irqdomain)
    goto out_free_pmc;

    - pmc_write(pmc, AT91_PMC_IDR, 0xffffffff);
    + regmap_write(pmc->regmap, AT91_PMC_IDR, 0xffffffff);
    if (request_irq(pmc->virq, pmc_irq_handler,
    IRQF_SHARED | IRQF_COND_SUSPEND, "pmc", pmc))
    goto out_remove_irqdomain;
    @@ -264,137 +267,10 @@ out_free_pmc:
    return NULL;
    }

    -static const struct of_device_id pmc_clk_ids[] __initconst = {
    - /* Slow oscillator */
    - {
    - .compatible = "atmel,at91sam9260-clk-slow",
    - .data = of_at91sam9260_clk_slow_setup,
    - },
    - /* Main clock */
    - {
    - .compatible = "atmel,at91rm9200-clk-main-osc",
    - .data = of_at91rm9200_clk_main_osc_setup,
    - },
    - {
    - .compatible = "atmel,at91sam9x5-clk-main-rc-osc",
    - .data = of_at91sam9x5_clk_main_rc_osc_setup,
    - },
    - {
    - .compatible = "atmel,at91rm9200-clk-main",
    - .data = of_at91rm9200_clk_main_setup,
    - },
    - {
    - .compatible = "atmel,at91sam9x5-clk-main",
    - .data = of_at91sam9x5_clk_main_setup,
    - },
    - /* PLL clocks */
    - {
    - .compatible = "atmel,at91rm9200-clk-pll",
    - .data = of_at91rm9200_clk_pll_setup,
    - },
    - {
    - .compatible = "atmel,at91sam9g45-clk-pll",
    - .data = of_at91sam9g45_clk_pll_setup,
    - },
    - {
    - .compatible = "atmel,at91sam9g20-clk-pllb",
    - .data = of_at91sam9g20_clk_pllb_setup,
    - },
    - {
    - .compatible = "atmel,sama5d3-clk-pll",
    - .data = of_sama5d3_clk_pll_setup,
    - },
    - {
    - .compatible = "atmel,at91sam9x5-clk-plldiv",
    - .data = of_at91sam9x5_clk_plldiv_setup,
    - },
    - /* Master clock */
    - {
    - .compatible = "atmel,at91rm9200-clk-master",
    - .data = of_at91rm9200_clk_master_setup,
    - },
    - {
    - .compatible = "atmel,at91sam9x5-clk-master",
    - .data = of_at91sam9x5_clk_master_setup,
    - },
    - /* System clocks */
    - {
    - .compatible = "atmel,at91rm9200-clk-system",
    - .data = of_at91rm9200_clk_sys_setup,
    - },
    - /* Peripheral clocks */
    - {
    - .compatible = "atmel,at91rm9200-clk-peripheral",
    - .data = of_at91rm9200_clk_periph_setup,
    - },
    - {
    - .compatible = "atmel,at91sam9x5-clk-peripheral",
    - .data = of_at91sam9x5_clk_periph_setup,
    - },
    - /* Programmable clocks */
    - {
    - .compatible = "atmel,at91rm9200-clk-programmable",
    - .data = of_at91rm9200_clk_prog_setup,
    - },
    - {
    - .compatible = "atmel,at91sam9g45-clk-programmable",
    - .data = of_at91sam9g45_clk_prog_setup,
    - },
    - {
    - .compatible = "atmel,at91sam9x5-clk-programmable",
    - .data = of_at91sam9x5_clk_prog_setup,
    - },
    - /* UTMI clock */
    -#if defined(CONFIG_HAVE_AT91_UTMI)
    - {
    - .compatible = "atmel,at91sam9x5-clk-utmi",
    - .data = of_at91sam9x5_clk_utmi_setup,
    - },
    -#endif
    - /* USB clock */
    -#if defined(CONFIG_HAVE_AT91_USB_CLK)
    - {
    - .compatible = "atmel,at91rm9200-clk-usb",
    - .data = of_at91rm9200_clk_usb_setup,
    - },
    - {
    - .compatible = "atmel,at91sam9x5-clk-usb",
    - .data = of_at91sam9x5_clk_usb_setup,
    - },
    - {
    - .compatible = "atmel,at91sam9n12-clk-usb",
    - .data = of_at91sam9n12_clk_usb_setup,
    - },
    -#endif
    - /* SMD clock */
    -#if defined(CONFIG_HAVE_AT91_SMD)
    - {
    - .compatible = "atmel,at91sam9x5-clk-smd",
    - .data = of_at91sam9x5_clk_smd_setup,
    - },
    -#endif
    -#if defined(CONFIG_HAVE_AT91_H32MX)
    - {
    - .compatible = "atmel,sama5d4-clk-h32mx",
    - .data = of_sama5d4_clk_h32mx_setup,
    - },
    -#endif
    -#if defined(CONFIG_HAVE_AT91_GENERATED_CLK)
    - {
    - .compatible = "atmel,sama5d2-clk-generated",
    - .data = of_sama5d2_clk_generated_setup,
    - },
    -#endif
    - { /*sentinel*/ }
    -};
    -
    static void __init of_at91_pmc_setup(struct device_node *np,
    const struct at91_pmc_caps *caps)
    {
    struct at91_pmc *pmc;
    - struct device_node *childnp;
    - void (*clk_setup)(struct device_node *, struct at91_pmc *);
    - const struct of_device_id *clk_id;
    void __iomem *regbase = of_iomap(np, 0);
    struct regmap *regmap;
    int virq;
    @@ -410,13 +286,6 @@ static void __init of_at91_pmc_setup(struct device_node *np,
    pmc = at91_pmc_init(np, regmap, regbase, virq, caps);
    if (!pmc)
    return;
    - for_each_child_of_node(np, childnp) {
    - clk_id = of_match_node(pmc_clk_ids, childnp);
    - if (!clk_id)
    - continue;
    - clk_setup = clk_id->data;
    - clk_setup(childnp, pmc);
    - }
    }

    static void __init of_at91rm9200_pmc_setup(struct device_node *np)
    diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
    index e1fc0b0e1d8c..3b96c53c194c 100644
    --- a/drivers/clk/at91/pmc.h
    +++ b/drivers/clk/at91/pmc.h
    @@ -31,99 +31,12 @@ struct at91_pmc_caps {
    struct at91_pmc {
    struct regmap *regmap;
    int virq;
    - spinlock_t lock;
    const struct at91_pmc_caps *caps;
    struct irq_domain *irqdomain;
    u32 imr;
    };

    -static inline void pmc_lock(struct at91_pmc *pmc)
    -{
    - spin_lock(&pmc->lock);
    -}
    -
    -static inline void pmc_unlock(struct at91_pmc *pmc)
    -{
    - spin_unlock(&pmc->lock);
    -}
    -
    -static inline u32 pmc_read(struct at91_pmc *pmc, int offset)
    -{
    - unsigned int ret = 0;
    -
    - regmap_read(pmc->regmap, offset, &ret);
    -
    - return ret;
    -}
    -
    -static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value)
    -{
    - regmap_write(pmc->regmap, offset, value);
    -}
    -
    int of_at91_get_clk_range(struct device_node *np, const char *propname,
    struct clk_range *range);

    -void of_at91sam9260_clk_slow_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -
    -void of_at91rm9200_clk_main_osc_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -void of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -void of_at91rm9200_clk_main_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -void of_at91sam9x5_clk_main_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -
    -void of_at91rm9200_clk_pll_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -void of_at91sam9g45_clk_pll_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -void of_at91sam9g20_clk_pllb_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -void of_sama5d3_clk_pll_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -void of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -
    -void of_at91rm9200_clk_master_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -void of_at91sam9x5_clk_master_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -
    -void of_at91rm9200_clk_sys_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -
    -void of_at91rm9200_clk_periph_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -void of_at91sam9x5_clk_periph_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -
    -void of_at91rm9200_clk_prog_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -void of_at91sam9g45_clk_prog_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -void of_at91sam9x5_clk_prog_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -
    -void of_at91sam9x5_clk_utmi_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -
    -void of_at91rm9200_clk_usb_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -void of_at91sam9x5_clk_usb_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -void of_at91sam9n12_clk_usb_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -
    -void of_at91sam9x5_clk_smd_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -
    -void of_sama5d4_clk_h32mx_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -
    -void of_sama5d2_clk_generated_setup(struct device_node *np,
    - struct at91_pmc *pmc);
    -
    #endif /* __PMC_H_ */
    --
    2.5.0


    \
     
     \ /
      Last update: 2015-12-04 19:01    [W:3.439 / U:0.408 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site