diff mbox series

[RFC,1/5] misc: introduce notify-device driver

Message ID db30127ab4741d4e71b768881197f4791174f545.1666786471.git.matthias.schiffer@ew.tq-group.com
State New
Headers show
Series "notify-device" for cross-driver readiness notification | expand

Commit Message

Matthias Schiffer Oct. 26, 2022, 1:15 p.m. UTC
A notify-device is a synchronization facility that allows to query
"readiness" across drivers, without creating a direct dependency between
the driver modules. The notify-device can also be used to trigger deferred
probes.

Signed-off-by: Matthias Schiffer <matthias.schiffer@ew.tq-group.com>
---
 drivers/misc/Kconfig          |   4 ++
 drivers/misc/Makefile         |   1 +
 drivers/misc/notify-device.c  | 109 ++++++++++++++++++++++++++++++++++
 include/linux/notify-device.h |  33 ++++++++++
 4 files changed, 147 insertions(+)
 create mode 100644 drivers/misc/notify-device.c
 create mode 100644 include/linux/notify-device.h
diff mbox series

Patch

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 358ad56f6524..63559e9f854c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -496,6 +496,10 @@  config VCPU_STALL_DETECTOR
 
 	  If you do not intend to run this kernel as a guest, say N.
 
+config NOTIFY_DEVICE
+	tristate "Notify device"
+	depends on OF
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index ac9b3e757ba1..1e8012112b43 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -62,3 +62,4 @@  obj-$(CONFIG_HI6421V600_IRQ)	+= hi6421v600-irq.o
 obj-$(CONFIG_OPEN_DICE)		+= open-dice.o
 obj-$(CONFIG_GP_PCI1XXXX)	+= mchp_pci1xxxx/
 obj-$(CONFIG_VCPU_STALL_DETECTOR)	+= vcpu_stall_detector.o
+obj-$(CONFIG_NOTIFY_DEVICE)	+= notify-device.o
diff --git a/drivers/misc/notify-device.c b/drivers/misc/notify-device.c
new file mode 100644
index 000000000000..42e0980394ea
--- /dev/null
+++ b/drivers/misc/notify-device.c
@@ -0,0 +1,109 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/device/class.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/notify-device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+static void notify_device_release(struct device *dev)
+{
+	of_node_put(dev->of_node);
+	kfree(dev);
+}
+
+static struct class notify_device_class = {
+	.name = "notify-device",
+	.owner = THIS_MODULE,
+	.dev_release = notify_device_release,
+};
+
+static struct platform_driver notify_device_driver = {
+	.driver = {
+		.name = "notify-device",
+	},
+};
+
+struct device *notify_device_create(struct device *parent, const char *child)
+{
+	struct device_node *node;
+	struct device *dev;
+	int err;
+
+	if (!parent->of_node)
+		return ERR_PTR(-EINVAL);
+
+	node = of_get_child_by_name(parent->of_node, child);
+	if (!node)
+		return NULL;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		of_node_put(node);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	dev_set_name(dev, "%s:%s", dev_name(parent), child);
+	dev->class = &notify_device_class;
+	dev->parent = parent;
+	dev->of_node = node;
+	err = device_register(dev);
+	if (err) {
+		put_device(dev);
+		return ERR_PTR(err);
+	}
+
+	dev->driver = &notify_device_driver.driver;
+	err = device_bind_driver(dev);
+	if (err) {
+		device_unregister(dev);
+		return ERR_PTR(err);
+	}
+
+	return dev;
+}
+EXPORT_SYMBOL_GPL(notify_device_create);
+
+void notify_device_destroy(struct device *dev)
+{
+	if (!dev)
+		return;
+
+	device_release_driver(dev);
+	device_unregister(dev);
+}
+EXPORT_SYMBOL_GPL(notify_device_destroy);
+
+struct device *notify_device_find_by_of_node(struct device_node *node)
+{
+	return class_find_device_by_of_node(&notify_device_class, node);
+}
+EXPORT_SYMBOL_GPL(notify_device_find_by_of_node);
+
+static int __init notify_device_init(void)
+{
+	int err;
+
+	err = class_register(&notify_device_class);
+	if (err)
+		return err;
+
+	err = platform_driver_register(&notify_device_driver);
+	if (err) {
+		class_unregister(&notify_device_class);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __exit notify_device_exit(void)
+{
+	platform_driver_unregister(&notify_device_driver);
+	class_unregister(&notify_device_class);
+}
+
+module_init(notify_device_init);
+module_exit(notify_device_exit);
+MODULE_LICENSE("GPL");
diff --git a/include/linux/notify-device.h b/include/linux/notify-device.h
new file mode 100644
index 000000000000..f8c3e15d3b8f
--- /dev/null
+++ b/include/linux/notify-device.h
@@ -0,0 +1,33 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_NOTIFY_DEVICE_H
+#define _LINUX_NOTIFY_DEVICE_H
+#include <linux/device.h>
+#include <linux/of.h>
+
+#ifdef CONFIG_NOTIFY_DEVICE
+
+struct device *notify_device_create(struct device *parent, const char *child);
+void notify_device_destroy(struct device *dev);
+struct device *notify_device_find_by_of_node(struct device_node *node);
+
+#else
+
+static inline struct device *notify_device_create(struct device *parent,
+						  const char *child)
+{
+	return NULL;
+}
+
+static inline void notify_device_destroy(struct device *dev)
+{
+}
+
+static inline struct device *notify_device_find_by_of_node(struct device_node *node)
+{
+	return NULL;
+}
+
+#endif
+
+#endif /* _LINUX_NOTIFY_DEVICE_H */