| From: Boris Brezillon <boris.brezillon@free-electrons.com> |
| Date: Sun, 7 Sep 2014 08:14:29 +0200 |
| Subject: [PATCH 02/13] clk: at91: make use of syscon/regmap internally |
| |
| 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> |
| Acked-by: Stephen Boyd <sboyd@codeaurora.org> |
| Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> |
| Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| --- |
| drivers/clk/at91/clk-generated.c | 91 +++++++------ |
| 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 | 134 +++++++++++-------- |
| 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 | 26 ++- |
| 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 | 89 ------------ |
| 15 files changed, 691 insertions(+), 693 deletions(-) |
| |
| --- a/drivers/clk/at91/clk-generated.c |
| +++ b/drivers/clk/at91/clk-generated.c |
| @@ -17,6 +17,8 @@ |
| #include <linux/of.h> |
| #include <linux/of_address.h> |
| #include <linux/io.h> |
| +#include <linux/mfd/syscon.h> |
| +#include <linux/regmap.h> |
| |
| #include "pmc.h" |
| |
| @@ -28,8 +30,9 @@ |
| |
| struct clk_generated { |
| struct clk_hw hw; |
| - struct at91_pmc *pmc; |
| + struct regmap *regmap; |
| struct clk_range range; |
| + spinlock_t *lock; |
| u32 id; |
| u32 gckdiv; |
| u8 parent_id; |
| @@ -41,49 +44,52 @@ struct clk_generated { |
| static int clk_generated_enable(struct clk_hw *hw) |
| { |
| struct clk_generated *gck = to_clk_generated(hw); |
| - struct at91_pmc *pmc = gck->pmc; |
| - u32 tmp; |
| + unsigned long flags; |
| |
| pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n", |
| __func__, gck->gckdiv, gck->parent_id); |
| |
| - pmc_lock(pmc); |
| - pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); |
| - tmp = pmc_read(pmc, AT91_PMC_PCR) & |
| - ~(AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK); |
| - pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_GCKCSS(gck->parent_id) |
| - | AT91_PMC_PCR_CMD |
| - | AT91_PMC_PCR_GCKDIV(gck->gckdiv) |
| - | AT91_PMC_PCR_GCKEN); |
| - pmc_unlock(pmc); |
| + spin_lock_irqsave(gck->lock, flags); |
| + regmap_write(gck->regmap, AT91_PMC_PCR, |
| + (gck->id & AT91_PMC_PCR_PID_MASK)); |
| + regmap_update_bits(gck->regmap, AT91_PMC_PCR, |
| + AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK | |
| + AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN, |
| + AT91_PMC_PCR_GCKCSS(gck->parent_id) | |
| + AT91_PMC_PCR_CMD | |
| + AT91_PMC_PCR_GCKDIV(gck->gckdiv) | |
| + AT91_PMC_PCR_GCKEN); |
| + spin_unlock_irqrestore(gck->lock, flags); |
| return 0; |
| } |
| |
| static void clk_generated_disable(struct clk_hw *hw) |
| { |
| struct clk_generated *gck = to_clk_generated(hw); |
| - struct at91_pmc *pmc = gck->pmc; |
| - u32 tmp; |
| + 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) & ~AT91_PMC_PCR_GCKEN; |
| - pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD); |
| - 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_CMD | AT91_PMC_PCR_GCKEN, |
| + AT91_PMC_PCR_CMD); |
| + spin_unlock_irqrestore(gck->lock, flags); |
| } |
| |
| static int clk_generated_is_enabled(struct clk_hw *hw) |
| { |
| struct clk_generated *gck = to_clk_generated(hw); |
| - struct at91_pmc *pmc = gck->pmc; |
| - int ret; |
| + unsigned long flags; |
| + unsigned int status; |
| |
| - pmc_lock(pmc); |
| - pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); |
| - ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_GCKEN); |
| - pmc_unlock(pmc); |
| + spin_lock_irqsave(gck->lock, flags); |
| + regmap_write(gck->regmap, AT91_PMC_PCR, |
| + (gck->id & AT91_PMC_PCR_PID_MASK)); |
| + regmap_read(gck->regmap, AT91_PMC_PCR, &status); |
| + spin_unlock_irqrestore(gck->lock, flags); |
| |
| - return ret; |
| + return status & AT91_PMC_PCR_GCKEN ? 1 : 0; |
| } |
| |
| static unsigned long |
| @@ -214,13 +220,14 @@ static const struct clk_ops generated_op |
| */ |
| static void clk_generated_startup(struct clk_generated *gck) |
| { |
| - struct at91_pmc *pmc = gck->pmc; |
| u32 tmp; |
| + unsigned long flags; |
| |
| - pmc_lock(pmc); |
| - pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); |
| - tmp = pmc_read(pmc, AT91_PMC_PCR); |
| - pmc_unlock(pmc); |
| + spin_lock_irqsave(gck->lock, flags); |
| + regmap_write(gck->regmap, AT91_PMC_PCR, |
| + (gck->id & AT91_PMC_PCR_PID_MASK)); |
| + regmap_read(gck->regmap, AT91_PMC_PCR, &tmp); |
| + spin_unlock_irqrestore(gck->lock, flags); |
| |
| gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK) |
| >> AT91_PMC_PCR_GCKCSS_OFFSET; |
| @@ -229,8 +236,8 @@ static void clk_generated_startup(struct |
| } |
| |
| static struct clk * __init |
| -at91_clk_register_generated(struct at91_pmc *pmc, const char *name, |
| - const char **parent_names, u8 num_parents, |
| +at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, const char |
| + *name, const char **parent_names, u8 num_parents, |
| u8 id, const struct clk_range *range) |
| { |
| struct clk_generated *gck; |
| @@ -249,7 +256,8 @@ at91_clk_register_generated(struct at91_ |
| |
| gck->id = id; |
| gck->hw.init = &init; |
| - gck->pmc = pmc; |
| + gck->regmap = regmap; |
| + gck->lock = lock; |
| gck->range = *range; |
| |
| clk = clk_register(NULL, &gck->hw); |
| @@ -261,8 +269,7 @@ at91_clk_register_generated(struct at91_ |
| return clk; |
| } |
| |
| -void __init of_sama5d2_clk_generated_setup(struct device_node *np, |
| - struct at91_pmc *pmc) |
| +void __init of_sama5d2_clk_generated_setup(struct device_node *np) |
| { |
| int num; |
| u32 id; |
| @@ -272,6 +279,7 @@ void __init of_sama5d2_clk_generated_set |
| const char *parent_names[GENERATED_SOURCE_MAX]; |
| struct device_node *gcknp; |
| struct clk_range range = CLK_RANGE(0, 0); |
| + struct regmap *regmap; |
| |
| num_parents = of_clk_get_parent_count(np); |
| if (num_parents <= 0 || num_parents > GENERATED_SOURCE_MAX) |
| @@ -283,6 +291,10 @@ void __init of_sama5d2_clk_generated_set |
| if (!num || num > PERIPHERAL_MAX) |
| return; |
| |
| + regmap = syscon_node_to_regmap(of_get_parent(np)); |
| + if (IS_ERR(regmap)) |
| + return; |
| + |
| for_each_child_of_node(np, gcknp) { |
| if (of_property_read_u32(gcknp, "reg", &id)) |
| continue; |
| @@ -296,11 +308,14 @@ void __init of_sama5d2_clk_generated_set |
| 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); |
| --- 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_r |
| 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(st |
| 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(s |
| 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(s |
| |
| 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); |
| --- 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_hand |
| 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 c |
| 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(struc |
| 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_p |
| 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_p |
| 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_p |
| } |
| |
| 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_p |
| 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_h |
| 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(struc |
| 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_ |
| }; |
| |
| 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 at9 |
| 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 at9 |
| 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 at9 |
| 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_os |
| 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(stru |
| 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_rec |
| { |
| 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_ |
| }; |
| |
| 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 at9 |
| 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 at9 |
| 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 at9 |
| 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_h |
| 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_rec |
| { |
| 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(st |
| 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_ |
| }; |
| |
| 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 at9 |
| 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 at9 |
| 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 at9 |
| 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 |
| 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); |
| --- 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_handle |
| |
| 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 |
| { |
| 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_r |
| 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_r |
| 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 |
| 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 |
| 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 @@ of_at91_clk_master_get_characteristics(s |
| } |
| |
| 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_n |
| 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_n |
| 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 @@ of_at91_clk_master_setup(struct device_n |
| 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); |
| --- 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 |
| 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(struc |
| 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_o |
| }; |
| |
| 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 |
| |
| 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_autodi |
| 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 |
| 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_perip |
| }; |
| |
| 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(stru |
| 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(stru |
| } |
| |
| 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_n |
| 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_n |
| 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_n |
| 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_n |
| "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,16 @@ of_at91_clk_periph_setup(struct device_n |
| } |
| } |
| |
| -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); |
| --- 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(i |
| 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 |
| 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)); |
| + |
| + 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 (!(pmc_read(pmc, AT91_PMC_SR) & mask)) { |
| + 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 |
| 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 *p |
| 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 *p |
| 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 @@ of_at91_clk_pll_get_characteristics(stru |
| } |
| |
| 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 |
| |
| 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 |
| 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 @@ of_at91_clk_pll_setup(struct device_node |
| 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); |
| --- 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 cl |
| 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 |
| 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 |
| } |
| |
| 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); |
| --- 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(s |
| { |
| 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(str |
| 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 |
| }; |
| |
| 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 at |
| 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_lay |
| }; |
| |
| 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_nod |
| 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_nod |
| 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_nod |
| 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_nod |
| } |
| |
| |
| -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); |
| --- 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 |
| 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 |
| }; |
| |
| 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 at |
| 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 at |
| init.flags = 0; |
| |
| slowck->hw.init = &init; |
| - slowck->pmc = pmc; |
| + slowck->regmap = regmap; |
| |
| clk = clk_register(NULL, &slowck->hw); |
| if (IS_ERR(clk)) |
| @@ -439,29 +444,34 @@ at91_clk_register_sam9260_slow(struct at |
| 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; |
| |
| 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 + |
| --- 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_rat |
| |
| 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_s |
| }; |
| |
| 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_ |
| 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_ |
| 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( |
| |
| 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); |
| --- 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_handle |
| 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 |
| 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 |
| |
| 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 |
| 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 |
| 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 |
| |
| 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); |
| --- 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_ |
| |
| 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(s |
| 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_u |
| 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_ |
| }; |
| |
| 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_ |
| 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_ |
| } |
| |
| 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 |
| 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_ |
| 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_rat |
| 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(s |
| |
| 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_u |
| }; |
| |
| 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_ |
| 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_ |
| 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( |
| |
| 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 |
| |
| 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( |
| |
| 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); |
| --- 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( |
| 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_h |
| 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 * |
| 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 * |
| 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_nod |
| 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); |
| --- 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 |
| { |
| 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_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_i |
| 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_ |
| 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 @@ static struct at91_pmc *__init at91_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(str |
| 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) |
| --- a/drivers/clk/at91/pmc.h |
| +++ b/drivers/clk/at91/pmc.h |
| @@ -17,6 +17,8 @@ |
| #include <linux/regmap.h> |
| #include <linux/spinlock.h> |
| |
| +extern spinlock_t pmc_pcr_lock; |
| + |
| struct clk_range { |
| unsigned long min; |
| unsigned long max; |
| @@ -31,99 +33,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_ */ |