diff options
Diffstat (limited to 'drivers/clk/at91/clk-generated.c')
-rw-r--r-- | drivers/clk/at91/clk-generated.c | 185 |
1 files changed, 32 insertions, 153 deletions
diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c index 4e1cd5aa69..60516ca10f 100644 --- a/drivers/clk/at91/clk-generated.c +++ b/drivers/clk/at91/clk-generated.c @@ -11,26 +11,23 @@ * */ -#include <linux/clk-provider.h> -#include <linux/clkdev.h> +#include <common.h> +#include <clock.h> +#include <io.h> +#include <linux/list.h> +#include <linux/clk.h> #include <linux/clk/at91_pmc.h> -#include <linux/of.h> -#include <linux/mfd/syscon.h> -#include <linux/regmap.h> +#include <mfd/syscon.h> +#include <regmap.h> #include "pmc.h" -#define PERIPHERAL_MAX 64 -#define PERIPHERAL_ID_MIN 2 - -#define GENERATED_SOURCE_MAX 6 #define GENERATED_MAX_DIV 255 struct clk_generated { - struct clk_hw hw; + struct clk hw; struct regmap *regmap; struct clk_range range; - spinlock_t *lock; u32 id; u32 gckdiv; u8 parent_id; @@ -39,15 +36,13 @@ struct clk_generated { #define to_clk_generated(hw) \ container_of(hw, struct clk_generated, hw) -static int clk_generated_enable(struct clk_hw *hw) +static int clk_generated_enable(struct clk *hw) { struct clk_generated *gck = to_clk_generated(hw); - unsigned long flags; pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n", __func__, gck->gckdiv, gck->parent_id); - 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, @@ -57,41 +52,34 @@ static int clk_generated_enable(struct clk_hw *hw) 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) +static void clk_generated_disable(struct clk *hw) { struct clk_generated *gck = to_clk_generated(hw); - unsigned long flags; - spin_lock_irqsave(gck->lock, flags); regmap_write(gck->regmap, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); regmap_update_bits(gck->regmap, AT91_PMC_PCR, AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN, AT91_PMC_PCR_CMD); - spin_unlock_irqrestore(gck->lock, flags); } -static int clk_generated_is_enabled(struct clk_hw *hw) +static int clk_generated_is_enabled(struct clk *hw) { struct clk_generated *gck = to_clk_generated(hw); - unsigned long flags; unsigned int status; - 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 status & AT91_PMC_PCR_GCKEN ? 1 : 0; } static unsigned long -clk_generated_recalc_rate(struct clk_hw *hw, +clk_generated_recalc_rate(struct clk *hw, unsigned long parent_rate) { struct clk_generated *gck = to_clk_generated(hw); @@ -99,75 +87,19 @@ clk_generated_recalc_rate(struct clk_hw *hw, return DIV_ROUND_CLOSEST(parent_rate, gck->gckdiv + 1); } -static int clk_generated_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - struct clk_generated *gck = to_clk_generated(hw); - struct clk_hw *parent = NULL; - long best_rate = -EINVAL; - unsigned long tmp_rate, min_rate; - int best_diff = -1; - int tmp_diff; - int i; - - for (i = 0; i < clk_hw_get_num_parents(hw); i++) { - u32 div; - unsigned long parent_rate; - - parent = clk_hw_get_parent_by_index(hw, i); - if (!parent) - continue; - - parent_rate = clk_hw_get_rate(parent); - min_rate = DIV_ROUND_CLOSEST(parent_rate, GENERATED_MAX_DIV + 1); - if (!parent_rate || - (gck->range.max && min_rate > gck->range.max)) - continue; - - for (div = 1; div < GENERATED_MAX_DIV + 2; div++) { - tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div); - tmp_diff = abs(req->rate - tmp_rate); - - if (best_diff < 0 || best_diff > tmp_diff) { - best_rate = tmp_rate; - best_diff = tmp_diff; - req->best_parent_rate = parent_rate; - req->best_parent_hw = parent; - } - - if (!best_diff || tmp_rate < req->rate) - break; - } - - if (!best_diff) - break; - } - - pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n", - __func__, best_rate, - __clk_get_name((req->best_parent_hw)->clk), - req->best_parent_rate); - - if (best_rate < 0) - return best_rate; - - req->rate = best_rate; - return 0; -} - /* No modification of hardware as we have the flag CLK_SET_PARENT_GATE set */ -static int clk_generated_set_parent(struct clk_hw *hw, u8 index) +static int clk_generated_set_parent(struct clk *hw, u8 index) { struct clk_generated *gck = to_clk_generated(hw); - if (index >= clk_hw_get_num_parents(hw)) + if (index >= clk_get_num_parents(hw)) return -EINVAL; gck->parent_id = index; return 0; } -static u8 clk_generated_get_parent(struct clk_hw *hw) +static int clk_generated_get_parent(struct clk *hw) { struct clk_generated *gck = to_clk_generated(hw); @@ -175,7 +107,7 @@ static u8 clk_generated_get_parent(struct clk_hw *hw) } /* No modification of hardware as we have the flag CLK_SET_RATE_GATE set */ -static int clk_generated_set_rate(struct clk_hw *hw, +static int clk_generated_set_rate(struct clk *hw, unsigned long rate, unsigned long parent_rate) { @@ -201,7 +133,6 @@ static const struct clk_ops generated_ops = { .disable = clk_generated_disable, .is_enabled = clk_generated_is_enabled, .recalc_rate = clk_generated_recalc_rate, - .determine_rate = clk_generated_determine_rate, .get_parent = clk_generated_get_parent, .set_parent = clk_generated_set_parent, .set_rate = clk_generated_set_rate, @@ -219,13 +150,10 @@ static const struct clk_ops generated_ops = { static void clk_generated_startup(struct clk_generated *gck) { u32 tmp; - unsigned long flags; - 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; @@ -233,35 +161,37 @@ static void clk_generated_startup(struct clk_generated *gck) >> AT91_PMC_PCR_GCKDIV_OFFSET; } -static struct clk_hw * __init -at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, +struct clk * __init +at91_clk_register_generated(struct regmap *regmap, const char *name, const char **parent_names, - u8 num_parents, u8 id, + u8 num_parents, u8 id, bool pll_audio, const struct clk_range *range) { + size_t parents_array_size; struct clk_generated *gck; - struct clk_init_data init; - struct clk_hw *hw; + struct clk *hw; int ret; gck = kzalloc(sizeof(*gck), GFP_KERNEL); if (!gck) return ERR_PTR(-ENOMEM); - init.name = name; - init.ops = &generated_ops; - init.parent_names = parent_names; - init.num_parents = num_parents; - init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; - gck->id = id; - gck->hw.init = &init; + gck->hw.name = name; + gck->hw.ops = &generated_ops; + + parents_array_size = num_parents * sizeof(gck->hw.parent_names[0]); + gck->hw.parent_names = xzalloc(parents_array_size); + memcpy(gck->hw.parent_names, parent_names, parents_array_size); + gck->hw.num_parents = num_parents; + + /* gck->hw.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; */ gck->regmap = regmap; - gck->lock = lock; gck->range = *range; + /* gck->audio_pll_allowed = pll_audio; */ hw = &gck->hw; - ret = clk_hw_register(NULL, &gck->hw); + ret = clk_register(&gck->hw); if (ret) { kfree(gck); hw = ERR_PTR(ret); @@ -270,54 +200,3 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, return hw; } - -static void __init of_sama5d2_clk_generated_setup(struct device_node *np) -{ - int num; - u32 id; - const char *name; - struct clk_hw *hw; - unsigned int num_parents; - 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) - return; - - of_clk_parent_fill(np, parent_names, num_parents); - - num = of_get_child_count(np); - if (!num || num > PERIPHERAL_MAX) - return; - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - for_each_child_of_node(np, gcknp) { - if (of_property_read_u32(gcknp, "reg", &id)) - continue; - - if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX) - continue; - - if (of_property_read_string(np, "clock-output-names", &name)) - name = gcknp->name; - - of_at91_get_clk_range(gcknp, "atmel,clk-output-range", - &range); - - hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name, - parent_names, num_parents, - id, &range); - if (IS_ERR(hw)) - continue; - - of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw); - } -} -CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated", - of_sama5d2_clk_generated_setup); |