Blame view

drivers/clk/clkdev.c 3.6 KB
0318e693d   Russell King   [ARM] clkdev: add...
1
  /*
6d803ba73   Jean-Christop PLAGNIOL-VILLARD   ARM: 6483/1: arm ...
2
   * drivers/clk/clkdev.c
0318e693d   Russell King   [ARM] clkdev: add...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
   *
   *  Copyright (C) 2008 Russell King.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
   * Helper for the clk API to assist looking up a struct clk.
   */
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/device.h>
  #include <linux/list.h>
  #include <linux/errno.h>
  #include <linux/err.h>
  #include <linux/string.h>
  #include <linux/mutex.h>
c0c60c4b9   Hartley Sweeten   ARM: 5639/1: arm:...
20
  #include <linux/clk.h>
6d803ba73   Jean-Christop PLAGNIOL-VILLARD   ARM: 6483/1: arm ...
21
  #include <linux/clkdev.h>
0318e693d   Russell King   [ARM] clkdev: add...
22
23
24
  
  static LIST_HEAD(clocks);
  static DEFINE_MUTEX(clocks_mutex);
409dc360b   Russell King   [ARM] clkdev: fix...
25
26
27
28
29
30
31
  /*
   * Find the correct struct clk for the device and connection ID.
   * We do slightly fuzzy matching here:
   *  An entry with a NULL ID is assumed to be a wildcard.
   *  If an entry has a device ID, it must match
   *  If an entry has a connection ID, it must match
   * Then we take the most specific entry - with the following
659431fca   Uwe Kleine-König   fix typos "precid...
32
   * order of precedence: dev+con > dev only > con only.
409dc360b   Russell King   [ARM] clkdev: fix...
33
   */
0318e693d   Russell King   [ARM] clkdev: add...
34
35
36
37
38
39
40
  static struct clk *clk_find(const char *dev_id, const char *con_id)
  {
  	struct clk_lookup *p;
  	struct clk *clk = NULL;
  	int match, best = 0;
  
  	list_for_each_entry(p, &clocks, node) {
0318e693d   Russell King   [ARM] clkdev: add...
41
  		match = 0;
409dc360b   Russell King   [ARM] clkdev: fix...
42
43
44
45
46
47
48
49
50
51
  		if (p->dev_id) {
  			if (!dev_id || strcmp(p->dev_id, dev_id))
  				continue;
  			match += 2;
  		}
  		if (p->con_id) {
  			if (!con_id || strcmp(p->con_id, con_id))
  				continue;
  			match += 1;
  		}
0318e693d   Russell King   [ARM] clkdev: add...
52
53
54
  
  		if (match > best) {
  			clk = p->clk;
e4bf5becc   viresh kumar   ARM: 5979/1: CLKD...
55
56
57
58
  			if (match != 3)
  				best = match;
  			else
  				break;
0318e693d   Russell King   [ARM] clkdev: add...
59
60
61
62
  		}
  	}
  	return clk;
  }
05fd8e73e   Sascha Hauer   clkdev: add possi...
63
  struct clk *clk_get_sys(const char *dev_id, const char *con_id)
0318e693d   Russell King   [ARM] clkdev: add...
64
  {
0318e693d   Russell King   [ARM] clkdev: add...
65
66
67
68
69
70
71
72
73
74
  	struct clk *clk;
  
  	mutex_lock(&clocks_mutex);
  	clk = clk_find(dev_id, con_id);
  	if (clk && !__clk_get(clk))
  		clk = NULL;
  	mutex_unlock(&clocks_mutex);
  
  	return clk ? clk : ERR_PTR(-ENOENT);
  }
05fd8e73e   Sascha Hauer   clkdev: add possi...
75
76
77
78
79
80
81
82
  EXPORT_SYMBOL(clk_get_sys);
  
  struct clk *clk_get(struct device *dev, const char *con_id)
  {
  	const char *dev_id = dev ? dev_name(dev) : NULL;
  
  	return clk_get_sys(dev_id, con_id);
  }
0318e693d   Russell King   [ARM] clkdev: add...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
  EXPORT_SYMBOL(clk_get);
  
  void clk_put(struct clk *clk)
  {
  	__clk_put(clk);
  }
  EXPORT_SYMBOL(clk_put);
  
  void clkdev_add(struct clk_lookup *cl)
  {
  	mutex_lock(&clocks_mutex);
  	list_add_tail(&cl->node, &clocks);
  	mutex_unlock(&clocks_mutex);
  }
  EXPORT_SYMBOL(clkdev_add);
0a0300dc8   Russell King   ARM: Consolidate ...
98
99
100
101
102
103
104
105
106
  void __init clkdev_add_table(struct clk_lookup *cl, size_t num)
  {
  	mutex_lock(&clocks_mutex);
  	while (num--) {
  		list_add_tail(&cl->node, &clocks);
  		cl++;
  	}
  	mutex_unlock(&clocks_mutex);
  }
0318e693d   Russell King   [ARM] clkdev: add...
107
108
109
110
111
112
113
114
  #define MAX_DEV_ID	20
  #define MAX_CON_ID	16
  
  struct clk_lookup_alloc {
  	struct clk_lookup cl;
  	char	dev_id[MAX_DEV_ID];
  	char	con_id[MAX_CON_ID];
  };
6d803ba73   Jean-Christop PLAGNIOL-VILLARD   ARM: 6483/1: arm ...
115
116
  struct clk_lookup * __init_refok
  clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...)
0318e693d   Russell King   [ARM] clkdev: add...
117
118
  {
  	struct clk_lookup_alloc *cla;
6d803ba73   Jean-Christop PLAGNIOL-VILLARD   ARM: 6483/1: arm ...
119
  	cla = __clkdev_alloc(sizeof(*cla));
0318e693d   Russell King   [ARM] clkdev: add...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  	if (!cla)
  		return NULL;
  
  	cla->cl.clk = clk;
  	if (con_id) {
  		strlcpy(cla->con_id, con_id, sizeof(cla->con_id));
  		cla->cl.con_id = cla->con_id;
  	}
  
  	if (dev_fmt) {
  		va_list ap;
  
  		va_start(ap, dev_fmt);
  		vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap);
  		cla->cl.dev_id = cla->dev_id;
  		va_end(ap);
  	}
  
  	return &cla->cl;
  }
  EXPORT_SYMBOL(clkdev_alloc);
c06830392   Tony Lindgren   [ARM] 5536/1: Mov...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
  	struct device *dev)
  {
  	struct clk *r = clk_get(dev, id);
  	struct clk_lookup *l;
  
  	if (IS_ERR(r))
  		return PTR_ERR(r);
  
  	l = clkdev_alloc(r, alias, alias_dev_name);
  	clk_put(r);
  	if (!l)
  		return -ENODEV;
  	clkdev_add(l);
  	return 0;
  }
  EXPORT_SYMBOL(clk_add_alias);
0318e693d   Russell King   [ARM] clkdev: add...
158
159
160
161
162
163
164
165
166
167
168
  /*
   * clkdev_drop - remove a clock dynamically allocated
   */
  void clkdev_drop(struct clk_lookup *cl)
  {
  	mutex_lock(&clocks_mutex);
  	list_del(&cl->node);
  	mutex_unlock(&clocks_mutex);
  	kfree(cl);
  }
  EXPORT_SYMBOL(clkdev_drop);