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