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>
17 #include <linux/of_device.h>
18 #include <linux/vexpress.h>
21 struct vexpress_config_bridge
{
22 struct vexpress_config_bridge_ops
*ops
;
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
)
61 if (of_property_read_u32(node
, name
, val
) == 0) {
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
))
77 vexpress_config_find_prop(node
, "arm,vexpress,position", position
);
78 vexpress_config_find_prop(node
, "arm,vexpress,dcc", dcc
);
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
;
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
),
108 return ERR_PTR(-ENOMEM
);
110 regmap
= bridge
->ops
->regmap_init(dev
, bridge
->context
);
111 if (IS_ERR(regmap
)) {
117 devres_add(dev
, res
);
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
)
127 struct vexpress_config_bridge
*bridge
;
129 if (!vexpress_config_class
) {
130 vexpress_config_class
= class_create(THIS_MODULE
,
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
));
142 bridge
= devm_kmalloc(dev
, sizeof(*bridge
), GFP_KERNEL
);
145 device_unregister(dev
);
146 return ERR_PTR(-ENOMEM
);
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
);
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
;
175 bridge
= of_parse_phandle(node
, "arm,vexpress,config-bridge", 0);
179 parent
= class_find_device(vexpress_config_class
, NULL
, bridge
,
180 vexpress_config_node_match
);
181 if (WARN_ON(!parent
))
184 return of_platform_populate(node
, NULL
, NULL
, parent
);
187 static int __init
vexpress_config_init(void)
190 struct device_node
*node
;
192 /* Need the config devices early, before the "normal" devices... */
193 for_each_compatible_node(node
, NULL
, "arm,vexpress,config-bus") {
194 err
= vexpress_config_populate(node
);
201 postcore_initcall(vexpress_config_init
);