summaryrefslogtreecommitdiffstats
path: root/drivers/iio/common
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2015-11-19 10:15:17 +0100
committerJonathan Cameron <jic23@kernel.org>2016-01-10 12:35:32 +0000
commita9fd053b56c6bb14972ab7a19da0b575fe4c5d66 (patch)
tree625a014d7de7fd5ad114f8c045e8f2821f99679a /drivers/iio/common
parentc4f0ebd91467c701b32879bf6091e5c91c6e79c1 (diff)
downloadop-kernel-dev-a9fd053b56c6bb14972ab7a19da0b575fe4c5d66.zip
op-kernel-dev-a9fd053b56c6bb14972ab7a19da0b575fe4c5d66.tar.gz
iio: st_sensors: support active-low interrupts
Most ST MEMS Sensors that support interrupts can also handle sending an active low interrupt, i.e. going from high to low on data ready (or other interrupt) and thus triggering on a falling edge to the interrupt controller. Set up logic to inspect the interrupt line we get for a sensor: if it is triggering on rising edge, leave everything alone, but if it triggers on falling edges, set up active low, and if unsupported configurations appear: warn with errors and reconfigure the interrupt to a rising edge, which all interrupt generating sensors support. Create a local header for st_sensors_core.h to share functions between the sensor core and the trigger setup code. Cc: Giuseppe Barba <giuseppe.barba@st.com> Cc: Denis Ciocca <denis.ciocca@st.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/common')
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c6
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.h8
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_trigger.c52
3 files changed, 54 insertions, 12 deletions
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index 8447c31..f5a2d44 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -18,13 +18,15 @@
#include <asm/unaligned.h>
#include <linux/iio/common/st_sensors.h>
+#include "st_sensors_core.h"
+
static inline u32 st_sensors_get_unaligned_le24(const u8 *p)
{
return (s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8;
}
-static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
- u8 reg_addr, u8 mask, u8 data)
+int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
+ u8 reg_addr, u8 mask, u8 data)
{
int err;
u8 new_data;
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.h b/drivers/iio/common/st_sensors/st_sensors_core.h
new file mode 100644
index 0000000..cd88098
--- /dev/null
+++ b/drivers/iio/common/st_sensors/st_sensors_core.h
@@ -0,0 +1,8 @@
+/*
+ * Local functions in the ST Sensors core
+ */
+#ifndef __ST_SENSORS_CORE_H
+#define __ST_SENSORS_CORE_H
+int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
+ u8 reg_addr, u8 mask, u8 data);
+#endif
diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c
index 3e90704..6a8c983 100644
--- a/drivers/iio/common/st_sensors/st_sensors_trigger.c
+++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c
@@ -14,32 +14,65 @@
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/interrupt.h>
-
#include <linux/iio/common/st_sensors.h>
-
+#include "st_sensors_core.h"
int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
const struct iio_trigger_ops *trigger_ops)
{
- int err;
+ int err, irq;
struct st_sensor_data *sdata = iio_priv(indio_dev);
+ unsigned long irq_trig;
sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
if (sdata->trig == NULL) {
- err = -ENOMEM;
dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
- goto iio_trigger_alloc_error;
+ return -ENOMEM;
}
- err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
+ irq = sdata->get_irq_data_ready(indio_dev);
+ irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
+ /*
+ * If the IRQ is triggered on falling edge, we need to mark the
+ * interrupt as active low, if the hardware supports this.
+ */
+ if (irq_trig == IRQF_TRIGGER_FALLING) {
+ if (!sdata->sensor_settings->drdy_irq.addr_ihl) {
+ dev_err(&indio_dev->dev,
+ "falling edge specified for IRQ but hardware "
+ "only support rising edge, will request "
+ "rising edge\n");
+ irq_trig = IRQF_TRIGGER_RISING;
+ } else {
+ /* Set up INT active low i.e. falling edge */
+ err = st_sensors_write_data_with_mask(indio_dev,
+ sdata->sensor_settings->drdy_irq.addr_ihl,
+ sdata->sensor_settings->drdy_irq.mask_ihl, 1);
+ if (err < 0)
+ goto iio_trigger_free;
+ dev_info(&indio_dev->dev,
+ "interrupts on the falling edge\n");
+ }
+ } else if (irq_trig == IRQF_TRIGGER_RISING) {
+ dev_info(&indio_dev->dev,
+ "interrupts on the rising edge\n");
+
+ } else {
+ dev_err(&indio_dev->dev,
+ "unsupported IRQ trigger specified (%lx), only "
+ "rising and falling edges supported, enforce "
+ "rising edge\n", irq_trig);
+ irq_trig = IRQF_TRIGGER_RISING;
+ }
+ err = request_threaded_irq(irq,
iio_trigger_generic_data_rdy_poll,
NULL,
- IRQF_TRIGGER_RISING,
+ irq_trig,
sdata->trig->name,
sdata->trig);
if (err) {
dev_err(&indio_dev->dev, "failed to request trigger IRQ.\n");
- goto request_irq_error;
+ goto iio_trigger_free;
}
iio_trigger_set_drvdata(sdata->trig, indio_dev);
@@ -57,9 +90,8 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
iio_trigger_register_error:
free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
-request_irq_error:
+iio_trigger_free:
iio_trigger_free(sdata->trig);
-iio_trigger_alloc_error:
return err;
}
EXPORT_SYMBOL(st_sensors_allocate_trigger);
OpenPOWER on IntegriCloud