On 07/02/13 13:15, Lukasz Czerwinski wrote:
This patch adds threshold events support for the ST common
library.
Various minor bits and bobs inline.
Signed-off-by: Lukasz Czerwinski <l.czerwinski@xxxxxxxxxxx>
Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>
---
drivers/iio/common/st_sensors/st_sensors_core.c | 218 ++++++++++++++++++++++-
drivers/iio/common/st_sensors/st_sensors_i2c.c | 11 ++
drivers/iio/common/st_sensors/st_sensors_spi.c | 11 ++
include/linux/iio/common/st_sensors.h | 79 +++++++-
4 files changed, 316 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index 461eaf2..211661e 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -13,7 +13,9 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
+#include <linux/iio/events.h>
#include <asm/unaligned.h>
+#include <linux/interrupt.h>
#include <linux/iio/common/st_sensors.h>
@@ -359,7 +361,8 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev,
*val = *val >> ch->scan_type.shift;
- err = st_sensors_set_enable(indio_dev, false);
+ if (!sdata->events_flag)
+ err = st_sensors_set_enable(indio_dev, false);
This could do with a comment to say why you don't want to disable the sensor.
(it is kind of obvious I suppose but it took me a few seconds to figure out
why!)
}
mutex_unlock(&indio_dev->mlock);
@@ -488,6 +491,219 @@ ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
}
EXPORT_SYMBOL(st_sensors_sysfs_scale_avail);
+static struct st_sensor_event *st_sensor_find_event_data(struct
+ st_sensor_data * sdata, u64 event_code)
+{
+ int i;
+ int mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code);
+ int type = IIO_EVENT_CODE_EXTRACT_TYPE(event_code);
+ int chan_type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code);
+ int dir = IIO_EVENT_CODE_EXTRACT_DIR(event_code);
+ struct st_sensor_event_irq *irq = &sdata->sensor->event_irq;
+ struct st_sensor_event *event;
+
+ if (irq->event_count == 0)
+ return NULL;
+
+ for (i = 0; i < irq->event_count; i++) {
+ event = &irq->events[i];
+
+ if (event->modifier == mod &&
+ event->event_type == type &&
+ event->direction == dir &&
+ event->chan_type == chan_type)
+ return event;
+ }
+
+ return NULL;
+}
+
+int st_sensors_read_event_config(struct iio_dev *indio_dev,
+ u64 event_code)
+{
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+ struct st_sensor_event *event =
+ st_sensor_find_event_data(sdata, event_code);
+
If (!event)
return -EINVAL;
would be more in keeping with how you have done it elsewhere and
slightly easier to follow.
+ if (event)
+ return (bool)(sdata->events_flag & (1 << event->bit));
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(st_sensors_read_event_config);
+
+int st_sensors_write_event_config(struct iio_dev *indio_dev,
+ u64 event_code,
+ int state)
+{
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+ struct st_sensor_event *event =
+ st_sensor_find_event_data(sdata, event_code);
+ int unsigned mask;
+ int err = -EINVAL;
+
+ mutex_lock(&indio_dev->mlock);
+
+ if (!event)
+ goto error;
+
+ mask = (1 << event->bit);
+ err = st_sensors_write_data_with_mask(indio_dev,
+ sdata->sensor->event_irq.ctrl_reg.addr,
+ mask, (bool)state);
+ if (err < 0)
+ goto error;
+
+ if (state)
+ sdata->events_flag |= mask;
+ else
+ sdata->events_flag &= ~mask;
+
+ err = st_sensors_set_enable(indio_dev, (bool)sdata->events_flag);
If err indicates an error?
+
+ mutex_unlock(&indio_dev->mlock);
+
+ return 0;
+
+error:
+ mutex_unlock(&indio_dev->mlock);
+ return err;
+}
+EXPORT_SYMBOL(st_sensors_write_event_config);
+
+int st_sensors_read_event_value(struct iio_dev *indio_dev,
+ u64 event_code,
+ int *val)
+{
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+ struct st_sensor_event *event =
+ st_sensor_find_event_data(sdata, event_code);
+ u8 byte;
+ int err;
+
+ if (!event)
Just do the return -EINVAL here instead of botherring with the goto.
+ goto error;
+
+ mutex_lock(&indio_dev->mlock);
+
+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
+ event->event_ths_reg.addr, &byte);
+ if (!err)
+ *val = byte;
+
+ mutex_unlock(&indio_dev->mlock);
+ return err;
+
+error:
+ return -EINVAL;
+
+}
+EXPORT_SYMBOL(st_sensors_read_event_value);
+
+int st_sensors_write_event_value(struct iio_dev *indio_dev,
+ u64 event_code,
+ int val)
+{
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+ struct st_sensor_event *event =
+ st_sensor_find_event_data(sdata, event_code);
+ int err;
+
+ if (!event)
return directly here.
+ goto error;
+
+ mutex_lock(&indio_dev->mlock);
+
+ err = st_sensors_write_data_with_mask(indio_dev,
+ event->event_ths_reg.addr,
+ event->event_ths_reg.mask,
+ (u8)val);
+
+ mutex_unlock(&indio_dev->mlock);
+
+ return err;
+error:
+ return -EINVAL;
+
+}
+EXPORT_SYMBOL(st_sensors_write_event_value);
+
+static irqreturn_t st_sensor_event_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+ struct st_sensor_event_irq *irq_data =
+ &sdata->sensor->event_irq;
+ struct st_sensor_event *event;
+ s64 timestamp = iio_get_time_ns();
+ u8 status, mask, i;
+ int err = -EIO;
+
+ if (sdata)
+ err = sdata->tf->read_byte(&sdata->tb,
+ sdata->dev,
+ irq_data->status_reg.addr,
+ &status);
+
+ if (err < 0)
+ goto exit;
+
+ for (i = 0; i < irq_data->event_count; i++) {
+ event = &irq_data->events[i];
+ mask = (1 << event->bit);
+ if (status & mask)
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(event->chan_type,
+ 0,
+ event->modifier,
+ event->event_type,
+ event->direction),
+ timestamp);
+ }
+
+exit:
+
+ return IRQ_HANDLED;
+}
+
+int st_sensors_request_event_irq(struct iio_dev *indio_dev)
+{
+ int err;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ err = request_threaded_irq(sdata->get_irq_event(indio_dev),
+ NULL,
+ st_sensor_event_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ dev_name(&indio_dev->dev),
+ indio_dev);
+
Don't bother introducing the local variable err.
return request_threaded_irq(...);
+ return err;
+}
+
+int st_sensors_enable_events(struct iio_dev *indio_dev)
+{
+ int err;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+ struct st_sensor_event_irq *irq = &sdata->sensor->event_irq;
+
+ err = st_sensors_write_data_with_mask(indio_dev,
+ irq->addr,
+ irq->mask,
+ 1);
+
+ if (err < 0)
+ goto error;
+
+ err = st_sensors_write_data_with_mask(indio_dev,
+ irq->ctrl_reg.addr,
+ irq->ctrl_reg.mask,
+ irq->ctrl_reg.val);
+error:
+ return err;
+}
+EXPORT_SYMBOL(st_sensors_enable_events);
+
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@xxxxxx>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors core");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c
index cad5acc..b364398 100644
--- a/drivers/iio/common/st_sensors/st_sensors_i2c.c
+++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c
@@ -27,6 +27,13 @@ static unsigned int st_sensors_i2c_get_data_rdy_irq(struct iio_dev *indio_dev)
return sdata->irq_map[ST_SENSORS_INT1];
}
+static unsigned int st_sensors_i2c_get_event_irq(struct iio_dev *indio_dev)
+{
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ return sdata->irq_map[ST_SENSORS_INT2];
+}
+
static void st_sensors_parse_platform_data(struct i2c_client *client,
struct iio_dev *indio_dev)
{
@@ -62,6 +69,9 @@ static void st_sensors_i2c_map_irqs(struct i2c_client *client,
sdata->irq_map[ST_SENSORS_INT1] =
st_sensors_i2c_map_irq(client, ST_SENSORS_INT1);
+
+ sdata->irq_map[ST_SENSORS_INT2] =
+ st_sensors_i2c_map_irq(client, ST_SENSORS_INT2);
}
static int st_sensors_i2c_read_byte(struct st_sensor_transfer_buffer *tb,
@@ -115,6 +125,7 @@ void st_sensors_i2c_configure(struct iio_dev *indio_dev,
sdata->tf = &st_sensors_tf_i2c;
st_sensors_i2c_map_irqs(client, indio_dev);
sdata->get_irq_data_ready = st_sensors_i2c_get_data_rdy_irq;
+ sdata->get_irq_event = st_sensors_i2c_get_event_irq;
}
EXPORT_SYMBOL(st_sensors_i2c_configure);
diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c
index 5531bd4..5baf0ec 100644
--- a/drivers/iio/common/st_sensors/st_sensors_spi.c
+++ b/drivers/iio/common/st_sensors/st_sensors_spi.c
@@ -28,6 +28,13 @@ static unsigned int st_sensors_spi_get_data_rdy_irq(struct iio_dev *indio_dev)
return sdata->irq_map[ST_SENSORS_INT1];
}
+static unsigned int st_sensors_spi_get_event_irq(struct iio_dev *indio_dev)
+{
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ return sdata->irq_map[ST_SENSORS_INT2];
+}
+
static void st_sensors_parse_platform_data(struct spi_device *spi,
struct iio_dev *indio_dev)
{
@@ -63,6 +70,9 @@ static void st_sensors_spi_map_irqs(struct spi_device *spi,
sdata->irq_map[ST_SENSORS_INT1] =
st_sensors_spi_map_irq(spi, ST_SENSORS_INT1);
+
+ sdata->irq_map[ST_SENSORS_INT2] =
+ st_sensors_spi_map_irq(spi, ST_SENSORS_INT2);
}
static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
@@ -155,6 +165,7 @@ void st_sensors_spi_configure(struct iio_dev *indio_dev,
sdata->tf = &st_sensors_tf_spi;
st_sensors_spi_map_irqs(spi, indio_dev);
sdata->get_irq_data_ready = st_sensors_spi_get_data_rdy_irq;
+ sdata->get_irq_event = st_sensors_spi_get_event_irq;
}
EXPORT_SYMBOL(st_sensors_spi_configure);
diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h
index 07e27e4..428d02b 100644
--- a/include/linux/iio/common/st_sensors.h
+++ b/include/linux/iio/common/st_sensors.h
@@ -14,6 +14,7 @@
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/irqreturn.h>
+#include <linux/iio/events.h>
#include <linux/iio/trigger.h>
#include <linux/bitops.h>
@@ -24,6 +25,7 @@
#define ST_SENSORS_ODR_LIST_MAX 10
#define ST_SENSORS_FULLSCALE_AVL_MAX 10
+#define ST_SENSORS_EVENTS_MAX 10
#define ST_SENSORS_NUMBER_ALL_CHANNELS 4
#define ST_SENSORS_ENABLE_ALL_AXIS 0x07
@@ -44,14 +46,19 @@
#define ST_SENSORS_INT1 0
#define ST_SENSORS_INT2 1
+#define ST_SENSORS_LSM_EVENTS_MASK \
+ (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
+ IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
+
#define ST_SENSORS_LSM_CHANNELS(device_type, mask, index, mod, \
- ch2, s, endian, rbits, sbits, addr) \
+ ch, s, endian, rbits, sbits, addr) \
{ \
.type = device_type, \
.modified = mod, \
.info_mask_separate = mask, \
.scan_index = index, \
- .channel2 = ch2, \
+ .channel = ch, \
+ .channel2 = ch, \
This is 'interesting'. What is the intent?
The result will be writing the modifier to both channel and channel2.
I don't htink that will have any effect, but it is incorrect so please
drop the setting of channel. It might be more appropriate to name
you ch instead as mod or something like that to make it clear what
is going on?