aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/clkdev.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-03-08 07:45:19 -0500
committerPaul Mundt <lethal@linux-sh.org>2010-03-08 21:57:17 -0500
commit51a5006afcd13176276f0935ee57c4cc6f210e83 (patch)
treea5842fabed2ac33ac5b807d5764687babf5787d3 /arch/sh/kernel/clkdev.c
parent40d1f0048289b1baed859baee06878417fae540e (diff)
sh: Merge clkdev API updates.
This rolls in the remainder of the clkdev API bits from the ARM tree. This can more or less be used verbatim, so we just copy it over and nuke our local version. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/clkdev.c')
-rw-r--r--arch/sh/kernel/clkdev.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/arch/sh/kernel/clkdev.c b/arch/sh/kernel/clkdev.c
new file mode 100644
index 000000000000..29cd802ac388
--- /dev/null
+++ b/arch/sh/kernel/clkdev.c
@@ -0,0 +1,162 @@
1/*
2 * arch/sh/kernel/clkdev.c
3 *
4 * Cloned from arch/arm/common/clkdev.c:
5 *
6 * Copyright (C) 2008 Russell King.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Helper for the clk API to assist looking up a struct clk.
13 */
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/device.h>
17#include <linux/list.h>
18#include <linux/errno.h>
19#include <linux/err.h>
20#include <linux/string.h>
21#include <linux/mutex.h>
22#include <linux/clk.h>
23#include <asm/clock.h>
24#include <asm/clkdev.h>
25
26static LIST_HEAD(clocks);
27static DEFINE_MUTEX(clocks_mutex);
28
29/*
30 * Find the correct struct clk for the device and connection ID.
31 * We do slightly fuzzy matching here:
32 * An entry with a NULL ID is assumed to be a wildcard.
33 * If an entry has a device ID, it must match
34 * If an entry has a connection ID, it must match
35 * Then we take the most specific entry - with the following
36 * order of precidence: dev+con > dev only > con only.
37 */
38static struct clk *clk_find(const char *dev_id, const char *con_id)
39{
40 struct clk_lookup *p;
41 struct clk *clk = NULL;
42 int match, best = 0;
43
44 list_for_each_entry(p, &clocks, node) {
45 match = 0;
46 if (p->dev_id) {
47 if (!dev_id || strcmp(p->dev_id, dev_id))
48 continue;
49 match += 2;
50 }
51 if (p->con_id) {
52 if (!con_id || strcmp(p->con_id, con_id))
53 continue;
54 match += 1;
55 }
56 if (match == 0)
57 continue;
58
59 if (match > best) {
60 clk = p->clk;
61 best = match;
62 }
63 }
64 return clk;
65}
66
67struct clk *clk_get_sys(const char *dev_id, const char *con_id)
68{
69 struct clk *clk;
70
71 mutex_lock(&clocks_mutex);
72 clk = clk_find(dev_id, con_id);
73 mutex_unlock(&clocks_mutex);
74
75 return clk ? clk : ERR_PTR(-ENOENT);
76}
77EXPORT_SYMBOL(clk_get_sys);
78
79void clkdev_add(struct clk_lookup *cl)
80{
81 mutex_lock(&clocks_mutex);
82 list_add_tail(&cl->node, &clocks);
83 mutex_unlock(&clocks_mutex);
84}
85EXPORT_SYMBOL(clkdev_add);
86
87void __init clkdev_add_table(struct clk_lookup *cl, size_t num)
88{
89 mutex_lock(&clocks_mutex);
90 while (num--) {
91 list_add_tail(&cl->node, &clocks);
92 cl++;
93 }
94 mutex_unlock(&clocks_mutex);
95}
96
97#define MAX_DEV_ID 20
98#define MAX_CON_ID 16
99
100struct clk_lookup_alloc {
101 struct clk_lookup cl;
102 char dev_id[MAX_DEV_ID];
103 char con_id[MAX_CON_ID];
104};
105
106struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
107 const char *dev_fmt, ...)
108{
109 struct clk_lookup_alloc *cla;
110
111 cla = kzalloc(sizeof(*cla), GFP_KERNEL);
112 if (!cla)
113 return NULL;
114
115 cla->cl.clk = clk;
116 if (con_id) {
117 strlcpy(cla->con_id, con_id, sizeof(cla->con_id));
118 cla->cl.con_id = cla->con_id;
119 }
120
121 if (dev_fmt) {
122 va_list ap;
123
124 va_start(ap, dev_fmt);
125 vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap);
126 cla->cl.dev_id = cla->dev_id;
127 va_end(ap);
128 }
129
130 return &cla->cl;
131}
132EXPORT_SYMBOL(clkdev_alloc);
133
134int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
135 struct device *dev)
136{
137 struct clk *r = clk_get(dev, id);
138 struct clk_lookup *l;
139
140 if (IS_ERR(r))
141 return PTR_ERR(r);
142
143 l = clkdev_alloc(r, alias, alias_dev_name);
144 clk_put(r);
145 if (!l)
146 return -ENODEV;
147 clkdev_add(l);
148 return 0;
149}
150EXPORT_SYMBOL(clk_add_alias);
151
152/*
153 * clkdev_drop - remove a clock dynamically allocated
154 */
155void clkdev_drop(struct clk_lookup *cl)
156{
157 mutex_lock(&clocks_mutex);
158 list_del(&cl->node);
159 mutex_unlock(&clocks_mutex);
160 kfree(cl);
161}
162EXPORT_SYMBOL(clkdev_drop);