mirror of https://github.com/torvalds/linux.git
iio: backend: add debugFs interface
This adds a basic debugfs interface for backends. Two new ops are being added: * debugfs_reg_access: Analogous to the core IIO one but for backend devices. * debugfs_print_chan_status: One useful usecase for this one 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. Signed-off-by: Nuno Sa <nuno.sa@analog.com> Link: https://patch.msgid.link/20240802-dev-iio-backend-add-debugfs-v2-2-4cb62852f0d0@analog.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
2256f37e24
commit
cdf01e0809
|
|
@ -0,0 +1,20 @@
|
|||
What: /sys/kernel/debug/iio/iio:deviceX/backendY/name
|
||||
KernelVersion: 6.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Name of Backend Y connected to device X.
|
||||
|
||||
What: /sys/kernel/debug/iio/iio:deviceX/backendY/direct_reg_access
|
||||
KernelVersion: 6.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Directly access the registers of backend Y. Typical usage is:
|
||||
|
||||
Reading address 0x50
|
||||
echo 0x50 > direct_reg_access
|
||||
cat direct_reg_access
|
||||
|
||||
Writing address 0x50
|
||||
echo 0x50 0x3 > direct_reg_access
|
||||
//readback address 0x50
|
||||
cat direct_reg_access
|
||||
|
|
@ -10894,6 +10894,7 @@ M: Nuno Sa <nuno.sa@analog.com>
|
|||
R: Olivier Moysan <olivier.moysan@foss.st.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/debugfs-iio-backend
|
||||
F: drivers/iio/industrialio-backend.c
|
||||
F: include/linux/iio/backend.h
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -53,6 +54,14 @@ struct iio_backend {
|
|||
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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -117,6 +126,138 @@ static DEFINE_MUTEX(iio_back_lock);
|
|||
__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;
|
||||
|
||||
rc = simple_write_to_buffer(buf, sizeof(buf), ppos, userbuf, count);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
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 (!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
|
||||
|
|
@ -577,6 +718,9 @@ struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name)
|
|||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (name)
|
||||
back->idx = index;
|
||||
|
||||
return back;
|
||||
}
|
||||
|
||||
|
|
@ -668,6 +812,7 @@ int devm_iio_backend_register(struct device *dev,
|
|||
return -ENOMEM;
|
||||
|
||||
back->ops = info->ops;
|
||||
back->name = info->name;
|
||||
back->owner = dev->driver->owner;
|
||||
back->dev = dev;
|
||||
back->priv = priv;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ enum iio_backend_data_source {
|
|||
IIO_BACKEND_DATA_SOURCE_MAX
|
||||
};
|
||||
|
||||
#define iio_backend_debugfs_ptr(ptr) PTR_IF(IS_ENABLED(CONFIG_DEBUG_FS), ptr)
|
||||
|
||||
/**
|
||||
* IIO_BACKEND_EX_INFO - Helper for an IIO extended channel attribute
|
||||
* @_name: Attribute name
|
||||
|
|
@ -81,6 +83,8 @@ enum iio_backend_sample_trigger {
|
|||
* @extend_chan_spec: Extend an IIO channel.
|
||||
* @ext_info_set: Extended info setter.
|
||||
* @ext_info_get: Extended info getter.
|
||||
* @debugfs_print_chan_status: Print channel status into a buffer.
|
||||
* @debugfs_reg_access: Read or write register value of backend.
|
||||
**/
|
||||
struct iio_backend_ops {
|
||||
int (*enable)(struct iio_backend *back);
|
||||
|
|
@ -113,6 +117,11 @@ struct iio_backend_ops {
|
|||
const char *buf, size_t len);
|
||||
int (*ext_info_get)(struct iio_backend *back, uintptr_t private,
|
||||
const struct iio_chan_spec *chan, char *buf);
|
||||
int (*debugfs_print_chan_status)(struct iio_backend *back,
|
||||
unsigned int chan, char *buf,
|
||||
size_t len);
|
||||
int (*debugfs_reg_access)(struct iio_backend *back, unsigned int reg,
|
||||
unsigned int writeval, unsigned int *readval);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -163,4 +172,9 @@ __devm_iio_backend_get_from_fwnode_lookup(struct device *dev,
|
|||
int devm_iio_backend_register(struct device *dev,
|
||||
const struct iio_backend_info *info, void *priv);
|
||||
|
||||
ssize_t iio_backend_debugfs_print_chan_status(struct iio_backend *back,
|
||||
unsigned int chan, char *buf,
|
||||
size_t len);
|
||||
void iio_backend_debugfs_add(struct iio_backend *back,
|
||||
struct iio_dev *indio_dev);
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue