]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/mfd/vexpress-config.c
of: Keep track of populated platform devices
[mirror_ubuntu-artful-kernel.git] / drivers / mfd / vexpress-config.c
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * Copyright (C) 2012 ARM Limited
12 */
13
14 #define pr_fmt(fmt) "vexpress-config: " fmt
15
16 #include <linux/bitops.h>
17 #include <linux/completion.h>
18 #include <linux/export.h>
19 #include <linux/list.h>
20 #include <linux/of.h>
21 #include <linux/of_device.h>
22 #include <linux/slab.h>
23 #include <linux/string.h>
24 #include <linux/vexpress.h>
25
26
27 #define VEXPRESS_CONFIG_MAX_BRIDGES 2
28
29 static struct vexpress_config_bridge {
30 struct device_node *node;
31 struct vexpress_config_bridge_info *info;
32 struct list_head transactions;
33 spinlock_t transactions_lock;
34 } vexpress_config_bridges[VEXPRESS_CONFIG_MAX_BRIDGES];
35
36 static DECLARE_BITMAP(vexpress_config_bridges_map,
37 ARRAY_SIZE(vexpress_config_bridges));
38 static DEFINE_MUTEX(vexpress_config_bridges_mutex);
39
40 struct vexpress_config_bridge *vexpress_config_bridge_register(
41 struct device_node *node,
42 struct vexpress_config_bridge_info *info)
43 {
44 struct vexpress_config_bridge *bridge;
45 int i;
46
47 pr_debug("Registering bridge '%s'\n", info->name);
48
49 mutex_lock(&vexpress_config_bridges_mutex);
50 i = find_first_zero_bit(vexpress_config_bridges_map,
51 ARRAY_SIZE(vexpress_config_bridges));
52 if (i >= ARRAY_SIZE(vexpress_config_bridges)) {
53 pr_err("Can't register more bridges!\n");
54 mutex_unlock(&vexpress_config_bridges_mutex);
55 return NULL;
56 }
57 __set_bit(i, vexpress_config_bridges_map);
58 bridge = &vexpress_config_bridges[i];
59
60 bridge->node = node;
61 bridge->info = info;
62 INIT_LIST_HEAD(&bridge->transactions);
63 spin_lock_init(&bridge->transactions_lock);
64
65 mutex_unlock(&vexpress_config_bridges_mutex);
66
67 return bridge;
68 }
69 EXPORT_SYMBOL(vexpress_config_bridge_register);
70
71 void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge)
72 {
73 struct vexpress_config_bridge __bridge = *bridge;
74 int i;
75
76 mutex_lock(&vexpress_config_bridges_mutex);
77 for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++)
78 if (&vexpress_config_bridges[i] == bridge)
79 __clear_bit(i, vexpress_config_bridges_map);
80 mutex_unlock(&vexpress_config_bridges_mutex);
81
82 WARN_ON(!list_empty(&__bridge.transactions));
83 while (!list_empty(&__bridge.transactions))
84 cpu_relax();
85 }
86 EXPORT_SYMBOL(vexpress_config_bridge_unregister);
87
88
89 struct vexpress_config_func {
90 struct vexpress_config_bridge *bridge;
91 void *func;
92 };
93
94 struct vexpress_config_func *__vexpress_config_func_get(struct device *dev,
95 struct device_node *node)
96 {
97 struct device_node *bridge_node;
98 struct vexpress_config_func *func;
99 int i;
100
101 if (WARN_ON(dev && node && dev->of_node != node))
102 return NULL;
103 if (dev && !node)
104 node = dev->of_node;
105
106 func = kzalloc(sizeof(*func), GFP_KERNEL);
107 if (!func)
108 return NULL;
109
110 bridge_node = of_node_get(node);
111 while (bridge_node) {
112 const __be32 *prop = of_get_property(bridge_node,
113 "arm,vexpress,config-bridge", NULL);
114
115 if (prop) {
116 bridge_node = of_find_node_by_phandle(
117 be32_to_cpup(prop));
118 break;
119 }
120
121 bridge_node = of_get_next_parent(bridge_node);
122 }
123
124 mutex_lock(&vexpress_config_bridges_mutex);
125 for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++) {
126 struct vexpress_config_bridge *bridge =
127 &vexpress_config_bridges[i];
128
129 if (test_bit(i, vexpress_config_bridges_map) &&
130 bridge->node == bridge_node) {
131 func->bridge = bridge;
132 func->func = bridge->info->func_get(dev, node);
133 break;
134 }
135 }
136 mutex_unlock(&vexpress_config_bridges_mutex);
137
138 if (!func->func) {
139 of_node_put(node);
140 kfree(func);
141 return NULL;
142 }
143
144 return func;
145 }
146 EXPORT_SYMBOL(__vexpress_config_func_get);
147
148 void vexpress_config_func_put(struct vexpress_config_func *func)
149 {
150 func->bridge->info->func_put(func->func);
151 of_node_put(func->bridge->node);
152 kfree(func);
153 }
154 EXPORT_SYMBOL(vexpress_config_func_put);
155
156 struct vexpress_config_trans {
157 struct vexpress_config_func *func;
158 int offset;
159 bool write;
160 u32 *data;
161 int status;
162 struct completion completion;
163 struct list_head list;
164 };
165
166 static void vexpress_config_dump_trans(const char *what,
167 struct vexpress_config_trans *trans)
168 {
169 pr_debug("%s %s trans %p func 0x%p offset %d data 0x%x status %d\n",
170 what, trans->write ? "write" : "read", trans,
171 trans->func->func, trans->offset,
172 trans->data ? *trans->data : 0, trans->status);
173 }
174
175 static int vexpress_config_schedule(struct vexpress_config_trans *trans)
176 {
177 int status;
178 struct vexpress_config_bridge *bridge = trans->func->bridge;
179 unsigned long flags;
180
181 init_completion(&trans->completion);
182 trans->status = -EFAULT;
183
184 spin_lock_irqsave(&bridge->transactions_lock, flags);
185
186 if (list_empty(&bridge->transactions)) {
187 vexpress_config_dump_trans("Executing", trans);
188 status = bridge->info->func_exec(trans->func->func,
189 trans->offset, trans->write, trans->data);
190 } else {
191 vexpress_config_dump_trans("Queuing", trans);
192 status = VEXPRESS_CONFIG_STATUS_WAIT;
193 }
194
195 switch (status) {
196 case VEXPRESS_CONFIG_STATUS_DONE:
197 vexpress_config_dump_trans("Finished", trans);
198 trans->status = status;
199 break;
200 case VEXPRESS_CONFIG_STATUS_WAIT:
201 list_add_tail(&trans->list, &bridge->transactions);
202 break;
203 }
204
205 spin_unlock_irqrestore(&bridge->transactions_lock, flags);
206
207 return status;
208 }
209
210 void vexpress_config_complete(struct vexpress_config_bridge *bridge,
211 int status)
212 {
213 struct vexpress_config_trans *trans;
214 unsigned long flags;
215 const char *message = "Completed";
216
217 spin_lock_irqsave(&bridge->transactions_lock, flags);
218
219 trans = list_first_entry(&bridge->transactions,
220 struct vexpress_config_trans, list);
221 trans->status = status;
222
223 do {
224 vexpress_config_dump_trans(message, trans);
225 list_del(&trans->list);
226 complete(&trans->completion);
227
228 if (list_empty(&bridge->transactions))
229 break;
230
231 trans = list_first_entry(&bridge->transactions,
232 struct vexpress_config_trans, list);
233 vexpress_config_dump_trans("Executing pending", trans);
234 trans->status = bridge->info->func_exec(trans->func->func,
235 trans->offset, trans->write, trans->data);
236 message = "Finished pending";
237 } while (trans->status == VEXPRESS_CONFIG_STATUS_DONE);
238
239 spin_unlock_irqrestore(&bridge->transactions_lock, flags);
240 }
241 EXPORT_SYMBOL(vexpress_config_complete);
242
243 int vexpress_config_wait(struct vexpress_config_trans *trans)
244 {
245 wait_for_completion(&trans->completion);
246
247 return trans->status;
248 }
249 EXPORT_SYMBOL(vexpress_config_wait);
250
251 int vexpress_config_read(struct vexpress_config_func *func, int offset,
252 u32 *data)
253 {
254 struct vexpress_config_trans trans = {
255 .func = func,
256 .offset = offset,
257 .write = false,
258 .data = data,
259 .status = 0,
260 };
261 int status = vexpress_config_schedule(&trans);
262
263 if (status == VEXPRESS_CONFIG_STATUS_WAIT)
264 status = vexpress_config_wait(&trans);
265
266 return status;
267 }
268 EXPORT_SYMBOL(vexpress_config_read);
269
270 int vexpress_config_write(struct vexpress_config_func *func, int offset,
271 u32 data)
272 {
273 struct vexpress_config_trans trans = {
274 .func = func,
275 .offset = offset,
276 .write = true,
277 .data = &data,
278 .status = 0,
279 };
280 int status = vexpress_config_schedule(&trans);
281
282 if (status == VEXPRESS_CONFIG_STATUS_WAIT)
283 status = vexpress_config_wait(&trans);
284
285 return status;
286 }
287 EXPORT_SYMBOL(vexpress_config_write);