aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c
blob: 68f830d7553108facd16a3c0e33827cc4e83c028 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// SPDX-License-Identifier: GPL-2.0
/*
 * vchiq_device.c - VCHIQ generic device and bus-type
 *
 * Copyright (c) 2023 Ideas On Board Oy
 */

#include <linux/device/bus.h>
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/string.h>

#include "vchiq_bus.h"

static int vchiq_bus_type_match(struct device *dev, struct device_driver *drv)
{
	if (dev->bus == &vchiq_bus_type &&
	    strcmp(dev_name(dev), drv->name) == 0)
		return true;

	return false;
}

static int vchiq_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
	const struct vchiq_device *device = container_of_const(dev, struct vchiq_device, dev);

	return add_uevent_var(env, "MODALIAS=vchiq:%s", dev_name(&device->dev));
}

static int vchiq_bus_probe(struct device *dev)
{
	struct vchiq_device *device = to_vchiq_device(dev);
	struct vchiq_driver *driver = to_vchiq_driver(dev->driver);

	return driver->probe(device);
}

const struct bus_type vchiq_bus_type = {
	.name   = "vchiq-bus",
	.match  = vchiq_bus_type_match,
	.uevent = vchiq_bus_uevent,
	.probe  = vchiq_bus_probe,
};

static void vchiq_device_release(struct device *dev)
{
	struct vchiq_device *device = to_vchiq_device(dev);

	kfree(device);
}

struct vchiq_device *
vchiq_device_register(struct device *parent, const char *name)
{
	struct vchiq_device *device;
	int ret;

	device = kzalloc(sizeof(*device), GFP_KERNEL);
	if (!device)
		return NULL;

	device->dev.init_name = name;
	device->dev.parent = parent;
	device->dev.bus = &vchiq_bus_type;
	device->dev.dma_mask = &device->dev.coherent_dma_mask;
	device->dev.release = vchiq_device_release;

	of_dma_configure(&device->dev, parent->of_node, true);

	ret = device_register(&device->dev);
	if (ret) {
		dev_err(parent, "Cannot register %s: %d\n", name, ret);
		put_device(&device->dev);
		return NULL;
	}

	return device;
}

void vchiq_device_unregister(struct vchiq_device *vchiq_dev)
{
	device_unregister(&vchiq_dev->dev);
}

int vchiq_driver_register(struct vchiq_driver *vchiq_drv)
{
	vchiq_drv->driver.bus = &vchiq_bus_type;

	return driver_register(&vchiq_drv->driver);
}
EXPORT_SYMBOL_GPL(vchiq_driver_register);

void vchiq_driver_unregister(struct vchiq_driver *vchiq_drv)
{
	driver_unregister(&vchiq_drv->driver);
}
EXPORT_SYMBOL_GPL(vchiq_driver_unregister);