All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/11] iio: add support for hardware buffers
@ 2014-12-21  0:42 Octavian Purdila
  2014-12-21  0:42 ` [PATCH v2 01/11] iio: buffer: fix custom buffer attributes copy Octavian Purdila
                   ` (10 more replies)
  0 siblings, 11 replies; 50+ messages in thread
From: Octavian Purdila @ 2014-12-21  0:42 UTC (permalink / raw)
  To: linux-iio; +Cc: Octavian Purdila

This 2nd patch set brings a new approach to hadware buffers, as a
result of the feedback from the first patch set. It also fixes a few
issues in the bmc150 refactor patches found during the review.

It builds on the patch of Josselin and Yannick but with the timeout
parameter removed, as the poll timeout can be used instead (for
non-blocking reads).

In order to provide support for hardware buffers a driver must expose
a watermark trigger, a function to set the watermark level in hadware
and a function to flush the hardware buffers. It must also expose the
maximum number of samples that the hardware buffer can hold. When the
watermark trigger is set the driver must make sure that the hardware
buffer is operational so that we can hold samples until the watermark
level is reached. When the watermark level is reached (the watermark
triggered is activated) and when the flush operation is called, the
driver must read all of the entries from the hardware buffers and
store then in the device buffer.

>From the userspace point of view, to enable hardware buffers, the
application must set the device buffer and the watermark level to an
appropriate value then switch to using the watermark trigger. At that
point the data will be hold in the hadware buffer and the processor
will not be interrupted until the hadware buffer level reaches the
watermark level. 

The application can force a flush operation when reading from the
device and there is not enough data available to satisfy the
request. This allows the application to balance power-consumption and
latency by setting a poll timeout and forcing a non-blocking read when
the poll timeout expires which allows the application to retrieve any
samples stored in the hardware buffer.


Josselin Costanzi (1):
  iio: add watermark logic to iio read and poll

Octavian Purdila (10):
  iio: buffer: fix custom buffer attributes copy
  iio: buffer: refactor buffer attributes setup
  iio: add support for hardware fifo
  iio: bmc150: refactor slope duration and threshold update
  iio: bmc150: refactor interrupt enabling
  iio: bmc150: exit early if event / trigger state is not changed
  iio: bmc150: introduce bmc150_accel_interrupt
  iio: bmc150: introduce bmc150_accel_trigger
  iio: bmc150: introduce bmc150_accel_event
  iio: bmc150: add support for hardware fifo

 Documentation/ABI/testing/sysfs-bus-iio  |  32 ++
 drivers/iio/accel/bmc150-accel.c         | 919 ++++++++++++++++++++-----------
 drivers/iio/industrialio-buffer.c        | 179 ++++--
 drivers/iio/kfifo_buf.c                  |  11 +-
 drivers/staging/iio/accel/sca3000_ring.c |   4 +-
 include/linux/iio/buffer.h               |   9 +-
 include/linux/iio/iio.h                  |  17 +
 7 files changed, 819 insertions(+), 352 deletions(-)

-- 
1.9.1


^ permalink raw reply	[flat|nested] 50+ messages in thread

* [PATCH v2 01/11] iio: buffer: fix custom buffer attributes copy
  2014-12-21  0:42 [PATCH v2 00/11] iio: add support for hardware buffers Octavian Purdila
@ 2014-12-21  0:42 ` Octavian Purdila
  2015-01-04 11:25   ` Jonathan Cameron
  2014-12-21  0:42 ` [PATCH v2 02/11] iio: buffer: refactor buffer attributes setup Octavian Purdila
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2014-12-21  0:42 UTC (permalink / raw)
  To: linux-iio; +Cc: Octavian Purdila

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 drivers/iio/industrialio-buffer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 2bd8d39..403b728 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -789,7 +789,7 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
 	buffer->buffer_group.attrs[1] = &dev_attr_enable.attr;
 	if (buffer->attrs)
 		memcpy(&buffer->buffer_group.attrs[2], buffer->attrs,
-			sizeof(*&buffer->buffer_group.attrs) * (attrcount - 2));
+			sizeof(*&buffer->buffer_group.attrs) * attrcount);
 	buffer->buffer_group.attrs[attrcount+2] = NULL;
 
 	indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 02/11] iio: buffer: refactor buffer attributes setup
  2014-12-21  0:42 [PATCH v2 00/11] iio: add support for hardware buffers Octavian Purdila
  2014-12-21  0:42 ` [PATCH v2 01/11] iio: buffer: fix custom buffer attributes copy Octavian Purdila
@ 2014-12-21  0:42 ` Octavian Purdila
  2015-01-04 11:31   ` Jonathan Cameron
  2014-12-21  0:42 ` [PATCH v2 03/11] iio: add watermark logic to iio read and poll Octavian Purdila
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2014-12-21  0:42 UTC (permalink / raw)
  To: linux-iio; +Cc: Octavian Purdila

Move all core (non-cusotm) buffer attributes to a vector to make it
easier to add more of them in the future.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 drivers/iio/industrialio-buffer.c | 31 +++++++++++++++++++------------
 1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 403b728..bc55434 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -759,6 +759,11 @@ static struct device_attribute dev_attr_length_ro = __ATTR(length,
 static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
 		   iio_buffer_show_enable, iio_buffer_store_enable);
 
+static struct attribute *iio_buffer_attrs[] = {
+	&dev_attr_length.attr,
+	&dev_attr_enable.attr,
+};
+
 int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
 {
 	struct iio_dev_attr *p;
@@ -776,21 +781,23 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
 			attrcount++;
 	}
 
-	buffer->buffer_group.name = "buffer";
-	buffer->buffer_group.attrs = kcalloc(attrcount + 3,
-			sizeof(*buffer->buffer_group.attrs), GFP_KERNEL);
-	if (!buffer->buffer_group.attrs)
+	attr = kcalloc(attrcount + ARRAY_SIZE(iio_buffer_attrs) + 1,
+		       sizeof(struct attribute *), GFP_KERNEL);
+	if (!attr)
 		return -ENOMEM;
 
-	if (buffer->access->set_length)
-		buffer->buffer_group.attrs[0] = &dev_attr_length.attr;
-	else
-		buffer->buffer_group.attrs[0] = &dev_attr_length_ro.attr;
-	buffer->buffer_group.attrs[1] = &dev_attr_enable.attr;
+	memcpy(attr, iio_buffer_attrs, sizeof(iio_buffer_attrs));
+	if (!buffer->access->set_length)
+		attr[0] = &dev_attr_length_ro.attr;
+
 	if (buffer->attrs)
-		memcpy(&buffer->buffer_group.attrs[2], buffer->attrs,
-			sizeof(*&buffer->buffer_group.attrs) * attrcount);
-	buffer->buffer_group.attrs[attrcount+2] = NULL;
+		memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs,
+		       sizeof(struct attribute *) * attrcount);
+
+	attr[attrcount + ARRAY_SIZE(iio_buffer_attrs)] = NULL;
+
+	buffer->buffer_group.name = "buffer";
+	buffer->buffer_group.attrs = attr;
 
 	indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group;
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 03/11] iio: add watermark logic to iio read and poll
  2014-12-21  0:42 [PATCH v2 00/11] iio: add support for hardware buffers Octavian Purdila
  2014-12-21  0:42 ` [PATCH v2 01/11] iio: buffer: fix custom buffer attributes copy Octavian Purdila
  2014-12-21  0:42 ` [PATCH v2 02/11] iio: buffer: refactor buffer attributes setup Octavian Purdila
@ 2014-12-21  0:42 ` Octavian Purdila
  2015-01-04 15:44   ` Jonathan Cameron
  2015-01-25 21:22   ` Hartmut Knaack
  2014-12-21  0:42 ` [PATCH v2 04/11] iio: add support for hardware fifo Octavian Purdila
                   ` (7 subsequent siblings)
  10 siblings, 2 replies; 50+ messages in thread
From: Octavian Purdila @ 2014-12-21  0:42 UTC (permalink / raw)
  To: linux-iio; +Cc: Josselin Costanzi, Octavian Purdila

From: Josselin Costanzi <josselin.costanzi@mobile-devices.fr>

Currently the IIO buffer blocking read only wait until at least one
data element is available.
This patch makes the reader sleep until enough data is collected before
returning to userspace. This should limit the read() calls count when
trying to get data in batches.

Co-author: Yannick Bedhomme <yannick.bedhomme@mobile-devices.fr>
Signed-off-by: Josselin Costanzi <josselin.costanzi@mobile-devices.fr>
[rebased and remove buffer timeout]
Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 Documentation/ABI/testing/sysfs-bus-iio  |  10 +++
 drivers/iio/industrialio-buffer.c        | 114 ++++++++++++++++++++++++++-----
 drivers/iio/kfifo_buf.c                  |  11 ++-
 drivers/staging/iio/accel/sca3000_ring.c |   4 +-
 include/linux/iio/buffer.h               |   9 ++-
 5 files changed, 118 insertions(+), 30 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index df5e69e..7260f1f 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -1142,3 +1142,13 @@ Contact:	linux-iio@vger.kernel.org
 Description:
 		This attribute is used to read the number of steps taken by the user
 		since the last reboot while activated.
+
+What:		/sys/bus/iio/devices/iio:deviceX/buffer/low_watermark
+KernelVersion:	3.20
+Contact:	linux-iio@vger.kernel.org
+Description:
+		A single positive integer specifying the maximum number of scan
+		elements to wait for.
+		Poll will block until the watermark is reached.
+		Blocking read will wait until the minimum between the requested
+		read amount or the low water mark is available.
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index bc55434..7f74c7f 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -37,7 +37,7 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
 	return !list_empty(&buf->buffer_list);
 }
 
-static bool iio_buffer_data_available(struct iio_buffer *buf)
+static size_t iio_buffer_data_available(struct iio_buffer *buf)
 {
 	return buf->access->data_available(buf);
 }
@@ -53,6 +53,9 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
 {
 	struct iio_dev *indio_dev = filp->private_data;
 	struct iio_buffer *rb = indio_dev->buffer;
+	size_t datum_size = rb->bytes_per_datum;
+	size_t to_read = min_t(size_t, n / datum_size, rb->low_watermark);
+	size_t count = 0;
 	int ret;
 
 	if (!indio_dev->info)
@@ -62,25 +65,38 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
 		return -EINVAL;
 
 	do {
-		if (!iio_buffer_data_available(rb)) {
-			if (filp->f_flags & O_NONBLOCK)
-				return -EAGAIN;
-
+		if (filp->f_flags & O_NONBLOCK) {
+			if (!iio_buffer_data_available(rb)) {
+				ret = -EAGAIN;
+				break;
+			}
+		} else {
 			ret = wait_event_interruptible(rb->pollq,
-					iio_buffer_data_available(rb) ||
-					indio_dev->info == NULL);
+			       iio_buffer_data_available(rb) >= to_read ||
+						       indio_dev->info == NULL);
 			if (ret)
 				return ret;
-			if (indio_dev->info == NULL)
-				return -ENODEV;
+			if (indio_dev->info == NULL) {
+				ret = -ENODEV;
+				break;
+			}
 		}
 
-		ret = rb->access->read_first_n(rb, n, buf);
-		if (ret == 0 && (filp->f_flags & O_NONBLOCK))
-			ret = -EAGAIN;
-	 } while (ret == 0);
+		ret = rb->access->read_first_n(rb, n, buf + count);
+		if (ret < 0)
+			break;
 
-	return ret;
+		count += ret;
+		n -= ret;
+		to_read -= ret / datum_size;
+	 } while (to_read > 0);
+
+	if (count)
+		return count;
+	if (ret < 0)
+		return ret;
+
+	return -EAGAIN;
 }
 
 /**
@@ -96,9 +112,8 @@ unsigned int iio_buffer_poll(struct file *filp,
 		return -ENODEV;
 
 	poll_wait(filp, &rb->pollq, wait);
-	if (iio_buffer_data_available(rb))
+	if (iio_buffer_data_available(rb) >= rb->low_watermark)
 		return POLLIN | POLLRDNORM;
-	/* need a way of knowing if there may be enough data... */
 	return 0;
 }
 
@@ -123,6 +138,7 @@ void iio_buffer_init(struct iio_buffer *buffer)
 	INIT_LIST_HEAD(&buffer->buffer_list);
 	init_waitqueue_head(&buffer->pollq);
 	kref_init(&buffer->ref);
+	buffer->low_watermark = 1;
 }
 EXPORT_SYMBOL(iio_buffer_init);
 
@@ -418,7 +434,16 @@ static ssize_t iio_buffer_write_length(struct device *dev,
 	}
 	mutex_unlock(&indio_dev->mlock);
 
-	return ret ? ret : len;
+	if (ret)
+		return ret;
+
+	if (buffer->length)
+		val = buffer->length;
+
+	if (val < buffer->low_watermark)
+		buffer->low_watermark = val;
+
+	return len;
 }
 
 static ssize_t iio_buffer_show_enable(struct device *dev,
@@ -472,6 +497,7 @@ static void iio_buffer_activate(struct iio_dev *indio_dev,
 static void iio_buffer_deactivate(struct iio_buffer *buffer)
 {
 	list_del_init(&buffer->buffer_list);
+	wake_up_interruptible(&buffer->pollq);
 	iio_buffer_put(buffer);
 }
 
@@ -752,16 +778,59 @@ done:
 
 static const char * const iio_scan_elements_group_name = "scan_elements";
 
+static ssize_t iio_buffer_show_watermark(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_buffer *buffer = indio_dev->buffer;
+
+	return sprintf(buf, "%u\n", buffer->low_watermark);
+}
+
+static ssize_t iio_buffer_store_watermark(struct device *dev,
+					  struct device_attribute *attr,
+					  const char *buf,
+					  size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct iio_buffer *buffer = indio_dev->buffer;
+	unsigned int val;
+	int ret;
+
+	ret = kstrtouint(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	if (val > buffer->length)
+		return -EINVAL;
+
+	mutex_lock(&indio_dev->mlock);
+	if (iio_buffer_is_active(indio_dev->buffer)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	buffer->low_watermark = val;
+	ret = 0;
+out:
+	mutex_unlock(&indio_dev->mlock);
+	return ret ? ret : len;
+}
+
 static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
 		   iio_buffer_write_length);
 static struct device_attribute dev_attr_length_ro = __ATTR(length,
 	S_IRUGO, iio_buffer_read_length, NULL);
 static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
 		   iio_buffer_show_enable, iio_buffer_store_enable);
+static DEVICE_ATTR(low_watermark, S_IRUGO | S_IWUSR,
+		   iio_buffer_show_watermark, iio_buffer_store_watermark);
 
 static struct attribute *iio_buffer_attrs[] = {
 	&dev_attr_length.attr,
 	&dev_attr_enable.attr,
+	&dev_attr_low_watermark.attr,
 };
 
 int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
@@ -942,8 +1011,17 @@ static const void *iio_demux(struct iio_buffer *buffer,
 static int iio_push_to_buffer(struct iio_buffer *buffer, const void *data)
 {
 	const void *dataout = iio_demux(buffer, data);
+	int ret;
 
-	return buffer->access->store_to(buffer, dataout);
+	ret = buffer->access->store_to(buffer, dataout);
+	if (ret)
+		return ret;
+
+	/* We can't just test for watermark to decide if we wake the poll queue
+	 * because read may request less samples than the watermark
+	 */
+	wake_up_interruptible(&buffer->pollq);
+	return 0;
 }
 
 static void iio_buffer_demux_free(struct iio_buffer *buffer)
diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c
index b20a9cf..30a9bfa 100644
--- a/drivers/iio/kfifo_buf.c
+++ b/drivers/iio/kfifo_buf.c
@@ -83,9 +83,6 @@ static int iio_store_to_kfifo(struct iio_buffer *r,
 	ret = kfifo_in(&kf->kf, data, 1);
 	if (ret != 1)
 		return -EBUSY;
-
-	wake_up_interruptible_poll(&r->pollq, POLLIN | POLLRDNORM);
-
 	return 0;
 }
 
@@ -109,16 +106,16 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
 	return copied;
 }
 
-static bool iio_kfifo_buf_data_available(struct iio_buffer *r)
+static size_t iio_kfifo_buf_data_available(struct iio_buffer *r)
 {
 	struct iio_kfifo *kf = iio_to_kfifo(r);
-	bool empty;
+	size_t samples;
 
 	mutex_lock(&kf->user_lock);
-	empty = kfifo_is_empty(&kf->kf);
+	samples = kfifo_len(&kf->kf);
 	mutex_unlock(&kf->user_lock);
 
-	return !empty;
+	return samples;
 }
 
 static void iio_kfifo_buffer_release(struct iio_buffer *buffer)
diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c
index f76a268..1e65dea 100644
--- a/drivers/staging/iio/accel/sca3000_ring.c
+++ b/drivers/staging/iio/accel/sca3000_ring.c
@@ -129,9 +129,9 @@ error_ret:
 	return ret ? ret : num_read;
 }
 
-static bool sca3000_ring_buf_data_available(struct iio_buffer *r)
+static size_t sca3000_ring_buf_data_available(struct iio_buffer *r)
 {
-	return r->stufftoread;
+	return r->stufftoread ? r->low_watermark : 0;
 }
 
 /**
diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
index b65850a..768593c 100644
--- a/include/linux/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -21,8 +21,8 @@ struct iio_buffer;
  * struct iio_buffer_access_funcs - access functions for buffers.
  * @store_to:		actually store stuff to the buffer
  * @read_first_n:	try to get a specified number of bytes (must exist)
- * @data_available:	indicates whether data for reading from the buffer is
- *			available.
+ * @data_available:	indicates how much data is available for reading from
+ *			the buffer.
  * @request_update:	if a parameter change has been marked, update underlying
  *			storage.
  * @set_bytes_per_datum:set number of bytes per datum
@@ -43,7 +43,7 @@ struct iio_buffer_access_funcs {
 	int (*read_first_n)(struct iio_buffer *buffer,
 			    size_t n,
 			    char __user *buf);
-	bool (*data_available)(struct iio_buffer *buffer);
+	size_t (*data_available)(struct iio_buffer *buffer);
 
 	int (*request_update)(struct iio_buffer *buffer);
 
@@ -72,6 +72,8 @@ struct iio_buffer_access_funcs {
  * @demux_bounce:	[INTERN] buffer for doing gather from incoming scan.
  * @buffer_list:	[INTERN] entry in the devices list of current buffers.
  * @ref:		[INTERN] reference count of the buffer.
+ * @low_watermark:	[INTERN] number of datums for poll/blocking read to
+ * 			wait for.
  */
 struct iio_buffer {
 	int					length;
@@ -90,6 +92,7 @@ struct iio_buffer {
 	void					*demux_bounce;
 	struct list_head			buffer_list;
 	struct kref				ref;
+	unsigned int				low_watermark;
 };
 
 /**
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 04/11] iio: add support for hardware fifo
  2014-12-21  0:42 [PATCH v2 00/11] iio: add support for hardware buffers Octavian Purdila
                   ` (2 preceding siblings ...)
  2014-12-21  0:42 ` [PATCH v2 03/11] iio: add watermark logic to iio read and poll Octavian Purdila
@ 2014-12-21  0:42 ` Octavian Purdila
  2015-01-04 16:07   ` Jonathan Cameron
  2015-01-28 23:46   ` Hartmut Knaack
  2014-12-21  0:42 ` [PATCH v2 05/11] iio: bmc150: refactor slope duration and threshold update Octavian Purdila
                   ` (6 subsequent siblings)
  10 siblings, 2 replies; 50+ messages in thread
From: Octavian Purdila @ 2014-12-21  0:42 UTC (permalink / raw)
  To: linux-iio; +Cc: Octavian Purdila

Some devices have hardware buffers that can store a number of samples
for later consumption. Hardware usually provides interrupts to notify
the processor when the fifo is full or when it has reached a certain
threshold. This helps with reducing the number of interrupts to the
host processor and thus it helps decreasing the power consumption.

This patch adds support for hardware fifo to IIO by allowing the
drivers to register operations for flushing the hadware fifo and
setting the watermark level.

A driver implementing hardware fifo support must also provide a
watermark trigger which must contain "watermark" in its name.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 Documentation/ABI/testing/sysfs-bus-iio | 22 +++++++++++++++++
 drivers/iio/industrialio-buffer.c       | 44 ++++++++++++++++++++++++++++-----
 include/linux/iio/iio.h                 | 17 +++++++++++++
 3 files changed, 77 insertions(+), 6 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 7260f1f..6bb67ac 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -1152,3 +1152,25 @@ Description:
 		Poll will block until the watermark is reached.
 		Blocking read will wait until the minimum between the requested
 		read amount or the low water mark is available.
+		If the device has a hardware fifo this value is going to be used
+		for the hardware fifo watermark as well.
+
+What:		/sys/bus/iio/devices/iio:deviceX/buffer/hwfifo-length
+KernelVersion:	3.20
+Contact:	linux-iio@vger.kernel.org
+Description:
+		A single positive integer specifying the maximum number of
+		samples that the hardware fifo has. If the device does not
+		support hardware fifo this is zero.
+		When a device supports hardware fifo it will expose a trigger
+		with the name that contains "watermark"
+		(e.g. i2c-BMC150A:00-watermark-dev0).
+		To use the hardware fifo the user must set an appropriate value
+		in the buffer/length and buffer/low_watermark entries and select
+		the watermark trigger. At that poin the hardware fifo will be
+		enabled and the samples will be collected in a hardware buffer.
+		When the number of samples in the hardware fifo reaches the
+		watermark level the watermark trigger is issued and data is
+		flushed to the devices buffer.
+		A hardware buffer flush will also be triggered when reading from
+		the device buffer and there is not enough data available.
\ No newline at end of file
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 7f74c7f..3da6d07 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -37,9 +37,17 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
 	return !list_empty(&buf->buffer_list);
 }
 
-static size_t iio_buffer_data_available(struct iio_buffer *buf)
+static bool iio_buffer_data_available(struct iio_dev *indio_dev,
+				      struct iio_buffer *buf, size_t required)
 {
-	return buf->access->data_available(buf);
+	size_t avail = buf->access->data_available(buf);
+
+	if (avail < required && indio_dev->hwfifo) {
+		indio_dev->hwfifo->flush(indio_dev);
+		avail = buf->access->data_available(buf);
+	}
+
+	return avail >= required;
 }
 
 /**
@@ -66,13 +74,13 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
 
 	do {
 		if (filp->f_flags & O_NONBLOCK) {
-			if (!iio_buffer_data_available(rb)) {
+			if (!iio_buffer_data_available(indio_dev, rb, 1)) {
 				ret = -EAGAIN;
 				break;
 			}
 		} else {
 			ret = wait_event_interruptible(rb->pollq,
-			       iio_buffer_data_available(rb) >= to_read ||
+		            iio_buffer_data_available(indio_dev, rb, to_read) ||
 						       indio_dev->info == NULL);
 			if (ret)
 				return ret;
@@ -112,7 +120,7 @@ unsigned int iio_buffer_poll(struct file *filp,
 		return -ENODEV;
 
 	poll_wait(filp, &rb->pollq, wait);
-	if (iio_buffer_data_available(rb) >= rb->low_watermark)
+	if (iio_buffer_data_available(indio_dev, rb, rb->low_watermark))
 		return POLLIN | POLLRDNORM;
 	return 0;
 }
@@ -440,8 +448,14 @@ static ssize_t iio_buffer_write_length(struct device *dev,
 	if (buffer->length)
 		val = buffer->length;
 
-	if (val < buffer->low_watermark)
+	if (val < buffer->low_watermark) {
+		if (indio_dev->hwfifo) {
+			ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
+			if (ret)
+				return ret;
+		}
 		buffer->low_watermark = val;
+	}
 
 	return len;
 }
@@ -811,6 +825,12 @@ static ssize_t iio_buffer_store_watermark(struct device *dev,
 		goto out;
 	}
 
+	if (indio_dev->hwfifo) {
+		ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
+		if (ret)
+			goto out;
+	}
+
 	buffer->low_watermark = val;
 	ret = 0;
 out:
@@ -818,6 +838,16 @@ out:
 	return ret ? ret : len;
 }
 
+ssize_t iio_buffer_hwfifo_read_length(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	const struct iio_hwfifo *hwfifo = indio_dev->hwfifo;
+
+	return sprintf(buf, "%u\n", hwfifo ? hwfifo->length : 0);
+}
+
 static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
 		   iio_buffer_write_length);
 static struct device_attribute dev_attr_length_ro = __ATTR(length,
@@ -826,11 +856,13 @@ static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
 		   iio_buffer_show_enable, iio_buffer_store_enable);
 static DEVICE_ATTR(low_watermark, S_IRUGO | S_IWUSR,
 		   iio_buffer_show_watermark, iio_buffer_store_watermark);
+static DEVICE_ATTR(hwfifo_length, S_IRUGO, iio_buffer_hwfifo_read_length, NULL);
 
 static struct attribute *iio_buffer_attrs[] = {
 	&dev_attr_length.attr,
 	&dev_attr_enable.attr,
 	&dev_attr_low_watermark.attr,
+	&dev_attr_hwfifo_length.attr,
 };
 
 int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 878d861..f64a05f 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -417,6 +417,22 @@ struct iio_buffer_setup_ops {
 };
 
 /**
+ * struct iio_buffer_hwfifo_ops - hardware fifo operations
+ *
+ * @length:		[DRIVER] the hardware fifo length
+ * @set_watermark:	[DRIVER] setups the watermark level
+ * @flush:		[DRIVER] copies data from the hardware buffer to the
+ *		 	device buffer
+ * @watermark_trig:	[DRIVER] an allocated and registered trigger containing
+ *			"watermark" in its name
+ */
+struct iio_hwfifo {
+	int length;
+	int (*set_watermark)(struct iio_dev *, unsigned int);
+	int (*flush)(struct iio_dev *);
+};
+
+/**
  * struct iio_dev - industrial I/O device
  * @id:			[INTERN] used to identify device internally
  * @modes:		[DRIVER] operating modes supported by device
@@ -491,6 +507,7 @@ struct iio_dev {
 	int				groupcounter;
 
 	unsigned long			flags;
+	const struct iio_hwfifo		*hwfifo;
 #if defined(CONFIG_DEBUG_FS)
 	struct dentry			*debugfs_dentry;
 	unsigned			cached_reg_addr;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 05/11] iio: bmc150: refactor slope duration and threshold update
  2014-12-21  0:42 [PATCH v2 00/11] iio: add support for hardware buffers Octavian Purdila
                   ` (3 preceding siblings ...)
  2014-12-21  0:42 ` [PATCH v2 04/11] iio: add support for hardware fifo Octavian Purdila
@ 2014-12-21  0:42 ` Octavian Purdila
  2015-01-04 16:21   ` Jonathan Cameron
  2014-12-21  0:42 ` [PATCH v2 06/11] iio: bmc150: refactor interrupt enabling Octavian Purdila
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2014-12-21  0:42 UTC (permalink / raw)
  To: linux-iio; +Cc: Octavian Purdila

Move the slope duration and threshold update in separate functions
to reduce code duplicate between chip init and motion interrupt setup.

The patch also moves the update from the motion interrupt setup
function to the write event function so that we can later refactor the
interrupt code.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 drivers/iio/accel/bmc150-accel.c | 110 ++++++++++++++++++++++-----------------
 1 file changed, 63 insertions(+), 47 deletions(-)

diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index 22c096c..92f1d2b 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel.c
@@ -266,6 +266,52 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val,
 	return -EINVAL;
 }
 
+static int bmc150_accel_update_slope_threshold(struct bmc150_accel_data *data,
+					       int val)
+{
+	int ret = 0;
+
+	val &= 0xFF;
+
+	ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_6,
+					val);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error writing reg_int_6\n");
+		return ret;
+	}
+	data->slope_thres = val;
+
+	dev_dbg(&data->client->dev, "%s: %x\n", __func__, val);
+
+	return ret;
+}
+
+static int bmc150_accel_update_slope_duration(struct bmc150_accel_data *data,
+					      int val)
+{
+	int ret;
+
+	val &= BMC150_ACCEL_SLOPE_DUR_MASK;
+
+	ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_int_5\n");
+		return ret;
+	}
+	val |= ret & ~BMC150_ACCEL_SLOPE_DUR_MASK;
+	ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_5,
+					val);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error write reg_int_5\n");
+		return ret;
+	}
+	data->slope_dur = val;
+
+	dev_dbg(&data->client->dev, "%s: %x\n", __func__, val);
+
+	return ret;
+}
+
 static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
 {
 	int ret;
@@ -304,32 +350,16 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
 
 	data->range = BMC150_ACCEL_DEF_RANGE_4G;
 
-	/* Set default slope duration */
-	ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Error reading reg_int_5\n");
-		return ret;
-	}
-	data->slope_dur |= BMC150_ACCEL_DEF_SLOPE_DURATION;
-	ret = i2c_smbus_write_byte_data(data->client,
-					BMC150_ACCEL_REG_INT_5,
-					data->slope_dur);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_int_5\n");
+	/* Set default slope duration and thresholds */
+	ret = bmc150_accel_update_slope_duration(data,
+					 BMC150_ACCEL_DEF_SLOPE_DURATION);
+	if (ret < 0)
 		return ret;
-	}
-	dev_dbg(&data->client->dev, "slope_dur %x\n", data->slope_dur);
 
-	/* Set default slope thresholds */
-	ret = i2c_smbus_write_byte_data(data->client,
-					BMC150_ACCEL_REG_INT_6,
-					BMC150_ACCEL_DEF_SLOPE_THRESHOLD);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_int_6\n");
+	ret = bmc150_accel_update_slope_threshold(data,
+					  BMC150_ACCEL_DEF_SLOPE_THRESHOLD);
+	if (ret < 0)
 		return ret;
-	}
-	data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD;
-	dev_dbg(&data->client->dev, "slope_thres %x\n", data->slope_thres);
 
 	/* Set default as latched interrupts */
 	ret = i2c_smbus_write_byte_data(data->client,
@@ -372,24 +402,6 @@ static int bmc150_accel_setup_any_motion_interrupt(
 	}
 
 	if (status) {
-		/* Set slope duration (no of samples) */
-		ret = i2c_smbus_write_byte_data(data->client,
-						BMC150_ACCEL_REG_INT_5,
-						data->slope_dur);
-		if (ret < 0) {
-			dev_err(&data->client->dev, "Error write reg_int_5\n");
-			return ret;
-		}
-
-		/* Set slope thresholds */
-		ret = i2c_smbus_write_byte_data(data->client,
-						BMC150_ACCEL_REG_INT_6,
-						data->slope_thres);
-		if (ret < 0) {
-			dev_err(&data->client->dev, "Error write reg_int_6\n");
-			return ret;
-		}
-
 		/*
 		 * New data interrupt is always non-latched,
 		 * which will have higher priority, so no need
@@ -726,7 +738,7 @@ static int bmc150_accel_read_event(struct iio_dev *indio_dev,
 		*val = data->slope_thres;
 		break;
 	case IIO_EV_INFO_PERIOD:
-		*val = data->slope_dur & BMC150_ACCEL_SLOPE_DUR_MASK;
+		*val = data->slope_dur;
 		break;
 	default:
 		return -EINVAL;
@@ -743,23 +755,27 @@ static int bmc150_accel_write_event(struct iio_dev *indio_dev,
 				    int val, int val2)
 {
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	int ret;
 
 	if (data->ev_enable_state)
 		return -EBUSY;
 
 	switch (info) {
 	case IIO_EV_INFO_VALUE:
-		data->slope_thres = val;
+		mutex_lock(&data->mutex);
+		ret = bmc150_accel_update_slope_threshold(data, val);
+		mutex_unlock(&data->mutex);
 		break;
 	case IIO_EV_INFO_PERIOD:
-		data->slope_dur &= ~BMC150_ACCEL_SLOPE_DUR_MASK;
-		data->slope_dur |= val & BMC150_ACCEL_SLOPE_DUR_MASK;
+		mutex_lock(&data->mutex);
+		ret = bmc150_accel_update_slope_duration(data, val);
+		mutex_unlock(&data->mutex);
 		break;
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
 	}
 
-	return 0;
+	return ret;
 }
 
 static int bmc150_accel_read_event_config(struct iio_dev *indio_dev,
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 06/11] iio: bmc150: refactor interrupt enabling
  2014-12-21  0:42 [PATCH v2 00/11] iio: add support for hardware buffers Octavian Purdila
                   ` (4 preceding siblings ...)
  2014-12-21  0:42 ` [PATCH v2 05/11] iio: bmc150: refactor slope duration and threshold update Octavian Purdila
@ 2014-12-21  0:42 ` Octavian Purdila
  2015-01-04 16:27   ` Jonathan Cameron
  2014-12-21  0:42 ` [PATCH v2 07/11] iio: bmc150: exit early if event / trigger state is not changed Octavian Purdila
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2014-12-21  0:42 UTC (permalink / raw)
  To: linux-iio; +Cc: Octavian Purdila

This patch combines the any motion and new data interrupts function
into a single, generic, interrupt enable function. On top of this, we
can later refactor triggers to make it easier to add new triggers.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 drivers/iio/accel/bmc150-accel.c | 269 ++++++++++++++++-----------------------
 1 file changed, 113 insertions(+), 156 deletions(-)

diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index 92f1d2b..53d1d1d 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel.c
@@ -144,6 +144,13 @@ struct bmc150_accel_chip_info {
 	const struct bmc150_scale_info scale_table[4];
 };
 
+struct bmc150_accel_interrupt_info {
+	u8 map_reg;
+	u8 map_bitmask;
+	u8 en_reg;
+	u8 en_bitmask;
+};
+
 struct bmc150_accel_data {
 	struct i2c_client *client;
 	struct iio_trigger *dready_trig;
@@ -375,137 +382,6 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
 	return 0;
 }
 
-static int bmc150_accel_setup_any_motion_interrupt(
-					struct bmc150_accel_data *data,
-					bool status)
-{
-	int ret;
-
-	/* Enable/Disable INT1 mapping */
-	ret = i2c_smbus_read_byte_data(data->client,
-				       BMC150_ACCEL_REG_INT_MAP_0);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Error reading reg_int_map_0\n");
-		return ret;
-	}
-	if (status)
-		ret |= BMC150_ACCEL_INT_MAP_0_BIT_SLOPE;
-	else
-		ret &= ~BMC150_ACCEL_INT_MAP_0_BIT_SLOPE;
-
-	ret = i2c_smbus_write_byte_data(data->client,
-					BMC150_ACCEL_REG_INT_MAP_0,
-					ret);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_int_map_0\n");
-		return ret;
-	}
-
-	if (status) {
-		/*
-		 * New data interrupt is always non-latched,
-		 * which will have higher priority, so no need
-		 * to set latched mode, we will be flooded anyway with INTR
-		 */
-		if (!data->dready_trigger_on) {
-			ret = i2c_smbus_write_byte_data(data->client,
-					BMC150_ACCEL_REG_INT_RST_LATCH,
-					BMC150_ACCEL_INT_MODE_LATCH_INT |
-					BMC150_ACCEL_INT_MODE_LATCH_RESET);
-			if (ret < 0) {
-				dev_err(&data->client->dev,
-					"Error writing reg_int_rst_latch\n");
-				return ret;
-			}
-		}
-
-		ret = i2c_smbus_write_byte_data(data->client,
-						BMC150_ACCEL_REG_INT_EN_0,
-						BMC150_ACCEL_INT_EN_BIT_SLP_X |
-						BMC150_ACCEL_INT_EN_BIT_SLP_Y |
-						BMC150_ACCEL_INT_EN_BIT_SLP_Z);
-	} else
-		ret = i2c_smbus_write_byte_data(data->client,
-						BMC150_ACCEL_REG_INT_EN_0,
-						0);
-
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_int_en_0\n");
-		return ret;
-	}
-
-	return 0;
-}
-
-static int bmc150_accel_setup_new_data_interrupt(struct bmc150_accel_data *data,
-					   bool status)
-{
-	int ret;
-
-	/* Enable/Disable INT1 mapping */
-	ret = i2c_smbus_read_byte_data(data->client,
-				       BMC150_ACCEL_REG_INT_MAP_1);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Error reading reg_int_map_1\n");
-		return ret;
-	}
-	if (status)
-		ret |= BMC150_ACCEL_INT_MAP_1_BIT_DATA;
-	else
-		ret &= ~BMC150_ACCEL_INT_MAP_1_BIT_DATA;
-
-	ret = i2c_smbus_write_byte_data(data->client,
-					BMC150_ACCEL_REG_INT_MAP_1,
-					ret);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_int_map_1\n");
-		return ret;
-	}
-
-	if (status) {
-		/*
-		 * Set non latched mode interrupt and clear any latched
-		 * interrupt
-		 */
-		ret = i2c_smbus_write_byte_data(data->client,
-					BMC150_ACCEL_REG_INT_RST_LATCH,
-					BMC150_ACCEL_INT_MODE_NON_LATCH_INT |
-					BMC150_ACCEL_INT_MODE_LATCH_RESET);
-		if (ret < 0) {
-			dev_err(&data->client->dev,
-				"Error writing reg_int_rst_latch\n");
-			return ret;
-		}
-
-		ret = i2c_smbus_write_byte_data(data->client,
-					BMC150_ACCEL_REG_INT_EN_1,
-					BMC150_ACCEL_INT_EN_BIT_DATA_EN);
-
-	} else {
-		/* Restore default interrupt mode */
-		ret = i2c_smbus_write_byte_data(data->client,
-					BMC150_ACCEL_REG_INT_RST_LATCH,
-					BMC150_ACCEL_INT_MODE_LATCH_INT |
-					BMC150_ACCEL_INT_MODE_LATCH_RESET);
-		if (ret < 0) {
-			dev_err(&data->client->dev,
-				"Error writing reg_int_rst_latch\n");
-			return ret;
-		}
-
-		ret = i2c_smbus_write_byte_data(data->client,
-						BMC150_ACCEL_REG_INT_EN_1,
-						0);
-	}
-
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_int_en_1\n");
-		return ret;
-	}
-
-	return 0;
-}
-
 static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val,
 			       int *val2)
 {
@@ -560,6 +436,97 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
 }
 #endif
 
+static struct bmc150_accel_interrupt_info bmc150_accel_interrupts[] = {
+	{ /* data ready interrupt */
+		.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
+		.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA,
+		.en_reg = BMC150_ACCEL_REG_INT_EN_1,
+		.en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN,
+	},
+	{  /* motion interrupt */
+		.map_reg = BMC150_ACCEL_REG_INT_MAP_0,
+		.map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_SLOPE,
+		.en_reg = BMC150_ACCEL_REG_INT_EN_0,
+		.en_bitmask =  BMC150_ACCEL_INT_EN_BIT_SLP_X |
+			BMC150_ACCEL_INT_EN_BIT_SLP_Y |
+			BMC150_ACCEL_INT_EN_BIT_SLP_Z
+	},
+};
+
+static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data,
+				      struct bmc150_accel_interrupt_info *info,
+				      bool state)
+{
+	int ret;
+
+	/*
+	 * We will expect the enable and disable to do operation in
+	 * in reverse order. This will happen here anyway as our
+	 * resume operation uses sync mode runtime pm calls, the
+	 * suspend operation will be delayed by autosuspend delay
+	 * So the disable operation will still happen in reverse of
+	 * enable operation. When runtime pm is disabled the mode
+	 * is always on so sequence doesn't matter
+	 */
+	ret = bmc150_accel_set_power_state(data, state);
+	if (ret < 0)
+		return ret;
+
+
+	/* map the interrupt to the appropriate pins */
+	ret = i2c_smbus_read_byte_data(data->client, info->map_reg);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_int_map\n");
+		return ret;
+	}
+	if (state)
+		ret |= info->map_bitmask;
+	else
+		ret &= ~info->map_bitmask;
+
+	ret = i2c_smbus_write_byte_data(data->client, info->map_reg,
+					ret);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error writing reg_int_map\n");
+		return ret;
+	}
+
+	/* enable/disable the interrupt */
+	ret = i2c_smbus_read_byte_data(data->client, info->en_reg);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_int_en\n");
+		return ret;
+	}
+
+	if (state)
+		ret |= info->en_bitmask;
+	else
+		ret &= ~info->en_bitmask;
+
+	ret = i2c_smbus_write_byte_data(data->client, info->en_reg, ret);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error writing reg_int_en\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int bmc150_accel_setup_any_motion_interrupt(
+					struct bmc150_accel_data *data,
+					bool status)
+{
+	return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[1],
+					  status);
+}
+
+static int bmc150_accel_setup_new_data_interrupt(struct bmc150_accel_data *data,
+					   bool status)
+{
+	return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[0],
+					  status);
+}
+
 static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
 {
 	int ret, i;
@@ -809,22 +776,6 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
 		return 0;
 	}
 
-	/*
-	 * We will expect the enable and disable to do operation in
-	 * in reverse order. This will happen here anyway as our
-	 * resume operation uses sync mode runtime pm calls, the
-	 * suspend operation will be delayed by autosuspend delay
-	 * So the disable operation will still happen in reverse of
-	 * enable operation. When runtime pm is disabled the mode
-	 * is always on so sequence doesn't matter
-	 */
-
-	ret = bmc150_accel_set_power_state(data, state);
-	if (ret < 0) {
-		mutex_unlock(&data->mutex);
-		return ret;
-	}
-
 	ret =  bmc150_accel_setup_any_motion_interrupt(data, state);
 	if (ret < 0) {
 		mutex_unlock(&data->mutex);
@@ -1056,15 +1007,6 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
 		return 0;
 	}
 
-	/*
-	 * Refer to comment in bmc150_accel_write_event_config for
-	 * enable/disable operation order
-	 */
-	ret = bmc150_accel_set_power_state(data, state);
-	if (ret < 0) {
-		mutex_unlock(&data->mutex);
-		return ret;
-	}
 	if (data->motion_trig == trig)
 		ret =  bmc150_accel_setup_any_motion_interrupt(data, state);
 	else
@@ -1241,6 +1183,21 @@ static int bmc150_accel_probe(struct i2c_client *client,
 		if (ret)
 			return ret;
 
+		/*
+		 * Set latched mode interrupt. While certain interrupts are
+		 * non-latched regardless of this settings (e.g. new data) we
+		 * want to use latch mode when we can to prevent interrupt
+		 * flooding.
+		 */
+		ret = i2c_smbus_write_byte_data(data->client,
+						BMC150_ACCEL_REG_INT_RST_LATCH,
+					     BMC150_ACCEL_INT_MODE_LATCH_RESET);
+		if (ret < 0) {
+			dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n");
+			return ret;
+		}
+
+
 		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
 							   "%s-dev%d",
 							   indio_dev->name,
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 07/11] iio: bmc150: exit early if event / trigger state is not changed
  2014-12-21  0:42 [PATCH v2 00/11] iio: add support for hardware buffers Octavian Purdila
                   ` (5 preceding siblings ...)
  2014-12-21  0:42 ` [PATCH v2 06/11] iio: bmc150: refactor interrupt enabling Octavian Purdila
@ 2014-12-21  0:42 ` Octavian Purdila
  2015-01-04 16:29   ` Jonathan Cameron
  2014-12-21  0:42 ` [PATCH v2 08/11] iio: bmc150: introduce bmc150_accel_interrupt Octavian Purdila
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2014-12-21  0:42 UTC (permalink / raw)
  To: linux-iio; +Cc: Octavian Purdila

Previous of this patch the check was only done if we enabled the event
and it was already enabled. We can do the same if the event is
disabled and we want to disable it.

The patch also adds the same check on the trigger code.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 drivers/iio/accel/bmc150-accel.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index 53d1d1d..aaad2fb 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel.c
@@ -765,7 +765,7 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
 	int ret;
 
-	if (state && data->ev_enable_state)
+	if (state == data->ev_enable_state)
 		return 0;
 
 	mutex_lock(&data->mutex);
@@ -1001,6 +1001,18 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
 
 	mutex_lock(&data->mutex);
 
+	if (data->motion_trig == trig) {
+		if (data->motion_trigger_on == state) {
+			mutex_unlock(&data->mutex);
+			return 0;
+		}
+	} else {
+		if (data->dready_trigger_on == state) {
+			mutex_unlock(&data->mutex);
+			return 0;
+		}
+	}
+
 	if (!state && data->ev_enable_state && data->motion_trigger_on) {
 		data->motion_trigger_on = false;
 		mutex_unlock(&data->mutex);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 08/11] iio: bmc150: introduce bmc150_accel_interrupt
  2014-12-21  0:42 [PATCH v2 00/11] iio: add support for hardware buffers Octavian Purdila
                   ` (6 preceding siblings ...)
  2014-12-21  0:42 ` [PATCH v2 07/11] iio: bmc150: exit early if event / trigger state is not changed Octavian Purdila
@ 2014-12-21  0:42 ` Octavian Purdila
  2015-01-04 16:36   ` Jonathan Cameron
  2014-12-21  0:42 ` [PATCH v2 09/11] iio: bmc150: introduce bmc150_accel_trigger Octavian Purdila
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2014-12-21  0:42 UTC (permalink / raw)
  To: linux-iio; +Cc: Octavian Purdila

Since both triggers and events can share an interrupt, add a data
structure that tracks the users of an interrupt so that it enables or
disables it only for the first users and respectively last user.

This will allows us to easily add more events or triggers.

The patch also adds an interrupt enabled counter, so that we can
easily know if we need to put the device in normal mode when the
resume callback is issued.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 drivers/iio/accel/bmc150-accel.c | 87 +++++++++++++++++++++-------------------
 1 file changed, 45 insertions(+), 42 deletions(-)

diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index aaad2fb..7c905f6 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel.c
@@ -151,10 +151,19 @@ struct bmc150_accel_interrupt_info {
 	u8 en_bitmask;
 };
 
+struct bmc150_accel_interrupt {
+	struct bmc150_accel_interrupt_info *info;
+	atomic_t users;
+};
+
+#define BMC150_ACCEL_INTERRUPTS		2
+
 struct bmc150_accel_data {
 	struct i2c_client *client;
+	struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
 	struct iio_trigger *dready_trig;
 	struct iio_trigger *motion_trig;
+	atomic_t active_intr;
 	struct mutex mutex;
 	s16 buffer[8];
 	u8 bw_bits;
@@ -436,7 +445,8 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
 }
 #endif
 
-static struct bmc150_accel_interrupt_info bmc150_accel_interrupts[] = {
+static struct bmc150_accel_interrupt_info
+bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = {
 	{ /* data ready interrupt */
 		.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
 		.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA,
@@ -453,12 +463,30 @@ static struct bmc150_accel_interrupt_info bmc150_accel_interrupts[] = {
 	},
 };
 
+static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
+					 struct bmc150_accel_data *data)
+{
+	int i;
+
+	for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++)
+		data->interrupts[i].info = &bmc150_accel_interrupts[i];
+}
+
 static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data,
-				      struct bmc150_accel_interrupt_info *info,
+				      struct bmc150_accel_interrupt *intr,
 				      bool state)
 {
+	struct bmc150_accel_interrupt_info *info = intr->info;
 	int ret;
 
+	if (state) {
+		if (atomic_inc_return(&intr->users) > 1)
+			return 0;
+	} else {
+		if (atomic_dec_return(&intr->users) > 0)
+			return 0;
+	}
+
 	/*
 	 * We will expect the enable and disable to do operation in
 	 * in reverse order. This will happen here anyway as our
@@ -509,22 +537,12 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data,
 		return ret;
 	}
 
-	return 0;
-}
-
-static int bmc150_accel_setup_any_motion_interrupt(
-					struct bmc150_accel_data *data,
-					bool status)
-{
-	return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[1],
-					  status);
-}
+	if (state)
+		atomic_inc(&data->active_intr);
+	else
+		atomic_dec(&data->active_intr);
 
-static int bmc150_accel_setup_new_data_interrupt(struct bmc150_accel_data *data,
-					   bool status)
-{
-	return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[0],
-					  status);
+	return 0;
 }
 
 static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
@@ -769,23 +787,12 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
 		return 0;
 
 	mutex_lock(&data->mutex);
-
-	if (!state && data->motion_trigger_on) {
-		data->ev_enable_state = 0;
-		mutex_unlock(&data->mutex);
-		return 0;
-	}
-
-	ret =  bmc150_accel_setup_any_motion_interrupt(data, state);
-	if (ret < 0) {
-		mutex_unlock(&data->mutex);
-		return ret;
-	}
-
-	data->ev_enable_state = state;
+	ret = bmc150_accel_set_interrupt(data, &data->interrupts[1], state);
+	if (!ret)
+		data->ev_enable_state = state;
 	mutex_unlock(&data->mutex);
 
-	return 0;
+	return ret;
 }
 
 static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev,
@@ -1013,16 +1020,12 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
 		}
 	}
 
-	if (!state && data->ev_enable_state && data->motion_trigger_on) {
-		data->motion_trigger_on = false;
-		mutex_unlock(&data->mutex);
-		return 0;
-	}
-
 	if (data->motion_trig == trig)
-		ret =  bmc150_accel_setup_any_motion_interrupt(data, state);
+		ret = bmc150_accel_set_interrupt(data, &data->interrupts[1],
+						 state);
 	else
-		ret = bmc150_accel_setup_new_data_interrupt(data, state);
+		ret = bmc150_accel_set_interrupt(data, &data->interrupts[0],
+						 state);
 	if (ret < 0) {
 		mutex_unlock(&data->mutex);
 		return ret;
@@ -1209,6 +1212,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
 			return ret;
 		}
 
+		bmc150_accel_interrupts_setup(indio_dev, data);
 
 		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
 							   "%s-dev%d",
@@ -1325,8 +1329,7 @@ static int bmc150_accel_resume(struct device *dev)
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
 
 	mutex_lock(&data->mutex);
-	if (data->dready_trigger_on || data->motion_trigger_on ||
-							data->ev_enable_state)
+	if (atomic_read(&data->active_intr))
 		bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
 	mutex_unlock(&data->mutex);
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 09/11] iio: bmc150: introduce bmc150_accel_trigger
  2014-12-21  0:42 [PATCH v2 00/11] iio: add support for hardware buffers Octavian Purdila
                   ` (7 preceding siblings ...)
  2014-12-21  0:42 ` [PATCH v2 08/11] iio: bmc150: introduce bmc150_accel_interrupt Octavian Purdila
@ 2014-12-21  0:42 ` Octavian Purdila
  2015-01-04 16:39   ` Jonathan Cameron
  2014-12-21  0:42 ` [PATCH v2 10/11] iio: bmc150: introduce bmc150_accel_event Octavian Purdila
  2014-12-21  0:42 ` [PATCH v2 11/11] iio: bmc150: add support for hardware fifo Octavian Purdila
  10 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2014-12-21  0:42 UTC (permalink / raw)
  To: linux-iio; +Cc: Octavian Purdila

Add a separate structure for triggers and add the infrastructure to
support an arbitrary number of triggers. Each trigger is associated
with an interrupt and has an enabled/disabled state.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 drivers/iio/accel/bmc150-accel.c | 174 ++++++++++++++++++++++-----------------
 1 file changed, 100 insertions(+), 74 deletions(-)

diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index 7c905f6..cd2f5d9 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel.c
@@ -156,14 +156,21 @@ struct bmc150_accel_interrupt {
 	atomic_t users;
 };
 
+struct bmc150_accel_trigger {
+	struct bmc150_accel_interrupt *intr;
+	struct bmc150_accel_data *data;
+	struct iio_trigger *indio_trig;
+	bool enabled;
+};
+
 #define BMC150_ACCEL_INTERRUPTS		2
+#define BMC150_ACCEL_TRIGGERS		2
 
 struct bmc150_accel_data {
 	struct i2c_client *client;
 	struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
-	struct iio_trigger *dready_trig;
-	struct iio_trigger *motion_trig;
 	atomic_t active_intr;
+	struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
 	struct mutex mutex;
 	s16 buffer[8];
 	u8 bw_bits;
@@ -171,8 +178,6 @@ struct bmc150_accel_data {
 	u32 slope_thres;
 	u32 range;
 	int ev_enable_state;
-	bool dready_trigger_on;
-	bool motion_trigger_on;
 	int64_t timestamp;
 	const struct bmc150_accel_chip_info *chip_info;
 };
@@ -799,11 +804,14 @@ static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev,
 				   struct iio_trigger *trig)
 {
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	int i;
 
-	if (data->dready_trig != trig && data->motion_trig != trig)
-		return -EINVAL;
+	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
+		if (data->triggers[i].indio_trig == trig)
+			return 0;
+	}
 
-	return 0;
+	return -EINVAL;
 }
 
 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
@@ -975,12 +983,12 @@ err_read:
 
 static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
 {
-	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
-	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig);
+	struct bmc150_accel_data *data = t->data;
 	int ret;
 
 	/* new data interrupts don't need ack */
-	if (data->dready_trigger_on)
+	if (t == &t->data->triggers[0])
 		return 0;
 
 	mutex_lock(&data->mutex);
@@ -1002,38 +1010,24 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
 static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
 						   bool state)
 {
-	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
-	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig);
+	struct bmc150_accel_data *data = t->data;
 	int ret;
 
 	mutex_lock(&data->mutex);
 
-	if (data->motion_trig == trig) {
-		if (data->motion_trigger_on == state) {
-			mutex_unlock(&data->mutex);
-			return 0;
-		}
-	} else {
-		if (data->dready_trigger_on == state) {
-			mutex_unlock(&data->mutex);
-			return 0;
-		}
+	if (t->enabled == state) {
+		mutex_unlock(&data->mutex);
+		return 0;
 	}
 
-	if (data->motion_trig == trig)
-		ret = bmc150_accel_set_interrupt(data, &data->interrupts[1],
-						 state);
-	else
-		ret = bmc150_accel_set_interrupt(data, &data->interrupts[0],
-						 state);
+	ret = bmc150_accel_set_interrupt(data, t->intr, state);
 	if (ret < 0) {
 		mutex_unlock(&data->mutex);
 		return ret;
 	}
-	if (data->motion_trig == trig)
-		data->motion_trigger_on = state;
-	else
-		data->dready_trigger_on = state;
+
+	t->enabled = state;
 
 	mutex_unlock(&data->mutex);
 
@@ -1073,7 +1067,7 @@ static irqreturn_t bmc150_accel_event_handler(int irq, void *private)
 							IIO_EV_DIR_EITHER),
 							data->timestamp);
 ack_intr_status:
-	if (!data->dready_trigger_on)
+	if (!data->triggers[0].enabled)
 		ret = i2c_smbus_write_byte_data(data->client,
 					BMC150_ACCEL_REG_INT_RST_LATCH,
 					BMC150_ACCEL_INT_MODE_LATCH_INT |
@@ -1086,13 +1080,16 @@ static irqreturn_t bmc150_accel_data_rdy_trig_poll(int irq, void *private)
 {
 	struct iio_dev *indio_dev = private;
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	int i;
 
 	data->timestamp = iio_get_time_ns();
 
-	if (data->dready_trigger_on)
-		iio_trigger_poll(data->dready_trig);
-	else if (data->motion_trigger_on)
-		iio_trigger_poll(data->motion_trig);
+	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
+		if (data->triggers[i].enabled) {
+			iio_trigger_poll(data->triggers[i].indio_trig);
+			break;
+		}
+	}
 
 	if (data->ev_enable_state)
 		return IRQ_WAKE_THREAD;
@@ -1144,6 +1141,68 @@ static int bmc150_accel_gpio_probe(struct i2c_client *client,
 	return ret;
 }
 
+static struct {
+	int intr;
+	const char *name;
+} bmc150_accel_triggers[BMC150_ACCEL_TRIGGERS] = {
+	{
+		.intr = 0,
+		.name = "%s-dev%d",
+	},
+	{
+		.intr = 1,
+		.name = "%s-any-motion-dev%d",
+	},
+};
+
+static void bmc150_accel_unregister_triggers(struct bmc150_accel_data *data,
+					     int from)
+{
+	int i;
+
+	for (i = from; i >= 0; i++) {
+		if (data->triggers[i].indio_trig) {
+			iio_trigger_unregister(data->triggers[i].indio_trig);
+			data->triggers[i].indio_trig = NULL;
+		}
+	}
+}
+
+static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
+				       struct bmc150_accel_data *data)
+{
+	int i, ret;
+
+	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
+		struct bmc150_accel_trigger *t = &data->triggers[i];
+		const char *name = bmc150_accel_triggers[i].name;
+		int intr = bmc150_accel_triggers[i].intr;
+
+		t->indio_trig = devm_iio_trigger_alloc(&data->client->dev, name,
+						       indio_dev->name,
+						       indio_dev->id);
+		if (!t->indio_trig) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		t->indio_trig->dev.parent = &data->client->dev;
+		t->indio_trig->ops = &bmc150_accel_trigger_ops;
+		t->intr = &data->interrupts[intr];
+		t->data = data;
+		iio_trigger_set_drvdata(t->indio_trig, t);
+
+		ret = iio_trigger_register(t->indio_trig);
+		if (ret)
+			break;
+	}
+
+	if (ret)
+		bmc150_accel_unregister_triggers(data, i - 1);
+
+	return ret;
+}
+
 static int bmc150_accel_probe(struct i2c_client *client,
 			      const struct i2c_device_id *id)
 {
@@ -1214,36 +1273,10 @@ static int bmc150_accel_probe(struct i2c_client *client,
 
 		bmc150_accel_interrupts_setup(indio_dev, data);
 
-		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
-							   "%s-dev%d",
-							   indio_dev->name,
-							   indio_dev->id);
-		if (!data->dready_trig)
-			return -ENOMEM;
-
-		data->motion_trig = devm_iio_trigger_alloc(&client->dev,
-							  "%s-any-motion-dev%d",
-							  indio_dev->name,
-							  indio_dev->id);
-		if (!data->motion_trig)
-			return -ENOMEM;
-
-		data->dready_trig->dev.parent = &client->dev;
-		data->dready_trig->ops = &bmc150_accel_trigger_ops;
-		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
-		ret = iio_trigger_register(data->dready_trig);
+		ret = bmc150_accel_triggers_setup(indio_dev, data);
 		if (ret)
 			return ret;
 
-		data->motion_trig->dev.parent = &client->dev;
-		data->motion_trig->ops = &bmc150_accel_trigger_ops;
-		iio_trigger_set_drvdata(data->motion_trig, indio_dev);
-		ret = iio_trigger_register(data->motion_trig);
-		if (ret) {
-			data->motion_trig = NULL;
-			goto err_trigger_unregister;
-		}
-
 		ret = iio_triggered_buffer_setup(indio_dev,
 						 &iio_pollfunc_store_time,
 						 bmc150_accel_trigger_handler,
@@ -1275,13 +1308,10 @@ static int bmc150_accel_probe(struct i2c_client *client,
 err_iio_unregister:
 	iio_device_unregister(indio_dev);
 err_buffer_cleanup:
-	if (data->dready_trig)
+	if (indio_dev->pollfunc)
 		iio_triggered_buffer_cleanup(indio_dev);
 err_trigger_unregister:
-	if (data->dready_trig)
-		iio_trigger_unregister(data->dready_trig);
-	if (data->motion_trig)
-		iio_trigger_unregister(data->motion_trig);
+	bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
 
 	return ret;
 }
@@ -1297,11 +1327,7 @@ static int bmc150_accel_remove(struct i2c_client *client)
 
 	iio_device_unregister(indio_dev);
 
-	if (data->dready_trig) {
-		iio_triggered_buffer_cleanup(indio_dev);
-		iio_trigger_unregister(data->dready_trig);
-		iio_trigger_unregister(data->motion_trig);
-	}
+	bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
 
 	mutex_lock(&data->mutex);
 	bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 10/11] iio: bmc150: introduce bmc150_accel_event
  2014-12-21  0:42 [PATCH v2 00/11] iio: add support for hardware buffers Octavian Purdila
                   ` (8 preceding siblings ...)
  2014-12-21  0:42 ` [PATCH v2 09/11] iio: bmc150: introduce bmc150_accel_trigger Octavian Purdila
@ 2014-12-21  0:42 ` Octavian Purdila
  2015-01-04 16:49   ` Jonathan Cameron
  2014-12-21  0:42 ` [PATCH v2 11/11] iio: bmc150: add support for hardware fifo Octavian Purdila
  10 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2014-12-21  0:42 UTC (permalink / raw)
  To: linux-iio; +Cc: Octavian Purdila

Add a separate structure for events and add the infrastructure to
support an arbitrary number of events. Each event is associated
with an interrupt and has an enabled/disabled state.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 drivers/iio/accel/bmc150-accel.c | 177 ++++++++++++++++++++++++++++++---------
 1 file changed, 139 insertions(+), 38 deletions(-)

diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index cd2f5d9..14509be 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel.c
@@ -163,21 +163,37 @@ struct bmc150_accel_trigger {
 	bool enabled;
 };
 
+struct bmc150_accel_event {
+	struct bmc150_accel_interrupt *intr;
+	struct bmc150_accel_data *data;
+	enum iio_event_type type;
+	bool enabled;
+	int (*read)(struct bmc150_accel_event *event, enum iio_event_info info,
+		    int *val, int *val2);
+	int (*write)(struct bmc150_accel_event *event, enum iio_event_info info,
+		     int val, int val2);
+	union {
+		struct {
+			u32 duration;
+			u32 threshold;
+		} slope;
+	};
+};
+
 #define BMC150_ACCEL_INTERRUPTS		2
 #define BMC150_ACCEL_TRIGGERS		2
+#define BMC150_ACCEL_EVENTS		1
 
 struct bmc150_accel_data {
 	struct i2c_client *client;
 	struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
 	atomic_t active_intr;
 	struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
+	struct bmc150_accel_event events[BMC150_ACCEL_EVENTS];
 	struct mutex mutex;
 	s16 buffer[8];
 	u8 bw_bits;
-	u32 slope_dur;
-	u32 slope_thres;
 	u32 range;
-	int ev_enable_state;
 	int64_t timestamp;
 	const struct bmc150_accel_chip_info *chip_info;
 };
@@ -287,7 +303,8 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val,
 	return -EINVAL;
 }
 
-static int bmc150_accel_update_slope_threshold(struct bmc150_accel_data *data,
+static int bmc150_accel_update_slope_threshold(struct bmc150_accel_event *event,
+					       struct bmc150_accel_data *data,
 					       int val)
 {
 	int ret = 0;
@@ -300,14 +317,15 @@ static int bmc150_accel_update_slope_threshold(struct bmc150_accel_data *data,
 		dev_err(&data->client->dev, "Error writing reg_int_6\n");
 		return ret;
 	}
-	data->slope_thres = val;
+	event->slope.threshold = val;
 
 	dev_dbg(&data->client->dev, "%s: %x\n", __func__, val);
 
 	return ret;
 }
 
-static int bmc150_accel_update_slope_duration(struct bmc150_accel_data *data,
+static int bmc150_accel_update_slope_duration(struct bmc150_accel_event *event,
+					      struct bmc150_accel_data *data,
 					      int val)
 {
 	int ret;
@@ -326,7 +344,7 @@ static int bmc150_accel_update_slope_duration(struct bmc150_accel_data *data,
 		dev_err(&data->client->dev, "Error write reg_int_5\n");
 		return ret;
 	}
-	data->slope_dur = val;
+	event->slope.duration = val;
 
 	dev_dbg(&data->client->dev, "%s: %x\n", __func__, val);
 
@@ -372,12 +390,12 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
 	data->range = BMC150_ACCEL_DEF_RANGE_4G;
 
 	/* Set default slope duration and thresholds */
-	ret = bmc150_accel_update_slope_duration(data,
+	ret = bmc150_accel_update_slope_duration(&data->events[0], data,
 					 BMC150_ACCEL_DEF_SLOPE_DURATION);
 	if (ret < 0)
 		return ret;
 
-	ret = bmc150_accel_update_slope_threshold(data,
+	ret = bmc150_accel_update_slope_threshold(&data->events[0], data,
 					  BMC150_ACCEL_DEF_SLOPE_THRESHOLD);
 	if (ret < 0)
 		return ret;
@@ -713,22 +731,30 @@ static int bmc150_accel_write_raw(struct iio_dev *indio_dev,
 	return ret;
 }
 
-static int bmc150_accel_read_event(struct iio_dev *indio_dev,
-				   const struct iio_chan_spec *chan,
-				   enum iio_event_type type,
-				   enum iio_event_direction dir,
-				   enum iio_event_info info,
-				   int *val, int *val2)
+static struct bmc150_accel_event*
+bmc150_accel_get_event(struct iio_dev *indio_dev, enum iio_event_type type)
 {
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	int i;
+
+	for (i = 0; i < BMC150_ACCEL_EVENTS; i++)
+		if (data->events[i].type == type)
+			return &data->events[i];
+
+	return NULL;
+}
 
+static int bmc150_accel_event_roc_read(struct bmc150_accel_event *event,
+				       enum iio_event_info info,
+				       int *val, int *val2)
+{
 	*val2 = 0;
 	switch (info) {
 	case IIO_EV_INFO_VALUE:
-		*val = data->slope_thres;
+		*val = event->slope.threshold;
 		break;
 	case IIO_EV_INFO_PERIOD:
-		*val = data->slope_dur;
+		*val = event->slope.duration;
 		break;
 	default:
 		return -EINVAL;
@@ -737,28 +763,40 @@ static int bmc150_accel_read_event(struct iio_dev *indio_dev,
 	return IIO_VAL_INT;
 }
 
-static int bmc150_accel_write_event(struct iio_dev *indio_dev,
-				    const struct iio_chan_spec *chan,
-				    enum iio_event_type type,
-				    enum iio_event_direction dir,
-				    enum iio_event_info info,
-				    int val, int val2)
+static int bmc150_accel_read_event(struct iio_dev *indio_dev,
+				   const struct iio_chan_spec *chan,
+				   enum iio_event_type type,
+				   enum iio_event_direction dir,
+				   enum iio_event_info info,
+				   int *val, int *val2)
 {
-	struct bmc150_accel_data *data = iio_priv(indio_dev);
-	int ret;
+	struct bmc150_accel_event *event;
 
-	if (data->ev_enable_state)
-		return -EBUSY;
+	event = bmc150_accel_get_event(indio_dev, type);
+	if (!event || !event->read)
+		return -EINVAL;
+
+	return event->read(event, info, val, val2);
+}
+
+static int bmc150_accel_event_roc_write(struct bmc150_accel_event *event,
+					enum iio_event_info info,
+					int val, int val2)
+{
+	struct bmc150_accel_data *data = event->data;
+	int ret;
 
 	switch (info) {
 	case IIO_EV_INFO_VALUE:
 		mutex_lock(&data->mutex);
-		ret = bmc150_accel_update_slope_threshold(data, val);
+		ret = bmc150_accel_update_slope_threshold(event, event->data,
+							  val);
 		mutex_unlock(&data->mutex);
 		break;
 	case IIO_EV_INFO_PERIOD:
 		mutex_lock(&data->mutex);
-		ret = bmc150_accel_update_slope_duration(data, val);
+		ret = bmc150_accel_update_slope_duration(event, event->data,
+							 val);
 		mutex_unlock(&data->mutex);
 		break;
 	default:
@@ -768,15 +806,37 @@ static int bmc150_accel_write_event(struct iio_dev *indio_dev,
 	return ret;
 }
 
+static int bmc150_accel_write_event(struct iio_dev *indio_dev,
+				    const struct iio_chan_spec *chan,
+				    enum iio_event_type type,
+				    enum iio_event_direction dir,
+				    enum iio_event_info info,
+				    int val, int val2)
+{
+	struct bmc150_accel_event *event;
+
+	event = bmc150_accel_get_event(indio_dev, type);
+	if (!event || !event->write)
+		return -EINVAL;
+
+	if (event->enabled)
+		return -EBUSY;
+
+	return event->write(event, info, val, val2);
+}
+
 static int bmc150_accel_read_event_config(struct iio_dev *indio_dev,
 					  const struct iio_chan_spec *chan,
 					  enum iio_event_type type,
 					  enum iio_event_direction dir)
 {
+	struct bmc150_accel_event *event;
 
-	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	event = bmc150_accel_get_event(indio_dev, type);
+	if (!event)
+		return -EINVAL;
 
-	return data->ev_enable_state;
+	return event->enabled;
 }
 
 static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
@@ -786,15 +846,20 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
 					   int state)
 {
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	struct bmc150_accel_event *event;
 	int ret;
 
-	if (state == data->ev_enable_state)
+	event = bmc150_accel_get_event(indio_dev, type);
+	if (!event)
+		return -EINVAL;
+
+	if (state == event->enabled)
 		return 0;
 
 	mutex_lock(&data->mutex);
-	ret = bmc150_accel_set_interrupt(data, &data->interrupts[1], state);
+	ret = bmc150_accel_set_interrupt(data, event->intr, state);
 	if (!ret)
-		data->ev_enable_state = state;
+		event->enabled = state;
 	mutex_unlock(&data->mutex);
 
 	return ret;
@@ -826,12 +891,14 @@ static const struct attribute_group bmc150_accel_attrs_group = {
 	.attrs = bmc150_accel_attributes,
 };
 
-static const struct iio_event_spec bmc150_accel_event = {
+static const struct iio_event_spec bmc150_accel_events[BMC150_ACCEL_EVENTS] = {
+	{
 		.type = IIO_EV_TYPE_ROC,
 		.dir = IIO_EV_DIR_RISING | IIO_EV_DIR_FALLING,
 		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
 				 BIT(IIO_EV_INFO_ENABLE) |
 				 BIT(IIO_EV_INFO_PERIOD)
+	},
 };
 
 #define BMC150_ACCEL_CHANNEL(_axis, bits) {				\
@@ -848,8 +915,8 @@ static const struct iio_event_spec bmc150_accel_event = {
 		.storagebits = 16,					\
 		.shift = 16 - (bits),					\
 	},								\
-	.event_spec = &bmc150_accel_event,				\
-	.num_event_specs = 1						\
+	.event_spec = bmc150_accel_events,				\
+	.num_event_specs = ARRAY_SIZE(bmc150_accel_events)		\
 }
 
 #define BMC150_ACCEL_CHANNELS(bits) {					\
@@ -1091,7 +1158,7 @@ static irqreturn_t bmc150_accel_data_rdy_trig_poll(int irq, void *private)
 		}
 	}
 
-	if (data->ev_enable_state)
+	if (data->events[0].enabled)
 		return IRQ_WAKE_THREAD;
 	else
 		return IRQ_HANDLED;
@@ -1203,6 +1270,38 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
 	return ret;
 }
 
+static struct {
+	int intr;
+	enum iio_event_type type;
+	int (*read)(struct bmc150_accel_event *event, enum iio_event_info info,
+		    int *val, int *val2);
+	int (*write)(struct bmc150_accel_event *event, enum iio_event_info info,
+		     int val, int val2);
+} bmc150_accel_events_info[BMC150_ACCEL_EVENTS] = {
+	{
+		.intr = 1,
+		.type = IIO_EV_TYPE_ROC,
+		.read = bmc150_accel_event_roc_read,
+		.write = bmc150_accel_event_roc_write,
+	},
+};
+
+static void bmc150_accel_events_setup(struct iio_dev *indio_dev,
+				      struct bmc150_accel_data *data)
+{
+	int i;
+
+	for (i = 0; i < BMC150_ACCEL_EVENTS; i++) {
+		int intr = bmc150_accel_events_info[i].intr;
+
+		data->events[i].intr = &data->interrupts[intr];
+		data->events[i].data = data;
+		data->events[i].type = bmc150_accel_events_info[i].type;
+		data->events[i].read = bmc150_accel_events_info[i].read;
+		data->events[i].write = bmc150_accel_events_info[i].write;
+	}
+}
+
 static int bmc150_accel_probe(struct i2c_client *client,
 			      const struct i2c_device_id *id)
 {
@@ -1277,6 +1376,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
 		if (ret)
 			return ret;
 
+		bmc150_accel_events_setup(indio_dev, data);
+
 		ret = iio_triggered_buffer_setup(indio_dev,
 						 &iio_pollfunc_store_time,
 						 bmc150_accel_trigger_handler,
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* [PATCH v2 11/11] iio: bmc150: add support for hardware fifo
  2014-12-21  0:42 [PATCH v2 00/11] iio: add support for hardware buffers Octavian Purdila
                   ` (9 preceding siblings ...)
  2014-12-21  0:42 ` [PATCH v2 10/11] iio: bmc150: introduce bmc150_accel_event Octavian Purdila
@ 2014-12-21  0:42 ` Octavian Purdila
  2015-01-04 17:08   ` Jonathan Cameron
  10 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2014-12-21  0:42 UTC (permalink / raw)
  To: linux-iio; +Cc: Octavian Purdila

Add a new watermark trigger and hardware fifo operations. When the
watermark trigger is activated the watermark level is set and the
hardware FIFO is activated.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 drivers/iio/accel/bmc150-accel.c | 194 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 190 insertions(+), 4 deletions(-)

diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index 14509be..0aa3126 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel.c
@@ -67,7 +67,9 @@
 #define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE	BIT(2)
 
 #define BMC150_ACCEL_REG_INT_MAP_1		0x1A
-#define BMC150_ACCEL_INT_MAP_1_BIT_DATA	BIT(0)
+#define BMC150_ACCEL_INT_MAP_1_BIT_DATA		BIT(0)
+#define BMC150_ACCEL_INT_MAP_1_BIT_FWM		BIT(1)
+#define BMC150_ACCEL_INT_MAP_1_BIT_FFULL	BIT(2)
 
 #define BMC150_ACCEL_REG_INT_RST_LATCH		0x21
 #define BMC150_ACCEL_INT_MODE_LATCH_RESET	0x80
@@ -80,7 +82,9 @@
 #define BMC150_ACCEL_INT_EN_BIT_SLP_Z		BIT(2)
 
 #define BMC150_ACCEL_REG_INT_EN_1		0x17
-#define BMC150_ACCEL_INT_EN_BIT_DATA_EN	BIT(4)
+#define BMC150_ACCEL_INT_EN_BIT_DATA_EN		BIT(4)
+#define BMC150_ACCEL_INT_EN_BIT_FFULL_EN	BIT(5)
+#define BMC150_ACCEL_INT_EN_BIT_FWM_EN		BIT(6)
 
 #define BMC150_ACCEL_REG_INT_OUT_CTRL		0x20
 #define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL	BIT(0)
@@ -119,6 +123,12 @@
 #define BMC150_ACCEL_AXIS_TO_REG(axis)	(BMC150_ACCEL_REG_XOUT_L + (axis * 2))
 #define BMC150_AUTO_SUSPEND_DELAY_MS		2000
 
+#define BMC150_ACCEL_REG_FIFO_STATUS		0x0E
+#define BMC150_ACCEL_REG_FIFO_CONFIG0		0x30
+#define BMC150_ACCEL_REG_FIFO_CONFIG1		0x3E
+#define BMC150_ACCEL_REG_FIFO_DATA		0x3F
+#define BMC150_ACCEL_FIFO_LENGTH		32
+
 enum bmc150_accel_axis {
 	AXIS_X,
 	AXIS_Y,
@@ -161,6 +171,7 @@ struct bmc150_accel_trigger {
 	struct bmc150_accel_data *data;
 	struct iio_trigger *indio_trig;
 	bool enabled;
+	int (*setup)(struct bmc150_accel_trigger *t, bool state);
 };
 
 struct bmc150_accel_event {
@@ -180,8 +191,8 @@ struct bmc150_accel_event {
 	};
 };
 
-#define BMC150_ACCEL_INTERRUPTS		2
-#define BMC150_ACCEL_TRIGGERS		2
+#define BMC150_ACCEL_INTERRUPTS		3
+#define BMC150_ACCEL_TRIGGERS		3
 #define BMC150_ACCEL_EVENTS		1
 
 struct bmc150_accel_data {
@@ -191,6 +202,7 @@ struct bmc150_accel_data {
 	struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
 	struct bmc150_accel_event events[BMC150_ACCEL_EVENTS];
 	struct mutex mutex;
+	u8 fifo_mode, watermark;
 	s16 buffer[8];
 	u8 bw_bits;
 	u32 range;
@@ -484,6 +496,12 @@ bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = {
 			BMC150_ACCEL_INT_EN_BIT_SLP_Y |
 			BMC150_ACCEL_INT_EN_BIT_SLP_Z
 	},
+	{ /* fifo watermark interrupt */
+		.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
+		.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FWM,
+		.en_reg = BMC150_ACCEL_REG_INT_EN_1,
+		.en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
+	},
 };
 
 static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
@@ -1020,6 +1038,8 @@ static const struct iio_info bmc150_accel_info = {
 	.driver_module		= THIS_MODULE,
 };
 
+static int bmc150_accel_fifo_flush(struct iio_dev *indio_dev);
+
 static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
 {
 	struct iio_poll_func *pf = p;
@@ -1027,6 +1047,12 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
 	int bit, ret, i = 0;
 
+	if (data->fifo_mode) {
+		bmc150_accel_fifo_flush(indio_dev);
+		iio_trigger_notify_done(indio_dev->trig);
+		return IRQ_HANDLED;
+	}
+
 	mutex_lock(&data->mutex);
 	for_each_set_bit(bit, indio_dev->buffer->scan_mask,
 			 indio_dev->masklength) {
@@ -1088,6 +1114,14 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
 		return 0;
 	}
 
+	if (t->setup) {
+		ret = t->setup(t, state);
+		if (ret < 0) {
+			mutex_unlock(&data->mutex);
+			return ret;
+		}
+	}
+
 	ret = bmc150_accel_set_interrupt(data, t->intr, state);
 	if (ret < 0) {
 		mutex_unlock(&data->mutex);
@@ -1208,9 +1242,12 @@ static int bmc150_accel_gpio_probe(struct i2c_client *client,
 	return ret;
 }
 
+static int bmc150_accel_fifo_setup(struct bmc150_accel_trigger *t, bool state);
+
 static struct {
 	int intr;
 	const char *name;
+	int (*setup)(struct bmc150_accel_trigger *t, bool state);
 } bmc150_accel_triggers[BMC150_ACCEL_TRIGGERS] = {
 	{
 		.intr = 0,
@@ -1220,6 +1257,11 @@ static struct {
 		.intr = 1,
 		.name = "%s-any-motion-dev%d",
 	},
+	{
+		.intr = 2,
+		.name = "%s-watermark-dev%d",
+		.setup = bmc150_accel_fifo_setup,
+	},
 };
 
 static void bmc150_accel_unregister_triggers(struct bmc150_accel_data *data,
@@ -1257,6 +1299,7 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
 		t->indio_trig->ops = &bmc150_accel_trigger_ops;
 		t->intr = &data->interrupts[intr];
 		t->data = data;
+		t->setup = bmc150_accel_triggers[i].setup;
 		iio_trigger_set_drvdata(t->indio_trig, t);
 
 		ret = iio_trigger_register(t->indio_trig);
@@ -1302,6 +1345,143 @@ static void bmc150_accel_events_setup(struct iio_dev *indio_dev,
 	}
 }
 
+static int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val)
+
+{
+	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG0;
+	int ret;
+
+	if (val > BMC150_ACCEL_FIFO_LENGTH)
+		return -EINVAL;
+
+	ret = i2c_smbus_write_byte_data(data->client, reg, val);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error writing reg_fifo_config0\n");
+		return ret;
+	}
+
+	data->watermark = val;
+
+	return 0;
+}
+
+
+static int bmc150_accel_fifo_flush(struct iio_dev *indio_dev)
+{
+	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	int ret, i;
+	u8 count;
+	u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3];
+	u8 reg_fifo_data = BMC150_ACCEL_REG_FIFO_DATA;
+	struct i2c_msg msg[2];
+	int64_t tstamp;
+	int sample_freq = 0, sec, ms;
+
+	ret = bmc150_accel_get_bw(data, &sec, &ms);
+	if (ret == IIO_VAL_INT_PLUS_MICRO)
+		sample_freq = sec * 1000000000 + ms * 1000;
+
+	ret = i2c_smbus_read_byte_data(data->client,
+				       BMC150_ACCEL_REG_FIFO_STATUS);
+	if (ret < 0) {
+		dev_err(&indio_dev->dev, "Error reading reg_fifo_status\n");
+		return ret;
+	}
+
+	count = ret & 0x7F;
+
+	if (!count)
+		return 0;
+
+	msg[0].addr = data->client->addr;
+	msg[0].flags = 0;
+	msg[0].buf = &reg_fifo_data;
+	msg[0].len = sizeof(reg_fifo_data);
+
+	msg[1].addr = data->client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].buf = (u8 *)buffer;
+	msg[1].len = count * 3 * 2;
+
+	ret = i2c_transfer(data->client->adapter, msg, 2);
+	if (ret != 2) {
+		dev_err(&indio_dev->dev, "Error reading reg_fifo_data\n");
+		return ret;
+	}
+
+	if (!data->timestamp)
+		data->timestamp = iio_get_time_ns();
+
+	tstamp = data->timestamp - count * sample_freq;
+
+	for (i = 0; i < count; i++) {
+		u16 sample[8];
+		int j, bit;
+
+		j = 0;
+		for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+				 indio_dev->masklength) {
+			memcpy(&sample[j++], &buffer[i * 3 + bit], 2);
+		}
+
+		iio_push_to_buffers_with_timestamp(indio_dev, sample, tstamp);
+
+		tstamp += sample_freq;
+	}
+
+	data->timestamp = 0;
+
+	return 0;
+}
+
+static int bmc150_accel_fifo_mode_set(struct bmc150_accel_data *data)
+{
+	u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(data->client, reg);
+
+	/* writting the fifo config discards FIFO data - avoid it if possible */
+	if (ret == data->fifo_mode)
+		return 0;
+
+	ret = i2c_smbus_write_byte_data(data->client, reg, data->fifo_mode);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error writing reg_fifo_config1\n");
+		return ret;
+	}
+
+	if (!data->fifo_mode)
+		return 0;
+
+	/* we can set the the watermark value only after FIFO is enabled */
+	ret = i2c_smbus_write_byte_data(data->client,
+					BMC150_ACCEL_REG_FIFO_CONFIG0,
+					data->watermark);
+
+	if (ret < 0)
+		dev_err(&data->client->dev, "Error writing reg_fifo_config0\n");
+
+	return ret;
+}
+
+static int bmc150_accel_fifo_setup(struct bmc150_accel_trigger *t, bool state)
+{
+	if (state)
+		t->data->fifo_mode = 0x40;
+	else
+		t->data->fifo_mode = 0;
+
+	return bmc150_accel_fifo_mode_set(t->data);
+}
+
+const struct iio_hwfifo bmc150_accel_hwfifo = {
+	.length = BMC150_ACCEL_FIFO_LENGTH,
+	.set_watermark = bmc150_accel_set_watermark,
+	.flush = bmc150_accel_fifo_flush,
+};
+
 static int bmc150_accel_probe(struct i2c_client *client,
 			      const struct i2c_device_id *id)
 {
@@ -1387,6 +1567,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
 				"Failed: iio triggered buffer setup\n");
 			goto err_trigger_unregister;
 		}
+
+		indio_dev->hwfifo = &bmc150_accel_hwfifo;
 	}
 
 	ret = iio_device_register(indio_dev);
@@ -1458,6 +1640,7 @@ static int bmc150_accel_resume(struct device *dev)
 	mutex_lock(&data->mutex);
 	if (atomic_read(&data->active_intr))
 		bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
+	bmc150_accel_fifo_mode_set(data);
 	mutex_unlock(&data->mutex);
 
 	return 0;
@@ -1487,6 +1670,9 @@ static int bmc150_accel_runtime_resume(struct device *dev)
 	ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
 	if (ret < 0)
 		return ret;
+	ret = bmc150_accel_fifo_mode_set(data);
+	if (ret < 0)
+		return ret;
 
 	sleep_val = bmc150_accel_get_startup_times(data);
 	if (sleep_val < 20)
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 01/11] iio: buffer: fix custom buffer attributes copy
  2014-12-21  0:42 ` [PATCH v2 01/11] iio: buffer: fix custom buffer attributes copy Octavian Purdila
@ 2015-01-04 11:25   ` Jonathan Cameron
  2015-01-04 11:34     ` Lars-Peter Clausen
  0 siblings, 1 reply; 50+ messages in thread
From: Jonathan Cameron @ 2015-01-04 11:25 UTC (permalink / raw)
  To: Octavian Purdila, linux-iio, lars-Peter Clausen

On 21/12/14 00:42, Octavian Purdila wrote:
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
Definitely looks like a bug has snuck in here.  Lars, it's your bit of code.
Want to just sanity check this fix before I apply it?

Thanks,

Jonathan
> ---
>  drivers/iio/industrialio-buffer.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index 2bd8d39..403b728 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -789,7 +789,7 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
>  	buffer->buffer_group.attrs[1] = &dev_attr_enable.attr;
>  	if (buffer->attrs)
>  		memcpy(&buffer->buffer_group.attrs[2], buffer->attrs,
> -			sizeof(*&buffer->buffer_group.attrs) * (attrcount - 2));
> +			sizeof(*&buffer->buffer_group.attrs) * attrcount);
>  	buffer->buffer_group.attrs[attrcount+2] = NULL;
>  
>  	indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group;
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 02/11] iio: buffer: refactor buffer attributes setup
  2014-12-21  0:42 ` [PATCH v2 02/11] iio: buffer: refactor buffer attributes setup Octavian Purdila
@ 2015-01-04 11:31   ` Jonathan Cameron
  2015-01-05 10:48     ` Octavian Purdila
  0 siblings, 1 reply; 50+ messages in thread
From: Jonathan Cameron @ 2015-01-04 11:31 UTC (permalink / raw)
  To: Octavian Purdila, linux-iio

On 21/12/14 00:42, Octavian Purdila wrote:
> Move all core (non-cusotm) buffer attributes to a vector to make it
custom
> easier to add more of them in the future.
> 
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>

A sensible tidy up.
> ---
>  drivers/iio/industrialio-buffer.c | 31 +++++++++++++++++++------------
>  1 file changed, 19 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index 403b728..bc55434 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -759,6 +759,11 @@ static struct device_attribute dev_attr_length_ro = __ATTR(length,
>  static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
>  		   iio_buffer_show_enable, iio_buffer_store_enable);
>  
> +static struct attribute *iio_buffer_attrs[] = {
> +	&dev_attr_length.attr,
> +	&dev_attr_enable.attr,
> +};
> +
>  int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
>  {
>  	struct iio_dev_attr *p;
> @@ -776,21 +781,23 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
>  			attrcount++;
>  	}
>  
> -	buffer->buffer_group.name = "buffer";
> -	buffer->buffer_group.attrs = kcalloc(attrcount + 3,
> -			sizeof(*buffer->buffer_group.attrs), GFP_KERNEL);
> -	if (!buffer->buffer_group.attrs)
> +	attr = kcalloc(attrcount + ARRAY_SIZE(iio_buffer_attrs) + 1,
> +		       sizeof(struct attribute *), GFP_KERNEL);
> +	if (!attr)
>  		return -ENOMEM;
>  
> -	if (buffer->access->set_length)
> -		buffer->buffer_group.attrs[0] = &dev_attr_length.attr;
> -	else
> -		buffer->buffer_group.attrs[0] = &dev_attr_length_ro.attr;
> -	buffer->buffer_group.attrs[1] = &dev_attr_enable.attr;
> +	memcpy(attr, iio_buffer_attrs, sizeof(iio_buffer_attrs));
> +	if (!buffer->access->set_length)
> +		attr[0] = &dev_attr_length_ro.attr;
> +
>  	if (buffer->attrs)
> -		memcpy(&buffer->buffer_group.attrs[2], buffer->attrs,
> -			sizeof(*&buffer->buffer_group.attrs) * attrcount);
> -	buffer->buffer_group.attrs[attrcount+2] = NULL;
> +		memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs,
> +		       sizeof(struct attribute *) * attrcount);
> +
> +	attr[attrcount + ARRAY_SIZE(iio_buffer_attrs)] = NULL;
> +
> +	buffer->buffer_group.name = "buffer";
> +	buffer->buffer_group.attrs = attr;
>  
>  	indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group;
>  
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 01/11] iio: buffer: fix custom buffer attributes copy
  2015-01-04 11:25   ` Jonathan Cameron
@ 2015-01-04 11:34     ` Lars-Peter Clausen
  2015-01-04 16:11       ` Jonathan Cameron
  0 siblings, 1 reply; 50+ messages in thread
From: Lars-Peter Clausen @ 2015-01-04 11:34 UTC (permalink / raw)
  To: Jonathan Cameron, Octavian Purdila, linux-iio

On 01/04/2015 12:25 PM, Jonathan Cameron wrote:
> On 21/12/14 00:42, Octavian Purdila wrote:
>> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> Definitely looks like a bug has snuck in here.  Lars, it's your bit of code.
> Want to just sanity check this fix before I apply it?

Reviewed-by: Lars-Peter Clausen <lars@metafoo.de>

Thanks.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 03/11] iio: add watermark logic to iio read and poll
  2014-12-21  0:42 ` [PATCH v2 03/11] iio: add watermark logic to iio read and poll Octavian Purdila
@ 2015-01-04 15:44   ` Jonathan Cameron
  2015-01-25 21:22   ` Hartmut Knaack
  1 sibling, 0 replies; 50+ messages in thread
From: Jonathan Cameron @ 2015-01-04 15:44 UTC (permalink / raw)
  To: Octavian Purdila, linux-iio; +Cc: Josselin Costanzi, Lars-Peter Clausen

On 21/12/14 00:42, Octavian Purdila wrote:
> From: Josselin Costanzi <josselin.costanzi@mobile-devices.fr>
> 
> Currently the IIO buffer blocking read only wait until at least one
> data element is available.
> This patch makes the reader sleep until enough data is collected before
> returning to userspace. This should limit the read() calls count when
> trying to get data in batches.
> 
> Co-author: Yannick Bedhomme <yannick.bedhomme@mobile-devices.fr>
> Signed-off-by: Josselin Costanzi <josselin.costanzi@mobile-devices.fr>
> [rebased and remove buffer timeout]
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
Looks good. I think everyone was pretty much behind this patch in it's
original form (except for the bit you dropped).  Still I'd like confirmation
from Lars and others (if they want to!)

Jonathan
> ---
>  Documentation/ABI/testing/sysfs-bus-iio  |  10 +++
>  drivers/iio/industrialio-buffer.c        | 114 ++++++++++++++++++++++++++-----
>  drivers/iio/kfifo_buf.c                  |  11 ++-
>  drivers/staging/iio/accel/sca3000_ring.c |   4 +-
>  include/linux/iio/buffer.h               |   9 ++-
>  5 files changed, 118 insertions(+), 30 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index df5e69e..7260f1f 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -1142,3 +1142,13 @@ Contact:	linux-iio@vger.kernel.org
>  Description:
>  		This attribute is used to read the number of steps taken by the user
>  		since the last reboot while activated.
> +
> +What:		/sys/bus/iio/devices/iio:deviceX/buffer/low_watermark
> +KernelVersion:	3.20
> +Contact:	linux-iio@vger.kernel.org
> +Description:
> +		A single positive integer specifying the maximum number of scan
> +		elements to wait for.
> +		Poll will block until the watermark is reached.
> +		Blocking read will wait until the minimum between the requested
> +		read amount or the low water mark is available.
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index bc55434..7f74c7f 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -37,7 +37,7 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
>  	return !list_empty(&buf->buffer_list);
>  }
>  
> -static bool iio_buffer_data_available(struct iio_buffer *buf)
> +static size_t iio_buffer_data_available(struct iio_buffer *buf)
>  {
>  	return buf->access->data_available(buf);
>  }
> @@ -53,6 +53,9 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
>  {
>  	struct iio_dev *indio_dev = filp->private_data;
>  	struct iio_buffer *rb = indio_dev->buffer;
> +	size_t datum_size = rb->bytes_per_datum;
> +	size_t to_read = min_t(size_t, n / datum_size, rb->low_watermark);
> +	size_t count = 0;
>  	int ret;
>  
>  	if (!indio_dev->info)
> @@ -62,25 +65,38 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
>  		return -EINVAL;
>  
>  	do {
> -		if (!iio_buffer_data_available(rb)) {
> -			if (filp->f_flags & O_NONBLOCK)
> -				return -EAGAIN;
> -
> +		if (filp->f_flags & O_NONBLOCK) {
> +			if (!iio_buffer_data_available(rb)) {
> +				ret = -EAGAIN;
> +				break;
> +			}
> +		} else {
>  			ret = wait_event_interruptible(rb->pollq,
> -					iio_buffer_data_available(rb) ||
> -					indio_dev->info == NULL);
> +			       iio_buffer_data_available(rb) >= to_read ||
> +						       indio_dev->info == NULL);
>  			if (ret)
>  				return ret;
> -			if (indio_dev->info == NULL)
> -				return -ENODEV;
> +			if (indio_dev->info == NULL) {
> +				ret = -ENODEV;
> +				break;
> +			}
>  		}
>  
> -		ret = rb->access->read_first_n(rb, n, buf);
> -		if (ret == 0 && (filp->f_flags & O_NONBLOCK))
> -			ret = -EAGAIN;
> -	 } while (ret == 0);
> +		ret = rb->access->read_first_n(rb, n, buf + count);
> +		if (ret < 0)
> +			break;
>  
> -	return ret;
> +		count += ret;
> +		n -= ret;
> +		to_read -= ret / datum_size;
> +	 } while (to_read > 0);
> +
> +	if (count)
> +		return count;
> +	if (ret < 0)
> +		return ret;
> +
> +	return -EAGAIN;
>  }
>  
>  /**
> @@ -96,9 +112,8 @@ unsigned int iio_buffer_poll(struct file *filp,
>  		return -ENODEV;
>  
>  	poll_wait(filp, &rb->pollq, wait);
> -	if (iio_buffer_data_available(rb))
> +	if (iio_buffer_data_available(rb) >= rb->low_watermark)
>  		return POLLIN | POLLRDNORM;
> -	/* need a way of knowing if there may be enough data... */
>  	return 0;
>  }
>  
> @@ -123,6 +138,7 @@ void iio_buffer_init(struct iio_buffer *buffer)
>  	INIT_LIST_HEAD(&buffer->buffer_list);
>  	init_waitqueue_head(&buffer->pollq);
>  	kref_init(&buffer->ref);
> +	buffer->low_watermark = 1;
>  }
>  EXPORT_SYMBOL(iio_buffer_init);
>  
> @@ -418,7 +434,16 @@ static ssize_t iio_buffer_write_length(struct device *dev,
>  	}
>  	mutex_unlock(&indio_dev->mlock);
>  
> -	return ret ? ret : len;
> +	if (ret)
> +		return ret;
> +
> +	if (buffer->length)
> +		val = buffer->length;
> +
> +	if (val < buffer->low_watermark)
> +		buffer->low_watermark = val;
> +
> +	return len;
>  }
>  
>  static ssize_t iio_buffer_show_enable(struct device *dev,
> @@ -472,6 +497,7 @@ static void iio_buffer_activate(struct iio_dev *indio_dev,
>  static void iio_buffer_deactivate(struct iio_buffer *buffer)
>  {
>  	list_del_init(&buffer->buffer_list);
> +	wake_up_interruptible(&buffer->pollq);
>  	iio_buffer_put(buffer);
>  }
>  
> @@ -752,16 +778,59 @@ done:
>  
>  static const char * const iio_scan_elements_group_name = "scan_elements";
>  
> +static ssize_t iio_buffer_show_watermark(struct device *dev,
> +					 struct device_attribute *attr,
> +					 char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct iio_buffer *buffer = indio_dev->buffer;
> +
> +	return sprintf(buf, "%u\n", buffer->low_watermark);
> +}
> +
> +static ssize_t iio_buffer_store_watermark(struct device *dev,
> +					  struct device_attribute *attr,
> +					  const char *buf,
> +					  size_t len)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct iio_buffer *buffer = indio_dev->buffer;
> +	unsigned int val;
> +	int ret;
> +
> +	ret = kstrtouint(buf, 10, &val);
> +	if (ret)
> +		return ret;
> +
> +	if (val > buffer->length)
> +		return -EINVAL;
> +
> +	mutex_lock(&indio_dev->mlock);
> +	if (iio_buffer_is_active(indio_dev->buffer)) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	buffer->low_watermark = val;
> +	ret = 0;
> +out:
> +	mutex_unlock(&indio_dev->mlock);
> +	return ret ? ret : len;
> +}
> +
>  static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
>  		   iio_buffer_write_length);
>  static struct device_attribute dev_attr_length_ro = __ATTR(length,
>  	S_IRUGO, iio_buffer_read_length, NULL);
>  static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
>  		   iio_buffer_show_enable, iio_buffer_store_enable);
> +static DEVICE_ATTR(low_watermark, S_IRUGO | S_IWUSR,
> +		   iio_buffer_show_watermark, iio_buffer_store_watermark);
>  
>  static struct attribute *iio_buffer_attrs[] = {
>  	&dev_attr_length.attr,
>  	&dev_attr_enable.attr,
> +	&dev_attr_low_watermark.attr,
>  };
>  
>  int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
> @@ -942,8 +1011,17 @@ static const void *iio_demux(struct iio_buffer *buffer,
>  static int iio_push_to_buffer(struct iio_buffer *buffer, const void *data)
>  {
>  	const void *dataout = iio_demux(buffer, data);
> +	int ret;
>  
> -	return buffer->access->store_to(buffer, dataout);
> +	ret = buffer->access->store_to(buffer, dataout);
> +	if (ret)
> +		return ret;
> +
> +	/* We can't just test for watermark to decide if we wake the poll queue
> +	 * because read may request less samples than the watermark
> +	 */
> +	wake_up_interruptible(&buffer->pollq);
> +	return 0;
>  }
>  
>  static void iio_buffer_demux_free(struct iio_buffer *buffer)
> diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c
> index b20a9cf..30a9bfa 100644
> --- a/drivers/iio/kfifo_buf.c
> +++ b/drivers/iio/kfifo_buf.c
> @@ -83,9 +83,6 @@ static int iio_store_to_kfifo(struct iio_buffer *r,
>  	ret = kfifo_in(&kf->kf, data, 1);
>  	if (ret != 1)
>  		return -EBUSY;
> -
> -	wake_up_interruptible_poll(&r->pollq, POLLIN | POLLRDNORM);
> -
>  	return 0;
>  }
>  
> @@ -109,16 +106,16 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
>  	return copied;
>  }
>  
> -static bool iio_kfifo_buf_data_available(struct iio_buffer *r)
> +static size_t iio_kfifo_buf_data_available(struct iio_buffer *r)
>  {
>  	struct iio_kfifo *kf = iio_to_kfifo(r);
> -	bool empty;
> +	size_t samples;
>  
>  	mutex_lock(&kf->user_lock);
> -	empty = kfifo_is_empty(&kf->kf);
> +	samples = kfifo_len(&kf->kf);
>  	mutex_unlock(&kf->user_lock);
>  
> -	return !empty;
> +	return samples;
>  }
>  
>  static void iio_kfifo_buffer_release(struct iio_buffer *buffer)
> diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c
> index f76a268..1e65dea 100644
> --- a/drivers/staging/iio/accel/sca3000_ring.c
> +++ b/drivers/staging/iio/accel/sca3000_ring.c
> @@ -129,9 +129,9 @@ error_ret:
>  	return ret ? ret : num_read;
>  }
>  
> -static bool sca3000_ring_buf_data_available(struct iio_buffer *r)
> +static size_t sca3000_ring_buf_data_available(struct iio_buffer *r)
>  {
> -	return r->stufftoread;
> +	return r->stufftoread ? r->low_watermark : 0;
>  }
>  
>  /**
> diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
> index b65850a..768593c 100644
> --- a/include/linux/iio/buffer.h
> +++ b/include/linux/iio/buffer.h
> @@ -21,8 +21,8 @@ struct iio_buffer;
>   * struct iio_buffer_access_funcs - access functions for buffers.
>   * @store_to:		actually store stuff to the buffer
>   * @read_first_n:	try to get a specified number of bytes (must exist)
> - * @data_available:	indicates whether data for reading from the buffer is
> - *			available.
> + * @data_available:	indicates how much data is available for reading from
> + *			the buffer.
>   * @request_update:	if a parameter change has been marked, update underlying
>   *			storage.
>   * @set_bytes_per_datum:set number of bytes per datum
> @@ -43,7 +43,7 @@ struct iio_buffer_access_funcs {
>  	int (*read_first_n)(struct iio_buffer *buffer,
>  			    size_t n,
>  			    char __user *buf);
> -	bool (*data_available)(struct iio_buffer *buffer);
> +	size_t (*data_available)(struct iio_buffer *buffer);
>  
>  	int (*request_update)(struct iio_buffer *buffer);
>  
> @@ -72,6 +72,8 @@ struct iio_buffer_access_funcs {
>   * @demux_bounce:	[INTERN] buffer for doing gather from incoming scan.
>   * @buffer_list:	[INTERN] entry in the devices list of current buffers.
>   * @ref:		[INTERN] reference count of the buffer.
> + * @low_watermark:	[INTERN] number of datums for poll/blocking read to
> + * 			wait for.
>   */
>  struct iio_buffer {
>  	int					length;
> @@ -90,6 +92,7 @@ struct iio_buffer {
>  	void					*demux_bounce;
>  	struct list_head			buffer_list;
>  	struct kref				ref;
> +	unsigned int				low_watermark;
>  };
>  
>  /**
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 04/11] iio: add support for hardware fifo
  2014-12-21  0:42 ` [PATCH v2 04/11] iio: add support for hardware fifo Octavian Purdila
@ 2015-01-04 16:07   ` Jonathan Cameron
  2015-01-05 11:29     ` Octavian Purdila
  2015-01-28 23:46   ` Hartmut Knaack
  1 sibling, 1 reply; 50+ messages in thread
From: Jonathan Cameron @ 2015-01-04 16:07 UTC (permalink / raw)
  To: Octavian Purdila, linux-iio

On 21/12/14 00:42, Octavian Purdila wrote:

Thanks for taking this on!

This all looks fairly sensible, though a few comments inline.
One big semantic change I'd suggest is to allow the watermark
level passed to the hardware to be a 'hint' rather than a hard
and fast rull.  A lot of these hardware buffers are fairly small
(perhaps 32 entries) and the devices can run fast so whilst
we will obviously have to handle an interrupt often, we may well
want to have a much larger software front end buffer with a
much larger watermark.  For example, a 8192Hz accelerometer
with 32 entry fifo (watermark at 16).  Will fire an interrupt 512 times
a second.  Userspace might be only interested in getting data 32 times
a second and hence want a watermark of 256 entries and probably have
a buffer that is 512 entries long or more.

> Some devices have hardware buffers that can store a number of samples
> for later consumption. Hardware usually provides interrupts to notify
> the processor when the fifo is full or when it has reached a certain
> threshold. This helps with reducing the number of interrupts to the
> host processor and thus it helps decreasing the power consumption.
> 
> This patch adds support for hardware fifo to IIO by allowing the
> drivers to register operations for flushing the hadware fifo and
> setting the watermark level.

Perhaps put something in here to observe that this is a different approach
to the straight hardware buffer stuff we already have - of most interest
for hybrid buffering rather than a pure hardware buffer.

> 
> A driver implementing hardware fifo support must also provide a
> watermark trigger which must contain "watermark" in its name.
> 
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> ---
>  Documentation/ABI/testing/sysfs-bus-iio | 22 +++++++++++++++++
>  drivers/iio/industrialio-buffer.c       | 44 ++++++++++++++++++++++++++++-----
>  include/linux/iio/iio.h                 | 17 +++++++++++++
>  3 files changed, 77 insertions(+), 6 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index 7260f1f..6bb67ac 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -1152,3 +1152,25 @@ Description:
>  		Poll will block until the watermark is reached.
>  		Blocking read will wait until the minimum between the requested
>  		read amount or the low water mark is available.
> +		If the device has a hardware fifo this value is going to be used
> +		for the hardware fifo watermark as well.

I'd make this a litle vaguer (deliberately ;).   Perhaps used as a 'hint'
for the hardware fifo watermark as well.  The reason being that if we set
the software watermark at say 20 and the hardware only has 15 fifo entries,
then we might want to be clever and say set the hardware fifo watershed to 10.
For now that would be a decision of the hardware driver rather than one for
the core.
> +
> +What:		/sys/bus/iio/devices/iio:deviceX/buffer/hwfifo-length
> +KernelVersion:	3.20
> +Contact:	linux-iio@vger.kernel.org
> +Description:
> +		A single positive integer specifying the maximum number of
> +		samples that the hardware fifo has. If the device does not
> +		support hardware fifo this is zero.
> +		When a device supports hardware fifo it will expose a trigger
> +		with the name that contains "watermark"
> +		(e.g. i2c-BMC150A:00-watermark-dev0).
> +		To use the hardware fifo the user must set an appropriate value
> +		in the buffer/length and buffer/low_watermark entries and select
> +		the watermark trigger. At that poin the hardware fifo will be
point
> +		enabled and the samples will be collected in a hardware buffer.
Hmm. I wonder to a degree if the trigger approach really makes sense for
fifo equiped devices.  We've deliberately not added one in a few existing
cases.

Otherwise, is there a reason to run this separately from a trigger not using
the fifo.  Surely that's just the same as a watermark of 1?

Anyhow, a point for discussion!

> +		When the number of samples in the hardware fifo reaches the
> +		watermark level the watermark trigger is issued and data is
> +		flushed to the devices buffer.
> +		A hardware buffer flush will also be triggered when reading from
> +		the device buffer and there is not enough data available.
> \ No newline at end of file
Fix this..
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index 7f74c7f..3da6d07 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -37,9 +37,17 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
>  	return !list_empty(&buf->buffer_list);
>  }
>  
> -static size_t iio_buffer_data_available(struct iio_buffer *buf)
> +static bool iio_buffer_data_available(struct iio_dev *indio_dev,
> +				      struct iio_buffer *buf, size_t required)
>  {
> -	return buf->access->data_available(buf);
> +	size_t avail = buf->access->data_available(buf);
> +
> +	if (avail < required && indio_dev->hwfifo) {
> +		indio_dev->hwfifo->flush(indio_dev);
> +		avail = buf->access->data_available(buf);
> +	}
> +
> +	return avail >= required;
Does it make sense to move the decision in here?  Could just as easily
have left this as returning the length and done the logic outside...
I don't mind that much... However, we probably want to rename the function
now that it is doing more than strictly querying availability.

Could also have flush take a parameter for what is desired and only read
that many?  On relatively slow buses might make sense...
>  }
>  
>  /**
> @@ -66,13 +74,13 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
>  
>  	do {
>  		if (filp->f_flags & O_NONBLOCK) {
> -			if (!iio_buffer_data_available(rb)) {
> +			if (!iio_buffer_data_available(indio_dev, rb, 1)) {
>  				ret = -EAGAIN;
>  				break;
>  			}
>  		} else {
>  			ret = wait_event_interruptible(rb->pollq,
> -			       iio_buffer_data_available(rb) >= to_read ||
> +		            iio_buffer_data_available(indio_dev, rb, to_read) ||
>  						       indio_dev->info == NULL);
>  			if (ret)
>  				return ret;
> @@ -112,7 +120,7 @@ unsigned int iio_buffer_poll(struct file *filp,
>  		return -ENODEV;
>  
>  	poll_wait(filp, &rb->pollq, wait);
> -	if (iio_buffer_data_available(rb) >= rb->low_watermark)
> +	if (iio_buffer_data_available(indio_dev, rb, rb->low_watermark))
>  		return POLLIN | POLLRDNORM;
>  	return 0;
>  }
> @@ -440,8 +448,14 @@ static ssize_t iio_buffer_write_length(struct device *dev,
>  	if (buffer->length)
>  		val = buffer->length;
>  
> -	if (val < buffer->low_watermark)
> +	if (val < buffer->low_watermark) {
> +		if (indio_dev->hwfifo) {
> +			ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
> +			if (ret)
> +				return ret;
> +		}
>  		buffer->low_watermark = val;
> +	}
>  
>  	return len;
>  }
> @@ -811,6 +825,12 @@ static ssize_t iio_buffer_store_watermark(struct device *dev,
>  		goto out;
>  	}
>  
> +	if (indio_dev->hwfifo) {
> +		ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
> +		if (ret)
> +			goto out;
> +	}
> +
>  	buffer->low_watermark = val;
>  	ret = 0;
>  out:
> @@ -818,6 +838,16 @@ out:
>  	return ret ? ret : len;
>  }
>  
> +ssize_t iio_buffer_hwfifo_read_length(struct device *dev,
> +				      struct device_attribute *attr,
> +				      char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	const struct iio_hwfifo *hwfifo = indio_dev->hwfifo;
> +
> +	return sprintf(buf, "%u\n", hwfifo ? hwfifo->length : 0);
> +}
> +
>  static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
>  		   iio_buffer_write_length);
>  static struct device_attribute dev_attr_length_ro = __ATTR(length,
> @@ -826,11 +856,13 @@ static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
>  		   iio_buffer_show_enable, iio_buffer_store_enable);
>  static DEVICE_ATTR(low_watermark, S_IRUGO | S_IWUSR,
>  		   iio_buffer_show_watermark, iio_buffer_store_watermark);
> +static DEVICE_ATTR(hwfifo_length, S_IRUGO, iio_buffer_hwfifo_read_length, NULL);
>  
>  static struct attribute *iio_buffer_attrs[] = {
>  	&dev_attr_length.attr,
>  	&dev_attr_enable.attr,
>  	&dev_attr_low_watermark.attr,
> +	&dev_attr_hwfifo_length.attr,
>  };
>  
>  int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> index 878d861..f64a05f 100644
> --- a/include/linux/iio/iio.h
> +++ b/include/linux/iio/iio.h
> @@ -417,6 +417,22 @@ struct iio_buffer_setup_ops {
>  };
>  
>  /**
> + * struct iio_buffer_hwfifo_ops - hardware fifo operations
> + *
> + * @length:		[DRIVER] the hardware fifo length
> + * @set_watermark:	[DRIVER] setups the watermark level
> + * @flush:		[DRIVER] copies data from the hardware buffer to the
> + *		 	device buffer
> + * @watermark_trig:	[DRIVER] an allocated and registered trigger containing
> + *			"watermark" in its name
err. This last one isn't actually in the structure...
> + */
> +struct iio_hwfifo {
> +	int length;
> +	int (*set_watermark)(struct iio_dev *, unsigned int);
> +	int (*flush)(struct iio_dev *);
> +};
> +
> +/**
>   * struct iio_dev - industrial I/O device
>   * @id:			[INTERN] used to identify device internally
>   * @modes:		[DRIVER] operating modes supported by device
> @@ -491,6 +507,7 @@ struct iio_dev {
>  	int				groupcounter;
>  
>  	unsigned long			flags;
> +	const struct iio_hwfifo		*hwfifo;
>  #if defined(CONFIG_DEBUG_FS)
>  	struct dentry			*debugfs_dentry;
>  	unsigned			cached_reg_addr;
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 01/11] iio: buffer: fix custom buffer attributes copy
  2015-01-04 11:34     ` Lars-Peter Clausen
@ 2015-01-04 16:11       ` Jonathan Cameron
  0 siblings, 0 replies; 50+ messages in thread
From: Jonathan Cameron @ 2015-01-04 16:11 UTC (permalink / raw)
  To: Lars-Peter Clausen, Octavian Purdila, linux-iio

On 04/01/15 11:34, Lars-Peter Clausen wrote:
> On 01/04/2015 12:25 PM, Jonathan Cameron wrote:
>> On 21/12/14 00:42, Octavian Purdila wrote:
>>> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
>> Definitely looks like a bug has snuck in here.  Lars, it's your bit of code.
>> Want to just sanity check this fix before I apply it?
> 
> Reviewed-by: Lars-Peter Clausen <lars@metafoo.de>
Thanks.

Applied to the togreg branch of iio.git seeing as I haven't actually
sent the patch it is fixing upstream yet.

Jonathan
> 
> Thanks.
> -- 
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 05/11] iio: bmc150: refactor slope duration and threshold update
  2014-12-21  0:42 ` [PATCH v2 05/11] iio: bmc150: refactor slope duration and threshold update Octavian Purdila
@ 2015-01-04 16:21   ` Jonathan Cameron
  2015-01-06 18:53     ` Srinivas Pandruvada
  0 siblings, 1 reply; 50+ messages in thread
From: Jonathan Cameron @ 2015-01-04 16:21 UTC (permalink / raw)
  To: Octavian Purdila, linux-iio, Srinivas Pandruvada, Laurentiu Palcu

On 21/12/14 00:42, Octavian Purdila wrote:
> Move the slope duration and threshold update in separate functions
> to reduce code duplicate between chip init and motion interrupt setup.
> 
> The patch also moves the update from the motion interrupt setup
> function to the write event function so that we can later refactor the
> interrupt code.
The side effect of this is that these will get updated at a different
point in time from before.  Previously these values would only get
updated when the event was enabled (or the trigger).  So to change
them a disable / enable cycle was needed. Now they happen the moment
they are relevant.

I prefer the new option, but it is an ABI change (be it one most people
won't notice!)

Hence I'd like an Ack from Srinivas and time for comments from others
before taking this one.

Otherwise, looks good ;)

Jonathan
> 
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> ---
>  drivers/iio/accel/bmc150-accel.c | 110 ++++++++++++++++++++++-----------------
>  1 file changed, 63 insertions(+), 47 deletions(-)
> 
> diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
> index 22c096c..92f1d2b 100644
> --- a/drivers/iio/accel/bmc150-accel.c
> +++ b/drivers/iio/accel/bmc150-accel.c
> @@ -266,6 +266,52 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val,
>  	return -EINVAL;
>  }
>  
> +static int bmc150_accel_update_slope_threshold(struct bmc150_accel_data *data,
> +					       int val)
> +{
> +	int ret = 0;
> +
> +	val &= 0xFF;
> +
> +	ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_6,
> +					val);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev, "Error writing reg_int_6\n");
> +		return ret;
> +	}
> +	data->slope_thres = val;
> +
> +	dev_dbg(&data->client->dev, "%s: %x\n", __func__, val);
> +
> +	return ret;
> +}
> +
> +static int bmc150_accel_update_slope_duration(struct bmc150_accel_data *data,
> +					      int val)
> +{
> +	int ret;
> +
> +	val &= BMC150_ACCEL_SLOPE_DUR_MASK;
> +
> +	ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev, "Error reading reg_int_5\n");
> +		return ret;
> +	}
> +	val |= ret & ~BMC150_ACCEL_SLOPE_DUR_MASK;
> +	ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_5,
> +					val);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev, "Error write reg_int_5\n");
> +		return ret;
> +	}
> +	data->slope_dur = val;
> +
> +	dev_dbg(&data->client->dev, "%s: %x\n", __func__, val);
> +
> +	return ret;
> +}
> +
>  static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
>  {
>  	int ret;
> @@ -304,32 +350,16 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
>  
>  	data->range = BMC150_ACCEL_DEF_RANGE_4G;
>  
> -	/* Set default slope duration */
> -	ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5);
> -	if (ret < 0) {
> -		dev_err(&data->client->dev, "Error reading reg_int_5\n");
> -		return ret;
> -	}
> -	data->slope_dur |= BMC150_ACCEL_DEF_SLOPE_DURATION;
> -	ret = i2c_smbus_write_byte_data(data->client,
> -					BMC150_ACCEL_REG_INT_5,
> -					data->slope_dur);
> -	if (ret < 0) {
> -		dev_err(&data->client->dev, "Error writing reg_int_5\n");
> +	/* Set default slope duration and thresholds */
> +	ret = bmc150_accel_update_slope_duration(data,
> +					 BMC150_ACCEL_DEF_SLOPE_DURATION);
> +	if (ret < 0)
>  		return ret;
> -	}
> -	dev_dbg(&data->client->dev, "slope_dur %x\n", data->slope_dur);
>  
> -	/* Set default slope thresholds */
> -	ret = i2c_smbus_write_byte_data(data->client,
> -					BMC150_ACCEL_REG_INT_6,
> -					BMC150_ACCEL_DEF_SLOPE_THRESHOLD);
> -	if (ret < 0) {
> -		dev_err(&data->client->dev, "Error writing reg_int_6\n");
> +	ret = bmc150_accel_update_slope_threshold(data,
> +					  BMC150_ACCEL_DEF_SLOPE_THRESHOLD);
> +	if (ret < 0)
>  		return ret;
> -	}
> -	data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD;
> -	dev_dbg(&data->client->dev, "slope_thres %x\n", data->slope_thres);
>  
>  	/* Set default as latched interrupts */
>  	ret = i2c_smbus_write_byte_data(data->client,
> @@ -372,24 +402,6 @@ static int bmc150_accel_setup_any_motion_interrupt(
>  	}
>  
>  	if (status) {
> -		/* Set slope duration (no of samples) */
> -		ret = i2c_smbus_write_byte_data(data->client,
> -						BMC150_ACCEL_REG_INT_5,
> -						data->slope_dur);
> -		if (ret < 0) {
> -			dev_err(&data->client->dev, "Error write reg_int_5\n");
> -			return ret;
> -		}
> -
> -		/* Set slope thresholds */
> -		ret = i2c_smbus_write_byte_data(data->client,
> -						BMC150_ACCEL_REG_INT_6,
> -						data->slope_thres);
> -		if (ret < 0) {
> -			dev_err(&data->client->dev, "Error write reg_int_6\n");
> -			return ret;
> -		}
> -
>  		/*
>  		 * New data interrupt is always non-latched,
>  		 * which will have higher priority, so no need
> @@ -726,7 +738,7 @@ static int bmc150_accel_read_event(struct iio_dev *indio_dev,
>  		*val = data->slope_thres;
>  		break;
>  	case IIO_EV_INFO_PERIOD:
> -		*val = data->slope_dur & BMC150_ACCEL_SLOPE_DUR_MASK;
> +		*val = data->slope_dur;
>  		break;
>  	default:
>  		return -EINVAL;
> @@ -743,23 +755,27 @@ static int bmc150_accel_write_event(struct iio_dev *indio_dev,
>  				    int val, int val2)
>  {
>  	struct bmc150_accel_data *data = iio_priv(indio_dev);
> +	int ret;
>  
>  	if (data->ev_enable_state)
>  		return -EBUSY;
>  
>  	switch (info) {
>  	case IIO_EV_INFO_VALUE:
> -		data->slope_thres = val;
> +		mutex_lock(&data->mutex);
> +		ret = bmc150_accel_update_slope_threshold(data, val);
> +		mutex_unlock(&data->mutex);
>  		break;
>  	case IIO_EV_INFO_PERIOD:
> -		data->slope_dur &= ~BMC150_ACCEL_SLOPE_DUR_MASK;
> -		data->slope_dur |= val & BMC150_ACCEL_SLOPE_DUR_MASK;
> +		mutex_lock(&data->mutex);
> +		ret = bmc150_accel_update_slope_duration(data, val);
> +		mutex_unlock(&data->mutex);
>  		break;
>  	default:
> -		return -EINVAL;
> +		ret = -EINVAL;
>  	}
>  
> -	return 0;
> +	return ret;
>  }
>  
>  static int bmc150_accel_read_event_config(struct iio_dev *indio_dev,
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 06/11] iio: bmc150: refactor interrupt enabling
  2014-12-21  0:42 ` [PATCH v2 06/11] iio: bmc150: refactor interrupt enabling Octavian Purdila
@ 2015-01-04 16:27   ` Jonathan Cameron
  2015-01-28 10:33     ` Octavian Purdila
  0 siblings, 1 reply; 50+ messages in thread
From: Jonathan Cameron @ 2015-01-04 16:27 UTC (permalink / raw)
  To: Octavian Purdila, linux-iio

On 21/12/14 00:42, Octavian Purdila wrote:
> This patch combines the any motion and new data interrupts function
> into a single, generic, interrupt enable function. On top of this, we
> can later refactor triggers to make it easier to add new triggers.
> 
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
Some really trivial suggests inline.  Looks good even without it being
useful for later stuff ;)
> ---
>  drivers/iio/accel/bmc150-accel.c | 269 ++++++++++++++++-----------------------
>  1 file changed, 113 insertions(+), 156 deletions(-)
> 
> diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
> index 92f1d2b..53d1d1d 100644
> --- a/drivers/iio/accel/bmc150-accel.c
> +++ b/drivers/iio/accel/bmc150-accel.c
> @@ -144,6 +144,13 @@ struct bmc150_accel_chip_info {
>  	const struct bmc150_scale_info scale_table[4];
>  };
>
I'd be tempted to define this at the place where you fill them below...
> +struct bmc150_accel_interrupt_info {
> +	u8 map_reg;
> +	u8 map_bitmask;
> +	u8 en_reg;
> +	u8 en_bitmask;
> +};
> +
>  struct bmc150_accel_data {
>  	struct i2c_client *client;
>  	struct iio_trigger *dready_trig;
> @@ -375,137 +382,6 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
>  	return 0;
>  }
>  
> -static int bmc150_accel_setup_any_motion_interrupt(
> -					struct bmc150_accel_data *data,
> -					bool status)
> -{
> -	int ret;
> -
> -	/* Enable/Disable INT1 mapping */
> -	ret = i2c_smbus_read_byte_data(data->client,
> -				       BMC150_ACCEL_REG_INT_MAP_0);
> -	if (ret < 0) {
> -		dev_err(&data->client->dev, "Error reading reg_int_map_0\n");
> -		return ret;
> -	}
> -	if (status)
> -		ret |= BMC150_ACCEL_INT_MAP_0_BIT_SLOPE;
> -	else
> -		ret &= ~BMC150_ACCEL_INT_MAP_0_BIT_SLOPE;
> -
> -	ret = i2c_smbus_write_byte_data(data->client,
> -					BMC150_ACCEL_REG_INT_MAP_0,
> -					ret);
> -	if (ret < 0) {
> -		dev_err(&data->client->dev, "Error writing reg_int_map_0\n");
> -		return ret;
> -	}
> -
> -	if (status) {
> -		/*
> -		 * New data interrupt is always non-latched,
> -		 * which will have higher priority, so no need
> -		 * to set latched mode, we will be flooded anyway with INTR
> -		 */
> -		if (!data->dready_trigger_on) {
> -			ret = i2c_smbus_write_byte_data(data->client,
> -					BMC150_ACCEL_REG_INT_RST_LATCH,
> -					BMC150_ACCEL_INT_MODE_LATCH_INT |
> -					BMC150_ACCEL_INT_MODE_LATCH_RESET);
> -			if (ret < 0) {
> -				dev_err(&data->client->dev,
> -					"Error writing reg_int_rst_latch\n");
> -				return ret;
> -			}
> -		}
> -
> -		ret = i2c_smbus_write_byte_data(data->client,
> -						BMC150_ACCEL_REG_INT_EN_0,
> -						BMC150_ACCEL_INT_EN_BIT_SLP_X |
> -						BMC150_ACCEL_INT_EN_BIT_SLP_Y |
> -						BMC150_ACCEL_INT_EN_BIT_SLP_Z);
> -	} else
> -		ret = i2c_smbus_write_byte_data(data->client,
> -						BMC150_ACCEL_REG_INT_EN_0,
> -						0);
> -
> -	if (ret < 0) {
> -		dev_err(&data->client->dev, "Error writing reg_int_en_0\n");
> -		return ret;
> -	}
> -
> -	return 0;
> -}
> -
> -static int bmc150_accel_setup_new_data_interrupt(struct bmc150_accel_data *data,
> -					   bool status)
> -{
> -	int ret;
> -
> -	/* Enable/Disable INT1 mapping */
> -	ret = i2c_smbus_read_byte_data(data->client,
> -				       BMC150_ACCEL_REG_INT_MAP_1);
> -	if (ret < 0) {
> -		dev_err(&data->client->dev, "Error reading reg_int_map_1\n");
> -		return ret;
> -	}
> -	if (status)
> -		ret |= BMC150_ACCEL_INT_MAP_1_BIT_DATA;
> -	else
> -		ret &= ~BMC150_ACCEL_INT_MAP_1_BIT_DATA;
> -
> -	ret = i2c_smbus_write_byte_data(data->client,
> -					BMC150_ACCEL_REG_INT_MAP_1,
> -					ret);
> -	if (ret < 0) {
> -		dev_err(&data->client->dev, "Error writing reg_int_map_1\n");
> -		return ret;
> -	}
> -
> -	if (status) {
> -		/*
> -		 * Set non latched mode interrupt and clear any latched
> -		 * interrupt
> -		 */
> -		ret = i2c_smbus_write_byte_data(data->client,
> -					BMC150_ACCEL_REG_INT_RST_LATCH,
> -					BMC150_ACCEL_INT_MODE_NON_LATCH_INT |
> -					BMC150_ACCEL_INT_MODE_LATCH_RESET);
> -		if (ret < 0) {
> -			dev_err(&data->client->dev,
> -				"Error writing reg_int_rst_latch\n");
> -			return ret;
> -		}
> -
> -		ret = i2c_smbus_write_byte_data(data->client,
> -					BMC150_ACCEL_REG_INT_EN_1,
> -					BMC150_ACCEL_INT_EN_BIT_DATA_EN);
> -
> -	} else {
> -		/* Restore default interrupt mode */
> -		ret = i2c_smbus_write_byte_data(data->client,
> -					BMC150_ACCEL_REG_INT_RST_LATCH,
> -					BMC150_ACCEL_INT_MODE_LATCH_INT |
> -					BMC150_ACCEL_INT_MODE_LATCH_RESET);
> -		if (ret < 0) {
> -			dev_err(&data->client->dev,
> -				"Error writing reg_int_rst_latch\n");
> -			return ret;
> -		}
> -
> -		ret = i2c_smbus_write_byte_data(data->client,
> -						BMC150_ACCEL_REG_INT_EN_1,
> -						0);
> -	}
> -
> -	if (ret < 0) {
> -		dev_err(&data->client->dev, "Error writing reg_int_en_1\n");
> -		return ret;
> -	}
> -
> -	return 0;
> -}
> -
>  static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val,
>  			       int *val2)
>  {
> @@ -560,6 +436,97 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
>  }
>  #endif
>  
> +static struct bmc150_accel_interrupt_info bmc150_accel_interrupts[] = {
> +	{ /* data ready interrupt */
> +		.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
> +		.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA,
> +		.en_reg = BMC150_ACCEL_REG_INT_EN_1,
> +		.en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN,
> +	},
> +	{  /* motion interrupt */
> +		.map_reg = BMC150_ACCEL_REG_INT_MAP_0,
> +		.map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_SLOPE,
> +		.en_reg = BMC150_ACCEL_REG_INT_EN_0,
> +		.en_bitmask =  BMC150_ACCEL_INT_EN_BIT_SLP_X |
> +			BMC150_ACCEL_INT_EN_BIT_SLP_Y |
> +			BMC150_ACCEL_INT_EN_BIT_SLP_Z
> +	},
> +};
> +
> +static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data,
> +				      struct bmc150_accel_interrupt_info *info,
> +				      bool state)
> +{
> +	int ret;
> +
> +	/*
> +	 * We will expect the enable and disable to do operation in
> +	 * in reverse order. This will happen here anyway as our
> +	 * resume operation uses sync mode runtime pm calls, the
> +	 * suspend operation will be delayed by autosuspend delay
> +	 * So the disable operation will still happen in reverse of
> +	 * enable operation. When runtime pm is disabled the mode
> +	 * is always on so sequence doesn't matter
> +	 */
> +	ret = bmc150_accel_set_power_state(data, state);
> +	if (ret < 0)
> +		return ret;
> +
> +
> +	/* map the interrupt to the appropriate pins */
> +	ret = i2c_smbus_read_byte_data(data->client, info->map_reg);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev, "Error reading reg_int_map\n");
> +		return ret;
> +	}
> +	if (state)
> +		ret |= info->map_bitmask;
> +	else
> +		ret &= ~info->map_bitmask;
> +
> +	ret = i2c_smbus_write_byte_data(data->client, info->map_reg,
> +					ret);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev, "Error writing reg_int_map\n");
> +		return ret;
> +	}
> +
> +	/* enable/disable the interrupt */
> +	ret = i2c_smbus_read_byte_data(data->client, info->en_reg);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev, "Error reading reg_int_en\n");
> +		return ret;
> +	}
> +
> +	if (state)
> +		ret |= info->en_bitmask;
> +	else
> +		ret &= ~info->en_bitmask;
> +
> +	ret = i2c_smbus_write_byte_data(data->client, info->en_reg, ret);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev, "Error writing reg_int_en\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int bmc150_accel_setup_any_motion_interrupt(
> +					struct bmc150_accel_data *data,
> +					bool status)
> +{
> +	return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[1],
Maybe define a matching enum so the indexes are obvious.
Then is there a lot of point in having these wrappers? I'd just call
it directly so you'd get something like.

bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[bmc150_int_any_mo],
			   status);
> +					  status);
> +}
> +
> +static int bmc150_accel_setup_new_data_interrupt(struct bmc150_accel_data *data,
> +					   bool status)
> +{
> +	return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[0],
> +					  status);
> +}
> +
>  static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
>  {
>  	int ret, i;
> @@ -809,22 +776,6 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
>  		return 0;
>  	}
>  
> -	/*
> -	 * We will expect the enable and disable to do operation in
> -	 * in reverse order. This will happen here anyway as our
> -	 * resume operation uses sync mode runtime pm calls, the
> -	 * suspend operation will be delayed by autosuspend delay
> -	 * So the disable operation will still happen in reverse of
> -	 * enable operation. When runtime pm is disabled the mode
> -	 * is always on so sequence doesn't matter
> -	 */
> -
> -	ret = bmc150_accel_set_power_state(data, state);
> -	if (ret < 0) {
> -		mutex_unlock(&data->mutex);
> -		return ret;
> -	}
> -
>  	ret =  bmc150_accel_setup_any_motion_interrupt(data, state);
>  	if (ret < 0) {
>  		mutex_unlock(&data->mutex);
> @@ -1056,15 +1007,6 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
>  		return 0;
>  	}
>  
> -	/*
> -	 * Refer to comment in bmc150_accel_write_event_config for
> -	 * enable/disable operation order
> -	 */
> -	ret = bmc150_accel_set_power_state(data, state);
> -	if (ret < 0) {
> -		mutex_unlock(&data->mutex);
> -		return ret;
> -	}
>  	if (data->motion_trig == trig)
>  		ret =  bmc150_accel_setup_any_motion_interrupt(data, state);
>  	else
> @@ -1241,6 +1183,21 @@ static int bmc150_accel_probe(struct i2c_client *client,
>  		if (ret)
>  			return ret;
>  
> +		/*
> +		 * Set latched mode interrupt. While certain interrupts are
> +		 * non-latched regardless of this settings (e.g. new data) we
> +		 * want to use latch mode when we can to prevent interrupt
> +		 * flooding.
> +		 */
> +		ret = i2c_smbus_write_byte_data(data->client,
> +						BMC150_ACCEL_REG_INT_RST_LATCH,
> +					     BMC150_ACCEL_INT_MODE_LATCH_RESET);
> +		if (ret < 0) {
> +			dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n");
> +			return ret;
> +		}
> +
> +
>  		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
>  							   "%s-dev%d",
>  							   indio_dev->name,
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 07/11] iio: bmc150: exit early if event / trigger state is not changed
  2014-12-21  0:42 ` [PATCH v2 07/11] iio: bmc150: exit early if event / trigger state is not changed Octavian Purdila
@ 2015-01-04 16:29   ` Jonathan Cameron
  0 siblings, 0 replies; 50+ messages in thread
From: Jonathan Cameron @ 2015-01-04 16:29 UTC (permalink / raw)
  To: Octavian Purdila, linux-iio

On 21/12/14 00:42, Octavian Purdila wrote:
> Previous of this patch the check was only done if we enabled the event
> and it was already enabled. We can do the same if the event is
> disabled and we want to disable it.
> 
> The patch also adds the same check on the trigger code.
> 
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
Another sensible stand alone change.  Will take this whenever
the earlier patches are ready.

> ---
>  drivers/iio/accel/bmc150-accel.c | 14 +++++++++++++-
>  1 file changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
> index 53d1d1d..aaad2fb 100644
> --- a/drivers/iio/accel/bmc150-accel.c
> +++ b/drivers/iio/accel/bmc150-accel.c
> @@ -765,7 +765,7 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
>  	struct bmc150_accel_data *data = iio_priv(indio_dev);
>  	int ret;
>  
> -	if (state && data->ev_enable_state)
> +	if (state == data->ev_enable_state)
>  		return 0;
>  
>  	mutex_lock(&data->mutex);
> @@ -1001,6 +1001,18 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
>  
>  	mutex_lock(&data->mutex);
>  
> +	if (data->motion_trig == trig) {
> +		if (data->motion_trigger_on == state) {
> +			mutex_unlock(&data->mutex);
> +			return 0;
> +		}
> +	} else {
> +		if (data->dready_trigger_on == state) {
> +			mutex_unlock(&data->mutex);
> +			return 0;
> +		}
> +	}
> +
>  	if (!state && data->ev_enable_state && data->motion_trigger_on) {
>  		data->motion_trigger_on = false;
>  		mutex_unlock(&data->mutex);
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 08/11] iio: bmc150: introduce bmc150_accel_interrupt
  2014-12-21  0:42 ` [PATCH v2 08/11] iio: bmc150: introduce bmc150_accel_interrupt Octavian Purdila
@ 2015-01-04 16:36   ` Jonathan Cameron
  2015-01-28 11:09     ` Octavian Purdila
  0 siblings, 1 reply; 50+ messages in thread
From: Jonathan Cameron @ 2015-01-04 16:36 UTC (permalink / raw)
  To: Octavian Purdila, linux-iio

On 21/12/14 00:42, Octavian Purdila wrote:
> Since both triggers and events can share an interrupt, add a data
> structure that tracks the users of an interrupt so that it enables or
> disables it only for the first users and respectively last user.
> 
> This will allows us to easily add more events or triggers.
> 
> The patch also adds an interrupt enabled counter, so that we can
> easily know if we need to put the device in normal mode when the
> resume callback is issued.
> 
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
This is probably the cleanest way of doing this, but an alternative is
to register an interrupt chip and then you can have each interrupt source
(internal to the device) have it's own interrupt and register as if
it had direct access (rather than having to read what interrupt occured
first).  This is the preferred method these days for MFDs where this
tree structure of interrupts is common.

I think that would result in slightly more code though, so perhaps this
local version of some of that infrastructure is fine.

Jonathan
> ---
>  drivers/iio/accel/bmc150-accel.c | 87 +++++++++++++++++++++-------------------
>  1 file changed, 45 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
> index aaad2fb..7c905f6 100644
> --- a/drivers/iio/accel/bmc150-accel.c
> +++ b/drivers/iio/accel/bmc150-accel.c
> @@ -151,10 +151,19 @@ struct bmc150_accel_interrupt_info {
>  	u8 en_bitmask;
>  };
>  
> +struct bmc150_accel_interrupt {
> +	struct bmc150_accel_interrupt_info *info;
> +	atomic_t users;
> +};
> +
> +#define BMC150_ACCEL_INTERRUPTS		2
> +
>  struct bmc150_accel_data {
>  	struct i2c_client *client;
> +	struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
>  	struct iio_trigger *dready_trig;
>  	struct iio_trigger *motion_trig;
> +	atomic_t active_intr;
>  	struct mutex mutex;
>  	s16 buffer[8];
>  	u8 bw_bits;
> @@ -436,7 +445,8 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
>  }
>  #endif
>  
> -static struct bmc150_accel_interrupt_info bmc150_accel_interrupts[] = {
> +static struct bmc150_accel_interrupt_info
Just noticed. Should this not also be const?
> +bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = {
>  	{ /* data ready interrupt */
>  		.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
>  		.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA,
> @@ -453,12 +463,30 @@ static struct bmc150_accel_interrupt_info bmc150_accel_interrupts[] = {
>  	},
>  };
>  
> +static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
> +					 struct bmc150_accel_data *data)
> +{
> +	int i;
> +
> +	for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++)
> +		data->interrupts[i].info = &bmc150_accel_interrupts[i];
> +}
> +
>  static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data,
> -				      struct bmc150_accel_interrupt_info *info,
> +				      struct bmc150_accel_interrupt *intr,
>  				      bool state)
>  {
> +	struct bmc150_accel_interrupt_info *info = intr->info;
>  	int ret;
>  
> +	if (state) {
> +		if (atomic_inc_return(&intr->users) > 1)
> +			return 0;
> +	} else {
> +		if (atomic_dec_return(&intr->users) > 0)
> +			return 0;
> +	}
> +
>  	/*
>  	 * We will expect the enable and disable to do operation in
>  	 * in reverse order. This will happen here anyway as our
> @@ -509,22 +537,12 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data,
>  		return ret;
>  	}
>  
> -	return 0;
> -}
> -
> -static int bmc150_accel_setup_any_motion_interrupt(
> -					struct bmc150_accel_data *data,
> -					bool status)
> -{
> -	return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[1],
> -					  status);
> -}
> +	if (state)
> +		atomic_inc(&data->active_intr);
> +	else
> +		atomic_dec(&data->active_intr);
>  
> -static int bmc150_accel_setup_new_data_interrupt(struct bmc150_accel_data *data,
> -					   bool status)
> -{
> -	return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[0],
> -					  status);
> +	return 0;
>  }
>  
>  static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
> @@ -769,23 +787,12 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
>  		return 0;
>  
>  	mutex_lock(&data->mutex);
> -
> -	if (!state && data->motion_trigger_on) {
> -		data->ev_enable_state = 0;
> -		mutex_unlock(&data->mutex);
> -		return 0;
> -	}
> -
> -	ret =  bmc150_accel_setup_any_motion_interrupt(data, state);
> -	if (ret < 0) {
> -		mutex_unlock(&data->mutex);
> -		return ret;
> -	}
> -
> -	data->ev_enable_state = state;
> +	ret = bmc150_accel_set_interrupt(data, &data->interrupts[1], state);
> +	if (!ret)
> +		data->ev_enable_state = state;
>  	mutex_unlock(&data->mutex);
>  
> -	return 0;
> +	return ret;
>  }
>  
>  static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev,
> @@ -1013,16 +1020,12 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
>  		}
>  	}
>  
> -	if (!state && data->ev_enable_state && data->motion_trigger_on) {
> -		data->motion_trigger_on = false;
> -		mutex_unlock(&data->mutex);
> -		return 0;
> -	}
> -
>  	if (data->motion_trig == trig)
> -		ret =  bmc150_accel_setup_any_motion_interrupt(data, state);
> +		ret = bmc150_accel_set_interrupt(data, &data->interrupts[1],
> +						 state);
>  	else
> -		ret = bmc150_accel_setup_new_data_interrupt(data, state);
> +		ret = bmc150_accel_set_interrupt(data, &data->interrupts[0],
> +						 state);
>  	if (ret < 0) {
>  		mutex_unlock(&data->mutex);
>  		return ret;
> @@ -1209,6 +1212,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
>  			return ret;
>  		}
>  
> +		bmc150_accel_interrupts_setup(indio_dev, data);
>  
>  		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
>  							   "%s-dev%d",
> @@ -1325,8 +1329,7 @@ static int bmc150_accel_resume(struct device *dev)
>  	struct bmc150_accel_data *data = iio_priv(indio_dev);
>  
>  	mutex_lock(&data->mutex);
> -	if (data->dready_trigger_on || data->motion_trigger_on ||
> -							data->ev_enable_state)
> +	if (atomic_read(&data->active_intr))
>  		bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
>  	mutex_unlock(&data->mutex);
>  
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 09/11] iio: bmc150: introduce bmc150_accel_trigger
  2014-12-21  0:42 ` [PATCH v2 09/11] iio: bmc150: introduce bmc150_accel_trigger Octavian Purdila
@ 2015-01-04 16:39   ` Jonathan Cameron
  0 siblings, 0 replies; 50+ messages in thread
From: Jonathan Cameron @ 2015-01-04 16:39 UTC (permalink / raw)
  To: Octavian Purdila, linux-iio

On 21/12/14 00:42, Octavian Purdila wrote:
> Add a separate structure for triggers and add the infrastructure to
> support an arbitrary number of triggers. Each trigger is associated
> with an interrupt and has an enabled/disabled state.
> 
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
This makes sense if we conclude that having triggers for the fifo watermark
is the way to go...  Otherwise, still a reasonable bit of refactoring.
> ---
>  drivers/iio/accel/bmc150-accel.c | 174 ++++++++++++++++++++++-----------------
>  1 file changed, 100 insertions(+), 74 deletions(-)
> 
> diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
> index 7c905f6..cd2f5d9 100644
> --- a/drivers/iio/accel/bmc150-accel.c
> +++ b/drivers/iio/accel/bmc150-accel.c
> @@ -156,14 +156,21 @@ struct bmc150_accel_interrupt {
>  	atomic_t users;
>  };
>  
> +struct bmc150_accel_trigger {
> +	struct bmc150_accel_interrupt *intr;
> +	struct bmc150_accel_data *data;
> +	struct iio_trigger *indio_trig;
> +	bool enabled;
> +};
> +
>  #define BMC150_ACCEL_INTERRUPTS		2
> +#define BMC150_ACCEL_TRIGGERS		2
>  
>  struct bmc150_accel_data {
>  	struct i2c_client *client;
>  	struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
> -	struct iio_trigger *dready_trig;
> -	struct iio_trigger *motion_trig;
>  	atomic_t active_intr;
> +	struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
>  	struct mutex mutex;
>  	s16 buffer[8];
>  	u8 bw_bits;
> @@ -171,8 +178,6 @@ struct bmc150_accel_data {
>  	u32 slope_thres;
>  	u32 range;
>  	int ev_enable_state;
> -	bool dready_trigger_on;
> -	bool motion_trigger_on;
>  	int64_t timestamp;
>  	const struct bmc150_accel_chip_info *chip_info;
>  };
> @@ -799,11 +804,14 @@ static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev,
>  				   struct iio_trigger *trig)
>  {
>  	struct bmc150_accel_data *data = iio_priv(indio_dev);
> +	int i;
>  
> -	if (data->dready_trig != trig && data->motion_trig != trig)
> -		return -EINVAL;
> +	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
> +		if (data->triggers[i].indio_trig == trig)
> +			return 0;
> +	}
>  
> -	return 0;
> +	return -EINVAL;
>  }
>  
>  static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
> @@ -975,12 +983,12 @@ err_read:
>  
>  static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
>  {
> -	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
> -	struct bmc150_accel_data *data = iio_priv(indio_dev);
> +	struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig);
> +	struct bmc150_accel_data *data = t->data;
>  	int ret;
>  
>  	/* new data interrupts don't need ack */
> -	if (data->dready_trigger_on)
> +	if (t == &t->data->triggers[0])
>  		return 0;
>  
>  	mutex_lock(&data->mutex);
> @@ -1002,38 +1010,24 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
>  static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
>  						   bool state)
>  {
> -	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
> -	struct bmc150_accel_data *data = iio_priv(indio_dev);
> +	struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig);
> +	struct bmc150_accel_data *data = t->data;
>  	int ret;
>  
>  	mutex_lock(&data->mutex);
>  
> -	if (data->motion_trig == trig) {
> -		if (data->motion_trigger_on == state) {
> -			mutex_unlock(&data->mutex);
> -			return 0;
> -		}
> -	} else {
> -		if (data->dready_trigger_on == state) {
> -			mutex_unlock(&data->mutex);
> -			return 0;
> -		}
> +	if (t->enabled == state) {
> +		mutex_unlock(&data->mutex);
> +		return 0;
>  	}
>  
> -	if (data->motion_trig == trig)
> -		ret = bmc150_accel_set_interrupt(data, &data->interrupts[1],
> -						 state);
> -	else
> -		ret = bmc150_accel_set_interrupt(data, &data->interrupts[0],
> -						 state);
> +	ret = bmc150_accel_set_interrupt(data, t->intr, state);
>  	if (ret < 0) {
>  		mutex_unlock(&data->mutex);
>  		return ret;
>  	}
> -	if (data->motion_trig == trig)
> -		data->motion_trigger_on = state;
> -	else
> -		data->dready_trigger_on = state;
> +
> +	t->enabled = state;
>  
>  	mutex_unlock(&data->mutex);
>  
> @@ -1073,7 +1067,7 @@ static irqreturn_t bmc150_accel_event_handler(int irq, void *private)
>  							IIO_EV_DIR_EITHER),
>  							data->timestamp);
>  ack_intr_status:
> -	if (!data->dready_trigger_on)
> +	if (!data->triggers[0].enabled)
>  		ret = i2c_smbus_write_byte_data(data->client,
>  					BMC150_ACCEL_REG_INT_RST_LATCH,
>  					BMC150_ACCEL_INT_MODE_LATCH_INT |
> @@ -1086,13 +1080,16 @@ static irqreturn_t bmc150_accel_data_rdy_trig_poll(int irq, void *private)
>  {
>  	struct iio_dev *indio_dev = private;
>  	struct bmc150_accel_data *data = iio_priv(indio_dev);
> +	int i;
>  
>  	data->timestamp = iio_get_time_ns();
>  
> -	if (data->dready_trigger_on)
> -		iio_trigger_poll(data->dready_trig);
> -	else if (data->motion_trigger_on)
> -		iio_trigger_poll(data->motion_trig);
> +	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
> +		if (data->triggers[i].enabled) {
> +			iio_trigger_poll(data->triggers[i].indio_trig);
> +			break;
> +		}
> +	}
>  
>  	if (data->ev_enable_state)
>  		return IRQ_WAKE_THREAD;
> @@ -1144,6 +1141,68 @@ static int bmc150_accel_gpio_probe(struct i2c_client *client,
>  	return ret;
>  }
>  
> +static struct {
> +	int intr;
> +	const char *name;
> +} bmc150_accel_triggers[BMC150_ACCEL_TRIGGERS] = {
> +	{
> +		.intr = 0,
> +		.name = "%s-dev%d",
> +	},
> +	{
> +		.intr = 1,
> +		.name = "%s-any-motion-dev%d",
> +	},
> +};
> +
> +static void bmc150_accel_unregister_triggers(struct bmc150_accel_data *data,
> +					     int from)
> +{
> +	int i;
> +
> +	for (i = from; i >= 0; i++) {
> +		if (data->triggers[i].indio_trig) {
> +			iio_trigger_unregister(data->triggers[i].indio_trig);
> +			data->triggers[i].indio_trig = NULL;
> +		}
> +	}
> +}
> +
> +static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
> +				       struct bmc150_accel_data *data)
> +{
> +	int i, ret;
> +
> +	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
> +		struct bmc150_accel_trigger *t = &data->triggers[i];
> +		const char *name = bmc150_accel_triggers[i].name;
> +		int intr = bmc150_accel_triggers[i].intr;
> +
> +		t->indio_trig = devm_iio_trigger_alloc(&data->client->dev, name,
> +						       indio_dev->name,
> +						       indio_dev->id);
> +		if (!t->indio_trig) {
> +			ret = -ENOMEM;
> +			break;
> +		}
> +
> +		t->indio_trig->dev.parent = &data->client->dev;
> +		t->indio_trig->ops = &bmc150_accel_trigger_ops;
> +		t->intr = &data->interrupts[intr];
> +		t->data = data;
> +		iio_trigger_set_drvdata(t->indio_trig, t);
> +
> +		ret = iio_trigger_register(t->indio_trig);
> +		if (ret)
> +			break;
> +	}
> +
> +	if (ret)
> +		bmc150_accel_unregister_triggers(data, i - 1);
> +
> +	return ret;
> +}
> +
>  static int bmc150_accel_probe(struct i2c_client *client,
>  			      const struct i2c_device_id *id)
>  {
> @@ -1214,36 +1273,10 @@ static int bmc150_accel_probe(struct i2c_client *client,
>  
>  		bmc150_accel_interrupts_setup(indio_dev, data);
>  
> -		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
> -							   "%s-dev%d",
> -							   indio_dev->name,
> -							   indio_dev->id);
> -		if (!data->dready_trig)
> -			return -ENOMEM;
> -
> -		data->motion_trig = devm_iio_trigger_alloc(&client->dev,
> -							  "%s-any-motion-dev%d",
> -							  indio_dev->name,
> -							  indio_dev->id);
> -		if (!data->motion_trig)
> -			return -ENOMEM;
> -
> -		data->dready_trig->dev.parent = &client->dev;
> -		data->dready_trig->ops = &bmc150_accel_trigger_ops;
> -		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
> -		ret = iio_trigger_register(data->dready_trig);
> +		ret = bmc150_accel_triggers_setup(indio_dev, data);
>  		if (ret)
>  			return ret;
>  
> -		data->motion_trig->dev.parent = &client->dev;
> -		data->motion_trig->ops = &bmc150_accel_trigger_ops;
> -		iio_trigger_set_drvdata(data->motion_trig, indio_dev);
> -		ret = iio_trigger_register(data->motion_trig);
> -		if (ret) {
> -			data->motion_trig = NULL;
> -			goto err_trigger_unregister;
> -		}
> -
>  		ret = iio_triggered_buffer_setup(indio_dev,
>  						 &iio_pollfunc_store_time,
>  						 bmc150_accel_trigger_handler,
> @@ -1275,13 +1308,10 @@ static int bmc150_accel_probe(struct i2c_client *client,
>  err_iio_unregister:
>  	iio_device_unregister(indio_dev);
>  err_buffer_cleanup:
> -	if (data->dready_trig)
> +	if (indio_dev->pollfunc)
>  		iio_triggered_buffer_cleanup(indio_dev);
>  err_trigger_unregister:
> -	if (data->dready_trig)
> -		iio_trigger_unregister(data->dready_trig);
> -	if (data->motion_trig)
> -		iio_trigger_unregister(data->motion_trig);
> +	bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
>  
>  	return ret;
>  }
> @@ -1297,11 +1327,7 @@ static int bmc150_accel_remove(struct i2c_client *client)
>  
>  	iio_device_unregister(indio_dev);
>  
> -	if (data->dready_trig) {
> -		iio_triggered_buffer_cleanup(indio_dev);
> -		iio_trigger_unregister(data->dready_trig);
> -		iio_trigger_unregister(data->motion_trig);
> -	}
> +	bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
>  
>  	mutex_lock(&data->mutex);
>  	bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0);
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 10/11] iio: bmc150: introduce bmc150_accel_event
  2014-12-21  0:42 ` [PATCH v2 10/11] iio: bmc150: introduce bmc150_accel_event Octavian Purdila
@ 2015-01-04 16:49   ` Jonathan Cameron
  0 siblings, 0 replies; 50+ messages in thread
From: Jonathan Cameron @ 2015-01-04 16:49 UTC (permalink / raw)
  To: Octavian Purdila, linux-iio

On 21/12/14 00:42, Octavian Purdila wrote:
> Add a separate structure for events and add the infrastructure to
> support an arbitrary number of events. Each event is associated
> with an interrupt and has an enabled/disabled state.
> 
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
This patch adds a lot of code considering you haven't actually taken
advantage of the infrastructure in this series.  I'd be tempted to
pull this one out for now.  I'm guessing you want to support
some of the other 'events' at a later date? 

I'd also pull out the static const bits of your new structure (already
done but then you copy them in) and use a pointer to reference them...
See inline.
> ---
>  drivers/iio/accel/bmc150-accel.c | 177 ++++++++++++++++++++++++++++++---------
>  1 file changed, 139 insertions(+), 38 deletions(-)
> 
> diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
> index cd2f5d9..14509be 100644
> --- a/drivers/iio/accel/bmc150-accel.c
> +++ b/drivers/iio/accel/bmc150-accel.c
> @@ -163,21 +163,37 @@ struct bmc150_accel_trigger {
>  	bool enabled;
>  };
>  
> +struct bmc150_accel_event {
> +	struct bmc150_accel_interrupt *intr;
> +	struct bmc150_accel_data *data;
> +	enum iio_event_type type;
> +	bool enabled;
> +	int (*read)(struct bmc150_accel_event *event, enum iio_event_info info,
> +		    int *val, int *val2);
> +	int (*write)(struct bmc150_accel_event *event, enum iio_event_info info,
> +		     int val, int val2);
> +	union {
> +		struct {
> +			u32 duration;
> +			u32 threshold;
> +		} slope;
> +	};
> +};
> +
>  #define BMC150_ACCEL_INTERRUPTS		2
>  #define BMC150_ACCEL_TRIGGERS		2
> +#define BMC150_ACCEL_EVENTS		1
>  
>  struct bmc150_accel_data {
>  	struct i2c_client *client;
>  	struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
>  	atomic_t active_intr;
>  	struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
> +	struct bmc150_accel_event events[BMC150_ACCEL_EVENTS];
>  	struct mutex mutex;
>  	s16 buffer[8];
>  	u8 bw_bits;
> -	u32 slope_dur;
> -	u32 slope_thres;
>  	u32 range;
> -	int ev_enable_state;
>  	int64_t timestamp;
>  	const struct bmc150_accel_chip_info *chip_info;
>  };
> @@ -287,7 +303,8 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val,
>  	return -EINVAL;
>  }
>  
> -static int bmc150_accel_update_slope_threshold(struct bmc150_accel_data *data,
> +static int bmc150_accel_update_slope_threshold(struct bmc150_accel_event *event,
> +					       struct bmc150_accel_data *data,
>  					       int val)
>  {
>  	int ret = 0;
> @@ -300,14 +317,15 @@ static int bmc150_accel_update_slope_threshold(struct bmc150_accel_data *data,
>  		dev_err(&data->client->dev, "Error writing reg_int_6\n");
>  		return ret;
>  	}
> -	data->slope_thres = val;
> +	event->slope.threshold = val;
>  
>  	dev_dbg(&data->client->dev, "%s: %x\n", __func__, val);
>  
>  	return ret;
>  }
>  
> -static int bmc150_accel_update_slope_duration(struct bmc150_accel_data *data,
> +static int bmc150_accel_update_slope_duration(struct bmc150_accel_event *event,
> +					      struct bmc150_accel_data *data,
>  					      int val)
>  {
>  	int ret;
> @@ -326,7 +344,7 @@ static int bmc150_accel_update_slope_duration(struct bmc150_accel_data *data,
>  		dev_err(&data->client->dev, "Error write reg_int_5\n");
>  		return ret;
>  	}
> -	data->slope_dur = val;
> +	event->slope.duration = val;
>  
>  	dev_dbg(&data->client->dev, "%s: %x\n", __func__, val);
>  
> @@ -372,12 +390,12 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
>  	data->range = BMC150_ACCEL_DEF_RANGE_4G;
>  
>  	/* Set default slope duration and thresholds */
> -	ret = bmc150_accel_update_slope_duration(data,
> +	ret = bmc150_accel_update_slope_duration(&data->events[0], data,
>  					 BMC150_ACCEL_DEF_SLOPE_DURATION);
>  	if (ret < 0)
>  		return ret;
>  
> -	ret = bmc150_accel_update_slope_threshold(data,
> +	ret = bmc150_accel_update_slope_threshold(&data->events[0], data,
>  					  BMC150_ACCEL_DEF_SLOPE_THRESHOLD);
>  	if (ret < 0)
>  		return ret;
> @@ -713,22 +731,30 @@ static int bmc150_accel_write_raw(struct iio_dev *indio_dev,
>  	return ret;
>  }
>  
> -static int bmc150_accel_read_event(struct iio_dev *indio_dev,
> -				   const struct iio_chan_spec *chan,
> -				   enum iio_event_type type,
> -				   enum iio_event_direction dir,
> -				   enum iio_event_info info,
> -				   int *val, int *val2)
> +static struct bmc150_accel_event*
> +bmc150_accel_get_event(struct iio_dev *indio_dev, enum iio_event_type type)
>  {
>  	struct bmc150_accel_data *data = iio_priv(indio_dev);
> +	int i;
> +
> +	for (i = 0; i < BMC150_ACCEL_EVENTS; i++)
> +		if (data->events[i].type == type)
> +			return &data->events[i];
> +
> +	return NULL;
> +}
>  
> +static int bmc150_accel_event_roc_read(struct bmc150_accel_event *event,
> +				       enum iio_event_info info,
> +				       int *val, int *val2)
> +{
>  	*val2 = 0;
>  	switch (info) {
>  	case IIO_EV_INFO_VALUE:
> -		*val = data->slope_thres;
> +		*val = event->slope.threshold;
>  		break;
>  	case IIO_EV_INFO_PERIOD:
> -		*val = data->slope_dur;
> +		*val = event->slope.duration;
>  		break;
>  	default:
>  		return -EINVAL;
> @@ -737,28 +763,40 @@ static int bmc150_accel_read_event(struct iio_dev *indio_dev,
>  	return IIO_VAL_INT;
>  }
>  
> -static int bmc150_accel_write_event(struct iio_dev *indio_dev,
> -				    const struct iio_chan_spec *chan,
> -				    enum iio_event_type type,
> -				    enum iio_event_direction dir,
> -				    enum iio_event_info info,
> -				    int val, int val2)
> +static int bmc150_accel_read_event(struct iio_dev *indio_dev,
> +				   const struct iio_chan_spec *chan,
> +				   enum iio_event_type type,
> +				   enum iio_event_direction dir,
> +				   enum iio_event_info info,
> +				   int *val, int *val2)
>  {
> -	struct bmc150_accel_data *data = iio_priv(indio_dev);
> -	int ret;
> +	struct bmc150_accel_event *event;
>  
> -	if (data->ev_enable_state)
> -		return -EBUSY;
> +	event = bmc150_accel_get_event(indio_dev, type);
> +	if (!event || !event->read)
> +		return -EINVAL;
> +
> +	return event->read(event, info, val, val2);
> +}
> +
> +static int bmc150_accel_event_roc_write(struct bmc150_accel_event *event,
> +					enum iio_event_info info,
> +					int val, int val2)
> +{
> +	struct bmc150_accel_data *data = event->data;
> +	int ret;
>  
>  	switch (info) {
>  	case IIO_EV_INFO_VALUE:
>  		mutex_lock(&data->mutex);
> -		ret = bmc150_accel_update_slope_threshold(data, val);
> +		ret = bmc150_accel_update_slope_threshold(event, event->data,
> +							  val);
>  		mutex_unlock(&data->mutex);
>  		break;
>  	case IIO_EV_INFO_PERIOD:
>  		mutex_lock(&data->mutex);
> -		ret = bmc150_accel_update_slope_duration(data, val);
> +		ret = bmc150_accel_update_slope_duration(event, event->data,
> +							 val);
>  		mutex_unlock(&data->mutex);
>  		break;
>  	default:
> @@ -768,15 +806,37 @@ static int bmc150_accel_write_event(struct iio_dev *indio_dev,
>  	return ret;
>  }
>  
> +static int bmc150_accel_write_event(struct iio_dev *indio_dev,
> +				    const struct iio_chan_spec *chan,
> +				    enum iio_event_type type,
> +				    enum iio_event_direction dir,
> +				    enum iio_event_info info,
> +				    int val, int val2)
> +{
> +	struct bmc150_accel_event *event;
> +
> +	event = bmc150_accel_get_event(indio_dev, type);
> +	if (!event || !event->write)
> +		return -EINVAL;
> +
> +	if (event->enabled)
> +		return -EBUSY;
> +
> +	return event->write(event, info, val, val2);
> +}
> +
>  static int bmc150_accel_read_event_config(struct iio_dev *indio_dev,
>  					  const struct iio_chan_spec *chan,
>  					  enum iio_event_type type,
>  					  enum iio_event_direction dir)
>  {
> +	struct bmc150_accel_event *event;
>  
> -	struct bmc150_accel_data *data = iio_priv(indio_dev);
> +	event = bmc150_accel_get_event(indio_dev, type);
> +	if (!event)
> +		return -EINVAL;
>  
> -	return data->ev_enable_state;
> +	return event->enabled;
>  }
>  
>  static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
> @@ -786,15 +846,20 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev,
>  					   int state)
>  {
>  	struct bmc150_accel_data *data = iio_priv(indio_dev);
> +	struct bmc150_accel_event *event;
>  	int ret;
>  
> -	if (state == data->ev_enable_state)
> +	event = bmc150_accel_get_event(indio_dev, type);
> +	if (!event)
> +		return -EINVAL;
> +
> +	if (state == event->enabled)
>  		return 0;
>  
>  	mutex_lock(&data->mutex);
> -	ret = bmc150_accel_set_interrupt(data, &data->interrupts[1], state);
> +	ret = bmc150_accel_set_interrupt(data, event->intr, state);
>  	if (!ret)
> -		data->ev_enable_state = state;
> +		event->enabled = state;
>  	mutex_unlock(&data->mutex);
>  
>  	return ret;
> @@ -826,12 +891,14 @@ static const struct attribute_group bmc150_accel_attrs_group = {
>  	.attrs = bmc150_accel_attributes,
>  };
>  
> -static const struct iio_event_spec bmc150_accel_event = {
> +static const struct iio_event_spec bmc150_accel_events[BMC150_ACCEL_EVENTS] = {
> +	{
>  		.type = IIO_EV_TYPE_ROC,
>  		.dir = IIO_EV_DIR_RISING | IIO_EV_DIR_FALLING,
>  		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
>  				 BIT(IIO_EV_INFO_ENABLE) |
>  				 BIT(IIO_EV_INFO_PERIOD)
> +	},
>  };
>  
>  #define BMC150_ACCEL_CHANNEL(_axis, bits) {				\
> @@ -848,8 +915,8 @@ static const struct iio_event_spec bmc150_accel_event = {
>  		.storagebits = 16,					\
>  		.shift = 16 - (bits),					\
>  	},								\
> -	.event_spec = &bmc150_accel_event,				\
> -	.num_event_specs = 1						\
> +	.event_spec = bmc150_accel_events,				\
> +	.num_event_specs = ARRAY_SIZE(bmc150_accel_events)		\
>  }
>  
>  #define BMC150_ACCEL_CHANNELS(bits) {					\
> @@ -1091,7 +1158,7 @@ static irqreturn_t bmc150_accel_data_rdy_trig_poll(int irq, void *private)
>  		}
>  	}
>  
> -	if (data->ev_enable_state)
> +	if (data->events[0].enabled)
>  		return IRQ_WAKE_THREAD;
>  	else
>  		return IRQ_HANDLED;
> @@ -1203,6 +1270,38 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
>  	return ret;
>  }
>  
> +static struct {
> +	int intr;
> +	enum iio_event_type type;
> +	int (*read)(struct bmc150_accel_event *event, enum iio_event_info info,
> +		    int *val, int *val2);
> +	int (*write)(struct bmc150_accel_event *event, enum iio_event_info info,
> +		     int val, int val2);
> +} bmc150_accel_events_info[BMC150_ACCEL_EVENTS] = {
> +	{
> +		.intr = 1,
> +		.type = IIO_EV_TYPE_ROC,
> +		.read = bmc150_accel_event_roc_read,
> +		.write = bmc150_accel_event_roc_write,
> +	},
> +};
> +
> +static void bmc150_accel_events_setup(struct iio_dev *indio_dev,
> +				      struct bmc150_accel_data *data)
> +{
> +	int i;
> +
> +	for (i = 0; i < BMC150_ACCEL_EVENTS; i++) {

This would be simpler if you embedded the constant elements into
one structure and stuck a pointer to that in an outer structure.

> +		int intr = bmc150_accel_events_info[i].intr;
> +
> +		data->events[i].intr = &data->interrupts[intr];
Why do this here?  Probably cleaner just to do this when needed.
> +		data->events[i].data = data;
> +		data->events[i].type = bmc150_accel_events_info[i].type;
> +		data->events[i].read = bmc150_accel_events_info[i].read;
> +		data->events[i].write = bmc150_accel_events_info[i].write;
> +	}
> +}
> +
>  static int bmc150_accel_probe(struct i2c_client *client,
>  			      const struct i2c_device_id *id)
>  {
> @@ -1277,6 +1376,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
>  		if (ret)
>  			return ret;
>  
> +		bmc150_accel_events_setup(indio_dev, data);
> +
>  		ret = iio_triggered_buffer_setup(indio_dev,
>  						 &iio_pollfunc_store_time,
>  						 bmc150_accel_trigger_handler,
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 11/11] iio: bmc150: add support for hardware fifo
  2014-12-21  0:42 ` [PATCH v2 11/11] iio: bmc150: add support for hardware fifo Octavian Purdila
@ 2015-01-04 17:08   ` Jonathan Cameron
  2015-01-28 19:26     ` Octavian Purdila
  0 siblings, 1 reply; 50+ messages in thread
From: Jonathan Cameron @ 2015-01-04 17:08 UTC (permalink / raw)
  To: Octavian Purdila, linux-iio

On 21/12/14 00:42, Octavian Purdila wrote:
> Add a new watermark trigger and hardware fifo operations. When the
> watermark trigger is activated the watermark level is set and the
> hardware FIFO is activated.
> 
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
Mostly good, though I spot a demux in here that definitely shouldn't
be there and connected access to indio_dev->buffer->scan_mask which is
very dangerous as it may well not be the same as indio_dev->active_scan_mask
(which is what controls which data is captured).

This is also true of the original driver trigger handler and a number of
other drivers.  Ooops, I've not been picking up on that in reviews recently
by the look of it.

If anyone is feeling bored a quick grep highlights the buggy drivers...
If not I'll get to it, but isn't that critical as right now, no mainline
driver is using the interface that will cause this issue.

Jonathan
> ---
>  drivers/iio/accel/bmc150-accel.c | 194 ++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 190 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
> index 14509be..0aa3126 100644
> --- a/drivers/iio/accel/bmc150-accel.c
> +++ b/drivers/iio/accel/bmc150-accel.c
> @@ -67,7 +67,9 @@
>  #define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE	BIT(2)
>  
>  #define BMC150_ACCEL_REG_INT_MAP_1		0x1A
> -#define BMC150_ACCEL_INT_MAP_1_BIT_DATA	BIT(0)
> +#define BMC150_ACCEL_INT_MAP_1_BIT_DATA		BIT(0)
> +#define BMC150_ACCEL_INT_MAP_1_BIT_FWM		BIT(1)
> +#define BMC150_ACCEL_INT_MAP_1_BIT_FFULL	BIT(2)
>  
>  #define BMC150_ACCEL_REG_INT_RST_LATCH		0x21
>  #define BMC150_ACCEL_INT_MODE_LATCH_RESET	0x80
> @@ -80,7 +82,9 @@
>  #define BMC150_ACCEL_INT_EN_BIT_SLP_Z		BIT(2)
>  
>  #define BMC150_ACCEL_REG_INT_EN_1		0x17
> -#define BMC150_ACCEL_INT_EN_BIT_DATA_EN	BIT(4)
> +#define BMC150_ACCEL_INT_EN_BIT_DATA_EN		BIT(4)
> +#define BMC150_ACCEL_INT_EN_BIT_FFULL_EN	BIT(5)
> +#define BMC150_ACCEL_INT_EN_BIT_FWM_EN		BIT(6)
>  
>  #define BMC150_ACCEL_REG_INT_OUT_CTRL		0x20
>  #define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL	BIT(0)
> @@ -119,6 +123,12 @@
>  #define BMC150_ACCEL_AXIS_TO_REG(axis)	(BMC150_ACCEL_REG_XOUT_L + (axis * 2))
>  #define BMC150_AUTO_SUSPEND_DELAY_MS		2000
>  
> +#define BMC150_ACCEL_REG_FIFO_STATUS		0x0E
> +#define BMC150_ACCEL_REG_FIFO_CONFIG0		0x30
> +#define BMC150_ACCEL_REG_FIFO_CONFIG1		0x3E
> +#define BMC150_ACCEL_REG_FIFO_DATA		0x3F
> +#define BMC150_ACCEL_FIFO_LENGTH		32
> +
>  enum bmc150_accel_axis {
>  	AXIS_X,
>  	AXIS_Y,
> @@ -161,6 +171,7 @@ struct bmc150_accel_trigger {
>  	struct bmc150_accel_data *data;
>  	struct iio_trigger *indio_trig;
>  	bool enabled;
> +	int (*setup)(struct bmc150_accel_trigger *t, bool state);
>  };
>  
>  struct bmc150_accel_event {
> @@ -180,8 +191,8 @@ struct bmc150_accel_event {
>  	};
>  };
>  
> -#define BMC150_ACCEL_INTERRUPTS		2
> -#define BMC150_ACCEL_TRIGGERS		2
> +#define BMC150_ACCEL_INTERRUPTS		3
> +#define BMC150_ACCEL_TRIGGERS		3
>  #define BMC150_ACCEL_EVENTS		1
>  
>  struct bmc150_accel_data {
> @@ -191,6 +202,7 @@ struct bmc150_accel_data {
>  	struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
>  	struct bmc150_accel_event events[BMC150_ACCEL_EVENTS];
>  	struct mutex mutex;
> +	u8 fifo_mode, watermark;
>  	s16 buffer[8];
>  	u8 bw_bits;
>  	u32 range;
> @@ -484,6 +496,12 @@ bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = {
>  			BMC150_ACCEL_INT_EN_BIT_SLP_Y |
>  			BMC150_ACCEL_INT_EN_BIT_SLP_Z
>  	},
> +	{ /* fifo watermark interrupt */
> +		.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
> +		.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FWM,
> +		.en_reg = BMC150_ACCEL_REG_INT_EN_1,
> +		.en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
> +	},
>  };
>  
>  static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
> @@ -1020,6 +1038,8 @@ static const struct iio_info bmc150_accel_info = {
>  	.driver_module		= THIS_MODULE,
>  };
>  
> +static int bmc150_accel_fifo_flush(struct iio_dev *indio_dev);
> +
>  static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
>  {
>  	struct iio_poll_func *pf = p;
> @@ -1027,6 +1047,12 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
>  	struct bmc150_accel_data *data = iio_priv(indio_dev);
>  	int bit, ret, i = 0;
>  
> +	if (data->fifo_mode) {
> +		bmc150_accel_fifo_flush(indio_dev);
When you flush here, you want to get the best possible timestamp as close
to the interrupt as possible.  Perhaps even in the top half interrupt
handler - then pass it through to here...
> +		iio_trigger_notify_done(indio_dev->trig);
> +		return IRQ_HANDLED;
> +	}
> +
>  	mutex_lock(&data->mutex);
>  	for_each_set_bit(bit, indio_dev->buffer->scan_mask,
>  			 indio_dev->masklength) {
> @@ -1088,6 +1114,14 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig,
>  		return 0;
>  	}
>  
> +	if (t->setup) {
> +		ret = t->setup(t, state);
> +		if (ret < 0) {
> +			mutex_unlock(&data->mutex);
> +			return ret;
> +		}
> +	}
> +
>  	ret = bmc150_accel_set_interrupt(data, t->intr, state);
>  	if (ret < 0) {
>  		mutex_unlock(&data->mutex);
> @@ -1208,9 +1242,12 @@ static int bmc150_accel_gpio_probe(struct i2c_client *client,
>  	return ret;
>  }
>  
> +static int bmc150_accel_fifo_setup(struct bmc150_accel_trigger *t, bool state);
> +
>  static struct {
>  	int intr;
>  	const char *name;
> +	int (*setup)(struct bmc150_accel_trigger *t, bool state);
>  } bmc150_accel_triggers[BMC150_ACCEL_TRIGGERS] = {
>  	{
>  		.intr = 0,
> @@ -1220,6 +1257,11 @@ static struct {
>  		.intr = 1,
>  		.name = "%s-any-motion-dev%d",
>  	},
> +	{
> +		.intr = 2,
> +		.name = "%s-watermark-dev%d",
> +		.setup = bmc150_accel_fifo_setup,
> +	},
>  };
>  
>  static void bmc150_accel_unregister_triggers(struct bmc150_accel_data *data,
> @@ -1257,6 +1299,7 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
>  		t->indio_trig->ops = &bmc150_accel_trigger_ops;
>  		t->intr = &data->interrupts[intr];
>  		t->data = data;
> +		t->setup = bmc150_accel_triggers[i].setup;
>  		iio_trigger_set_drvdata(t->indio_trig, t);
>  
>  		ret = iio_trigger_register(t->indio_trig);
> @@ -1302,6 +1345,143 @@ static void bmc150_accel_events_setup(struct iio_dev *indio_dev,
>  	}
>  }
>  
> +static int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val)
> +
> +{
> +	struct bmc150_accel_data *data = iio_priv(indio_dev);
> +	u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG0;
> +	int ret;
> +
> +	if (val > BMC150_ACCEL_FIFO_LENGTH)
> +		return -EINVAL;
> +
> +	ret = i2c_smbus_write_byte_data(data->client, reg, val);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev, "Error writing reg_fifo_config0\n");
> +		return ret;
> +	}
> +
> +	data->watermark = val;
> +
> +	return 0;
> +}
> +
> +
> +static int bmc150_accel_fifo_flush(struct iio_dev *indio_dev)
> +{
> +	struct bmc150_accel_data *data = iio_priv(indio_dev);
> +	int ret, i;
> +	u8 count;
> +	u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3];
> +	u8 reg_fifo_data = BMC150_ACCEL_REG_FIFO_DATA;
> +	struct i2c_msg msg[2];
> +	int64_t tstamp;
> +	int sample_freq = 0, sec, ms;
> +
> +	ret = bmc150_accel_get_bw(data, &sec, &ms);
> +	if (ret == IIO_VAL_INT_PLUS_MICRO)
> +		sample_freq = sec * 1000000000 + ms * 1000;
> +
> +	ret = i2c_smbus_read_byte_data(data->client,
> +				       BMC150_ACCEL_REG_FIFO_STATUS);
> +	if (ret < 0) {
> +		dev_err(&indio_dev->dev, "Error reading reg_fifo_status\n");
> +		return ret;
> +	}
> +
> +	count = ret & 0x7F;
> +
> +	if (!count)
> +		return 0;
> +
> +	msg[0].addr = data->client->addr;
> +	msg[0].flags = 0;
> +	msg[0].buf = &reg_fifo_data;
> +	msg[0].len = sizeof(reg_fifo_data);
> +
> +	msg[1].addr = data->client->addr;
> +	msg[1].flags = I2C_M_RD;
> +	msg[1].buf = (u8 *)buffer;
> +	msg[1].len = count * 3 * 2;
> +
> +	ret = i2c_transfer(data->client->adapter, msg, 2);
> +	if (ret != 2) {
> +		dev_err(&indio_dev->dev, "Error reading reg_fifo_data\n");
> +		return ret;
> +	}
> +
> +	if (!data->timestamp)
> +		data->timestamp = iio_get_time_ns();
As this is on the flush rather than an interrupt these are going
to be of dubious benefit... There isn't an obvious way of doing better though
unless we do have an interrupt.  In that case you want to grab them as
early as possible (typically even in the interrupt top half) and pass it
down to where you want to use it.
> +
> +	tstamp = data->timestamp - count * sample_freq;
> +
> +	for (i = 0; i < count; i++) {
> +		u16 sample[8];
> +		int j, bit;
> +
> +		j = 0;
> +		for_each_set_bit(bit, indio_dev->buffer->scan_mask,
> +				 indio_dev->masklength) {
> +			memcpy(&sample[j++], &buffer[i * 3 + bit], 2);
> +		}

A local demux rather than using the main iio one. Given you clearly read the
lot anyway is there any reason not to just pass it all on and let the IIO
demux handling the demux on the way to the kfifo?

There should be no access to the buffer scan_mask by drivers.

They should only see the indio_dev->active_scan_mask (they may well not
be the same due to client devices).

> +
> +		iio_push_to_buffers_with_timestamp(indio_dev, sample, tstamp);
> +
> +		tstamp += sample_freq;
> +	}
> +
> +	data->timestamp = 0;
> +
> +	return 0;
> +}
> +
> +static int bmc150_accel_fifo_mode_set(struct bmc150_accel_data *data)
> +{
> +	u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1;
> +	int ret;
> +
> +	ret = i2c_smbus_read_byte_data(data->client, reg);
> +
> +	/* writting the fifo config discards FIFO data - avoid it if possible */
Strikes me that caching the values of some registers would be a good idea
- probably by using regmap to handle it.   Still a job for another day.

> +	if (ret == data->fifo_mode)
> +		return 0;
> +
> +	ret = i2c_smbus_write_byte_data(data->client, reg, data->fifo_mode);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev, "Error writing reg_fifo_config1\n");
> +		return ret;
> +	}
> +
> +	if (!data->fifo_mode)
> +		return 0;
> +
> +	/* we can set the the watermark value only after FIFO is enabled */
> +	ret = i2c_smbus_write_byte_data(data->client,
> +					BMC150_ACCEL_REG_FIFO_CONFIG0,
> +					data->watermark);
> +
> +	if (ret < 0)
> +		dev_err(&data->client->dev, "Error writing reg_fifo_config0\n");
> +
> +	return ret;
> +}
> +
> +static int bmc150_accel_fifo_setup(struct bmc150_accel_trigger *t, bool state)
> +{
> +	if (state)
a #define for the magic 0x40 perhaps?
> +		t->data->fifo_mode = 0x40;
> +	else
> +		t->data->fifo_mode = 0;
> +
> +	return bmc150_accel_fifo_mode_set(t->data);
> +}
> +
> +const struct iio_hwfifo bmc150_accel_hwfifo = {
> +	.length = BMC150_ACCEL_FIFO_LENGTH,
> +	.set_watermark = bmc150_accel_set_watermark,
> +	.flush = bmc150_accel_fifo_flush,
> +};
> +
>  static int bmc150_accel_probe(struct i2c_client *client,
>  			      const struct i2c_device_id *id)
>  {
> @@ -1387,6 +1567,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
>  				"Failed: iio triggered buffer setup\n");
>  			goto err_trigger_unregister;
>  		}
> +
> +		indio_dev->hwfifo = &bmc150_accel_hwfifo;
>  	}
>  
>  	ret = iio_device_register(indio_dev);
> @@ -1458,6 +1640,7 @@ static int bmc150_accel_resume(struct device *dev)
>  	mutex_lock(&data->mutex);
>  	if (atomic_read(&data->active_intr))
>  		bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
> +	bmc150_accel_fifo_mode_set(data);
>  	mutex_unlock(&data->mutex);
>  
>  	return 0;
> @@ -1487,6 +1670,9 @@ static int bmc150_accel_runtime_resume(struct device *dev)
>  	ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
>  	if (ret < 0)
>  		return ret;
> +	ret = bmc150_accel_fifo_mode_set(data);
> +	if (ret < 0)
> +		return ret;
>  
>  	sleep_val = bmc150_accel_get_startup_times(data);
>  	if (sleep_val < 20)
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 02/11] iio: buffer: refactor buffer attributes setup
  2015-01-04 11:31   ` Jonathan Cameron
@ 2015-01-05 10:48     ` Octavian Purdila
  0 siblings, 0 replies; 50+ messages in thread
From: Octavian Purdila @ 2015-01-05 10:48 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio

On Sun, Jan 4, 2015 at 9:31 PM, Jonathan Cameron <jic23@kernel.org> wrote:
> On 21/12/14 00:42, Octavian Purdila wrote:
>> Move all core (non-cusotm) buffer attributes to a vector to make it
> custom
>> easier to add more of them in the future.
>>
>> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
>
> A sensible tidy up.

Can you fix-up the commit message for me, or would you prefer a new
patch? I am travelling for the next two weeks with limited internet
access, so it might take a while to get to it.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 04/11] iio: add support for hardware fifo
  2015-01-04 16:07   ` Jonathan Cameron
@ 2015-01-05 11:29     ` Octavian Purdila
  2015-02-04 17:08       ` Jonathan Cameron
  0 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2015-01-05 11:29 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio

On Mon, Jan 5, 2015 at 2:07 AM, Jonathan Cameron <jic23@kernel.org> wrote:
> On 21/12/14 00:42, Octavian Purdila wrote:
>
> Thanks for taking this on!
>
> This all looks fairly sensible, though a few comments inline.
> One big semantic change I'd suggest is to allow the watermark
> level passed to the hardware to be a 'hint' rather than a hard
> and fast rull.  A lot of these hardware buffers are fairly small
> (perhaps 32 entries) and the devices can run fast so whilst
> we will obviously have to handle an interrupt often, we may well
> want to have a much larger software front end buffer with a
> much larger watermark.  For example, a 8192Hz accelerometer
> with 32 entry fifo (watermark at 16).  Will fire an interrupt 512 times
> a second.  Userspace might be only interested in getting data 32 times
> a second and hence want a watermark of 256 entries and probably have
> a buffer that is 512 entries long or more.
>

Very good point with the above example, but I find the hint approach a
bit too hard to diagnose and tune by the application.

Could we perhaps expose the hwfifo watermark as well, in addition to
the software watermark? We can even keep the hint behavior if the
application only touches the software watermark, but if it the
application directly sets the hwfifo level then we use that.

>> Some devices have hardware buffers that can store a number of samples
>> for later consumption. Hardware usually provides interrupts to notify
>> the processor when the fifo is full or when it has reached a certain
>> threshold. This helps with reducing the number of interrupts to the
>> host processor and thus it helps decreasing the power consumption.
>>
>> This patch adds support for hardware fifo to IIO by allowing the
>> drivers to register operations for flushing the hadware fifo and
>> setting the watermark level.
>
> Perhaps put something in here to observe that this is a different approach
> to the straight hardware buffer stuff we already have - of most interest
> for hybrid buffering rather than a pure hardware buffer.
>

Will do.

>>
>> A driver implementing hardware fifo support must also provide a
>> watermark trigger which must contain "watermark" in its name.
>>
>> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
>> ---
>>  Documentation/ABI/testing/sysfs-bus-iio | 22 +++++++++++++++++
>>  drivers/iio/industrialio-buffer.c       | 44 ++++++++++++++++++++++++++++-----
>>  include/linux/iio/iio.h                 | 17 +++++++++++++
>>  3 files changed, 77 insertions(+), 6 deletions(-)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
>> index 7260f1f..6bb67ac 100644
>> --- a/Documentation/ABI/testing/sysfs-bus-iio
>> +++ b/Documentation/ABI/testing/sysfs-bus-iio
>> @@ -1152,3 +1152,25 @@ Description:
>>               Poll will block until the watermark is reached.
>>               Blocking read will wait until the minimum between the requested
>>               read amount or the low water mark is available.
>> +             If the device has a hardware fifo this value is going to be used
>> +             for the hardware fifo watermark as well.
>
> I'd make this a litle vaguer (deliberately ;).   Perhaps used as a 'hint'
> for the hardware fifo watermark as well.  The reason being that if we set
> the software watermark at say 20 and the hardware only has 15 fifo entries,
> then we might want to be clever and say set the hardware fifo watershed to 10.
> For now that would be a decision of the hardware driver rather than one for
> the core.

Sure, I'll update the docs with what ever we end-up deciding its best :)

>> +
>> +What:                /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo-length
>> +KernelVersion:       3.20
>> +Contact:     linux-iio@vger.kernel.org
>> +Description:
>> +             A single positive integer specifying the maximum number of
>> +             samples that the hardware fifo has. If the device does not
>> +             support hardware fifo this is zero.
>> +             When a device supports hardware fifo it will expose a trigger
>> +             with the name that contains "watermark"
>> +             (e.g. i2c-BMC150A:00-watermark-dev0).
>> +             To use the hardware fifo the user must set an appropriate value
>> +             in the buffer/length and buffer/low_watermark entries and select
>> +             the watermark trigger. At that poin the hardware fifo will be
> point
>> +             enabled and the samples will be collected in a hardware buffer.
> Hmm. I wonder to a degree if the trigger approach really makes sense for
> fifo equiped devices.  We've deliberately not added one in a few existing
> cases.
>
> Otherwise, is there a reason to run this separately from a trigger not using
> the fifo.  Surely that's just the same as a watermark of 1?
>
> Anyhow, a point for discussion!

I might be misunderstand you here, but the reason for which we use a
separate trigger is to have a way to enable/disable FIFO mode, because
enabling the FIFO might have some downsides, e.g. more power
consumption. This matters only when the application is interested in
low latency sampling ( watermark of 1).

I don't know if this is really an issue in practice, but I chose the
safe option.

>
>> +             When the number of samples in the hardware fifo reaches the
>> +             watermark level the watermark trigger is issued and data is
>> +             flushed to the devices buffer.
>> +             A hardware buffer flush will also be triggered when reading from
>> +             the device buffer and there is not enough data available.
>> \ No newline at end of file
> Fix this..
>> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
>> index 7f74c7f..3da6d07 100644
>> --- a/drivers/iio/industrialio-buffer.c
>> +++ b/drivers/iio/industrialio-buffer.c
>> @@ -37,9 +37,17 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
>>       return !list_empty(&buf->buffer_list);
>>  }
>>
>> -static size_t iio_buffer_data_available(struct iio_buffer *buf)
>> +static bool iio_buffer_data_available(struct iio_dev *indio_dev,
>> +                                   struct iio_buffer *buf, size_t required)
>>  {
>> -     return buf->access->data_available(buf);
>> +     size_t avail = buf->access->data_available(buf);
>> +
>> +     if (avail < required && indio_dev->hwfifo) {
>> +             indio_dev->hwfifo->flush(indio_dev);
>> +             avail = buf->access->data_available(buf);
>> +     }
>> +
>> +     return avail >= required;
> Does it make sense to move the decision in here?  Could just as easily
> have left this as returning the length and done the logic outside...
> I don't mind that much... However, we probably want to rename the function
> now that it is doing more than strictly querying availability.

I've put it here so that it affects both read and poll so that we
avoid avoid latencies if possible. Will change the name.

>
> Could also have flush take a parameter for what is desired and only read
> that many?  On relatively slow buses might make sense...

Good point, will add that.

>>  /**
>> + * struct iio_buffer_hwfifo_ops - hardware fifo operations
>> + *
>> + * @length:          [DRIVER] the hardware fifo length
>> + * @set_watermark:   [DRIVER] setups the watermark level
>> + * @flush:           [DRIVER] copies data from the hardware buffer to the
>> + *                   device buffer
>> + * @watermark_trig:  [DRIVER] an allocated and registered trigger containing
>> + *                   "watermark" in its name
> err. This last one isn't actually in the structure...

Yeah, I wanted to add some checks in the core to make sure that if the
driver is registering the hwfifo ops then it should allocate and
register a watermark trigger as well. If we decide to go with the
trigger approach, do you think it is a good idea to add the checks?

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 05/11] iio: bmc150: refactor slope duration and threshold update
  2015-01-04 16:21   ` Jonathan Cameron
@ 2015-01-06 18:53     ` Srinivas Pandruvada
  2015-01-28  9:22       ` Octavian Purdila
  0 siblings, 1 reply; 50+ messages in thread
From: Srinivas Pandruvada @ 2015-01-06 18:53 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: Octavian Purdila, linux-iio, Laurentiu Palcu

On Sun, 2015-01-04 at 16:21 +0000, Jonathan Cameron wrote: 
> On 21/12/14 00:42, Octavian Purdila wrote:
> > Move the slope duration and threshold update in separate functions
> > to reduce code duplicate between chip init and motion interrupt setup.
> > 
> > The patch also moves the update from the motion interrupt setup
> > function to the write event function so that we can later refactor the
> > interrupt code.
> The side effect of this is that these will get updated at a different
> point in time from before.  Previously these values would only get
> updated when the event was enabled (or the trigger).  So to change
> them a disable / enable cycle was needed. Now they happen the moment
> they are relevant.
> 
> I prefer the new option, but it is an ABI change (be it one most people
> won't notice!)
I did purposely this way.
IMO when user is changing critical parameters he should disable and re
enable to avoid undesirable side effects. 
We have similar situation in other  thermal drivers where user can
change policy parameters. Initially we let them change while zone is
enabled (system is armed), this led to undesirable side effects due to
race conditions.

Thanks,
Srinivas

> 
> Hence I'd like an Ack from Srinivas and time for comments from others
> before taking this one.
> 
> Otherwise, looks good ;)
> 
> Jonathan
> > 
> > Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> > ---
> >  drivers/iio/accel/bmc150-accel.c | 110 ++++++++++++++++++++++-----------------
> >  1 file changed, 63 insertions(+), 47 deletions(-)
> > 
> > diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
> > index 22c096c..92f1d2b 100644
> > --- a/drivers/iio/accel/bmc150-accel.c
> > +++ b/drivers/iio/accel/bmc150-accel.c
> > @@ -266,6 +266,52 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val,
> >  	return -EINVAL;
> >  }
> >  
> > +static int bmc150_accel_update_slope_threshold(struct bmc150_accel_data *data,
> > +					       int val)
> > +{
> > +	int ret = 0;
> > +
> > +	val &= 0xFF;
> > +
> > +	ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_6,
> > +					val);
> > +	if (ret < 0) {
> > +		dev_err(&data->client->dev, "Error writing reg_int_6\n");
> > +		return ret;
> > +	}
> > +	data->slope_thres = val;
> > +
> > +	dev_dbg(&data->client->dev, "%s: %x\n", __func__, val);
> > +
> > +	return ret;
> > +}
> > +
> > +static int bmc150_accel_update_slope_duration(struct bmc150_accel_data *data,
> > +					      int val)
> > +{
> > +	int ret;
> > +
> > +	val &= BMC150_ACCEL_SLOPE_DUR_MASK;
> > +
> > +	ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5);
> > +	if (ret < 0) {
> > +		dev_err(&data->client->dev, "Error reading reg_int_5\n");
> > +		return ret;
> > +	}
> > +	val |= ret & ~BMC150_ACCEL_SLOPE_DUR_MASK;
> > +	ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_5,
> > +					val);
> > +	if (ret < 0) {
> > +		dev_err(&data->client->dev, "Error write reg_int_5\n");
> > +		return ret;
> > +	}
> > +	data->slope_dur = val;
> > +
> > +	dev_dbg(&data->client->dev, "%s: %x\n", __func__, val);
> > +
> > +	return ret;
> > +}
> > +
> >  static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
> >  {
> >  	int ret;
> > @@ -304,32 +350,16 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
> >  
> >  	data->range = BMC150_ACCEL_DEF_RANGE_4G;
> >  
> > -	/* Set default slope duration */
> > -	ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5);
> > -	if (ret < 0) {
> > -		dev_err(&data->client->dev, "Error reading reg_int_5\n");
> > -		return ret;
> > -	}
> > -	data->slope_dur |= BMC150_ACCEL_DEF_SLOPE_DURATION;
> > -	ret = i2c_smbus_write_byte_data(data->client,
> > -					BMC150_ACCEL_REG_INT_5,
> > -					data->slope_dur);
> > -	if (ret < 0) {
> > -		dev_err(&data->client->dev, "Error writing reg_int_5\n");
> > +	/* Set default slope duration and thresholds */
> > +	ret = bmc150_accel_update_slope_duration(data,
> > +					 BMC150_ACCEL_DEF_SLOPE_DURATION);
> > +	if (ret < 0)
> >  		return ret;
> > -	}
> > -	dev_dbg(&data->client->dev, "slope_dur %x\n", data->slope_dur);
> >  
> > -	/* Set default slope thresholds */
> > -	ret = i2c_smbus_write_byte_data(data->client,
> > -					BMC150_ACCEL_REG_INT_6,
> > -					BMC150_ACCEL_DEF_SLOPE_THRESHOLD);
> > -	if (ret < 0) {
> > -		dev_err(&data->client->dev, "Error writing reg_int_6\n");
> > +	ret = bmc150_accel_update_slope_threshold(data,
> > +					  BMC150_ACCEL_DEF_SLOPE_THRESHOLD);
> > +	if (ret < 0)
> >  		return ret;
> > -	}
> > -	data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD;
> > -	dev_dbg(&data->client->dev, "slope_thres %x\n", data->slope_thres);
> >  
> >  	/* Set default as latched interrupts */
> >  	ret = i2c_smbus_write_byte_data(data->client,
> > @@ -372,24 +402,6 @@ static int bmc150_accel_setup_any_motion_interrupt(
> >  	}
> >  
> >  	if (status) {
> > -		/* Set slope duration (no of samples) */
> > -		ret = i2c_smbus_write_byte_data(data->client,
> > -						BMC150_ACCEL_REG_INT_5,
> > -						data->slope_dur);
> > -		if (ret < 0) {
> > -			dev_err(&data->client->dev, "Error write reg_int_5\n");
> > -			return ret;
> > -		}
> > -
> > -		/* Set slope thresholds */
> > -		ret = i2c_smbus_write_byte_data(data->client,
> > -						BMC150_ACCEL_REG_INT_6,
> > -						data->slope_thres);
> > -		if (ret < 0) {
> > -			dev_err(&data->client->dev, "Error write reg_int_6\n");
> > -			return ret;
> > -		}
> > -
> >  		/*
> >  		 * New data interrupt is always non-latched,
> >  		 * which will have higher priority, so no need
> > @@ -726,7 +738,7 @@ static int bmc150_accel_read_event(struct iio_dev *indio_dev,
> >  		*val = data->slope_thres;
> >  		break;
> >  	case IIO_EV_INFO_PERIOD:
> > -		*val = data->slope_dur & BMC150_ACCEL_SLOPE_DUR_MASK;
> > +		*val = data->slope_dur;
> >  		break;
> >  	default:
> >  		return -EINVAL;
> > @@ -743,23 +755,27 @@ static int bmc150_accel_write_event(struct iio_dev *indio_dev,
> >  				    int val, int val2)
> >  {
> >  	struct bmc150_accel_data *data = iio_priv(indio_dev);
> > +	int ret;
> >  
> >  	if (data->ev_enable_state)
> >  		return -EBUSY;
> >  
> >  	switch (info) {
> >  	case IIO_EV_INFO_VALUE:
> > -		data->slope_thres = val;
> > +		mutex_lock(&data->mutex);
> > +		ret = bmc150_accel_update_slope_threshold(data, val);
> > +		mutex_unlock(&data->mutex);
> >  		break;
> >  	case IIO_EV_INFO_PERIOD:
> > -		data->slope_dur &= ~BMC150_ACCEL_SLOPE_DUR_MASK;
> > -		data->slope_dur |= val & BMC150_ACCEL_SLOPE_DUR_MASK;
> > +		mutex_lock(&data->mutex);
> > +		ret = bmc150_accel_update_slope_duration(data, val);
> > +		mutex_unlock(&data->mutex);
> >  		break;
> >  	default:
> > -		return -EINVAL;
> > +		ret = -EINVAL;
> >  	}
> >  
> > -	return 0;
> > +	return ret;
> >  }
> >  
> >  static int bmc150_accel_read_event_config(struct iio_dev *indio_dev,
> > 
> 

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 03/11] iio: add watermark logic to iio read and poll
  2014-12-21  0:42 ` [PATCH v2 03/11] iio: add watermark logic to iio read and poll Octavian Purdila
  2015-01-04 15:44   ` Jonathan Cameron
@ 2015-01-25 21:22   ` Hartmut Knaack
  2015-01-26  9:40     ` Octavian Purdila
  1 sibling, 1 reply; 50+ messages in thread
From: Hartmut Knaack @ 2015-01-25 21:22 UTC (permalink / raw)
  To: Octavian Purdila, linux-iio; +Cc: Josselin Costanzi

Octavian Purdila schrieb am 21.12.2014 um 01:42:
> From: Josselin Costanzi <josselin.costanzi@mobile-devices.fr>
> 
> Currently the IIO buffer blocking read only wait until at least one
> data element is available.
> This patch makes the reader sleep until enough data is collected before
> returning to userspace. This should limit the read() calls count when
> trying to get data in batches.
> 

Hi,
I have a question and a minor recommendation, please see inline.

> Co-author: Yannick Bedhomme <yannick.bedhomme@mobile-devices.fr>
> Signed-off-by: Josselin Costanzi <josselin.costanzi@mobile-devices.fr>
> [rebased and remove buffer timeout]
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> ---
>  Documentation/ABI/testing/sysfs-bus-iio  |  10 +++
>  drivers/iio/industrialio-buffer.c        | 114 ++++++++++++++++++++++++++-----
>  drivers/iio/kfifo_buf.c                  |  11 ++-
>  drivers/staging/iio/accel/sca3000_ring.c |   4 +-
>  include/linux/iio/buffer.h               |   9 ++-
>  5 files changed, 118 insertions(+), 30 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index df5e69e..7260f1f 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -1142,3 +1142,13 @@ Contact:	linux-iio@vger.kernel.org
>  Description:
>  		This attribute is used to read the number of steps taken by the user
>  		since the last reboot while activated.
> +
> +What:		/sys/bus/iio/devices/iio:deviceX/buffer/low_watermark
> +KernelVersion:	3.20
> +Contact:	linux-iio@vger.kernel.org
> +Description:
> +		A single positive integer specifying the maximum number of scan
> +		elements to wait for.
> +		Poll will block until the watermark is reached.
> +		Blocking read will wait until the minimum between the requested
> +		read amount or the low water mark is available.
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index bc55434..7f74c7f 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -37,7 +37,7 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
>  	return !list_empty(&buf->buffer_list);
>  }
>  
> -static bool iio_buffer_data_available(struct iio_buffer *buf)
> +static size_t iio_buffer_data_available(struct iio_buffer *buf)
>  {
>  	return buf->access->data_available(buf);
>  }
> @@ -53,6 +53,9 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
>  {
>  	struct iio_dev *indio_dev = filp->private_data;
>  	struct iio_buffer *rb = indio_dev->buffer;
> +	size_t datum_size = rb->bytes_per_datum;
> +	size_t to_read = min_t(size_t, n / datum_size, rb->low_watermark);
Are you sure that rb->bytes_per_datum can not be zero, when accessed here? From
what I could see, there is a chance of it being zero, if the scan_mask is clear
and timestamps are disabled.

> +	size_t count = 0;
>  	int ret;
>  
>  	if (!indio_dev->info)
> @@ -62,25 +65,38 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
>  		return -EINVAL;
>  
>  	do {
> -		if (!iio_buffer_data_available(rb)) {
> -			if (filp->f_flags & O_NONBLOCK)
> -				return -EAGAIN;
> -
> +		if (filp->f_flags & O_NONBLOCK) {
> +			if (!iio_buffer_data_available(rb)) {
> +				ret = -EAGAIN;
> +				break;
> +			}
> +		} else {
>  			ret = wait_event_interruptible(rb->pollq,
> -					iio_buffer_data_available(rb) ||
> -					indio_dev->info == NULL);
> +			       iio_buffer_data_available(rb) >= to_read ||
> +						       indio_dev->info == NULL);
>  			if (ret)
>  				return ret;
> -			if (indio_dev->info == NULL)
> -				return -ENODEV;
> +			if (indio_dev->info == NULL) {
> +				ret = -ENODEV;
> +				break;
> +			}
>  		}
>  
> -		ret = rb->access->read_first_n(rb, n, buf);
> -		if (ret == 0 && (filp->f_flags & O_NONBLOCK))
> -			ret = -EAGAIN;
> -	 } while (ret == 0);
> +		ret = rb->access->read_first_n(rb, n, buf + count);
> +		if (ret < 0)
> +			break;
>  
> -	return ret;
> +		count += ret;
> +		n -= ret;
> +		to_read -= ret / datum_size;
> +	 } while (to_read > 0);
> +
> +	if (count)
> +		return count;
> +	if (ret < 0)
> +		return ret;
> +
> +	return -EAGAIN;
>  }
>  
>  /**
> @@ -96,9 +112,8 @@ unsigned int iio_buffer_poll(struct file *filp,
>  		return -ENODEV;
>  
>  	poll_wait(filp, &rb->pollq, wait);
> -	if (iio_buffer_data_available(rb))
> +	if (iio_buffer_data_available(rb) >= rb->low_watermark)
>  		return POLLIN | POLLRDNORM;
> -	/* need a way of knowing if there may be enough data... */
>  	return 0;
>  }
>  
> @@ -123,6 +138,7 @@ void iio_buffer_init(struct iio_buffer *buffer)
>  	INIT_LIST_HEAD(&buffer->buffer_list);
>  	init_waitqueue_head(&buffer->pollq);
>  	kref_init(&buffer->ref);
> +	buffer->low_watermark = 1;
>  }
>  EXPORT_SYMBOL(iio_buffer_init);
>  
> @@ -418,7 +434,16 @@ static ssize_t iio_buffer_write_length(struct device *dev,
>  	}
>  	mutex_unlock(&indio_dev->mlock);
>  
> -	return ret ? ret : len;
> +	if (ret)
> +		return ret;
> +
> +	if (buffer->length)
> +		val = buffer->length;
> +
> +	if (val < buffer->low_watermark)
> +		buffer->low_watermark = val;
> +
> +	return len;
>  }
>  
>  static ssize_t iio_buffer_show_enable(struct device *dev,
> @@ -472,6 +497,7 @@ static void iio_buffer_activate(struct iio_dev *indio_dev,
>  static void iio_buffer_deactivate(struct iio_buffer *buffer)
>  {
>  	list_del_init(&buffer->buffer_list);
> +	wake_up_interruptible(&buffer->pollq);
>  	iio_buffer_put(buffer);
>  }
>  
> @@ -752,16 +778,59 @@ done:
>  
>  static const char * const iio_scan_elements_group_name = "scan_elements";
>  
> +static ssize_t iio_buffer_show_watermark(struct device *dev,
> +					 struct device_attribute *attr,
> +					 char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct iio_buffer *buffer = indio_dev->buffer;
> +
> +	return sprintf(buf, "%u\n", buffer->low_watermark);
> +}
> +
> +static ssize_t iio_buffer_store_watermark(struct device *dev,
> +					  struct device_attribute *attr,
> +					  const char *buf,
> +					  size_t len)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct iio_buffer *buffer = indio_dev->buffer;
> +	unsigned int val;
> +	int ret;
> +
> +	ret = kstrtouint(buf, 10, &val);
> +	if (ret)
> +		return ret;
> +
> +	if (val > buffer->length)
> +		return -EINVAL;
> +
> +	mutex_lock(&indio_dev->mlock);
> +	if (iio_buffer_is_active(indio_dev->buffer)) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	buffer->low_watermark = val;
> +	ret = 0;
> +out:
> +	mutex_unlock(&indio_dev->mlock);
> +	return ret ? ret : len;
> +}
> +
>  static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
>  		   iio_buffer_write_length);
>  static struct device_attribute dev_attr_length_ro = __ATTR(length,
>  	S_IRUGO, iio_buffer_read_length, NULL);
>  static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
>  		   iio_buffer_show_enable, iio_buffer_store_enable);
> +static DEVICE_ATTR(low_watermark, S_IRUGO | S_IWUSR,
> +		   iio_buffer_show_watermark, iio_buffer_store_watermark);
>  
>  static struct attribute *iio_buffer_attrs[] = {
>  	&dev_attr_length.attr,
>  	&dev_attr_enable.attr,
> +	&dev_attr_low_watermark.attr,
>  };
>  
>  int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
> @@ -942,8 +1011,17 @@ static const void *iio_demux(struct iio_buffer *buffer,
>  static int iio_push_to_buffer(struct iio_buffer *buffer, const void *data)
>  {
>  	const void *dataout = iio_demux(buffer, data);
> +	int ret;
>  
> -	return buffer->access->store_to(buffer, dataout);
> +	ret = buffer->access->store_to(buffer, dataout);
> +	if (ret)
> +		return ret;
> +
> +	/* We can't just test for watermark to decide if we wake the poll queue
> +	 * because read may request less samples than the watermark
I think this comment could end with a full stop. Also, first line should be
empty.

> +	 */
> +	wake_up_interruptible(&buffer->pollq);
> +	return 0;
>  }
>  
>  static void iio_buffer_demux_free(struct iio_buffer *buffer)
> diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c
> index b20a9cf..30a9bfa 100644
> --- a/drivers/iio/kfifo_buf.c
> +++ b/drivers/iio/kfifo_buf.c
> @@ -83,9 +83,6 @@ static int iio_store_to_kfifo(struct iio_buffer *r,
>  	ret = kfifo_in(&kf->kf, data, 1);
>  	if (ret != 1)
>  		return -EBUSY;
> -
> -	wake_up_interruptible_poll(&r->pollq, POLLIN | POLLRDNORM);
> -
>  	return 0;
>  }
>  
> @@ -109,16 +106,16 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
>  	return copied;
>  }
>  
> -static bool iio_kfifo_buf_data_available(struct iio_buffer *r)
> +static size_t iio_kfifo_buf_data_available(struct iio_buffer *r)
>  {
>  	struct iio_kfifo *kf = iio_to_kfifo(r);
> -	bool empty;
> +	size_t samples;
>  
>  	mutex_lock(&kf->user_lock);
> -	empty = kfifo_is_empty(&kf->kf);
> +	samples = kfifo_len(&kf->kf);
>  	mutex_unlock(&kf->user_lock);
>  
> -	return !empty;
> +	return samples;
>  }
>  
>  static void iio_kfifo_buffer_release(struct iio_buffer *buffer)
> diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c
> index f76a268..1e65dea 100644
> --- a/drivers/staging/iio/accel/sca3000_ring.c
> +++ b/drivers/staging/iio/accel/sca3000_ring.c
> @@ -129,9 +129,9 @@ error_ret:
>  	return ret ? ret : num_read;
>  }
>  
> -static bool sca3000_ring_buf_data_available(struct iio_buffer *r)
> +static size_t sca3000_ring_buf_data_available(struct iio_buffer *r)
>  {
> -	return r->stufftoread;
> +	return r->stufftoread ? r->low_watermark : 0;
>  }
>  
>  /**
> diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
> index b65850a..768593c 100644
> --- a/include/linux/iio/buffer.h
> +++ b/include/linux/iio/buffer.h
> @@ -21,8 +21,8 @@ struct iio_buffer;
>   * struct iio_buffer_access_funcs - access functions for buffers.
>   * @store_to:		actually store stuff to the buffer
>   * @read_first_n:	try to get a specified number of bytes (must exist)
> - * @data_available:	indicates whether data for reading from the buffer is
> - *			available.
> + * @data_available:	indicates how much data is available for reading from
> + *			the buffer.
>   * @request_update:	if a parameter change has been marked, update underlying
>   *			storage.
>   * @set_bytes_per_datum:set number of bytes per datum
> @@ -43,7 +43,7 @@ struct iio_buffer_access_funcs {
>  	int (*read_first_n)(struct iio_buffer *buffer,
>  			    size_t n,
>  			    char __user *buf);
> -	bool (*data_available)(struct iio_buffer *buffer);
> +	size_t (*data_available)(struct iio_buffer *buffer);
>  
>  	int (*request_update)(struct iio_buffer *buffer);
>  
> @@ -72,6 +72,8 @@ struct iio_buffer_access_funcs {
>   * @demux_bounce:	[INTERN] buffer for doing gather from incoming scan.
>   * @buffer_list:	[INTERN] entry in the devices list of current buffers.
>   * @ref:		[INTERN] reference count of the buffer.
> + * @low_watermark:	[INTERN] number of datums for poll/blocking read to
> + * 			wait for.
>   */
>  struct iio_buffer {
>  	int					length;
> @@ -90,6 +92,7 @@ struct iio_buffer {
>  	void					*demux_bounce;
>  	struct list_head			buffer_list;
>  	struct kref				ref;
> +	unsigned int				low_watermark;
>  };
>  
>  /**
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 03/11] iio: add watermark logic to iio read and poll
  2015-01-25 21:22   ` Hartmut Knaack
@ 2015-01-26  9:40     ` Octavian Purdila
  0 siblings, 0 replies; 50+ messages in thread
From: Octavian Purdila @ 2015-01-26  9:40 UTC (permalink / raw)
  To: Hartmut Knaack; +Cc: linux-iio, Josselin Costanzi

On Sun, Jan 25, 2015 at 11:22 PM, Hartmut Knaack <knaack.h@gmx.de> wrote:
>
> Octavian Purdila schrieb am 21.12.2014 um 01:42:
> > From: Josselin Costanzi <josselin.costanzi@mobile-devices.fr>
> >
> > Currently the IIO buffer blocking read only wait until at least one
> > data element is available.
> > This patch makes the reader sleep until enough data is collected before
> > returning to userspace. This should limit the read() calls count when
> > trying to get data in batches.
> >
>
> Hi,
> I have a question and a minor recommendation, please see inline.
>

Thanks for looking at this.

Any feedback on the hardware buffer stuff? We are still trying to find
the right ABIs. I did not get feedback after my last reply, did it got
lost?

<snip>

> >       struct iio_dev *indio_dev = filp->private_data;
> >       struct iio_buffer *rb = indio_dev->buffer;
> > +     size_t datum_size = rb->bytes_per_datum;
> > +     size_t to_read = min_t(size_t, n / datum_size, rb->low_watermark);
> Are you sure that rb->bytes_per_datum can not be zero, when accessed here? From
> what I could see, there is a chance of it being zero, if the scan_mask is clear
> and timestamps are disabled.
>

Good catch, I will fix that.

> > +
> > +     /* We can't just test for watermark to decide if we wake the poll queue
> > +      * because read may request less samples than the watermark
> I think this comment could end with a full stop. Also, first line should be
> empty.
>

Correct.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 05/11] iio: bmc150: refactor slope duration and threshold update
  2015-01-06 18:53     ` Srinivas Pandruvada
@ 2015-01-28  9:22       ` Octavian Purdila
  2015-01-28 17:15         ` Srinivas Pandruvada
  0 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2015-01-28  9:22 UTC (permalink / raw)
  To: Srinivas Pandruvada; +Cc: Jonathan Cameron, linux-iio, Laurentiu Palcu

On Tue, Jan 6, 2015 at 8:53 PM, Srinivas Pandruvada
<srinivas.pandruvada@linux.intel.com> wrote:
>
> On Sun, 2015-01-04 at 16:21 +0000, Jonathan Cameron wrote:
> > On 21/12/14 00:42, Octavian Purdila wrote:
> > > Move the slope duration and threshold update in separate functions
> > > to reduce code duplicate between chip init and motion interrupt setup.
> > >
> > > The patch also moves the update from the motion interrupt setup
> > > function to the write event function so that we can later refactor the
> > > interrupt code.
> > The side effect of this is that these will get updated at a different
> > point in time from before.  Previously these values would only get
> > updated when the event was enabled (or the trigger).  So to change
> > them a disable / enable cycle was needed. Now they happen the moment
> > they are relevant.
> >
> > I prefer the new option, but it is an ABI change (be it one most people
> > won't notice!)
> I did purposely this way.
> IMO when user is changing critical parameters he should disable and re
> enable to avoid undesirable side effects.
> We have similar situation in other  thermal drivers where user can
> change policy parameters. Initially we let them change while zone is
> enabled (system is armed), this led to undesirable side effects due to
> race conditions.
>

We already have a check that prevents the change while the event is
active. We could add a check for the data motion trigger as well, to
avoid the above scenario.

Alternatively I can rewrite the patch to keep the current behavior and
update the parameters when we enable the trigger.

Which one sounds better?

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 06/11] iio: bmc150: refactor interrupt enabling
  2015-01-04 16:27   ` Jonathan Cameron
@ 2015-01-28 10:33     ` Octavian Purdila
  0 siblings, 0 replies; 50+ messages in thread
From: Octavian Purdila @ 2015-01-28 10:33 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio

On Sun, Jan 4, 2015 at 6:27 PM, Jonathan Cameron <jic23@kernel.org> wrote:
> On 21/12/14 00:42, Octavian Purdila wrote:
>> This patch combines the any motion and new data interrupts function
>> into a single, generic, interrupt enable function. On top of this, we
>> can later refactor triggers to make it easier to add new triggers.
>>
>> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> Some really trivial suggests inline.  Looks good even without it being
> useful for later stuff ;)
>> ---
>>  drivers/iio/accel/bmc150-accel.c | 269 ++++++++++++++++-----------------------
>>  1 file changed, 113 insertions(+), 156 deletions(-)
>>
>> diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
>> index 92f1d2b..53d1d1d 100644
>> --- a/drivers/iio/accel/bmc150-accel.c
>> +++ b/drivers/iio/accel/bmc150-accel.c
>> @@ -144,6 +144,13 @@ struct bmc150_accel_chip_info {
>>       const struct bmc150_scale_info scale_table[4];
>>  };
>>
> I'd be tempted to define this at the place where you fill them below...

Done.

<snip>

>> +
>> +static int bmc150_accel_setup_any_motion_interrupt(
>> +                                     struct bmc150_accel_data *data,
>> +                                     bool status)
>> +{
>> +     return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[1],
> Maybe define a matching enum so the indexes are obvious.
> Then is there a lot of point in having these wrappers? I'd just call
> it directly so you'd get something like.
>

The wrappers go away in one of the subsequent patches. I have kept
them here for now to make the review a bit simpler.

In another subsequent patch the interrupts are integrated to the
trigger structure and with that we can remove the ugly indexes as
well.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 08/11] iio: bmc150: introduce bmc150_accel_interrupt
  2015-01-04 16:36   ` Jonathan Cameron
@ 2015-01-28 11:09     ` Octavian Purdila
  2015-01-28 13:20       ` Jonathan Cameron
  0 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2015-01-28 11:09 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio

On Sun, Jan 4, 2015 at 6:36 PM, Jonathan Cameron <jic23@kernel.org> wrote:
> On 21/12/14 00:42, Octavian Purdila wrote:
>> Since both triggers and events can share an interrupt, add a data
>> structure that tracks the users of an interrupt so that it enables or
>> disables it only for the first users and respectively last user.
>>
>> This will allows us to easily add more events or triggers.
>>
>> The patch also adds an interrupt enabled counter, so that we can
>> easily know if we need to put the device in normal mode when the
>> resume callback is issued.
>>
>> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> This is probably the cleanest way of doing this, but an alternative is
> to register an interrupt chip and then you can have each interrupt source
> (internal to the device) have it's own interrupt and register as if
> it had direct access (rather than having to read what interrupt occured
> first).  This is the preferred method these days for MFDs where this
> tree structure of interrupts is common.
>
> I think that would result in slightly more code though, so perhaps this
> local version of some of that infrastructure is fine.
>

Good to know about the interrupt chip approach. I also think in this
case the local version is better.

But if we see a common pattern across multiple drivers, perhaps we can
add the interrupt chip to the IIO core for those drivers that want to
make use of it. I'll take a look, but on the top of your head, do you
know of any drivers for this would be useful?

>> ---
>>  drivers/iio/accel/bmc150-accel.c | 87 +++++++++++++++++++++-------------------
>>  1 file changed, 45 insertions(+), 42 deletions(-)
>>
>> diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
>> index aaad2fb..7c905f6 100644
>> --- a/drivers/iio/accel/bmc150-accel.c
>> +++ b/drivers/iio/accel/bmc150-accel.c
>> @@ -151,10 +151,19 @@ struct bmc150_accel_interrupt_info {
>>       u8 en_bitmask;
>>  };
>>
>> +struct bmc150_accel_interrupt {
>> +     struct bmc150_accel_interrupt_info *info;
>> +     atomic_t users;
>> +};
>> +
>> +#define BMC150_ACCEL_INTERRUPTS              2
>> +
>>  struct bmc150_accel_data {
>>       struct i2c_client *client;
>> +     struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
>>       struct iio_trigger *dready_trig;
>>       struct iio_trigger *motion_trig;
>> +     atomic_t active_intr;
>>       struct mutex mutex;
>>       s16 buffer[8];
>>       u8 bw_bits;
>> @@ -436,7 +445,8 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
>>  }
>>  #endif
>>
>> -static struct bmc150_accel_interrupt_info bmc150_accel_interrupts[] = {
>> +static struct bmc150_accel_interrupt_info
> Just noticed. Should this not also be const?
>> +bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = {

Yes indeed, fixed.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 08/11] iio: bmc150: introduce bmc150_accel_interrupt
  2015-01-28 11:09     ` Octavian Purdila
@ 2015-01-28 13:20       ` Jonathan Cameron
  0 siblings, 0 replies; 50+ messages in thread
From: Jonathan Cameron @ 2015-01-28 13:20 UTC (permalink / raw)
  To: Octavian Purdila, Jonathan Cameron; +Cc: linux-iio



On 28 January 2015 11:09:46 GMT+00:00, Octavian Purdila <octavian.purdila@intel.com> wrote:
>On Sun, Jan 4, 2015 at 6:36 PM, Jonathan Cameron <jic23@kernel.org>
>wrote:
>> On 21/12/14 00:42, Octavian Purdila wrote:
>>> Since both triggers and events can share an interrupt, add a data
>>> structure that tracks the users of an interrupt so that it enables
>or
>>> disables it only for the first users and respectively last user.
>>>
>>> This will allows us to easily add more events or triggers.
>>>
>>> The patch also adds an interrupt enabled counter, so that we can
>>> easily know if we need to put the device in normal mode when the
>>> resume callback is issued.
>>>
>>> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
>> This is probably the cleanest way of doing this, but an alternative
>is
>> to register an interrupt chip and then you can have each interrupt
>source
>> (internal to the device) have it's own interrupt and register as if
>> it had direct access (rather than having to read what interrupt
>occured
>> first).  This is the preferred method these days for MFDs where this
>> tree structure of interrupts is common.
>>
>> I think that would result in slightly more code though, so perhaps
>this
>> local version of some of that infrastructure is fine.
>>
>
>Good to know about the interrupt chip approach. I also think in this
>case the local version is better.
>
>But if we see a common pattern across multiple drivers, perhaps we can
>add the interrupt chip to the IIO core for those drivers that want to
>make use of it. I'll take a look, but on the top of your head, do you
>know of any drivers for this would be useful?
I doubt it would generalise in a useful way.
The code needed is pretty compact and mostly very part specific.
Note the triggers in iio are already using this approach but there the purpose is a bit different. We always want to interrupt all children who are ready...
>
>>> ---
>>>  drivers/iio/accel/bmc150-accel.c | 87
>+++++++++++++++++++++-------------------
>>>  1 file changed, 45 insertions(+), 42 deletions(-)
>>>
>>> diff --git a/drivers/iio/accel/bmc150-accel.c
>b/drivers/iio/accel/bmc150-accel.c
>>> index aaad2fb..7c905f6 100644
>>> --- a/drivers/iio/accel/bmc150-accel.c
>>> +++ b/drivers/iio/accel/bmc150-accel.c
>>> @@ -151,10 +151,19 @@ struct bmc150_accel_interrupt_info {
>>>       u8 en_bitmask;
>>>  };
>>>
>>> +struct bmc150_accel_interrupt {
>>> +     struct bmc150_accel_interrupt_info *info;
>>> +     atomic_t users;
>>> +};
>>> +
>>> +#define BMC150_ACCEL_INTERRUPTS              2
>>> +
>>>  struct bmc150_accel_data {
>>>       struct i2c_client *client;
>>> +     struct bmc150_accel_interrupt
>interrupts[BMC150_ACCEL_INTERRUPTS];
>>>       struct iio_trigger *dready_trig;
>>>       struct iio_trigger *motion_trig;
>>> +     atomic_t active_intr;
>>>       struct mutex mutex;
>>>       s16 buffer[8];
>>>       u8 bw_bits;
>>> @@ -436,7 +445,8 @@ static int bmc150_accel_set_power_state(struct
>bmc150_accel_data *data, bool on)
>>>  }
>>>  #endif
>>>
>>> -static struct bmc150_accel_interrupt_info bmc150_accel_interrupts[]
>= {
>>> +static struct bmc150_accel_interrupt_info
>> Just noticed. Should this not also be const?
>>> +bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = {
>
>Yes indeed, fixed.

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 05/11] iio: bmc150: refactor slope duration and threshold update
  2015-01-28  9:22       ` Octavian Purdila
@ 2015-01-28 17:15         ` Srinivas Pandruvada
  0 siblings, 0 replies; 50+ messages in thread
From: Srinivas Pandruvada @ 2015-01-28 17:15 UTC (permalink / raw)
  To: Octavian Purdila; +Cc: Jonathan Cameron, linux-iio, Laurentiu Palcu

On Wed, 2015-01-28 at 11:22 +0200, Octavian Purdila wrote: 
> On Tue, Jan 6, 2015 at 8:53 PM, Srinivas Pandruvada
> <srinivas.pandruvada@linux.intel.com> wrote:
> >
> > On Sun, 2015-01-04 at 16:21 +0000, Jonathan Cameron wrote:
> > > On 21/12/14 00:42, Octavian Purdila wrote:
> > > > Move the slope duration and threshold update in separate functions
> > > > to reduce code duplicate between chip init and motion interrupt setup.
> > > >
> > > > The patch also moves the update from the motion interrupt setup
> > > > function to the write event function so that we can later refactor the
> > > > interrupt code.
> > > The side effect of this is that these will get updated at a different
> > > point in time from before.  Previously these values would only get
> > > updated when the event was enabled (or the trigger).  So to change
> > > them a disable / enable cycle was needed. Now they happen the moment
> > > they are relevant.
> > >
> > > I prefer the new option, but it is an ABI change (be it one most people
> > > won't notice!)
> > I did purposely this way.
> > IMO when user is changing critical parameters he should disable and re
> > enable to avoid undesirable side effects.
> > We have similar situation in other  thermal drivers where user can
> > change policy parameters. Initially we let them change while zone is
> > enabled (system is armed), this led to undesirable side effects due to
> > race conditions.
> >
> 
> We already have a check that prevents the change while the event is
> active. We could add a check for the data motion trigger as well, to
> avoid the above scenario.
> 
> Alternatively I can rewrite the patch to keep the current behavior and
> update the parameters when we enable the trigger.
> 
> Which one sounds better?
I prefer the second option.

Thanks,
Srinivas



^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 11/11] iio: bmc150: add support for hardware fifo
  2015-01-04 17:08   ` Jonathan Cameron
@ 2015-01-28 19:26     ` Octavian Purdila
  2015-02-04 17:16       ` Jonathan Cameron
  0 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2015-01-28 19:26 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio

On Sun, Jan 4, 2015 at 7:08 PM, Jonathan Cameron <jic23@kernel.org> wrote:
> On 21/12/14 00:42, Octavian Purdila wrote:
>> Add a new watermark trigger and hardware fifo operations. When the
>> watermark trigger is activated the watermark level is set and the
>> hardware FIFO is activated.
>>
>> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> Mostly good, though I spot a demux in here that definitely shouldn't
> be there and connected access to indio_dev->buffer->scan_mask which is
> very dangerous as it may well not be the same as indio_dev->active_scan_mask
> (which is what controls which data is captured).
>
> This is also true of the original driver trigger handler and a number of
> other drivers.  Ooops, I've not been picking up on that in reviews recently
> by the look of it.
>
> If anyone is feeling bored a quick grep highlights the buggy drivers...
> If not I'll get to it, but isn't that critical as right now, no mainline
> driver is using the interface that will cause this issue.
>

Oh, ok, didn't know that we should use indio_dev->active_scan_mask
instead of indio_dev->buffer->scan_mask. I will take a closer look
after I am done reworking this patch set.

> Jonathan
>> ---
>>  drivers/iio/accel/bmc150-accel.c | 194 ++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 190 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
>> index 14509be..0aa3126 100644
>> --- a/drivers/iio/accel/bmc150-accel.c
>> +++ b/drivers/iio/accel/bmc150-accel.c
>> @@ -67,7 +67,9 @@
>>  #define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE     BIT(2)
>>
>>  #define BMC150_ACCEL_REG_INT_MAP_1           0x1A
>> -#define BMC150_ACCEL_INT_MAP_1_BIT_DATA      BIT(0)
>> +#define BMC150_ACCEL_INT_MAP_1_BIT_DATA              BIT(0)
>> +#define BMC150_ACCEL_INT_MAP_1_BIT_FWM               BIT(1)
>> +#define BMC150_ACCEL_INT_MAP_1_BIT_FFULL     BIT(2)
>>
>>  #define BMC150_ACCEL_REG_INT_RST_LATCH               0x21
>>  #define BMC150_ACCEL_INT_MODE_LATCH_RESET    0x80
>> @@ -80,7 +82,9 @@
>>  #define BMC150_ACCEL_INT_EN_BIT_SLP_Z                BIT(2)
>>
>>  #define BMC150_ACCEL_REG_INT_EN_1            0x17
>> -#define BMC150_ACCEL_INT_EN_BIT_DATA_EN      BIT(4)
>> +#define BMC150_ACCEL_INT_EN_BIT_DATA_EN              BIT(4)
>> +#define BMC150_ACCEL_INT_EN_BIT_FFULL_EN     BIT(5)
>> +#define BMC150_ACCEL_INT_EN_BIT_FWM_EN               BIT(6)
>>
>>  #define BMC150_ACCEL_REG_INT_OUT_CTRL                0x20
>>  #define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL   BIT(0)
>> @@ -119,6 +123,12 @@
>>  #define BMC150_ACCEL_AXIS_TO_REG(axis)       (BMC150_ACCEL_REG_XOUT_L + (axis * 2))
>>  #define BMC150_AUTO_SUSPEND_DELAY_MS         2000
>>
>> +#define BMC150_ACCEL_REG_FIFO_STATUS         0x0E
>> +#define BMC150_ACCEL_REG_FIFO_CONFIG0                0x30
>> +#define BMC150_ACCEL_REG_FIFO_CONFIG1                0x3E
>> +#define BMC150_ACCEL_REG_FIFO_DATA           0x3F
>> +#define BMC150_ACCEL_FIFO_LENGTH             32
>> +
>>  enum bmc150_accel_axis {
>>       AXIS_X,
>>       AXIS_Y,
>> @@ -161,6 +171,7 @@ struct bmc150_accel_trigger {
>>       struct bmc150_accel_data *data;
>>       struct iio_trigger *indio_trig;
>>       bool enabled;
>> +     int (*setup)(struct bmc150_accel_trigger *t, bool state);
>>  };
>>
>>  struct bmc150_accel_event {
>> @@ -180,8 +191,8 @@ struct bmc150_accel_event {
>>       };
>>  };
>>
>> -#define BMC150_ACCEL_INTERRUPTS              2
>> -#define BMC150_ACCEL_TRIGGERS                2
>> +#define BMC150_ACCEL_INTERRUPTS              3
>> +#define BMC150_ACCEL_TRIGGERS                3
>>  #define BMC150_ACCEL_EVENTS          1
>>
>>  struct bmc150_accel_data {
>> @@ -191,6 +202,7 @@ struct bmc150_accel_data {
>>       struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
>>       struct bmc150_accel_event events[BMC150_ACCEL_EVENTS];
>>       struct mutex mutex;
>> +     u8 fifo_mode, watermark;
>>       s16 buffer[8];
>>       u8 bw_bits;
>>       u32 range;
>> @@ -484,6 +496,12 @@ bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = {
>>                       BMC150_ACCEL_INT_EN_BIT_SLP_Y |
>>                       BMC150_ACCEL_INT_EN_BIT_SLP_Z
>>       },
>> +     { /* fifo watermark interrupt */
>> +             .map_reg = BMC150_ACCEL_REG_INT_MAP_1,
>> +             .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FWM,
>> +             .en_reg = BMC150_ACCEL_REG_INT_EN_1,
>> +             .en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
>> +     },
>>  };
>>
>>  static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
>> @@ -1020,6 +1038,8 @@ static const struct iio_info bmc150_accel_info = {
>>       .driver_module          = THIS_MODULE,
>>  };
>>
>> +static int bmc150_accel_fifo_flush(struct iio_dev *indio_dev);
>> +
>>  static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
>>  {
>>       struct iio_poll_func *pf = p;
>> @@ -1027,6 +1047,12 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
>>       struct bmc150_accel_data *data = iio_priv(indio_dev);
>>       int bit, ret, i = 0;
>>
>> +     if (data->fifo_mode) {
>> +             bmc150_accel_fifo_flush(indio_dev);
> When you flush here, you want to get the best possible timestamp as close
> to the interrupt as possible.  Perhaps even in the top half interrupt
> handler - then pass it through to here...

Yes, we already take the timestamp in the IRQ handler
(bmc150_accel_data_rdy_trig_poll).

>> +
>> +     if (!data->timestamp)
>> +             data->timestamp = iio_get_time_ns();
> As this is on the flush rather than an interrupt these are going
> to be of dubious benefit... There isn't an obvious way of doing better though
> unless we do have an interrupt.  In that case you want to grab them as
> early as possible (typically even in the interrupt top half) and pass it
> down to where you want to use it.

Actually flush gets called from two places: from the watermark trigger
and in this case we take the timestamp in the IRQ handler, and when we
do a read or poll and there is not enough data available in the
buffer.

For this later case we will have an error of up to a maximum of a one
sample period since flush was called in between one of the sampling
periods - the watermark interrupt makes sure we don't stall forever.
That is not that bad.

Also, the later case should be an exception if the application sets
the right watermark level and uses the right timeout. Otherwise it
will not use power optimally which is the whole point of the hw fifo.

>> +
>> +     tstamp = data->timestamp - count * sample_freq;
>> +
>> +     for (i = 0; i < count; i++) {
>> +             u16 sample[8];
>> +             int j, bit;
>> +
>> +             j = 0;
>> +             for_each_set_bit(bit, indio_dev->buffer->scan_mask,
>> +                              indio_dev->masklength) {
>> +                     memcpy(&sample[j++], &buffer[i * 3 + bit], 2);
>> +             }
>
> A local demux rather than using the main iio one. Given you clearly read the
> lot anyway is there any reason not to just pass it all on and let the IIO
> demux handling the demux on the way to the kfifo?
>

Hmm, isn't the demux part only used when we have client buffers?  The
demux part is not used at all in my tests, due to
indio_dev->active_scan_mask being equal to buffer->scan_mask.

> There should be no access to the buffer scan_mask by drivers.
>
> They should only see the indio_dev->active_scan_mask (they may well not
> be the same due to client devices).
>

Right, after taking a closer look at the demux part I finally
understand it. I will fix it in the next version.

>> +
>> +             iio_push_to_buffers_with_timestamp(indio_dev, sample, tstamp);
>> +
>> +             tstamp += sample_freq;
>> +     }
>> +
>> +     data->timestamp = 0;
>> +
>> +     return 0;
>> +}
>> +
>> +static int bmc150_accel_fifo_mode_set(struct bmc150_accel_data *data)
>> +{
>> +     u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1;
>> +     int ret;
>> +
>> +     ret = i2c_smbus_read_byte_data(data->client, reg);
>> +
>> +     /* writting the fifo config discards FIFO data - avoid it if possible */
> Strikes me that caching the values of some registers would be a good idea
> - probably by using regmap to handle it.   Still a job for another day.
>I will keep this in mind.

Good point, I'll add this to my todo list.

>> +     if (ret == data->fifo_mode)
>> +             return 0;
>> +
>> +     ret = i2c_smbus_write_byte_data(data->client, reg, data->fifo_mode);
>> +     if (ret < 0) {
>> +             dev_err(&data->client->dev, "Error writing reg_fifo_config1\n");
>> +             return ret;
>> +     }
>> +
>> +     if (!data->fifo_mode)
>> +             return 0;
>> +
>> +     /* we can set the the watermark value only after FIFO is enabled */
>> +     ret = i2c_smbus_write_byte_data(data->client,
>> +                                     BMC150_ACCEL_REG_FIFO_CONFIG0,
>> +                                     data->watermark);
>> +
>> +     if (ret < 0)
>> +             dev_err(&data->client->dev, "Error writing reg_fifo_config0\n");
>> +
>> +     return ret;
>> +}
>> +
>> +static int bmc150_accel_fifo_setup(struct bmc150_accel_trigger *t, bool state)
>> +{
>> +     if (state)
> a #define for the magic 0x40 perhaps?
>> +             t->data->fifo_mode = 0x40;
>> +     else
>> +             t->data->fifo_mode = 0;
>> +
>> +     return bmc150_accel_fifo_mode_set(t->data);
>> +}
>> +
>> +const struct iio_hwfifo bmc150_accel_hwfifo = {
>> +     .length = BMC150_ACCEL_FIFO_LENGTH,
>> +     .set_watermark = bmc150_accel_set_watermark,
>> +     .flush = bmc150_accel_fifo_flush,
>> +};
>> +
>>  static int bmc150_accel_probe(struct i2c_client *client,
>>                             const struct i2c_device_id *id)
>>  {
>> @@ -1387,6 +1567,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
>>                               "Failed: iio triggered buffer setup\n");
>>                       goto err_trigger_unregister;
>>               }
>> +
>> +             indio_dev->hwfifo = &bmc150_accel_hwfifo;
>>       }
>>
>>       ret = iio_device_register(indio_dev);
>> @@ -1458,6 +1640,7 @@ static int bmc150_accel_resume(struct device *dev)
>>       mutex_lock(&data->mutex);
>>       if (atomic_read(&data->active_intr))
>>               bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
>> +     bmc150_accel_fifo_mode_set(data);
>>       mutex_unlock(&data->mutex);
>>
>>       return 0;
>> @@ -1487,6 +1670,9 @@ static int bmc150_accel_runtime_resume(struct device *dev)
>>       ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
>>       if (ret < 0)
>>               return ret;
>> +     ret = bmc150_accel_fifo_mode_set(data);
>> +     if (ret < 0)
>> +             return ret;
>>
>>       sleep_val = bmc150_accel_get_startup_times(data);
>>       if (sleep_val < 20)
>>
>

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 04/11] iio: add support for hardware fifo
  2014-12-21  0:42 ` [PATCH v2 04/11] iio: add support for hardware fifo Octavian Purdila
  2015-01-04 16:07   ` Jonathan Cameron
@ 2015-01-28 23:46   ` Hartmut Knaack
  2015-01-29 11:38     ` Octavian Purdila
  1 sibling, 1 reply; 50+ messages in thread
From: Hartmut Knaack @ 2015-01-28 23:46 UTC (permalink / raw)
  To: Octavian Purdila, linux-iio
  Cc: Jonathan Cameron, Lars-Peter Clausen, Peter Meerwald

Octavian Purdila schrieb am 21.12.2014 um 01:42:
> Some devices have hardware buffers that can store a number of samples
> for later consumption. Hardware usually provides interrupts to notify
> the processor when the fifo is full or when it has reached a certain
> threshold. This helps with reducing the number of interrupts to the
> host processor and thus it helps decreasing the power consumption.
> 
> This patch adds support for hardware fifo to IIO by allowing the
> drivers to register operations for flushing the hadware fifo and
> setting the watermark level.
> 
> A driver implementing hardware fifo support must also provide a
> watermark trigger which must contain "watermark" in its name.
> 

A few comments inline, also addressed to the other IIO maintainers.

> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> ---
>  Documentation/ABI/testing/sysfs-bus-iio | 22 +++++++++++++++++
>  drivers/iio/industrialio-buffer.c       | 44 ++++++++++++++++++++++++++++-----
>  include/linux/iio/iio.h                 | 17 +++++++++++++
>  3 files changed, 77 insertions(+), 6 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index 7260f1f..6bb67ac 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -1152,3 +1152,25 @@ Description:
>  		Poll will block until the watermark is reached.
>  		Blocking read will wait until the minimum between the requested
>  		read amount or the low water mark is available.
> +		If the device has a hardware fifo this value is going to be used
> +		for the hardware fifo watermark as well.
> +
> +What:		/sys/bus/iio/devices/iio:deviceX/buffer/hwfifo-length
> +KernelVersion:	3.20
> +Contact:	linux-iio@vger.kernel.org
> +Description:
> +		A single positive integer specifying the maximum number of
> +		samples that the hardware fifo has. If the device does not
> +		support hardware fifo this is zero.
> +		When a device supports hardware fifo it will expose a trigger
> +		with the name that contains "watermark"
> +		(e.g. i2c-BMC150A:00-watermark-dev0).
> +		To use the hardware fifo the user must set an appropriate value
> +		in the buffer/length and buffer/low_watermark entries and select
> +		the watermark trigger. At that poin the hardware fifo will be
> +		enabled and the samples will be collected in a hardware buffer.
> +		When the number of samples in the hardware fifo reaches the
> +		watermark level the watermark trigger is issued and data is
> +		flushed to the devices buffer.
> +		A hardware buffer flush will also be triggered when reading from
> +		the device buffer and there is not enough data available.
> \ No newline at end of file
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index 7f74c7f..3da6d07 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -37,9 +37,17 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
>  	return !list_empty(&buf->buffer_list);
>  }
>  
> -static size_t iio_buffer_data_available(struct iio_buffer *buf)
> +static bool iio_buffer_data_available(struct iio_dev *indio_dev,
> +				      struct iio_buffer *buf, size_t required)
>  {
> -	return buf->access->data_available(buf);
> +	size_t avail = buf->access->data_available(buf);
> +
> +	if (avail < required && indio_dev->hwfifo) {
> +		indio_dev->hwfifo->flush(indio_dev);
> +		avail = buf->access->data_available(buf);
> +	}
> +
> +	return avail >= required;
>  }
>  
>  /**
> @@ -66,13 +74,13 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
>  
>  	do {
>  		if (filp->f_flags & O_NONBLOCK) {
> -			if (!iio_buffer_data_available(rb)) {
> +			if (!iio_buffer_data_available(indio_dev, rb, 1)) {
>  				ret = -EAGAIN;
>  				break;
>  			}
>  		} else {
>  			ret = wait_event_interruptible(rb->pollq,
> -			       iio_buffer_data_available(rb) >= to_read ||
> +		            iio_buffer_data_available(indio_dev, rb, to_read) ||
>  						       indio_dev->info == NULL);
>  			if (ret)
>  				return ret;
> @@ -112,7 +120,7 @@ unsigned int iio_buffer_poll(struct file *filp,
>  		return -ENODEV;
>  
>  	poll_wait(filp, &rb->pollq, wait);
> -	if (iio_buffer_data_available(rb) >= rb->low_watermark)
> +	if (iio_buffer_data_available(indio_dev, rb, rb->low_watermark))
>  		return POLLIN | POLLRDNORM;
>  	return 0;
>  }
> @@ -440,8 +448,14 @@ static ssize_t iio_buffer_write_length(struct device *dev,
>  	if (buffer->length)
>  		val = buffer->length;
>  
> -	if (val < buffer->low_watermark)
> +	if (val < buffer->low_watermark) {
> +		if (indio_dev->hwfifo) {
> +			ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
> +			if (ret)
> +				return ret;
> +		}
>  		buffer->low_watermark = val;
> +	}
>  
>  	return len;
>  }
> @@ -811,6 +825,12 @@ static ssize_t iio_buffer_store_watermark(struct device *dev,
>  		goto out;
>  	}
>  
> +	if (indio_dev->hwfifo) {
> +		ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
> +		if (ret)
> +			goto out;
> +	}
> +
>  	buffer->low_watermark = val;
>  	ret = 0;
>  out:
> @@ -818,6 +838,16 @@ out:
>  	return ret ? ret : len;
>  }
>  
> +ssize_t iio_buffer_hwfifo_read_length(struct device *dev,
> +				      struct device_attribute *attr,
> +				      char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	const struct iio_hwfifo *hwfifo = indio_dev->hwfifo;
> +
> +	return sprintf(buf, "%u\n", hwfifo ? hwfifo->length : 0);
> +}
> +
>  static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
>  		   iio_buffer_write_length);
>  static struct device_attribute dev_attr_length_ro = __ATTR(length,
> @@ -826,11 +856,13 @@ static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
>  		   iio_buffer_show_enable, iio_buffer_store_enable);
>  static DEVICE_ATTR(low_watermark, S_IRUGO | S_IWUSR,
>  		   iio_buffer_show_watermark, iio_buffer_store_watermark);
> +static DEVICE_ATTR(hwfifo_length, S_IRUGO, iio_buffer_hwfifo_read_length, NULL);
>  
>  static struct attribute *iio_buffer_attrs[] = {
>  	&dev_attr_length.attr,
>  	&dev_attr_enable.attr,
>  	&dev_attr_low_watermark.attr,
> +	&dev_attr_hwfifo_length.attr,
>  };
>  
>  int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> index 878d861..f64a05f 100644
> --- a/include/linux/iio/iio.h
> +++ b/include/linux/iio/iio.h
> @@ -417,6 +417,22 @@ struct iio_buffer_setup_ops {
>  };
>  
>  /**
> + * struct iio_buffer_hwfifo_ops - hardware fifo operations
> + *
> + * @length:		[DRIVER] the hardware fifo length
> + * @set_watermark:	[DRIVER] setups the watermark level
Maybe use "sets" instead of "setups".
Also, and this is more a general question, as it was quite annoying when getting into
the topic: I would prefer to place some information about the expected return values of
these functions into these descriptions. What do you guys think about that?

> + * @flush:		[DRIVER] copies data from the hardware buffer to the
> + *		 	device buffer
> + * @watermark_trig:	[DRIVER] an allocated and registered trigger containing
> + *			"watermark" in its name
> + */
> +struct iio_hwfifo {
> +	int length;
> +	int (*set_watermark)(struct iio_dev *, unsigned int);
> +	int (*flush)(struct iio_dev *);
> +};
> +
> +/**
>   * struct iio_dev - industrial I/O device
>   * @id:			[INTERN] used to identify device internally
>   * @modes:		[DRIVER] operating modes supported by device
> @@ -491,6 +507,7 @@ struct iio_dev {
>  	int				groupcounter;
>  
>  	unsigned long			flags;
> +	const struct iio_hwfifo		*hwfifo;
This new entry should be added to the description of the iio_dev struct, as well.
>  #if defined(CONFIG_DEBUG_FS)
>  	struct dentry			*debugfs_dentry;
>  	unsigned			cached_reg_addr;
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 04/11] iio: add support for hardware fifo
  2015-01-28 23:46   ` Hartmut Knaack
@ 2015-01-29 11:38     ` Octavian Purdila
  2015-01-29 22:49       ` Hartmut Knaack
  2015-02-04 17:11       ` Jonathan Cameron
  0 siblings, 2 replies; 50+ messages in thread
From: Octavian Purdila @ 2015-01-29 11:38 UTC (permalink / raw)
  To: Hartmut Knaack
  Cc: linux-iio, Jonathan Cameron, Lars-Peter Clausen, Peter Meerwald

On Thu, Jan 29, 2015 at 1:46 AM, Hartmut Knaack <knaack.h@gmx.de> wrote:
>
> Octavian Purdila schrieb am 21.12.2014 um 01:42:
> > Some devices have hardware buffers that can store a number of samples
> > for later consumption. Hardware usually provides interrupts to notify
> > the processor when the fifo is full or when it has reached a certain
> > threshold. This helps with reducing the number of interrupts to the
> > host processor and thus it helps decreasing the power consumption.
> >
> > This patch adds support for hardware fifo to IIO by allowing the
> > drivers to register operations for flushing the hadware fifo and
> > setting the watermark level.
> >
> > A driver implementing hardware fifo support must also provide a
> > watermark trigger which must contain "watermark" in its name.
> >
>
> A few comments inline, also addressed to the other IIO maintainers.
>

Thanks for the review Hartmut. What do you think about the watermark
trigger approach?

Also, after the discussion with Jonathan I am thinking of exposing a
dedicated watermark level for the hardware FIFO. That way userspace
can set a large value for the software buffer watermark and it also
give control to userspace over the hardware watermark. I think that
control is very important to achieve a good power/latency balance.

> > Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> > ---
> >  Documentation/ABI/testing/sysfs-bus-iio | 22 +++++++++++++++++
> >  drivers/iio/industrialio-buffer.c       | 44 ++++++++++++++++++++++++++++-----
> >  include/linux/iio/iio.h                 | 17 +++++++++++++
> >  3 files changed, 77 insertions(+), 6 deletions(-)
> >
> > diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> > index 7260f1f..6bb67ac 100644
> > --- a/Documentation/ABI/testing/sysfs-bus-iio
> > +++ b/Documentation/ABI/testing/sysfs-bus-iio
> > @@ -1152,3 +1152,25 @@ Description:
> >               Poll will block until the watermark is reached.
> >               Blocking read will wait until the minimum between the requested
> >               read amount or the low water mark is available.
> > +             If the device has a hardware fifo this value is going to be used
> > +             for the hardware fifo watermark as well.
> > +
> > +What:                /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo-length
> > +KernelVersion:       3.20
> > +Contact:     linux-iio@vger.kernel.org
> > +Description:
> > +             A single positive integer specifying the maximum number of
> > +             samples that the hardware fifo has. If the device does not
> > +             support hardware fifo this is zero.
> > +             When a device supports hardware fifo it will expose a trigger
> > +             with the name that contains "watermark"
> > +             (e.g. i2c-BMC150A:00-watermark-dev0).
> > +             To use the hardware fifo the user must set an appropriate value
> > +             in the buffer/length and buffer/low_watermark entries and select
> > +             the watermark trigger. At that poin the hardware fifo will be
> > +             enabled and the samples will be collected in a hardware buffer.
> > +             When the number of samples in the hardware fifo reaches the
> > +             watermark level the watermark trigger is issued and data is
> > +             flushed to the devices buffer.
> > +             A hardware buffer flush will also be triggered when reading from
> > +             the device buffer and there is not enough data available.
> > \ No newline at end of file
> > diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> > index 7f74c7f..3da6d07 100644
> > --- a/drivers/iio/industrialio-buffer.c
> > +++ b/drivers/iio/industrialio-buffer.c
> > @@ -37,9 +37,17 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
> >       return !list_empty(&buf->buffer_list);
> >  }
> >
> > -static size_t iio_buffer_data_available(struct iio_buffer *buf)
> > +static bool iio_buffer_data_available(struct iio_dev *indio_dev,
> > +                                   struct iio_buffer *buf, size_t required)
> >  {
> > -     return buf->access->data_available(buf);
> > +     size_t avail = buf->access->data_available(buf);
> > +
> > +     if (avail < required && indio_dev->hwfifo) {
> > +             indio_dev->hwfifo->flush(indio_dev);
> > +             avail = buf->access->data_available(buf);
> > +     }
> > +
> > +     return avail >= required;
> >  }
> >
> >  /**
> > @@ -66,13 +74,13 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
> >
> >       do {
> >               if (filp->f_flags & O_NONBLOCK) {
> > -                     if (!iio_buffer_data_available(rb)) {
> > +                     if (!iio_buffer_data_available(indio_dev, rb, 1)) {
> >                               ret = -EAGAIN;
> >                               break;
> >                       }
> >               } else {
> >                       ret = wait_event_interruptible(rb->pollq,
> > -                            iio_buffer_data_available(rb) >= to_read ||
> > +                         iio_buffer_data_available(indio_dev, rb, to_read) ||
> >                                                      indio_dev->info == NULL);
> >                       if (ret)
> >                               return ret;
> > @@ -112,7 +120,7 @@ unsigned int iio_buffer_poll(struct file *filp,
> >               return -ENODEV;
> >
> >       poll_wait(filp, &rb->pollq, wait);
> > -     if (iio_buffer_data_available(rb) >= rb->low_watermark)
> > +     if (iio_buffer_data_available(indio_dev, rb, rb->low_watermark))
> >               return POLLIN | POLLRDNORM;
> >       return 0;
> >  }
> > @@ -440,8 +448,14 @@ static ssize_t iio_buffer_write_length(struct device *dev,
> >       if (buffer->length)
> >               val = buffer->length;
> >
> > -     if (val < buffer->low_watermark)
> > +     if (val < buffer->low_watermark) {
> > +             if (indio_dev->hwfifo) {
> > +                     ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
> > +                     if (ret)
> > +                             return ret;
> > +             }
> >               buffer->low_watermark = val;
> > +     }
> >
> >       return len;
> >  }
> > @@ -811,6 +825,12 @@ static ssize_t iio_buffer_store_watermark(struct device *dev,
> >               goto out;
> >       }
> >
> > +     if (indio_dev->hwfifo) {
> > +             ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
> > +             if (ret)
> > +                     goto out;
> > +     }
> > +
> >       buffer->low_watermark = val;
> >       ret = 0;
> >  out:
> > @@ -818,6 +838,16 @@ out:
> >       return ret ? ret : len;
> >  }
> >
> > +ssize_t iio_buffer_hwfifo_read_length(struct device *dev,
> > +                                   struct device_attribute *attr,
> > +                                   char *buf)
> > +{
> > +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> > +     const struct iio_hwfifo *hwfifo = indio_dev->hwfifo;
> > +
> > +     return sprintf(buf, "%u\n", hwfifo ? hwfifo->length : 0);
> > +}
> > +
> >  static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
> >                  iio_buffer_write_length);
> >  static struct device_attribute dev_attr_length_ro = __ATTR(length,
> > @@ -826,11 +856,13 @@ static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
> >                  iio_buffer_show_enable, iio_buffer_store_enable);
> >  static DEVICE_ATTR(low_watermark, S_IRUGO | S_IWUSR,
> >                  iio_buffer_show_watermark, iio_buffer_store_watermark);
> > +static DEVICE_ATTR(hwfifo_length, S_IRUGO, iio_buffer_hwfifo_read_length, NULL);
> >
> >  static struct attribute *iio_buffer_attrs[] = {
> >       &dev_attr_length.attr,
> >       &dev_attr_enable.attr,
> >       &dev_attr_low_watermark.attr,
> > +     &dev_attr_hwfifo_length.attr,
> >  };
> >
> >  int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
> > diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> > index 878d861..f64a05f 100644
> > --- a/include/linux/iio/iio.h
> > +++ b/include/linux/iio/iio.h
> > @@ -417,6 +417,22 @@ struct iio_buffer_setup_ops {
> >  };
> >
> >  /**
> > + * struct iio_buffer_hwfifo_ops - hardware fifo operations
> > + *
> > + * @length:          [DRIVER] the hardware fifo length
> > + * @set_watermark:   [DRIVER] setups the watermark level
> Maybe use "sets" instead of "setups".
>

Ok, sensible suggestion, I'll do that in the next version.

> Also, and this is more a general question, as it was quite annoying when getting into
> the topic: I would prefer to place some information about the expected return values of
> these functions into these descriptions. What do you guys think about that?
>
> > + * @flush:           [DRIVER] copies data from the hardware buffer to the
> > + *                   device buffer
> > + * @watermark_trig:  [DRIVER] an allocated and registered trigger containing
> > + *                   "watermark" in its name
> > + */
> > +struct iio_hwfifo {
> > +     int length;
> > +     int (*set_watermark)(struct iio_dev *, unsigned int);
> > +     int (*flush)(struct iio_dev *);
> > +};
> > +
> > +/**
> >   * struct iio_dev - industrial I/O device
> >   * @id:                      [INTERN] used to identify device internally
> >   * @modes:           [DRIVER] operating modes supported by device
> > @@ -491,6 +507,7 @@ struct iio_dev {
> >       int                             groupcounter;
> >
> >       unsigned long                   flags;
> > +     const struct iio_hwfifo         *hwfifo;
> This new entry should be added to the description of the iio_dev struct, as well.

Sure.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 04/11] iio: add support for hardware fifo
  2015-01-29 11:38     ` Octavian Purdila
@ 2015-01-29 22:49       ` Hartmut Knaack
  2015-02-04 17:18         ` Jonathan Cameron
  2015-02-04 17:11       ` Jonathan Cameron
  1 sibling, 1 reply; 50+ messages in thread
From: Hartmut Knaack @ 2015-01-29 22:49 UTC (permalink / raw)
  To: Octavian Purdila
  Cc: linux-iio, Jonathan Cameron, Lars-Peter Clausen, Peter Meerwald

Octavian Purdila schrieb am 29.01.2015 um 12:38:
> On Thu, Jan 29, 2015 at 1:46 AM, Hartmut Knaack <knaack.h@gmx.de> wrote:
>>
>> Octavian Purdila schrieb am 21.12.2014 um 01:42:
>>> Some devices have hardware buffers that can store a number of samples
>>> for later consumption. Hardware usually provides interrupts to notify
>>> the processor when the fifo is full or when it has reached a certain
>>> threshold. This helps with reducing the number of interrupts to the
>>> host processor and thus it helps decreasing the power consumption.
>>>
>>> This patch adds support for hardware fifo to IIO by allowing the
>>> drivers to register operations for flushing the hadware fifo and
>>> setting the watermark level.
>>>
>>> A driver implementing hardware fifo support must also provide a
>>> watermark trigger which must contain "watermark" in its name.
>>>
>>
>> A few comments inline, also addressed to the other IIO maintainers.
>>
> 
> Thanks for the review Hartmut. What do you think about the watermark
> trigger approach?

Looks good to me, so far. But keep in mind, that I am still pretty new
to the IIO area, so people like Jonathan have a better understanding
where the core development started out and where it should be heading.
I will have a look at your other patches during the next days, as time
permits.

> 
> Also, after the discussion with Jonathan I am thinking of exposing a
> dedicated watermark level for the hardware FIFO. That way userspace
> can set a large value for the software buffer watermark and it also
> give control to userspace over the hardware watermark. I think that
> control is very important to achieve a good power/latency balance.
> 
>>> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
>>> ---
>>>  Documentation/ABI/testing/sysfs-bus-iio | 22 +++++++++++++++++
>>>  drivers/iio/industrialio-buffer.c       | 44 ++++++++++++++++++++++++++++-----
>>>  include/linux/iio/iio.h                 | 17 +++++++++++++
>>>  3 files changed, 77 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
>>> index 7260f1f..6bb67ac 100644
>>> --- a/Documentation/ABI/testing/sysfs-bus-iio
>>> +++ b/Documentation/ABI/testing/sysfs-bus-iio
>>> @@ -1152,3 +1152,25 @@ Description:
>>>               Poll will block until the watermark is reached.
>>>               Blocking read will wait until the minimum between the requested
>>>               read amount or the low water mark is available.
>>> +             If the device has a hardware fifo this value is going to be used
>>> +             for the hardware fifo watermark as well.
>>> +
>>> +What:                /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo-length
>>> +KernelVersion:       3.20
>>> +Contact:     linux-iio@vger.kernel.org
>>> +Description:
>>> +             A single positive integer specifying the maximum number of
>>> +             samples that the hardware fifo has. If the device does not
>>> +             support hardware fifo this is zero.
>>> +             When a device supports hardware fifo it will expose a trigger
>>> +             with the name that contains "watermark"
>>> +             (e.g. i2c-BMC150A:00-watermark-dev0).
>>> +             To use the hardware fifo the user must set an appropriate value
>>> +             in the buffer/length and buffer/low_watermark entries and select
>>> +             the watermark trigger. At that poin the hardware fifo will be
>>> +             enabled and the samples will be collected in a hardware buffer.
>>> +             When the number of samples in the hardware fifo reaches the
>>> +             watermark level the watermark trigger is issued and data is
>>> +             flushed to the devices buffer.
>>> +             A hardware buffer flush will also be triggered when reading from
>>> +             the device buffer and there is not enough data available.
>>> \ No newline at end of file
>>> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
>>> index 7f74c7f..3da6d07 100644
>>> --- a/drivers/iio/industrialio-buffer.c
>>> +++ b/drivers/iio/industrialio-buffer.c
>>> @@ -37,9 +37,17 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
>>>       return !list_empty(&buf->buffer_list);
>>>  }
>>>
>>> -static size_t iio_buffer_data_available(struct iio_buffer *buf)
>>> +static bool iio_buffer_data_available(struct iio_dev *indio_dev,
>>> +                                   struct iio_buffer *buf, size_t required)
>>>  {
>>> -     return buf->access->data_available(buf);
>>> +     size_t avail = buf->access->data_available(buf);
>>> +
>>> +     if (avail < required && indio_dev->hwfifo) {
>>> +             indio_dev->hwfifo->flush(indio_dev);
>>> +             avail = buf->access->data_available(buf);
>>> +     }
>>> +
>>> +     return avail >= required;
>>>  }
>>>
>>>  /**
>>> @@ -66,13 +74,13 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
>>>
>>>       do {
>>>               if (filp->f_flags & O_NONBLOCK) {
>>> -                     if (!iio_buffer_data_available(rb)) {
>>> +                     if (!iio_buffer_data_available(indio_dev, rb, 1)) {
>>>                               ret = -EAGAIN;
>>>                               break;
>>>                       }
>>>               } else {
>>>                       ret = wait_event_interruptible(rb->pollq,
>>> -                            iio_buffer_data_available(rb) >= to_read ||
>>> +                         iio_buffer_data_available(indio_dev, rb, to_read) ||
>>>                                                      indio_dev->info == NULL);
>>>                       if (ret)
>>>                               return ret;
>>> @@ -112,7 +120,7 @@ unsigned int iio_buffer_poll(struct file *filp,
>>>               return -ENODEV;
>>>
>>>       poll_wait(filp, &rb->pollq, wait);
>>> -     if (iio_buffer_data_available(rb) >= rb->low_watermark)
>>> +     if (iio_buffer_data_available(indio_dev, rb, rb->low_watermark))
>>>               return POLLIN | POLLRDNORM;
>>>       return 0;
>>>  }
>>> @@ -440,8 +448,14 @@ static ssize_t iio_buffer_write_length(struct device *dev,
>>>       if (buffer->length)
>>>               val = buffer->length;
>>>
>>> -     if (val < buffer->low_watermark)
>>> +     if (val < buffer->low_watermark) {
>>> +             if (indio_dev->hwfifo) {
>>> +                     ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
>>> +                     if (ret)
>>> +                             return ret;
>>> +             }
>>>               buffer->low_watermark = val;
>>> +     }
>>>
>>>       return len;
>>>  }
>>> @@ -811,6 +825,12 @@ static ssize_t iio_buffer_store_watermark(struct device *dev,
>>>               goto out;
>>>       }
>>>
>>> +     if (indio_dev->hwfifo) {
>>> +             ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
>>> +             if (ret)
>>> +                     goto out;
>>> +     }
>>> +
>>>       buffer->low_watermark = val;
>>>       ret = 0;
>>>  out:
>>> @@ -818,6 +838,16 @@ out:
>>>       return ret ? ret : len;
>>>  }
>>>
>>> +ssize_t iio_buffer_hwfifo_read_length(struct device *dev,
>>> +                                   struct device_attribute *attr,
>>> +                                   char *buf)
>>> +{
>>> +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
>>> +     const struct iio_hwfifo *hwfifo = indio_dev->hwfifo;
>>> +
>>> +     return sprintf(buf, "%u\n", hwfifo ? hwfifo->length : 0);
>>> +}
>>> +
>>>  static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
>>>                  iio_buffer_write_length);
>>>  static struct device_attribute dev_attr_length_ro = __ATTR(length,
>>> @@ -826,11 +856,13 @@ static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
>>>                  iio_buffer_show_enable, iio_buffer_store_enable);
>>>  static DEVICE_ATTR(low_watermark, S_IRUGO | S_IWUSR,
>>>                  iio_buffer_show_watermark, iio_buffer_store_watermark);
>>> +static DEVICE_ATTR(hwfifo_length, S_IRUGO, iio_buffer_hwfifo_read_length, NULL);
>>>
>>>  static struct attribute *iio_buffer_attrs[] = {
>>>       &dev_attr_length.attr,
>>>       &dev_attr_enable.attr,
>>>       &dev_attr_low_watermark.attr,
>>> +     &dev_attr_hwfifo_length.attr,
>>>  };
>>>
>>>  int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
>>> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
>>> index 878d861..f64a05f 100644
>>> --- a/include/linux/iio/iio.h
>>> +++ b/include/linux/iio/iio.h
>>> @@ -417,6 +417,22 @@ struct iio_buffer_setup_ops {
>>>  };
>>>
>>>  /**
>>> + * struct iio_buffer_hwfifo_ops - hardware fifo operations
>>> + *
>>> + * @length:          [DRIVER] the hardware fifo length
>>> + * @set_watermark:   [DRIVER] setups the watermark level
>> Maybe use "sets" instead of "setups".
>>
> 
> Ok, sensible suggestion, I'll do that in the next version.
> 
>> Also, and this is more a general question, as it was quite annoying when getting into
>> the topic: I would prefer to place some information about the expected return values of
>> these functions into these descriptions. What do you guys think about that?
>>
>>> + * @flush:           [DRIVER] copies data from the hardware buffer to the
>>> + *                   device buffer
>>> + * @watermark_trig:  [DRIVER] an allocated and registered trigger containing
>>> + *                   "watermark" in its name
>>> + */
>>> +struct iio_hwfifo {
>>> +     int length;
>>> +     int (*set_watermark)(struct iio_dev *, unsigned int);
>>> +     int (*flush)(struct iio_dev *);
>>> +};
>>> +
>>> +/**
>>>   * struct iio_dev - industrial I/O device
>>>   * @id:                      [INTERN] used to identify device internally
>>>   * @modes:           [DRIVER] operating modes supported by device
>>> @@ -491,6 +507,7 @@ struct iio_dev {
>>>       int                             groupcounter;
>>>
>>>       unsigned long                   flags;
>>> +     const struct iio_hwfifo         *hwfifo;
>> This new entry should be added to the description of the iio_dev struct, as well.
> 
> Sure.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 04/11] iio: add support for hardware fifo
  2015-01-05 11:29     ` Octavian Purdila
@ 2015-02-04 17:08       ` Jonathan Cameron
  2015-02-05 21:36         ` Octavian Purdila
  0 siblings, 1 reply; 50+ messages in thread
From: Jonathan Cameron @ 2015-02-04 17:08 UTC (permalink / raw)
  To: Octavian Purdila; +Cc: linux-iio

On 05/01/15 11:29, Octavian Purdila wrote:
> On Mon, Jan 5, 2015 at 2:07 AM, Jonathan Cameron <jic23@kernel.org> wrote:
>> On 21/12/14 00:42, Octavian Purdila wrote:
>>
>> Thanks for taking this on!
>>
>> This all looks fairly sensible, though a few comments inline.
>> One big semantic change I'd suggest is to allow the watermark
>> level passed to the hardware to be a 'hint' rather than a hard
>> and fast rull.  A lot of these hardware buffers are fairly small
>> (perhaps 32 entries) and the devices can run fast so whilst
>> we will obviously have to handle an interrupt often, we may well
>> want to have a much larger software front end buffer with a
>> much larger watermark.  For example, a 8192Hz accelerometer
>> with 32 entry fifo (watermark at 16).  Will fire an interrupt 512 times
>> a second.  Userspace might be only interested in getting data 32 times
>> a second and hence want a watermark of 256 entries and probably have
>> a buffer that is 512 entries long or more.
>>
> 
> Very good point with the above example, but I find the hint approach a
> bit too hard to diagnose and tune by the application.
> 
> Could we perhaps expose the hwfifo watermark as well, in addition to
> the software watermark? We can even keep the hint behavior if the
> application only touches the software watermark, but if it the
> application directly sets the hwfifo level then we use that.
Hmm. Not sure how well this would work.  We probably need a way of indicating
the hardware buffer has not been 'pinned' to a particular value.
Maybe we can have it read only? 
That way it is obvious what effect the 'hint' is having on the hardware
without adding a confusing double control for the same thing...
> 
>>> Some devices have hardware buffers that can store a number of samples
>>> for later consumption. Hardware usually provides interrupts to notify
>>> the processor when the fifo is full or when it has reached a certain
>>> threshold. This helps with reducing the number of interrupts to the
>>> host processor and thus it helps decreasing the power consumption.
>>>
>>> This patch adds support for hardware fifo to IIO by allowing the
>>> drivers to register operations for flushing the hadware fifo and
>>> setting the watermark level.
>>
>> Perhaps put something in here to observe that this is a different approach
>> to the straight hardware buffer stuff we already have - of most interest
>> for hybrid buffering rather than a pure hardware buffer.
>>
> 
> Will do.
> 
>>>
>>> A driver implementing hardware fifo support must also provide a
>>> watermark trigger which must contain "watermark" in its name.
>>>
>>> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
>>> ---
>>>  Documentation/ABI/testing/sysfs-bus-iio | 22 +++++++++++++++++
>>>  drivers/iio/industrialio-buffer.c       | 44 ++++++++++++++++++++++++++++-----
>>>  include/linux/iio/iio.h                 | 17 +++++++++++++
>>>  3 files changed, 77 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
>>> index 7260f1f..6bb67ac 100644
>>> --- a/Documentation/ABI/testing/sysfs-bus-iio
>>> +++ b/Documentation/ABI/testing/sysfs-bus-iio
>>> @@ -1152,3 +1152,25 @@ Description:
>>>               Poll will block until the watermark is reached.
>>>               Blocking read will wait until the minimum between the requested
>>>               read amount or the low water mark is available.
>>> +             If the device has a hardware fifo this value is going to be used
>>> +             for the hardware fifo watermark as well.
>>
>> I'd make this a litle vaguer (deliberately ;).   Perhaps used as a 'hint'
>> for the hardware fifo watermark as well.  The reason being that if we set
>> the software watermark at say 20 and the hardware only has 15 fifo entries,
>> then we might want to be clever and say set the hardware fifo watershed to 10.
>> For now that would be a decision of the hardware driver rather than one for
>> the core.
> 
> Sure, I'll update the docs with what ever we end-up deciding its best :)
> 
>>> +
>>> +What:                /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo-length
>>> +KernelVersion:       3.20
>>> +Contact:     linux-iio@vger.kernel.org
>>> +Description:
>>> +             A single positive integer specifying the maximum number of
>>> +             samples that the hardware fifo has. If the device does not
>>> +             support hardware fifo this is zero.
>>> +             When a device supports hardware fifo it will expose a trigger
>>> +             with the name that contains "watermark"
>>> +             (e.g. i2c-BMC150A:00-watermark-dev0).
>>> +             To use the hardware fifo the user must set an appropriate value
>>> +             in the buffer/length and buffer/low_watermark entries and select
>>> +             the watermark trigger. At that poin the hardware fifo will be
>> point
>>> +             enabled and the samples will be collected in a hardware buffer.
>> Hmm. I wonder to a degree if the trigger approach really makes sense for
>> fifo equiped devices.  We've deliberately not added one in a few existing
>> cases.
>>
>> Otherwise, is there a reason to run this separately from a trigger not using
>> the fifo.  Surely that's just the same as a watermark of 1?
>>
>> Anyhow, a point for discussion!
> 
> I might be misunderstand you here, but the reason for which we use a
> separate trigger is to have a way to enable/disable FIFO mode, because
> enabling the FIFO might have some downsides, e.g. more power
> consumption. This matters only when the application is interested in
> low latency sampling ( watermark of 1).
Perhaps we use a watermark of one to disable the fifo if present.  Can't
think why you'd want it under those circumstances unless the data can't
be read without.  This then becomes a driver issue as all the core
cares about is that the data turns up, not particularly whether it very
briefly bounces through a buffer or not.
> 
> I don't know if this is really an issue in practice, but I chose the
> safe option.
> 
>>
>>> +             When the number of samples in the hardware fifo reaches the
>>> +             watermark level the watermark trigger is issued and data is
>>> +             flushed to the devices buffer.
>>> +             A hardware buffer flush will also be triggered when reading from
>>> +             the device buffer and there is not enough data available.
>>> \ No newline at end of file
>> Fix this..
>>> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
>>> index 7f74c7f..3da6d07 100644
>>> --- a/drivers/iio/industrialio-buffer.c
>>> +++ b/drivers/iio/industrialio-buffer.c
>>> @@ -37,9 +37,17 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
>>>       return !list_empty(&buf->buffer_list);
>>>  }
>>>
>>> -static size_t iio_buffer_data_available(struct iio_buffer *buf)
>>> +static bool iio_buffer_data_available(struct iio_dev *indio_dev,
>>> +                                   struct iio_buffer *buf, size_t required)
>>>  {
>>> -     return buf->access->data_available(buf);
>>> +     size_t avail = buf->access->data_available(buf);
>>> +
>>> +     if (avail < required && indio_dev->hwfifo) {
>>> +             indio_dev->hwfifo->flush(indio_dev);
>>> +             avail = buf->access->data_available(buf);
>>> +     }
>>> +
>>> +     return avail >= required;
>> Does it make sense to move the decision in here?  Could just as easily
>> have left this as returning the length and done the logic outside...
>> I don't mind that much... However, we probably want to rename the function
>> now that it is doing more than strictly querying availability.
> 
> I've put it here so that it affects both read and poll so that we
> avoid avoid latencies if possible. Will change the name.
> 
>>
>> Could also have flush take a parameter for what is desired and only read
>> that many?  On relatively slow buses might make sense...
> 
> Good point, will add that.
> 
>>>  /**
>>> + * struct iio_buffer_hwfifo_ops - hardware fifo operations
>>> + *
>>> + * @length:          [DRIVER] the hardware fifo length
>>> + * @set_watermark:   [DRIVER] setups the watermark level
>>> + * @flush:           [DRIVER] copies data from the hardware buffer to the
>>> + *                   device buffer
>>> + * @watermark_trig:  [DRIVER] an allocated and registered trigger containing
>>> + *                   "watermark" in its name
>> err. This last one isn't actually in the structure...
> 
> Yeah, I wanted to add some checks in the core to make sure that if the
> driver is registering the hwfifo ops then it should allocate and
> register a watermark trigger as well. If we decide to go with the
> trigger approach, do you think it is a good idea to add the checks?
> 
If so, but I'll be honest I really don't like the trigger approach here.
It feels like an abuse of an interface that is really there to allow
synchronized capture/ controllable capture on devices without fixed
timing... (when they are fixed, the point is really to allow other
non fixed devices to lock on and sample at the same time - very handy
for inertial data fusion and other places...)

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 04/11] iio: add support for hardware fifo
  2015-01-29 11:38     ` Octavian Purdila
  2015-01-29 22:49       ` Hartmut Knaack
@ 2015-02-04 17:11       ` Jonathan Cameron
  1 sibling, 0 replies; 50+ messages in thread
From: Jonathan Cameron @ 2015-02-04 17:11 UTC (permalink / raw)
  To: Octavian Purdila, Hartmut Knaack
  Cc: linux-iio, Lars-Peter Clausen, Peter Meerwald

On 29/01/15 11:38, Octavian Purdila wrote:
> On Thu, Jan 29, 2015 at 1:46 AM, Hartmut Knaack <knaack.h@gmx.de> wrote:
>>
>> Octavian Purdila schrieb am 21.12.2014 um 01:42:
>>> Some devices have hardware buffers that can store a number of samples
>>> for later consumption. Hardware usually provides interrupts to notify
>>> the processor when the fifo is full or when it has reached a certain
>>> threshold. This helps with reducing the number of interrupts to the
>>> host processor and thus it helps decreasing the power consumption.
>>>
>>> This patch adds support for hardware fifo to IIO by allowing the
>>> drivers to register operations for flushing the hadware fifo and
>>> setting the watermark level.
>>>
>>> A driver implementing hardware fifo support must also provide a
>>> watermark trigger which must contain "watermark" in its name.
>>>
>>
>> A few comments inline, also addressed to the other IIO maintainers.
>>
> 
> Thanks for the review Hartmut. What do you think about the watermark
> trigger approach?
> 
> Also, after the discussion with Jonathan I am thinking of exposing a
> dedicated watermark level for the hardware FIFO. That way userspace
> can set a large value for the software buffer watermark and it also
> give control to userspace over the hardware watermark. I think that
> control is very important to achieve a good power/latency balance.
It would be odd to have a high watermark for the software buffer and a
low one for the hardware, but I guess there might be some 'on demand'
applications where this makes sense.  Ones where they will do a lower
latency capture if they have time or demand, but otherwise do a high
latency pass. This feels niche enough to me that maybe we don't
want to support it in the first instance, but keep it in mind for
future fun and games!
> 
>>> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
>>> ---
>>>  Documentation/ABI/testing/sysfs-bus-iio | 22 +++++++++++++++++
>>>  drivers/iio/industrialio-buffer.c       | 44 ++++++++++++++++++++++++++++-----
>>>  include/linux/iio/iio.h                 | 17 +++++++++++++
>>>  3 files changed, 77 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
>>> index 7260f1f..6bb67ac 100644
>>> --- a/Documentation/ABI/testing/sysfs-bus-iio
>>> +++ b/Documentation/ABI/testing/sysfs-bus-iio
>>> @@ -1152,3 +1152,25 @@ Description:
>>>               Poll will block until the watermark is reached.
>>>               Blocking read will wait until the minimum between the requested
>>>               read amount or the low water mark is available.
>>> +             If the device has a hardware fifo this value is going to be used
>>> +             for the hardware fifo watermark as well.
>>> +
>>> +What:                /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo-length
>>> +KernelVersion:       3.20
>>> +Contact:     linux-iio@vger.kernel.org
>>> +Description:
>>> +             A single positive integer specifying the maximum number of
>>> +             samples that the hardware fifo has. If the device does not
>>> +             support hardware fifo this is zero.
>>> +             When a device supports hardware fifo it will expose a trigger
>>> +             with the name that contains "watermark"
>>> +             (e.g. i2c-BMC150A:00-watermark-dev0).
>>> +             To use the hardware fifo the user must set an appropriate value
>>> +             in the buffer/length and buffer/low_watermark entries and select
>>> +             the watermark trigger. At that poin the hardware fifo will be
>>> +             enabled and the samples will be collected in a hardware buffer.
>>> +             When the number of samples in the hardware fifo reaches the
>>> +             watermark level the watermark trigger is issued and data is
>>> +             flushed to the devices buffer.
>>> +             A hardware buffer flush will also be triggered when reading from
>>> +             the device buffer and there is not enough data available.
>>> \ No newline at end of file
>>> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
>>> index 7f74c7f..3da6d07 100644
>>> --- a/drivers/iio/industrialio-buffer.c
>>> +++ b/drivers/iio/industrialio-buffer.c
>>> @@ -37,9 +37,17 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
>>>       return !list_empty(&buf->buffer_list);
>>>  }
>>>
>>> -static size_t iio_buffer_data_available(struct iio_buffer *buf)
>>> +static bool iio_buffer_data_available(struct iio_dev *indio_dev,
>>> +                                   struct iio_buffer *buf, size_t required)
>>>  {
>>> -     return buf->access->data_available(buf);
>>> +     size_t avail = buf->access->data_available(buf);
>>> +
>>> +     if (avail < required && indio_dev->hwfifo) {
>>> +             indio_dev->hwfifo->flush(indio_dev);
>>> +             avail = buf->access->data_available(buf);
>>> +     }
>>> +
>>> +     return avail >= required;
>>>  }
>>>
>>>  /**
>>> @@ -66,13 +74,13 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
>>>
>>>       do {
>>>               if (filp->f_flags & O_NONBLOCK) {
>>> -                     if (!iio_buffer_data_available(rb)) {
>>> +                     if (!iio_buffer_data_available(indio_dev, rb, 1)) {
>>>                               ret = -EAGAIN;
>>>                               break;
>>>                       }
>>>               } else {
>>>                       ret = wait_event_interruptible(rb->pollq,
>>> -                            iio_buffer_data_available(rb) >= to_read ||
>>> +                         iio_buffer_data_available(indio_dev, rb, to_read) ||
>>>                                                      indio_dev->info == NULL);
>>>                       if (ret)
>>>                               return ret;
>>> @@ -112,7 +120,7 @@ unsigned int iio_buffer_poll(struct file *filp,
>>>               return -ENODEV;
>>>
>>>       poll_wait(filp, &rb->pollq, wait);
>>> -     if (iio_buffer_data_available(rb) >= rb->low_watermark)
>>> +     if (iio_buffer_data_available(indio_dev, rb, rb->low_watermark))
>>>               return POLLIN | POLLRDNORM;
>>>       return 0;
>>>  }
>>> @@ -440,8 +448,14 @@ static ssize_t iio_buffer_write_length(struct device *dev,
>>>       if (buffer->length)
>>>               val = buffer->length;
>>>
>>> -     if (val < buffer->low_watermark)
>>> +     if (val < buffer->low_watermark) {
>>> +             if (indio_dev->hwfifo) {
>>> +                     ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
>>> +                     if (ret)
>>> +                             return ret;
>>> +             }
>>>               buffer->low_watermark = val;
>>> +     }
>>>
>>>       return len;
>>>  }
>>> @@ -811,6 +825,12 @@ static ssize_t iio_buffer_store_watermark(struct device *dev,
>>>               goto out;
>>>       }
>>>
>>> +     if (indio_dev->hwfifo) {
>>> +             ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
>>> +             if (ret)
>>> +                     goto out;
>>> +     }
>>> +
>>>       buffer->low_watermark = val;
>>>       ret = 0;
>>>  out:
>>> @@ -818,6 +838,16 @@ out:
>>>       return ret ? ret : len;
>>>  }
>>>
>>> +ssize_t iio_buffer_hwfifo_read_length(struct device *dev,
>>> +                                   struct device_attribute *attr,
>>> +                                   char *buf)
>>> +{
>>> +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
>>> +     const struct iio_hwfifo *hwfifo = indio_dev->hwfifo;
>>> +
>>> +     return sprintf(buf, "%u\n", hwfifo ? hwfifo->length : 0);
>>> +}
>>> +
>>>  static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
>>>                  iio_buffer_write_length);
>>>  static struct device_attribute dev_attr_length_ro = __ATTR(length,
>>> @@ -826,11 +856,13 @@ static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
>>>                  iio_buffer_show_enable, iio_buffer_store_enable);
>>>  static DEVICE_ATTR(low_watermark, S_IRUGO | S_IWUSR,
>>>                  iio_buffer_show_watermark, iio_buffer_store_watermark);
>>> +static DEVICE_ATTR(hwfifo_length, S_IRUGO, iio_buffer_hwfifo_read_length, NULL);
>>>
>>>  static struct attribute *iio_buffer_attrs[] = {
>>>       &dev_attr_length.attr,
>>>       &dev_attr_enable.attr,
>>>       &dev_attr_low_watermark.attr,
>>> +     &dev_attr_hwfifo_length.attr,
>>>  };
>>>
>>>  int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
>>> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
>>> index 878d861..f64a05f 100644
>>> --- a/include/linux/iio/iio.h
>>> +++ b/include/linux/iio/iio.h
>>> @@ -417,6 +417,22 @@ struct iio_buffer_setup_ops {
>>>  };
>>>
>>>  /**
>>> + * struct iio_buffer_hwfifo_ops - hardware fifo operations
>>> + *
>>> + * @length:          [DRIVER] the hardware fifo length
>>> + * @set_watermark:   [DRIVER] setups the watermark level
>> Maybe use "sets" instead of "setups".
>>
> 
> Ok, sensible suggestion, I'll do that in the next version.
> 
>> Also, and this is more a general question, as it was quite annoying when getting into
>> the topic: I would prefer to place some information about the expected return values of
>> these functions into these descriptions. What do you guys think about that?
Absolutely - Not sure how one does that whilst keeping within kernel-doc, but
would definitely be a good thing (even if kernel-doc doesn't have a nice format for it!)

>>
>>> + * @flush:           [DRIVER] copies data from the hardware buffer to the
>>> + *                   device buffer
>>> + * @watermark_trig:  [DRIVER] an allocated and registered trigger containing
>>> + *                   "watermark" in its name
>>> + */
>>> +struct iio_hwfifo {
>>> +     int length;
>>> +     int (*set_watermark)(struct iio_dev *, unsigned int);
>>> +     int (*flush)(struct iio_dev *);
>>> +};
>>> +
>>> +/**
>>>   * struct iio_dev - industrial I/O device
>>>   * @id:                      [INTERN] used to identify device internally
>>>   * @modes:           [DRIVER] operating modes supported by device
>>> @@ -491,6 +507,7 @@ struct iio_dev {
>>>       int                             groupcounter;
>>>
>>>       unsigned long                   flags;
>>> +     const struct iio_hwfifo         *hwfifo;
>> This new entry should be added to the description of the iio_dev struct, as well.
> 
> Sure.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 11/11] iio: bmc150: add support for hardware fifo
  2015-01-28 19:26     ` Octavian Purdila
@ 2015-02-04 17:16       ` Jonathan Cameron
  2015-02-04 20:18         ` Octavian Purdila
  0 siblings, 1 reply; 50+ messages in thread
From: Jonathan Cameron @ 2015-02-04 17:16 UTC (permalink / raw)
  To: Octavian Purdila; +Cc: linux-iio

On 28/01/15 19:26, Octavian Purdila wrote:
> On Sun, Jan 4, 2015 at 7:08 PM, Jonathan Cameron <jic23@kernel.org> wrote:
>> On 21/12/14 00:42, Octavian Purdila wrote:
>>> Add a new watermark trigger and hardware fifo operations. When the
>>> watermark trigger is activated the watermark level is set and the
>>> hardware FIFO is activated.
>>>
>>> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
>> Mostly good, though I spot a demux in here that definitely shouldn't
>> be there and connected access to indio_dev->buffer->scan_mask which is
>> very dangerous as it may well not be the same as indio_dev->active_scan_mask
>> (which is what controls which data is captured).
>>
>> This is also true of the original driver trigger handler and a number of
>> other drivers.  Ooops, I've not been picking up on that in reviews recently
>> by the look of it.
>>
>> If anyone is feeling bored a quick grep highlights the buggy drivers...
>> If not I'll get to it, but isn't that critical as right now, no mainline
>> driver is using the interface that will cause this issue.
>>
> 
> Oh, ok, didn't know that we should use indio_dev->active_scan_mask
> instead of indio_dev->buffer->scan_mask. I will take a closer look
> after I am done reworking this patch set.
> 
>> Jonathan
>>> ---
>>>  drivers/iio/accel/bmc150-accel.c | 194 ++++++++++++++++++++++++++++++++++++++-
>>>  1 file changed, 190 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
>>> index 14509be..0aa3126 100644
>>> --- a/drivers/iio/accel/bmc150-accel.c
>>> +++ b/drivers/iio/accel/bmc150-accel.c
>>> @@ -67,7 +67,9 @@
>>>  #define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE     BIT(2)
>>>
>>>  #define BMC150_ACCEL_REG_INT_MAP_1           0x1A
>>> -#define BMC150_ACCEL_INT_MAP_1_BIT_DATA      BIT(0)
>>> +#define BMC150_ACCEL_INT_MAP_1_BIT_DATA              BIT(0)
>>> +#define BMC150_ACCEL_INT_MAP_1_BIT_FWM               BIT(1)
>>> +#define BMC150_ACCEL_INT_MAP_1_BIT_FFULL     BIT(2)
>>>
>>>  #define BMC150_ACCEL_REG_INT_RST_LATCH               0x21
>>>  #define BMC150_ACCEL_INT_MODE_LATCH_RESET    0x80
>>> @@ -80,7 +82,9 @@
>>>  #define BMC150_ACCEL_INT_EN_BIT_SLP_Z                BIT(2)
>>>
>>>  #define BMC150_ACCEL_REG_INT_EN_1            0x17
>>> -#define BMC150_ACCEL_INT_EN_BIT_DATA_EN      BIT(4)
>>> +#define BMC150_ACCEL_INT_EN_BIT_DATA_EN              BIT(4)
>>> +#define BMC150_ACCEL_INT_EN_BIT_FFULL_EN     BIT(5)
>>> +#define BMC150_ACCEL_INT_EN_BIT_FWM_EN               BIT(6)
>>>
>>>  #define BMC150_ACCEL_REG_INT_OUT_CTRL                0x20
>>>  #define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL   BIT(0)
>>> @@ -119,6 +123,12 @@
>>>  #define BMC150_ACCEL_AXIS_TO_REG(axis)       (BMC150_ACCEL_REG_XOUT_L + (axis * 2))
>>>  #define BMC150_AUTO_SUSPEND_DELAY_MS         2000
>>>
>>> +#define BMC150_ACCEL_REG_FIFO_STATUS         0x0E
>>> +#define BMC150_ACCEL_REG_FIFO_CONFIG0                0x30
>>> +#define BMC150_ACCEL_REG_FIFO_CONFIG1                0x3E
>>> +#define BMC150_ACCEL_REG_FIFO_DATA           0x3F
>>> +#define BMC150_ACCEL_FIFO_LENGTH             32
>>> +
>>>  enum bmc150_accel_axis {
>>>       AXIS_X,
>>>       AXIS_Y,
>>> @@ -161,6 +171,7 @@ struct bmc150_accel_trigger {
>>>       struct bmc150_accel_data *data;
>>>       struct iio_trigger *indio_trig;
>>>       bool enabled;
>>> +     int (*setup)(struct bmc150_accel_trigger *t, bool state);
>>>  };
>>>
>>>  struct bmc150_accel_event {
>>> @@ -180,8 +191,8 @@ struct bmc150_accel_event {
>>>       };
>>>  };
>>>
>>> -#define BMC150_ACCEL_INTERRUPTS              2
>>> -#define BMC150_ACCEL_TRIGGERS                2
>>> +#define BMC150_ACCEL_INTERRUPTS              3
>>> +#define BMC150_ACCEL_TRIGGERS                3
>>>  #define BMC150_ACCEL_EVENTS          1
>>>
>>>  struct bmc150_accel_data {
>>> @@ -191,6 +202,7 @@ struct bmc150_accel_data {
>>>       struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
>>>       struct bmc150_accel_event events[BMC150_ACCEL_EVENTS];
>>>       struct mutex mutex;
>>> +     u8 fifo_mode, watermark;
>>>       s16 buffer[8];
>>>       u8 bw_bits;
>>>       u32 range;
>>> @@ -484,6 +496,12 @@ bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = {
>>>                       BMC150_ACCEL_INT_EN_BIT_SLP_Y |
>>>                       BMC150_ACCEL_INT_EN_BIT_SLP_Z
>>>       },
>>> +     { /* fifo watermark interrupt */
>>> +             .map_reg = BMC150_ACCEL_REG_INT_MAP_1,
>>> +             .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FWM,
>>> +             .en_reg = BMC150_ACCEL_REG_INT_EN_1,
>>> +             .en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
>>> +     },
>>>  };
>>>
>>>  static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
>>> @@ -1020,6 +1038,8 @@ static const struct iio_info bmc150_accel_info = {
>>>       .driver_module          = THIS_MODULE,
>>>  };
>>>
>>> +static int bmc150_accel_fifo_flush(struct iio_dev *indio_dev);
>>> +
>>>  static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
>>>  {
>>>       struct iio_poll_func *pf = p;
>>> @@ -1027,6 +1047,12 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
>>>       struct bmc150_accel_data *data = iio_priv(indio_dev);
>>>       int bit, ret, i = 0;
>>>
>>> +     if (data->fifo_mode) {
>>> +             bmc150_accel_fifo_flush(indio_dev);
>> When you flush here, you want to get the best possible timestamp as close
>> to the interrupt as possible.  Perhaps even in the top half interrupt
>> handler - then pass it through to here...
> 
> Yes, we already take the timestamp in the IRQ handler
> (bmc150_accel_data_rdy_trig_poll).
> 
>>> +
>>> +     if (!data->timestamp)
>>> +             data->timestamp = iio_get_time_ns();
>> As this is on the flush rather than an interrupt these are going
>> to be of dubious benefit... There isn't an obvious way of doing better though
>> unless we do have an interrupt.  In that case you want to grab them as
>> early as possible (typically even in the interrupt top half) and pass it
>> down to where you want to use it.
> 
> Actually flush gets called from two places: from the watermark trigger
> and in this case we take the timestamp in the IRQ handler, and when we
> do a read or poll and there is not enough data available in the
> buffer.
> 
> For this later case we will have an error of up to a maximum of a one
> sample period since flush was called in between one of the sampling
> periods - the watermark interrupt makes sure we don't stall forever.
> That is not that bad.
Not terrible.  I wonder if we want to indicated a dubious timestamp
in some way?  Or maybe event specify a jitter on the channel?
(been wondering if we want this sort of description for channels in
general - how noisy are they?)  Can be very useful to userspace and
is often tied up with the particular settings of the device.
> 
> Also, the later case should be an exception if the application sets
> the right watermark level and uses the right timeout. Otherwise it
> will not use power optimally which is the whole point of the hw fifo.
> 
>>> +
>>> +     tstamp = data->timestamp - count * sample_freq;
>>> +
>>> +     for (i = 0; i < count; i++) {
>>> +             u16 sample[8];
>>> +             int j, bit;
>>> +
>>> +             j = 0;
>>> +             for_each_set_bit(bit, indio_dev->buffer->scan_mask,
>>> +                              indio_dev->masklength) {
>>> +                     memcpy(&sample[j++], &buffer[i * 3 + bit], 2);
>>> +             }
>>
>> A local demux rather than using the main iio one. Given you clearly read the
>> lot anyway is there any reason not to just pass it all on and let the IIO
>> demux handling the demux on the way to the kfifo?
>>
> 
> Hmm, isn't the demux part only used when we have client buffers?  The
> demux part is not used at all in my tests, due to
> indio_dev->active_scan_mask being equal to buffer->scan_mask.
I'm guessing you figured this out. Yes, only used with client buffers,
but the normal buffered access is a client buffer :)
> 
>> There should be no access to the buffer scan_mask by drivers.
>>
>> They should only see the indio_dev->active_scan_mask (they may well not
>> be the same due to client devices).
>>
> 
> Right, after taking a closer look at the demux part I finally
> understand it. I will fix it in the next version.
> 
>>> +
>>> +             iio_push_to_buffers_with_timestamp(indio_dev, sample, tstamp);
>>> +
>>> +             tstamp += sample_freq;
>>> +     }
>>> +
>>> +     data->timestamp = 0;
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int bmc150_accel_fifo_mode_set(struct bmc150_accel_data *data)
>>> +{
>>> +     u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1;
>>> +     int ret;
>>> +
>>> +     ret = i2c_smbus_read_byte_data(data->client, reg);
>>> +
>>> +     /* writting the fifo config discards FIFO data - avoid it if possible */
>> Strikes me that caching the values of some registers would be a good idea
>> - probably by using regmap to handle it.   Still a job for another day.
>> I will keep this in mind.
> 
> Good point, I'll add this to my todo list.
> 
>>> +     if (ret == data->fifo_mode)
>>> +             return 0;
>>> +
>>> +     ret = i2c_smbus_write_byte_data(data->client, reg, data->fifo_mode);
>>> +     if (ret < 0) {
>>> +             dev_err(&data->client->dev, "Error writing reg_fifo_config1\n");
>>> +             return ret;
>>> +     }
>>> +
>>> +     if (!data->fifo_mode)
>>> +             return 0;
>>> +
>>> +     /* we can set the the watermark value only after FIFO is enabled */
>>> +     ret = i2c_smbus_write_byte_data(data->client,
>>> +                                     BMC150_ACCEL_REG_FIFO_CONFIG0,
>>> +                                     data->watermark);
>>> +
>>> +     if (ret < 0)
>>> +             dev_err(&data->client->dev, "Error writing reg_fifo_config0\n");
>>> +
>>> +     return ret;
>>> +}
>>> +
>>> +static int bmc150_accel_fifo_setup(struct bmc150_accel_trigger *t, bool state)
>>> +{
>>> +     if (state)
>> a #define for the magic 0x40 perhaps?
>>> +             t->data->fifo_mode = 0x40;
>>> +     else
>>> +             t->data->fifo_mode = 0;
>>> +
>>> +     return bmc150_accel_fifo_mode_set(t->data);
>>> +}
>>> +
>>> +const struct iio_hwfifo bmc150_accel_hwfifo = {
>>> +     .length = BMC150_ACCEL_FIFO_LENGTH,
>>> +     .set_watermark = bmc150_accel_set_watermark,
>>> +     .flush = bmc150_accel_fifo_flush,
>>> +};
>>> +
>>>  static int bmc150_accel_probe(struct i2c_client *client,
>>>                             const struct i2c_device_id *id)
>>>  {
>>> @@ -1387,6 +1567,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
>>>                               "Failed: iio triggered buffer setup\n");
>>>                       goto err_trigger_unregister;
>>>               }
>>> +
>>> +             indio_dev->hwfifo = &bmc150_accel_hwfifo;
>>>       }
>>>
>>>       ret = iio_device_register(indio_dev);
>>> @@ -1458,6 +1640,7 @@ static int bmc150_accel_resume(struct device *dev)
>>>       mutex_lock(&data->mutex);
>>>       if (atomic_read(&data->active_intr))
>>>               bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
>>> +     bmc150_accel_fifo_mode_set(data);
>>>       mutex_unlock(&data->mutex);
>>>
>>>       return 0;
>>> @@ -1487,6 +1670,9 @@ static int bmc150_accel_runtime_resume(struct device *dev)
>>>       ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
>>>       if (ret < 0)
>>>               return ret;
>>> +     ret = bmc150_accel_fifo_mode_set(data);
>>> +     if (ret < 0)
>>> +             return ret;
>>>
>>>       sleep_val = bmc150_accel_get_startup_times(data);
>>>       if (sleep_val < 20)
>>>
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 04/11] iio: add support for hardware fifo
  2015-01-29 22:49       ` Hartmut Knaack
@ 2015-02-04 17:18         ` Jonathan Cameron
  0 siblings, 0 replies; 50+ messages in thread
From: Jonathan Cameron @ 2015-02-04 17:18 UTC (permalink / raw)
  To: Hartmut Knaack, Octavian Purdila
  Cc: linux-iio, Lars-Peter Clausen, Peter Meerwald

On 29/01/15 22:49, Hartmut Knaack wrote:
> Octavian Purdila schrieb am 29.01.2015 um 12:38:
>> On Thu, Jan 29, 2015 at 1:46 AM, Hartmut Knaack <knaack.h@gmx.de> wrote:
>>>
>>> Octavian Purdila schrieb am 21.12.2014 um 01:42:
>>>> Some devices have hardware buffers that can store a number of samples
>>>> for later consumption. Hardware usually provides interrupts to notify
>>>> the processor when the fifo is full or when it has reached a certain
>>>> threshold. This helps with reducing the number of interrupts to the
>>>> host processor and thus it helps decreasing the power consumption.
>>>>
>>>> This patch adds support for hardware fifo to IIO by allowing the
>>>> drivers to register operations for flushing the hadware fifo and
>>>> setting the watermark level.
>>>>
>>>> A driver implementing hardware fifo support must also provide a
>>>> watermark trigger which must contain "watermark" in its name.
>>>>
>>>
>>> A few comments inline, also addressed to the other IIO maintainers.
>>>
>>
>> Thanks for the review Hartmut. What do you think about the watermark
>> trigger approach?
> 
> Looks good to me, so far. But keep in mind, that I am still pretty new
> to the IIO area, so people like Jonathan have a better understanding
> where the core development started out and where it should be heading.
> I will have a look at your other patches during the next days, as time
> permits.
You are under selling yourself Hartmut!  Anyhow, for the 'exciting'
end of buffers, Lars is probably the most familiar with them these
days as he has a lot of out of tree code in this area (dma stuff).

Anyhow, I like the general approach, only the details that need
pinning down in my view.  This is heading towards pretty much what
I always envisioned.
> 
>>
>> Also, after the discussion with Jonathan I am thinking of exposing a
>> dedicated watermark level for the hardware FIFO. That way userspace
>> can set a large value for the software buffer watermark and it also
>> give control to userspace over the hardware watermark. I think that
>> control is very important to achieve a good power/latency balance.
>>
>>>> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
>>>> ---
>>>>  Documentation/ABI/testing/sysfs-bus-iio | 22 +++++++++++++++++
>>>>  drivers/iio/industrialio-buffer.c       | 44 ++++++++++++++++++++++++++++-----
>>>>  include/linux/iio/iio.h                 | 17 +++++++++++++
>>>>  3 files changed, 77 insertions(+), 6 deletions(-)
>>>>
>>>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
>>>> index 7260f1f..6bb67ac 100644
>>>> --- a/Documentation/ABI/testing/sysfs-bus-iio
>>>> +++ b/Documentation/ABI/testing/sysfs-bus-iio
>>>> @@ -1152,3 +1152,25 @@ Description:
>>>>               Poll will block until the watermark is reached.
>>>>               Blocking read will wait until the minimum between the requested
>>>>               read amount or the low water mark is available.
>>>> +             If the device has a hardware fifo this value is going to be used
>>>> +             for the hardware fifo watermark as well.
>>>> +
>>>> +What:                /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo-length
>>>> +KernelVersion:       3.20
>>>> +Contact:     linux-iio@vger.kernel.org
>>>> +Description:
>>>> +             A single positive integer specifying the maximum number of
>>>> +             samples that the hardware fifo has. If the device does not
>>>> +             support hardware fifo this is zero.
>>>> +             When a device supports hardware fifo it will expose a trigger
>>>> +             with the name that contains "watermark"
>>>> +             (e.g. i2c-BMC150A:00-watermark-dev0).
>>>> +             To use the hardware fifo the user must set an appropriate value
>>>> +             in the buffer/length and buffer/low_watermark entries and select
>>>> +             the watermark trigger. At that poin the hardware fifo will be
>>>> +             enabled and the samples will be collected in a hardware buffer.
>>>> +             When the number of samples in the hardware fifo reaches the
>>>> +             watermark level the watermark trigger is issued and data is
>>>> +             flushed to the devices buffer.
>>>> +             A hardware buffer flush will also be triggered when reading from
>>>> +             the device buffer and there is not enough data available.
>>>> \ No newline at end of file
>>>> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
>>>> index 7f74c7f..3da6d07 100644
>>>> --- a/drivers/iio/industrialio-buffer.c
>>>> +++ b/drivers/iio/industrialio-buffer.c
>>>> @@ -37,9 +37,17 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
>>>>       return !list_empty(&buf->buffer_list);
>>>>  }
>>>>
>>>> -static size_t iio_buffer_data_available(struct iio_buffer *buf)
>>>> +static bool iio_buffer_data_available(struct iio_dev *indio_dev,
>>>> +                                   struct iio_buffer *buf, size_t required)
>>>>  {
>>>> -     return buf->access->data_available(buf);
>>>> +     size_t avail = buf->access->data_available(buf);
>>>> +
>>>> +     if (avail < required && indio_dev->hwfifo) {
>>>> +             indio_dev->hwfifo->flush(indio_dev);
>>>> +             avail = buf->access->data_available(buf);
>>>> +     }
>>>> +
>>>> +     return avail >= required;
>>>>  }
>>>>
>>>>  /**
>>>> @@ -66,13 +74,13 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
>>>>
>>>>       do {
>>>>               if (filp->f_flags & O_NONBLOCK) {
>>>> -                     if (!iio_buffer_data_available(rb)) {
>>>> +                     if (!iio_buffer_data_available(indio_dev, rb, 1)) {
>>>>                               ret = -EAGAIN;
>>>>                               break;
>>>>                       }
>>>>               } else {
>>>>                       ret = wait_event_interruptible(rb->pollq,
>>>> -                            iio_buffer_data_available(rb) >= to_read ||
>>>> +                         iio_buffer_data_available(indio_dev, rb, to_read) ||
>>>>                                                      indio_dev->info == NULL);
>>>>                       if (ret)
>>>>                               return ret;
>>>> @@ -112,7 +120,7 @@ unsigned int iio_buffer_poll(struct file *filp,
>>>>               return -ENODEV;
>>>>
>>>>       poll_wait(filp, &rb->pollq, wait);
>>>> -     if (iio_buffer_data_available(rb) >= rb->low_watermark)
>>>> +     if (iio_buffer_data_available(indio_dev, rb, rb->low_watermark))
>>>>               return POLLIN | POLLRDNORM;
>>>>       return 0;
>>>>  }
>>>> @@ -440,8 +448,14 @@ static ssize_t iio_buffer_write_length(struct device *dev,
>>>>       if (buffer->length)
>>>>               val = buffer->length;
>>>>
>>>> -     if (val < buffer->low_watermark)
>>>> +     if (val < buffer->low_watermark) {
>>>> +             if (indio_dev->hwfifo) {
>>>> +                     ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
>>>> +                     if (ret)
>>>> +                             return ret;
>>>> +             }
>>>>               buffer->low_watermark = val;
>>>> +     }
>>>>
>>>>       return len;
>>>>  }
>>>> @@ -811,6 +825,12 @@ static ssize_t iio_buffer_store_watermark(struct device *dev,
>>>>               goto out;
>>>>       }
>>>>
>>>> +     if (indio_dev->hwfifo) {
>>>> +             ret = indio_dev->hwfifo->set_watermark(indio_dev, val);
>>>> +             if (ret)
>>>> +                     goto out;
>>>> +     }
>>>> +
>>>>       buffer->low_watermark = val;
>>>>       ret = 0;
>>>>  out:
>>>> @@ -818,6 +838,16 @@ out:
>>>>       return ret ? ret : len;
>>>>  }
>>>>
>>>> +ssize_t iio_buffer_hwfifo_read_length(struct device *dev,
>>>> +                                   struct device_attribute *attr,
>>>> +                                   char *buf)
>>>> +{
>>>> +     struct iio_dev *indio_dev = dev_to_iio_dev(dev);
>>>> +     const struct iio_hwfifo *hwfifo = indio_dev->hwfifo;
>>>> +
>>>> +     return sprintf(buf, "%u\n", hwfifo ? hwfifo->length : 0);
>>>> +}
>>>> +
>>>>  static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
>>>>                  iio_buffer_write_length);
>>>>  static struct device_attribute dev_attr_length_ro = __ATTR(length,
>>>> @@ -826,11 +856,13 @@ static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
>>>>                  iio_buffer_show_enable, iio_buffer_store_enable);
>>>>  static DEVICE_ATTR(low_watermark, S_IRUGO | S_IWUSR,
>>>>                  iio_buffer_show_watermark, iio_buffer_store_watermark);
>>>> +static DEVICE_ATTR(hwfifo_length, S_IRUGO, iio_buffer_hwfifo_read_length, NULL);
>>>>
>>>>  static struct attribute *iio_buffer_attrs[] = {
>>>>       &dev_attr_length.attr,
>>>>       &dev_attr_enable.attr,
>>>>       &dev_attr_low_watermark.attr,
>>>> +     &dev_attr_hwfifo_length.attr,
>>>>  };
>>>>
>>>>  int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
>>>> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
>>>> index 878d861..f64a05f 100644
>>>> --- a/include/linux/iio/iio.h
>>>> +++ b/include/linux/iio/iio.h
>>>> @@ -417,6 +417,22 @@ struct iio_buffer_setup_ops {
>>>>  };
>>>>
>>>>  /**
>>>> + * struct iio_buffer_hwfifo_ops - hardware fifo operations
>>>> + *
>>>> + * @length:          [DRIVER] the hardware fifo length
>>>> + * @set_watermark:   [DRIVER] setups the watermark level
>>> Maybe use "sets" instead of "setups".
>>>
>>
>> Ok, sensible suggestion, I'll do that in the next version.
>>
>>> Also, and this is more a general question, as it was quite annoying when getting into
>>> the topic: I would prefer to place some information about the expected return values of
>>> these functions into these descriptions. What do you guys think about that?
>>>
>>>> + * @flush:           [DRIVER] copies data from the hardware buffer to the
>>>> + *                   device buffer
>>>> + * @watermark_trig:  [DRIVER] an allocated and registered trigger containing
>>>> + *                   "watermark" in its name
>>>> + */
>>>> +struct iio_hwfifo {
>>>> +     int length;
>>>> +     int (*set_watermark)(struct iio_dev *, unsigned int);
>>>> +     int (*flush)(struct iio_dev *);
>>>> +};
>>>> +
>>>> +/**
>>>>   * struct iio_dev - industrial I/O device
>>>>   * @id:                      [INTERN] used to identify device internally
>>>>   * @modes:           [DRIVER] operating modes supported by device
>>>> @@ -491,6 +507,7 @@ struct iio_dev {
>>>>       int                             groupcounter;
>>>>
>>>>       unsigned long                   flags;
>>>> +     const struct iio_hwfifo         *hwfifo;
>>> This new entry should be added to the description of the iio_dev struct, as well.
>>
>> Sure.
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 11/11] iio: bmc150: add support for hardware fifo
  2015-02-04 17:16       ` Jonathan Cameron
@ 2015-02-04 20:18         ` Octavian Purdila
  2015-02-05 11:20           ` Jonathan Cameron
  0 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2015-02-04 20:18 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio

On Wed, Feb 4, 2015 at 7:16 PM, Jonathan Cameron <jic23@kernel.org> wrote:
<snip>
>>> As this is on the flush rather than an interrupt these are going
>>> to be of dubious benefit... There isn't an obvious way of doing better though
>>> unless we do have an interrupt.  In that case you want to grab them as
>>> early as possible (typically even in the interrupt top half) and pass it
>>> down to where you want to use it.
>>
>> Actually flush gets called from two places: from the watermark trigger
>> and in this case we take the timestamp in the IRQ handler, and when we
>> do a read or poll and there is not enough data available in the
>> buffer.
>>
>> For this later case we will have an error of up to a maximum of a one
>> sample period since flush was called in between one of the sampling
>> periods - the watermark interrupt makes sure we don't stall forever.
>> That is not that bad.
> Not terrible.  I wonder if we want to indicated a dubious timestamp
> in some way?  Or maybe event specify a jitter on the channel?
> (been wondering if we want this sort of description for channels in
> general - how noisy are they?)  Can be very useful to userspace and
> is often tied up with the particular settings of the device.

Do you mean adding something like IIO_CHAN_INFO_JITTER? That would be
nice, but in this case the value is variable and depends on the
sampling frequency. What could work would be to also add a new event
IIO_EV_TYPE_JITTER_CHANGED and issue it when the sampling frequency is
changed.

But at this point is getting too complex and I don't know how much it
helps userspace.


>> Also, the later case should be an exception if the application sets
>> the right watermark level and uses the right timeout. Otherwise it
>> will not use power optimally which is the whole point of the hw fifo.
>>
>>>> +
>>>> +     tstamp = data->timestamp - count * sample_freq;
>>>> +
>>>> +     for (i = 0; i < count; i++) {
>>>> +             u16 sample[8];
>>>> +             int j, bit;
>>>> +
>>>> +             j = 0;
>>>> +             for_each_set_bit(bit, indio_dev->buffer->scan_mask,
>>>> +                              indio_dev->masklength) {
>>>> +                     memcpy(&sample[j++], &buffer[i * 3 + bit], 2);
>>>> +             }
>>>
>>> A local demux rather than using the main iio one. Given you clearly read the
>>> lot anyway is there any reason not to just pass it all on and let the IIO
>>> demux handling the demux on the way to the kfifo?
>>>
>>
>> Hmm, isn't the demux part only used when we have client buffers?  The
>> demux part is not used at all in my tests, due to
>> indio_dev->active_scan_mask being equal to buffer->scan_mask.
> I'm guessing you figured this out. Yes, only used with client buffers,
> but the normal buffered access is a client buffer :)
>>

Correct me if I am wrong: when we only use normal buffer access (no
kernel clients) the active_scan_mask is always equal to
buffer->scan_mask thus no demux will happen in core. So we still need
to do the demux in the driver.

In fact the above is true when we have only one client, be it user or kernel.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 11/11] iio: bmc150: add support for hardware fifo
  2015-02-04 20:18         ` Octavian Purdila
@ 2015-02-05 11:20           ` Jonathan Cameron
  2015-02-05 20:04             ` Octavian Purdila
  0 siblings, 1 reply; 50+ messages in thread
From: Jonathan Cameron @ 2015-02-05 11:20 UTC (permalink / raw)
  To: Octavian Purdila; +Cc: linux-iio

On 04/02/15 20:18, Octavian Purdila wrote:
> On Wed, Feb 4, 2015 at 7:16 PM, Jonathan Cameron <jic23@kernel.org> wrote:
> <snip>
>>>> As this is on the flush rather than an interrupt these are going
>>>> to be of dubious benefit... There isn't an obvious way of doing better though
>>>> unless we do have an interrupt.  In that case you want to grab them as
>>>> early as possible (typically even in the interrupt top half) and pass it
>>>> down to where you want to use it.
>>>
>>> Actually flush gets called from two places: from the watermark trigger
>>> and in this case we take the timestamp in the IRQ handler, and when we
>>> do a read or poll and there is not enough data available in the
>>> buffer.
>>>
>>> For this later case we will have an error of up to a maximum of a one
>>> sample period since flush was called in between one of the sampling
>>> periods - the watermark interrupt makes sure we don't stall forever.
>>> That is not that bad.
>> Not terrible.  I wonder if we want to indicated a dubious timestamp
>> in some way?  Or maybe event specify a jitter on the channel?
>> (been wondering if we want this sort of description for channels in
>> general - how noisy are they?)  Can be very useful to userspace and
>> is often tied up with the particular settings of the device.
> 
> Do you mean adding something like IIO_CHAN_INFO_JITTER? That would be
> nice, but in this case the value is variable and depends on the
> sampling frequency. What could work would be to also add a new event
> IIO_EV_TYPE_JITTER_CHANGED and issue it when the sampling frequency is
> changed.
General principle has always been that any sysfs type writes can effect
any of other attributes, so if userspace cares it should verify that
everything is as it expects.
> 
> But at this point is getting too complex and I don't know how much it
> helps userspace.
Definitely a job for another day!

Also in this category is having _available type information for all 
attributes, rather just some. Makes for nicer handling in userspace
but adds a lot of additional sysfs files!
> 
> 
>>> Also, the later case should be an exception if the application sets
>>> the right watermark level and uses the right timeout. Otherwise it
>>> will not use power optimally which is the whole point of the hw fifo.
>>>
>>>>> +
>>>>> +     tstamp = data->timestamp - count * sample_freq;
>>>>> +
>>>>> +     for (i = 0; i < count; i++) {
>>>>> +             u16 sample[8];
>>>>> +             int j, bit;
>>>>> +
>>>>> +             j = 0;
>>>>> +             for_each_set_bit(bit, indio_dev->buffer->scan_mask,
>>>>> +                              indio_dev->masklength) {
>>>>> +                     memcpy(&sample[j++], &buffer[i * 3 + bit], 2);
>>>>> +             }
>>>>
>>>> A local demux rather than using the main iio one. Given you clearly read the
>>>> lot anyway is there any reason not to just pass it all on and let the IIO
>>>> demux handling the demux on the way to the kfifo?
>>>>
>>>
>>> Hmm, isn't the demux part only used when we have client buffers?  The
>>> demux part is not used at all in my tests, due to
>>> indio_dev->active_scan_mask being equal to buffer->scan_mask.
>> I'm guessing you figured this out. Yes, only used with client buffers,
>> but the normal buffered access is a client buffer :)
>>>
> 
> Correct me if I am wrong: when we only use normal buffer access (no
> kernel clients) the active_scan_mask is always equal to
> buffer->scan_mask thus no demux will happen in core. So we still need
> to do the demux in the driver.
> 
> In fact the above is true when we have only one client, be it user or kernel.
Not quite.  If the device driver provides available_scan_masks (e.g. indicates
that general random access is not possible) then the demux is used to pull
out what the buffer wants from the in coming stream.

Basically, there is no point in doing local demux of incoming data as this
is better left to the core (which knows about everything that wants the data
and can chose appropriately).

Now, if you have a true random access part (any channel, any order any time -
so basically convert on demand devices) then don't provide available_scan_masks
and everything works as you say.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 11/11] iio: bmc150: add support for hardware fifo
  2015-02-05 11:20           ` Jonathan Cameron
@ 2015-02-05 20:04             ` Octavian Purdila
  2015-02-06 12:19               ` Jonathan Cameron
  0 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2015-02-05 20:04 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Irina Tirdea, Srinivas Pandruvada

On Thu, Feb 5, 2015 at 1:20 PM, Jonathan Cameron <jic23@kernel.org> wrote:
>
> On 04/02/15 20:18, Octavian Purdila wrote:
> > On Wed, Feb 4, 2015 at 7:16 PM, Jonathan Cameron <jic23@kernel.org> wrote:
> > <snip>
> >>>> As this is on the flush rather than an interrupt these are going
> >>>> to be of dubious benefit... There isn't an obvious way of doing better though
> >>>> unless we do have an interrupt.  In that case you want to grab them as
> >>>> early as possible (typically even in the interrupt top half) and pass it
> >>>> down to where you want to use it.
> >>>
> >>> Actually flush gets called from two places: from the watermark trigger
> >>> and in this case we take the timestamp in the IRQ handler, and when we
> >>> do a read or poll and there is not enough data available in the
> >>> buffer.
> >>>
> >>> For this later case we will have an error of up to a maximum of a one
> >>> sample period since flush was called in between one of the sampling
> >>> periods - the watermark interrupt makes sure we don't stall forever.
> >>> That is not that bad.
> >> Not terrible.  I wonder if we want to indicated a dubious timestamp
> >> in some way?  Or maybe event specify a jitter on the channel?
> >> (been wondering if we want this sort of description for channels in
> >> general - how noisy are they?)  Can be very useful to userspace and
> >> is often tied up with the particular settings of the device.
> >
> > Do you mean adding something like IIO_CHAN_INFO_JITTER? That would be
> > nice, but in this case the value is variable and depends on the
> > sampling frequency. What could work would be to also add a new event
> > IIO_EV_TYPE_JITTER_CHANGED and issue it when the sampling frequency is
> > changed.
> General principle has always been that any sysfs type writes can effect
> any of other attributes, so if userspace cares it should verify that
> everything is as it expects.
> >
> > But at this point is getting too complex and I don't know how much it
> > helps userspace.
> Definitely a job for another day!
>
> Also in this category is having _available type information for all
> attributes, rather just some. Makes for nicer handling in userspace
> but adds a lot of additional sysfs files!
> >
> >
> >>> Also, the later case should be an exception if the application sets
> >>> the right watermark level and uses the right timeout. Otherwise it
> >>> will not use power optimally which is the whole point of the hw fifo.
> >>>
> >>>>> +
> >>>>> +     tstamp = data->timestamp - count * sample_freq;
> >>>>> +
> >>>>> +     for (i = 0; i < count; i++) {
> >>>>> +             u16 sample[8];
> >>>>> +             int j, bit;
> >>>>> +
> >>>>> +             j = 0;
> >>>>> +             for_each_set_bit(bit, indio_dev->buffer->scan_mask,
> >>>>> +                              indio_dev->masklength) {
> >>>>> +                     memcpy(&sample[j++], &buffer[i * 3 + bit], 2);
> >>>>> +             }
> >>>>
> >>>> A local demux rather than using the main iio one. Given you clearly read the
> >>>> lot anyway is there any reason not to just pass it all on and let the IIO
> >>>> demux handling the demux on the way to the kfifo?
> >>>>
> >>>
> >>> Hmm, isn't the demux part only used when we have client buffers?  The
> >>> demux part is not used at all in my tests, due to
> >>> indio_dev->active_scan_mask being equal to buffer->scan_mask.
> >> I'm guessing you figured this out. Yes, only used with client buffers,
> >> but the normal buffered access is a client buffer :)
> >>>
> >
> > Correct me if I am wrong: when we only use normal buffer access (no
> > kernel clients) the active_scan_mask is always equal to
> > buffer->scan_mask thus no demux will happen in core. So we still need
> > to do the demux in the driver.
> >
> > In fact the above is true when we have only one client, be it user or kernel.
> Not quite.  If the device driver provides available_scan_masks (e.g. indicates
> that general random access is not possible) then the demux is used to pull
> out what the buffer wants from the in coming stream.
>
> Basically, there is no point in doing local demux of incoming data as this
> is better left to the core (which knows about everything that wants the data
> and can chose appropriately).
>
> Now, if you have a true random access part (any channel, any order any time -
> so basically convert on demand devices) then don't provide available_scan_masks
> and everything works as you say.


Aha so that is what available_scan_masks is for !

Now, if I set available_scan_masks it means that we should also change
the bmc150_accel_trigger_handler to always read the 3 axes, right?

This actually fits well with some optimizations Irina has in the works.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 04/11] iio: add support for hardware fifo
  2015-02-04 17:08       ` Jonathan Cameron
@ 2015-02-05 21:36         ` Octavian Purdila
  2015-02-08 10:53           ` Jonathan Cameron
  0 siblings, 1 reply; 50+ messages in thread
From: Octavian Purdila @ 2015-02-05 21:36 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio

On Wed, Feb 4, 2015 at 7:08 PM, Jonathan Cameron <jic23@kernel.org> wrote:
> On 05/01/15 11:29, Octavian Purdila wrote:
>> On Mon, Jan 5, 2015 at 2:07 AM, Jonathan Cameron <jic23@kernel.org> wrote:
>>> On 21/12/14 00:42, Octavian Purdila wrote:
>>>
>>> Thanks for taking this on!
>>>
>>> This all looks fairly sensible, though a few comments inline.
>>> One big semantic change I'd suggest is to allow the watermark
>>> level passed to the hardware to be a 'hint' rather than a hard
>>> and fast rull.  A lot of these hardware buffers are fairly small
>>> (perhaps 32 entries) and the devices can run fast so whilst
>>> we will obviously have to handle an interrupt often, we may well
>>> want to have a much larger software front end buffer with a
>>> much larger watermark.  For example, a 8192Hz accelerometer
>>> with 32 entry fifo (watermark at 16).  Will fire an interrupt 512 times
>>> a second.  Userspace might be only interested in getting data 32 times
>>> a second and hence want a watermark of 256 entries and probably have
>>> a buffer that is 512 entries long or more.
>>>
>>
>> Very good point with the above example, but I find the hint approach a
>> bit too hard to diagnose and tune by the application.
>>
>> Could we perhaps expose the hwfifo watermark as well, in addition to
>> the software watermark? We can even keep the hint behavior if the
>> application only touches the software watermark, but if it the
>> application directly sets the hwfifo level then we use that.
> Hmm. Not sure how well this would work.  We probably need a way of indicating
> the hardware buffer has not been 'pinned' to a particular value.
> Maybe we can have it read only?
> That way it is obvious what effect the 'hint' is having on the hardware
> without adding a confusing double control for the same thing...

Yeah, the double control do seem confusing...

>>> Hmm. I wonder to a degree if the trigger approach really makes sense for
>>> fifo equiped devices.  We've deliberately not added one in a few existing
>>> cases.
>>>
>>> Otherwise, is there a reason to run this separately from a trigger not using
>>> the fifo.  Surely that's just the same as a watermark of 1?
>>>
>>> Anyhow, a point for discussion!
>>
>> I might be misunderstand you here, but the reason for which we use a
>> separate trigger is to have a way to enable/disable FIFO mode, because
>> enabling the FIFO might have some downsides, e.g. more power
>> consumption. This matters only when the application is interested in
>> low latency sampling ( watermark of 1).
> Perhaps we use a watermark of one to disable the fifo if present.  Can't
> think why you'd want it under those circumstances unless the data can't
> be read without.  This then becomes a driver issue as all the core
> cares about is that the data turns up, not particularly whether it very
> briefly bounces through a buffer or not.
>>

There is another reason to use a trigger to enable/disable the FIFO.

Lets take the bmc150 driver and say that the user sets the any-motion
trigger. In this case we only get data in the buffer when the
accelerometer is moved regardless of sample_frequency. Now, if we
enable the FIFO, the user might expect to see this behavior unchanged
- get data only when the accelerometer is moved. With BMC150's FIFO
this is not true, the FIFO will be filled with data at the
sample_frequency. We effectively switched to a data ready trigger.

>> Yeah, I wanted to add some checks in the core to make sure that if the
>> driver is registering the hwfifo ops then it should allocate and
>> register a watermark trigger as well. If we decide to go with the
>> trigger approach, do you think it is a good idea to add the checks?
>>
> If so, but I'll be honest I really don't like the trigger approach here.
> It feels like an abuse of an interface that is really there to allow
> synchronized capture/ controllable capture on devices without fixed
> timing... (when they are fixed, the point is really to allow other
> non fixed devices to lock on and sample at the same time - very handy
> for inertial data fusion and other places...)

Ah, I was not aware of what the trigger abstraction was intended for.
I always thought it was the equivalent of a device interrupt so it
felt natural to me to implement it as a trigger.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 11/11] iio: bmc150: add support for hardware fifo
  2015-02-05 20:04             ` Octavian Purdila
@ 2015-02-06 12:19               ` Jonathan Cameron
  0 siblings, 0 replies; 50+ messages in thread
From: Jonathan Cameron @ 2015-02-06 12:19 UTC (permalink / raw)
  To: Octavian Purdila, Jonathan Cameron
  Cc: linux-iio, Irina Tirdea, Srinivas Pandruvada



On 5 February 2015 20:04:45 GMT+00:00, Octavian Purdila <octavian.purdila@intel.com> wrote:
>On Thu, Feb 5, 2015 at 1:20 PM, Jonathan Cameron <jic23@kernel.org>
>wrote:
>>
>> On 04/02/15 20:18, Octavian Purdila wrote:
>> > On Wed, Feb 4, 2015 at 7:16 PM, Jonathan Cameron <jic23@kernel.org>
>wrote:
>> > <snip>
>> >>>> As this is on the flush rather than an interrupt these are going
>> >>>> to be of dubious benefit... There isn't an obvious way of doing
>better though
>> >>>> unless we do have an interrupt.  In that case you want to grab
>them as
>> >>>> early as possible (typically even in the interrupt top half) and
>pass it
>> >>>> down to where you want to use it.
>> >>>
>> >>> Actually flush gets called from two places: from the watermark
>trigger
>> >>> and in this case we take the timestamp in the IRQ handler, and
>when we
>> >>> do a read or poll and there is not enough data available in the
>> >>> buffer.
>> >>>
>> >>> For this later case we will have an error of up to a maximum of a
>one
>> >>> sample period since flush was called in between one of the
>sampling
>> >>> periods - the watermark interrupt makes sure we don't stall
>forever.
>> >>> That is not that bad.
>> >> Not terrible.  I wonder if we want to indicated a dubious
>timestamp
>> >> in some way?  Or maybe event specify a jitter on the channel?
>> >> (been wondering if we want this sort of description for channels
>in
>> >> general - how noisy are they?)  Can be very useful to userspace
>and
>> >> is often tied up with the particular settings of the device.
>> >
>> > Do you mean adding something like IIO_CHAN_INFO_JITTER? That would
>be
>> > nice, but in this case the value is variable and depends on the
>> > sampling frequency. What could work would be to also add a new
>event
>> > IIO_EV_TYPE_JITTER_CHANGED and issue it when the sampling frequency
>is
>> > changed.
>> General principle has always been that any sysfs type writes can
>effect
>> any of other attributes, so if userspace cares it should verify that
>> everything is as it expects.
>> >
>> > But at this point is getting too complex and I don't know how much
>it
>> > helps userspace.
>> Definitely a job for another day!
>>
>> Also in this category is having _available type information for all
>> attributes, rather just some. Makes for nicer handling in userspace
>> but adds a lot of additional sysfs files!
>> >
>> >
>> >>> Also, the later case should be an exception if the application
>sets
>> >>> the right watermark level and uses the right timeout. Otherwise
>it
>> >>> will not use power optimally which is the whole point of the hw
>fifo.
>> >>>
>> >>>>> +
>> >>>>> +     tstamp = data->timestamp - count * sample_freq;
>> >>>>> +
>> >>>>> +     for (i = 0; i < count; i++) {
>> >>>>> +             u16 sample[8];
>> >>>>> +             int j, bit;
>> >>>>> +
>> >>>>> +             j = 0;
>> >>>>> +             for_each_set_bit(bit,
>indio_dev->buffer->scan_mask,
>> >>>>> +                              indio_dev->masklength) {
>> >>>>> +                     memcpy(&sample[j++], &buffer[i * 3 +
>bit], 2);
>> >>>>> +             }
>> >>>>
>> >>>> A local demux rather than using the main iio one. Given you
>clearly read the
>> >>>> lot anyway is there any reason not to just pass it all on and
>let the IIO
>> >>>> demux handling the demux on the way to the kfifo?
>> >>>>
>> >>>
>> >>> Hmm, isn't the demux part only used when we have client buffers? 
>The
>> >>> demux part is not used at all in my tests, due to
>> >>> indio_dev->active_scan_mask being equal to buffer->scan_mask.
>> >> I'm guessing you figured this out. Yes, only used with client
>buffers,
>> >> but the normal buffered access is a client buffer :)
>> >>>
>> >
>> > Correct me if I am wrong: when we only use normal buffer access (no
>> > kernel clients) the active_scan_mask is always equal to
>> > buffer->scan_mask thus no demux will happen in core. So we still
>need
>> > to do the demux in the driver.
>> >
>> > In fact the above is true when we have only one client, be it user
>or kernel.
>> Not quite.  If the device driver provides available_scan_masks (e.g.
>indicates
>> that general random access is not possible) then the demux is used to
>pull
>> out what the buffer wants from the in coming stream.
>>
>> Basically, there is no point in doing local demux of incoming data as
>this
>> is better left to the core (which knows about everything that wants
>the data
>> and can chose appropriately).
>>
>> Now, if you have a true random access part (any channel, any order
>any time -
>> so basically convert on demand devices) then don't provide
>available_scan_masks
>> and everything works as you say.
>
>
>Aha so that is what available_scan_masks is for !
>
>Now, if I set available_scan_masks it means that we should also change
>the bmc150_accel_trigger_handler to always read the 3 axes, right?
Yes
>
>This actually fits well with some optimizations Irina has in the works.
>--
>To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 04/11] iio: add support for hardware fifo
  2015-02-05 21:36         ` Octavian Purdila
@ 2015-02-08 10:53           ` Jonathan Cameron
  2015-02-09 13:44             ` Octavian Purdila
  0 siblings, 1 reply; 50+ messages in thread
From: Jonathan Cameron @ 2015-02-08 10:53 UTC (permalink / raw)
  To: Octavian Purdila; +Cc: linux-iio

On 05/02/15 21:36, Octavian Purdila wrote:
> On Wed, Feb 4, 2015 at 7:08 PM, Jonathan Cameron <jic23@kernel.org> wrote:
>> On 05/01/15 11:29, Octavian Purdila wrote:
>>> On Mon, Jan 5, 2015 at 2:07 AM, Jonathan Cameron <jic23@kernel.org> wrote:
>>>> On 21/12/14 00:42, Octavian Purdila wrote:
>>>>
>>>> Thanks for taking this on!
>>>>
>>>> This all looks fairly sensible, though a few comments inline.
>>>> One big semantic change I'd suggest is to allow the watermark
>>>> level passed to the hardware to be a 'hint' rather than a hard
>>>> and fast rull.  A lot of these hardware buffers are fairly small
>>>> (perhaps 32 entries) and the devices can run fast so whilst
>>>> we will obviously have to handle an interrupt often, we may well
>>>> want to have a much larger software front end buffer with a
>>>> much larger watermark.  For example, a 8192Hz accelerometer
>>>> with 32 entry fifo (watermark at 16).  Will fire an interrupt 512 times
>>>> a second.  Userspace might be only interested in getting data 32 times
>>>> a second and hence want a watermark of 256 entries and probably have
>>>> a buffer that is 512 entries long or more.
>>>>
>>>
>>> Very good point with the above example, but I find the hint approach a
>>> bit too hard to diagnose and tune by the application.
>>>
>>> Could we perhaps expose the hwfifo watermark as well, in addition to
>>> the software watermark? We can even keep the hint behavior if the
>>> application only touches the software watermark, but if it the
>>> application directly sets the hwfifo level then we use that.
>> Hmm. Not sure how well this would work.  We probably need a way of indicating
>> the hardware buffer has not been 'pinned' to a particular value.
>> Maybe we can have it read only?
>> That way it is obvious what effect the 'hint' is having on the hardware
>> without adding a confusing double control for the same thing...
> 
> Yeah, the double control do seem confusing...
> 
>>>> Hmm. I wonder to a degree if the trigger approach really makes sense for
>>>> fifo equiped devices.  We've deliberately not added one in a few existing
>>>> cases.
>>>>
>>>> Otherwise, is there a reason to run this separately from a trigger not using
>>>> the fifo.  Surely that's just the same as a watermark of 1?
>>>>
>>>> Anyhow, a point for discussion!
>>>
>>> I might be misunderstand you here, but the reason for which we use a
>>> separate trigger is to have a way to enable/disable FIFO mode, because
>>> enabling the FIFO might have some downsides, e.g. more power
>>> consumption. This matters only when the application is interested in
>>> low latency sampling ( watermark of 1).
>> Perhaps we use a watermark of one to disable the fifo if present.  Can't
>> think why you'd want it under those circumstances unless the data can't
>> be read without.  This then becomes a driver issue as all the core
>> cares about is that the data turns up, not particularly whether it very
>> briefly bounces through a buffer or not.
>>>
> 
> There is another reason to use a trigger to enable/disable the FIFO.
> 
> Lets take the bmc150 driver and say that the user sets the any-motion
> trigger. In this case we only get data in the buffer when the
> accelerometer is moved regardless of sample_frequency. Now, if we
> enable the FIFO, the user might expect to see this behavior unchanged
> - get data only when the accelerometer is moved. With BMC150's FIFO
> this is not true, the FIFO will be filled with data at the
> sample_frequency. We effectively switched to a data ready trigger.
Hmm. They way to stop that would be to prevent the fifo being enabled
if the any-motion trigger is enabled.  Effectively the hardware doesn't
support doing this in a coherent (e.g. vaguely expected!) way.

This is getting a little tricky.  My general concept of this would normally
say that a hardware fifo and trigger are mutually exclusive.  We've effectively
never seen both in a single driver before.

I can see it might be a little confusing to have to 'unset' the trigger if
the fifo is to be used.  The question is which is worse from a usability
point of view?  From a control point of view, both are fine - we can do
what we want either way.

So options:

1) Have a 'fake' trigger for the hardware fifo. This trigger is set to reject
   any other devices binding to it.

2) Use no trigger when enabling the hardware fifo.  Basically if the buffer
   is enabled with no trigger and a watermark of greater than 1 it will go
   through the fifo.  If watermark is 1 it won't (or at least userspace will
   think it looks like it doesn't).  If a trigger is selected, then the
   watermark for the software buffer will work as normal, but the hardware
   fifo will be disabled (and this will be reflected in the hw_watermark
   value if read).

The second option corresponds to what our few existing hardware buffered drivers
effectively do.  Be it that they don't have a trigger consumer registered so
no one would try to set a trigger!
> 
>>> Yeah, I wanted to add some checks in the core to make sure that if the
>>> driver is registering the hwfifo ops then it should allocate and
>>> register a watermark trigger as well. If we decide to go with the
>>> trigger approach, do you think it is a good idea to add the checks?
>>>
>> If so, but I'll be honest I really don't like the trigger approach here.
>> It feels like an abuse of an interface that is really there to allow
>> synchronized capture/ controllable capture on devices without fixed
>> timing... (when they are fixed, the point is really to allow other
>> non fixed devices to lock on and sample at the same time - very handy
>> for inertial data fusion and other places...)
> 
> Ah, I was not aware of what the trigger abstraction was intended for.
> I always thought it was the equivalent of a device interrupt so it
> felt natural to me to implement it as a trigger.
It's always been an interesting corner as it's sometimes helpful for
events to trigger data capture (e.g. the anymotion-triggers).
At somepoint I'd like to figure out how to allow any iio event
to act as at trigger in a generic fashion.  Keeping the interface
clean for that might however be a pain.  Probably more of the configfs
magic that we've discussed on the list before (and I keep making a
start on but never finishing!)

Jonathan

^ permalink raw reply	[flat|nested] 50+ messages in thread

* Re: [PATCH v2 04/11] iio: add support for hardware fifo
  2015-02-08 10:53           ` Jonathan Cameron
@ 2015-02-09 13:44             ` Octavian Purdila
  0 siblings, 0 replies; 50+ messages in thread
From: Octavian Purdila @ 2015-02-09 13:44 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio

On Sun, Feb 8, 2015 at 12:53 PM, Jonathan Cameron <jic23@kernel.org> wrote:
> On 05/02/15 21:36, Octavian Purdila wrote:
>> On Wed, Feb 4, 2015 at 7:08 PM, Jonathan Cameron <jic23@kernel.org> wrote:
>>> On 05/01/15 11:29, Octavian Purdila wrote:
>>>> On Mon, Jan 5, 2015 at 2:07 AM, Jonathan Cameron <jic23@kernel.org> wrote:
>>>>> On 21/12/14 00:42, Octavian Purdila wrote:
>>>>>
>>>>> Thanks for taking this on!
>>>>>
>>>>> This all looks fairly sensible, though a few comments inline.
>>>>> One big semantic change I'd suggest is to allow the watermark
>>>>> level passed to the hardware to be a 'hint' rather than a hard
>>>>> and fast rull.  A lot of these hardware buffers are fairly small
>>>>> (perhaps 32 entries) and the devices can run fast so whilst
>>>>> we will obviously have to handle an interrupt often, we may well
>>>>> want to have a much larger software front end buffer with a
>>>>> much larger watermark.  For example, a 8192Hz accelerometer
>>>>> with 32 entry fifo (watermark at 16).  Will fire an interrupt 512 times
>>>>> a second.  Userspace might be only interested in getting data 32 times
>>>>> a second and hence want a watermark of 256 entries and probably have
>>>>> a buffer that is 512 entries long or more.
>>>>>
>>>>
>>>> Very good point with the above example, but I find the hint approach a
>>>> bit too hard to diagnose and tune by the application.
>>>>
>>>> Could we perhaps expose the hwfifo watermark as well, in addition to
>>>> the software watermark? We can even keep the hint behavior if the
>>>> application only touches the software watermark, but if it the
>>>> application directly sets the hwfifo level then we use that.
>>> Hmm. Not sure how well this would work.  We probably need a way of indicating
>>> the hardware buffer has not been 'pinned' to a particular value.
>>> Maybe we can have it read only?
>>> That way it is obvious what effect the 'hint' is having on the hardware
>>> without adding a confusing double control for the same thing...
>>
>> Yeah, the double control do seem confusing...
>>
>>>>> Hmm. I wonder to a degree if the trigger approach really makes sense for
>>>>> fifo equiped devices.  We've deliberately not added one in a few existing
>>>>> cases.
>>>>>
>>>>> Otherwise, is there a reason to run this separately from a trigger not using
>>>>> the fifo.  Surely that's just the same as a watermark of 1?
>>>>>
>>>>> Anyhow, a point for discussion!
>>>>
>>>> I might be misunderstand you here, but the reason for which we use a
>>>> separate trigger is to have a way to enable/disable FIFO mode, because
>>>> enabling the FIFO might have some downsides, e.g. more power
>>>> consumption. This matters only when the application is interested in
>>>> low latency sampling ( watermark of 1).
>>> Perhaps we use a watermark of one to disable the fifo if present.  Can't
>>> think why you'd want it under those circumstances unless the data can't
>>> be read without.  This then becomes a driver issue as all the core
>>> cares about is that the data turns up, not particularly whether it very
>>> briefly bounces through a buffer or not.
>>>>
>>
>> There is another reason to use a trigger to enable/disable the FIFO.
>>
>> Lets take the bmc150 driver and say that the user sets the any-motion
>> trigger. In this case we only get data in the buffer when the
>> accelerometer is moved regardless of sample_frequency. Now, if we
>> enable the FIFO, the user might expect to see this behavior unchanged
>> - get data only when the accelerometer is moved. With BMC150's FIFO
>> this is not true, the FIFO will be filled with data at the
>> sample_frequency. We effectively switched to a data ready trigger.
> Hmm. They way to stop that would be to prevent the fifo being enabled
> if the any-motion trigger is enabled.  Effectively the hardware doesn't
> support doing this in a coherent (e.g. vaguely expected!) way.
>
> This is getting a little tricky.  My general concept of this would normally
> say that a hardware fifo and trigger are mutually exclusive.  We've effectively
> never seen both in a single driver before.
>
> I can see it might be a little confusing to have to 'unset' the trigger if
> the fifo is to be used.  The question is which is worse from a usability
> point of view?  From a control point of view, both are fine - we can do
> what we want either way.
>
> So options:
>
> 1) Have a 'fake' trigger for the hardware fifo. This trigger is set to reject
>    any other devices binding to it.
>
> 2) Use no trigger when enabling the hardware fifo.  Basically if the buffer
>    is enabled with no trigger and a watermark of greater than 1 it will go
>    through the fifo.  If watermark is 1 it won't (or at least userspace will
>    think it looks like it doesn't).  If a trigger is selected, then the
>    watermark for the software buffer will work as normal, but the hardware
>    fifo will be disabled (and this will be reflected in the hw_watermark
>    value if read).
>
> The second option corresponds to what our few existing hardware buffered drivers
> effectively do.  Be it that they don't have a trigger consumer registered so
> no one would try to set a trigger!

OK, the second approach seems the right way to go. It matches nicely
with the trigger-less / hardware buffered drivers, things I did not
looked closely enough before :)

I will rework the patch set with this approach, hopefully by end of this week.

Thanks a lot for the reviews and feedback Jonathan !


>>>> Yeah, I wanted to add some checks in the core to make sure that if the
>>>> driver is registering the hwfifo ops then it should allocate and
>>>> register a watermark trigger as well. If we decide to go with the
>>>> trigger approach, do you think it is a good idea to add the checks?
>>>>
>>> If so, but I'll be honest I really don't like the trigger approach here.
>>> It feels like an abuse of an interface that is really there to allow
>>> synchronized capture/ controllable capture on devices without fixed
>>> timing... (when they are fixed, the point is really to allow other
>>> non fixed devices to lock on and sample at the same time - very handy
>>> for inertial data fusion and other places...)
>>
>> Ah, I was not aware of what the trigger abstraction was intended for.
>> I always thought it was the equivalent of a device interrupt so it
>> felt natural to me to implement it as a trigger.
> It's always been an interesting corner as it's sometimes helpful for
> events to trigger data capture (e.g. the anymotion-triggers).
> At somepoint I'd like to figure out how to allow any iio event
> to act as at trigger in a generic fashion.  Keeping the interface
> clean for that might however be a pain.  Probably more of the configfs
> magic that we've discussed on the list before (and I keep making a
> start on but never finishing!)
>

That sounds cool :)

^ permalink raw reply	[flat|nested] 50+ messages in thread

end of thread, other threads:[~2015-02-09 13:44 UTC | newest]

Thread overview: 50+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-21  0:42 [PATCH v2 00/11] iio: add support for hardware buffers Octavian Purdila
2014-12-21  0:42 ` [PATCH v2 01/11] iio: buffer: fix custom buffer attributes copy Octavian Purdila
2015-01-04 11:25   ` Jonathan Cameron
2015-01-04 11:34     ` Lars-Peter Clausen
2015-01-04 16:11       ` Jonathan Cameron
2014-12-21  0:42 ` [PATCH v2 02/11] iio: buffer: refactor buffer attributes setup Octavian Purdila
2015-01-04 11:31   ` Jonathan Cameron
2015-01-05 10:48     ` Octavian Purdila
2014-12-21  0:42 ` [PATCH v2 03/11] iio: add watermark logic to iio read and poll Octavian Purdila
2015-01-04 15:44   ` Jonathan Cameron
2015-01-25 21:22   ` Hartmut Knaack
2015-01-26  9:40     ` Octavian Purdila
2014-12-21  0:42 ` [PATCH v2 04/11] iio: add support for hardware fifo Octavian Purdila
2015-01-04 16:07   ` Jonathan Cameron
2015-01-05 11:29     ` Octavian Purdila
2015-02-04 17:08       ` Jonathan Cameron
2015-02-05 21:36         ` Octavian Purdila
2015-02-08 10:53           ` Jonathan Cameron
2015-02-09 13:44             ` Octavian Purdila
2015-01-28 23:46   ` Hartmut Knaack
2015-01-29 11:38     ` Octavian Purdila
2015-01-29 22:49       ` Hartmut Knaack
2015-02-04 17:18         ` Jonathan Cameron
2015-02-04 17:11       ` Jonathan Cameron
2014-12-21  0:42 ` [PATCH v2 05/11] iio: bmc150: refactor slope duration and threshold update Octavian Purdila
2015-01-04 16:21   ` Jonathan Cameron
2015-01-06 18:53     ` Srinivas Pandruvada
2015-01-28  9:22       ` Octavian Purdila
2015-01-28 17:15         ` Srinivas Pandruvada
2014-12-21  0:42 ` [PATCH v2 06/11] iio: bmc150: refactor interrupt enabling Octavian Purdila
2015-01-04 16:27   ` Jonathan Cameron
2015-01-28 10:33     ` Octavian Purdila
2014-12-21  0:42 ` [PATCH v2 07/11] iio: bmc150: exit early if event / trigger state is not changed Octavian Purdila
2015-01-04 16:29   ` Jonathan Cameron
2014-12-21  0:42 ` [PATCH v2 08/11] iio: bmc150: introduce bmc150_accel_interrupt Octavian Purdila
2015-01-04 16:36   ` Jonathan Cameron
2015-01-28 11:09     ` Octavian Purdila
2015-01-28 13:20       ` Jonathan Cameron
2014-12-21  0:42 ` [PATCH v2 09/11] iio: bmc150: introduce bmc150_accel_trigger Octavian Purdila
2015-01-04 16:39   ` Jonathan Cameron
2014-12-21  0:42 ` [PATCH v2 10/11] iio: bmc150: introduce bmc150_accel_event Octavian Purdila
2015-01-04 16:49   ` Jonathan Cameron
2014-12-21  0:42 ` [PATCH v2 11/11] iio: bmc150: add support for hardware fifo Octavian Purdila
2015-01-04 17:08   ` Jonathan Cameron
2015-01-28 19:26     ` Octavian Purdila
2015-02-04 17:16       ` Jonathan Cameron
2015-02-04 20:18         ` Octavian Purdila
2015-02-05 11:20           ` Jonathan Cameron
2015-02-05 20:04             ` Octavian Purdila
2015-02-06 12: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.