aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/industrialio-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/industrialio-core.c')
-rw-r--r--drivers/iio/industrialio-core.c198
1 files changed, 130 insertions, 68 deletions
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 7db761afa578..d92c58a94fe4 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -157,6 +157,7 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_PHASE] = "phase",
[IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain",
[IIO_CHAN_INFO_HYSTERESIS] = "hysteresis",
+ [IIO_CHAN_INFO_HYSTERESIS_RELATIVE] = "hysteresis_relative",
[IIO_CHAN_INFO_INT_TIME] = "integration_time",
[IIO_CHAN_INFO_ENABLE] = "en",
[IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight",
@@ -233,7 +234,7 @@ ssize_t iio_read_const_attr(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return sprintf(buf, "%s\n", to_iio_const_attr(attr)->string);
+ return sysfs_emit(buf, "%s\n", to_iio_const_attr(attr)->string);
}
EXPORT_SYMBOL(iio_read_const_attr);
@@ -503,7 +504,7 @@ ssize_t iio_enum_available_read(struct iio_dev *indio_dev,
for (i = 0; i < e->num_items; ++i) {
if (!e->items[i])
continue;
- len += scnprintf(buf + len, PAGE_SIZE - len, "%s ", e->items[i]);
+ len += sysfs_emit_at(buf, len, "%s ", e->items[i]);
}
/* replace last space with a newline */
@@ -528,7 +529,7 @@ ssize_t iio_enum_read(struct iio_dev *indio_dev,
else if (i >= e->num_items || !e->items[i])
return -EINVAL;
- return snprintf(buf, PAGE_SIZE, "%s\n", e->items[i]);
+ return sysfs_emit(buf, "%s\n", e->items[i]);
}
EXPORT_SYMBOL_GPL(iio_enum_read);
@@ -579,10 +580,10 @@ ssize_t iio_show_mount_matrix(struct iio_dev *indio_dev, uintptr_t priv,
if (!mtx)
mtx = &iio_mount_idmatrix;
- return snprintf(buf, PAGE_SIZE, "%s, %s, %s; %s, %s, %s; %s, %s, %s\n",
- mtx->rotation[0], mtx->rotation[1], mtx->rotation[2],
- mtx->rotation[3], mtx->rotation[4], mtx->rotation[5],
- mtx->rotation[6], mtx->rotation[7], mtx->rotation[8]);
+ return sysfs_emit(buf, "%s, %s, %s; %s, %s, %s; %s, %s, %s\n",
+ mtx->rotation[0], mtx->rotation[1], mtx->rotation[2],
+ mtx->rotation[3], mtx->rotation[4], mtx->rotation[5],
+ mtx->rotation[6], mtx->rotation[7], mtx->rotation[8]);
}
EXPORT_SYMBOL_GPL(iio_show_mount_matrix);
@@ -622,59 +623,62 @@ int iio_read_mount_matrix(struct device *dev, const char *propname,
}
EXPORT_SYMBOL(iio_read_mount_matrix);
-static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type,
+static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type,
int size, const int *vals)
{
- unsigned long long tmp;
int tmp0, tmp1;
s64 tmp2;
bool scale_db = false;
switch (type) {
case IIO_VAL_INT:
- return scnprintf(buf, len, "%d", vals[0]);
+ return sysfs_emit_at(buf, offset, "%d", vals[0]);
case IIO_VAL_INT_PLUS_MICRO_DB:
scale_db = true;
fallthrough;
case IIO_VAL_INT_PLUS_MICRO:
if (vals[1] < 0)
- return scnprintf(buf, len, "-%d.%06u%s", abs(vals[0]),
- -vals[1], scale_db ? " dB" : "");
+ return sysfs_emit_at(buf, offset, "-%d.%06u%s",
+ abs(vals[0]), -vals[1],
+ scale_db ? " dB" : "");
else
- return scnprintf(buf, len, "%d.%06u%s", vals[0], vals[1],
- scale_db ? " dB" : "");
+ return sysfs_emit_at(buf, offset, "%d.%06u%s", vals[0],
+ vals[1], scale_db ? " dB" : "");
case IIO_VAL_INT_PLUS_NANO:
if (vals[1] < 0)
- return scnprintf(buf, len, "-%d.%09u", abs(vals[0]),
- -vals[1]);
+ return sysfs_emit_at(buf, offset, "-%d.%09u",
+ abs(vals[0]), -vals[1]);
else
- return scnprintf(buf, len, "%d.%09u", vals[0], vals[1]);
+ return sysfs_emit_at(buf, offset, "%d.%09u", vals[0],
+ vals[1]);
case IIO_VAL_FRACTIONAL:
tmp2 = div_s64((s64)vals[0] * 1000000000LL, vals[1]);
tmp1 = vals[1];
tmp0 = (int)div_s64_rem(tmp2, 1000000000, &tmp1);
if ((tmp2 < 0) && (tmp0 == 0))
- return snprintf(buf, len, "-0.%09u", abs(tmp1));
+ return sysfs_emit_at(buf, offset, "-0.%09u", abs(tmp1));
else
- return snprintf(buf, len, "%d.%09u", tmp0, abs(tmp1));
+ return sysfs_emit_at(buf, offset, "%d.%09u", tmp0,
+ abs(tmp1));
case IIO_VAL_FRACTIONAL_LOG2:
- tmp = shift_right((s64)vals[0] * 1000000000LL, vals[1]);
- tmp0 = (int)div_s64_rem(tmp, 1000000000LL, &tmp1);
- return scnprintf(buf, len, "%d.%09u", tmp0, abs(tmp1));
+ tmp2 = shift_right((s64)vals[0] * 1000000000LL, vals[1]);
+ tmp0 = (int)div_s64_rem(tmp2, 1000000000LL, &tmp1);
+ if (tmp0 == 0 && tmp2 < 0)
+ return sysfs_emit_at(buf, offset, "-0.%09u", abs(tmp1));
+ else
+ return sysfs_emit_at(buf, offset, "%d.%09u", tmp0,
+ abs(tmp1));
case IIO_VAL_INT_MULTIPLE:
{
int i;
int l = 0;
- for (i = 0; i < size; ++i) {
- l += scnprintf(&buf[l], len - l, "%d ", vals[i]);
- if (l >= len)
- break;
- }
+ for (i = 0; i < size; ++i)
+ l += sysfs_emit_at(buf, offset + l, "%d ", vals[i]);
return l;
}
case IIO_VAL_CHAR:
- return scnprintf(buf, len, "%c", (char)vals[0]);
+ return sysfs_emit_at(buf, offset, "%c", (char)vals[0]);
default:
return 0;
}
@@ -698,11 +702,11 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
{
ssize_t len;
- len = __iio_format_value(buf, PAGE_SIZE, type, size, vals);
+ len = __iio_format_value(buf, 0, type, size, vals);
if (len >= PAGE_SIZE - 1)
return -EFBIG;
- return len + sprintf(buf + len, "\n");
+ return len + sysfs_emit_at(buf, len, "\n");
}
EXPORT_SYMBOL_GPL(iio_format_value);
@@ -760,22 +764,21 @@ static ssize_t iio_format_list(char *buf, const int *vals, int type, int length,
break;
}
- len = scnprintf(buf, PAGE_SIZE, prefix);
+ len = sysfs_emit(buf, prefix);
for (i = 0; i <= length - stride; i += stride) {
if (i != 0) {
- len += scnprintf(buf + len, PAGE_SIZE - len, " ");
+ len += sysfs_emit_at(buf, len, " ");
if (len >= PAGE_SIZE)
return -EFBIG;
}
- len += __iio_format_value(buf + len, PAGE_SIZE - len, type,
- stride, &vals[i]);
+ len += __iio_format_value(buf, len, type, stride, &vals[i]);
if (len >= PAGE_SIZE)
return -EFBIG;
}
- len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", suffix);
+ len += sysfs_emit_at(buf, len, "%s\n", suffix);
return len;
}
@@ -1114,6 +1117,7 @@ int __iio_add_chan_devattr(const char *postfix,
u64 mask,
enum iio_shared_by shared_by,
struct device *dev,
+ struct iio_buffer *buffer,
struct list_head *attr_list)
{
int ret;
@@ -1129,6 +1133,7 @@ int __iio_add_chan_devattr(const char *postfix,
goto error_iio_dev_attr_free;
iio_attr->c = chan;
iio_attr->address = mask;
+ iio_attr->buffer = buffer;
list_for_each_entry(t, attr_list, l)
if (strcmp(t->dev_attr.attr.name,
iio_attr->dev_attr.attr.name) == 0) {
@@ -1165,6 +1170,7 @@ static int iio_device_add_channel_label(struct iio_dev *indio_dev,
0,
IIO_SEPARATE,
&indio_dev->dev,
+ NULL,
&iio_dev_opaque->channel_attr_list);
if (ret < 0)
return ret;
@@ -1190,6 +1196,7 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev,
i,
shared_by,
&indio_dev->dev,
+ NULL,
&iio_dev_opaque->channel_attr_list);
if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE))
continue;
@@ -1226,6 +1233,7 @@ static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev,
i,
shared_by,
&indio_dev->dev,
+ NULL,
&iio_dev_opaque->channel_attr_list);
kfree(avail_postfix);
if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE))
@@ -1322,6 +1330,7 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
i,
ext_info->shared,
&indio_dev->dev,
+ NULL,
&iio_dev_opaque->channel_attr_list);
i++;
if (ret == -EBUSY && ext_info->shared)
@@ -1349,7 +1358,7 @@ void iio_free_chan_devattr_list(struct list_head *attr_list)
struct iio_dev_attr *p, *n;
list_for_each_entry_safe(p, n, attr_list, l) {
- kfree(p->dev_attr.attr.name);
+ kfree_const(p->dev_attr.attr.name);
list_del(&p->l);
kfree(p);
}
@@ -1360,7 +1369,7 @@ static ssize_t iio_show_dev_name(struct device *dev,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n", indio_dev->name);
+ return sysfs_emit(buf, "%s\n", indio_dev->name);
}
static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL);
@@ -1370,7 +1379,7 @@ static ssize_t iio_show_dev_label(struct device *dev,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n", indio_dev->label);
+ return sysfs_emit(buf, "%s\n", indio_dev->label);
}
static DEVICE_ATTR(label, S_IRUGO, iio_show_dev_label, NULL);
@@ -1452,6 +1461,25 @@ static ssize_t iio_store_timestamp_clock(struct device *dev,
return len;
}
+int iio_device_register_sysfs_group(struct iio_dev *indio_dev,
+ const struct attribute_group *group)
+{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ const struct attribute_group **new, **old = iio_dev_opaque->groups;
+ unsigned int cnt = iio_dev_opaque->groupcounter;
+
+ new = krealloc(old, sizeof(*new) * (cnt + 2), GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
+
+ new[iio_dev_opaque->groupcounter++] = group;
+ new[iio_dev_opaque->groupcounter] = NULL;
+
+ iio_dev_opaque->groups = new;
+
+ return 0;
+}
+
static DEVICE_ATTR(current_timestamp_clock, S_IRUGO | S_IWUSR,
iio_show_timestamp_clock, iio_store_timestamp_clock);
@@ -1525,8 +1553,10 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
if (clk)
iio_dev_opaque->chan_attr_group.attrs[attrn++] = clk;
- indio_dev->groups[indio_dev->groupcounter++] =
- &iio_dev_opaque->chan_attr_group;
+ ret = iio_device_register_sysfs_group(indio_dev,
+ &iio_dev_opaque->chan_attr_group);
+ if (ret)
+ goto error_clear_attrs;
return 0;
@@ -1543,6 +1573,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
iio_free_chan_devattr_list(&iio_dev_opaque->channel_attr_list);
kfree(iio_dev_opaque->chan_attr_group.attrs);
iio_dev_opaque->chan_attr_group.attrs = NULL;
+ kfree(iio_dev_opaque->groups);
}
static void iio_dev_release(struct device *device)
@@ -1555,7 +1586,7 @@ static void iio_dev_release(struct device *device)
iio_device_unregister_eventset(indio_dev);
iio_device_unregister_sysfs(indio_dev);
- iio_buffer_put(indio_dev->buffer);
+ iio_device_detach_buffers(indio_dev);
ida_simple_remove(&iio_ida, indio_dev->id);
kfree(iio_dev_opaque);
@@ -1574,7 +1605,7 @@ struct device_type iio_device_type = {
struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
{
struct iio_dev_opaque *iio_dev_opaque;
- struct iio_dev *dev;
+ struct iio_dev *indio_dev;
size_t alloc_size;
alloc_size = sizeof(struct iio_dev_opaque);
@@ -1587,32 +1618,31 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
if (!iio_dev_opaque)
return NULL;
- dev = &iio_dev_opaque->indio_dev;
- dev->priv = (char *)iio_dev_opaque +
+ indio_dev = &iio_dev_opaque->indio_dev;
+ indio_dev->priv = (char *)iio_dev_opaque +
ALIGN(sizeof(struct iio_dev_opaque), IIO_ALIGN);
- dev->dev.parent = parent;
- dev->dev.groups = dev->groups;
- dev->dev.type = &iio_device_type;
- dev->dev.bus = &iio_bus_type;
- device_initialize(&dev->dev);
- dev_set_drvdata(&dev->dev, (void *)dev);
- mutex_init(&dev->mlock);
- mutex_init(&dev->info_exist_lock);
+ indio_dev->dev.parent = parent;
+ indio_dev->dev.type = &iio_device_type;
+ indio_dev->dev.bus = &iio_bus_type;
+ device_initialize(&indio_dev->dev);
+ iio_device_set_drvdata(indio_dev, (void *)indio_dev);
+ mutex_init(&indio_dev->mlock);
+ mutex_init(&indio_dev->info_exist_lock);
INIT_LIST_HEAD(&iio_dev_opaque->channel_attr_list);
- dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
- if (dev->id < 0) {
+ indio_dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
+ if (indio_dev->id < 0) {
/* cannot use a dev_err as the name isn't available */
pr_err("failed to get device id\n");
kfree(iio_dev_opaque);
return NULL;
}
- dev_set_name(&dev->dev, "iio:device%d", dev->id);
+ dev_set_name(&indio_dev->dev, "iio:device%d", indio_dev->id);
INIT_LIST_HEAD(&iio_dev_opaque->buffer_list);
INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers);
- return dev;
+ return indio_dev;
}
EXPORT_SYMBOL(iio_device_alloc);
@@ -1676,13 +1706,24 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp)
{
struct iio_dev *indio_dev = container_of(inode->i_cdev,
struct iio_dev, chrdev);
+ struct iio_dev_buffer_pair *ib;
if (test_and_set_bit(IIO_BUSY_BIT_POS, &indio_dev->flags))
return -EBUSY;
iio_device_get(indio_dev);
- filp->private_data = indio_dev;
+ ib = kmalloc(sizeof(*ib), GFP_KERNEL);
+ if (!ib) {
+ iio_device_put(indio_dev);
+ clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags);
+ return -ENOMEM;
+ }
+
+ ib->indio_dev = indio_dev;
+ ib->buffer = indio_dev->buffer;
+
+ filp->private_data = ib;
return 0;
}
@@ -1696,8 +1737,10 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp)
*/
static int iio_chrdev_release(struct inode *inode, struct file *filp)
{
+ struct iio_dev_buffer_pair *ib = filp->private_data;
struct iio_dev *indio_dev = container_of(inode->i_cdev,
struct iio_dev, chrdev);
+ kfree(ib);
clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags);
iio_device_put(indio_dev);
@@ -1719,7 +1762,8 @@ void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h)
static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
- struct iio_dev *indio_dev = filp->private_data;
+ struct iio_dev_buffer_pair *ib = filp->private_data;
+ struct iio_dev *indio_dev = ib->indio_dev;
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
struct iio_ioctl_handler *h;
int ret = -ENODEV;
@@ -1761,6 +1805,15 @@ static const struct file_operations iio_buffer_fileops = {
.release = iio_chrdev_release,
};
+static const struct file_operations iio_event_fileops = {
+ .owner = THIS_MODULE,
+ .llseek = noop_llseek,
+ .unlocked_ioctl = iio_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
+ .open = iio_chrdev_open,
+ .release = iio_chrdev_release,
+};
+
static int iio_check_unique_scan_index(struct iio_dev *indio_dev)
{
int i, j;
@@ -1788,6 +1841,8 @@ static const struct iio_buffer_setup_ops noop_ring_setup_ops;
int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+ const char *label;
int ret;
if (!indio_dev->info)
@@ -1798,19 +1853,17 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
if (!indio_dev->dev.of_node && indio_dev->dev.parent)
indio_dev->dev.of_node = indio_dev->dev.parent->of_node;
- indio_dev->label = of_get_property(indio_dev->dev.of_node, "label",
- NULL);
+ label = of_get_property(indio_dev->dev.of_node, "label", NULL);
+ if (label)
+ indio_dev->label = label;
ret = iio_check_unique_scan_index(indio_dev);
if (ret < 0)
return ret;
- /* configure elements for the chrdev */
- indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
-
iio_device_register_debugfs(indio_dev);
- ret = iio_buffer_alloc_sysfs_and_mask(indio_dev);
+ ret = iio_buffers_alloc_sysfs_and_mask(indio_dev);
if (ret) {
dev_err(indio_dev->dev.parent,
"Failed to create buffer sysfs interfaces\n");
@@ -1836,9 +1889,18 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
indio_dev->setup_ops == NULL)
indio_dev->setup_ops = &noop_ring_setup_ops;
- cdev_init(&indio_dev->chrdev, &iio_buffer_fileops);
+ if (iio_dev_opaque->attached_buffers_cnt)
+ cdev_init(&indio_dev->chrdev, &iio_buffer_fileops);
+ else if (iio_dev_opaque->event_interface)
+ cdev_init(&indio_dev->chrdev, &iio_event_fileops);
+
+ if (iio_dev_opaque->attached_buffers_cnt || iio_dev_opaque->event_interface) {
+ indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
+ indio_dev->chrdev.owner = this_mod;
+ }
- indio_dev->chrdev.owner = this_mod;
+ /* assign device groups now; they should be all registered now */
+ indio_dev->dev.groups = iio_dev_opaque->groups;
ret = cdev_device_add(&indio_dev->chrdev, &indio_dev->dev);
if (ret < 0)
@@ -1851,7 +1913,7 @@ error_unreg_eventset:
error_free_sysfs:
iio_device_unregister_sysfs(indio_dev);
error_buffer_free_sysfs:
- iio_buffer_free_sysfs_and_mask(indio_dev);
+ iio_buffers_free_sysfs_and_mask(indio_dev);
error_unreg_debugfs:
iio_device_unregister_debugfs(indio_dev);
return ret;
@@ -1885,7 +1947,7 @@ void iio_device_unregister(struct iio_dev *indio_dev)
mutex_unlock(&indio_dev->info_exist_lock);
- iio_buffer_free_sysfs_and_mask(indio_dev);
+ iio_buffers_free_sysfs_and_mask(indio_dev);
}
EXPORT_SYMBOL(iio_device_unregister);