devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4]iio: STMicroelectronics DT and event support
@ 2013-07-02 12:15 Lukasz Czerwinski
       [not found] ` <1372767338-13179-1-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  0 siblings, 1 reply; 11+ messages in thread
From: Lukasz Czerwinski @ 2013-07-02 12:15 UTC (permalink / raw)
  To: jic23-DgEjT+Ai2ygdnm+yROfE0A, denis.ciocca-qxv4g6HH51o
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Lukasz Czerwinski

Hi,

This is the patchset that adds device tree and event subsytem support
for generic st_common library.

I tested our patches with Exynos4x12 board. We tested sensors:
- LSM330DLC accelerometer and gyroscope (I2C)
- LPS331AP pressure sensor (I2C)

Generally it works fine.
I couldn't implement event patch for lsm330dlc gyroscope because I
don't have connected INT1 pin to SoC.

My implementation allows to use event system or triggered buffer by
proper declaration of irqs in device tree/platform data.

Jacek Anaszewski (1):
  iio: lps331ap: Add support for DT

Lukasz Czerwinski (3):
  iio: st_sensors:  Add DT bindings for st_accel and st_gyro
  iio: st_sensors: Add threshold events support
  iio: accel: Add event subsystem to st_accel driver

 .../bindings/iio/accelerometer/st_accel.txt        |   54 +++++
 .../devicetree/bindings/iio/gyroscope/st_gyro.txt  |   51 +++++
 .../bindings/iio/pressure/st_pressure.txt          |   41 ++++
 drivers/iio/accel/st_accel.h                       |   19 +-
 drivers/iio/accel/st_accel_core.c                  |  159 +++++++++++++-
 drivers/iio/accel/st_accel_i2c.c                   |   19 +-
 drivers/iio/accel/st_accel_spi.c                   |   19 +-
 drivers/iio/common/st_sensors/st_sensors_core.c    |  225 +++++++++++++++++++-
 drivers/iio/common/st_sensors/st_sensors_i2c.c     |   59 ++++-
 drivers/iio/common/st_sensors/st_sensors_spi.c     |   59 ++++-
 drivers/iio/gyro/st_gyro.h                         |   15 +-
 drivers/iio/gyro/st_gyro_core.c                    |    8 +-
 drivers/iio/gyro/st_gyro_i2c.c                     |   18 +-
 drivers/iio/gyro/st_gyro_spi.c                     |   18 +-
 drivers/iio/magnetometer/st_magn.h                 |    3 +-
 drivers/iio/magnetometer/st_magn_core.c            |    5 +-
 drivers/iio/magnetometer/st_magn_i2c.c             |    2 +-
 drivers/iio/magnetometer/st_magn_spi.c             |    2 +-
 drivers/iio/pressure/st_pressure.h                 |    3 +-
 drivers/iio/pressure/st_pressure_core.c            |   12 +-
 drivers/iio/pressure/st_pressure_i2c.c             |   11 +-
 drivers/iio/pressure/st_pressure_spi.c             |   11 +-
 include/linux/iio/common/st_sensors.h              |   88 +++++++-
 include/linux/platform_data/st_sensors_pdata.h     |    2 +
 24 files changed, 837 insertions(+), 66 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/accelerometer/st_accel.txt
 create mode 100644 Documentation/devicetree/bindings/iio/gyroscope/st_gyro.txt
 create mode 100644 Documentation/devicetree/bindings/iio/pressure/st_pressure.txt

-- 
1.7.9.5

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

* [PATCH 1/4] iio: st_sensors:  Add DT bindings for st_accel and st_gyro
       [not found] ` <1372767338-13179-1-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
@ 2013-07-02 12:15   ` Lukasz Czerwinski
  2013-07-02 12:15   ` [PATCH 2/4] iio: st_sensors: Add threshold events support Lukasz Czerwinski
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 11+ messages in thread
From: Lukasz Czerwinski @ 2013-07-02 12:15 UTC (permalink / raw)
  To: jic23-DgEjT+Ai2ygdnm+yROfE0A, denis.ciocca-qxv4g6HH51o
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Lukasz Czerwinski,
	Kyungmin Park

This patch adds DT support for the STM accelometers and gyroscopes.

Signed-off-by: Lukasz Czerwinski <l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 .../bindings/iio/accelerometer/st_accel.txt        |   53 ++++++++++++++++++++
 .../devicetree/bindings/iio/gyroscope/st_gyro.txt  |   51 +++++++++++++++++++
 drivers/iio/accel/st_accel.h                       |   19 ++++---
 drivers/iio/accel/st_accel_core.c                  |   10 ++--
 drivers/iio/accel/st_accel_i2c.c                   |   19 ++++++-
 drivers/iio/accel/st_accel_spi.c                   |   19 ++++++-
 drivers/iio/common/st_sensors/st_sensors_core.c    |    7 +--
 drivers/iio/common/st_sensors/st_sensors_i2c.c     |   48 ++++++++++++++++--
 drivers/iio/common/st_sensors/st_sensors_spi.c     |   48 ++++++++++++++++--
 drivers/iio/gyro/st_gyro.h                         |   15 +++---
 drivers/iio/gyro/st_gyro_core.c                    |    8 +--
 drivers/iio/gyro/st_gyro_i2c.c                     |   18 ++++++-
 drivers/iio/gyro/st_gyro_spi.c                     |   18 ++++++-
 drivers/iio/magnetometer/st_magn.h                 |    3 +-
 drivers/iio/magnetometer/st_magn_core.c            |    5 +-
 drivers/iio/magnetometer/st_magn_i2c.c             |    2 +-
 drivers/iio/magnetometer/st_magn_spi.c             |    2 +-
 drivers/iio/pressure/st_pressure.h                 |    3 +-
 drivers/iio/pressure/st_pressure_core.c            |   12 ++---
 drivers/iio/pressure/st_pressure_i2c.c             |    2 +-
 drivers/iio/pressure/st_pressure_spi.c             |    2 +-
 include/linux/iio/common/st_sensors.h              |    9 +++-
 include/linux/platform_data/st_sensors_pdata.h     |    2 +
 23 files changed, 312 insertions(+), 63 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/accelerometer/st_accel.txt
 create mode 100644 Documentation/devicetree/bindings/iio/gyroscope/st_gyro.txt

diff --git a/Documentation/devicetree/bindings/iio/accelerometer/st_accel.txt b/Documentation/devicetree/bindings/iio/accelerometer/st_accel.txt
new file mode 100644
index 0000000..9eab7d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/accelerometer/st_accel.txt
@@ -0,0 +1,53 @@
+STMicroelectronics 3D  accelerometer
+
+Required properties:
+
+  - compatible : should be one from
+	"st,lsm330dlhc-accel"
+	"st,lis3dh"
+	"st,lsm330d-accel"
+	"st,lsm330dl-accel"
+	"st,lsm330dlc-accel"
+	"st,lsm331dlh"
+	"st,lsm303dl-accel"
+	"st,lsm303dlh-accel"
+	"st,lsm303dlm-accel"
+	"st,lsm330-accel"
+
+  - reg : the I2C address of the accelerometer
+
+Optional properties:
+  - drdy-int-pin: default DRDY interrupt pin number (u8)
+  - interrupt-parent : phandle to the interrupt map subnode
+  - interrupts : interrupt mapping for st_accel interrupt sources:
+	0: INT1 irq_data_ready
+  - irq-map : irq sub-node defining interrupt map
+              (all properties listed below are required):
+      - #interrupt-cells : should be 1
+      - #address-cells : should be 0
+      - #size-cells : should be 0
+      - interrupt-map : table of entries consisting of three child elements:
+          - unit_interrupt_specifier - 0 : INT1, 1 : INT2
+          - interrupt parent phandle
+          - parent unit interrupt specifier consisiting of two elements:
+              - index of the interrupt within the controller
+              - flags : should be 0
+
+Example:
+
+lsm330dlc_accel@19 {
+	compatible = "st,lsm330dlc-accel";
+	reg = <0x19>;
+	drdy-int-pin = /bits/ 8 <1>;
+	interrupt-parent = <&lsm330dlc_accel_map>;
+	interrupts= <0>, <1>;
+
+	lsm330dlc_accel_map: lsm330dlc-accel-map {
+		compatible = "samsung,lsm330dlc-accel-map";
+		#interrupt-cells = <1>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		interrupt-map = <1 &gpx0 0 0>;
+	};
+};
+
diff --git a/Documentation/devicetree/bindings/iio/gyroscope/st_gyro.txt b/Documentation/devicetree/bindings/iio/gyroscope/st_gyro.txt
new file mode 100644
index 0000000..f4bf233
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/gyroscope/st_gyro.txt
@@ -0,0 +1,51 @@
+STMicroelectronics 3D  gyroscope
+
+Required properties:
+
+  - compatible : should be one from
+	"st,l3g4200d"
+	"st,lsm330d-gyro"
+	"st,lsm330dl-gyro"
+	"st,lsm330dlc-gyro"
+	"st,l3gd20"
+	"st,l3gd20h"
+	"st,l3g4is-ui"
+	"st,lsm330-gyro"
+
+  - reg : the I2C address of the gyroscope
+
+Optional properties:
+
+  - drdy-int-pin: default DRDY interrupt pin number (u8)
+  - interrupt-parent : phandle to the interrupt map subnode
+  - interrupts : interrupt mapping for st_accel interrupt sources:
+	0: INT1 irq_data_ready
+  - irq-map : irq sub-node defining interrupt map
+              (all properties listed below are required):
+      - #interrupt-cells : should be 1
+      - #address-cells : should be 0
+      - #size-cells : should be 0
+      - interrupt-map : table of entries consisting of three child elements:
+          - unit_interrupt_specifier - 0 : INT1, 1 : INT2
+          - interrupt parent phandle
+          - parent unit interrupt specifier consisiting of two elements:
+              - index of the interrupt within the controller
+              - flags : should be 0
+
+Example:
+
+lsm330dlc_gyro@6b {
+	compatible = "st,lsm330dlc-gyro";
+	reg = <0x6b>;
+	drdy-int-pin = /bits/ 8 <1>;
+	interrupt-parent = <&lsm330dlc_gyro_map>;
+	interrupts= <0> , <1>;
+
+	lsm330dlc_gyro_map: lsm330dlc-gyro-map {
+		compatible = "samsung,lsm330dlc-gyro-map";
+		#interrupt-cells = <1>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		interrupt-map = <0 &gpf0 3 0>;
+	};
+};
diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h
index c387763..08a0eb7 100644
--- a/drivers/iio/accel/st_accel.h
+++ b/drivers/iio/accel/st_accel.h
@@ -14,16 +14,16 @@
 #include <linux/types.h>
 #include <linux/iio/common/st_sensors.h>
 
