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_bus.h"
15 
vchiq_bus_type_match(struct device * dev,struct device_driver * drv)16 static int vchiq_bus_type_match(struct device *dev, struct device_driver *drv)
17 {
18 	if (dev->bus == &vchiq_bus_type &&
19 	    strcmp(dev_name(dev), drv->name) == 0)
20 		return true;
21 
22 	return false;
23 }
24 
vchiq_bus_uevent(const struct device * dev,struct kobj_uevent_env * env)25 static int vchiq_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
26 {
27 	const struct vchiq_device *device = container_of_const(dev, struct vchiq_device, dev);
28 
29 	return add_uevent_var(env, "MODALIAS=vchiq:%s", dev_name(&device->dev));
30 }
31 
vchiq_bus_probe(struct device * dev)32 static int vchiq_bus_probe(struct device *dev)
33 {
34 	struct vchiq_device *device = to_vchiq_device(dev);
35 	struct vchiq_driver *driver = to_vchiq_driver(dev->driver);
36 
37 	return driver->probe(device);
38 }
39 
40 struct bus_type vchiq_bus_type = {
41 	.name   = "vchiq-bus",
42 	.match  = vchiq_bus_type_match,
43 	.uevent = vchiq_bus_uevent,
44 	.probe  = vchiq_bus_probe,
45 };
46 
vchiq_device_release(struct device * dev)47 static void vchiq_device_release(struct device *dev)
48 {
49 	struct vchiq_device *device = to_vchiq_device(dev);
50 
51 	kfree(device);
52 }
53 
54 struct vchiq_device *
vchiq_device_register(struct device * parent,const char * name)55 vchiq_device_register(struct device *parent, const char *name)
56 {
57 	struct vchiq_device *device;
58 	int ret;
59 
60 	device = kzalloc(sizeof(*device), GFP_KERNEL);
61 	if (!device)
62 		return NULL;
63 
64 	device->dev.init_name = name;
65 	device->dev.parent = parent;
66 	device->dev.bus = &vchiq_bus_type;
67 	device->dev.dma_mask = &device->dev.coherent_dma_mask;
68 	device->dev.release = vchiq_device_release;
69 
70 	of_dma_configure(&device->dev, parent->of_node, true);
71 
72 	ret = device_register(&device->dev);
73 	if (ret) {
74 		dev_err(parent, "Cannot register %s: %d\n", name, ret);
75 		put_device(&device->dev);
76 		return NULL;
77 	}
78 
79 	return device;
80 }
81 
vchiq_device_unregister(struct vchiq_device * vchiq_dev)82 void vchiq_device_unregister(struct vchiq_device *vchiq_dev)
83 {
84 	device_unregister(&vchiq_dev->dev);
85 }
86 
vchiq_driver_register(struct vchiq_driver * vchiq_drv)87 int vchiq_driver_register(struct vchiq_driver *vchiq_drv)
88 {
89 	vchiq_drv->driver.bus = &vchiq_bus_type;
90 
91 	return driver_register(&vchiq_drv->driver);
92 }
93 EXPORT_SYMBOL_GPL(vchiq_driver_register);
94 
vchiq_driver_unregister(struct vchiq_driver * vchiq_drv)95 void vchiq_driver_unregister(struct vchiq_driver *vchiq_drv)
96 {
97 	driver_unregister(&vchiq_drv->driver);
98 }
99 EXPORT_SYMBOL_GPL(vchiq_driver_unregister);
100