source: src/linux/universal/linux-4.9/arch/arm/plat-brcm/clkdev.c @ 31707

Last change on this file since 31707 was 31707, checked in by brainslayer, 10 days ago

compiles on northstar, but nand driver will likelly not work yet. still something todo

File size: 4.9 KB
Line 
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#include <linux/clk.h>
21#include <linux/slab.h>
22
23#include <asm/clkdev.h>
24#include <mach/clkdev.h>
25
26static LIST_HEAD(clocks);
27static DEFINE_MUTEX(clocks_mutex);
28
29static struct clk_hw *__clk_get_hw(struct clk *clk)
30{
31        return (struct clk_hw *)clk;
32}
33
34/*
35 * Find the correct struct clk for the device and connection ID.
36 * We do slightly fuzzy matching here:
37 *  An entry with a NULL ID is assumed to be a wildcard.
38 *  If an entry has a device ID, it must match
39 *  If an entry has a connection ID, it must match
40 * Then we take the most specific entry - with the following
41 * order of precedence: dev+con > dev only > con only.
42 */
43static struct clk *clk_find(const char *dev_id, const char *con_id)
44{
45        struct clk_lookup *p;
46        struct clk *clk = NULL;
47        int match, best = 0;
48
49        list_for_each_entry(p, &clocks, node) {
50                match = 0;
51                if (p->dev_id) {
52                        if (!dev_id || strcmp(p->dev_id, dev_id))
53                                continue;
54                        match += 2;
55                }
56                if (p->con_id) {
57                        if (!con_id || strcmp(p->con_id, con_id))
58                                continue;
59                        match += 1;
60                }
61
62                if (match > best) {
63                        clk = p->clk;
64                        if (match != 3)
65                                best = match;
66                        else
67                                break;
68                }
69        }
70        return clk;
71}
72
73struct clk *clk_get_sys(const char *dev_id, const char *con_id)
74{
75        struct clk *clk;
76
77        mutex_lock(&clocks_mutex);
78        clk = clk_find(dev_id, con_id);
79        if (clk && !__clk_get(clk))
80                clk = NULL;
81        mutex_unlock(&clocks_mutex);
82
83        return clk ? clk : ERR_PTR(-ENOENT);
84}
85EXPORT_SYMBOL(clk_get_sys);
86
87struct clk *clk_get(struct device *dev, const char *con_id)
88{
89        const char *dev_id = dev ? dev_name(dev) : NULL;
90
91        return clk_get_sys(dev_id, con_id);
92}
93EXPORT_SYMBOL(clk_get);
94
95void clk_put(struct clk *clk)
96{
97        __clk_put(clk);
98}
99EXPORT_SYMBOL(clk_put);
100static void __clkdev_add(struct clk_lookup *cl)
101{
102        mutex_lock(&clocks_mutex);
103        list_add_tail(&cl->node, &clocks);
104        mutex_unlock(&clocks_mutex);
105}
106
107void clkdev_add(struct clk_lookup *cl)
108{
109        if (!cl->clk_hw)
110                cl->clk_hw = __clk_get_hw(cl->clk);
111        __clkdev_add(cl);
112}
113EXPORT_SYMBOL(clkdev_add);
114
115
116void __init clkdev_add_table(struct clk_lookup *cl, size_t num)
117{
118        mutex_lock(&clocks_mutex);
119        while (num--) {
120                list_add_tail(&cl->node, &clocks);
121                cl++;
122        }
123        mutex_unlock(&clocks_mutex);
124}
125
126#define MAX_DEV_ID      20
127#define MAX_CON_ID      16
128
129struct clk_lookup_alloc {
130        struct clk_lookup cl;
131        char    dev_id[MAX_DEV_ID];
132        char    con_id[MAX_CON_ID];
133};
134
135static struct clk_lookup * __ref
136vclkdev_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt,
137        va_list ap)
138{
139        struct clk_lookup_alloc *cla;
140
141        cla = __clkdev_alloc(sizeof(*cla));
142        if (!cla)
143                return NULL;
144
145        cla->cl.clk_hw = hw;
146        if (con_id) {
147                strlcpy(cla->con_id, con_id, sizeof(cla->con_id));
148                cla->cl.con_id = cla->con_id;
149        }
150
151        if (dev_fmt) {
152                vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap);
153                cla->cl.dev_id = cla->dev_id;
154        }
155
156        return &cla->cl;
157}
158
159static struct clk_lookup *
160vclkdev_create(struct clk_hw *hw, const char *con_id, const char *dev_fmt,
161        va_list ap)
162{
163        struct clk_lookup *cl;
164
165        cl = vclkdev_alloc(hw, con_id, dev_fmt, ap);
166        if (cl)
167                __clkdev_add(cl);
168
169        return cl;
170}
171
172
173struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
174        const char *dev_fmt, ...)
175{
176        struct clk_lookup_alloc *cla;
177
178        cla = kzalloc(sizeof(*cla), GFP_KERNEL);
179        if (!cla)
180                return NULL;
181
182        cla->cl.clk = clk;
183        if (con_id) {
184                strlcpy(cla->con_id, con_id, sizeof(cla->con_id));
185                cla->cl.con_id = cla->con_id;
186        }
187
188        if (dev_fmt) {
189                va_list ap;
190
191                va_start(ap, dev_fmt);
192                vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap);
193                cla->cl.dev_id = cla->dev_id;
194                va_end(ap);
195        }
196
197        return &cla->cl;
198}
199EXPORT_SYMBOL(clkdev_alloc);
200
201struct clk_lookup *clkdev_create(struct clk *clk, const char *con_id,
202        const char *dev_fmt, ...)
203{
204        struct clk_lookup *cl;
205        va_list ap;
206
207        va_start(ap, dev_fmt);
208        cl = vclkdev_create(__clk_get_hw(clk), con_id, dev_fmt, ap);
209        va_end(ap);
210
211        return cl;
212}
213EXPORT_SYMBOL_GPL(clkdev_create);
214
215
216int clk_add_alias(const char *alias, const char *alias_dev_name,
217        const char *con_id, struct device *dev)
218{
219        struct clk *r = clk_get(dev, con_id);
220        struct clk_lookup *l;
221
222        if (IS_ERR(r))
223                return PTR_ERR(r);
224
225        l = clkdev_create(r, alias, alias_dev_name ? "%s" : NULL,
226                          alias_dev_name);
227        clk_put(r);
228
229        return l ? 0 : -ENODEV;
230}
231EXPORT_SYMBOL(clk_add_alias);
232
233/*
234 * clkdev_drop - remove a clock dynamically allocated
235 */
236void clkdev_drop(struct clk_lookup *cl)
237{
238        mutex_lock(&clocks_mutex);
239        list_del(&cl->node);
240        mutex_unlock(&clocks_mutex);
241        kfree(cl);
242}
243EXPORT_SYMBOL(clkdev_drop);
Note: See TracBrowser for help on using the repository browser.