Linux 5.0.7
[linux/fpc-iii.git] / drivers / bus / vexpress-config.c
blob493e7b9fc81357bc7366539cc4a8eaf22413be7f
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.
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.
11 * Copyright (C) 2014 ARM Limited
14 #include <linux/err.h>
15 #include <linux/init.h>
16 #include <linux/of.h>
17 #include <linux/of_device.h>
18 #include <linux/vexpress.h>
21 struct vexpress_config_bridge {
22 struct vexpress_config_bridge_ops *ops;
23 void *context;
27 static DEFINE_MUTEX(vexpress_config_mutex);
28 static struct class *vexpress_config_class;
29 static u32 vexpress_config_site_master = VEXPRESS_SITE_MASTER;
32 void vexpress_config_set_master(u32 site)
34 vexpress_config_site_master = site;
37 u32 vexpress_config_get_master(void)
39 return vexpress_config_site_master;
42 void vexpress_config_lock(void *arg)
44 mutex_lock(&vexpress_config_mutex);
47 void vexpress_config_unlock(void *arg)
49 mutex_unlock(&vexpress_config_mutex);
53 static void vexpress_config_find_prop(struct device_node *node,
54 const char *name, u32 *val)
56 /* Default value */
57 *val = 0;
59 of_node_get(node);
60 while (node) {
61 if (of_property_read_u32(node, name, val) == 0) {
62 of_node_put(node);
63 return;
65 node = of_get_next_parent(node);
69 int vexpress_config_get_topo(struct device_node *node, u32 *site,
70 u32 *position, u32 *dcc)
72 vexpress_config_find_prop(node, "arm,vexpress,site", site);
73 if (*site == VEXPRESS_SITE_MASTER)
74 *site = vexpress_config_site_master;
75 if (WARN_ON(vexpress_config_site_master == VEXPRESS_SITE_MASTER))
76 return -EINVAL;
77 vexpress_config_find_prop(node, "arm,vexpress,position", position);
78 vexpress_config_find_prop(node, "arm,vexpress,dcc", dcc);
80 return 0;
84 static void vexpress_config_devres_release(struct device *dev, void *res)
86 struct vexpress_config_bridge *bridge = dev_get_drvdata(dev->parent);
87 struct regmap *regmap = res;
89 bridge->ops->regmap_exit(regmap, bridge->context);
92 struct regmap *devm_regmap_init_vexpress_config(struct device *dev)
94 struct vexpress_config_bridge *bridge;
95 struct regmap *regmap;
96 struct regmap **res;
98 if (WARN_ON(dev->parent->class != vexpress_config_class))
99 return ERR_PTR(-ENODEV);
101 bridge = dev_get_drvdata(dev->parent);
102 if (WARN_ON(!bridge))
103 return ERR_PTR(-EINVAL);
105 res = devres_alloc(vexpress_config_devres_release, sizeof(*res),
106 GFP_KERNEL);
107 if (!res)
108 return ERR_PTR(-ENOMEM);
110 regmap = (bridge->ops->regmap_init)(dev, bridge->context);
111 if (IS_ERR(regmap)) {
112 devres_free(res);
113 return regmap;
116 *res = regmap;
117 devres_add(dev, res);
119 return regmap;
121 EXPORT_SYMBOL_GPL(devm_regmap_init_vexpress_config);
123 struct device *vexpress_config_bridge_register(struct device *parent,
124 struct vexpress_config_bridge_ops *ops, void *context)
126 struct device *dev;
127 struct vexpress_config_bridge *bridge;
129 if (!vexpress_config_class) {
130 vexpress_config_class = class_create(THIS_MODULE,
131 "vexpress-config");
132 if (IS_ERR(vexpress_config_class))
133 return (void *)vexpress_config_class;
136 dev = device_create(vexpress_config_class, parent, 0,
137 NULL, "%s.bridge", dev_name(parent));
139 if (IS_ERR(dev))
140 return dev;
142 bridge = devm_kmalloc(dev, sizeof(*bridge), GFP_KERNEL);
143 if (!bridge) {
144 put_device(dev);
145 device_unregister(dev);
146 return ERR_PTR(-ENOMEM);
148 bridge->ops = ops;
149 bridge->context = context;
151 dev_set_drvdata(dev, bridge);
153 dev_dbg(parent, "Registered bridge '%s', parent node %p\n",
154 dev_name(dev), parent->of_node);
156 return dev;
160 static int vexpress_config_node_match(struct device *dev, const void *data)
162 const struct device_node *node = data;
164 dev_dbg(dev, "Parent node %p, looking for %p\n",
165 dev->parent->of_node, node);
167 return dev->parent->of_node == node;
170 static int vexpress_config_populate(struct device_node *node)
172 struct device_node *bridge;
173 struct device *parent;
174 int ret;
176 bridge = of_parse_phandle(node, "arm,vexpress,config-bridge", 0);
177 if (!bridge)
178 return -EINVAL;
180 parent = class_find_device(vexpress_config_class, NULL, bridge,
181 vexpress_config_node_match);
182 of_node_put(bridge);
183 if (WARN_ON(!parent))
184 return -ENODEV;
186 ret = of_platform_populate(node, NULL, NULL, parent);
188 put_device(parent);
190 return ret;
193 static int __init vexpress_config_init(void)
195 int err = 0;
196 struct device_node *node;
198 /* Need the config devices early, before the "normal" devices... */
199 for_each_compatible_node(node, NULL, "arm,vexpress,config-bus") {
200 err = vexpress_config_populate(node);
201 if (err) {
202 of_node_put(node);
203 break;
207 return err;
209 postcore_initcall(vexpress_config_init);