mfd: vexpress: Staticize vexpress_config_bridges
[deliverable/linux.git] / drivers / mfd / vexpress-config.c
CommitLineData
3ecbf05b
PM
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>
3ecbf05b
PM
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
39296693 29static struct vexpress_config_bridge {
3ecbf05b
PM
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
36static DECLARE_BITMAP(vexpress_config_bridges_map,
37 ARRAY_SIZE(vexpress_config_bridges));
38static DEFINE_MUTEX(vexpress_config_bridges_mutex);
39
40struct 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}
a17155bc 69EXPORT_SYMBOL(vexpress_config_bridge_register);
3ecbf05b
PM
70
71void 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}
a17155bc 86EXPORT_SYMBOL(vexpress_config_bridge_unregister);
3ecbf05b
PM
87
88
89struct vexpress_config_func {
90 struct vexpress_config_bridge *bridge;
91 void *func;
92};
93
94struct 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}
a17155bc 146EXPORT_SYMBOL(__vexpress_config_func_get);
3ecbf05b
PM
147
148void 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}
a17155bc 154EXPORT_SYMBOL(vexpress_config_func_put);
3ecbf05b
PM
155
156struct 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
166static 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
175static 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
367764a4
PM
186 if (list_empty(&bridge->transactions)) {
187 vexpress_config_dump_trans("Executing", trans);
3ecbf05b
PM
188 status = bridge->info->func_exec(trans->func->func,
189 trans->offset, trans->write, trans->data);
367764a4
PM
190 } else {
191 vexpress_config_dump_trans("Queuing", trans);
3ecbf05b 192 status = VEXPRESS_CONFIG_STATUS_WAIT;
367764a4 193 }
3ecbf05b
PM
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
210void vexpress_config_complete(struct vexpress_config_bridge *bridge,
211 int status)
212{
213 struct vexpress_config_trans *trans;
214 unsigned long flags;
367764a4 215 const char *message = "Completed";
3ecbf05b
PM
216
217 spin_lock_irqsave(&bridge->transactions_lock, flags);
218
219 trans = list_first_entry(&bridge->transactions,
220 struct vexpress_config_trans, list);
3ecbf05b 221 trans->status = status;
3ecbf05b 222
367764a4
PM
223 do {
224 vexpress_config_dump_trans(message, trans);
225 list_del(&trans->list);
226 complete(&trans->completion);
3ecbf05b 227
367764a4
PM
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);
3ecbf05b 238
367764a4 239 spin_unlock_irqrestore(&bridge->transactions_lock, flags);
3ecbf05b 240}
a17155bc 241EXPORT_SYMBOL(vexpress_config_complete);
3ecbf05b
PM
242
243int vexpress_config_wait(struct vexpress_config_trans *trans)
244{
245 wait_for_completion(&trans->completion);
246
247 return trans->status;
248}
a17155bc 249EXPORT_SYMBOL(vexpress_config_wait);
3ecbf05b
PM
250
251int 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}
268EXPORT_SYMBOL(vexpress_config_read);
269
270int 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}
287EXPORT_SYMBOL(vexpress_config_write);
This page took 0.108828 seconds and 5 git commands to generate.