All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michael Hennerich <michael.hennerich@analog.com>
To: "jic23@cam.ac.uk" <jic23@cam.ac.uk>
Cc: "linux-iio@vger.kernel.org" <linux-iio@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"guenter.roeck@ericsson.com" <guenter.roeck@ericsson.com>,
	"khali@linux-fr.org" <khali@linux-fr.org>,
	"dmitry.torokhov@gmail.com" <dmitry.torokhov@gmail.com>,
	"broonie@opensource.wolfsonmicro.com"
	<broonie@opensource.wolfsonmicro.com>,
	"gregkh@suse.de" <gregkh@suse.de>,
	"alan@lxorguk.ukuu.org.uk" <alan@lxorguk.ukuu.org.uk>,
	"arnd@arndb.de" <arnd@arndb.de>,
	"linus.walleij@linaro.org" <linus.walleij@linaro.org>,
	"lars@metafoo.de" <lars@metafoo.de>,
	"maxime.ripard@free-electrons.com"
	<maxime.ripard@free-electrons.com>
Subject: Re: [PATCH 1/6] IIO: Core sysfs only support.
Date: Fri, 11 Nov 2011 11:40:42 +0100	[thread overview]
Message-ID: <4EBCFBAA.5010408@analog.com> (raw)
In-Reply-To: <1320677563-18378-2-git-send-email-jic23@cam.ac.uk>

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

  reply	other threads:[~2011-11-11 10:40 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-11-07 14:52 [PATCH 0/6 V2] IIO: Out of staging step 1: The core jic23
2011-11-07 14:52 ` [PATCH 1/6] IIO: Core sysfs only support jic23
2011-11-11 10:40   ` Michael Hennerich [this message]
2012-02-01 15:20   ` Maxime Ripard
2011-11-07 14:52 ` [PATCH 2/6] IIO:ADC: max1363 initial import jic23
2011-11-07 14:52 ` [PATCH 3/6] IIO:ADC:ad799x " jic23
2011-11-08 13:07   ` Lars-Peter Clausen
2011-11-08 13:35     ` Jonathan Cameron
2011-11-07 14:52 ` [PATCH 4/6] IIO:light:tsl2563 initial move out of staging jic23
2011-11-07 14:52 ` [PATCH 5/6] IIO:imu:adis16400 partial move from staging jic23
2011-11-11 10:41   ` Michael Hennerich
2011-11-07 14:52 ` [PATCH 6/6] IIO: ABI documetation jic23
2011-11-11 10:41   ` Michael Hennerich
2011-11-08 13:32 ` [PATCH 0/6 V2] IIO: Out of staging step 1: The core Lars-Peter Clausen
2011-11-08 14:23   ` Jonathan Cameron
2011-11-08 14:53     ` Lars-Peter Clausen
2011-11-08 15:29       ` Jonathan Cameron
  -- strict thread matches above, loose matches on Subject: below --
2011-10-17 13:16 [PATCH 0/6] " Jonathan Cameron
2011-10-17 13:16 ` [PATCH 1/6] IIO: Core sysfs only support Jonathan Cameron
2011-10-17 13:42   ` Alexander Stein
2011-10-17 13:48     ` Jonathan Cameron
2011-10-17 16:27   ` Jonathan Cameron
2011-09-27 14:29 [RFC PATCH 0/6 V2] IIO: Out of staging step 1: The core Jonathan Cameron
2011-09-27 14:29 ` [PATCH 1/6] IIO: Core sysfs only support Jonathan Cameron

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4EBCFBAA.5010408@analog.com \
    --to=michael.hennerich@analog.com \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=arnd@arndb.de \
    --cc=broonie@opensource.wolfsonmicro.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=gregkh@suse.de \
    --cc=guenter.roeck@ericsson.com \
    --cc=jic23@cam.ac.uk \
    --cc=khali@linux-fr.org \
    --cc=lars@metafoo.de \
    --cc=linus.walleij@linaro.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maxime.ripard@free-electrons.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.