From 300bb762513f12068bf6166e0a1a02a4031a979c Mon Sep 17 00:00:00 2001 From: Alex Raimondi Date: Mon, 22 Sep 2008 21:40:55 +0200 Subject: [PATCH] avr32: Replace static clock list with dynamic linked list This replaces the at32_clock_list array with a linked list. Clocks can now be registered (added) to the list. Signed-off-by: Alex Raimondi Signed-off-by: Haavard Skinnemoen --- arch/avr32/mach-at32ap/at32ap700x.c | 22 +++++++----- arch/avr32/mach-at32ap/clock.c | 52 ++++++++++++++++++++++------- arch/avr32/mach-at32ap/clock.h | 8 +++-- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index c28dd172f62..fd306c49194 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c @@ -2028,7 +2028,7 @@ static struct clk gclk4 = { .index = 4, }; -struct clk *at32_clock_list[] = { +static __initdata struct clk *init_clocks[] = { &osc32k, &osc0, &osc1, @@ -2092,7 +2092,6 @@ struct clk *at32_clock_list[] = { &gclk3, &gclk4, }; -unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list); void __init setup_platform(void) { @@ -2123,14 +2122,19 @@ void __init setup_platform(void) genclk_init_parent(&abdac0_sample_clk); /* - * Turn on all clocks that have at least one user already, and - * turn off everything else. We only do this for module - * clocks, and even though it isn't particularly pretty to - * check the address of the mode function, it should do the - * trick... + * Build initial dynamic clock list by registering all clocks + * from the array. + * At the same time, turn on all clocks that have at least one + * user already, and turn off everything else. We only do this + * for module clocks, and even though it isn't particularly + * pretty to check the address of the mode function, it should + * do the trick... */ - for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) { - struct clk *clk = at32_clock_list[i]; + for (i = 0; i < ARRAY_SIZE(init_clocks); i++) { + struct clk *clk = init_clocks[i]; + + /* first, register clock */ + at32_clk_register(clk); if (clk->users == 0) continue; diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c index 6c27ddac5ad..138a00a2a2d 100644 --- a/arch/avr32/mach-at32ap/clock.c +++ b/arch/avr32/mach-at32ap/clock.c @@ -15,24 +15,40 @@ #include #include #include +#include #include #include "clock.h" +/* at32 clock list */ +static LIST_HEAD(at32_clock_list); + static DEFINE_SPINLOCK(clk_lock); +static DEFINE_SPINLOCK(clk_list_lock); + +void at32_clk_register(struct clk *clk) +{ + spin_lock(&clk_list_lock); + /* add the new item to the end of the list */ + list_add_tail(&clk->list, &at32_clock_list); + spin_unlock(&clk_list_lock); +} struct clk *clk_get(struct device *dev, const char *id) { - int i; + struct clk *clk; - for (i = 0; i < at32_nr_clocks; i++) { - struct clk *clk = at32_clock_list[i]; + spin_lock(&clk_list_lock); - if (clk->dev == dev && strcmp(id, clk->name) == 0) + list_for_each_entry(clk, &at32_clock_list, list) { + if (clk->dev == dev && strcmp(id, clk->name) == 0) { + spin_unlock(&clk_list_lock); return clk; + } } + spin_unlock(&clk_list_lock); return ERR_PTR(-ENOENT); } EXPORT_SYMBOL(clk_get); @@ -203,8 +219,8 @@ dump_clock(struct clk *parent, struct clkinf *r) /* cost of this scan is small, but not linear... */ r->nest = nest + NEST_DELTA; - for (i = 3; i < at32_nr_clocks; i++) { - clk = at32_clock_list[i]; + + list_for_each_entry(clk, &at32_clock_list, list) { if (clk->parent == parent) dump_clock(clk, r); } @@ -215,6 +231,7 @@ static int clk_show(struct seq_file *s, void *unused) { struct clkinf r; int i; + struct clk *clk; /* show all the power manager registers */ seq_printf(s, "MCCTRL = %8x\n", pm_readl(MCCTRL)); @@ -234,14 +251,25 @@ static int clk_show(struct seq_file *s, void *unused) seq_printf(s, "\n"); - /* show clock tree as derived from the three oscillators - * we "know" are at the head of the list - */ r.s = s; r.nest = 0; - dump_clock(at32_clock_list[0], &r); - dump_clock(at32_clock_list[1], &r); - dump_clock(at32_clock_list[2], &r); + /* protected from changes on the list while dumping */ + spin_lock(&clk_list_lock); + + /* show clock tree as derived from the three oscillators */ + clk = clk_get(NULL, "osc32k"); + dump_clock(clk, &r); + clk_put(clk); + + clk = clk_get(NULL, "osc0"); + dump_clock(clk, &r); + clk_put(clk); + + clk = clk_get(NULL, "osc1"); + dump_clock(clk, &r); + clk_put(clk); + + spin_unlock(&clk_list_lock); return 0; } diff --git a/arch/avr32/mach-at32ap/clock.h b/arch/avr32/mach-at32ap/clock.h index bb8e1f29583..623bf0e9a1e 100644 --- a/arch/avr32/mach-at32ap/clock.h +++ b/arch/avr32/mach-at32ap/clock.h @@ -12,8 +12,13 @@ * published by the Free Software Foundation. */ #include +#include + + +void at32_clk_register(struct clk *clk); struct clk { + struct list_head list; /* linking element */ const char *name; /* Clock name/function */ struct device *dev; /* Device the clock is used by */ struct clk *parent; /* Parent clock, if any */ @@ -25,6 +30,3 @@ struct clk { u16 users; /* Enabled if non-zero */ u16 index; /* Sibling index */ }; - -extern struct clk *at32_clock_list[]; -extern unsigned int at32_nr_clocks; -- 2.32.0.93.g670b81a890