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
   */
e8bf8df9c   Russell King   CLKDEV: Fix clkde...
34
  static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
0318e693d   Russell King   [ARM] clkdev: add...
35
  {
e8bf8df9c   Russell King   CLKDEV: Fix clkde...
36
  	struct clk_lookup *p, *cl = NULL;
0318e693d   Russell King   [ARM] clkdev: add...
37
38
39
  	int match, best = 0;
  
  	list_for_each_entry(p, &clocks, node) {
0318e693d   Russell King   [ARM] clkdev: add...
40
  		match = 0;
409dc360b   Russell King   [ARM] clkdev: fix...
41
42
43
44
45
46
47
48
49
50
  		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...
51
52
  
  		if (match > best) {
e8bf8df9c   Russell King   CLKDEV: Fix clkde...
53
  			cl = p;
e4bf5becc   viresh kumar   ARM: 5979/1: CLKD...
54
55
56
57
  			if (match != 3)
  				best = match;
  			else
  				break;
0318e693d   Russell King   [ARM] clkdev: add...
58
59
  		}
  	}
e8bf8df9c   Russell King   CLKDEV: Fix clkde...
60
  	return cl;
0318e693d   Russell King   [ARM] clkdev: add...
61
  }
05fd8e73e   Sascha Hauer   clkdev: add possi...
62
  struct clk *clk_get_sys(const char *dev_id, const char *con_id)
0318e693d   Russell King   [ARM] clkdev: add...
63
  {
e8bf8df9c   Russell King   CLKDEV: Fix clkde...
64
  	struct clk_lookup *cl;
0318e693d   Russell King   [ARM] clkdev: add...
65
66
  
  	mutex_lock(&clocks_mutex);
e8bf8df9c   Russell King   CLKDEV: Fix clkde...
67
68
69
  	cl = clk_find(dev_id, con_id);
  	if (cl && !__clk_get(cl->clk))
  		cl = NULL;
0318e693d   Russell King   [ARM] clkdev: add...
70
  	mutex_unlock(&clocks_mutex);
e8bf8df9c   Russell King   CLKDEV: Fix clkde...
71
  	return cl ? cl->clk : ERR_PTR(-ENOENT);
0318e693d   Russell King   [ARM] clkdev: add...
72
  }
05fd8e73e   Sascha Hauer   clkdev: add possi...
73
74
75
76
77
78
79
80
  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...
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  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 ...
96
97
98
99
100
101
102
103
104
  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...
105
106
107
108
109
110
111
112
  #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 ...
113
114
  struct clk_lookup * __init_refok
  clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...)
0318e693d   Russell King   [ARM] clkdev: add...
115
116
  {
  	struct clk_lookup_alloc *cla;
6d803ba73   Jean-Christop PLAGNIOL-VILLARD   ARM: 6483/1: arm ...
117
  	cla = __clkdev_alloc(sizeof(*cla));
0318e693d   Russell King   [ARM] clkdev: add...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  	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...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
  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...
156
157
158
159
160
161
162
163
164
165
166
  /*
   * 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);