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 <raimondi@miromico.ch>
Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
This commit is contained in:
Alex Raimondi 2008-09-22 21:40:55 +02:00 committed by Haavard Skinnemoen
parent 787928e747
commit 300bb76251
3 changed files with 58 additions and 24 deletions

View file

@ -2028,7 +2028,7 @@ static struct clk gclk4 = {
.index = 4, .index = 4,
}; };
struct clk *at32_clock_list[] = { static __initdata struct clk *init_clocks[] = {
&osc32k, &osc32k,
&osc0, &osc0,
&osc1, &osc1,
@ -2092,7 +2092,6 @@ struct clk *at32_clock_list[] = {
&gclk3, &gclk3,
&gclk4, &gclk4,
}; };
unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
void __init setup_platform(void) void __init setup_platform(void)
{ {
@ -2123,14 +2122,19 @@ void __init setup_platform(void)
genclk_init_parent(&abdac0_sample_clk); genclk_init_parent(&abdac0_sample_clk);
/* /*
* Turn on all clocks that have at least one user already, and * Build initial dynamic clock list by registering all clocks
* turn off everything else. We only do this for module * from the array.
* clocks, and even though it isn't particularly pretty to * At the same time, turn on all clocks that have at least one
* check the address of the mode function, it should do the * user already, and turn off everything else. We only do this
* trick... * 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++) { for (i = 0; i < ARRAY_SIZE(init_clocks); i++) {
struct clk *clk = at32_clock_list[i]; struct clk *clk = init_clocks[i];
/* first, register clock */
at32_clk_register(clk);
if (clk->users == 0) if (clk->users == 0)
continue; continue;

View file

@ -15,24 +15,40 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/list.h>
#include <mach/chip.h> #include <mach/chip.h>
#include "clock.h" #include "clock.h"
/* at32 clock list */
static LIST_HEAD(at32_clock_list);
static DEFINE_SPINLOCK(clk_lock); 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) struct clk *clk_get(struct device *dev, const char *id)
{ {
int i; struct clk *clk;
for (i = 0; i < at32_nr_clocks; i++) { spin_lock(&clk_list_lock);
struct clk *clk = at32_clock_list[i];
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; return clk;
}
} }
spin_unlock(&clk_list_lock);
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
EXPORT_SYMBOL(clk_get); 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... */ /* cost of this scan is small, but not linear... */
r->nest = nest + NEST_DELTA; 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) if (clk->parent == parent)
dump_clock(clk, r); dump_clock(clk, r);
} }
@ -215,6 +231,7 @@ static int clk_show(struct seq_file *s, void *unused)
{ {
struct clkinf r; struct clkinf r;
int i; int i;
struct clk *clk;
/* show all the power manager registers */ /* show all the power manager registers */
seq_printf(s, "MCCTRL = %8x\n", pm_readl(MCCTRL)); 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"); 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.s = s;
r.nest = 0; r.nest = 0;
dump_clock(at32_clock_list[0], &r); /* protected from changes on the list while dumping */
dump_clock(at32_clock_list[1], &r); spin_lock(&clk_list_lock);
dump_clock(at32_clock_list[2], &r);
/* 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; return 0;
} }

View file

@ -12,8 +12,13 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/list.h>
void at32_clk_register(struct clk *clk);
struct clk { struct clk {
struct list_head list; /* linking element */
const char *name; /* Clock name/function */ const char *name; /* Clock name/function */
struct device *dev; /* Device the clock is used by */ struct device *dev; /* Device the clock is used by */
struct clk *parent; /* Parent clock, if any */ struct clk *parent; /* Parent clock, if any */
@ -25,6 +30,3 @@ struct clk {
u16 users; /* Enabled if non-zero */ u16 users; /* Enabled if non-zero */
u16 index; /* Sibling index */ u16 index; /* Sibling index */
}; };
extern struct clk *at32_clock_list[];
extern unsigned int at32_nr_clocks;