summaryrefslogtreecommitdiffstats
path: root/drivers/iio/industrialio-core.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-09-22 20:30:12 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-09-22 20:30:12 +0200
commit3ffdea3feca9e2c95c2e93e217d77c9c368f747a (patch)
treee970c502cbd02244344ee1449af072d0d7086bbd /drivers/iio/industrialio-core.c
parentstaging/lustre: fix coccinelle warnings (diff)
parentiio: ti_am335x_adc: cleanup error case (diff)
downloadlinux-3ffdea3feca9e2c95c2e93e217d77c9c368f747a.tar.xz
linux-3ffdea3feca9e2c95c2e93e217d77c9c368f747a.zip
Merge tag 'iio-for-3.13a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes: First round of new drivers, functionality and cleanups for IIO in the 3.13 cycle A number of new drivers and some new functionality + a lot of cleanups all over IIO. New Core Elements 1) New INT_TIME info_mask element for integration time, which may have different effects on measurement noise and similar, than an amplifier and hence is different from existing SCALE. Already existed in some drivers as a custom attribute. 2) Introduce a iio_push_buffers_with_timestamp helper to cover the common case of filling the last 64 bits of data to be passed to the buffer with a timestamp. Applied to lots of drivers. Cuts down on repeated code and moves a slightly fiddly bit of logic into a single location. 3) Introduce info_mask_[shared_by_dir/shared_by_all] elements to allow support of elements such as sampling_frequency which is typically shared by all input channels on a device. This reduces code and makes these controls available from in kernel consumers of IIO devices. New drivers 1) MCP3422/3/4 ADC 2) TSL4531 ambient light sensor 3) TCS3472/5 color light sensor 4) GP2AP020A00F ambient light / proximity sensor 5) LPS001WP support added to ST pressure sensor driver. New driver functionality 1) ti_am335x_adc Add buffered sampling support. This device has a hardware fifo that is fed directly into an IIO kfifo buffer based on a watershed interrupt. Note this will act as an example of how to handle this increasingly common type of device. The only previous example - sca3000 - take a less than optimal approach which is largely why it is still in staging. A couple of little cleanups for that new functionality followed later. Core cleanups: 1) MAINTAINERS - Sachin actually brought my email address up to date because I said I'd do it and never got around to it :) 2) Assign buffer list elements as single element lists to simplify the iio_buffer_is_active logic. 3) wake_up_interruptible_poll instead of wake_up_interruptible to only wake up threads waiting for poll notifications. 4) Add O_CLOEXEC flag to anon_inode_get_fd call for IIO event interface. 5) Change iio_push_to_buffers to take a void * pointer so as to avoid some annoying and unnecessary type casts. 6) iio_compute_scan_bytes incorrectly took a long rather than unsigned long. 7) Various minor tidy ups. Driver cleanups (in no particular order) 1) Another set of devm_ allocations patches from Sachin Kamat. 2) tsl2x7x - 0 to NULL cleanup. 3) hmc5843 - fix missing > in MODULE_AUTHOR 4) Set of strict_strto* to kstrto* conversions. 5) mxs-lradc - fix ordering of resource removal to match creation 6) mxs-lradc - add MODULE_ALIAS 7) adc7606 - drop a work pending test duplicated in core functions. 8) hmc5843 - devm_ allocation patch 9) Series of redundant breaks removed. 10) ad2s1200 - pr_err -> dev_err 11) adjd_s311 - use INT_TIME 12) ST sensors - large set of cleanups from Lee Jones and removed restriction to using only triggers provided by the st_sensors themselves from Dennis Ciocca. 13) dummy and tmp006 provide sampling_frequency via info_mask_shared_by_all. 14) tcs3472 - fix incorrect buffer size and wrong device pointer used in suspend / resume functions. 15) max1363 - use defaults for buffer setup ops as provided by the triggered buffer helpers as they are the same as were specified in max1363 driver. 16) Trivial tidy ups in a number of other drivers.
Diffstat (limited to 'drivers/iio/industrialio-core.c')
-rw-r--r--drivers/iio/industrialio-core.c180
1 files changed, 111 insertions, 69 deletions
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 97f0297b120f..24db1855dbab 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -101,6 +101,7 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_PHASE] = "phase",
[IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain",
[IIO_CHAN_INFO_HYSTERESIS] = "hysteresis",
+ [IIO_CHAN_INFO_INT_TIME] = "integration_time",
};
const struct iio_chan_spec
@@ -516,14 +517,15 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
struct device_attribute *attr,
const char *buf,
size_t len),
- bool generic)
+ enum iio_shared_by shared_by)
{
- int ret;
- char *name_format, *full_postfix;
+ int ret = 0;
+ char *name_format = NULL;
+ char *full_postfix;
sysfs_attr_init(&dev_attr->attr);
/* Build up postfix of <extend_name>_<modifier>_postfix */
- if (chan->modified && !generic) {
+ if (chan->modified && (shared_by == IIO_SEPARATE)) {
if (chan->extend_name)
full_postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
iio_modifier_names[chan
@@ -544,53 +546,78 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
chan->extend_name,
postfix);
}
- if (full_postfix == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
+ if (full_postfix == NULL)
+ return -ENOMEM;
if (chan->differential) { /* Differential can not have modifier */
- if (generic)
+ switch (shared_by) {
+ case IIO_SHARED_BY_ALL:
+ name_format = kasprintf(GFP_KERNEL, "%s", full_postfix);
+ break;
+ case IIO_SHARED_BY_DIR:
+ name_format = kasprintf(GFP_KERNEL, "%s_%s",
+ iio_direction[chan->output],
+ full_postfix);
+ break;
+ case IIO_SHARED_BY_TYPE:
name_format
= kasprintf(GFP_KERNEL, "%s_%s-%s_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
iio_chan_type_name_spec[chan->type],
full_postfix);
- else if (chan->indexed)
+ break;
+ case IIO_SEPARATE:
+ if (!chan->indexed) {
+ WARN_ON("Differential channels must be indexed\n");
+ ret = -EINVAL;
+ goto error_free_full_postfix;
+ }
name_format
- = kasprintf(GFP_KERNEL, "%s_%s%d-%s%d_%s",
+ = kasprintf(GFP_KERNEL,
+ "%s_%s%d-%s%d_%s",
iio_direction[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;
+ break;
}
} else { /* Single ended */
- if (generic)
- name_format
- = kasprintf(GFP_KERNEL, "%s_%s_%s",
- iio_direction[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[chan->output],
- iio_chan_type_name_spec[chan->type],
- chan->channel,
- full_postfix);
- else
+ switch (shared_by) {
+ case IIO_SHARED_BY_ALL:
+ name_format = kasprintf(GFP_KERNEL, "%s", full_postfix);
+ break;
+ case IIO_SHARED_BY_DIR:
+ name_format = kasprintf(GFP_KERNEL, "%s_%s",
+ iio_direction[chan->output],
+ full_postfix);
+ break;
+ case IIO_SHARED_BY_TYPE:
name_format
= kasprintf(GFP_KERNEL, "%s_%s_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
full_postfix);
+ break;
+
+ case IIO_SEPARATE:
+ if (chan->indexed)
+ name_format
+ = kasprintf(GFP_KERNEL, "%s_%s%d_%s",
+ iio_direction[chan->output],
+ iio_chan_type_name_spec[chan->type],
+ chan->channel,
+ full_postfix);
+ else
+ name_format
+ = kasprintf(GFP_KERNEL, "%s_%s_%s",
+ iio_direction[chan->output],
+ iio_chan_type_name_spec[chan->type],
+ full_postfix);
+ break;
+ }
}
if (name_format == NULL) {
ret = -ENOMEM;
@@ -614,16 +641,11 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
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;
}
@@ -642,7 +664,7 @@ int __iio_add_chan_devattr(const char *postfix,
const char *buf,
size_t len),
u64 mask,
- bool generic,
+ enum iio_shared_by shared_by,
struct device *dev,
struct list_head *attr_list)
{
@@ -656,7 +678,7 @@ int __iio_add_chan_devattr(const char *postfix,
}
ret = __iio_device_attr_init(&iio_attr->dev_attr,
postfix, chan,
- readfunc, writefunc, generic);
+ readfunc, writefunc, shared_by);
if (ret)
goto error_iio_dev_attr_free;
iio_attr->c = chan;
@@ -664,7 +686,7 @@ int __iio_add_chan_devattr(const char *postfix,
list_for_each_entry(t, attr_list, l)
if (strcmp(t->dev_attr.attr.name,
iio_attr->dev_attr.attr.name) == 0) {
- if (!generic)
+ if (shared_by == IIO_SEPARATE)
dev_err(dev, "tried to double register : %s\n",
t->dev_attr.attr.name);
ret = -EBUSY;
@@ -682,46 +704,68 @@ error_ret:
return ret;
}
-static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan)
+static int iio_device_add_info_mask_type(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ enum iio_shared_by shared_by,
+ const long *infomask)
{
- int ret, attrcount = 0;
- int i;
- const struct iio_chan_spec_ext_info *ext_info;
+ int i, ret, attrcount = 0;
- if (chan->channel < 0)
- return 0;
- for_each_set_bit(i, &chan->info_mask_separate, sizeof(long)*8) {
+ for_each_set_bit(i, infomask, sizeof(infomask)*8) {
ret = __iio_add_chan_devattr(iio_chan_info_postfix[i],
chan,
&iio_read_channel_info,
&iio_write_channel_info,
i,
- 0,
+ shared_by,
&indio_dev->dev,
&indio_dev->channel_attr_list);
- if (ret < 0)
- goto error_ret;
- attrcount++;
- }
- for_each_set_bit(i, &chan->info_mask_shared_by_type, sizeof(long)*8) {
- ret = __iio_add_chan_devattr(iio_chan_info_postfix[i],
- chan,
- &iio_read_channel_info,
- &iio_write_channel_info,
- i,
- 1,
- &indio_dev->dev,
- &indio_dev->channel_attr_list);
- if (ret == -EBUSY) {
- ret = 0;
+ if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE))
continue;
- } else if (ret < 0) {
- goto error_ret;
- }
+ else if (ret < 0)
+ return ret;
attrcount++;
}
+ return attrcount;
+}
+
+static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan)
+{
+ int ret, attrcount = 0;
+ const struct iio_chan_spec_ext_info *ext_info;
+
+ if (chan->channel < 0)
+ return 0;
+ ret = iio_device_add_info_mask_type(indio_dev, chan,
+ IIO_SEPARATE,
+ &chan->info_mask_separate);
+ if (ret < 0)
+ return ret;
+ attrcount += ret;
+
+ ret = iio_device_add_info_mask_type(indio_dev, chan,
+ IIO_SHARED_BY_TYPE,
+ &chan->info_mask_shared_by_type);
+ if (ret < 0)
+ return ret;
+ attrcount += ret;
+
+ ret = iio_device_add_info_mask_type(indio_dev, chan,
+ IIO_SHARED_BY_DIR,
+ &chan->info_mask_shared_by_dir);
+ if (ret < 0)
+ return ret;
+ attrcount += ret;
+
+ ret = iio_device_add_info_mask_type(indio_dev, chan,
+ IIO_SHARED_BY_ALL,
+ &chan->info_mask_shared_by_all);
+ if (ret < 0)
+ return ret;
+ attrcount += ret;
+
if (chan->ext_info) {
unsigned int i = 0;
for (ext_info = chan->ext_info; ext_info->name; ext_info++) {
@@ -740,15 +784,13 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
continue;
if (ret)
- goto error_ret;
+ return ret;
attrcount++;
}
}
- ret = attrcount;
-error_ret:
- return ret;
+ return attrcount;
}
static void iio_device_remove_and_free_read_attr(struct iio_dev *indio_dev,