summaryrefslogtreecommitdiff
path: root/drivers/iio/industrialio-backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/industrialio-backend.c')
-rw-r--r--drivers/iio/industrialio-backend.c744
1 files changed, 696 insertions, 48 deletions
diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c
index 2fea2bbbe47f..266e1b29bf91 100644
--- a/drivers/iio/industrialio-backend.c
+++ b/drivers/iio/industrialio-backend.c
@@ -32,6 +32,7 @@
#define dev_fmt(fmt) "iio-backend: " fmt
#include <linux/cleanup.h>
+#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
@@ -40,16 +41,27 @@
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/slab.h>
+#include <linux/stringify.h>
#include <linux/types.h>
#include <linux/iio/backend.h>
+#include <linux/iio/iio.h>
struct iio_backend {
struct list_head entry;
const struct iio_backend_ops *ops;
+ struct device *frontend_dev;
struct device *dev;
struct module *owner;
void *priv;
+ const char *name;
+ unsigned int cached_reg_addr;
+ /*
+ * This index is relative to the frontend. Meaning that for
+ * frontends with multiple backends, this will be the index of this
+ * backend. Used for the debugfs directory name.
+ */
+ u8 idx;
};
/*
@@ -109,12 +121,152 @@ static DEFINE_MUTEX(iio_back_lock);
__ret = iio_backend_check_op(__back, op); \
if (!__ret) \
__back->ops->op(__back, ##args); \
+ else \
+ dev_dbg(__back->dev, "Op(%s) not implemented\n",\
+ __stringify(op)); \
+}
+
+static ssize_t iio_backend_debugfs_read_reg(struct file *file,
+ char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct iio_backend *back = file->private_data;
+ char read_buf[20];
+ unsigned int val;
+ int ret, len;
+
+ ret = iio_backend_op_call(back, debugfs_reg_access,
+ back->cached_reg_addr, 0, &val);
+ if (ret)
+ return ret;
+
+ len = scnprintf(read_buf, sizeof(read_buf), "0x%X\n", val);
+
+ return simple_read_from_buffer(userbuf, count, ppos, read_buf, len);
+}
+
+static ssize_t iio_backend_debugfs_write_reg(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct iio_backend *back = file->private_data;
+ unsigned int val;
+ char buf[80];
+ ssize_t rc;
+ int ret;
+
+ if (count >= sizeof(buf))
+ return -ENOSPC;
+
+ rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf, count);
+ if (rc < 0)
+ return rc;
+
+ buf[rc] = '\0';
+
+ ret = sscanf(buf, "%i %i", &back->cached_reg_addr, &val);
+
+ switch (ret) {
+ case 1:
+ return count;
+ case 2:
+ ret = iio_backend_op_call(back, debugfs_reg_access,
+ back->cached_reg_addr, val, NULL);
+ if (ret)
+ return ret;
+ return count;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct file_operations iio_backend_debugfs_reg_fops = {
+ .open = simple_open,
+ .read = iio_backend_debugfs_read_reg,
+ .write = iio_backend_debugfs_write_reg,
+};
+
+static ssize_t iio_backend_debugfs_read_name(struct file *file,
+ char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct iio_backend *back = file->private_data;
+ char name[128];
+ int len;
+
+ len = scnprintf(name, sizeof(name), "%s\n", back->name);
+
+ return simple_read_from_buffer(userbuf, count, ppos, name, len);
+}
+
+static const struct file_operations iio_backend_debugfs_name_fops = {
+ .open = simple_open,
+ .read = iio_backend_debugfs_read_name,
+};
+
+/**
+ * iio_backend_debugfs_add - Add debugfs interfaces for Backends
+ * @back: Backend device
+ * @indio_dev: IIO device
+ */
+void iio_backend_debugfs_add(struct iio_backend *back,
+ struct iio_dev *indio_dev)
+{
+ struct dentry *d = iio_get_debugfs_dentry(indio_dev);
+ struct dentry *back_d;
+ char name[128];
+
+ if (!IS_ENABLED(CONFIG_DEBUG_FS) || !d)
+ return;
+ if (!back->ops->debugfs_reg_access && !back->name)
+ return;
+
+ snprintf(name, sizeof(name), "backend%d", back->idx);
+
+ back_d = debugfs_create_dir(name, d);
+ if (IS_ERR(back_d))
+ return;
+
+ if (back->ops->debugfs_reg_access)
+ debugfs_create_file("direct_reg_access", 0600, back_d, back,
+ &iio_backend_debugfs_reg_fops);
+
+ if (back->name)
+ debugfs_create_file("name", 0400, back_d, back,
+ &iio_backend_debugfs_name_fops);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_debugfs_add, "IIO_BACKEND");
+
+/**
+ * iio_backend_debugfs_print_chan_status - Print channel status
+ * @back: Backend device
+ * @chan: Channel number
+ * @buf: Buffer where to print the status
+ * @len: Available space
+ *
+ * One usecase where this is useful is for testing test tones in a digital
+ * interface and "ask" the backend to dump more details on why a test tone might
+ * have errors.
+ *
+ * RETURNS:
+ * Number of copied bytes on success, negative error code on failure.
+ */
+ssize_t iio_backend_debugfs_print_chan_status(struct iio_backend *back,
+ unsigned int chan, char *buf,
+ size_t len)
+{
+ if (!IS_ENABLED(CONFIG_DEBUG_FS))
+ return -ENODEV;
+
+ return iio_backend_op_call(back, debugfs_print_chan_status, chan, buf,
+ len);
}
+EXPORT_SYMBOL_NS_GPL(iio_backend_debugfs_print_chan_status, "IIO_BACKEND");
/**
* iio_backend_chan_enable - Enable a backend channel
- * @back: Backend device
- * @chan: Channel number
+ * @back: Backend device
+ * @chan: Channel number
*
* RETURNS:
* 0 on success, negative error number on failure.
@@ -123,12 +275,12 @@ int iio_backend_chan_enable(struct iio_backend *back, unsigned int chan)
{
return iio_backend_op_call(back, chan_enable, chan);
}
-EXPORT_SYMBOL_NS_GPL(iio_backend_chan_enable, IIO_BACKEND);
+EXPORT_SYMBOL_NS_GPL(iio_backend_chan_enable, "IIO_BACKEND");
/**
* iio_backend_chan_disable - Disable a backend channel
- * @back: Backend device
- * @chan: Channel number
+ * @back: Backend device
+ * @chan: Channel number
*
* RETURNS:
* 0 on success, negative error number on failure.
@@ -137,7 +289,7 @@ int iio_backend_chan_disable(struct iio_backend *back, unsigned int chan)
{
return iio_backend_op_call(back, chan_disable, chan);
}
-EXPORT_SYMBOL_NS_GPL(iio_backend_chan_disable, IIO_BACKEND);
+EXPORT_SYMBOL_NS_GPL(iio_backend_chan_disable, "IIO_BACKEND");
static void __iio_backend_disable(void *back)
{
@@ -145,9 +297,32 @@ static void __iio_backend_disable(void *back)
}
/**
+ * iio_backend_disable - Backend disable
+ * @back: Backend device
+ */
+void iio_backend_disable(struct iio_backend *back)
+{
+ __iio_backend_disable(back);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_disable, "IIO_BACKEND");
+
+/**
+ * iio_backend_enable - Backend enable
+ * @back: Backend device
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_enable(struct iio_backend *back)
+{
+ return iio_backend_op_call(back, enable);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_enable, "IIO_BACKEND");
+
+/**
* devm_iio_backend_enable - Device managed backend enable
- * @dev: Consumer device for the backend
- * @back: Backend device
+ * @dev: Consumer device for the backend
+ * @back: Backend device
*
* RETURNS:
* 0 on success, negative error number on failure.
@@ -156,19 +331,19 @@ int devm_iio_backend_enable(struct device *dev, struct iio_backend *back)
{
int ret;
- ret = iio_backend_op_call(back, enable);
+ ret = iio_backend_enable(back);
if (ret)
return ret;
return devm_add_action_or_reset(dev, __iio_backend_disable, back);
}
-EXPORT_SYMBOL_NS_GPL(devm_iio_backend_enable, IIO_BACKEND);
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_enable, "IIO_BACKEND");
/**
* iio_backend_data_format_set - Configure the channel data format
- * @back: Backend device
- * @chan: Channel number
- * @data: Data format
+ * @back: Backend device
+ * @chan: Channel number
+ * @data: Data format
*
* Properly configure a channel with respect to the expected data format. A
* @struct iio_backend_data_fmt must be passed with the settings.
@@ -184,7 +359,159 @@ int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan,
return iio_backend_op_call(back, data_format_set, chan, data);
}
-EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, IIO_BACKEND);
+EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, "IIO_BACKEND");
+
+/**
+ * iio_backend_data_source_set - Select data source
+ * @back: Backend device
+ * @chan: Channel number
+ * @data: Data source
+ *
+ * A given backend may have different sources to stream/sync data. This allows
+ * to choose that source.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_data_source_set(struct iio_backend *back, unsigned int chan,
+ enum iio_backend_data_source data)
+{
+ if (data >= IIO_BACKEND_DATA_SOURCE_MAX)
+ return -EINVAL;
+
+ return iio_backend_op_call(back, data_source_set, chan, data);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_data_source_set, "IIO_BACKEND");
+
+/**
+ * iio_backend_data_source_get - Get current data source
+ * @back: Backend device
+ * @chan: Channel number
+ * @data: Pointer to receive the current source value
+ *
+ * A given backend may have different sources to stream/sync data. This allows
+ * to know what source is in use.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_data_source_get(struct iio_backend *back, unsigned int chan,
+ enum iio_backend_data_source *data)
+{
+ int ret;
+
+ ret = iio_backend_op_call(back, data_source_get, chan, data);
+ if (ret)
+ return ret;
+
+ if (*data >= IIO_BACKEND_DATA_SOURCE_MAX)
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_data_source_get, "IIO_BACKEND");
+
+/**
+ * iio_backend_set_sampling_freq - Set channel sampling rate
+ * @back: Backend device
+ * @chan: Channel number
+ * @sample_rate_hz: Sample rate
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_set_sampling_freq(struct iio_backend *back, unsigned int chan,
+ u64 sample_rate_hz)
+{
+ return iio_backend_op_call(back, set_sample_rate, chan, sample_rate_hz);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_set_sampling_freq, "IIO_BACKEND");
+
+/**
+ * iio_backend_test_pattern_set - Configure a test pattern
+ * @back: Backend device
+ * @chan: Channel number
+ * @pattern: Test pattern
+ *
+ * Configure a test pattern on the backend. This is typically used for
+ * calibrating the timings on the data digital interface.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_test_pattern_set(struct iio_backend *back,
+ unsigned int chan,
+ enum iio_backend_test_pattern pattern)
+{
+ if (pattern >= IIO_BACKEND_TEST_PATTERN_MAX)
+ return -EINVAL;
+
+ return iio_backend_op_call(back, test_pattern_set, chan, pattern);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_test_pattern_set, "IIO_BACKEND");
+
+/**
+ * iio_backend_chan_status - Get the channel status
+ * @back: Backend device
+ * @chan: Channel number
+ * @error: Error indication
+ *
+ * Get the current state of the backend channel. Typically used to check if
+ * there were any errors sending/receiving data.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_chan_status(struct iio_backend *back, unsigned int chan,
+ bool *error)
+{
+ return iio_backend_op_call(back, chan_status, chan, error);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_chan_status, "IIO_BACKEND");
+
+/**
+ * iio_backend_iodelay_set - Set digital I/O delay
+ * @back: Backend device
+ * @lane: Lane number
+ * @taps: Number of taps
+ *
+ * Controls delays on sending/receiving data. One usecase for this is to
+ * calibrate the data digital interface so we get the best results when
+ * transferring data. Note that @taps has no unit since the actual delay per tap
+ * is very backend specific. Hence, frontend devices typically should go through
+ * an array of @taps (the size of that array should typically match the size of
+ * calibration points on the frontend device) and call this API.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_iodelay_set(struct iio_backend *back, unsigned int lane,
+ unsigned int taps)
+{
+ return iio_backend_op_call(back, iodelay_set, lane, taps);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_iodelay_set, "IIO_BACKEND");
+
+/**
+ * iio_backend_data_sample_trigger - Control when to sample data
+ * @back: Backend device
+ * @trigger: Data trigger
+ *
+ * Mostly useful for input backends. Configures the backend for when to sample
+ * data (eg: rising vs falling edge).
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_data_sample_trigger(struct iio_backend *back,
+ enum iio_backend_sample_trigger trigger)
+{
+ if (trigger >= IIO_BACKEND_SAMPLE_TRIGGER_MAX)
+ return -EINVAL;
+
+ return iio_backend_op_call(back, data_sample_trigger, trigger);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_data_sample_trigger, "IIO_BACKEND");
static void iio_backend_free_buffer(void *arg)
{
@@ -195,9 +522,9 @@ static void iio_backend_free_buffer(void *arg)
/**
* devm_iio_backend_request_buffer - Device managed buffer request
- * @dev: Consumer device for the backend
- * @back: Backend device
- * @indio_dev: IIO device
+ * @dev: Consumer device for the backend
+ * @back: Backend device
+ * @indio_dev: IIO device
*
* Request an IIO buffer from the backend. The type of the buffer (typically
* INDIO_BUFFER_HARDWARE) is up to the backend to decide. This is because,
@@ -229,7 +556,221 @@ int devm_iio_backend_request_buffer(struct device *dev,
return devm_add_action_or_reset(dev, iio_backend_free_buffer, pair);
}
-EXPORT_SYMBOL_NS_GPL(devm_iio_backend_request_buffer, IIO_BACKEND);
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_request_buffer, "IIO_BACKEND");
+
+/**
+ * iio_backend_read_raw - Read a channel attribute from a backend device.
+ * @back: Backend device
+ * @chan: IIO channel reference
+ * @val: First returned value
+ * @val2: Second returned value
+ * @mask: Specify the attribute to return
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_read_raw(struct iio_backend *back,
+ struct iio_chan_spec const *chan, int *val, int *val2,
+ long mask)
+{
+ return iio_backend_op_call(back, read_raw, chan, val, val2, mask);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_read_raw, "IIO_BACKEND");
+
+static struct iio_backend *iio_backend_from_indio_dev_parent(const struct device *dev)
+{
+ struct iio_backend *back = ERR_PTR(-ENODEV), *iter;
+
+ /*
+ * We deliberately go through all backends even after finding a match.
+ * The reason is that we want to catch frontend devices which have more
+ * than one backend in which case returning the first we find is bogus.
+ * For those cases, frontends need to explicitly define
+ * get_iio_backend() in struct iio_info.
+ */
+ guard(mutex)(&iio_back_lock);
+ list_for_each_entry(iter, &iio_back_list, entry) {
+ if (dev == iter->frontend_dev) {
+ if (!IS_ERR(back)) {
+ dev_warn(dev,
+ "Multiple backends! get_iio_backend() needs to be implemented");
+ return ERR_PTR(-ENODEV);
+ }
+
+ back = iter;
+ }
+ }
+
+ return back;
+}
+
+/**
+ * iio_backend_ext_info_get - IIO ext_info read callback
+ * @indio_dev: IIO device
+ * @private: Data private to the driver
+ * @chan: IIO channel
+ * @buf: Buffer where to place the attribute data
+ *
+ * This helper is intended to be used by backends that extend an IIO channel
+ * (through iio_backend_extend_chan_spec()) with extended info. In that case,
+ * backends are not supposed to give their own callbacks (as they would not have
+ * a way to get the backend from indio_dev). This is the getter.
+ *
+ * RETURNS:
+ * Number of bytes written to buf, negative error number on failure.
+ */
+ssize_t iio_backend_ext_info_get(struct iio_dev *indio_dev, uintptr_t private,
+ const struct iio_chan_spec *chan, char *buf)
+{
+ struct iio_backend *back;
+
+ /*
+ * The below should work for the majority of the cases. It will not work
+ * when one frontend has multiple backends in which case we'll need a
+ * new callback in struct iio_info so we can directly request the proper
+ * backend from the frontend. Anyways, let's only introduce new options
+ * when really needed...
+ */
+ back = iio_backend_from_indio_dev_parent(indio_dev->dev.parent);
+ if (IS_ERR(back))
+ return PTR_ERR(back);
+
+ return iio_backend_op_call(back, ext_info_get, private, chan, buf);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_get, "IIO_BACKEND");
+
+/**
+ * iio_backend_ext_info_set - IIO ext_info write callback
+ * @indio_dev: IIO device
+ * @private: Data private to the driver
+ * @chan: IIO channel
+ * @buf: Buffer holding the sysfs attribute
+ * @len: Buffer length
+ *
+ * This helper is intended to be used by backends that extend an IIO channel
+ * (trough iio_backend_extend_chan_spec()) with extended info. In that case,
+ * backends are not supposed to give their own callbacks (as they would not have
+ * a way to get the backend from indio_dev). This is the setter.
+ *
+ * RETURNS:
+ * Buffer length on success, negative error number on failure.
+ */
+ssize_t iio_backend_ext_info_set(struct iio_dev *indio_dev, uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct iio_backend *back;
+
+ back = iio_backend_from_indio_dev_parent(indio_dev->dev.parent);
+ if (IS_ERR(back))
+ return PTR_ERR(back);
+
+ return iio_backend_op_call(back, ext_info_set, private, chan, buf, len);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_set, "IIO_BACKEND");
+
+/**
+ * iio_backend_interface_type_get - get the interface type used.
+ * @back: Backend device
+ * @type: Interface type
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_interface_type_get(struct iio_backend *back,
+ enum iio_backend_interface_type *type)
+{
+ int ret;
+
+ ret = iio_backend_op_call(back, interface_type_get, type);
+ if (ret)
+ return ret;
+
+ if (*type >= IIO_BACKEND_INTERFACE_MAX)
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_interface_type_get, "IIO_BACKEND");
+
+/**
+ * iio_backend_data_size_set - set the data width/size in the data bus.
+ * @back: Backend device
+ * @size: Size in bits
+ *
+ * Some frontend devices can dynamically control the word/data size on the
+ * interface/data bus. Hence, the backend device needs to be aware of it so
+ * data can be correctly transferred.
+ *
+ * Return:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_data_size_set(struct iio_backend *back, unsigned int size)
+{
+ if (!size)
+ return -EINVAL;
+
+ return iio_backend_op_call(back, data_size_set, size);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_data_size_set, "IIO_BACKEND");
+
+/**
+ * iio_backend_oversampling_ratio_set - set the oversampling ratio
+ * @back: Backend device
+ * @ratio: The oversampling ratio - value 1 corresponds to no oversampling.
+ *
+ * Return:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_oversampling_ratio_set(struct iio_backend *back,
+ unsigned int ratio)
+{
+ return iio_backend_op_call(back, oversampling_ratio_set, ratio);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_oversampling_ratio_set, "IIO_BACKEND");
+
+/**
+ * iio_backend_extend_chan_spec - Extend an IIO channel
+ * @back: Backend device
+ * @chan: IIO channel
+ *
+ * Some backends may have their own functionalities and hence capable of
+ * extending a frontend's channel.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_extend_chan_spec(struct iio_backend *back,
+ struct iio_chan_spec *chan)
+{
+ const struct iio_chan_spec_ext_info *frontend_ext_info = chan->ext_info;
+ const struct iio_chan_spec_ext_info *back_ext_info;
+ int ret;
+
+ ret = iio_backend_op_call(back, extend_chan_spec, chan);
+ if (ret)
+ return ret;
+ /*
+ * Let's keep things simple for now. Don't allow to overwrite the
+ * frontend's extended info. If ever needed, we can support appending
+ * it.
+ */
+ if (frontend_ext_info && chan->ext_info != frontend_ext_info)
+ return -EOPNOTSUPP;
+ if (!chan->ext_info)
+ return 0;
+
+ /* Don't allow backends to get creative and force their own handlers */
+ for (back_ext_info = chan->ext_info; back_ext_info->name; back_ext_info++) {
+ if (back_ext_info->read != iio_backend_ext_info_get)
+ return -EINVAL;
+ if (back_ext_info->write != iio_backend_ext_info_set)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_extend_chan_spec, "IIO_BACKEND");
static void iio_backend_release(void *arg)
{
@@ -263,24 +804,95 @@ static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back)
"Could not link to supplier(%s)\n",
dev_name(back->dev));
+ back->frontend_dev = dev;
+
dev_dbg(dev, "Found backend(%s) device\n", dev_name(back->dev));
return 0;
}
/**
- * devm_iio_backend_get - Device managed backend device get
- * @dev: Consumer device for the backend
- * @name: Backend name
+ * iio_backend_ddr_enable - Enable interface DDR (Double Data Rate) mode
+ * @back: Backend device
*
- * Get's the backend associated with @dev.
+ * Enable DDR, data is generated by the IP at each front (raising and falling)
+ * of the bus clock signal.
*
* RETURNS:
- * A backend pointer, negative error pointer otherwise.
+ * 0 on success, negative error number on failure.
*/
-struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name)
+int iio_backend_ddr_enable(struct iio_backend *back)
{
- struct fwnode_handle *fwnode;
+ return iio_backend_op_call(back, ddr_enable);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_enable, "IIO_BACKEND");
+
+/**
+ * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate) mode
+ * @back: Backend device
+ *
+ * Disable DDR, setting into SDR mode (Single Data Rate).
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_ddr_disable(struct iio_backend *back)
+{
+ return iio_backend_op_call(back, ddr_disable);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, "IIO_BACKEND");
+
+/**
+ * iio_backend_data_stream_enable - Enable data stream
+ * @back: Backend device
+ *
+ * Enable data stream over the bus interface.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_data_stream_enable(struct iio_backend *back)
+{
+ return iio_backend_op_call(back, data_stream_enable);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_data_stream_enable, "IIO_BACKEND");
+
+/**
+ * iio_backend_data_stream_disable - Disable data stream
+ * @back: Backend device
+ *
+ * Disable data stream over the bus interface.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_data_stream_disable(struct iio_backend *back)
+{
+ return iio_backend_op_call(back, data_stream_disable);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_data_stream_disable, "IIO_BACKEND");
+
+/**
+ * iio_backend_data_transfer_addr - Set data address.
+ * @back: Backend device
+ * @address: Data register address
+ *
+ * Some devices may need to inform the backend about an address
+ * where to read or write the data.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_data_transfer_addr(struct iio_backend *back, u32 address)
+{
+ return iio_backend_op_call(back, data_transfer_addr, address);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_data_transfer_addr, "IIO_BACKEND");
+
+static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, const char *name,
+ struct fwnode_handle *fwnode)
+{
+ struct fwnode_handle *fwnode_back;
struct iio_backend *back;
unsigned int index;
int ret;
@@ -295,35 +907,70 @@ struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name)
index = 0;
}
- fwnode = fwnode_find_reference(dev_fwnode(dev), "io-backends", index);
- if (IS_ERR(fwnode)) {
- dev_err_probe(dev, PTR_ERR(fwnode),
- "Cannot get Firmware reference\n");
- return ERR_CAST(fwnode);
- }
+ fwnode_back = fwnode_find_reference(fwnode, "io-backends", index);
+ if (IS_ERR(fwnode_back))
+ return dev_err_cast_probe(dev, fwnode_back,
+ "Cannot get Firmware reference\n");
guard(mutex)(&iio_back_lock);
list_for_each_entry(back, &iio_back_list, entry) {
- if (!device_match_fwnode(back->dev, fwnode))
+ if (!device_match_fwnode(back->dev, fwnode_back))
continue;
- fwnode_handle_put(fwnode);
+ fwnode_handle_put(fwnode_back);
ret = __devm_iio_backend_get(dev, back);
if (ret)
return ERR_PTR(ret);
+ if (name)
+ back->idx = index;
+
return back;
}
- fwnode_handle_put(fwnode);
+ fwnode_handle_put(fwnode_back);
return ERR_PTR(-EPROBE_DEFER);
}
-EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, IIO_BACKEND);
+
+/**
+ * devm_iio_backend_get - Device managed backend device get
+ * @dev: Consumer device for the backend
+ * @name: Backend name
+ *
+ * Get's the backend associated with @dev.
+ *
+ * RETURNS:
+ * A backend pointer, negative error pointer otherwise.
+ */
+struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name)
+{
+ return __devm_iio_backend_fwnode_get(dev, name, dev_fwnode(dev));
+}
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, "IIO_BACKEND");
+
+/**
+ * devm_iio_backend_fwnode_get - Device managed backend firmware node get
+ * @dev: Consumer device for the backend
+ * @name: Backend name
+ * @fwnode: Firmware node of the backend consumer
+ *
+ * Get's the backend associated with a firmware node.
+ *
+ * RETURNS:
+ * A backend pointer, negative error pointer otherwise.
+ */
+struct iio_backend *devm_iio_backend_fwnode_get(struct device *dev,
+ const char *name,
+ struct fwnode_handle *fwnode)
+{
+ return __devm_iio_backend_fwnode_get(dev, name, fwnode);
+}
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_fwnode_get, "IIO_BACKEND");
/**
* __devm_iio_backend_get_from_fwnode_lookup - Device managed fwnode backend device get
- * @dev: Consumer device for the backend
- * @fwnode: Firmware node of the backend device
+ * @dev: Consumer device for the backend
+ * @fwnode: Firmware node of the backend device
*
* Search the backend list for a device matching @fwnode.
* This API should not be used and it's only present for preventing the first
@@ -353,17 +1000,17 @@ __devm_iio_backend_get_from_fwnode_lookup(struct device *dev,
return ERR_PTR(-EPROBE_DEFER);
}
-EXPORT_SYMBOL_NS_GPL(__devm_iio_backend_get_from_fwnode_lookup, IIO_BACKEND);
+EXPORT_SYMBOL_NS_GPL(__devm_iio_backend_get_from_fwnode_lookup, "IIO_BACKEND");
/**
* iio_backend_get_priv - Get driver private data
- * @back: Backend device
+ * @back: Backend device
*/
void *iio_backend_get_priv(const struct iio_backend *back)
{
return back->priv;
}
-EXPORT_SYMBOL_NS_GPL(iio_backend_get_priv, IIO_BACKEND);
+EXPORT_SYMBOL_NS_GPL(iio_backend_get_priv, "IIO_BACKEND");
static void iio_backend_unregister(void *arg)
{
@@ -375,21 +1022,21 @@ static void iio_backend_unregister(void *arg)
/**
* devm_iio_backend_register - Device managed backend device register
- * @dev: Backend device being registered
- * @ops: Backend ops
- * @priv: Device private data
+ * @dev: Backend device being registered
+ * @info: Backend info
+ * @priv: Device private data
*
- * @ops is mandatory. Not providing it results in -EINVAL.
+ * @info is mandatory. Not providing it results in -EINVAL.
*
* RETURNS:
* 0 on success, negative error number on failure.
*/
int devm_iio_backend_register(struct device *dev,
- const struct iio_backend_ops *ops, void *priv)
+ const struct iio_backend_info *info, void *priv)
{
struct iio_backend *back;
- if (!ops)
+ if (!info || !info->ops)
return dev_err_probe(dev, -EINVAL, "No backend ops given\n");
/*
@@ -402,7 +1049,8 @@ int devm_iio_backend_register(struct device *dev,
if (!back)
return -ENOMEM;
- back->ops = ops;
+ back->ops = info->ops;
+ back->name = info->name;
back->owner = dev->driver->owner;
back->dev = dev;
back->priv = priv;
@@ -411,7 +1059,7 @@ int devm_iio_backend_register(struct device *dev,
return devm_add_action_or_reset(dev, iio_backend_unregister, back);
}
-EXPORT_SYMBOL_NS_GPL(devm_iio_backend_register, IIO_BACKEND);
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_register, "IIO_BACKEND");
MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
MODULE_DESCRIPTION("Framework to handle complex IIO aggregate devices");