Merge git://git.marvell.com/orion into devel
[linux-2.6] / arch / arm / common / clkdev.c
1 /*
2  *  arch/arm/common/clkdev.c
3  *
4  *  Copyright (C) 2008 Russell King.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * Helper for the clk API to assist looking up a struct clk.
11  */
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/device.h>
15 #include <linux/list.h>
16 #include <linux/errno.h>
17 #include <linux/err.h>
18 #include <linux/string.h>
19 #include <linux/mutex.h>
20
21 #include <asm/clkdev.h>
22 #include <mach/clkdev.h>
23
24 static LIST_HEAD(clocks);
25 static DEFINE_MUTEX(clocks_mutex);
26
27 static struct clk *clk_find(const char *dev_id, const char *con_id)
28 {
29         struct clk_lookup *p;
30         struct clk *clk = NULL;
31         int match, best = 0;
32
33         list_for_each_entry(p, &clocks, node) {
34                 if ((p->dev_id && !dev_id) || (p->con_id && !con_id))
35                         continue;
36                 match = 0;
37                 if (p->dev_id)
38                         match += 2 * (strcmp(p->dev_id, dev_id) == 0);
39                 if (p->con_id)
40                         match += 1 * (strcmp(p->con_id, con_id) == 0);
41                 if (match == 0)
42                         continue;
43
44                 if (match > best) {
45                         clk = p->clk;
46                         best = match;
47                 }
48         }
49         return clk;
50 }
51
52 struct clk *clk_get(struct device *dev, const char *con_id)
53 {
54         const char *dev_id = dev ? dev_name(dev) : NULL;
55         struct clk *clk;
56
57         mutex_lock(&clocks_mutex);
58         clk = clk_find(dev_id, con_id);
59         if (clk && !__clk_get(clk))
60                 clk = NULL;
61         mutex_unlock(&clocks_mutex);
62
63         return clk ? clk : ERR_PTR(-ENOENT);
64 }
65 EXPORT_SYMBOL(clk_get);
66
67 void clk_put(struct clk *clk)
68 {
69         __clk_put(clk);
70 }
71 EXPORT_SYMBOL(clk_put);
72
73 void clkdev_add(struct clk_lookup *cl)
74 {
75         mutex_lock(&clocks_mutex);
76         list_add_tail(&cl->node, &clocks);
77         mutex_unlock(&clocks_mutex);
78 }
79 EXPORT_SYMBOL(clkdev_add);
80
81 #define MAX_DEV_ID      20
82 #define MAX_CON_ID      16
83
84 struct clk_lookup_alloc {
85         struct clk_lookup cl;
86         char    dev_id[MAX_DEV_ID];
87         char    con_id[MAX_CON_ID];
88 };
89
90 struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
91         const char *dev_fmt, ...)
92 {
93         struct clk_lookup_alloc *cla;
94
95         cla = kzalloc(sizeof(*cla), GFP_KERNEL);
96         if (!cla)
97                 return NULL;
98
99         cla->cl.clk = clk;
100         if (con_id) {
101                 strlcpy(cla->con_id, con_id, sizeof(cla->con_id));
102                 cla->cl.con_id = cla->con_id;
103         }
104
105         if (dev_fmt) {
106                 va_list ap;
107
108                 va_start(ap, dev_fmt);
109                 vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap);
110                 cla->cl.dev_id = cla->dev_id;
111                 va_end(ap);
112         }
113
114         return &cla->cl;
115 }
116 EXPORT_SYMBOL(clkdev_alloc);
117
118 /*
119  * clkdev_drop - remove a clock dynamically allocated
120  */
121 void clkdev_drop(struct clk_lookup *cl)
122 {
123         mutex_lock(&clocks_mutex);
124         list_del(&cl->node);
125         mutex_unlock(&clocks_mutex);
126         kfree(cl);
127 }
128 EXPORT_SYMBOL(clkdev_drop);