-#define LSM303DLHC_ACCEL_DEV_NAME	"lsm303dlhc_accel"
+#define LSM303DLHC_ACCEL_DEV_NAME	"lsm303dlhc-accel"
 #define LIS3DH_ACCEL_DEV_NAME		"lis3dh"
-#define LSM330D_ACCEL_DEV_NAME		"lsm330d_accel"
-#define LSM330DL_ACCEL_DEV_NAME		"lsm330dl_accel"
-#define LSM330DLC_ACCEL_DEV_NAME	"lsm330dlc_accel"
+#define LSM330D_ACCEL_DEV_NAME		"lsm330d-accel"
+#define LSM330DL_ACCEL_DEV_NAME		"lsm330dl-accel"
+#define LSM330DLC_ACCEL_DEV_NAME	"lsm330dlc-accel"
 #define LIS331DLH_ACCEL_DEV_NAME	"lis331dlh"
-#define LSM303DL_ACCEL_DEV_NAME		"lsm303dl_accel"
-#define LSM303DLH_ACCEL_DEV_NAME	"lsm303dlh_accel"
-#define LSM303DLM_ACCEL_DEV_NAME	"lsm303dlm_accel"
-#define LSM330_ACCEL_DEV_NAME		"lsm330_accel"
+#define LSM303DL_ACCEL_DEV_NAME		"lsm303dl-accel"
+#define LSM303DLH_ACCEL_DEV_NAME	"lsm303dlh-accel"
+#define LSM303DLM_ACCEL_DEV_NAME	"lsm303dlm-accel"
+#define LSM330_ACCEL_DEV_NAME		"lsm330-accel"
 
 /**
 * struct st_sensors_platform_data - default accel platform data
@@ -33,8 +33,7 @@ static const struct st_sensors_platform_data default_accel_pdata = {
 	.drdy_int_pin = 1,
 };
 
-int st_accel_common_probe(struct iio_dev *indio_dev,
-					struct st_sensors_platform_data *pdata);
+int st_accel_common_probe(struct iio_dev *indio_dev);
 void st_accel_common_remove(struct iio_dev *indio_dev);
 
 #ifdef CONFIG_IIO_BUFFER
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index aef3c9b..385cd86 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -449,8 +449,7 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
 #define ST_ACCEL_TRIGGER_OPS NULL
 #endif
 
-int st_accel_common_probe(struct iio_dev *indio_dev,
-				struct st_sensors_platform_data *plat_data)
+int st_accel_common_probe(struct iio_dev *indio_dev)
 {
 	int err;
 	struct st_sensor_data *adata = iio_priv(indio_dev);
@@ -472,11 +471,10 @@ int st_accel_common_probe(struct iio_dev *indio_dev,
 						&adata->sensor->fs.fs_avl[0];
 	adata->odr = adata->sensor->odr.odr_avl[0].hz;
 
-	if (!plat_data)
-		plat_data =
-			(struct st_sensors_platform_data *)&default_accel_pdata;
+	if (!adata->dev->platform_data && !adata->dev->of_node)
+		adata->drdy_int_pin = default_accel_pdata.drdy_int_pin;
 
-	err = st_sensors_init_sensor(indio_dev, plat_data);
+	err = st_sensors_init_sensor(indio_dev);
 	if (err < 0)
 		goto st_accel_common_probe_error;
 
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index 58d164d..63992f2 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -36,7 +36,7 @@ static int st_accel_i2c_probe(struct i2c_client *client,
 
 	st_sensors_i2c_configure(indio_dev, client, adata);
 
-	err = st_accel_common_probe(indio_dev, client->dev.platform_data);
+	err = st_accel_common_probe(indio_dev);
 	if (err < 0)
 		goto st_accel_common_probe_error;
 
@@ -70,10 +70,27 @@ static const struct i2c_device_id st_accel_id_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
 
+#ifdef CONFIG_OF
+static struct of_device_id st_accel_dt_match[] = {
+	{ .compatible = "st,lsm330dlhc_accel" },
+	{ .compatible = "st,lis3dh" },
+	{ .compatible = "st,lsm330d-accel" },
+	{ .compatible = "st,lsm330dl-accel" },
+	{ .compatible = "st,lsm330dlc-accel" },
+	{ .compatible = "st,lsm331dlh" },
+	{ .compatible = "st,lsm303dl-accel" },
+	{ .compatible = "st,lsm303dlh-accel" },
+	{ .compatible = "st,lsm303dlm-accel" },
+	{ .compatible = "st,lsm330-accel" },
+	{ }
+};
+#endif
+
 static struct i2c_driver st_accel_driver = {
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = "st-accel-i2c",
+		.of_match_table = of_match_ptr(st_accel_dt_match),
 	},
 	.probe = st_accel_i2c_probe,
 	.remove = st_accel_i2c_remove,
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index 21ed929..671fd48 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -35,7 +35,7 @@ static int st_accel_spi_probe(struct spi_device *spi)
 
 	st_sensors_spi_configure(indio_dev, spi, adata);
 
-	err = st_accel_common_probe(indio_dev, spi->dev.platform_data);
+	err = st_accel_common_probe(indio_dev);
 	if (err < 0)
 		goto st_accel_common_probe_error;
 
@@ -69,10 +69,27 @@ static const struct spi_device_id st_accel_id_table[] = {
 };
 MODULE_DEVICE_TABLE(spi, st_accel_id_table);
 
+#ifdef CONFIG_OF
+static struct of_device_id st_accel_dt_match[] = {
+	{ .compatible = "st,lsm330dlhc-accel" },
+	{ .compatible = "st,lis3dh" },
+	{ .compatible = "st,lsm330d-accel" },
+	{ .compatible = "st,lsm330dl-accel" },
+	{ .compatible = "st,lsm330dlc-accel" },
+	{ .compatible = "st,lsm331dlh" },
+	{ .compatible = "st,lsm303dl-accel" },
+	{ .compatible = "st,lsm303dlh-accel" },
+	{ .compatible = "st,lsm303dlm-accel" },
+	{ .compatible = "st,lsm330-accel" },
+	{ }
+};
+#endif
+
 static struct spi_driver st_accel_driver = {
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = "st-accel-spi",
+		.of_match_table = of_match_ptr(st_accel_dt_match),
 	},
 	.probe = st_accel_spi_probe,
 	.remove = st_accel_spi_remove,
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index 965ee22..461eaf2 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -198,15 +198,14 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
 }
 EXPORT_SYMBOL(st_sensors_set_axis_enable);
 
-int st_sensors_init_sensor(struct iio_dev *indio_dev,
-					struct st_sensors_platform_data *pdata)
+int st_sensors_init_sensor(struct iio_dev *indio_dev)
 {
 	int err;
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
 
 	mutex_init(&sdata->tb.buf_lock);
 
-	switch (pdata->drdy_int_pin) {
+	switch (sdata->drdy_int_pin) {
 	case 1:
 		if (sdata->sensor->drdy_irq.mask_int1 == 0) {
 			dev_err(&indio_dev->dev,
@@ -214,7 +213,6 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
 			err = -EINVAL;
 			goto init_error;
 		}
-		sdata->drdy_int_pin = 1;
 		break;
 	case 2:
 		if (sdata->sensor->drdy_irq.mask_int2 == 0) {
@@ -223,7 +221,6 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
 			err = -EINVAL;
 			goto init_error;
 		}
-		sdata->drdy_int_pin = 2;
 		break;
 	default:
 		dev_err(&indio_dev->dev, "DRDY on pdata not valid.\n");
diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c
index 38af944..cad5acc 100644
--- a/drivers/iio/common/st_sensors/st_sensors_i2c.c
+++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c
@@ -8,6 +8,8 @@
  * Licensed under the GPL-2.
  */
 
+#include <linux/of.h>
+#include <linux/of_irq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -18,11 +20,48 @@
 
 #define ST_SENSORS_I2C_MULTIREAD	0x80
 
