xref: /linux-6.15/drivers/gpio/dev-sync-probe.c (revision eb5ab6ff)
1*eb5ab6ffSKoichiro Den // SPDX-License-Identifier: GPL-2.0-or-later
2*eb5ab6ffSKoichiro Den /*
3*eb5ab6ffSKoichiro Den  * Common code for drivers creating fake platform devices.
4*eb5ab6ffSKoichiro Den  *
5*eb5ab6ffSKoichiro Den  * Provides synchronous device creation: waits for probe completion and
6*eb5ab6ffSKoichiro Den  * returns the probe success or error status to the device creator.
7*eb5ab6ffSKoichiro Den  *
8*eb5ab6ffSKoichiro Den  * Copyright (C) 2021 Bartosz Golaszewski <[email protected]>
9*eb5ab6ffSKoichiro Den  * Copyright (C) 2025 Koichiro Den <[email protected]>
10*eb5ab6ffSKoichiro Den  */
11*eb5ab6ffSKoichiro Den 
12*eb5ab6ffSKoichiro Den #include <linux/device.h>
13*eb5ab6ffSKoichiro Den #include <linux/slab.h>
14*eb5ab6ffSKoichiro Den 
15*eb5ab6ffSKoichiro Den #include "dev-sync-probe.h"
16*eb5ab6ffSKoichiro Den 
dev_sync_probe_notifier_call(struct notifier_block * nb,unsigned long action,void * data)17*eb5ab6ffSKoichiro Den static int dev_sync_probe_notifier_call(struct notifier_block *nb,
18*eb5ab6ffSKoichiro Den 					unsigned long action, void *data)
19*eb5ab6ffSKoichiro Den {
20*eb5ab6ffSKoichiro Den 	struct dev_sync_probe_data *pdata;
21*eb5ab6ffSKoichiro Den 	struct device *dev = data;
22*eb5ab6ffSKoichiro Den 
23*eb5ab6ffSKoichiro Den 	pdata = container_of(nb, struct dev_sync_probe_data, bus_notifier);
24*eb5ab6ffSKoichiro Den 	if (!device_match_name(dev, pdata->name))
25*eb5ab6ffSKoichiro Den 		return NOTIFY_DONE;
26*eb5ab6ffSKoichiro Den 
27*eb5ab6ffSKoichiro Den 	switch (action) {
28*eb5ab6ffSKoichiro Den 	case BUS_NOTIFY_BOUND_DRIVER:
29*eb5ab6ffSKoichiro Den 		pdata->driver_bound = true;
30*eb5ab6ffSKoichiro Den 		break;
31*eb5ab6ffSKoichiro Den 	case BUS_NOTIFY_DRIVER_NOT_BOUND:
32*eb5ab6ffSKoichiro Den 		pdata->driver_bound = false;
33*eb5ab6ffSKoichiro Den 		break;
34*eb5ab6ffSKoichiro Den 	default:
35*eb5ab6ffSKoichiro Den 		return NOTIFY_DONE;
36*eb5ab6ffSKoichiro Den 	}
37*eb5ab6ffSKoichiro Den 
38*eb5ab6ffSKoichiro Den 	complete(&pdata->probe_completion);
39*eb5ab6ffSKoichiro Den 	return NOTIFY_OK;
40*eb5ab6ffSKoichiro Den }
41*eb5ab6ffSKoichiro Den 
dev_sync_probe_init(struct dev_sync_probe_data * data)42*eb5ab6ffSKoichiro Den void dev_sync_probe_init(struct dev_sync_probe_data *data)
43*eb5ab6ffSKoichiro Den {
44*eb5ab6ffSKoichiro Den 	memset(data, 0, sizeof(*data));
45*eb5ab6ffSKoichiro Den 	init_completion(&data->probe_completion);
46*eb5ab6ffSKoichiro Den 	data->bus_notifier.notifier_call = dev_sync_probe_notifier_call;
47*eb5ab6ffSKoichiro Den }
48*eb5ab6ffSKoichiro Den EXPORT_SYMBOL_GPL(dev_sync_probe_init);
49*eb5ab6ffSKoichiro Den 
dev_sync_probe_register(struct dev_sync_probe_data * data,struct platform_device_info * pdevinfo)50*eb5ab6ffSKoichiro Den int dev_sync_probe_register(struct dev_sync_probe_data *data,
51*eb5ab6ffSKoichiro Den 			    struct platform_device_info *pdevinfo)
52*eb5ab6ffSKoichiro Den {
53*eb5ab6ffSKoichiro Den 	struct platform_device *pdev;
54*eb5ab6ffSKoichiro Den 	char *name;
55*eb5ab6ffSKoichiro Den 
56*eb5ab6ffSKoichiro Den 	name = kasprintf(GFP_KERNEL, "%s.%d", pdevinfo->name, pdevinfo->id);
57*eb5ab6ffSKoichiro Den 	if (!name)
58*eb5ab6ffSKoichiro Den 		return -ENOMEM;
59*eb5ab6ffSKoichiro Den 
60*eb5ab6ffSKoichiro Den 	data->driver_bound = false;
61*eb5ab6ffSKoichiro Den 	data->name = name;
62*eb5ab6ffSKoichiro Den 	reinit_completion(&data->probe_completion);
63*eb5ab6ffSKoichiro Den 	bus_register_notifier(&platform_bus_type, &data->bus_notifier);
64*eb5ab6ffSKoichiro Den 
65*eb5ab6ffSKoichiro Den 	pdev = platform_device_register_full(pdevinfo);
66*eb5ab6ffSKoichiro Den 	if (IS_ERR(pdev)) {
67*eb5ab6ffSKoichiro Den 		bus_unregister_notifier(&platform_bus_type, &data->bus_notifier);
68*eb5ab6ffSKoichiro Den 		kfree(data->name);
69*eb5ab6ffSKoichiro Den 		return PTR_ERR(pdev);
70*eb5ab6ffSKoichiro Den 	}
71*eb5ab6ffSKoichiro Den 
72*eb5ab6ffSKoichiro Den 	wait_for_completion(&data->probe_completion);
73*eb5ab6ffSKoichiro Den 	bus_unregister_notifier(&platform_bus_type, &data->bus_notifier);
74*eb5ab6ffSKoichiro Den 
75*eb5ab6ffSKoichiro Den 	if (!data->driver_bound) {
76*eb5ab6ffSKoichiro Den 		platform_device_unregister(pdev);
77*eb5ab6ffSKoichiro Den 		kfree(data->name);
78*eb5ab6ffSKoichiro Den 		return -ENXIO;
79*eb5ab6ffSKoichiro Den 	}
80*eb5ab6ffSKoichiro Den 
81*eb5ab6ffSKoichiro Den 	data->pdev = pdev;
82*eb5ab6ffSKoichiro Den 	return 0;
83*eb5ab6ffSKoichiro Den }
84*eb5ab6ffSKoichiro Den EXPORT_SYMBOL_GPL(dev_sync_probe_register);
85*eb5ab6ffSKoichiro Den 
dev_sync_probe_unregister(struct dev_sync_probe_data * data)86*eb5ab6ffSKoichiro Den void dev_sync_probe_unregister(struct dev_sync_probe_data *data)
87*eb5ab6ffSKoichiro Den {
88*eb5ab6ffSKoichiro Den 	platform_device_unregister(data->pdev);
89*eb5ab6ffSKoichiro Den 	kfree(data->name);
90*eb5ab6ffSKoichiro Den 	data->pdev = NULL;
91*eb5ab6ffSKoichiro Den }
92*eb5ab6ffSKoichiro Den EXPORT_SYMBOL_GPL(dev_sync_probe_unregister);
93*eb5ab6ffSKoichiro Den 
94*eb5ab6ffSKoichiro Den MODULE_AUTHOR("Bartosz Golaszewski <[email protected]>");
95*eb5ab6ffSKoichiro Den MODULE_AUTHOR("Koichiro Den <[email protected]>");
96*eb5ab6ffSKoichiro Den MODULE_DESCRIPTION("Utilities for synchronous fake device creation");
97*eb5ab6ffSKoichiro Den MODULE_LICENSE("GPL");
98