xref: /openbmc/linux/drivers/base/auxiliary.c (revision 8142a46c)
17de3697eSDave Ertman // SPDX-License-Identifier: GPL-2.0-only
27de3697eSDave Ertman /*
37de3697eSDave Ertman  * Copyright (c) 2019-2020 Intel Corporation
47de3697eSDave Ertman  *
57de3697eSDave Ertman  * Please see Documentation/driver-api/auxiliary_bus.rst for more information.
67de3697eSDave Ertman  */
77de3697eSDave Ertman 
87de3697eSDave Ertman #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
97de3697eSDave Ertman 
107de3697eSDave Ertman #include <linux/device.h>
117de3697eSDave Ertman #include <linux/init.h>
127bbb79ffSGreg Kroah-Hartman #include <linux/slab.h>
137de3697eSDave Ertman #include <linux/module.h>
147de3697eSDave Ertman #include <linux/pm_domain.h>
157de3697eSDave Ertman #include <linux/pm_runtime.h>
167de3697eSDave Ertman #include <linux/string.h>
177de3697eSDave Ertman #include <linux/auxiliary_bus.h>
187de3697eSDave Ertman 
197de3697eSDave Ertman static const struct auxiliary_device_id *auxiliary_match_id(const struct auxiliary_device_id *id,
207de3697eSDave Ertman 							    const struct auxiliary_device *auxdev)
217de3697eSDave Ertman {
227de3697eSDave Ertman 	for (; id->name[0]; id++) {
237de3697eSDave Ertman 		const char *p = strrchr(dev_name(&auxdev->dev), '.');
247de3697eSDave Ertman 		int match_size;
257de3697eSDave Ertman 
267de3697eSDave Ertman 		if (!p)
277de3697eSDave Ertman 			continue;
287de3697eSDave Ertman 		match_size = p - dev_name(&auxdev->dev);
297de3697eSDave Ertman 
307de3697eSDave Ertman 		/* use dev_name(&auxdev->dev) prefix before last '.' char to match to */
317de3697eSDave Ertman 		if (strlen(id->name) == match_size &&
327de3697eSDave Ertman 		    !strncmp(dev_name(&auxdev->dev), id->name, match_size))
337de3697eSDave Ertman 			return id;
347de3697eSDave Ertman 	}
357de3697eSDave Ertman 	return NULL;
367de3697eSDave Ertman }
377de3697eSDave Ertman 
387de3697eSDave Ertman static int auxiliary_match(struct device *dev, struct device_driver *drv)
397de3697eSDave Ertman {
407de3697eSDave Ertman 	struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
417de3697eSDave Ertman 	struct auxiliary_driver *auxdrv = to_auxiliary_drv(drv);
427de3697eSDave Ertman 
437de3697eSDave Ertman 	return !!auxiliary_match_id(auxdrv->id_table, auxdev);
447de3697eSDave Ertman }
457de3697eSDave Ertman 
467de3697eSDave Ertman static int auxiliary_uevent(struct device *dev, struct kobj_uevent_env *env)
477de3697eSDave Ertman {
487de3697eSDave Ertman 	const char *name, *p;
497de3697eSDave Ertman 
507de3697eSDave Ertman 	name = dev_name(dev);
517de3697eSDave Ertman 	p = strrchr(name, '.');
527de3697eSDave Ertman 
537de3697eSDave Ertman 	return add_uevent_var(env, "MODALIAS=%s%.*s", AUXILIARY_MODULE_PREFIX, (int)(p - name),
547de3697eSDave Ertman 			      name);
557de3697eSDave Ertman }
567de3697eSDave Ertman 
577de3697eSDave Ertman static const struct dev_pm_ops auxiliary_dev_pm_ops = {
587de3697eSDave Ertman 	SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend, pm_generic_runtime_resume, NULL)
597de3697eSDave Ertman 	SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume)
607de3697eSDave Ertman };
617de3697eSDave Ertman 
627de3697eSDave Ertman static int auxiliary_bus_probe(struct device *dev)
637de3697eSDave Ertman {
647de3697eSDave Ertman 	struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver);
657de3697eSDave Ertman 	struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
667de3697eSDave Ertman 	int ret;
677de3697eSDave Ertman 
687de3697eSDave Ertman 	ret = dev_pm_domain_attach(dev, true);
697de3697eSDave Ertman 	if (ret) {
707de3697eSDave Ertman 		dev_warn(dev, "Failed to attach to PM Domain : %d\n", ret);
717de3697eSDave Ertman 		return ret;
727de3697eSDave Ertman 	}
737de3697eSDave Ertman 
747de3697eSDave Ertman 	ret = auxdrv->probe(auxdev, auxiliary_match_id(auxdrv->id_table, auxdev));
757de3697eSDave Ertman 	if (ret)
767de3697eSDave Ertman 		dev_pm_domain_detach(dev, true);
777de3697eSDave Ertman 
787de3697eSDave Ertman 	return ret;
797de3697eSDave Ertman }
807de3697eSDave Ertman 
817de3697eSDave Ertman static int auxiliary_bus_remove(struct device *dev)
827de3697eSDave Ertman {
837de3697eSDave Ertman 	struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver);
847de3697eSDave Ertman 	struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
857de3697eSDave Ertman 
867de3697eSDave Ertman 	if (auxdrv->remove)
87*8142a46cSGreg Kroah-Hartman 		auxdrv->remove(auxdev);
887de3697eSDave Ertman 	dev_pm_domain_detach(dev, true);
897de3697eSDave Ertman 
90*8142a46cSGreg Kroah-Hartman 	return 0;
917de3697eSDave Ertman }
927de3697eSDave Ertman 
937de3697eSDave Ertman static void auxiliary_bus_shutdown(struct device *dev)
947de3697eSDave Ertman {
957de3697eSDave Ertman 	struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver);
967de3697eSDave Ertman 	struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
977de3697eSDave Ertman 
987de3697eSDave Ertman 	if (auxdrv->shutdown)
997de3697eSDave Ertman 		auxdrv->shutdown(auxdev);
1007de3697eSDave Ertman }
1017de3697eSDave Ertman 
1027de3697eSDave Ertman static struct bus_type auxiliary_bus_type = {
1037de3697eSDave Ertman 	.name = "auxiliary",
1047de3697eSDave Ertman 	.probe = auxiliary_bus_probe,
1057de3697eSDave Ertman 	.remove = auxiliary_bus_remove,
1067de3697eSDave Ertman 	.shutdown = auxiliary_bus_shutdown,
1077de3697eSDave Ertman 	.match = auxiliary_match,
1087de3697eSDave Ertman 	.uevent = auxiliary_uevent,
1097de3697eSDave Ertman 	.pm = &auxiliary_dev_pm_ops,
1107de3697eSDave Ertman };
1117de3697eSDave Ertman 
1127de3697eSDave Ertman /**
1137de3697eSDave Ertman  * auxiliary_device_init - check auxiliary_device and initialize
1147de3697eSDave Ertman  * @auxdev: auxiliary device struct
1157de3697eSDave Ertman  *
1167de3697eSDave Ertman  * This is the first step in the two-step process to register an auxiliary_device.
1177de3697eSDave Ertman  *
1187de3697eSDave Ertman  * When this function returns an error code, then the device_initialize will *not* have
1197de3697eSDave Ertman  * been performed, and the caller will be responsible to free any memory allocated for the
1207de3697eSDave Ertman  * auxiliary_device in the error path directly.
1217de3697eSDave Ertman  *
1227de3697eSDave Ertman  * It returns 0 on success.  On success, the device_initialize has been performed.  After this
1237de3697eSDave Ertman  * point any error unwinding will need to include a call to auxiliary_device_uninit().
1247de3697eSDave Ertman  * In this post-initialize error scenario, a call to the device's .release callback will be
1257de3697eSDave Ertman  * triggered, and all memory clean-up is expected to be handled there.
1267de3697eSDave Ertman  */
1277de3697eSDave Ertman int auxiliary_device_init(struct auxiliary_device *auxdev)
1287de3697eSDave Ertman {
1297de3697eSDave Ertman 	struct device *dev = &auxdev->dev;
1307de3697eSDave Ertman 
1317de3697eSDave Ertman 	if (!dev->parent) {
1327de3697eSDave Ertman 		pr_err("auxiliary_device has a NULL dev->parent\n");
1337de3697eSDave Ertman 		return -EINVAL;
1347de3697eSDave Ertman 	}
1357de3697eSDave Ertman 
1367de3697eSDave Ertman 	if (!auxdev->name) {
1377de3697eSDave Ertman 		pr_err("auxiliary_device has a NULL name\n");
1387de3697eSDave Ertman 		return -EINVAL;
1397de3697eSDave Ertman 	}
1407de3697eSDave Ertman 
1417de3697eSDave Ertman 	dev->bus = &auxiliary_bus_type;
1427de3697eSDave Ertman 	device_initialize(&auxdev->dev);
1437de3697eSDave Ertman 	return 0;
1447de3697eSDave Ertman }
1457de3697eSDave Ertman EXPORT_SYMBOL_GPL(auxiliary_device_init);
1467de3697eSDave Ertman 
1477de3697eSDave Ertman /**
1487de3697eSDave Ertman  * __auxiliary_device_add - add an auxiliary bus device
1497de3697eSDave Ertman  * @auxdev: auxiliary bus device to add to the bus
1507de3697eSDave Ertman  * @modname: name of the parent device's driver module
1517de3697eSDave Ertman  *
1527de3697eSDave Ertman  * This is the second step in the two-step process to register an auxiliary_device.
1537de3697eSDave Ertman  *
1547de3697eSDave Ertman  * This function must be called after a successful call to auxiliary_device_init(), which
1557de3697eSDave Ertman  * will perform the device_initialize.  This means that if this returns an error code, then a
1567de3697eSDave Ertman  * call to auxiliary_device_uninit() must be performed so that the .release callback will
1577de3697eSDave Ertman  * be triggered to free the memory associated with the auxiliary_device.
1587de3697eSDave Ertman  *
1597de3697eSDave Ertman  * The expectation is that users will call the "auxiliary_device_add" macro so that the caller's
1607de3697eSDave Ertman  * KBUILD_MODNAME is automatically inserted for the modname parameter.  Only if a user requires
1617de3697eSDave Ertman  * a custom name would this version be called directly.
1627de3697eSDave Ertman  */
1637de3697eSDave Ertman int __auxiliary_device_add(struct auxiliary_device *auxdev, const char *modname)
1647de3697eSDave Ertman {
1657de3697eSDave Ertman 	struct device *dev = &auxdev->dev;
1667de3697eSDave Ertman 	int ret;
1677de3697eSDave Ertman 
1687de3697eSDave Ertman 	if (!modname) {
1697de3697eSDave Ertman 		pr_err("auxiliary device modname is NULL\n");
1707de3697eSDave Ertman 		return -EINVAL;
1717de3697eSDave Ertman 	}
1727de3697eSDave Ertman 
1737de3697eSDave Ertman 	ret = dev_set_name(dev, "%s.%s.%d", modname, auxdev->name, auxdev->id);
1747de3697eSDave Ertman 	if (ret) {
1757de3697eSDave Ertman 		pr_err("auxiliary device dev_set_name failed: %d\n", ret);
1767de3697eSDave Ertman 		return ret;
1777de3697eSDave Ertman 	}
1787de3697eSDave Ertman 
1797de3697eSDave Ertman 	ret = device_add(dev);
1807de3697eSDave Ertman 	if (ret)
1817de3697eSDave Ertman 		dev_err(dev, "adding auxiliary device failed!: %d\n", ret);
1827de3697eSDave Ertman 
1837de3697eSDave Ertman 	return ret;
1847de3697eSDave Ertman }
1857de3697eSDave Ertman EXPORT_SYMBOL_GPL(__auxiliary_device_add);
1867de3697eSDave Ertman 
1877de3697eSDave Ertman /**
1887de3697eSDave Ertman  * auxiliary_find_device - auxiliary device iterator for locating a particular device.
1897de3697eSDave Ertman  * @start: Device to begin with
1907de3697eSDave Ertman  * @data: Data to pass to match function
1917de3697eSDave Ertman  * @match: Callback function to check device
1927de3697eSDave Ertman  *
1937de3697eSDave Ertman  * This function returns a reference to a device that is 'found'
1947de3697eSDave Ertman  * for later use, as determined by the @match callback.
1957de3697eSDave Ertman  *
1967de3697eSDave Ertman  * The callback should return 0 if the device doesn't match and non-zero
1977de3697eSDave Ertman  * if it does.  If the callback returns non-zero, this function will
1987de3697eSDave Ertman  * return to the caller and not iterate over any more devices.
1997de3697eSDave Ertman  */
2007de3697eSDave Ertman struct auxiliary_device *
2017de3697eSDave Ertman auxiliary_find_device(struct device *start, const void *data,
2027de3697eSDave Ertman 		      int (*match)(struct device *dev, const void *data))
2037de3697eSDave Ertman {
2047de3697eSDave Ertman 	struct device *dev;
2057de3697eSDave Ertman 
2067de3697eSDave Ertman 	dev = bus_find_device(&auxiliary_bus_type, start, data, match);
2077de3697eSDave Ertman 	if (!dev)
2087de3697eSDave Ertman 		return NULL;
2097de3697eSDave Ertman 
2107de3697eSDave Ertman 	return to_auxiliary_dev(dev);
2117de3697eSDave Ertman }
2127de3697eSDave Ertman EXPORT_SYMBOL_GPL(auxiliary_find_device);
2137de3697eSDave Ertman 
2147de3697eSDave Ertman /**
2157de3697eSDave Ertman  * __auxiliary_driver_register - register a driver for auxiliary bus devices
2167de3697eSDave Ertman  * @auxdrv: auxiliary_driver structure
2177de3697eSDave Ertman  * @owner: owning module/driver
2187de3697eSDave Ertman  * @modname: KBUILD_MODNAME for parent driver
2197de3697eSDave Ertman  */
2207de3697eSDave Ertman int __auxiliary_driver_register(struct auxiliary_driver *auxdrv, struct module *owner,
2217de3697eSDave Ertman 				const char *modname)
2227de3697eSDave Ertman {
2237de3697eSDave Ertman 	if (WARN_ON(!auxdrv->probe) || WARN_ON(!auxdrv->id_table))
2247de3697eSDave Ertman 		return -EINVAL;
2257de3697eSDave Ertman 
2267de3697eSDave Ertman 	if (auxdrv->name)
2277de3697eSDave Ertman 		auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s.%s", modname, auxdrv->name);
2287de3697eSDave Ertman 	else
2297de3697eSDave Ertman 		auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s", modname);
2307de3697eSDave Ertman 	if (!auxdrv->driver.name)
2317de3697eSDave Ertman 		return -ENOMEM;
2327de3697eSDave Ertman 
2337de3697eSDave Ertman 	auxdrv->driver.owner = owner;
2347de3697eSDave Ertman 	auxdrv->driver.bus = &auxiliary_bus_type;
2357de3697eSDave Ertman 	auxdrv->driver.mod_name = modname;
2367de3697eSDave Ertman 
2377de3697eSDave Ertman 	return driver_register(&auxdrv->driver);
2387de3697eSDave Ertman }
2397de3697eSDave Ertman EXPORT_SYMBOL_GPL(__auxiliary_driver_register);
2407de3697eSDave Ertman 
2417de3697eSDave Ertman /**
2427de3697eSDave Ertman  * auxiliary_driver_unregister - unregister a driver
2437de3697eSDave Ertman  * @auxdrv: auxiliary_driver structure
2447de3697eSDave Ertman  */
2457de3697eSDave Ertman void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv)
2467de3697eSDave Ertman {
2477de3697eSDave Ertman 	driver_unregister(&auxdrv->driver);
2487de3697eSDave Ertman 	kfree(auxdrv->driver.name);
2497de3697eSDave Ertman }
2507de3697eSDave Ertman EXPORT_SYMBOL_GPL(auxiliary_driver_unregister);
2517de3697eSDave Ertman 
2527de3697eSDave Ertman static int __init auxiliary_bus_init(void)
2537de3697eSDave Ertman {
2547de3697eSDave Ertman 	return bus_register(&auxiliary_bus_type);
2557de3697eSDave Ertman }
2567de3697eSDave Ertman 
2577de3697eSDave Ertman static void __exit auxiliary_bus_exit(void)
2587de3697eSDave Ertman {
2597de3697eSDave Ertman 	bus_unregister(&auxiliary_bus_type);
2607de3697eSDave Ertman }
2617de3697eSDave Ertman 
2627de3697eSDave Ertman module_init(auxiliary_bus_init);
2637de3697eSDave Ertman module_exit(auxiliary_bus_exit);
2647de3697eSDave Ertman 
2657de3697eSDave Ertman MODULE_LICENSE("GPL v2");
2667de3697eSDave Ertman MODULE_DESCRIPTION("Auxiliary Bus");
2677de3697eSDave Ertman MODULE_AUTHOR("David Ertman <david.m.ertman@intel.com>");
2687de3697eSDave Ertman MODULE_AUTHOR("Kiran Patil <kiran.patil@intel.com>");
269