Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * System Control and Management Interface (SCMI) Message Protocol bus layer
  4 *
  5 * Copyright (C) 2018 ARM Ltd.
  6 */
  7
  8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  9
 10#include <linux/types.h>
 11#include <linux/module.h>
 12#include <linux/kernel.h>
 13#include <linux/slab.h>
 14#include <linux/device.h>
 15
 16#include "common.h"
 17
 18static DEFINE_IDA(scmi_bus_id);
 19static DEFINE_IDR(scmi_protocols);
 20static DEFINE_SPINLOCK(protocol_lock);
 21
 22static const struct scmi_device_id *
 23scmi_dev_match_id(struct scmi_device *scmi_dev, struct scmi_driver *scmi_drv)
 24{
 25	const struct scmi_device_id *id = scmi_drv->id_table;
 26
 27	if (!id)
 28		return NULL;
 29
 30	for (; id->protocol_id; id++)
 31		if (id->protocol_id == scmi_dev->protocol_id)
 32			return id;
 33
 34	return NULL;
 35}
 36
 37static int scmi_dev_match(struct device *dev, struct device_driver *drv)
 38{
 39	struct scmi_driver *scmi_drv = to_scmi_driver(drv);
 40	struct scmi_device *scmi_dev = to_scmi_dev(dev);
 41	const struct scmi_device_id *id;
 42
 43	id = scmi_dev_match_id(scmi_dev, scmi_drv);
 44	if (id)
 45		return 1;
 46
 47	return 0;
 48}
 49
 50static int scmi_protocol_init(int protocol_id, struct scmi_handle *handle)
 51{
 52	scmi_prot_init_fn_t fn = idr_find(&scmi_protocols, protocol_id);
 53
 54	if (unlikely(!fn))
 55		return -EINVAL;
 56	return fn(handle);
 57}
 58
 59static int scmi_dev_probe(struct device *dev)
 60{
 61	struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver);
 62	struct scmi_device *scmi_dev = to_scmi_dev(dev);
 63	const struct scmi_device_id *id;
 64	int ret;
 65
 66	id = scmi_dev_match_id(scmi_dev, scmi_drv);
 67	if (!id)
 68		return -ENODEV;
 69
 70	if (!scmi_dev->handle)
 71		return -EPROBE_DEFER;
 72
 73	ret = scmi_protocol_init(scmi_dev->protocol_id, scmi_dev->handle);
 74	if (ret)
 75		return ret;
 76
 77	return scmi_drv->probe(scmi_dev);
 78}
 79
 80static int scmi_dev_remove(struct device *dev)
 81{
 82	struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver);
 83	struct scmi_device *scmi_dev = to_scmi_dev(dev);
 84
 85	if (scmi_drv->remove)
 86		scmi_drv->remove(scmi_dev);
 87
 88	return 0;
 89}
 90
 91static struct bus_type scmi_bus_type = {
 92	.name =	"scmi_protocol",
 93	.match = scmi_dev_match,
 94	.probe = scmi_dev_probe,
 95	.remove = scmi_dev_remove,
 96};
 97
 98int scmi_driver_register(struct scmi_driver *driver, struct module *owner,
 99			 const char *mod_name)
100{
101	int retval;
102
103	driver->driver.bus = &scmi_bus_type;
104	driver->driver.name = driver->name;
105	driver->driver.owner = owner;
106	driver->driver.mod_name = mod_name;
107
108	retval = driver_register(&driver->driver);
109	if (!retval)
110		pr_debug("registered new scmi driver %s\n", driver->name);
111
112	return retval;
113}
114EXPORT_SYMBOL_GPL(scmi_driver_register);
115
116void scmi_driver_unregister(struct scmi_driver *driver)
117{
118	driver_unregister(&driver->driver);
119}
120EXPORT_SYMBOL_GPL(scmi_driver_unregister);
121
122static void scmi_device_release(struct device *dev)
123{
124	kfree(to_scmi_dev(dev));
125}
126
127struct scmi_device *
128scmi_device_create(struct device_node *np, struct device *parent, int protocol)
129{
130	int id, retval;
131	struct scmi_device *scmi_dev;
132
133	scmi_dev = kzalloc(sizeof(*scmi_dev), GFP_KERNEL);
134	if (!scmi_dev)
135		return NULL;
136
137	id = ida_simple_get(&scmi_bus_id, 1, 0, GFP_KERNEL);
138	if (id < 0)
139		goto free_mem;
140
141	scmi_dev->id = id;
142	scmi_dev->protocol_id = protocol;
143	scmi_dev->dev.parent = parent;
144	scmi_dev->dev.of_node = np;
145	scmi_dev->dev.bus = &scmi_bus_type;
146	scmi_dev->dev.release = scmi_device_release;
147	dev_set_name(&scmi_dev->dev, "scmi_dev.%d", id);
148
149	retval = device_register(&scmi_dev->dev);
150	if (retval)
151		goto put_dev;
152
153	return scmi_dev;
154put_dev:
155	put_device(&scmi_dev->dev);
156	ida_simple_remove(&scmi_bus_id, id);
157free_mem:
158	kfree(scmi_dev);
159	return NULL;
160}
161
162void scmi_device_destroy(struct scmi_device *scmi_dev)
163{
164	scmi_handle_put(scmi_dev->handle);
165	ida_simple_remove(&scmi_bus_id, scmi_dev->id);
166	device_unregister(&scmi_dev->dev);
167}
168
169void scmi_set_handle(struct scmi_device *scmi_dev)
170{
171	scmi_dev->handle = scmi_handle_get(&scmi_dev->dev);
172}
173
174int scmi_protocol_register(int protocol_id, scmi_prot_init_fn_t fn)
175{
176	int ret;
177
178	spin_lock(&protocol_lock);
179	ret = idr_alloc(&scmi_protocols, fn, protocol_id, protocol_id + 1,
180			GFP_ATOMIC);
181	spin_unlock(&protocol_lock);
182	if (ret != protocol_id)
183		pr_err("unable to allocate SCMI idr slot, err %d\n", ret);
184
185	return ret;
186}
187EXPORT_SYMBOL_GPL(scmi_protocol_register);
188
189void scmi_protocol_unregister(int protocol_id)
190{
191	spin_lock(&protocol_lock);
192	idr_remove(&scmi_protocols, protocol_id);
193	spin_unlock(&protocol_lock);
194}
195EXPORT_SYMBOL_GPL(scmi_protocol_unregister);
196
197static int __scmi_devices_unregister(struct device *dev, void *data)
198{
199	struct scmi_device *scmi_dev = to_scmi_dev(dev);
200
201	scmi_device_destroy(scmi_dev);
202	return 0;
203}
204
205static void scmi_devices_unregister(void)
206{
207	bus_for_each_dev(&scmi_bus_type, NULL, NULL, __scmi_devices_unregister);
208}
209
210static int __init scmi_bus_init(void)
211{
212	int retval;
213
214	retval = bus_register(&scmi_bus_type);
215	if (retval)
216		pr_err("scmi protocol bus register failed (%d)\n", retval);
217
218	return retval;
219}
220subsys_initcall(scmi_bus_init);
221
222static void __exit scmi_bus_exit(void)
223{
224	scmi_devices_unregister();
225	bus_unregister(&scmi_bus_type);
226	ida_destroy(&scmi_bus_id);
227}
228module_exit(scmi_bus_exit);