summaryrefslogtreecommitdiff
path: root/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c')
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c
new file mode 100644
index 000000000000..933027e0011e
--- /dev/null
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * vchiq_device.c - VCHIQ generic device and bus-type
+ *
+ * Copyright (c) 2023 Ideas On Board Oy
+ */
+
+#include <linux/device/bus.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "vchiq_bus.h"
+
+static int vchiq_bus_type_match(struct device *dev, struct device_driver *drv)
+{
+ if (dev->bus == &vchiq_bus_type &&
+ strcmp(dev_name(dev), drv->name) == 0)
+ return true;
+
+ return false;
+}
+
+static int vchiq_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
+{
+ const struct vchiq_device *device = container_of_const(dev, struct vchiq_device, dev);
+
+ return add_uevent_var(env, "MODALIAS=vchiq:%s", dev_name(&device->dev));
+}
+
+static int vchiq_bus_probe(struct device *dev)
+{
+ struct vchiq_device *device = to_vchiq_device(dev);
+ struct vchiq_driver *driver = to_vchiq_driver(dev->driver);
+
+ return driver->probe(device);
+}
+
+struct bus_type vchiq_bus_type = {
+ .name = "vchiq-bus",
+ .match = vchiq_bus_type_match,
+ .uevent = vchiq_bus_uevent,
+ .probe = vchiq_bus_probe,
+};
+
+static void vchiq_device_release(struct device *dev)
+{
+ struct vchiq_device *device = to_vchiq_device(dev);
+
+ kfree(device);
+}
+
+struct vchiq_device *
+vchiq_device_register(struct device *parent, const char *name)
+{
+ struct vchiq_device *device;
+ int ret;
+
+ device = kzalloc(sizeof(*device), GFP_KERNEL);
+ if (!device)
+ return NULL;
+
+ device->dev.init_name = name;
+ device->dev.parent = parent;
+ device->dev.bus = &vchiq_bus_type;
+ device->dev.dma_mask = &device->dev.coherent_dma_mask;
+ device->dev.release = vchiq_device_release;
+
+ of_dma_configure(&device->dev, parent->of_node, true);
+
+ ret = device_register(&device->dev);
+ if (ret) {
+ dev_err(parent, "Cannot register %s: %d\n", name, ret);
+ put_device(&device->dev);
+ return NULL;
+ }
+
+ return device;
+}
+
+void vchiq_device_unregister(struct vchiq_device *vchiq_dev)
+{
+ device_unregister(&vchiq_dev->dev);
+}
+
+int vchiq_driver_register(struct vchiq_driver *vchiq_drv)
+{
+ vchiq_drv->driver.bus = &vchiq_bus_type;
+
+ return driver_register(&vchiq_drv->driver);
+}
+EXPORT_SYMBOL_GPL(vchiq_driver_register);
+
+void vchiq_driver_unregister(struct vchiq_driver *vchiq_drv)
+{
+ driver_unregister(&vchiq_drv->driver);
+}
+EXPORT_SYMBOL_GPL(vchiq_driver_unregister);