Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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 <linux/raspberrypi/vchiq_arm.h>
15#include <linux/raspberrypi/vchiq_bus.h>
16
17static 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
26static 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
33static 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
41static 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
50const 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
58static void vchiq_device_release(struct device *dev)
59{
60 struct vchiq_device *device = to_vchiq_device(dev);
61
62 kfree(device);
63}
64
65struct vchiq_device *
66vchiq_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
95void vchiq_device_unregister(struct vchiq_device *vchiq_dev)
96{
97 device_unregister(&vchiq_dev->dev);
98}
99
100int 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}
106EXPORT_SYMBOL_GPL(vchiq_driver_register);
107
108void vchiq_driver_unregister(struct vchiq_driver *vchiq_drv)
109{
110 driver_unregister(&vchiq_drv->driver);
111}
112EXPORT_SYMBOL_GPL(vchiq_driver_unregister);