Merge tag 'v3.14.25' into backport/v3.14.24-ltsi-rc1+v3.14.25/snapshot-merge.wip
[platform/adaptation/renesas_rcar/renesas_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 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);