avr32: Replace static clock list with dynamic linked list
Alex Raimondi [Mon, 22 Sep 2008 19:40:55 +0000 (21:40 +0200)]
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>

arch/avr32/mach-at32ap/at32ap700x.c
arch/avr32/mach-at32ap/clock.c
arch/avr32/mach-at32ap/clock.h

index c28dd17..fd306c4 100644 (file)
@@ -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;
index 6c27dda..138a00a 100644 (file)
 #include <linux/err.h>
 #include <linux/device.h>
 #include <linux/string.h>
+#include <linux/list.h>
 
 #include <mach/chip.h>
 
 #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;
 }
index bb8e1f2..623bf0e 100644 (file)
  * published by the Free Software Foundation.
  */
 #include <linux/clk.h>
+#include <linux/list.h>
+
+
+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;