linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] Add MMA9553 driver & PM support for MMA9551
@ 2014-12-19 22:57 Irina Tirdea
  2014-12-19 22:57 ` [PATCH 1/8] iio: core: Introduce CALORIES channel type Irina Tirdea
                   ` (7 more replies)
  0 siblings, 8 replies; 27+ messages in thread
From: Irina Tirdea @ 2014-12-19 22:57 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Irina Tirdea

This set of patches includes changes for the MMA9551 and MMA9553 drivers:
- add support for Freescale MMA9553L Intelligent Pedometer Platform
(http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
- add new iio channels for CALORIES, DISTANCE and SPEED needed by the pedometer
- add IIO_CHAN_INFO_CALIBGENDER and IO_CHAN_INFO_CALIBWEIGHT needed to
configure the pedometer
- add runtime PM support for MMA9551

Irina Tirdea (8):
  iio: core: Introduce CALORIES channel type
  iio: core: Introduce DISTANCE channel type
  iio: core: Introduce SPEED channel type
  iio: core: Introduce IO_CHAN_INFO_CALIBWEIGHT
  iio: core: Introduce IIO_CHAN_INFO_CALIBGENDER
  iio: accel: mma9551: Add runtime pm support
  iio: accel: mma9551: split driver to expose mma955x api
  iio: add driver for Freescale MMA9553

 Documentation/ABI/testing/sysfs-bus-iio |   42 ++
 drivers/iio/accel/Kconfig               |   16 +
 drivers/iio/accel/Makefile              |    5 +-
 drivers/iio/accel/mma9551.c             |  488 +++---------
 drivers/iio/accel/mma9551_core.c        |  531 +++++++++++++
 drivers/iio/accel/mma9551_core.h        |   89 +++
 drivers/iio/accel/mma9553.c             | 1239 +++++++++++++++++++++++++++++++
 drivers/iio/industrialio-core.c         |    5 +
 include/linux/iio/iio.h                 |    2 +
 include/linux/iio/types.h               |    3 +
 10 files changed, 2015 insertions(+), 405 deletions(-)
 create mode 100644 drivers/iio/accel/mma9551_core.c
 create mode 100644 drivers/iio/accel/mma9551_core.h
 create mode 100644 drivers/iio/accel/mma9553.c

-- 
1.7.9.5


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

* [PATCH 1/8] iio: core: Introduce CALORIES channel type
  2014-12-19 22:57 [PATCH 0/8] Add MMA9553 driver & PM support for MMA9551 Irina Tirdea
@ 2014-12-19 22:57 ` Irina Tirdea
  2014-12-26 13:26   ` Jonathan Cameron
  2014-12-19 22:57 ` [PATCH 2/8] iio: core: Introduce DISTANCE " Irina Tirdea
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 27+ messages in thread
From: Irina Tirdea @ 2014-12-19 22:57 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Irina Tirdea

Some devices compute the number of calories that the user has
burnt since the last reset.

One of this devices is Freescale's MMA9553L
(http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
that computes the number of calories based on weight and step rate.

Introduce a new channel type CALORIES to export these values.

Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
---
 Documentation/ABI/testing/sysfs-bus-iio |    9 +++++++++
 drivers/iio/industrialio-core.c         |    1 +
 include/linux/iio/types.h               |    1 +
 3 files changed, 11 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index df5e69e..bb9342b 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -282,6 +282,7 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_current_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_calories_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
@@ -1049,6 +1050,14 @@ Description:
 		For a list of available output power modes read
 		in_accel_power_mode_available.
 
+What:		/sys/.../iio:deviceX/in_calories_input
+What:		/sys/.../iio:deviceX/in_calories_raw
+KernelVersion:	3.17
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This attribute is used to read the number of calories burned since the last
+		reset. Units after application of scale are Joules.
+
 What:		/sys/bus/iio/devices/iio:deviceX/store_eeprom
 KernelVersion:	3.4.0
 Contact:	linux-iio@vger.kernel.org
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index ee442ee..5d95e84 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -72,6 +72,7 @@ static const char * const iio_chan_type_name_spec[] = {
 	[IIO_HUMIDITYRELATIVE] = "humidityrelative",
 	[IIO_ACTIVITY] = "activity",
 	[IIO_STEPS] = "steps",
+	[IIO_CALORIES] = "calories",
 };
 
 static const char * const iio_modifier_names[] = {
diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
index 904dcbb..d2fe930 100644
--- a/include/linux/iio/types.h
+++ b/include/linux/iio/types.h
@@ -32,6 +32,7 @@ enum iio_chan_type {
 	IIO_HUMIDITYRELATIVE,
 	IIO_ACTIVITY,
 	IIO_STEPS,
+	IIO_CALORIES,
 };
 
 enum iio_modifier {
-- 
1.7.9.5


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

* [PATCH 2/8] iio: core: Introduce DISTANCE channel type
  2014-12-19 22:57 [PATCH 0/8] Add MMA9553 driver & PM support for MMA9551 Irina Tirdea
  2014-12-19 22:57 ` [PATCH 1/8] iio: core: Introduce CALORIES channel type Irina Tirdea
@ 2014-12-19 22:57 ` Irina Tirdea
  2014-12-19 22:57 ` [PATCH 3/8] iio: core: Introduce SPEED " Irina Tirdea
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 27+ messages in thread
From: Irina Tirdea @ 2014-12-19 22:57 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Irina Tirdea

Some devices export an estimation of the distance the user has covered
since the last reset.

One of this devices is Freescale's MMA9553L
(http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
that computes the distance based on the stride length and step rate.

Introduce a new channel type DISTANCE to export these values.

Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
---
 Documentation/ABI/testing/sysfs-bus-iio |    9 +++++++++
 drivers/iio/industrialio-core.c         |    1 +
 include/linux/iio/types.h               |    1 +
 3 files changed, 11 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index bb9342b..a5c1dcc 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -283,6 +283,7 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_calories_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_distance_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
@@ -1058,6 +1059,14 @@ Description:
 		This attribute is used to read the number of calories burned since the last
 		reset. Units after application of scale are Joules.
 
+What:		/sys/.../iio:deviceX/in_distance_input
+What:		/sys/.../iio:deviceX/in_distance_raw
+KernelVersion:	3.17
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This attribute is used to read the distance covered by the user since
+		the last reboot while activated. Units after application of scale are meters.
+
 What:		/sys/bus/iio/devices/iio:deviceX/store_eeprom
 KernelVersion:	3.4.0
 Contact:	linux-iio@vger.kernel.org
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 5d95e84..4a10d31 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -73,6 +73,7 @@ static const char * const iio_chan_type_name_spec[] = {
 	[IIO_ACTIVITY] = "activity",
 	[IIO_STEPS] = "steps",
 	[IIO_CALORIES] = "calories",
+	[IIO_DISTANCE] = "distance",
 };
 
 static const char * const iio_modifier_names[] = {
diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
index d2fe930..b98f751 100644
--- a/include/linux/iio/types.h
+++ b/include/linux/iio/types.h
@@ -33,6 +33,7 @@ enum iio_chan_type {
 	IIO_ACTIVITY,
 	IIO_STEPS,
 	IIO_CALORIES,
+	IIO_DISTANCE,
 };
 
 enum iio_modifier {
-- 
1.7.9.5


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

* [PATCH 3/8] iio: core: Introduce SPEED channel type
  2014-12-19 22:57 [PATCH 0/8] Add MMA9553 driver & PM support for MMA9551 Irina Tirdea
  2014-12-19 22:57 ` [PATCH 1/8] iio: core: Introduce CALORIES channel type Irina Tirdea
  2014-12-19 22:57 ` [PATCH 2/8] iio: core: Introduce DISTANCE " Irina Tirdea
@ 2014-12-19 22:57 ` Irina Tirdea
  2014-12-26 13:28   ` Jonathan Cameron
  2014-12-19 22:57 ` [PATCH 4/8] iio: core: Introduce IO_CHAN_INFO_CALIBWEIGHT Irina Tirdea
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 27+ messages in thread
From: Irina Tirdea @ 2014-12-19 22:57 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Irina Tirdea

Some devices export the current speed value of the user.

One of this devices is Freescale's MMA9553L
(http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
that computes the speed of the user based on the number of steps and
stride length.

Introduce a new channel type SPEED to export these values.

Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
---
 Documentation/ABI/testing/sysfs-bus-iio |    9 +++++++++
 drivers/iio/industrialio-core.c         |    1 +
 include/linux/iio/types.h               |    1 +
 3 files changed, 11 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index a5c1dcc..07acef7 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -295,6 +295,7 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_pressure_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_humidityrelative_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_speed_scale
 KernelVersion:	2.6.35
 Contact:	linux-iio@vger.kernel.org
 Description:
@@ -1146,6 +1147,14 @@ Description:
 		present, output should be considered as processed with the
 		unit in milliamps.
 
+What:		/sys/.../iio:deviceX/in_speed_input
+What:		/sys/.../iio:deviceX/in_speed_raw
+KernelVersion:	3.19
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This attribute is used to read the current speed value of the user.
+		Units after application of scale are m/s.
+
 What:		/sys/.../iio:deviceX/in_steps_en
 KernelVersion:	3.19
 Contact:	linux-iio@vger.kernel.org
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 4a10d31..5e50aca 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -74,6 +74,7 @@ static const char * const iio_chan_type_name_spec[] = {
 	[IIO_STEPS] = "steps",
 	[IIO_CALORIES] = "calories",
 	[IIO_DISTANCE] = "distance",
+	[IIO_SPEED] = "speed",
 };
 
 static const char * const iio_modifier_names[] = {
diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
index b98f751..c848f45 100644
--- a/include/linux/iio/types.h
+++ b/include/linux/iio/types.h
@@ -34,6 +34,7 @@ enum iio_chan_type {
 	IIO_STEPS,
 	IIO_CALORIES,
 	IIO_DISTANCE,
+	IIO_SPEED,
 };
 
 enum iio_modifier {
-- 
1.7.9.5


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

* [PATCH 4/8] iio: core: Introduce IO_CHAN_INFO_CALIBWEIGHT
  2014-12-19 22:57 [PATCH 0/8] Add MMA9553 driver & PM support for MMA9551 Irina Tirdea
                   ` (2 preceding siblings ...)
  2014-12-19 22:57 ` [PATCH 3/8] iio: core: Introduce SPEED " Irina Tirdea
@ 2014-12-19 22:57 ` Irina Tirdea
  2014-12-26 13:31   ` Jonathan Cameron
  2014-12-19 22:57 ` [PATCH 5/8] iio: core: Introduce IIO_CHAN_INFO_CALIBGENDER Irina Tirdea
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 27+ messages in thread
From: Irina Tirdea @ 2014-12-19 22:57 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Irina Tirdea

Some devices need the weight of the user to compute other
parameters. One of this devices is Freescale's MMA9553L
(http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
that needs the weight of the user to compute the number of calories burnt.

Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
---
 Documentation/ABI/testing/sysfs-bus-iio |    7 +++++++
 drivers/iio/industrialio-core.c         |    1 +
 include/linux/iio/iio.h                 |    1 +
 3 files changed, 9 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 07acef7..e480175 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -351,6 +351,13 @@ Description:
 		to compute the stride length, distance, speed and activity
 		type.
 
+What:		/sys/bus/iio/devices/iio:deviceX/in_steps_calibweight
+KernelVersion:	3.19
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Weight of the user (in kg). It is needed by some pedometers
+		to compute the calories burnt by the user.
+
 What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale_available
 What:		/sys/.../iio:deviceX/in_voltageX_scale_available
 What:		/sys/.../iio:deviceX/in_voltage-voltage_scale_available
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 5e50aca..4c435c8 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -124,6 +124,7 @@ static const char * const iio_chan_info_postfix[] = {
 	[IIO_CHAN_INFO_INT_TIME] = "integration_time",
 	[IIO_CHAN_INFO_ENABLE] = "en",
 	[IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight",
+	[IIO_CHAN_INFO_CALIBWEIGHT] = "calibweight",
 };
 
 /**
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 878d861..752a929 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -40,6 +40,7 @@ enum iio_chan_info_enum {
 	IIO_CHAN_INFO_INT_TIME,
 	IIO_CHAN_INFO_ENABLE,
 	IIO_CHAN_INFO_CALIBHEIGHT,
+	IIO_CHAN_INFO_CALIBWEIGHT,
 };
 
 enum iio_shared_by {
-- 
1.7.9.5


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

* [PATCH 5/8] iio: core: Introduce IIO_CHAN_INFO_CALIBGENDER
  2014-12-19 22:57 [PATCH 0/8] Add MMA9553 driver & PM support for MMA9551 Irina Tirdea
                   ` (3 preceding siblings ...)
  2014-12-19 22:57 ` [PATCH 4/8] iio: core: Introduce IO_CHAN_INFO_CALIBWEIGHT Irina Tirdea
@ 2014-12-19 22:57 ` Irina Tirdea
  2014-12-26 13:29   ` Jonathan Cameron
  2014-12-19 22:57 ` [PATCH 6/8] iio: accel: mma9551: Add runtime pm support Irina Tirdea
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 27+ messages in thread
From: Irina Tirdea @ 2014-12-19 22:57 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Irina Tirdea

Some devices need the gender of the user to compute various
parameters. One of this devices is Freescale's MMA9553L
(http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
that needs the gender of the user to compute distance, speed and activity type.

Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
---
 Documentation/ABI/testing/sysfs-bus-iio |    8 ++++++++
 drivers/iio/industrialio-core.c         |    1 +
 include/linux/iio/iio.h                 |    1 +
 3 files changed, 10 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index e480175..3b68c2d 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -343,6 +343,14 @@ Description:
 		production inaccuracies).  If shared across all channels,
 		<type>_calibscale is used.
 
+What:		/sys/bus/iio/devices/iio:deviceX/in_steps_calibgender
+KernelVersion:	3.19
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Gender of the user: 0 for female and 1 for male. It is needed
+		by some pedometers to compute the stride length, distance,
+		speed and activity type.
+
 What:		/sys/bus/iio/devices/iio:deviceX/in_steps_calibheight
 KernelVersion:	3.19
 Contact:	linux-iio@vger.kernel.org
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 4c435c8..93a39f9 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -125,6 +125,7 @@ static const char * const iio_chan_info_postfix[] = {
 	[IIO_CHAN_INFO_ENABLE] = "en",
 	[IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight",
 	[IIO_CHAN_INFO_CALIBWEIGHT] = "calibweight",
+	[IIO_CHAN_INFO_CALIBGENDER] = "calibgender",
 };
 
 /**
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 752a929..63dac0f 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -41,6 +41,7 @@ enum iio_chan_info_enum {
 	IIO_CHAN_INFO_ENABLE,
 	IIO_CHAN_INFO_CALIBHEIGHT,
 	IIO_CHAN_INFO_CALIBWEIGHT,
+	IIO_CHAN_INFO_CALIBGENDER,
 };
 
 enum iio_shared_by {
-- 
1.7.9.5


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

* [PATCH 6/8] iio: accel: mma9551: Add runtime pm support
  2014-12-19 22:57 [PATCH 0/8] Add MMA9553 driver & PM support for MMA9551 Irina Tirdea
                   ` (4 preceding siblings ...)
  2014-12-19 22:57 ` [PATCH 5/8] iio: core: Introduce IIO_CHAN_INFO_CALIBGENDER Irina Tirdea
@ 2014-12-19 22:57 ` Irina Tirdea
  2014-12-19 22:57 ` [PATCH 7/8] iio: accel: mma9551: split driver to expose mma955x api Irina Tirdea
  2014-12-19 22:57 ` [PATCH 8/8] iio: add driver for Freescale MMA9553 Irina Tirdea
  7 siblings, 0 replies; 27+ messages in thread
From: Irina Tirdea @ 2014-12-19 22:57 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Irina Tirdea

Add support for runtime pm to reduce the power consumed by the device
when not used.

If CONFIG_PM is not enabled, the device will be powered on at
init and only powered off on system suspend.

If CONFIG_PM is enabled, runtime pm autosuspend is used:
- for raw reads will keep the device on for a specified time
- for events it will keep the device on as long as we have at least
one event active

Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
Reviewed-by: Vlad Dogaru <vlad.dogaru@intel.com>
---
 drivers/iio/accel/mma9551.c |  161 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 138 insertions(+), 23 deletions(-)

diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
index 1be125b..34ee9d6 100644
--- a/drivers/iio/accel/mma9551.c
+++ b/drivers/iio/accel/mma9551.c
@@ -22,6 +22,7 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/events.h>
+#include <linux/pm_runtime.h>
 
 #define MMA9551_DRV_NAME		"mma9551"
 #define MMA9551_IRQ_NAME		"mma9551_event"
@@ -71,6 +72,7 @@ enum mma9551_gpio_pin {
 /* Sleep/Wake application */
 #define MMA9551_SLEEP_CFG		0x06
 #define MMA9551_SLEEP_CFG_SNCEN		BIT(0)
+#define MMA9551_SLEEP_CFG_FLEEN		BIT(1)
 #define MMA9551_SLEEP_CFG_SCHEN		BIT(2)
 
 /* AFE application */
@@ -114,6 +116,9 @@ enum mma9551_tilt_axis {
 #define MMA9551_I2C_READ_RETRIES	5
 #define MMA9551_I2C_READ_DELAY	50	/* us */
 
+#define MMA9551_DEFAULT_SAMPLE_RATE	122	/* Hz */
+#define MMA9551_AUTO_SUSPEND_DELAY_MS	2000
+
 struct mma9551_mbox_request {
 	u8 start_mbox;		/* Always 0. */
 	u8 app_id;
@@ -387,16 +392,55 @@ static int mma9551_read_version(struct i2c_client *client)
 }
 
 /*
+ * Power on chip and enable doze mode.
  * Use 'false' as the second parameter to cause the device to enter
  * sleep.
  */
-static int mma9551_set_device_state(struct i2c_client *client,
-				    bool enable)
+static int mma9551_set_device_state(struct i2c_client *client, bool enable)
 {
 	return mma9551_update_config_bits(client, MMA9551_APPID_SLEEP_WAKE,
 					  MMA9551_SLEEP_CFG,
-					  MMA9551_SLEEP_CFG_SNCEN,
-					  enable ? 0 : MMA9551_SLEEP_CFG_SNCEN);
+					  MMA9551_SLEEP_CFG_SNCEN |
+					  MMA9551_SLEEP_CFG_FLEEN |
+					  MMA9551_SLEEP_CFG_SCHEN,
+					  enable ? MMA9551_SLEEP_CFG_SCHEN |
+					  MMA9551_SLEEP_CFG_FLEEN :
+					  MMA9551_SLEEP_CFG_SNCEN);
+}
+
+static int mma9551_set_power_state(struct i2c_client *client, bool on)
+{
+#ifdef CONFIG_PM
+	int ret;
+
+	if (on)
+		ret = pm_runtime_get_sync(&client->dev);
+	else {
+		pm_runtime_mark_last_busy(&client->dev);
+		ret = pm_runtime_put_autosuspend(&client->dev);
+	}
+
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"failed to change power state to %d\n", on);
+		if (on)
+			pm_runtime_put_noidle(&client->dev);
+
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+
+static void mma9551_sleep(int freq)
+{
+	int sleep_val = 1000 / freq;
+
+	if (sleep_val < 20)
+		usleep_range(sleep_val * 1000, 20000);
+	else
+		msleep_interruptible(sleep_val);
 }
 
 static int mma9551_read_incli_chan(struct i2c_client *client,
@@ -424,15 +468,19 @@ static int mma9551_read_incli_chan(struct i2c_client *client,
 		return -EINVAL;
 	}
 
+	ret = mma9551_set_power_state(client, true);
+	if (ret < 0)
+		return ret;
+
 	ret = mma9551_read_status_byte(client, MMA9551_APPID_TILT,
 				       reg_addr, &angle);
 	if (ret < 0)
-		return ret;
+		goto out_poweroff;
 
 	ret = mma9551_read_status_byte(client, MMA9551_APPID_TILT,
 				       MMA9551_TILT_QUAD_REG, &quadrant);
 	if (ret < 0)
-		return ret;
+		goto out_poweroff;
 
 	angle &= ~MMA9551_TILT_ANGFLG;
 	quadrant = (quadrant >> quad_shift) & 0x03;
@@ -442,7 +490,11 @@ static int mma9551_read_incli_chan(struct i2c_client *client,
 	else
 		*val = angle + 90 * quadrant;
 
-	return IIO_VAL_INT;
+	ret = IIO_VAL_INT;
+
+out_poweroff:
+	mma9551_set_power_state(client, false);
+	return ret;
 }
 
 static int mma9551_read_accel_chan(struct i2c_client *client,
@@ -467,14 +519,22 @@ static int mma9551_read_accel_chan(struct i2c_client *client,
 		return -EINVAL;
 	}
 
+	ret = mma9551_set_power_state(client, true);
+	if (ret < 0)
+		return ret;
+
 	ret = mma9551_read_status_word(client, MMA9551_APPID_AFE,
 				       reg_addr, &raw_accel);
 	if (ret < 0)
-		return ret;
+		goto out_poweroff;
 
 	*val = raw_accel;
 
-	return IIO_VAL_INT;
+	ret = IIO_VAL_INT;
+
+out_poweroff:
+	mma9551_set_power_state(client, false);
+	return ret;
 }
 
 static int mma9551_read_raw(struct iio_dev *indio_dev,
@@ -555,6 +615,10 @@ static int mma9551_config_incli_event(struct iio_dev *indio_dev,
 					  MMA9551_APPID_NONE, 0, 0);
 		if (ret < 0)
 			return ret;
+
+		ret = mma9551_set_power_state(data->client, false);
+		if (ret < 0)
+			return ret;
 	} else {
 		int bitnum;
 
@@ -573,10 +637,16 @@ static int mma9551_config_incli_event(struct iio_dev *indio_dev,
 			return -EINVAL;
 		}
 
+		ret = mma9551_set_power_state(data->client, true);
+		if (ret < 0)
+			return ret;
+
 		ret = mma9551_gpio_config(data->client, mma_axis,
 					  MMA9551_APPID_TILT, bitnum, 0);
-		if (ret < 0)
+		if (ret < 0) {
+			mma9551_set_power_state(data->client, false);
 			return ret;
+		}
 	}
 
 	data->event_enabled[mma_axis] = state;
@@ -769,12 +839,7 @@ static int mma9551_init(struct mma9551_data *data)
 	if (ret)
 		return ret;
 
-	/* Power on chip and enable doze mode. */
-	return mma9551_update_config_bits(data->client,
-			 MMA9551_APPID_SLEEP_WAKE,
-			 MMA9551_SLEEP_CFG,
-			 MMA9551_SLEEP_CFG_SCHEN | MMA9551_SLEEP_CFG_SNCEN,
-			 MMA9551_SLEEP_CFG_SCHEN);
+	return mma9551_set_device_state(data->client, true);
 }
 
 static int mma9551_gpio_probe(struct iio_dev *indio_dev)
@@ -867,8 +932,19 @@ static int mma9551_probe(struct i2c_client *client,
 		goto out_poweroff;
 	}
 
+	ret = pm_runtime_set_active(&client->dev);
+	if (ret < 0)
+		goto out_iio_unregister;
+
+	pm_runtime_enable(&client->dev);
+	pm_runtime_set_autosuspend_delay(&client->dev,
+					 MMA9551_AUTO_SUSPEND_DELAY_MS);
+	pm_runtime_use_autosuspend(&client->dev);
+
 	return 0;
 
+out_iio_unregister:
+	iio_device_unregister(indio_dev);
 out_poweroff:
 	mma9551_set_device_state(client, false);
 
@@ -880,6 +956,10 @@ static int mma9551_remove(struct i2c_client *client)
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 	struct mma9551_data *data = iio_priv(indio_dev);
 
+	pm_runtime_disable(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+	pm_runtime_put_noidle(&client->dev);
+
 	iio_device_unregister(indio_dev);
 	mutex_lock(&data->mutex);
 	mma9551_set_device_state(data->client, false);
@@ -888,37 +968,72 @@ static int mma9551_remove(struct i2c_client *client)
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int mma9551_runtime_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9551_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = mma9551_set_device_state(data->client, false);
+	mutex_unlock(&data->mutex);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "powering off device failed\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static int mma9551_runtime_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9551_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ret = mma9551_set_device_state(data->client, true);
+	if (ret < 0)
+		return ret;
+
+	mma9551_sleep(MMA9551_DEFAULT_SAMPLE_RATE);
+
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_PM_SLEEP
 static int mma9551_suspend(struct device *dev)
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 	struct mma9551_data *data = iio_priv(indio_dev);
+	int ret;
 
 	mutex_lock(&data->mutex);
-	mma9551_set_device_state(data->client, false);
+	ret = mma9551_set_device_state(data->client, false);
 	mutex_unlock(&data->mutex);
 
-	return 0;
+	return ret;
 }
 
 static int mma9551_resume(struct device *dev)
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 	struct mma9551_data *data = iio_priv(indio_dev);
+	int ret;
 
 	mutex_lock(&data->mutex);
-	mma9551_set_device_state(data->client, true);
+	ret = mma9551_set_device_state(data->client, true);
 	mutex_unlock(&data->mutex);
 
-	return 0;
+	return ret;
 }
-#else
-#define mma9551_suspend NULL
-#define mma9551_resume NULL
 #endif
 
 static const struct dev_pm_ops mma9551_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(mma9551_suspend, mma9551_resume)
+	SET_RUNTIME_PM_OPS(mma9551_runtime_suspend,
+			   mma9551_runtime_resume, NULL)
 };
 
 static const struct acpi_device_id mma9551_acpi_match[] = {
-- 
1.7.9.5


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

* [PATCH 7/8] iio: accel: mma9551: split driver to expose mma955x api
  2014-12-19 22:57 [PATCH 0/8] Add MMA9553 driver & PM support for MMA9551 Irina Tirdea
                   ` (5 preceding siblings ...)
  2014-12-19 22:57 ` [PATCH 6/8] iio: accel: mma9551: Add runtime pm support Irina Tirdea
@ 2014-12-19 22:57 ` Irina Tirdea
  2015-01-01 10:58   ` Jonathan Cameron
  2014-12-19 22:57 ` [PATCH 8/8] iio: add driver for Freescale MMA9553 Irina Tirdea
  7 siblings, 1 reply; 27+ messages in thread
From: Irina Tirdea @ 2014-12-19 22:57 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Irina Tirdea

Freescale has the MMA955xL family of devices that use the
same communication protocol (based on i2c messages):
http://www.freescale.com/files/sensors/doc/data_sheet/MMA955xL.pdf.

To support more devices from this family, we need to split the
mma9551 driver so we can export the common functions that will
be used by other mma955x drivers.

Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
Reviewed-by: Vlad Dogaru <vlad.dogaru@intel.com>
---
 drivers/iio/accel/Kconfig        |    6 +
 drivers/iio/accel/Makefile       |    4 +-
 drivers/iio/accel/mma9551.c      |  443 +-------------------------------------
 drivers/iio/accel/mma9551_core.c |  443 ++++++++++++++++++++++++++++++++++++++
 drivers/iio/accel/mma9551_core.h |   74 +++++++
 5 files changed, 530 insertions(+), 440 deletions(-)
 create mode 100644 drivers/iio/accel/mma9551_core.c
 create mode 100644 drivers/iio/accel/mma9551_core.h

diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index d80616d..0600798 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -105,9 +105,15 @@ config KXCJK1013
 	  To compile this driver as a module, choose M here: the module will
 	  be called kxcjk-1013.
 
+config MMA9551_CORE
+	tristate
+	depends on MMA9551
+
 config MMA9551
 	tristate "Freescale MMA9551L Intelligent Motion-Sensing Platform Driver"
 	depends on I2C
+	select MMA9551_CORE
+
 	help
 	  Say yes here to build support for the Freescale MMA9551L
 	  Intelligent Motion-Sensing Platform Driver.
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index de5b9cb..8105316 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -9,7 +9,9 @@ obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
 obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
 obj-$(CONFIG_KXSD9)	+= kxsd9.o
 obj-$(CONFIG_MMA8452)	+= mma8452.o
-obj-$(CONFIG_MMA9551)	+= mma9551.o
+
+obj-$(CONFIG_MMA9551_CORE)	+= mma9551_core.o
+obj-$(CONFIG_MMA9551)		+= mma9551.o
 
 obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
 st_accel-y := st_accel_core.o
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
index 34ee9d6..6031b5a 100644
--- a/drivers/iio/accel/mma9551.c
+++ b/drivers/iio/accel/mma9551.c
@@ -23,63 +23,13 @@
 #include <linux/iio/sysfs.h>
 #include <linux/iio/events.h>
 #include <linux/pm_runtime.h>
+#include "mma9551_core.h"
 
 #define MMA9551_DRV_NAME		"mma9551"
 #define MMA9551_IRQ_NAME		"mma9551_event"
 #define MMA9551_GPIO_NAME		"mma9551_int"
 #define MMA9551_GPIO_COUNT		4
 
-/* Applications IDs */
-#define MMA9551_APPID_VERSION		0x00
-#define MMA9551_APPID_GPIO		0x03
-#define MMA9551_APPID_AFE		0x06
-#define MMA9551_APPID_TILT		0x0B
-#define MMA9551_APPID_SLEEP_WAKE	0x12
-#define MMA9551_APPID_RESET		0x17
-#define MMA9551_APPID_NONE		0xff
-
-/* Command masks for mailbox write command */
-#define MMA9551_CMD_READ_VERSION_INFO	0x00
-#define MMA9551_CMD_READ_CONFIG		0x10
-#define MMA9551_CMD_WRITE_CONFIG	0x20
-#define MMA9551_CMD_READ_STATUS		0x30
-
-enum mma9551_gpio_pin {
-	mma9551_gpio6 = 0,
-	mma9551_gpio7,
-	mma9551_gpio8,
-	mma9551_gpio9,
-	mma9551_gpio_max = mma9551_gpio9,
-};
-
-/* Mailbox read command */
-#define MMA9551_RESPONSE_COCO		BIT(7)
-
-/* Error-Status codes returned in mailbox read command */
-#define MMA9551_MCI_ERROR_NONE			0x00
-#define MMA9551_MCI_ERROR_PARAM			0x04
-#define MMA9551_MCI_INVALID_COUNT		0x19
-#define MMA9551_MCI_ERROR_COMMAND		0x1C
-#define MMA9551_MCI_ERROR_INVALID_LENGTH	0x21
-#define MMA9551_MCI_ERROR_FIFO_BUSY		0x22
-#define MMA9551_MCI_ERROR_FIFO_ALLOCATED	0x23
-#define MMA9551_MCI_ERROR_FIFO_OVERSIZE		0x24
-
-/* GPIO Application */
-#define MMA9551_GPIO_POL_MSB		0x08
-#define MMA9551_GPIO_POL_LSB		0x09
-
-/* Sleep/Wake application */
-#define MMA9551_SLEEP_CFG		0x06
-#define MMA9551_SLEEP_CFG_SNCEN		BIT(0)
-#define MMA9551_SLEEP_CFG_FLEEN		BIT(1)
-#define MMA9551_SLEEP_CFG_SCHEN		BIT(2)
-
-/* AFE application */
-#define MMA9551_AFE_X_ACCEL_REG		0x00
-#define MMA9551_AFE_Y_ACCEL_REG		0x02
-#define MMA9551_AFE_Z_ACCEL_REG		0x04
-
 /* Tilt application (inclination in IIO terms). */
 #define MMA9551_TILT_XZ_ANG_REG		0x00
 #define MMA9551_TILT_YZ_ANG_REG		0x01
@@ -92,6 +42,8 @@ enum mma9551_gpio_pin {
 #define MMA9551_TILT_CFG_REG		0x01
 #define MMA9551_TILT_ANG_THRESH_MASK	GENMASK(3, 0)
 
+#define MMA9551_DEFAULT_SAMPLE_RATE	122	/* Hz */
+
 /* Tilt events are mapped to the first three GPIO pins. */
 enum mma9551_tilt_axis {
 	mma9551_x = 0,
@@ -99,64 +51,6 @@ enum mma9551_tilt_axis {
 	mma9551_z,
 };
 
-/*
- * A response is composed of:
- * - control registers: MB0-3
- * - data registers: MB4-31
- *
- * A request is composed of:
- * - mbox to write to (always 0)
- * - control registers: MB1-4
- * - data registers: MB5-31
- */
-#define MMA9551_MAILBOX_CTRL_REGS	4
-#define MMA9551_MAX_MAILBOX_DATA_REGS	28
-#define MMA9551_MAILBOX_REGS		32
-
-#define MMA9551_I2C_READ_RETRIES	5
-#define MMA9551_I2C_READ_DELAY	50	/* us */
-
-#define MMA9551_DEFAULT_SAMPLE_RATE	122	/* Hz */
-#define MMA9551_AUTO_SUSPEND_DELAY_MS	2000
-
-struct mma9551_mbox_request {
-	u8 start_mbox;		/* Always 0. */
-	u8 app_id;
-	/*
-	 * See Section 5.3.1 of the MMA955xL Software Reference Manual.
-	 *
-	 * Bit 7: reserved, always 0
-	 * Bits 6-4: command
-	 * Bits 3-0: upper bits of register offset
-	 */
-	u8 cmd_off;
-	u8 lower_off;
-	u8 nbytes;
-	u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS - 1];
-} __packed;
-
-struct mma9551_mbox_response {
-	u8 app_id;
-	/*
-	 * See Section 5.3.3 of the MMA955xL Software Reference Manual.
-	 *
-	 * Bit 7: COCO
-	 * Bits 6-0: Error code.
-	 */
-	u8 coco_err;
-	u8 nbytes;
-	u8 req_bytes;
-	u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS];
-} __packed;
-
-struct mma9551_version_info {
-	__be32 device_id;
-	u8 rom_version[2];
-	u8 fw_version[2];
-	u8 hw_version[2];
-	u8 fw_build[2];
-};
-
 struct mma9551_data {
 	struct i2c_client *client;
 	struct mutex mutex;
@@ -164,285 +58,6 @@ struct mma9551_data {
 	int irqs[MMA9551_GPIO_COUNT];
 };
 
-static int mma9551_transfer(struct i2c_client *client,
-			    u8 app_id, u8 command, u16 offset,
-			    u8 *inbytes, int num_inbytes,
-			    u8 *outbytes, int num_outbytes)
-{
-	struct mma9551_mbox_request req;
-	struct mma9551_mbox_response rsp;
-	struct i2c_msg in, out;
-	u8 req_len, err_code;
-	int ret, retries;
-
-	if (offset >= 1 << 12) {
-		dev_err(&client->dev, "register offset too large\n");
-		return -EINVAL;
-	}
-
-	req_len = 1 + MMA9551_MAILBOX_CTRL_REGS + num_inbytes;
-	req.start_mbox = 0;
-	req.app_id = app_id;
-	req.cmd_off = command | (offset >> 8);
-	req.lower_off = offset;
-
-	if (command == MMA9551_CMD_WRITE_CONFIG)
-		req.nbytes = num_inbytes;
-	else
-		req.nbytes = num_outbytes;
-	if (num_inbytes)
-		memcpy(req.buf, inbytes, num_inbytes);
-
-	out.addr = client->addr;
-	out.flags = 0;
-	out.len = req_len;
-	out.buf = (u8 *)&req;
-
-	ret = i2c_transfer(client->adapter, &out, 1);
-	if (ret < 0) {
-		dev_err(&client->dev, "i2c write failed\n");
-		return ret;
-	}
-
-	retries = MMA9551_I2C_READ_RETRIES;
-	do {
-		udelay(MMA9551_I2C_READ_DELAY);
-
-		in.addr = client->addr;
-		in.flags = I2C_M_RD;
-		in.len = sizeof(rsp);
-		in.buf = (u8 *)&rsp;
-
-		ret = i2c_transfer(client->adapter, &in, 1);
-		if (ret < 0) {
-			dev_err(&client->dev, "i2c read failed\n");
-			return ret;
-		}
-
-		if (rsp.coco_err & MMA9551_RESPONSE_COCO)
-			break;
-	} while (--retries > 0);
-
-	if (retries == 0) {
-		dev_err(&client->dev,
-			"timed out while waiting for command response\n");
-		return -ETIMEDOUT;
-	}
-
-	if (rsp.app_id != app_id) {
-		dev_err(&client->dev,
-			"app_id mismatch in response got %02x expected %02x\n",
-			rsp.app_id, app_id);
-		return -EINVAL;
-	}
-
-	err_code = rsp.coco_err & ~MMA9551_RESPONSE_COCO;
-	if (err_code != MMA9551_MCI_ERROR_NONE) {
-		dev_err(&client->dev, "read returned error %x\n", err_code);
-		return -EINVAL;
-	}
-
-	if (rsp.nbytes != rsp.req_bytes) {
-		dev_err(&client->dev,
-			"output length mismatch got %d expected %d\n",
-			rsp.nbytes, rsp.req_bytes);
-		return -EINVAL;
-	}
-
-	if (num_outbytes)
-		memcpy(outbytes, rsp.buf, num_outbytes);
-
-	return 0;
-}
-
-static int mma9551_read_config_byte(struct i2c_client *client, u8 app_id,
-				    u16 reg, u8 *val)
-{
-	return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
-				reg, NULL, 0, val, 1);
-}
-
-static int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
-				     u16 reg, u8 val)
-{
-	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
-				&val, 1, NULL, 0);
-}
-
-static int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
-				    u16 reg, u8 *val)
-{
-	return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
-				reg, NULL, 0, val, 1);
-}
-
-static int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
-				    u16 reg, u16 *val)
-{
-	int ret;
-	__be16 v;
-
-	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
-			       reg, NULL, 0, (u8 *)&v, 2);
-	*val = be16_to_cpu(v);
-
-	return ret;
-}
-
-static int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
-				      u16 reg, u8 mask, u8 val)
-{
-	int ret;
-	u8 tmp, orig;
-
-	ret = mma9551_read_config_byte(client, app_id, reg, &orig);
-	if (ret < 0)
-		return ret;
-
-	tmp = orig & ~mask;
-	tmp |= val & mask;
-
-	if (tmp == orig)
-		return 0;
-
-	return mma9551_write_config_byte(client, app_id, reg, tmp);
-}
-
-/*
- * The polarity parameter is described in section 6.2.2, page 66, of the
- * Software Reference Manual.  Basically, polarity=0 means the interrupt
- * line has the same value as the selected bit, while polarity=1 means
- * the line is inverted.
- */
-static int mma9551_gpio_config(struct i2c_client *client,
-			       enum mma9551_gpio_pin pin,
-			       u8 app_id, u8 bitnum, int polarity)
-{
-	u8 reg, pol_mask, pol_val;
-	int ret;
-
-	if (pin > mma9551_gpio_max) {
-		dev_err(&client->dev, "bad GPIO pin\n");
-		return -EINVAL;
-	}
-
-	/*
-	 * Pin 6 is configured by regs 0x00 and 0x01, pin 7 by 0x02 and
-	 * 0x03, and so on.
-	 */
-	reg = pin * 2;
-
-	ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
-					reg, app_id);
-	if (ret < 0) {
-		dev_err(&client->dev, "error setting GPIO app_id\n");
-		return ret;
-	}
-
-	ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
-					reg + 1, bitnum);
-	if (ret < 0) {
-		dev_err(&client->dev, "error setting GPIO bit number\n");
-		return ret;
-	}
-
-	switch (pin) {
-	case mma9551_gpio6:
-		reg = MMA9551_GPIO_POL_LSB;
-		pol_mask = 1 << 6;
-		break;
-	case mma9551_gpio7:
-		reg = MMA9551_GPIO_POL_LSB;
-		pol_mask = 1 << 7;
-		break;
-	case mma9551_gpio8:
-		reg = MMA9551_GPIO_POL_MSB;
-		pol_mask = 1 << 0;
-		break;
-	case mma9551_gpio9:
-		reg = MMA9551_GPIO_POL_MSB;
-		pol_mask = 1 << 1;
-		break;
-	}
-	pol_val = polarity ? pol_mask : 0;
-
-	ret = mma9551_update_config_bits(client, MMA9551_APPID_GPIO, reg,
-					 pol_mask, pol_val);
-	if (ret < 0)
-		dev_err(&client->dev, "error setting GPIO polarity\n");
-
-	return ret;
-}
-
-static int mma9551_read_version(struct i2c_client *client)
-{
-	struct mma9551_version_info info;
-	int ret;
-
-	ret = mma9551_transfer(client, MMA9551_APPID_VERSION, 0x00, 0x00,
-			       NULL, 0, (u8 *)&info, sizeof(info));
-	if (ret < 0)
-		return ret;
-
-	dev_info(&client->dev, "Device ID 0x%x, firmware version %02x.%02x\n",
-		 be32_to_cpu(info.device_id), info.fw_version[0],
-		 info.fw_version[1]);
-
-	return 0;
-}
-
-/*
- * Power on chip and enable doze mode.
- * Use 'false' as the second parameter to cause the device to enter
- * sleep.
- */
-static int mma9551_set_device_state(struct i2c_client *client, bool enable)
-{
-	return mma9551_update_config_bits(client, MMA9551_APPID_SLEEP_WAKE,
-					  MMA9551_SLEEP_CFG,
-					  MMA9551_SLEEP_CFG_SNCEN |
-					  MMA9551_SLEEP_CFG_FLEEN |
-					  MMA9551_SLEEP_CFG_SCHEN,
-					  enable ? MMA9551_SLEEP_CFG_SCHEN |
-					  MMA9551_SLEEP_CFG_FLEEN :
-					  MMA9551_SLEEP_CFG_SNCEN);
-}
-
-static int mma9551_set_power_state(struct i2c_client *client, bool on)
-{
-#ifdef CONFIG_PM
-	int ret;
-
-	if (on)
-		ret = pm_runtime_get_sync(&client->dev);
-	else {
-		pm_runtime_mark_last_busy(&client->dev);
-		ret = pm_runtime_put_autosuspend(&client->dev);
-	}
-
-	if (ret < 0) {
-		dev_err(&client->dev,
-			"failed to change power state to %d\n", on);
-		if (on)
-			pm_runtime_put_noidle(&client->dev);
-
-		return ret;
-	}
-#endif
-
-	return 0;
-}
-
-static void mma9551_sleep(int freq)
-{
-	int sleep_val = 1000 / freq;
-
-	if (sleep_val < 20)
-		usleep_range(sleep_val * 1000, 20000);
-	else
-		msleep_interruptible(sleep_val);
-}
-
 static int mma9551_read_incli_chan(struct i2c_client *client,
 				   const struct iio_chan_spec *chan,
 				   int *val)
@@ -497,46 +112,6 @@ out_poweroff:
 	return ret;
 }
 
-static int mma9551_read_accel_chan(struct i2c_client *client,
-				   const struct iio_chan_spec *chan,
-				   int *val, int *val2)
-{
-	u16 reg_addr;
-	s16 raw_accel;
-	int ret;
-
-	switch (chan->channel2) {
-	case IIO_MOD_X:
-		reg_addr = MMA9551_AFE_X_ACCEL_REG;
-		break;
-	case IIO_MOD_Y:
-		reg_addr = MMA9551_AFE_Y_ACCEL_REG;
-		break;
-	case IIO_MOD_Z:
-		reg_addr = MMA9551_AFE_Z_ACCEL_REG;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	ret = mma9551_set_power_state(client, true);
-	if (ret < 0)
-		return ret;
-
-	ret = mma9551_read_status_word(client, MMA9551_APPID_AFE,
-				       reg_addr, &raw_accel);
-	if (ret < 0)
-		goto out_poweroff;
-
-	*val = raw_accel;
-
-	ret = IIO_VAL_INT;
-
-out_poweroff:
-	mma9551_set_power_state(client, false);
-	return ret;
-}
-
 static int mma9551_read_raw(struct iio_dev *indio_dev,
 			    struct iio_chan_spec const *chan,
 			    int *val, int *val2, long mask)
@@ -569,9 +144,7 @@ static int mma9551_read_raw(struct iio_dev *indio_dev,
 	case IIO_CHAN_INFO_SCALE:
 		switch (chan->type) {
 		case IIO_ACCEL:
-			*val = 0;
-			*val2 = 2440;
-			return IIO_VAL_INT_PLUS_MICRO;
+			return mma9551_read_accel_scale(val, val2);
 		default:
 			return -EINVAL;
 		}
@@ -737,14 +310,6 @@ static const struct iio_event_spec mma9551_incli_event = {
 	.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
 };
 
-#define MMA9551_ACCEL_CHANNEL(axis) {				\
-	.type = IIO_ACCEL,					\
-	.modified = 1,						\
-	.channel2 = axis,					\
-	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
-	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
-}
-
 #define MMA9551_INCLI_CHANNEL(axis) {				\
 	.type = IIO_INCLI,					\
 	.modified = 1,						\
diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c
new file mode 100644
index 0000000..cab481b
--- /dev/null
+++ b/drivers/iio/accel/mma9551_core.c
@@ -0,0 +1,443 @@
+/*
+ * Common code for Freescale MMA955x Intelligent Sensor Platform drivers
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/pm_runtime.h>
+#include "mma9551_core.h"
+
+/* Command masks for mailbox write command */
+#define MMA9551_CMD_READ_VERSION_INFO	0x00
+#define MMA9551_CMD_READ_CONFIG		0x10
+#define MMA9551_CMD_WRITE_CONFIG	0x20
+#define MMA9551_CMD_READ_STATUS		0x30
+
+/* Mailbox read command */
+#define MMA9551_RESPONSE_COCO		BIT(7)
+
+/* Error-Status codes returned in mailbox read command */
+#define MMA9551_MCI_ERROR_NONE			0x00
+#define MMA9551_MCI_ERROR_PARAM			0x04
+#define MMA9551_MCI_INVALID_COUNT		0x19
+#define MMA9551_MCI_ERROR_COMMAND		0x1C
+#define MMA9551_MCI_ERROR_INVALID_LENGTH	0x21
+#define MMA9551_MCI_ERROR_FIFO_BUSY		0x22
+#define MMA9551_MCI_ERROR_FIFO_ALLOCATED	0x23
+#define MMA9551_MCI_ERROR_FIFO_OVERSIZE		0x24
+
+/* GPIO Application */
+#define MMA9551_GPIO_POL_MSB		0x08
+#define MMA9551_GPIO_POL_LSB		0x09
+
+/* Sleep/Wake application */
+#define MMA9551_SLEEP_CFG		0x06
+#define MMA9551_SLEEP_CFG_SNCEN		BIT(0)
+#define MMA9551_SLEEP_CFG_FLEEN		BIT(1)
+#define MMA9551_SLEEP_CFG_SCHEN		BIT(2)
+
+/* AFE application */
+#define MMA9551_AFE_X_ACCEL_REG		0x00
+#define MMA9551_AFE_Y_ACCEL_REG		0x02
+#define MMA9551_AFE_Z_ACCEL_REG		0x04
+
+/*
+ * A response is composed of:
+ * - control registers: MB0-3
+ * - data registers: MB4-31
+ *
+ * A request is composed of:
+ * - mbox to write to (always 0)
+ * - control registers: MB1-4
+ * - data registers: MB5-31
+ */
+#define MMA9551_MAILBOX_CTRL_REGS	4
+#define MMA9551_MAX_MAILBOX_DATA_REGS	28
+#define MMA9551_MAILBOX_REGS		32
+
+#define MMA9551_I2C_READ_RETRIES	5
+#define MMA9551_I2C_READ_DELAY	50	/* us */
+
+struct mma9551_mbox_request {
+	u8 start_mbox;		/* Always 0. */
+	u8 app_id;
+	/*
+	 * See Section 5.3.1 of the MMA955xL Software Reference Manual.
+	 *
+	 * Bit 7: reserved, always 0
+	 * Bits 6-4: command
+	 * Bits 3-0: upper bits of register offset
+	 */
+	u8 cmd_off;
+	u8 lower_off;
+	u8 nbytes;
+	u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS - 1];
+} __packed;
+
+struct mma9551_mbox_response {
+	u8 app_id;
+	/*
+	 * See Section 5.3.3 of the MMA955xL Software Reference Manual.
+	 *
+	 * Bit 7: COCO
+	 * Bits 6-0: Error code.
+	 */
+	u8 coco_err;
+	u8 nbytes;
+	u8 req_bytes;
+	u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+} __packed;
+
+static int mma9551_transfer(struct i2c_client *client,
+			    u8 app_id, u8 command, u16 offset,
+			    u8 *inbytes, int num_inbytes,
+			    u8 *outbytes, int num_outbytes)
+{
+	struct mma9551_mbox_request req;
+	struct mma9551_mbox_response rsp;
+	struct i2c_msg in, out;
+	u8 req_len, err_code;
+	int ret, retries;
+
+	if (offset >= 1 << 12) {
+		dev_err(&client->dev, "register offset too large\n");
+		return -EINVAL;
+	}
+
+	req_len = 1 + MMA9551_MAILBOX_CTRL_REGS + num_inbytes;
+	req.start_mbox = 0;
+	req.app_id = app_id;
+	req.cmd_off = command | (offset >> 8);
+	req.lower_off = offset;
+
+	if (command == MMA9551_CMD_WRITE_CONFIG)
+		req.nbytes = num_inbytes;
+	else
+		req.nbytes = num_outbytes;
+	if (num_inbytes)
+		memcpy(req.buf, inbytes, num_inbytes);
+
+	out.addr = client->addr;
+	out.flags = 0;
+	out.len = req_len;
+	out.buf = (u8 *)&req;
+
+	ret = i2c_transfer(client->adapter, &out, 1);
+	if (ret < 0) {
+		dev_err(&client->dev, "i2c write failed\n");
+		return ret;
+	}
+
+	retries = MMA9551_I2C_READ_RETRIES;
+	do {
+		udelay(MMA9551_I2C_READ_DELAY);
+
+		in.addr = client->addr;
+		in.flags = I2C_M_RD;
+		in.len = sizeof(rsp);
+		in.buf = (u8 *)&rsp;
+
+		ret = i2c_transfer(client->adapter, &in, 1);
+		if (ret < 0) {
+			dev_err(&client->dev, "i2c read failed\n");
+			return ret;
+		}
+
+		if (rsp.coco_err & MMA9551_RESPONSE_COCO)
+			break;
+	} while (--retries > 0);
+
+	if (retries == 0) {
+		dev_err(&client->dev,
+			"timed out while waiting for command response\n");
+		return -ETIMEDOUT;
+	}
+
+	if (rsp.app_id != app_id) {
+		dev_err(&client->dev,
+			"app_id mismatch in response got %02x expected %02x\n",
+			rsp.app_id, app_id);
+		return -EINVAL;
+	}
+
+	err_code = rsp.coco_err & ~MMA9551_RESPONSE_COCO;
+	if (err_code != MMA9551_MCI_ERROR_NONE) {
+		dev_err(&client->dev, "read returned error %x\n", err_code);
+		return -EINVAL;
+	}
+
+	if (rsp.nbytes != rsp.req_bytes) {
+		dev_err(&client->dev,
+			"output length mismatch got %d expected %d\n",
+			rsp.nbytes, rsp.req_bytes);
+		return -EINVAL;
+	}
+
+	if (num_outbytes)
+		memcpy(outbytes, rsp.buf, num_outbytes);
+
+	return 0;
+}
+
+int mma9551_read_config_byte(struct i2c_client *client, u8 app_id,
+			     u16 reg, u8 *val)
+{
+	return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
+				reg, NULL, 0, val, 1);
+}
+EXPORT_SYMBOL(mma9551_read_config_byte);
+
+int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
+			      u16 reg, u8 val)
+{
+	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
+				&val, 1, NULL, 0);
+}
+EXPORT_SYMBOL(mma9551_write_config_byte);
+
+int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
+			     u16 reg, u8 *val)
+{
+	return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
+				reg, NULL, 0, val, 1);
+}
+EXPORT_SYMBOL(mma9551_read_status_byte);
+
+int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
+			     u16 reg, u16 *val)
+{
+	int ret;
+	__be16 v;
+
+	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
+			       reg, NULL, 0, (u8 *)&v, 2);
+	*val = be16_to_cpu(v);
+
+	return ret;
+}
+EXPORT_SYMBOL(mma9551_read_status_word);
+
+int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
+			       u16 reg, u8 mask, u8 val)
+{
+	int ret;
+	u8 tmp, orig;
+
+	ret = mma9551_read_config_byte(client, app_id, reg, &orig);
+	if (ret < 0)
+		return ret;
+
+	tmp = orig & ~mask;
+	tmp |= val & mask;
+
+	if (tmp == orig)
+		return 0;
+
+	return mma9551_write_config_byte(client, app_id, reg, tmp);
+}
+EXPORT_SYMBOL(mma9551_update_config_bits);
+
+/*
+ * The polarity parameter is described in section 6.2.2, page 66, of the
+ * Software Reference Manual.  Basically, polarity=0 means the interrupt
+ * line has the same value as the selected bit, while polarity=1 means
+ * the line is inverted.
+ */
+int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin,
+			u8 app_id, u8 bitnum, int polarity)
+{
+	u8 reg, pol_mask, pol_val;
+	int ret;
+
+	if (pin > mma9551_gpio_max) {
+		dev_err(&client->dev, "bad GPIO pin\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Pin 6 is configured by regs 0x00 and 0x01, pin 7 by 0x02 and
+	 * 0x03, and so on.
+	 */
+	reg = pin * 2;
+
+	ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
+					reg, app_id);
+	if (ret < 0) {
+		dev_err(&client->dev, "error setting GPIO app_id\n");
+		return ret;
+	}
+
+	ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
+					reg + 1, bitnum);
+	if (ret < 0) {
+		dev_err(&client->dev, "error setting GPIO bit number\n");
+		return ret;
+	}
+
+	switch (pin) {
+	case mma9551_gpio6:
+		reg = MMA9551_GPIO_POL_LSB;
+		pol_mask = 1 << 6;
+		break;
+	case mma9551_gpio7:
+		reg = MMA9551_GPIO_POL_LSB;
+		pol_mask = 1 << 7;
+		break;
+	case mma9551_gpio8:
+		reg = MMA9551_GPIO_POL_MSB;
+		pol_mask = 1 << 0;
+		break;
+	case mma9551_gpio9:
+		reg = MMA9551_GPIO_POL_MSB;
+		pol_mask = 1 << 1;
+		break;
+	}
+	pol_val = polarity ? pol_mask : 0;
+
+	ret = mma9551_update_config_bits(client, MMA9551_APPID_GPIO, reg,
+					 pol_mask, pol_val);
+	if (ret < 0)
+		dev_err(&client->dev, "error setting GPIO polarity\n");
+
+	return ret;
+}
+EXPORT_SYMBOL(mma9551_gpio_config);
+
+int mma9551_read_version(struct i2c_client *client)
+{
+	struct mma9551_version_info info;
+	int ret;
+
+	ret = mma9551_transfer(client, MMA9551_APPID_VERSION, 0x00, 0x00,
+			       NULL, 0, (u8 *)&info, sizeof(info));
+	if (ret < 0)
+		return ret;
+
+	dev_info(&client->dev, "device ID 0x%x, firmware version %02x.%02x\n",
+		 be32_to_cpu(info.device_id), info.fw_version[0],
+		 info.fw_version[1]);
+
+	return 0;
+}
+EXPORT_SYMBOL(mma9551_read_version);
+
+/*
+ * Power on chip and enable doze mode.
+ * Use 'false' as the second parameter to cause the device to enter
+ * sleep.
+ */
+int mma9551_set_device_state(struct i2c_client *client, bool enable)
+{
+	return mma9551_update_config_bits(client, MMA9551_APPID_SLEEP_WAKE,
+					  MMA9551_SLEEP_CFG,
+					  MMA9551_SLEEP_CFG_SNCEN |
+					  MMA9551_SLEEP_CFG_FLEEN |
+					  MMA9551_SLEEP_CFG_SCHEN,
+					  enable ? MMA9551_SLEEP_CFG_SCHEN |
+					  MMA9551_SLEEP_CFG_FLEEN :
+					  MMA9551_SLEEP_CFG_SNCEN);
+}
+EXPORT_SYMBOL(mma9551_set_device_state);
+
+int mma9551_set_power_state(struct i2c_client *client, bool on)
+{
+#ifdef CONFIG_PM
+	int ret;
+
+	if (on)
+		ret = pm_runtime_get_sync(&client->dev);
+	else {
+		pm_runtime_mark_last_busy(&client->dev);
+		ret = pm_runtime_put_autosuspend(&client->dev);
+	}
+
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"failed to change power state to %d\n", on);
+		if (on)
+			pm_runtime_put_noidle(&client->dev);
+
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+EXPORT_SYMBOL(mma9551_set_power_state);
+
+void mma9551_sleep(int freq)
+{
+	int sleep_val = 1000 / freq;
+
+	if (sleep_val < 20)
+		usleep_range(sleep_val * 1000, 20000);
+	else
+		msleep_interruptible(sleep_val);
+}
+EXPORT_SYMBOL(mma9551_sleep);
+
+int mma9551_read_accel_chan(struct i2c_client *client,
+			    const struct iio_chan_spec *chan,
+			    int *val, int *val2)
+{
+	u16 reg_addr;
+	s16 raw_accel;
+	int ret;
+
+	switch (chan->channel2) {
+	case IIO_MOD_X:
+		reg_addr = MMA9551_AFE_X_ACCEL_REG;
+		break;
+	case IIO_MOD_Y:
+		reg_addr = MMA9551_AFE_Y_ACCEL_REG;
+		break;
+	case IIO_MOD_Z:
+		reg_addr = MMA9551_AFE_Z_ACCEL_REG;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = mma9551_set_power_state(client, true);
+	if (ret < 0)
+		return ret;
+
+	ret = mma9551_read_status_word(client, MMA9551_APPID_AFE,
+				       reg_addr, &raw_accel);
+	if (ret < 0)
+		goto out_poweroff;
+
+	*val = raw_accel;
+
+	ret = IIO_VAL_INT;
+
+out_poweroff:
+	mma9551_set_power_state(client, false);
+	return ret;
+}
+EXPORT_SYMBOL(mma9551_read_accel_chan);
+
+int mma9551_read_accel_scale(int *val, int *val2)
+{
+	*val = 0;
+	*val2 = 2440;
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+EXPORT_SYMBOL(mma9551_read_accel_scale);
+
+MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
+MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MMA955xL sensors core");
diff --git a/drivers/iio/accel/mma9551_core.h b/drivers/iio/accel/mma9551_core.h
new file mode 100644
index 0000000..0e1c9bb
--- /dev/null
+++ b/drivers/iio/accel/mma9551_core.h
@@ -0,0 +1,74 @@
+/*
+ * Common code for Freescale MMA955x Intelligent Sensor Platform drivers
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _MMA9551_CORE_H_
+#define _MMA9551_CORE_H_
+
+/* Applications IDs */
+#define MMA9551_APPID_VERSION		0x00
+#define MMA9551_APPID_GPIO		0x03
+#define MMA9551_APPID_AFE		0x06
+#define MMA9551_APPID_TILT		0x0B
+#define MMA9551_APPID_SLEEP_WAKE	0x12
+#define MMA9551_APPID_RESET		0x17
+#define MMA9551_APPID_NONE		0xff
+
+#define MMA9551_AUTO_SUSPEND_DELAY_MS	2000
+
+enum mma9551_gpio_pin {
+	mma9551_gpio6 = 0,
+	mma9551_gpio7,
+	mma9551_gpio8,
+	mma9551_gpio9,
+	mma9551_gpio_max = mma9551_gpio9,
+};
+
+struct mma9551_version_info {
+	__be32 device_id;
+	u8 rom_version[2];
+	u8 fw_version[2];
+	u8 hw_version[2];
+	u8 fw_build[2];
+};
+
+#define MMA9551_ACCEL_CHANNEL(axis) {				\
+	.type = IIO_ACCEL,					\
+	.modified = 1,						\
+	.channel2 = axis,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+}
+
+int mma9551_read_config_byte(struct i2c_client *client, u8 app_id,
+			     u16 reg, u8 *val);
+int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
+			      u16 reg, u8 val);
+int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
+			     u16 reg, u8 *val);
+int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
+			     u16 reg, u16 *val);
+int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
+			       u16 reg, u8 mask, u8 val);
+int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin,
+			u8 app_id, u8 bitnum, int polarity);
+int mma9551_read_version(struct i2c_client *client);
+int mma9551_set_device_state(struct i2c_client *client, bool enable);
+int mma9551_set_power_state(struct i2c_client *client, bool on);
+void mma9551_sleep(int freq);
+int mma9551_read_accel_chan(struct i2c_client *client,
+			    const struct iio_chan_spec *chan,
+			    int *val, int *val2);
+int mma9551_read_accel_scale(int *val, int *val2);
+
+#endif /* _MMA9551_CORE_H_ */
-- 
1.7.9.5


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

* [PATCH 8/8] iio: add driver for Freescale MMA9553
  2014-12-19 22:57 [PATCH 0/8] Add MMA9553 driver & PM support for MMA9551 Irina Tirdea
                   ` (6 preceding siblings ...)
  2014-12-19 22:57 ` [PATCH 7/8] iio: accel: mma9551: split driver to expose mma955x api Irina Tirdea
@ 2014-12-19 22:57 ` Irina Tirdea
  2015-01-01 11:58   ` Jonathan Cameron
  7 siblings, 1 reply; 27+ messages in thread
From: Irina Tirdea @ 2014-12-19 22:57 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Irina Tirdea

Add support for Freescale MMA9553L Intelligent Pedometer Platform.

The following functionalities are supported:
 - step counter (counts the number of steps using a HW register)
 - step detector (generates an iio event at every step the user takes)
 - activity recognition (rest, walking, jogging, running)
 - speed
 - calories
 - distance

To get accurate pedometer results, the user's height, weight and gender
need to be configured.

The specifications can be downloaded from:
http://www.freescale.com/files/sensors/doc/ref_manual/MMA955xLSWRM.pdf
http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf

Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
---
 drivers/iio/accel/Kconfig        |   12 +-
 drivers/iio/accel/Makefile       |    1 +
 drivers/iio/accel/mma9551_core.c |   88 +++
 drivers/iio/accel/mma9551_core.h |   17 +-
 drivers/iio/accel/mma9553.c      | 1239 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 1355 insertions(+), 2 deletions(-)
 create mode 100644 drivers/iio/accel/mma9553.c

diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 0600798..afd50d0 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -107,7 +107,7 @@ config KXCJK1013
 
 config MMA9551_CORE
 	tristate
-	depends on MMA9551
+	depends on MMA9551 || MMA9553
 
 config MMA9551
 	tristate "Freescale MMA9551L Intelligent Motion-Sensing Platform Driver"
@@ -121,4 +121,14 @@ config MMA9551
 	  To compile this driver as a module, choose M here: the module
 	  will be called mma9551.
 
+config MMA9553
+	tristate "Freescale MMA9553L Intelligent Pedometer Platform Driver"
+	depends on I2C
+	select MMA9551_CORE
+	help
+	  Say yes here to build support for the Freescale MMA9553L
+	  Intelligent Pedometer Platform Driver.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called mma9553.
 endmenu
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 8105316..f815695 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_MMA8452)	+= mma8452.o
 
 obj-$(CONFIG_MMA9551_CORE)	+= mma9551_core.o
 obj-$(CONFIG_MMA9551)		+= mma9551.o
+obj-$(CONFIG_MMA9553)		+= mma9553.o
 
 obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
 st_accel-y := st_accel_core.o
diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c
index cab481b..743a868 100644
--- a/drivers/iio/accel/mma9551_core.c
+++ b/drivers/iio/accel/mma9551_core.c
@@ -53,6 +53,11 @@
 #define MMA9551_AFE_Y_ACCEL_REG		0x02
 #define MMA9551_AFE_Z_ACCEL_REG		0x04
 
+/* Reset/Suspend/Clear application */
+#define MMA9551_RSC_RESET		0x00
+#define MMA9551_RSC_OFFSET(mask)	(3 - (ffs(mask) - 1) / 8)
+#define MMA9551_RSC_VAL(mask)		(mask >> (((ffs(mask) - 1) / 8) * 8))
+
 /*
  * A response is composed of:
  * - control registers: MB0-3
@@ -215,6 +220,30 @@ int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
 }
 EXPORT_SYMBOL(mma9551_read_status_byte);
 
+int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
+			    u16 reg, u16 *val)
+{
+	int ret;
+	__be16 v;
+
+	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
+			       reg, NULL, 0, (u8 *)&v, 2);
+	*val = be16_to_cpu(v);
+
+	return ret;
+}
+EXPORT_SYMBOL(mma9551_read_config_word);
+
+int mma9551_write_config_word(struct i2c_client *client, u8 app_id,
+			     u16 reg, u16 val)
+{
+	__be16 v = cpu_to_be16(val);
+
+	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
+				(u8 *) &v, 2, NULL, 0);
+}
+EXPORT_SYMBOL(mma9551_write_config_word);
+
 int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
 			     u16 reg, u16 *val)
 {
@@ -229,6 +258,56 @@ int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
 }
 EXPORT_SYMBOL(mma9551_read_status_word);
 
+int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
+			     u16 reg, u8 len, u16 *buf)
+{
+	int ret, i;
+	int len_words = len / sizeof(u16);
+	__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+
+	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
+			       reg, NULL, 0, (u8 *) be_buf, len);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < len_words; i++)
+		buf[i] = be16_to_cpu(be_buf[i]);
+	return 0;
+}
+EXPORT_SYMBOL(mma9551_read_config_words);
+
+int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
+			      u16 reg, u8 len, u16 *buf)
+{
+	int ret, i;
+	int len_words = len / sizeof(u16);
+	__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+
+	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
+			       reg, NULL, 0, (u8 *) be_buf, len);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < len_words; i++)
+		buf[i] = be16_to_cpu(be_buf[i]);
+	return 0;
+}
+EXPORT_SYMBOL(mma9551_read_status_words);
+
+int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
+			       u16 reg, u8 len, u16 *buf)
+{
+	int i;
+	int len_words = len / sizeof(u16);
+	__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+
+	for (i = 0; i < len_words; i++)
+		be_buf[i] = cpu_to_be16(buf[i]);
+	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG,
+				reg, (u8 *) be_buf, len, NULL, 0);
+}
+EXPORT_SYMBOL(mma9551_write_config_words);
+
 int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
 			       u16 reg, u8 mask, u8 val)
 {
@@ -437,6 +516,15 @@ int mma9551_read_accel_scale(int *val, int *val2)
 }
 EXPORT_SYMBOL(mma9551_read_accel_scale);
 
+int mma9551_app_reset(struct i2c_client *client, u32 app_mask)
+{
+	return mma9551_write_config_byte(client, MMA9551_APPID_RCS,
+					 MMA9551_RSC_RESET +
+					 MMA9551_RSC_OFFSET(app_mask),
+					 MMA9551_RSC_VAL(app_mask));
+}
+EXPORT_SYMBOL(mma9551_app_reset);
+
 MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
 MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/mma9551_core.h b/drivers/iio/accel/mma9551_core.h
index 0e1c9bb..19b6253 100644
--- a/drivers/iio/accel/mma9551_core.h
+++ b/drivers/iio/accel/mma9551_core.h
@@ -21,9 +21,13 @@
 #define MMA9551_APPID_AFE		0x06
 #define MMA9551_APPID_TILT		0x0B
 #define MMA9551_APPID_SLEEP_WAKE	0x12
-#define MMA9551_APPID_RESET		0x17
+#define MMA9551_APPID_PEDOMETER	        0x15
+#define MMA9551_APPID_RCS		0x17
 #define MMA9551_APPID_NONE		0xff
 
+/* Reset/Suspend/Clear application app masks */
+#define MMA9551_RSC_PED			BIT(21)
+
 #define MMA9551_AUTO_SUSPEND_DELAY_MS	2000
 
 enum mma9551_gpio_pin {
@@ -56,8 +60,18 @@ int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
 			      u16 reg, u8 val);
 int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
 			     u16 reg, u8 *val);
+int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
+			    u16 reg, u16 *val);
+int mma9551_write_config_word(struct i2c_client *client, u8 app_id,
+			     u16 reg, u16 val);
 int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
 			     u16 reg, u16 *val);
+int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
+			     u16 reg, u8 len, u16 *buf);
+int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
+			      u16 reg, u8 len, u16 *buf);
+int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
+			       u16 reg, u8 len, u16 *buf);
 int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
 			       u16 reg, u8 mask, u8 val);
 int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin,
@@ -70,5 +84,6 @@ int mma9551_read_accel_chan(struct i2c_client *client,
 			    const struct iio_chan_spec *chan,
 			    int *val, int *val2);
 int mma9551_read_accel_scale(int *val, int *val2);
+int mma9551_app_reset(struct i2c_client *client, u32 app_mask);
 
 #endif /* _MMA9551_CORE_H_ */
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
new file mode 100644
index 0000000..35b657d
--- /dev/null
+++ b/drivers/iio/accel/mma9553.c
@@ -0,0 +1,1239 @@
+/*
+ * Freescale MMA9553L Intelligent Pedometer driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/pm_runtime.h>
+#include "mma9551_core.h"
+
+#define MMA9553_DRV_NAME			"mma9553"
+#define MMA9553_IRQ_NAME			"mma9553_event"
+#define MMA9553_GPIO_NAME			"mma9553_int"
+
+/* Pedometer configuration registers (R/W) */
+#define MMA9553_CONF_SLEEPMIN		0x00
+#define MMA9553_CONF_SLEEPMAX		0x02
+#define MMA9553_CONF_SLEEPTHD		0x04
+#define MMA9553_CONF_WORD		GENMASK(15, 0)
+
+#define MMA9553_CONF_CONF_STEPLEN	0x06
+#define MMA9553_CONF_CONFIG		BIT(15)
+#define MMA9553_CONF_ACT_DBCNTM		BIT(14)
+#define MMA9553_CONF_SLP_DBCNTM		BIT(13)
+#define MMA9553_CONF_STEPLEN		GENMASK(7, 0)
+
+#define MMA9553_CONF_HEIGHT_WEIGHT	0x08
+#define MMA9553_CONF_HEIGHT		GENMASK(15, 8)
+#define MMA9553_CONF_WEIGHT		GENMASK(7, 0)
+
+#define MMA9553_CONF_FILTER		0x0A
+#define MMA9553_CONF_FILTSTEP		GENMASK(15, 8)
+#define MMA9553_CONF_MALE		BIT(7)
+#define MMA9553_CONF_FILTTIME		GENMASK(6, 0)
+
+#define MMA9553_CONF_SPEED_STEP		0x0C
+#define MMA9553_CONF_SPDPRD		GENMASK(15, 8)
+#define MMA9553_CONF_STEPCOALESCE	GENMASK(7, 0)
+
+#define MMA9553_CONF_ACTTHD		0x0E
+
+/* Pedometer status registers (R-only) */
+#define MMA9553_STATUS			0x00
+#define MMA9553_STATUS_MRGFL		BIT(15)
+#define MMA9553_STATUS_SUSPCHG		BIT(14)
+#define MMA9553_STATUS_STEPCHG		BIT(13)
+#define MMA9553_STATUS_ACTCHG		BIT(12)
+#define MMA9553_STATUS_SUSP		BIT(11)
+#define MMA9553_STATUS_ACTIVITY		(BIT(10) | BIT(9) | BIT(8))
+#define MMA9553_STATUS_VERSION		0x00FF
+
+#define MMA9553_STEPCNT			0x02
+#define MMA9553_DISTANCE		0x04
+#define MMA9553_SPEED			0x06
+#define MMA9553_CALORIES		0x08
+#define MMA9553_SLEEPCNT		0x0A
+
+/* Pedometer events are always mapped to this pin. */
+#define MMA9553_DEFAULT_GPIO_PIN	mma9551_gpio6
+#define MMA9553_DEFAULT_GPIO_POLARITY	0
+
+/* Bitnum used for gpio configuration = bit number in high status byte */
+#define STATUS_TO_BITNUM(bit)		(ffs(bit) - 9)
+
+#define MMA9553_DEFAULT_SAMPLE_RATE	30	/* Hz */
+
+/*
+ * The internal activity level must be stable for ACTTHD samples before
+ * ACTIVITY is updated.The ACTIVITY variable contains the current activity
+ * level and is updated every time a step is detected or once a second
+ * if there are no steps. So for 100% confidence level we need to have
+ * the same activity level for about 30 sec.
+ */
+#define MMA9553_MAX_ACTTHD		(MMA9553_DEFAULT_SAMPLE_RATE * 30)
+#define MMA9553_PERCENTAGE_TO_THD(prc) (((prc) * MMA9553_MAX_ACTTHD) / 100)
+#define MMA9553_THD_TO_PERCENTAGE(thr) (((thr) * 100) / MMA9553_MAX_ACTTHD)
+
+/*
+ * Autonomously suspend pedometer if acceleration vector magnitude
+ * is near 1g (4096 at 0.244 mg/LSB resolution) for 30 seconds.
+ */
+#define MMA9553_DEFAULT_SLEEPMIN	3688	/* 0,9 g */
+#define MMA9553_DEFAULT_SLEEPMAX	4508	/* 1,1 g */
+#define MMA9553_DEFAULT_SLEEPTHD	(MMA9553_DEFAULT_SAMPLE_RATE * 30)
+
+#define MMA9553_CONFIG_RETRIES		2
+
+/* Status register - activity field  */
+enum activity_level {
+	ACTIVITY_UNKNOWN,
+	ACTIVITY_REST,
+	ACTIVITY_WALKING,
+	ACTIVITY_JOGGING,
+	ACTIVITY_RUNNING,
+};
+
+struct mma9553_event {
+	enum iio_chan_type type;
+	enum iio_modifier mod;
+	enum iio_event_direction dir;
+	bool enabled;
+};
+
+struct mma9553_conf_regs {
+	u16 sleepmin;
+	u16 sleepmax;
+	u16 sleepthd;
+	u16 config;
+	u16 height_weight;
+	u16 filter;
+	u16 speed_step;
+	u16 actthd;
+} __packed;
+
+struct mma9553_data {
+	struct i2c_client *client;
+	struct mutex mutex;
+	struct mma9553_conf_regs conf;
+	struct mma9553_event *events;
+	int num_events;
+	u8 gpio_bitnum;
+	/*
+	 * This is used for all features that depend on step count:
+	 * step count, distance, speed, calories.
+	 */
+	bool stepcnt_enabled;
+	u16 stepcnt;
+	u8 activity;
+};
+
+static u8 mma9553_get_bits(u16 val, u16 mask)
+{
+	return (val & mask) >> (ffs(mask) - 1);
+}
+
+static u16 mma9553_set_bits(u16 current_val, u16 val, u16 mask)
+{
+	return (current_val & ~mask) | (val << (ffs(mask) - 1));
+}
+
+static enum iio_modifier mma9553_activity_to_mod(enum activity_level activity)
+{
+	switch (activity) {
+	case ACTIVITY_RUNNING:
+		return IIO_MOD_RUNNING;
+	case ACTIVITY_JOGGING:
+		return IIO_MOD_JOGGING;
+	case ACTIVITY_WALKING:
+		return IIO_MOD_WALKING;
+	case ACTIVITY_REST:
+		return IIO_MOD_STILL;
+	case ACTIVITY_UNKNOWN:
+	default:
+		return IIO_NO_MOD;
+	}
+}
+
+static struct mma9553_event *mma9553_get_event(struct mma9553_data *data,
+					       enum iio_chan_type type,
+					       enum iio_modifier mod,
+					       enum iio_event_direction dir)
+{
+	int i;
+
+	for (i = 0; i < data->num_events; i++)
+		if (data->events[i].type == type &&
+		    data->events[i].mod == mod &&
+		    data->events[i].dir == dir)
+			return &data->events[i];
+	return NULL;
+}
+
+static bool mma9553_is_any_event_enabled(struct mma9553_data *data,
+					 bool check_type,
+					 enum iio_chan_type type)
+{
+	int i;
+
+	for (i = 0; i < data->num_events; i++)
+		if ((check_type && data->events[i].type == type &&
+		     data->events[i].enabled) ||
+		     (!check_type && data->events[i].enabled))
+			return true;
+	return false;
+}
+
+static int mma9553_set_config(struct mma9553_data *data, u16 reg,
+			      u16 *p_reg_val, u16 val, u16 mask)
+{
+	int ret, retries;
+	u16 reg_val, config;
+
+	reg_val = *p_reg_val;
+	if (val == mma9553_get_bits(reg_val, mask))
+		return 0;
+
+	reg_val = mma9553_set_bits(reg_val, val, mask);
+	ret = mma9551_write_config_word(data->client, MMA9551_APPID_PEDOMETER,
+					reg, reg_val);
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"error writing config register 0x%x\n", reg);
+		return ret;
+	}
+
+	*p_reg_val = reg_val;
+
+	/* Reinitializes the pedometer with current configuration values */
+	config = mma9553_set_bits(data->conf.config, 1, MMA9553_CONF_CONFIG);
+
+	ret = mma9551_write_config_word(data->client, MMA9551_APPID_PEDOMETER,
+					MMA9553_CONF_CONF_STEPLEN, config);
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"error writing config register 0x%x\n",
+			MMA9553_CONF_CONF_STEPLEN);
+		return ret;
+	}
+
+	retries = MMA9553_CONFIG_RETRIES;
+	do {
+		mma9551_sleep(MMA9553_DEFAULT_SAMPLE_RATE);
+		ret = mma9551_read_config_word(data->client,
+					       MMA9551_APPID_PEDOMETER,
+					       MMA9553_CONF_CONF_STEPLEN,
+					       &config);
+		if (ret < 0)
+			return ret;
+	} while (mma9553_get_bits(config, MMA9553_CONF_CONFIG) &&
+		 --retries > 0);
+
+	return 0;
+}
+
+static int mma9553_read_activity_stepcnt(struct mma9553_data *data,
+					 u8 *activity, u16 *stepcnt)
+{
+	u32 status_stepcnt;
+	u16 status;
+	int ret;
+
+	ret = mma9551_read_status_words(data->client, MMA9551_APPID_PEDOMETER,
+					MMA9553_STATUS, sizeof(u32),
+					(u16 *) &status_stepcnt);
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"error reading status and stepcnt\n");
+		return ret;
+	}
+
+	status = status_stepcnt & MMA9553_CONF_WORD;
+	*activity = mma9553_get_bits(status, MMA9553_STATUS_ACTIVITY);
+	*stepcnt = status_stepcnt >> 16;
+	return 0;
+}
+
+static int mma9553_conf_gpio(struct mma9553_data *data)
+{
+	u8 bitnum = 0, appid = MMA9551_APPID_PEDOMETER;
+	int ret;
+	struct mma9553_event *ev_step_detect;
+	bool activity_enabled;
+
+	activity_enabled =
+	    mma9553_is_any_event_enabled(data, true, IIO_ACTIVITY);
+	ev_step_detect =
+	    mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
+
+	/*
+	 * If both step detector and activity are enabled, use the MRGFL bit.
+	 * This bit is the logical OR of the SUSPCHG, STEPCHG, and ACTCHG flags.
+	 */
+	if (activity_enabled && ev_step_detect->enabled) {
+		bitnum = STATUS_TO_BITNUM(MMA9553_STATUS_MRGFL);
+	} else if (ev_step_detect->enabled) {
+		bitnum = STATUS_TO_BITNUM(MMA9553_STATUS_STEPCHG);
+	} else if (activity_enabled) {
+		bitnum = STATUS_TO_BITNUM(MMA9553_STATUS_ACTCHG);
+	} else {		/* Reset */
+		appid = MMA9551_APPID_NONE;
+	}
+
+	if (data->gpio_bitnum == bitnum)
+		return 0;
+
+	/* Save initial values for activity and stepcnt */
+	if (activity_enabled || ev_step_detect->enabled)
+		mma9553_read_activity_stepcnt(data, &data->activity,
+					      &data->stepcnt);
+
+	ret = mma9551_gpio_config(data->client,
+				  MMA9553_DEFAULT_GPIO_PIN,
+				  appid, bitnum, MMA9553_DEFAULT_GPIO_POLARITY);
+	if (ret < 0)
+		return ret;
+	data->gpio_bitnum = bitnum;
+	return 0;
+}
+
+static int mma9553_init(struct mma9553_data *data)
+{
+	int ret;
+
+	ret = mma9551_read_version(data->client);
+	if (ret)
+		return ret;
+
+	/*
+	 * Read all the pedometer configuration registers. This is used as
+	 * a device identification command to differentiate the MMA9553L
+	 * from the MMA9550L.
+	 */
+	ret =
+	    mma9551_read_config_words(data->client, MMA9551_APPID_PEDOMETER,
+				      MMA9553_CONF_SLEEPMIN,
+				      sizeof(data->conf), (u16 *) &data->conf);
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"device is not MMA9553L: failed to read cfg regs.\n");
+		return ret;
+	}
+
+
+	/* Reset gpio */
+	data->gpio_bitnum = -1;
+	ret = mma9553_conf_gpio(data);
+	if (ret < 0)
+		return ret;
+
+	ret = mma9551_app_reset(data->client, MMA9551_RSC_PED);
+	if (ret < 0)
+		return ret;
+
+	/* Init config registers */
+	data->conf.sleepmin = MMA9553_DEFAULT_SLEEPMIN;
+	data->conf.sleepmax = MMA9553_DEFAULT_SLEEPMAX;
+	data->conf.sleepthd = MMA9553_DEFAULT_SLEEPTHD;
+	data->conf.config =
+	    mma9553_set_bits(data->conf.config, 1, MMA9553_CONF_CONFIG);
+	/*
+	 * Clear the activity debounce counter when the activity level changes,
+	 * so that the confidence level applies for any activity level.
+	 */
+	data->conf.config =
+	    mma9553_set_bits(data->conf.config, 1, MMA9553_CONF_ACT_DBCNTM);
+	ret =
+	    mma9551_write_config_words(data->client, MMA9551_APPID_PEDOMETER,
+				       MMA9553_CONF_SLEEPMIN,
+				       sizeof(data->conf), (u16 *) &data->conf);
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"failed to write configuration registers.\n");
+		return ret;
+	}
+
+	return mma9551_set_device_state(data->client, true);
+}
+
+static int mma9553_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int *val, int *val2, long mask)
+{
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int ret;
+	u16 tmp;
+	u8 activity;
+	bool powered_on;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (chan->type) {
+		case IIO_STEPS:
+			/*
+			 * The HW only counts steps and other dependent
+			 * parameters (speed, distance, calories, activity)
+			 * if power is on (from enabling an event or the
+			 * step counter */
+			powered_on =
+			    mma9553_is_any_event_enabled(data, false, 0) ||
+			    data->stepcnt_enabled;
+			if (!powered_on)
+				return -EINVAL;
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_status_word(data->client,
+						       MMA9551_APPID_PEDOMETER,
+						       MMA9553_STEPCNT, &tmp);
+			mutex_unlock(&data->mutex);
+			if (ret < 0)
+				return ret;
+			*val = tmp;
+			return IIO_VAL_INT;
+		case IIO_DISTANCE:
+			powered_on =
+			    mma9553_is_any_event_enabled(data, false, 0) ||
+			    data->stepcnt_enabled;
+			if (!powered_on)
+				return -EINVAL;
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_status_word(data->client,
+						       MMA9551_APPID_PEDOMETER,
+						       MMA9553_DISTANCE, &tmp);
+			mutex_unlock(&data->mutex);
+			if (ret < 0)
+				return ret;
+			*val = tmp;
+			return IIO_VAL_INT;
+		case IIO_ACTIVITY:
+			powered_on =
+			    mma9553_is_any_event_enabled(data, false, 0) ||
+			    data->stepcnt_enabled;
+			if (!powered_on)
+				return -EINVAL;
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_status_word(data->client,
+						       MMA9551_APPID_PEDOMETER,
+						       MMA9553_STATUS, &tmp);
+			mutex_unlock(&data->mutex);
+			if (ret < 0)
+				return ret;
+
+			activity =
+			    mma9553_get_bits(tmp, MMA9553_STATUS_ACTIVITY);
+
+			/*
+			 * The device does not support confidence value levels,
+			 * so we will always have 100% for current activity and
+			 * 0% for the others.
+			 */
+			if (chan->channel2 == mma9553_activity_to_mod(activity))
+				*val = 100;
+			else
+				*val = 0;
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_SPEED:	/* m/h */
+			powered_on =
+			    mma9553_is_any_event_enabled(data, false, 0) ||
+			    data->stepcnt_enabled;
+			if (!powered_on)
+				return -EINVAL;
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_status_word(data->client,
+						       MMA9551_APPID_PEDOMETER,
+						       MMA9553_SPEED, &tmp);
+			mutex_unlock(&data->mutex);
+			if (ret < 0)
+				return ret;
+			*val = tmp;
+			return IIO_VAL_INT;
+		case IIO_CALORIES:	/* Cal or kcal */
+			powered_on =
+			    mma9553_is_any_event_enabled(data, false, 0) ||
+			    data->stepcnt_enabled;
+			if (!powered_on)
+				return -EINVAL;
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_status_word(data->client,
+						       MMA9551_APPID_PEDOMETER,
+						       MMA9553_CALORIES, &tmp);
+			mutex_unlock(&data->mutex);
+			if (ret < 0)
+				return ret;
+			*val = tmp;
+			return IIO_VAL_INT;
+		case IIO_ACCEL:
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_accel_chan(data->client,
+						      chan, val, val2);
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->type) {
+		case IIO_SPEED:	/* m/h to m/s */
+			*val = 0;
+			*val2 = 277;	/* 0.000277 */
+			return IIO_VAL_INT_PLUS_MICRO;
+		case IIO_CALORIES:	/* Cal or kcal to J */
+			*val = 4184;
+			return IIO_VAL_INT;
+		case IIO_ACCEL:
+			return mma9551_read_accel_scale(val, val2);
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_ENABLE:
+		*val = data->stepcnt_enabled;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBHEIGHT:
+		*val = mma9553_get_bits(data->conf.height_weight,
+					MMA9553_CONF_HEIGHT);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBWEIGHT:
+		*val = mma9553_get_bits(data->conf.height_weight,
+					MMA9553_CONF_WEIGHT);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBGENDER:
+		*val = mma9553_get_bits(data->conf.filter, MMA9553_CONF_MALE);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_OFFSET:
+		switch (chan->type) {
+		case IIO_STEPS:
+			*val = mma9553_get_bits(data->conf.filter,
+						MMA9553_CONF_FILTSTEP);
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_INT_TIME:
+		switch (chan->type) {
+		case IIO_STEPS:
+			*val = mma9553_get_bits(data->conf.filter,
+						MMA9553_CONF_FILTTIME);
+			return IIO_VAL_INT;
+		case IIO_SPEED:
+			*val = mma9553_get_bits(data->conf.speed_step,
+						MMA9553_CONF_SPDPRD);
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mma9553_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_ENABLE:
+		if (data->stepcnt_enabled == !!val)
+			return 0;
+		mutex_lock(&data->mutex);
+		ret = mma9551_set_power_state(data->client, val);
+		if (ret < 0) {
+			mutex_unlock(&data->mutex);
+			return ret;
+		}
+		data->stepcnt_enabled = val;
+		mutex_unlock(&data->mutex);
+		return 0;
+	case IIO_CHAN_INFO_CALIBHEIGHT:
+		if (val < 0 || val > 255)
+			return -EINVAL;
+		mutex_lock(&data->mutex);
+		ret = mma9553_set_config(data,
+					 MMA9553_CONF_HEIGHT_WEIGHT,
+					 &data->conf.height_weight,
+					 val, MMA9553_CONF_HEIGHT);
+		mutex_unlock(&data->mutex);
+		return ret;
+	case IIO_CHAN_INFO_CALIBWEIGHT:
+		if (val < 0 || val > 255)
+			return -EINVAL;
+		mutex_lock(&data->mutex);
+		ret = mma9553_set_config(data,
+					 MMA9553_CONF_HEIGHT_WEIGHT,
+					 &data->conf.height_weight,
+					 val, MMA9553_CONF_WEIGHT);
+		mutex_unlock(&data->mutex);
+		return ret;
+	case IIO_CHAN_INFO_CALIBGENDER:
+		/* Gender can only be 0(female) or 1(male) */
+		if ((val != 0) && (val != 1))
+			return -EINVAL;
+		mutex_lock(&data->mutex);
+		ret = mma9553_set_config(data, MMA9553_CONF_FILTER,
+					 &data->conf.filter, val,
+					 MMA9553_CONF_MALE);
+		mutex_unlock(&data->mutex);
+		return ret;
+	case IIO_CHAN_INFO_OFFSET:
+		switch (chan->type) {
+		case IIO_STEPS:
+			/*
+			 * Set to 0 to disable step filtering. If the value
+			 * specified is greater than 6, then 6 will be used.
+			 */
+			if (val < 0)
+				return -EINVAL;
+			if (val > 6)
+				val = 6;
+			mutex_lock(&data->mutex);
+			ret = mma9553_set_config(data, MMA9553_CONF_FILTER,
+						 &data->conf.filter, val,
+						 MMA9553_CONF_FILTSTEP);
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_INT_TIME:
+		switch (chan->type) {
+		case IIO_STEPS:
+			if (val < 0 || val > 127)
+				return -EINVAL;
+			mutex_lock(&data->mutex);
+			ret = mma9553_set_config(data, MMA9553_CONF_FILTER,
+						 &data->conf.filter, val,
+						 MMA9553_CONF_FILTTIME);
+			mutex_unlock(&data->mutex);
+			return ret;
+		case IIO_SPEED:
+			/*
+			 * If set to a value greater than 5, then 5 will be
+			 * used. Warning: Do not set SPDPRD to 0 or 1 as
+			 * this may cause undesirable behavior.
+			 */
+			if (val < 2)
+				return -EINVAL;
+			if (val > 5)
+				val = 5;
+			mutex_lock(&data->mutex);
+			ret = mma9553_set_config(data, MMA9553_CONF_SPEED_STEP,
+						 &data->conf.speed_step, val,
+						 MMA9553_CONF_SPDPRD);
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mma9553_read_event_config(struct iio_dev *indio_dev,
+				     const struct iio_chan_spec *chan,
+				     enum iio_event_type type,
+				     enum iio_event_direction dir)
+{
+
+	struct mma9553_data *data = iio_priv(indio_dev);
+	struct mma9553_event *event;
+
+	event = mma9553_get_event(data, chan->type, chan->channel2, dir);
+	if (!event)
+		return -EINVAL;
+	return event->enabled;
+}
+
+static int mma9553_write_event_config(struct iio_dev *indio_dev,
+				      const struct iio_chan_spec *chan,
+				      enum iio_event_type type,
+				      enum iio_event_direction dir, int state)
+{
+	struct mma9553_data *data = iio_priv(indio_dev);
+	struct mma9553_event *event;
+	int ret;
+
+	event = mma9553_get_event(data, chan->type, chan->channel2, dir);
+	if (!event)
+		return -EINVAL;
+
+	if (event->enabled == state)
+		return 0;
+
+	mutex_lock(&data->mutex);
+
+	ret = mma9551_set_power_state(data->client, state);
+	if (ret < 0)
+		goto out;
+	event->enabled = state;
+
+	ret = mma9553_conf_gpio(data);
+	if (ret < 0)
+		goto err_conf_gpio;
+
+	goto out;
+
+err_conf_gpio:
+	if (state) {
+		event->enabled = false;
+		mma9551_set_power_state(data->client, false);
+	}
+out:
+	mutex_unlock(&data->mutex);
+	return ret;
+}
+
+static int mma9553_read_event_value(struct iio_dev *indio_dev,
+				    const struct iio_chan_spec *chan,
+				    enum iio_event_type type,
+				    enum iio_event_direction dir,
+				    enum iio_event_info info,
+				    int *val, int *val2)
+{
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int prc;
+
+	*val2 = 0;
+	switch (info) {
+	case IIO_EV_INFO_VALUE:
+		switch (chan->type) {
+		case IIO_ACTIVITY:
+			prc = MMA9553_THD_TO_PERCENTAGE(data->conf.actthd);
+			if (dir == IIO_EV_DIR_RISING)
+				*val = prc;
+			else if (dir == IIO_EV_DIR_FALLING)
+				*val = 100 - prc;
+			else
+				return -EINVAL;
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_EV_INFO_PERIOD:
+		switch (chan->type) {
+		case IIO_STEPS:
+			*val = mma9553_get_bits(data->conf.speed_step,
+						MMA9553_CONF_STEPCOALESCE);
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mma9553_write_event_value(struct iio_dev *indio_dev,
+				     const struct iio_chan_spec *chan,
+				     enum iio_event_type type,
+				     enum iio_event_direction dir,
+				     enum iio_event_info info,
+				     int val, int val2)
+{
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int prc, thd;
+	int ret;
+
+	switch (info) {
+	case IIO_EV_INFO_VALUE:
+		switch (chan->type) {
+		case IIO_ACTIVITY:
+			if (val < 0 || val > 100)
+				return -EINVAL;
+
+			if (dir == IIO_EV_DIR_RISING)
+				prc = val;
+			else if (dir == IIO_EV_DIR_FALLING)
+				prc = 100 - val;
+			else
+				return -EINVAL;
+			thd = MMA9553_PERCENTAGE_TO_THD(prc);
+
+			mutex_lock(&data->mutex);
+			ret = mma9553_set_config(data, MMA9553_CONF_ACTTHD,
+						 &data->conf.actthd, thd,
+						 MMA9553_CONF_WORD);
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	case IIO_EV_INFO_PERIOD:
+		switch (chan->type) {
+		case IIO_STEPS:
+			if (val < 0 || val > 255)
+				return -EINVAL;
+			mutex_lock(&data->mutex);
+			ret = mma9553_set_config(data, MMA9553_CONF_SPEED_STEP,
+						 &data->conf.speed_step, val,
+						 MMA9553_CONF_STEPCOALESCE);
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_event_spec mma9553_step_event = {
+	.type = IIO_EV_TYPE_INSTANCE,
+	.dir = IIO_EV_DIR_NONE,
+	.mask_separate = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_PERIOD),
+};
+
+static const struct iio_event_spec mma9553_activity_events[] = {
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_RISING,
+		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+				 BIT(IIO_EV_INFO_VALUE),
+	 },
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_FALLING,
+		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+				 BIT(IIO_EV_INFO_VALUE),
+	},
+};
+
+#define MMA9553_PEDOMETER_CHANNEL(_type, _mask) {		\
+	.type = _type,						\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_ENABLE)      |	\
+			      BIT(IIO_CHAN_INFO_CALIBHEIGHT) |	\
+			      BIT(IIO_CHAN_INFO_CALIBGENDER) |	\
+			      _mask,				\
+}
+
+#define MMA9553_ACTIVITY_CHANNEL(_chan2) {				\
+	.type = IIO_ACTIVITY,						\
+	.modified = 1,							\
+	.channel2 = _chan2,						\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT) |	\
+				    BIT(IIO_CHAN_INFO_CALIBGENDER),	\
+	.event_spec = mma9553_activity_events,				\
+	.num_event_specs = ARRAY_SIZE(mma9553_activity_events),		\
+}
+
+static const struct iio_chan_spec mma9553_channels[] = {
+	MMA9551_ACCEL_CHANNEL(IIO_MOD_X),
+	MMA9551_ACCEL_CHANNEL(IIO_MOD_Y),
+	MMA9551_ACCEL_CHANNEL(IIO_MOD_Z),
+
+	{
+		.type = IIO_STEPS,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_ENABLE) |
+				      BIT(IIO_CHAN_INFO_OFFSET) |
+				      BIT(IIO_CHAN_INFO_INT_TIME),
+		.event_spec = &mma9553_step_event,
+		.num_event_specs = 1,
+	},
+
+	MMA9553_PEDOMETER_CHANNEL(IIO_DISTANCE, BIT(IIO_CHAN_INFO_PROCESSED)),
+	MMA9553_PEDOMETER_CHANNEL(IIO_SPEED, BIT(IIO_CHAN_INFO_RAW) |
+				  BIT(IIO_CHAN_INFO_SCALE) |
+				  BIT(IIO_CHAN_INFO_INT_TIME)),
+	MMA9553_PEDOMETER_CHANNEL(IIO_CALORIES, BIT(IIO_CHAN_INFO_RAW) |
+				  BIT(IIO_CHAN_INFO_SCALE) |
+				  BIT(IIO_CHAN_INFO_CALIBWEIGHT)),
+
+	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_RUNNING),
+	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_JOGGING),
+	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_WALKING),
+	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_STILL),
+};
+
+static const struct iio_info mma9553_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = mma9553_read_raw,
+	.write_raw = mma9553_write_raw,
+	.read_event_config = mma9553_read_event_config,
+	.write_event_config = mma9553_write_event_config,
+	.read_event_value = mma9553_read_event_value,
+	.write_event_value = mma9553_write_event_value,
+};
+
+static struct mma9553_event mma9553_events[] = {
+	{
+		.type = IIO_STEPS,
+		.mod = IIO_NO_MOD,
+		.dir = IIO_EV_DIR_NONE,
+		.enabled = false,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_STILL,
+		.dir = IIO_EV_DIR_RISING,
+		.enabled = false,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_STILL,
+		.dir = IIO_EV_DIR_FALLING,
+		.enabled = false,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_WALKING,
+		.dir = IIO_EV_DIR_RISING,
+		.enabled = false,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_WALKING,
+		.dir = IIO_EV_DIR_FALLING,
+		.enabled = false,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_JOGGING,
+		.dir = IIO_EV_DIR_RISING,
+		.enabled = false,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_JOGGING,
+		.dir = IIO_EV_DIR_FALLING,
+		.enabled = false,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_RUNNING,
+		.dir = IIO_EV_DIR_RISING,
+		.enabled = false,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_RUNNING,
+		.dir = IIO_EV_DIR_FALLING,
+		.enabled = false,
+	},
+};
+
+static irqreturn_t mma9553_irq_handler(int irq, void *private)
+{
+	/*
+	 * Since we only configure the interrupt pin when an
+	 * event is enabled, we are sure we have at least
+	 * one event enabled at this point.
+	 */
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t mma9553_event_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct mma9553_data *data = iio_priv(indio_dev);
+	u16 stepcnt;
+	u8 activity;
+	struct mma9553_event *ev_activity, *ev_prev_activity, *ev_step_detect;
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = mma9553_read_activity_stepcnt(data, &activity, &stepcnt);
+	if (ret < 0) {
+		mutex_unlock(&data->mutex);
+		return IRQ_HANDLED;
+	}
+
+	ev_prev_activity =
+	    mma9553_get_event(data, IIO_ACTIVITY,
+			      mma9553_activity_to_mod(data->activity),
+			      IIO_EV_DIR_FALLING);
+	ev_activity =
+	    mma9553_get_event(data, IIO_ACTIVITY,
+			      mma9553_activity_to_mod(activity),
+			      IIO_EV_DIR_RISING);
+	ev_step_detect =
+	    mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
+
+	if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) {
+		data->stepcnt = stepcnt;
+		iio_push_event(indio_dev,
+			       IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
+			       IIO_EV_DIR_NONE, IIO_EV_TYPE_INSTANCE, 0, 0, 0),
+			       iio_get_time_ns());
+	}
+
+	if (activity != data->activity) {
+		data->activity = activity;
+		/* ev_activity can be NULL if activity == ACTIVITY_UNKNOWN */
+		if (ev_prev_activity && ev_prev_activity->enabled)
+			iio_push_event(indio_dev,
+				       IIO_EVENT_CODE(IIO_ACTIVITY, 0,
+				       ev_prev_activity->mod,
+				       IIO_EV_DIR_FALLING,
+				       IIO_EV_TYPE_THRESH, 0, 0, 0),
+				       iio_get_time_ns());
+
+		if (ev_activity && ev_activity->enabled)
+			iio_push_event(indio_dev,
+				       IIO_EVENT_CODE(IIO_ACTIVITY, 0,
+				       ev_activity->mod,
+				       IIO_EV_DIR_RISING,
+				       IIO_EV_TYPE_THRESH, 0, 0, 0),
+				       iio_get_time_ns());
+	}
+	mutex_unlock(&data->mutex);
+	return IRQ_HANDLED;
+}
+
+static int mma9553_gpio_probe(struct i2c_client *client)
+{
+	struct device *dev;
+	struct gpio_desc *gpio;
+	int ret;
+
+	if (!client)
+		return -EINVAL;
+
+	dev = &client->dev;
+
+	/* data ready gpio interrupt pin */
+	gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0);
+	if (IS_ERR(gpio)) {
+		dev_err(dev, "acpi gpio get index failed\n");
+		return PTR_ERR(gpio);
+	}
+
+	ret = gpiod_direction_input(gpio);
+	if (ret)
+		return ret;
+
+	ret = gpiod_to_irq(gpio);
+
+	dev_dbg(dev, "gpio resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+
+	return ret;
+}
+
+static const char *mma9553_match_acpi_device(struct device *dev)
+{
+	const struct acpi_device_id *id;
+
+	id = acpi_match_device(dev->driver->acpi_match_table, dev);
+	if (!id)
+		return NULL;
+
+	return dev_name(dev);
+}
+
+static int mma9553_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct mma9553_data *data;
+	struct iio_dev *indio_dev;
+	const char *name = NULL;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+
+	if (id)
+		name = id->name;
+	else if (ACPI_HANDLE(&client->dev))
+		name = mma9553_match_acpi_device(&client->dev);
+	else
+		return -ENOSYS;
+
+	mutex_init(&data->mutex);
+	data->events = mma9553_events;
+	data->num_events = ARRAY_SIZE(mma9553_events);
+
+	ret = mma9553_init(data);
+	if (ret < 0)
+		return ret;
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->channels = mma9553_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mma9553_channels);
+	indio_dev->name = name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &mma9553_info;
+
+	if (client->irq < 0)
+		client->irq = mma9553_gpio_probe(client);
+
+	if (client->irq >= 0) {
+		ret = devm_request_threaded_irq(&client->dev, client->irq,
+						mma9553_irq_handler,
+						mma9553_event_handler,
+						IRQF_TRIGGER_RISING,
+						MMA9553_IRQ_NAME, indio_dev);
+		if (ret < 0) {
+			dev_err(&client->dev, "request irq %d failed\n",
+				client->irq);
+			goto out_poweroff;
+		}
+
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to register iio device\n");
+		goto out_poweroff;
+	}
+
+	ret = pm_runtime_set_active(&client->dev);
+	if (ret < 0)
+		goto out_iio_unregister;
+
+	pm_runtime_enable(&client->dev);
+	pm_runtime_set_autosuspend_delay(&client->dev,
+					 MMA9551_AUTO_SUSPEND_DELAY_MS);
+	pm_runtime_use_autosuspend(&client->dev);
+
+	dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
+	return 0;
+
+out_iio_unregister:
+	iio_device_unregister(indio_dev);
+out_poweroff:
+	mma9551_set_device_state(client, false);
+	return ret;
+}
+
+static int mma9553_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct mma9553_data *data = iio_priv(indio_dev);
+
+	pm_runtime_disable(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+	pm_runtime_put_noidle(&client->dev);
+
+	iio_device_unregister(indio_dev);
+	mutex_lock(&data->mutex);
+	mma9551_set_device_state(data->client, false);
+	mutex_unlock(&data->mutex);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int mma9553_runtime_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = mma9551_set_device_state(data->client, false);
+	mutex_unlock(&data->mutex);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "powering off device failed\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static int mma9553_runtime_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ret = mma9551_set_device_state(data->client, true);
+	if (ret < 0)
+		return ret;
+
+	mma9551_sleep(MMA9553_DEFAULT_SAMPLE_RATE);
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int mma9553_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = mma9551_set_device_state(data->client, false);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static int mma9553_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = mma9551_set_device_state(data->client, true);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+#endif
+
+static const struct dev_pm_ops mma9553_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mma9553_suspend, mma9553_resume)
+	SET_RUNTIME_PM_OPS(mma9553_runtime_suspend,
+			   mma9553_runtime_resume, NULL)
+};
+
+static const struct acpi_device_id mma9553_acpi_match[] = {
+	{"MMA9553", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match);
+
+static const struct i2c_device_id mma9553_id[] = {
+	{"mma9553", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, mma9553_id);
+
+static struct i2c_driver mma9553_driver = {
+	.driver = {
+		   .name = MMA9553_DRV_NAME,
+		   .acpi_match_table = ACPI_PTR(mma9553_acpi_match),
+		   .pm = &mma9553_pm_ops,
+		   },
+	.probe = mma9553_probe,
+	.remove = mma9553_remove,
+	.id_table = mma9553_id,
+};
+
+module_i2c_driver(mma9553_driver);
+
+MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MMA9553L pedometer platform driver");
-- 
1.7.9.5


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

* Re: [PATCH 1/8] iio: core: Introduce CALORIES channel type
  2014-12-19 22:57 ` [PATCH 1/8] iio: core: Introduce CALORIES channel type Irina Tirdea
@ 2014-12-26 13:26   ` Jonathan Cameron
  2014-12-29 14:42     ` Tirdea, Irina
  0 siblings, 1 reply; 27+ messages in thread
From: Jonathan Cameron @ 2014-12-26 13:26 UTC (permalink / raw)
  To: Irina Tirdea, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

On 19/12/14 22:57, Irina Tirdea wrote:
> Some devices compute the number of calories that the user has
> burnt since the last reset.
> 
> One of this devices is Freescale's MMA9553L
> (http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
> that computes the number of calories based on weight and step rate.
> 
> Introduce a new channel type CALORIES to export these values.
> 
> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
hmm..  Ideally we use SI units for everything, but in human energy usage
Calories are the most common unit by a long way.  I'm having some trouble
even finding the conversion for this particular for of calorie. 

Now clearly it doesn't matter if the only energy sensors we ever get
are for human activity. However, that's unlikely to be the case.  We
already have devices doing instantaneous power and there are plenty
of smart meter chips out there (though of course, they will use the
option of kW Hours just to confuse matters).

I'd definitely prefer joules if we can do it with out a large amount of
pain.

Lars - any views on this?  (Analog do make plenty of 'energy' measurement
devices after all!)
> ---
>  Documentation/ABI/testing/sysfs-bus-iio |    9 +++++++++
>  drivers/iio/industrialio-core.c         |    1 +
>  include/linux/iio/types.h               |    1 +
>  3 files changed, 11 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index df5e69e..bb9342b 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -282,6 +282,7 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_current_scale
>  What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale
>  What:		/sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
>  What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
> +What:		/sys/bus/iio/devices/iio:deviceX/in_calories_scale
>  What:		/sys/bus/iio/devices/iio:deviceX/in_magn_scale
>  What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
>  What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
> @@ -1049,6 +1050,14 @@ Description:
>  		For a list of available output power modes read
>  		in_accel_power_mode_available.
>  
> +What:		/sys/.../iio:deviceX/in_calories_input
> +What:		/sys/.../iio:deviceX/in_calories_raw
> +KernelVersion:	3.17
> +Contact:	linux-iio@vger.kernel.org
> +Description:
> +		This attribute is used to read the number of calories burned since the last
> +		reset. Units after application of scale are Joules.
> +
>  What:		/sys/bus/iio/devices/iio:deviceX/store_eeprom
>  KernelVersion:	3.4.0
>  Contact:	linux-iio@vger.kernel.org
> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> index ee442ee..5d95e84 100644
> --- a/drivers/iio/industrialio-core.c
> +++ b/drivers/iio/industrialio-core.c
> @@ -72,6 +72,7 @@ static const char * const iio_chan_type_name_spec[] = {
>  	[IIO_HUMIDITYRELATIVE] = "humidityrelative",
>  	[IIO_ACTIVITY] = "activity",
>  	[IIO_STEPS] = "steps",
> +	[IIO_CALORIES] = "calories",
>  };
>  
>  static const char * const iio_modifier_names[] = {
> diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
> index 904dcbb..d2fe930 100644
> --- a/include/linux/iio/types.h
> +++ b/include/linux/iio/types.h
> @@ -32,6 +32,7 @@ enum iio_chan_type {
>  	IIO_HUMIDITYRELATIVE,
>  	IIO_ACTIVITY,
>  	IIO_STEPS,
> +	IIO_CALORIES,
>  };
>  
>  enum iio_modifier {
> 


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

* Re: [PATCH 3/8] iio: core: Introduce SPEED channel type
  2014-12-19 22:57 ` [PATCH 3/8] iio: core: Introduce SPEED " Irina Tirdea
@ 2014-12-26 13:28   ` Jonathan Cameron
  2014-12-29 18:13     ` Tirdea, Irina
  0 siblings, 1 reply; 27+ messages in thread
From: Jonathan Cameron @ 2014-12-26 13:28 UTC (permalink / raw)
  To: Irina Tirdea, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

On 19/12/14 22:57, Irina Tirdea wrote:
> Some devices export the current speed value of the user.
> 
> One of this devices is Freescale's MMA9553L
> (http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
> that computes the speed of the user based on the number of steps and
> stride length.
> 
> Introduce a new channel type SPEED to export these values.
> 
A fun question raised by this is whether we are going to end up with
both speed and velocity (depending on whether it is signed or not).
I suppose there isn't much to be done about that though and this looks fine
to me (as does the previous one).
> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
> ---
>  Documentation/ABI/testing/sysfs-bus-iio |    9 +++++++++
>  drivers/iio/industrialio-core.c         |    1 +
>  include/linux/iio/types.h               |    1 +
>  3 files changed, 11 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index a5c1dcc..07acef7 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -295,6 +295,7 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_scale
>  What:		/sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
>  What:		/sys/bus/iio/devices/iio:deviceX/in_pressure_scale
>  What:		/sys/bus/iio/devices/iio:deviceX/in_humidityrelative_scale
> +What:		/sys/bus/iio/devices/iio:deviceX/in_speed_scale
>  KernelVersion:	2.6.35
>  Contact:	linux-iio@vger.kernel.org
>  Description:
> @@ -1146,6 +1147,14 @@ Description:
>  		present, output should be considered as processed with the
>  		unit in milliamps.
>  
> +What:		/sys/.../iio:deviceX/in_speed_input
> +What:		/sys/.../iio:deviceX/in_speed_raw
> +KernelVersion:	3.19
> +Contact:	linux-iio@vger.kernel.org
> +Description:
> +		This attribute is used to read the current speed value of the user.
> +		Units after application of scale are m/s.
> +
>  What:		/sys/.../iio:deviceX/in_steps_en
>  KernelVersion:	3.19
>  Contact:	linux-iio@vger.kernel.org
> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> index 4a10d31..5e50aca 100644
> --- a/drivers/iio/industrialio-core.c
> +++ b/drivers/iio/industrialio-core.c
> @@ -74,6 +74,7 @@ static const char * const iio_chan_type_name_spec[] = {
>  	[IIO_STEPS] = "steps",
>  	[IIO_CALORIES] = "calories",
>  	[IIO_DISTANCE] = "distance",
> +	[IIO_SPEED] = "speed",
>  };
>  
>  static const char * const iio_modifier_names[] = {
> diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
> index b98f751..c848f45 100644
> --- a/include/linux/iio/types.h
> +++ b/include/linux/iio/types.h
> @@ -34,6 +34,7 @@ enum iio_chan_type {
>  	IIO_STEPS,
>  	IIO_CALORIES,
>  	IIO_DISTANCE,
> +	IIO_SPEED,
>  };
>  
>  enum iio_modifier {
> 


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

* Re: [PATCH 5/8] iio: core: Introduce IIO_CHAN_INFO_CALIBGENDER
  2014-12-19 22:57 ` [PATCH 5/8] iio: core: Introduce IIO_CHAN_INFO_CALIBGENDER Irina Tirdea
@ 2014-12-26 13:29   ` Jonathan Cameron
  2014-12-29 19:59     ` Tirdea, Irina
  0 siblings, 1 reply; 27+ messages in thread
From: Jonathan Cameron @ 2014-12-26 13:29 UTC (permalink / raw)
  To: Irina Tirdea, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

On 19/12/14 22:57, Irina Tirdea wrote:
> Some devices need the gender of the user to compute various
> parameters. One of this devices is Freescale's MMA9553L
> (http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
> that needs the gender of the user to compute distance, speed and activity type.
> 
> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>

> ---
>  Documentation/ABI/testing/sysfs-bus-iio |    8 ++++++++
>  drivers/iio/industrialio-core.c         |    1 +
>  include/linux/iio/iio.h                 |    1 +
>  3 files changed, 10 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index e480175..3b68c2d 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -343,6 +343,14 @@ Description:
>  		production inaccuracies).  If shared across all channels,
>  		<type>_calibscale is used.
>  
> +What:		/sys/bus/iio/devices/iio:deviceX/in_steps_calibgender
> +KernelVersion:	3.19
> +Contact:	linux-iio@vger.kernel.org
> +Description:
> +		Gender of the user: 0 for female and 1 for male. It is needed
> +		by some pedometers to compute the stride length, distance,
> +		speed and activity type.
This will have to go through the extended attribute enum interface. No magic
numbers in the interface please.  
> +
>  What:		/sys/bus/iio/devices/iio:deviceX/in_steps_calibheight
>  KernelVersion:	3.19
>  Contact:	linux-iio@vger.kernel.org
> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> index 4c435c8..93a39f9 100644
> --- a/drivers/iio/industrialio-core.c
> +++ b/drivers/iio/industrialio-core.c
> @@ -125,6 +125,7 @@ static const char * const iio_chan_info_postfix[] = {
>  	[IIO_CHAN_INFO_ENABLE] = "en",
>  	[IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight",
>  	[IIO_CHAN_INFO_CALIBWEIGHT] = "calibweight",
> +	[IIO_CHAN_INFO_CALIBGENDER] = "calibgender",
>  };
>  
>  /**
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> index 752a929..63dac0f 100644
> --- a/include/linux/iio/iio.h
> +++ b/include/linux/iio/iio.h
> @@ -41,6 +41,7 @@ enum iio_chan_info_enum {
>  	IIO_CHAN_INFO_ENABLE,
>  	IIO_CHAN_INFO_CALIBHEIGHT,
>  	IIO_CHAN_INFO_CALIBWEIGHT,
> +	IIO_CHAN_INFO_CALIBGENDER,
>  };
>  
>  enum iio_shared_by {
> 


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

* Re: [PATCH 4/8] iio: core: Introduce IO_CHAN_INFO_CALIBWEIGHT
  2014-12-19 22:57 ` [PATCH 4/8] iio: core: Introduce IO_CHAN_INFO_CALIBWEIGHT Irina Tirdea
@ 2014-12-26 13:31   ` Jonathan Cameron
  2014-12-29 15:05     ` Tirdea, Irina
  0 siblings, 1 reply; 27+ messages in thread
From: Jonathan Cameron @ 2014-12-26 13:31 UTC (permalink / raw)
  To: Irina Tirdea, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

On 19/12/14 22:57, Irina Tirdea wrote:
> Some devices need the weight of the user to compute other
> parameters. One of this devices is Freescale's MMA9553L
> (http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
> that needs the weight of the user to compute the number of calories burnt.
> 
> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
> ---
>  Documentation/ABI/testing/sysfs-bus-iio |    7 +++++++
>  drivers/iio/industrialio-core.c         |    1 +
>  include/linux/iio/iio.h                 |    1 +
>  3 files changed, 9 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index 07acef7..e480175 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -351,6 +351,13 @@ Description:
>  		to compute the stride length, distance, speed and activity
>  		type.
>  
> +What:		/sys/bus/iio/devices/iio:deviceX/in_steps_calibweight
> +KernelVersion:	3.19
> +Contact:	linux-iio@vger.kernel.org
> +Description:
> +		Weight of the user (in kg). It is needed by some pedometers
> +		to compute the calories burnt by the user.
How about grams?  Nice to keep to SI units going forward (I appreciate we
have broken that for what seemed like good reasons at the time) in one
or two places, but it makes it much harder to define consistent interfaces in the
long run.

J
> +
>  What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale_available
>  What:		/sys/.../iio:deviceX/in_voltageX_scale_available
>  What:		/sys/.../iio:deviceX/in_voltage-voltage_scale_available
> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> index 5e50aca..4c435c8 100644
> --- a/drivers/iio/industrialio-core.c
> +++ b/drivers/iio/industrialio-core.c
> @@ -124,6 +124,7 @@ static const char * const iio_chan_info_postfix[] = {
>  	[IIO_CHAN_INFO_INT_TIME] = "integration_time",
>  	[IIO_CHAN_INFO_ENABLE] = "en",
>  	[IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight",
> +	[IIO_CHAN_INFO_CALIBWEIGHT] = "calibweight",
>  };
>  
>  /**
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> index 878d861..752a929 100644
> --- a/include/linux/iio/iio.h
> +++ b/include/linux/iio/iio.h
> @@ -40,6 +40,7 @@ enum iio_chan_info_enum {
>  	IIO_CHAN_INFO_INT_TIME,
>  	IIO_CHAN_INFO_ENABLE,
>  	IIO_CHAN_INFO_CALIBHEIGHT,
> +	IIO_CHAN_INFO_CALIBWEIGHT,
>  };
>  
>  enum iio_shared_by {
> 


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

* RE: [PATCH 1/8] iio: core: Introduce CALORIES channel type
  2014-12-26 13:26   ` Jonathan Cameron
@ 2014-12-29 14:42     ` Tirdea, Irina
  2015-01-01 10:29       ` Jonathan Cameron
  0 siblings, 1 reply; 27+ messages in thread
From: Tirdea, Irina @ 2014-12-29 14:42 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Dogaru, Vlad, Baluta, Daniel, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald



> -----Original Message-----
> From: linux-iio-owner@vger.kernel.org [mailto:linux-iio-owner@vger.kernel.org] On Behalf Of Jonathan Cameron
> Sent: 26 December, 2014 15:26
> To: Tirdea, Irina; linux-iio@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
> Subject: Re: [PATCH 1/8] iio: core: Introduce CALORIES channel type
> 
> On 19/12/14 22:57, Irina Tirdea wrote:
> > Some devices compute the number of calories that the user has
> > burnt since the last reset.
> >
> > One of this devices is Freescale's MMA9553L
> > (http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
> > that computes the number of calories based on weight and step rate.
> >
> > Introduce a new channel type CALORIES to export these values.
> >
> > Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
> hmm..  Ideally we use SI units for everything, but in human energy usage
> Calories are the most common unit by a long way.  I'm having some trouble
> even finding the conversion for this particular for of calorie.
> 

Initially I wanted to use the calorie as unit, but it seemed a little bit confusing because there are 2 different units both called calorie:
- The small calorie or gram calorie approximates the energy needed to increase the temperature of 1 gram of water by 1 C.
- The kilogram calorie or "large calorie" is an obsolete term used for the kilocalorie, which is the calorie used to express the energy content of foods. However, in practice, the prefix "kilo" is usually omitted.

Instead of using cal (small calorie), kcal or Calorie (large calorie) as unit, I think it would be more clear to use Joule since that would eliminate confusion and it is also a SI unit.

According to the conversion table from here http://physics.nist.gov/Pubs/SP811/appenB9.html#ENERGY, we could convert nutritional calories to Joules using the following formula:
  Energy (Joules) = 4 184 * calories_th_nutrition
I used this formula in the implementation of the driver.

> Now clearly it doesn't matter if the only energy sensors we ever get
> are for human activity. However, that's unlikely to be the case.  We
> already have devices doing instantaneous power and there are plenty
> of smart meter chips out there (though of course, they will use the
> option of kW Hours just to confuse matters).
> 
> I'd definitely prefer joules if we can do it with out a large amount of
> pain.
> 
> Lars - any views on this?  (Analog do make plenty of 'energy' measurement
> devices after all!)
> > ---
> >  Documentation/ABI/testing/sysfs-bus-iio |    9 +++++++++
> >  drivers/iio/industrialio-core.c         |    1 +
> >  include/linux/iio/types.h               |    1 +
> >  3 files changed, 11 insertions(+)
> >
> > diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> > index df5e69e..bb9342b 100644
> > --- a/Documentation/ABI/testing/sysfs-bus-iio
> > +++ b/Documentation/ABI/testing/sysfs-bus-iio
> > @@ -282,6 +282,7 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_current_scale
> >  What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale
> >  What:		/sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
> >  What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
> > +What:		/sys/bus/iio/devices/iio:deviceX/in_calories_scale
> >  What:		/sys/bus/iio/devices/iio:deviceX/in_magn_scale
> >  What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
> >  What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
> > @@ -1049,6 +1050,14 @@ Description:
> >  		For a list of available output power modes read
> >  		in_accel_power_mode_available.
> >
> > +What:		/sys/.../iio:deviceX/in_calories_input
> > +What:		/sys/.../iio:deviceX/in_calories_raw
> > +KernelVersion:	3.17
> > +Contact:	linux-iio@vger.kernel.org
> > +Description:
> > +		This attribute is used to read the number of calories burned since the last
> > +		reset. Units after application of scale are Joules.
> > +
> >  What:		/sys/bus/iio/devices/iio:deviceX/store_eeprom
> >  KernelVersion:	3.4.0
> >  Contact:	linux-iio@vger.kernel.org
> > diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> > index ee442ee..5d95e84 100644
> > --- a/drivers/iio/industrialio-core.c
> > +++ b/drivers/iio/industrialio-core.c
> > @@ -72,6 +72,7 @@ static const char * const iio_chan_type_name_spec[] = {
> >  	[IIO_HUMIDITYRELATIVE] = "humidityrelative",
> >  	[IIO_ACTIVITY] = "activity",
> >  	[IIO_STEPS] = "steps",
> > +	[IIO_CALORIES] = "calories",
> >  };
> >
> >  static const char * const iio_modifier_names[] = {
> > diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
> > index 904dcbb..d2fe930 100644
> > --- a/include/linux/iio/types.h
> > +++ b/include/linux/iio/types.h
> > @@ -32,6 +32,7 @@ enum iio_chan_type {
> >  	IIO_HUMIDITYRELATIVE,
> >  	IIO_ACTIVITY,
> >  	IIO_STEPS,
> > +	IIO_CALORIES,
> >  };
> >
> >  enum iio_modifier {
> >
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH 4/8] iio: core: Introduce IO_CHAN_INFO_CALIBWEIGHT
  2014-12-26 13:31   ` Jonathan Cameron
@ 2014-12-29 15:05     ` Tirdea, Irina
  2015-01-01 10:37       ` Jonathan Cameron
  0 siblings, 1 reply; 27+ messages in thread
From: Tirdea, Irina @ 2014-12-29 15:05 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Dogaru, Vlad, Baluta, Daniel, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald



> -----Original Message-----
> From: Jonathan Cameron [mailto:jic23@kernel.org]
> Sent: 26 December, 2014 15:31
> To: Tirdea, Irina; linux-iio@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
> Subject: Re: [PATCH 4/8] iio: core: Introduce IO_CHAN_INFO_CALIBWEIGHT
> 
> On 19/12/14 22:57, Irina Tirdea wrote:
> > Some devices need the weight of the user to compute other
> > parameters. One of this devices is Freescale's MMA9553L
> > (http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
> > that needs the weight of the user to compute the number of calories burnt.
> >
> > Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
> > ---
> >  Documentation/ABI/testing/sysfs-bus-iio |    7 +++++++
> >  drivers/iio/industrialio-core.c         |    1 +
> >  include/linux/iio/iio.h                 |    1 +
> >  3 files changed, 9 insertions(+)
> >
> > diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> > index 07acef7..e480175 100644
> > --- a/Documentation/ABI/testing/sysfs-bus-iio
> > +++ b/Documentation/ABI/testing/sysfs-bus-iio
> > @@ -351,6 +351,13 @@ Description:
> >  		to compute the stride length, distance, speed and activity
> >  		type.
> >
> > +What:		/sys/bus/iio/devices/iio:deviceX/in_steps_calibweight
> > +KernelVersion:	3.19
> > +Contact:	linux-iio@vger.kernel.org
> > +Description:
> > +		Weight of the user (in kg). It is needed by some pedometers
> > +		to compute the calories burnt by the user.
> How about grams?  Nice to keep to SI units going forward (I appreciate we
> have broken that for what seemed like good reasons at the time) in one
> or two places, but it makes it much harder to define consistent interfaces in the
> long run.

According to SI [1] kg is the base unit for mass, so this was the obvious first choice.
I have nothing against using grams, but it is not clear to me why using grams would make it easier to define consistent interfaces in the long run.
I am probably missing something, so could you please clarify this?

Thanks,
Irina

[1] http://www.bipm.org/en/measurement-units/

> J
> > +
> >  What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale_available
> >  What:		/sys/.../iio:deviceX/in_voltageX_scale_available
> >  What:		/sys/.../iio:deviceX/in_voltage-voltage_scale_available
> > diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> > index 5e50aca..4c435c8 100644
> > --- a/drivers/iio/industrialio-core.c
> > +++ b/drivers/iio/industrialio-core.c
> > @@ -124,6 +124,7 @@ static const char * const iio_chan_info_postfix[] = {
> >  	[IIO_CHAN_INFO_INT_TIME] = "integration_time",
> >  	[IIO_CHAN_INFO_ENABLE] = "en",
> >  	[IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight",
> > +	[IIO_CHAN_INFO_CALIBWEIGHT] = "calibweight",
> >  };
> >
> >  /**
> > diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> > index 878d861..752a929 100644
> > --- a/include/linux/iio/iio.h
> > +++ b/include/linux/iio/iio.h
> > @@ -40,6 +40,7 @@ enum iio_chan_info_enum {
> >  	IIO_CHAN_INFO_INT_TIME,
> >  	IIO_CHAN_INFO_ENABLE,
> >  	IIO_CHAN_INFO_CALIBHEIGHT,
> > +	IIO_CHAN_INFO_CALIBWEIGHT,
> >  };
> >
> >  enum iio_shared_by {
> >


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

* RE: [PATCH 3/8] iio: core: Introduce SPEED channel type
  2014-12-26 13:28   ` Jonathan Cameron
@ 2014-12-29 18:13     ` Tirdea, Irina
  2015-01-01 10:34       ` Jonathan Cameron
  0 siblings, 1 reply; 27+ messages in thread
From: Tirdea, Irina @ 2014-12-29 18:13 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Dogaru, Vlad, Baluta, Daniel, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald



> -----Original Message-----
> From: Jonathan Cameron [mailto:jic23@kernel.org]
> Sent: 26 December, 2014 15:28
> To: Tirdea, Irina; linux-iio@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
> Subject: Re: [PATCH 3/8] iio: core: Introduce SPEED channel type
> 
> On 19/12/14 22:57, Irina Tirdea wrote:
> > Some devices export the current speed value of the user.
> >
> > One of this devices is Freescale's MMA9553L
> > (http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
> > that computes the speed of the user based on the number of steps and
> > stride length.
> >
> > Introduce a new channel type SPEED to export these values.
> >
> A fun question raised by this is whether we are going to end up with
> both speed and velocity (depending on whether it is signed or not).
> I suppose there isn't much to be done about that though and this looks fine
> to me (as does the previous one).

We might be able to unify speed and velocity if we use modifiers.

I am not sure how a device would export velocity information, but I assume it would be similar to acceleration (since we are talking about a vector as well). In this case we would need one channel type IIO_VELOCITY with modifiers for the 3 axes (IIO_MOD_X, IIO_MOD_Y, IIO_MOD_Z). We can further compute speed as the magnitude or the norm of the velocity vector (root of the sum squared values for x, y, z), so we can export it as an additional modifier IIO_MOD_NORM.

The pedometer only gives speed information without keeping track of the direction, so in this case we will have one channel IIO_VELOCITY with one modifier IIO_MOD_NORM.

Would this be a better approach than just exporting IIO_SPEED?

Thanks,
Irina

> > Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
> > ---
> >  Documentation/ABI/testing/sysfs-bus-iio |    9 +++++++++
> >  drivers/iio/industrialio-core.c         |    1 +
> >  include/linux/iio/types.h               |    1 +
> >  3 files changed, 11 insertions(+)
> >
> > diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> > index a5c1dcc..07acef7 100644
> > --- a/Documentation/ABI/testing/sysfs-bus-iio
> > +++ b/Documentation/ABI/testing/sysfs-bus-iio
> > @@ -295,6 +295,7 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_scale
> >  What:		/sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
> >  What:		/sys/bus/iio/devices/iio:deviceX/in_pressure_scale
> >  What:		/sys/bus/iio/devices/iio:deviceX/in_humidityrelative_scale
> > +What:		/sys/bus/iio/devices/iio:deviceX/in_speed_scale
> >  KernelVersion:	2.6.35
> >  Contact:	linux-iio@vger.kernel.org
> >  Description:
> > @@ -1146,6 +1147,14 @@ Description:
> >  		present, output should be considered as processed with the
> >  		unit in milliamps.
> >
> > +What:		/sys/.../iio:deviceX/in_speed_input
> > +What:		/sys/.../iio:deviceX/in_speed_raw
> > +KernelVersion:	3.19
> > +Contact:	linux-iio@vger.kernel.org
> > +Description:
> > +		This attribute is used to read the current speed value of the user.
> > +		Units after application of scale are m/s.
> > +
> >  What:		/sys/.../iio:deviceX/in_steps_en
> >  KernelVersion:	3.19
> >  Contact:	linux-iio@vger.kernel.org
> > diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> > index 4a10d31..5e50aca 100644
> > --- a/drivers/iio/industrialio-core.c
> > +++ b/drivers/iio/industrialio-core.c
> > @@ -74,6 +74,7 @@ static const char * const iio_chan_type_name_spec[] = {
> >  	[IIO_STEPS] = "steps",
> >  	[IIO_CALORIES] = "calories",
> >  	[IIO_DISTANCE] = "distance",
> > +	[IIO_SPEED] = "speed",
> >  };
> >
> >  static const char * const iio_modifier_names[] = {
> > diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
> > index b98f751..c848f45 100644
> > --- a/include/linux/iio/types.h
> > +++ b/include/linux/iio/types.h
> > @@ -34,6 +34,7 @@ enum iio_chan_type {
> >  	IIO_STEPS,
> >  	IIO_CALORIES,
> >  	IIO_DISTANCE,
> > +	IIO_SPEED,
> >  };
> >
> >  enum iio_modifier {
> >


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

* RE: [PATCH 5/8] iio: core: Introduce IIO_CHAN_INFO_CALIBGENDER
  2014-12-26 13:29   ` Jonathan Cameron
@ 2014-12-29 19:59     ` Tirdea, Irina
  0 siblings, 0 replies; 27+ messages in thread
From: Tirdea, Irina @ 2014-12-29 19:59 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Dogaru, Vlad, Baluta, Daniel, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald



> -----Original Message-----
> From: Jonathan Cameron [mailto:jic23@kernel.org]
> Sent: 26 December, 2014 15:30
> To: Tirdea, Irina; linux-iio@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
> Subject: Re: [PATCH 5/8] iio: core: Introduce IIO_CHAN_INFO_CALIBGENDER
> 
> On 19/12/14 22:57, Irina Tirdea wrote:
> > Some devices need the gender of the user to compute various
> > parameters. One of this devices is Freescale's MMA9553L
> > (http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
> > that needs the gender of the user to compute distance, speed and activity type.
> >
> > Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
> 
> > ---
> >  Documentation/ABI/testing/sysfs-bus-iio |    8 ++++++++
> >  drivers/iio/industrialio-core.c         |    1 +
> >  include/linux/iio/iio.h                 |    1 +
> >  3 files changed, 10 insertions(+)
> >
> > diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> > index e480175..3b68c2d 100644
> > --- a/Documentation/ABI/testing/sysfs-bus-iio
> > +++ b/Documentation/ABI/testing/sysfs-bus-iio
> > @@ -343,6 +343,14 @@ Description:
> >  		production inaccuracies).  If shared across all channels,
> >  		<type>_calibscale is used.
> >
> > +What:		/sys/bus/iio/devices/iio:deviceX/in_steps_calibgender
> > +KernelVersion:	3.19
> > +Contact:	linux-iio@vger.kernel.org
> > +Description:
> > +		Gender of the user: 0 for female and 1 for male. It is needed
> > +		by some pedometers to compute the stride length, distance,
> > +		speed and activity type.
> This will have to go through the extended attribute enum interface. No magic
> numbers in the interface please.

Sure, I will change this in next version.

Thanks for the reviews, Jonathan!

Irina

> > +
> >  What:		/sys/bus/iio/devices/iio:deviceX/in_steps_calibheight
> >  KernelVersion:	3.19
> >  Contact:	linux-iio@vger.kernel.org
> > diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> > index 4c435c8..93a39f9 100644
> > --- a/drivers/iio/industrialio-core.c
> > +++ b/drivers/iio/industrialio-core.c
> > @@ -125,6 +125,7 @@ static const char * const iio_chan_info_postfix[] = {
> >  	[IIO_CHAN_INFO_ENABLE] = "en",
> >  	[IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight",
> >  	[IIO_CHAN_INFO_CALIBWEIGHT] = "calibweight",
> > +	[IIO_CHAN_INFO_CALIBGENDER] = "calibgender",
> >  };
> >
> >  /**
> > diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> > index 752a929..63dac0f 100644
> > --- a/include/linux/iio/iio.h
> > +++ b/include/linux/iio/iio.h
> > @@ -41,6 +41,7 @@ enum iio_chan_info_enum {
> >  	IIO_CHAN_INFO_ENABLE,
> >  	IIO_CHAN_INFO_CALIBHEIGHT,
> >  	IIO_CHAN_INFO_CALIBWEIGHT,
> > +	IIO_CHAN_INFO_CALIBGENDER,
> >  };
> >
> >  enum iio_shared_by {
> >


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

* Re: [PATCH 1/8] iio: core: Introduce CALORIES channel type
  2014-12-29 14:42     ` Tirdea, Irina
@ 2015-01-01 10:29       ` Jonathan Cameron
  2015-01-11 13:44         ` Tirdea, Irina
  0 siblings, 1 reply; 27+ messages in thread
From: Jonathan Cameron @ 2015-01-01 10:29 UTC (permalink / raw)
  To: Tirdea, Irina, linux-iio
  Cc: linux-kernel, Dogaru, Vlad, Baluta, Daniel, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

On 29/12/14 14:42, Tirdea, Irina wrote:
> 
> 
>> -----Original Message-----
>> From: linux-iio-owner@vger.kernel.org [mailto:linux-iio-owner@vger.kernel.org] On Behalf Of Jonathan Cameron
>> Sent: 26 December, 2014 15:26
>> To: Tirdea, Irina; linux-iio@vger.kernel.org
>> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
>> Subject: Re: [PATCH 1/8] iio: core: Introduce CALORIES channel type
>>
>> On 19/12/14 22:57, Irina Tirdea wrote:
>>> Some devices compute the number of calories that the user has
>>> burnt since the last reset.
>>>
>>> One of this devices is Freescale's MMA9553L
>>> (http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
>>> that computes the number of calories based on weight and step rate.
>>>
>>> Introduce a new channel type CALORIES to export these values.
>>>
>>> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
>> hmm..  Ideally we use SI units for everything, but in human energy usage
>> Calories are the most common unit by a long way.  I'm having some trouble
>> even finding the conversion for this particular for of calorie.
>>
> 
> Initially I wanted to use the calorie as unit, but it seemed a little bit confusing because there are 2 different units both called calorie:
> - The small calorie or gram calorie approximates the energy needed to increase the temperature of 1 gram of water by 1 C.
> - The kilogram calorie or "large calorie" is an obsolete term used for the kilocalorie, which is the calorie used to express the energy content of foods. However, in practice, the prefix "kilo" is usually omitted.
> 
oops. I didn't actually read the patch beyond seeing CALORIES as the type in the title ;)
> Instead of using cal (small calorie), kcal or Calorie (large calorie) as unit, I think it would be more clear to use Joule since that would eliminate confusion and it is also a SI unit.
> 
> According to the conversion table from here http://physics.nist.gov/Pubs/SP811/appenB9.html#ENERGY, we could convert nutritional calories to Joules using the following formula:
>   Energy (Joules) = 4 184 * calories_th_nutrition
> I used this formula in the implementation of the driver.
Joules is good, but then the type needs to be ENERGY rather than CALORIES.
(and in_energy_* etc).
> 
>> Now clearly it doesn't matter if the only energy sensors we ever get
>> are for human activity. However, that's unlikely to be the case.  We
>> already have devices doing instantaneous power and there are plenty
>> of smart meter chips out there (though of course, they will use the
>> option of kW Hours just to confuse matters).
>>
>> I'd definitely prefer joules if we can do it with out a large amount of
>> pain.
>>
>> Lars - any views on this?  (Analog do make plenty of 'energy' measurement
>> devices after all!)
>>> ---
>>>  Documentation/ABI/testing/sysfs-bus-iio |    9 +++++++++
>>>  drivers/iio/industrialio-core.c         |    1 +
>>>  include/linux/iio/types.h               |    1 +
>>>  3 files changed, 11 insertions(+)
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
>>> index df5e69e..bb9342b 100644
>>> --- a/Documentation/ABI/testing/sysfs-bus-iio
>>> +++ b/Documentation/ABI/testing/sysfs-bus-iio
>>> @@ -282,6 +282,7 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_current_scale
>>>  What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale
>>>  What:		/sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
>>>  What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
>>> +What:		/sys/bus/iio/devices/iio:deviceX/in_calories_scale
>>>  What:		/sys/bus/iio/devices/iio:deviceX/in_magn_scale
>>>  What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
>>>  What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
>>> @@ -1049,6 +1050,14 @@ Description:
>>>  		For a list of available output power modes read
>>>  		in_accel_power_mode_available.
>>>
>>> +What:		/sys/.../iio:deviceX/in_calories_input
>>> +What:		/sys/.../iio:deviceX/in_calories_raw
>>> +KernelVersion:	3.17
>>> +Contact:	linux-iio@vger.kernel.org
>>> +Description:
>>> +		This attribute is used to read the number of calories burned since the last
>>> +		reset. Units after application of scale are Joules.
>>> +
>>>  What:		/sys/bus/iio/devices/iio:deviceX/store_eeprom
>>>  KernelVersion:	3.4.0
>>>  Contact:	linux-iio@vger.kernel.org
>>> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
>>> index ee442ee..5d95e84 100644
>>> --- a/drivers/iio/industrialio-core.c
>>> +++ b/drivers/iio/industrialio-core.c
>>> @@ -72,6 +72,7 @@ static const char * const iio_chan_type_name_spec[] = {
>>>  	[IIO_HUMIDITYRELATIVE] = "humidityrelative",
>>>  	[IIO_ACTIVITY] = "activity",
>>>  	[IIO_STEPS] = "steps",
>>> +	[IIO_CALORIES] = "calories",
>>>  };
>>>
>>>  static const char * const iio_modifier_names[] = {
>>> diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
>>> index 904dcbb..d2fe930 100644
>>> --- a/include/linux/iio/types.h
>>> +++ b/include/linux/iio/types.h
>>> @@ -32,6 +32,7 @@ enum iio_chan_type {
>>>  	IIO_HUMIDITYRELATIVE,
>>>  	IIO_ACTIVITY,
>>>  	IIO_STEPS,
>>> +	IIO_CALORIES,
>>>  };
>>>
>>>  enum iio_modifier {
>>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH 3/8] iio: core: Introduce SPEED channel type
  2014-12-29 18:13     ` Tirdea, Irina
@ 2015-01-01 10:34       ` Jonathan Cameron
  2015-01-11 13:47         ` Tirdea, Irina
  0 siblings, 1 reply; 27+ messages in thread
From: Jonathan Cameron @ 2015-01-01 10:34 UTC (permalink / raw)
  To: Tirdea, Irina, linux-iio
  Cc: linux-kernel, Dogaru, Vlad, Baluta, Daniel, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

On 29/12/14 18:13, Tirdea, Irina wrote:
> 
> 
>> -----Original Message-----
>> From: Jonathan Cameron [mailto:jic23@kernel.org]
>> Sent: 26 December, 2014 15:28
>> To: Tirdea, Irina; linux-iio@vger.kernel.org
>> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
>> Subject: Re: [PATCH 3/8] iio: core: Introduce SPEED channel type
>>
>> On 19/12/14 22:57, Irina Tirdea wrote:
>>> Some devices export the current speed value of the user.
>>>
>>> One of this devices is Freescale's MMA9553L
>>> (http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
>>> that computes the speed of the user based on the number of steps and
>>> stride length.
>>>
>>> Introduce a new channel type SPEED to export these values.
>>>
>> A fun question raised by this is whether we are going to end up with
>> both speed and velocity (depending on whether it is signed or not).
>> I suppose there isn't much to be done about that though and this looks fine
>> to me (as does the previous one).
> 
> We might be able to unify speed and velocity if we use modifiers.
> 
> I am not sure how a device would export velocity information, but I
> assume it would be similar to acceleration (since we are talking
> about a vector as well). In this case we would need one channel type
> IIO_VELOCITY with modifiers for the 3 axes (IIO_MOD_X, IIO_MOD_Y,
> IIO_MOD_Z). We can further compute speed as the magnitude or the norm
> of the velocity vector (root of the sum squared values for x, y, z),
> so we can export it as an additional modifier IIO_MOD_NORM.
Good, except for the last bit. We already have IIO_MOD_ROOT_SUM_SQUARED_X_Y so
should add IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z for 3D devices and use that.  A little
confusing perhaps for people just looking for a speed though.  Meh. Most
people will use this through a library anyway so that can wrap up the
measurement as speed if it wants to.
Note resulting attribute names will end up as the somewhat convoluted

in_velocity_sqrt(x^2+y^2+z^2)_* 

I suppose that's clear enough...
> 
> The pedometer only gives speed information without keeping track of
> the direction, so in this case we will have one channel IIO_VELOCITY
> with one modifier IIO_MOD_NORM.
> 
> Would this be a better approach than just exporting IIO_SPEED?> 
Saves us some confusion later, so yes I prefer this.
> Thanks,
> Irina
> 
>>> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
>>> ---
>>>  Documentation/ABI/testing/sysfs-bus-iio |    9 +++++++++
>>>  drivers/iio/industrialio-core.c         |    1 +
>>>  include/linux/iio/types.h               |    1 +
>>>  3 files changed, 11 insertions(+)
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
>>> index a5c1dcc..07acef7 100644
>>> --- a/Documentation/ABI/testing/sysfs-bus-iio
>>> +++ b/Documentation/ABI/testing/sysfs-bus-iio
>>> @@ -295,6 +295,7 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_scale
>>>  What:		/sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
>>>  What:		/sys/bus/iio/devices/iio:deviceX/in_pressure_scale
>>>  What:		/sys/bus/iio/devices/iio:deviceX/in_humidityrelative_scale
>>> +What:		/sys/bus/iio/devices/iio:deviceX/in_speed_scale
>>>  KernelVersion:	2.6.35
>>>  Contact:	linux-iio@vger.kernel.org
>>>  Description:
>>> @@ -1146,6 +1147,14 @@ Description:
>>>  		present, output should be considered as processed with the
>>>  		unit in milliamps.
>>>
>>> +What:		/sys/.../iio:deviceX/in_speed_input
>>> +What:		/sys/.../iio:deviceX/in_speed_raw
>>> +KernelVersion:	3.19
>>> +Contact:	linux-iio@vger.kernel.org
>>> +Description:
>>> +		This attribute is used to read the current speed value of the user.
>>> +		Units after application of scale are m/s.
>>> +
>>>  What:		/sys/.../iio:deviceX/in_steps_en
>>>  KernelVersion:	3.19
>>>  Contact:	linux-iio@vger.kernel.org
>>> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
>>> index 4a10d31..5e50aca 100644
>>> --- a/drivers/iio/industrialio-core.c
>>> +++ b/drivers/iio/industrialio-core.c
>>> @@ -74,6 +74,7 @@ static const char * const iio_chan_type_name_spec[] = {
>>>  	[IIO_STEPS] = "steps",
>>>  	[IIO_CALORIES] = "calories",
>>>  	[IIO_DISTANCE] = "distance",
>>> +	[IIO_SPEED] = "speed",
>>>  };
>>>
>>>  static const char * const iio_modifier_names[] = {
>>> diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
>>> index b98f751..c848f45 100644
>>> --- a/include/linux/iio/types.h
>>> +++ b/include/linux/iio/types.h
>>> @@ -34,6 +34,7 @@ enum iio_chan_type {
>>>  	IIO_STEPS,
>>>  	IIO_CALORIES,
>>>  	IIO_DISTANCE,
>>> +	IIO_SPEED,
>>>  };
>>>
>>>  enum iio_modifier {
>>>
> 


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

* Re: [PATCH 4/8] iio: core: Introduce IO_CHAN_INFO_CALIBWEIGHT
  2014-12-29 15:05     ` Tirdea, Irina
@ 2015-01-01 10:37       ` Jonathan Cameron
  0 siblings, 0 replies; 27+ messages in thread
From: Jonathan Cameron @ 2015-01-01 10:37 UTC (permalink / raw)
  To: Tirdea, Irina, linux-iio
  Cc: linux-kernel, Dogaru, Vlad, Baluta, Daniel, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

On 29/12/14 15:05, Tirdea, Irina wrote:
> 
> 
>> -----Original Message-----
>> From: Jonathan Cameron [mailto:jic23@kernel.org]
>> Sent: 26 December, 2014 15:31
>> To: Tirdea, Irina; linux-iio@vger.kernel.org
>> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
>> Subject: Re: [PATCH 4/8] iio: core: Introduce IO_CHAN_INFO_CALIBWEIGHT
>>
>> On 19/12/14 22:57, Irina Tirdea wrote:
>>> Some devices need the weight of the user to compute other
>>> parameters. One of this devices is Freescale's MMA9553L
>>> (http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
>>> that needs the weight of the user to compute the number of calories burnt.
>>>
>>> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
>>> ---
>>>  Documentation/ABI/testing/sysfs-bus-iio |    7 +++++++
>>>  drivers/iio/industrialio-core.c         |    1 +
>>>  include/linux/iio/iio.h                 |    1 +
>>>  3 files changed, 9 insertions(+)
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
>>> index 07acef7..e480175 100644
>>> --- a/Documentation/ABI/testing/sysfs-bus-iio
>>> +++ b/Documentation/ABI/testing/sysfs-bus-iio
>>> @@ -351,6 +351,13 @@ Description:
>>>  		to compute the stride length, distance, speed and activity
>>>  		type.
>>>
>>> +What:		/sys/bus/iio/devices/iio:deviceX/in_steps_calibweight
>>> +KernelVersion:	3.19
>>> +Contact:	linux-iio@vger.kernel.org
>>> +Description:
>>> +		Weight of the user (in kg). It is needed by some pedometers
>>> +		to compute the calories burnt by the user.
>> How about grams?  Nice to keep to SI units going forward (I appreciate we
>> have broken that for what seemed like good reasons at the time) in one
>> or two places, but it makes it much harder to define consistent interfaces in the
>> long run.
> 
> According to SI [1] kg is the base unit for mass, so this was the obvious first choice.
I'd forgotten that piece if 'entirely intuitive' unit choice ;)

> I have nothing against using grams, but it is not clear to me why using grams would make it easier to define consistent interfaces in the long run.
> I am probably missing something, so could you please clarify this?
kg fine as we have a good argument for why ;)

The consistent interface bit comes when we start getting compound units if we had picked
non SI choices (such is mA and mV - which we are stuck with unfortunately).
Now as Joules are kg m^2 s^-2 for example, we are on good grounds with the kg.
> 
> Thanks,
> Irina
> 
> [1] http://www.bipm.org/en/measurement-units/
> 
>> J
>>> +
>>>  What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale_available
>>>  What:		/sys/.../iio:deviceX/in_voltageX_scale_available
>>>  What:		/sys/.../iio:deviceX/in_voltage-voltage_scale_available
>>> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
>>> index 5e50aca..4c435c8 100644
>>> --- a/drivers/iio/industrialio-core.c
>>> +++ b/drivers/iio/industrialio-core.c
>>> @@ -124,6 +124,7 @@ static const char * const iio_chan_info_postfix[] = {
>>>  	[IIO_CHAN_INFO_INT_TIME] = "integration_time",
>>>  	[IIO_CHAN_INFO_ENABLE] = "en",
>>>  	[IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight",
>>> +	[IIO_CHAN_INFO_CALIBWEIGHT] = "calibweight",
>>>  };
>>>
>>>  /**
>>> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
>>> index 878d861..752a929 100644
>>> --- a/include/linux/iio/iio.h
>>> +++ b/include/linux/iio/iio.h
>>> @@ -40,6 +40,7 @@ enum iio_chan_info_enum {
>>>  	IIO_CHAN_INFO_INT_TIME,
>>>  	IIO_CHAN_INFO_ENABLE,
>>>  	IIO_CHAN_INFO_CALIBHEIGHT,
>>> +	IIO_CHAN_INFO_CALIBWEIGHT,
>>>  };
>>>
>>>  enum iio_shared_by {
>>>
> 


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

* Re: [PATCH 7/8] iio: accel: mma9551: split driver to expose mma955x api
  2014-12-19 22:57 ` [PATCH 7/8] iio: accel: mma9551: split driver to expose mma955x api Irina Tirdea
@ 2015-01-01 10:58   ` Jonathan Cameron
  2015-01-11 13:52     ` Tirdea, Irina
  0 siblings, 1 reply; 27+ messages in thread
From: Jonathan Cameron @ 2015-01-01 10:58 UTC (permalink / raw)
  To: Irina Tirdea, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

On 19/12/14 22:57, Irina Tirdea wrote:
> Freescale has the MMA955xL family of devices that use the
> same communication protocol (based on i2c messages):
> http://www.freescale.com/files/sensors/doc/data_sheet/MMA955xL.pdf.
> 
> To support more devices from this family, we need to split the
> mma9551 driver so we can export the common functions that will
> be used by other mma955x drivers.
> 
> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
> Reviewed-by: Vlad Dogaru <vlad.dogaru@intel.com>
Sorry, didn't get this far the other day.

Anyhow, other than a query on the depends and a suggestion that some
documentation of locking semantics might be good (perhaps in some
general kernel doc for the exported functions) - this looks good to
me.

Jonathan
> ---
>  drivers/iio/accel/Kconfig        |    6 +
>  drivers/iio/accel/Makefile       |    4 +-
>  drivers/iio/accel/mma9551.c      |  443 +-------------------------------------
>  drivers/iio/accel/mma9551_core.c |  443 ++++++++++++++++++++++++++++++++++++++
>  drivers/iio/accel/mma9551_core.h |   74 +++++++
>  5 files changed, 530 insertions(+), 440 deletions(-)
>  create mode 100644 drivers/iio/accel/mma9551_core.c
>  create mode 100644 drivers/iio/accel/mma9551_core.h
> 
> diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
> index d80616d..0600798 100644
> --- a/drivers/iio/accel/Kconfig
> +++ b/drivers/iio/accel/Kconfig
> @@ -105,9 +105,15 @@ config KXCJK1013
>  	  To compile this driver as a module, choose M here: the module will
>  	  be called kxcjk-1013.
>  
> +config MMA9551_CORE
> +	tristate
> +	depends on MMA9551
Why depend here?  THis isn't visible (due to lack of help) and in theory
an out of tree driver might want to use it.  Hence don't think you want this.
> +
>  config MMA9551
>  	tristate "Freescale MMA9551L Intelligent Motion-Sensing Platform Driver"
>  	depends on I2C
> +	select MMA9551_CORE
> +
>  	help
>  	  Say yes here to build support for the Freescale MMA9551L
>  	  Intelligent Motion-Sensing Platform Driver.
> diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
> index de5b9cb..8105316 100644
> --- a/drivers/iio/accel/Makefile
> +++ b/drivers/iio/accel/Makefile
> @@ -9,7 +9,9 @@ obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
>  obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
>  obj-$(CONFIG_KXSD9)	+= kxsd9.o
>  obj-$(CONFIG_MMA8452)	+= mma8452.o
> -obj-$(CONFIG_MMA9551)	+= mma9551.o
> +
> +obj-$(CONFIG_MMA9551_CORE)	+= mma9551_core.o
> +obj-$(CONFIG_MMA9551)		+= mma9551.o
>  
>  obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
>  st_accel-y := st_accel_core.o
> diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
> index 34ee9d6..6031b5a 100644
> --- a/drivers/iio/accel/mma9551.c
> +++ b/drivers/iio/accel/mma9551.c
> @@ -23,63 +23,13 @@
>  #include <linux/iio/sysfs.h>
>  #include <linux/iio/events.h>
>  #include <linux/pm_runtime.h>
> +#include "mma9551_core.h"
>  
>  #define MMA9551_DRV_NAME		"mma9551"
>  #define MMA9551_IRQ_NAME		"mma9551_event"
>  #define MMA9551_GPIO_NAME		"mma9551_int"
>  #define MMA9551_GPIO_COUNT		4
>  
> -/* Applications IDs */
> -#define MMA9551_APPID_VERSION		0x00
> -#define MMA9551_APPID_GPIO		0x03
> -#define MMA9551_APPID_AFE		0x06
> -#define MMA9551_APPID_TILT		0x0B
> -#define MMA9551_APPID_SLEEP_WAKE	0x12
> -#define MMA9551_APPID_RESET		0x17
> -#define MMA9551_APPID_NONE		0xff
> -
> -/* Command masks for mailbox write command */
> -#define MMA9551_CMD_READ_VERSION_INFO	0x00
> -#define MMA9551_CMD_READ_CONFIG		0x10
> -#define MMA9551_CMD_WRITE_CONFIG	0x20
> -#define MMA9551_CMD_READ_STATUS		0x30
> -
> -enum mma9551_gpio_pin {
> -	mma9551_gpio6 = 0,
> -	mma9551_gpio7,
> -	mma9551_gpio8,
> -	mma9551_gpio9,
> -	mma9551_gpio_max = mma9551_gpio9,
> -};
> -
> -/* Mailbox read command */
> -#define MMA9551_RESPONSE_COCO		BIT(7)
> -
> -/* Error-Status codes returned in mailbox read command */
> -#define MMA9551_MCI_ERROR_NONE			0x00
> -#define MMA9551_MCI_ERROR_PARAM			0x04
> -#define MMA9551_MCI_INVALID_COUNT		0x19
> -#define MMA9551_MCI_ERROR_COMMAND		0x1C
> -#define MMA9551_MCI_ERROR_INVALID_LENGTH	0x21
> -#define MMA9551_MCI_ERROR_FIFO_BUSY		0x22
> -#define MMA9551_MCI_ERROR_FIFO_ALLOCATED	0x23
> -#define MMA9551_MCI_ERROR_FIFO_OVERSIZE		0x24
> -
> -/* GPIO Application */
> -#define MMA9551_GPIO_POL_MSB		0x08
> -#define MMA9551_GPIO_POL_LSB		0x09
> -
> -/* Sleep/Wake application */
> -#define MMA9551_SLEEP_CFG		0x06
> -#define MMA9551_SLEEP_CFG_SNCEN		BIT(0)
> -#define MMA9551_SLEEP_CFG_FLEEN		BIT(1)
> -#define MMA9551_SLEEP_CFG_SCHEN		BIT(2)
> -
> -/* AFE application */
> -#define MMA9551_AFE_X_ACCEL_REG		0x00
> -#define MMA9551_AFE_Y_ACCEL_REG		0x02
> -#define MMA9551_AFE_Z_ACCEL_REG		0x04
> -
>  /* Tilt application (inclination in IIO terms). */
>  #define MMA9551_TILT_XZ_ANG_REG		0x00
>  #define MMA9551_TILT_YZ_ANG_REG		0x01
> @@ -92,6 +42,8 @@ enum mma9551_gpio_pin {
>  #define MMA9551_TILT_CFG_REG		0x01
>  #define MMA9551_TILT_ANG_THRESH_MASK	GENMASK(3, 0)
>  
> +#define MMA9551_DEFAULT_SAMPLE_RATE	122	/* Hz */
> +
>  /* Tilt events are mapped to the first three GPIO pins. */
>  enum mma9551_tilt_axis {
>  	mma9551_x = 0,
> @@ -99,64 +51,6 @@ enum mma9551_tilt_axis {
>  	mma9551_z,
>  };
>  
> -/*
> - * A response is composed of:
> - * - control registers: MB0-3
> - * - data registers: MB4-31
> - *
> - * A request is composed of:
> - * - mbox to write to (always 0)
> - * - control registers: MB1-4
> - * - data registers: MB5-31
> - */
> -#define MMA9551_MAILBOX_CTRL_REGS	4
> -#define MMA9551_MAX_MAILBOX_DATA_REGS	28
> -#define MMA9551_MAILBOX_REGS		32
> -
> -#define MMA9551_I2C_READ_RETRIES	5
> -#define MMA9551_I2C_READ_DELAY	50	/* us */
> -
> -#define MMA9551_DEFAULT_SAMPLE_RATE	122	/* Hz */
> -#define MMA9551_AUTO_SUSPEND_DELAY_MS	2000
> -
> -struct mma9551_mbox_request {
> -	u8 start_mbox;		/* Always 0. */
> -	u8 app_id;
> -	/*
> -	 * See Section 5.3.1 of the MMA955xL Software Reference Manual.
> -	 *
> -	 * Bit 7: reserved, always 0
> -	 * Bits 6-4: command
> -	 * Bits 3-0: upper bits of register offset
> -	 */
> -	u8 cmd_off;
> -	u8 lower_off;
> -	u8 nbytes;
> -	u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS - 1];
> -} __packed;
> -
> -struct mma9551_mbox_response {
> -	u8 app_id;
> -	/*
> -	 * See Section 5.3.3 of the MMA955xL Software Reference Manual.
> -	 *
> -	 * Bit 7: COCO
> -	 * Bits 6-0: Error code.
> -	 */
> -	u8 coco_err;
> -	u8 nbytes;
> -	u8 req_bytes;
> -	u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS];
> -} __packed;
> -
> -struct mma9551_version_info {
> -	__be32 device_id;
> -	u8 rom_version[2];
> -	u8 fw_version[2];
> -	u8 hw_version[2];
> -	u8 fw_build[2];
> -};
> -
>  struct mma9551_data {
>  	struct i2c_client *client;
>  	struct mutex mutex;
> @@ -164,285 +58,6 @@ struct mma9551_data {
>  	int irqs[MMA9551_GPIO_COUNT];
>  };
>  
> -static int mma9551_transfer(struct i2c_client *client,
> -			    u8 app_id, u8 command, u16 offset,
> -			    u8 *inbytes, int num_inbytes,
> -			    u8 *outbytes, int num_outbytes)
> -{
> -	struct mma9551_mbox_request req;
> -	struct mma9551_mbox_response rsp;
> -	struct i2c_msg in, out;
> -	u8 req_len, err_code;
> -	int ret, retries;
> -
> -	if (offset >= 1 << 12) {
> -		dev_err(&client->dev, "register offset too large\n");
> -		return -EINVAL;
> -	}
> -
> -	req_len = 1 + MMA9551_MAILBOX_CTRL_REGS + num_inbytes;
> -	req.start_mbox = 0;
> -	req.app_id = app_id;
> -	req.cmd_off = command | (offset >> 8);
> -	req.lower_off = offset;
> -
> -	if (command == MMA9551_CMD_WRITE_CONFIG)
> -		req.nbytes = num_inbytes;
> -	else
> -		req.nbytes = num_outbytes;
> -	if (num_inbytes)
> -		memcpy(req.buf, inbytes, num_inbytes);
> -
> -	out.addr = client->addr;
> -	out.flags = 0;
> -	out.len = req_len;
> -	out.buf = (u8 *)&req;
> -
> -	ret = i2c_transfer(client->adapter, &out, 1);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "i2c write failed\n");
> -		return ret;
> -	}
> -
> -	retries = MMA9551_I2C_READ_RETRIES;
> -	do {
> -		udelay(MMA9551_I2C_READ_DELAY);
> -
> -		in.addr = client->addr;
> -		in.flags = I2C_M_RD;
> -		in.len = sizeof(rsp);
> -		in.buf = (u8 *)&rsp;
> -
> -		ret = i2c_transfer(client->adapter, &in, 1);
> -		if (ret < 0) {
> -			dev_err(&client->dev, "i2c read failed\n");
> -			return ret;
> -		}
> -
> -		if (rsp.coco_err & MMA9551_RESPONSE_COCO)
> -			break;
> -	} while (--retries > 0);
> -
> -	if (retries == 0) {
> -		dev_err(&client->dev,
> -			"timed out while waiting for command response\n");
> -		return -ETIMEDOUT;
> -	}
> -
> -	if (rsp.app_id != app_id) {
> -		dev_err(&client->dev,
> -			"app_id mismatch in response got %02x expected %02x\n",
> -			rsp.app_id, app_id);
> -		return -EINVAL;
> -	}
> -
> -	err_code = rsp.coco_err & ~MMA9551_RESPONSE_COCO;
> -	if (err_code != MMA9551_MCI_ERROR_NONE) {
> -		dev_err(&client->dev, "read returned error %x\n", err_code);
> -		return -EINVAL;
> -	}
> -
> -	if (rsp.nbytes != rsp.req_bytes) {
> -		dev_err(&client->dev,
> -			"output length mismatch got %d expected %d\n",
> -			rsp.nbytes, rsp.req_bytes);
> -		return -EINVAL;
> -	}
> -
> -	if (num_outbytes)
> -		memcpy(outbytes, rsp.buf, num_outbytes);
> -
> -	return 0;
> -}
> -
> -static int mma9551_read_config_byte(struct i2c_client *client, u8 app_id,
> -				    u16 reg, u8 *val)
> -{
> -	return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
> -				reg, NULL, 0, val, 1);
> -}
> -
> -static int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
> -				     u16 reg, u8 val)
> -{
> -	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
> -				&val, 1, NULL, 0);
> -}
> -
> -static int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
> -				    u16 reg, u8 *val)
> -{
> -	return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
> -				reg, NULL, 0, val, 1);
> -}
> -
> -static int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
> -				    u16 reg, u16 *val)
> -{
> -	int ret;
> -	__be16 v;
> -
> -	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
> -			       reg, NULL, 0, (u8 *)&v, 2);
> -	*val = be16_to_cpu(v);
> -
> -	return ret;
> -}
> -
> -static int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
> -				      u16 reg, u8 mask, u8 val)
> -{
> -	int ret;
> -	u8 tmp, orig;
> -
> -	ret = mma9551_read_config_byte(client, app_id, reg, &orig);
> -	if (ret < 0)
> -		return ret;
> -
> -	tmp = orig & ~mask;
> -	tmp |= val & mask;
> -
> -	if (tmp == orig)
> -		return 0;
> -
> -	return mma9551_write_config_byte(client, app_id, reg, tmp);
> -}
> -
> -/*
> - * The polarity parameter is described in section 6.2.2, page 66, of the
> - * Software Reference Manual.  Basically, polarity=0 means the interrupt
> - * line has the same value as the selected bit, while polarity=1 means
> - * the line is inverted.
> - */
> -static int mma9551_gpio_config(struct i2c_client *client,
> -			       enum mma9551_gpio_pin pin,
> -			       u8 app_id, u8 bitnum, int polarity)
> -{
> -	u8 reg, pol_mask, pol_val;
> -	int ret;
> -
> -	if (pin > mma9551_gpio_max) {
> -		dev_err(&client->dev, "bad GPIO pin\n");
> -		return -EINVAL;
> -	}
> -
> -	/*
> -	 * Pin 6 is configured by regs 0x00 and 0x01, pin 7 by 0x02 and
> -	 * 0x03, and so on.
> -	 */
> -	reg = pin * 2;
> -
> -	ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
> -					reg, app_id);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "error setting GPIO app_id\n");
> -		return ret;
> -	}
> -
> -	ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
> -					reg + 1, bitnum);
> -	if (ret < 0) {
> -		dev_err(&client->dev, "error setting GPIO bit number\n");
> -		return ret;
> -	}
> -
> -	switch (pin) {
> -	case mma9551_gpio6:
> -		reg = MMA9551_GPIO_POL_LSB;
> -		pol_mask = 1 << 6;
> -		break;
> -	case mma9551_gpio7:
> -		reg = MMA9551_GPIO_POL_LSB;
> -		pol_mask = 1 << 7;
> -		break;
> -	case mma9551_gpio8:
> -		reg = MMA9551_GPIO_POL_MSB;
> -		pol_mask = 1 << 0;
> -		break;
> -	case mma9551_gpio9:
> -		reg = MMA9551_GPIO_POL_MSB;
> -		pol_mask = 1 << 1;
> -		break;
> -	}
> -	pol_val = polarity ? pol_mask : 0;
> -
> -	ret = mma9551_update_config_bits(client, MMA9551_APPID_GPIO, reg,
> -					 pol_mask, pol_val);
> -	if (ret < 0)
> -		dev_err(&client->dev, "error setting GPIO polarity\n");
> -
> -	return ret;
> -}
> -
> -static int mma9551_read_version(struct i2c_client *client)
> -{
> -	struct mma9551_version_info info;
> -	int ret;
> -
> -	ret = mma9551_transfer(client, MMA9551_APPID_VERSION, 0x00, 0x00,
> -			       NULL, 0, (u8 *)&info, sizeof(info));
> -	if (ret < 0)
> -		return ret;
> -
> -	dev_info(&client->dev, "Device ID 0x%x, firmware version %02x.%02x\n",
> -		 be32_to_cpu(info.device_id), info.fw_version[0],
> -		 info.fw_version[1]);
> -
> -	return 0;
> -}
> -
> -/*
> - * Power on chip and enable doze mode.
> - * Use 'false' as the second parameter to cause the device to enter
> - * sleep.
> - */
> -static int mma9551_set_device_state(struct i2c_client *client, bool enable)
> -{
> -	return mma9551_update_config_bits(client, MMA9551_APPID_SLEEP_WAKE,
> -					  MMA9551_SLEEP_CFG,
> -					  MMA9551_SLEEP_CFG_SNCEN |
> -					  MMA9551_SLEEP_CFG_FLEEN |
> -					  MMA9551_SLEEP_CFG_SCHEN,
> -					  enable ? MMA9551_SLEEP_CFG_SCHEN |
> -					  MMA9551_SLEEP_CFG_FLEEN :
> -					  MMA9551_SLEEP_CFG_SNCEN);
> -}
> -
> -static int mma9551_set_power_state(struct i2c_client *client, bool on)
> -{
> -#ifdef CONFIG_PM
> -	int ret;
> -
> -	if (on)
> -		ret = pm_runtime_get_sync(&client->dev);
> -	else {
> -		pm_runtime_mark_last_busy(&client->dev);
> -		ret = pm_runtime_put_autosuspend(&client->dev);
> -	}
> -
> -	if (ret < 0) {
> -		dev_err(&client->dev,
> -			"failed to change power state to %d\n", on);
> -		if (on)
> -			pm_runtime_put_noidle(&client->dev);
> -
> -		return ret;
> -	}
> -#endif
> -
> -	return 0;
> -}
> -
> -static void mma9551_sleep(int freq)
> -{
> -	int sleep_val = 1000 / freq;
> -
> -	if (sleep_val < 20)
> -		usleep_range(sleep_val * 1000, 20000);
> -	else
> -		msleep_interruptible(sleep_val);
> -}
> -
>  static int mma9551_read_incli_chan(struct i2c_client *client,
>  				   const struct iio_chan_spec *chan,
>  				   int *val)
> @@ -497,46 +112,6 @@ out_poweroff:
>  	return ret;
>  }
>  
> -static int mma9551_read_accel_chan(struct i2c_client *client,
> -				   const struct iio_chan_spec *chan,
> -				   int *val, int *val2)
> -{
> -	u16 reg_addr;
> -	s16 raw_accel;
> -	int ret;
> -
> -	switch (chan->channel2) {
> -	case IIO_MOD_X:
> -		reg_addr = MMA9551_AFE_X_ACCEL_REG;
> -		break;
> -	case IIO_MOD_Y:
> -		reg_addr = MMA9551_AFE_Y_ACCEL_REG;
> -		break;
> -	case IIO_MOD_Z:
> -		reg_addr = MMA9551_AFE_Z_ACCEL_REG;
> -		break;
> -	default:
> -		return -EINVAL;
> -	}
> -
> -	ret = mma9551_set_power_state(client, true);
> -	if (ret < 0)
> -		return ret;
> -
> -	ret = mma9551_read_status_word(client, MMA9551_APPID_AFE,
> -				       reg_addr, &raw_accel);
> -	if (ret < 0)
> -		goto out_poweroff;
> -
> -	*val = raw_accel;
> -
> -	ret = IIO_VAL_INT;
> -
> -out_poweroff:
> -	mma9551_set_power_state(client, false);
> -	return ret;
> -}
> -
>  static int mma9551_read_raw(struct iio_dev *indio_dev,
>  			    struct iio_chan_spec const *chan,
>  			    int *val, int *val2, long mask)
> @@ -569,9 +144,7 @@ static int mma9551_read_raw(struct iio_dev *indio_dev,
>  	case IIO_CHAN_INFO_SCALE:
>  		switch (chan->type) {
>  		case IIO_ACCEL:
> -			*val = 0;
> -			*val2 = 2440;
> -			return IIO_VAL_INT_PLUS_MICRO;
> +			return mma9551_read_accel_scale(val, val2);
>  		default:
>  			return -EINVAL;
>  		}
> @@ -737,14 +310,6 @@ static const struct iio_event_spec mma9551_incli_event = {
>  	.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
>  };
>  
> -#define MMA9551_ACCEL_CHANNEL(axis) {				\
> -	.type = IIO_ACCEL,					\
> -	.modified = 1,						\
> -	.channel2 = axis,					\
> -	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
> -	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
> -}
> -
>  #define MMA9551_INCLI_CHANNEL(axis) {				\
>  	.type = IIO_INCLI,					\
>  	.modified = 1,						\
> diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c
> new file mode 100644
> index 0000000..cab481b
> --- /dev/null
> +++ b/drivers/iio/accel/mma9551_core.c
> @@ -0,0 +1,443 @@
> +/*
> + * Common code for Freescale MMA955x Intelligent Sensor Platform drivers
> + * Copyright (c) 2014, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/delay.h>
> +#include <linux/iio/iio.h>
> +#include <linux/pm_runtime.h>
> +#include "mma9551_core.h"
> +
> +/* Command masks for mailbox write command */
> +#define MMA9551_CMD_READ_VERSION_INFO	0x00
> +#define MMA9551_CMD_READ_CONFIG		0x10
> +#define MMA9551_CMD_WRITE_CONFIG	0x20
> +#define MMA9551_CMD_READ_STATUS		0x30
> +
> +/* Mailbox read command */
> +#define MMA9551_RESPONSE_COCO		BIT(7)
> +
> +/* Error-Status codes returned in mailbox read command */
> +#define MMA9551_MCI_ERROR_NONE			0x00
> +#define MMA9551_MCI_ERROR_PARAM			0x04
> +#define MMA9551_MCI_INVALID_COUNT		0x19
> +#define MMA9551_MCI_ERROR_COMMAND		0x1C
> +#define MMA9551_MCI_ERROR_INVALID_LENGTH	0x21
> +#define MMA9551_MCI_ERROR_FIFO_BUSY		0x22
> +#define MMA9551_MCI_ERROR_FIFO_ALLOCATED	0x23
> +#define MMA9551_MCI_ERROR_FIFO_OVERSIZE		0x24
> +
> +/* GPIO Application */
> +#define MMA9551_GPIO_POL_MSB		0x08
> +#define MMA9551_GPIO_POL_LSB		0x09
> +
> +/* Sleep/Wake application */
> +#define MMA9551_SLEEP_CFG		0x06
> +#define MMA9551_SLEEP_CFG_SNCEN		BIT(0)
> +#define MMA9551_SLEEP_CFG_FLEEN		BIT(1)
> +#define MMA9551_SLEEP_CFG_SCHEN		BIT(2)
> +
> +/* AFE application */
> +#define MMA9551_AFE_X_ACCEL_REG		0x00
> +#define MMA9551_AFE_Y_ACCEL_REG		0x02
> +#define MMA9551_AFE_Z_ACCEL_REG		0x04
> +
> +/*
> + * A response is composed of:
> + * - control registers: MB0-3
> + * - data registers: MB4-31
> + *
> + * A request is composed of:
> + * - mbox to write to (always 0)
> + * - control registers: MB1-4
> + * - data registers: MB5-31
> + */
> +#define MMA9551_MAILBOX_CTRL_REGS	4
> +#define MMA9551_MAX_MAILBOX_DATA_REGS	28
> +#define MMA9551_MAILBOX_REGS		32
> +
> +#define MMA9551_I2C_READ_RETRIES	5
> +#define MMA9551_I2C_READ_DELAY	50	/* us */
> +
> +struct mma9551_mbox_request {
> +	u8 start_mbox;		/* Always 0. */
> +	u8 app_id;
> +	/*
> +	 * See Section 5.3.1 of the MMA955xL Software Reference Manual.
> +	 *
> +	 * Bit 7: reserved, always 0
> +	 * Bits 6-4: command
> +	 * Bits 3-0: upper bits of register offset
> +	 */
> +	u8 cmd_off;
> +	u8 lower_off;
> +	u8 nbytes;
> +	u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS - 1];
> +} __packed;
> +
> +struct mma9551_mbox_response {
> +	u8 app_id;
> +	/*
> +	 * See Section 5.3.3 of the MMA955xL Software Reference Manual.
> +	 *
> +	 * Bit 7: COCO
> +	 * Bits 6-0: Error code.
> +	 */
> +	u8 coco_err;
> +	u8 nbytes;
> +	u8 req_bytes;
> +	u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS];
> +} __packed;
> +
> +static int mma9551_transfer(struct i2c_client *client,
> +			    u8 app_id, u8 command, u16 offset,
> +			    u8 *inbytes, int num_inbytes,
> +			    u8 *outbytes, int num_outbytes)
> +{
> +	struct mma9551_mbox_request req;
> +	struct mma9551_mbox_response rsp;
> +	struct i2c_msg in, out;
> +	u8 req_len, err_code;
> +	int ret, retries;
> +
> +	if (offset >= 1 << 12) {
> +		dev_err(&client->dev, "register offset too large\n");
> +		return -EINVAL;
> +	}
> +
> +	req_len = 1 + MMA9551_MAILBOX_CTRL_REGS + num_inbytes;
> +	req.start_mbox = 0;
> +	req.app_id = app_id;
> +	req.cmd_off = command | (offset >> 8);
> +	req.lower_off = offset;
> +
> +	if (command == MMA9551_CMD_WRITE_CONFIG)
> +		req.nbytes = num_inbytes;
> +	else
> +		req.nbytes = num_outbytes;
> +	if (num_inbytes)
> +		memcpy(req.buf, inbytes, num_inbytes);
> +
> +	out.addr = client->addr;
> +	out.flags = 0;
> +	out.len = req_len;
> +	out.buf = (u8 *)&req;
> +
> +	ret = i2c_transfer(client->adapter, &out, 1);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "i2c write failed\n");
> +		return ret;
> +	}
> +
> +	retries = MMA9551_I2C_READ_RETRIES;
> +	do {
> +		udelay(MMA9551_I2C_READ_DELAY);
> +
> +		in.addr = client->addr;
> +		in.flags = I2C_M_RD;
> +		in.len = sizeof(rsp);
> +		in.buf = (u8 *)&rsp;
> +
> +		ret = i2c_transfer(client->adapter, &in, 1);
> +		if (ret < 0) {
> +			dev_err(&client->dev, "i2c read failed\n");
> +			return ret;
> +		}
> +
> +		if (rsp.coco_err & MMA9551_RESPONSE_COCO)
> +			break;
> +	} while (--retries > 0);
> +
> +	if (retries == 0) {
> +		dev_err(&client->dev,
> +			"timed out while waiting for command response\n");
> +		return -ETIMEDOUT;
> +	}
> +
> +	if (rsp.app_id != app_id) {
> +		dev_err(&client->dev,
> +			"app_id mismatch in response got %02x expected %02x\n",
> +			rsp.app_id, app_id);
> +		return -EINVAL;
> +	}
> +
> +	err_code = rsp.coco_err & ~MMA9551_RESPONSE_COCO;
> +	if (err_code != MMA9551_MCI_ERROR_NONE) {
> +		dev_err(&client->dev, "read returned error %x\n", err_code);
> +		return -EINVAL;
> +	}
> +
> +	if (rsp.nbytes != rsp.req_bytes) {
> +		dev_err(&client->dev,
> +			"output length mismatch got %d expected %d\n",
> +			rsp.nbytes, rsp.req_bytes);
> +		return -EINVAL;
> +	}
> +
> +	if (num_outbytes)
> +		memcpy(outbytes, rsp.buf, num_outbytes);
> +
> +	return 0;
> +}
> +
> +int mma9551_read_config_byte(struct i2c_client *client, u8 app_id,
> +			     u16 reg, u8 *val)
> +{
> +	return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
> +				reg, NULL, 0, val, 1);
> +}
> +EXPORT_SYMBOL(mma9551_read_config_byte);
> +
> +int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
> +			      u16 reg, u8 val)
> +{
> +	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
> +				&val, 1, NULL, 0);
> +}
> +EXPORT_SYMBOL(mma9551_write_config_byte);
> +
> +int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
> +			     u16 reg, u8 *val)
> +{
> +	return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
> +				reg, NULL, 0, val, 1);
> +}
> +EXPORT_SYMBOL(mma9551_read_status_byte);
> +
> +int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
> +			     u16 reg, u16 *val)
> +{
> +	int ret;
> +	__be16 v;
> +
> +	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
> +			       reg, NULL, 0, (u8 *)&v, 2);
> +	*val = be16_to_cpu(v);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(mma9551_read_status_word);
> +
I wonder if it's worth adding documentation to these functions - to point
out that they should only be used under a lock. Might get forgotten as
it's not readily apparent from the naming that locking is done externally
rather than internally.

> +int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
> +			       u16 reg, u8 mask, u8 val)
> +{
> +	int ret;
> +	u8 tmp, orig;
> +
> +	ret = mma9551_read_config_byte(client, app_id, reg, &orig);
> +	if (ret < 0)
> +		return ret;
> +
> +	tmp = orig & ~mask;
> +	tmp |= val & mask;
> +
> +	if (tmp == orig)
> +		return 0;
> +
> +	return mma9551_write_config_byte(client, app_id, reg, tmp);
> +}
> +EXPORT_SYMBOL(mma9551_update_config_bits);
> +
> +/*
> + * The polarity parameter is described in section 6.2.2, page 66, of the
> + * Software Reference Manual.  Basically, polarity=0 means the interrupt
> + * line has the same value as the selected bit, while polarity=1 means
> + * the line is inverted.
> + */
> +int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin,
> +			u8 app_id, u8 bitnum, int polarity)
> +{
> +	u8 reg, pol_mask, pol_val;
> +	int ret;
> +
> +	if (pin > mma9551_gpio_max) {
> +		dev_err(&client->dev, "bad GPIO pin\n");
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * Pin 6 is configured by regs 0x00 and 0x01, pin 7 by 0x02 and
> +	 * 0x03, and so on.
> +	 */
> +	reg = pin * 2;
> +
> +	ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
> +					reg, app_id);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "error setting GPIO app_id\n");
> +		return ret;
> +	}
> +
> +	ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
> +					reg + 1, bitnum);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "error setting GPIO bit number\n");
> +		return ret;
> +	}
> +
> +	switch (pin) {
> +	case mma9551_gpio6:
> +		reg = MMA9551_GPIO_POL_LSB;
> +		pol_mask = 1 << 6;
> +		break;
> +	case mma9551_gpio7:
> +		reg = MMA9551_GPIO_POL_LSB;
> +		pol_mask = 1 << 7;
> +		break;
> +	case mma9551_gpio8:
> +		reg = MMA9551_GPIO_POL_MSB;
> +		pol_mask = 1 << 0;
> +		break;
> +	case mma9551_gpio9:
> +		reg = MMA9551_GPIO_POL_MSB;
> +		pol_mask = 1 << 1;
> +		break;
> +	}
> +	pol_val = polarity ? pol_mask : 0;
> +
> +	ret = mma9551_update_config_bits(client, MMA9551_APPID_GPIO, reg,
> +					 pol_mask, pol_val);
> +	if (ret < 0)
> +		dev_err(&client->dev, "error setting GPIO polarity\n");
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(mma9551_gpio_config);
> +
> +int mma9551_read_version(struct i2c_client *client)
> +{
> +	struct mma9551_version_info info;
> +	int ret;
> +
> +	ret = mma9551_transfer(client, MMA9551_APPID_VERSION, 0x00, 0x00,
> +			       NULL, 0, (u8 *)&info, sizeof(info));
> +	if (ret < 0)
> +		return ret;
> +
> +	dev_info(&client->dev, "device ID 0x%x, firmware version %02x.%02x\n",
> +		 be32_to_cpu(info.device_id), info.fw_version[0],
> +		 info.fw_version[1]);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(mma9551_read_version);
> +
> +/*
> + * Power on chip and enable doze mode.
> + * Use 'false' as the second parameter to cause the device to enter
> + * sleep.
> + */
> +int mma9551_set_device_state(struct i2c_client *client, bool enable)
> +{
> +	return mma9551_update_config_bits(client, MMA9551_APPID_SLEEP_WAKE,
> +					  MMA9551_SLEEP_CFG,
> +					  MMA9551_SLEEP_CFG_SNCEN |
> +					  MMA9551_SLEEP_CFG_FLEEN |
> +					  MMA9551_SLEEP_CFG_SCHEN,
> +					  enable ? MMA9551_SLEEP_CFG_SCHEN |
> +					  MMA9551_SLEEP_CFG_FLEEN :
> +					  MMA9551_SLEEP_CFG_SNCEN);
> +}
> +EXPORT_SYMBOL(mma9551_set_device_state);
> +
> +int mma9551_set_power_state(struct i2c_client *client, bool on)
> +{
> +#ifdef CONFIG_PM
> +	int ret;
> +
> +	if (on)
> +		ret = pm_runtime_get_sync(&client->dev);
> +	else {
> +		pm_runtime_mark_last_busy(&client->dev);
> +		ret = pm_runtime_put_autosuspend(&client->dev);
> +	}
> +
> +	if (ret < 0) {
> +		dev_err(&client->dev,
> +			"failed to change power state to %d\n", on);
> +		if (on)
> +			pm_runtime_put_noidle(&client->dev);
> +
> +		return ret;
> +	}
> +#endif
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(mma9551_set_power_state);
> +
> +void mma9551_sleep(int freq)
> +{
> +	int sleep_val = 1000 / freq;
> +
> +	if (sleep_val < 20)
> +		usleep_range(sleep_val * 1000, 20000);
> +	else
> +		msleep_interruptible(sleep_val);
> +}
> +EXPORT_SYMBOL(mma9551_sleep);
> +
> +int mma9551_read_accel_chan(struct i2c_client *client,
> +			    const struct iio_chan_spec *chan,
> +			    int *val, int *val2)
> +{
> +	u16 reg_addr;
> +	s16 raw_accel;
> +	int ret;
> +
> +	switch (chan->channel2) {
> +	case IIO_MOD_X:
> +		reg_addr = MMA9551_AFE_X_ACCEL_REG;
> +		break;
> +	case IIO_MOD_Y:
> +		reg_addr = MMA9551_AFE_Y_ACCEL_REG;
> +		break;
> +	case IIO_MOD_Z:
> +		reg_addr = MMA9551_AFE_Z_ACCEL_REG;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	ret = mma9551_set_power_state(client, true);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mma9551_read_status_word(client, MMA9551_APPID_AFE,
> +				       reg_addr, &raw_accel);
> +	if (ret < 0)
> +		goto out_poweroff;
> +
> +	*val = raw_accel;
> +
> +	ret = IIO_VAL_INT;
> +
> +out_poweroff:
> +	mma9551_set_power_state(client, false);
> +	return ret;
> +}
> +EXPORT_SYMBOL(mma9551_read_accel_chan);
> +
> +int mma9551_read_accel_scale(int *val, int *val2)
> +{
> +	*val = 0;
> +	*val2 = 2440;
> +	return IIO_VAL_INT_PLUS_MICRO;
> +}
> +EXPORT_SYMBOL(mma9551_read_accel_scale);
> +
> +MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
> +MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("MMA955xL sensors core");
> diff --git a/drivers/iio/accel/mma9551_core.h b/drivers/iio/accel/mma9551_core.h
> new file mode 100644
> index 0000000..0e1c9bb
> --- /dev/null
> +++ b/drivers/iio/accel/mma9551_core.h
> @@ -0,0 +1,74 @@
> +/*
> + * Common code for Freescale MMA955x Intelligent Sensor Platform drivers
> + * Copyright (c) 2014, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + */
> +
> +#ifndef _MMA9551_CORE_H_
> +#define _MMA9551_CORE_H_
> +
> +/* Applications IDs */
> +#define MMA9551_APPID_VERSION		0x00
> +#define MMA9551_APPID_GPIO		0x03
> +#define MMA9551_APPID_AFE		0x06
> +#define MMA9551_APPID_TILT		0x0B
> +#define MMA9551_APPID_SLEEP_WAKE	0x12
> +#define MMA9551_APPID_RESET		0x17
> +#define MMA9551_APPID_NONE		0xff
> +
> +#define MMA9551_AUTO_SUSPEND_DELAY_MS	2000
> +
> +enum mma9551_gpio_pin {
> +	mma9551_gpio6 = 0,
> +	mma9551_gpio7,
> +	mma9551_gpio8,
> +	mma9551_gpio9,
> +	mma9551_gpio_max = mma9551_gpio9,
> +};
> +
> +struct mma9551_version_info {
> +	__be32 device_id;
> +	u8 rom_version[2];
> +	u8 fw_version[2];
> +	u8 hw_version[2];
> +	u8 fw_build[2];
> +};
> +
> +#define MMA9551_ACCEL_CHANNEL(axis) {				\
> +	.type = IIO_ACCEL,					\
> +	.modified = 1,						\
> +	.channel2 = axis,					\
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
> +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
> +}
> +
> +int mma9551_read_config_byte(struct i2c_client *client, u8 app_id,
> +			     u16 reg, u8 *val);
> +int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
> +			      u16 reg, u8 val);
> +int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
> +			     u16 reg, u8 *val);
> +int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
> +			     u16 reg, u16 *val);
> +int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
> +			       u16 reg, u8 mask, u8 val);
> +int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin,
> +			u8 app_id, u8 bitnum, int polarity);
> +int mma9551_read_version(struct i2c_client *client);
> +int mma9551_set_device_state(struct i2c_client *client, bool enable);
> +int mma9551_set_power_state(struct i2c_client *client, bool on);
> +void mma9551_sleep(int freq);
> +int mma9551_read_accel_chan(struct i2c_client *client,
> +			    const struct iio_chan_spec *chan,
> +			    int *val, int *val2);
> +int mma9551_read_accel_scale(int *val, int *val2);
> +
> +#endif /* _MMA9551_CORE_H_ */
> 


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

* Re: [PATCH 8/8] iio: add driver for Freescale MMA9553
  2014-12-19 22:57 ` [PATCH 8/8] iio: add driver for Freescale MMA9553 Irina Tirdea
@ 2015-01-01 11:58   ` Jonathan Cameron
  2015-01-11 15:10     ` Tirdea, Irina
  0 siblings, 1 reply; 27+ messages in thread
From: Jonathan Cameron @ 2015-01-01 11:58 UTC (permalink / raw)
  To: Irina Tirdea, linux-iio
  Cc: linux-kernel, Vlad Dogaru, Daniel Baluta, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

On 19/12/14 22:57, Irina Tirdea wrote:
> Add support for Freescale MMA9553L Intelligent Pedometer Platform.
> 
> The following functionalities are supported:
>  - step counter (counts the number of steps using a HW register)
>  - step detector (generates an iio event at every step the user takes)
>  - activity recognition (rest, walking, jogging, running)
>  - speed
>  - calories
>  - distance
> 
> To get accurate pedometer results, the user's height, weight and gender
> need to be configured.
> 
> The specifications can be downloaded from:
> http://www.freescale.com/files/sensors/doc/ref_manual/MMA955xLSWRM.pdf
> http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf
> 
> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
A few bits an bobs beyond the interface discussions in the earlier patches
in the series.

A nice looking driver on the whole, for a complex little device ;)

Jonathan
> ---
>  drivers/iio/accel/Kconfig        |   12 +-
>  drivers/iio/accel/Makefile       |    1 +
>  drivers/iio/accel/mma9551_core.c |   88 +++
>  drivers/iio/accel/mma9551_core.h |   17 +-
>  drivers/iio/accel/mma9553.c      | 1239 ++++++++++++++++++++++++++++++++++++++
>  5 files changed, 1355 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/iio/accel/mma9553.c
> 
> diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
> index 0600798..afd50d0 100644
> --- a/drivers/iio/accel/Kconfig
> +++ b/drivers/iio/accel/Kconfig
> @@ -107,7 +107,7 @@ config KXCJK1013
>  
>  config MMA9551_CORE
>  	tristate
> -	depends on MMA9551
> +	depends on MMA9551 || MMA9553
>  
>  config MMA9551
>  	tristate "Freescale MMA9551L Intelligent Motion-Sensing Platform Driver"
> @@ -121,4 +121,14 @@ config MMA9551
>  	  To compile this driver as a module, choose M here: the module
>  	  will be called mma9551.
>  
> +config MMA9553
> +	tristate "Freescale MMA9553L Intelligent Pedometer Platform Driver"
> +	depends on I2C
> +	select MMA9551_CORE
> +	help
> +	  Say yes here to build support for the Freescale MMA9553L
> +	  Intelligent Pedometer Platform Driver.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called mma9553.
>  endmenu
> diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
> index 8105316..f815695 100644
> --- a/drivers/iio/accel/Makefile
> +++ b/drivers/iio/accel/Makefile
> @@ -12,6 +12,7 @@ obj-$(CONFIG_MMA8452)	+= mma8452.o
>  
>  obj-$(CONFIG_MMA9551_CORE)	+= mma9551_core.o
>  obj-$(CONFIG_MMA9551)		+= mma9551.o
> +obj-$(CONFIG_MMA9553)		+= mma9553.o
>  
>  obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
>  st_accel-y := st_accel_core.o
> diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c
> index cab481b..743a868 100644
> --- a/drivers/iio/accel/mma9551_core.c
> +++ b/drivers/iio/accel/mma9551_core.c
> @@ -53,6 +53,11 @@
>  #define MMA9551_AFE_Y_ACCEL_REG		0x02
>  #define MMA9551_AFE_Z_ACCEL_REG		0x04
>  
> +/* Reset/Suspend/Clear application */
> +#define MMA9551_RSC_RESET		0x00
> +#define MMA9551_RSC_OFFSET(mask)	(3 - (ffs(mask) - 1) / 8)
> +#define MMA9551_RSC_VAL(mask)		(mask >> (((ffs(mask) - 1) / 8) * 8))
> +
>  /*
>   * A response is composed of:
>   * - control registers: MB0-3
> @@ -215,6 +220,30 @@ int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
>  }
>  EXPORT_SYMBOL(mma9551_read_status_byte);
>  
> +int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
> +			    u16 reg, u16 *val)
> +{
> +	int ret;
> +	__be16 v;
> +
> +	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
> +			       reg, NULL, 0, (u8 *)&v, 2);
> +	*val = be16_to_cpu(v);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(mma9551_read_config_word);
> +
> +int mma9551_write_config_word(struct i2c_client *client, u8 app_id,
> +			     u16 reg, u16 val)
> +{
> +	__be16 v = cpu_to_be16(val);
> +
> +	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
> +				(u8 *) &v, 2, NULL, 0);
> +}
> +EXPORT_SYMBOL(mma9551_write_config_word);
> +
>  int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
>  			     u16 reg, u16 *val)
>  {
> @@ -229,6 +258,56 @@ int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
>  }
>  EXPORT_SYMBOL(mma9551_read_status_word);
>  
> +int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
> +			     u16 reg, u8 len, u16 *buf)
> +{
> +	int ret, i;
> +	int len_words = len / sizeof(u16);
> +	__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
> +
> +	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
> +			       reg, NULL, 0, (u8 *) be_buf, len);
> +	if (ret < 0)
> +		return ret;
> +
> +	for (i = 0; i < len_words; i++)
> +		buf[i] = be16_to_cpu(be_buf[i]);
blank line
> +	return 0;
> +}
> +EXPORT_SYMBOL(mma9551_read_config_words);
> +
> +int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
> +			      u16 reg, u8 len, u16 *buf)
> +{
> +	int ret, i;
> +	int len_words = len / sizeof(u16);
> +	__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
> +
> +	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
> +			       reg, NULL, 0, (u8 *) be_buf, len);
> +	if (ret < 0)
> +		return ret;
> +
> +	for (i = 0; i < len_words; i++)
> +		buf[i] = be16_to_cpu(be_buf[i]);
blank line
> +	return 0;
> +}
> +EXPORT_SYMBOL(mma9551_read_status_words);
> +
> +int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
> +			       u16 reg, u8 len, u16 *buf)
> +{
> +	int i;
> +	int len_words = len / sizeof(u16);
> +	__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
> +
> +	for (i = 0; i < len_words; i++)
> +		be_buf[i] = cpu_to_be16(buf[i]);
blank line.
> +	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG,
> +				reg, (u8 *) be_buf, len, NULL, 0);
> +}
> +EXPORT_SYMBOL(mma9551_write_config_words);
> +
>  int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
>  			       u16 reg, u8 mask, u8 val)
>  {
> @@ -437,6 +516,15 @@ int mma9551_read_accel_scale(int *val, int *val2)
>  }
>  EXPORT_SYMBOL(mma9551_read_accel_scale);
>  
> +int mma9551_app_reset(struct i2c_client *client, u32 app_mask)
> +{
> +	return mma9551_write_config_byte(client, MMA9551_APPID_RCS,
> +					 MMA9551_RSC_RESET +
> +					 MMA9551_RSC_OFFSET(app_mask),
> +					 MMA9551_RSC_VAL(app_mask));
> +}
> +EXPORT_SYMBOL(mma9551_app_reset);
> +
>  MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
>  MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
>  MODULE_LICENSE("GPL v2");
> diff --git a/drivers/iio/accel/mma9551_core.h b/drivers/iio/accel/mma9551_core.h
> index 0e1c9bb..19b6253 100644
> --- a/drivers/iio/accel/mma9551_core.h
> +++ b/drivers/iio/accel/mma9551_core.h
> @@ -21,9 +21,13 @@
>  #define MMA9551_APPID_AFE		0x06
>  #define MMA9551_APPID_TILT		0x0B
>  #define MMA9551_APPID_SLEEP_WAKE	0x12
> -#define MMA9551_APPID_RESET		0x17
> +#define MMA9551_APPID_PEDOMETER	        0x15
> +#define MMA9551_APPID_RCS		0x17
>  #define MMA9551_APPID_NONE		0xff
>  
> +/* Reset/Suspend/Clear application app masks */
> +#define MMA9551_RSC_PED			BIT(21)
> +
>  #define MMA9551_AUTO_SUSPEND_DELAY_MS	2000
>  
>  enum mma9551_gpio_pin {
> @@ -56,8 +60,18 @@ int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
>  			      u16 reg, u8 val);
>  int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
>  			     u16 reg, u8 *val);
> +int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
> +			    u16 reg, u16 *val);
> +int mma9551_write_config_word(struct i2c_client *client, u8 app_id,
> +			     u16 reg, u16 val);
>  int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
>  			     u16 reg, u16 *val);
> +int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
> +			     u16 reg, u8 len, u16 *buf);
> +int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
> +			      u16 reg, u8 len, u16 *buf);
> +int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
> +			       u16 reg, u8 len, u16 *buf);
>  int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
>  			       u16 reg, u8 mask, u8 val);
>  int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin,
> @@ -70,5 +84,6 @@ int mma9551_read_accel_chan(struct i2c_client *client,
>  			    const struct iio_chan_spec *chan,
>  			    int *val, int *val2);
>  int mma9551_read_accel_scale(int *val, int *val2);
> +int mma9551_app_reset(struct i2c_client *client, u32 app_mask);
>  
>  #endif /* _MMA9551_CORE_H_ */
> diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
> new file mode 100644
> index 0000000..35b657d
> --- /dev/null
> +++ b/drivers/iio/accel/mma9553.c
> @@ -0,0 +1,1239 @@
> +/*
> + * Freescale MMA9553L Intelligent Pedometer driver
> + * Copyright (c) 2014, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/slab.h>
> +#include <linux/acpi.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/events.h>
> +#include <linux/pm_runtime.h>
> +#include "mma9551_core.h"
> +
> +#define MMA9553_DRV_NAME			"mma9553"
> +#define MMA9553_IRQ_NAME			"mma9553_event"
> +#define MMA9553_GPIO_NAME			"mma9553_int"
> +
> +/* Pedometer configuration registers (R/W) */
> +#define MMA9553_CONF_SLEEPMIN		0x00
> +#define MMA9553_CONF_SLEEPMAX		0x02
> +#define MMA9553_CONF_SLEEPTHD		0x04
> +#define MMA9553_CONF_WORD		GENMASK(15, 0)
> +
> +#define MMA9553_CONF_CONF_STEPLEN	0x06
> +#define MMA9553_CONF_CONFIG		BIT(15)
> +#define MMA9553_CONF_ACT_DBCNTM		BIT(14)
> +#define MMA9553_CONF_SLP_DBCNTM		BIT(13)
> +#define MMA9553_CONF_STEPLEN		GENMASK(7, 0)
> +
> +#define MMA9553_CONF_HEIGHT_WEIGHT	0x08
> +#define MMA9553_CONF_HEIGHT		GENMASK(15, 8)
> +#define MMA9553_CONF_WEIGHT		GENMASK(7, 0)
> +
> +#define MMA9553_CONF_FILTER		0x0A
> +#define MMA9553_CONF_FILTSTEP		GENMASK(15, 8)
> +#define MMA9553_CONF_MALE		BIT(7)
> +#define MMA9553_CONF_FILTTIME		GENMASK(6, 0)
> +
> +#define MMA9553_CONF_SPEED_STEP		0x0C
> +#define MMA9553_CONF_SPDPRD		GENMASK(15, 8)
> +#define MMA9553_CONF_STEPCOALESCE	GENMASK(7, 0)
> +
> +#define MMA9553_CONF_ACTTHD		0x0E
> +
> +/* Pedometer status registers (R-only) */
> +#define MMA9553_STATUS			0x00
> +#define MMA9553_STATUS_MRGFL		BIT(15)
> +#define MMA9553_STATUS_SUSPCHG		BIT(14)
> +#define MMA9553_STATUS_STEPCHG		BIT(13)
> +#define MMA9553_STATUS_ACTCHG		BIT(12)
> +#define MMA9553_STATUS_SUSP		BIT(11)
> +#define MMA9553_STATUS_ACTIVITY		(BIT(10) | BIT(9) | BIT(8))
> +#define MMA9553_STATUS_VERSION		0x00FF
> +
> +#define MMA9553_STEPCNT			0x02
> +#define MMA9553_DISTANCE		0x04
> +#define MMA9553_SPEED			0x06
> +#define MMA9553_CALORIES		0x08
> +#define MMA9553_SLEEPCNT		0x0A
> +
> +/* Pedometer events are always mapped to this pin. */
> +#define MMA9553_DEFAULT_GPIO_PIN	mma9551_gpio6
> +#define MMA9553_DEFAULT_GPIO_POLARITY	0
> +
> +/* Bitnum used for gpio configuration = bit number in high status byte */
> +#define STATUS_TO_BITNUM(bit)		(ffs(bit) - 9)
> +
> +#define MMA9553_DEFAULT_SAMPLE_RATE	30	/* Hz */
> +
> +/*
> + * The internal activity level must be stable for ACTTHD samples before
> + * ACTIVITY is updated.The ACTIVITY variable contains the current activity
> + * level and is updated every time a step is detected or once a second
> + * if there are no steps. So for 100% confidence level we need to have
> + * the same activity level for about 30 sec.
Not entirely sure I follow this argument on the confidence level.
We do have period to directly in_activity_walking_thresh_rising_period etc
to directly handle how long a condition has to be active before we fire an
event.  Perhaps that would be better.  You'd then make the activity threshold
read only (just return -EINVAL in the write) and set it at say 50% when read
back.
> + */
> +#define MMA9553_MAX_ACTTHD		(MMA9553_DEFAULT_SAMPLE_RATE * 30)
> +#define MMA9553_PERCENTAGE_TO_THD(prc) (((prc) * MMA9553_MAX_ACTTHD) / 100)
> +#define MMA9553_THD_TO_PERCENTAGE(thr) (((thr) * 100) / MMA9553_MAX_ACTTHD)
> +
> +/*
> + * Autonomously suspend pedometer if acceleration vector magnitude
> + * is near 1g (4096 at 0.244 mg/LSB resolution) for 30 seconds.
> + */
> +#define MMA9553_DEFAULT_SLEEPMIN	3688	/* 0,9 g */
> +#define MMA9553_DEFAULT_SLEEPMAX	4508	/* 1,1 g */
> +#define MMA9553_DEFAULT_SLEEPTHD	(MMA9553_DEFAULT_SAMPLE_RATE * 30)
> +
> +#define MMA9553_CONFIG_RETRIES		2
> +
> +/* Status register - activity field  */
> +enum activity_level {
> +	ACTIVITY_UNKNOWN,
> +	ACTIVITY_REST,
> +	ACTIVITY_WALKING,
> +	ACTIVITY_JOGGING,
> +	ACTIVITY_RUNNING,
> +};
> +
> +struct mma9553_event {
> +	enum iio_chan_type type;
> +	enum iio_modifier mod;
> +	enum iio_event_direction dir;
> +	bool enabled;
> +};
> +
> +struct mma9553_conf_regs {
> +	u16 sleepmin;
> +	u16 sleepmax;
> +	u16 sleepthd;
> +	u16 config;
> +	u16 height_weight;
> +	u16 filter;
> +	u16 speed_step;
> +	u16 actthd;
> +} __packed;
> +
> +struct mma9553_data {
> +	struct i2c_client *client;
> +	struct mutex mutex;
> +	struct mma9553_conf_regs conf;
> +	struct mma9553_event *events;
> +	int num_events;
> +	u8 gpio_bitnum;
> +	/*
> +	 * This is used for all features that depend on step count:
> +	 * step count, distance, speed, calories.
> +	 */
> +	bool stepcnt_enabled;
> +	u16 stepcnt;
> +	u8 activity;
> +};
> +
> +static u8 mma9553_get_bits(u16 val, u16 mask)
> +{
> +	return (val & mask) >> (ffs(mask) - 1);
> +}
> +
> +static u16 mma9553_set_bits(u16 current_val, u16 val, u16 mask)
> +{
> +	return (current_val & ~mask) | (val << (ffs(mask) - 1));
> +}
> +
> +static enum iio_modifier mma9553_activity_to_mod(enum activity_level activity)
> +{
> +	switch (activity) {
> +	case ACTIVITY_RUNNING:
> +		return IIO_MOD_RUNNING;
> +	case ACTIVITY_JOGGING:
> +		return IIO_MOD_JOGGING;
> +	case ACTIVITY_WALKING:
> +		return IIO_MOD_WALKING;
> +	case ACTIVITY_REST:
> +		return IIO_MOD_STILL;
> +	case ACTIVITY_UNKNOWN:
> +	default:
> +		return IIO_NO_MOD;
> +	}
> +}
> +
> +static struct mma9553_event *mma9553_get_event(struct mma9553_data *data,
> +					       enum iio_chan_type type,
> +					       enum iio_modifier mod,
> +					       enum iio_event_direction dir)
> +{
> +	int i;
> +
> +	for (i = 0; i < data->num_events; i++)
> +		if (data->events[i].type == type &&
> +		    data->events[i].mod == mod &&
> +		    data->events[i].dir == dir)
> +			return &data->events[i];
blank line.
> +	return NULL;
> +}
> +
> +static bool mma9553_is_any_event_enabled(struct mma9553_data *data,
> +					 bool check_type,
> +					 enum iio_chan_type type)
> +{
> +	int i;
> +
> +	for (i = 0; i < data->num_events; i++)
> +		if ((check_type && data->events[i].type == type &&
> +		     data->events[i].enabled) ||
> +		     (!check_type && data->events[i].enabled))
> +			return true;
> +	return false;
> +}
> +
> +static int mma9553_set_config(struct mma9553_data *data, u16 reg,
> +			      u16 *p_reg_val, u16 val, u16 mask)
> +{
> +	int ret, retries;
> +	u16 reg_val, config;
> +
> +	reg_val = *p_reg_val;
> +	if (val == mma9553_get_bits(reg_val, mask))
> +		return 0;
> +
> +	reg_val = mma9553_set_bits(reg_val, val, mask);
> +	ret = mma9551_write_config_word(data->client, MMA9551_APPID_PEDOMETER,
> +					reg, reg_val);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev,
> +			"error writing config register 0x%x\n", reg);
> +		return ret;
> +	}
> +
> +	*p_reg_val = reg_val;
> +
> +	/* Reinitializes the pedometer with current configuration values */
> +	config = mma9553_set_bits(data->conf.config, 1, MMA9553_CONF_CONFIG);
> +
> +	ret = mma9551_write_config_word(data->client, MMA9551_APPID_PEDOMETER,
> +					MMA9553_CONF_CONF_STEPLEN, config);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev,
> +			"error writing config register 0x%x\n",
> +			MMA9553_CONF_CONF_STEPLEN);
> +		return ret;
> +	}
> +
> +	retries = MMA9553_CONFIG_RETRIES;
> +	do {
> +		mma9551_sleep(MMA9553_DEFAULT_SAMPLE_RATE);
> +		ret = mma9551_read_config_word(data->client,
> +					       MMA9551_APPID_PEDOMETER,
> +					       MMA9553_CONF_CONF_STEPLEN,
> +					       &config);
> +		if (ret < 0)
> +			return ret;
> +	} while (mma9553_get_bits(config, MMA9553_CONF_CONFIG) &&
> +		 --retries > 0);
> +
> +	return 0;
> +}
> +
> +static int mma9553_read_activity_stepcnt(struct mma9553_data *data,
> +					 u8 *activity, u16 *stepcnt)
> +{
> +	u32 status_stepcnt;
> +	u16 status;
> +	int ret;
> +
> +	ret = mma9551_read_status_words(data->client, MMA9551_APPID_PEDOMETER,
> +					MMA9553_STATUS, sizeof(u32),
> +					(u16 *) &status_stepcnt);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev,
> +			"error reading status and stepcnt\n");
> +		return ret;
> +	}
> +
> +	status = status_stepcnt & MMA9553_CONF_WORD;
> +	*activity = mma9553_get_bits(status, MMA9553_STATUS_ACTIVITY);
> +	*stepcnt = status_stepcnt >> 16;
> +	return 0;
> +}
> +
> +static int mma9553_conf_gpio(struct mma9553_data *data)
> +{
> +	u8 bitnum = 0, appid = MMA9551_APPID_PEDOMETER;
> +	int ret;
> +	struct mma9553_event *ev_step_detect;
> +	bool activity_enabled;
> +
> +	activity_enabled =
> +	    mma9553_is_any_event_enabled(data, true, IIO_ACTIVITY);
> +	ev_step_detect =
> +	    mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
> +
> +	/*
> +	 * If both step detector and activity are enabled, use the MRGFL bit.
> +	 * This bit is the logical OR of the SUSPCHG, STEPCHG, and ACTCHG flags.
> +	 */
No brackets around single line statements (i.e. Drop all the {} below.)
> +	if (activity_enabled && ev_step_detect->enabled) {
> +		bitnum = STATUS_TO_BITNUM(MMA9553_STATUS_MRGFL);
> +	} else if (ev_step_detect->enabled) {
> +		bitnum = STATUS_TO_BITNUM(MMA9553_STATUS_STEPCHG);
> +	} else if (activity_enabled) {
> +		bitnum = STATUS_TO_BITNUM(MMA9553_STATUS_ACTCHG);
> +	} else {		/* Reset */
> +		appid = MMA9551_APPID_NONE;
> +	}
> +
> +	if (data->gpio_bitnum == bitnum)
> +		return 0;
> +
> +	/* Save initial values for activity and stepcnt */
> +	if (activity_enabled || ev_step_detect->enabled)
> +		mma9553_read_activity_stepcnt(data, &data->activity,
> +					      &data->stepcnt);
> +
> +	ret = mma9551_gpio_config(data->client,
> +				  MMA9553_DEFAULT_GPIO_PIN,
> +				  appid, bitnum, MMA9553_DEFAULT_GPIO_POLARITY);
> +	if (ret < 0)
> +		return ret;
> +	data->gpio_bitnum = bitnum;
blank line here.
> +	return 0;
> +}
> +
> +static int mma9553_init(struct mma9553_data *data)
> +{
> +	int ret;
> +
> +	ret = mma9551_read_version(data->client);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * Read all the pedometer configuration registers. This is used as
> +	 * a device identification command to differentiate the MMA9553L
> +	 * from the MMA9550L.
> +	 */
> +	ret =
> +	    mma9551_read_config_words(data->client, MMA9551_APPID_PEDOMETER,
> +				      MMA9553_CONF_SLEEPMIN,
> +				      sizeof(data->conf), (u16 *) &data->conf);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev,
> +			"device is not MMA9553L: failed to read cfg regs.\n");
> +		return ret;
> +	}
> +
> +
> +	/* Reset gpio */
> +	data->gpio_bitnum = -1;
> +	ret = mma9553_conf_gpio(data);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mma9551_app_reset(data->client, MMA9551_RSC_PED);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Init config registers */
> +	data->conf.sleepmin = MMA9553_DEFAULT_SLEEPMIN;
> +	data->conf.sleepmax = MMA9553_DEFAULT_SLEEPMAX;
> +	data->conf.sleepthd = MMA9553_DEFAULT_SLEEPTHD;
> +	data->conf.config =
> +	    mma9553_set_bits(data->conf.config, 1, MMA9553_CONF_CONFIG);
> +	/*
> +	 * Clear the activity debounce counter when the activity level changes,
> +	 * so that the confidence level applies for any activity level.
> +	 */
> +	data->conf.config =
> +	    mma9553_set_bits(data->conf.config, 1, MMA9553_CONF_ACT_DBCNTM);
> +	ret =
> +	    mma9551_write_config_words(data->client, MMA9551_APPID_PEDOMETER,
> +				       MMA9553_CONF_SLEEPMIN,
> +				       sizeof(data->conf), (u16 *) &data->conf);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev,
> +			"failed to write configuration registers.\n");
> +		return ret;
> +	}
> +
> +	return mma9551_set_device_state(data->client, true);
> +}
> +
> +static int mma9553_read_raw(struct iio_dev *indio_dev,
> +			    struct iio_chan_spec const *chan,
> +			    int *val, int *val2, long mask)
> +{
> +	struct mma9553_data *data = iio_priv(indio_dev);
> +	int ret;
> +	u16 tmp;
> +	u8 activity;
> +	bool powered_on;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_PROCESSED:
> +		switch (chan->type) {
> +		case IIO_STEPS:
> +			/*
> +			 * The HW only counts steps and other dependent
> +			 * parameters (speed, distance, calories, activity)
> +			 * if power is on (from enabling an event or the
> +			 * step counter */
> +			powered_on =
> +			    mma9553_is_any_event_enabled(data, false, 0) ||
> +			    data->stepcnt_enabled;
> +			if (!powered_on)
> +				return -EINVAL;
> +			mutex_lock(&data->mutex);
> +			ret = mma9551_read_status_word(data->client,
> +						       MMA9551_APPID_PEDOMETER,
> +						       MMA9553_STEPCNT, &tmp);
> +			mutex_unlock(&data->mutex);
> +			if (ret < 0)
> +				return ret;
> +			*val = tmp;
> +			return IIO_VAL_INT;
> +		case IIO_DISTANCE:
> +			powered_on =
> +			    mma9553_is_any_event_enabled(data, false, 0) ||
> +			    data->stepcnt_enabled;
> +			if (!powered_on)
> +				return -EINVAL;
> +			mutex_lock(&data->mutex);
> +			ret = mma9551_read_status_word(data->client,
> +						       MMA9551_APPID_PEDOMETER,
> +						       MMA9553_DISTANCE, &tmp);
> +			mutex_unlock(&data->mutex);
> +			if (ret < 0)
> +				return ret;
> +			*val = tmp;
> +			return IIO_VAL_INT;
> +		case IIO_ACTIVITY:
> +			powered_on =
> +			    mma9553_is_any_event_enabled(data, false, 0) ||
> +			    data->stepcnt_enabled;
> +			if (!powered_on)
> +				return -EINVAL;
> +			mutex_lock(&data->mutex);
> +			ret = mma9551_read_status_word(data->client,
> +						       MMA9551_APPID_PEDOMETER,
> +						       MMA9553_STATUS, &tmp);
> +			mutex_unlock(&data->mutex);
> +			if (ret < 0)
> +				return ret;
> +
> +			activity =
> +			    mma9553_get_bits(tmp, MMA9553_STATUS_ACTIVITY);
> +
> +			/*
> +			 * The device does not support confidence value levels,
> +			 * so we will always have 100% for current activity and
> +			 * 0% for the others.
> +			 */
> +			if (chan->channel2 == mma9553_activity_to_mod(activity))
> +				*val = 100;
> +			else
> +				*val = 0;
> +			return IIO_VAL_INT;
> +		default:
> +			return -EINVAL;
> +		}
> +	case IIO_CHAN_INFO_RAW:
> +		switch (chan->type) {
> +		case IIO_SPEED:	/* m/h */
> +			powered_on =
> +			    mma9553_is_any_event_enabled(data, false, 0) ||
> +			    data->stepcnt_enabled;
> +			if (!powered_on)
> +				return -EINVAL;
Seems like there ought to be a better error code - but I can't find one ;)
> +			mutex_lock(&data->mutex);
> +			ret = mma9551_read_status_word(data->client,
> +						       MMA9551_APPID_PEDOMETER,
> +						       MMA9553_SPEED, &tmp);
> +			mutex_unlock(&data->mutex);
> +			if (ret < 0)
> +				return ret;
> +			*val = tmp;
> +			return IIO_VAL_INT;
> +		case IIO_CALORIES:	/* Cal or kcal */
> +			powered_on =
> +			    mma9553_is_any_event_enabled(data, false, 0) ||
> +			    data->stepcnt_enabled;
> +			if (!powered_on)
> +				return -EINVAL;
> +			mutex_lock(&data->mutex);
> +			ret = mma9551_read_status_word(data->client,
> +						       MMA9551_APPID_PEDOMETER,
> +						       MMA9553_CALORIES, &tmp);
> +			mutex_unlock(&data->mutex);
> +			if (ret < 0)
> +				return ret;
> +			*val = tmp;
> +			return IIO_VAL_INT;
> +		case IIO_ACCEL:
> +			mutex_lock(&data->mutex);
> +			ret = mma9551_read_accel_chan(data->client,
> +						      chan, val, val2);
> +			mutex_unlock(&data->mutex);
> +			return ret;
> +		default:
> +			return -EINVAL;
> +		}
> +	case IIO_CHAN_INFO_SCALE:
> +		switch (chan->type) {
> +		case IIO_SPEED:	/* m/h to m/s */
> +			*val = 0;
> +			*val2 = 277;	/* 0.000277 */
> +			return IIO_VAL_INT_PLUS_MICRO;
> +		case IIO_CALORIES:	/* Cal or kcal to J */
> +			*val = 4184;
> +			return IIO_VAL_INT;
> +		case IIO_ACCEL:
> +			return mma9551_read_accel_scale(val, val2);
> +		default:
> +			return -EINVAL;
> +		}
> +	case IIO_CHAN_INFO_ENABLE:
> +		*val = data->stepcnt_enabled;
> +		return IIO_VAL_INT;
> +	case IIO_CHAN_INFO_CALIBHEIGHT:
> +		*val = mma9553_get_bits(data->conf.height_weight,
> +					MMA9553_CONF_HEIGHT);
> +		return IIO_VAL_INT;
> +	case IIO_CHAN_INFO_CALIBWEIGHT:
> +		*val = mma9553_get_bits(data->conf.height_weight,
> +					MMA9553_CONF_WEIGHT);
> +		return IIO_VAL_INT;
> +	case IIO_CHAN_INFO_CALIBGENDER:
> +		*val = mma9553_get_bits(data->conf.filter, MMA9553_CONF_MALE);
> +		return IIO_VAL_INT;
> +	case IIO_CHAN_INFO_OFFSET:
> +		switch (chan->type) {
> +		case IIO_STEPS:
> +			*val = mma9553_get_bits(data->conf.filter,
> +						MMA9553_CONF_FILTSTEP);
> +			return IIO_VAL_INT;
> +		default:
> +			return -EINVAL;
> +		}
> +	case IIO_CHAN_INFO_INT_TIME:
> +		switch (chan->type) {
> +		case IIO_STEPS:
> +			*val = mma9553_get_bits(data->conf.filter,
> +						MMA9553_CONF_FILTTIME);
> +			return IIO_VAL_INT;
> +		case IIO_SPEED:
> +			*val = mma9553_get_bits(data->conf.speed_step,
> +						MMA9553_CONF_SPDPRD);
> +			return IIO_VAL_INT;
> +		default:
> +			return -EINVAL;
> +		}
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int mma9553_write_raw(struct iio_dev *indio_dev,
> +			     struct iio_chan_spec const *chan,
> +			     int val, int val2, long mask)
> +{
> +	struct mma9553_data *data = iio_priv(indio_dev);
> +	int ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_ENABLE:
> +		if (data->stepcnt_enabled == !!val)
> +			return 0;
> +		mutex_lock(&data->mutex);
> +		ret = mma9551_set_power_state(data->client, val);
> +		if (ret < 0) {
> +			mutex_unlock(&data->mutex);
> +			return ret;
> +		}
> +		data->stepcnt_enabled = val;
> +		mutex_unlock(&data->mutex);
> +		return 0;
> +	case IIO_CHAN_INFO_CALIBHEIGHT:
> +		if (val < 0 || val > 255)
> +			return -EINVAL;
> +		mutex_lock(&data->mutex);
> +		ret = mma9553_set_config(data,
> +					 MMA9553_CONF_HEIGHT_WEIGHT,
> +					 &data->conf.height_weight,
> +					 val, MMA9553_CONF_HEIGHT);
> +		mutex_unlock(&data->mutex);
> +		return ret;
> +	case IIO_CHAN_INFO_CALIBWEIGHT:
> +		if (val < 0 || val > 255)
> +			return -EINVAL;
> +		mutex_lock(&data->mutex);
> +		ret = mma9553_set_config(data,
> +					 MMA9553_CONF_HEIGHT_WEIGHT,
> +					 &data->conf.height_weight,
> +					 val, MMA9553_CONF_WEIGHT);
> +		mutex_unlock(&data->mutex);
> +		return ret;
> +	case IIO_CHAN_INFO_CALIBGENDER:
As commented before - no magic numbers.  Hence this will need to use
the extended interface with enums etc.
> +		/* Gender can only be 0(female) or 1(male) */
> +		if ((val != 0) && (val != 1))
> +			return -EINVAL;
> +		mutex_lock(&data->mutex);
> +		ret = mma9553_set_config(data, MMA9553_CONF_FILTER,
> +					 &data->conf.filter, val,
> +					 MMA9553_CONF_MALE);
> +		mutex_unlock(&data->mutex);
> +		return ret;
> +	case IIO_CHAN_INFO_OFFSET:
> +		switch (chan->type) {
> +		case IIO_STEPS:
This seems like an ususual use of offset.
A quick look is this is about rejection of steps based on the fact the
user doesn't seem to be walking.  It's not an offset that I can see.
Probably needs a completely new interface.

Off the top of my head

in_steps_filter_outliers_num
and
in_steps_filter_outliers_period

err. Not that keen on this though but will let you propose something better!
> +			/*
> +			 * Set to 0 to disable step filtering. If the value
> +			 * specified is greater than 6, then 6 will be used.
> +			 */
> +			if (val < 0)
> +				return -EINVAL;
> +			if (val > 6)
> +				val = 6;
> +			mutex_lock(&data->mutex);
> +			ret = mma9553_set_config(data, MMA9553_CONF_FILTER,
> +						 &data->conf.filter, val,
> +						 MMA9553_CONF_FILTSTEP);
> +			mutex_unlock(&data->mutex);
> +			return ret;
> +		default:
> +			return -EINVAL;
> +		}
> +	case IIO_CHAN_INFO_INT_TIME:
> +		switch (chan->type) {
> +		case IIO_STEPS:
> +			if (val < 0 || val > 127)
> +				return -EINVAL;
> +			mutex_lock(&data->mutex);
> +			ret = mma9553_set_config(data, MMA9553_CONF_FILTER,
> +						 &data->conf.filter, val,
> +						 MMA9553_CONF_FILTTIME);
This isn't an integration time really either...  Hence need a new element
for this. 
> +			mutex_unlock(&data->mutex);
> +			return ret;
> +		case IIO_SPEED:
> +			/*
> +			 * If set to a value greater than 5, then 5 will be
> +			 * used. Warning: Do not set SPDPRD to 0 or 1 as
> +			 * this may cause undesirable behavior.
> +			 */
I suppose this one is an integration time (be in it a different fashion to
normal!)
> +			if (val < 2)
> +				return -EINVAL;
> +			if (val > 5)
> +				val = 5;
> +			mutex_lock(&data->mutex);
> +			ret = mma9553_set_config(data, MMA9553_CONF_SPEED_STEP,
> +						 &data->conf.speed_step, val,
> +						 MMA9553_CONF_SPDPRD);
> +			mutex_unlock(&data->mutex);
> +			return ret;
> +		default:
> +			return -EINVAL;
> +		}
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int mma9553_read_event_config(struct iio_dev *indio_dev,
> +				     const struct iio_chan_spec *chan,
> +				     enum iio_event_type type,
> +				     enum iio_event_direction dir)
> +{
> +
> +	struct mma9553_data *data = iio_priv(indio_dev);
> +	struct mma9553_event *event;
> +
> +	event = mma9553_get_event(data, chan->type, chan->channel2, dir);
> +	if (!event)
> +		return -EINVAL;
blank line here prefered. (or someone one will send me a patch adding
one within the week!)
> +	return event->enabled;
> +}
> +
> +static int mma9553_write_event_config(struct iio_dev *indio_dev,
> +				      const struct iio_chan_spec *chan,
> +				      enum iio_event_type type,
> +				      enum iio_event_direction dir, int state)
> +{
> +	struct mma9553_data *data = iio_priv(indio_dev);
> +	struct mma9553_event *event;
> +	int ret;
> +
> +	event = mma9553_get_event(data, chan->type, chan->channel2, dir);
> +	if (!event)
> +		return -EINVAL;
> +
> +	if (event->enabled == state)
> +		return 0;
> +
> +	mutex_lock(&data->mutex);
> +
> +	ret = mma9551_set_power_state(data->client, state);
> +	if (ret < 0)
> +		goto out;
> +	event->enabled = state;
> +
> +	ret = mma9553_conf_gpio(data);
> +	if (ret < 0)
> +		goto err_conf_gpio;
> +
> +	goto out;
Normal code style in IIO at least would be to have a separate return
here (with unlocking) rather than jumping to the end of the error
handling. Bit easier to follow.
> +
> +err_conf_gpio:
> +	if (state) {
> +		event->enabled = false;
> +		mma9551_set_power_state(data->client, false);
> +	}
> +out:
> +	mutex_unlock(&data->mutex);
> +	return ret;
> +}
> +
> +static int mma9553_read_event_value(struct iio_dev *indio_dev,
> +				    const struct iio_chan_spec *chan,
> +				    enum iio_event_type type,
> +				    enum iio_event_direction dir,
> +				    enum iio_event_info info,
> +				    int *val, int *val2)
> +{
> +	struct mma9553_data *data = iio_priv(indio_dev);
> +	int prc;
> +
> +	*val2 = 0;
> +	switch (info) {
> +	case IIO_EV_INFO_VALUE:
> +		switch (chan->type) {
> +		case IIO_ACTIVITY:
> +			prc = MMA9553_THD_TO_PERCENTAGE(data->conf.actthd);
> +			if (dir == IIO_EV_DIR_RISING)
> +				*val = prc;
> +			else if (dir == IIO_EV_DIR_FALLING)
> +				*val = 100 - prc;
> +			else
> +				return -EINVAL;
> +			return IIO_VAL_INT;
> +		default:
> +			return -EINVAL;
> +		}
> +	case IIO_EV_INFO_PERIOD:
> +		switch (chan->type) {
> +		case IIO_STEPS:
> +			*val = mma9553_get_bits(data->conf.speed_step,
> +						MMA9553_CONF_STEPCOALESCE);
> +			return IIO_VAL_INT;
> +		default:
> +			return -EINVAL;
> +		}
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int mma9553_write_event_value(struct iio_dev *indio_dev,
> +				     const struct iio_chan_spec *chan,
> +				     enum iio_event_type type,
> +				     enum iio_event_direction dir,
> +				     enum iio_event_info info,
> +				     int val, int val2)
> +{
> +	struct mma9553_data *data = iio_priv(indio_dev);
> +	int prc, thd;
> +	int ret;
> +
> +	switch (info) {
> +	case IIO_EV_INFO_VALUE:
> +		switch (chan->type) {
> +		case IIO_ACTIVITY:
> +			if (val < 0 || val > 100)
> +				return -EINVAL;
> +
> +			if (dir == IIO_EV_DIR_RISING)
> +				prc = val;
> +			else if (dir == IIO_EV_DIR_FALLING)
> +				prc = 100 - val;
> +			else
> +				return -EINVAL;
> +			thd = MMA9553_PERCENTAGE_TO_THD(prc);
> +
> +			mutex_lock(&data->mutex);
> +			ret = mma9553_set_config(data, MMA9553_CONF_ACTTHD,
> +						 &data->conf.actthd, thd,
> +						 MMA9553_CONF_WORD);
As commented above. this is a threshold on how long an activity is true
- not the direct confidence interval - so I'd suggest handling it as as
the event period, not threshold.
> +			mutex_unlock(&data->mutex);
> +			return ret;
> +		default:
> +			return -EINVAL;
> +		}
> +	case IIO_EV_INFO_PERIOD:
> +		switch (chan->type) {
> +		case IIO_STEPS:
> +			if (val < 0 || val > 255)
> +				return -EINVAL;
> +			mutex_lock(&data->mutex);
> +			ret = mma9553_set_config(data, MMA9553_CONF_SPEED_STEP,
> +						 &data->conf.speed_step, val,
> +						 MMA9553_CONF_STEPCOALESCE);
So this makes it fire every N steps?  Kind of nice, but not quite what period
is usually used for.  We have talked about having an absolute change
(rather than ROC) event type before - (requires a change of N and doesn't care
how long it took to happen).  Perhaps that makes sense here rather than
an instance event and a period?

> +			mutex_unlock(&data->mutex);
> +			return ret;
> +		default:
> +			return -EINVAL;
> +		}
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static const struct iio_event_spec mma9553_step_event = {
> +	.type = IIO_EV_TYPE_INSTANCE,
> +	.dir = IIO_EV_DIR_NONE,
> +	.mask_separate = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_PERIOD),
> +};
> +
> +static const struct iio_event_spec mma9553_activity_events[] = {
> +	{
> +		.type = IIO_EV_TYPE_THRESH,
> +		.dir = IIO_EV_DIR_RISING,
> +		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
> +				 BIT(IIO_EV_INFO_VALUE),
> +	 },
> +	{
> +		.type = IIO_EV_TYPE_THRESH,
> +		.dir = IIO_EV_DIR_FALLING,
> +		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
> +				 BIT(IIO_EV_INFO_VALUE),
> +	},
> +};
> +
> +#define MMA9553_PEDOMETER_CHANNEL(_type, _mask) {		\
> +	.type = _type,						\
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_ENABLE)      |	\
> +			      BIT(IIO_CHAN_INFO_CALIBHEIGHT) |	\
> +			      BIT(IIO_CHAN_INFO_CALIBGENDER) |	\
> +			      _mask,				\
> +}
> +
> +#define MMA9553_ACTIVITY_CHANNEL(_chan2) {				\
> +	.type = IIO_ACTIVITY,						\
> +	.modified = 1,							\
> +	.channel2 = _chan2,						\
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),		\
> +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT) |	\
> +				    BIT(IIO_CHAN_INFO_CALIBGENDER),	\
> +	.event_spec = mma9553_activity_events,				\
> +	.num_event_specs = ARRAY_SIZE(mma9553_activity_events),		\
> +}
> +
> +static const struct iio_chan_spec mma9553_channels[] = {
> +	MMA9551_ACCEL_CHANNEL(IIO_MOD_X),
> +	MMA9551_ACCEL_CHANNEL(IIO_MOD_Y),
> +	MMA9551_ACCEL_CHANNEL(IIO_MOD_Z),
> +
> +	{
> +		.type = IIO_STEPS,
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
> +				      BIT(IIO_CHAN_INFO_ENABLE) |
> +				      BIT(IIO_CHAN_INFO_OFFSET) |
> +				      BIT(IIO_CHAN_INFO_INT_TIME),
> +		.event_spec = &mma9553_step_event,
> +		.num_event_specs = 1,
> +	},
> +
> +	MMA9553_PEDOMETER_CHANNEL(IIO_DISTANCE, BIT(IIO_CHAN_INFO_PROCESSED)),
> +	MMA9553_PEDOMETER_CHANNEL(IIO_SPEED, BIT(IIO_CHAN_INFO_RAW) |
> +				  BIT(IIO_CHAN_INFO_SCALE) |
> +				  BIT(IIO_CHAN_INFO_INT_TIME)),
> +	MMA9553_PEDOMETER_CHANNEL(IIO_CALORIES, BIT(IIO_CHAN_INFO_RAW) |
> +				  BIT(IIO_CHAN_INFO_SCALE) |
> +				  BIT(IIO_CHAN_INFO_CALIBWEIGHT)),
> +
> +	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_RUNNING),
> +	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_JOGGING),
> +	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_WALKING),
> +	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_STILL),
> +};
> +
> +static const struct iio_info mma9553_info = {
> +	.driver_module = THIS_MODULE,
> +	.read_raw = mma9553_read_raw,
> +	.write_raw = mma9553_write_raw,
> +	.read_event_config = mma9553_read_event_config,
> +	.write_event_config = mma9553_write_event_config,
> +	.read_event_value = mma9553_read_event_value,
> +	.write_event_value = mma9553_write_event_value,
> +};
> +
Only one copy of this?  We don't want to prevent people having more
than one of these devices attached to a given machine.
Hence by all means have a default version of this but then
clone it into the mma9553_data structure for manipulation.
Or have a mached array of booleans in there (same indexes)
to use for the "enabled"s.

> +static struct mma9553_event mma9553_events[] = {
> +	{
> +		.type = IIO_STEPS,
> +		.mod = IIO_NO_MOD,
> +		.dir = IIO_EV_DIR_NONE,
> +		.enabled = false,
> +	},
> +	{
> +		.type = IIO_ACTIVITY,
> +		.mod = IIO_MOD_STILL,
> +		.dir = IIO_EV_DIR_RISING,
> +		.enabled = false,
> +	},
> +	{
> +		.type = IIO_ACTIVITY,
> +		.mod = IIO_MOD_STILL,
> +		.dir = IIO_EV_DIR_FALLING,
> +		.enabled = false,
> +	},
> +	{
> +		.type = IIO_ACTIVITY,
> +		.mod = IIO_MOD_WALKING,
> +		.dir = IIO_EV_DIR_RISING,
> +		.enabled = false,
> +	},
> +	{
> +		.type = IIO_ACTIVITY,
> +		.mod = IIO_MOD_WALKING,
> +		.dir = IIO_EV_DIR_FALLING,
> +		.enabled = false,
> +	},
> +	{
> +		.type = IIO_ACTIVITY,
> +		.mod = IIO_MOD_JOGGING,
> +		.dir = IIO_EV_DIR_RISING,
> +		.enabled = false,
> +	},
> +	{
> +		.type = IIO_ACTIVITY,
> +		.mod = IIO_MOD_JOGGING,
> +		.dir = IIO_EV_DIR_FALLING,
> +		.enabled = false,
> +	},
> +	{
> +		.type = IIO_ACTIVITY,
> +		.mod = IIO_MOD_RUNNING,
> +		.dir = IIO_EV_DIR_RISING,
> +		.enabled = false,
> +	},
> +	{
> +		.type = IIO_ACTIVITY,
> +		.mod = IIO_MOD_RUNNING,
> +		.dir = IIO_EV_DIR_FALLING,
> +		.enabled = false,
> +	},
> +};
> +
> +static irqreturn_t mma9553_irq_handler(int irq, void *private)
> +{
> +	/*
> +	 * Since we only configure the interrupt pin when an
> +	 * event is enabled, we are sure we have at least
> +	 * one event enabled at this point.
> +	 */
IIRC simply not supplyling the top half handler has the same effect as
this (though then you don't have anywhere to put the comment!)
Actually - I'd be tempted to grab and stash a timestamp in here to
increase the precision of you step timing etc.
> +	return IRQ_WAKE_THREAD;
> +}
> +
> +static irqreturn_t mma9553_event_handler(int irq, void *private)
> +{
> +	struct iio_dev *indio_dev = private;
> +	struct mma9553_data *data = iio_priv(indio_dev);
> +	u16 stepcnt;
> +	u8 activity;
> +	struct mma9553_event *ev_activity, *ev_prev_activity, *ev_step_detect;
> +	int ret;
> +
> +	mutex_lock(&data->mutex);
> +	ret = mma9553_read_activity_stepcnt(data, &activity, &stepcnt);
> +	if (ret < 0) {
> +		mutex_unlock(&data->mutex);
> +		return IRQ_HANDLED;
> +	}
> +
> +	ev_prev_activity =
> +	    mma9553_get_event(data, IIO_ACTIVITY,
> +			      mma9553_activity_to_mod(data->activity),
> +			      IIO_EV_DIR_FALLING);
> +	ev_activity =
> +	    mma9553_get_event(data, IIO_ACTIVITY,
> +			      mma9553_activity_to_mod(activity),
> +			      IIO_EV_DIR_RISING);
> +	ev_step_detect =
> +	    mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
> +
> +	if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) {
> +		data->stepcnt = stepcnt;
> +		iio_push_event(indio_dev,
> +			       IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
> +			       IIO_EV_DIR_NONE, IIO_EV_TYPE_INSTANCE, 0, 0, 0),
> +			       iio_get_time_ns());
Worth grabbing the timestamp earlier than this for precision reasons?
> +	}
> +
> +	if (activity != data->activity) {
> +		data->activity = activity;
> +		/* ev_activity can be NULL if activity == ACTIVITY_UNKNOWN */
> +		if (ev_prev_activity && ev_prev_activity->enabled)
> +			iio_push_event(indio_dev,
> +				       IIO_EVENT_CODE(IIO_ACTIVITY, 0,
> +				       ev_prev_activity->mod,
> +				       IIO_EV_DIR_FALLING,
> +				       IIO_EV_TYPE_THRESH, 0, 0, 0),
> +				       iio_get_time_ns());
> +
> +		if (ev_activity && ev_activity->enabled)
> +			iio_push_event(indio_dev,
> +				       IIO_EVENT_CODE(IIO_ACTIVITY, 0,
> +				       ev_activity->mod,
> +				       IIO_EV_DIR_RISING,
> +				       IIO_EV_TYPE_THRESH, 0, 0, 0),
> +				       iio_get_time_ns());
> +	}
> +	mutex_unlock(&data->mutex);
> +	return IRQ_HANDLED;
> +}
> +
> +static int mma9553_gpio_probe(struct i2c_client *client)
> +{
> +	struct device *dev;
> +	struct gpio_desc *gpio;
> +	int ret;
> +
> +	if (!client)
> +		return -EINVAL;
> +
> +	dev = &client->dev;
> +
> +	/* data ready gpio interrupt pin */
> +	gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0);
> +	if (IS_ERR(gpio)) {
> +		dev_err(dev, "acpi gpio get index failed\n");
> +		return PTR_ERR(gpio);
> +	}
> +
> +	ret = gpiod_direction_input(gpio);
> +	if (ret)
> +		return ret;
> +
> +	ret = gpiod_to_irq(gpio);
> +
> +	dev_dbg(dev, "gpio resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
> +
> +	return ret;
> +}
> +
> +static const char *mma9553_match_acpi_device(struct device *dev)
> +{
> +	const struct acpi_device_id *id;
> +
> +	id = acpi_match_device(dev->driver->acpi_match_table, dev);
> +	if (!id)
> +		return NULL;
> +
> +	return dev_name(dev);
> +}
> +
> +static int mma9553_probe(struct i2c_client *client,
> +			 const struct i2c_device_id *id)
> +{
> +	struct mma9553_data *data;
> +	struct iio_dev *indio_dev;
> +	const char *name = NULL;
> +	int ret;
> +
> +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	data = iio_priv(indio_dev);
> +	i2c_set_clientdata(client, indio_dev);
> +	data->client = client;
> +
> +	if (id)
> +		name = id->name;
> +	else if (ACPI_HANDLE(&client->dev))
> +		name = mma9553_match_acpi_device(&client->dev);
> +	else
Interesting to note the original driver doesn't have this else.  Worth
checking?
> +		return -ENOSYS;
> +
> +	mutex_init(&data->mutex);
> +	data->events = mma9553_events;
> +	data->num_events = ARRAY_SIZE(mma9553_events);
> +
> +	ret = mma9553_init(data);
> +	if (ret < 0)
> +		return ret;
> +
> +	indio_dev->dev.parent = &client->dev;
> +	indio_dev->channels = mma9553_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(mma9553_channels);
> +	indio_dev->name = name;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->info = &mma9553_info;
> +
> +	if (client->irq < 0)
> +		client->irq = mma9553_gpio_probe(client);
> +
So this time we just have a single irq.  That makes life simpler!
> +	if (client->irq >= 0) {
> +		ret = devm_request_threaded_irq(&client->dev, client->irq,
> +						mma9553_irq_handler,
> +						mma9553_event_handler,
> +						IRQF_TRIGGER_RISING,
> +						MMA9553_IRQ_NAME, indio_dev);
> +		if (ret < 0) {
> +			dev_err(&client->dev, "request irq %d failed\n",
> +				client->irq);
> +			goto out_poweroff;
> +		}
> +
> +	}
> +
> +	ret = iio_device_register(indio_dev);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "unable to register iio device\n");
> +		goto out_poweroff;
> +	}
> +
> +	ret = pm_runtime_set_active(&client->dev);
> +	if (ret < 0)
> +		goto out_iio_unregister;
> +
> +	pm_runtime_enable(&client->dev);
> +	pm_runtime_set_autosuspend_delay(&client->dev,
> +					 MMA9551_AUTO_SUSPEND_DELAY_MS);
> +	pm_runtime_use_autosuspend(&client->dev);
> +
> +	dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
> +	return 0;
> +
> +out_iio_unregister:
> +	iio_device_unregister(indio_dev);
> +out_poweroff:
> +	mma9551_set_device_state(client, false);
> +	return ret;
> +}
> +
> +static int mma9553_remove(struct i2c_client *client)
> +{
> +	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> +	struct mma9553_data *data = iio_priv(indio_dev);
> +
> +	pm_runtime_disable(&client->dev);
> +	pm_runtime_set_suspended(&client->dev);
> +	pm_runtime_put_noidle(&client->dev);
> +
> +	iio_device_unregister(indio_dev);
> +	mutex_lock(&data->mutex);
> +	mma9551_set_device_state(data->client, false);
> +	mutex_unlock(&data->mutex);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int mma9553_runtime_suspend(struct device *dev)
> +{
> +	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> +	struct mma9553_data *data = iio_priv(indio_dev);
> +	int ret;
> +
> +	mutex_lock(&data->mutex);
> +	ret = mma9551_set_device_state(data->client, false);
> +	mutex_unlock(&data->mutex);
> +	if (ret < 0) {
> +		dev_err(&data->client->dev, "powering off device failed\n");
> +		return -EAGAIN;
> +	}
> +
> +	return 0;
> +}
> +
> +static int mma9553_runtime_resume(struct device *dev)
> +{
> +	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> +	struct mma9553_data *data = iio_priv(indio_dev);
> +	int ret;
> +
> +	ret = mma9551_set_device_state(data->client, true);
> +	if (ret < 0)
> +		return ret;
> +
> +	mma9551_sleep(MMA9553_DEFAULT_SAMPLE_RATE);
> +	return 0;
> +}
> +#endif
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int mma9553_suspend(struct device *dev)
> +{
> +	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> +	struct mma9553_data *data = iio_priv(indio_dev);
> +	int ret;
> +
> +	mutex_lock(&data->mutex);
> +	ret = mma9551_set_device_state(data->client, false);
> +	mutex_unlock(&data->mutex);
> +
> +	return ret;
> +}
> +
> +static int mma9553_resume(struct device *dev)
> +{
> +	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> +	struct mma9553_data *data = iio_priv(indio_dev);
> +	int ret;
> +
> +	mutex_lock(&data->mutex);
> +	ret = mma9551_set_device_state(data->client, true);
> +	mutex_unlock(&data->mutex);
> +
> +	return ret;
> +}
> +#endif
> +
> +static const struct dev_pm_ops mma9553_pm_ops = {
> +	SET_SYSTEM_SLEEP_PM_OPS(mma9553_suspend, mma9553_resume)
> +	SET_RUNTIME_PM_OPS(mma9553_runtime_suspend,
> +			   mma9553_runtime_resume, NULL)
> +};
> +
> +static const struct acpi_device_id mma9553_acpi_match[] = {
> +	{"MMA9553", 0},
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match);
> +
> +static const struct i2c_device_id mma9553_id[] = {
> +	{"mma9553", 0},
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, mma9553_id);
> +
> +static struct i2c_driver mma9553_driver = {
> +	.driver = {
> +		   .name = MMA9553_DRV_NAME,
> +		   .acpi_match_table = ACPI_PTR(mma9553_acpi_match),
> +		   .pm = &mma9553_pm_ops,
> +		   },
> +	.probe = mma9553_probe,
> +	.remove = mma9553_remove,
> +	.id_table = mma9553_id,
> +};
> +
> +module_i2c_driver(mma9553_driver);
> +
> +MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("MMA9553L pedometer platform driver");
> 


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

* RE: [PATCH 1/8] iio: core: Introduce CALORIES channel type
  2015-01-01 10:29       ` Jonathan Cameron
@ 2015-01-11 13:44         ` Tirdea, Irina
  0 siblings, 0 replies; 27+ messages in thread
From: Tirdea, Irina @ 2015-01-11 13:44 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Dogaru, Vlad, Baluta, Daniel, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald



> -----Original Message-----
> From: Jonathan Cameron [mailto:jic23@kernel.org]
> Sent: 01 January, 2015 12:30
> To: Tirdea, Irina; linux-iio@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
> Subject: Re: [PATCH 1/8] iio: core: Introduce CALORIES channel type
> 
> On 29/12/14 14:42, Tirdea, Irina wrote:
> >
> >
> >> -----Original Message-----
> >> From: linux-iio-owner@vger.kernel.org [mailto:linux-iio-owner@vger.kernel.org] On Behalf Of Jonathan Cameron
> >> Sent: 26 December, 2014 15:26
> >> To: Tirdea, Irina; linux-iio@vger.kernel.org
> >> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
> >> Subject: Re: [PATCH 1/8] iio: core: Introduce CALORIES channel type
> >>
> >> On 19/12/14 22:57, Irina Tirdea wrote:
> >>> Some devices compute the number of calories that the user has
> >>> burnt since the last reset.
> >>>
> >>> One of this devices is Freescale's MMA9553L
> >>> (http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
> >>> that computes the number of calories based on weight and step rate.
> >>>
> >>> Introduce a new channel type CALORIES to export these values.
> >>>
> >>> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
> >> hmm..  Ideally we use SI units for everything, but in human energy usage
> >> Calories are the most common unit by a long way.  I'm having some trouble
> >> even finding the conversion for this particular for of calorie.
> >>
> >
> > Initially I wanted to use the calorie as unit, but it seemed a little bit confusing because there are 2 different units both called calorie:
> > - The small calorie or gram calorie approximates the energy needed to increase the temperature of 1 gram of water by 1 C.
> > - The kilogram calorie or "large calorie" is an obsolete term used for the kilocalorie, which is the calorie used to express the energy
> content of foods. However, in practice, the prefix "kilo" is usually omitted.
> >
> oops. I didn't actually read the patch beyond seeing CALORIES as the type in the title ;)
> > Instead of using cal (small calorie), kcal or Calorie (large calorie) as unit, I think it would be more clear to use Joule since that would
> eliminate confusion and it is also a SI unit.
> >
> > According to the conversion table from here http://physics.nist.gov/Pubs/SP811/appenB9.html#ENERGY, we could convert
> nutritional calories to Joules using the following formula:
> >   Energy (Joules) = 4 184 * calories_th_nutrition
> > I used this formula in the implementation of the driver.
> Joules is good, but then the type needs to be ENERGY rather than CALORIES.
> (and in_energy_* etc).


That sounds better. Will change the type to ENERGY.

> >
> >> Now clearly it doesn't matter if the only energy sensors we ever get
> >> are for human activity. However, that's unlikely to be the case.  We
> >> already have devices doing instantaneous power and there are plenty
> >> of smart meter chips out there (though of course, they will use the
> >> option of kW Hours just to confuse matters).
> >>
> >> I'd definitely prefer joules if we can do it with out a large amount of
> >> pain.
> >>
> >> Lars - any views on this?  (Analog do make plenty of 'energy' measurement
> >> devices after all!)
> >>> ---
> >>>  Documentation/ABI/testing/sysfs-bus-iio |    9 +++++++++
> >>>  drivers/iio/industrialio-core.c         |    1 +
> >>>  include/linux/iio/types.h               |    1 +
> >>>  3 files changed, 11 insertions(+)
> >>>
> >>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> >>> index df5e69e..bb9342b 100644
> >>> --- a/Documentation/ABI/testing/sysfs-bus-iio
> >>> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> >>> @@ -282,6 +282,7 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_current_scale
> >>>  What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale
> >>>  What:		/sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
> >>>  What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
> >>> +What:		/sys/bus/iio/devices/iio:deviceX/in_calories_scale
> >>>  What:		/sys/bus/iio/devices/iio:deviceX/in_magn_scale
> >>>  What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
> >>>  What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
> >>> @@ -1049,6 +1050,14 @@ Description:
> >>>  		For a list of available output power modes read
> >>>  		in_accel_power_mode_available.
> >>>
> >>> +What:		/sys/.../iio:deviceX/in_calories_input
> >>> +What:		/sys/.../iio:deviceX/in_calories_raw
> >>> +KernelVersion:	3.17
> >>> +Contact:	linux-iio@vger.kernel.org
> >>> +Description:
> >>> +		This attribute is used to read the number of calories burned since the last
> >>> +		reset. Units after application of scale are Joules.
> >>> +
> >>>  What:		/sys/bus/iio/devices/iio:deviceX/store_eeprom
> >>>  KernelVersion:	3.4.0
> >>>  Contact:	linux-iio@vger.kernel.org
> >>> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> >>> index ee442ee..5d95e84 100644
> >>> --- a/drivers/iio/industrialio-core.c
> >>> +++ b/drivers/iio/industrialio-core.c
> >>> @@ -72,6 +72,7 @@ static const char * const iio_chan_type_name_spec[] = {
> >>>  	[IIO_HUMIDITYRELATIVE] = "humidityrelative",
> >>>  	[IIO_ACTIVITY] = "activity",
> >>>  	[IIO_STEPS] = "steps",
> >>> +	[IIO_CALORIES] = "calories",
> >>>  };
> >>>
> >>>  static const char * const iio_modifier_names[] = {
> >>> diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
> >>> index 904dcbb..d2fe930 100644
> >>> --- a/include/linux/iio/types.h
> >>> +++ b/include/linux/iio/types.h
> >>> @@ -32,6 +32,7 @@ enum iio_chan_type {
> >>>  	IIO_HUMIDITYRELATIVE,
> >>>  	IIO_ACTIVITY,
> >>>  	IIO_STEPS,
> >>> +	IIO_CALORIES,
> >>>  };
> >>>
> >>>  enum iio_modifier {
> >>>
> >>
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* RE: [PATCH 3/8] iio: core: Introduce SPEED channel type
  2015-01-01 10:34       ` Jonathan Cameron
@ 2015-01-11 13:47         ` Tirdea, Irina
  0 siblings, 0 replies; 27+ messages in thread
From: Tirdea, Irina @ 2015-01-11 13:47 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Dogaru, Vlad, Baluta, Daniel, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald



> -----Original Message-----
> From: Jonathan Cameron [mailto:jic23@kernel.org]
> Sent: 01 January, 2015 12:34
> To: Tirdea, Irina; linux-iio@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
> Subject: Re: [PATCH 3/8] iio: core: Introduce SPEED channel type
> 
> On 29/12/14 18:13, Tirdea, Irina wrote:
> >
> >
> >> -----Original Message-----
> >> From: Jonathan Cameron [mailto:jic23@kernel.org]
> >> Sent: 26 December, 2014 15:28
> >> To: Tirdea, Irina; linux-iio@vger.kernel.org
> >> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
> >> Subject: Re: [PATCH 3/8] iio: core: Introduce SPEED channel type
> >>
> >> On 19/12/14 22:57, Irina Tirdea wrote:
> >>> Some devices export the current speed value of the user.
> >>>
> >>> One of this devices is Freescale's MMA9553L
> >>> (http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf)
> >>> that computes the speed of the user based on the number of steps and
> >>> stride length.
> >>>
> >>> Introduce a new channel type SPEED to export these values.
> >>>
> >> A fun question raised by this is whether we are going to end up with
> >> both speed and velocity (depending on whether it is signed or not).
> >> I suppose there isn't much to be done about that though and this looks fine
> >> to me (as does the previous one).
> >
> > We might be able to unify speed and velocity if we use modifiers.
> >
> > I am not sure how a device would export velocity information, but I
> > assume it would be similar to acceleration (since we are talking
> > about a vector as well). In this case we would need one channel type
> > IIO_VELOCITY with modifiers for the 3 axes (IIO_MOD_X, IIO_MOD_Y,
> > IIO_MOD_Z). We can further compute speed as the magnitude or the norm
> > of the velocity vector (root of the sum squared values for x, y, z),
> > so we can export it as an additional modifier IIO_MOD_NORM.
> Good, except for the last bit. We already have IIO_MOD_ROOT_SUM_SQUARED_X_Y so
> should add IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z for 3D devices and use that.  A little
> confusing perhaps for people just looking for a speed though.  Meh. Most
> people will use this through a library anyway so that can wrap up the
> measurement as speed if it wants to.
> Note resulting attribute names will end up as the somewhat convoluted
> 
> in_velocity_sqrt(x^2+y^2+z^2)_*
> 
> I suppose that's clear enough...
Yes, IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z would fit better. I will also add ABI documentation to make it easier for people looking for speed.

> >
> > The pedometer only gives speed information without keeping track of
> > the direction, so in this case we will have one channel IIO_VELOCITY
> > with one modifier IIO_MOD_NORM.
> >
> > Would this be a better approach than just exporting IIO_SPEED?>
> Saves us some confusion later, so yes I prefer this.
> > Thanks,
> > Irina
> >
> >>> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
> >>> ---
> >>>  Documentation/ABI/testing/sysfs-bus-iio |    9 +++++++++
> >>>  drivers/iio/industrialio-core.c         |    1 +
> >>>  include/linux/iio/types.h               |    1 +
> >>>  3 files changed, 11 insertions(+)
> >>>
> >>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> >>> index a5c1dcc..07acef7 100644
> >>> --- a/Documentation/ABI/testing/sysfs-bus-iio
> >>> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> >>> @@ -295,6 +295,7 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_scale
> >>>  What:		/sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
> >>>  What:		/sys/bus/iio/devices/iio:deviceX/in_pressure_scale
> >>>  What:		/sys/bus/iio/devices/iio:deviceX/in_humidityrelative_scale
> >>> +What:		/sys/bus/iio/devices/iio:deviceX/in_speed_scale
> >>>  KernelVersion:	2.6.35
> >>>  Contact:	linux-iio@vger.kernel.org
> >>>  Description:
> >>> @@ -1146,6 +1147,14 @@ Description:
> >>>  		present, output should be considered as processed with the
> >>>  		unit in milliamps.
> >>>
> >>> +What:		/sys/.../iio:deviceX/in_speed_input
> >>> +What:		/sys/.../iio:deviceX/in_speed_raw
> >>> +KernelVersion:	3.19
> >>> +Contact:	linux-iio@vger.kernel.org
> >>> +Description:
> >>> +		This attribute is used to read the current speed value of the user.
> >>> +		Units after application of scale are m/s.
> >>> +
> >>>  What:		/sys/.../iio:deviceX/in_steps_en
> >>>  KernelVersion:	3.19
> >>>  Contact:	linux-iio@vger.kernel.org
> >>> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> >>> index 4a10d31..5e50aca 100644
> >>> --- a/drivers/iio/industrialio-core.c
> >>> +++ b/drivers/iio/industrialio-core.c
> >>> @@ -74,6 +74,7 @@ static const char * const iio_chan_type_name_spec[] = {
> >>>  	[IIO_STEPS] = "steps",
> >>>  	[IIO_CALORIES] = "calories",
> >>>  	[IIO_DISTANCE] = "distance",
> >>> +	[IIO_SPEED] = "speed",
> >>>  };
> >>>
> >>>  static const char * const iio_modifier_names[] = {
> >>> diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
> >>> index b98f751..c848f45 100644
> >>> --- a/include/linux/iio/types.h
> >>> +++ b/include/linux/iio/types.h
> >>> @@ -34,6 +34,7 @@ enum iio_chan_type {
> >>>  	IIO_STEPS,
> >>>  	IIO_CALORIES,
> >>>  	IIO_DISTANCE,
> >>> +	IIO_SPEED,
> >>>  };
> >>>
> >>>  enum iio_modifier {
> >>>
> >


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

* RE: [PATCH 7/8] iio: accel: mma9551: split driver to expose mma955x api
  2015-01-01 10:58   ` Jonathan Cameron
@ 2015-01-11 13:52     ` Tirdea, Irina
  0 siblings, 0 replies; 27+ messages in thread
From: Tirdea, Irina @ 2015-01-11 13:52 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Dogaru, Vlad, Baluta, Daniel, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald



> -----Original Message-----
> From: Jonathan Cameron [mailto:jic23@kernel.org]
> Sent: 01 January, 2015 12:59
> To: Tirdea, Irina; linux-iio@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
> Subject: Re: [PATCH 7/8] iio: accel: mma9551: split driver to expose mma955x api
> 
> On 19/12/14 22:57, Irina Tirdea wrote:
> > Freescale has the MMA955xL family of devices that use the
> > same communication protocol (based on i2c messages):
> > http://www.freescale.com/files/sensors/doc/data_sheet/MMA955xL.pdf.
> >
> > To support more devices from this family, we need to split the
> > mma9551 driver so we can export the common functions that will
> > be used by other mma955x drivers.
> >
> > Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
> > Reviewed-by: Vlad Dogaru <vlad.dogaru@intel.com>
> Sorry, didn't get this far the other day.
> 
> Anyhow, other than a query on the depends and a suggestion that some
> documentation of locking semantics might be good (perhaps in some
> general kernel doc for the exported functions) - this looks good to
> me.
> 
> Jonathan
> > ---
> >  drivers/iio/accel/Kconfig        |    6 +
> >  drivers/iio/accel/Makefile       |    4 +-
> >  drivers/iio/accel/mma9551.c      |  443 +-------------------------------------
> >  drivers/iio/accel/mma9551_core.c |  443 ++++++++++++++++++++++++++++++++++++++
> >  drivers/iio/accel/mma9551_core.h |   74 +++++++
> >  5 files changed, 530 insertions(+), 440 deletions(-)
> >  create mode 100644 drivers/iio/accel/mma9551_core.c
> >  create mode 100644 drivers/iio/accel/mma9551_core.h
> >
> > diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
> > index d80616d..0600798 100644
> > --- a/drivers/iio/accel/Kconfig
> > +++ b/drivers/iio/accel/Kconfig
> > @@ -105,9 +105,15 @@ config KXCJK1013
> >  	  To compile this driver as a module, choose M here: the module will
> >  	  be called kxcjk-1013.
> >
> > +config MMA9551_CORE
> > +	tristate
> > +	depends on MMA9551
> Why depend here?  THis isn't visible (due to lack of help) and in theory
> an out of tree driver might want to use it.  Hence don't think you want this.

Right. Will remove this.

> > +
> >  config MMA9551
> >  	tristate "Freescale MMA9551L Intelligent Motion-Sensing Platform Driver"
> >  	depends on I2C
> > +	select MMA9551_CORE
> > +
> >  	help
> >  	  Say yes here to build support for the Freescale MMA9551L
> >  	  Intelligent Motion-Sensing Platform Driver.
> > diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
> > index de5b9cb..8105316 100644
> > --- a/drivers/iio/accel/Makefile
> > +++ b/drivers/iio/accel/Makefile
> > @@ -9,7 +9,9 @@ obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
> >  obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
> >  obj-$(CONFIG_KXSD9)	+= kxsd9.o
> >  obj-$(CONFIG_MMA8452)	+= mma8452.o
> > -obj-$(CONFIG_MMA9551)	+= mma9551.o
> > +
> > +obj-$(CONFIG_MMA9551_CORE)	+= mma9551_core.o
> > +obj-$(CONFIG_MMA9551)		+= mma9551.o
> >
> >  obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
> >  st_accel-y := st_accel_core.o
> > diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
> > index 34ee9d6..6031b5a 100644
> > --- a/drivers/iio/accel/mma9551.c
> > +++ b/drivers/iio/accel/mma9551.c
> > @@ -23,63 +23,13 @@
> >  #include <linux/iio/sysfs.h>
> >  #include <linux/iio/events.h>
> >  #include <linux/pm_runtime.h>
> > +#include "mma9551_core.h"
> >
> >  #define MMA9551_DRV_NAME		"mma9551"
> >  #define MMA9551_IRQ_NAME		"mma9551_event"
> >  #define MMA9551_GPIO_NAME		"mma9551_int"
> >  #define MMA9551_GPIO_COUNT		4
> >
> > -/* Applications IDs */
> > -#define MMA9551_APPID_VERSION		0x00
> > -#define MMA9551_APPID_GPIO		0x03
> > -#define MMA9551_APPID_AFE		0x06
> > -#define MMA9551_APPID_TILT		0x0B
> > -#define MMA9551_APPID_SLEEP_WAKE	0x12
> > -#define MMA9551_APPID_RESET		0x17
> > -#define MMA9551_APPID_NONE		0xff
> > -
> > -/* Command masks for mailbox write command */
> > -#define MMA9551_CMD_READ_VERSION_INFO	0x00
> > -#define MMA9551_CMD_READ_CONFIG		0x10
> > -#define MMA9551_CMD_WRITE_CONFIG	0x20
> > -#define MMA9551_CMD_READ_STATUS		0x30
> > -
[...]
> > diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c
> > new file mode 100644
> > index 0000000..cab481b
> > --- /dev/null
> > +++ b/drivers/iio/accel/mma9551_core.c
> > @@ -0,0 +1,443 @@
> > +/*
> > + * Common code for Freescale MMA955x Intelligent Sensor Platform drivers
> > + * Copyright (c) 2014, Intel Corporation.
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + */
> > +
> > +#include <linux/module.h>
> > +#include <linux/i2c.h>
> > +#include <linux/delay.h>
> > +#include <linux/iio/iio.h>
> > +#include <linux/pm_runtime.h>
> > +#include "mma9551_core.h"
> > +
> > +/* Command masks for mailbox write command */
> > +#define MMA9551_CMD_READ_VERSION_INFO	0x00
> > +#define MMA9551_CMD_READ_CONFIG		0x10
> > +#define MMA9551_CMD_WRITE_CONFIG	0x20
> > +#define MMA9551_CMD_READ_STATUS		0x30
> > +
> > +/* Mailbox read command */
> > +#define MMA9551_RESPONSE_COCO		BIT(7)
> > +
> > +/* Error-Status codes returned in mailbox read command */
> > +#define MMA9551_MCI_ERROR_NONE			0x00
> > +#define MMA9551_MCI_ERROR_PARAM			0x04
> > +#define MMA9551_MCI_INVALID_COUNT		0x19
> > +#define MMA9551_MCI_ERROR_COMMAND		0x1C
> > +#define MMA9551_MCI_ERROR_INVALID_LENGTH	0x21
> > +#define MMA9551_MCI_ERROR_FIFO_BUSY		0x22
> > +#define MMA9551_MCI_ERROR_FIFO_ALLOCATED	0x23
> > +#define MMA9551_MCI_ERROR_FIFO_OVERSIZE		0x24
> > +
> > +/* GPIO Application */
> > +#define MMA9551_GPIO_POL_MSB		0x08
> > +#define MMA9551_GPIO_POL_LSB		0x09
> > +
> > +/* Sleep/Wake application */
> > +#define MMA9551_SLEEP_CFG		0x06
> > +#define MMA9551_SLEEP_CFG_SNCEN		BIT(0)
> > +#define MMA9551_SLEEP_CFG_FLEEN		BIT(1)
> > +#define MMA9551_SLEEP_CFG_SCHEN		BIT(2)
> > +
> > +/* AFE application */
> > +#define MMA9551_AFE_X_ACCEL_REG		0x00
> > +#define MMA9551_AFE_Y_ACCEL_REG		0x02
> > +#define MMA9551_AFE_Z_ACCEL_REG		0x04
> > +
> > +/*
> > + * A response is composed of:
> > + * - control registers: MB0-3
> > + * - data registers: MB4-31
> > + *
> > + * A request is composed of:
> > + * - mbox to write to (always 0)
> > + * - control registers: MB1-4
> > + * - data registers: MB5-31
> > + */
> > +#define MMA9551_MAILBOX_CTRL_REGS	4
> > +#define MMA9551_MAX_MAILBOX_DATA_REGS	28
> > +#define MMA9551_MAILBOX_REGS		32
> > +
> > +#define MMA9551_I2C_READ_RETRIES	5
> > +#define MMA9551_I2C_READ_DELAY	50	/* us */
> > +
> > +struct mma9551_mbox_request {
> > +	u8 start_mbox;		/* Always 0. */
> > +	u8 app_id;
> > +	/*
> > +	 * See Section 5.3.1 of the MMA955xL Software Reference Manual.
> > +	 *
> > +	 * Bit 7: reserved, always 0
> > +	 * Bits 6-4: command
> > +	 * Bits 3-0: upper bits of register offset
> > +	 */
> > +	u8 cmd_off;
> > +	u8 lower_off;
> > +	u8 nbytes;
> > +	u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS - 1];
> > +} __packed;
> > +
> > +struct mma9551_mbox_response {
> > +	u8 app_id;
> > +	/*
> > +	 * See Section 5.3.3 of the MMA955xL Software Reference Manual.
> > +	 *
> > +	 * Bit 7: COCO
> > +	 * Bits 6-0: Error code.
> > +	 */
> > +	u8 coco_err;
> > +	u8 nbytes;
> > +	u8 req_bytes;
> > +	u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS];
> > +} __packed;
> > +
> > +static int mma9551_transfer(struct i2c_client *client,
> > +			    u8 app_id, u8 command, u16 offset,
> > +			    u8 *inbytes, int num_inbytes,
> > +			    u8 *outbytes, int num_outbytes)
> > +{
> > +	struct mma9551_mbox_request req;
> > +	struct mma9551_mbox_response rsp;
> > +	struct i2c_msg in, out;
> > +	u8 req_len, err_code;
> > +	int ret, retries;
> > +
> > +	if (offset >= 1 << 12) {
> > +		dev_err(&client->dev, "register offset too large\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	req_len = 1 + MMA9551_MAILBOX_CTRL_REGS + num_inbytes;
> > +	req.start_mbox = 0;
> > +	req.app_id = app_id;
> > +	req.cmd_off = command | (offset >> 8);
> > +	req.lower_off = offset;
> > +
> > +	if (command == MMA9551_CMD_WRITE_CONFIG)
> > +		req.nbytes = num_inbytes;
> > +	else
> > +		req.nbytes = num_outbytes;
> > +	if (num_inbytes)
> > +		memcpy(req.buf, inbytes, num_inbytes);
> > +
> > +	out.addr = client->addr;
> > +	out.flags = 0;
> > +	out.len = req_len;
> > +	out.buf = (u8 *)&req;
> > +
> > +	ret = i2c_transfer(client->adapter, &out, 1);
> > +	if (ret < 0) {
> > +		dev_err(&client->dev, "i2c write failed\n");
> > +		return ret;
> > +	}
> > +
> > +	retries = MMA9551_I2C_READ_RETRIES;
> > +	do {
> > +		udelay(MMA9551_I2C_READ_DELAY);
> > +
> > +		in.addr = client->addr;
> > +		in.flags = I2C_M_RD;
> > +		in.len = sizeof(rsp);
> > +		in.buf = (u8 *)&rsp;
> > +
> > +		ret = i2c_transfer(client->adapter, &in, 1);
> > +		if (ret < 0) {
> > +			dev_err(&client->dev, "i2c read failed\n");
> > +			return ret;
> > +		}
> > +
> > +		if (rsp.coco_err & MMA9551_RESPONSE_COCO)
> > +			break;
> > +	} while (--retries > 0);
> > +
> > +	if (retries == 0) {
> > +		dev_err(&client->dev,
> > +			"timed out while waiting for command response\n");
> > +		return -ETIMEDOUT;
> > +	}
> > +
> > +	if (rsp.app_id != app_id) {
> > +		dev_err(&client->dev,
> > +			"app_id mismatch in response got %02x expected %02x\n",
> > +			rsp.app_id, app_id);
> > +		return -EINVAL;
> > +	}
> > +
> > +	err_code = rsp.coco_err & ~MMA9551_RESPONSE_COCO;
> > +	if (err_code != MMA9551_MCI_ERROR_NONE) {
> > +		dev_err(&client->dev, "read returned error %x\n", err_code);
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (rsp.nbytes != rsp.req_bytes) {
> > +		dev_err(&client->dev,
> > +			"output length mismatch got %d expected %d\n",
> > +			rsp.nbytes, rsp.req_bytes);
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (num_outbytes)
> > +		memcpy(outbytes, rsp.buf, num_outbytes);
> > +
> > +	return 0;
> > +}
> > +
> > +int mma9551_read_config_byte(struct i2c_client *client, u8 app_id,
> > +			     u16 reg, u8 *val)
> > +{
> > +	return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
> > +				reg, NULL, 0, val, 1);
> > +}
> > +EXPORT_SYMBOL(mma9551_read_config_byte);
> > +
> > +int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
> > +			      u16 reg, u8 val)
> > +{
> > +	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
> > +				&val, 1, NULL, 0);
> > +}
> > +EXPORT_SYMBOL(mma9551_write_config_byte);
> > +
> > +int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
> > +			     u16 reg, u8 *val)
> > +{
> > +	return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
> > +				reg, NULL, 0, val, 1);
> > +}
> > +EXPORT_SYMBOL(mma9551_read_status_byte);
> > +
> > +int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
> > +			     u16 reg, u16 *val)
> > +{
> > +	int ret;
> > +	__be16 v;
> > +
> > +	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
> > +			       reg, NULL, 0, (u8 *)&v, 2);
> > +	*val = be16_to_cpu(v);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL(mma9551_read_status_word);
> > +
> I wonder if it's worth adding documentation to these functions - to point
> out that they should only be used under a lock. Might get forgotten as
> it's not readily apparent from the naming that locking is done externally
> rather than internally.
> 
Good point. Will add some kernel-doc comments to these functions.


> > +int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
> > +			       u16 reg, u8 mask, u8 val)
> > +{
> > +	int ret;
> > +	u8 tmp, orig;
> > +
> > +	ret = mma9551_read_config_byte(client, app_id, reg, &orig);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	tmp = orig & ~mask;
> > +	tmp |= val & mask;
> > +
> > +	if (tmp == orig)
> > +		return 0;
> > +
> > +	return mma9551_write_config_byte(client, app_id, reg, tmp);
> > +}
> > +EXPORT_SYMBOL(mma9551_update_config_bits);
[...]


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

* RE: [PATCH 8/8] iio: add driver for Freescale MMA9553
  2015-01-01 11:58   ` Jonathan Cameron
@ 2015-01-11 15:10     ` Tirdea, Irina
  2015-01-11 17:51       ` Jonathan Cameron
  0 siblings, 1 reply; 27+ messages in thread
From: Tirdea, Irina @ 2015-01-11 15:10 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Dogaru, Vlad, Baluta, Daniel, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald



> -----Original Message-----
> From: Jonathan Cameron [mailto:jic23@kernel.org]
> Sent: 01 January, 2015 13:58
> To: Tirdea, Irina; linux-iio@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
> Subject: Re: [PATCH 8/8] iio: add driver for Freescale MMA9553
> 
> On 19/12/14 22:57, Irina Tirdea wrote:
> > Add support for Freescale MMA9553L Intelligent Pedometer Platform.
> >
> > The following functionalities are supported:
> >  - step counter (counts the number of steps using a HW register)
> >  - step detector (generates an iio event at every step the user takes)
> >  - activity recognition (rest, walking, jogging, running)
> >  - speed
> >  - calories
> >  - distance
> >
> > To get accurate pedometer results, the user's height, weight and gender
> > need to be configured.
> >
> > The specifications can be downloaded from:
> > http://www.freescale.com/files/sensors/doc/ref_manual/MMA955xLSWRM.pdf
> > http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf
> >
> > Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
> A few bits an bobs beyond the interface discussions in the earlier patches
> in the series.
> 
> A nice looking driver on the whole, for a complex little device ;)

Thanks for the detailed review, Jonathan!

> 
> Jonathan
> > ---
> >  drivers/iio/accel/Kconfig        |   12 +-
> >  drivers/iio/accel/Makefile       |    1 +
> >  drivers/iio/accel/mma9551_core.c |   88 +++
> >  drivers/iio/accel/mma9551_core.h |   17 +-
> >  drivers/iio/accel/mma9553.c      | 1239 ++++++++++++++++++++++++++++++++++++++
> >  5 files changed, 1355 insertions(+), 2 deletions(-)
> >  create mode 100644 drivers/iio/accel/mma9553.c
> >
> > diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
> > index 0600798..afd50d0 100644
> > --- a/drivers/iio/accel/Kconfig
> > +++ b/drivers/iio/accel/Kconfig
> > @@ -107,7 +107,7 @@ config KXCJK1013
> >
> >  config MMA9551_CORE
> >  	tristate
> > -	depends on MMA9551
> > +	depends on MMA9551 || MMA9553
> >
> >  config MMA9551
> >  	tristate "Freescale MMA9551L Intelligent Motion-Sensing Platform Driver"
> > @@ -121,4 +121,14 @@ config MMA9551
> >  	  To compile this driver as a module, choose M here: the module
> >  	  will be called mma9551.
> >
> > +config MMA9553
> > +	tristate "Freescale MMA9553L Intelligent Pedometer Platform Driver"
> > +	depends on I2C
> > +	select MMA9551_CORE
> > +	help
> > +	  Say yes here to build support for the Freescale MMA9553L
> > +	  Intelligent Pedometer Platform Driver.
> > +
> > +	  To compile this driver as a module, choose M here: the module
> > +	  will be called mma9553.
> >  endmenu
> > diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
> > index 8105316..f815695 100644
> > --- a/drivers/iio/accel/Makefile
> > +++ b/drivers/iio/accel/Makefile
> > @@ -12,6 +12,7 @@ obj-$(CONFIG_MMA8452)	+= mma8452.o
> >
> >  obj-$(CONFIG_MMA9551_CORE)	+= mma9551_core.o
> >  obj-$(CONFIG_MMA9551)		+= mma9551.o
> > +obj-$(CONFIG_MMA9553)		+= mma9553.o
> >
> >  obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
> >  st_accel-y := st_accel_core.o
> > diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c
> > index cab481b..743a868 100644
> > --- a/drivers/iio/accel/mma9551_core.c
> > +++ b/drivers/iio/accel/mma9551_core.c
> > @@ -53,6 +53,11 @@
> >  #define MMA9551_AFE_Y_ACCEL_REG		0x02
> >  #define MMA9551_AFE_Z_ACCEL_REG		0x04
> >
> > +/* Reset/Suspend/Clear application */
> > +#define MMA9551_RSC_RESET		0x00
> > +#define MMA9551_RSC_OFFSET(mask)	(3 - (ffs(mask) - 1) / 8)
> > +#define MMA9551_RSC_VAL(mask)		(mask >> (((ffs(mask) - 1) / 8) * 8))
> > +
> >  /*
> >   * A response is composed of:
> >   * - control registers: MB0-3
> > @@ -215,6 +220,30 @@ int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
> >  }
> >  EXPORT_SYMBOL(mma9551_read_status_byte);
> >
> > +int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
> > +			    u16 reg, u16 *val)
> > +{
> > +	int ret;
> > +	__be16 v;
> > +
> > +	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
> > +			       reg, NULL, 0, (u8 *)&v, 2);
> > +	*val = be16_to_cpu(v);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL(mma9551_read_config_word);
> > +
> > +int mma9551_write_config_word(struct i2c_client *client, u8 app_id,
> > +			     u16 reg, u16 val)
> > +{
> > +	__be16 v = cpu_to_be16(val);
> > +
> > +	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
> > +				(u8 *) &v, 2, NULL, 0);
> > +}
> > +EXPORT_SYMBOL(mma9551_write_config_word);
> > +
> >  int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
> >  			     u16 reg, u16 *val)
> >  {
> > @@ -229,6 +258,56 @@ int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
> >  }
> >  EXPORT_SYMBOL(mma9551_read_status_word);
> >
> > +int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
> > +			     u16 reg, u8 len, u16 *buf)
> > +{
> > +	int ret, i;
> > +	int len_words = len / sizeof(u16);
> > +	__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
> > +
> > +	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
> > +			       reg, NULL, 0, (u8 *) be_buf, len);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	for (i = 0; i < len_words; i++)
> > +		buf[i] = be16_to_cpu(be_buf[i]);
> blank line
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(mma9551_read_config_words);
> > +
> > +int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
> > +			      u16 reg, u8 len, u16 *buf)
> > +{
> > +	int ret, i;
> > +	int len_words = len / sizeof(u16);
> > +	__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
> > +
> > +	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
> > +			       reg, NULL, 0, (u8 *) be_buf, len);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	for (i = 0; i < len_words; i++)
> > +		buf[i] = be16_to_cpu(be_buf[i]);
> blank line
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(mma9551_read_status_words);
> > +
> > +int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
> > +			       u16 reg, u8 len, u16 *buf)
> > +{
> > +	int i;
> > +	int len_words = len / sizeof(u16);
> > +	__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
> > +
> > +	for (i = 0; i < len_words; i++)
> > +		be_buf[i] = cpu_to_be16(buf[i]);
> blank line.
> > +	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG,
> > +				reg, (u8 *) be_buf, len, NULL, 0);
> > +}
> > +EXPORT_SYMBOL(mma9551_write_config_words);
> > +
> >  int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
> >  			       u16 reg, u8 mask, u8 val)
> >  {
> > @@ -437,6 +516,15 @@ int mma9551_read_accel_scale(int *val, int *val2)
> >  }
> >  EXPORT_SYMBOL(mma9551_read_accel_scale);
> >
> > +int mma9551_app_reset(struct i2c_client *client, u32 app_mask)
> > +{
> > +	return mma9551_write_config_byte(client, MMA9551_APPID_RCS,
> > +					 MMA9551_RSC_RESET +
> > +					 MMA9551_RSC_OFFSET(app_mask),
> > +					 MMA9551_RSC_VAL(app_mask));
> > +}
> > +EXPORT_SYMBOL(mma9551_app_reset);
> > +
> >  MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
> >  MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
> >  MODULE_LICENSE("GPL v2");
> > diff --git a/drivers/iio/accel/mma9551_core.h b/drivers/iio/accel/mma9551_core.h
> > index 0e1c9bb..19b6253 100644
> > --- a/drivers/iio/accel/mma9551_core.h
> > +++ b/drivers/iio/accel/mma9551_core.h
> > @@ -21,9 +21,13 @@
> >  #define MMA9551_APPID_AFE		0x06
> >  #define MMA9551_APPID_TILT		0x0B
> >  #define MMA9551_APPID_SLEEP_WAKE	0x12
> > -#define MMA9551_APPID_RESET		0x17
> > +#define MMA9551_APPID_PEDOMETER	        0x15
> > +#define MMA9551_APPID_RCS		0x17
> >  #define MMA9551_APPID_NONE		0xff
> >
> > +/* Reset/Suspend/Clear application app masks */
> > +#define MMA9551_RSC_PED			BIT(21)
> > +
> >  #define MMA9551_AUTO_SUSPEND_DELAY_MS	2000
> >
> >  enum mma9551_gpio_pin {
> > @@ -56,8 +60,18 @@ int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
> >  			      u16 reg, u8 val);
> >  int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
> >  			     u16 reg, u8 *val);
> > +int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
> > +			    u16 reg, u16 *val);
> > +int mma9551_write_config_word(struct i2c_client *client, u8 app_id,
> > +			     u16 reg, u16 val);
> >  int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
> >  			     u16 reg, u16 *val);
> > +int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
> > +			     u16 reg, u8 len, u16 *buf);
> > +int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
> > +			      u16 reg, u8 len, u16 *buf);
> > +int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
> > +			       u16 reg, u8 len, u16 *buf);
> >  int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
> >  			       u16 reg, u8 mask, u8 val);
> >  int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin,
> > @@ -70,5 +84,6 @@ int mma9551_read_accel_chan(struct i2c_client *client,
> >  			    const struct iio_chan_spec *chan,
> >  			    int *val, int *val2);
> >  int mma9551_read_accel_scale(int *val, int *val2);
> > +int mma9551_app_reset(struct i2c_client *client, u32 app_mask);
> >
> >  #endif /* _MMA9551_CORE_H_ */
> > diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
> > new file mode 100644
> > index 0000000..35b657d
> > --- /dev/null
> > +++ b/drivers/iio/accel/mma9553.c
> > @@ -0,0 +1,1239 @@
> > +/*
> > + * Freescale MMA9553L Intelligent Pedometer driver
> > + * Copyright (c) 2014, Intel Corporation.
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + */
> > +
> > +#include <linux/module.h>
> > +#include <linux/i2c.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/slab.h>
> > +#include <linux/acpi.h>
> > +#include <linux/gpio/consumer.h>
> > +#include <linux/iio/iio.h>
> > +#include <linux/iio/sysfs.h>
> > +#include <linux/iio/events.h>
> > +#include <linux/pm_runtime.h>
> > +#include "mma9551_core.h"
> > +
> > +#define MMA9553_DRV_NAME			"mma9553"
> > +#define MMA9553_IRQ_NAME			"mma9553_event"
> > +#define MMA9553_GPIO_NAME			"mma9553_int"
> > +
> > +/* Pedometer configuration registers (R/W) */
> > +#define MMA9553_CONF_SLEEPMIN		0x00
> > +#define MMA9553_CONF_SLEEPMAX		0x02
> > +#define MMA9553_CONF_SLEEPTHD		0x04
> > +#define MMA9553_CONF_WORD		GENMASK(15, 0)
> > +
> > +#define MMA9553_CONF_CONF_STEPLEN	0x06
> > +#define MMA9553_CONF_CONFIG		BIT(15)
> > +#define MMA9553_CONF_ACT_DBCNTM		BIT(14)
> > +#define MMA9553_CONF_SLP_DBCNTM		BIT(13)
> > +#define MMA9553_CONF_STEPLEN		GENMASK(7, 0)
> > +
> > +#define MMA9553_CONF_HEIGHT_WEIGHT	0x08
> > +#define MMA9553_CONF_HEIGHT		GENMASK(15, 8)
> > +#define MMA9553_CONF_WEIGHT		GENMASK(7, 0)
> > +
> > +#define MMA9553_CONF_FILTER		0x0A
> > +#define MMA9553_CONF_FILTSTEP		GENMASK(15, 8)
> > +#define MMA9553_CONF_MALE		BIT(7)
> > +#define MMA9553_CONF_FILTTIME		GENMASK(6, 0)
> > +
> > +#define MMA9553_CONF_SPEED_STEP		0x0C
> > +#define MMA9553_CONF_SPDPRD		GENMASK(15, 8)
> > +#define MMA9553_CONF_STEPCOALESCE	GENMASK(7, 0)
> > +
> > +#define MMA9553_CONF_ACTTHD		0x0E
> > +
> > +/* Pedometer status registers (R-only) */
> > +#define MMA9553_STATUS			0x00
> > +#define MMA9553_STATUS_MRGFL		BIT(15)
> > +#define MMA9553_STATUS_SUSPCHG		BIT(14)
> > +#define MMA9553_STATUS_STEPCHG		BIT(13)
> > +#define MMA9553_STATUS_ACTCHG		BIT(12)
> > +#define MMA9553_STATUS_SUSP		BIT(11)
> > +#define MMA9553_STATUS_ACTIVITY		(BIT(10) | BIT(9) | BIT(8))
> > +#define MMA9553_STATUS_VERSION		0x00FF
> > +
> > +#define MMA9553_STEPCNT			0x02
> > +#define MMA9553_DISTANCE		0x04
> > +#define MMA9553_SPEED			0x06
> > +#define MMA9553_CALORIES		0x08
> > +#define MMA9553_SLEEPCNT		0x0A
> > +
> > +/* Pedometer events are always mapped to this pin. */
> > +#define MMA9553_DEFAULT_GPIO_PIN	mma9551_gpio6
> > +#define MMA9553_DEFAULT_GPIO_POLARITY	0
> > +
> > +/* Bitnum used for gpio configuration = bit number in high status byte */
> > +#define STATUS_TO_BITNUM(bit)		(ffs(bit) - 9)
> > +
> > +#define MMA9553_DEFAULT_SAMPLE_RATE	30	/* Hz */
> > +
> > +/*
> > + * The internal activity level must be stable for ACTTHD samples before
> > + * ACTIVITY is updated.The ACTIVITY variable contains the current activity
> > + * level and is updated every time a step is detected or once a second
> > + * if there are no steps. So for 100% confidence level we need to have
> > + * the same activity level for about 30 sec.
> Not entirely sure I follow this argument on the confidence level.
> We do have period to directly in_activity_walking_thresh_rising_period etc
> to directly handle how long a condition has to be active before we fire an
> event.  Perhaps that would be better.  You'd then make the activity threshold
> read only (just return -EINVAL in the write) and set it at say 50% when read
> back.
Yes, this does not seem to fit in_activity_walking_thresh_rising_value at all and is a perfect fit for in_activity_walking_thresh_rising_period. Will change this.

> > + */
> > +#define MMA9553_MAX_ACTTHD		(MMA9553_DEFAULT_SAMPLE_RATE * 30)
> > +#define MMA9553_PERCENTAGE_TO_THD(prc) (((prc) * MMA9553_MAX_ACTTHD) / 100)
> > +#define MMA9553_THD_TO_PERCENTAGE(thr) (((thr) * 100) / MMA9553_MAX_ACTTHD)
> > +
> > +/*
> > + * Autonomously suspend pedometer if acceleration vector magnitude
> > + * is near 1g (4096 at 0.244 mg/LSB resolution) for 30 seconds.
> > + */
> > +#define MMA9553_DEFAULT_SLEEPMIN	3688	/* 0,9 g */
> > +#define MMA9553_DEFAULT_SLEEPMAX	4508	/* 1,1 g */
> > +#define MMA9553_DEFAULT_SLEEPTHD	(MMA9553_DEFAULT_SAMPLE_RATE * 30)
> > +
> > +#define MMA9553_CONFIG_RETRIES		2
> > +
> > +/* Status register - activity field  */
> > +enum activity_level {
> > +	ACTIVITY_UNKNOWN,
> > +	ACTIVITY_REST,
> > +	ACTIVITY_WALKING,
> > +	ACTIVITY_JOGGING,
> > +	ACTIVITY_RUNNING,
> > +};
> > +
> > +struct mma9553_event {
> > +	enum iio_chan_type type;
> > +	enum iio_modifier mod;
> > +	enum iio_event_direction dir;
> > +	bool enabled;
> > +};
> > +
> > +struct mma9553_conf_regs {
> > +	u16 sleepmin;
> > +	u16 sleepmax;
> > +	u16 sleepthd;
> > +	u16 config;
> > +	u16 height_weight;
> > +	u16 filter;
> > +	u16 speed_step;
> > +	u16 actthd;
> > +} __packed;
> > +
> > +struct mma9553_data {
> > +	struct i2c_client *client;
> > +	struct mutex mutex;
> > +	struct mma9553_conf_regs conf;
> > +	struct mma9553_event *events;
> > +	int num_events;
> > +	u8 gpio_bitnum;
> > +	/*
> > +	 * This is used for all features that depend on step count:
> > +	 * step count, distance, speed, calories.
> > +	 */
> > +	bool stepcnt_enabled;
> > +	u16 stepcnt;
> > +	u8 activity;
> > +};
> > +
> > +static u8 mma9553_get_bits(u16 val, u16 mask)
> > +{
> > +	return (val & mask) >> (ffs(mask) - 1);
> > +}
> > +
> > +static u16 mma9553_set_bits(u16 current_val, u16 val, u16 mask)
> > +{
> > +	return (current_val & ~mask) | (val << (ffs(mask) - 1));
> > +}
> > +
> > +static enum iio_modifier mma9553_activity_to_mod(enum activity_level activity)
> > +{
> > +	switch (activity) {
> > +	case ACTIVITY_RUNNING:
> > +		return IIO_MOD_RUNNING;
> > +	case ACTIVITY_JOGGING:
> > +		return IIO_MOD_JOGGING;
> > +	case ACTIVITY_WALKING:
> > +		return IIO_MOD_WALKING;
> > +	case ACTIVITY_REST:
> > +		return IIO_MOD_STILL;
> > +	case ACTIVITY_UNKNOWN:
> > +	default:
> > +		return IIO_NO_MOD;
> > +	}
> > +}
> > +
> > +static struct mma9553_event *mma9553_get_event(struct mma9553_data *data,
> > +					       enum iio_chan_type type,
> > +					       enum iio_modifier mod,
> > +					       enum iio_event_direction dir)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < data->num_events; i++)
> > +		if (data->events[i].type == type &&
> > +		    data->events[i].mod == mod &&
> > +		    data->events[i].dir == dir)
> > +			return &data->events[i];
> blank line.
> > +	return NULL;
> > +}
> > +
> > +static bool mma9553_is_any_event_enabled(struct mma9553_data *data,
> > +					 bool check_type,
> > +					 enum iio_chan_type type)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < data->num_events; i++)
> > +		if ((check_type && data->events[i].type == type &&
> > +		     data->events[i].enabled) ||
> > +		     (!check_type && data->events[i].enabled))
> > +			return true;
> > +	return false;
> > +}
> > +
> > +static int mma9553_set_config(struct mma9553_data *data, u16 reg,
> > +			      u16 *p_reg_val, u16 val, u16 mask)
> > +{
> > +	int ret, retries;
> > +	u16 reg_val, config;
> > +
> > +	reg_val = *p_reg_val;
> > +	if (val == mma9553_get_bits(reg_val, mask))
> > +		return 0;
> > +
> > +	reg_val = mma9553_set_bits(reg_val, val, mask);
> > +	ret = mma9551_write_config_word(data->client, MMA9551_APPID_PEDOMETER,
> > +					reg, reg_val);
> > +	if (ret < 0) {
> > +		dev_err(&data->client->dev,
> > +			"error writing config register 0x%x\n", reg);
> > +		return ret;
> > +	}
> > +
> > +	*p_reg_val = reg_val;
> > +
> > +	/* Reinitializes the pedometer with current configuration values */
> > +	config = mma9553_set_bits(data->conf.config, 1, MMA9553_CONF_CONFIG);
> > +
> > +	ret = mma9551_write_config_word(data->client, MMA9551_APPID_PEDOMETER,
> > +					MMA9553_CONF_CONF_STEPLEN, config);
> > +	if (ret < 0) {
> > +		dev_err(&data->client->dev,
> > +			"error writing config register 0x%x\n",
> > +			MMA9553_CONF_CONF_STEPLEN);
> > +		return ret;
> > +	}
> > +
> > +	retries = MMA9553_CONFIG_RETRIES;
> > +	do {
> > +		mma9551_sleep(MMA9553_DEFAULT_SAMPLE_RATE);
> > +		ret = mma9551_read_config_word(data->client,
> > +					       MMA9551_APPID_PEDOMETER,
> > +					       MMA9553_CONF_CONF_STEPLEN,
> > +					       &config);
> > +		if (ret < 0)
> > +			return ret;
> > +	} while (mma9553_get_bits(config, MMA9553_CONF_CONFIG) &&
> > +		 --retries > 0);
> > +
> > +	return 0;
> > +}
> > +
> > +static int mma9553_read_activity_stepcnt(struct mma9553_data *data,
> > +					 u8 *activity, u16 *stepcnt)
> > +{
> > +	u32 status_stepcnt;
> > +	u16 status;
> > +	int ret;
> > +
> > +	ret = mma9551_read_status_words(data->client, MMA9551_APPID_PEDOMETER,
> > +					MMA9553_STATUS, sizeof(u32),
> > +					(u16 *) &status_stepcnt);
> > +	if (ret < 0) {
> > +		dev_err(&data->client->dev,
> > +			"error reading status and stepcnt\n");
> > +		return ret;
> > +	}
> > +
> > +	status = status_stepcnt & MMA9553_CONF_WORD;
> > +	*activity = mma9553_get_bits(status, MMA9553_STATUS_ACTIVITY);
> > +	*stepcnt = status_stepcnt >> 16;
> > +	return 0;
> > +}
> > +
> > +static int mma9553_conf_gpio(struct mma9553_data *data)
> > +{
> > +	u8 bitnum = 0, appid = MMA9551_APPID_PEDOMETER;
> > +	int ret;
> > +	struct mma9553_event *ev_step_detect;
> > +	bool activity_enabled;
> > +
> > +	activity_enabled =
> > +	    mma9553_is_any_event_enabled(data, true, IIO_ACTIVITY);
> > +	ev_step_detect =
> > +	    mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
> > +
> > +	/*
> > +	 * If both step detector and activity are enabled, use the MRGFL bit.
> > +	 * This bit is the logical OR of the SUSPCHG, STEPCHG, and ACTCHG flags.
> > +	 */
> No brackets around single line statements (i.e. Drop all the {} below.)
Ok.

> > +	if (activity_enabled && ev_step_detect->enabled) {
> > +		bitnum = STATUS_TO_BITNUM(MMA9553_STATUS_MRGFL);
> > +	} else if (ev_step_detect->enabled) {
> > +		bitnum = STATUS_TO_BITNUM(MMA9553_STATUS_STEPCHG);
> > +	} else if (activity_enabled) {
> > +		bitnum = STATUS_TO_BITNUM(MMA9553_STATUS_ACTCHG);
> > +	} else {		/* Reset */
> > +		appid = MMA9551_APPID_NONE;
> > +	}
> > +
> > +	if (data->gpio_bitnum == bitnum)
> > +		return 0;
> > +
> > +	/* Save initial values for activity and stepcnt */
> > +	if (activity_enabled || ev_step_detect->enabled)
> > +		mma9553_read_activity_stepcnt(data, &data->activity,
> > +					      &data->stepcnt);
> > +
> > +	ret = mma9551_gpio_config(data->client,
> > +				  MMA9553_DEFAULT_GPIO_PIN,
> > +				  appid, bitnum, MMA9553_DEFAULT_GPIO_POLARITY);
> > +	if (ret < 0)
> > +		return ret;
> > +	data->gpio_bitnum = bitnum;
> blank line here.
Seems I am consistent in missing these blank lines ... :) I will fix all instances.

> > +	return 0;
> > +}
> > +
> > +static int mma9553_init(struct mma9553_data *data)
> > +{
> > +	int ret;
> > +
> > +	ret = mma9551_read_version(data->client);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/*
> > +	 * Read all the pedometer configuration registers. This is used as
> > +	 * a device identification command to differentiate the MMA9553L
> > +	 * from the MMA9550L.
> > +	 */
> > +	ret =
> > +	    mma9551_read_config_words(data->client, MMA9551_APPID_PEDOMETER,
> > +				      MMA9553_CONF_SLEEPMIN,
> > +				      sizeof(data->conf), (u16 *) &data->conf);
> > +	if (ret < 0) {
> > +		dev_err(&data->client->dev,
> > +			"device is not MMA9553L: failed to read cfg regs.\n");
> > +		return ret;
> > +	}
> > +
> > +
> > +	/* Reset gpio */
> > +	data->gpio_bitnum = -1;
> > +	ret = mma9553_conf_gpio(data);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = mma9551_app_reset(data->client, MMA9551_RSC_PED);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	/* Init config registers */
> > +	data->conf.sleepmin = MMA9553_DEFAULT_SLEEPMIN;
> > +	data->conf.sleepmax = MMA9553_DEFAULT_SLEEPMAX;
> > +	data->conf.sleepthd = MMA9553_DEFAULT_SLEEPTHD;
> > +	data->conf.config =
> > +	    mma9553_set_bits(data->conf.config, 1, MMA9553_CONF_CONFIG);
> > +	/*
> > +	 * Clear the activity debounce counter when the activity level changes,
> > +	 * so that the confidence level applies for any activity level.
> > +	 */
> > +	data->conf.config =
> > +	    mma9553_set_bits(data->conf.config, 1, MMA9553_CONF_ACT_DBCNTM);
> > +	ret =
> > +	    mma9551_write_config_words(data->client, MMA9551_APPID_PEDOMETER,
> > +				       MMA9553_CONF_SLEEPMIN,
> > +				       sizeof(data->conf), (u16 *) &data->conf);
> > +	if (ret < 0) {
> > +		dev_err(&data->client->dev,
> > +			"failed to write configuration registers.\n");
> > +		return ret;
> > +	}
> > +
> > +	return mma9551_set_device_state(data->client, true);
> > +}
> > +
> > +static int mma9553_read_raw(struct iio_dev *indio_dev,
> > +			    struct iio_chan_spec const *chan,
> > +			    int *val, int *val2, long mask)
> > +{
> > +	struct mma9553_data *data = iio_priv(indio_dev);
> > +	int ret;
> > +	u16 tmp;
> > +	u8 activity;
> > +	bool powered_on;
> > +
> > +	switch (mask) {
> > +	case IIO_CHAN_INFO_PROCESSED:
> > +		switch (chan->type) {
> > +		case IIO_STEPS:
> > +			/*
> > +			 * The HW only counts steps and other dependent
> > +			 * parameters (speed, distance, calories, activity)
> > +			 * if power is on (from enabling an event or the
> > +			 * step counter */
> > +			powered_on =
> > +			    mma9553_is_any_event_enabled(data, false, 0) ||
> > +			    data->stepcnt_enabled;
> > +			if (!powered_on)
> > +				return -EINVAL;
> > +			mutex_lock(&data->mutex);
> > +			ret = mma9551_read_status_word(data->client,
> > +						       MMA9551_APPID_PEDOMETER,
> > +						       MMA9553_STEPCNT, &tmp);
> > +			mutex_unlock(&data->mutex);
> > +			if (ret < 0)
> > +				return ret;
> > +			*val = tmp;
> > +			return IIO_VAL_INT;
> > +		case IIO_DISTANCE:
> > +			powered_on =
> > +			    mma9553_is_any_event_enabled(data, false, 0) ||
> > +			    data->stepcnt_enabled;
> > +			if (!powered_on)
> > +				return -EINVAL;
> > +			mutex_lock(&data->mutex);
> > +			ret = mma9551_read_status_word(data->client,
> > +						       MMA9551_APPID_PEDOMETER,
> > +						       MMA9553_DISTANCE, &tmp);
> > +			mutex_unlock(&data->mutex);
> > +			if (ret < 0)
> > +				return ret;
> > +			*val = tmp;
> > +			return IIO_VAL_INT;
> > +		case IIO_ACTIVITY:
> > +			powered_on =
> > +			    mma9553_is_any_event_enabled(data, false, 0) ||
> > +			    data->stepcnt_enabled;
> > +			if (!powered_on)
> > +				return -EINVAL;
> > +			mutex_lock(&data->mutex);
> > +			ret = mma9551_read_status_word(data->client,
> > +						       MMA9551_APPID_PEDOMETER,
> > +						       MMA9553_STATUS, &tmp);
> > +			mutex_unlock(&data->mutex);
> > +			if (ret < 0)
> > +				return ret;
> > +
> > +			activity =
> > +			    mma9553_get_bits(tmp, MMA9553_STATUS_ACTIVITY);
> > +
> > +			/*
> > +			 * The device does not support confidence value levels,
> > +			 * so we will always have 100% for current activity and
> > +			 * 0% for the others.
> > +			 */
> > +			if (chan->channel2 == mma9553_activity_to_mod(activity))
> > +				*val = 100;
> > +			else
> > +				*val = 0;
> > +			return IIO_VAL_INT;
> > +		default:
> > +			return -EINVAL;
> > +		}
> > +	case IIO_CHAN_INFO_RAW:
> > +		switch (chan->type) {
> > +		case IIO_SPEED:	/* m/h */
> > +			powered_on =
> > +			    mma9553_is_any_event_enabled(data, false, 0) ||
> > +			    data->stepcnt_enabled;
> > +			if (!powered_on)
> > +				return -EINVAL;
> Seems like there ought to be a better error code - but I can't find one ;)
Yes, EINVAL does not offer enough information to the user, but I could not find a better option either. I will print an error message as well to make this more clear to the user.

> > +			mutex_lock(&data->mutex);
> > +			ret = mma9551_read_status_word(data->client,
> > +						       MMA9551_APPID_PEDOMETER,
> > +						       MMA9553_SPEED, &tmp);
> > +			mutex_unlock(&data->mutex);
> > +			if (ret < 0)
> > +				return ret;
> > +			*val = tmp;
> > +			return IIO_VAL_INT;
> > +		case IIO_CALORIES:	/* Cal or kcal */
> > +			powered_on =
> > +			    mma9553_is_any_event_enabled(data, false, 0) ||
> > +			    data->stepcnt_enabled;
> > +			if (!powered_on)
> > +				return -EINVAL;
> > +			mutex_lock(&data->mutex);
> > +			ret = mma9551_read_status_word(data->client,
> > +						       MMA9551_APPID_PEDOMETER,
> > +						       MMA9553_CALORIES, &tmp);
> > +			mutex_unlock(&data->mutex);
> > +			if (ret < 0)
> > +				return ret;
> > +			*val = tmp;
> > +			return IIO_VAL_INT;
> > +		case IIO_ACCEL:
> > +			mutex_lock(&data->mutex);
> > +			ret = mma9551_read_accel_chan(data->client,
> > +						      chan, val, val2);
> > +			mutex_unlock(&data->mutex);
> > +			return ret;
> > +		default:
> > +			return -EINVAL;
> > +		}
> > +	case IIO_CHAN_INFO_SCALE:
> > +		switch (chan->type) {
> > +		case IIO_SPEED:	/* m/h to m/s */
> > +			*val = 0;
> > +			*val2 = 277;	/* 0.000277 */
> > +			return IIO_VAL_INT_PLUS_MICRO;
> > +		case IIO_CALORIES:	/* Cal or kcal to J */
> > +			*val = 4184;
> > +			return IIO_VAL_INT;
> > +		case IIO_ACCEL:
> > +			return mma9551_read_accel_scale(val, val2);
> > +		default:
> > +			return -EINVAL;
> > +		}
> > +	case IIO_CHAN_INFO_ENABLE:
> > +		*val = data->stepcnt_enabled;
> > +		return IIO_VAL_INT;
> > +	case IIO_CHAN_INFO_CALIBHEIGHT:
> > +		*val = mma9553_get_bits(data->conf.height_weight,
> > +					MMA9553_CONF_HEIGHT);
> > +		return IIO_VAL_INT;
> > +	case IIO_CHAN_INFO_CALIBWEIGHT:
> > +		*val = mma9553_get_bits(data->conf.height_weight,
> > +					MMA9553_CONF_WEIGHT);
> > +		return IIO_VAL_INT;
> > +	case IIO_CHAN_INFO_CALIBGENDER:
> > +		*val = mma9553_get_bits(data->conf.filter, MMA9553_CONF_MALE);
> > +		return IIO_VAL_INT;
> > +	case IIO_CHAN_INFO_OFFSET:
> > +		switch (chan->type) {
> > +		case IIO_STEPS:
> > +			*val = mma9553_get_bits(data->conf.filter,
> > +						MMA9553_CONF_FILTSTEP);
> > +			return IIO_VAL_INT;
> > +		default:
> > +			return -EINVAL;
> > +		}
> > +	case IIO_CHAN_INFO_INT_TIME:
> > +		switch (chan->type) {
> > +		case IIO_STEPS:
> > +			*val = mma9553_get_bits(data->conf.filter,
> > +						MMA9553_CONF_FILTTIME);
> > +			return IIO_VAL_INT;
> > +		case IIO_SPEED:
> > +			*val = mma9553_get_bits(data->conf.speed_step,
> > +						MMA9553_CONF_SPDPRD);
> > +			return IIO_VAL_INT;
> > +		default:
> > +			return -EINVAL;
> > +		}
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static int mma9553_write_raw(struct iio_dev *indio_dev,
> > +			     struct iio_chan_spec const *chan,
> > +			     int val, int val2, long mask)
> > +{
> > +	struct mma9553_data *data = iio_priv(indio_dev);
> > +	int ret;
> > +
> > +	switch (mask) {
> > +	case IIO_CHAN_INFO_ENABLE:
> > +		if (data->stepcnt_enabled == !!val)
> > +			return 0;
> > +		mutex_lock(&data->mutex);
> > +		ret = mma9551_set_power_state(data->client, val);
> > +		if (ret < 0) {
> > +			mutex_unlock(&data->mutex);
> > +			return ret;
> > +		}
> > +		data->stepcnt_enabled = val;
> > +		mutex_unlock(&data->mutex);
> > +		return 0;
> > +	case IIO_CHAN_INFO_CALIBHEIGHT:
> > +		if (val < 0 || val > 255)
> > +			return -EINVAL;
> > +		mutex_lock(&data->mutex);
> > +		ret = mma9553_set_config(data,
> > +					 MMA9553_CONF_HEIGHT_WEIGHT,
> > +					 &data->conf.height_weight,
> > +					 val, MMA9553_CONF_HEIGHT);
> > +		mutex_unlock(&data->mutex);
> > +		return ret;
> > +	case IIO_CHAN_INFO_CALIBWEIGHT:
> > +		if (val < 0 || val > 255)
> > +			return -EINVAL;
> > +		mutex_lock(&data->mutex);
> > +		ret = mma9553_set_config(data,
> > +					 MMA9553_CONF_HEIGHT_WEIGHT,
> > +					 &data->conf.height_weight,
> > +					 val, MMA9553_CONF_WEIGHT);
> > +		mutex_unlock(&data->mutex);
> > +		return ret;
> > +	case IIO_CHAN_INFO_CALIBGENDER:
> As commented before - no magic numbers.  Hence this will need to use
> the extended interface with enums etc.
Yes, will replace this with ext_info.

> > +		/* Gender can only be 0(female) or 1(male) */
> > +		if ((val != 0) && (val != 1))
> > +			return -EINVAL;
> > +		mutex_lock(&data->mutex);
> > +		ret = mma9553_set_config(data, MMA9553_CONF_FILTER,
> > +					 &data->conf.filter, val,
> > +					 MMA9553_CONF_MALE);
> > +		mutex_unlock(&data->mutex);
> > +		return ret;
> > +	case IIO_CHAN_INFO_OFFSET:
> > +		switch (chan->type) {
> > +		case IIO_STEPS:
> This seems like an ususual use of offset.
> A quick look is this is about rejection of steps based on the fact the
> user doesn't seem to be walking.  It's not an offset that I can see.
> Probably needs a completely new interface.
> 
> Off the top of my head
> 
> in_steps_filter_outliers_num
> and
> in_steps_filter_outliers_period
> 
> err. Not that keen on this though but will let you propose something better!
This sounds good. I would use in_steps_filter_outliers_thresh instead of in_steps_filter_outliers_num to make it more clear we filter steps below a threshold.

> > +			/*
> > +			 * Set to 0 to disable step filtering. If the value
> > +			 * specified is greater than 6, then 6 will be used.
> > +			 */
> > +			if (val < 0)
> > +				return -EINVAL;
> > +			if (val > 6)
> > +				val = 6;
> > +			mutex_lock(&data->mutex);
> > +			ret = mma9553_set_config(data, MMA9553_CONF_FILTER,
> > +						 &data->conf.filter, val,
> > +						 MMA9553_CONF_FILTSTEP);
> > +			mutex_unlock(&data->mutex);
> > +			return ret;
> > +		default:
> > +			return -EINVAL;
> > +		}
> > +	case IIO_CHAN_INFO_INT_TIME:
> > +		switch (chan->type) {
> > +		case IIO_STEPS:
> > +			if (val < 0 || val > 127)
> > +				return -EINVAL;
> > +			mutex_lock(&data->mutex);
> > +			ret = mma9553_set_config(data, MMA9553_CONF_FILTER,
> > +						 &data->conf.filter, val,
> > +						 MMA9553_CONF_FILTTIME);
> This isn't an integration time really either...  Hence need a new element
> for this.
Yes, will use in_steps_filter_outliers_period mentioned above.

> > +			mutex_unlock(&data->mutex);
> > +			return ret;
> > +		case IIO_SPEED:
> > +			/*
> > +			 * If set to a value greater than 5, then 5 will be
> > +			 * used. Warning: Do not set SPDPRD to 0 or 1 as
> > +			 * this may cause undesirable behavior.
> > +			 */
> I suppose this one is an integration time (be in it a different fashion to
> normal!)
> > +			if (val < 2)
> > +				return -EINVAL;
> > +			if (val > 5)
> > +				val = 5;
> > +			mutex_lock(&data->mutex);
> > +			ret = mma9553_set_config(data, MMA9553_CONF_SPEED_STEP,
> > +						 &data->conf.speed_step, val,
> > +						 MMA9553_CONF_SPDPRD);
> > +			mutex_unlock(&data->mutex);
> > +			return ret;
> > +		default:
> > +			return -EINVAL;
> > +		}
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static int mma9553_read_event_config(struct iio_dev *indio_dev,
> > +				     const struct iio_chan_spec *chan,
> > +				     enum iio_event_type type,
> > +				     enum iio_event_direction dir)
> > +{
> > +
> > +	struct mma9553_data *data = iio_priv(indio_dev);
> > +	struct mma9553_event *event;
> > +
> > +	event = mma9553_get_event(data, chan->type, chan->channel2, dir);
> > +	if (!event)
> > +		return -EINVAL;
> blank line here prefered. (or someone one will send me a patch adding
> one within the week!)
> > +	return event->enabled;
> > +}
> > +
> > +static int mma9553_write_event_config(struct iio_dev *indio_dev,
> > +				      const struct iio_chan_spec *chan,
> > +				      enum iio_event_type type,
> > +				      enum iio_event_direction dir, int state)
> > +{
> > +	struct mma9553_data *data = iio_priv(indio_dev);
> > +	struct mma9553_event *event;
> > +	int ret;
> > +
> > +	event = mma9553_get_event(data, chan->type, chan->channel2, dir);
> > +	if (!event)
> > +		return -EINVAL;
> > +
> > +	if (event->enabled == state)
> > +		return 0;
> > +
> > +	mutex_lock(&data->mutex);
> > +
> > +	ret = mma9551_set_power_state(data->client, state);
> > +	if (ret < 0)
> > +		goto out;
> > +	event->enabled = state;
> > +
> > +	ret = mma9553_conf_gpio(data);
> > +	if (ret < 0)
> > +		goto err_conf_gpio;
> > +
> > +	goto out;
> Normal code style in IIO at least would be to have a separate return
> here (with unlocking) rather than jumping to the end of the error
> handling. Bit easier to follow.
Ok, will change this.

> > +
> > +err_conf_gpio:
> > +	if (state) {
> > +		event->enabled = false;
> > +		mma9551_set_power_state(data->client, false);
> > +	}
> > +out:
> > +	mutex_unlock(&data->mutex);
> > +	return ret;
> > +}
> > +
> > +static int mma9553_read_event_value(struct iio_dev *indio_dev,
> > +				    const struct iio_chan_spec *chan,
> > +				    enum iio_event_type type,
> > +				    enum iio_event_direction dir,
> > +				    enum iio_event_info info,
> > +				    int *val, int *val2)
> > +{
> > +	struct mma9553_data *data = iio_priv(indio_dev);
> > +	int prc;
> > +
> > +	*val2 = 0;
> > +	switch (info) {
> > +	case IIO_EV_INFO_VALUE:
> > +		switch (chan->type) {
> > +		case IIO_ACTIVITY:
> > +			prc = MMA9553_THD_TO_PERCENTAGE(data->conf.actthd);
> > +			if (dir == IIO_EV_DIR_RISING)
> > +				*val = prc;
> > +			else if (dir == IIO_EV_DIR_FALLING)
> > +				*val = 100 - prc;
> > +			else
> > +				return -EINVAL;
> > +			return IIO_VAL_INT;
> > +		default:
> > +			return -EINVAL;
> > +		}
> > +	case IIO_EV_INFO_PERIOD:
> > +		switch (chan->type) {
> > +		case IIO_STEPS:
> > +			*val = mma9553_get_bits(data->conf.speed_step,
> > +						MMA9553_CONF_STEPCOALESCE);
> > +			return IIO_VAL_INT;
> > +		default:
> > +			return -EINVAL;
> > +		}
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static int mma9553_write_event_value(struct iio_dev *indio_dev,
> > +				     const struct iio_chan_spec *chan,
> > +				     enum iio_event_type type,
> > +				     enum iio_event_direction dir,
> > +				     enum iio_event_info info,
> > +				     int val, int val2)
> > +{
> > +	struct mma9553_data *data = iio_priv(indio_dev);
> > +	int prc, thd;
> > +	int ret;
> > +
> > +	switch (info) {
> > +	case IIO_EV_INFO_VALUE:
> > +		switch (chan->type) {
> > +		case IIO_ACTIVITY:
> > +			if (val < 0 || val > 100)
> > +				return -EINVAL;
> > +
> > +			if (dir == IIO_EV_DIR_RISING)
> > +				prc = val;
> > +			else if (dir == IIO_EV_DIR_FALLING)
> > +				prc = 100 - val;
> > +			else
> > +				return -EINVAL;
> > +			thd = MMA9553_PERCENTAGE_TO_THD(prc);
> > +
> > +			mutex_lock(&data->mutex);
> > +			ret = mma9553_set_config(data, MMA9553_CONF_ACTTHD,
> > +						 &data->conf.actthd, thd,
> > +						 MMA9553_CONF_WORD);
> As commented above. this is a threshold on how long an activity is true
> - not the direct confidence interval - so I'd suggest handling it as as
> the event period, not threshold.
> > +			mutex_unlock(&data->mutex);
> > +			return ret;
> > +		default:
> > +			return -EINVAL;
> > +		}
> > +	case IIO_EV_INFO_PERIOD:
> > +		switch (chan->type) {
> > +		case IIO_STEPS:
> > +			if (val < 0 || val > 255)
> > +				return -EINVAL;
> > +			mutex_lock(&data->mutex);
> > +			ret = mma9553_set_config(data, MMA9553_CONF_SPEED_STEP,
> > +						 &data->conf.speed_step, val,
> > +						 MMA9553_CONF_STEPCOALESCE);
> So this makes it fire every N steps?  Kind of nice, but not quite what period
> is usually used for.  We have talked about having an absolute change
> (rather than ROC) event type before - (requires a change of N and doesn't care
> how long it took to happen).  Perhaps that makes sense here rather than
> an instance event and a period?
Considering the stepcoalesce option, a change event does make more sense. I will add IIO_CHANGE and use it instead.

Adding IIO_CHANGE event type will make IIO_INSTANCE redundant (since instance is change with a value of 1). I know once an interface is introduced it cannot be changed, but since nobody is using IIO_INSTANCE could we remove it?

> 
> > +			mutex_unlock(&data->mutex);
> > +			return ret;
> > +		default:
> > +			return -EINVAL;
> > +		}
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static const struct iio_event_spec mma9553_step_event = {
> > +	.type = IIO_EV_TYPE_INSTANCE,
> > +	.dir = IIO_EV_DIR_NONE,
> > +	.mask_separate = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_PERIOD),
> > +};
> > +
> > +static const struct iio_event_spec mma9553_activity_events[] = {
> > +	{
> > +		.type = IIO_EV_TYPE_THRESH,
> > +		.dir = IIO_EV_DIR_RISING,
> > +		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
> > +				 BIT(IIO_EV_INFO_VALUE),
> > +	 },
> > +	{
> > +		.type = IIO_EV_TYPE_THRESH,
> > +		.dir = IIO_EV_DIR_FALLING,
> > +		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
> > +				 BIT(IIO_EV_INFO_VALUE),
> > +	},
> > +};
> > +
> > +#define MMA9553_PEDOMETER_CHANNEL(_type, _mask) {		\
> > +	.type = _type,						\
> > +	.info_mask_separate = BIT(IIO_CHAN_INFO_ENABLE)      |	\
> > +			      BIT(IIO_CHAN_INFO_CALIBHEIGHT) |	\
> > +			      BIT(IIO_CHAN_INFO_CALIBGENDER) |	\
> > +			      _mask,				\
> > +}
> > +
> > +#define MMA9553_ACTIVITY_CHANNEL(_chan2) {				\
> > +	.type = IIO_ACTIVITY,						\
> > +	.modified = 1,							\
> > +	.channel2 = _chan2,						\
> > +	.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),		\
> > +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT) |	\
> > +				    BIT(IIO_CHAN_INFO_CALIBGENDER),	\
> > +	.event_spec = mma9553_activity_events,				\
> > +	.num_event_specs = ARRAY_SIZE(mma9553_activity_events),		\
> > +}
> > +
> > +static const struct iio_chan_spec mma9553_channels[] = {
> > +	MMA9551_ACCEL_CHANNEL(IIO_MOD_X),
> > +	MMA9551_ACCEL_CHANNEL(IIO_MOD_Y),
> > +	MMA9551_ACCEL_CHANNEL(IIO_MOD_Z),
> > +
> > +	{
> > +		.type = IIO_STEPS,
> > +		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
> > +				      BIT(IIO_CHAN_INFO_ENABLE) |
> > +				      BIT(IIO_CHAN_INFO_OFFSET) |
> > +				      BIT(IIO_CHAN_INFO_INT_TIME),
> > +		.event_spec = &mma9553_step_event,
> > +		.num_event_specs = 1,
> > +	},
> > +
> > +	MMA9553_PEDOMETER_CHANNEL(IIO_DISTANCE, BIT(IIO_CHAN_INFO_PROCESSED)),
> > +	MMA9553_PEDOMETER_CHANNEL(IIO_SPEED, BIT(IIO_CHAN_INFO_RAW) |
> > +				  BIT(IIO_CHAN_INFO_SCALE) |
> > +				  BIT(IIO_CHAN_INFO_INT_TIME)),
> > +	MMA9553_PEDOMETER_CHANNEL(IIO_CALORIES, BIT(IIO_CHAN_INFO_RAW) |
> > +				  BIT(IIO_CHAN_INFO_SCALE) |
> > +				  BIT(IIO_CHAN_INFO_CALIBWEIGHT)),
> > +
> > +	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_RUNNING),
> > +	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_JOGGING),
> > +	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_WALKING),
> > +	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_STILL),
> > +};
> > +
> > +static const struct iio_info mma9553_info = {
> > +	.driver_module = THIS_MODULE,
> > +	.read_raw = mma9553_read_raw,
> > +	.write_raw = mma9553_write_raw,
> > +	.read_event_config = mma9553_read_event_config,
> > +	.write_event_config = mma9553_write_event_config,
> > +	.read_event_value = mma9553_read_event_value,
> > +	.write_event_value = mma9553_write_event_value,
> > +};
> > +
> Only one copy of this?  We don't want to prevent people having more
> than one of these devices attached to a given machine.
> Hence by all means have a default version of this but then
> clone it into the mma9553_data structure for manipulation.
> Or have a mached array of booleans in there (same indexes)
> to use for the "enabled"s.
> 
Will fix this.

> > +static struct mma9553_event mma9553_events[] = {
> > +	{
> > +		.type = IIO_STEPS,
> > +		.mod = IIO_NO_MOD,
> > +		.dir = IIO_EV_DIR_NONE,
> > +		.enabled = false,
> > +	},
> > +	{
> > +		.type = IIO_ACTIVITY,
> > +		.mod = IIO_MOD_STILL,
> > +		.dir = IIO_EV_DIR_RISING,
> > +		.enabled = false,
> > +	},
> > +	{
> > +		.type = IIO_ACTIVITY,
> > +		.mod = IIO_MOD_STILL,
> > +		.dir = IIO_EV_DIR_FALLING,
> > +		.enabled = false,
> > +	},
> > +	{
> > +		.type = IIO_ACTIVITY,
> > +		.mod = IIO_MOD_WALKING,
> > +		.dir = IIO_EV_DIR_RISING,
> > +		.enabled = false,
> > +	},
> > +	{
> > +		.type = IIO_ACTIVITY,
> > +		.mod = IIO_MOD_WALKING,
> > +		.dir = IIO_EV_DIR_FALLING,
> > +		.enabled = false,
> > +	},
> > +	{
> > +		.type = IIO_ACTIVITY,
> > +		.mod = IIO_MOD_JOGGING,
> > +		.dir = IIO_EV_DIR_RISING,
> > +		.enabled = false,
> > +	},
> > +	{
> > +		.type = IIO_ACTIVITY,
> > +		.mod = IIO_MOD_JOGGING,
> > +		.dir = IIO_EV_DIR_FALLING,
> > +		.enabled = false,
> > +	},
> > +	{
> > +		.type = IIO_ACTIVITY,
> > +		.mod = IIO_MOD_RUNNING,
> > +		.dir = IIO_EV_DIR_RISING,
> > +		.enabled = false,
> > +	},
> > +	{
> > +		.type = IIO_ACTIVITY,
> > +		.mod = IIO_MOD_RUNNING,
> > +		.dir = IIO_EV_DIR_FALLING,
> > +		.enabled = false,
> > +	},
> > +};
> > +
> > +static irqreturn_t mma9553_irq_handler(int irq, void *private)
> > +{
> > +	/*
> > +	 * Since we only configure the interrupt pin when an
> > +	 * event is enabled, we are sure we have at least
> > +	 * one event enabled at this point.
> > +	 */
> IIRC simply not supplyling the top half handler has the same effect as
> this (though then you don't have anywhere to put the comment!)
> Actually - I'd be tempted to grab and stash a timestamp in here to
> increase the precision of you step timing etc.
Initially I used a NULL pointer instead of mma9553_irq_handler in devm_request_threaded_irq, but the registration failed with "Threaded irq requested with handler=NULL and !ONESHOT".
However, it is better to grab the timestamp anyway so I will do that here.

> > +	return IRQ_WAKE_THREAD;
> > +}
> > +
> > +static irqreturn_t mma9553_event_handler(int irq, void *private)
> > +{
> > +	struct iio_dev *indio_dev = private;
> > +	struct mma9553_data *data = iio_priv(indio_dev);
> > +	u16 stepcnt;
> > +	u8 activity;
> > +	struct mma9553_event *ev_activity, *ev_prev_activity, *ev_step_detect;
> > +	int ret;
> > +
> > +	mutex_lock(&data->mutex);
> > +	ret = mma9553_read_activity_stepcnt(data, &activity, &stepcnt);
> > +	if (ret < 0) {
> > +		mutex_unlock(&data->mutex);
> > +		return IRQ_HANDLED;
> > +	}
> > +
> > +	ev_prev_activity =
> > +	    mma9553_get_event(data, IIO_ACTIVITY,
> > +			      mma9553_activity_to_mod(data->activity),
> > +			      IIO_EV_DIR_FALLING);
> > +	ev_activity =
> > +	    mma9553_get_event(data, IIO_ACTIVITY,
> > +			      mma9553_activity_to_mod(activity),
> > +			      IIO_EV_DIR_RISING);
> > +	ev_step_detect =
> > +	    mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
> > +
> > +	if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) {
> > +		data->stepcnt = stepcnt;
> > +		iio_push_event(indio_dev,
> > +			       IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
> > +			       IIO_EV_DIR_NONE, IIO_EV_TYPE_INSTANCE, 0, 0, 0),
> > +			       iio_get_time_ns());
> Worth grabbing the timestamp earlier than this for precision reasons?
> > +	}
> > +
> > +	if (activity != data->activity) {
> > +		data->activity = activity;
> > +		/* ev_activity can be NULL if activity == ACTIVITY_UNKNOWN */
> > +		if (ev_prev_activity && ev_prev_activity->enabled)
> > +			iio_push_event(indio_dev,
> > +				       IIO_EVENT_CODE(IIO_ACTIVITY, 0,
> > +				       ev_prev_activity->mod,
> > +				       IIO_EV_DIR_FALLING,
> > +				       IIO_EV_TYPE_THRESH, 0, 0, 0),
> > +				       iio_get_time_ns());
> > +
> > +		if (ev_activity && ev_activity->enabled)
> > +			iio_push_event(indio_dev,
> > +				       IIO_EVENT_CODE(IIO_ACTIVITY, 0,
> > +				       ev_activity->mod,
> > +				       IIO_EV_DIR_RISING,
> > +				       IIO_EV_TYPE_THRESH, 0, 0, 0),
> > +				       iio_get_time_ns());
> > +	}
> > +	mutex_unlock(&data->mutex);
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static int mma9553_gpio_probe(struct i2c_client *client)
> > +{
> > +	struct device *dev;
> > +	struct gpio_desc *gpio;
> > +	int ret;
> > +
> > +	if (!client)
> > +		return -EINVAL;
> > +
> > +	dev = &client->dev;
> > +
> > +	/* data ready gpio interrupt pin */
> > +	gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0);
> > +	if (IS_ERR(gpio)) {
> > +		dev_err(dev, "acpi gpio get index failed\n");
> > +		return PTR_ERR(gpio);
> > +	}
> > +
> > +	ret = gpiod_direction_input(gpio);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = gpiod_to_irq(gpio);
> > +
> > +	dev_dbg(dev, "gpio resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
> > +
> > +	return ret;
> > +}
> > +
> > +static const char *mma9553_match_acpi_device(struct device *dev)
> > +{
> > +	const struct acpi_device_id *id;
> > +
> > +	id = acpi_match_device(dev->driver->acpi_match_table, dev);
> > +	if (!id)
> > +		return NULL;
> > +
> > +	return dev_name(dev);
> > +}
> > +
> > +static int mma9553_probe(struct i2c_client *client,
> > +			 const struct i2c_device_id *id)
> > +{
> > +	struct mma9553_data *data;
> > +	struct iio_dev *indio_dev;
> > +	const char *name = NULL;
> > +	int ret;
> > +
> > +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> > +	if (!indio_dev)
> > +		return -ENOMEM;
> > +
> > +	data = iio_priv(indio_dev);
> > +	i2c_set_clientdata(client, indio_dev);
> > +	data->client = client;
> > +
> > +	if (id)
> > +		name = id->name;
> > +	else if (ACPI_HANDLE(&client->dev))
> > +		name = mma9553_match_acpi_device(&client->dev);
> > +	else
> Interesting to note the original driver doesn't have this else.  Worth
> checking?
There was a similar check in the initial driver (it checked for name == NULL instead) that somehow got removed in a later version.
I could add the check in mma9551 as well, but I am not sure on what is the proper way to handle this.
There is an ongoing discussion on this: http://www.spinics.net/lists/linux-iio/msg16231.html.
I would rather for this to be cleared out and send a separate patch to fix both drivers if needed.

> > +		return -ENOSYS;
> > +
> > +	mutex_init(&data->mutex);
> > +	data->events = mma9553_events;
> > +	data->num_events = ARRAY_SIZE(mma9553_events);
> > +
> > +	ret = mma9553_init(data);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	indio_dev->dev.parent = &client->dev;
> > +	indio_dev->channels = mma9553_channels;
> > +	indio_dev->num_channels = ARRAY_SIZE(mma9553_channels);
> > +	indio_dev->name = name;
> > +	indio_dev->modes = INDIO_DIRECT_MODE;
> > +	indio_dev->info = &mma9553_info;
> > +
> > +	if (client->irq < 0)
> > +		client->irq = mma9553_gpio_probe(client);
> > +
> So this time we just have a single irq.  That makes life simpler!
Yes, mma9553 provides the option to combine all its interrupts in one status bit (while mma9551 does not).

> > +	if (client->irq >= 0) {
> > +		ret = devm_request_threaded_irq(&client->dev, client->irq,
> > +						mma9553_irq_handler,
> > +						mma9553_event_handler,
> > +						IRQF_TRIGGER_RISING,
> > +						MMA9553_IRQ_NAME, indio_dev);
> > +		if (ret < 0) {
> > +			dev_err(&client->dev, "request irq %d failed\n",
> > +				client->irq);
> > +			goto out_poweroff;
> > +		}
> > +
> > +	}
> > +
> > +	ret = iio_device_register(indio_dev);
> > +	if (ret < 0) {
> > +		dev_err(&client->dev, "unable to register iio device\n");
> > +		goto out_poweroff;
> > +	}
> > +
> > +	ret = pm_runtime_set_active(&client->dev);
> > +	if (ret < 0)
> > +		goto out_iio_unregister;
> > +
> > +	pm_runtime_enable(&client->dev);
> > +	pm_runtime_set_autosuspend_delay(&client->dev,
> > +					 MMA9551_AUTO_SUSPEND_DELAY_MS);
> > +	pm_runtime_use_autosuspend(&client->dev);
> > +
> > +	dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
> > +	return 0;
> > +
> > +out_iio_unregister:
> > +	iio_device_unregister(indio_dev);
> > +out_poweroff:
> > +	mma9551_set_device_state(client, false);
> > +	return ret;
> > +}
> > +
> > +static int mma9553_remove(struct i2c_client *client)
> > +{
> > +	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> > +	struct mma9553_data *data = iio_priv(indio_dev);
> > +
> > +	pm_runtime_disable(&client->dev);
> > +	pm_runtime_set_suspended(&client->dev);
> > +	pm_runtime_put_noidle(&client->dev);
> > +
> > +	iio_device_unregister(indio_dev);
> > +	mutex_lock(&data->mutex);
> > +	mma9551_set_device_state(data->client, false);
> > +	mutex_unlock(&data->mutex);
> > +
> > +	return 0;
> > +}
> > +
> > +#ifdef CONFIG_PM
> > +static int mma9553_runtime_suspend(struct device *dev)
> > +{
> > +	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> > +	struct mma9553_data *data = iio_priv(indio_dev);
> > +	int ret;
> > +
> > +	mutex_lock(&data->mutex);
> > +	ret = mma9551_set_device_state(data->client, false);
> > +	mutex_unlock(&data->mutex);
> > +	if (ret < 0) {
> > +		dev_err(&data->client->dev, "powering off device failed\n");
> > +		return -EAGAIN;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int mma9553_runtime_resume(struct device *dev)
> > +{
> > +	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> > +	struct mma9553_data *data = iio_priv(indio_dev);
> > +	int ret;
> > +
> > +	ret = mma9551_set_device_state(data->client, true);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	mma9551_sleep(MMA9553_DEFAULT_SAMPLE_RATE);
> > +	return 0;
> > +}
> > +#endif
> > +
> > +#ifdef CONFIG_PM_SLEEP
> > +static int mma9553_suspend(struct device *dev)
> > +{
> > +	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> > +	struct mma9553_data *data = iio_priv(indio_dev);
> > +	int ret;
> > +
> > +	mutex_lock(&data->mutex);
> > +	ret = mma9551_set_device_state(data->client, false);
> > +	mutex_unlock(&data->mutex);
> > +
> > +	return ret;
> > +}
> > +
> > +static int mma9553_resume(struct device *dev)
> > +{
> > +	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> > +	struct mma9553_data *data = iio_priv(indio_dev);
> > +	int ret;
> > +
> > +	mutex_lock(&data->mutex);
> > +	ret = mma9551_set_device_state(data->client, true);
> > +	mutex_unlock(&data->mutex);
> > +
> > +	return ret;
> > +}
> > +#endif
> > +
> > +static const struct dev_pm_ops mma9553_pm_ops = {
> > +	SET_SYSTEM_SLEEP_PM_OPS(mma9553_suspend, mma9553_resume)
> > +	SET_RUNTIME_PM_OPS(mma9553_runtime_suspend,
> > +			   mma9553_runtime_resume, NULL)
> > +};
> > +
> > +static const struct acpi_device_id mma9553_acpi_match[] = {
> > +	{"MMA9553", 0},
> > +	{},
> > +};
> > +
> > +MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match);
> > +
> > +static const struct i2c_device_id mma9553_id[] = {
> > +	{"mma9553", 0},
> > +	{},
> > +};
> > +
> > +MODULE_DEVICE_TABLE(i2c, mma9553_id);
> > +
> > +static struct i2c_driver mma9553_driver = {
> > +	.driver = {
> > +		   .name = MMA9553_DRV_NAME,
> > +		   .acpi_match_table = ACPI_PTR(mma9553_acpi_match),
> > +		   .pm = &mma9553_pm_ops,
> > +		   },
> > +	.probe = mma9553_probe,
> > +	.remove = mma9553_remove,
> > +	.id_table = mma9553_id,
> > +};
> > +
> > +module_i2c_driver(mma9553_driver);
> > +
> > +MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
> > +MODULE_LICENSE("GPL v2");
> > +MODULE_DESCRIPTION("MMA9553L pedometer platform driver");
> >


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

* Re: [PATCH 8/8] iio: add driver for Freescale MMA9553
  2015-01-11 15:10     ` Tirdea, Irina
@ 2015-01-11 17:51       ` Jonathan Cameron
  0 siblings, 0 replies; 27+ messages in thread
From: Jonathan Cameron @ 2015-01-11 17:51 UTC (permalink / raw)
  To: Tirdea, Irina, linux-iio
  Cc: linux-kernel, Dogaru, Vlad, Baluta, Daniel, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald

On 11/01/15 15:10, Tirdea, Irina wrote:
> 
> 
>> -----Original Message-----
>> From: Jonathan Cameron [mailto:jic23@kernel.org]
>> Sent: 01 January, 2015 13:58
>> To: Tirdea, Irina; linux-iio@vger.kernel.org
>> Cc: linux-kernel@vger.kernel.org; Dogaru, Vlad; Baluta, Daniel; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald
>> Subject: Re: [PATCH 8/8] iio: add driver for Freescale MMA9553
>>
>> On 19/12/14 22:57, Irina Tirdea wrote:
>>> Add support for Freescale MMA9553L Intelligent Pedometer Platform.
>>>
>>> The following functionalities are supported:
>>>  - step counter (counts the number of steps using a HW register)
>>>  - step detector (generates an iio event at every step the user takes)
>>>  - activity recognition (rest, walking, jogging, running)
>>>  - speed
>>>  - calories
>>>  - distance
>>>
>>> To get accurate pedometer results, the user's height, weight and gender
>>> need to be configured.
>>>
>>> The specifications can be downloaded from:
>>> http://www.freescale.com/files/sensors/doc/ref_manual/MMA955xLSWRM.pdf
>>> http://www.freescale.com/files/sensors/doc/ref_manual/MMA9553LSWRM.pdf
>>>
>>> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
>> A few bits an bobs beyond the interface discussions in the earlier patches
>> in the series.
>>
>> A nice looking driver on the whole, for a complex little device ;)
> 
> Thanks for the detailed review, Jonathan!
> 
<snip>
>>> +			mutex_unlock(&data->mutex);
>>> +			return ret;
>>> +		default:
>>> +			return -EINVAL;
>>> +		}
>>> +	case IIO_EV_INFO_PERIOD:
>>> +		switch (chan->type) {
>>> +		case IIO_STEPS:
>>> +			if (val < 0 || val > 255)
>>> +				return -EINVAL;
>>> +			mutex_lock(&data->mutex);
>>> +			ret = mma9553_set_config(data, MMA9553_CONF_SPEED_STEP,
>>> +						 &data->conf.speed_step, val,
>>> +						 MMA9553_CONF_STEPCOALESCE);
>> So this makes it fire every N steps?  Kind of nice, but not quite what period
>> is usually used for.  We have talked about having an absolute change
>> (rather than ROC) event type before - (requires a change of N and doesn't care
>> how long it took to happen).  Perhaps that makes sense here rather than
>> an instance event and a period?
> Considering the stepcoalesce option, a change event does make more
> sense. I will add IIO_CHANGE and use it instead.
> 
> Adding IIO_CHANGE event type will make IIO_INSTANCE redundant (since
> instance is change with a value of 1). I know once an interface is
> introduced it cannot be changed, but since nobody is using
> IIO_INSTANCE could we remove it?
Drop it and don't worry about.  ABI changes are only a problem if anyone
notices :)

>>
>>> +			mutex_unlock(&data->mutex);
>>> +			return ret;
>>> +		default:
>>> +			return -EINVAL;
>>> +		}
>>> +	default:
>>> +		return -EINVAL;
>>> +	}
>>> +}
>>> +
>>> +static const struct iio_event_spec mma9553_step_event = {
>>> +	.type = IIO_EV_TYPE_INSTANCE,
>>> +	.dir = IIO_EV_DIR_NONE,
>>> +	.mask_separate = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_PERIOD),
>>> +};
>>> +
>>> +static const struct iio_event_spec mma9553_activity_events[] = {
>>> +	{
>>> +		.type = IIO_EV_TYPE_THRESH,
>>> +		.dir = IIO_EV_DIR_RISING,
>>> +		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
>>> +				 BIT(IIO_EV_INFO_VALUE),
>>> +	 },
>>> +	{
>>> +		.type = IIO_EV_TYPE_THRESH,
>>> +		.dir = IIO_EV_DIR_FALLING,
>>> +		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
>>> +				 BIT(IIO_EV_INFO_VALUE),
>>> +	},
>>> +};
>>> +
>>> +#define MMA9553_PEDOMETER_CHANNEL(_type, _mask) {		\
>>> +	.type = _type,						\
>>> +	.info_mask_separate = BIT(IIO_CHAN_INFO_ENABLE)      |	\
>>> +			      BIT(IIO_CHAN_INFO_CALIBHEIGHT) |	\
>>> +			      BIT(IIO_CHAN_INFO_CALIBGENDER) |	\
>>> +			      _mask,				\
>>> +}
>>> +
>>> +#define MMA9553_ACTIVITY_CHANNEL(_chan2) {				\
>>> +	.type = IIO_ACTIVITY,						\
>>> +	.modified = 1,							\
>>> +	.channel2 = _chan2,						\
>>> +	.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),		\
>>> +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT) |	\
>>> +				    BIT(IIO_CHAN_INFO_CALIBGENDER),	\
>>> +	.event_spec = mma9553_activity_events,				\
>>> +	.num_event_specs = ARRAY_SIZE(mma9553_activity_events),		\
>>> +}
>>> +
>>> +static const struct iio_chan_spec mma9553_channels[] = {
>>> +	MMA9551_ACCEL_CHANNEL(IIO_MOD_X),
>>> +	MMA9551_ACCEL_CHANNEL(IIO_MOD_Y),
>>> +	MMA9551_ACCEL_CHANNEL(IIO_MOD_Z),
>>> +
>>> +	{
>>> +		.type = IIO_STEPS,
>>> +		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
>>> +				      BIT(IIO_CHAN_INFO_ENABLE) |
>>> +				      BIT(IIO_CHAN_INFO_OFFSET) |
>>> +				      BIT(IIO_CHAN_INFO_INT_TIME),
>>> +		.event_spec = &mma9553_step_event,
>>> +		.num_event_specs = 1,
>>> +	},
>>> +
>>> +	MMA9553_PEDOMETER_CHANNEL(IIO_DISTANCE, BIT(IIO_CHAN_INFO_PROCESSED)),
>>> +	MMA9553_PEDOMETER_CHANNEL(IIO_SPEED, BIT(IIO_CHAN_INFO_RAW) |
>>> +				  BIT(IIO_CHAN_INFO_SCALE) |
>>> +				  BIT(IIO_CHAN_INFO_INT_TIME)),
>>> +	MMA9553_PEDOMETER_CHANNEL(IIO_CALORIES, BIT(IIO_CHAN_INFO_RAW) |
>>> +				  BIT(IIO_CHAN_INFO_SCALE) |
>>> +				  BIT(IIO_CHAN_INFO_CALIBWEIGHT)),
>>> +
>>> +	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_RUNNING),
>>> +	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_JOGGING),
>>> +	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_WALKING),
>>> +	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_STILL),
>>> +};
>>> +
>>> +static const struct iio_info mma9553_info = {
>>> +	.driver_module = THIS_MODULE,
>>> +	.read_raw = mma9553_read_raw,
>>> +	.write_raw = mma9553_write_raw,
>>> +	.read_event_config = mma9553_read_event_config,
>>> +	.write_event_config = mma9553_write_event_config,
>>> +	.read_event_value = mma9553_read_event_value,
>>> +	.write_event_value = mma9553_write_event_value,
>>> +};
>>> +
>> Only one copy of this?  We don't want to prevent people having more
>> than one of these devices attached to a given machine.
>> Hence by all means have a default version of this but then
>> clone it into the mma9553_data structure for manipulation.
>> Or have a mached array of booleans in there (same indexes)
>> to use for the "enabled"s.
>>
> Will fix this.
> 
>>> +static struct mma9553_event mma9553_events[] = {
>>> +	{
>>> +		.type = IIO_STEPS,
>>> +		.mod = IIO_NO_MOD,
>>> +		.dir = IIO_EV_DIR_NONE,
>>> +		.enabled = false,
>>> +	},
>>> +	{
>>> +		.type = IIO_ACTIVITY,
>>> +		.mod = IIO_MOD_STILL,
>>> +		.dir = IIO_EV_DIR_RISING,
>>> +		.enabled = false,
>>> +	},
>>> +	{
>>> +		.type = IIO_ACTIVITY,
>>> +		.mod = IIO_MOD_STILL,
>>> +		.dir = IIO_EV_DIR_FALLING,
>>> +		.enabled = false,
>>> +	},
>>> +	{
>>> +		.type = IIO_ACTIVITY,
>>> +		.mod = IIO_MOD_WALKING,
>>> +		.dir = IIO_EV_DIR_RISING,
>>> +		.enabled = false,
>>> +	},
>>> +	{
>>> +		.type = IIO_ACTIVITY,
>>> +		.mod = IIO_MOD_WALKING,
>>> +		.dir = IIO_EV_DIR_FALLING,
>>> +		.enabled = false,
>>> +	},
>>> +	{
>>> +		.type = IIO_ACTIVITY,
>>> +		.mod = IIO_MOD_JOGGING,
>>> +		.dir = IIO_EV_DIR_RISING,
>>> +		.enabled = false,
>>> +	},
>>> +	{
>>> +		.type = IIO_ACTIVITY,
>>> +		.mod = IIO_MOD_JOGGING,
>>> +		.dir = IIO_EV_DIR_FALLING,
>>> +		.enabled = false,
>>> +	},
>>> +	{
>>> +		.type = IIO_ACTIVITY,
>>> +		.mod = IIO_MOD_RUNNING,
>>> +		.dir = IIO_EV_DIR_RISING,
>>> +		.enabled = false,
>>> +	},
>>> +	{
>>> +		.type = IIO_ACTIVITY,
>>> +		.mod = IIO_MOD_RUNNING,
>>> +		.dir = IIO_EV_DIR_FALLING,
>>> +		.enabled = false,
>>> +	},
>>> +};
>>> +
>>> +static irqreturn_t mma9553_irq_handler(int irq, void *private)
>>> +{
>>> +	/*
>>> +	 * Since we only configure the interrupt pin when an
>>> +	 * event is enabled, we are sure we have at least
>>> +	 * one event enabled at this point.
>>> +	 */
>> IIRC simply not supplyling the top half handler has the same effect as
>> this (though then you don't have anywhere to put the comment!)
>> Actually - I'd be tempted to grab and stash a timestamp in here to
>> increase the precision of you step timing etc.
> Initially I used a NULL pointer instead of mma9553_irq_handler in devm_request_threaded_irq, but the registration failed with "Threaded irq requested with handler=NULL and !ONESHOT".
> However, it is better to grab the timestamp anyway so I will do that here.
> 
>>> +	return IRQ_WAKE_THREAD;
>>> +}
>>> +
>>> +static irqreturn_t mma9553_event_handler(int irq, void *private)
>>> +{
>>> +	struct iio_dev *indio_dev = private;
>>> +	struct mma9553_data *data = iio_priv(indio_dev);
>>> +	u16 stepcnt;
>>> +	u8 activity;
>>> +	struct mma9553_event *ev_activity, *ev_prev_activity, *ev_step_detect;
>>> +	int ret;
>>> +
>>> +	mutex_lock(&data->mutex);
>>> +	ret = mma9553_read_activity_stepcnt(data, &activity, &stepcnt);
>>> +	if (ret < 0) {
>>> +		mutex_unlock(&data->mutex);
>>> +		return IRQ_HANDLED;
>>> +	}
>>> +
>>> +	ev_prev_activity =
>>> +	    mma9553_get_event(data, IIO_ACTIVITY,
>>> +			      mma9553_activity_to_mod(data->activity),
>>> +			      IIO_EV_DIR_FALLING);
>>> +	ev_activity =
>>> +	    mma9553_get_event(data, IIO_ACTIVITY,
>>> +			      mma9553_activity_to_mod(activity),
>>> +			      IIO_EV_DIR_RISING);
>>> +	ev_step_detect =
>>> +	    mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
>>> +
>>> +	if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) {
>>> +		data->stepcnt = stepcnt;
>>> +		iio_push_event(indio_dev,
>>> +			       IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
>>> +			       IIO_EV_DIR_NONE, IIO_EV_TYPE_INSTANCE, 0, 0, 0),
>>> +			       iio_get_time_ns());
>> Worth grabbing the timestamp earlier than this for precision reasons?
>>> +	}
>>> +
>>> +	if (activity != data->activity) {
>>> +		data->activity = activity;
>>> +		/* ev_activity can be NULL if activity == ACTIVITY_UNKNOWN */
>>> +		if (ev_prev_activity && ev_prev_activity->enabled)
>>> +			iio_push_event(indio_dev,
>>> +				       IIO_EVENT_CODE(IIO_ACTIVITY, 0,
>>> +				       ev_prev_activity->mod,
>>> +				       IIO_EV_DIR_FALLING,
>>> +				       IIO_EV_TYPE_THRESH, 0, 0, 0),
>>> +				       iio_get_time_ns());
>>> +
>>> +		if (ev_activity && ev_activity->enabled)
>>> +			iio_push_event(indio_dev,
>>> +				       IIO_EVENT_CODE(IIO_ACTIVITY, 0,
>>> +				       ev_activity->mod,
>>> +				       IIO_EV_DIR_RISING,
>>> +				       IIO_EV_TYPE_THRESH, 0, 0, 0),
>>> +				       iio_get_time_ns());
>>> +	}
>>> +	mutex_unlock(&data->mutex);
>>> +	return IRQ_HANDLED;
>>> +}
>>> +
>>> +static int mma9553_gpio_probe(struct i2c_client *client)
>>> +{
>>> +	struct device *dev;
>>> +	struct gpio_desc *gpio;
>>> +	int ret;
>>> +
>>> +	if (!client)
>>> +		return -EINVAL;
>>> +
>>> +	dev = &client->dev;
>>> +
>>> +	/* data ready gpio interrupt pin */
>>> +	gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0);
>>> +	if (IS_ERR(gpio)) {
>>> +		dev_err(dev, "acpi gpio get index failed\n");
>>> +		return PTR_ERR(gpio);
>>> +	}
>>> +
>>> +	ret = gpiod_direction_input(gpio);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	ret = gpiod_to_irq(gpio);
>>> +
>>> +	dev_dbg(dev, "gpio resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
>>> +
>>> +	return ret;
>>> +}
>>> +
>>> +static const char *mma9553_match_acpi_device(struct device *dev)
>>> +{
>>> +	const struct acpi_device_id *id;
>>> +
>>> +	id = acpi_match_device(dev->driver->acpi_match_table, dev);
>>> +	if (!id)
>>> +		return NULL;
>>> +
>>> +	return dev_name(dev);
>>> +}
>>> +
>>> +static int mma9553_probe(struct i2c_client *client,
>>> +			 const struct i2c_device_id *id)
>>> +{
>>> +	struct mma9553_data *data;
>>> +	struct iio_dev *indio_dev;
>>> +	const char *name = NULL;
>>> +	int ret;
>>> +
>>> +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
>>> +	if (!indio_dev)
>>> +		return -ENOMEM;
>>> +
>>> +	data = iio_priv(indio_dev);
>>> +	i2c_set_clientdata(client, indio_dev);
>>> +	data->client = client;
>>> +
>>> +	if (id)
>>> +		name = id->name;
>>> +	else if (ACPI_HANDLE(&client->dev))
>>> +		name = mma9553_match_acpi_device(&client->dev);
>>> +	else
>> Interesting to note the original driver doesn't have this else.  Worth
>> checking?
> There was a similar check in the initial driver (it checked for name == NULL instead) that somehow got removed in a later version.
> I could add the check in mma9551 as well, but I am not sure on what is the proper way to handle this.
> There is an ongoing discussion on this: http://www.spinics.net/lists/linux-iio/msg16231.html.
> I would rather for this to be cleared out and send a separate patch to fix both drivers if needed.
> 
>>> +		return -ENOSYS;
>>> +
>>> +	mutex_init(&data->mutex);
>>> +	data->events = mma9553_events;
>>> +	data->num_events = ARRAY_SIZE(mma9553_events);
>>> +
>>> +	ret = mma9553_init(data);
>>> +	if (ret < 0)
>>> +		return ret;
>>> +
>>> +	indio_dev->dev.parent = &client->dev;
>>> +	indio_dev->channels = mma9553_channels;
>>> +	indio_dev->num_channels = ARRAY_SIZE(mma9553_channels);
>>> +	indio_dev->name = name;
>>> +	indio_dev->modes = INDIO_DIRECT_MODE;
>>> +	indio_dev->info = &mma9553_info;
>>> +
>>> +	if (client->irq < 0)
>>> +		client->irq = mma9553_gpio_probe(client);
>>> +
>> So this time we just have a single irq.  That makes life simpler!
> Yes, mma9553 provides the option to combine all its interrupts in one status bit (while mma9551 does not).
> 
>>> +	if (client->irq >= 0) {
>>> +		ret = devm_request_threaded_irq(&client->dev, client->irq,
>>> +						mma9553_irq_handler,
>>> +						mma9553_event_handler,
>>> +						IRQF_TRIGGER_RISING,
>>> +						MMA9553_IRQ_NAME, indio_dev);
>>> +		if (ret < 0) {
>>> +			dev_err(&client->dev, "request irq %d failed\n",
>>> +				client->irq);
>>> +			goto out_poweroff;
>>> +		}
>>> +
>>> +	}
>>> +
>>> +	ret = iio_device_register(indio_dev);
>>> +	if (ret < 0) {
>>> +		dev_err(&client->dev, "unable to register iio device\n");
>>> +		goto out_poweroff;
>>> +	}
>>> +
>>> +	ret = pm_runtime_set_active(&client->dev);
>>> +	if (ret < 0)
>>> +		goto out_iio_unregister;
>>> +
>>> +	pm_runtime_enable(&client->dev);
>>> +	pm_runtime_set_autosuspend_delay(&client->dev,
>>> +					 MMA9551_AUTO_SUSPEND_DELAY_MS);
>>> +	pm_runtime_use_autosuspend(&client->dev);
>>> +
>>> +	dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
>>> +	return 0;
>>> +
>>> +out_iio_unregister:
>>> +	iio_device_unregister(indio_dev);
>>> +out_poweroff:
>>> +	mma9551_set_device_state(client, false);
>>> +	return ret;
>>> +}
>>> +
>>> +static int mma9553_remove(struct i2c_client *client)
>>> +{
>>> +	struct iio_dev *indio_dev = i2c_get_clientdata(client);
>>> +	struct mma9553_data *data = iio_priv(indio_dev);
>>> +
>>> +	pm_runtime_disable(&client->dev);
>>> +	pm_runtime_set_suspended(&client->dev);
>>> +	pm_runtime_put_noidle(&client->dev);
>>> +
>>> +	iio_device_unregister(indio_dev);
>>> +	mutex_lock(&data->mutex);
>>> +	mma9551_set_device_state(data->client, false);
>>> +	mutex_unlock(&data->mutex);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +#ifdef CONFIG_PM
>>> +static int mma9553_runtime_suspend(struct device *dev)
>>> +{
>>> +	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
>>> +	struct mma9553_data *data = iio_priv(indio_dev);
>>> +	int ret;
>>> +
>>> +	mutex_lock(&data->mutex);
>>> +	ret = mma9551_set_device_state(data->client, false);
>>> +	mutex_unlock(&data->mutex);
>>> +	if (ret < 0) {
>>> +		dev_err(&data->client->dev, "powering off device failed\n");
>>> +		return -EAGAIN;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int mma9553_runtime_resume(struct device *dev)
>>> +{
>>> +	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
>>> +	struct mma9553_data *data = iio_priv(indio_dev);
>>> +	int ret;
>>> +
>>> +	ret = mma9551_set_device_state(data->client, true);
>>> +	if (ret < 0)
>>> +		return ret;
>>> +
>>> +	mma9551_sleep(MMA9553_DEFAULT_SAMPLE_RATE);
>>> +	return 0;
>>> +}
>>> +#endif
>>> +
>>> +#ifdef CONFIG_PM_SLEEP
>>> +static int mma9553_suspend(struct device *dev)
>>> +{
>>> +	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
>>> +	struct mma9553_data *data = iio_priv(indio_dev);
>>> +	int ret;
>>> +
>>> +	mutex_lock(&data->mutex);
>>> +	ret = mma9551_set_device_state(data->client, false);
>>> +	mutex_unlock(&data->mutex);
>>> +
>>> +	return ret;
>>> +}
>>> +
>>> +static int mma9553_resume(struct device *dev)
>>> +{
>>> +	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
>>> +	struct mma9553_data *data = iio_priv(indio_dev);
>>> +	int ret;
>>> +
>>> +	mutex_lock(&data->mutex);
>>> +	ret = mma9551_set_device_state(data->client, true);
>>> +	mutex_unlock(&data->mutex);
>>> +
>>> +	return ret;
>>> +}
>>> +#endif
>>> +
>>> +static const struct dev_pm_ops mma9553_pm_ops = {
>>> +	SET_SYSTEM_SLEEP_PM_OPS(mma9553_suspend, mma9553_resume)
>>> +	SET_RUNTIME_PM_OPS(mma9553_runtime_suspend,
>>> +			   mma9553_runtime_resume, NULL)
>>> +};
>>> +
>>> +static const struct acpi_device_id mma9553_acpi_match[] = {
>>> +	{"MMA9553", 0},
>>> +	{},
>>> +};
>>> +
>>> +MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match);
>>> +
>>> +static const struct i2c_device_id mma9553_id[] = {
>>> +	{"mma9553", 0},
>>> +	{},
>>> +};
>>> +
>>> +MODULE_DEVICE_TABLE(i2c, mma9553_id);
>>> +
>>> +static struct i2c_driver mma9553_driver = {
>>> +	.driver = {
>>> +		   .name = MMA9553_DRV_NAME,
>>> +		   .acpi_match_table = ACPI_PTR(mma9553_acpi_match),
>>> +		   .pm = &mma9553_pm_ops,
>>> +		   },
>>> +	.probe = mma9553_probe,
>>> +	.remove = mma9553_remove,
>>> +	.id_table = mma9553_id,
>>> +};
>>> +
>>> +module_i2c_driver(mma9553_driver);
>>> +
>>> +MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
>>> +MODULE_LICENSE("GPL v2");
>>> +MODULE_DESCRIPTION("MMA9553L pedometer platform driver");
>>>
> 


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

end of thread, other threads:[~2015-01-11 17:51 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-19 22:57 [PATCH 0/8] Add MMA9553 driver & PM support for MMA9551 Irina Tirdea
2014-12-19 22:57 ` [PATCH 1/8] iio: core: Introduce CALORIES channel type Irina Tirdea
2014-12-26 13:26   ` Jonathan Cameron
2014-12-29 14:42     ` Tirdea, Irina
2015-01-01 10:29       ` Jonathan Cameron
2015-01-11 13:44         ` Tirdea, Irina
2014-12-19 22:57 ` [PATCH 2/8] iio: core: Introduce DISTANCE " Irina Tirdea
2014-12-19 22:57 ` [PATCH 3/8] iio: core: Introduce SPEED " Irina Tirdea
2014-12-26 13:28   ` Jonathan Cameron
2014-12-29 18:13     ` Tirdea, Irina
2015-01-01 10:34       ` Jonathan Cameron
2015-01-11 13:47         ` Tirdea, Irina
2014-12-19 22:57 ` [PATCH 4/8] iio: core: Introduce IO_CHAN_INFO_CALIBWEIGHT Irina Tirdea
2014-12-26 13:31   ` Jonathan Cameron
2014-12-29 15:05     ` Tirdea, Irina
2015-01-01 10:37       ` Jonathan Cameron
2014-12-19 22:57 ` [PATCH 5/8] iio: core: Introduce IIO_CHAN_INFO_CALIBGENDER Irina Tirdea
2014-12-26 13:29   ` Jonathan Cameron
2014-12-29 19:59     ` Tirdea, Irina
2014-12-19 22:57 ` [PATCH 6/8] iio: accel: mma9551: Add runtime pm support Irina Tirdea
2014-12-19 22:57 ` [PATCH 7/8] iio: accel: mma9551: split driver to expose mma955x api Irina Tirdea
2015-01-01 10:58   ` Jonathan Cameron
2015-01-11 13:52     ` Tirdea, Irina
2014-12-19 22:57 ` [PATCH 8/8] iio: add driver for Freescale MMA9553 Irina Tirdea
2015-01-01 11:58   ` Jonathan Cameron
2015-01-11 15:10     ` Tirdea, Irina
2015-01-11 17:51       ` Jonathan Cameron

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).