1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * vchiq_device.c - VCHIQ generic device and bus-type
4 *
5 * Copyright (c) 2023 Ideas On Board Oy
6 */
7
8 #include <linux/device/bus.h>
9 #include <linux/dma-mapping.h>
10 #include <linux/of_device.h>
11 #include <linux/slab.h>
12 #include <linux/string.h>
13
14 #include "vchiq_arm.h"
15 #include "vchiq_bus.h"
16
vchiq_bus_type_match(struct device * dev,const struct device_driver * drv)17 static int vchiq_bus_type_match(struct device *dev, const struct device_driver *drv)
18 {
19 if (dev->bus == &vchiq_bus_type &&
20 strcmp(dev_name(dev), drv->name) == 0)
21 return true;
22
23 return false;
24 }
25
vchiq_bus_uevent(const struct device * dev,struct kobj_uevent_env * env)26 static int vchiq_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
27 {
28 const struct vchiq_device *device = container_of_const(dev, struct vchiq_device, dev);
29
30 return add_uevent_var(env, "MODALIAS=vchiq:%s", dev_name(&device->dev));
31 }
32
vchiq_bus_probe(struct device * dev)33 static int vchiq_bus_probe(struct device *dev)
34 {
35 struct vchiq_device *device = to_vchiq_device(dev);
36 struct vchiq_driver *driver = to_vchiq_driver(dev->driver);
37
38 return driver->probe(device);
39 }
40
vchiq_bus_remove(struct device * dev)41 static void vchiq_bus_remove(struct device *dev)
42 {
43 struct vchiq_device *device = to_vchiq_device(dev);
44 struct vchiq_driver *driver = to_vchiq_driver(dev->driver);
45
46 if (driver->remove)
47 driver->remove(device);
48 }
49
50 const struct bus_type vchiq_bus_type = {
51 .name = "vchiq-bus",
52 .match = vchiq_bus_type_match,
53 .uevent = vchiq_bus_uevent,
54 .probe = vchiq_bus_probe,
55 .remove = vchiq_bus_remove,
56 };
57
vchiq_device_release(struct device * dev)58 static void vchiq_device_release(struct device *dev)
59 {
60 struct vchiq_device *device = to_vchiq_device(dev);
61
62 kfree(device);
63 }
64
65 struct vchiq_device *
vchiq_device_register(struct device * parent,const char * name)66 vchiq_device_register(struct device *parent, const char *name)
67 {
68 struct vchiq_device *device;
69 int ret;
70
71 device = kzalloc(sizeof(*device), GFP_KERNEL);
72 if (!device)
73 return NULL;
74
75 device->dev.init_name = name;
76 device->dev.parent = parent;
77 device->dev.bus = &vchiq_bus_type;
78 device->dev.dma_mask = &device->dev.coherent_dma_mask;
79 device->dev.release = vchiq_device_release;
80
81 device->drv_mgmt = dev_get_drvdata(parent);
82
83 of_dma_configure(&device->dev, parent->of_node, true);
84
85 ret = device_register(&device->dev);
86 if (ret) {
87 dev_err(parent, "Cannot register %s: %d\n", name, ret);
88 put_device(&device->dev);
89 return NULL;
90 }
91
92 return device;
93 }
94
vchiq_device_unregister(struct vchiq_device * vchiq_dev)95 void vchiq_device_unregister(struct vchiq_device *vchiq_dev)
96 {
97 device_unregister(&vchiq_dev->dev);
98 }
99
vchiq_driver_register(struct vchiq_driver * vchiq_drv)100 int vchiq_driver_register(struct vchiq_driver *vchiq_drv)
101 {
102 vchiq_drv->driver.bus = &vchiq_bus_type;
103
104 return driver_register(&vchiq_drv->driver);
105 }
106 EXPORT_SYMBOL_GPL(vchiq_driver_register);
107
vchiq_driver_unregister(struct vchiq_driver * vchiq_drv)108 void vchiq_driver_unregister(struct vchiq_driver *vchiq_drv)
109 {
110 driver_unregister(&vchiq_drv->driver);
111 }
112 EXPORT_SYMBOL_GPL(vchiq_driver_unregister);
113