[RFC v2 01/11] iio: introduce iio backend device

From: Olivier Moysan
Date: Thu Jul 27 2023 - 11:04:06 EST


Add a new device type in IIO framework.
This backend device does not compute channel attributes and does not expose
them through sysfs, as done typically in iio-rescale frontend device.
Instead, it allows to report information applying to channel
attributes through callbacks. These backend devices can be cascaded
to represent chained components.
An IIO device configured as a consumer of a backend device can compute
the channel attributes of the whole chain.

Signed-off-by: Olivier Moysan <olivier.moysan@xxxxxxxxxxx>
---
drivers/iio/Makefile | 1 +
drivers/iio/industrialio-backend.c | 107 +++++++++++++++++++++++++++++
include/linux/iio/backend.h | 56 +++++++++++++++
3 files changed, 164 insertions(+)
create mode 100644 drivers/iio/industrialio-backend.c
create mode 100644 include/linux/iio/backend.h

diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 9622347a1c1b..9b59c6ab1738 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -5,6 +5,7 @@

obj-$(CONFIG_IIO) += industrialio.o
industrialio-y := industrialio-core.o industrialio-event.o inkern.o
+industrialio-$(CONFIG_IIO_BACKEND) += industrialio-backend.o
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o

diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c
new file mode 100644
index 000000000000..7d0625889873
--- /dev/null
+++ b/drivers/iio/industrialio-backend.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0
+/* The industrial I/O core, backend handling functions
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/property.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/backend.h>
+
+static DEFINE_IDA(iio_backend_ida);
+
+#define to_iio_backend(_device) container_of((_device), struct iio_backend, dev)
+
+static void iio_backend_release(struct device *device)
+{
+ struct iio_backend *backend = to_iio_backend(device);
+
+ kfree(backend->name);
+ kfree(backend);
+}
+
+static const struct device_type iio_backend_type = {
+ .release = iio_backend_release,
+ .name = "iio_backend_device",
+};
+
+struct iio_backend *iio_backend_alloc(struct device *parent)
+{
+ struct iio_backend *backend;
+
+ backend = devm_kzalloc(parent, sizeof(*backend), GFP_KERNEL);
+
+ backend->dev.parent = parent;
+ backend->dev.type = &iio_backend_type;
+ backend->dev.bus = &iio_bus_type;
+ device_initialize(&backend->dev);
+
+ return backend;
+};
+EXPORT_SYMBOL(iio_backend_alloc);
+
+void iio_backend_free(struct device *dev)
+{
+ if (dev)
+ put_device(dev);
+}
+EXPORT_SYMBOL(iio_backend_free);
+
+int iio_backend_register(struct iio_backend *backend)
+{
+ struct fwnode_handle *fwnode;
+ int id;
+
+ id = ida_alloc(&iio_backend_ida, GFP_KERNEL);
+ if (id < 0)
+ return id;
+ backend->id = id;
+
+ dev_set_name(&backend->dev, "backend%d", backend->id);
+
+ if (dev_fwnode(&backend->dev))
+ fwnode = dev_fwnode(&backend->dev);
+ else
+ fwnode = dev_fwnode(backend->dev.parent);
+ device_set_node(&backend->dev, fwnode);
+
+ return device_add(&backend->dev);
+};
+EXPORT_SYMBOL(iio_backend_register);
+
+void iio_backend_unregister(struct iio_backend *backend)
+{
+ device_del(&backend->dev);
+};
+EXPORT_SYMBOL(iio_backend_unregister);
+
+struct iio_backend *fwnode_iio_backend_get(struct fwnode_handle *fwnode, int index)
+{
+ struct iio_backend *backend;
+ struct fwnode_reference_args iiospec;
+ struct device *bdev;
+ int ret;
+
+ if (index < 0)
+ return ERR_PTR(-EINVAL);
+
+ ret = fwnode_property_get_reference_args(fwnode, "io-backends",
+ "#io-backend-cells", 0,
+ index, &iiospec);
+ if (ret)
+ return ERR_PTR(ret);
+
+ bdev = bus_find_device_by_fwnode(&iio_bus_type, iiospec.fwnode);
+ if (!bdev) {
+ fwnode_handle_put(iiospec.fwnode);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ backend = to_iio_backend(bdev);
+
+ fwnode_handle_put(iiospec.fwnode);
+
+ return backend;
+};
+EXPORT_SYMBOL(fwnode_iio_backend_get);
diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h
new file mode 100644
index 000000000000..d90d345a4625
--- /dev/null
+++ b/include/linux/iio/backend.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * The industrial I/O core, backend handling functions
+ *
+ * Author: Olivier Moysan <olivier.moysan@xxxxxxxxxxx>.
+ */
+
+#ifndef _IIO_BACKEND_H_
+#define _IIO_BACKEND_H_
+#include <linux/iio/iio.h>
+
+struct iio_backend_ops;
+struct iio_backend;
+
+/**
+ * struct iio_backend_ops - operations structure for an iio_backend
+ * @enable: switch on backend
+ * @disable: switch off backend
+ * @read_raw: read data from backend
+ **/
+struct iio_backend_ops {
+ int (*enable)(struct iio_backend *backend);
+ int (*disable)(struct iio_backend *backend);
+ int (*read_raw)(struct iio_backend *backend, int *val, int *val2, long mask);
+};
+
+/**
+ * truct iio_backend - industrial I/O backend device
+ * @ops: operations structure
+ * @module: owner of this driver module
+ * @id: unique id number
+ * @name: unique name
+ * @dev: associated device
+ * @priv: private data pointer
+ **/
+struct iio_backend {
+ const struct iio_backend_ops *ops;
+ struct module *owner;
+ int id;
+ const char *name;
+ struct device dev;
+ struct list_head list;
+ void *priv;
+};
+
+struct iio_backend *iio_backend_alloc(struct device *parent);
+
+void iio_backend_free(struct device *dev);
+
+int iio_backend_register(struct iio_backend *backend);
+
+void iio_backend_unregister(struct iio_backend *backend);
+
+struct iio_backend *fwnode_iio_backend_get(struct fwnode_handle *fwnode, int index);
+
+#endif /* _IIO_BACKEND_H_ */
--
2.25.1