* [RFC PATCH 0/3] Experimenting with channel specification structures.
@ 2011-03-24 20:05 Jonathan Cameron
2011-03-24 20:05 ` [PATCH 1/3] staging:iio: allow channels to be set up using a table of iio_channel_spec structures Jonathan Cameron
` (3 more replies)
0 siblings, 4 replies; 12+ messages in thread
From: Jonathan Cameron @ 2011-03-24 20:05 UTC (permalink / raw)
To: linux-iio; +Cc: arnd, Jonathan Cameron
Hi All,
This set came out a suggestion of Arnd Bergmann that we look into
alternatives to the huge attribute tables that dominate some of the
current drivers (max1363 may be the worst).
To that end, what we have in this set is an initial stab at
at using an iio_chan_spec structure to specify an awful lot
about a given channel.
Advantages I can see from this experiement
1) Simple drivers are more consise.
2) It is infact possible to do this for a lot of cases (I had
my doubts ;)
3) It gives us many of the rigid constraints that the many
attribute macros now handle in a nice clean form.
Disadvantages:
1) The core code is rather more complex than I'd like.
2) There are cases I haven't yet worked out how to handle properly
- for example, our lis3l02dq used to output accel_mag_value
as the threshold value is shared across all high and low threshold
interrupts. Right now I have no way of specifying this level
of control for the events lines.
Also the use of shared event handlers is clunky to say the least.
This may go away when we rethink the event system though.
3) Putting hard requirements on numeric formatting of some
parameters is a pain. If nothing else I need to write a fixed point
input function.
Anyhow, all comments welcome. Personally I'm currently in favour of
this approach, but we will need routes around it for the 'odd'
cases. The trick is going to be limiting what we let through that
way to the absolute minimum of extremely device specific stuff.
Lots still to do here, and I need to take on one of the devices
where 'naming' the channels is important such as a light sensor...
At least in theory this set shouldn't 'break' anything.
Note it is on top of the general fixes I sent out last week.
Jonathan
p.s. Despite Arnd's original thread going to lkml I've kept this
on list for now (+ Arnd of course!) because I want to pin it down
a bit more before throwing it out more generally. Basically
this is big and ugly and I'm a wimp ;)
Jonathan Cameron (3):
staging:iio: allow channels to be set up using a table of
iio_channel_spec structures.
staging:iio:lis3l02dq - experimental move to new channel_spec
approach.
staging:iio:max1363 - experimental move to channel_spec registration.
drivers/staging/iio/accel/lis3l02dq.h | 13 +-
drivers/staging/iio/accel/lis3l02dq_core.c | 525 +++++-------
drivers/staging/iio/accel/lis3l02dq_ring.c | 228 ++---
drivers/staging/iio/adc/max1363.h | 8 +-
drivers/staging/iio/adc/max1363_core.c | 1277 +++++++++++-----------------
drivers/staging/iio/adc/max1363_ring.c | 1 -
drivers/staging/iio/chrdev.h | 3 +
drivers/staging/iio/iio.h | 157 ++++
drivers/staging/iio/industrialio-core.c | 535 ++++++++++++-
drivers/staging/iio/industrialio-ring.c | 188 ++++-
drivers/staging/iio/ring_generic.h | 19 +
drivers/staging/iio/sysfs.h | 31 +-
12 files changed, 1693 insertions(+), 1292 deletions(-)
--
1.7.3.4
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/3] staging:iio: allow channels to be set up using a table of iio_channel_spec structures.
2011-03-24 20:05 [RFC PATCH 0/3] Experimenting with channel specification structures Jonathan Cameron
@ 2011-03-24 20:05 ` Jonathan Cameron
2011-03-25 14:37 ` Arnd Bergmann
2011-03-24 20:05 ` [PATCH 2/3] staging:iio:lis3l02dq - experimental move to new channel_spec approach Jonathan Cameron
` (2 subsequent siblings)
3 siblings, 1 reply; 12+ messages in thread
From: Jonathan Cameron @ 2011-03-24 20:05 UTC (permalink / raw)
To: linux-iio; +Cc: arnd, Jonathan Cameron
This is a VERY early version - lots to work out yet.
---
drivers/staging/iio/chrdev.h | 3 +
drivers/staging/iio/iio.h | 157 +++++++++
drivers/staging/iio/industrialio-core.c | 535 ++++++++++++++++++++++++++++++-
drivers/staging/iio/industrialio-ring.c | 188 +++++++++++-
drivers/staging/iio/ring_generic.h | 19 ++
drivers/staging/iio/sysfs.h | 31 ++-
6 files changed, 910 insertions(+), 23 deletions(-)
diff --git a/drivers/staging/iio/chrdev.h b/drivers/staging/iio/chrdev.h
index 98d1a2c..95b439e 100644
--- a/drivers/staging/iio/chrdev.h
+++ b/drivers/staging/iio/chrdev.h
@@ -91,6 +91,9 @@ struct iio_event_interface {
void *private;
char _name[35];
char _attrname[20];
+
+ struct list_head event_attr_list;
+ struct list_head dev_attr_list;
};
/**
diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h
index bf84799..43da02c 100644
--- a/drivers/staging/iio/iio.h
+++ b/drivers/staging/iio/iio.h
@@ -26,6 +26,138 @@
struct iio_dev;
+/* naughty temporary hack to match these against the event version
+ - need to flattern these together */
+enum iio_chan_type {
+ /* Need this here for now to support buffer events
+ * set to 0 to avoid changes to ring_generic.c */
+ IIO_BUFFER = 0,
+
+ /* real channel types */
+ IIO_IN,
+ IIO_ACCEL,
+ IIO_IN_DIFF,
+ IIO_GYRO,
+ IIO_MAGN,
+ IIO_LIGHT,
+ IIO_PROXIMITY,
+ IIO_TIMESTAMP,
+};
+
+/* Could add the raw attributes as well - allowing buffer only devices */
+enum iio_chan_info_enum {
+ IIO_CHAN_INFO_SCALE_SHARED,
+ IIO_CHAN_INFO_SCALE_SEPARATE,
+ IIO_CHAN_INFO_OFFSET_SHARED,
+ IIO_CHAN_INFO_OFFSET_SEPARATE,
+ IIO_CHAN_INFO_CALIBSCALE_SHARED,
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE,
+ IIO_CHAN_INFO_CALIBBIAS_SHARED,
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE
+};
+
+/**
+ * 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.
+ * @address: driver specific identifier.
+ * @scan_index: monotonic index to give ordering in scans when read
+ * from a buffer.
+ * @scan_type: sign is 's' or 'u' to specify signed or unsigned
+ * realbits is the number of valid bits of data
+ * storage bits is realbits + padding
+ * shift tells you how much to shift right before masking
+ * out realbits.
+ * @info_mask: what information is to be exported about this channel.
+ * This includes calibbias, scale etc.
+ * @event_mask: what events can this channel produce.
+ * @shared_handler: single handler for the events registered.
+ */
+struct iio_chan_spec {
+ enum iio_chan_type type;
+ int channel;
+ int channel2;
+ int address;
+ int scan_index;
+ struct {
+ char sign;
+ u8 realbits;
+ u8 storagebits;
+ u8 shift;
+ } scan_type;
+ const long info_mask;
+ const long event_mask;
+ //how to handle device with sets of shared events?
+ //perhaps we push the event handling out into the drivers.
+ struct iio_event_handler_list *shared_handler;
+};
+/* Meant for internal use only */
+void __iio_device_attr_deinit(struct device_attribute *dev_attr);
+int __iio_device_attr_init(struct device_attribute *dev_attr,
+ const char *postfix,
+ struct iio_chan_spec *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);
+#define IIO_ST(si, rb, sb, sh) \
+ { .sign = si, .realbits = rb, .storagebits = sb, .shift = sh }
+
+#define IIO_CHAN(_type, _chan, _inf_mask, _address, _si, _stype) \
+ { .type = _type, .channel = _chan, .info_mask = _inf_mask, \
+ .address = _address, \
+ .scan_index = _si, .scan_type = _stype }
+
+#define IIO_CHAN_EV(_type, _chan, _inf_mask, _address, _si, \
+ _stype, _event_mask, _shared_h) \
+ { .type = _type, \
+ .channel = _chan, \
+ .info_mask = _inf_mask, \
+ .address = _address, \
+ .scan_index = _si, .scan_type = _stype, \
+ .event_mask = _event_mask, \
+ .shared_handler = _shared_h }
+
+#define IIO_CHAN_COMPOUND(_type, _chan1, _chan2, _inf_mask,_address, _si, _stype) \
+ { .type = _type, .channel = _chan1, .channel2 = _chan2, \
+ .info_mask = _inf_mask, \
+ .address = _address, \
+ .scan_index = _si, .scan_type = _stype }
+
+#define IIO_CHAN_COMPOUND_EV(_type, _chan1, _chan2, _inf_mask, \
+ _address, _si, _stype, _event_mask, _shared_h) \
+ { .type = _type, \
+ .channel = _chan1, .channel2 = _chan2, \
+ .info_mask = _inf_mask, \
+ .address = _address, \
+ .scan_index = _si, .scan_type = _stype, \
+ .event_mask = _event_mask, \
+ .shared_handler = _shared_h}
+
+#define IIO_CHAN_SOFT_TIMESTAMP(_si) \
+ { .type = IIO_TIMESTAMP, .channel = -1, \
+ .scan_index = _si, .scan_type = IIO_ST('s', 64, 64, 0) }
+
+int __iio_add_chan_devattr(const char *postfix,
+ const char *group,
+ struct iio_chan_spec *chan,
+ ssize_t (*func)(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),
+ int mask,
+ bool generic,
+ struct device *dev,
+ struct list_head *attr_list);
/**
* iio_get_time_ns() - utility function to get a time stamp for events etc
**/
@@ -116,6 +248,31 @@ struct iio_dev {
u32 *available_scan_masks;
struct iio_trigger *trig;
struct iio_poll_func *pollfunc;
+
+ struct iio_chan_spec *channels;
+ int num_channels;
+ struct list_head channel_attr_list;
+
+ char *name; /*device name - IMPLEMENT */
+ int (*read_raw)(struct iio_dev *indio_dev,
+ struct iio_chan_spec *chan,
+ int *val,
+ long mask);
+
+ int (*read_event_config)(struct iio_dev *indio_dev,
+ int event_code);
+
+ int (*write_event_config)(struct iio_dev *indio_dev,
+ int event_code,
+ struct iio_event_handler_list *listel,
+ int state);
+
+ int (*read_event_value)(struct iio_dev *indio_dev,
+ int event_code,
+ int *val);
+ int (*write_event_value)(struct iio_dev *indio_dev,
+ int event_code,
+ int val);
};
/**
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c
index 54a61a3..e3b76b4 100644
--- a/drivers/staging/iio/industrialio-core.c
+++ b/drivers/staging/iio/industrialio-core.c
@@ -44,6 +44,28 @@ struct bus_type iio_bus_type = {
};
EXPORT_SYMBOL(iio_bus_type);
+static const char *iio_chan_type_name_spec_shared[] = {
+ [IIO_TIMESTAMP] = "timestamp",
+ [IIO_ACCEL] = "accel",
+ [IIO_IN] = "in",
+ [IIO_IN_DIFF] = "in-in",
+};
+
+static const char *iio_chan_type_name_spec[] = {
+ [IIO_TIMESTAMP] = "timestamp",
+ [IIO_ACCEL] = "accel_%c",
+ [IIO_IN] = "in%d",
+ [IIO_IN_DIFF] = "in%d-in%d",
+};
+
+/* relies on pairs of these shared then separate */
+static const char *iio_chan_info_postfix[] = {
+ [IIO_CHAN_INFO_SCALE_SHARED/2] = "scale",
+ [IIO_CHAN_INFO_OFFSET_SHARED/2] = "offset",
+ [IIO_CHAN_INFO_CALIBSCALE_SHARED/2] = "calibscale",
+ [IIO_CHAN_INFO_CALIBBIAS_SHARED/2] = "calibbias",
+};
+
void __iio_change_event(struct iio_detected_event_list *ev,
int ev_code,
s64 timestamp)
@@ -488,9 +510,218 @@ static void __exit iio_exit(void)
bus_unregister(&iio_bus_type);
}
+static ssize_t iio_read_single_channel(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, ret;
+
+ ret = indio_dev->read_raw(indio_dev, this_attr->c, &val, 0);
+
+ return ret < 0 ? ret : sprintf(buf, "%d\n", val);
+}
+
+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;
+ int ret = indio_dev->read_raw(indio_dev, this_attr->c,
+ &val, this_attr->address);
+
+ if (ret < 0)
+ return ret;
+ else /* may want a longer type for val */
+ return sprintf(buf, "%d.%06ld\n", val/1000000,
+ abs(val)%1000000);
+}
+
+static ssize_t iio_write_channel_info(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ /* To be implemented - need to decide if we pass a number
+ on to the drivers or a string and let them do the handling
+ */
+ return len;
+}
+
+int __iio_device_attr_init(struct device_attribute *dev_attr,
+ const char *postfix,
+ struct iio_chan_spec *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;
+ sysfs_attr_init(&dev_attr->attr);
+ if (generic)
+ name_format
+ = kasprintf(GFP_KERNEL, "%s_%s",
+ iio_chan_type_name_spec_shared[chan->type],
+ postfix);
+ else
+ name_format = kasprintf(GFP_KERNEL, "%s_%s",
+ iio_chan_type_name_spec[chan->type],
+ postfix);
+ if (name_format == NULL) {
+ ret = ENOMEM;
+ goto error_ret;
+ }
+
+ 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);
+
+ return 0;
+
+error_free_name_format:
+ kfree(name_format);
+error_ret:
+ return ret;
+}
+
+void __iio_device_attr_deinit(struct device_attribute *dev_attr)
+{
+ kfree(dev_attr->attr.name);
+}
+
+int __iio_add_chan_devattr(const char *postfix,
+ const char *group,
+ struct iio_chan_spec *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),
+ int 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_iio_dev_attr_free;
+ }
+
+ ret = sysfs_add_file_to_group(&dev->kobj,
+ &iio_attr->dev_attr.attr, group);
+ if (ret < 0)
+ 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 *dev_info,
+ struct iio_chan_spec *chan)
+{
+ int ret, i;
+
+
+ if (chan->channel < 0)
+ return 0;
+
+ ret = __iio_add_chan_devattr("raw", NULL, chan,
+ &iio_read_single_channel,
+ NULL,
+ 0,
+ 0,
+ &dev_info->dev,
+ &dev_info->channel_attr_list);
+ if (ret)
+ goto error_ret;
+
+ for_each_set_bit(i, &chan->info_mask, sizeof(long)*8) {
+ ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2],
+ NULL, chan,
+ &iio_read_channel_info,
+ &iio_write_channel_info,
+ (1 << i),
+ !(i%2),
+ &dev_info->dev,
+ &dev_info->channel_attr_list);
+ if (ret == -EBUSY && (i%2 == 0)) {
+ ret = 0;
+ continue;
+ }
+ if (ret < 0)
+ goto error_ret;
+ }
+error_ret:
+ return ret;
+}
+
+static void iio_device_remove_and_free_read_attr(struct iio_dev *dev_info,
+ struct iio_dev_attr *p)
+{
+ sysfs_remove_file_from_group(&dev_info->dev.kobj,
+ &p->dev_attr.attr, NULL);
+ kfree(p->dev_attr.attr.name);
+ kfree(p);
+}
+
static int iio_device_register_sysfs(struct iio_dev *dev_info)
{
- int ret = 0;
+ int i, ret = 0;
+ struct iio_dev_attr *p, *n;
ret = sysfs_create_group(&dev_info->dev.kobj, dev_info->attrs);
if (ret) {
@@ -499,12 +730,39 @@ static int iio_device_register_sysfs(struct iio_dev *dev_info)
goto error_ret;
}
+ /* New channel registration method - currently assumes at there
+ * is an existing group to which attributes are to be added*/
+ if (dev_info->channels) {
+ INIT_LIST_HEAD(&dev_info->channel_attr_list);
+ for (i = 0; i < dev_info->num_channels; i++) {
+ ret = iio_device_add_channel_sysfs(dev_info,
+ &dev_info
+ ->channels[i]);
+ if (ret < 0)
+ goto error_clear_attrs;
+ }
+ }
+ return 0;
+error_clear_attrs:
+ list_for_each_entry_safe(p, n,
+ &dev_info->channel_attr_list, l)
+ iio_device_remove_and_free_read_attr(dev_info, p);
+
+ sysfs_remove_group(&dev_info->dev.kobj, dev_info->attrs);
error_ret:
return ret;
+
}
static void iio_device_unregister_sysfs(struct iio_dev *dev_info)
{
+
+ struct iio_dev_attr *p, *n;
+ if (dev_info->channels)
+ list_for_each_entry_safe(p, n,
+ &dev_info->channel_attr_list, l)
+ iio_device_remove_and_free_read_attr(dev_info, p);
+
sysfs_remove_group(&dev_info->dev.kobj, dev_info->attrs);
}
@@ -552,6 +810,225 @@ static void iio_device_unregister_id(struct iio_dev *dev_info)
iio_free_ida_val(&iio_ida, dev_info->id);
}
+static const char *iio_ev_type_text[] = {
+ [IIO_EV_TYPE_THRESH] = "thresh",
+ [IIO_EV_TYPE_MAG] = "mag",
+ [IIO_EV_TYPE_ROC] = "roc"
+};
+
+static const char *iio_ev_dir_text[] = {
+ [IIO_EV_DIR_EITHER] = "either",
+ [IIO_EV_DIR_RISING] = "rising",
+ [IIO_EV_DIR_FALLING] = "falling"
+};
+
+static ssize_t iio_ev_state_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_event_attr *this_attr = to_iio_event_attr(attr);
+ int ret;
+ unsigned long val;
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret || val < 0 || val > 1)
+ return -EINVAL;
+
+ ret = indio_dev->write_event_config(indio_dev, this_attr->mask,
+ this_attr->listel,
+ val);
+ return (ret < 0) ? ret : len;
+}
+
+static ssize_t iio_ev_state_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_event_attr *this_attr = to_iio_event_attr(attr);
+ int val = indio_dev->read_event_config(indio_dev, this_attr->mask);
+
+ if (val < 0)
+ return val;
+ else
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t iio_ev_value_show(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, ret;
+
+ ret = indio_dev->read_event_value(indio_dev,
+ this_attr->address, &val);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t iio_ev_value_store(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);
+ unsigned long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ ret = indio_dev->write_event_value(indio_dev, this_attr->address,
+ val);
+ if (ret < 0)
+ return ret;
+
+ return len;
+}
+
+static int __iio_add_chan_event_attr(const char *postfix,
+ const char *group,
+ struct iio_chan_spec *chan,
+ unsigned int mask,
+ struct device *dev,
+ struct list_head *attr_list)
+{
+ char *name_format;
+ int ret;
+ struct iio_event_attr *iio_ev_attr;
+
+ iio_ev_attr = kzalloc(sizeof *iio_ev_attr, GFP_KERNEL);
+ if (iio_ev_attr == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ sysfs_attr_init(&iio_ev_attr->dev_attr.attr);
+
+ name_format = kasprintf(GFP_KERNEL, "%s_%s",
+ iio_chan_type_name_spec[chan->type],
+ postfix);
+ if (name_format == NULL) {
+ ret = -ENOMEM;
+ goto error_free_attr;
+ }
+
+ iio_ev_attr->dev_attr.attr.name = kasprintf(GFP_KERNEL,
+ name_format,
+ chan->channel,
+ chan->channel2);
+ if (iio_ev_attr->dev_attr.attr.name == NULL) {
+ ret = -ENOMEM;
+ goto error_free_name_format;
+ }
+
+ iio_ev_attr->dev_attr.attr.mode = S_IRUGO | S_IWUSR;
+ iio_ev_attr->dev_attr.show = &iio_ev_state_show;
+ iio_ev_attr->dev_attr.store = &iio_ev_state_store;
+ iio_ev_attr->mask = mask;
+ iio_ev_attr->listel = chan->shared_handler;
+ ret = sysfs_add_file_to_group(&dev->kobj,
+ &iio_ev_attr->dev_attr.attr,
+ group);
+ if (ret < 0)
+ goto error_free_name;
+ list_add(&iio_ev_attr->l, attr_list);
+ kfree(name_format);
+ return 0;
+
+error_free_name:
+ kfree(iio_ev_attr->dev_attr.attr.name);
+error_free_name_format:
+ kfree(name_format);
+error_free_attr:
+ kfree(iio_ev_attr);
+error_ret:
+ return ret;
+}
+
+
+static int iio_device_add_event_sysfs(struct iio_dev *dev_info,
+ struct iio_chan_spec *chan)
+{
+
+ int ret = 0, i, mask;
+ char *postfix;
+ if (!chan->event_mask)
+ return 0;
+
+ for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) {
+ postfix = kasprintf(GFP_KERNEL, "%s_%s_en",
+ iio_ev_type_text[i/IIO_EV_TYPE_MAX],
+ iio_ev_dir_text[i%IIO_EV_TYPE_MAX]);
+ if (postfix == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ switch (chan->type) {
+ //TODO, use a table so as to make it easy to add more types
+ case IIO_IN:
+
+ mask = IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
+ i/IIO_EV_TYPE_MAX,
+ i%IIO_EV_TYPE_MAX);
+ break;
+ case IIO_ACCEL:
+ mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel,
+ i/IIO_EV_TYPE_MAX,
+ i%IIO_EV_TYPE_MAX);
+ break;
+ default:
+ printk("currently unhandled\n");
+ }
+ ret = __iio_add_chan_event_attr(postfix,
+ NULL,
+ chan,
+ mask,
+ /*HACK. - limits us to one
+ event interface - fix by
+ extending the bitmask - but
+ how far*/
+ &dev_info->event_interfaces[0]
+ .dev,
+ &dev_info->event_interfaces[0].
+ event_attr_list);
+ kfree(postfix);
+ if (ret)
+ goto error_ret;
+
+ postfix = kasprintf(GFP_KERNEL, "%s_%s_value",
+ iio_ev_type_text[i/IIO_EV_TYPE_MAX],
+ iio_ev_dir_text[i%IIO_EV_TYPE_MAX]);
+ if (postfix == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ ret = __iio_add_chan_devattr(postfix, NULL, chan,
+ iio_ev_value_show,
+ iio_ev_value_store,
+ mask,
+ 0,
+ &dev_info->event_interfaces[0]
+ .dev,
+ &dev_info->event_interfaces[0]
+ .dev_attr_list);
+ kfree(postfix);
+ if (ret)
+ goto error_ret;
+
+ }
+
+error_ret:
+ return ret;
+}
+
static inline int __iio_add_event_config_attrs(struct iio_dev *dev_info, int i)
{
int ret;
@@ -570,7 +1047,22 @@ static inline int __iio_add_event_config_attrs(struct iio_dev *dev_info, int i)
attrp++;
}
}
+ INIT_LIST_HEAD(&dev_info->event_interfaces[0].event_attr_list);
+ INIT_LIST_HEAD(&dev_info->event_interfaces[0].dev_attr_list);
+ /* Dynically created from the channels array */
+ if (dev_info->channels) {
+ for (i = 0; i < dev_info->num_channels; i++) {
+ ret = iio_device_add_event_sysfs(dev_info,
+ &dev_info
+ ->channels[i]);
+ if (ret)
+ goto error_clear_attrs;
+
+ }
+ }
return 0;
+error_clear_attrs:
+ //to implement - shared code with the similar bits elsewhere.
error_ret:
attrq = dev_info->event_conf_attrs[i].attrs;
@@ -603,6 +1095,14 @@ static inline int __iio_remove_event_config_attrs(struct iio_dev *dev_info,
return 0;
}
+static struct attribute *iio_event_dummy_attrs[] = {
+ NULL
+};
+
+static struct attribute_group iio_event_dummy_attr_group = {
+ .name = NULL,
+ .attrs = iio_event_dummy_attrs,
+};
static int iio_device_register_eventset(struct iio_dev *dev_info)
{
@@ -650,10 +1150,17 @@ static int iio_device_register_eventset(struct iio_dev *dev_info)
dev_set_drvdata(&dev_info->event_interfaces[i].dev,
(void *)dev_info);
- ret = sysfs_create_group(&dev_info
- ->event_interfaces[i]
- .dev.kobj,
- &dev_info->event_attrs[i]);
+
+ if (dev_info->event_attrs == NULL)
+ ret = sysfs_create_group(&dev_info
+ ->event_interfaces[i]
+ .dev.kobj,
+ &iio_event_dummy_attr_group);
+ else
+ ret = sysfs_create_group(&dev_info
+ ->event_interfaces[i]
+ .dev.kobj,
+ &dev_info->event_attrs[i]);
if (ret) {
dev_err(&dev_info->dev,
@@ -676,7 +1183,12 @@ error_unregister_config_attrs:
i = dev_info->num_interrupt_lines - 1;
error_remove_sysfs_interfaces:
for (j = 0; j < i; j++)
- sysfs_remove_group(&dev_info
+ if (dev_info->event_attrs == NULL)
+ sysfs_remove_group(&dev_info
+ ->event_interfaces[j].dev.kobj,
+ &iio_event_dummy_attr_group);
+ else
+ sysfs_remove_group(&dev_info
->event_interfaces[j].dev.kobj,
&dev_info->event_attrs[j]);
error_free_setup_ev_ints:
@@ -697,9 +1209,14 @@ static void iio_device_unregister_eventset(struct iio_dev *dev_info)
if (dev_info->num_interrupt_lines == 0)
return;
for (i = 0; i < dev_info->num_interrupt_lines; i++)
- sysfs_remove_group(&dev_info
- ->event_interfaces[i].dev.kobj,
- &dev_info->event_attrs[i]);
+ if (dev_info->event_attrs == NULL)
+ sysfs_remove_group(&dev_info
+ ->event_interfaces[i].dev.kobj,
+ &iio_event_dummy_attr_group);
+ else
+ sysfs_remove_group(&dev_info
+ ->event_interfaces[i].dev.kobj,
+ &dev_info->event_attrs[i]);
for (i = 0; i < dev_info->num_interrupt_lines; i++)
iio_free_ev_int(&dev_info->event_interfaces[i]);
diff --git a/drivers/staging/iio/industrialio-ring.c b/drivers/staging/iio/industrialio-ring.c
index 3f6bee0..1dfbc6e 100644
--- a/drivers/staging/iio/industrialio-ring.c
+++ b/drivers/staging/iio/industrialio-ring.c
@@ -233,9 +233,162 @@ void iio_ring_buffer_init(struct iio_ring_buffer *ring,
}
EXPORT_SYMBOL(iio_ring_buffer_init);
-int iio_ring_buffer_register(struct iio_ring_buffer *ring, int id)
+static ssize_t iio_show_scan_index(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ return sprintf(buf, "%u\n", this_attr->c->scan_index);
+}
+
+static ssize_t iio_show_fixed_type(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ return sprintf(buf, "%c%d/%d>>%u\n",
+ this_attr->c->scan_type.sign,
+ this_attr->c->scan_type.realbits,
+ this_attr->c->scan_type.storagebits,
+ this_attr->c->scan_type.shift);
+}
+
+static int __iio_add_chan_scan_elattr(const char *postfix,
+ const char *group,
+ struct iio_chan_spec *chan,
+ struct device *dev,
+ struct list_head *attr_list)
{
int ret;
+ struct iio_scan_el *scan_el;
+
+ scan_el = kzalloc(sizeof *scan_el, GFP_KERNEL);
+ if (scan_el == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ if (chan->type != IIO_TIMESTAMP)
+ ret = __iio_device_attr_init(&scan_el->dev_attr, postfix, chan,
+ iio_scan_el_show,
+ iio_scan_el_store, 0);
+ else /*
+ * Timestamp handled separately because it simplifies a lot of
+ * drivers by ensuring they don't have to know its magic index
+ */
+ ret = __iio_device_attr_init(&scan_el->dev_attr, postfix, chan,
+ iio_scan_el_ts_show,
+ iio_scan_el_ts_store, 0);
+ if (ret)
+ goto error_free_scan_el;
+
+ scan_el->number = chan->scan_index;
+
+ ret = sysfs_add_file_to_group(&dev->kobj,
+ &scan_el->dev_attr.attr,
+ group);
+ if (ret < 0)
+ goto error_device_attr_deinit;
+
+ list_add(&scan_el->l, attr_list);
+
+ return 0;
+error_device_attr_deinit:
+ __iio_device_attr_deinit(&scan_el->dev_attr);
+error_free_scan_el:
+ kfree(scan_el);
+error_ret:
+ return ret;
+}
+
+static int iio_ring_add_channel_sysfs(struct iio_ring_buffer *ring,
+ struct iio_chan_spec *chan)
+{
+ int ret;
+
+ ret = __iio_add_chan_devattr("index", "scan_elements",
+ chan,
+ &iio_show_scan_index,
+ NULL,
+ 0,
+ 0,
+ &ring->dev,
+ &ring->scan_el_dev_attr_list);
+ if (ret)
+ goto error_ret;
+
+ ret = __iio_add_chan_devattr("type", "scan_elements",
+ chan,
+ &iio_show_fixed_type,
+ NULL,
+ 0,
+ 0,
+ &ring->dev,
+ &ring->scan_el_dev_attr_list);
+
+ if (ret)
+ goto error_ret;
+
+ ret = __iio_add_chan_scan_elattr("en", "scan_elements",
+ chan, &ring->dev,
+ &ring->scan_el_en_attr_list);
+
+error_ret:
+ return ret;
+}
+
+static void iio_ring_remove_and_free_scan_el_attr(struct iio_ring_buffer *ring,
+ struct iio_scan_el *p)
+{
+ sysfs_remove_file_from_group(&ring->dev.kobj,
+ &p->dev_attr.attr, "scan_elements");
+ kfree(p->dev_attr.attr.name);
+ kfree(p);
+}
+
+static void iio_ring_remove_and_free_scan_dev_attr(struct iio_ring_buffer *ring,
+ struct iio_dev_attr *p)
+{
+ sysfs_remove_file_from_group(&ring->dev.kobj,
+ &p->dev_attr.attr, "scan_elements");
+ kfree(p->dev_attr.attr.name);
+ kfree(p);
+}
+
+static struct attribute *iio_scan_el_dummy_attrs[] = {
+ NULL
+};
+
+static struct attribute_group iio_scan_el_dummy_group = {
+ .name = "scan_elements",
+ .attrs = iio_scan_el_dummy_attrs
+};
+
+static void __iio_ring_attr_cleanup(struct iio_ring_buffer *ring)
+{
+ struct iio_dev_attr *p, *n;
+ struct iio_scan_el *q, *m;
+ int anydynamic = !(list_empty(&ring->scan_el_dev_attr_list) &&
+ list_empty(&ring->scan_el_en_attr_list));
+ list_for_each_entry_safe(p, n,
+ &ring->scan_el_dev_attr_list, l)
+ iio_ring_remove_and_free_scan_dev_attr(ring, p);
+ list_for_each_entry_safe(q, m,
+ &ring->scan_el_en_attr_list, l)
+ iio_ring_remove_and_free_scan_el_attr(ring, q);
+
+ if (ring->scan_el_attrs)
+ sysfs_remove_group(&ring->dev.kobj,
+ ring->scan_el_attrs);
+ else if (anydynamic)
+ sysfs_remove_group(&ring->dev.kobj,
+ &iio_scan_el_dummy_group);
+}
+
+int iio_ring_buffer_register_ex(struct iio_ring_buffer *ring, int id,
+ struct iio_chan_spec *channels,
+ int num_channels)
+{
+ int ret, i;
ring->id = id;
@@ -268,9 +421,28 @@ int iio_ring_buffer_register(struct iio_ring_buffer *ring, int id)
"Failed to add sysfs scan elements\n");
goto error_free_ring_buffer_event_chrdev;
}
+ } else if (channels) {
+ ret = sysfs_create_group(&ring->dev.kobj,
+ &iio_scan_el_dummy_group);
+ if (ret)
+ goto error_free_ring_buffer_event_chrdev;
}
- return ret;
+
+ INIT_LIST_HEAD(&ring->scan_el_dev_attr_list);
+ INIT_LIST_HEAD(&ring->scan_el_en_attr_list);
+ if (channels) {
+ /* new magic */
+ for (i = 0; i < num_channels; i++) {
+ ret = iio_ring_add_channel_sysfs(ring, &channels[i]);
+ if (ret < 0)
+ goto error_cleanup_dynamic;
+ }
+ }
+
+ return 0;
+error_cleanup_dynamic:
+ __iio_ring_attr_cleanup(ring);
error_free_ring_buffer_event_chrdev:
__iio_free_ring_buffer_event_chrdev(ring);
error_remove_device:
@@ -278,14 +450,17 @@ error_remove_device:
error_ret:
return ret;
}
+EXPORT_SYMBOL(iio_ring_buffer_register_ex);
+
+int iio_ring_buffer_register(struct iio_ring_buffer *ring, int id)
+{
+ return iio_ring_buffer_register_ex(ring, id, NULL, 0);
+}
EXPORT_SYMBOL(iio_ring_buffer_register);
void iio_ring_buffer_unregister(struct iio_ring_buffer *ring)
{
- if (ring->scan_el_attrs)
- sysfs_remove_group(&ring->dev.kobj,
- ring->scan_el_attrs);
-
+ __iio_ring_attr_cleanup(ring);
__iio_free_ring_buffer_access_chrdev(ring);
__iio_free_ring_buffer_event_chrdev(ring);
device_del(&ring->dev);
@@ -540,4 +715,3 @@ error_ret:
return ret ? ret : len;
}
EXPORT_SYMBOL(iio_scan_el_ts_store);
-
diff --git a/drivers/staging/iio/ring_generic.h b/drivers/staging/iio/ring_generic.h
index bae2d6d..8ffbdc5 100644
--- a/drivers/staging/iio/ring_generic.h
+++ b/drivers/staging/iio/ring_generic.h
@@ -140,6 +140,8 @@ struct iio_ring_buffer {
int (*predisable)(struct iio_dev *);
int (*postdisable)(struct iio_dev *);
+ struct list_head scan_el_dev_attr_list;
+ struct list_head scan_el_en_attr_list;
};
/**
@@ -177,6 +179,7 @@ struct iio_scan_el {
struct device_attribute dev_attr;
unsigned int number;
unsigned int label;
+ struct list_head l;
int (*set_state)(struct iio_scan_el *scanel,
struct iio_dev *dev_info,
@@ -430,6 +433,13 @@ static inline void iio_put_ring_buffer(struct iio_ring_buffer *ring)
**/
int iio_ring_buffer_register(struct iio_ring_buffer *ring, int id);
+/** iio_ring_buffer_register_ex() - register the buffer with IIO core
+ * @ring: the buffer to be registered
+ * @id: the id of the buffer (typically 0)
+ **/
+int iio_ring_buffer_register_ex(struct iio_ring_buffer *ring, int id,
+ struct iio_chan_spec *channels, int num_channels);
+
/**
* iio_ring_buffer_unregister() - unregister the buffer from IIO core
* @ring: the buffer to be unregistered
@@ -481,6 +491,15 @@ static inline int iio_ring_buffer_register(struct iio_ring_buffer *ring, int id)
{
return 0;
};
+
+static inline int iio_ring_buffer_register_ex(struct iio_ring_buffer *ring,
+ int id,
+ struct iio_chan_spec *channels,
+ int num_channels)
+{
+ return 0;
+}
+
static inline void iio_ring_buffer_unregister(struct iio_ring_buffer *ring)
{};
diff --git a/drivers/staging/iio/sysfs.h b/drivers/staging/iio/sysfs.h
index 24b74dd..17ddf36 100644
--- a/drivers/staging/iio/sysfs.h
+++ b/drivers/staging/iio/sysfs.h
@@ -24,6 +24,7 @@ struct iio_event_attr {
struct device_attribute dev_attr;
int mask;
struct iio_event_handler_list *listel;
+ struct list_head l;
};
#define to_iio_event_attr(_dev_attr) \
@@ -34,11 +35,15 @@ struct iio_event_attr {
* @dev_attr: underlying device attribute
* @address: associated register address
* @val2: secondary attribute value
+ * @l: list head for maintaining list of dynamically created attrs.
*/
struct iio_dev_attr {
struct device_attribute dev_attr;
int address;
int val2;
+ struct list_head l;
+ //should be able to get this out of here. But is it worth it?
+ struct iio_chan_spec *c;
};
#define to_iio_dev_attr(_dev_attr) \
@@ -259,13 +264,14 @@ struct iio_const_attr {
#define IIO_EVENT_ATTR_DATA_RDY(_show, _store, _mask, _handler) \
IIO_EVENT_ATTR(data_rdy, _show, _store, _mask, _handler)
-#define IIO_EV_CLASS_BUFFER 0
-#define IIO_EV_CLASS_IN 1
-#define IIO_EV_CLASS_ACCEL 2
-#define IIO_EV_CLASS_GYRO 3
-#define IIO_EV_CLASS_MAGN 4
-#define IIO_EV_CLASS_LIGHT 5
-#define IIO_EV_CLASS_PROXIMITY 6
+/* must match our channel defs */
+#define IIO_EV_CLASS_IN IIO_IN
+#define IIO_EV_CLASS_ACCEL IIO_ACCEL
+#define IIO_EV_CLASS_GYRO IIO_GYRO
+#define IIO_EV_CLASS_MAGN IIO_MAGN
+#define IIO_EV_CLASS_LIGHT IIO_LIGHT
+#define IIO_EV_CLASS_PROXIMITY IIO_PROXIMITY
+#define IIO_EV_CLASS_BUFFER IIO_BUFFER
#define IIO_EV_MOD_X 0
#define IIO_EV_MOD_Y 1
@@ -287,6 +293,10 @@ struct iio_const_attr {
#define IIO_EV_DIR_RISING 1
#define IIO_EV_DIR_FALLING 2
+#define IIO_EV_TYPE_MAX 8
+#define IIO_EV_BIT(type, direction) \
+ 1 << (type*IIO_EV_TYPE_MAX + direction)
+
#define IIO_EVENT_CODE(channelclass, orient_bit, number, \
modifier, type, direction) \
(channelclass | (orient_bit << 8) | ((number) << 9) | \
@@ -303,6 +313,13 @@ struct iio_const_attr {
#define IIO_BUFFER_EVENT_CODE(code) \
(IIO_EV_CLASS_BUFFER | (code << 8))
+#define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 24) & 0xf)
+
+//FIXME - mask probably completely wrong
+#define IIO_EVENT_CODE_EXTRACT_NUM(mask) ((mask >> 9) & 0xff)
+
+#define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 13) & 0x7)
+
/**
* IIO_EVENT_ATTR_RING_50_FULL - ring buffer event to indicate 50% full
* @_show: output method for the attribute
--
1.7.3.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/3] staging:iio:lis3l02dq - experimental move to new channel_spec approach.
2011-03-24 20:05 [RFC PATCH 0/3] Experimenting with channel specification structures Jonathan Cameron
2011-03-24 20:05 ` [PATCH 1/3] staging:iio: allow channels to be set up using a table of iio_channel_spec structures Jonathan Cameron
@ 2011-03-24 20:05 ` Jonathan Cameron
2011-03-25 14:26 ` Arnd Bergmann
2011-03-24 20:05 ` [PATCH 3/3] staging:iio:max1363 - experimental move to channel_spec registration Jonathan Cameron
2011-03-25 15:03 ` [RFC PATCH 0/3] Experimenting with channel specification structures Arnd Bergmann
3 siblings, 1 reply; 12+ messages in thread
From: Jonathan Cameron @ 2011-03-24 20:05 UTC (permalink / raw)
To: linux-iio; +Cc: arnd, Jonathan Cameron
---
drivers/staging/iio/accel/lis3l02dq.h | 13 +-
drivers/staging/iio/accel/lis3l02dq_core.c | 525 +++++++++++-----------------
drivers/staging/iio/accel/lis3l02dq_ring.c | 228 +++++-------
3 files changed, 305 insertions(+), 461 deletions(-)
diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h
index 579b3a2..1d90b7d 100644
--- a/drivers/staging/iio/accel/lis3l02dq.h
+++ b/drivers/staging/iio/accel/lis3l02dq.h
@@ -188,9 +188,9 @@ int lis3l02dq_spi_write_reg_8(struct device *dev,
void lis3l02dq_remove_trigger(struct iio_dev *indio_dev);
int lis3l02dq_probe_trigger(struct iio_dev *indio_dev);
-ssize_t lis3l02dq_read_accel_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf);
+ssize_t lis3l02dq_read_accel_from_ring(struct iio_ring_buffer *ring,
+ int index,
+ int *val);
int lis3l02dq_configure_ring(struct iio_dev *indio_dev);
@@ -215,11 +215,10 @@ static inline int lis3l02dq_probe_trigger(struct iio_dev *indio_dev)
{
return 0;
}
-
static inline ssize_t
-lis3l02dq_read_accel_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+lis3l02dq_read_accel_from_ring(struct iio_ring_buffer *ring,
+ int index,
+ int *val)
{
return 0;
}
diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c
index b5d6711..9c2d2b7 100644
--- a/drivers/staging/iio/accel/lis3l02dq_core.c
+++ b/drivers/staging/iio/accel/lis3l02dq_core.c
@@ -39,20 +39,11 @@
* This means that use cannot be made of spi_write etc.
*/
-/**
- * lis3l02dq_spi_read_reg_8() - read single byte from a single register
- * @dev: device asosciated with child of actual device (iio_dev or iio_trig)
- * @reg_address: the address of the register to be read
- * @val: pass back the resulting value
- **/
-int lis3l02dq_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
+static int __lis3l02dq_spi_read_reg_8(struct lis3l02dq_state *st,
+ u8 reg_address, u8 *val)
{
- int ret;
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct iio_sw_ring_helper_state *h = iio_dev_get_devdata(indio_dev);
- struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
-
+ int ret;
struct spi_transfer xfer = {
.tx_buf = st->tx,
.rx_buf = st->rx,
@@ -73,6 +64,19 @@ int lis3l02dq_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
return ret;
}
+/**
+ * lis3l02dq_spi_read_reg_8() - read single byte from a single register
+ * @dev: device asosciated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the register to be read
+ * @val: pass back the resulting value
+ **/
+int lis3l02dq_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_sw_ring_helper_state *h = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
+ return __lis3l02dq_spi_read_reg_8(st, reg_address, val);
+}
/**
* lis3l02dq_spi_write_reg_8() - write single byte to a register
@@ -154,23 +158,13 @@ static int lis3l02dq_spi_write_reg_s16(struct device *dev,
return ret;
}
-/**
- * lisl302dq_spi_read_reg_s16() - write 2 bytes to a pair of registers
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
- * @reg_address: the address of the lower of the two registers. Second register
- * is assumed to have address one greater.
- * @val: somewhere to pass back the value read
- **/
-static int lis3l02dq_spi_read_reg_s16(struct device *dev,
- u8 lower_reg_address,
- s16 *val)
+static int lis3l02dq_read_16bit_s(struct lis3l02dq_state *st,
+ u8 lower_reg_address,
+ int *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct iio_sw_ring_helper_state *h
- = iio_dev_get_devdata(indio_dev);
- struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
int ret;
+ s16 tempval;
struct spi_transfer xfers[] = { {
.tx_buf = st->tx,
.rx_buf = st->rx,
@@ -182,15 +176,14 @@ static int lis3l02dq_spi_read_reg_s16(struct device *dev,
.rx_buf = st->rx + 2,
.bits_per_word = 8,
.len = 2,
- .cs_change = 1,
-
+ .cs_change = 0,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = LIS3L02DQ_READ_REG(lower_reg_address);
st->tx[1] = 0;
- st->tx[2] = LIS3L02DQ_READ_REG(lower_reg_address+1);
+ st->tx[2] = LIS3L02DQ_READ_REG(lower_reg_address + 1);
st->tx[3] = 0;
spi_message_init(&msg);
@@ -201,135 +194,100 @@ static int lis3l02dq_spi_read_reg_s16(struct device *dev,
dev_err(&st->us->dev, "problem when reading 16 bit register");
goto error_ret;
}
- *val = (s16)(st->rx[1]) | ((s16)(st->rx[3]) << 8);
+ tempval = (s16)(st->rx[1]) | ((s16)(st->rx[3]) << 8);
+ *val = tempval;
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
-/**
- * lis3l02dq_read_signed() - attribute function used for 8 bit signed values
- * @dev: the child device associated with the iio_dev or iio_trigger
- * @attr: the attribute being processed
- * @buf: buffer into which put the output string
- **/
-static ssize_t lis3l02dq_read_signed(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- int ret;
- s8 val;
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
- ret = lis3l02dq_spi_read_reg_8(dev, this_attr->address, (u8 *)&val);
-
- return ret ? ret : sprintf(buf, "%d\n", val);
-}
-
-static ssize_t lis3l02dq_read_unsigned(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- int ret;
- u8 val;
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
- ret = lis3l02dq_spi_read_reg_8(dev, this_attr->address, &val);
-
- return ret ? ret : sprintf(buf, "%d\n", val);
-}
-
-static ssize_t lis3l02dq_write_signed(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- long valin;
- s8 val;
- int ret;
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
- ret = strict_strtol(buf, 10, &valin);
- if (ret)
- goto error_ret;
- val = valin;
- ret = lis3l02dq_spi_write_reg_8(dev, this_attr->address, (u8 *)&val);
-
-error_ret:
- return ret ? ret : len;
-}
-
-static ssize_t lis3l02dq_write_unsigned(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- int ret;
- ulong valin;
- u8 val;
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
- ret = strict_strtoul(buf, 10, &valin);
- if (ret)
- goto err_ret;
- val = valin;
- ret = lis3l02dq_spi_write_reg_8(dev, this_attr->address, &val);
+enum lis3l02dq_rm_ind {
+ LIS3L02DQ_ACCEL,
+ LIS3L02DQ_GAIN,
+ LIS3L02DQ_BIAS,
+};
-err_ret:
- return ret ? ret : len;
-}
+static u8 lis3l02dq_axis_map[3][3] = {
+ [LIS3L02DQ_ACCEL] = { LIS3L02DQ_REG_OUT_X_L_ADDR,
+ LIS3L02DQ_REG_OUT_Y_L_ADDR,
+ LIS3L02DQ_REG_OUT_Z_L_ADDR },
+ [LIS3L02DQ_GAIN] = { LIS3L02DQ_REG_GAIN_X_ADDR,
+ LIS3L02DQ_REG_GAIN_Y_ADDR,
+ LIS3L02DQ_REG_GAIN_Z_ADDR },
+ [LIS3L02DQ_BIAS] = { LIS3L02DQ_REG_OFFSET_X_ADDR,
+ LIS3L02DQ_REG_OFFSET_Y_ADDR,
+ LIS3L02DQ_REG_OFFSET_Z_ADDR }
+};
-static ssize_t lis3l02dq_read_16bit_signed(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int lis3l02dq_read_thresh(struct iio_dev *indio_dev,
+ int e,
+ int *val)
{
- int ret;
- s16 val = 0;
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
- ret = lis3l02dq_spi_read_reg_s16(dev, this_attr->address, &val);
-
- if (ret)
- return ret;
+ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
- return sprintf(buf, "%d\n", val);
+ return lis3l02dq_read_16bit_s(st, LIS3L02DQ_REG_THS_L_ADDR, val);
}
-static ssize_t lis3l02dq_read_accel(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int lis3l02dq_write_thresh(struct iio_dev *indio_dev,
+ int event_code,
+ int val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- ssize_t ret;
-
- /* Take the iio_dev status lock */
- mutex_lock(&indio_dev->mlock);
- if (indio_dev->currentmode == INDIO_RING_TRIGGERED)
- ret = lis3l02dq_read_accel_from_ring(dev, attr, buf);
- else
- ret = lis3l02dq_read_16bit_signed(dev, attr, buf);
- mutex_unlock(&indio_dev->mlock);
-
- return ret;
+ u16 value = val;
+ return lis3l02dq_spi_write_reg_s16(&indio_dev->dev,
+ LIS3L02DQ_REG_THS_L_ADDR,
+ value);
}
-static ssize_t lis3l02dq_write_16bit_signed(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
+static int lis3l02dq_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec *chan,
+ int *val,
+ long mask)
{
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- int ret;
- long val;
+ u8 utemp;
+ s8 stemp;
+ ssize_t ret = 0;
+ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
+ u8 reg;
+ switch (mask) {
+ case 0:
+ /* Take the iio_dev status lock */
+ mutex_lock(&indio_dev->mlock);
+ if (indio_dev->currentmode == INDIO_RING_TRIGGERED)
+ ret = lis3l02dq_read_accel_from_ring(indio_dev->ring,
+ chan->scan_index, val);
+ else {
+ reg = lis3l02dq_axis_map[LIS3L02DQ_ACCEL][chan->address];
+ ret = lis3l02dq_read_16bit_s(st, reg, val);
+ }
+ mutex_unlock(&indio_dev->mlock);
+ break;
+ case (1 << IIO_CHAN_INFO_SCALE_SHARED):
+ *val = 9580;
+ break;
+ case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE):
+ reg = lis3l02dq_axis_map[LIS3L02DQ_GAIN][chan->address];
+ ret = __lis3l02dq_spi_read_reg_8(st, reg, &utemp);
+ if (ret)
+ goto error_ret;
+ /* to match with what previous code does */
+ *val = 1000000*utemp;
+ break;
- ret = strict_strtol(buf, 10, &val);
- if (ret)
- goto error_ret;
- ret = lis3l02dq_spi_write_reg_s16(dev, this_attr->address, val);
+ case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE):
+ reg = lis3l02dq_axis_map[LIS3L02DQ_ACCEL][chan->address];
+ ret = __lis3l02dq_spi_read_reg_8(st, reg, (u8 *)&stemp);
+ /* to match with what previous code does */
+ *val = 1000000*stemp;
+ break;
+ }
error_ret:
- return ret ? ret : len;
+ return ret;
}
static ssize_t lis3l02dq_read_frequency(struct device *dev,
@@ -483,145 +441,130 @@ err_ret:
lis3l02dq_write_unsigned, \
reg);
-static LIS3L02DQ_SIGNED_ATTR(accel_x_calibbias,
- LIS3L02DQ_REG_OFFSET_X_ADDR);
-static LIS3L02DQ_SIGNED_ATTR(accel_y_calibbias,
- LIS3L02DQ_REG_OFFSET_Y_ADDR);
-static LIS3L02DQ_SIGNED_ATTR(accel_z_calibbias,
- LIS3L02DQ_REG_OFFSET_Z_ADDR);
-
-static LIS3L02DQ_UNSIGNED_ATTR(accel_x_calibscale,
- LIS3L02DQ_REG_GAIN_X_ADDR);
-static LIS3L02DQ_UNSIGNED_ATTR(accel_y_calibscale,
- LIS3L02DQ_REG_GAIN_Y_ADDR);
-static LIS3L02DQ_UNSIGNED_ATTR(accel_z_calibscale,
- LIS3L02DQ_REG_GAIN_Z_ADDR);
-
-static IIO_DEVICE_ATTR(accel_raw_mag_value,
- S_IWUSR | S_IRUGO,
- lis3l02dq_read_16bit_signed,
- lis3l02dq_write_16bit_signed,
- LIS3L02DQ_REG_THS_L_ADDR);
-/* RFC The reading method for these will change depending on whether
- * ring buffer capture is in use. Is it worth making these take two
- * functions and let the core handle which to call, or leave as in this
- * driver where it is the drivers problem to manage this?
- */
-
-static IIO_DEV_ATTR_ACCEL_X(lis3l02dq_read_accel,
- LIS3L02DQ_REG_OUT_X_L_ADDR);
-
-static IIO_DEV_ATTR_ACCEL_Y(lis3l02dq_read_accel,
- LIS3L02DQ_REG_OUT_Y_L_ADDR);
-
-static IIO_DEV_ATTR_ACCEL_Z(lis3l02dq_read_accel,
- LIS3L02DQ_REG_OUT_Z_L_ADDR);
-
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
lis3l02dq_read_frequency,
lis3l02dq_write_frequency);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("280 560 1120 4480");
-static ssize_t lis3l02dq_read_interrupt_config(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int lis3l02dq_thresh_handler_th(struct iio_dev *indio_dev,
+ int index,
+ s64 timestamp,
+ int no_test)
{
- int ret;
- s8 val;
- struct iio_event_attr *this_attr = to_iio_event_attr(attr);
+ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
- ret = lis3l02dq_spi_read_reg_8(dev->parent,
- LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
- (u8 *)&val);
+ /* Stash the timestamp somewhere convenient for the bh */
+ st->thresh_timestamp = timestamp;
+ schedule_work(&st->work_thresh);
- return ret ? ret : sprintf(buf, "%d\n", !!(val & this_attr->mask));
+ return 0;
}
-static ssize_t lis3l02dq_write_interrupt_config(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_event_attr *this_attr = to_iio_event_attr(attr);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- int ret, currentlyset, changed = 0;
- u8 valold, controlold;
- bool val;
+/* A shared handler for a number of threshold types */
+IIO_EVENT_SH(threshold, &lis3l02dq_thresh_handler_th);
- val = !(buf[0] == '0');
- mutex_lock(&indio_dev->mlock);
- /* read current value */
- ret = lis3l02dq_spi_read_reg_8(dev->parent,
+#define LIS3L02DQ_INFO_MASK \
+ (1 << IIO_CHAN_INFO_SCALE_SHARED) | \
+ (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | \
+ (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE)
+
+#define LIS3L02DQ_EVENT_MASK \
+ IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
+ IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)
+
+static struct iio_chan_spec lis3l02dq_channels[] = {
+ IIO_CHAN_EV(IIO_ACCEL, 'x', LIS3L02DQ_INFO_MASK,
+ 0, 0, IIO_ST('s', 12, 16, 0),
+ LIS3L02DQ_EVENT_MASK, &iio_event_threshold),
+ IIO_CHAN_EV(IIO_ACCEL, 'y', LIS3L02DQ_INFO_MASK,
+ 1, 1, IIO_ST('s', 12, 16, 0),
+ LIS3L02DQ_EVENT_MASK, &iio_event_threshold),
+ IIO_CHAN(IIO_ACCEL, 'z', LIS3L02DQ_INFO_MASK,
+ 2, 2, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_SOFT_TIMESTAMP(3)
+};
+
+
+static ssize_t lis3l02dq_read_event_config(struct iio_dev *indio_dev,
+ int event_code)
+{
+
+ u8 val;
+ int ret;
+ u8 mask = (1 << (IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code)*2 +
+ (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
+ IIO_EV_DIR_RISING)));
+ ret = lis3l02dq_spi_read_reg_8(&indio_dev->dev,
LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
- &valold);
- if (ret)
- goto error_mutex_unlock;
+ &val);
+ if (ret < 0)
+ return ret;
+
+ return !!(val & mask);
+}
+
+static int lis3l02dq_write_event_config(struct iio_dev *indio_dev,
+ int event_code,
+ struct iio_event_handler_list *list_el,
+ int state)
+{
+ int ret = 0;
+ u8 val, control;
+ u8 currentlyset;
+ bool changed = false;
+ u8 mask = (1 << (IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code)*2 +
+ (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
+ IIO_EV_DIR_RISING)));
+ mutex_lock(&indio_dev->mlock);
/* read current control */
- ret = lis3l02dq_spi_read_reg_8(dev,
+ ret = lis3l02dq_spi_read_reg_8(&indio_dev->dev,
LIS3L02DQ_REG_CTRL_2_ADDR,
- &controlold);
+ &control);
if (ret)
- goto error_mutex_unlock;
- currentlyset = !!(valold & this_attr->mask);
- if (val == false && currentlyset) {
- valold &= ~this_attr->mask;
- changed = 1;
- iio_remove_event_from_list(this_attr->listel,
- &indio_dev->interrupts[0]
- ->ev_list);
- } else if (val == true && !currentlyset) {
- changed = 1;
- valold |= this_attr->mask;
- iio_add_event_to_list(this_attr->listel,
- &indio_dev->interrupts[0]->ev_list);
+ goto error_ret;
+ ret = lis3l02dq_spi_read_reg_8(&indio_dev->dev,
+ LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
+ &val);
+ if (ret < 0)
+ goto error_ret;
+ currentlyset = val & mask;
+
+ if (!currentlyset && state) {
+ changed = true;
+ val |= mask;
+ iio_add_event_to_list(list_el,
+ &indio_dev->interrupts[0]->ev_list);
+
+ } else if (currentlyset && !state) {
+ changed = true;
+ val &= ~mask;
+ iio_remove_event_from_list(list_el,
+ &indio_dev->interrupts[0]->ev_list);
}
-
if (changed) {
- ret = lis3l02dq_spi_write_reg_8(dev,
+ ret = lis3l02dq_spi_write_reg_8(&indio_dev->dev,
LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
- &valold);
- if (ret)
- goto error_mutex_unlock;
- /* This always enables the interrupt, even if we've remove the
- * last thing using it. For this device we can use the reference
- * count on the handler to tell us if anyone wants the interrupt
- */
- controlold = this_attr->listel->refcount ?
- (controlold | LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT) :
- (controlold & ~LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT);
- ret = lis3l02dq_spi_write_reg_8(dev,
- LIS3L02DQ_REG_CTRL_2_ADDR,
- &controlold);
+ &val);
if (ret)
- goto error_mutex_unlock;
+ goto error_ret;
+ control = list_el->refcount ?
+ (control | LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT) :
+ (control & ~LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT);
+ ret = lis3l02dq_spi_write_reg_8(&indio_dev->dev,
+ LIS3L02DQ_REG_CTRL_2_ADDR,
+ &control);
}
-error_mutex_unlock:
- mutex_unlock(&indio_dev->mlock);
-
- return ret ? ret : len;
-}
-
-
-static int lis3l02dq_thresh_handler_th(struct iio_dev *indio_dev,
- int index,
- s64 timestamp,
- int no_test)
-{
- struct iio_sw_ring_helper_state *h
- = iio_dev_get_devdata(indio_dev);
- struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
- /* Stash the timestamp somewhere convenient for the bh */
- st->thresh_timestamp = timestamp;
- schedule_work(&st->work_thresh);
-
- return 0;
+error_ret:
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
}
-
/* Unforunately it appears the interrupt won't clear unless you read from the
* src register.
*/
@@ -700,75 +643,9 @@ static void lis3l02dq_thresh_handler_bh_no_check(struct work_struct *work_s)
return;
}
-/* A shared handler for a number of threshold types */
-IIO_EVENT_SH(threshold, &lis3l02dq_thresh_handler_th);
-
-IIO_EVENT_ATTR_SH(accel_x_thresh_rising_en,
- iio_event_threshold,
- lis3l02dq_read_interrupt_config,
- lis3l02dq_write_interrupt_config,
- LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_X_HIGH);
-
-IIO_EVENT_ATTR_SH(accel_y_thresh_rising_en,
- iio_event_threshold,
- lis3l02dq_read_interrupt_config,
- lis3l02dq_write_interrupt_config,
- LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Y_HIGH);
-
-IIO_EVENT_ATTR_SH(accel_z_thresh_rising_en,
- iio_event_threshold,
- lis3l02dq_read_interrupt_config,
- lis3l02dq_write_interrupt_config,
- LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Z_HIGH);
-
-IIO_EVENT_ATTR_SH(accel_x_thresh_falling_en,
- iio_event_threshold,
- lis3l02dq_read_interrupt_config,
- lis3l02dq_write_interrupt_config,
- LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_X_LOW);
-
-IIO_EVENT_ATTR_SH(accel_y_thresh_falling_en,
- iio_event_threshold,
- lis3l02dq_read_interrupt_config,
- lis3l02dq_write_interrupt_config,
- LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Y_LOW);
-
-IIO_EVENT_ATTR_SH(accel_z_thresh_falling_en,
- iio_event_threshold,
- lis3l02dq_read_interrupt_config,
- lis3l02dq_write_interrupt_config,
- LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Z_LOW);
-
-
-static struct attribute *lis3l02dq_event_attributes[] = {
- &iio_event_attr_accel_x_thresh_rising_en.dev_attr.attr,
- &iio_event_attr_accel_y_thresh_rising_en.dev_attr.attr,
- &iio_event_attr_accel_z_thresh_rising_en.dev_attr.attr,
- &iio_event_attr_accel_x_thresh_falling_en.dev_attr.attr,
- &iio_event_attr_accel_y_thresh_falling_en.dev_attr.attr,
- &iio_event_attr_accel_z_thresh_falling_en.dev_attr.attr,
- &iio_dev_attr_accel_raw_mag_value.dev_attr.attr,
- NULL
-};
-
-static struct attribute_group lis3l02dq_event_attribute_group = {
- .attrs = lis3l02dq_event_attributes,
-};
-
static IIO_CONST_ATTR_NAME("lis3l02dq");
-static IIO_CONST_ATTR(accel_scale, "0.00958");
static struct attribute *lis3l02dq_attributes[] = {
- &iio_dev_attr_accel_x_calibbias.dev_attr.attr,
- &iio_dev_attr_accel_y_calibbias.dev_attr.attr,
- &iio_dev_attr_accel_z_calibbias.dev_attr.attr,
- &iio_dev_attr_accel_x_calibscale.dev_attr.attr,
- &iio_dev_attr_accel_y_calibscale.dev_attr.attr,
- &iio_dev_attr_accel_z_calibscale.dev_attr.attr,
- &iio_const_attr_accel_scale.dev_attr.attr,
- &iio_dev_attr_accel_x_raw.dev_attr.attr,
- &iio_dev_attr_accel_y_raw.dev_attr.attr,
- &iio_dev_attr_accel_z_raw.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_const_attr_name.dev_attr.attr,
@@ -813,7 +690,13 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
st->help.indio_dev->dev.parent = &spi->dev;
st->help.indio_dev->num_interrupt_lines = 1;
- st->help.indio_dev->event_attrs = &lis3l02dq_event_attribute_group;
+ st->help.indio_dev->channels = lis3l02dq_channels;
+ st->help.indio_dev->num_channels = ARRAY_SIZE(lis3l02dq_channels);
+ st->help.indio_dev->read_raw = &lis3l02dq_read_raw;
+ st->help.indio_dev->read_event_value = &lis3l02dq_read_thresh;
+ st->help.indio_dev->write_event_value = &lis3l02dq_write_thresh;
+ st->help.indio_dev->write_event_config = &lis3l02dq_write_event_config;
+ st->help.indio_dev->read_event_config = &lis3l02dq_read_event_config;
st->help.indio_dev->attrs = &lis3l02dq_attribute_group;
st->help.indio_dev->dev_data = (void *)(&st->help);
st->help.indio_dev->driver_module = THIS_MODULE;
@@ -828,7 +711,9 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
goto error_unreg_ring_funcs;
regdone = 1;
- ret = iio_ring_buffer_register(st->help.indio_dev->ring, 0);
+ ret = iio_ring_buffer_register_ex(st->help.indio_dev->ring, 0,
+ lis3l02dq_channels,
+ ARRAY_SIZE(lis3l02dq_channels));
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 2c461a3..1ed037c 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -29,86 +29,6 @@ static inline u16 combine_8_to_16(u8 lower, u8 upper)
}
/**
- * lis3l02dq_scan_el_set_state() set whether a scan contains a given channel
- * @scan_el: associtate iio scan element attribute
- * @indio_dev: the device structure
- * @bool: desired state
- *
- * mlock already held when this is called.
- **/
-static int lis3l02dq_scan_el_set_state(struct iio_scan_el *scan_el,
- struct iio_dev *indio_dev,
- bool state)
-{
- u8 t, mask;
- int ret;
-
- ret = lis3l02dq_spi_read_reg_8(&indio_dev->dev,
- LIS3L02DQ_REG_CTRL_1_ADDR,
- &t);
- if (ret)
- goto error_ret;
- switch (scan_el->label) {
- case LIS3L02DQ_REG_OUT_X_L_ADDR:
- mask = LIS3L02DQ_REG_CTRL_1_AXES_X_ENABLE;
- break;
- case LIS3L02DQ_REG_OUT_Y_L_ADDR:
- mask = LIS3L02DQ_REG_CTRL_1_AXES_Y_ENABLE;
- break;
- case LIS3L02DQ_REG_OUT_Z_L_ADDR:
- mask = LIS3L02DQ_REG_CTRL_1_AXES_Z_ENABLE;
- break;
- default:
- ret = -EINVAL;
- goto error_ret;
- }
-
- if (!(mask & t) == state) {
- if (state)
- t |= mask;
- else
- t &= ~mask;
- ret = lis3l02dq_spi_write_reg_8(&indio_dev->dev,
- LIS3L02DQ_REG_CTRL_1_ADDR,
- &t);
- }
-error_ret:
- return ret;
-
-}
-static IIO_SCAN_EL_C(accel_x, 0,
- LIS3L02DQ_REG_OUT_X_L_ADDR,
- &lis3l02dq_scan_el_set_state);
-static IIO_SCAN_EL_C(accel_y, 1,
- LIS3L02DQ_REG_OUT_Y_L_ADDR,
- &lis3l02dq_scan_el_set_state);
-static IIO_SCAN_EL_C(accel_z, 2,
- LIS3L02DQ_REG_OUT_Z_L_ADDR,
- &lis3l02dq_scan_el_set_state);
-static IIO_CONST_ATTR_SCAN_EL_TYPE(accel, s, 12, 16);
-static IIO_SCAN_EL_TIMESTAMP(3);
-static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
-
-static struct attribute *lis3l02dq_scan_el_attrs[] = {
- &iio_scan_el_accel_x.dev_attr.attr,
- &iio_const_attr_accel_x_index.dev_attr.attr,
- &iio_scan_el_accel_y.dev_attr.attr,
- &iio_const_attr_accel_y_index.dev_attr.attr,
- &iio_scan_el_accel_z.dev_attr.attr,
- &iio_const_attr_accel_z_index.dev_attr.attr,
- &iio_const_attr_accel_type.dev_attr.attr,
- &iio_scan_el_timestamp.dev_attr.attr,
- &iio_const_attr_timestamp_index.dev_attr.attr,
- &iio_const_attr_timestamp_type.dev_attr.attr,
- NULL,
-};
-
-static struct attribute_group lis3l02dq_scan_el_group = {
- .attrs = lis3l02dq_scan_el_attrs,
- .name = "scan_elements",
-};
-
-/**
* lis3l02dq_poll_func_th() top half interrupt handler called by trigger
* @private_data: iio_dev
**/
@@ -151,58 +71,27 @@ IIO_EVENT_SH(data_rdy_trig, &lis3l02dq_data_rdy_trig_poll);
/**
* lis3l02dq_read_accel_from_ring() individual acceleration read from ring
**/
-ssize_t lis3l02dq_read_accel_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ssize_t lis3l02dq_read_accel_from_ring(struct iio_ring_buffer *ring,
+ int index,
+ int *val)
{
- struct iio_scan_el *el = NULL;
- int ret, len = 0, i = 0;
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct iio_ring_buffer *ring = dev_info->ring;
- struct attribute_group *scan_el_attrs = ring->scan_el_attrs;
+ int ret;
s16 *data;
+ if (!iio_scan_mask_query(ring, index))
+ return -EINVAL;
- while (scan_el_attrs->attrs[i]) {
- el = to_iio_scan_el((struct device_attribute *)
- (scan_el_attrs->attrs[i]));
- /* label is in fact the address */
- if (el->label == this_attr->address)
- break;
- i++;
- }
- if (!scan_el_attrs->attrs[i]) {
- ret = -EINVAL;
- goto error_ret;
- }
- /* If this element is in the scan mask */
- ret = iio_scan_mask_query(ring, el->number);
- if (ret < 0)
- goto error_ret;
- if (ret) {
- data = kmalloc(ring->access.get_bytes_per_datum(ring),
- GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
- ret = ring->access.read_last(ring,
- (u8 *)data);
- if (ret)
- goto error_free_data;
- } else {
- ret = -EINVAL;
- goto error_ret;
- }
- len = iio_scan_mask_count_to_right(ring, el->number);
- if (len < 0) {
- ret = len;
+ data = kmalloc(ring->access.get_bytes_per_datum(ring),
+ GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ ret = ring->access.read_last(ring, (u8 *)data);
+ if (ret)
goto error_free_data;
- }
- len = sprintf(buf, "ring %d\n", data[len]);
+ *val = data[iio_scan_mask_count_to_right(ring, index)];
error_free_data:
kfree(data);
-error_ret:
- return ret ? ret : len;
-
+ return ret;
}
static const u8 read_all_tx_array[] = {
@@ -234,7 +123,7 @@ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array)
mutex_lock(&st->buf_lock);
- for (i = 0; i < ARRAY_SIZE(read_all_tx_array)/4; i++) {
+ for (i = 0; i < ARRAY_SIZE(read_all_tx_array)/4; i++)
if (ring->scan_mask & (1 << i)) {
/* lower byte */
xfers[j].tx_buf = st->tx + 2*j;
@@ -258,7 +147,7 @@ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array)
xfers[j].cs_change = 1;
j++;
}
- }
+
/* After these are transmitted, the rx_buff should have
* values in alternate bytes
*/
@@ -430,6 +319,7 @@ static int lis3l02dq_trig_try_reen(struct iio_trigger *trig)
enable_irq(st->us->irq);
return 0;
}
+ printk("datardy still high\n");
return -EAGAIN;
}
/* irq reenabled so success! */
@@ -488,6 +378,76 @@ void lis3l02dq_unconfigure_ring(struct iio_dev *indio_dev)
lis3l02dq_free_buf(indio_dev->ring);
}
+int lis3l02dq_ring_postenable(struct iio_dev *indio_dev)
+{
+ /* Disable unwanted channels otherwise the interrupt will not clear */
+ u8 t;
+ int ret;
+ bool oneenabled = false;
+
+ ret = lis3l02dq_spi_read_reg_8(&indio_dev->dev,
+ LIS3L02DQ_REG_CTRL_1_ADDR,
+ &t);
+ if (ret)
+ goto error_ret;
+
+ if (iio_scan_mask_query(indio_dev->ring, 0)) {
+ t |= LIS3L02DQ_REG_CTRL_1_AXES_X_ENABLE;
+ oneenabled = true;
+ } else
+ t &= ~LIS3L02DQ_REG_CTRL_1_AXES_X_ENABLE;
+ if (iio_scan_mask_query(indio_dev->ring, 1)) {
+ t |= LIS3L02DQ_REG_CTRL_1_AXES_Y_ENABLE;
+ oneenabled = true;
+ } else
+ t &= ~LIS3L02DQ_REG_CTRL_1_AXES_Y_ENABLE;
+ if (iio_scan_mask_query(indio_dev->ring, 2)) {
+ t |= LIS3L02DQ_REG_CTRL_1_AXES_Z_ENABLE;
+ oneenabled = true;
+ } else
+ t &= ~LIS3L02DQ_REG_CTRL_1_AXES_Z_ENABLE;
+
+ if (!oneenabled) /* what happens in this case is unknown */
+ return -EINVAL;
+ ret = lis3l02dq_spi_write_reg_8(&indio_dev->dev,
+ LIS3L02DQ_REG_CTRL_1_ADDR,
+ &t);
+ if (ret)
+ goto error_ret;
+
+ return iio_triggered_ring_postenable(indio_dev);
+error_ret:
+ return ret;
+}
+
+/* Turn all channels on again */
+static int lis3l02dq_ring_predisable(struct iio_dev *indio_dev)
+{
+ u8 t;
+ int ret;
+
+ ret = iio_triggered_ring_predisable(indio_dev);
+ if (ret)
+ goto error_ret;
+
+ ret = lis3l02dq_spi_read_reg_8(&indio_dev->dev,
+ LIS3L02DQ_REG_CTRL_1_ADDR,
+ &t);
+ if (ret)
+ goto error_ret;
+ t |= LIS3L02DQ_REG_CTRL_1_AXES_X_ENABLE |
+ LIS3L02DQ_REG_CTRL_1_AXES_Y_ENABLE |
+ LIS3L02DQ_REG_CTRL_1_AXES_Z_ENABLE;
+
+ ret = lis3l02dq_spi_write_reg_8(&indio_dev->dev,
+ LIS3L02DQ_REG_CTRL_1_ADDR,
+ &t);
+
+error_ret:
+ return ret;
+}
+
+
int lis3l02dq_configure_ring(struct iio_dev *indio_dev)
{
int ret;
@@ -504,17 +464,17 @@ int lis3l02dq_configure_ring(struct iio_dev *indio_dev)
/* Effectively select the ring buffer implementation */
lis3l02dq_register_buf_funcs(&ring->access);
ring->bpe = 2;
- ring->scan_el_attrs = &lis3l02dq_scan_el_group;
+
ring->scan_timestamp = true;
ring->preenable = &iio_sw_ring_preenable;
- ring->postenable = &iio_triggered_ring_postenable;
- ring->predisable = &iio_triggered_ring_predisable;
+ ring->postenable = &lis3l02dq_ring_postenable;
+ ring->predisable = &lis3l02dq_ring_predisable;
ring->owner = THIS_MODULE;
/* Set default scan mode */
- iio_scan_mask_set(ring, iio_scan_el_accel_x.number);
- iio_scan_mask_set(ring, iio_scan_el_accel_y.number);
- iio_scan_mask_set(ring, iio_scan_el_accel_z.number);
+ iio_scan_mask_set(ring, 0);
+ iio_scan_mask_set(ring, 1);
+ iio_scan_mask_set(ring, 2);
ret = iio_alloc_pollfunc(indio_dev, NULL, &lis3l02dq_poll_func_th);
if (ret)
--
1.7.3.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/3] staging:iio:max1363 - experimental move to channel_spec registration.
2011-03-24 20:05 [RFC PATCH 0/3] Experimenting with channel specification structures Jonathan Cameron
2011-03-24 20:05 ` [PATCH 1/3] staging:iio: allow channels to be set up using a table of iio_channel_spec structures Jonathan Cameron
2011-03-24 20:05 ` [PATCH 2/3] staging:iio:lis3l02dq - experimental move to new channel_spec approach Jonathan Cameron
@ 2011-03-24 20:05 ` Jonathan Cameron
2011-03-25 15:03 ` [RFC PATCH 0/3] Experimenting with channel specification structures Arnd Bergmann
3 siblings, 0 replies; 12+ messages in thread
From: Jonathan Cameron @ 2011-03-24 20:05 UTC (permalink / raw)
To: linux-iio; +Cc: arnd, Jonathan Cameron
---
drivers/staging/iio/adc/max1363.h | 8 +-
drivers/staging/iio/adc/max1363_core.c | 1277 ++++++++++++--------------------
drivers/staging/iio/adc/max1363_ring.c | 1 -
3 files changed, 478 insertions(+), 808 deletions(-)
diff --git a/drivers/staging/iio/adc/max1363.h b/drivers/staging/iio/adc/max1363.h
index 6a8687f..b5a3dcd 100644
--- a/drivers/staging/iio/adc/max1363.h
+++ b/drivers/staging/iio/adc/max1363.h
@@ -152,24 +152,24 @@ enum max1363_modes {
/**
* struct max1363_chip_info - chip specifc information
* @name: indentification string for chip
- * @num_inputs: number of physical inputs on chip
* @bits: accuracy of the adc in bits
* @int_vref_mv: the internal reference voltage
* @monitor_mode: whether the chip supports monitor interrupts
* @mode_list: array of available scan modes
* @num_modes: the number of scan modes available
* @default_mode: the scan mode in which the chip starts up
+ * @channel: channel specification
+ * @num_channels: number of channels
*/
struct max1363_chip_info {
- u8 num_inputs;
u8 bits;
u16 int_vref_mv;
bool monitor_mode;
const enum max1363_modes *mode_list;
int num_modes;
enum max1363_modes default_mode;
- struct attribute_group *dev_attrs;
- struct attribute_group *scan_attrs;
+ struct iio_chan_spec *channels;
+ int num_channels;
};
/**
diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c
index a060b3d..2672784 100644
--- a/drivers/staging/iio/adc/max1363_core.c
+++ b/drivers/staging/iio/adc/max1363_core.c
@@ -42,39 +42,6 @@
/* Here we claim all are 16 bits. This currently does no harm and saves
* us a lot of scan element listings */
-#define MAX1363_SCAN_EL(number) \
- IIO_SCAN_EL_C(in##number, number, 0, NULL);
-#define MAX1363_SCAN_EL_D(p, n, number) \
- IIO_SCAN_NAMED_EL_C(in##p##m##in##n, in##p-in##n, number, 0, NULL);
-
-static MAX1363_SCAN_EL(0);
-static MAX1363_SCAN_EL(1);
-static MAX1363_SCAN_EL(2);
-static MAX1363_SCAN_EL(3);
-static MAX1363_SCAN_EL(4);
-static MAX1363_SCAN_EL(5);
-static MAX1363_SCAN_EL(6);
-static MAX1363_SCAN_EL(7);
-static MAX1363_SCAN_EL(8);
-static MAX1363_SCAN_EL(9);
-static MAX1363_SCAN_EL(10);
-static MAX1363_SCAN_EL(11);
-static MAX1363_SCAN_EL_D(0, 1, 12);
-static MAX1363_SCAN_EL_D(2, 3, 13);
-static MAX1363_SCAN_EL_D(4, 5, 14);
-static MAX1363_SCAN_EL_D(6, 7, 15);
-static MAX1363_SCAN_EL_D(8, 9, 16);
-static MAX1363_SCAN_EL_D(10, 11, 17);
-static MAX1363_SCAN_EL_D(1, 0, 18);
-static MAX1363_SCAN_EL_D(3, 2, 19);
-static MAX1363_SCAN_EL_D(5, 4, 20);
-static MAX1363_SCAN_EL_D(7, 6, 21);
-static MAX1363_SCAN_EL_D(9, 8, 22);
-static MAX1363_SCAN_EL_D(11, 10, 23);
-
-static IIO_SCAN_EL_TIMESTAMP(24);
-static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
-
static const struct max1363_mode max1363_mode_table[] = {
/* All of the single channel options first */
MAX1363_MODE_SINGLE(0, 1 << 0),
@@ -150,58 +117,6 @@ const struct max1363_mode
return NULL;
}
-static ssize_t max1363_show_precision_u(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_ring_buffer *ring = dev_get_drvdata(dev);
- struct max1363_state *st = iio_priv(ring->indio_dev);
- return sprintf(buf, "u%d/16\n", st->chip_info->bits);
-}
-
-static ssize_t max1363_show_precision_s(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_ring_buffer *ring = dev_get_drvdata(dev);
- struct max1363_state *st = iio_priv(ring->indio_dev);
- return sprintf(buf, "s%d/16\n", st->chip_info->bits);
-}
-
-#define MAX1363_SCAN_TYPE(n) \
- DEVICE_ATTR(in##n##_type, S_IRUGO, \
- max1363_show_precision_u, NULL);
-#define MAX1363_SCAN_TYPE_D(p, n) \
- struct device_attribute dev_attr_in##p##m##in##n##_type = \
- __ATTR(in##p-in##n##_type, S_IRUGO, \
- max1363_show_precision_s, NULL);
-
-static MAX1363_SCAN_TYPE(0);
-static MAX1363_SCAN_TYPE(1);
-static MAX1363_SCAN_TYPE(2);
-static MAX1363_SCAN_TYPE(3);
-static MAX1363_SCAN_TYPE(4);
-static MAX1363_SCAN_TYPE(5);
-static MAX1363_SCAN_TYPE(6);
-static MAX1363_SCAN_TYPE(7);
-static MAX1363_SCAN_TYPE(8);
-static MAX1363_SCAN_TYPE(9);
-static MAX1363_SCAN_TYPE(10);
-static MAX1363_SCAN_TYPE(11);
-
-static MAX1363_SCAN_TYPE_D(0, 1);
-static MAX1363_SCAN_TYPE_D(2, 3);
-static MAX1363_SCAN_TYPE_D(4, 5);
-static MAX1363_SCAN_TYPE_D(6, 7);
-static MAX1363_SCAN_TYPE_D(8, 9);
-static MAX1363_SCAN_TYPE_D(10, 11);
-static MAX1363_SCAN_TYPE_D(1, 0);
-static MAX1363_SCAN_TYPE_D(3, 2);
-static MAX1363_SCAN_TYPE_D(5, 4);
-static MAX1363_SCAN_TYPE_D(7, 6);
-static MAX1363_SCAN_TYPE_D(9, 8);
-static MAX1363_SCAN_TYPE_D(11, 10);
-
static int max1363_write_basic_config(struct i2c_client *client,
unsigned char d1,
unsigned char d2)
@@ -232,18 +147,17 @@ int max1363_set_scan_mode(struct max1363_state *st)
st->configbyte);
}
-static ssize_t max1363_read_single_channel(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int max1363_read_single_chan(struct iio_dev *indio_dev,
+ struct iio_chan_spec *chan,
+ int *val,
+ long m)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct max1363_state *st = iio_priv(indio_dev);
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct i2c_client *client = st->client;
- int ret = 0, len = 0;
- s32 data ;
+ int ret = 0;
+ s32 data;
char rxbuf[2];
long mask;
+ struct max1363_state *st = iio_priv(indio_dev);
+ struct i2c_client *client = st->client;
mutex_lock(&indio_dev->mlock);
/*
@@ -258,7 +172,7 @@ static ssize_t max1363_read_single_channel(struct device *dev,
/* If ring buffer capture is occuring, query the buffer */
if (iio_ring_enabled(indio_dev)) {
- mask = max1363_mode_table[this_attr->address].modemask;
+ mask = max1363_mode_table[chan->address].modemask;
data = max1363_single_channel_from_ring(mask, st);
if (data < 0) {
ret = data;
@@ -267,10 +181,10 @@ static ssize_t max1363_read_single_channel(struct device *dev,
} else {
/* Check to see if current scan mode is correct */
if (st->current_mode !=
- &max1363_mode_table[this_attr->address]) {
+ &max1363_mode_table[chan->address]) {
/* Update scan mode if needed */
st->current_mode
- = &max1363_mode_table[this_attr->address];
+ = &max1363_mode_table[chan->address];
ret = max1363_set_scan_mode(st);
if (ret)
goto error_ret;
@@ -282,7 +196,7 @@ static ssize_t max1363_read_single_channel(struct device *dev,
ret = data;
goto error_ret;
}
-
+
data = (s32)(rxbuf[1]) | ((s32)(rxbuf[0] & 0x0F)) << 8;
} else {
/* Get reading */
@@ -294,60 +208,38 @@ static ssize_t max1363_read_single_channel(struct device *dev,
data = rxbuf[0];
}
}
- /* Pretty print the result */
- len = sprintf(buf, "%u\n", data);
-
+ *val = data;
error_ret:
mutex_unlock(&indio_dev->mlock);
- return ret ? ret : len;
+ return ret;
+
}
-/* Direct read attribtues */
-static IIO_DEV_ATTR_IN_RAW(0, max1363_read_single_channel, _s0);
-static IIO_DEV_ATTR_IN_RAW(1, max1363_read_single_channel, _s1);
-static IIO_DEV_ATTR_IN_RAW(2, max1363_read_single_channel, _s2);
-static IIO_DEV_ATTR_IN_RAW(3, max1363_read_single_channel, _s3);
-static IIO_DEV_ATTR_IN_RAW(4, max1363_read_single_channel, _s4);
-static IIO_DEV_ATTR_IN_RAW(5, max1363_read_single_channel, _s5);
-static IIO_DEV_ATTR_IN_RAW(6, max1363_read_single_channel, _s6);
-static IIO_DEV_ATTR_IN_RAW(7, max1363_read_single_channel, _s7);
-static IIO_DEV_ATTR_IN_RAW(8, max1363_read_single_channel, _s8);
-static IIO_DEV_ATTR_IN_RAW(9, max1363_read_single_channel, _s9);
-static IIO_DEV_ATTR_IN_RAW(10, max1363_read_single_channel, _s10);
-static IIO_DEV_ATTR_IN_RAW(11, max1363_read_single_channel, _s11);
-
-static IIO_DEV_ATTR_IN_DIFF_RAW(0, 1, max1363_read_single_channel, d0m1);
-static IIO_DEV_ATTR_IN_DIFF_RAW(2, 3, max1363_read_single_channel, d2m3);
-static IIO_DEV_ATTR_IN_DIFF_RAW(4, 5, max1363_read_single_channel, d4m5);
-static IIO_DEV_ATTR_IN_DIFF_RAW(6, 7, max1363_read_single_channel, d6m7);
-static IIO_DEV_ATTR_IN_DIFF_RAW(8, 9, max1363_read_single_channel, d8m9);
-static IIO_DEV_ATTR_IN_DIFF_RAW(10, 11, max1363_read_single_channel, d10m11);
-static IIO_DEV_ATTR_IN_DIFF_RAW(1, 0, max1363_read_single_channel, d1m0);
-static IIO_DEV_ATTR_IN_DIFF_RAW(3, 2, max1363_read_single_channel, d3m2);
-static IIO_DEV_ATTR_IN_DIFF_RAW(5, 4, max1363_read_single_channel, d5m4);
-static IIO_DEV_ATTR_IN_DIFF_RAW(7, 6, max1363_read_single_channel, d7m6);
-static IIO_DEV_ATTR_IN_DIFF_RAW(9, 8, max1363_read_single_channel, d9m8);
-static IIO_DEV_ATTR_IN_DIFF_RAW(11, 10, max1363_read_single_channel, d11m10);
-
-
-static ssize_t max1363_show_scale(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int max1363_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec *chan,
+ int *val,
+ long m)
{
- /* Driver currently only support internal vref */
- struct max1363_state *st = iio_priv(dev_get_drvdata(dev));
- /* Corresponds to Vref / 2^(bits) */
+ struct max1363_state *st = iio_priv(indio_dev);
- if ((1 << (st->chip_info->bits + 1))
- > st->chip_info->int_vref_mv)
- return sprintf(buf, "0.5\n");
- else
- return sprintf(buf, "%d\n",
- st->chip_info->int_vref_mv >> st->chip_info->bits);
+ switch (m) {
+ case 0:
+ return max1363_read_single_chan(indio_dev, chan, val, m);
+ break;
+ case (1 << IIO_CHAN_INFO_SCALE_SHARED):
+ if ((1 << (st->chip_info->bits + 1)) >
+ st->chip_info->int_vref_mv)
+ *val = 500000;
+ else
+ *val = (1000000*st->chip_info->int_vref_mv)
+ >> st->chip_info->bits;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
}
-static IIO_DEVICE_ATTR(in_scale, S_IRUGO, max1363_show_scale, NULL, 0);
-
static ssize_t max1363_show_name(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -366,17 +258,119 @@ static const enum max1363_modes max1363_mode_list[] = {
d0m1to2m3, d1m0to3m2,
};
+static int max1363_int_th(struct iio_dev *indio_dev,
+ int index,
+ s64 timestamp,
+ int not_test)
+{
+ struct max1363_state *st = iio_priv(indio_dev);
+
+ st->last_timestamp = timestamp;
+ schedule_work(&st->thresh_work);
+ return 0;
+}
+
+IIO_EVENT_SH(max1363_thresh, max1363_int_th);
+
+#define MAX1363_EV_M \
+ (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \
+ | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
+#define MAX1363_INFO_MASK (1 << IIO_CHAN_INFO_SCALE_SHARED)
+
+static struct iio_chan_spec max1363_channels[] = {
+ IIO_CHAN_EV(IIO_IN, 0, MAX1363_INFO_MASK, _s0, 0,
+ IIO_ST('u', 12, 16, 0),
+ MAX1363_EV_M, &iio_event_max1363_thresh),
+ IIO_CHAN_EV(IIO_IN, 1, MAX1363_INFO_MASK,
+ _s1, 1, IIO_ST('u', 12, 16, 0),
+ MAX1363_EV_M, &iio_event_max1363_thresh),
+ IIO_CHAN_EV(IIO_IN, 2, MAX1363_INFO_MASK,
+ _s2, 2, IIO_ST('u', 12, 16, 0),
+ MAX1363_EV_M, &iio_event_max1363_thresh),
+ IIO_CHAN_EV(IIO_IN, 3, MAX1363_INFO_MASK,
+ _s3, 3, IIO_ST('u', 12, 16, 0),
+ MAX1363_EV_M, &iio_event_max1363_thresh),
+ IIO_CHAN_COMPOUND_EV(IIO_IN_DIFF, 0, 1, MAX1363_INFO_MASK,
+ d0m1, 4, IIO_ST('s', 12, 16, 0),
+ MAX1363_EV_M, &iio_event_max1363_thresh),
+ IIO_CHAN_COMPOUND_EV(IIO_IN_DIFF, 2, 3, MAX1363_INFO_MASK,
+ d2m3, 5, IIO_ST('s', 12, 16, 0),
+ MAX1363_EV_M, &iio_event_max1363_thresh),
+ IIO_CHAN_COMPOUND_EV(IIO_IN_DIFF, 1, 0, MAX1363_INFO_MASK,
+ d1m0, 6, IIO_ST('s', 12, 16, 0),
+ MAX1363_EV_M, &iio_event_max1363_thresh),
+ IIO_CHAN_COMPOUND_EV(IIO_IN_DIFF, 3, 2, MAX1363_INFO_MASK,
+ d3m2, 7, IIO_ST('s', 12, 16, 0),
+ MAX1363_EV_M, &iio_event_max1363_thresh),
+ IIO_CHAN_SOFT_TIMESTAMP(8)
+};
+
+static struct iio_chan_spec max1236_channels[] = {
+ IIO_CHAN(IIO_IN, 0, MAX1363_INFO_MASK, _s0, 0, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 1, MAX1363_INFO_MASK, _s1, 1, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 2, MAX1363_INFO_MASK, _s2, 2, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 3, MAX1363_INFO_MASK, _s3, 3, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 0, 1, MAX1363_INFO_MASK,
+ d0m1, 4, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 2, 3, MAX1363_INFO_MASK,
+ d2m3, 5, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 1, 0, MAX1363_INFO_MASK,
+ d1m0, 6, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 3, 2, MAX1363_INFO_MASK,
+ d3m2, 7, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_SOFT_TIMESTAMP(8)
+};
+
+static struct iio_chan_spec max1361_channels[] = {
+ IIO_CHAN(IIO_IN, 0, MAX1363_INFO_MASK, _s0, 0, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 1, MAX1363_INFO_MASK, _s1, 1, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 2, MAX1363_INFO_MASK, _s2, 2, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 3, MAX1363_INFO_MASK, _s3, 3, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 0, 1, MAX1363_INFO_MASK,
+ d0m1, 4, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 2, 3, MAX1363_INFO_MASK,
+ d2m3, 5, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 1, 0, MAX1363_INFO_MASK,
+ d1m0, 6, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 3, 2, MAX1363_INFO_MASK,
+ d3m2, 7, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_SOFT_TIMESTAMP(8)
+};
+
+static struct iio_chan_spec max1136_channels[] = {
+ IIO_CHAN(IIO_IN, 0, MAX1363_INFO_MASK,_s0, 0, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 1, MAX1363_INFO_MASK, _s1, 1, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 2, MAX1363_INFO_MASK, _s2, 2, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 3, MAX1363_INFO_MASK, _s3, 3, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 0, 1, MAX1363_INFO_MASK,
+ d0m1, 4, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 2, 3, MAX1363_INFO_MASK,
+ d2m3, 5, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 1, 0, MAX1363_INFO_MASK,
+ d1m0, 6, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 3, 2, MAX1363_INFO_MASK,
+ d3m2, 7, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_SOFT_TIMESTAMP(8)
+};
+
+static struct iio_chan_spec max1036_channels[] = {
+ IIO_CHAN(IIO_IN, 0, MAX1363_INFO_MASK, _s0, 0, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 1, MAX1363_INFO_MASK, _s1, 1, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 2, MAX1363_INFO_MASK, _s2, 2, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 3, MAX1363_INFO_MASK, _s3, 3, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 0, 1, MAX1363_INFO_MASK,
+ d0m1, 4, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 2, 3, MAX1363_INFO_MASK,
+ d2m3, 5, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 1, 0, MAX1363_INFO_MASK,
+ d1m0, 6, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 3, 2, MAX1363_INFO_MASK,
+ d3m2, 7, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_SOFT_TIMESTAMP(8)
+};
+
static struct attribute *max1363_device_attrs[] = {
- &iio_dev_attr_in0_raw.dev_attr.attr,
- &iio_dev_attr_in1_raw.dev_attr.attr,
- &iio_dev_attr_in2_raw.dev_attr.attr,
- &iio_dev_attr_in3_raw.dev_attr.attr,
- &iio_dev_attr_in0min1_raw.dev_attr.attr,
- &iio_dev_attr_in2min3_raw.dev_attr.attr,
- &iio_dev_attr_in1min0_raw.dev_attr.attr,
- &iio_dev_attr_in3min2_raw.dev_attr.attr,
&iio_dev_attr_name.dev_attr.attr,
- &iio_dev_attr_in_scale.dev_attr.attr,
NULL
};
@@ -384,34 +378,6 @@ static struct attribute_group max1363_dev_attr_group = {
.attrs = max1363_device_attrs,
};
-static struct attribute *max1363_scan_el_attrs[] = {
- &iio_scan_el_in0.dev_attr.attr, &dev_attr_in0_type.attr,
- &iio_const_attr_in0_index.dev_attr.attr,
- &iio_scan_el_in1.dev_attr.attr, &dev_attr_in1_type.attr,
- &iio_const_attr_in1_index.dev_attr.attr,
- &iio_scan_el_in2.dev_attr.attr, &dev_attr_in2_type.attr,
- &iio_const_attr_in2_index.dev_attr.attr,
- &iio_scan_el_in3.dev_attr.attr, &dev_attr_in3_type.attr,
- &iio_const_attr_in3_index.dev_attr.attr,
- &iio_scan_el_in0min1.dev_attr.attr, &dev_attr_in0min1_type.attr,
- &iio_const_attr_in0min1_index.dev_attr.attr,
- &iio_scan_el_in2min3.dev_attr.attr, &dev_attr_in2min3_type.attr,
- &iio_const_attr_in2min3_index.dev_attr.attr,
- &iio_scan_el_in1min0.dev_attr.attr, &dev_attr_in1min0_type.attr,
- &iio_const_attr_in1min0_index.dev_attr.attr,
- &iio_scan_el_in3min2.dev_attr.attr, &dev_attr_in3min2_type.attr,
- &iio_const_attr_in3min2_index.dev_attr.attr,
- &iio_const_attr_timestamp_index.dev_attr.attr,
- &iio_scan_el_timestamp.dev_attr.attr,
- &iio_const_attr_timestamp_type.dev_attr.attr,
- NULL,
-};
-
-static struct attribute_group max1363_scan_el_group = {
- .name = "scan_elements",
- .attrs = max1363_scan_el_attrs,
-};
-
/* Appies to max1236, max1237 */
static const enum max1363_modes max1236_mode_list[] = {
_s0, _s1, _s2, _s3,
@@ -434,101 +400,126 @@ static const enum max1363_modes max1238_mode_list[] = {
d6m7to8m9, d6m7to10m11, d7m6to9m8, d7m6to11m10,
};
-static struct attribute *max1238_device_attrs[] = {
- &iio_dev_attr_in0_raw.dev_attr.attr,
- &iio_dev_attr_in1_raw.dev_attr.attr,
- &iio_dev_attr_in2_raw.dev_attr.attr,
- &iio_dev_attr_in3_raw.dev_attr.attr,
- &iio_dev_attr_in4_raw.dev_attr.attr,
- &iio_dev_attr_in5_raw.dev_attr.attr,
- &iio_dev_attr_in6_raw.dev_attr.attr,
- &iio_dev_attr_in7_raw.dev_attr.attr,
- &iio_dev_attr_in8_raw.dev_attr.attr,
- &iio_dev_attr_in9_raw.dev_attr.attr,
- &iio_dev_attr_in10_raw.dev_attr.attr,
- &iio_dev_attr_in11_raw.dev_attr.attr,
- &iio_dev_attr_in0min1_raw.dev_attr.attr,
- &iio_dev_attr_in2min3_raw.dev_attr.attr,
- &iio_dev_attr_in4min5_raw.dev_attr.attr,
- &iio_dev_attr_in6min7_raw.dev_attr.attr,
- &iio_dev_attr_in8min9_raw.dev_attr.attr,
- &iio_dev_attr_in10min11_raw.dev_attr.attr,
- &iio_dev_attr_in1min0_raw.dev_attr.attr,
- &iio_dev_attr_in3min2_raw.dev_attr.attr,
- &iio_dev_attr_in5min4_raw.dev_attr.attr,
- &iio_dev_attr_in7min6_raw.dev_attr.attr,
- &iio_dev_attr_in9min8_raw.dev_attr.attr,
- &iio_dev_attr_in11min10_raw.dev_attr.attr,
- &iio_dev_attr_name.dev_attr.attr,
- &iio_dev_attr_in_scale.dev_attr.attr,
- NULL
+static struct iio_chan_spec max1038_channels[] = {
+ IIO_CHAN(IIO_IN, 0, MAX1363_INFO_MASK, _s0, 0, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 1, MAX1363_INFO_MASK, _s0, 1, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 2, MAX1363_INFO_MASK, _s0, 2, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 3, MAX1363_INFO_MASK, _s0, 3, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 4, MAX1363_INFO_MASK, _s0, 4, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 5, MAX1363_INFO_MASK, _s0, 5, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 6, MAX1363_INFO_MASK, _s0, 6, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 7, MAX1363_INFO_MASK, _s0, 7, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 8, MAX1363_INFO_MASK, _s0, 8, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 9, MAX1363_INFO_MASK, _s0, 9, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 10, MAX1363_INFO_MASK, _s0, 10, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 11, MAX1363_INFO_MASK, _s0, 11, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 0, 1, MAX1363_INFO_MASK,
+ d0m1, 12, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 2, 3, MAX1363_INFO_MASK,
+ d2m3, 13, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 4, 5, MAX1363_INFO_MASK,
+ d4m5, 14, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 6, 7, MAX1363_INFO_MASK,
+ d6m7, 15, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 8, 9, MAX1363_INFO_MASK,
+ d8m9, 16, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 10, 11, MAX1363_INFO_MASK,
+ d10m11, 17, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 1, 0, MAX1363_INFO_MASK,
+ d1m0, 18, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 3, 2, MAX1363_INFO_MASK,
+ d3m2, 19, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 5, 4, MAX1363_INFO_MASK,
+ d5m4, 20, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 7, 6, MAX1363_INFO_MASK,
+ d7m6, 21, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 9, 8, MAX1363_INFO_MASK,
+ d9m8, 22, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 11, 10, MAX1363_INFO_MASK,
+ d11m10, 23, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_SOFT_TIMESTAMP(24)
};
-static struct attribute_group max1238_dev_attr_group = {
- .attrs = max1238_device_attrs,
-};
-
-static struct attribute *max1238_scan_el_attrs[] = {
- &iio_scan_el_in0.dev_attr.attr, &dev_attr_in0_type.attr,
- &iio_const_attr_in0_index.dev_attr.attr,
- &iio_scan_el_in1.dev_attr.attr, &dev_attr_in1_type.attr,
- &iio_const_attr_in1_index.dev_attr.attr,
- &iio_scan_el_in2.dev_attr.attr, &dev_attr_in2_type.attr,
- &iio_const_attr_in2_index.dev_attr.attr,
- &iio_scan_el_in3.dev_attr.attr, &dev_attr_in3_type.attr,
- &iio_const_attr_in3_index.dev_attr.attr,
- &iio_scan_el_in4.dev_attr.attr, &dev_attr_in4_type.attr,
- &iio_const_attr_in4_index.dev_attr.attr,
- &iio_scan_el_in5.dev_attr.attr, &dev_attr_in5_type.attr,
- &iio_const_attr_in5_index.dev_attr.attr,
- &iio_scan_el_in6.dev_attr.attr, &dev_attr_in6_type.attr,
- &iio_const_attr_in6_index.dev_attr.attr,
- &iio_scan_el_in7.dev_attr.attr, &dev_attr_in7_type.attr,
- &iio_const_attr_in7_index.dev_attr.attr,
- &iio_scan_el_in8.dev_attr.attr, &dev_attr_in8_type.attr,
- &iio_const_attr_in8_index.dev_attr.attr,
- &iio_scan_el_in9.dev_attr.attr, &dev_attr_in9_type.attr,
- &iio_const_attr_in9_index.dev_attr.attr,
- &iio_scan_el_in10.dev_attr.attr, &dev_attr_in10_type.attr,
- &iio_const_attr_in10_index.dev_attr.attr,
- &iio_scan_el_in11.dev_attr.attr, &dev_attr_in11_type.attr,
- &iio_const_attr_in11_index.dev_attr.attr,
- &iio_scan_el_in0min1.dev_attr.attr, &dev_attr_in0min1_type.attr,
- &iio_const_attr_in0min1_index.dev_attr.attr,
- &iio_scan_el_in2min3.dev_attr.attr, &dev_attr_in2min3_type.attr,
- &iio_const_attr_in2min3_index.dev_attr.attr,
- &iio_scan_el_in4min5.dev_attr.attr, &dev_attr_in4min5_type.attr,
- &iio_const_attr_in4min5_index.dev_attr.attr,
- &iio_scan_el_in6min7.dev_attr.attr, &dev_attr_in6min7_type.attr,
- &iio_const_attr_in6min7_index.dev_attr.attr,
- &iio_scan_el_in8min9.dev_attr.attr, &dev_attr_in8min9_type.attr,
- &iio_const_attr_in8min9_index.dev_attr.attr,
- &iio_scan_el_in10min11.dev_attr.attr, &dev_attr_in10min11_type.attr,
- &iio_const_attr_in10min11_index.dev_attr.attr,
- &iio_scan_el_in1min0.dev_attr.attr, &dev_attr_in1min0_type.attr,
- &iio_const_attr_in1min0_index.dev_attr.attr,
- &iio_scan_el_in3min2.dev_attr.attr, &dev_attr_in3min2_type.attr,
- &iio_const_attr_in3min2_index.dev_attr.attr,
- &iio_scan_el_in5min4.dev_attr.attr, &dev_attr_in5min4_type.attr,
- &iio_const_attr_in5min4_index.dev_attr.attr,
- &iio_scan_el_in7min6.dev_attr.attr, &dev_attr_in7min6_type.attr,
- &iio_const_attr_in7min6_index.dev_attr.attr,
- &iio_scan_el_in9min8.dev_attr.attr, &dev_attr_in9min8_type.attr,
- &iio_const_attr_in9min8_index.dev_attr.attr,
- &iio_scan_el_in11min10.dev_attr.attr, &dev_attr_in11min10_type.attr,
- &iio_const_attr_in11min10_index.dev_attr.attr,
- &iio_const_attr_timestamp_index.dev_attr.attr,
- &iio_scan_el_timestamp.dev_attr.attr,
- &iio_const_attr_timestamp_type.dev_attr.attr,
- NULL,
+static struct iio_chan_spec max1138_channels[] = {
+ IIO_CHAN(IIO_IN, 0, MAX1363_INFO_MASK, _s0, 0, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 1, MAX1363_INFO_MASK, _s0, 1, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 2, MAX1363_INFO_MASK, _s0, 2, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 3, MAX1363_INFO_MASK, _s0, 3, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 4, MAX1363_INFO_MASK, _s0, 4, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 5, MAX1363_INFO_MASK, _s0, 5, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 6, MAX1363_INFO_MASK, _s0, 6, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 7, MAX1363_INFO_MASK, _s0, 7, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 8, MAX1363_INFO_MASK, _s0, 8, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 9, MAX1363_INFO_MASK, _s0, 9, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 10, MAX1363_INFO_MASK, _s0, 10, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 11, MAX1363_INFO_MASK, _s0, 11, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 0, 1, MAX1363_INFO_MASK,
+ d0m1, 12, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 2, 3, MAX1363_INFO_MASK,
+ d2m3, 13, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 4, 5, MAX1363_INFO_MASK,
+ d4m5, 14, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 6, 7, MAX1363_INFO_MASK,
+ d6m7, 15, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 8, 9, MAX1363_INFO_MASK,
+ d8m9, 16, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 10, 11, MAX1363_INFO_MASK,
+ d10m11, 17, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 1, 0, MAX1363_INFO_MASK,
+ d1m0, 18, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 3, 2, MAX1363_INFO_MASK,
+ d3m2, 19, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 5, 4, MAX1363_INFO_MASK,
+ d5m4, 20, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 7, 6, MAX1363_INFO_MASK,
+ d7m6, 21, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 9, 8, MAX1363_INFO_MASK,
+ d9m8, 22, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 11, 10, MAX1363_INFO_MASK,
+ d11m10, 23, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_SOFT_TIMESTAMP(24)
};
-static struct attribute_group max1238_scan_el_group = {
- .name = "scan_elements",
- .attrs = max1238_scan_el_attrs,
+static struct iio_chan_spec max1238_channels[] = {
+ IIO_CHAN(IIO_IN, 0, MAX1363_INFO_MASK, _s0, 0, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 1, MAX1363_INFO_MASK, _s0, 1, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 2, MAX1363_INFO_MASK, _s0, 2, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 3, MAX1363_INFO_MASK, _s0, 3, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 4, MAX1363_INFO_MASK, _s0, 4, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 5, MAX1363_INFO_MASK, _s0, 5, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 6, MAX1363_INFO_MASK, _s0, 6, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 7, MAX1363_INFO_MASK, _s0, 7, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 8, MAX1363_INFO_MASK, _s0, 8, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 9, MAX1363_INFO_MASK, _s0, 9, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 10, MAX1363_INFO_MASK, _s0, 10, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 11, MAX1363_INFO_MASK, _s0, 11, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 0, 1, MAX1363_INFO_MASK,
+ d0m1, 12, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 2, 3, MAX1363_INFO_MASK,
+ d2m3, 13, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 4, 5, MAX1363_INFO_MASK,
+ d4m5, 14, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 6, 7, MAX1363_INFO_MASK,
+ d6m7, 15, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 8, 9, MAX1363_INFO_MASK,
+ d8m9, 16, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 10, 11, MAX1363_INFO_MASK,
+ d10m11, 17, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 1, 0, MAX1363_INFO_MASK,
+ d1m0, 18, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 3, 2, MAX1363_INFO_MASK,
+ d3m2, 19, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 5, 4, MAX1363_INFO_MASK,
+ d5m4, 20, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 7, 6, MAX1363_INFO_MASK,
+ d7m6, 21, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 9, 8, MAX1363_INFO_MASK,
+ d9m8, 22, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 11, 10, MAX1363_INFO_MASK,
+ d11m10, 23, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_SOFT_TIMESTAMP(24)
};
-
static const enum max1363_modes max11607_mode_list[] = {
_s0, _s1, _s2, _s3,
s0to1, s0to2, s0to3,
@@ -547,74 +538,88 @@ static const enum max1363_modes max11608_mode_list[] = {
d1m0to3m2, d1m0to5m4, d1m0to7m6,
};
-static struct attribute *max11608_device_attrs[] = {
- &iio_dev_attr_in0_raw.dev_attr.attr,
- &iio_dev_attr_in1_raw.dev_attr.attr,
- &iio_dev_attr_in2_raw.dev_attr.attr,
- &iio_dev_attr_in3_raw.dev_attr.attr,
- &iio_dev_attr_in4_raw.dev_attr.attr,
- &iio_dev_attr_in5_raw.dev_attr.attr,
- &iio_dev_attr_in6_raw.dev_attr.attr,
- &iio_dev_attr_in7_raw.dev_attr.attr,
- &iio_dev_attr_in0min1_raw.dev_attr.attr,
- &iio_dev_attr_in2min3_raw.dev_attr.attr,
- &iio_dev_attr_in4min5_raw.dev_attr.attr,
- &iio_dev_attr_in6min7_raw.dev_attr.attr,
- &iio_dev_attr_in1min0_raw.dev_attr.attr,
- &iio_dev_attr_in3min2_raw.dev_attr.attr,
- &iio_dev_attr_in5min4_raw.dev_attr.attr,
- &iio_dev_attr_in7min6_raw.dev_attr.attr,
- &iio_dev_attr_name.dev_attr.attr,
- &iio_dev_attr_in_scale.dev_attr.attr,
- NULL
-};
-
-static struct attribute_group max11608_dev_attr_group = {
- .attrs = max11608_device_attrs,
+static struct iio_chan_spec max11602_channels[] = {
+ IIO_CHAN(IIO_IN, 0, MAX1363_INFO_MASK, _s0, 0, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 1, MAX1363_INFO_MASK, _s0, 1, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 2, MAX1363_INFO_MASK, _s0, 2, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 3, MAX1363_INFO_MASK, _s0, 3, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 4, MAX1363_INFO_MASK, _s0, 4, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 5, MAX1363_INFO_MASK, _s0, 5, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 6, MAX1363_INFO_MASK, _s0, 6, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN(IIO_IN, 7, MAX1363_INFO_MASK, _s0, 7, IIO_ST('u', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 0, 1, MAX1363_INFO_MASK,
+ d0m1, 8, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 2, 3, MAX1363_INFO_MASK,
+ d2m3, 9, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 4, 5, MAX1363_INFO_MASK,
+ d4m5, 10, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 6, 7, MAX1363_INFO_MASK,
+ d6m7, 11, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 1, 0, MAX1363_INFO_MASK,
+ d1m0, 12, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 3, 2, MAX1363_INFO_MASK,
+ d3m2, 13, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 5, 4, MAX1363_INFO_MASK,
+ d5m4, 14, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 7, 6, MAX1363_INFO_MASK,
+ d7m6, 15, IIO_ST('s', 8, 8, 0)),
+ IIO_CHAN_SOFT_TIMESTAMP(16)
};
-static struct attribute *max11608_scan_el_attrs[] = {
- &iio_scan_el_in0.dev_attr.attr, &dev_attr_in0_type.attr,
- &iio_const_attr_in0_index.dev_attr.attr,
- &iio_scan_el_in1.dev_attr.attr, &dev_attr_in1_type.attr,
- &iio_const_attr_in1_index.dev_attr.attr,
- &iio_scan_el_in2.dev_attr.attr, &dev_attr_in2_type.attr,
- &iio_const_attr_in2_index.dev_attr.attr,
- &iio_scan_el_in3.dev_attr.attr, &dev_attr_in3_type.attr,
- &iio_const_attr_in3_index.dev_attr.attr,
- &iio_scan_el_in4.dev_attr.attr, &dev_attr_in4_type.attr,
- &iio_const_attr_in4_index.dev_attr.attr,
- &iio_scan_el_in5.dev_attr.attr, &dev_attr_in5_type.attr,
- &iio_const_attr_in5_index.dev_attr.attr,
- &iio_scan_el_in6.dev_attr.attr, &dev_attr_in6_type.attr,
- &iio_const_attr_in6_index.dev_attr.attr,
- &iio_scan_el_in7.dev_attr.attr, &dev_attr_in7_type.attr,
- &iio_const_attr_in7_index.dev_attr.attr,
- &iio_scan_el_in0min1.dev_attr.attr, &dev_attr_in0min1_type.attr,
- &iio_const_attr_in0min1_index.dev_attr.attr,
- &iio_scan_el_in2min3.dev_attr.attr, &dev_attr_in2min3_type.attr,
- &iio_const_attr_in2min3_index.dev_attr.attr,
- &iio_scan_el_in4min5.dev_attr.attr, &dev_attr_in4min5_type.attr,
- &iio_const_attr_in4min5_index.dev_attr.attr,
- &iio_scan_el_in6min7.dev_attr.attr, &dev_attr_in6min7_type.attr,
- &iio_const_attr_in6min7_index.dev_attr.attr,
- &iio_scan_el_in1min0.dev_attr.attr, &dev_attr_in1min0_type.attr,
- &iio_const_attr_in1min0_index.dev_attr.attr,
- &iio_scan_el_in3min2.dev_attr.attr, &dev_attr_in3min2_type.attr,
- &iio_const_attr_in3min2_index.dev_attr.attr,
- &iio_scan_el_in5min4.dev_attr.attr, &dev_attr_in5min4_type.attr,
- &iio_const_attr_in5min4_index.dev_attr.attr,
- &iio_scan_el_in7min6.dev_attr.attr, &dev_attr_in7min6_type.attr,
- &iio_const_attr_in7min6_index.dev_attr.attr,
- &iio_const_attr_timestamp_index.dev_attr.attr,
- &iio_scan_el_timestamp.dev_attr.attr,
- &iio_const_attr_timestamp_type.dev_attr.attr,
- NULL
+static struct iio_chan_spec max11608_channels[] = {
+ IIO_CHAN(IIO_IN, 0, MAX1363_INFO_MASK, _s0, 0, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 1, MAX1363_INFO_MASK, _s0, 1, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 2, MAX1363_INFO_MASK, _s0, 2, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 3, MAX1363_INFO_MASK, _s0, 3, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 4, MAX1363_INFO_MASK, _s0, 4, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 5, MAX1363_INFO_MASK, _s0, 5, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 6, MAX1363_INFO_MASK, _s0, 6, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN(IIO_IN, 7, MAX1363_INFO_MASK, _s0, 7, IIO_ST('u', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 0, 1, MAX1363_INFO_MASK,
+ d0m1, 8, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 2, 3, MAX1363_INFO_MASK,
+ d2m3, 9, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 4, 5, MAX1363_INFO_MASK,
+ d4m5, 10, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 6, 7, MAX1363_INFO_MASK,
+ d6m7, 11, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 1, 0, MAX1363_INFO_MASK,
+ d1m0, 12, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 3, 2, MAX1363_INFO_MASK,
+ d3m2, 13, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 5, 4, MAX1363_INFO_MASK,
+ d5m4, 14, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 7, 6, MAX1363_INFO_MASK,
+ d7m6, 15, IIO_ST('s', 10, 16, 0)),
+ IIO_CHAN_SOFT_TIMESTAMP(16)
};
-static struct attribute_group max11608_scan_el_group = {
- .name = "scan_elements",
- .attrs = max11608_scan_el_attrs,
+static struct iio_chan_spec max11614_channels[] = {
+ IIO_CHAN(IIO_IN, 0, MAX1363_INFO_MASK, _s0, 0, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 1, MAX1363_INFO_MASK, _s0, 1, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 2, MAX1363_INFO_MASK, _s0, 2, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 3, MAX1363_INFO_MASK, _s0, 3, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 4, MAX1363_INFO_MASK, _s0, 4, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 5, MAX1363_INFO_MASK, _s0, 5, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 6, MAX1363_INFO_MASK, _s0, 6, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN(IIO_IN, 7, MAX1363_INFO_MASK, _s0, 7, IIO_ST('u', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 0, 1, MAX1363_INFO_MASK,
+ d0m1, 8, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 2, 3, MAX1363_INFO_MASK,
+ d2m3, 9, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 4, 5, MAX1363_INFO_MASK,
+ d4m5, 10, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 6, 7, MAX1363_INFO_MASK,
+ d6m7, 11, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 1, 0, MAX1363_INFO_MASK,
+ d1m0, 12, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 3, 2, MAX1363_INFO_MASK,
+ d3m2, 13, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 5, 4, MAX1363_INFO_MASK,
+ d5m4, 14, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_COMPOUND(IIO_IN_DIFF, 7, 6, MAX1363_INFO_MASK,
+ d7m6, 15, IIO_ST('s', 12, 16, 0)),
+ IIO_CHAN_SOFT_TIMESTAMP(16)
};
enum { max1361,
@@ -656,348 +661,314 @@ enum { max1361,
/* max1363 and max1368 tested - rest from data sheet */
static const struct max1363_chip_info max1363_chip_info_tbl[] = {
[max1361] = {
- .num_inputs = 4,
.bits = 10,
.int_vref_mv = 2048,
.monitor_mode = 1,
.mode_list = max1363_mode_list,
.num_modes = ARRAY_SIZE(max1363_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1361_channels,
+ .num_channels = ARRAY_SIZE(max1361_channels),
},
[max1362] = {
- .num_inputs = 4,
.bits = 10,
.int_vref_mv = 4096,
.monitor_mode = 1,
.mode_list = max1363_mode_list,
.num_modes = ARRAY_SIZE(max1363_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1361_channels,
+ .num_channels = ARRAY_SIZE(max1361_channels),
},
[max1363] = {
- .num_inputs = 4,
.bits = 12,
.int_vref_mv = 2048,
.monitor_mode = 1,
.mode_list = max1363_mode_list,
.num_modes = ARRAY_SIZE(max1363_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1363_channels,
+ .num_channels = ARRAY_SIZE(max1363_channels),
},
[max1364] = {
- .num_inputs = 4,
.bits = 12,
.int_vref_mv = 4096,
.monitor_mode = 1,
.mode_list = max1363_mode_list,
.num_modes = ARRAY_SIZE(max1363_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1363_channels,
+ .num_channels = ARRAY_SIZE(max1363_channels),
},
[max1036] = {
- .num_inputs = 4,
.bits = 8,
.int_vref_mv = 4096,
.mode_list = max1236_mode_list,
.num_modes = ARRAY_SIZE(max1236_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1036_channels,
+ .num_channels = ARRAY_SIZE(max1036_channels),
},
[max1037] = {
- .num_inputs = 4,
.bits = 8,
.int_vref_mv = 2048,
.mode_list = max1236_mode_list,
.num_modes = ARRAY_SIZE(max1236_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1036_channels,
+ .num_channels = ARRAY_SIZE(max1036_channels),
},
[max1038] = {
- .num_inputs = 12,
.bits = 8,
.int_vref_mv = 4096,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
- .dev_attrs = &max1238_dev_attr_group,
- .scan_attrs = &max1238_scan_el_group,
+ .channels = max1038_channels,
+ .num_channels = ARRAY_SIZE(max1038_channels),
},
[max1039] = {
- .num_inputs = 12,
.bits = 8,
.int_vref_mv = 2048,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
- .dev_attrs = &max1238_dev_attr_group,
- .scan_attrs = &max1238_scan_el_group,
+ .channels = max1038_channels,
+ .num_channels = ARRAY_SIZE(max1038_channels),
},
[max1136] = {
- .num_inputs = 4,
.bits = 10,
.int_vref_mv = 4096,
.mode_list = max1236_mode_list,
.num_modes = ARRAY_SIZE(max1236_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1136_channels,
+ .num_channels = ARRAY_SIZE(max1136_channels),
},
[max1137] = {
- .num_inputs = 4,
.bits = 10,
.int_vref_mv = 2048,
.mode_list = max1236_mode_list,
.num_modes = ARRAY_SIZE(max1236_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1136_channels,
+ .num_channels = ARRAY_SIZE(max1136_channels),
},
[max1138] = {
- .num_inputs = 12,
.bits = 10,
.int_vref_mv = 4096,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
- .dev_attrs = &max1238_dev_attr_group,
- .scan_attrs = &max1238_scan_el_group,
+ .channels = max1138_channels,
+ .num_channels = ARRAY_SIZE(max1138_channels),
},
[max1139] = {
- .num_inputs = 12,
.bits = 10,
.int_vref_mv = 2048,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
- .dev_attrs = &max1238_dev_attr_group,
- .scan_attrs = &max1238_scan_el_group,
+ .channels = max1138_channels,
+ .num_channels = ARRAY_SIZE(max1138_channels),
},
[max1236] = {
- .num_inputs = 4,
.bits = 12,
.int_vref_mv = 4096,
.mode_list = max1236_mode_list,
.num_modes = ARRAY_SIZE(max1236_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1236_channels,
+ .num_channels = ARRAY_SIZE(max1236_channels),
},
[max1237] = {
- .num_inputs = 4,
.bits = 12,
.int_vref_mv = 2048,
.mode_list = max1236_mode_list,
.num_modes = ARRAY_SIZE(max1236_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1236_channels,
+ .num_channels = ARRAY_SIZE(max1236_channels),
},
[max1238] = {
- .num_inputs = 12,
.bits = 12,
.int_vref_mv = 4096,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
- .dev_attrs = &max1238_dev_attr_group,
- .scan_attrs = &max1238_scan_el_group,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
},
[max1239] = {
- .num_inputs = 12,
.bits = 12,
.int_vref_mv = 2048,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
- .dev_attrs = &max1238_dev_attr_group,
- .scan_attrs = &max1238_scan_el_group,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
},
[max11600] = {
- .num_inputs = 4,
.bits = 8,
.int_vref_mv = 4096,
.mode_list = max11607_mode_list,
.num_modes = ARRAY_SIZE(max11607_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1036_channels,
+ .num_channels = ARRAY_SIZE(max1036_channels),
},
[max11601] = {
- .num_inputs = 4,
.bits = 8,
.int_vref_mv = 2048,
.mode_list = max11607_mode_list,
.num_modes = ARRAY_SIZE(max11607_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1036_channels,
+ .num_channels = ARRAY_SIZE(max1036_channels),
},
[max11602] = {
- .num_inputs = 8,
.bits = 8,
.int_vref_mv = 4096,
.mode_list = max11608_mode_list,
.num_modes = ARRAY_SIZE(max11608_mode_list),
.default_mode = s0to7,
- .dev_attrs = &max11608_dev_attr_group,
- .scan_attrs = &max11608_scan_el_group,
+ .channels = max11602_channels,
+ .num_channels = ARRAY_SIZE(max11602_channels),
},
[max11603] = {
- .num_inputs = 8,
.bits = 8,
.int_vref_mv = 2048,
.mode_list = max11608_mode_list,
.num_modes = ARRAY_SIZE(max11608_mode_list),
.default_mode = s0to7,
- .dev_attrs = &max11608_dev_attr_group,
- .scan_attrs = &max11608_scan_el_group,
+ .channels = max11602_channels,
+ .num_channels = ARRAY_SIZE(max11602_channels),
},
[max11604] = {
- .num_inputs = 12,
.bits = 8,
.int_vref_mv = 4098,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
- .dev_attrs = &max1238_dev_attr_group,
- .scan_attrs = &max1238_scan_el_group,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
},
[max11605] = {
- .num_inputs = 12,
.bits = 8,
.int_vref_mv = 2048,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
- .dev_attrs = &max1238_dev_attr_group,
- .scan_attrs = &max1238_scan_el_group,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
},
[max11606] = {
- .num_inputs = 4,
.bits = 10,
.int_vref_mv = 4096,
.mode_list = max11607_mode_list,
.num_modes = ARRAY_SIZE(max11607_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1136_channels,
+ .num_channels = ARRAY_SIZE(max1136_channels),
},
[max11607] = {
- .num_inputs = 4,
.bits = 10,
.int_vref_mv = 2048,
.mode_list = max11607_mode_list,
.num_modes = ARRAY_SIZE(max11607_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1136_channels,
+ .num_channels = ARRAY_SIZE(max1136_channels),
},
[max11608] = {
- .num_inputs = 8,
.bits = 10,
.int_vref_mv = 4096,
.mode_list = max11608_mode_list,
.num_modes = ARRAY_SIZE(max11608_mode_list),
.default_mode = s0to7,
- .dev_attrs = &max11608_dev_attr_group,
- .scan_attrs = &max11608_scan_el_group,
+ .channels = max11608_channels,
+ .num_channels = ARRAY_SIZE(max11608_channels),
},
[max11609] = {
- .num_inputs = 8,
.bits = 10,
.int_vref_mv = 2048,
.mode_list = max11608_mode_list,
.num_modes = ARRAY_SIZE(max11608_mode_list),
.default_mode = s0to7,
- .dev_attrs = &max11608_dev_attr_group,
- .scan_attrs = &max11608_scan_el_group,
+ .channels = max11608_channels,
+ .num_channels = ARRAY_SIZE(max11608_channels),
},
[max11610] = {
- .num_inputs = 12,
.bits = 10,
.int_vref_mv = 4098,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
- .dev_attrs = &max1238_dev_attr_group,
- .scan_attrs = &max1238_scan_el_group,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
},
[max11611] = {
- .num_inputs = 12,
.bits = 10,
.int_vref_mv = 2048,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
- .dev_attrs = &max1238_dev_attr_group,
- .scan_attrs = &max1238_scan_el_group,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
},
[max11612] = {
- .num_inputs = 4,
.bits = 12,
.int_vref_mv = 4096,
.mode_list = max11607_mode_list,
.num_modes = ARRAY_SIZE(max11607_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1363_channels,
+ .num_channels = ARRAY_SIZE(max1363_channels),
},
[max11613] = {
- .num_inputs = 4,
.bits = 12,
.int_vref_mv = 2048,
.mode_list = max11607_mode_list,
.num_modes = ARRAY_SIZE(max11607_mode_list),
.default_mode = s0to3,
- .dev_attrs = &max1363_dev_attr_group,
- .scan_attrs = &max1363_scan_el_group,
+ .channels = max1363_channels,
+ .num_channels = ARRAY_SIZE(max1363_channels),
},
[max11614] = {
- .num_inputs = 8,
.bits = 12,
.int_vref_mv = 4096,
.mode_list = max11608_mode_list,
.num_modes = ARRAY_SIZE(max11608_mode_list),
.default_mode = s0to7,
- .dev_attrs = &max11608_dev_attr_group,
- .scan_attrs = &max11608_scan_el_group,
+ .channels = max11614_channels,
+ .num_channels = ARRAY_SIZE(max11614_channels),
},
[max11615] = {
- .num_inputs = 8,
.bits = 12,
.int_vref_mv = 2048,
.mode_list = max11608_mode_list,
.num_modes = ARRAY_SIZE(max11608_mode_list),
.default_mode = s0to7,
- .dev_attrs = &max11608_dev_attr_group,
- .scan_attrs = &max11608_scan_el_group,
+ .channels = max11614_channels,
+ .num_channels = ARRAY_SIZE(max11614_channels),
},
[max11616] = {
- .num_inputs = 12,
.bits = 12,
.int_vref_mv = 4098,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
- .dev_attrs = &max1238_dev_attr_group,
- .scan_attrs = &max1238_scan_el_group,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
},
[max11617] = {
- .num_inputs = 12,
.bits = 12,
.int_vref_mv = 2048,
.mode_list = max1238_mode_list,
.num_modes = ARRAY_SIZE(max1238_mode_list),
.default_mode = s0to11,
- .dev_attrs = &max1238_dev_attr_group,
- .scan_attrs = &max1238_scan_el_group,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
}
};
@@ -1048,51 +1019,24 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR,
static IIO_CONST_ATTR(sampling_frequency_available,
"133000 665000 33300 16600 8300 4200 2000 1000");
-static ssize_t max1363_show_thresh(struct device *dev,
- struct device_attribute *attr,
- char *buf,
- bool high)
+static int max1363_read_thresh(struct iio_dev *indio_dev,
+ int event_code,
+ int *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct max1363_state *st = iio_priv(indio_dev);
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
- if (high)
- return sprintf(buf, "%d\n",
- st->thresh_high[this_attr->address]);
+ if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING)
+ *val = st->thresh_low[IIO_EVENT_CODE_EXTRACT_NUM(event_code)];
else
- return sprintf(buf, "%d\n",
- st->thresh_low[this_attr->address & 0x7]);
-}
-
-static ssize_t max1363_show_thresh_low(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return max1363_show_thresh(dev, attr, buf, false);
-}
-
-static ssize_t max1363_show_thresh_high(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return max1363_show_thresh(dev, attr, buf, true);
+ *val = st->thresh_high[IIO_EVENT_CODE_EXTRACT_NUM(event_code)];
+ return 0;
}
-static ssize_t max1363_store_thresh_unsigned(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len,
- bool high)
+static int max1363_write_thresh(struct iio_dev *indio_dev,
+ int event_code,
+ int val)
{
- struct max1363_state *st = iio_priv(dev_get_drvdata(dev));
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- unsigned long val;
- int ret;
-
- ret = strict_strtoul(buf, 10, &val);
- if (ret)
- return -EINVAL;
+ struct max1363_state *st = iio_priv(indio_dev);
+ /* make it handle signed correctly as well */
switch (st->chip_info->bits) {
case 10:
if (val > 0x3FF)
@@ -1104,154 +1048,15 @@ static ssize_t max1363_store_thresh_unsigned(struct device *dev,
break;
}
- switch (high) {
- case 1:
- st->thresh_high[this_attr->address] = val;
+ switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+ case IIO_EV_DIR_FALLING:
+ st->thresh_low[IIO_EVENT_CODE_EXTRACT_NUM(event_code)] = val;
break;
- case 0:
- st->thresh_low[this_attr->address & 0x7] = val;
+ case IIO_EV_DIR_RISING:
+ st->thresh_high[IIO_EVENT_CODE_EXTRACT_NUM(event_code)] = val;
break;
}
- return len;
-}
-
-static ssize_t max1363_store_thresh_high_unsigned(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- return max1363_store_thresh_unsigned(dev, attr, buf, len, true);
-}
-
-static ssize_t max1363_store_thresh_low_unsigned(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- return max1363_store_thresh_unsigned(dev, attr, buf, len, false);
-}
-
-static ssize_t max1363_store_thresh_signed(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len,
- bool high)
-{
- struct max1363_state *st = iio_priv(dev_get_drvdata(dev));
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- long val;
- int ret;
-
- ret = strict_strtol(buf, 10, &val);
- if (ret)
- return -EINVAL;
- switch (st->chip_info->bits) {
- case 10:
- if (val < -512 || val > 511)
- return -EINVAL;
- break;
- case 12:
- if (val < -2048 || val > 2047)
- return -EINVAL;
- break;
- }
-
- switch (high) {
- case 1:
- st->thresh_high[this_attr->address] = val;
- break;
- case 0:
- st->thresh_low[this_attr->address & 0x7] = val;
- break;
- }
-
- return len;
-}
-
-static ssize_t max1363_store_thresh_high_signed(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- return max1363_store_thresh_signed(dev, attr, buf, len, true);
-}
-
-static ssize_t max1363_store_thresh_low_signed(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- return max1363_store_thresh_signed(dev, attr, buf, len, false);
-}
-
-static IIO_DEVICE_ATTR(in0_thresh_high_value, S_IRUGO | S_IWUSR,
- max1363_show_thresh_high,
- max1363_store_thresh_high_unsigned, 0);
-static IIO_DEVICE_ATTR(in0_thresh_low_value, S_IRUGO | S_IWUSR,
- max1363_show_thresh_low,
- max1363_store_thresh_low_unsigned, 0);
-static IIO_DEVICE_ATTR(in1_thresh_high_value, S_IRUGO | S_IWUSR,
- max1363_show_thresh_high,
- max1363_store_thresh_high_unsigned, 1);
-static IIO_DEVICE_ATTR(in1_thresh_low_value, S_IRUGO | S_IWUSR,
- max1363_show_thresh_low,
- max1363_store_thresh_low_unsigned, 1);
-static IIO_DEVICE_ATTR(in2_thresh_high_value, S_IRUGO | S_IWUSR,
- max1363_show_thresh_high,
- max1363_store_thresh_high_unsigned, 2);
-static IIO_DEVICE_ATTR(in2_thresh_low_value, S_IRUGO | S_IWUSR,
- max1363_show_thresh_low,
- max1363_store_thresh_low_unsigned, 2);
-static IIO_DEVICE_ATTR(in3_thresh_high_value, S_IRUGO | S_IWUSR,
- max1363_show_thresh_high,
- max1363_store_thresh_high_unsigned, 3);
-static IIO_DEVICE_ATTR(in3_thresh_low_value, S_IRUGO | S_IWUSR,
- max1363_show_thresh_low,
- max1363_store_thresh_low_unsigned, 3);
-
-static IIO_DEVICE_ATTR_NAMED(in0min1_thresh_high_value,
- in0-in1_thresh_high_value,
- S_IRUGO | S_IWUSR, max1363_show_thresh_high,
- max1363_store_thresh_high_signed, 4);
-static IIO_DEVICE_ATTR_NAMED(in0min1_thresh_low_value,
- in0-in1_thresh_low_value,
- S_IRUGO | S_IWUSR, max1363_show_thresh_low,
- max1363_store_thresh_low_signed, 4);
-static IIO_DEVICE_ATTR_NAMED(in2min3_thresh_high_value,
- in2-in3_thresh_high_value,
- S_IRUGO | S_IWUSR, max1363_show_thresh_high,
- max1363_store_thresh_high_signed, 5);
-static IIO_DEVICE_ATTR_NAMED(in2min3_thresh_low_value,
- in2-in3_thresh_low_value,
- S_IRUGO | S_IWUSR, max1363_show_thresh_low,
- max1363_store_thresh_low_signed, 5);
-static IIO_DEVICE_ATTR_NAMED(in1min0_thresh_high_value,
- in1-in0_thresh_high_value,
- S_IRUGO | S_IWUSR, max1363_show_thresh_high,
- max1363_store_thresh_high_signed, 6);
-static IIO_DEVICE_ATTR_NAMED(in1min0_thresh_low_value,
- in1-in0_thresh_low_value,
- S_IRUGO | S_IWUSR, max1363_show_thresh_low,
- max1363_store_thresh_low_signed, 6);
-static IIO_DEVICE_ATTR_NAMED(in3min2_thresh_high_value,
- in3-in2_thresh_high_value,
- S_IRUGO | S_IWUSR, max1363_show_thresh_high,
- max1363_store_thresh_high_signed, 7);
-static IIO_DEVICE_ATTR_NAMED(in3min2_thresh_low_value,
- in3-in2_thresh_low_value,
- S_IRUGO | S_IWUSR, max1363_show_thresh_low,
- max1363_store_thresh_low_signed, 7);
-
-static int max1363_int_th(struct iio_dev *indio_dev,
- int index,
- s64 timestamp,
- int not_test)
-{
- struct max1363_state *st = iio_priv(indio_dev);
-
- st->last_timestamp = timestamp;
- schedule_work(&st->thresh_work);
return 0;
}
@@ -1265,6 +1070,7 @@ static void max1363_thresh_handler_bh(struct work_struct *work_s)
MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0 };
i2c_master_recv(st->client, &rx, 1);
+ /* todo - begging for use of for_each_set_bit */
if (rx & (1 << 0))
iio_push_event(indio_dev, 0,
IIO_EVENT_CODE_IN_LOW_THRESH(3),
@@ -1301,23 +1107,21 @@ static void max1363_thresh_handler_bh(struct work_struct *work_s)
i2c_master_send(st->client, tx, 2);
}
-static ssize_t max1363_read_interrupt_config(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int max1363_read_event_config(struct iio_dev *indio_dev,
+ int event_code)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct max1363_state *st = iio_priv(indio_dev);
- struct iio_event_attr *this_attr = to_iio_event_attr(attr);
- int val;
+ int val;
+ int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
mutex_lock(&indio_dev->mlock);
- if (this_attr->mask & 0x8)
- val = (1 << (this_attr->mask & 0x7)) & st->mask_low;
+ if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING)
+ val = (1 << number) & st->mask_low;
else
- val = (1 << this_attr->mask) & st->mask_high;
+ val = (1 << number) & st->mask_high;
mutex_unlock(&indio_dev->mlock);
- return sprintf(buf, "%d\n", !!val);
+ return val;
}
static int max1363_monitor_mode_update(struct max1363_state *st, int enabled)
@@ -1434,6 +1238,7 @@ error_ret:
* To keep this managable we always use one of 3 scan modes.
* Scan 0...3, 0-1,2-3 and 1-0,3-2
*/
+
static inline int __max1363_check_event_mask(int thismask, int checkmask)
{
int ret = 0;
@@ -1454,206 +1259,62 @@ error_ret:
return ret;
}
-static ssize_t max1363_write_interrupt_config(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
+static int max1363_write_event_config(struct iio_dev *indio_dev,
+ int event_code,
+ //move list manipulation into core?
+ struct iio_event_handler_list *listel,
+ int state)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ int ret = 0;
struct max1363_state *st = iio_priv(indio_dev);
- struct iio_event_attr *this_attr = to_iio_event_attr(attr);
- unsigned long val;
- int ret;
u16 unifiedmask;
- ret = strict_strtoul(buf, 10, &val);
- if (ret)
- return -EINVAL;
+ int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
+
mutex_lock(&indio_dev->mlock);
unifiedmask = st->mask_low | st->mask_high;
- if (this_attr->mask & 0x08) {
- /* If we are disabling no need to test */
- if (val == 0)
- st->mask_low &= ~(1 << (this_attr->mask & 0x7));
+ if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) {
+
+ if (state == 0)
+ st->mask_low &= ~(1 << number);
else {
- ret = __max1363_check_event_mask(this_attr->mask & 0x7,
- unifiedmask);
+ ret = __max1363_check_event_mask((1 << number),
+ unifiedmask);
if (ret)
goto error_ret;
- st->mask_low |= (1 << (this_attr->mask & 0x7));
+ st->mask_low |= (1 << number);
}
} else {
- if (val == 0)
- st->mask_high &= ~(1 << (this_attr->mask));
+ if (state == 0)
+ st->mask_high &= ~(1 << number);
else {
- ret = __max1363_check_event_mask(this_attr->mask,
- unifiedmask);
+ ret = __max1363_check_event_mask((1 << number),
+ unifiedmask);
if (ret)
goto error_ret;
- st->mask_high |= (1 << this_attr->mask);
+ st->mask_high |= (1 << number);
}
}
if (st->monitor_on && !st->mask_high && !st->mask_low)
- iio_remove_event_from_list(this_attr->listel,
- &indio_dev->interrupts[0]->ev_list);
- if (!st->monitor_on && val)
- iio_add_event_to_list(this_attr->listel,
- &indio_dev->interrupts[0]->ev_list);
+ iio_remove_event_from_list(listel,
+ &indio_dev->interrupts[0]->ev_list);
+ if (!st->monitor_on && state)
+ iio_add_event_to_list(listel,
+ &indio_dev->interrupts[0]->ev_list);
max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low));
error_ret:
mutex_unlock(&indio_dev->mlock);
- return len;
+ return ret;
}
-IIO_EVENT_SH(max1363_thresh, max1363_int_th);
-
-#define MAX1363_HIGH_THRESH(a) a
-#define MAX1363_LOW_THRESH(a) (a | 0x8)
-
-IIO_EVENT_ATTR_SH(in0_thresh_high_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_HIGH_THRESH(0));
-
-IIO_EVENT_ATTR_SH(in0_thresh_low_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_LOW_THRESH(0));
-
-IIO_EVENT_ATTR_SH(in1_thresh_high_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_HIGH_THRESH(1));
-
-IIO_EVENT_ATTR_SH(in1_thresh_low_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_LOW_THRESH(1));
-
-IIO_EVENT_ATTR_SH(in2_thresh_high_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_HIGH_THRESH(2));
-
-IIO_EVENT_ATTR_SH(in2_thresh_low_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_LOW_THRESH(2));
-
-IIO_EVENT_ATTR_SH(in3_thresh_high_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_HIGH_THRESH(3));
-
-IIO_EVENT_ATTR_SH(in3_thresh_low_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_LOW_THRESH(3));
-
-IIO_EVENT_ATTR_NAMED_SH(in0min1_thresh_high_en,
- in0-in1_thresh_high_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_HIGH_THRESH(4));
-
-IIO_EVENT_ATTR_NAMED_SH(in0min1_thresh_low_en,
- in0-in1_thresh_low_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_LOW_THRESH(4));
-
-IIO_EVENT_ATTR_NAMED_SH(in3min2_thresh_high_en,
- in3-in2_thresh_high_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_HIGH_THRESH(5));
-
-IIO_EVENT_ATTR_NAMED_SH(in3min2_thresh_low_en,
- in3-in2_thresh_low_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_LOW_THRESH(5));
-
-IIO_EVENT_ATTR_NAMED_SH(in1min0_thresh_high_en,
- in1-in0_thresh_high_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_HIGH_THRESH(6));
-
-IIO_EVENT_ATTR_NAMED_SH(in1min0_thresh_low_en,
- in1-in0_thresh_low_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_LOW_THRESH(6));
-
-IIO_EVENT_ATTR_NAMED_SH(in2min3_thresh_high_en,
- in2-in3_thresh_high_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_HIGH_THRESH(7));
-
-IIO_EVENT_ATTR_NAMED_SH(in2min3_thresh_low_en,
- in2-in3_thresh_low_en,
- iio_event_max1363_thresh,
- max1363_read_interrupt_config,
- max1363_write_interrupt_config,
- MAX1363_LOW_THRESH(7));
-
/*
* As with scan_elements, only certain sets of these can
* be combined.
*/
static struct attribute *max1363_event_attributes[] = {
- &iio_dev_attr_in0_thresh_high_value.dev_attr.attr,
- &iio_dev_attr_in0_thresh_low_value.dev_attr.attr,
- &iio_dev_attr_in1_thresh_high_value.dev_attr.attr,
- &iio_dev_attr_in1_thresh_low_value.dev_attr.attr,
- &iio_dev_attr_in2_thresh_high_value.dev_attr.attr,
- &iio_dev_attr_in2_thresh_low_value.dev_attr.attr,
- &iio_dev_attr_in3_thresh_high_value.dev_attr.attr,
- &iio_dev_attr_in3_thresh_low_value.dev_attr.attr,
- &iio_dev_attr_in0min1_thresh_high_value.dev_attr.attr,
- &iio_dev_attr_in0min1_thresh_low_value.dev_attr.attr,
- &iio_dev_attr_in2min3_thresh_high_value.dev_attr.attr,
- &iio_dev_attr_in2min3_thresh_low_value.dev_attr.attr,
- &iio_dev_attr_in1min0_thresh_high_value.dev_attr.attr,
- &iio_dev_attr_in1min0_thresh_low_value.dev_attr.attr,
- &iio_dev_attr_in3min2_thresh_high_value.dev_attr.attr,
- &iio_dev_attr_in3min2_thresh_low_value.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
- &iio_event_attr_in0_thresh_high_en.dev_attr.attr,
- &iio_event_attr_in0_thresh_low_en.dev_attr.attr,
- &iio_event_attr_in1_thresh_high_en.dev_attr.attr,
- &iio_event_attr_in1_thresh_low_en.dev_attr.attr,
- &iio_event_attr_in2_thresh_high_en.dev_attr.attr,
- &iio_event_attr_in2_thresh_low_en.dev_attr.attr,
- &iio_event_attr_in3_thresh_high_en.dev_attr.attr,
- &iio_event_attr_in3_thresh_low_en.dev_attr.attr,
- &iio_event_attr_in0min1_thresh_high_en.dev_attr.attr,
- &iio_event_attr_in0min1_thresh_low_en.dev_attr.attr,
- &iio_event_attr_in3min2_thresh_high_en.dev_attr.attr,
- &iio_event_attr_in3min2_thresh_low_en.dev_attr.attr,
- &iio_event_attr_in1min0_thresh_high_en.dev_attr.attr,
- &iio_event_attr_in1min0_thresh_low_en.dev_attr.attr,
- &iio_event_attr_in2min3_thresh_high_en.dev_attr.attr,
- &iio_event_attr_in2min3_thresh_low_en.dev_attr.attr,
NULL,
};
@@ -1685,6 +1346,7 @@ static int __devinit max1363_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
struct regulator *reg;
+ printk("version test 1.2 %s\n", client->name);
reg = regulator_get(&client->dev, "vcc");
if (!IS_ERR(reg)) {
ret = regulator_enable(reg);
@@ -1721,8 +1383,14 @@ static int __devinit max1363_probe(struct i2c_client *client,
.modemask;
/* Estabilish that the iio_dev is a child of the i2c device */
indio_dev->dev.parent = &client->dev;
- indio_dev->attrs = st->chip_info->dev_attrs;
-
+ indio_dev->attrs = &max1363_dev_attr_group;
+ indio_dev->read_event_value = &max1363_read_thresh;
+ indio_dev->write_event_value = &max1363_write_thresh;
+ indio_dev->read_event_config = &max1363_read_event_config;
+ indio_dev->write_event_config = &max1363_write_event_config;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+ indio_dev->read_raw = &max1363_read_raw;
/* Todo: this shouldn't be here. */
indio_dev->driver_module = THIS_MODULE;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -1744,7 +1412,9 @@ static int __devinit max1363_probe(struct i2c_client *client,
if (ret)
goto error_cleanup_ring;
regdone = 1;
- ret = iio_ring_buffer_register(indio_dev->ring, 0);
+ ret = iio_ring_buffer_register_ex(indio_dev->ring, 0,
+ st->chip_info->channels,
+ st->chip_info->num_channels);
if (ret)
goto error_cleanup_ring;
@@ -1754,9 +1424,10 @@ static int __devinit max1363_probe(struct i2c_client *client,
0,
IRQF_TRIGGER_RISING,
client->name);
+
if (ret)
goto error_uninit_ring;
-
+ printk("interrupt stuff\n");
INIT_WORK(&st->thresh_work, max1363_thresh_handler_bh);
}
diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c
index 944ff7a..caebe44 100644
--- a/drivers/staging/iio/adc/max1363_ring.c
+++ b/drivers/staging/iio/adc/max1363_ring.c
@@ -199,7 +199,6 @@ int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev)
goto error_deallocate_sw_rb;
/* Ring buffer functions - here trigger setup related */
- indio_dev->ring->scan_el_attrs = st->chip_info->scan_attrs;
indio_dev->ring->postenable = &iio_triggered_ring_postenable;
indio_dev->ring->preenable = &max1363_ring_preenable;
indio_dev->ring->predisable = &iio_triggered_ring_predisable;
--
1.7.3.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 2/3] staging:iio:lis3l02dq - experimental move to new channel_spec approach.
2011-03-24 20:05 ` [PATCH 2/3] staging:iio:lis3l02dq - experimental move to new channel_spec approach Jonathan Cameron
@ 2011-03-25 14:26 ` Arnd Bergmann
2011-03-25 15:38 ` Jonathan Cameron
0 siblings, 1 reply; 12+ messages in thread
From: Arnd Bergmann @ 2011-03-25 14:26 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-iio
I like the changes. The savings are a little less than what I had hoped
for, but a lot of the redundant code that gets copied to each driver
is gone.
On Thursday 24 March 2011, Jonathan Cameron wrote:
> -/**
> - * lis3l02dq_spi_read_reg_8() - read single byte from a single register
> - * @dev: device asosciated with child of actual device (iio_dev or iio_trig)
> - * @reg_address: the address of the register to be read
> - * @val: pass back the resulting value
> - **/
> -int lis3l02dq_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
> +static int __lis3l02dq_spi_read_reg_8(struct lis3l02dq_state *st,
> + u8 reg_address, u8 *val)
> {
> - int ret;
> struct spi_message msg;
> - struct iio_dev *indio_dev = dev_get_drvdata(dev);
> - struct iio_sw_ring_helper_state *h = iio_dev_get_devdata(indio_dev);
> - struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
> -
> + int ret;
> struct spi_transfer xfer = {
> .tx_buf = st->tx,
> .rx_buf = st->rx,
>
> @@ -73,6 +64,19 @@ int lis3l02dq_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
>
> return ret;
> }
> +/**
> + * lis3l02dq_spi_read_reg_8() - read single byte from a single register
> + * @dev: device asosciated with child of actual device (iio_dev or iio_trig)
> + * @reg_address: the address of the register to be read
> + * @val: pass back the resulting value
> + **/
> +int lis3l02dq_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
> +{
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + struct iio_sw_ring_helper_state *h = iio_dev_get_devdata(indio_dev);
> + struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
> + return __lis3l02dq_spi_read_reg_8(st, reg_address, val);
> +}
This change seems unrelated to the main intention of the driver.
I think the cleanest way to handle this would be to always pass the
iio_dev to the low-level functions. Passing a bare struct device
is hardly ever helpful, and from the iio_dev, you can easily get to
both the device and the lis3l02dq_state.
> +enum lis3l02dq_rm_ind {
> + LIS3L02DQ_ACCEL,
> + LIS3L02DQ_GAIN,
> + LIS3L02DQ_BIAS,
> +};
>
> +static u8 lis3l02dq_axis_map[3][3] = {
> + [LIS3L02DQ_ACCEL] = { LIS3L02DQ_REG_OUT_X_L_ADDR,
> + LIS3L02DQ_REG_OUT_Y_L_ADDR,
> + LIS3L02DQ_REG_OUT_Z_L_ADDR },
> + [LIS3L02DQ_GAIN] = { LIS3L02DQ_REG_GAIN_X_ADDR,
> + LIS3L02DQ_REG_GAIN_Y_ADDR,
> + LIS3L02DQ_REG_GAIN_Z_ADDR },
> + [LIS3L02DQ_BIAS] = { LIS3L02DQ_REG_OFFSET_X_ADDR,
> + LIS3L02DQ_REG_OFFSET_Y_ADDR,
> + LIS3L02DQ_REG_OFFSET_Z_ADDR }
> +};
The table looks nice and small, but I can't see where the BIAS
value is used. Is that something that the hardware supports but
the driver does not?
> +static int lis3l02dq_read_thresh(struct iio_dev *indio_dev,
> + int e,
> + int *val)
> {
> + struct iio_sw_ring_helper_state *h
> + = iio_dev_get_devdata(indio_dev);
> + struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
>
> + return lis3l02dq_read_16bit_s(st, LIS3L02DQ_REG_THS_L_ADDR, val);
> }
>
> +static int lis3l02dq_write_thresh(struct iio_dev *indio_dev,
> + int event_code,
> + int val)
> {
> + u16 value = val;
> + return lis3l02dq_spi_write_reg_s16(&indio_dev->dev,
> + LIS3L02DQ_REG_THS_L_ADDR,
> + value);
> }
Can be made even smaller if you drop the u16 value variable and
rely on the implicit type conversion ;-)
> +static int lis3l02dq_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec *chan,
> + int *val,
> + long mask)
> {
I guess that in the mask work, you can only pass one bit at most,
right? How about passing the bit number instead?
> +/* A shared handler for a number of threshold types */
> +IIO_EVENT_SH(threshold, &lis3l02dq_thresh_handler_th);
>
> +#define LIS3L02DQ_INFO_MASK \
> + (1 << IIO_CHAN_INFO_SCALE_SHARED) | \
> + (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | \
> + (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE)
> +
> +#define LIS3L02DQ_EVENT_MASK \
> + IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
> + IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)
> +
> +static struct iio_chan_spec lis3l02dq_channels[] = {
> + IIO_CHAN_EV(IIO_ACCEL, 'x', LIS3L02DQ_INFO_MASK,
> + 0, 0, IIO_ST('s', 12, 16, 0),
> + LIS3L02DQ_EVENT_MASK, &iio_event_threshold),
> + IIO_CHAN_EV(IIO_ACCEL, 'y', LIS3L02DQ_INFO_MASK,
> + 1, 1, IIO_ST('s', 12, 16, 0),
> + LIS3L02DQ_EVENT_MASK, &iio_event_threshold),
> + IIO_CHAN(IIO_ACCEL, 'z', LIS3L02DQ_INFO_MASK,
> + 2, 2, IIO_ST('s', 12, 16, 0)),
> + IIO_CHAN_SOFT_TIMESTAMP(3)
> +};
Hmm, this has turned out more complex than I had hoped for,
but that's probably the way things go when you put them into
real code.
> +static ssize_t lis3l02dq_read_event_config(struct iio_dev *indio_dev,
> + int event_code)
> +{
> +
> + u8 val;
> + int ret;
> + u8 mask = (1 << (IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code)*2 +
> + (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
> + IIO_EV_DIR_RISING)));
> + ret = lis3l02dq_spi_read_reg_8(&indio_dev->dev,
> LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
> + &val);
> + if (ret < 0)
> + return ret;
> +
> + return !!(val & mask);
> +}
I need some background information here. Why do you expose the configuration
register directly? Is this something that users normally access?
I would assume that it's highly device specific and would need to be
abstracted by the kernel.
> @@ -813,7 +690,13 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
>
> st->help.indio_dev->dev.parent = &spi->dev;
> st->help.indio_dev->num_interrupt_lines = 1;
> - st->help.indio_dev->event_attrs = &lis3l02dq_event_attribute_group;
> + st->help.indio_dev->channels = lis3l02dq_channels;
> + st->help.indio_dev->num_channels = ARRAY_SIZE(lis3l02dq_channels);
> + st->help.indio_dev->read_raw = &lis3l02dq_read_raw;
> + st->help.indio_dev->read_event_value = &lis3l02dq_read_thresh;
> + st->help.indio_dev->write_event_value = &lis3l02dq_write_thresh;
> + st->help.indio_dev->write_event_config = &lis3l02dq_write_event_config;
> + st->help.indio_dev->read_event_config = &lis3l02dq_read_event_config;
> st->help.indio_dev->attrs = &lis3l02dq_attribute_group;
> st->help.indio_dev->dev_data = (void *)(&st->help);
> st->help.indio_dev->driver_module = THIS_MODULE;
I think a lof of this can be turned from code into data if you define
a new structure for all the constant members:
static const struct iio_dev_ops = {
.owner = THIS_MODULE,
.attrs = &lis3l02dq_attribute_group,
.channels = lis3l02dq_channels,
...
};
st->help.indio_dev->ops = &iio_dev_ops;
st->help.indio_dev->dev_data = (void *)(&st->help);
=> somewhat more readable, and smaller object code.
Arnd
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/3] staging:iio: allow channels to be set up using a table of iio_channel_spec structures.
2011-03-24 20:05 ` [PATCH 1/3] staging:iio: allow channels to be set up using a table of iio_channel_spec structures Jonathan Cameron
@ 2011-03-25 14:37 ` Arnd Bergmann
2011-03-25 15:15 ` Jonathan Cameron
0 siblings, 1 reply; 12+ messages in thread
From: Arnd Bergmann @ 2011-03-25 14:37 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-iio
On Thursday 24 March 2011, Jonathan Cameron wrote:
> +
> +/**
> + * 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.
> + * @address: driver specific identifier.
Better make it "unsigned long" instead of int when it's driver specific.
That way, a driver can store a pointer here if necessary.
> +#define IIO_ST(si, rb, sb, sh) \
> + { .sign = si, .realbits = rb, .storagebits = sb, .shift = sh }
> +
> +#define IIO_CHAN(_type, _chan, _inf_mask, _address, _si, _stype) \
> + { .type = _type, .channel = _chan, .info_mask = _inf_mask, \
> + .address = _address, \
> + .scan_index = _si, .scan_type = _stype }
> +
> +#define IIO_CHAN_EV(_type, _chan, _inf_mask, _address, _si, \
> + _stype, _event_mask, _shared_h) \
> + { .type = _type, \
> + .channel = _chan, \
> + .info_mask = _inf_mask, \
> + .address = _address, \
> + .scan_index = _si, .scan_type = _stype, \
> + .event_mask = _event_mask, \
> + .shared_handler = _shared_h }
> +
> +#define IIO_CHAN_COMPOUND(_type, _chan1, _chan2, _inf_mask,_address, _si, _stype) \
> + { .type = _type, .channel = _chan1, .channel2 = _chan2, \
> + .info_mask = _inf_mask, \
> + .address = _address, \
> + .scan_index = _si, .scan_type = _stype }
> +
> +#define IIO_CHAN_COMPOUND_EV(_type, _chan1, _chan2, _inf_mask, \
> + _address, _si, _stype, _event_mask, _shared_h) \
> + { .type = _type, \
> + .channel = _chan1, .channel2 = _chan2, \
> + .info_mask = _inf_mask, \
> + .address = _address, \
> + .scan_index = _si, .scan_type = _stype, \
> + .event_mask = _event_mask, \
> + .shared_handler = _shared_h}
> +
> +#define IIO_CHAN_SOFT_TIMESTAMP(_si) \
> + { .type = IIO_TIMESTAMP, .channel = -1, \
> + .scan_index = _si, .scan_type = IIO_ST('s', 64, 64, 0) }
Maybe try to reduce the number of macros here. In many cases, doing the
assignment manually would be more readable than calling the macro with
unspecified arguments, IMHO.
> @@ -116,6 +248,31 @@ struct iio_dev {
> u32 *available_scan_masks;
> struct iio_trigger *trig;
> struct iio_poll_func *pollfunc;
> +
> + struct iio_chan_spec *channels;
> + int num_channels;
> + struct list_head channel_attr_list;
> +
> + char *name; /*device name - IMPLEMENT */
> + int (*read_raw)(struct iio_dev *indio_dev,
> + struct iio_chan_spec *chan,
> + int *val,
> + long mask);
> +
> + int (*read_event_config)(struct iio_dev *indio_dev,
> + int event_code);
> +
> + int (*write_event_config)(struct iio_dev *indio_dev,
> + int event_code,
> + struct iio_event_handler_list *listel,
> + int state);
> +
> + int (*read_event_value)(struct iio_dev *indio_dev,
> + int event_code,
> + int *val);
> + int (*write_event_value)(struct iio_dev *indio_dev,
> + int event_code,
> + int val);
> };
As mentioned in the comment for 2/3, a number of the members here are
constant, so you could split the structure into a per-driver constant
part and a per-device part, like most other subsystems do.
Arnd
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC PATCH 0/3] Experimenting with channel specification structures.
2011-03-24 20:05 [RFC PATCH 0/3] Experimenting with channel specification structures Jonathan Cameron
` (2 preceding siblings ...)
2011-03-24 20:05 ` [PATCH 3/3] staging:iio:max1363 - experimental move to channel_spec registration Jonathan Cameron
@ 2011-03-25 15:03 ` Arnd Bergmann
2011-03-25 15:19 ` Jonathan Cameron
3 siblings, 1 reply; 12+ messages in thread
From: Arnd Bergmann @ 2011-03-25 15:03 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-iio
On Thursday 24 March 2011, Jonathan Cameron wrote:
> Advantages I can see from this experiement
>
> 1) Simple drivers are more consise.
> 2) It is infact possible to do this for a lot of cases (I had
> my doubts ;)
> 3) It gives us many of the rigid constraints that the many
> attribute macros now handle in a nice clean form.
Very nice!
> Disadvantages:
>
> 1) The core code is rather more complex than I'd like.
Yes, but I think not overly so. Moving complexity from the drivers
into the core should almost always be worth it in the long run.
Remember that people who write the drivers should not need to
worry about many of the complexities of kernel hacking, such
as sysfs attributes or character devices. The more of that you
can do in the core, the less work you have helping your downstream
developers.
> 2) There are cases I haven't yet worked out how to handle properly
> - for example, our lis3l02dq used to output accel_mag_value
> as the threshold value is shared across all high and low threshold
> interrupts. Right now I have no way of specifying this level
> of control for the events lines.
> Also the use of shared event handlers is clunky to say the least.
> This may go away when we rethink the event system though.
I think reworking the way that event buffers work is quite
central here, although mostly orthogonal to the rework of the
internal API.
> 3) Putting hard requirements on numeric formatting of some
> parameters is a pain. If nothing else I need to write a fixed point
> input function.
Yes, but at least you only need to write it once ;-)
> p.s. Despite Arnd's original thread going to lkml I've kept this
> on list for now (+ Arnd of course!) because I want to pin it down
> a bit more before throwing it out more generally.
Fair enough.
Arnd
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/3] staging:iio: allow channels to be set up using a table of iio_channel_spec structures.
2011-03-25 14:37 ` Arnd Bergmann
@ 2011-03-25 15:15 ` Jonathan Cameron
2011-03-25 15:26 ` Arnd Bergmann
0 siblings, 1 reply; 12+ messages in thread
From: Jonathan Cameron @ 2011-03-25 15:15 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linux-iio
On 03/25/11 14:37, Arnd Bergmann wrote:
> On Thursday 24 March 2011, Jonathan Cameron wrote:
>> +
>> +/**
>> + * 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.
>> + * @address: driver specific identifier.
>
> Better make it "unsigned long" instead of int when it's driver specific.
> That way, a driver can store a pointer here if necessary.
Makes sense. Perhaps a union to make the option explicit would be even
better?
Whilst we are talking about types, some of the masks should probably switch to
fixed length arrays of longs though so we don't have massive changes the
moment we run out of space in the single longs. All access will have to then
be through the bitmap functions, but that should be fine.
>
>> +#define IIO_ST(si, rb, sb, sh) \
>> + { .sign = si, .realbits = rb, .storagebits = sb, .shift = sh }
>> +
>> +#define IIO_CHAN(_type, _chan, _inf_mask, _address, _si, _stype) \
>> + { .type = _type, .channel = _chan, .info_mask = _inf_mask, \
>> + .address = _address, \
>> + .scan_index = _si, .scan_type = _stype }
>> +
>> +#define IIO_CHAN_EV(_type, _chan, _inf_mask, _address, _si, \
>> + _stype, _event_mask, _shared_h) \
>> + { .type = _type, \
>> + .channel = _chan, \
>> + .info_mask = _inf_mask, \
>> + .address = _address, \
>> + .scan_index = _si, .scan_type = _stype, \
>> + .event_mask = _event_mask, \
>> + .shared_handler = _shared_h }
>> +
>> +#define IIO_CHAN_COMPOUND(_type, _chan1, _chan2, _inf_mask,_address, _si, _stype) \
>> + { .type = _type, .channel = _chan1, .channel2 = _chan2, \
>> + .info_mask = _inf_mask, \
>> + .address = _address, \
>> + .scan_index = _si, .scan_type = _stype }
>> +
>> +#define IIO_CHAN_COMPOUND_EV(_type, _chan1, _chan2, _inf_mask, \
>> + _address, _si, _stype, _event_mask, _shared_h) \
>> + { .type = _type, \
>> + .channel = _chan1, .channel2 = _chan2, \
>> + .info_mask = _inf_mask, \
>> + .address = _address, \
>> + .scan_index = _si, .scan_type = _stype, \
>> + .event_mask = _event_mask, \
>> + .shared_handler = _shared_h}
>> +
>> +#define IIO_CHAN_SOFT_TIMESTAMP(_si) \
>> + { .type = IIO_TIMESTAMP, .channel = -1, \
>> + .scan_index = _si, .scan_type = IIO_ST('s', 64, 64, 0) }
>
> Maybe try to reduce the number of macros here. In many cases, doing the
> assignment manually would be more readable than calling the macro with
> unspecified arguments, IMHO.
Perhaps. The advantage of macros is it gives us a common point to do nasty
tricks like that .channel = -1 in the timestamp macro. What I don't want to
end up with is having to change thousands of calls the moment we need something
to default to a value other than 0. Having said that, some of these only
really evolved as I wanted to mess around with the internal structure whilst
developing this and can reasonably go away now.
>
>> @@ -116,6 +248,31 @@ struct iio_dev {
>> u32 *available_scan_masks;
>> struct iio_trigger *trig;
>> struct iio_poll_func *pollfunc;
>> +
>> + struct iio_chan_spec *channels;
>> + int num_channels;
>> + struct list_head channel_attr_list;
>> +
>> + char *name; /*device name - IMPLEMENT */
>> + int (*read_raw)(struct iio_dev *indio_dev,
>> + struct iio_chan_spec *chan,
>> + int *val,
>> + long mask);
>> +
>> + int (*read_event_config)(struct iio_dev *indio_dev,
>> + int event_code);
>> +
>> + int (*write_event_config)(struct iio_dev *indio_dev,
>> + int event_code,
>> + struct iio_event_handler_list *listel,
>> + int state);
>> +
>> + int (*read_event_value)(struct iio_dev *indio_dev,
>> + int event_code,
>> + int *val);
>> + int (*write_event_value)(struct iio_dev *indio_dev,
>> + int event_code,
>> + int val);
>> };
>
> As mentioned in the comment for 2/3, a number of the members here are
> constant, so you could split the structure into a per-driver constant
> part and a per-device part, like most other subsystems do.
Good idea. Might have to be at a finer level than per driver though.
I can certainly envision some drivers want for example to have a number
of variants of read_raw to account for subtle difference in what channels
are present on individual parts.
However I think this refactoring should wait until after the other
big changes are in.
>
> Arnd
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC PATCH 0/3] Experimenting with channel specification structures.
2011-03-25 15:03 ` [RFC PATCH 0/3] Experimenting with channel specification structures Arnd Bergmann
@ 2011-03-25 15:19 ` Jonathan Cameron
0 siblings, 0 replies; 12+ messages in thread
From: Jonathan Cameron @ 2011-03-25 15:19 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linux-iio
On 03/25/11 15:03, Arnd Bergmann wrote:
> On Thursday 24 March 2011, Jonathan Cameron wrote:
>> Advantages I can see from this experiement
>>
>> 1) Simple drivers are more consise.
>> 2) It is infact possible to do this for a lot of cases (I had
>> my doubts ;)
>> 3) It gives us many of the rigid constraints that the many
>> attribute macros now handle in a nice clean form.
>
> Very nice!
>
>> Disadvantages:
>>
>> 1) The core code is rather more complex than I'd like.
>
> Yes, but I think not overly so. Moving complexity from the drivers
> into the core should almost always be worth it in the long run.
>
> Remember that people who write the drivers should not need to
> worry about many of the complexities of kernel hacking, such
> as sysfs attributes or character devices. The more of that you
> can do in the core, the less work you have helping your downstream
> developers.
My current downstream developers are going to moan about this change ;)
>
>> 2) There are cases I haven't yet worked out how to handle properly
>> - for example, our lis3l02dq used to output accel_mag_value
>> as the threshold value is shared across all high and low threshold
>> interrupts. Right now I have no way of specifying this level
>> of control for the events lines.
>> Also the use of shared event handlers is clunky to say the least.
>> This may go away when we rethink the event system though.
>
> I think reworking the way that event buffers work is quite
> central here, although mostly orthogonal to the rework of the
> internal API.
Next on the list.
>
>> 3) Putting hard requirements on numeric formatting of some
>> parameters is a pain. If nothing else I need to write a fixed point
>> input function.
>
> Yes, but at least you only need to write it once ;-)
hmph.
>
>> p.s. Despite Arnd's original thread going to lkml I've kept this
>> on list for now (+ Arnd of course!) because I want to pin it down
>> a bit more before throwing it out more generally.
>
> Fair enough.
>
> Arnd
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/3] staging:iio: allow channels to be set up using a table of iio_channel_spec structures.
2011-03-25 15:15 ` Jonathan Cameron
@ 2011-03-25 15:26 ` Arnd Bergmann
0 siblings, 0 replies; 12+ messages in thread
From: Arnd Bergmann @ 2011-03-25 15:26 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-iio
On Friday 25 March 2011, Jonathan Cameron wrote:
> > Better make it "unsigned long" instead of int when it's driver specific.
> > That way, a driver can store a pointer here if necessary.
> Makes sense. Perhaps a union to make the option explicit would be even
> better?
You can try it, but often unions cause more trouble than they are
worth. If most drivers just need an integer, using unsigned long
should be easier than a union.
> Whilst we are talking about types, some of the masks should probably switch to
> fixed length arrays of longs though so we don't have massive changes the
> moment we run out of space in the single longs. All access will have to then
> be through the bitmap functions, but that should be fine.
Depends on whether you expect the masks to be exceeded any time soon.
I would expect 32 bits to be quite a lot, and it's easy to extend to
64 before you need to move to the bitops API.
> >> @@ -116,6 +248,31 @@ struct iio_dev {
> >> u32 *available_scan_masks;
> >> struct iio_trigger *trig;
> >> struct iio_poll_func *pollfunc;
> >> +
> >> + struct iio_chan_spec *channels;
> >> + int num_channels;
> >> + struct list_head channel_attr_list;
> >> +
> >> + char *name; /*device name - IMPLEMENT */
> >> + int (*read_raw)(struct iio_dev *indio_dev,
> >> + struct iio_chan_spec *chan,
> >> + int *val,
> >> + long mask);
> >> +
> >> + int (*read_event_config)(struct iio_dev *indio_dev,
> >> + int event_code);
> >> +
> >> + int (*write_event_config)(struct iio_dev *indio_dev,
> >> + int event_code,
> >> + struct iio_event_handler_list *listel,
> >> + int state);
> >> +
> >> + int (*read_event_value)(struct iio_dev *indio_dev,
> >> + int event_code,
> >> + int *val);
> >> + int (*write_event_value)(struct iio_dev *indio_dev,
> >> + int event_code,
> >> + int val);
> >> };
> >
> > As mentioned in the comment for 2/3, a number of the members here are
> > constant, so you could split the structure into a per-driver constant
> > part and a per-device part, like most other subsystems do.
>
> Good idea. Might have to be at a finer level than per driver though.
> I can certainly envision some drivers want for example to have a number
> of variants of read_raw to account for subtle difference in what channels
> are present on individual parts.
Right.
> However I think this refactoring should wait until after the other
> big changes are in.
Ok.
Arnd
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/3] staging:iio:lis3l02dq - experimental move to new channel_spec approach.
2011-03-25 14:26 ` Arnd Bergmann
@ 2011-03-25 15:38 ` Jonathan Cameron
2011-03-25 16:02 ` Arnd Bergmann
0 siblings, 1 reply; 12+ messages in thread
From: Jonathan Cameron @ 2011-03-25 15:38 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linux-iio
On 03/25/11 14:26, Arnd Bergmann wrote:
> I like the changes. The savings are a little less than what I had hoped
> for, but a lot of the redundant code that gets copied to each driver
> is gone.
>
> On Thursday 24 March 2011, Jonathan Cameron wrote:
>> -/**
>> - * lis3l02dq_spi_read_reg_8() - read single byte from a single register
>> - * @dev: device asosciated with child of actual device (iio_dev or iio_trig)
>> - * @reg_address: the address of the register to be read
>> - * @val: pass back the resulting value
>> - **/
>> -int lis3l02dq_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
>> +static int __lis3l02dq_spi_read_reg_8(struct lis3l02dq_state *st,
>> + u8 reg_address, u8 *val)
>> {
>> - int ret;
>> struct spi_message msg;
>> - struct iio_dev *indio_dev = dev_get_drvdata(dev);
>> - struct iio_sw_ring_helper_state *h = iio_dev_get_devdata(indio_dev);
>> - struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
>> -
>> + int ret;
>> struct spi_transfer xfer = {
>> .tx_buf = st->tx,
>> .rx_buf = st->rx,
>>
>> @@ -73,6 +64,19 @@ int lis3l02dq_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
>>
>> return ret;
>> }
>> +/**
>> + * lis3l02dq_spi_read_reg_8() - read single byte from a single register
>> + * @dev: device asosciated with child of actual device (iio_dev or iio_trig)
>> + * @reg_address: the address of the register to be read
>> + * @val: pass back the resulting value
>> + **/
>> +int lis3l02dq_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
>> +{
>> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
>> + struct iio_sw_ring_helper_state *h = iio_dev_get_devdata(indio_dev);
>> + struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
>> + return __lis3l02dq_spi_read_reg_8(st, reg_address, val);
>> +}
>
>
> This change seems unrelated to the main intention of the driver.
> I think the cleanest way to handle this would be to always pass the
> iio_dev to the low-level functions. Passing a bare struct device
> is hardly ever helpful, and from the iio_dev, you can easily get to
> both the device and the lis3l02dq_state.
Good point. I should have taken a closer look at where we've ended up in
this driver. Some of this has evolved from pre IIO days!
>
>> +enum lis3l02dq_rm_ind {
>> + LIS3L02DQ_ACCEL,
>> + LIS3L02DQ_GAIN,
>> + LIS3L02DQ_BIAS,
>> +};
>>
>> +static u8 lis3l02dq_axis_map[3][3] = {
>> + [LIS3L02DQ_ACCEL] = { LIS3L02DQ_REG_OUT_X_L_ADDR,
>> + LIS3L02DQ_REG_OUT_Y_L_ADDR,
>> + LIS3L02DQ_REG_OUT_Z_L_ADDR },
>> + [LIS3L02DQ_GAIN] = { LIS3L02DQ_REG_GAIN_X_ADDR,
>> + LIS3L02DQ_REG_GAIN_Y_ADDR,
>> + LIS3L02DQ_REG_GAIN_Z_ADDR },
>> + [LIS3L02DQ_BIAS] = { LIS3L02DQ_REG_OFFSET_X_ADDR,
>> + LIS3L02DQ_REG_OFFSET_Y_ADDR,
>> + LIS3L02DQ_REG_OFFSET_Z_ADDR }
>> +};
>
> The table looks nice and small, but I can't see where the BIAS
> value is used. Is that something that the hardware supports but
> the driver does not?
Gah. That's just a straight bug. BIAS on the chip maps to calibbias
in sysfs. Last case statement in lis3l02dq_read_raw has the wrong element
of the array. Good spot!
>
>> +static int lis3l02dq_read_thresh(struct iio_dev *indio_dev,
>> + int e,
>> + int *val)
>> {
>> + struct iio_sw_ring_helper_state *h
>> + = iio_dev_get_devdata(indio_dev);
>> + struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
>>
>> + return lis3l02dq_read_16bit_s(st, LIS3L02DQ_REG_THS_L_ADDR, val);
>> }
>>
>> +static int lis3l02dq_write_thresh(struct iio_dev *indio_dev,
>> + int event_code,
>> + int val)
>> {
>> + u16 value = val;
>> + return lis3l02dq_spi_write_reg_s16(&indio_dev->dev,
>> + LIS3L02DQ_REG_THS_L_ADDR,
>> + value);
>> }
>
> Can be made even smaller if you drop the u16 value variable and
> rely on the implicit type conversion ;-)
Should probably have some specific checking on that parameter rather
than clamping it down to a u16 instead.
>
>> +static int lis3l02dq_read_raw(struct iio_dev *indio_dev,
>> + struct iio_chan_spec *chan,
>> + int *val,
>> + long mask)
>> {
>
> I guess that in the mask work, you can only pass one bit at most,
> right? How about passing the bit number instead?
Fair point.
>
>
>> +/* A shared handler for a number of threshold types */
>> +IIO_EVENT_SH(threshold, &lis3l02dq_thresh_handler_th);
>>
>> +#define LIS3L02DQ_INFO_MASK \
>> + (1 << IIO_CHAN_INFO_SCALE_SHARED) | \
>> + (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | \
>> + (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE)
>> +
>> +#define LIS3L02DQ_EVENT_MASK \
>> + IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
>> + IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)
>> +
>> +static struct iio_chan_spec lis3l02dq_channels[] = {
>> + IIO_CHAN_EV(IIO_ACCEL, 'x', LIS3L02DQ_INFO_MASK,
>> + 0, 0, IIO_ST('s', 12, 16, 0),
>> + LIS3L02DQ_EVENT_MASK, &iio_event_threshold),
>> + IIO_CHAN_EV(IIO_ACCEL, 'y', LIS3L02DQ_INFO_MASK,
>> + 1, 1, IIO_ST('s', 12, 16, 0),
>> + LIS3L02DQ_EVENT_MASK, &iio_event_threshold),
>> + IIO_CHAN(IIO_ACCEL, 'z', LIS3L02DQ_INFO_MASK,
>> + 2, 2, IIO_ST('s', 12, 16, 0)),
>> + IIO_CHAN_SOFT_TIMESTAMP(3)
>> +};
>
> Hmm, this has turned out more complex than I had hoped for,
> but that's probably the way things go when you put them into
> real code.
Interestingly it's actually a touch simpler than I thought it would be ;)
>
>> +static ssize_t lis3l02dq_read_event_config(struct iio_dev *indio_dev,
>> + int event_code)
>> +{
>> +
>> + u8 val;
>> + int ret;
>> + u8 mask = (1 << (IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code)*2 +
>> + (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
>> + IIO_EV_DIR_RISING)));
>> + ret = lis3l02dq_spi_read_reg_8(&indio_dev->dev,
>> LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
>> + &val);
>> + if (ret < 0)
>> + return ret;
>> +
>> + return !!(val & mask);
>> +}
>
> I need some background information here. Why do you expose the configuration
> register directly? Is this something that users normally access?
>
> I would assume that it's highly device specific and would need to be
> abstracted by the kernel.
We could cache what events are enabled, and in some drivers we do. Here it is
just simpler to ask the device as it has a convenient bitmap of what is enabled.
It's actually a real pain to completely abstract this away because some
devices only support sets of events at a time and exactly which are
supported can be extremely complex. The common cases are:
1) Separate comparators for each event. (simple as we have here!)
2) n comparators which can be configured to any n events from a large list (adis16350
is a classic example though we haven't finally merged event support for that
part yet).
3) n comparators each of which can be configured to a subset of thresholds. e.g. one
comparator per channel, lots of different things it can compare about the channel.
It is possible that we can abstract these at some point, but right now I'm not even
tempted to try! We are mostly avoiding the nastiest case at the moment which is
where you have controllable compound events. In this particular device you can
either have the events as 'or' as we do or 'and' for any set of them. Right now
we simply don't implement the 'and' case.
>
>> @@ -813,7 +690,13 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
>>
>> st->help.indio_dev->dev.parent = &spi->dev;
>> st->help.indio_dev->num_interrupt_lines = 1;
>> - st->help.indio_dev->event_attrs = &lis3l02dq_event_attribute_group;
>> + st->help.indio_dev->channels = lis3l02dq_channels;
>> + st->help.indio_dev->num_channels = ARRAY_SIZE(lis3l02dq_channels);
>> + st->help.indio_dev->read_raw = &lis3l02dq_read_raw;
>> + st->help.indio_dev->read_event_value = &lis3l02dq_read_thresh;
>> + st->help.indio_dev->write_event_value = &lis3l02dq_write_thresh;
>> + st->help.indio_dev->write_event_config = &lis3l02dq_write_event_config;
>> + st->help.indio_dev->read_event_config = &lis3l02dq_read_event_config;
>> st->help.indio_dev->attrs = &lis3l02dq_attribute_group;
>> st->help.indio_dev->dev_data = (void *)(&st->help);
>> st->help.indio_dev->driver_module = THIS_MODULE;
>
> I think a lof of this can be turned from code into data if you define
> a new structure for all the constant members:
I agree entirely. I just haven't done it yet!
>
> static const struct iio_dev_ops = {
> .owner = THIS_MODULE,
> .attrs = &lis3l02dq_attribute_group,
> .channels = lis3l02dq_channels,
> ...
> };
>
> st->help.indio_dev->ops = &iio_dev_ops;
> st->help.indio_dev->dev_data = (void *)(&st->help);
>
> => somewhat more readable, and smaller object code.
>
> Arnd
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/3] staging:iio:lis3l02dq - experimental move to new channel_spec approach.
2011-03-25 15:38 ` Jonathan Cameron
@ 2011-03-25 16:02 ` Arnd Bergmann
0 siblings, 0 replies; 12+ messages in thread
From: Arnd Bergmann @ 2011-03-25 16:02 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-iio
On Friday 25 March 2011, Jonathan Cameron wrote:
> > I need some background information here. Why do you expose the configuration
> > register directly? Is this something that users normally access?
> >
> > I would assume that it's highly device specific and would need to be
> > abstracted by the kernel.
> We could cache what events are enabled, and in some drivers we do. Here it is
> just simpler to ask the device as it has a convenient bitmap of what is enabled.
>
> It's actually a real pain to completely abstract this away because some
> devices only support sets of events at a time and exactly which are
> supported can be extremely complex. The common cases are:
>
> 1) Separate comparators for each event. (simple as we have here!)
> 2) n comparators which can be configured to any n events from a large list (adis16350
> is a classic example though we haven't finally merged event support for that
> part yet).
> 3) n comparators each of which can be configured to a subset of thresholds. e.g. one
> comparator per channel, lots of different things it can compare about the channel.
>
> It is possible that we can abstract these at some point, but right now I'm not even
> tempted to try! We are mostly avoiding the nastiest case at the moment which is
> where you have controllable compound events. In this particular device you can
> either have the events as 'or' as we do or 'and' for any set of them. Right now
> we simply don't implement the 'and' case.
Ok, thanks for the explanation.
Arnd
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2011-03-25 16:02 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-24 20:05 [RFC PATCH 0/3] Experimenting with channel specification structures Jonathan Cameron
2011-03-24 20:05 ` [PATCH 1/3] staging:iio: allow channels to be set up using a table of iio_channel_spec structures Jonathan Cameron
2011-03-25 14:37 ` Arnd Bergmann
2011-03-25 15:15 ` Jonathan Cameron
2011-03-25 15:26 ` Arnd Bergmann
2011-03-24 20:05 ` [PATCH 2/3] staging:iio:lis3l02dq - experimental move to new channel_spec approach Jonathan Cameron
2011-03-25 14:26 ` Arnd Bergmann
2011-03-25 15:38 ` Jonathan Cameron
2011-03-25 16:02 ` Arnd Bergmann
2011-03-24 20:05 ` [PATCH 3/3] staging:iio:max1363 - experimental move to channel_spec registration Jonathan Cameron
2011-03-25 15:03 ` [RFC PATCH 0/3] Experimenting with channel specification structures Arnd Bergmann
2011-03-25 15:19 ` Jonathan Cameron
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.