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 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 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 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 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 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 * 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 95 void vchiq_device_unregister(struct vchiq_device *vchiq_dev) 96 { 97 device_unregister(&vchiq_dev->dev); 98 } 99 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 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