[PATCH 2/4] iio: st_sensors: Add threshold events support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds threshold events support for the ST common
library.

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);
 	}
 	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 (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);
+
+	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)
+		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)
+		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);
+
+	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, \
 	.address = addr, \
 	.scan_type = { \
 		.sign = s, \
@@ -111,6 +118,12 @@ struct st_sensor_fullscale {
 	struct st_sensor_fullscale_avl fs_avl[ST_SENSORS_FULLSCALE_AVL_MAX];
 };
 
+struct st_sensor_register {
+	u8 addr;
+	u8 mask;
+	u8 val;
+};
+
 /**
  * struct st_sensor_bdu - ST sensor device block data update
  * @addr: address of the register.
@@ -141,6 +154,47 @@ struct st_sensor_data_ready_irq {
 };
 
 /**
+ * struct st_sensor_event - event data.
+ * @bit: position of bit in status register related to event
+ * @chan: channel number.
+ * @chan_type: channel type.
+ * @modifier: modifier for the channel.
+ * @event_type: type of the event.
+ * @direction: direction of the event.
+ * @event_ths_reg:  represents the threshold
+ *	register of event.
+ */
+struct st_sensor_event {
+	u8 bit;
+	u8 chan;
+	enum iio_chan_type chan_type;
+	enum iio_modifier modifier;
+	enum iio_event_type event_type;
+	enum iio_event_direction direction;
+	struct st_sensor_register event_ths_reg;
+};
+
+/**
+ * struct st_sensor_event_irq -ST sensor event interrupt.
+ * @addr: address of the interrupt register.
+ * @mask: mask to write on/off value.
+ * @event_count: number of events declared in @events array.
+ * @ctrl_reg: represents the control register
+ *	of event system
+ * @status_reg: status register of event subsystem.
+ * @events array: driver events declared by user
+ */
+struct st_sensor_event_irq {
+	u8 addr;
+	u8 mask;
+	u8 event_count;
+	struct st_sensor_register ctrl_reg;
+	struct st_sensor_register status_reg;
+	struct st_sensor_event events[ST_SENSORS_EVENTS_MAX];
+};
+
+
+/**
  * struct st_sensor_transfer_buffer - ST sensor device I/O buffer
  * @buf_lock: Mutex to protect rx and tx buffers.
  * @tx_buf: Buffer used by SPI transfer function to send data to the sensors.
@@ -181,6 +235,7 @@ struct st_sensor_transfer_function {
  * @fs: Full scale register and full scale list available.
  * @bdu: Block data update register.
  * @drdy_irq: Data ready register of the sensor.
+ * @event_irq: Event register of the sensor.
  * @multi_read_bit: Use or not particular bit for [I2C/SPI] multi-read.
  * @bootime: samples to discard when sensor passing from power-down to power-up.
  */
@@ -194,6 +249,7 @@ struct st_sensors {
 	struct st_sensor_fullscale fs;
 	struct st_sensor_bdu bdu;
 	struct st_sensor_data_ready_irq drdy_irq;
+	struct st_sensor_event_irq event_irq;
 	bool multi_read_bit;
 	unsigned int bootime;
 };
@@ -209,9 +265,11 @@ struct st_sensors {
  * @buffer_data: Data used by buffer part.
  * @odr: Output data rate of the sensor [Hz].
  * num_data_channels: Number of data channels used in buffer.
+ * @events_flag: Data used by event part.
  * @irq_map: Container of mapped IRQs.
  * @drdy_int_pin: Redirect DRDY on pin 1 (1) or pin 2 (2).
  * @get_irq_data_ready: Function to get the IRQ used for data ready signal.
+ * @get_irq_event: Function to get the IRQ used for event signal.
  * @tf: Transfer function structure used by I/O operations.
  * @tb: Transfer buffers and mutex used by I/O operations.
  */
@@ -228,11 +286,13 @@ struct st_sensor_data {
 
 	unsigned int odr;
 	unsigned int num_data_channels;
+	unsigned int events_flag;
 	unsigned int irq_map[ST_SENSORS_INT_MAX];
 
 	u8 drdy_int_pin;
 
 	unsigned int (*get_irq_data_ready) (struct iio_dev *indio_dev);
+	unsigned int (*get_irq_event) (struct iio_dev *indio_dev);
 
 	const struct st_sensor_transfer_function *tf;
 	struct st_sensor_transfer_buffer tb;
@@ -292,4 +352,19 @@ ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
 ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
 				struct device_attribute *attr, char *buf);
 
+int st_sensors_read_event_config(struct iio_dev *indio_dev,
+				u64 event_code);
+
+int st_sensors_write_event_config(struct iio_dev *indio_dev,
+				  u64 event_code, int state);
+
+int st_sensors_read_event_value(struct iio_dev *indio_dev,
+				  u64 event_code, int *val);
+
+int st_sensors_write_event_value(struct iio_dev *indio_dev,
+				  u64 event_code, int val);
+
+int st_sensors_request_event_irq(struct iio_dev *indio_dev);
+
+int st_sensors_enable_events(struct iio_dev *indio_dev);
 #endif /* ST_SENSORS_H */
-- 
1.7.9.5

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




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux