xref: /linux/drivers/mcb/mcb-core.c (revision 4d2ec8575357d4afc965564e2e910a72fe608d39)
13764e82eSJohannes Thumshirn /*
23764e82eSJohannes Thumshirn  * MEN Chameleon Bus.
33764e82eSJohannes Thumshirn  *
43764e82eSJohannes Thumshirn  * Copyright (C) 2013 MEN Mikroelektronik GmbH (www.men.de)
53764e82eSJohannes Thumshirn  * Author: Johannes Thumshirn <johannes.thumshirn@men.de>
63764e82eSJohannes Thumshirn  *
73764e82eSJohannes Thumshirn  * This program is free software; you can redistribute it and/or modify it
83764e82eSJohannes Thumshirn  * under the terms of the GNU General Public License as published by the Free
93764e82eSJohannes Thumshirn  * Software Foundation; version 2 of the License.
103764e82eSJohannes Thumshirn  */
113764e82eSJohannes Thumshirn #include <linux/kernel.h>
123764e82eSJohannes Thumshirn #include <linux/module.h>
133764e82eSJohannes Thumshirn #include <linux/slab.h>
143764e82eSJohannes Thumshirn #include <linux/types.h>
153764e82eSJohannes Thumshirn #include <linux/idr.h>
163764e82eSJohannes Thumshirn #include <linux/mcb.h>
173764e82eSJohannes Thumshirn 
183764e82eSJohannes Thumshirn static DEFINE_IDA(mcb_ida);
193764e82eSJohannes Thumshirn 
203764e82eSJohannes Thumshirn static const struct mcb_device_id *mcb_match_id(const struct mcb_device_id *ids,
213764e82eSJohannes Thumshirn 						struct mcb_device *dev)
223764e82eSJohannes Thumshirn {
233764e82eSJohannes Thumshirn 	if (ids) {
243764e82eSJohannes Thumshirn 		while (ids->device) {
253764e82eSJohannes Thumshirn 			if (ids->device == dev->id)
263764e82eSJohannes Thumshirn 				return ids;
273764e82eSJohannes Thumshirn 			ids++;
283764e82eSJohannes Thumshirn 		}
293764e82eSJohannes Thumshirn 	}
303764e82eSJohannes Thumshirn 
313764e82eSJohannes Thumshirn 	return NULL;
323764e82eSJohannes Thumshirn }
333764e82eSJohannes Thumshirn 
343764e82eSJohannes Thumshirn static int mcb_match(struct device *dev, struct device_driver *drv)
353764e82eSJohannes Thumshirn {
363764e82eSJohannes Thumshirn 	struct mcb_driver *mdrv = to_mcb_driver(drv);
373764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
383764e82eSJohannes Thumshirn 	const struct mcb_device_id *found_id;
393764e82eSJohannes Thumshirn 
403764e82eSJohannes Thumshirn 	found_id = mcb_match_id(mdrv->id_table, mdev);
413764e82eSJohannes Thumshirn 	if (found_id)
423764e82eSJohannes Thumshirn 		return 1;
433764e82eSJohannes Thumshirn 
443764e82eSJohannes Thumshirn 	return 0;
453764e82eSJohannes Thumshirn }
463764e82eSJohannes Thumshirn 
473764e82eSJohannes Thumshirn static int mcb_uevent(struct device *dev, struct kobj_uevent_env *env)
483764e82eSJohannes Thumshirn {
493764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
503764e82eSJohannes Thumshirn 	int ret;
513764e82eSJohannes Thumshirn 
523764e82eSJohannes Thumshirn 	ret = add_uevent_var(env, "MODALIAS=mcb:16z%03d", mdev->id);
533764e82eSJohannes Thumshirn 	if (ret)
543764e82eSJohannes Thumshirn 		return -ENOMEM;
553764e82eSJohannes Thumshirn 
563764e82eSJohannes Thumshirn 	return 0;
573764e82eSJohannes Thumshirn }
583764e82eSJohannes Thumshirn 
593764e82eSJohannes Thumshirn static int mcb_probe(struct device *dev)
603764e82eSJohannes Thumshirn {
613764e82eSJohannes Thumshirn 	struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
623764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
633764e82eSJohannes Thumshirn 	const struct mcb_device_id *found_id;
64*4d2ec857SJohannes Thumshirn 	struct module *carrier_mod;
65*4d2ec857SJohannes Thumshirn 	int ret;
663764e82eSJohannes Thumshirn 
673764e82eSJohannes Thumshirn 	found_id = mcb_match_id(mdrv->id_table, mdev);
683764e82eSJohannes Thumshirn 	if (!found_id)
693764e82eSJohannes Thumshirn 		return -ENODEV;
703764e82eSJohannes Thumshirn 
71*4d2ec857SJohannes Thumshirn 	carrier_mod = mdev->dev.parent->driver->owner;
72*4d2ec857SJohannes Thumshirn 	if (!try_module_get(carrier_mod))
73*4d2ec857SJohannes Thumshirn 		return -EINVAL;
74*4d2ec857SJohannes Thumshirn 
757bc36409SJohannes Thumshirn 	get_device(dev);
76*4d2ec857SJohannes Thumshirn 	ret = mdrv->probe(mdev, found_id);
77*4d2ec857SJohannes Thumshirn 	if (ret)
78*4d2ec857SJohannes Thumshirn 		module_put(carrier_mod);
79*4d2ec857SJohannes Thumshirn 
80*4d2ec857SJohannes Thumshirn 	return ret;
813764e82eSJohannes Thumshirn }
823764e82eSJohannes Thumshirn 
833764e82eSJohannes Thumshirn static int mcb_remove(struct device *dev)
843764e82eSJohannes Thumshirn {
853764e82eSJohannes Thumshirn 	struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
863764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
87*4d2ec857SJohannes Thumshirn 	struct module *carrier_mod;
883764e82eSJohannes Thumshirn 
893764e82eSJohannes Thumshirn 	mdrv->remove(mdev);
903764e82eSJohannes Thumshirn 
91*4d2ec857SJohannes Thumshirn 	carrier_mod = mdev->dev.parent->driver->owner;
92*4d2ec857SJohannes Thumshirn 	module_put(carrier_mod);
93*4d2ec857SJohannes Thumshirn 
943764e82eSJohannes Thumshirn 	put_device(&mdev->dev);
953764e82eSJohannes Thumshirn 
963764e82eSJohannes Thumshirn 	return 0;
973764e82eSJohannes Thumshirn }
983764e82eSJohannes Thumshirn 
993764e82eSJohannes Thumshirn static void mcb_shutdown(struct device *dev)
1003764e82eSJohannes Thumshirn {
1015d9e2ab9SJohannes Thumshirn 	struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
1023764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
1033764e82eSJohannes Thumshirn 
1043764e82eSJohannes Thumshirn 	if (mdrv && mdrv->shutdown)
1053764e82eSJohannes Thumshirn 		mdrv->shutdown(mdev);
1063764e82eSJohannes Thumshirn }
1073764e82eSJohannes Thumshirn 
108803f1ca6SJohannes Thumshirn static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
109803f1ca6SJohannes Thumshirn 			 char *buf)
110803f1ca6SJohannes Thumshirn {
111803f1ca6SJohannes Thumshirn 	struct mcb_bus *bus = to_mcb_bus(dev);
112803f1ca6SJohannes Thumshirn 
113803f1ca6SJohannes Thumshirn 	return scnprintf(buf, PAGE_SIZE, "%d\n", bus->revision);
114803f1ca6SJohannes Thumshirn }
115803f1ca6SJohannes Thumshirn static DEVICE_ATTR_RO(revision);
116803f1ca6SJohannes Thumshirn 
117803f1ca6SJohannes Thumshirn static ssize_t model_show(struct device *dev, struct device_attribute *attr,
118803f1ca6SJohannes Thumshirn 			 char *buf)
119803f1ca6SJohannes Thumshirn {
120803f1ca6SJohannes Thumshirn 	struct mcb_bus *bus = to_mcb_bus(dev);
121803f1ca6SJohannes Thumshirn 
122803f1ca6SJohannes Thumshirn 	return scnprintf(buf, PAGE_SIZE, "%c\n", bus->model);
123803f1ca6SJohannes Thumshirn }
124803f1ca6SJohannes Thumshirn static DEVICE_ATTR_RO(model);
125803f1ca6SJohannes Thumshirn 
126803f1ca6SJohannes Thumshirn static ssize_t minor_show(struct device *dev, struct device_attribute *attr,
127803f1ca6SJohannes Thumshirn 			 char *buf)
128803f1ca6SJohannes Thumshirn {
129803f1ca6SJohannes Thumshirn 	struct mcb_bus *bus = to_mcb_bus(dev);
130803f1ca6SJohannes Thumshirn 
131803f1ca6SJohannes Thumshirn 	return scnprintf(buf, PAGE_SIZE, "%d\n", bus->minor);
132803f1ca6SJohannes Thumshirn }
133803f1ca6SJohannes Thumshirn static DEVICE_ATTR_RO(minor);
134803f1ca6SJohannes Thumshirn 
135803f1ca6SJohannes Thumshirn static ssize_t name_show(struct device *dev, struct device_attribute *attr,
136803f1ca6SJohannes Thumshirn 			 char *buf)
137803f1ca6SJohannes Thumshirn {
138803f1ca6SJohannes Thumshirn 	struct mcb_bus *bus = to_mcb_bus(dev);
139803f1ca6SJohannes Thumshirn 
140803f1ca6SJohannes Thumshirn 	return scnprintf(buf, PAGE_SIZE, "%s\n", bus->name);
141803f1ca6SJohannes Thumshirn }
142803f1ca6SJohannes Thumshirn static DEVICE_ATTR_RO(name);
143803f1ca6SJohannes Thumshirn 
144803f1ca6SJohannes Thumshirn static struct attribute *mcb_bus_attrs[] = {
145803f1ca6SJohannes Thumshirn 	&dev_attr_revision.attr,
146803f1ca6SJohannes Thumshirn 	&dev_attr_model.attr,
147803f1ca6SJohannes Thumshirn 	&dev_attr_minor.attr,
148803f1ca6SJohannes Thumshirn 	&dev_attr_name.attr,
149803f1ca6SJohannes Thumshirn 	NULL,
150803f1ca6SJohannes Thumshirn };
151803f1ca6SJohannes Thumshirn 
152803f1ca6SJohannes Thumshirn static const struct attribute_group mcb_carrier_group = {
153803f1ca6SJohannes Thumshirn 	.attrs = mcb_bus_attrs,
154803f1ca6SJohannes Thumshirn };
155803f1ca6SJohannes Thumshirn 
156803f1ca6SJohannes Thumshirn static const struct attribute_group *mcb_carrier_groups[] = {
157803f1ca6SJohannes Thumshirn 	&mcb_carrier_group,
158803f1ca6SJohannes Thumshirn 	NULL,
159803f1ca6SJohannes Thumshirn };
160803f1ca6SJohannes Thumshirn 
161803f1ca6SJohannes Thumshirn 
1623764e82eSJohannes Thumshirn static struct bus_type mcb_bus_type = {
1633764e82eSJohannes Thumshirn 	.name = "mcb",
1643764e82eSJohannes Thumshirn 	.match = mcb_match,
1653764e82eSJohannes Thumshirn 	.uevent = mcb_uevent,
1663764e82eSJohannes Thumshirn 	.probe = mcb_probe,
1673764e82eSJohannes Thumshirn 	.remove = mcb_remove,
1683764e82eSJohannes Thumshirn 	.shutdown = mcb_shutdown,
1693764e82eSJohannes Thumshirn };
1703764e82eSJohannes Thumshirn 
171803f1ca6SJohannes Thumshirn static struct device_type mcb_carrier_device_type = {
172803f1ca6SJohannes Thumshirn 	.name = "mcb-carrier",
173803f1ca6SJohannes Thumshirn 	.groups = mcb_carrier_groups,
174803f1ca6SJohannes Thumshirn };
175803f1ca6SJohannes Thumshirn 
1763764e82eSJohannes Thumshirn /**
1773764e82eSJohannes Thumshirn  * __mcb_register_driver() - Register a @mcb_driver at the system
1783764e82eSJohannes Thumshirn  * @drv: The @mcb_driver
1793764e82eSJohannes Thumshirn  * @owner: The @mcb_driver's module
1803764e82eSJohannes Thumshirn  * @mod_name: The name of the @mcb_driver's module
1813764e82eSJohannes Thumshirn  *
1823764e82eSJohannes Thumshirn  * Register a @mcb_driver at the system. Perform some sanity checks, if
1833764e82eSJohannes Thumshirn  * the .probe and .remove methods are provided by the driver.
1843764e82eSJohannes Thumshirn  */
1853764e82eSJohannes Thumshirn int __mcb_register_driver(struct mcb_driver *drv, struct module *owner,
1863764e82eSJohannes Thumshirn 			const char *mod_name)
1873764e82eSJohannes Thumshirn {
1883764e82eSJohannes Thumshirn 	if (!drv->probe || !drv->remove)
1893764e82eSJohannes Thumshirn 		return -EINVAL;
1903764e82eSJohannes Thumshirn 
1913764e82eSJohannes Thumshirn 	drv->driver.owner = owner;
1923764e82eSJohannes Thumshirn 	drv->driver.bus = &mcb_bus_type;
1933764e82eSJohannes Thumshirn 	drv->driver.mod_name = mod_name;
1943764e82eSJohannes Thumshirn 
1953764e82eSJohannes Thumshirn 	return driver_register(&drv->driver);
1963764e82eSJohannes Thumshirn }
1973764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(__mcb_register_driver);
1983764e82eSJohannes Thumshirn 
1993764e82eSJohannes Thumshirn /**
2003764e82eSJohannes Thumshirn  * mcb_unregister_driver() - Unregister a @mcb_driver from the system
2013764e82eSJohannes Thumshirn  * @drv: The @mcb_driver
2023764e82eSJohannes Thumshirn  *
2033764e82eSJohannes Thumshirn  * Unregister a @mcb_driver from the system.
2043764e82eSJohannes Thumshirn  */
2053764e82eSJohannes Thumshirn void mcb_unregister_driver(struct mcb_driver *drv)
2063764e82eSJohannes Thumshirn {
2073764e82eSJohannes Thumshirn 	driver_unregister(&drv->driver);
2083764e82eSJohannes Thumshirn }
2093764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_unregister_driver);
2103764e82eSJohannes Thumshirn 
2113764e82eSJohannes Thumshirn static void mcb_release_dev(struct device *dev)
2123764e82eSJohannes Thumshirn {
2133764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
2143764e82eSJohannes Thumshirn 
2153764e82eSJohannes Thumshirn 	mcb_bus_put(mdev->bus);
2163764e82eSJohannes Thumshirn 	kfree(mdev);
2173764e82eSJohannes Thumshirn }
2183764e82eSJohannes Thumshirn 
2193764e82eSJohannes Thumshirn /**
2203764e82eSJohannes Thumshirn  * mcb_device_register() - Register a mcb_device
2213764e82eSJohannes Thumshirn  * @bus: The @mcb_bus of the device
2223764e82eSJohannes Thumshirn  * @dev: The @mcb_device
2233764e82eSJohannes Thumshirn  *
2243764e82eSJohannes Thumshirn  * Register a specific @mcb_device at a @mcb_bus and the system itself.
2253764e82eSJohannes Thumshirn  */
2263764e82eSJohannes Thumshirn int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev)
2273764e82eSJohannes Thumshirn {
2283764e82eSJohannes Thumshirn 	int ret;
2293764e82eSJohannes Thumshirn 	int device_id;
2303764e82eSJohannes Thumshirn 
2313764e82eSJohannes Thumshirn 	device_initialize(&dev->dev);
2325d9e2ab9SJohannes Thumshirn 	mcb_bus_get(bus);
2333764e82eSJohannes Thumshirn 	dev->dev.bus = &mcb_bus_type;
2343764e82eSJohannes Thumshirn 	dev->dev.parent = bus->dev.parent;
2353764e82eSJohannes Thumshirn 	dev->dev.release = mcb_release_dev;
2363764e82eSJohannes Thumshirn 
2373764e82eSJohannes Thumshirn 	device_id = dev->id;
2383764e82eSJohannes Thumshirn 	dev_set_name(&dev->dev, "mcb%d-16z%03d-%d:%d:%d",
2393764e82eSJohannes Thumshirn 		bus->bus_nr, device_id, dev->inst, dev->group, dev->var);
2403764e82eSJohannes Thumshirn 
2413764e82eSJohannes Thumshirn 	ret = device_add(&dev->dev);
2423764e82eSJohannes Thumshirn 	if (ret < 0) {
2433764e82eSJohannes Thumshirn 		pr_err("Failed registering device 16z%03d on bus mcb%d (%d)\n",
2443764e82eSJohannes Thumshirn 			device_id, bus->bus_nr, ret);
2453764e82eSJohannes Thumshirn 		goto out;
2463764e82eSJohannes Thumshirn 	}
2473764e82eSJohannes Thumshirn 
2483764e82eSJohannes Thumshirn 	return 0;
2493764e82eSJohannes Thumshirn 
2503764e82eSJohannes Thumshirn out:
2513764e82eSJohannes Thumshirn 
2523764e82eSJohannes Thumshirn 	return ret;
2533764e82eSJohannes Thumshirn }
2543764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_device_register);
2553764e82eSJohannes Thumshirn 
2565d9e2ab9SJohannes Thumshirn static void mcb_free_bus(struct device *dev)
2575d9e2ab9SJohannes Thumshirn {
2585d9e2ab9SJohannes Thumshirn 	struct mcb_bus *bus = to_mcb_bus(dev);
2595d9e2ab9SJohannes Thumshirn 
2605d9e2ab9SJohannes Thumshirn 	put_device(bus->carrier);
2615d9e2ab9SJohannes Thumshirn 	ida_simple_remove(&mcb_ida, bus->bus_nr);
2625d9e2ab9SJohannes Thumshirn 	kfree(bus);
2635d9e2ab9SJohannes Thumshirn }
2645d9e2ab9SJohannes Thumshirn 
2653764e82eSJohannes Thumshirn /**
2663764e82eSJohannes Thumshirn  * mcb_alloc_bus() - Allocate a new @mcb_bus
2673764e82eSJohannes Thumshirn  *
2683764e82eSJohannes Thumshirn  * Allocate a new @mcb_bus.
2693764e82eSJohannes Thumshirn  */
2704ec65b77SJohannes Thumshirn struct mcb_bus *mcb_alloc_bus(struct device *carrier)
2713764e82eSJohannes Thumshirn {
2723764e82eSJohannes Thumshirn 	struct mcb_bus *bus;
2733764e82eSJohannes Thumshirn 	int bus_nr;
27418d28819SJohannes Thumshirn 	int rc;
2753764e82eSJohannes Thumshirn 
2763764e82eSJohannes Thumshirn 	bus = kzalloc(sizeof(struct mcb_bus), GFP_KERNEL);
2773764e82eSJohannes Thumshirn 	if (!bus)
2784ec65b77SJohannes Thumshirn 		return ERR_PTR(-ENOMEM);
2793764e82eSJohannes Thumshirn 
2803764e82eSJohannes Thumshirn 	bus_nr = ida_simple_get(&mcb_ida, 0, 0, GFP_KERNEL);
2813764e82eSJohannes Thumshirn 	if (bus_nr < 0) {
28218d28819SJohannes Thumshirn 		rc = bus_nr;
28318d28819SJohannes Thumshirn 		goto err_free;
2843764e82eSJohannes Thumshirn 	}
2853764e82eSJohannes Thumshirn 
2863764e82eSJohannes Thumshirn 	bus->bus_nr = bus_nr;
2875d9e2ab9SJohannes Thumshirn 	bus->carrier = get_device(carrier);
28818d28819SJohannes Thumshirn 
28918d28819SJohannes Thumshirn 	device_initialize(&bus->dev);
29018d28819SJohannes Thumshirn 	bus->dev.parent = carrier;
29118d28819SJohannes Thumshirn 	bus->dev.bus = &mcb_bus_type;
292803f1ca6SJohannes Thumshirn 	bus->dev.type = &mcb_carrier_device_type;
2935d9e2ab9SJohannes Thumshirn 	bus->dev.release = &mcb_free_bus;
29418d28819SJohannes Thumshirn 
29518d28819SJohannes Thumshirn 	dev_set_name(&bus->dev, "mcb:%d", bus_nr);
29618d28819SJohannes Thumshirn 	rc = device_add(&bus->dev);
29718d28819SJohannes Thumshirn 	if (rc)
29818d28819SJohannes Thumshirn 		goto err_free;
29918d28819SJohannes Thumshirn 
3003764e82eSJohannes Thumshirn 	return bus;
30118d28819SJohannes Thumshirn err_free:
3025d9e2ab9SJohannes Thumshirn 	put_device(carrier);
30318d28819SJohannes Thumshirn 	kfree(bus);
30418d28819SJohannes Thumshirn 	return ERR_PTR(rc);
3053764e82eSJohannes Thumshirn }
3063764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_alloc_bus);
3073764e82eSJohannes Thumshirn 
3083764e82eSJohannes Thumshirn static int __mcb_devices_unregister(struct device *dev, void *data)
3093764e82eSJohannes Thumshirn {
3103764e82eSJohannes Thumshirn 	device_unregister(dev);
3113764e82eSJohannes Thumshirn 	return 0;
3123764e82eSJohannes Thumshirn }
3133764e82eSJohannes Thumshirn 
3143764e82eSJohannes Thumshirn static void mcb_devices_unregister(struct mcb_bus *bus)
3153764e82eSJohannes Thumshirn {
3163764e82eSJohannes Thumshirn 	bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_devices_unregister);
3173764e82eSJohannes Thumshirn }
3183764e82eSJohannes Thumshirn /**
3193764e82eSJohannes Thumshirn  * mcb_release_bus() - Free a @mcb_bus
3203764e82eSJohannes Thumshirn  * @bus: The @mcb_bus to release
3213764e82eSJohannes Thumshirn  *
3223764e82eSJohannes Thumshirn  * Release an allocated @mcb_bus from the system.
3233764e82eSJohannes Thumshirn  */
3243764e82eSJohannes Thumshirn void mcb_release_bus(struct mcb_bus *bus)
3253764e82eSJohannes Thumshirn {
3263764e82eSJohannes Thumshirn 	mcb_devices_unregister(bus);
3273764e82eSJohannes Thumshirn }
3283764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_release_bus);
3293764e82eSJohannes Thumshirn 
3303764e82eSJohannes Thumshirn /**
3313764e82eSJohannes Thumshirn  * mcb_bus_put() - Increment refcnt
3323764e82eSJohannes Thumshirn  * @bus: The @mcb_bus
3333764e82eSJohannes Thumshirn  *
3343764e82eSJohannes Thumshirn  * Get a @mcb_bus' ref
3353764e82eSJohannes Thumshirn  */
3363764e82eSJohannes Thumshirn struct mcb_bus *mcb_bus_get(struct mcb_bus *bus)
3373764e82eSJohannes Thumshirn {
3383764e82eSJohannes Thumshirn 	if (bus)
3393764e82eSJohannes Thumshirn 		get_device(&bus->dev);
3403764e82eSJohannes Thumshirn 
3413764e82eSJohannes Thumshirn 	return bus;
3423764e82eSJohannes Thumshirn }
3433764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_bus_get);
3443764e82eSJohannes Thumshirn 
3453764e82eSJohannes Thumshirn /**
3463764e82eSJohannes Thumshirn  * mcb_bus_put() - Decrement refcnt
3473764e82eSJohannes Thumshirn  * @bus: The @mcb_bus
3483764e82eSJohannes Thumshirn  *
3493764e82eSJohannes Thumshirn  * Release a @mcb_bus' ref
3503764e82eSJohannes Thumshirn  */
3513764e82eSJohannes Thumshirn void mcb_bus_put(struct mcb_bus *bus)
3523764e82eSJohannes Thumshirn {
3533764e82eSJohannes Thumshirn 	if (bus)
3543764e82eSJohannes Thumshirn 		put_device(&bus->dev);
3553764e82eSJohannes Thumshirn }
3563764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_bus_put);
3573764e82eSJohannes Thumshirn 
3583764e82eSJohannes Thumshirn /**
3593764e82eSJohannes Thumshirn  * mcb_alloc_dev() - Allocate a device
3603764e82eSJohannes Thumshirn  * @bus: The @mcb_bus the device is part of
3613764e82eSJohannes Thumshirn  *
3623764e82eSJohannes Thumshirn  * Allocate a @mcb_device and add bus.
3633764e82eSJohannes Thumshirn  */
3643764e82eSJohannes Thumshirn struct mcb_device *mcb_alloc_dev(struct mcb_bus *bus)
3653764e82eSJohannes Thumshirn {
3663764e82eSJohannes Thumshirn 	struct mcb_device *dev;
3673764e82eSJohannes Thumshirn 
3683764e82eSJohannes Thumshirn 	dev = kzalloc(sizeof(struct mcb_device), GFP_KERNEL);
3693764e82eSJohannes Thumshirn 	if (!dev)
3703764e82eSJohannes Thumshirn 		return NULL;
3713764e82eSJohannes Thumshirn 
3723764e82eSJohannes Thumshirn 	INIT_LIST_HEAD(&dev->bus_list);
3733764e82eSJohannes Thumshirn 	dev->bus = bus;
3743764e82eSJohannes Thumshirn 
3753764e82eSJohannes Thumshirn 	return dev;
3763764e82eSJohannes Thumshirn }
3773764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_alloc_dev);
3783764e82eSJohannes Thumshirn 
3793764e82eSJohannes Thumshirn /**
3803764e82eSJohannes Thumshirn  * mcb_free_dev() - Free @mcb_device
3813764e82eSJohannes Thumshirn  * @dev: The device to free
3823764e82eSJohannes Thumshirn  *
3833764e82eSJohannes Thumshirn  * Free a @mcb_device
3843764e82eSJohannes Thumshirn  */
3853764e82eSJohannes Thumshirn void mcb_free_dev(struct mcb_device *dev)
3863764e82eSJohannes Thumshirn {
3873764e82eSJohannes Thumshirn 	kfree(dev);
3883764e82eSJohannes Thumshirn }
3893764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_free_dev);
3903764e82eSJohannes Thumshirn 
3913764e82eSJohannes Thumshirn static int __mcb_bus_add_devices(struct device *dev, void *data)
3923764e82eSJohannes Thumshirn {
3933764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
3943764e82eSJohannes Thumshirn 	int retval;
3953764e82eSJohannes Thumshirn 
3963764e82eSJohannes Thumshirn 	if (mdev->is_added)
3973764e82eSJohannes Thumshirn 		return 0;
3983764e82eSJohannes Thumshirn 
3993764e82eSJohannes Thumshirn 	retval = device_attach(dev);
4003764e82eSJohannes Thumshirn 	if (retval < 0)
4013764e82eSJohannes Thumshirn 		dev_err(dev, "Error adding device (%d)\n", retval);
4023764e82eSJohannes Thumshirn 
4033764e82eSJohannes Thumshirn 	mdev->is_added = true;
4043764e82eSJohannes Thumshirn 
4053764e82eSJohannes Thumshirn 	return 0;
4063764e82eSJohannes Thumshirn }
4073764e82eSJohannes Thumshirn 
4083764e82eSJohannes Thumshirn static int __mcb_bus_add_child(struct device *dev, void *data)
4093764e82eSJohannes Thumshirn {
4103764e82eSJohannes Thumshirn 	struct mcb_device *mdev = to_mcb_device(dev);
4113764e82eSJohannes Thumshirn 	struct mcb_bus *child;
4123764e82eSJohannes Thumshirn 
4133764e82eSJohannes Thumshirn 	BUG_ON(!mdev->is_added);
4143764e82eSJohannes Thumshirn 	child = mdev->subordinate;
4153764e82eSJohannes Thumshirn 
4163764e82eSJohannes Thumshirn 	if (child)
4173764e82eSJohannes Thumshirn 		mcb_bus_add_devices(child);
4183764e82eSJohannes Thumshirn 
4193764e82eSJohannes Thumshirn 	return 0;
4203764e82eSJohannes Thumshirn }
4213764e82eSJohannes Thumshirn 
4223764e82eSJohannes Thumshirn /**
4233764e82eSJohannes Thumshirn  * mcb_bus_add_devices() - Add devices in the bus' internal device list
4243764e82eSJohannes Thumshirn  * @bus: The @mcb_bus we add the devices
4253764e82eSJohannes Thumshirn  *
4263764e82eSJohannes Thumshirn  * Add devices in the bus' internal device list to the system.
4273764e82eSJohannes Thumshirn  */
4283764e82eSJohannes Thumshirn void mcb_bus_add_devices(const struct mcb_bus *bus)
4293764e82eSJohannes Thumshirn {
4303764e82eSJohannes Thumshirn 	bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_devices);
4313764e82eSJohannes Thumshirn 	bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_child);
4323764e82eSJohannes Thumshirn 
4333764e82eSJohannes Thumshirn }
4343764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_bus_add_devices);
4353764e82eSJohannes Thumshirn 
4363764e82eSJohannes Thumshirn /**
4373764e82eSJohannes Thumshirn  * mcb_request_mem() - Request memory
4383764e82eSJohannes Thumshirn  * @dev: The @mcb_device the memory is for
4393764e82eSJohannes Thumshirn  * @name: The name for the memory reference.
4403764e82eSJohannes Thumshirn  *
4413764e82eSJohannes Thumshirn  * Request memory for a @mcb_device. If @name is NULL the driver name will
4423764e82eSJohannes Thumshirn  * be used.
4433764e82eSJohannes Thumshirn  */
4443764e82eSJohannes Thumshirn struct resource *mcb_request_mem(struct mcb_device *dev, const char *name)
4453764e82eSJohannes Thumshirn {
4463764e82eSJohannes Thumshirn 	struct resource *mem;
4473764e82eSJohannes Thumshirn 	u32 size;
4483764e82eSJohannes Thumshirn 
4493764e82eSJohannes Thumshirn 	if (!name)
4503764e82eSJohannes Thumshirn 		name = dev->dev.driver->name;
4513764e82eSJohannes Thumshirn 
4523764e82eSJohannes Thumshirn 	size = resource_size(&dev->mem);
4533764e82eSJohannes Thumshirn 
4543764e82eSJohannes Thumshirn 	mem = request_mem_region(dev->mem.start, size, name);
4553764e82eSJohannes Thumshirn 	if (!mem)
4563764e82eSJohannes Thumshirn 		return ERR_PTR(-EBUSY);
4573764e82eSJohannes Thumshirn 
4583764e82eSJohannes Thumshirn 	return mem;
4593764e82eSJohannes Thumshirn }
4603764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_request_mem);
4613764e82eSJohannes Thumshirn 
4623764e82eSJohannes Thumshirn /**
4633764e82eSJohannes Thumshirn  * mcb_release_mem() - Release memory requested by device
4643764e82eSJohannes Thumshirn  * @dev: The @mcb_device that requested the memory
4653764e82eSJohannes Thumshirn  *
4663764e82eSJohannes Thumshirn  * Release memory that was prior requested via @mcb_request_mem().
4673764e82eSJohannes Thumshirn  */
4683764e82eSJohannes Thumshirn void mcb_release_mem(struct resource *mem)
4693764e82eSJohannes Thumshirn {
4703764e82eSJohannes Thumshirn 	u32 size;
4713764e82eSJohannes Thumshirn 
4723764e82eSJohannes Thumshirn 	size = resource_size(mem);
4733764e82eSJohannes Thumshirn 	release_mem_region(mem->start, size);
4743764e82eSJohannes Thumshirn }
4753764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_release_mem);
4763764e82eSJohannes Thumshirn 
4774ec65b77SJohannes Thumshirn static int __mcb_get_irq(struct mcb_device *dev)
4784ec65b77SJohannes Thumshirn {
4794ec65b77SJohannes Thumshirn 	struct resource *irq = &dev->irq;
4804ec65b77SJohannes Thumshirn 
4814ec65b77SJohannes Thumshirn 	return irq->start;
4824ec65b77SJohannes Thumshirn }
4834ec65b77SJohannes Thumshirn 
4843764e82eSJohannes Thumshirn /**
4853764e82eSJohannes Thumshirn  * mcb_get_irq() - Get device's IRQ number
4863764e82eSJohannes Thumshirn  * @dev: The @mcb_device the IRQ is for
4873764e82eSJohannes Thumshirn  *
4883764e82eSJohannes Thumshirn  * Get the IRQ number of a given @mcb_device.
4893764e82eSJohannes Thumshirn  */
4903764e82eSJohannes Thumshirn int mcb_get_irq(struct mcb_device *dev)
4913764e82eSJohannes Thumshirn {
4924ec65b77SJohannes Thumshirn 	struct mcb_bus *bus = dev->bus;
4933764e82eSJohannes Thumshirn 
4944ec65b77SJohannes Thumshirn 	if (bus->get_irq)
4954ec65b77SJohannes Thumshirn 		return bus->get_irq(dev);
4964ec65b77SJohannes Thumshirn 
4974ec65b77SJohannes Thumshirn 	return __mcb_get_irq(dev);
4983764e82eSJohannes Thumshirn }
4993764e82eSJohannes Thumshirn EXPORT_SYMBOL_GPL(mcb_get_irq);
5003764e82eSJohannes Thumshirn 
5013764e82eSJohannes Thumshirn static int mcb_init(void)
5023764e82eSJohannes Thumshirn {
5033764e82eSJohannes Thumshirn 	return bus_register(&mcb_bus_type);
5043764e82eSJohannes Thumshirn }
5053764e82eSJohannes Thumshirn 
5063764e82eSJohannes Thumshirn static void mcb_exit(void)
5073764e82eSJohannes Thumshirn {
508169883a6SJohannes Thumshirn 	ida_destroy(&mcb_ida);
5093764e82eSJohannes Thumshirn 	bus_unregister(&mcb_bus_type);
5103764e82eSJohannes Thumshirn }
5113764e82eSJohannes Thumshirn 
5123764e82eSJohannes Thumshirn /* mcb must be initialized after PCI but before the chameleon drivers.
5133764e82eSJohannes Thumshirn  * That means we must use some initcall between subsys_initcall and
5143764e82eSJohannes Thumshirn  * device_initcall.
5153764e82eSJohannes Thumshirn  */
5163764e82eSJohannes Thumshirn fs_initcall(mcb_init);
5173764e82eSJohannes Thumshirn module_exit(mcb_exit);
5183764e82eSJohannes Thumshirn 
5193764e82eSJohannes Thumshirn MODULE_DESCRIPTION("MEN Chameleon Bus Driver");
5203764e82eSJohannes Thumshirn MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
5213764e82eSJohannes Thumshirn MODULE_LICENSE("GPL v2");
522