From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751595Ab1KKKnQ (ORCPT ); Fri, 11 Nov 2011 05:43:16 -0500 Received: from tx2ehsobe003.messaging.microsoft.com ([65.55.88.13]:53098 "EHLO TX2EHSOBE006.bigfish.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750783Ab1KKKnN (ORCPT ); Fri, 11 Nov 2011 05:43:13 -0500 X-SpamScore: -11 X-BigFish: VPS-11(zzbb2dK9371K1432N98dKc8kzz1202hzz84d07h8275bh8275dhz32i2a8h668h839h61h) X-Spam-TCS-SCL: 0:0 X-Forefront-Antispam-Report: CIP:137.71.25.57;KIP:(null);UIP:(null);IPVD:NLI;H:nwd2mta2.analog.com;RD:nwd2mail11.analog.com;EFVD:NLI Message-ID: <4EBCFBAA.5010408@analog.com> Date: Fri, 11 Nov 2011 11:40:42 +0100 From: Michael Hennerich Reply-To: Organization: Analog Devices Inc. User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.23) Gecko/20110921 Thunderbird/3.1.15 MIME-Version: 1.0 To: "jic23@cam.ac.uk" CC: "linux-iio@vger.kernel.org" , "linux-kernel@vger.kernel.org" , "guenter.roeck@ericsson.com" , "khali@linux-fr.org" , "dmitry.torokhov@gmail.com" , "broonie@opensource.wolfsonmicro.com" , "gregkh@suse.de" , "alan@lxorguk.ukuu.org.uk" , "arnd@arndb.de" , "linus.walleij@linaro.org" , "lars@metafoo.de" , "maxime.ripard@free-electrons.com" Subject: Re: [PATCH 1/6] IIO: Core sysfs only support. References: <1320677563-18378-1-git-send-email-jic23@cam.ac.uk> <1320677563-18378-2-git-send-email-jic23@cam.ac.uk> In-Reply-To: <1320677563-18378-2-git-send-email-jic23@cam.ac.uk> Content-Type: text/plain; charset="ISO-8859-1"; format=flowed Content-Transfer-Encoding: 7bit X-OriginatorOrg: analog.com Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 11/07/2011 03:52 PM, jic23@cam.ac.uk wrote: > From: Jonathan Cameron > > 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 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 > --- > 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 > +#include > +#include > +#include > +#include > +#include > + > +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__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"); > +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 > +#include > +#include > + > +/* 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 > +#include > + > +#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