-static unsigned int st_sensors_i2c_get_irq(struct iio_dev *indio_dev)
+static unsigned int st_sensors_i2c_get_data_rdy_irq(struct iio_dev *indio_dev)
 {
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
 
-	return to_i2c_client(sdata->dev)->irq;
+	return sdata->irq_map[ST_SENSORS_INT1];
+}
+
+static void st_sensors_parse_platform_data(struct i2c_client *client,
+		struct iio_dev *indio_dev)
+{
+	struct st_sensor_data *sdata = iio_priv(indio_dev);
+	struct device_node *np = client->dev.of_node;
+	struct st_sensors_platform_data *pdata = client->dev.platform_data;
+
+	if (pdata)
+		sdata->drdy_int_pin = pdata->drdy_int_pin;
+	else if (np)
+		of_property_read_u8(np, "drdy-int-pin",
+			(u8 *)&sdata->drdy_int_pin);
+}
+
+static unsigned int st_sensors_i2c_map_irq(struct i2c_client *client,
+		unsigned int irq_pos)
+{
+	struct device_node *np = client->dev.of_node;
+	struct st_sensors_platform_data *pdata = client->dev.platform_data;
+
+	if (pdata)
+		return pdata->irqs[irq_pos];
+	else if (np)
+		return irq_of_parse_and_map(np, irq_pos);
+
+	return 0;
+}
+
+static void st_sensors_i2c_map_irqs(struct i2c_client *client,
+		struct iio_dev *indio_dev)
+{
+	struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+	sdata->irq_map[ST_SENSORS_INT1] =
+		st_sensors_i2c_map_irq(client, ST_SENSORS_INT1);
 }
 
 static int st_sensors_i2c_read_byte(struct st_sensor_transfer_buffer *tb,
@@ -71,8 +110,11 @@ void st_sensors_i2c_configure(struct iio_dev *indio_dev,
 	indio_dev->dev.parent = &client->dev;
 	indio_dev->name = client->name;
 
+	st_sensors_parse_platform_data(client, indio_dev);
+
 	sdata->tf = &st_sensors_tf_i2c;
-	sdata->get_irq_data_ready = st_sensors_i2c_get_irq;
+	st_sensors_i2c_map_irqs(client, indio_dev);
+	sdata->get_irq_data_ready = st_sensors_i2c_get_data_rdy_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 251baf6..5531bd4 100644
--- a/drivers/iio/common/st_sensors/st_sensors_spi.c
+++ b/drivers/iio/common/st_sensors/st_sensors_spi.c
@@ -8,6 +8,8 @@
  * Licensed under the GPL-2.
  */
 
+#include <linux/of.h>
+#include <linux/of_irq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -19,11 +21,48 @@
 #define ST_SENSORS_SPI_MULTIREAD	0xc0
 #define ST_SENSORS_SPI_READ		0x80
 
-static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev)
+static unsigned int st_sensors_spi_get_data_rdy_irq(struct iio_dev *indio_dev)
 {
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
 
-	return to_spi_device(sdata->dev)->irq;
+	return sdata->irq_map[ST_SENSORS_INT1];
+}
+
+static void st_sensors_parse_platform_data(struct spi_device *spi,
+		struct iio_dev *indio_dev)
+{
+	struct st_sensor_data *sdata = iio_priv(indio_dev);
+	struct device_node *np = spi->dev.of_node;
+	struct st_sensors_platform_data *pdata = spi->dev.platform_data;
+
+	if (pdata)
+		sdata->drdy_int_pin = pdata->drdy_int_pin;
+	else if (np)
+		of_property_read_u8(np, "drdy-int-pin",
+			(u8 *)&sdata->drdy_int_pin);
+}
+
+static unsigned int st_sensors_spi_map_irq(struct spi_device *spi,
+		unsigned int irq_pos)
+{
+	struct device_node *np = spi->dev.of_node;
+	struct st_sensors_platform_data *pdata = spi->dev.platform_data;
+
+	if (pdata)
+		return pdata->irqs[irq_pos];
+	else if (np)
+		return irq_of_parse_and_map(np, irq_pos);
+
+	return 0;
+}
+
+static void st_sensors_spi_map_irqs(struct spi_device *spi,
+		struct iio_dev *indio_dev)
+{
+	struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+	sdata->irq_map[ST_SENSORS_INT1] =
+		st_sensors_spi_map_irq(spi, ST_SENSORS_INT1);
 }
 
 static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
@@ -111,8 +150,11 @@ void st_sensors_spi_configure(struct iio_dev *indio_dev,
 	indio_dev->dev.parent = &spi->dev;
 	indio_dev->name = spi->modalias;
 
+	st_sensors_parse_platform_data(spi, indio_dev);
+
 	sdata->tf = &st_sensors_tf_spi;
-	sdata->get_irq_data_ready = st_sensors_spi_get_irq;
+	st_sensors_spi_map_irqs(spi, indio_dev);
+	sdata->get_irq_data_ready = st_sensors_spi_get_data_rdy_irq;
 }
 EXPORT_SYMBOL(st_sensors_spi_configure);
 
diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h
index f8f2bf8..81e5ec3 100644
--- a/drivers/iio/gyro/st_gyro.h
+++ b/drivers/iio/gyro/st_gyro.h
@@ -15,24 +15,23 @@
 #include <linux/iio/common/st_sensors.h>
 
 #define L3G4200D_GYRO_DEV_NAME		"l3g4200d"
-#define LSM330D_GYRO_DEV_NAME		"lsm330d_gyro"
-#define LSM330DL_GYRO_DEV_NAME		"lsm330dl_gyro"
-#define LSM330DLC_GYRO_DEV_NAME		"lsm330dlc_gyro"
+#define LSM330D_GYRO_DEV_NAME		"lsm330d-gyro"
+#define LSM330DL_GYRO_DEV_NAME		"lsm330dl-gyro"
+#define LSM330DLC_GYRO_DEV_NAME		"lsm330dlc-gyro"
 #define L3GD20_GYRO_DEV_NAME		"l3gd20"
 #define L3GD20H_GYRO_DEV_NAME		"l3gd20h"
-#define L3G4IS_GYRO_DEV_NAME		"l3g4is_ui"
-#define LSM330_GYRO_DEV_NAME		"lsm330_gyro"
+#define L3G4IS_GYRO_DEV_NAME		"l3g4is-ui"
+#define LSM330_GYRO_DEV_NAME		"lsm330-gyro"
 
 /**
  * struct st_sensors_platform_data - gyro platform data
  * @drdy_int_pin: DRDY on gyros is available only on INT2 pin.
  */
-static const struct st_sensors_platform_data gyro_pdata = {
+static const struct st_sensors_platform_data default_gyro_pdata = {
 	.drdy_int_pin = 2,
 };
 
-int st_gyro_common_probe(struct iio_dev *indio_dev,
-					struct st_sensors_platform_data *pdata);
+int st_gyro_common_probe(struct iio_dev *indio_dev);
 void st_gyro_common_remove(struct iio_dev *indio_dev);
 
 #ifdef CONFIG_IIO_BUFFER
diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c
index 85fa8d3..e86684c 100644
--- a/drivers/iio/gyro/st_gyro_core.c
+++ b/drivers/iio/gyro/st_gyro_core.c
@@ -302,8 +302,7 @@ static const struct iio_trigger_ops st_gyro_trigger_ops = {
 #define ST_GYRO_TRIGGER_OPS NULL
 #endif
 
-int st_gyro_common_probe(struct iio_dev *indio_dev,
-					struct st_sensors_platform_data *pdata)
+int st_gyro_common_probe(struct iio_dev *indio_dev)
 {
 	int err;
 	struct st_sensor_data *gdata = iio_priv(indio_dev);
@@ -325,7 +324,10 @@ int st_gyro_common_probe(struct iio_dev *indio_dev,
 						&gdata->sensor->fs.fs_avl[0];
 	gdata->odr = gdata->sensor->odr.odr_avl[0].hz;
 
-	err = st_sensors_init_sensor(indio_dev, pdata);
+	if (!gdata->dev->platform_data && !gdata->dev->of_node)
+		gdata->drdy_int_pin = default_gyro_pdata.drdy_int_pin;
+
+	err = st_sensors_init_sensor(indio_dev);
 	if (err < 0)
 		goto st_gyro_common_probe_error;
 
diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c
index c7a29a4..413062e 100644
--- a/drivers/iio/gyro/st_gyro_i2c.c
+++ b/drivers/iio/gyro/st_gyro_i2c.c
@@ -36,8 +36,8 @@ static int st_gyro_i2c_probe(struct i2c_client *client,
 
 	st_sensors_i2c_configure(indio_dev, client, gdata);
 
-	err = st_gyro_common_probe(indio_dev,
-				(struct st_sensors_platform_data *)&gyro_pdata);
+	err = st_gyro_common_probe(indio_dev);
+
 	if (err < 0)
 		goto st_gyro_common_probe_error;
 
@@ -69,10 +69,24 @@ static const struct i2c_device_id st_gyro_id_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, st_gyro_id_table);
 
+#ifdef CONFIG_OF
+static struct of_device_id st_gyro_dt_match[] = {
+	{ .compatible = "st,l3g4200d" },
+	{ .compatible = "st,lsm330d-gyro" },
+	{ .compatible = "st,lsm330dl-gyro" },
+	{ .compatible = "st,lsm330dlc-gyro" },
+	{ .compatible = "st,l3gd20" },
+	{ .compatible = "st,l3gd20h" },
+	{ .compatible = "st,l3g4is-ui" },
+	{ .compatible = "st,lsm330-gyro" },
+};
+#endif
+
 static struct i2c_driver st_gyro_driver = {
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = "st-gyro-i2c",
+		.of_match_table = of_match_ptr(st_gyro_dt_match),
 	},
 	.probe = st_gyro_i2c_probe,
 	.remove = st_gyro_i2c_remove,
diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c
index 14b0762..4956dcc 100644
--- a/drivers/iio/gyro/st_gyro_spi.c
+++ b/drivers/iio/gyro/st_gyro_spi.c
@@ -35,8 +35,8 @@ static int st_gyro_spi_probe(struct spi_device *spi)
 
 	st_sensors_spi_configure(indio_dev, spi, gdata);
 
-	err = st_gyro_common_probe(indio_dev,
-				(struct st_sensors_platform_data *)&gyro_pdata);
+	err = st_gyro_common_probe(indio_dev);
+
 	if (err < 0)
 		goto st_gyro_common_probe_error;
 
@@ -68,10 +68,24 @@ static const struct spi_device_id st_gyro_id_table[] = {
 };
 MODULE_DEVICE_TABLE(spi, st_gyro_id_table);
 
+#ifdef CONFIG_OF
+static struct of_device_id st_gyro_dt_match[] = {
+	{ .compatible = "st,l3g4200d" },
+	{ .compatible = "st,lsm330d-gyro" },
+	{ .compatible = "st,lsm330dl-gyro" },
+	{ .compatible = "st,lsm330dlc-gyro" },
+	{ .compatible = "st,l3gd20" },
+	{ .compatible = "st,l3gd20h" },
+	{ .compatible = "st,l3g4is-ui" },
+	{ .compatible = "st,lsm330-gyro" },
+};
+#endif
+
 static struct spi_driver st_gyro_driver = {
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = "st-gyro-spi",
+		.of_match_table = of_match_ptr(st_gyro_dt_match),
 	},
 	.probe = st_gyro_spi_probe,
 	.remove = st_gyro_spi_remove,
diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h
index 694e33e..7e81d00 100644
--- a/drivers/iio/magnetometer/st_magn.h
+++ b/drivers/iio/magnetometer/st_magn.h
@@ -18,8 +18,7 @@
 #define LSM303DLM_MAGN_DEV_NAME		"lsm303dlm_magn"
 #define LIS3MDL_MAGN_DEV_NAME		"lis3mdl"
 
-int st_magn_common_probe(struct iio_dev *indio_dev,
-					struct st_sensors_platform_data *pdata);
+int st_magn_common_probe(struct iio_dev *indio_dev);
 void st_magn_common_remove(struct iio_dev *indio_dev);
 
 #ifdef CONFIG_IIO_BUFFER
diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c
index 7cd784f..ebfe8f1 100644
--- a/drivers/iio/magnetometer/st_magn_core.c
+++ b/drivers/iio/magnetometer/st_magn_core.c
@@ -345,8 +345,7 @@ static const struct iio_info magn_info = {
 	.write_raw = &st_magn_write_raw,
 };
 
-int st_magn_common_probe(struct iio_dev *indio_dev,
-					struct st_sensors_platform_data *pdata)
+int st_magn_common_probe(struct iio_dev *indio_dev)
 {
 	int err;
 	struct st_sensor_data *mdata = iio_priv(indio_dev);
@@ -368,7 +367,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev,
 						&mdata->sensor->fs.fs_avl[0];
 	mdata->odr = mdata->sensor->odr.odr_avl[0].hz;
 
-	err = st_sensors_init_sensor(indio_dev, pdata);
+	err = st_sensors_init_sensor(indio_dev);
 	if (err < 0)
 		goto st_magn_common_probe_error;
 
diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
index 1bed117..e6adc4a 100644
--- a/drivers/iio/magnetometer/st_magn_i2c.c
+++ b/drivers/iio/magnetometer/st_magn_i2c.c
@@ -36,7 +36,7 @@ static int st_magn_i2c_probe(struct i2c_client *client,
 
 	st_sensors_i2c_configure(indio_dev, client, mdata);
 
-	err = st_magn_common_probe(indio_dev, NULL);
+	err = st_magn_common_probe(indio_dev);
 	if (err < 0)
 		goto st_magn_common_probe_error;
 
diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
index a2333a1..51adb79 100644
--- a/drivers/iio/magnetometer/st_magn_spi.c
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -35,7 +35,7 @@ static int st_magn_spi_probe(struct spi_device *spi)
 
 	st_sensors_spi_configure(indio_dev, spi, mdata);
 
-	err = st_magn_common_probe(indio_dev, NULL);
+	err = st_magn_common_probe(indio_dev);
 	if (err < 0)
 		goto st_magn_common_probe_error;
 
diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h
index b0b6306..8a8a900 100644
--- a/drivers/iio/pressure/st_pressure.h
+++ b/drivers/iio/pressure/st_pressure.h
@@ -24,8 +24,7 @@ static const struct st_sensors_platform_data default_press_pdata = {
 	.drdy_int_pin = 1,
 };
 
-int st_press_common_probe(struct iio_dev *indio_dev,
-					struct st_sensors_platform_data *pdata);
+int st_press_common_probe(struct iio_dev *indio_dev);
 void st_press_common_remove(struct iio_dev *indio_dev);
 
 #ifdef CONFIG_IIO_BUFFER
diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c
index b8ecc87..aacea2a 100644
--- a/drivers/iio/pressure/st_pressure_core.c
+++ b/drivers/iio/pressure/st_pressure_core.c
@@ -202,8 +202,7 @@ static const struct iio_trigger_ops st_press_trigger_ops = {
 #define ST_PRESS_TRIGGER_OPS NULL
 #endif
 
-int st_press_common_probe(struct iio_dev *indio_dev,
-				struct st_sensors_platform_data *plat_data)
+int st_press_common_probe(struct iio_dev *indio_dev)
 {
 	int err;
 	struct st_sensor_data *pdata = iio_priv(indio_dev);
@@ -219,17 +218,18 @@ int st_press_common_probe(struct iio_dev *indio_dev,
 	pdata->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS;
 	pdata->multiread_bit = pdata->sensor->multi_read_bit;
 	indio_dev->channels = pdata->sensor->ch;
+
 	indio_dev->num_channels = ARRAY_SIZE(st_press_channels);
 
 	pdata->current_fullscale = (struct st_sensor_fullscale_avl *)
 						&pdata->sensor->fs.fs_avl[0];
 	pdata->odr = pdata->sensor->odr.odr_avl[0].hz;
 
-	if (!plat_data)
-		plat_data =
-			(struct st_sensors_platform_data *)&default_press_pdata;
 
-	err = st_sensors_init_sensor(indio_dev, plat_data);
+	if (!pdata->dev->platform_data && !pdata->dev->of_node)
+		pdata->drdy_int_pin = default_press_pdata.drdy_int_pin;
+
+	err = st_sensors_init_sensor(indio_dev);
 	if (err < 0)
 		goto st_press_common_probe_error;
 
diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
index 3065993..7cebcc7 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -36,7 +36,7 @@ static int st_press_i2c_probe(struct i2c_client *client,
 
 	st_sensors_i2c_configure(indio_dev, client, pdata);
 
-	err = st_press_common_probe(indio_dev, client->dev.platform_data);
+	err = st_press_common_probe(indio_dev);
 	if (err < 0)
 		goto st_press_common_probe_error;
 
diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c
index b2aded6..17a1490 100644
--- a/drivers/iio/pressure/st_pressure_spi.c
+++ b/drivers/iio/pressure/st_pressure_spi.c
@@ -35,7 +35,7 @@ static int st_press_spi_probe(struct spi_device *spi)
 
 	st_sensors_spi_configure(indio_dev, spi, pdata);
 
-	err = st_press_common_probe(indio_dev, spi->dev.platform_data);
+	err = st_press_common_probe(indio_dev);
 	if (err < 0)
 		goto st_press_common_probe_error;
 
diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h
index e51f654..07e27e4 100644
--- a/include/linux/iio/common/st_sensors.h
+++ b/include/linux/iio/common/st_sensors.h
@@ -40,6 +40,10 @@
 #define ST_SENSORS_MAX_NAME			17
 #define ST_SENSORS_MAX_4WAI			7
 
+#define ST_SENSORS_INT_MAX			2
+#define ST_SENSORS_INT1				0
+#define ST_SENSORS_INT2				1
+
 #define ST_SENSORS_LSM_CHANNELS(device_type, mask, index, mod, \
 					ch2, s, endian, rbits, sbits, addr) \
 { \
@@ -205,6 +209,7 @@ 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.
+ * @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.
  * @tf: Transfer function structure used by I/O operations.
@@ -223,6 +228,7 @@ struct st_sensor_data {
 
 	unsigned int odr;
 	unsigned int num_data_channels;
+	unsigned int irq_map[ST_SENSORS_INT_MAX];
 
 	u8 drdy_int_pin;
 
@@ -256,8 +262,7 @@ static inline void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
 }
 #endif
 
-int st_sensors_init_sensor(struct iio_dev *indio_dev,
-					struct st_sensors_platform_data *pdata);
+int st_sensors_init_sensor(struct iio_dev *indio_dev);
 
 int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable);
 
diff --git a/include/linux/platform_data/st_sensors_pdata.h b/include/linux/platform_data/st_sensors_pdata.h
index 7538391..991db72 100644
--- a/include/linux/platform_data/st_sensors_pdata.h
+++ b/include/linux/platform_data/st_sensors_pdata.h
@@ -19,6 +19,8 @@
  */
 struct st_sensors_platform_data {
 	u8 drdy_int_pin;
+
+	unsigned int irqs[2];
 };
 
 #endif /* ST_SENSORS_PDATA_H */
-- 
1.7.9.5

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

* [PATCH 2/4] iio: st_sensors: Add threshold events support
       [not found] ` <1372767338-13179-1-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  2013-07-02 12:15   ` [PATCH 1/4] iio: st_sensors: Add DT bindings for st_accel and st_gyro Lukasz Czerwinski
@ 2013-07-02 12:15   ` Lukasz Czerwinski
       [not found]     ` <1372767338-13179-3-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  2013-07-02 12:15   ` [PATCH 3/4] iio: accel: Add event subsystem to st_accel driver Lukasz Czerwinski
  2013-07-02 12:15   ` [PATCH 4/4] iio: lps331ap: Add support for DT Lukasz Czerwinski
  3 siblings, 1 reply; 11+ messages in thread
From: Lukasz Czerwinski @ 2013-07-02 12:15 UTC (permalink / raw)
  To: jic23-DgEjT+Ai2ygdnm+yROfE0A, denis.ciocca-qxv4g6HH51o
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Lukasz Czerwinski,
	Kyungmin Park

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

Signed-off-by: Lukasz Czerwinski <l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 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-qxv4g6HH51o@public.gmane.org>");
 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

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

* [PATCH 3/4] iio: accel: Add event subsystem to st_accel driver
       [not found] ` <1372767338-13179-1-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  2013-07-02 12:15   ` [PATCH 1/4] iio: st_sensors: Add DT bindings for st_accel and st_gyro Lukasz Czerwinski
  2013-07-02 12:15   ` [PATCH 2/4] iio: st_sensors: Add threshold events support Lukasz Czerwinski
@ 2013-07-02 12:15   ` Lukasz Czerwinski
       [not found]     ` <1372767338-13179-4-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  2013-07-02 12:15   ` [PATCH 4/4] iio: lps331ap: Add support for DT Lukasz Czerwinski
  3 siblings, 1 reply; 11+ messages in thread
From: Lukasz Czerwinski @ 2013-07-02 12:15 UTC (permalink / raw)
  To: jic23-DgEjT+Ai2ygdnm+yROfE0A, denis.ciocca-qxv4g6HH51o
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Lukasz Czerwinski,
	Kyungmin Park

This patch adds event support for iio st_accel driver.

Signed-off-by: Lukasz Czerwinski <l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 .../bindings/iio/accelerometer/st_accel.txt        |    1 +
 drivers/iio/accel/st_accel_core.c                  |  149 ++++++++++++++++++++
 2 files changed, 150 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/accelerometer/st_accel.txt b/Documentation/devicetree/bindings/iio/accelerometer/st_accel.txt
index 9eab7d9..f461a77 100644
--- a/Documentation/devicetree/bindings/iio/accelerometer/st_accel.txt
+++ b/Documentation/devicetree/bindings/iio/accelerometer/st_accel.txt
@@ -21,6 +21,7 @@ Optional properties:
   - interrupt-parent : phandle to the interrupt map subnode
   - interrupts : interrupt mapping for st_accel interrupt sources:
 	0: INT1 irq_data_ready
+	1: INT2 irq_event
   - irq-map : irq sub-node defining interrupt map
               (all properties listed below are required):
       - #interrupt-cells : should be 1
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index 385cd86..983e8c4 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -19,6 +19,7 @@
 #include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/iio/iio.h>
+#include <linux/iio/events.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/trigger.h>
 #include <linux/iio/buffer.h>
@@ -68,6 +69,20 @@
 #define ST_ACCEL_1_DRDY_IRQ_INT1_MASK		0x10
 #define ST_ACCEL_1_DRDY_IRQ_INT2_MASK		0x08
 #define ST_ACCEL_1_MULTIREAD_BIT		true
+#define ST_ACCEL_1_EVENT_IRQ_ADDR		0x22
+#define ST_ACCEL_1_EVENT_IRQ_MASK		0x40
+#define ST_ACCEL_1_EVENT_CTRL_REG		0x30
+#define ST_ACCEL_1_EVENT_CTRL_MASK		0xc0
+#define ST_ACCEL_1_EVENT_CTRL_DEFAULT_VAL	0x01
+#define ST_ACCEL_1_THS_REG			0x32
+#define ST_ACCEL_1_EVENT_STATUS_REG		0x31
+#define ST_ACCEL_1_EVENT_STATUS_REG_MASK	0x7f
+#define ST_ACCEL_1_INT1_XL			0
+#define ST_ACCEL_1_INT1_XH			1
+#define ST_ACCEL_1_INT1_YL			2
+#define ST_ACCEL_1_INT1_YH			3
+#define ST_ACCEL_1_INT1_ZL			4
+#define ST_ACCEL_1_INT1_ZH			5
 
 /* CUSTOM VALUES FOR SENSOR 2 */
 #define ST_ACCEL_2_WAI_EXP			0x32
@@ -93,6 +108,20 @@
 #define ST_ACCEL_2_DRDY_IRQ_INT1_MASK		0x02
 #define ST_ACCEL_2_DRDY_IRQ_INT2_MASK		0x10
 #define ST_ACCEL_2_MULTIREAD_BIT		true
+#define ST_ACCEL_2_EVENT_IRQ_ADDR		0x22
+#define ST_ACCEL_2_EVENT_IRQ_MASK		0x01
+#define ST_ACCEL_2_EVENT_CTRL_REG		0x30
+#define ST_ACCEL_2_EVENT_CTRL_MASK		0xc0
+#define ST_ACCEL_2_EVENT_CTRL_DEFAULT_VAL	0x01
+#define ST_ACCEL_2_THS_REG			0x32
+#define ST_ACCEL_2_EVENT_STATUS_REG		0x31
+#define ST_ACCEL_2_EVENT_STATUS_REG_MASK	0x7f
+#define ST_ACCEL_2_INT1_XL			0
+#define ST_ACCEL_2_INT1_XH			1
+#define ST_ACCEL_2_INT1_YL			2
+#define ST_ACCEL_2_INT1_YH			3
+#define ST_ACCEL_2_INT1_ZL			4
+#define ST_ACCEL_2_INT1_ZH			5
 
 /* CUSTOM VALUES FOR SENSOR 3 */
 #define ST_ACCEL_3_WAI_EXP			0x40
@@ -129,6 +158,20 @@
 #define ST_ACCEL_3_IG1_EN_MASK			0x08
 #define ST_ACCEL_3_MULTIREAD_BIT		false
 
+#define ST_SENSORS_LSM_ACCEL_EVENT(ch, mod, dir, bit_pos, ths_reg) \
+{ \
+	.bit = bit_pos,\
+	.chan = ch, \
+	.chan_type = IIO_ACCEL, \
+	.modifier = mod, \
+	.event_type = IIO_EV_TYPE_THRESH, \
+	.direction = dir, \
+	.event_ths_reg = { \
+		.addr = ths_reg, \
+		.mask = 0x7f, \
+	}, \
+}
+
 static const struct iio_chan_spec st_accel_12bit_channels[] = {
 	ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
 			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
@@ -232,6 +275,46 @@ static const struct st_sensors st_accel_sensors[] = {
 		},
 		.multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT,
 		.bootime = 2,
+		.event_irq = {
+			.addr = ST_ACCEL_1_EVENT_IRQ_ADDR,
+			.mask = ST_ACCEL_1_EVENT_IRQ_MASK,
+			.event_count = 6,
+			.ctrl_reg = {
+				.addr = ST_ACCEL_1_EVENT_CTRL_REG,
+				.mask = ST_ACCEL_1_EVENT_CTRL_MASK,
+				.val = ST_ACCEL_1_EVENT_CTRL_DEFAULT_VAL,
+			},
+			.status_reg = {
+				.addr = ST_ACCEL_1_EVENT_STATUS_REG,
+				.mask = ST_ACCEL_1_EVENT_STATUS_REG_MASK,
+			},
+			.events = {
+				ST_SENSORS_LSM_ACCEL_EVENT(0, IIO_MOD_X,
+						IIO_EV_DIR_FALLING,
+						ST_ACCEL_1_INT1_XL,
+						ST_ACCEL_1_THS_REG),
+				ST_SENSORS_LSM_ACCEL_EVENT(0, IIO_MOD_X,
+						IIO_EV_DIR_RISING,
+						ST_ACCEL_1_INT1_XH,
+						ST_ACCEL_1_THS_REG),
+				ST_SENSORS_LSM_ACCEL_EVENT(1, IIO_MOD_Y,
+						IIO_EV_DIR_FALLING,
+						ST_ACCEL_1_INT1_YL,
+						ST_ACCEL_1_THS_REG),
+				ST_SENSORS_LSM_ACCEL_EVENT(1, IIO_MOD_Y,
+						IIO_EV_DIR_RISING,
+						ST_ACCEL_1_INT1_YH,
+						ST_ACCEL_1_THS_REG),
+				ST_SENSORS_LSM_ACCEL_EVENT(2, IIO_MOD_Z,
+						IIO_EV_DIR_FALLING,
+						ST_ACCEL_1_INT1_ZL,
+						ST_ACCEL_1_THS_REG),
+				ST_SENSORS_LSM_ACCEL_EVENT(2, IIO_MOD_Z,
+						IIO_EV_DIR_RISING,
+						ST_ACCEL_1_INT1_ZH,
+						ST_ACCEL_1_THS_REG),
+			},
+		},
 	},
 	{
 		.wai = ST_ACCEL_2_WAI_EXP,
@@ -294,6 +377,47 @@ static const struct st_sensors st_accel_sensors[] = {
 		},
 		.multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
 		.bootime = 2,
+		.event_irq = {
+			.addr = ST_ACCEL_2_EVENT_IRQ_ADDR,
+			.mask = ST_ACCEL_2_EVENT_IRQ_MASK,
+			.event_count = 6,
+			.ctrl_reg = {
+				.addr = ST_ACCEL_2_EVENT_CTRL_REG,
+				.mask = ST_ACCEL_2_EVENT_CTRL_MASK,
+				.val = ST_ACCEL_2_EVENT_CTRL_DEFAULT_VAL,
+			},
+			.status_reg = {
+				.addr = ST_ACCEL_2_EVENT_STATUS_REG,
+				.mask = ST_ACCEL_2_EVENT_STATUS_REG_MASK,
+			},
+			.events = {
+				ST_SENSORS_LSM_ACCEL_EVENT(0, IIO_MOD_X,
+						IIO_EV_DIR_FALLING,
+						ST_ACCEL_2_INT1_XL,
+						ST_ACCEL_2_THS_REG),
+				ST_SENSORS_LSM_ACCEL_EVENT(0, IIO_MOD_X,
+						IIO_EV_DIR_RISING,
+						ST_ACCEL_2_INT1_XH,
+						ST_ACCEL_2_THS_REG),
+				ST_SENSORS_LSM_ACCEL_EVENT(1, IIO_MOD_Y,
+						IIO_EV_DIR_FALLING,
+						ST_ACCEL_2_INT1_YL,
+						ST_ACCEL_2_THS_REG),
+				ST_SENSORS_LSM_ACCEL_EVENT(1, IIO_MOD_Y,
+						IIO_EV_DIR_RISING,
+						ST_ACCEL_2_INT1_YH,
+						ST_ACCEL_2_THS_REG),
+				ST_SENSORS_LSM_ACCEL_EVENT(2, IIO_MOD_Z,
+						IIO_EV_DIR_FALLING,
+						ST_ACCEL_2_INT1_ZL,
+						ST_ACCEL_2_THS_REG),
+				ST_SENSORS_LSM_ACCEL_EVENT(2, IIO_MOD_Z,
+						IIO_EV_DIR_RISING,
+						ST_ACCEL_2_INT1_ZH,
+						ST_ACCEL_2_THS_REG),
+			},
+		},
+
 	},
 	{
 		.wai = ST_ACCEL_3_WAI_EXP,
@@ -437,6 +561,10 @@ static const struct iio_info accel_info = {
 	.attrs = &st_accel_attribute_group,
 	.read_raw = &st_accel_read_raw,
 	.write_raw = &st_accel_write_raw,
+	.read_event_value = &st_sensors_read_event_value,
+	.write_event_value = &st_sensors_write_event_value,
+	.read_event_config = &st_sensors_read_event_config,
+	.write_event_config = &st_sensors_write_event_config,
 };
 
 #ifdef CONFIG_IIO_TRIGGER
@@ -452,6 +580,7 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
 int st_accel_common_probe(struct iio_dev *indio_dev)
 {
 	int err;
+	int i;
 	struct st_sensor_data *adata = iio_priv(indio_dev);
 
 	indio_dev->modes = INDIO_DIRECT_MODE;
@@ -489,6 +618,20 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
 			goto st_accel_probe_trigger_error;
 	}
 
+	if (adata->get_irq_event(indio_dev) > 0) {
+		err = st_sensors_request_event_irq(indio_dev);
+		if (err < 0)
+			goto st_accel_request_irq_event_error;
+
+		for (i = 0; i < indio_dev->num_channels; i++)
+			adata->sensor->ch[i].event_mask =
+				ST_SENSORS_LSM_EVENTS_MASK;
+
+		err = st_sensors_enable_events(indio_dev);
+		if (err < 0)
+			goto st_accel_enable_events_error;
+	}
+
 	err = iio_device_register(indio_dev);
 	if (err)
 		goto st_accel_device_register_error;
@@ -496,6 +639,10 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
 	return err;
 
 st_accel_device_register_error:
+st_accel_enable_events_error:
+	if (adata->get_irq_event(indio_dev) > 0)
+		free_irq(adata->get_irq_event(indio_dev), indio_dev);
+st_accel_request_irq_event_error:
 	if (adata->get_irq_data_ready(indio_dev) > 0)
 		st_sensors_deallocate_trigger(indio_dev);
 st_accel_probe_trigger_error:
@@ -515,6 +662,8 @@ void st_accel_common_remove(struct iio_dev *indio_dev)
 		st_sensors_deallocate_trigger(indio_dev);
 		st_accel_deallocate_ring(indio_dev);
 	}
+	if (adata->get_irq_event(indio_dev) > 0)
+		free_irq(adata->get_irq_event(indio_dev), indio_dev);
 	iio_device_free(indio_dev);
 }
 EXPORT_SYMBOL(st_accel_common_remove);
-- 
1.7.9.5

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

* [PATCH 4/4] iio: lps331ap: Add support for DT
       [not found] ` <1372767338-13179-1-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
                     ` (2 preceding siblings ...)
  2013-07-02 12:15   ` [PATCH 3/4] iio: accel: Add event subsystem to st_accel driver Lukasz Czerwinski
@ 2013-07-02 12:15   ` Lukasz Czerwinski
       [not found]     ` <1372767338-13179-5-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  3 siblings, 1 reply; 11+ messages in thread
From: Lukasz Czerwinski @ 2013-07-02 12:15 UTC (permalink / raw)
  To: jic23-DgEjT+Ai2ygdnm+yROfE0A, denis.ciocca-qxv4g6HH51o
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Jacek Anaszewski,
	Kyungmin Park

From: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>

This patch adds DT support for the lps331ap barometer
sensor.

Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 .../bindings/iio/pressure/st_pressure.txt          |   41 ++++++++++++++++++++
 drivers/iio/pressure/st_pressure_i2c.c             |    9 +++++
 drivers/iio/pressure/st_pressure_spi.c             |    9 +++++
 3 files changed, 59 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/pressure/st_pressure.txt

diff --git a/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt b/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
new file mode 100644
index 0000000..73a4b7d
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
@@ -0,0 +1,41 @@
+* STMicroelectronics LPS331AP barometer sensor
+
+Required properties:
+
+  - compatible : should be "lps331ap"
+  - reg : the I2C address of the barometer
+
+Optional properties:
+
+  - drdy-int-pin : redirect DRDY on pin INT1 (1) or pin INT2 (2) (u8)
+  - interrupt-parent : phandle to the interrupt map subnode
+  - interrupts : interrupt mapping for LPS331AP interrupt sources:
+		2 sources: 0 - INT1, 1 - INT2
+  - irq-map : irq sub-node defining interrupt map
+	      (all properties listed below are required):
+      - #interrupt-cells : should be 1
+      - #address-cells : should be 0
+      - #size-cells : should be 0
+      - interrupt-map : table of entries consisting of three child elements:
+	  - unit_interrupt_specifier - 0 : INT1, 1 : INT2
+	  - interrupt parent phandle
+	  - parent unit interrupt specifier consisiting of two elements:
+	      - index of the interrupt within the controller
+	      - flags : should be 0
+
+Example:
+
+lps331ap@5d {
+	compatible = "lps331ap";
+	reg = <0x5d>;
+	drdy-int-pin = /bits/ 8 <2>;
+	interrupt-parent = <&irq_map>;
+	interrupts = <0>, <1>;
+
+	irq_map: irq-map {
+		#interrupt-cells = <1>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		interrupt-map = <0 &gpf0 5 0>;
+	};
+};
diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
index 7cebcc7..a1ad3cf 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -61,10 +61,19 @@ static const struct i2c_device_id st_press_id_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, st_press_id_table);
 
+#ifdef CONFIG_OF
+static const struct of_device_id lps331ap_of_match[] = {
+	{ .compatible = LPS331AP_PRESS_DEV_NAME, },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, lps331ap_of_match);
+#endif
+
 static struct i2c_driver st_press_driver = {
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = "st-press-i2c",
+		.of_match_table = of_match_ptr(lps331ap_of_match),
 	},
 	.probe = st_press_i2c_probe,
 	.remove = st_press_i2c_remove,
diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c
index 17a1490..e49269d 100644
--- a/drivers/iio/pressure/st_pressure_spi.c
+++ b/drivers/iio/pressure/st_pressure_spi.c
@@ -60,10 +60,19 @@ static const struct spi_device_id st_press_id_table[] = {
 };
 MODULE_DEVICE_TABLE(spi, st_press_id_table);
 
+#ifdef CONFIG_OF
+static const struct of_device_id lps331ap_of_match[] = {
+	{ .compatible = LPS331AP_PRESS_DEV_NAME, },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, lps331ap_of_match);
+#endif
+
 static struct spi_driver st_press_driver = {
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = "st-press-spi",
+		.of_match_table = of_match_ptr(lps331ap_of_match),
 	},
 	.probe = st_press_spi_probe,
 	.remove = st_press_spi_remove,
-- 
1.7.9.5

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

* Re: [PATCH 4/4] iio: lps331ap: Add support for DT
       [not found]     ` <1372767338-13179-5-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
@ 2013-07-02 12:56       ` Lars-Peter Clausen
       [not found]         ` <51D2CE03.2070704-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
  2013-07-16 13:22       ` Maxime Ripard
  1 sibling, 1 reply; 11+ messages in thread
From: Lars-Peter Clausen @ 2013-07-02 12:56 UTC (permalink / raw)
  To: Lukasz Czerwinski
  Cc: jic23-DgEjT+Ai2ygdnm+yROfE0A, denis.ciocca-qxv4g6HH51o,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Jacek Anaszewski,
	Kyungmin Park

On 07/02/2013 02:15 PM, Lukasz Czerwinski wrote:
> From: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> 
> This patch adds DT support for the lps331ap barometer
> sensor.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
>  .../bindings/iio/pressure/st_pressure.txt          |   41 ++++++++++++++++++++
>  drivers/iio/pressure/st_pressure_i2c.c             |    9 +++++
>  drivers/iio/pressure/st_pressure_spi.c             |    9 +++++
>  3 files changed, 59 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
> 
> diff --git a/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt b/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
> new file mode 100644
> index 0000000..73a4b7d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
> @@ -0,0 +1,41 @@
> +* STMicroelectronics LPS331AP barometer sensor
> +
> +Required properties:
> +
> +  - compatible : should be "lps331ap"

Needs the vendor prefix.

> +  - reg : the I2C address of the barometer
> +
> +Optional properties:
> +
> +  - drdy-int-pin : redirect DRDY on pin INT1 (1) or pin INT2 (2) (u8)
> +  - interrupt-parent : phandle to the interrupt map subnode
> +  - interrupts : interrupt mapping for LPS331AP interrupt sources:
> +		2 sources: 0 - INT1, 1 - INT2
> +  - irq-map : irq sub-node defining interrupt map
> +	      (all properties listed below are required):
> +      - #interrupt-cells : should be 1
> +      - #address-cells : should be 0
> +      - #size-cells : should be 0
> +      - interrupt-map : table of entries consisting of three child elements:
> +	  - unit_interrupt_specifier - 0 : INT1, 1 : INT2
> +	  - interrupt parent phandle
> +	  - parent unit interrupt specifier consisiting of two elements:
> +	      - index of the interrupt within the controller
> +	      - flags : should be 0

While this works I wonder why you choose such a complicated example for setting
up the IRQ? Why not just reference the IRQ directly using the interrupts property?

> +
> +Example:
> +
> +lps331ap@5d {
> +	compatible = "lps331ap";
> +	reg = <0x5d>;
> +	drdy-int-pin = /bits/ 8 <2>;
> +	interrupt-parent = <&irq_map>;
> +	interrupts = <0>, <1>;
> +
> +	irq_map: irq-map {
> +		#interrupt-cells = <1>;
> +		#address-cells = <0>;
> +		#size-cells = <0>;
> +		interrupt-map = <0 &gpf0 5 0>;
> +	};
> +};
> diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
> index 7cebcc7..a1ad3cf 100644
> --- a/drivers/iio/pressure/st_pressure_i2c.c
> +++ b/drivers/iio/pressure/st_pressure_i2c.c
> @@ -61,10 +61,19 @@ static const struct i2c_device_id st_press_id_table[] = {
>  };
>  MODULE_DEVICE_TABLE(i2c, st_press_id_table);
>  
> +#ifdef CONFIG_OF
> +static const struct of_device_id lps331ap_of_match[] = {
> +	{ .compatible = LPS331AP_PRESS_DEV_NAME, },

I think it is better to write the name out. The name the device binds to should
be fixed and not depend on some macro.

> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, lps331ap_of_match);
> +#endif

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

* Re: [PATCH 4/4] iio: lps331ap: Add support for DT
       [not found]         ` <51D2CE03.2070704-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
@ 2013-07-02 15:28           ` Jacek Anaszewski
  0 siblings, 0 replies; 11+ messages in thread
From: Jacek Anaszewski @ 2013-07-02 15:28 UTC (permalink / raw)
  To: linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: devicetree-discuss-mnsaURCQ41sdnm+yROfE0A

On 07/02/2013 02:56 PM, Lars-Peter Clausen wrote:
> On 07/02/2013 02:15 PM, Lukasz Czerwinski wrote:
>> From: Jacek Anaszewski<j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>>
>> This patch adds DT support for the lps331ap barometer
>> sensor.
>>
>> Signed-off-by: Jacek Anaszewski<j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Signed-off-by: Kyungmin Park<kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> ---
>>   .../bindings/iio/pressure/st_pressure.txt          |   41 ++++++++++++++++++++
>>   drivers/iio/pressure/st_pressure_i2c.c             |    9 +++++
>>   drivers/iio/pressure/st_pressure_spi.c             |    9 +++++
>>   3 files changed, 59 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
>>
>> diff --git a/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt b/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
>> new file mode 100644
>> index 0000000..73a4b7d
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
>> @@ -0,0 +1,41 @@
>> +* STMicroelectronics LPS331AP barometer sensor
>> +
>> +Required properties:
>> +
>> +  - compatible : should be "lps331ap"
>
> Needs the vendor prefix.
>
>> +  - reg : the I2C address of the barometer
>> +
>> +Optional properties:
>> +
>> +  - drdy-int-pin : redirect DRDY on pin INT1 (1) or pin INT2 (2) (u8)
>> +  - interrupt-parent : phandle to the interrupt map subnode
>> +  - interrupts : interrupt mapping for LPS331AP interrupt sources:
>> +		2 sources: 0 - INT1, 1 - INT2
>> +  - irq-map : irq sub-node defining interrupt map
>> +	      (all properties listed below are required):
>> +      - #interrupt-cells : should be 1
>> +      - #address-cells : should be 0
>> +      - #size-cells : should be 0
>> +      - interrupt-map : table of entries consisting of three child elements:
>> +	  - unit_interrupt_specifier - 0 : INT1, 1 : INT2
>> +	  - interrupt parent phandle
>> +	  - parent unit interrupt specifier consisiting of two elements:
>> +	      - index of the interrupt within the controller
>> +	      - flags : should be 0
>
> While this works I wonder why you choose such a complicated example for setting
> up the IRQ? Why not just reference the IRQ directly using the interrupts property?

Hi Lars,

I will try to clarify the reasons why the interrupt map was exploited:

1) The device exposes two interrupt pins: INT1 and INT2.
2) Both of them can be configured either to generate data ready
    interrupts or event interrupts.
3) drdy-int-pin property conveys the information about the interrupt
    pin routed to the CPU and allows the driver to configure
    the device to generate data ready interrupts on the connected pin.
4) The lps331ap barometer sensor handles only data ready interrupts
    but it depends on the st_sensors library which expects interrupt map
    in the device tree node.
5) Because of the support for events added to the library in this
    series it should be possible to pass two irq's to the driver. From
    what I know it can't be accomplished with interrupts property if
    the interrupts originate from different interrupt parents (which is
    the case I deal with, where device int sources are routed to the
    GPIOs in different banks).
6) I agree that map filled with only one element may confuse the reader
    but it is required for the st_common library to successfully parse
    the node.

If you know better solution please let me know.
Of course I agree with your remaining remarks.

Thanks,
Jacek

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

* Re: [PATCH 4/4] iio: lps331ap: Add support for DT
       [not found]     ` <1372767338-13179-5-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  2013-07-02 12:56       ` Lars-Peter Clausen
@ 2013-07-16 13:22       ` Maxime Ripard
  2013-07-19 13:43         ` Jacek Anaszewski
  1 sibling, 1 reply; 11+ messages in thread
From: Maxime Ripard @ 2013-07-16 13:22 UTC (permalink / raw)
  To: Lukasz Czerwinski
  Cc: jic23-DgEjT+Ai2ygdnm+yROfE0A, denis.ciocca-qxv4g6HH51o,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Jacek Anaszewski,
	Kyungmin Park

[-- Attachment #1: Type: text/plain, Size: 2681 bytes --]

Hi Jacek,

I find myself needing these bindings as well, so I'm definitely
interested by your patches.

On Tue, Jul 02, 2013 at 02:15:38PM +0200, Lukasz Czerwinski wrote:
> From: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> 
> This patch adds DT support for the lps331ap barometer
> sensor.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
>  .../bindings/iio/pressure/st_pressure.txt          |   41 ++++++++++++++++++++
>  drivers/iio/pressure/st_pressure_i2c.c             |    9 +++++
>  drivers/iio/pressure/st_pressure_spi.c             |    9 +++++
>  3 files changed, 59 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
> 
> diff --git a/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt b/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
> new file mode 100644
> index 0000000..73a4b7d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
> @@ -0,0 +1,41 @@
> +* STMicroelectronics LPS331AP barometer sensor
> +
> +Required properties:
> +
> +  - compatible : should be "lps331ap"
> +  - reg : the I2C address of the barometer
> +
> +Optional properties:
> +
> +  - drdy-int-pin : redirect DRDY on pin INT1 (1) or pin INT2 (2) (u8)
> +  - interrupt-parent : phandle to the interrupt map subnode
> +  - interrupts : interrupt mapping for LPS331AP interrupt sources:
> +		2 sources: 0 - INT1, 1 - INT2

Maybe you could use interrupts-names here, instead of requiring to
hardcode the interrupt index. Plus, I guess that it's assuming that you
can only use INT2 when you already use INT1?

> +  - irq-map : irq sub-node defining interrupt map
> +	      (all properties listed below are required):
> +      - #interrupt-cells : should be 1
> +      - #address-cells : should be 0
> +      - #size-cells : should be 0
> +      - interrupt-map : table of entries consisting of three child elements:
> +	  - unit_interrupt_specifier - 0 : INT1, 1 : INT2
> +	  - interrupt parent phandle
> +	  - parent unit interrupt specifier consisiting of two elements:
> +	      - index of the interrupt within the controller
> +	      - flags : should be 0

I don't really get why it's needed. Isn't that redundant with the
interrupt parent and the interrupt number already defined by
interrupt-parent and interrupts in the top node?

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 4/4] iio: lps331ap: Add support for DT
  2013-07-16 13:22       ` Maxime Ripard
@ 2013-07-19 13:43         ` Jacek Anaszewski
  0 siblings, 0 replies; 11+ messages in thread
From: Jacek Anaszewski @ 2013-07-19 13:43 UTC (permalink / raw)
  To: linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: devicetree-discuss-mnsaURCQ41sdnm+yROfE0A

On 07/16/2013 03:22 PM, Maxime Ripard wrote:

Hi Maxime,

> Hi Jacek,
>
> I find myself needing these bindings as well, so I'm definitely
> interested by your patches.
>
> On Tue, Jul 02, 2013 at 02:15:38PM +0200, Lukasz Czerwinski wrote:
>> From: Jacek Anaszewski<j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>>
>> This patch adds DT support for the lps331ap barometer
>> sensor.
>>
>> Signed-off-by: Jacek Anaszewski<j.anaszewski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Signed-off-by: Kyungmin Park<kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> ---
>>   .../bindings/iio/pressure/st_pressure.txt          |   41 ++++++++++++++++++++
>>   drivers/iio/pressure/st_pressure_i2c.c             |    9 +++++
>>   drivers/iio/pressure/st_pressure_spi.c             |    9 +++++
>>   3 files changed, 59 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
>>
>> diff --git a/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt b/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
>> new file mode 100644
>> index 0000000..73a4b7d
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/iio/pressure/st_pressure.txt
>> @@ -0,0 +1,41 @@
>> +* STMicroelectronics LPS331AP barometer sensor
>> +
>> +Required properties:
>> +
>> +  - compatible : should be "lps331ap"
>> +  - reg : the I2C address of the barometer
>> +
>> +Optional properties:
>> +
>> +  - drdy-int-pin : redirect DRDY on pin INT1 (1) or pin INT2 (2) (u8)
>> +  - interrupt-parent : phandle to the interrupt map subnode
>> +  - interrupts : interrupt mapping for LPS331AP interrupt sources:
>> +		2 sources: 0 - INT1, 1 - INT2
>
> Maybe you could use interrupts-names here, instead of requiring to
> hardcode the interrupt index.

 From what I've figured out in order to obtain the interrupt id
by name the function

platform_get_irq_by_name(struct platform_device *dev, const char *name)

has to be exploited. Unfortunately required platform_device structure
is not available in the struct i2c_client that is passed to the
probe function of an i2c driver. The interrupt-names property would be 
indeed neater here, if only it was usable from i2c driver.

> Plus, I guess that it's assuming that you
> can only use INT2 when you already use INT1?

As I see now the binding documentation file I submitted is confusing.
I fixed it in the second version of the patch. Currently description
of the interrupt map elements is as follows:

0 - data ready interrupt
1 - threshold interrupt

which means that you can use INT2 even though you don't use INT1.
This is the case I have on my board - I have only INT2 pin of
lps331ap device routed to the CPU. I define interrupt map
with only one element with index 0 (which means that I want
it to act as a data ready interrupt) and I assign 2 to the
drdy-int-pin property which instructs the driver to configure
data ready interrupt on the INT2 pin.

>> +  - irq-map : irq sub-node defining interrupt map
>> +	      (all properties listed below are required):
>> +      - #interrupt-cells : should be 1
>> +      - #address-cells : should be 0
>> +      - #size-cells : should be 0
>> +      - interrupt-map : table of entries consisting of three child elements:
>> +	  - unit_interrupt_specifier - 0 : INT1, 1 : INT2
>> +	  - interrupt parent phandle
>> +	  - parent unit interrupt specifier consisiting of two elements:
>> +	      - index of the interrupt within the controller
>> +	      - flags : should be 0
>
> I don't really get why it's needed. Isn't that redundant with the
> interrupt parent and the interrupt number already defined by
> interrupt-parent and interrupts in the top node?

I'm aware that this adds much noise but I couldn't have found
other solution which would allow to define more than one interrupts
for the i2c device.

Thanks,
Jacek

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

* Re: [PATCH 2/4] iio: st_sensors: Add threshold events support
       [not found]     ` <1372767338-13179-3-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
@ 2013-08-04 14:55       ` Jonathan Cameron
  0 siblings, 0 replies; 11+ messages in thread
From: Jonathan Cameron @ 2013-08-04 14:55 UTC (permalink / raw)
  To: Lukasz Czerwinski
  Cc: denis.ciocca-qxv4g6HH51o, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Kyungmin Park

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-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
>  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-qxv4g6HH51o@public.gmane.org>");
>  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?

>  	.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 */
>

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

* Re: [PATCH 3/4] iio: accel: Add event subsystem to st_accel driver
       [not found]     ` <1372767338-13179-4-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
@ 2013-08-04 16:02       ` Jonathan Cameron
  0 siblings, 0 replies; 11+ messages in thread
From: Jonathan Cameron @ 2013-08-04 16:02 UTC (permalink / raw)
  To: Lukasz Czerwinski
  Cc: denis.ciocca-qxv4g6HH51o, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Kyungmin Park

On 07/02/13 13:15, Lukasz Czerwinski wrote:
> This patch adds event support for iio st_accel driver.
>
> Signed-off-by: Lukasz Czerwinski <l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>

Now I may have gotten lost in the driver, but I believe the underlying
channel specs are constant and in this patch you edit their event masks.
Not a good idea ;)

Also, I am going to guess you haven't tried building this version as
modules.  You are missing some symbol exports in the previous patch.

> ---
>  .../bindings/iio/accelerometer/st_accel.txt        |    1 +
>  drivers/iio/accel/st_accel_core.c                  |  149 ++++++++++++++++++++
>  2 files changed, 150 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/iio/accelerometer/st_accel.txt b/Documentation/devicetree/bindings/iio/accelerometer/st_accel.txt
> index 9eab7d9..f461a77 100644
> --- a/Documentation/devicetree/bindings/iio/accelerometer/st_accel.txt
> +++ b/Documentation/devicetree/bindings/iio/accelerometer/st_accel.txt
> @@ -21,6 +21,7 @@ Optional properties:
>    - interrupt-parent : phandle to the interrupt map subnode
>    - interrupts : interrupt mapping for st_accel interrupt sources:
>  	0: INT1 irq_data_ready
> +	1: INT2 irq_event
>    - irq-map : irq sub-node defining interrupt map
>                (all properties listed below are required):
>        - #interrupt-cells : should be 1
> diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
> index 385cd86..983e8c4 100644
> --- a/drivers/iio/accel/st_accel_core.c
> +++ b/drivers/iio/accel/st_accel_core.c
> @@ -19,6 +19,7 @@
>  #include <linux/gpio.h>
>  #include <linux/irq.h>
>  #include <linux/iio/iio.h>
> +#include <linux/iio/events.h>
>  #include <linux/iio/sysfs.h>
>  #include <linux/iio/trigger.h>
>  #include <linux/iio/buffer.h>
> @@ -68,6 +69,20 @@
>  #define ST_ACCEL_1_DRDY_IRQ_INT1_MASK		0x10
>  #define ST_ACCEL_1_DRDY_IRQ_INT2_MASK		0x08
>  #define ST_ACCEL_1_MULTIREAD_BIT		true
> +#define ST_ACCEL_1_EVENT_IRQ_ADDR		0x22
> +#define ST_ACCEL_1_EVENT_IRQ_MASK		0x40
> +#define ST_ACCEL_1_EVENT_CTRL_REG		0x30
> +#define ST_ACCEL_1_EVENT_CTRL_MASK		0xc0
> +#define ST_ACCEL_1_EVENT_CTRL_DEFAULT_VAL	0x01
> +#define ST_ACCEL_1_THS_REG			0x32
> +#define ST_ACCEL_1_EVENT_STATUS_REG		0x31
> +#define ST_ACCEL_1_EVENT_STATUS_REG_MASK	0x7f
> +#define ST_ACCEL_1_INT1_XL			0
> +#define ST_ACCEL_1_INT1_XH			1
> +#define ST_ACCEL_1_INT1_YL			2
> +#define ST_ACCEL_1_INT1_YH			3
> +#define ST_ACCEL_1_INT1_ZL			4
> +#define ST_ACCEL_1_INT1_ZH			5
>
>  /* CUSTOM VALUES FOR SENSOR 2 */
>  #define ST_ACCEL_2_WAI_EXP			0x32
> @@ -93,6 +108,20 @@
>  #define ST_ACCEL_2_DRDY_IRQ_INT1_MASK		0x02
>  #define ST_ACCEL_2_DRDY_IRQ_INT2_MASK		0x10
>  #define ST_ACCEL_2_MULTIREAD_BIT		true
> +#define ST_ACCEL_2_EVENT_IRQ_ADDR		0x22
> +#define ST_ACCEL_2_EVENT_IRQ_MASK		0x01
> +#define ST_ACCEL_2_EVENT_CTRL_REG		0x30
> +#define ST_ACCEL_2_EVENT_CTRL_MASK		0xc0
> +#define ST_ACCEL_2_EVENT_CTRL_DEFAULT_VAL	0x01
> +#define ST_ACCEL_2_THS_REG			0x32
> +#define ST_ACCEL_2_EVENT_STATUS_REG		0x31
> +#define ST_ACCEL_2_EVENT_STATUS_REG_MASK	0x7f
> +#define ST_ACCEL_2_INT1_XL			0
> +#define ST_ACCEL_2_INT1_XH			1
> +#define ST_ACCEL_2_INT1_YL			2
> +#define ST_ACCEL_2_INT1_YH			3
> +#define ST_ACCEL_2_INT1_ZL			4
> +#define ST_ACCEL_2_INT1_ZH			5
>
>  /* CUSTOM VALUES FOR SENSOR 3 */
>  #define ST_ACCEL_3_WAI_EXP			0x40
> @@ -129,6 +158,20 @@
>  #define ST_ACCEL_3_IG1_EN_MASK			0x08
>  #define ST_ACCEL_3_MULTIREAD_BIT		false
>
> +#define ST_SENSORS_LSM_ACCEL_EVENT(ch, mod, dir, bit_pos, ths_reg) \
> +{ \
> +	.bit = bit_pos,\
Hmm. A lot of this replicates info already available in the iio_chan_spec.
I guess this 'might' be the cleanest way of doing things but it seems
a little convoluted.
> +	.chan = ch, \
> +	.chan_type = IIO_ACCEL, \
> +	.modifier = mod, \
> +	.event_type = IIO_EV_TYPE_THRESH, \
> +	.direction = dir, \
> +	.event_ths_reg = { \
> +		.addr = ths_reg, \
> +		.mask = 0x7f, \
> +	}, \
> +}
> +
>  static const struct iio_chan_spec st_accel_12bit_channels[] = {
>  	ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
>  			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
> @@ -232,6 +275,46 @@ static const struct st_sensors st_accel_sensors[] = {
>  		},
>  		.multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT,
>  		.bootime = 2,
> +		.event_irq = {
> +			.addr = ST_ACCEL_1_EVENT_IRQ_ADDR,
> +			.mask = ST_ACCEL_1_EVENT_IRQ_MASK,
> +			.event_count = 6,
> +			.ctrl_reg = {
> +				.addr = ST_ACCEL_1_EVENT_CTRL_REG,
> +				.mask = ST_ACCEL_1_EVENT_CTRL_MASK,
> +				.val = ST_ACCEL_1_EVENT_CTRL_DEFAULT_VAL,
> +			},
> +			.status_reg = {
> +				.addr = ST_ACCEL_1_EVENT_STATUS_REG,
> +				.mask = ST_ACCEL_1_EVENT_STATUS_REG_MASK,
> +			},
> +			.events = {
> +				ST_SENSORS_LSM_ACCEL_EVENT(0, IIO_MOD_X,
> +						IIO_EV_DIR_FALLING,
> +						ST_ACCEL_1_INT1_XL,
> +						ST_ACCEL_1_THS_REG),
> +				ST_SENSORS_LSM_ACCEL_EVENT(0, IIO_MOD_X,
> +						IIO_EV_DIR_RISING,
> +						ST_ACCEL_1_INT1_XH,
> +						ST_ACCEL_1_THS_REG),
> +				ST_SENSORS_LSM_ACCEL_EVENT(1, IIO_MOD_Y,
> +						IIO_EV_DIR_FALLING,
> +						ST_ACCEL_1_INT1_YL,
> +						ST_ACCEL_1_THS_REG),
> +				ST_SENSORS_LSM_ACCEL_EVENT(1, IIO_MOD_Y,
> +						IIO_EV_DIR_RISING,
> +						ST_ACCEL_1_INT1_YH,
> +						ST_ACCEL_1_THS_REG),
> +				ST_SENSORS_LSM_ACCEL_EVENT(2, IIO_MOD_Z,
> +						IIO_EV_DIR_FALLING,
> +						ST_ACCEL_1_INT1_ZL,
> +						ST_ACCEL_1_THS_REG),
> +				ST_SENSORS_LSM_ACCEL_EVENT(2, IIO_MOD_Z,
> +						IIO_EV_DIR_RISING,
> +						ST_ACCEL_1_INT1_ZH,
> +						ST_ACCEL_1_THS_REG),
> +			},
> +		},
>  	},
>  	{
>  		.wai = ST_ACCEL_2_WAI_EXP,
> @@ -294,6 +377,47 @@ static const struct st_sensors st_accel_sensors[] = {
>  		},
>  		.multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
>  		.bootime = 2,
> +		.event_irq = {
> +			.addr = ST_ACCEL_2_EVENT_IRQ_ADDR,
> +			.mask = ST_ACCEL_2_EVENT_IRQ_MASK,
> +			.event_count = 6,
> +			.ctrl_reg = {
> +				.addr = ST_ACCEL_2_EVENT_CTRL_REG,
> +				.mask = ST_ACCEL_2_EVENT_CTRL_MASK,
> +				.val = ST_ACCEL_2_EVENT_CTRL_DEFAULT_VAL,
> +			},
> +			.status_reg = {
> +				.addr = ST_ACCEL_2_EVENT_STATUS_REG,
> +				.mask = ST_ACCEL_2_EVENT_STATUS_REG_MASK,
> +			},
> +			.events = {
> +				ST_SENSORS_LSM_ACCEL_EVENT(0, IIO_MOD_X,
> +						IIO_EV_DIR_FALLING,
> +						ST_ACCEL_2_INT1_XL,
> +						ST_ACCEL_2_THS_REG),
> +				ST_SENSORS_LSM_ACCEL_EVENT(0, IIO_MOD_X,
> +						IIO_EV_DIR_RISING,
> +						ST_ACCEL_2_INT1_XH,
> +						ST_ACCEL_2_THS_REG),
> +				ST_SENSORS_LSM_ACCEL_EVENT(1, IIO_MOD_Y,
> +						IIO_EV_DIR_FALLING,
> +						ST_ACCEL_2_INT1_YL,
> +						ST_ACCEL_2_THS_REG),
> +				ST_SENSORS_LSM_ACCEL_EVENT(1, IIO_MOD_Y,
> +						IIO_EV_DIR_RISING,
> +						ST_ACCEL_2_INT1_YH,
> +						ST_ACCEL_2_THS_REG),
> +				ST_SENSORS_LSM_ACCEL_EVENT(2, IIO_MOD_Z,
> +						IIO_EV_DIR_FALLING,
> +						ST_ACCEL_2_INT1_ZL,
> +						ST_ACCEL_2_THS_REG),
> +				ST_SENSORS_LSM_ACCEL_EVENT(2, IIO_MOD_Z,
> +						IIO_EV_DIR_RISING,
> +						ST_ACCEL_2_INT1_ZH,
> +						ST_ACCEL_2_THS_REG),
> +			},
> +		},
> +
>  	},
>  	{
>  		.wai = ST_ACCEL_3_WAI_EXP,
> @@ -437,6 +561,10 @@ static const struct iio_info accel_info = {
>  	.attrs = &st_accel_attribute_group,
>  	.read_raw = &st_accel_read_raw,
>  	.write_raw = &st_accel_write_raw,
> +	.read_event_value = &st_sensors_read_event_value,
> +	.write_event_value = &st_sensors_write_event_value,
> +	.read_event_config = &st_sensors_read_event_config,
> +	.write_event_config = &st_sensors_write_event_config,
>  };
>
>  #ifdef CONFIG_IIO_TRIGGER
> @@ -452,6 +580,7 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
>  int st_accel_common_probe(struct iio_dev *indio_dev)
>  {
>  	int err;
> +	int i;
>  	struct st_sensor_data *adata = iio_priv(indio_dev);
>
>  	indio_dev->modes = INDIO_DIRECT_MODE;
> @@ -489,6 +618,20 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
>  			goto st_accel_probe_trigger_error;
>  	}
>
> +	if (adata->get_irq_event(indio_dev) > 0) {
> +		err = st_sensors_request_event_irq(indio_dev);
Compile error as not exported in the previous patch.

> +		if (err < 0)
> +			goto st_accel_request_irq_event_error;
> +
> +		for (i = 0; i < indio_dev->num_channels; i++)
> +			adata->sensor->ch[i].event_mask =
> +				ST_SENSORS_LSM_EVENTS_MASK;

This is an easy driver to get lost in, but I think that adata->sensor is
pointing at some constant data, so you can't do the above.  Actually,
ideally this would be made explicit throughout the driver by making the
data pointed to by those pointers constant as well as the pointer.

> +
> +		err = st_sensors_enable_events(indio_dev);
> +		if (err < 0)
> +			goto st_accel_enable_events_error;
> +	}
> +
>  	err = iio_device_register(indio_dev);
>  	if (err)
>  		goto st_accel_device_register_error;
> @@ -496,6 +639,10 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
>  	return err;
>
>  st_accel_device_register_error:
> +st_accel_enable_events_error:
> +	if (adata->get_irq_event(indio_dev) > 0)
> +		free_irq(adata->get_irq_event(indio_dev), indio_dev);
> +st_accel_request_irq_event_error:
>  	if (adata->get_irq_data_ready(indio_dev) > 0)
>  		st_sensors_deallocate_trigger(indio_dev);
>  st_accel_probe_trigger_error:
> @@ -515,6 +662,8 @@ void st_accel_common_remove(struct iio_dev *indio_dev)
>  		st_sensors_deallocate_trigger(indio_dev);
>  		st_accel_deallocate_ring(indio_dev);
>  	}
> +	if (adata->get_irq_event(indio_dev) > 0)
> +		free_irq(adata->get_irq_event(indio_dev), indio_dev);
>  	iio_device_free(indio_dev);
>  }
>  EXPORT_SYMBOL(st_accel_common_remove);
>

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

end of thread, other threads:[~2013-08-04 16:02 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-07-02 12:15 [PATCH 0/4]iio: STMicroelectronics DT and event support Lukasz Czerwinski
     [not found] ` <1372767338-13179-1-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2013-07-02 12:15   ` [PATCH 1/4] iio: st_sensors: Add DT bindings for st_accel and st_gyro Lukasz Czerwinski
2013-07-02 12:15   ` [PATCH 2/4] iio: st_sensors: Add threshold events support Lukasz Czerwinski
     [not found]     ` <1372767338-13179-3-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2013-08-04 14:55       ` Jonathan Cameron
2013-07-02 12:15   ` [PATCH 3/4] iio: accel: Add event subsystem to st_accel driver Lukasz Czerwinski
     [not found]     ` <1372767338-13179-4-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2013-08-04 16:02       ` Jonathan Cameron
2013-07-02 12:15   ` [PATCH 4/4] iio: lps331ap: Add support for DT Lukasz Czerwinski
     [not found]     ` <1372767338-13179-5-git-send-email-l.czerwinski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2013-07-02 12:56       ` Lars-Peter Clausen
     [not found]         ` <51D2CE03.2070704-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
2013-07-02 15:28           ` Jacek Anaszewski
2013-07-16 13:22       ` Maxime Ripard
2013-07-19 13:43         ` Jacek Anaszewski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).