diff options
Diffstat (limited to 'kernel/drivers/clk/at91/clk-master.c')
-rw-r--r-- | kernel/drivers/clk/at91/clk-master.c | 103 |
1 files changed, 41 insertions, 62 deletions
diff --git a/kernel/drivers/clk/at91/clk-master.c b/kernel/drivers/clk/at91/clk-master.c index c1af80bcd..7d4a1864e 100644 --- a/kernel/drivers/clk/at91/clk-master.c +++ b/kernel/drivers/clk/at91/clk-master.c @@ -12,13 +12,8 @@ #include <linux/clkdev.h> #include <linux/clk/at91_pmc.h> #include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/io.h> -#include <linux/wait.h> -#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,32 +39,26 @@ struct clk_master_layout { struct clk_master { struct clk_hw hw; - struct at91_pmc *pmc; - unsigned int irq; - wait_queue_head_t wait; + struct regmap *regmap; const struct clk_master_layout *layout; const struct clk_master_characteristics *characteristics; }; -static irqreturn_t clk_master_irq_handler(int irq, void *dev_id) +static inline bool clk_master_ready(struct regmap *regmap) { - struct clk_master *master = (struct clk_master *)dev_id; + unsigned int status; - wake_up(&master->wait); - disable_irq_nosync(master->irq); + regmap_read(regmap, AT91_PMC_SR, &status); - return IRQ_HANDLED; + 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)) { - enable_irq(master->irq); - wait_event(master->wait, - pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY); - } + while (!clk_master_ready(master->regmap)) + cpu_relax(); return 0; } @@ -78,7 +67,7 @@ static int clk_master_is_prepared(struct clk_hw *hw) { struct clk_master *master = to_clk_master(hw); - return !!(pmc_read(master->pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY); + return clk_master_ready(master->regmap); } static unsigned long clk_master_recalc_rate(struct clk_hw *hw, @@ -88,18 +77,16 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw, u8 div; unsigned long rate = parent_rate; struct clk_master *master = to_clk_master(hw); - struct at91_pmc *pmc = master->pmc; const struct clk_master_layout *layout = master->layout; const struct clk_master_characteristics *characteristics = master->characteristics; - u32 tmp; + unsigned int mckr; - pmc_lock(pmc); - tmp = pmc_read(pmc, AT91_PMC_MCKR) & layout->mask; - pmc_unlock(pmc); + regmap_read(master->regmap, AT91_PMC_MCKR, &mckr); + mckr &= layout->mask; - pres = (tmp >> layout->pres_shift) & MASTER_PRES_MASK; - div = (tmp >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK; + pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK; + div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK; if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX) rate /= 3; @@ -119,9 +106,11 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw, static u8 clk_master_get_parent(struct clk_hw *hw) { struct clk_master *master = to_clk_master(hw); - struct at91_pmc *pmc = master->pmc; + unsigned int mckr; - return pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_CSS; + regmap_read(master->regmap, AT91_PMC_MCKR, &mckr); + + return mckr & AT91_PMC_CSS; } static const struct clk_ops master_ops = { @@ -132,18 +121,17 @@ 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, const char *name, int num_parents, const char **parent_names, const struct clk_master_layout *layout, const struct clk_master_characteristics *characteristics) { - int ret; struct clk_master *master; 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,18 +147,12 @@ at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq, master->hw.init = &init; master->layout = layout; master->characteristics = characteristics; - master->pmc = pmc; - master->irq = irq; - init_waitqueue_head(&master->wait); - irq_set_status_flags(master->irq, IRQ_NOAUTOEN); - ret = request_irq(master->irq, clk_master_irq_handler, - IRQF_TRIGGER_HIGH, "clk-master", master); - if (ret) - return ERR_PTR(ret); + master->regmap = regmap; clk = clk_register(NULL, &master->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { kfree(master); + } return clk; } @@ -213,26 +195,21 @@ out_free_characteristics: } static void __init -of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, +of_at91_clk_master_setup(struct device_node *np, const struct clk_master_layout *layout) { struct clk *clk; int num_parents; - int i; - unsigned int irq; const char *parent_names[MASTER_SOURCE_MAX]; const char *name = np->name; struct clk_master_characteristics *characteristics; + struct regmap *regmap; - num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); + num_parents = of_clk_get_parent_count(np); if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX) return; - for (i = 0; i < num_parents; ++i) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); of_property_read_string(np, "clock-output-names", &name); @@ -240,11 +217,11 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, if (!characteristics) return; - irq = irq_of_parse_and_map(np, 0); - if (!irq) - goto out_free_characteristics; + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; - clk = at91_clk_register_master(pmc, irq, name, num_parents, + clk = at91_clk_register_master(regmap, name, num_parents, parent_names, layout, characteristics); if (IS_ERR(clk)) @@ -257,14 +234,16 @@ out_free_characteristics: kfree(characteristics); } -void __init of_at91rm9200_clk_master_setup(struct device_node *np, - struct at91_pmc *pmc) +static void __init of_at91rm9200_clk_master_setup(struct device_node *np) { - of_at91_clk_master_setup(np, pmc, &at91rm9200_master_layout); + of_at91_clk_master_setup(np, &at91rm9200_master_layout); } +CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master", + of_at91rm9200_clk_master_setup); -void __init of_at91sam9x5_clk_master_setup(struct device_node *np, - struct at91_pmc *pmc) +static void __init of_at91sam9x5_clk_master_setup(struct device_node *np) { - of_at91_clk_master_setup(np, pmc, &at91sam9x5_master_layout); + of_at91_clk_master_setup(np, &at91sam9x5_master_layout); } +CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master", + of_at91sam9x5_clk_master_setup); |