xref: /linux/drivers/mcb/mcb-core.c (revision 3764e82e5150d87b205c10cd78a9c9ab86fbfa51)
1*3764e82eSJohannes Thumshirn /*
2*3764e82eSJohannes Thumshirn  * MEN Chameleon Bus.
3*3764e82eSJohannes Thumshirn  *
4*3764e82eSJohannes Thumshirn  * Copyright (C) 2013 MEN Mikroelektronik GmbH (www.men.de)
5*3764e82eSJohannes Thumshirn  * Author: Johannes Thumshirn <johannes.thumshirn@men.de>
6*3764e82eSJohannes Thumshirn  *
7*3764e82eSJohannes Thumshirn  * This program is free software; you can redistribute it and/or modify it
8*3764e82eSJohannes Thumshirn  * under the terms of the GNU General Public License as published by the Free
9*3764e82eSJohannes Thumshirn  * Software Foundation; version 2 of the License.
10*3764e82eSJohannes Thumshirn  */
11*3764e82eSJohannes Thumshirn #include <linux/kernel.h>
12*3764e82eSJohannes Thumshirn #include <linux/module.h>
13*3764e82eSJohannes Thumshirn #include <linux/slab.h>
14*3764e82eSJohannes Thumshirn #include <linux/types.h>
15*3764e82eSJohannes Thumshirn #include <linux/idr.h>
16*3764e82eSJohannes Thumshirn #include <linux/mcb.h>
17*3764e82eSJohannes Thumshirn 
18*3764e82eSJohannes Thumshirn static DEFINE_IDA(mcb_ida);
19*3764e82eSJohannes Thumshirn 
20*3764e82eSJohannes Thumshirn static const struct mcb_device_id *mcb_match_id(const struct mcb_device_id *ids,
21*3764e82eSJohannes Thumshirn 						struct mcb_device *dev)
22*3764e82eSJohannes Thumshirn {
23*3764e82eSJohannes Thumshirn 	if (ids) {
24*3764e82eSJohannes Thumshirn 		while (ids->device) {
25*3764e82eSJohannes Thumshirn 			if (ids->device == dev->id)
26*3764e82eSJohannes Thumshirn 				return ids;
27*3764e82eSJohannes Thumshirn 			ids++;
28*3764e82eSJohannes Thumshirn 		}
29*3764e82eSJohannes Thumshirn 	}
30*3764e82eSJohannes Thumshirn 
31*3764e82eSJohannes Thumshirn 	return NULL;
32*3764e82eSJohannes Thumshirn }
33*3764e82eSJohannes Thumshirn 
34*3764e82eSJohannes Thumshirn static int mcb_match(struct device *dev, struct device_driver *drv)
35*3764e82eSJohannes Thumshirn {
36*3764e82eSJohannes Thumshirn 	struct mcb_driver *mdrv = to_mcb_driver(drv);
37*3764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
38*3764e82eSJohannes Thumshirn 	const struct mcb_device_id *found_id;
39*3764e82eSJohannes Thumshirn 
40*3764e82eSJohannes Thumshirn 	found_id = mcb_match_id(mdrv->id_table, mdev);
41*3764e82eSJohannes Thumshirn 	if (found_id)
42*3764e82eSJohannes Thumshirn 		return 1;
43*3764e82eSJohannes Thumshirn 
44*3764e82eSJohannes Thumshirn 	return 0;
45*3764e82eSJohannes Thumshirn }
46*3764e82eSJohannes Thumshirn 
47*3764e82eSJohannes Thumshirn static int mcb_uevent(struct device *dev, struct kobj_uevent_env *env)
48*3764e82eSJohannes Thumshirn {
49*3764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
50*3764e82eSJohannes Thumshirn 	int ret;
51*3764e82eSJohannes Thumshirn 
52*3764e82eSJohannes Thumshirn 	ret = add_uevent_var(env, "MODALIAS=mcb:16z%03d", mdev->id);
53*3764e82eSJohannes Thumshirn 	if (ret)
54*3764e82eSJohannes Thumshirn 		return -ENOMEM;
55*3764e82eSJohannes Thumshirn 
56*3764e82eSJohannes Thumshirn 	return 0;
57*3764e82eSJohannes Thumshirn }
58*3764e82eSJohannes Thumshirn 
59*3764e82eSJohannes Thumshirn static int mcb_probe(struct device *dev)
60*3764e82eSJohannes Thumshirn {
61*3764e82eSJohannes Thumshirn 	struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
62*3764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
63*3764e82eSJohannes Thumshirn 	const struct mcb_device_id *found_id;
64*3764e82eSJohannes Thumshirn 
65*3764e82eSJohannes Thumshirn 	found_id = mcb_match_id(mdrv->id_table, mdev);
66*3764e82eSJohannes Thumshirn 	if (!found_id)
67*3764e82eSJohannes Thumshirn 		return -ENODEV;
68*3764e82eSJohannes Thumshirn 
69*3764e82eSJohannes Thumshirn 	return mdrv->probe(mdev, found_id);
70*3764e82eSJohannes Thumshirn }
71*3764e82eSJohannes Thumshirn 
72*3764e82eSJohannes Thumshirn static int mcb_remove(struct device *dev)
73*3764e82eSJohannes Thumshirn {
74*3764e82eSJohannes Thumshirn 	struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
75*3764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
76*3764e82eSJohannes Thumshirn 
77*3764e82eSJohannes Thumshirn 	mdrv->remove(mdev);
78*3764e82eSJohannes Thumshirn 
79*3764e82eSJohannes Thumshirn 	put_device(&mdev->dev);
80*3764e82eSJohannes Thumshirn 
81*3764e82eSJohannes Thumshirn 	return 0;
82*3764e82eSJohannes Thumshirn }
83*3764e82eSJohannes Thumshirn 
84*3764e82eSJohannes Thumshirn static void mcb_shutdown(struct device *dev)
85*3764e82eSJohannes Thumshirn {
86*3764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
87*3764e82eSJohannes Thumshirn 	struct mcb_driver *mdrv = mdev->driver;
88*3764e82eSJohannes Thumshirn 
89*3764e82eSJohannes Thumshirn 	if (mdrv && mdrv->shutdown)
90*3764e82eSJohannes Thumshirn 		mdrv->shutdown(mdev);
91*3764e82eSJohannes Thumshirn }
92*3764e82eSJohannes Thumshirn 
93*3764e82eSJohannes Thumshirn static struct bus_type mcb_bus_type = {
94*3764e82eSJohannes Thumshirn 	.name = "mcb",
95*3764e82eSJohannes Thumshirn 	.match = mcb_match,
96*3764e82eSJohannes Thumshirn 	.uevent = mcb_uevent,
97*3764e82eSJohannes Thumshirn 	.probe = mcb_probe,
98*3764e82eSJohannes Thumshirn 	.remove = mcb_remove,
99*3764e82eSJohannes Thumshirn 	.shutdown = mcb_shutdown,
100*3764e82eSJohannes Thumshirn };
101*3764e82eSJohannes Thumshirn 
102*3764e82eSJohannes Thumshirn /**
103*3764e82eSJohannes Thumshirn  * __mcb_register_driver() - Register a @mcb_driver at the system
104*3764e82eSJohannes Thumshirn  * @drv: The @mcb_driver
105*3764e82eSJohannes Thumshirn  * @owner: The @mcb_driver's module
106*3764e82eSJohannes Thumshirn  * @mod_name: The name of the @mcb_driver's module
107*3764e82eSJohannes Thumshirn  *
108*3764e82eSJohannes Thumshirn  * Register a @mcb_driver at the system. Perform some sanity checks, if
109*3764e82eSJohannes Thumshirn  * the .probe and .remove methods are provided by the driver.
110*3764e82eSJohannes Thumshirn  */
111*3764e82eSJohannes Thumshirn int __mcb_register_driver(struct mcb_driver *drv, struct module *owner,
112*3764e82eSJohannes Thumshirn 			const char *mod_name)
113*3764e82eSJohannes Thumshirn {
114*3764e82eSJohannes Thumshirn 	if (!drv->probe || !drv->remove)
115*3764e82eSJohannes Thumshirn 		return -EINVAL;
116*3764e82eSJohannes Thumshirn 
117*3764e82eSJohannes Thumshirn 	drv->driver.owner = owner;
118*3764e82eSJohannes Thumshirn 	drv->driver.bus = &mcb_bus_type;
119*3764e82eSJohannes Thumshirn 	drv->driver.mod_name = mod_name;
120*3764e82eSJohannes Thumshirn 
121*3764e82eSJohannes Thumshirn 	return driver_register(&drv->driver);
122*3764e82eSJohannes Thumshirn }
123*3764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(__mcb_register_driver);
124*3764e82eSJohannes Thumshirn 
125*3764e82eSJohannes Thumshirn /**
126*3764e82eSJohannes Thumshirn  * mcb_unregister_driver() - Unregister a @mcb_driver from the system
127*3764e82eSJohannes Thumshirn  * @drv: The @mcb_driver
128*3764e82eSJohannes Thumshirn  *
129*3764e82eSJohannes Thumshirn  * Unregister a @mcb_driver from the system.
130*3764e82eSJohannes Thumshirn  */
131*3764e82eSJohannes Thumshirn void mcb_unregister_driver(struct mcb_driver *drv)
132*3764e82eSJohannes Thumshirn {
133*3764e82eSJohannes Thumshirn 	driver_unregister(&drv->driver);
134*3764e82eSJohannes Thumshirn }
135*3764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_unregister_driver);
136*3764e82eSJohannes Thumshirn 
137*3764e82eSJohannes Thumshirn static void mcb_release_dev(struct device *dev)
138*3764e82eSJohannes Thumshirn {
139*3764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
140*3764e82eSJohannes Thumshirn 
141*3764e82eSJohannes Thumshirn 	mcb_bus_put(mdev->bus);
142*3764e82eSJohannes Thumshirn 	kfree(mdev);
143*3764e82eSJohannes Thumshirn }
144*3764e82eSJohannes Thumshirn 
145*3764e82eSJohannes Thumshirn /**
146*3764e82eSJohannes Thumshirn  * mcb_device_register() - Register a mcb_device
147*3764e82eSJohannes Thumshirn  * @bus: The @mcb_bus of the device
148*3764e82eSJohannes Thumshirn  * @dev: The @mcb_device
149*3764e82eSJohannes Thumshirn  *
150*3764e82eSJohannes Thumshirn  * Register a specific @mcb_device at a @mcb_bus and the system itself.
151*3764e82eSJohannes Thumshirn  */
152*3764e82eSJohannes Thumshirn int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev)
153*3764e82eSJohannes Thumshirn {
154*3764e82eSJohannes Thumshirn 	int ret;
155*3764e82eSJohannes Thumshirn 	int device_id;
156*3764e82eSJohannes Thumshirn 
157*3764e82eSJohannes Thumshirn 	device_initialize(&dev->dev);
158*3764e82eSJohannes Thumshirn 	dev->dev.bus = &mcb_bus_type;
159*3764e82eSJohannes Thumshirn 	dev->dev.parent = bus->dev.parent;
160*3764e82eSJohannes Thumshirn 	dev->dev.release = mcb_release_dev;
161*3764e82eSJohannes Thumshirn 
162*3764e82eSJohannes Thumshirn 	device_id = dev->id;
163*3764e82eSJohannes Thumshirn 	dev_set_name(&dev->dev, "mcb%d-16z%03d-%d:%d:%d",
164*3764e82eSJohannes Thumshirn 		bus->bus_nr, device_id, dev->inst, dev->group, dev->var);
165*3764e82eSJohannes Thumshirn 
166*3764e82eSJohannes Thumshirn 	ret = device_add(&dev->dev);
167*3764e82eSJohannes Thumshirn 	if (ret < 0) {
168*3764e82eSJohannes Thumshirn 		pr_err("Failed registering device 16z%03d on bus mcb%d (%d)\n",
169*3764e82eSJohannes Thumshirn 			device_id, bus->bus_nr, ret);
170*3764e82eSJohannes Thumshirn 		goto out;
171*3764e82eSJohannes Thumshirn 	}
172*3764e82eSJohannes Thumshirn 
173*3764e82eSJohannes Thumshirn 	return 0;
174*3764e82eSJohannes Thumshirn 
175*3764e82eSJohannes Thumshirn out:
176*3764e82eSJohannes Thumshirn 
177*3764e82eSJohannes Thumshirn 	return ret;
178*3764e82eSJohannes Thumshirn }
179*3764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_device_register);
180*3764e82eSJohannes Thumshirn 
181*3764e82eSJohannes Thumshirn /**
182*3764e82eSJohannes Thumshirn  * mcb_alloc_bus() - Allocate a new @mcb_bus
183*3764e82eSJohannes Thumshirn  *
184*3764e82eSJohannes Thumshirn  * Allocate a new @mcb_bus.
185*3764e82eSJohannes Thumshirn  */
186*3764e82eSJohannes Thumshirn struct mcb_bus *mcb_alloc_bus(void)
187*3764e82eSJohannes Thumshirn {
188*3764e82eSJohannes Thumshirn 	struct mcb_bus *bus;
189*3764e82eSJohannes Thumshirn 	int bus_nr;
190*3764e82eSJohannes Thumshirn 
191*3764e82eSJohannes Thumshirn 	bus = kzalloc(sizeof(struct mcb_bus), GFP_KERNEL);
192*3764e82eSJohannes Thumshirn 	if (!bus)
193*3764e82eSJohannes Thumshirn 		return NULL;
194*3764e82eSJohannes Thumshirn 
195*3764e82eSJohannes Thumshirn 	bus_nr = ida_simple_get(&mcb_ida, 0, 0, GFP_KERNEL);
196*3764e82eSJohannes Thumshirn 	if (bus_nr < 0) {
197*3764e82eSJohannes Thumshirn 		kfree(bus);
198*3764e82eSJohannes Thumshirn 		return ERR_PTR(bus_nr);
199*3764e82eSJohannes Thumshirn 	}
200*3764e82eSJohannes Thumshirn 
201*3764e82eSJohannes Thumshirn 	INIT_LIST_HEAD(&bus->children);
202*3764e82eSJohannes Thumshirn 	bus->bus_nr = bus_nr;
203*3764e82eSJohannes Thumshirn 
204*3764e82eSJohannes Thumshirn 	return bus;
205*3764e82eSJohannes Thumshirn }
206*3764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_alloc_bus);
207*3764e82eSJohannes Thumshirn 
208*3764e82eSJohannes Thumshirn static int __mcb_devices_unregister(struct device *dev, void *data)
209*3764e82eSJohannes Thumshirn {
210*3764e82eSJohannes Thumshirn 	device_unregister(dev);
211*3764e82eSJohannes Thumshirn 	return 0;
212*3764e82eSJohannes Thumshirn }
213*3764e82eSJohannes Thumshirn 
214*3764e82eSJohannes Thumshirn static void mcb_devices_unregister(struct mcb_bus *bus)
215*3764e82eSJohannes Thumshirn {
216*3764e82eSJohannes Thumshirn 	bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_devices_unregister);
217*3764e82eSJohannes Thumshirn }
218*3764e82eSJohannes Thumshirn /**
219*3764e82eSJohannes Thumshirn  * mcb_release_bus() - Free a @mcb_bus
220*3764e82eSJohannes Thumshirn  * @bus: The @mcb_bus to release
221*3764e82eSJohannes Thumshirn  *
222*3764e82eSJohannes Thumshirn  * Release an allocated @mcb_bus from the system.
223*3764e82eSJohannes Thumshirn  */
224*3764e82eSJohannes Thumshirn void mcb_release_bus(struct mcb_bus *bus)
225*3764e82eSJohannes Thumshirn {
226*3764e82eSJohannes Thumshirn 	mcb_devices_unregister(bus);
227*3764e82eSJohannes Thumshirn 
228*3764e82eSJohannes Thumshirn 	ida_simple_remove(&mcb_ida, bus->bus_nr);
229*3764e82eSJohannes Thumshirn 
230*3764e82eSJohannes Thumshirn 	kfree(bus);
231*3764e82eSJohannes Thumshirn }
232*3764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_release_bus);
233*3764e82eSJohannes Thumshirn 
234*3764e82eSJohannes Thumshirn /**
235*3764e82eSJohannes Thumshirn  * mcb_bus_put() - Increment refcnt
236*3764e82eSJohannes Thumshirn  * @bus: The @mcb_bus
237*3764e82eSJohannes Thumshirn  *
238*3764e82eSJohannes Thumshirn  * Get a @mcb_bus' ref
239*3764e82eSJohannes Thumshirn  */
240*3764e82eSJohannes Thumshirn struct mcb_bus *mcb_bus_get(struct mcb_bus *bus)
241*3764e82eSJohannes Thumshirn {
242*3764e82eSJohannes Thumshirn 	if (bus)
243*3764e82eSJohannes Thumshirn 		get_device(&bus->dev);
244*3764e82eSJohannes Thumshirn 
245*3764e82eSJohannes Thumshirn 	return bus;
246*3764e82eSJohannes Thumshirn }
247*3764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_bus_get);
248*3764e82eSJohannes Thumshirn 
249*3764e82eSJohannes Thumshirn /**
250*3764e82eSJohannes Thumshirn  * mcb_bus_put() - Decrement refcnt
251*3764e82eSJohannes Thumshirn  * @bus: The @mcb_bus
252*3764e82eSJohannes Thumshirn  *
253*3764e82eSJohannes Thumshirn  * Release a @mcb_bus' ref
254*3764e82eSJohannes Thumshirn  */
255*3764e82eSJohannes Thumshirn void mcb_bus_put(struct mcb_bus *bus)
256*3764e82eSJohannes Thumshirn {
257*3764e82eSJohannes Thumshirn 	if (bus)
258*3764e82eSJohannes Thumshirn 		put_device(&bus->dev);
259*3764e82eSJohannes Thumshirn }
260*3764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_bus_put);
261*3764e82eSJohannes Thumshirn 
262*3764e82eSJohannes Thumshirn /**
263*3764e82eSJohannes Thumshirn  * mcb_alloc_dev() - Allocate a device
264*3764e82eSJohannes Thumshirn  * @bus: The @mcb_bus the device is part of
265*3764e82eSJohannes Thumshirn  *
266*3764e82eSJohannes Thumshirn  * Allocate a @mcb_device and add bus.
267*3764e82eSJohannes Thumshirn  */
268*3764e82eSJohannes Thumshirn struct mcb_device *mcb_alloc_dev(struct mcb_bus *bus)
269*3764e82eSJohannes Thumshirn {
270*3764e82eSJohannes Thumshirn 	struct mcb_device *dev;
271*3764e82eSJohannes Thumshirn 
272*3764e82eSJohannes Thumshirn 	dev = kzalloc(sizeof(struct mcb_device), GFP_KERNEL);
273*3764e82eSJohannes Thumshirn 	if (!dev)
274*3764e82eSJohannes Thumshirn 		return NULL;
275*3764e82eSJohannes Thumshirn 
276*3764e82eSJohannes Thumshirn 	INIT_LIST_HEAD(&dev->bus_list);
277*3764e82eSJohannes Thumshirn 	dev->bus = bus;
278*3764e82eSJohannes Thumshirn 
279*3764e82eSJohannes Thumshirn 	return dev;
280*3764e82eSJohannes Thumshirn }
281*3764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_alloc_dev);
282*3764e82eSJohannes Thumshirn 
283*3764e82eSJohannes Thumshirn /**
284*3764e82eSJohannes Thumshirn  * mcb_free_dev() - Free @mcb_device
285*3764e82eSJohannes Thumshirn  * @dev: The device to free
286*3764e82eSJohannes Thumshirn  *
287*3764e82eSJohannes Thumshirn  * Free a @mcb_device
288*3764e82eSJohannes Thumshirn  */
289*3764e82eSJohannes Thumshirn void mcb_free_dev(struct mcb_device *dev)
290*3764e82eSJohannes Thumshirn {
291*3764e82eSJohannes Thumshirn 	kfree(dev);
292*3764e82eSJohannes Thumshirn }
293*3764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_free_dev);
294*3764e82eSJohannes Thumshirn 
295*3764e82eSJohannes Thumshirn static int __mcb_bus_add_devices(struct device *dev, void *data)
296*3764e82eSJohannes Thumshirn {
297*3764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
298*3764e82eSJohannes Thumshirn 	int retval;
299*3764e82eSJohannes Thumshirn 
300*3764e82eSJohannes Thumshirn 	if (mdev->is_added)
301*3764e82eSJohannes Thumshirn 		return 0;
302*3764e82eSJohannes Thumshirn 
303*3764e82eSJohannes Thumshirn 	retval = device_attach(dev);
304*3764e82eSJohannes Thumshirn 	if (retval < 0)
305*3764e82eSJohannes Thumshirn 		dev_err(dev, "Error adding device (%d)\n", retval);
306*3764e82eSJohannes Thumshirn 
307*3764e82eSJohannes Thumshirn 	mdev->is_added = true;
308*3764e82eSJohannes Thumshirn 
309*3764e82eSJohannes Thumshirn 	return 0;
310*3764e82eSJohannes Thumshirn }
311*3764e82eSJohannes Thumshirn 
312*3764e82eSJohannes Thumshirn static int __mcb_bus_add_child(struct device *dev, void *data)
313*3764e82eSJohannes Thumshirn {
314*3764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
315*3764e82eSJohannes Thumshirn 	struct mcb_bus *child;
316*3764e82eSJohannes Thumshirn 
317*3764e82eSJohannes Thumshirn 	BUG_ON(!mdev->is_added);
318*3764e82eSJohannes Thumshirn 	child = mdev->subordinate;
319*3764e82eSJohannes Thumshirn 
320*3764e82eSJohannes Thumshirn 	if (child)
321*3764e82eSJohannes Thumshirn 		mcb_bus_add_devices(child);
322*3764e82eSJohannes Thumshirn 
323*3764e82eSJohannes Thumshirn 	return 0;
324*3764e82eSJohannes Thumshirn }
325*3764e82eSJohannes Thumshirn 
326*3764e82eSJohannes Thumshirn /**
327*3764e82eSJohannes Thumshirn  * mcb_bus_add_devices() - Add devices in the bus' internal device list
328*3764e82eSJohannes Thumshirn  * @bus: The @mcb_bus we add the devices
329*3764e82eSJohannes Thumshirn  *
330*3764e82eSJohannes Thumshirn  * Add devices in the bus' internal device list to the system.
331*3764e82eSJohannes Thumshirn  */
332*3764e82eSJohannes Thumshirn void mcb_bus_add_devices(const struct mcb_bus *bus)
333*3764e82eSJohannes Thumshirn {
334*3764e82eSJohannes Thumshirn 	bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_devices);
335*3764e82eSJohannes Thumshirn 	bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_child);
336*3764e82eSJohannes Thumshirn 
337*3764e82eSJohannes Thumshirn }
338*3764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_bus_add_devices);
339*3764e82eSJohannes Thumshirn 
340*3764e82eSJohannes Thumshirn /**
341*3764e82eSJohannes Thumshirn  * mcb_request_mem() - Request memory
342*3764e82eSJohannes Thumshirn  * @dev: The @mcb_device the memory is for
343*3764e82eSJohannes Thumshirn  * @name: The name for the memory reference.
344*3764e82eSJohannes Thumshirn  *
345*3764e82eSJohannes Thumshirn  * Request memory for a @mcb_device. If @name is NULL the driver name will
346*3764e82eSJohannes Thumshirn  * be used.
347*3764e82eSJohannes Thumshirn  */
348*3764e82eSJohannes Thumshirn struct resource *mcb_request_mem(struct mcb_device *dev, const char *name)
349*3764e82eSJohannes Thumshirn {
350*3764e82eSJohannes Thumshirn 	struct resource *mem;
351*3764e82eSJohannes Thumshirn 	u32 size;
352*3764e82eSJohannes Thumshirn 
353*3764e82eSJohannes Thumshirn 	if (!name)
354*3764e82eSJohannes Thumshirn 		name = dev->dev.driver->name;
355*3764e82eSJohannes Thumshirn 
356*3764e82eSJohannes Thumshirn 	size = resource_size(&dev->mem);
357*3764e82eSJohannes Thumshirn 
358*3764e82eSJohannes Thumshirn 	mem = request_mem_region(dev->mem.start, size, name);
359*3764e82eSJohannes Thumshirn 	if (!mem)
360*3764e82eSJohannes Thumshirn 		return ERR_PTR(-EBUSY);
361*3764e82eSJohannes Thumshirn 
362*3764e82eSJohannes Thumshirn 	return mem;
363*3764e82eSJohannes Thumshirn }
364*3764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_request_mem);
365*3764e82eSJohannes Thumshirn 
366*3764e82eSJohannes Thumshirn /**
367*3764e82eSJohannes Thumshirn  * mcb_release_mem() - Release memory requested by device
368*3764e82eSJohannes Thumshirn  * @dev: The @mcb_device that requested the memory
369*3764e82eSJohannes Thumshirn  *
370*3764e82eSJohannes Thumshirn  * Release memory that was prior requested via @mcb_request_mem().
371*3764e82eSJohannes Thumshirn  */
372*3764e82eSJohannes Thumshirn void mcb_release_mem(struct resource *mem)
373*3764e82eSJohannes Thumshirn {
374*3764e82eSJohannes Thumshirn 	u32 size;
375*3764e82eSJohannes Thumshirn 
376*3764e82eSJohannes Thumshirn 	size = resource_size(mem);
377*3764e82eSJohannes Thumshirn 	release_mem_region(mem->start, size);
378*3764e82eSJohannes Thumshirn }
379*3764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_release_mem);
380*3764e82eSJohannes Thumshirn 
381*3764e82eSJohannes Thumshirn /**
382*3764e82eSJohannes Thumshirn  * mcb_get_irq() - Get device's IRQ number
383*3764e82eSJohannes Thumshirn  * @dev: The @mcb_device the IRQ is for
384*3764e82eSJohannes Thumshirn  *
385*3764e82eSJohannes Thumshirn  * Get the IRQ number of a given @mcb_device.
386*3764e82eSJohannes Thumshirn  */
387*3764e82eSJohannes Thumshirn int mcb_get_irq(struct mcb_device *dev)
388*3764e82eSJohannes Thumshirn {
389*3764e82eSJohannes Thumshirn 	struct resource *irq = &dev->irq;
390*3764e82eSJohannes Thumshirn 
391*3764e82eSJohannes Thumshirn 	return irq->start;
392*3764e82eSJohannes Thumshirn }
393*3764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_get_irq);
394*3764e82eSJohannes Thumshirn 
395*3764e82eSJohannes Thumshirn static int mcb_init(void)
396*3764e82eSJohannes Thumshirn {
397*3764e82eSJohannes Thumshirn 	return bus_register(&mcb_bus_type);
398*3764e82eSJohannes Thumshirn }
399*3764e82eSJohannes Thumshirn 
400*3764e82eSJohannes Thumshirn static void mcb_exit(void)
401*3764e82eSJohannes Thumshirn {
402*3764e82eSJohannes Thumshirn 	bus_unregister(&mcb_bus_type);
403*3764e82eSJohannes Thumshirn }
404*3764e82eSJohannes Thumshirn 
405*3764e82eSJohannes Thumshirn /* mcb must be initialized after PCI but before the chameleon drivers.
406*3764e82eSJohannes Thumshirn  * That means we must use some initcall between subsys_initcall and
407*3764e82eSJohannes Thumshirn  * device_initcall.
408*3764e82eSJohannes Thumshirn  */
409*3764e82eSJohannes Thumshirn fs_initcall(mcb_init);
410*3764e82eSJohannes Thumshirn module_exit(mcb_exit);
411*3764e82eSJohannes Thumshirn 
412*3764e82eSJohannes Thumshirn MODULE_DESCRIPTION("MEN Chameleon Bus Driver");
413*3764e82eSJohannes Thumshirn MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
414*3764e82eSJohannes Thumshirn MODULE_LICENSE("GPL v2");
415