xref: /openbmc/linux/drivers/base/auxiliary.c (revision 7de3697e)
1*7de3697eSDave Ertman // SPDX-License-Identifier: GPL-2.0-only
2*7de3697eSDave Ertman /*
3*7de3697eSDave Ertman  * Copyright (c) 2019-2020 Intel Corporation
4*7de3697eSDave Ertman  *
5*7de3697eSDave Ertman  * Please see Documentation/driver-api/auxiliary_bus.rst for more information.
6*7de3697eSDave Ertman  */
7*7de3697eSDave Ertman 
8*7de3697eSDave Ertman #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
9*7de3697eSDave Ertman 
10*7de3697eSDave Ertman #include <linux/device.h>
11*7de3697eSDave Ertman #include <linux/init.h>
12*7de3697eSDave Ertman #include <linux/module.h>
13*7de3697eSDave Ertman #include <linux/pm_domain.h>
14*7de3697eSDave Ertman #include <linux/pm_runtime.h>
15*7de3697eSDave Ertman #include <linux/string.h>
16*7de3697eSDave Ertman #include <linux/auxiliary_bus.h>
17*7de3697eSDave Ertman 
18*7de3697eSDave Ertman static const struct auxiliary_device_id *auxiliary_match_id(const struct auxiliary_device_id *id,
19*7de3697eSDave Ertman 							    const struct auxiliary_device *auxdev)
20*7de3697eSDave Ertman {
21*7de3697eSDave Ertman 	for (; id->name[0]; id++) {
22*7de3697eSDave Ertman 		const char *p = strrchr(dev_name(&auxdev->dev), '.');
23*7de3697eSDave Ertman 		int match_size;
24*7de3697eSDave Ertman 
25*7de3697eSDave Ertman 		if (!p)
26*7de3697eSDave Ertman 			continue;
27*7de3697eSDave Ertman 		match_size = p - dev_name(&auxdev->dev);
28*7de3697eSDave Ertman 
29*7de3697eSDave Ertman 		/* use dev_name(&auxdev->dev) prefix before last '.' char to match to */
30*7de3697eSDave Ertman 		if (strlen(id->name) == match_size &&
31*7de3697eSDave Ertman 		    !strncmp(dev_name(&auxdev->dev), id->name, match_size))
32*7de3697eSDave Ertman 			return id;
33*7de3697eSDave Ertman 	}
34*7de3697eSDave Ertman 	return NULL;
35*7de3697eSDave Ertman }
36*7de3697eSDave Ertman 
37*7de3697eSDave Ertman static int auxiliary_match(struct device *dev, struct device_driver *drv)
38*7de3697eSDave Ertman {
39*7de3697eSDave Ertman 	struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
40*7de3697eSDave Ertman 	struct auxiliary_driver *auxdrv = to_auxiliary_drv(drv);
41*7de3697eSDave Ertman 
42*7de3697eSDave Ertman 	return !!auxiliary_match_id(auxdrv->id_table, auxdev);
43*7de3697eSDave Ertman }
44*7de3697eSDave Ertman 
45*7de3697eSDave Ertman static int auxiliary_uevent(struct device *dev, struct kobj_uevent_env *env)
46*7de3697eSDave Ertman {
47*7de3697eSDave Ertman 	const char *name, *p;
48*7de3697eSDave Ertman 
49*7de3697eSDave Ertman 	name = dev_name(dev);
50*7de3697eSDave Ertman 	p = strrchr(name, '.');
51*7de3697eSDave Ertman 
52*7de3697eSDave Ertman 	return add_uevent_var(env, "MODALIAS=%s%.*s", AUXILIARY_MODULE_PREFIX, (int)(p - name),
53*7de3697eSDave Ertman 			      name);
54*7de3697eSDave Ertman }
55*7de3697eSDave Ertman 
56*7de3697eSDave Ertman static const struct dev_pm_ops auxiliary_dev_pm_ops = {
57*7de3697eSDave Ertman 	SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend, pm_generic_runtime_resume, NULL)
58*7de3697eSDave Ertman 	SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume)
59*7de3697eSDave Ertman };
60*7de3697eSDave Ertman 
61*7de3697eSDave Ertman static int auxiliary_bus_probe(struct device *dev)
62*7de3697eSDave Ertman {
63*7de3697eSDave Ertman 	struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver);
64*7de3697eSDave Ertman 	struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
65*7de3697eSDave Ertman 	int ret;
66*7de3697eSDave Ertman 
67*7de3697eSDave Ertman 	ret = dev_pm_domain_attach(dev, true);
68*7de3697eSDave Ertman 	if (ret) {
69*7de3697eSDave Ertman 		dev_warn(dev, "Failed to attach to PM Domain : %d\n", ret);
70*7de3697eSDave Ertman 		return ret;
71*7de3697eSDave Ertman 	}
72*7de3697eSDave Ertman 
73*7de3697eSDave Ertman 	ret = auxdrv->probe(auxdev, auxiliary_match_id(auxdrv->id_table, auxdev));
74*7de3697eSDave Ertman 	if (ret)
75*7de3697eSDave Ertman 		dev_pm_domain_detach(dev, true);
76*7de3697eSDave Ertman 
77*7de3697eSDave Ertman 	return ret;
78*7de3697eSDave Ertman }
79*7de3697eSDave Ertman 
80*7de3697eSDave Ertman static int auxiliary_bus_remove(struct device *dev)
81*7de3697eSDave Ertman {
82*7de3697eSDave Ertman 	struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver);
83*7de3697eSDave Ertman 	struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
84*7de3697eSDave Ertman 	int ret = 0;
85*7de3697eSDave Ertman 
86*7de3697eSDave Ertman 	if (auxdrv->remove)
87*7de3697eSDave Ertman 		ret = auxdrv->remove(auxdev);
88*7de3697eSDave Ertman 	dev_pm_domain_detach(dev, true);
89*7de3697eSDave Ertman 
90*7de3697eSDave Ertman 	return ret;
91*7de3697eSDave Ertman }
92*7de3697eSDave Ertman 
93*7de3697eSDave Ertman static void auxiliary_bus_shutdown(struct device *dev)
94*7de3697eSDave Ertman {
95*7de3697eSDave Ertman 	struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver);
96*7de3697eSDave Ertman 	struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
97*7de3697eSDave Ertman 
98*7de3697eSDave Ertman 	if (auxdrv->shutdown)
99*7de3697eSDave Ertman 		auxdrv->shutdown(auxdev);
100*7de3697eSDave Ertman }
101*7de3697eSDave Ertman 
102*7de3697eSDave Ertman static struct bus_type auxiliary_bus_type = {
103*7de3697eSDave Ertman 	.name = "auxiliary",
104*7de3697eSDave Ertman 	.probe = auxiliary_bus_probe,
105*7de3697eSDave Ertman 	.remove = auxiliary_bus_remove,
106*7de3697eSDave Ertman 	.shutdown = auxiliary_bus_shutdown,
107*7de3697eSDave Ertman 	.match = auxiliary_match,
108*7de3697eSDave Ertman 	.uevent = auxiliary_uevent,
109*7de3697eSDave Ertman 	.pm = &auxiliary_dev_pm_ops,
110*7de3697eSDave Ertman };
111*7de3697eSDave Ertman 
112*7de3697eSDave Ertman /**
113*7de3697eSDave Ertman  * auxiliary_device_init - check auxiliary_device and initialize
114*7de3697eSDave Ertman  * @auxdev: auxiliary device struct
115*7de3697eSDave Ertman  *
116*7de3697eSDave Ertman  * This is the first step in the two-step process to register an auxiliary_device.
117*7de3697eSDave Ertman  *
118*7de3697eSDave Ertman  * When this function returns an error code, then the device_initialize will *not* have
119*7de3697eSDave Ertman  * been performed, and the caller will be responsible to free any memory allocated for the
120*7de3697eSDave Ertman  * auxiliary_device in the error path directly.
121*7de3697eSDave Ertman  *
122*7de3697eSDave Ertman  * It returns 0 on success.  On success, the device_initialize has been performed.  After this
123*7de3697eSDave Ertman  * point any error unwinding will need to include a call to auxiliary_device_uninit().
124*7de3697eSDave Ertman  * In this post-initialize error scenario, a call to the device's .release callback will be
125*7de3697eSDave Ertman  * triggered, and all memory clean-up is expected to be handled there.
126*7de3697eSDave Ertman  */
127*7de3697eSDave Ertman int auxiliary_device_init(struct auxiliary_device *auxdev)
128*7de3697eSDave Ertman {
129*7de3697eSDave Ertman 	struct device *dev = &auxdev->dev;
130*7de3697eSDave Ertman 
131*7de3697eSDave Ertman 	if (!dev->parent) {
132*7de3697eSDave Ertman 		pr_err("auxiliary_device has a NULL dev->parent\n");
133*7de3697eSDave Ertman 		return -EINVAL;
134*7de3697eSDave Ertman 	}
135*7de3697eSDave Ertman 
136*7de3697eSDave Ertman 	if (!auxdev->name) {
137*7de3697eSDave Ertman 		pr_err("auxiliary_device has a NULL name\n");
138*7de3697eSDave Ertman 		return -EINVAL;
139*7de3697eSDave Ertman 	}
140*7de3697eSDave Ertman 
141*7de3697eSDave Ertman 	dev->bus = &auxiliary_bus_type;
142*7de3697eSDave Ertman 	device_initialize(&auxdev->dev);
143*7de3697eSDave Ertman 	return 0;
144*7de3697eSDave Ertman }
145*7de3697eSDave Ertman EXPORT_SYMBOL_GPL(auxiliary_device_init);
146*7de3697eSDave Ertman 
147*7de3697eSDave Ertman /**
148*7de3697eSDave Ertman  * __auxiliary_device_add - add an auxiliary bus device
149*7de3697eSDave Ertman  * @auxdev: auxiliary bus device to add to the bus
150*7de3697eSDave Ertman  * @modname: name of the parent device's driver module
151*7de3697eSDave Ertman  *
152*7de3697eSDave Ertman  * This is the second step in the two-step process to register an auxiliary_device.
153*7de3697eSDave Ertman  *
154*7de3697eSDave Ertman  * This function must be called after a successful call to auxiliary_device_init(), which
155*7de3697eSDave Ertman  * will perform the device_initialize.  This means that if this returns an error code, then a
156*7de3697eSDave Ertman  * call to auxiliary_device_uninit() must be performed so that the .release callback will
157*7de3697eSDave Ertman  * be triggered to free the memory associated with the auxiliary_device.
158*7de3697eSDave Ertman  *
159*7de3697eSDave Ertman  * The expectation is that users will call the "auxiliary_device_add" macro so that the caller's
160*7de3697eSDave Ertman  * KBUILD_MODNAME is automatically inserted for the modname parameter.  Only if a user requires
161*7de3697eSDave Ertman  * a custom name would this version be called directly.
162*7de3697eSDave Ertman  */
163*7de3697eSDave Ertman int __auxiliary_device_add(struct auxiliary_device *auxdev, const char *modname)
164*7de3697eSDave Ertman {
165*7de3697eSDave Ertman 	struct device *dev = &auxdev->dev;
166*7de3697eSDave Ertman 	int ret;
167*7de3697eSDave Ertman 
168*7de3697eSDave Ertman 	if (!modname) {
169*7de3697eSDave Ertman 		pr_err("auxiliary device modname is NULL\n");
170*7de3697eSDave Ertman 		return -EINVAL;
171*7de3697eSDave Ertman 	}
172*7de3697eSDave Ertman 
173*7de3697eSDave Ertman 	ret = dev_set_name(dev, "%s.%s.%d", modname, auxdev->name, auxdev->id);
174*7de3697eSDave Ertman 	if (ret) {
175*7de3697eSDave Ertman 		pr_err("auxiliary device dev_set_name failed: %d\n", ret);
176*7de3697eSDave Ertman 		return ret;
177*7de3697eSDave Ertman 	}
178*7de3697eSDave Ertman 
179*7de3697eSDave Ertman 	ret = device_add(dev);
180*7de3697eSDave Ertman 	if (ret)
181*7de3697eSDave Ertman 		dev_err(dev, "adding auxiliary device failed!: %d\n", ret);
182*7de3697eSDave Ertman 
183*7de3697eSDave Ertman 	return ret;
184*7de3697eSDave Ertman }
185*7de3697eSDave Ertman EXPORT_SYMBOL_GPL(__auxiliary_device_add);
186*7de3697eSDave Ertman 
187*7de3697eSDave Ertman /**
188*7de3697eSDave Ertman  * auxiliary_find_device - auxiliary device iterator for locating a particular device.
189*7de3697eSDave Ertman  * @start: Device to begin with
190*7de3697eSDave Ertman  * @data: Data to pass to match function
191*7de3697eSDave Ertman  * @match: Callback function to check device
192*7de3697eSDave Ertman  *
193*7de3697eSDave Ertman  * This function returns a reference to a device that is 'found'
194*7de3697eSDave Ertman  * for later use, as determined by the @match callback.
195*7de3697eSDave Ertman  *
196*7de3697eSDave Ertman  * The callback should return 0 if the device doesn't match and non-zero
197*7de3697eSDave Ertman  * if it does.  If the callback returns non-zero, this function will
198*7de3697eSDave Ertman  * return to the caller and not iterate over any more devices.
199*7de3697eSDave Ertman  */
200*7de3697eSDave Ertman struct auxiliary_device *
201*7de3697eSDave Ertman auxiliary_find_device(struct device *start, const void *data,
202*7de3697eSDave Ertman 		      int (*match)(struct device *dev, const void *data))
203*7de3697eSDave Ertman {
204*7de3697eSDave Ertman 	struct device *dev;
205*7de3697eSDave Ertman 
206*7de3697eSDave Ertman 	dev = bus_find_device(&auxiliary_bus_type, start, data, match);
207*7de3697eSDave Ertman 	if (!dev)
208*7de3697eSDave Ertman 		return NULL;
209*7de3697eSDave Ertman 
210*7de3697eSDave Ertman 	return to_auxiliary_dev(dev);
211*7de3697eSDave Ertman }
212*7de3697eSDave Ertman EXPORT_SYMBOL_GPL(auxiliary_find_device);
213*7de3697eSDave Ertman 
214*7de3697eSDave Ertman /**
215*7de3697eSDave Ertman  * __auxiliary_driver_register - register a driver for auxiliary bus devices
216*7de3697eSDave Ertman  * @auxdrv: auxiliary_driver structure
217*7de3697eSDave Ertman  * @owner: owning module/driver
218*7de3697eSDave Ertman  * @modname: KBUILD_MODNAME for parent driver
219*7de3697eSDave Ertman  */
220*7de3697eSDave Ertman int __auxiliary_driver_register(struct auxiliary_driver *auxdrv, struct module *owner,
221*7de3697eSDave Ertman 				const char *modname)
222*7de3697eSDave Ertman {
223*7de3697eSDave Ertman 	if (WARN_ON(!auxdrv->probe) || WARN_ON(!auxdrv->id_table))
224*7de3697eSDave Ertman 		return -EINVAL;
225*7de3697eSDave Ertman 
226*7de3697eSDave Ertman 	if (auxdrv->name)
227*7de3697eSDave Ertman 		auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s.%s", modname, auxdrv->name);
228*7de3697eSDave Ertman 	else
229*7de3697eSDave Ertman 		auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s", modname);
230*7de3697eSDave Ertman 	if (!auxdrv->driver.name)
231*7de3697eSDave Ertman 		return -ENOMEM;
232*7de3697eSDave Ertman 
233*7de3697eSDave Ertman 	auxdrv->driver.owner = owner;
234*7de3697eSDave Ertman 	auxdrv->driver.bus = &auxiliary_bus_type;
235*7de3697eSDave Ertman 	auxdrv->driver.mod_name = modname;
236*7de3697eSDave Ertman 
237*7de3697eSDave Ertman 	return driver_register(&auxdrv->driver);
238*7de3697eSDave Ertman }
239*7de3697eSDave Ertman EXPORT_SYMBOL_GPL(__auxiliary_driver_register);
240*7de3697eSDave Ertman 
241*7de3697eSDave Ertman /**
242*7de3697eSDave Ertman  * auxiliary_driver_unregister - unregister a driver
243*7de3697eSDave Ertman  * @auxdrv: auxiliary_driver structure
244*7de3697eSDave Ertman  */
245*7de3697eSDave Ertman void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv)
246*7de3697eSDave Ertman {
247*7de3697eSDave Ertman 	driver_unregister(&auxdrv->driver);
248*7de3697eSDave Ertman 	kfree(auxdrv->driver.name);
249*7de3697eSDave Ertman }
250*7de3697eSDave Ertman EXPORT_SYMBOL_GPL(auxiliary_driver_unregister);
251*7de3697eSDave Ertman 
252*7de3697eSDave Ertman static int __init auxiliary_bus_init(void)
253*7de3697eSDave Ertman {
254*7de3697eSDave Ertman 	return bus_register(&auxiliary_bus_type);
255*7de3697eSDave Ertman }
256*7de3697eSDave Ertman 
257*7de3697eSDave Ertman static void __exit auxiliary_bus_exit(void)
258*7de3697eSDave Ertman {
259*7de3697eSDave Ertman 	bus_unregister(&auxiliary_bus_type);
260*7de3697eSDave Ertman }
261*7de3697eSDave Ertman 
262*7de3697eSDave Ertman module_init(auxiliary_bus_init);
263*7de3697eSDave Ertman module_exit(auxiliary_bus_exit);
264*7de3697eSDave Ertman 
265*7de3697eSDave Ertman MODULE_LICENSE("GPL v2");
266*7de3697eSDave Ertman MODULE_DESCRIPTION("Auxiliary Bus");
267*7de3697eSDave Ertman MODULE_AUTHOR("David Ertman <david.m.ertman@intel.com>");
268*7de3697eSDave Ertman MODULE_AUTHOR("Kiran Patil <kiran.patil@intel.com>");
269