diff options
| -rw-r--r-- | arch/avr32/mach-at32ap/at32ap700x.c | 22 | ||||
| -rw-r--r-- | arch/avr32/mach-at32ap/clock.c | 52 | ||||
| -rw-r--r-- | 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 c28dd172f627..fd306c49194b 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c | |||
| @@ -2028,7 +2028,7 @@ static struct clk gclk4 = { | |||
| 2028 | .index = 4, | 2028 | .index = 4, |
| 2029 | }; | 2029 | }; |
| 2030 | 2030 | ||
| 2031 | struct clk *at32_clock_list[] = { | 2031 | static __initdata struct clk *init_clocks[] = { |
| 2032 | &osc32k, | 2032 | &osc32k, |
| 2033 | &osc0, | 2033 | &osc0, |
| 2034 | &osc1, | 2034 | &osc1, |
| @@ -2092,7 +2092,6 @@ struct clk *at32_clock_list[] = { | |||
| 2092 | &gclk3, | 2092 | &gclk3, |
| 2093 | &gclk4, | 2093 | &gclk4, |
| 2094 | }; | 2094 | }; |
| 2095 | unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list); | ||
| 2096 | 2095 | ||
| 2097 | void __init setup_platform(void) | 2096 | void __init setup_platform(void) |
| 2098 | { | 2097 | { |
| @@ -2123,14 +2122,19 @@ void __init setup_platform(void) | |||
| 2123 | genclk_init_parent(&abdac0_sample_clk); | 2122 | genclk_init_parent(&abdac0_sample_clk); |
| 2124 | 2123 | ||
| 2125 | /* | 2124 | /* |
| 2126 | * Turn on all clocks that have at least one user already, and | 2125 | * Build initial dynamic clock list by registering all clocks |
| 2127 | * turn off everything else. We only do this for module | 2126 | * from the array. |
| 2128 | * clocks, and even though it isn't particularly pretty to | 2127 | * At the same time, turn on all clocks that have at least one |
| 2129 | * check the address of the mode function, it should do the | 2128 | * user already, and turn off everything else. We only do this |
| 2130 | * trick... | 2129 | * for module clocks, and even though it isn't particularly |
| 2130 | * pretty to check the address of the mode function, it should | ||
| 2131 | * do the trick... | ||
| 2131 | */ | 2132 | */ |
| 2132 | for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) { | 2133 | for (i = 0; i < ARRAY_SIZE(init_clocks); i++) { |
| 2133 | struct clk *clk = at32_clock_list[i]; | 2134 | struct clk *clk = init_clocks[i]; |
| 2135 | |||
| 2136 | /* first, register clock */ | ||
| 2137 | at32_clk_register(clk); | ||
| 2134 | 2138 | ||
| 2135 | if (clk->users == 0) | 2139 | if (clk->users == 0) |
| 2136 | continue; | 2140 | continue; |
diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c index 6c27ddac5adf..138a00a2a2d0 100644 --- a/arch/avr32/mach-at32ap/clock.c +++ b/arch/avr32/mach-at32ap/clock.c | |||
| @@ -15,24 +15,40 @@ | |||
| 15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
| 16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
| 17 | #include <linux/string.h> | 17 | #include <linux/string.h> |
| 18 | #include <linux/list.h> | ||
| 18 | 19 | ||
| 19 | #include <mach/chip.h> | 20 | #include <mach/chip.h> |
| 20 | 21 | ||
| 21 | #include "clock.h" | 22 | #include "clock.h" |
| 22 | 23 | ||
| 24 | /* at32 clock list */ | ||
| 25 | static LIST_HEAD(at32_clock_list); | ||
| 26 | |||
| 23 | static DEFINE_SPINLOCK(clk_lock); | 27 | static DEFINE_SPINLOCK(clk_lock); |
| 28 | static DEFINE_SPINLOCK(clk_list_lock); | ||
| 29 | |||
| 30 | void at32_clk_register(struct clk *clk) | ||
| 31 | { | ||
| 32 | spin_lock(&clk_list_lock); | ||
| 33 | /* add the new item to the end of the list */ | ||
| 34 | list_add_tail(&clk->list, &at32_clock_list); | ||
| 35 | spin_unlock(&clk_list_lock); | ||
| 36 | } | ||
| 24 | 37 | ||
| 25 | struct clk *clk_get(struct device *dev, const char *id) | 38 | struct clk *clk_get(struct device *dev, const char *id) |
| 26 | { | 39 | { |
| 27 | int i; | 40 | struct clk *clk; |
| 28 | 41 | ||
| 29 | for (i = 0; i < at32_nr_clocks; i++) { | 42 | spin_lock(&clk_list_lock); |
| 30 | struct clk *clk = at32_clock_list[i]; | ||
| 31 | 43 | ||
| 32 | if (clk->dev == dev && strcmp(id, clk->name) == 0) | 44 | list_for_each_entry(clk, &at32_clock_list, list) { |
| 45 | if (clk->dev == dev && strcmp(id, clk->name) == 0) { | ||
| 46 | spin_unlock(&clk_list_lock); | ||
| 33 | return clk; | 47 | return clk; |
| 48 | } | ||
| 34 | } | 49 | } |
| 35 | 50 | ||
| 51 | spin_unlock(&clk_list_lock); | ||
| 36 | return ERR_PTR(-ENOENT); | 52 | return ERR_PTR(-ENOENT); |
| 37 | } | 53 | } |
| 38 | EXPORT_SYMBOL(clk_get); | 54 | EXPORT_SYMBOL(clk_get); |
| @@ -203,8 +219,8 @@ dump_clock(struct clk *parent, struct clkinf *r) | |||
| 203 | 219 | ||
| 204 | /* cost of this scan is small, but not linear... */ | 220 | /* cost of this scan is small, but not linear... */ |
| 205 | r->nest = nest + NEST_DELTA; | 221 | r->nest = nest + NEST_DELTA; |
| 206 | for (i = 3; i < at32_nr_clocks; i++) { | 222 | |
| 207 | clk = at32_clock_list[i]; | 223 | list_for_each_entry(clk, &at32_clock_list, list) { |
| 208 | if (clk->parent == parent) | 224 | if (clk->parent == parent) |
| 209 | dump_clock(clk, r); | 225 | dump_clock(clk, r); |
| 210 | } | 226 | } |
| @@ -215,6 +231,7 @@ static int clk_show(struct seq_file *s, void *unused) | |||
| 215 | { | 231 | { |
| 216 | struct clkinf r; | 232 | struct clkinf r; |
| 217 | int i; | 233 | int i; |
| 234 | struct clk *clk; | ||
| 218 | 235 | ||
| 219 | /* show all the power manager registers */ | 236 | /* show all the power manager registers */ |
| 220 | seq_printf(s, "MCCTRL = %8x\n", pm_readl(MCCTRL)); | 237 | seq_printf(s, "MCCTRL = %8x\n", pm_readl(MCCTRL)); |
| @@ -234,14 +251,25 @@ static int clk_show(struct seq_file *s, void *unused) | |||
| 234 | 251 | ||
| 235 | seq_printf(s, "\n"); | 252 | seq_printf(s, "\n"); |
| 236 | 253 | ||
| 237 | /* show clock tree as derived from the three oscillators | ||
| 238 | * we "know" are at the head of the list | ||
| 239 | */ | ||
| 240 | r.s = s; | 254 | r.s = s; |
| 241 | r.nest = 0; | 255 | r.nest = 0; |
| 242 | dump_clock(at32_clock_list[0], &r); | 256 | /* protected from changes on the list while dumping */ |
| 243 | dump_clock(at32_clock_list[1], &r); | 257 | spin_lock(&clk_list_lock); |
| 244 | dump_clock(at32_clock_list[2], &r); | 258 | |
| 259 | /* show clock tree as derived from the three oscillators */ | ||
| 260 | clk = clk_get(NULL, "osc32k"); | ||
| 261 | dump_clock(clk, &r); | ||
| 262 | clk_put(clk); | ||
| 263 | |||
| 264 | clk = clk_get(NULL, "osc0"); | ||
| 265 | dump_clock(clk, &r); | ||
| 266 | clk_put(clk); | ||
| 267 | |||
| 268 | clk = clk_get(NULL, "osc1"); | ||
| 269 | dump_clock(clk, &r); | ||
| 270 | clk_put(clk); | ||
| 271 | |||
| 272 | spin_unlock(&clk_list_lock); | ||
| 245 | 273 | ||
| 246 | return 0; | 274 | return 0; |
| 247 | } | 275 | } |
diff --git a/arch/avr32/mach-at32ap/clock.h b/arch/avr32/mach-at32ap/clock.h index bb8e1f295835..623bf0e9a1e7 100644 --- a/arch/avr32/mach-at32ap/clock.h +++ b/arch/avr32/mach-at32ap/clock.h | |||
| @@ -12,8 +12,13 @@ | |||
| 12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
| 13 | */ | 13 | */ |
| 14 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
| 15 | #include <linux/list.h> | ||
| 16 | |||
| 17 | |||
| 18 | void at32_clk_register(struct clk *clk); | ||
| 15 | 19 | ||
| 16 | struct clk { | 20 | struct clk { |
| 21 | struct list_head list; /* linking element */ | ||
| 17 | const char *name; /* Clock name/function */ | 22 | const char *name; /* Clock name/function */ |
| 18 | struct device *dev; /* Device the clock is used by */ | 23 | struct device *dev; /* Device the clock is used by */ |
| 19 | struct clk *parent; /* Parent clock, if any */ | 24 | struct clk *parent; /* Parent clock, if any */ |
| @@ -25,6 +30,3 @@ struct clk { | |||
| 25 | u16 users; /* Enabled if non-zero */ | 30 | u16 users; /* Enabled if non-zero */ |
| 26 | u16 index; /* Sibling index */ | 31 | u16 index; /* Sibling index */ |
| 27 | }; | 32 | }; |
| 28 | |||
| 29 | extern struct clk *at32_clock_list[]; | ||
| 30 | extern unsigned int at32_nr_clocks; | ||
