lkml.org 
[lkml]   [2011]   [Nov]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: [PATCH 1/6] IIO: Core sysfs only support.
On 11/07/2011 03:52 PM, jic23@cam.ac.uk wrote:
> From: Jonathan Cameron<jic23@cam.ac.uk>
>
> Add support for simple sysfs only interfaces.
>
> Bulk of patch is concerned with taking struct iio_chan_spec
> arrays and generating all the relevant interfaces from them.
>
> Signed-off-by: Jonathan Cameron<jic23@cam.ac.uk>
Since this is a subset of what we already reviewed and tested while in
staging -
I'm happy to add my ACK.

Acked-by: Michael Hennerich <michael.hennerich@analog.com>

> ---
> drivers/Kconfig | 2 +
> drivers/Makefile | 3 +
> drivers/iio/Kconfig | 11 +
> drivers/iio/Makefile | 6 +
> drivers/iio/iio.c | 591 +++++++++++++++++++++++++++++++++++++++++++++
> include/linux/iio/iio.h | 244 +++++++++++++++++++
> include/linux/iio/sysfs.h | 68 +++++
> include/linux/iio/types.h | 52 ++++
> 8 files changed, 977 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index b5e6f24..7410537 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -136,4 +136,6 @@ source "drivers/hv/Kconfig"
>
> source "drivers/devfreq/Kconfig"
>
> +source "drivers/iio/Kconfig"
> +
> endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 1b31421..216bba4 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -129,6 +129,9 @@ obj-$(CONFIG_IOMMU_SUPPORT) += iommu/
>
> # Virtualization drivers
> obj-$(CONFIG_VIRT_DRIVERS) += virt/
> +
> obj-$(CONFIG_HYPERV) += hv/
>
> obj-$(CONFIG_PM_DEVFREQ) += devfreq/
> +
> +obj-$(CONFIG_IIO) += iio/
> diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
> new file mode 100644
> index 0000000..012ebb0
> --- /dev/null
> +++ b/drivers/iio/Kconfig
> @@ -0,0 +1,11 @@
> +#
> +# Industrial I/O subsystem
> +#
> +
> +menuconfig IIO
> + tristate "Industrial I/O support"
> + depends on GENERIC_HARDIRQS
> + help
> + The Industrial input / output subsystem provides a unified
> + framework for many different types of embedded sensor.
> +
> diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
> new file mode 100644
> index 0000000..733846b
> --- /dev/null
> +++ b/drivers/iio/Makefile
> @@ -0,0 +1,6 @@
> +#
> +# Makefile for the Industrial I/O subsystem
> +#
> +
> +obj-$(CONFIG_IIO) += iio.o
> +industrialio-y := core.o
> diff --git a/drivers/iio/iio.c b/drivers/iio/iio.c
> new file mode 100644
> index 0000000..9a98f5f
> --- /dev/null
> +++ b/drivers/iio/iio.c
> @@ -0,0 +1,591 @@
> +/* The industrial I/O core
> + *
> + * Copyright (c) 2008-2011 Jonathan Cameron
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + *
> + * Based on elements of hwmon and input subsystems.
> + */
> +#include<linux/kernel.h>
> +#include<linux/module.h>
> +#include<linux/slab.h>
> +#include<linux/idr.h>
> +#include<linux/iio/iio.h>
> +#include<linux/iio/sysfs.h>
> +
> +static DEFINE_IDA(iio_ida);
> +
> +static struct bus_type iio_bus_type = {
> + .name = "iio",
> +};
> +
> +static const char * const iio_data_type_name[] = {
> + [IIO_RAW] = "raw",
> + [IIO_PROCESSED] = "input",
> +};
> +
> +static const char * const iio_chan_type_name_spec[] = {
> + [IIO_VOLTAGE] = "voltage",
> + [IIO_CURRENT] = "current",
> + [IIO_POWER] = "power",
> + [IIO_ACCEL] = "accel",
> + [IIO_ANGL_VEL] = "anglvel",
> + [IIO_MAGN] = "magn",
> + [IIO_LIGHT] = "illuminance",
> + [IIO_INTENSITY] = "intensity",
> + [IIO_PROXIMITY] = "proximity",
> + [IIO_TEMP] = "temp",
> + [IIO_INCLI] = "incli",
> + [IIO_ROT] = "rot",
> + [IIO_ANGL] = "angl",
> + [IIO_TIMESTAMP] = "timestamp",
> +};
> +
> +static const char * const iio_direction_name[] = {
> + [IIO_IN] = "in",
> + [IIO_OUT] = "out",
> +};
> +
> +static const char * const iio_modifier_names[] = {
> + [IIO_MOD_X] = "x",
> + [IIO_MOD_Y] = "y",
> + [IIO_MOD_Z] = "z",
> + [IIO_MOD_LIGHT_BOTH] = "both",
> + [IIO_MOD_LIGHT_INFRARED] = "ir",
> +};
> +
> +static const char * const iio_chan_info_postfix[] = {
> + [IIO_CHAN_INFO_SCALE] = "scale",
> + [IIO_CHAN_INFO_OFFSET] = "offset",
> + [IIO_CHAN_INFO_CALIBSCALE] = "calibscale",
> + [IIO_CHAN_INFO_CALIBBIAS] = "calibbias",
> + [IIO_CHAN_INFO_PEAK] = "peak_raw",
> + [IIO_CHAN_INFO_PEAK_SCALE] = "peak_scale",
> + [IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW] = "quadrature_correction_raw",
> +};
> +
> +static void iio_device_free_read_attr(struct iio_dev *indio_dev,
> + struct iio_dev_attr *p)
> +{
> + kfree(p->dev_attr.attr.name);
> + kfree(p);
> +}
> +
> +static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
> +{
> +
> + struct iio_dev_attr *p, *n;
> +
> + list_for_each_entry_safe(p, n,&indio_dev->channel_attr_list, l) {
> + list_del(&p->l);
> + iio_device_free_read_attr(indio_dev, p);
> + }
> + kfree(indio_dev->chan_attr_group.attrs);
> +}
> +
> +static void iio_dev_release(struct device *device)
> +{
> + struct iio_dev *indio_dev = container_of(device, struct iio_dev, dev);
> + iio_device_unregister_sysfs(indio_dev);
> +}
> +
> +static struct device_type iio_dev_type = {
> + .name = "iio_device",
> + .release = iio_dev_release,
> +};
> +
> +struct iio_dev *iio_device_allocate(int sizeof_priv)
> +{
> + struct iio_dev *dev;
> + size_t alloc_size;
> +
> + alloc_size = sizeof(struct iio_dev);
> + if (sizeof_priv) {
> + alloc_size = ALIGN(alloc_size, IIO_ALIGN);
> + alloc_size += sizeof_priv;
> + }
> + /* ensure cacheline alignment of whole construct */
> + alloc_size += IIO_ALIGN - 1;
> +
> + dev = kzalloc(alloc_size, GFP_KERNEL);
> +
> + if (dev) {
> + dev->dev.groups = dev->groups;
> + dev->dev.type =&iio_dev_type;
> + dev->dev.bus =&iio_bus_type;
> + device_initialize(&dev->dev);
> + dev_set_drvdata(&dev->dev, (void *)dev);
> + mutex_init(&dev->mlock);
> + }
> +
> + return dev;
> +}
> +EXPORT_SYMBOL_GPL(iio_device_allocate);
> +
> +void iio_device_free(struct iio_dev *dev)
> +{
> + if (dev)
> + iio_put_device(dev);
> +}
> +EXPORT_SYMBOL_GPL(iio_device_free);
> +
> +ssize_t __iio_read_const_attr(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + return sprintf(buf, "%s\n",
> + container_of(attr,
> + struct iio_const_attr,
> + dev_attr)->string);
> +}
> +EXPORT_SYMBOL_GPL(__iio_read_const_attr);
> +
> +static ssize_t iio_read_channel_info(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
> + int val, val2;
> + int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
> +&val,&val2, this_attr->address);
> +
> + if (ret< 0)
> + return ret;
> +
> + if (ret == IIO_VAL_INT)
> + return sprintf(buf, "%d\n", val);
> + else if (ret == IIO_VAL_INT_PLUS_MICRO) {
> + if (val2< 0)
> + return sprintf(buf, "-%d.%06u\n", val, -val2);
> + else
> + return sprintf(buf, "%d.%06u\n", val, val2);
> + } else if (ret == IIO_VAL_INT_PLUS_NANO) {
> + if (val2< 0)
> + return sprintf(buf, "-%d.%09u\n", val, -val2);
> + else
> + return sprintf(buf, "%d.%09u\n", val, val2);
> + } else
> + return 0;
> +}
> +
> +static ssize_t iio_write_channel_info(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf,
> + size_t len)
> +{
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
> + int ret, integer = 0, fract = 0, fract_mult = 100000;
> + bool integer_part = true, negative = false;
> +
> + /* Assumes decimal - precision based on number of digits */
> + if (!indio_dev->info->write_raw)
> + return -EINVAL;
> +
> + if (indio_dev->info->write_raw_get_fmt)
> + switch (indio_dev->info->write_raw_get_fmt(indio_dev,
> + this_attr->c, this_attr->address)) {
> + case IIO_VAL_INT_PLUS_MICRO:
> + fract_mult = 100000;
> + break;
> + case IIO_VAL_INT_PLUS_NANO:
> + fract_mult = 100000000;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + if (buf[0] == '-') {
> + negative = true;
> + buf++;
> + }
> +
> + while (*buf) {
> + if ('0'<= *buf&& *buf<= '9') {
> + if (integer_part)
> + integer = integer*10 + *buf - '0';
> + else {
> + fract += fract_mult*(*buf - '0');
> + if (fract_mult == 1)
> + break;
> + fract_mult /= 10;
> + }
> + } else if (*buf == '\n') {
> + if (*(buf + 1) == '\0')
> + break;
> + else
> + return -EINVAL;
> + } else if (*buf == '.') {
> + integer_part = false;
> + } else {
> + return -EINVAL;
> + }
> + buf++;
> + }
> + if (negative) {
> + if (integer)
> + integer = -integer;
> + else
> + fract = -fract;
> + }
> +
> + ret = indio_dev->info->write_raw(indio_dev, this_attr->c,
> + integer, fract, this_attr->address);
> + if (ret)
> + return ret;
> +
> + return len;
> +}
> +
> +static
> +int __iio_device_attr_init(struct device_attribute *dev_attr,
> + const char *postfix,
> + struct iio_chan_spec const *chan,
> + ssize_t (*readfunc)(struct device *dev,
> + struct device_attribute *attr,
> + char *buf),
> + ssize_t (*writefunc)(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf,
> + size_t len),
> + bool generic)
> +{
> + int ret;
> + char *name_format, *full_postfix;
> + sysfs_attr_init(&dev_attr->attr);
> +
> + /* Build up postfix of<extend_name>_<modifier>_postfix */
> + if (chan->modified&& !generic) {
> + if (chan->extend_name)
> + full_postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
> + iio_modifier_names[chan
> + ->channel2],
> + chan->extend_name,
> + postfix);
> + else
> + full_postfix = kasprintf(GFP_KERNEL, "%s_%s",
> + iio_modifier_names[chan
> + ->channel2],
> + postfix);
> + } else {
> + if (chan->extend_name == NULL)
> + full_postfix = kstrdup(postfix, GFP_KERNEL);
> + else
> + full_postfix = kasprintf(GFP_KERNEL,
> + "%s_%s",
> + chan->extend_name,
> + postfix);
> + }
> + if (full_postfix == NULL) {
> + ret = -ENOMEM;
> + goto error_ret;
> + }
> +
> + if (chan->differential) { /* Differential can not have modifier */
> + if (generic)
> + name_format
> + = kasprintf(GFP_KERNEL, "%s_%s-%s_%s",
> + iio_direction_name[chan->output],
> + iio_chan_type_name_spec[chan->type],
> + iio_chan_type_name_spec[chan->type],
> + full_postfix);
> + else if (chan->indexed)
> + name_format
> + = kasprintf(GFP_KERNEL, "%s_%s%d-%s%d_%s",
> + iio_direction_name[chan->output],
> + iio_chan_type_name_spec[chan->type],
> + chan->channel,
> + iio_chan_type_name_spec[chan->type],
> + chan->channel2,
> + full_postfix);
> + else {
> + WARN_ON("Differential channels must be indexed\n");
> + ret = -EINVAL;
> + goto error_free_full_postfix;
> + }
> + } else { /* Single ended */
> + if (generic)
> + name_format
> + = kasprintf(GFP_KERNEL, "%s_%s_%s",
> + iio_direction_name[chan->output],
> + iio_chan_type_name_spec[chan->type],
> + full_postfix);
> + else if (chan->indexed)
> + name_format
> + = kasprintf(GFP_KERNEL, "%s_%s%d_%s",
> + iio_direction_name[chan->output],
> + iio_chan_type_name_spec[chan->type],
> + chan->channel,
> + full_postfix);
> + else
> + name_format
> + = kasprintf(GFP_KERNEL, "%s_%s_%s",
> + iio_direction_name[chan->output],
> + iio_chan_type_name_spec[chan->type],
> + full_postfix);
> + }
> + if (name_format == NULL) {
> + ret = -ENOMEM;
> + goto error_free_full_postfix;
> + }
> + dev_attr->attr.name = kasprintf(GFP_KERNEL,
> + name_format,
> + chan->channel,
> + chan->channel2);
> + if (dev_attr->attr.name == NULL) {
> + ret = -ENOMEM;
> + goto error_free_name_format;
> + }
> +
> + if (readfunc) {
> + dev_attr->attr.mode |= S_IRUGO;
> + dev_attr->show = readfunc;
> + }
> +
> + if (writefunc) {
> + dev_attr->attr.mode |= S_IWUSR;
> + dev_attr->store = writefunc;
> + }
> + kfree(name_format);
> + kfree(full_postfix);
> +
> + return 0;
> +
> +error_free_name_format:
> + kfree(name_format);
> +error_free_full_postfix:
> + kfree(full_postfix);
> +error_ret:
> + return ret;
> +}
> +
> +static void __iio_device_attr_deinit(struct device_attribute *dev_attr)
> +{
> + kfree(dev_attr->attr.name);
> +}
> +
> +static
> +int __iio_add_chan_devattr(const char *postfix,
> + struct iio_chan_spec const *chan,
> + ssize_t (*readfunc)(struct device *dev,
> + struct device_attribute *attr,
> + char *buf),
> + ssize_t (*writefunc)(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf,
> + size_t len),
> + u64 mask,
> + bool generic,
> + struct device *dev,
> + struct list_head *attr_list)
> +{
> + int ret;
> + struct iio_dev_attr *iio_attr, *t;
> +
> + iio_attr = kzalloc(sizeof *iio_attr, GFP_KERNEL);
> + if (iio_attr == NULL) {
> + ret = -ENOMEM;
> + goto error_ret;
> + }
> + ret = __iio_device_attr_init(&iio_attr->dev_attr,
> + postfix, chan,
> + readfunc, writefunc, generic);
> + if (ret)
> + goto error_iio_dev_attr_free;
> + iio_attr->c = chan;
> + iio_attr->address = mask;
> + list_for_each_entry(t, attr_list, l)
> + if (strcmp(t->dev_attr.attr.name,
> + iio_attr->dev_attr.attr.name) == 0) {
> + if (!generic)
> + dev_err(dev, "tried to double register : %s\n",
> + t->dev_attr.attr.name);
> + ret = -EBUSY;
> + goto error_device_attr_deinit;
> + }
> +
> + list_add(&iio_attr->l, attr_list);
> +
> + return 0;
> +
> +error_device_attr_deinit:
> + __iio_device_attr_deinit(&iio_attr->dev_attr);
> +error_iio_dev_attr_free:
> + kfree(iio_attr);
> +error_ret:
> + return ret;
> +}
> +
> +static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan)
> +{
> + int ret, i, attrcount = 0;
> +
> + if (chan->channel< 0)
> + return 0;
> + ret = __iio_add_chan_devattr(iio_data_type_name[chan->processed_val],
> + chan,
> +&iio_read_channel_info,
> + (chan->output ?
> +&iio_write_channel_info : NULL),
> + 0,
> + 0,
> +&indio_dev->dev,
> +&indio_dev->channel_attr_list);
> + if (ret)
> + goto error_ret;
> + attrcount++;
> +
> + for_each_set_bit(i,&chan->info_mask,
> + ARRAY_SIZE(iio_chan_info_postfix)*2) {
> + ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2],
> + chan,
> +&iio_read_channel_info,
> +&iio_write_channel_info,
> + i/2,
> + !(i%2),
> +&indio_dev->dev,
> +&indio_dev->channel_attr_list);
> + if (ret == -EBUSY&& (i%2 == 0)) {
> + ret = 0;
> + continue;
> + }
> + if (ret< 0)
> + goto error_ret;
> + attrcount++;
> + }
> + ret = attrcount;
> +error_ret:
> + return ret;
> +}
> +
> +static ssize_t iio_show_dev_name(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + return sprintf(buf, "%s\n", indio_dev->name);
> +}
> +
> +static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL);
> +
> +static int iio_device_register_sysfs(struct iio_dev *indio_dev)
> +{
> + int i, ret = 0, attrcount, attrn, attrcount_orig = 0;
> + struct iio_dev_attr *p, *n;
> + struct attribute **attr;
> +
> + /* First count elements in any existing group */
> + if (indio_dev->info->attrs) {
> + attr = indio_dev->info->attrs->attrs;
> + while (*attr++ != NULL)
> + attrcount_orig++;
> + }
> + attrcount = attrcount_orig;
> +
> + INIT_LIST_HEAD(&indio_dev->channel_attr_list);
> + if (indio_dev->channels)
> + for (i = 0; i< indio_dev->num_channels; i++) {
> + ret = iio_device_add_channel_sysfs(indio_dev,
> +&indio_dev
> + ->channels[i]);
> + if (ret< 0)
> + goto error_clear_attrs;
> + attrcount += ret;
> + }
> + if (indio_dev->name)
> + attrcount++;
> +
> + indio_dev->chan_attr_group.attrs
> + = kzalloc(sizeof(indio_dev->chan_attr_group.attrs[0])*
> + (attrcount + 1),
> + GFP_KERNEL);
> + if (indio_dev->chan_attr_group.attrs == NULL) {
> + ret = -ENOMEM;
> + goto error_clear_attrs;
> + }
> + /* Copy across original attributes */
> + if (indio_dev->info->attrs)
> + memcpy(indio_dev->chan_attr_group.attrs,
> + indio_dev->info->attrs->attrs,
> + sizeof(indio_dev->chan_attr_group.attrs[0])
> + *attrcount_orig);
> + attrn = attrcount_orig;
> + /* Add all elements from the list. */
> + list_for_each_entry(p,&indio_dev->channel_attr_list, l)
> + indio_dev->chan_attr_group.attrs[attrn++] =&p->dev_attr.attr;
> + if (indio_dev->name)
> + indio_dev->chan_attr_group.attrs[attrn++] =&dev_attr_name.attr;
> +
> + indio_dev->groups[indio_dev->groupcounter++] =
> +&indio_dev->chan_attr_group;
> +
> + return 0;
> +
> +error_clear_attrs:
> + list_for_each_entry_safe(p, n,
> +&indio_dev->channel_attr_list, l) {
> + list_del(&p->l);
> + iio_device_free_read_attr(indio_dev, p);
> + }
> +
> + return ret;
> +}
> +
> +int iio_device_register(struct iio_dev *indio_dev)
> +{
> + int ret;
> +
> + indio_dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
> + if (indio_dev->id< 0) {
> + ret = indio_dev->id;
> + goto error_ret;
> + }
> +
> + dev_set_name(&indio_dev->dev, "iio:device%d", indio_dev->id);
> +
> + ret = iio_device_register_sysfs(indio_dev);
> + if (ret) {
> + dev_err(indio_dev->dev.parent,
> + "Failed to register sysfs interfaces\n");
> + goto error_free_ida;
> + }
> + ret = device_add(&indio_dev->dev);
> + if (ret)
> + goto error_free_sysfs;
> +
> + return 0;
> +
> +error_free_sysfs:
> + iio_device_unregister_sysfs(indio_dev);
> +error_free_ida:
> + ida_simple_remove(&iio_ida, indio_dev->id);
> +error_ret:
> + return ret;
> +}
> +EXPORT_SYMBOL(iio_device_register);
> +
> +void iio_device_unregister(struct iio_dev *indio_dev)
> +{
> + device_unregister(&indio_dev->dev);
> +}
> +EXPORT_SYMBOL(iio_device_unregister);
> +
> +static int __init iio_init(void)
> +{
> + return bus_register(&iio_bus_type);
> +}
> +subsys_initcall(iio_init);
> +
> +static void __exit iio_exit(void)
> +{
> + bus_unregister(&iio_bus_type);
> +}
> +module_exit(iio_exit);
> +
> +MODULE_AUTHOR("Jonathan Cameron<jic23@cam.ac.uk>");
> +MODULE_DESCRIPTION("Industrial I/O core");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> new file mode 100644
> index 0000000..4367d82
> --- /dev/null
> +++ b/include/linux/iio/iio.h
> @@ -0,0 +1,244 @@
> +/*
> + * The industrial I/O core
> + *
> + * Copyright (c) 2008-2011 Jonathan Cameron
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + */
> +#ifndef _IIO_H_
> +#define _IIO_H_
> +
> +#include<linux/klist.h>
> +#include<linux/device.h>
> +#include<linux/iio/types.h>
> +
> +/* Minimum alignment of priv within iio_dev */
> +#define IIO_ALIGN L1_CACHE_BYTES
> +
> +enum iio_data_type {
> + IIO_RAW,
> + IIO_PROCESSED,
> +};
> +
> +enum iio_chan_info_enum {
> + IIO_CHAN_INFO_SCALE = 1,
> + IIO_CHAN_INFO_OFFSET,
> + IIO_CHAN_INFO_CALIBSCALE,
> + IIO_CHAN_INFO_CALIBBIAS,
> + IIO_CHAN_INFO_PEAK,
> + IIO_CHAN_INFO_PEAK_SCALE,
> + IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW,
> +};
> +
> +#define IIO_CHAN_INFO_SHARED_BIT(type) BIT(type*2)
> +#define IIO_CHAN_INFO_SEPARATE_BIT(type) BIT(type*2 + 1)
> +
> +#define IIO_CHAN_INFO_SCALE_SEPARATE_BIT \
> + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_SCALE)
> +#define IIO_CHAN_INFO_SCALE_SHARED_BIT \
> + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_SCALE)
> +#define IIO_CHAN_INFO_OFFSET_SEPARATE_BIT \
> + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_OFFSET)
> +#define IIO_CHAN_INFO_OFFSET_SHARED_BIT \
> + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_OFFSET)
> +#define IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT \
> + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBSCALE)
> +#define IIO_CHAN_INFO_CALIBSCALE_SHARED_BIT \
> + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBSCALE)
> +#define IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT \
> + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBBIAS)
> +#define IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT \
> + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBBIAS)
> +#define IIO_CHAN_INFO_PEAK_SEPARATE_BIT \
> + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAK)
> +#define IIO_CHAN_INFO_PEAK_SHARED_BIT \
> + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAK)
> +#define IIO_CHAN_INFO_PEAKSCALE_SEPARATE_BIT \
> + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAKSCALE)
> +#define IIO_CHAN_INFO_PEAKSCALE_SHARED_BIT \
> + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAKSCALE)
> +#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT \
> + IIO_CHAN_INFO_SEPARATE_BIT( \
> + IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW)
> +#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SHARED_BIT \
> + IIO_CHAN_INFO_SHARED_BIT( \
> + IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW)
> +#define IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT \
> + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_AVERAGE_RAW)
> +#define IIO_CHAN_INFO_AVERAGE_RAW_SHARED_BIT \
> + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_AVERAGE_RAW)
> +
> +
> +enum iio_direction {
> + IIO_IN,
> + IIO_OUT,
> +};
> +
> +/**
> + * struct iio_chan_spec - specification of a single channel
> + * @type: What type of measurement is the channel making.
> + * @channel: What number or name do we wish to asign the channel.
> + * @channel2: If there is a second number for a differential
> + * channel then this is it. If modified is set then the
> + * value here specifies the modifier.
> + * @address: Driver specific identifier.
> + * @scan_type: Description of data format.
> + * @info_mask: What information is to be exported about this channel.
> + * This includes calibbias, scale etc.
> + * @extend_name: Allows labeling of channel attributes with an
> + * informative name. Note this has no effect codes etc,
> + * unlike modifiers.
> + * @processed_val: Flag to specify the data access attribute should be
> + * *_input rather than *_raw.
> + * @modified: Does a modifier apply to this channel. What these are
> + * depends on the channel type. Modifier is set in
> + * channel2. Examples are IIO_MOD_X for axial sensors about
> + * the 'x' axis.
> + * @indexed: Specify the channel has a numerical index. If not,
> + * the value in channel will be suppressed for attribute
> + * but not for event codes. Typically set it to 0 when
> + * the index is false.
> + * @output: Specify the channel is an output channel (DAC).
> + * @differential: Is the channel a differential channel. Cannot coexist
> + * with modified and requires indexed.
> + */
> +struct iio_chan_spec {
> + enum iio_chan_type type;
> + int channel;
> + int channel2;
> + unsigned long address;
> + /**
> + * struct scan_type - description of the data format
> + * @sign: Set if signed value
> + * @realbits: Number of valid bits of data
> + * @shift: Shift right by this before masking out realbits.
> + */
> + struct {
> + char sign;
> + u8 realbits;
> + u8 shift;
> + } scan_type;
> + long info_mask;
> + char *extend_name;
> + unsigned processed_val:1;
> + unsigned modified:1;
> + unsigned indexed:1;
> + unsigned output:1;
> + unsigned differential:1;
> +};
> +
> +struct iio_dev;
> +
> +/**
> + * struct iio_info - constant information about device
> + * @driver_module: module structure used to ensure correct
> + * ownership of chrdevs etc
> + * @attrs: general purpose device attributes
> + * @read_raw: function to request a value from the device.
> + * mask specifies which value. Note 0 means a reading of
> + * the channel in question. Return value will specify the
> + * type of value returned by the device. val and val2 will
> + * contain the elements making up the returned value.
> + * @write_raw: function to write a value to the device.
> + * Parameters are the same as for read_raw.
> + * @write_raw_get_fmt: callback function to query the expected
> + * format/precision. If not set by the driver, write_raw
> + * returns IIO_VAL_INT_PLUS_MICRO.
> + **/
> +struct iio_info {
> + struct module *driver_module;
> + const struct attribute_group *attrs;
> +
> + int (*read_raw)(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val,
> + int *val2,
> + long mask);
> +
> + int (*write_raw)(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int val,
> + int val2,
> + long mask);
> +
> + int (*write_raw_get_fmt)(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + long mask);
> +};
> +
> +/**
> + * struct iio_dev - industrial I/O device
> + * @id: [INTERN] used to identify device internally
> + * @dev: [DRIVER] device structure, should be assigned a parent
> + * and owner
> + * @mlock: [INTERN] lock used to prevent simultaneous device state
> + * changes
> + * @available_scan_masks: [DRIVER] optional array of allowed bitmasks
> + * @channels: [DRIVER] channel specification structure table
> + * @num_channels: [DRIVER] number of chanels specified in @channels
> + * @channel_attr_list: [INTERN] keep track of automatically created channel
> + * attributes
> + * @chan_attr_group: [INTERN] group for all attrs in base directory
> + * @name: [DRIVER] name of the device
> + * @info: [DRIVER] callbacks and constant info from driver
> + * @groups: [INTERN] attribute groups
> + * @groupcounter: [INTERN] index of next attribute group
> + **/
> +struct iio_dev {
> + int id;
> + struct device dev;
> + struct mutex mlock;
> + unsigned long *available_scan_masks;
> + struct iio_chan_spec const *channels;
> + int num_channels;
> + struct list_head channel_attr_list;
> + struct attribute_group chan_attr_group;
> + const char *name;
> + const struct iio_info *info;
> +#define IIO_MAX_GROUPS 1
> + const struct attribute_group *groups[IIO_MAX_GROUPS + 1];
> + int groupcounter;
> +};
> +
> +/**
> + * iio_device_allocate() - allocate an iio_dev from a driver
> + * @sizeof_priv: Space to allocate for private structure.
> + **/
> +struct iio_dev *iio_device_allocate(int sizeof_priv);
> +
> +static inline void *iio_priv(const struct iio_dev *dev)
> +{
> + return (char *)dev + ALIGN(sizeof(struct iio_dev), IIO_ALIGN);
> +}
> +
> +/**
> + * iio_device_free() - free an iio_dev from a driver
> + * @dev: the iio_dev associated with the device
> + **/
> +void iio_device_free(struct iio_dev *dev);
> +
> +/**
> + * iio_device_register() - register a device with the IIO subsystem
> + * @indio_dev: Device structure filled by the device driver
> + **/
> +int iio_device_register(struct iio_dev *indio_dev);
> +
> +/**
> + * iio_device_unregister() - unregister a device from the IIO subsystem
> + * @indio_dev: Device structure representing the device.
> + **/
> +void iio_device_unregister(struct iio_dev *indio_dev);
> +
> +/**
> + * iio_put_device() - reference counted deallocation of struct device
> + * @indio_dev: the iio_device containing the device
> + **/
> +static inline void iio_put_device(struct iio_dev *indio_dev)
> +{
> + if (indio_dev)
> + put_device(&indio_dev->dev);
> +};
> +
> +#endif /* _IIO_H_ */
> diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h
> new file mode 100644
> index 0000000..c6735bf
> --- /dev/null
> +++ b/include/linux/iio/sysfs.h
> @@ -0,0 +1,68 @@
> +/*
> + * The industrial I/O core
> + *
> + * Copyright (c) 2008 Jonathan Cameron
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + *
> + * General attributes
> + */
> +
> +#include<linux/klist.h>
> +#include<linux/device.h>
> +
> +#ifndef _IIO_SYSFS_H_
> +#define _IIO_SYSFS_H_
> +
> +struct iio_chan_spec;
> +
> +/**
> + * struct iio_dev_attr - iio specific device attribute
> + * @dev_attr: underlying device attribute
> + * @address: associated register address
> + * @l: list head for maintaining list of dynamically created attrs
> + * @c: channel spec for channel with which attr is associated if any
> + */
> +struct iio_dev_attr {
> + struct device_attribute dev_attr;
> + int address;
> + struct list_head l;
> + struct iio_chan_spec const *c;
> +};
> +
> +#define to_iio_dev_attr(_dev_attr) \
> + container_of(_dev_attr, struct iio_dev_attr, dev_attr)
> +
> +#define IIO_ATTR(_name, _mode, _show, _store, _addr) \
> + { .dev_attr = __ATTR(_name, _mode, _show, _store), \
> + .address = _addr }
> +
> +#define IIO_DEVICE_ATTR(_name, _mode, _show, _store, _addr) \
> + struct iio_dev_attr iio_dev_attr_##_name \
> + = IIO_ATTR(_name, _mode, _show, _store, _addr)
> +
> +/**
> + * struct iio_const_attr - constant device specific attribute
> + * often used for things like available modes
> + * @string: attribute string
> + * @dev_attr: underlying device attribute
> + */
> +struct iio_const_attr {
> + const char *string;
> + struct device_attribute dev_attr;
> +};
> +
> +#define to_iio_const_attr(_dev_attr) \
> + container_of(_dev_attr, struct iio_const_attr, dev_attr)
> +
> +ssize_t __iio_read_const_attr(struct device *dev,
> + struct device_attribute *attr,
> + char *len);
> +
> +#define IIO_CONST_ATTR(_name, _string) \
> + struct iio_const_attr iio_const_attr_##_name \
> + = { .string = _string, \
> + .dev_attr = __ATTR(_name, S_IRUGO, __iio_read_const_attr, NULL) }
> +#endif /* _IIO_SYSFS_H_ */
> diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
> new file mode 100644
> index 0000000..4cb24aa
> --- /dev/null
> +++ b/include/linux/iio/types.h
> @@ -0,0 +1,52 @@
> +/* industrial I/O data types needed both in and out of kernel
> + *
> + * Copyright (c) 2011 Jonathan Cameron
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + */
> +
> +#ifndef _IIO_TYPES_H_
> +#define _IIO_TYPES_H_
> +
> +enum iio_chan_type {
> + IIO_VOLTAGE,
> + IIO_CURRENT,
> + IIO_POWER,
> + IIO_CAPACITANCE,
> + IIO_ACCEL,
> + IIO_ANGL_VEL,
> + IIO_MAGN,
> + IIO_LIGHT,
> + IIO_INTENSITY,
> + IIO_PROXIMITY,
> + IIO_TEMP,
> + IIO_INCLI,
> + IIO_ROT,
> + IIO_ANGL,
> + IIO_TIMESTAMP,
> +};
> +
> +enum iio_modifier {
> + IIO_NO_MOD,
> + IIO_MOD_X,
> + IIO_MOD_Y,
> + IIO_MOD_Z,
> + IIO_MOD_X_AND_Y,
> + IIO_MOD_X_ANX_Z,
> + IIO_MOD_Y_AND_Z,
> + IIO_MOD_X_AND_Y_AND_Z,
> + IIO_MOD_X_OR_Y,
> + IIO_MOD_X_OR_Z,
> + IIO_MOD_Y_OR_Z,
> + IIO_MOD_X_OR_Y_OR_Z,
> + IIO_MOD_LIGHT_BOTH,
> + IIO_MOD_LIGHT_INFRARED,
> +};
> +
> +#define IIO_VAL_INT 1
> +#define IIO_VAL_INT_PLUS_MICRO 2
> +#define IIO_VAL_INT_PLUS_NANO 3
> +
> +#endif /* _IIO_TYPES_H_ */
> --
> 1.7.7.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>


--
Greetings,
Michael

--
Analog Devices GmbH Wilhelm-Wagenfeld-Str. 6 80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif




\
 
 \ /
  Last update: 2011-11-11 11:45    [W:3.650 / U:0.032 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site