Re: [PATCH] iio:common: Add STMicroelectronics common driver

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

 



On 12/04/2012 12:16 PM, Denis CIOCCA wrote:
> This patch adds generic common code driver for STMicroelectronics
> accelerometers, gyroscopes, currently it supports:
accelerometers and gyroscopes
> LSM303DLH, LSM303DLHC, LIS3DH, LIS331DLH, LSM303DL, LSM303DLM,
> L3G4200D, LSM330DL, L3GD20, L3GD20H, LSM330D, LSM330DLC, LSM9DS0,
> L3G4IS, LSM330

Much better to see the patch in this form. Makes reviewers
lives easier as we can actually test the code without lots
of fixing up.

One small point. This isn't against the latest version of staging-next
as it applies with a bit of fuzz.  Please do ensure you are sending
patches against the latest tree.

It also does not quite build for me... I haven't really looked into why...
drivers/iio/accel/st_accel.c:475:5: error: redefinition of 'st_accel_init_sensor'
drivers/iio/accel/../common/st-sensors/st_sensors.h:221:19: note: previous definition of 'st_accel_init_sensor' was here
make[3]: *** [drivers/iio/accel/st_accel.o] Error 1
make[2]: *** [drivers/iio/accel] Error 2
make[1]: *** [drivers/iio] Error 2
make: *** [drivers] Error 2


As for the general structure. I'd normally expect to have two drivers
here, each of which uses the common code as a library.  I'm guessing you may
have based this on hid-sensors.  There things are a little different there
as the sensors are connected to one 'hub' that handles all the data flow.
Here they are I think separate devices so I'd definitely expect the
init and exit + probably probe and remove to be in st_accel.c rather than
the common library.  This would give a cleaner structure and avoid
the ifdef stuff that is breaking building for me at least.

Now this does get a little more interesting as we have spi and i2c drivers
for both.  I'd break those up a little and have them as the util functions.
In general, adding an additional device type should not involve changes
to the common library code.

Hence,

st_accel would contain an init registering a pair of drivers, one spi and one
i2c (this would be a trivial bit of ifdef fun.) If you like you could have
separate st_accel_i2c and st_accel_spi.

Anyhow, the probe would then call the accel specific elements and make
a call into the core code to set up the spi stuff and to setup any generic
code.

So you might (in sort of pseudo code)

int st_accel_spi_probe(..)
{
	struct iio_dev *indio_dev;

	st_sensors_alloc(indio_dev); //allocate everything and do generic setup

	st_sensors_spi_configure(indio_dev, ...); //setup spi stuff.

	st_sensors_register(indio_dev); // everything that requires spi
...	

}

Thus all dependencies are from the device type code to the library code
not the other way around.

Other than that, the powerdown stuff is unfortunately still controversial
and arguably isn't an IIO question to answer.  As we have to maintain the
ABI to userspace long term, I'd prefer that for now you dropped those controls.
We can raise the issue yet again on lkml and other related lists and see if we
can get a generic solution in place.  This should be at the device level in my
opinion, not a job for individual drivers or subsystems.  To all intents and
purposes you are 'suspending' the device and if we don't link into that
infrastructure quite a lot of the benefits are lost.

It's a nice piece of code so very few other comments from me. Mostly nitpics
like unneeded temporaries or blank lines ;)

Jonathan
> ---
>  Documentation/ABI/testing/sysfs-bus-iio-accel-st   |    7 +
>  Documentation/ABI/testing/sysfs-bus-iio-gyro-st    |    7 +
>  drivers/iio/accel/Kconfig                          |   14 +
>  drivers/iio/accel/Makefile                         |    1 +
>  drivers/iio/accel/st_accel.c                       |  493 ++++++++++++++++
>  drivers/iio/common/Kconfig                         |    1 +
>  drivers/iio/common/Makefile                        |    1 +
>  drivers/iio/common/st-sensors/Kconfig              |   17 +
>  drivers/iio/common/st-sensors/Makefile             |    6 +
>  drivers/iio/common/st-sensors/st_sensors.h         |  259 +++++++++
>  drivers/iio/common/st-sensors/st_sensors_buffer.c  |  178 ++++++
>  drivers/iio/common/st-sensors/st_sensors_core.c    |  589 ++++++++++++++++++++
>  drivers/iio/common/st-sensors/st_sensors_i2c.c     |  137 +++++
>  drivers/iio/common/st-sensors/st_sensors_spi.c     |  183 ++++++
>  drivers/iio/common/st-sensors/st_sensors_trigger.c |   83 +++
>  drivers/iio/gyro/Kconfig                           |   14 +
>  drivers/iio/gyro/Makefile                          |    1 +
>  drivers/iio/gyro/st_gyro.c                         |  252 +++++++++
>  18 files changed, 2243 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-accel-st
>  create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-gyro-st
>  create mode 100644 drivers/iio/accel/st_accel.c
>  create mode 100644 drivers/iio/common/st-sensors/Kconfig
>  create mode 100644 drivers/iio/common/st-sensors/Makefile
>  create mode 100644 drivers/iio/common/st-sensors/st_sensors.h
>  create mode 100644 drivers/iio/common/st-sensors/st_sensors_buffer.c
>  create mode 100644 drivers/iio/common/st-sensors/st_sensors_core.c
>  create mode 100644 drivers/iio/common/st-sensors/st_sensors_i2c.c
>  create mode 100644 drivers/iio/common/st-sensors/st_sensors_spi.c
>  create mode 100644 drivers/iio/common/st-sensors/st_sensors_trigger.c
>  create mode 100644 drivers/iio/gyro/st_gyro.c
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-accel-st b/Documentation/ABI/testing/sysfs-bus-iio-accel-st
> new file mode 100644
> index 0000000..f426c02
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-iio-accel-st
> @@ -0,0 +1,7 @@
> +What:		/sys/bus/iio/devices/iio:deviceX/powerdown
> +KernelVersion:	3.7.0
> +Contact:	linux-iio@xxxxxxxxxxxxxxx
> +Description:
> +		Reading returns either '1' or '0'.
> +		'1' means that the device in question is off.
> +		'0' means that the devices in question is on.
Hmm.. This is always an interesting one.
Should userspace be able to power down a device explicitly like
this?
Not clear and much argued.

Also if you are going to do this you want to get the runtime power
management stuff correct so that the bus can also be powered down.
It's all a bit fiddly.

Would you be willing to drop this for now so as to avoid the issues
it raises an then propose it's introduction in a follow up patch?

We have allowed powerdown for dac lines but that's more because that
is a valid dac state than for power saving as here.

I really wish we'd get a kernel wide decision on this sort of fine
grained control.  There's always a preference for auto power
up / power down rather than manual intervention like this.


> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-gyro-st b/Documentation/ABI/testing/sysfs-bus-iio-gyro-st
> new file mode 100644
> index 0000000..f426c02
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-iio-gyro-st
> @@ -0,0 +1,7 @@
> +What:		/sys/bus/iio/devices/iio:deviceX/powerdown
> +KernelVersion:	3.7.0
> +Contact:	linux-iio@xxxxxxxxxxxxxxx
> +Description:
> +		Reading returns either '1' or '0'.
> +		'1' means that the device in question is off.
> +		'0' means that the devices in question is on.
> diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
> index b2510c4..6e8a955 100644
> --- a/drivers/iio/accel/Kconfig
> +++ b/drivers/iio/accel/Kconfig
> @@ -13,4 +13,18 @@ config HID_SENSOR_ACCEL_3D
>  	  Say yes here to build support for the HID SENSOR
>  	  accelerometers 3D.
>
> +config ST_ACCEL_3D
> +	tristate "STMicroelectronics accelerometers 3-Axis Driver"
> +	depends on (I2C || SPI_MASTER) && SYSFS
> +	select IIO_BUFFER
> +	select IIO_TRIGGERED_BUFFER
> +	select ST_SENSORS_IIO_COMMON
> +	help
> +	  Say yes here to build support for STMicroelectronics accelerometers:
> +	  LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC, LSM303D,
> +	  LSM9DS0, LIS331DLH, LSM303DL, LSM303DLM, LSM330.
> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called st_accel.
> +
>  endmenu
> diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
> index 5bc6855..d3ce19a 100644
> --- a/drivers/iio/accel/Makefile
> +++ b/drivers/iio/accel/Makefile
> @@ -3,3 +3,4 @@
>  #
>
>  obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
> +obj-$(CONFIG_ST_ACCEL_3D) += st_accel.o
> diff --git a/drivers/iio/accel/st_accel.c b/drivers/iio/accel/st_accel.c
> new file mode 100644
> index 0000000..02c9ff8
> --- /dev/null
> +++ b/drivers/iio/accel/st_accel.c
> @@ -0,0 +1,493 @@
> +/*
> + * STMicroelectronics accelerometers driver
> + *
> + * Copyright 2012 STMicroelectronics Inc.
> + *
> + * Denis Ciocca <denis.ciocca@xxxxxx>
> + *
> + * Licensed under the GPL-2.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/mutex.h>
> +#include <linux/interrupt.h>
> +#include <linux/i2c.h>
> +#include <linux/gpio.h>
> +#include <linux/irq.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <linux/iio/buffer.h>
> +
> +#include "../common/st-sensors/st_sensors.h"
> +
> +
> +/* FULLSCALE */
> +#define ST_ACCEL_FS_AVL_2G			2
> +#define ST_ACCEL_FS_AVL_4G			4
> +#define ST_ACCEL_FS_AVL_6G			6
> +#define ST_ACCEL_FS_AVL_8G			8
> +#define ST_ACCEL_FS_AVL_16G			16
> +
> +/* CUSTOM VALUES FOR SENSOR 1 */
> +#define ST_ACCEL_1_WAI_EXP			0x33
> +#define ST_ACCEL_1_ODR_ADDR			0x20
> +#define ST_ACCEL_1_ODR_MASK			0xf0
> +#define ST_ACCEL_1_ODR_N_BIT			4
> +#define ST_ACCEL_1_ODR_AVL_1HZ_VAL		0x01
> +#define ST_ACCEL_1_ODR_AVL_10HZ_VAL		0x02
> +#define ST_ACCEL_1_ODR_AVL_25HZ_VAL		0x03
> +#define ST_ACCEL_1_ODR_AVL_50HZ_VAL		0x04
> +#define ST_ACCEL_1_ODR_AVL_100HZ_VAL		0x05
> +#define ST_ACCEL_1_ODR_AVL_200HZ_VAL		0x06
> +#define ST_ACCEL_1_ODR_AVL_400HZ_VAL		0x07
> +#define ST_ACCEL_1_ODR_AVL_1600HZ_VAL		0x08
> +#define ST_ACCEL_1_FS_N_BIT			2
> +#define ST_ACCEL_1_FS_ADDR			0x23
> +#define ST_ACCEL_1_FS_MASK			0x30
> +#define ST_ACCEL_1_FS_AVL_2_VAL			0x00
> +#define ST_ACCEL_1_FS_AVL_4_VAL			0x01
> +#define ST_ACCEL_1_FS_AVL_8_VAL			0x02
> +#define ST_ACCEL_1_FS_AVL_16_VAL		0x03
> +#define ST_ACCEL_1_FS_AVL_2_GAIN		IIO_G_TO_M_S_2(1000)
> +#define ST_ACCEL_1_FS_AVL_4_GAIN		IIO_G_TO_M_S_2(2000)
> +#define ST_ACCEL_1_FS_AVL_8_GAIN		IIO_G_TO_M_S_2(4000)
> +#define ST_ACCEL_1_FS_AVL_16_GAIN		IIO_G_TO_M_S_2(12000)
> +#define ST_ACCEL_1_BDU_ADDR			0x23
> +#define ST_ACCEL_1_BDU_MASK			0x80
> +#define ST_ACCEL_1_DRDY_IRQ_ADDR		0x22
> +#define ST_ACCEL_1_DRDY_IRQ_MASK		0x10
> +#define ST_ACCEL_1_MULTIREAD_BIT		true
> +
> +/* CUSTOM VALUES FOR SENSOR 2 */
> +#define ST_ACCEL_2_WAI_EXP			0x49
> +#define ST_ACCEL_2_ODR_ADDR			0x20
> +#define ST_ACCEL_2_ODR_MASK			0xf0
> +#define ST_ACCEL_2_ODR_N_BIT			4
> +#define ST_ACCEL_2_ODR_AVL_3HZ_VAL		0x01
> +#define ST_ACCEL_2_ODR_AVL_6HZ_VAL		0x02
> +#define ST_ACCEL_2_ODR_AVL_12HZ_VAL		0x03
> +#define ST_ACCEL_2_ODR_AVL_25HZ_VAL		0x04
> +#define ST_ACCEL_2_ODR_AVL_50HZ_VAL		0x05
> +#define ST_ACCEL_2_ODR_AVL_100HZ_VAL		0x06
> +#define ST_ACCEL_2_ODR_AVL_200HZ_VAL		0x07
> +#define ST_ACCEL_2_ODR_AVL_400HZ_VAL		0x08
> +#define ST_ACCEL_2_ODR_AVL_800HZ_VAL		0x09
> +#define ST_ACCEL_2_ODR_AVL_1600HZ_VAL		0x0a
> +#define ST_ACCEL_2_FS_N_BIT			3
> +#define ST_ACCEL_2_FS_ADDR			0x21
> +#define ST_ACCEL_2_FS_MASK			0x38
> +#define ST_ACCEL_2_FS_AVL_2_VAL			0X00
> +#define ST_ACCEL_2_FS_AVL_4_VAL			0X01
> +#define ST_ACCEL_2_FS_AVL_6_VAL			0x02
> +#define ST_ACCEL_2_FS_AVL_8_VAL			0x03
> +#define ST_ACCEL_2_FS_AVL_16_VAL		0x04
> +#define ST_ACCEL_2_FS_AVL_2_GAIN		IIO_G_TO_M_S_2(61)
> +#define ST_ACCEL_2_FS_AVL_4_GAIN		IIO_G_TO_M_S_2(122)
> +#define ST_ACCEL_2_FS_AVL_6_GAIN		IIO_G_TO_M_S_2(183)
> +#define ST_ACCEL_2_FS_AVL_8_GAIN		IIO_G_TO_M_S_2(244)
> +#define ST_ACCEL_2_FS_AVL_16_GAIN		IIO_G_TO_M_S_2(732)
> +#define ST_ACCEL_2_BDU_ADDR			0x20
> +#define ST_ACCEL_2_BDU_MASK			0x08
> +#define ST_ACCEL_2_DRDY_IRQ_ADDR		0x22
> +#define ST_ACCEL_2_DRDY_IRQ_MASK		0x04
> +#define ST_ACCEL_2_MULTIREAD_BIT		true
> +
> +/* CUSTOM VALUES FOR SENSOR 3 */
> +#define ST_ACCEL_3_WAI_EXP			0x32
> +#define ST_ACCEL_3_ODR_ADDR			0x20
> +#define ST_ACCEL_3_ODR_MASK			0x18
> +#define ST_ACCEL_3_ODR_N_BIT			2
> +#define ST_ACCEL_3_ODR_AVL_50HZ_VAL		0x00
> +#define ST_ACCEL_3_ODR_AVL_100HZ_VAL		0x01
> +#define ST_ACCEL_3_ODR_AVL_400HZ_VAL		0x02
> +#define ST_ACCEL_3_ODR_AVL_1000HZ_VAL		0x03
> +#define ST_ACCEL_3_PW_ADDR			0x20
> +#define ST_ACCEL_3_PW_MASK			0xe0
> +#define ST_ACCEL_3_PW_N_BIT			3
> +#define ST_ACCEL_3_FS_N_BIT			2
> +#define ST_ACCEL_3_FS_ADDR			0x23
> +#define ST_ACCEL_3_FS_MASK			0x30
> +#define ST_ACCEL_3_FS_AVL_2_VAL			0X00
> +#define ST_ACCEL_3_FS_AVL_4_VAL			0X01
> +#define ST_ACCEL_3_FS_AVL_8_VAL			0x03
> +#define ST_ACCEL_3_FS_AVL_2_GAIN		IIO_G_TO_M_S_2(1000)
> +#define ST_ACCEL_3_FS_AVL_4_GAIN		IIO_G_TO_M_S_2(2000)
> +#define ST_ACCEL_3_FS_AVL_8_GAIN		IIO_G_TO_M_S_2(3900)
> +#define ST_ACCEL_3_BDU_ADDR			0x23
> +#define ST_ACCEL_3_BDU_MASK			0x80
> +#define ST_ACCEL_3_DRDY_IRQ_ADDR		0x22
> +#define ST_ACCEL_3_DRDY_IRQ_MASK		0x02
> +#define ST_ACCEL_3_MULTIREAD_BIT		true
> +
> +/* CUSTOM VALUES FOR SENSOR 4 */
> +#define ST_ACCEL_4_WAI_EXP			0x40
> +#define ST_ACCEL_4_ODR_ADDR			0x20
> +#define ST_ACCEL_4_ODR_MASK			0xf0
> +#define ST_ACCEL_4_ODR_N_BIT			4
> +#define ST_ACCEL_4_ODR_AVL_3HZ_VAL		0x01
> +#define ST_ACCEL_4_ODR_AVL_6HZ_VAL		0x02
> +#define ST_ACCEL_4_ODR_AVL_12HZ_VAL		0x03
> +#define ST_ACCEL_4_ODR_AVL_25HZ_VAL		0x04
> +#define ST_ACCEL_4_ODR_AVL_50HZ_VAL		0x05
> +#define ST_ACCEL_4_ODR_AVL_100HZ_VAL		0x06
> +#define ST_ACCEL_4_ODR_AVL_200HZ_VAL		0x07
> +#define ST_ACCEL_4_ODR_AVL_400HZ_VAL		0x08
> +#define ST_ACCEL_4_ODR_AVL_800HZ_VAL		0x09
> +#define ST_ACCEL_4_ODR_AVL_1600HZ_VAL		0x0a
> +#define ST_ACCEL_4_FS_N_BIT			3
> +#define ST_ACCEL_4_FS_ADDR			0x24
> +#define ST_ACCEL_4_FS_MASK			0x38
> +#define ST_ACCEL_4_FS_AVL_2_VAL			0X00
> +#define ST_ACCEL_4_FS_AVL_4_VAL			0X01
> +#define ST_ACCEL_4_FS_AVL_6_VAL			0x02
> +#define ST_ACCEL_4_FS_AVL_8_VAL			0x03
> +#define ST_ACCEL_4_FS_AVL_16_VAL		0x04
> +#define ST_ACCEL_4_FS_AVL_2_GAIN		IIO_G_TO_M_S_2(61)
> +#define ST_ACCEL_4_FS_AVL_4_GAIN		IIO_G_TO_M_S_2(122)
> +#define ST_ACCEL_4_FS_AVL_6_GAIN		IIO_G_TO_M_S_2(183)
> +#define ST_ACCEL_4_FS_AVL_8_GAIN		IIO_G_TO_M_S_2(244)
> +#define ST_ACCEL_4_FS_AVL_16_GAIN		IIO_G_TO_M_S_2(732)
> +#define ST_ACCEL_4_BDU_ADDR			0x20
> +#define ST_ACCEL_4_BDU_MASK			0x08
> +#define ST_ACCEL_4_DRDY_IRQ_ADDR		0x23
> +#define ST_ACCEL_4_DRDY_IRQ_MASK		0x80
> +#define ST_ACCEL_4_IG1_EN_ADDR			0x23
> +#define ST_ACCEL_4_IG1_EN_MASK			0x08
> +#define ST_ACCEL_4_MULTIREAD_BIT		false
> +
> +const struct iio_chan_spec st_accel_12bit_channels[] = {
> +	ST_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
> +		ST_SENSORS_DEF_12_REALBITS, ST_SENSORS_DEF_OUT_X_L_ADDR),
> +	ST_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
> +		ST_SENSORS_DEF_12_REALBITS, ST_SENSORS_DEF_OUT_Y_L_ADDR),
> +	ST_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
> +		ST_SENSORS_DEF_12_REALBITS, ST_SENSORS_DEF_OUT_Z_L_ADDR),
> +	IIO_CHAN_SOFT_TIMESTAMP(3)
> +};
> +
> +const struct iio_chan_spec st_accel_16bit_channels[] = {
> +	ST_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
> +		ST_SENSORS_DEF_16_REALBITS, ST_SENSORS_DEF_OUT_X_L_ADDR),
> +	ST_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
> +		ST_SENSORS_DEF_16_REALBITS, ST_SENSORS_DEF_OUT_Y_L_ADDR),
> +	ST_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
> +		ST_SENSORS_DEF_16_REALBITS, ST_SENSORS_DEF_OUT_Z_L_ADDR),
> +	IIO_CHAN_SOFT_TIMESTAMP(3)
> +};
> +
> +const struct st_sensors st_accel_sensors[] = {
> +	{
> +		.wai = ST_ACCEL_1_WAI_EXP,
> +		.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
> +		.odr = {
> +			.addr = ST_ACCEL_1_ODR_ADDR,
> +			.mask = ST_ACCEL_1_ODR_MASK,
> +			.num_bit = ST_ACCEL_1_ODR_N_BIT,
> +			.odr_avl = {
> +				{ 1, ST_ACCEL_1_ODR_AVL_1HZ_VAL, },
> +				{ 10, ST_ACCEL_1_ODR_AVL_10HZ_VAL, },
> +				{ 25, ST_ACCEL_1_ODR_AVL_25HZ_VAL, },
> +				{ 50, ST_ACCEL_1_ODR_AVL_50HZ_VAL, },
> +				{ 100, ST_ACCEL_1_ODR_AVL_100HZ_VAL, },
> +				{ 200, ST_ACCEL_1_ODR_AVL_200HZ_VAL, },
> +				{ 400, ST_ACCEL_1_ODR_AVL_400HZ_VAL, },
> +				{ 1600, ST_ACCEL_1_ODR_AVL_1600HZ_VAL, },
> +			},
> +		},
> +		.pw = {
> +			.addr = ST_ACCEL_1_ODR_ADDR,
> +			.mask = ST_ACCEL_1_ODR_MASK,
> +			.num_bit = ST_ACCEL_1_ODR_N_BIT,
> +			.value_off = ST_SENSORS_DEF_POWER_OFF_VALUE,
> +		},
> +		.enable_axis = {
> +			.addr = ST_SENSORS_DEF_AXIS_ADDR,
> +			.mask = ST_SENSORS_DEF_AXIS_MASK,
> +		},
> +		.fs = {
> +			.addr = ST_ACCEL_1_FS_ADDR,
> +			.mask = ST_ACCEL_1_FS_MASK,
> +			.num_bit = ST_ACCEL_1_FS_N_BIT,
> +			.fs_avl = {
> +				[0] = {
> +					.num = ST_ACCEL_FS_AVL_2G,
> +					.value = ST_ACCEL_1_FS_AVL_2_VAL,
> +					.gain = ST_ACCEL_1_FS_AVL_2_GAIN,
> +				},
> +				[1] = {
> +					.num = ST_ACCEL_FS_AVL_4G,
> +					.value = ST_ACCEL_1_FS_AVL_4_VAL,
> +					.gain = ST_ACCEL_1_FS_AVL_4_GAIN,
> +				},
> +				[2] = {
> +					.num = ST_ACCEL_FS_AVL_8G,
> +					.value = ST_ACCEL_1_FS_AVL_8_VAL,
> +					.gain = ST_ACCEL_1_FS_AVL_8_GAIN,
> +				},
> +				[3] = {
> +					.num = ST_ACCEL_FS_AVL_16G,
> +					.value = ST_ACCEL_1_FS_AVL_16_VAL,
> +					.gain = ST_ACCEL_1_FS_AVL_16_GAIN,
> +				},
> +			},
> +		},
> +		.bdu = {
> +			.addr = ST_ACCEL_1_BDU_ADDR,
> +			.mask = ST_ACCEL_1_BDU_MASK,
> +		},
> +		.drdy_irq = {
> +			.addr = ST_ACCEL_1_DRDY_IRQ_ADDR,
> +			.mask = ST_ACCEL_1_DRDY_IRQ_MASK,
> +		},
> +		.multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT,
> +	},
> +	{
> +		.wai = ST_ACCEL_2_WAI_EXP,
> +		.ch = (struct iio_chan_spec *)st_accel_16bit_channels,
> +		.odr = {
> +			.addr = ST_ACCEL_2_ODR_ADDR,
> +			.mask = ST_ACCEL_2_ODR_MASK,
> +			.num_bit = ST_ACCEL_2_ODR_N_BIT,
> +			.odr_avl = {
> +				{ 3, ST_ACCEL_2_ODR_AVL_3HZ_VAL, },
> +				{ 6, ST_ACCEL_2_ODR_AVL_6HZ_VAL, },
> +				{ 12, ST_ACCEL_2_ODR_AVL_12HZ_VAL, },
> +				{ 25, ST_ACCEL_2_ODR_AVL_25HZ_VAL, },
> +				{ 50, ST_ACCEL_2_ODR_AVL_50HZ_VAL, },
> +				{ 100, ST_ACCEL_2_ODR_AVL_100HZ_VAL, },
> +				{ 200, ST_ACCEL_2_ODR_AVL_200HZ_VAL, },
> +				{ 400, ST_ACCEL_2_ODR_AVL_400HZ_VAL, },
> +				{ 800, ST_ACCEL_2_ODR_AVL_800HZ_VAL, },
> +				{ 1600, ST_ACCEL_2_ODR_AVL_1600HZ_VAL, },
> +			},
> +		},
> +		.pw = {
> +			.addr = ST_ACCEL_2_ODR_ADDR,
> +			.mask = ST_ACCEL_2_ODR_MASK,
> +			.num_bit = ST_ACCEL_2_ODR_N_BIT,
> +			.value_off = ST_SENSORS_DEF_POWER_OFF_VALUE,
> +		},
> +		.enable_axis = {
> +			.addr = ST_SENSORS_DEF_AXIS_ADDR,
> +			.mask = ST_SENSORS_DEF_AXIS_MASK,
> +		},
> +		.fs = {
> +			.addr = ST_ACCEL_2_FS_ADDR,
> +			.mask = ST_ACCEL_2_FS_MASK,
> +			.num_bit = ST_ACCEL_2_FS_N_BIT,
> +			.fs_avl = {
> +				[0] = {
> +					.num = ST_ACCEL_FS_AVL_2G,
> +					.value = ST_ACCEL_2_FS_AVL_2_VAL,
> +					.gain = ST_ACCEL_2_FS_AVL_2_GAIN,
> +				},
> +				[1] = {
> +					.num = ST_ACCEL_FS_AVL_4G,
> +					.value = ST_ACCEL_2_FS_AVL_4_VAL,
> +					.gain = ST_ACCEL_2_FS_AVL_4_GAIN,
> +				},
> +				[2] = {
> +					.num = ST_ACCEL_FS_AVL_6G,
> +					.value = ST_ACCEL_2_FS_AVL_6_VAL,
> +					.gain = ST_ACCEL_2_FS_AVL_6_GAIN,
> +				},
> +				[3] = {
> +					.num = ST_ACCEL_FS_AVL_8G,
> +					.value = ST_ACCEL_2_FS_AVL_8_VAL,
> +					.gain = ST_ACCEL_2_FS_AVL_8_GAIN,
> +				},
> +				[4] = {
> +					.num = ST_ACCEL_FS_AVL_16G,
> +					.value = ST_ACCEL_2_FS_AVL_16_VAL,
> +					.gain = ST_ACCEL_2_FS_AVL_16_GAIN,
> +				},
> +			},
> +		},
> +		.drdy_irq = {
> +			.addr = ST_ACCEL_2_DRDY_IRQ_ADDR,
> +			.mask = ST_ACCEL_2_DRDY_IRQ_MASK,
> +		},
> +		.bdu = {
> +			.addr = ST_ACCEL_2_BDU_ADDR,
> +			.mask = ST_ACCEL_2_BDU_MASK,
> +		},
> +		.multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
> +	},
> +	{
> +		.wai = ST_ACCEL_3_WAI_EXP,
> +		.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
> +		.odr = {
> +			.addr = ST_ACCEL_3_ODR_ADDR,
> +			.mask = ST_ACCEL_3_ODR_MASK,
> +			.num_bit = ST_ACCEL_3_ODR_N_BIT,
> +			.odr_avl = {
> +				{ 50, ST_ACCEL_3_ODR_AVL_50HZ_VAL, },
> +				{ 100, ST_ACCEL_3_ODR_AVL_100HZ_VAL, },
> +				{ 400, ST_ACCEL_3_ODR_AVL_400HZ_VAL, },
> +				{ 1000, ST_ACCEL_3_ODR_AVL_1000HZ_VAL, },
> +			},
> +		},
> +		.pw = {
> +			.addr = ST_ACCEL_3_PW_ADDR,
> +			.mask = ST_ACCEL_3_PW_MASK,
> +			.num_bit = ST_ACCEL_3_PW_N_BIT,
> +			.value_on = ST_SENSORS_DEF_POWER_ON_VALUE,
> +			.value_off = ST_SENSORS_DEF_POWER_OFF_VALUE,
> +		},
> +		.enable_axis = {
> +			.addr = ST_SENSORS_DEF_AXIS_ADDR,
> +			.mask = ST_SENSORS_DEF_AXIS_MASK,
> +		},
> +		.fs = {
> +			.addr = ST_ACCEL_3_FS_ADDR,
> +			.mask = ST_ACCEL_3_FS_MASK,
> +			.num_bit = ST_ACCEL_3_FS_N_BIT,
> +			.fs_avl = {
> +				[0] = {
> +					.num = ST_ACCEL_FS_AVL_2G,
> +					.value = ST_ACCEL_3_FS_AVL_2_VAL,
> +					.gain = ST_ACCEL_3_FS_AVL_2_GAIN,
> +				},
> +				[1] = {
> +					.num = ST_ACCEL_FS_AVL_4G,
> +					.value = ST_ACCEL_3_FS_AVL_4_VAL,
> +					.gain = ST_ACCEL_3_FS_AVL_4_GAIN,
> +				},
> +				[2] = {
> +					.num = ST_ACCEL_FS_AVL_8G,
> +					.value = ST_ACCEL_3_FS_AVL_8_VAL,
> +					.gain = ST_ACCEL_3_FS_AVL_8_GAIN,
> +				},
> +			},
> +		},
> +		.bdu = {
> +			.addr = ST_ACCEL_3_BDU_ADDR,
> +			.mask = ST_ACCEL_3_BDU_MASK,
> +		},
> +		.drdy_irq = {
> +			.addr = ST_ACCEL_3_DRDY_IRQ_ADDR,
> +			.mask = ST_ACCEL_3_DRDY_IRQ_MASK,
> +		},
> +		.multi_read_bit = ST_ACCEL_3_MULTIREAD_BIT,
> +	},
> +	{
> +		.wai = ST_ACCEL_4_WAI_EXP,
> +		.ch = (struct iio_chan_spec *)st_accel_16bit_channels,
> +		.odr = {
> +			.addr = ST_ACCEL_4_ODR_ADDR,
> +			.mask = ST_ACCEL_4_ODR_MASK,
> +			.num_bit = ST_ACCEL_4_ODR_N_BIT,
> +			.odr_avl = {
> +				{ 3, ST_ACCEL_4_ODR_AVL_3HZ_VAL },
> +				{ 6, ST_ACCEL_4_ODR_AVL_6HZ_VAL, },
> +				{ 12, ST_ACCEL_4_ODR_AVL_12HZ_VAL, },
> +				{ 25, ST_ACCEL_4_ODR_AVL_25HZ_VAL, },
> +				{ 50, ST_ACCEL_4_ODR_AVL_50HZ_VAL, },
> +				{ 100, ST_ACCEL_4_ODR_AVL_100HZ_VAL, },
> +				{ 200, ST_ACCEL_4_ODR_AVL_200HZ_VAL, },
> +				{ 400, ST_ACCEL_4_ODR_AVL_400HZ_VAL, },
> +				{ 800, ST_ACCEL_4_ODR_AVL_800HZ_VAL, },
> +				{ 1600, ST_ACCEL_4_ODR_AVL_1600HZ_VAL, },
> +			},
> +		},
> +		.pw = {
> +			.addr = ST_ACCEL_4_ODR_ADDR,
> +			.mask = ST_ACCEL_4_ODR_MASK,
> +			.num_bit = ST_ACCEL_4_ODR_N_BIT,
> +			.value_off = ST_SENSORS_DEF_POWER_OFF_VALUE,
> +		},
> +		.enable_axis = {
> +			.addr = ST_SENSORS_DEF_AXIS_ADDR,
> +			.mask = ST_SENSORS_DEF_AXIS_MASK,
> +		},
> +		.fs = {
> +			.addr = ST_ACCEL_4_FS_ADDR,
> +			.mask = ST_ACCEL_4_FS_MASK,
> +			.num_bit = ST_ACCEL_4_FS_N_BIT,
> +			.fs_avl = {
> +				[0] = {
> +					.num = ST_ACCEL_FS_AVL_2G,
> +					.value = ST_ACCEL_4_FS_AVL_2_VAL,
> +					.gain = ST_ACCEL_4_FS_AVL_2_GAIN,
> +				},
> +				[1] = {
> +					.num = ST_ACCEL_FS_AVL_4G,
> +					.value = ST_ACCEL_4_FS_AVL_4_VAL,
> +					.gain = ST_ACCEL_4_FS_AVL_4_GAIN,
> +				},
> +				[2] = {
> +					.num = ST_ACCEL_FS_AVL_6G,
> +					.value = ST_ACCEL_4_FS_AVL_6_VAL,
> +					.gain = ST_ACCEL_4_FS_AVL_6_GAIN,
> +				},
> +				[3] = {
> +					.num = ST_ACCEL_FS_AVL_8G,
> +					.value = ST_ACCEL_4_FS_AVL_8_VAL,
> +					.gain = ST_ACCEL_4_FS_AVL_8_GAIN,
> +				},
> +				[4] = {
> +					.num = ST_ACCEL_FS_AVL_16G,
> +					.value = ST_ACCEL_4_FS_AVL_16_VAL,
> +					.gain = ST_ACCEL_4_FS_AVL_16_GAIN,
> +				},
> +			},
> +		},
> +		.bdu = {
> +			.addr = ST_ACCEL_4_BDU_ADDR,
> +			.mask = ST_ACCEL_4_BDU_MASK,
> +		},
> +		.drdy_irq = {
> +			.addr = ST_ACCEL_4_DRDY_IRQ_ADDR,
> +			.mask = ST_ACCEL_4_DRDY_IRQ_MASK,
> +			.ig1 = {
> +				.en_addr = ST_ACCEL_4_IG1_EN_ADDR,
> +				.en_mask = ST_ACCEL_4_IG1_EN_MASK,
> +			},
> +		},
> +		.multi_read_bit = ST_ACCEL_4_MULTIREAD_BIT,
> +	},
> +};
> +
> +static int st_accel_check_device_list(struct st_sensors_data *adata, u8 wai)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(st_accel_sensors); i++) {
> +		if (st_accel_sensors[i].wai == wai)
> +			break;
> +	}
> +	if (i == ARRAY_SIZE(st_accel_sensors))
> +		goto check_device_error;
> +
> +	adata->index = i;
> +
> +	return i;
> +
> +check_device_error:
> +	return -ENODEV;
> +}
> +
> +int st_accel_init_sensor(struct iio_dev *indio_dev, u8 wai)
> +{
> +	int err;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	err = st_accel_check_device_list(adata, wai);
> +	if (err < 0)
> +		goto init_error;
> +
> +	adata->st_sensors = (const struct st_sensors *)st_accel_sensors;
> +
> +init_error:
> +	return err;
> +}
> +EXPORT_SYMBOL(st_accel_init_sensor);
> +
> +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@xxxxxx>");
> +MODULE_DESCRIPTION("STMicroelectronics accelerometers driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
> index ed45ee5..315632f 100644
> --- a/drivers/iio/common/Kconfig
> +++ b/drivers/iio/common/Kconfig
> @@ -3,3 +3,4 @@
>  #
>
>  source "drivers/iio/common/hid-sensors/Kconfig"
> +source "drivers/iio/common/st-sensors/Kconfig"
> diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
> index 8158400..f876ca5 100644
> --- a/drivers/iio/common/Makefile
> +++ b/drivers/iio/common/Makefile
> @@ -7,3 +7,4 @@
>  #
>
>  obj-y += hid-sensors/
> +obj-y += st-sensors/
> diff --git a/drivers/iio/common/st-sensors/Kconfig b/drivers/iio/common/st-sensors/Kconfig
> new file mode 100644
> index 0000000..5e17159
> --- /dev/null
> +++ b/drivers/iio/common/st-sensors/Kconfig
> @@ -0,0 +1,17 @@
> +#
> +# STMicroelectronics sensors common modules
> +#
> +menu "STMicroelectronics Sensors IIO Common"
> +
> +config ST_SENSORS_IIO_COMMON
> +	tristate "Common modules for all ST Sensors IIO drivers"
> +	depends on (I2C || SPI_MASTER) && SYSFS
> +	select IIO_TRIGGER if IIO_BUFFER
> +	help
> +	  Say yes here to build support for HID sensor to use
> +	  HID sensor common processing for attributes and IIO triggers.
> +	  There are many attributes which can be shared among multiple
> +	  HID sensor drivers, this module contains processing for those
> +	  attributes.
> +
> +endmenu
> diff --git a/drivers/iio/common/st-sensors/Makefile b/drivers/iio/common/st-sensors/Makefile
> new file mode 100644
> index 0000000..5c517ff
> --- /dev/null
> +++ b/drivers/iio/common/st-sensors/Makefile
> @@ -0,0 +1,6 @@
> +#
> +# Makefile for the STMicroelectronics sensors common modules.
> +#
> +
> +obj-$(CONFIG_ST_SENSORS_IIO_COMMON) += st-sensors-iio-common.o
> +st-sensors-iio-common-y := st_sensors_core.o st_sensors_i2c.o st_sensors_spi.o st_sensors_trigger.o st_sensors_buffer.o
> diff --git a/drivers/iio/common/st-sensors/st_sensors.h b/drivers/iio/common/st-sensors/st_sensors.h
> new file mode 100644
> index 0000000..5daadfa
> --- /dev/null
> +++ b/drivers/iio/common/st-sensors/st_sensors.h
> @@ -0,0 +1,259 @@
> +/*
> + * STMicroelectronics sensors driver
> + *
> + * Copyright 2012 STMicroelectronics Inc.
> + *
> + * Denis Ciocca <denis.ciocca@xxxxxx>
> + * v. 1.0.0
> + * Licensed under the GPL-2.
> + */
> +
> +#ifndef ST_SENSORS_H
> +#define ST_SENSORS_H
> +
> +#define LSM303DLH_ACCEL_DEV_NAME		"lsm303dlh_accel"
> +#define LSM303DLHC_ACCEL_DEV_NAME		"lsm303dlhc_accel"
> +#define LIS3DH_ACCEL_DEV_NAME			"lis3dh"
> +#define LSM330D_ACCEL_DEV_NAME			"lsm330d_accel"
> +#define LSM330DL_ACCEL_DEV_NAME			"lsm330dl_accel"
> +#define LSM330DLC_ACCEL_DEV_NAME		"lsm330dlc_accel"
> +#define LSM303D_ACCEL_DEV_NAME			"lsm303d"
> +#define LSM9DS0_ACCEL_DEV_NAME			"lsm9ds0"
> +#define LIS331DLH_ACCEL_DEV_NAME		"lis331dlh"
> +#define LSM303DL_ACCEL_DEV_NAME			"lsm303dl_accel"
> +#define LSM303DLM_ACCEL_DEV_NAME		"lsm303dlm_accel"
> +#define LSM330_ACCEL_DEV_NAME			"lsm330_accel"
> +
> +#define L3G4200D_GYRO_DEV_NAME			"l3g4200d"
> +#define LSM330DL_GYRO_DEV_NAME			"lsm330dl_gyro"
> +#define L3GD20_GYRO_DEV_NAME			"l3gd20"
> +#define L3GD20H_GYRO_DEV_NAME			"l3gd20h"
> +#define LSM330D_GYRO_DEV_NAME			"lsm330d_gyro"
> +#define LSM330DLC_GYRO_DEV_NAME			"lsm330dlc_gyro"
> +#define LSM9DS0_GYRO_DEV_NAME			"lsm9ds0_gyro"
> +#define L3G4IS_GYRO_DEV_NAME			"l3g4is_ui"
> +#define LSM330_GYRO_DEV_NAME			"lsm330_gyro"
> +
> +#define ST_SENSORS_NUMBER_ALL_CHANNELS		4
> +#define ST_SENSORS_NUMBER_DATA_CHANNELS		3
> +#define ST_SENSORS_BYTE_4CHANNEL		2
> +#define ST_SENSORS_SCAN_X			0
> +#define ST_SENSORS_SCAN_Y			1
> +#define ST_SENSORS_SCAN_Z			2
> +#define ST_SENSORS_TX_MAX_LENGHT		2
> +#define ST_SENSORS_RX_MAX_LENGHT		6
> +#define ST_SENSORS_FULLSCALE_AVL_MAX		5
> +#define ST_SENSORS_ODR_LIST_MAX			10
> +#define ST_SENSORS_ENABLE_ALL_CHANNELS		0x07
> +
> +/* DEFAULT VALUES FOR SENSORS */
> +#define ST_SENSORS_DEF_OUT_X_L_ADDR		0x28
> +#define ST_SENSORS_DEF_OUT_X_H_ADDR		0x29
> +#define ST_SENSORS_DEF_OUT_Y_L_ADDR		0x2a
> +#define ST_SENSORS_DEF_OUT_Y_H_ADDR		0x2b
> +#define ST_SENSORS_DEF_OUT_Z_L_ADDR		0x2c
> +#define ST_SENSORS_DEF_OUT_Z_H_ADDR		0x2d
> +#define ST_SENSORS_DEF_WAI_ADDRESS		0x0f
> +#define ST_SENSORS_DEF_POWER_ON_VALUE		0x01
> +#define ST_SENSORS_DEF_POWER_OFF_VALUE		0x00
> +#define ST_SENSORS_DEF_12_REALBITS		12
> +#define ST_SENSORS_DEF_16_REALBITS		16
> +#define ST_SENSORS_DEF_AXIS_ADDR		0x20
> +#define ST_SENSORS_DEF_AXIS_MASK		0x07
> +#define ST_SENSORS_DEF_AXIS_N_BIT		3
> +
> +#define ST_LSM_CHANNELS(sensor_type, index, mod, endian, bits, addr) \
> +{ \
> +	.type = sensor_type, \
> +	.modified = 1, \
> +	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
> +					IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
> +	.scan_index = index, \
> +	.channel2 = mod, \
> +	.address = addr, \
> +	.scan_type = { \
> +		.sign = 's', \
> +		.realbits = bits, \
> +		.shift = 16 - bits, \
> +		.storagebits = 16, \
> +		.endianness = endian, \
> +	}, \
> +}
> +
> +/**
> + * struct st_sensors_data - ST sensors device status
> + * @dev: Pointer to instance of struct device (I2C or SPI).
> + * @trig: The trigger in use by the core driver.
> + * @enabled: Status of the sensor (false->off, true->on).
> + * @multiread_bit: Use or not particular bit for [I2C/SPI] multiread.
> + * @index: Number used to point the sensor being used in the
> + *	st_sensors_sensors struct.
> + * @buffer_data: Data used by buffer part.
> + * @fullscale: Maximum range of measure by the sensor.
> + * @gain: Sensitivity of the sensor [m/s^2/LSB].
> + * @odr: Output data rate of the sensor [Hz].
> + * @buf_lock: Mutex to protect rx and tx buffers.
> + * @tx_buf: Buffer used by SPI transfer function to send data to the sensors.
> + *	This buffer is used to avoid DMA not-aligned issue.
> + * @rx_buf: Buffer used by SPI transfer to receive data from sensors.
> + *	This buffer is used to avoid DMA not-aligned issue.
> + * @read_byte: Function used to read one byte.
> + * @write_byte: Function used to write one byte.
> + * @read_multiple_byte: Function used to read multiple byte.
> + */
> +
> +struct st_sensors_data {
> +	struct device *dev;
> +	struct iio_trigger *trig;
> +	const struct st_sensors *st_sensors;
> +
> +	bool enabled;
> +	bool multiread_bit;
> +
> +	short index;
> +
> +	char *buffer_data;
> +
> +	unsigned int fullscale;
> +	unsigned int gain;
> +	unsigned int odr;
> +
> +	struct mutex buf_lock;

much better on this btw ;)
> +	u8 tx_buf[ST_SENSORS_TX_MAX_LENGHT] ____cacheline_aligned;
> +	u8 rx_buf[ST_SENSORS_RX_MAX_LENGHT] ____cacheline_aligned;
> +
> +	int (*read_byte) (struct st_sensors_data *adata, u8 reg_addr,
> +								u8 *res_byte);
> +	int (*write_byte) (struct st_sensors_data *adata, u8 reg_addr, u8 data);
> +	int (*read_multiple_byte) (struct st_sensors_data *adata, u8 reg_addr,
> +							int len, u8 *data);
> +};
> +
> +struct st_sensors_odr_available {
> +	unsigned int hz;
> +	u8 value;
> +};
> +
> +struct st_sensors_odr {
> +	u8 addr;
> +	u8 mask;
> +	short num_bit;
> +	struct st_sensors_odr_available odr_avl[ST_SENSORS_ODR_LIST_MAX];
> +};
> +
> +struct st_sensors_power {
> +	u8 addr;
> +	u8 mask;
> +	unsigned short num_bit;
> +	u8 value_off;
> +	u8 value_on;
> +};
> +
> +struct st_sensors_axis {
> +	u8 addr;
> +	u8 mask;
> +};
> +
> +struct st_sensors_fs_available {
> +	unsigned int num;
> +	u8 value;
> +	unsigned int gain;
> +};
> +
> +struct st_sensors_fullscale {
> +	u8 addr;
> +	u8 mask;
> +	unsigned short num_bit;
> +	struct st_sensors_fs_available fs_avl[ST_SENSORS_FULLSCALE_AVL_MAX];
> +};
> +
> +struct st_sensors_bdu {
> +	u8 addr;
> +	u8 mask;
> +};
> +
> +struct st_sensors_interrupt_generator {
> +	u8 en_addr;
> +	u8 latch_mask_addr;
> +	u8 en_mask;
> +	u8 latching_mask;
> +};
> +
> +struct st_sensors_data_ready_irq {
> +	u8 addr;
> +	u8 mask;
> +	struct st_sensors_interrupt_generator ig1;
> +};
> +
> +/**
> + * struct st_sensors - ST sensors list
> + * @wai: Contents of WhoAmI register.
> + * @ch: IIO channels for the sensor.
> + * @odr: Output data rate register and odr list available.
> + * @pw: Power register of the sensor.
> + * @enable_axis: Enable one or more axis of the sensor.
> + * @fs: Full scale register and fs list available.
> + * @bdu: Block data update register.
> + * @drdy_irq: Data ready register of the sensor.
> + * @multi_read_bit: Use or not particular bit for [I2C/SPI] multiread.
> + */
convention is no blank line here.
> +
> +struct st_sensors {
> +	u8 wai;
> +	struct iio_chan_spec *ch;
> +	struct st_sensors_odr odr;
> +	struct st_sensors_power pw;
> +	struct st_sensors_axis enable_axis;
> +	struct st_sensors_fullscale fs;
> +	struct st_sensors_bdu bdu;
> +	struct st_sensors_data_ready_irq drdy_irq;
> +	bool multi_read_bit;
> +};
> +
> +int st_sensors_iio_probe(struct iio_dev *indio_dev, int irq);
> +void st_sensors_iio_remove(struct iio_dev *indio_dev, int irq);
> +int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable);
> +int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable);
> +

It's this next bit that is causing me to have build issues... anyhow
as explained I don't think it shouldbe here.
> +#ifdef CONFIG_ST_ACCEL_3D
> +int st_accel_init_sensor(struct iio_dev *indio_dev, u8 wai);
> +#else /* CONFIG_ST_ACCEL_3D */
> +static inline int st_accel_init_sensor(struct iio_dev *indio_dev, u8 wai)
> +{
> +	return -ENODEV;
> +}
> +#endif /* CONFIG_ST_ACCEL_3D */
> +
> +#ifdef CONFIG_ST_GYRO_3D
> +int st_gyro_init_sensor(struct iio_dev *indio_dev, u8 wai);
> +#else /* CONFIG_ST_GYRO_3D */
> +static inline int st_gyro_init_sensor(struct iio_dev *indio_dev, u8 wai)
> +{
> +	return -ENODEV;
> +}
> +#endif /* CONFIG_ST_GYRO_3D */
> +
> +#ifdef CONFIG_IIO_BUFFER
> +int st_sensors_probe_trigger(struct iio_dev *indio_dev, int irq);
> +void st_sensors_remove_trigger(struct iio_dev *indio_dev, int irq);
> +int st_sensors_allocate_ring(struct iio_dev *indio_dev);
> +void st_sensors_deallocate_ring(struct iio_dev *indio_dev);
> +#else /* CONFIG_IIO_BUFFER */
> +static inline int st_sensors_probe_trigger(struct iio_dev *indio_dev, int irq)
> +{
> +	return 0;
> +}
> +static inline void st_sensors_remove_trigger(struct iio_dev *indio_dev, int irq)
> +{
> +	return;
> +}
> +static inline int st_sensors_allocate_ring(struct iio_dev *indio_dev)
> +{
> +	return 0;
> +}
> +static inline void st_sensors_deallocate_ring(struct iio_dev *indio_dev)
> +{
> +}
> +#endif /* CONFIG_IIO_BUFFER */
> +
> +#endif /* ST_SENSORS_H */
> diff --git a/drivers/iio/common/st-sensors/st_sensors_buffer.c b/drivers/iio/common/st-sensors/st_sensors_buffer.c
> new file mode 100644
> index 0000000..b8d1cc3
> --- /dev/null
> +++ b/drivers/iio/common/st-sensors/st_sensors_buffer.c
> @@ -0,0 +1,178 @@
> +/*
> + * STMicroelectronics sensors driver
> + *
> + * Copyright 2012 STMicroelectronics Inc.
> + *
> + * Denis Ciocca <denis.ciocca@xxxxxx>
> + *
> + * Licensed under the GPL-2.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/stat.h>
> +#include <linux/interrupt.h>
> +#include <linux/byteorder/generic.h>
> +#include <linux/i2c.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <linux/iio/triggered_buffer.h>
> +
> +#include "st_sensors.h"
> +
one blank line is plenty.
> +
> +#define ST_SENSORS_ENABLE_ALL_CHANNELS		0x07
> +
> +static int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
> +{
> +	int i, n, len;
> +	u8 reg_addr[ST_SENSORS_NUMBER_DATA_CHANNELS];
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	for (i = 0; i < ST_SENSORS_NUMBER_DATA_CHANNELS; i++) {
> +		if (test_bit(i, indio_dev->active_scan_mask)) {
> +			reg_addr[n] = indio_dev->channels[i].address;
> +			n++;
> +		}
> +	}
> +	switch (n) {
> +	case 1:
> +		len = adata->read_multiple_byte(adata, reg_addr[0],
> +					ST_SENSORS_BYTE_4CHANNEL, buf);
> +		break;
> +	case 2:
> +		if ((reg_addr[1] - reg_addr[0]) == ST_SENSORS_BYTE_4CHANNEL) {
> +			len = adata->read_multiple_byte(adata, reg_addr[0],
> +					ST_SENSORS_BYTE_4CHANNEL*n,
> +					buf);
> +		} else {
> +			u8 rx_array[ST_SENSORS_BYTE_4CHANNEL*
> +				ST_SENSORS_NUMBER_DATA_CHANNELS];
> +			len = adata->read_multiple_byte(adata, reg_addr[0],
> +				ST_SENSORS_BYTE_4CHANNEL*
> +				ST_SENSORS_NUMBER_DATA_CHANNELS,
> +				rx_array);
> +			if (len < 0)
> +				goto read_data_channels_error;
> +
> +			for (i = 0; i < n * ST_SENSORS_NUMBER_DATA_CHANNELS;
> +									i++) {
> +				if (i < n)
> +					buf[i] = rx_array[i];
> +				else
> +					buf[i] = rx_array[n + i];
> +			}
> +			len = ST_SENSORS_BYTE_4CHANNEL*n;
> +		}
> +		break;
> +	case 3:
> +		len = adata->read_multiple_byte(adata, reg_addr[0],
> +			ST_SENSORS_BYTE_4CHANNEL*
> +			ST_SENSORS_NUMBER_DATA_CHANNELS,
> +			buf);
> +		break;
> +	default:
> +		len = -EINVAL;
> +		goto read_data_channels_error;
> +	}
> +	if (len != ST_SENSORS_BYTE_4CHANNEL*n) {
> +		len = -EIO;
> +		goto read_data_channels_error;
> +	}
> +
> +read_data_channels_error:
> +	return len;
> +}
> +
> +static irqreturn_t st_sensors_trigger_handler(int irq, void *p)
> +{
> +	int len;
> +	struct iio_poll_func *pf = p;
> +	struct iio_dev *indio_dev = pf->indio_dev;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	len = st_sensors_get_buffer_element(indio_dev, adata->buffer_data);
> +	if (len < 0)
> +		goto st_sensors_get_buffer_element_error;
> +
> +	if (indio_dev->scan_timestamp)
> +		*(s64 *)((u8 *)adata->buffer_data +
> +				ALIGN(len, sizeof(s64))) = pf->timestamp;
> +
> +	iio_push_to_buffers(indio_dev, adata->buffer_data);
> +
> +st_sensors_get_buffer_element_error:
> +	iio_trigger_notify_done(indio_dev->trig);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int st_sensors_buffer_postenable(struct iio_dev *indio_dev)
> +{
> +	int err, i;
> +	u8 active_bit = 0x00;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	adata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
> +	if (adata->buffer_data == NULL) {
> +		err = -ENOMEM;
> +		goto allocate_memory_error;
> +	}
> +
> +	for (i = 0; i < ST_SENSORS_NUMBER_DATA_CHANNELS; i++)
> +		if (test_bit(i, indio_dev->active_scan_mask))
> +			active_bit |= (1 << i);
> +
> +	err = st_sensors_set_axis_enable(indio_dev, active_bit);
> +	if (err < 0)
> +		goto st_sensors_buffer_postenable_error;
> +
> +	err = iio_triggered_buffer_postenable(indio_dev);
> +
> +	return err;
> +
> +st_sensors_buffer_postenable_error:
> +	kfree(adata->buffer_data);
> +allocate_memory_error:
> +	return err;
> +}
> +
> +static int st_sensors_buffer_predisable(struct iio_dev *indio_dev)
> +{
> +	int err;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	err = iio_triggered_buffer_predisable(indio_dev);
> +	if (err < 0)
> +		goto st_sensors_buffer_predisable_error;
> +
> +	err = st_sensors_set_axis_enable(indio_dev,
> +						ST_SENSORS_ENABLE_ALL_CHANNELS);
> +	if (err < 0)
> +		goto st_sensors_buffer_predisable_error;
don't bother with the goto given it doesn't go anywhere.  Note
various static analysers are going to pick this up so I give
you a about an hour after this hits the tree before patches removing
it turn up :)
> +
> +st_sensors_buffer_predisable_error:
> +	kfree(adata->buffer_data);
> +	return err;
> +}
> +
> +static const struct iio_buffer_setup_ops st_sensors_buffer_setup_ops = {
> +	.preenable = &iio_sw_buffer_preenable,
> +	.postenable = &st_sensors_buffer_postenable,
> +	.predisable = &st_sensors_buffer_predisable,
> +};
> +
> +int st_sensors_allocate_ring(struct iio_dev *indio_dev)
> +{
> +	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
> +		&st_sensors_trigger_handler, &st_sensors_buffer_setup_ops);
> +}
> +EXPORT_SYMBOL(st_sensors_allocate_ring);
> +
> +void st_sensors_deallocate_ring(struct iio_dev *indio_dev)
> +{
> +	iio_triggered_buffer_cleanup(indio_dev);
> +}
> +EXPORT_SYMBOL(st_sensors_deallocate_ring);
> diff --git a/drivers/iio/common/st-sensors/st_sensors_core.c b/drivers/iio/common/st-sensors/st_sensors_core.c
> new file mode 100644
> index 0000000..9b9e951
> --- /dev/null
> +++ b/drivers/iio/common/st-sensors/st_sensors_core.c
> @@ -0,0 +1,589 @@
> +/*
> + * STMicroelectronics sensors driver
> + *
> + * Copyright 2012 STMicroelectronics Inc.
> + *
> + * Denis Ciocca <denis.ciocca@xxxxxx>
> + *
> + * Licensed under the GPL-2.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/mutex.h>
> +#include <linux/interrupt.h>
> +#include <linux/i2c.h>
> +#include <linux/gpio.h>
> +#include <linux/irq.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <linux/iio/buffer.h>
> +
> +#include "st_sensors.h"
> +
One blank line is almost always enough (now I'm getting fussy ;)
> +
> +static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
> +				u8 reg_addr, u8 mask, short num_bit, u8 data)
> +{
> +	int err;
> +	u8 new_data;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	err = adata->read_byte(adata, reg_addr, &new_data);
> +	if (err < 0)
> +		goto st_sensors_write_data_with_mask_error;
> +
> +	new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask));
> +	err = adata->write_byte(adata, reg_addr, new_data);
> +
> +st_sensors_write_data_with_mask_error:
> +	return err;
> +}
> +
> +int st_sensors_match_odr(const struct st_sensors *sensor,
> +		unsigned int odr, struct st_sensors_odr_available *odr_out)
> +{
> +	int i, ret = -EINVAL;
> +
> +	for (i = 0; i < ARRAY_SIZE(sensor->odr.odr_avl); i++) {
> +		if (sensor->odr.odr_avl[i].hz == odr) {
> +			odr_out->hz = sensor->odr.odr_avl[i].hz;
> +			odr_out->value = sensor->odr.odr_avl[i].value;
> +			ret = 0;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +int st_sensors_match_fs(const struct st_sensors *sensor,
> +			unsigned int fs, struct st_sensors_fs_available *fs_out)
> +{
> +	int i, ret = -EINVAL;
> +
> +	for (i = 0; i < ARRAY_SIZE(sensor->fs.fs_avl); i++) {
> +		if (sensor->fs.fs_avl[i].num == fs) {
> +			fs_out->num = sensor->fs.fs_avl[i].num;
> +			fs_out->gain = sensor->fs.fs_avl[i].gain;
> +			fs_out->value = sensor->fs.fs_avl[i].value;
> +			ret = 0;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +int st_sensors_match_scale(const struct st_sensors *sensor,
> +			int scale, struct st_sensors_fs_available *fs_out)
> +{
> +	int i, ret = -EINVAL;
> +
> +	for (i = 0; i < ARRAY_SIZE(sensor->fs.fs_avl); i++) {
> +		if (sensor->fs.fs_avl[i].gain == scale) {
> +			fs_out->num = sensor->fs.fs_avl[i].num;
> +			fs_out->gain = sensor->fs.fs_avl[i].gain;
> +			fs_out->value = sensor->fs.fs_avl[i].value;
> +			ret = 0;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
> +{
> +	int err;
> +	struct st_sensors_data *adata;
> +
> +	adata = iio_priv(indio_dev);
> +	if (adata->st_sensors[adata->index].drdy_irq.ig1.en_addr > 0) {
> +		err = st_sensors_write_data_with_mask(indio_dev,
> +			adata->st_sensors[adata->index].drdy_irq.ig1.en_addr,
> +			adata->st_sensors[adata->index].drdy_irq.ig1.en_mask, 1,
> +			(int)enable);
> +		if (err < 0)
> +			goto st_sensors_set_dataready_irq_error;
> +	}
> +
> +	if (adata->st_sensors[adata->index].drdy_irq.ig1.latch_mask_addr > 0) {
> +		err = st_sensors_write_data_with_mask(indio_dev,
> +		adata->st_sensors[adata->index].drdy_irq.ig1.latch_mask_addr,
> +		adata->st_sensors[adata->index].drdy_irq.ig1.latching_mask, 1,
> +			(int)enable);
> +		if (err < 0)
> +			goto st_sensors_set_dataready_irq_error;
> +	}
> +
> +	err = st_sensors_write_data_with_mask(indio_dev,
> +		adata->st_sensors[adata->index].drdy_irq.addr,
> +		adata->st_sensors[adata->index].drdy_irq.mask, 1, (int)enable);
> +
> +st_sensors_set_dataready_irq_error:
> +	return err;
> +}
> +EXPORT_SYMBOL(st_sensors_set_dataready_irq);
> +
> +static int st_sensors_set_bdu(struct iio_dev *indio_dev,
> +				const struct st_sensors_bdu *bdu, bool value)
> +{
> +	return st_sensors_write_data_with_mask(indio_dev, bdu->addr, bdu->mask,
> +								1, (u8)value);
> +}
> +
> +static int st_sensors_set_odr(struct iio_dev *indio_dev,
> +				struct st_sensors_odr_available *odr_available)
> +{
> +	int err;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	if ((adata->st_sensors[adata->index].odr.addr ==
> +		adata->st_sensors[adata->index].pw.addr) &&
> +		(adata->st_sensors[adata->index].odr.mask ==
> +				adata->st_sensors[adata->index].pw.mask)) {
> +		if (adata->enabled == true) {
> +			err = st_sensors_write_data_with_mask(indio_dev,
> +				adata->st_sensors[adata->index].odr.addr,
> +				adata->st_sensors[adata->index].odr.mask,
> +				adata->st_sensors[adata->index].odr.num_bit,
> +				odr_available->value);
> +		} else {
> +			adata->odr = odr_available->hz;
> +			err = 0;
> +		}
> +	} else {
> +		err = st_sensors_write_data_with_mask(indio_dev,
> +				adata->st_sensors[adata->index].odr.addr,
> +				adata->st_sensors[adata->index].odr.mask,
> +				adata->st_sensors[adata->index].odr.num_bit,
> +				odr_available->value);
> +	}
> +
> +	return err;
> +}
> +
> +int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
> +{
> +	int err;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	err = st_sensors_write_data_with_mask(indio_dev,
> +			adata->st_sensors[adata->index].enable_axis.addr,
> +			adata->st_sensors[adata->index].enable_axis.mask,
> +			ST_SENSORS_DEF_AXIS_N_BIT, axis_enable);
> +
> +	return err;
Why introduce the temporary variable?

return st_sensors_write_data_with_mask(indio_dev,...

> +}
> +EXPORT_SYMBOL(st_sensors_set_axis_enable);
> +
> +static int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
> +{
> +	int err = -EINVAL;
> +	bool found;
> +	u8 tmp_value;
> +	struct st_sensors_odr_available odr_out;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	if (enable) {
> +		found = false;
> +		tmp_value = adata->st_sensors[adata->index].pw.value_on;
> +		if ((adata->st_sensors[adata->index].odr.addr ==
> +				adata->st_sensors[adata->index].pw.addr) &&
> +			(adata->st_sensors[adata->index].odr.mask ==
> +				adata->st_sensors[adata->index].pw.mask)) {
> +			err = st_sensors_match_odr(
> +				&adata->st_sensors[adata->index], adata->odr,
> +					&odr_out);
> +			if (err < 0)
> +				goto set_enable_error;
> +			tmp_value = odr_out.value;
> +			found = true;
> +		}
> +		err = st_sensors_write_data_with_mask(indio_dev,
> +				adata->st_sensors[adata->index].pw.addr,
> +				adata->st_sensors[adata->index].pw.mask,
> +				adata->st_sensors[adata->index].pw.num_bit,
> +				tmp_value);
> +		if (err < 0)
> +			goto set_enable_error;
> +		adata->enabled = true;
> +		if (found)
> +			adata->odr = odr_out.hz;
> +	} else {
> +		err = st_sensors_write_data_with_mask(indio_dev,
> +				adata->st_sensors[adata->index].pw.addr,
> +				adata->st_sensors[adata->index].pw.mask,
> +				adata->st_sensors[adata->index].pw.num_bit,
> +				adata->st_sensors[adata->index].pw.value_off);
> +		if (err < 0)
> +			goto set_enable_error;
> +		adata->enabled = false;
> +	}
> +
> +set_enable_error:
> +	return err;
> +}
> +
> +static int st_sensors_set_fullscale(struct iio_dev *indio_dev,
> +					struct st_sensors_fs_available *fs_avl)
> +{
> +	int err;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	err = st_sensors_write_data_with_mask(indio_dev,
> +				adata->st_sensors[adata->index].fs.addr,
> +				adata->st_sensors[adata->index].fs.mask,
> +				adata->st_sensors[adata->index].fs.num_bit,
> +				fs_avl->value);
> +	if (err < 0)
> +		goto st_sensors_set_fullscale_error;
> +
> +	adata->fullscale = fs_avl->num;
> +	adata->gain = fs_avl->gain;
> +	return err;
> +
> +st_sensors_set_fullscale_error:
> +	dev_err(&indio_dev->dev, "failed to set new fullscale.\n");
> +	return err;
> +}
> +
> +static int st_sensors_read_raw(struct iio_dev *indio_dev,
> +			struct iio_chan_spec const *ch, int *val,
> +							int *val2, long mask)
> +{
> +	int err;
> +	u8 outdata[ST_SENSORS_BYTE_4CHANNEL];
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		mutex_lock(&indio_dev->mlock);
> +		if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
> +			err = -EBUSY;
> +			goto read_error;
> +		} else {
> +			if (!adata->enabled) {
> +				err = -EIO;
> +				goto read_error;
> +			} else {
> +				err = adata->read_multiple_byte(adata,
> +					ch->address, ST_SENSORS_BYTE_4CHANNEL,
> +					outdata);
> +				if (err < 0)
> +					goto read_error;
> +
> +				*val = ((s16)le16_to_cpup((u16 *)outdata))
> +							>> ch->scan_type.shift;
> +			}
> +		}
> +		mutex_unlock(&indio_dev->mlock);
> +		return IIO_VAL_INT;
> +	case IIO_CHAN_INFO_SCALE:
> +		*val = 0;
> +		*val2 = adata->gain;
> +		return IIO_VAL_INT_PLUS_MICRO;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +read_error:
> +	mutex_unlock(&indio_dev->mlock);
> +	return err;
> +}
> +
> +static int st_sensors_write_raw(struct iio_dev *indio_dev,
> +		struct iio_chan_spec const *chan, int val, int val2, long mask)
> +{
> +	int err;
> +	struct st_sensors_fs_available fs_out;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_SCALE:
> +		err = st_sensors_match_scale(&adata->st_sensors[adata->index],
> +								val2, &fs_out);
> +		if (err < 0)
> +			goto write_error;
> +
> +		err = st_sensors_set_fullscale(indio_dev, &fs_out);
> +		break;
> +	default:
> +		err = -EINVAL;
> +	}
> +
> +write_error:
> +	return err;
> +}
> +
> +static ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev,
> +		struct device_attribute *attr, const char *buf, size_t size)
> +{
> +	int err;
> +	unsigned int freq;
> +	struct st_sensors_odr_available odr_out;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	err = kstrtoint(buf, 10, &freq);
> +	if (err < 0)
> +		goto conversion_error;
> +
> +	mutex_lock(&indio_dev->mlock);
> +	err = st_sensors_match_odr(&adata->st_sensors[adata->index],
> +								freq, &odr_out);
> +	if (err < 0)
> +		goto st_sensors_sysfs_set_sampling_frequency_error;
> +
> +	err = st_sensors_set_odr(indio_dev, &odr_out);
> +	if (err < 0)
> +		goto st_sensors_sysfs_set_sampling_frequency_error;
> +
> +	adata->odr = odr_out.hz;
> +
> +st_sensors_sysfs_set_sampling_frequency_error:
> +	mutex_unlock(&indio_dev->mlock);
> +conversion_error:
> +	return err < 0 ? err : size;
> +}
> +
> +static ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%d\n", adata->odr);
> +}
> +
> +static ssize_t st_sensors_sysfs_set_powerdown(struct device *dev,
> +		struct device_attribute *attr, const char *buf, size_t size)
> +{
> +	int err;
> +	bool powerdown;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +
> +	err = strtobool(buf, &powerdown);
> +	if (err < 0)
> +		goto set_enable_error;
> +
> +	mutex_lock(&indio_dev->mlock);
> +	err = st_sensors_set_enable(indio_dev, !powerdown);
> +	mutex_unlock(&indio_dev->mlock);
> +
> +set_enable_error:
> +	return err < 0 ? err : size;
> +}
> +
> +static ssize_t st_sensors_sysfs_get_powerdown(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	return sprintf(buf, "%d\n", (int)(!adata->enabled));
> +}
> +
> +static ssize_t st_sensors_sysfs_scale_available(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	int i, len = 0;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	mutex_lock(&indio_dev->mlock);
> +	for (i = 0; i < ARRAY_SIZE(adata->st_sensors[adata->index].fs.fs_avl);
> +									i++) {
> +		if (adata->st_sensors[adata->index].fs.fs_avl[i].num == 0)
> +			break;
> +
> +		len += sprintf(buf+len, "0.%06u ",
> +			adata->st_sensors[adata->index].fs.fs_avl[i].gain);
> +	}
> +	mutex_unlock(&indio_dev->mlock);
> +	buf[len-1] = '\n';
> +
> +	return len;
> +}
> +
> +static ssize_t st_sensors_sysfs_sampling_frequency_available(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	int i, len = 0;
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	mutex_lock(&indio_dev->mlock);
> +	for (i = 0; i < ARRAY_SIZE(adata->st_sensors[adata->index].odr.odr_avl);
> +									i++) {
> +		if (adata->st_sensors[adata->index].odr.odr_avl[i].hz == 0)
> +			break;
> +
> +		len += sprintf(buf + len, "%d ",
> +			adata->st_sensors[adata->index].odr.odr_avl[i].hz);
> +	}
> +	mutex_unlock(&indio_dev->mlock);
> +	buf[len - 1] = '\n';
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO,
> +		st_sensors_sysfs_sampling_frequency_available, NULL , 0);
> +
> +static IIO_DEVICE_ATTR(in_sensors_scale_available, S_IRUGO,
> +				st_sensors_sysfs_scale_available, NULL , 0);
> +
> +static IIO_DEVICE_ATTR(powerdown, S_IWUSR | S_IRUGO,
> +		st_sensors_sysfs_get_powerdown,
> +					st_sensors_sysfs_set_powerdown , 0);
> +
> +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
> +			st_sensors_sysfs_get_sampling_frequency,
> +				st_sensors_sysfs_set_sampling_frequency);
> +
> +static struct attribute *st_sensor_attributes[] = {
> +	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
> +	&iio_dev_attr_in_sensors_scale_available.dev_attr.attr,
> +	&iio_dev_attr_powerdown.dev_attr.attr,
> +	&iio_dev_attr_sampling_frequency.dev_attr.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group st_sensor_attribute_group = {
> +	.attrs = st_sensor_attributes,
> +};
> +
> +static const struct iio_info sensor_info = {
> +	.driver_module = THIS_MODULE,
> +	.attrs = &st_sensor_attribute_group,
> +	.read_raw = &st_sensors_read_raw,
> +	.write_raw = &st_sensors_write_raw,
> +};
> +
> +static int st_sensors_get_wai_device(struct iio_dev *indio_dev, u8 reg_addr,
> +								u8 *value)
> +{
> +	int ret;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	ret = adata->read_byte(adata, reg_addr, value);
> +	if (ret < 0)
> +		goto read_byte_wai_error;
> +
> +	return 0;
> +
> +read_byte_wai_error:
> +	dev_err(&indio_dev->dev,
> +			"failed to read WhoAmI (register 0x%x).\n", reg_addr);
> +	return -EIO;
> +}
> +
> +static int st_init_sensor(struct iio_dev *indio_dev, int wai)
> +{
> +	int err;
> +
This is the one bit I don't like as explained at the top of this review.
Dependencies are all the wrong way around.  This common core code should
have no knowledge of its users.

> +	err = st_accel_init_sensor(indio_dev, wai);
> +	if (err < 0)
> +		err = st_gyro_init_sensor(indio_dev, wai);
> +
> +	if (err < 0)
> +		dev_err(&indio_dev->dev,
> +				"device not supported -> wai (0x%x).\n", wai);
> +
> +	return err;
> +}
> +
> +int st_sensors_iio_probe(struct iio_dev *indio_dev, int irq)
> +{
> +	int err;
> +	u8 wai;
> +	struct st_sensors_odr_available odr_out;
> +	struct st_sensors_fs_available fs_out;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +
> +	err = st_sensors_get_wai_device(indio_dev,
> +					ST_SENSORS_DEF_WAI_ADDRESS, &wai);
> +	if (err < 0)
> +		goto st_sensors_iio_probe_error;
> +
> +	err = st_init_sensor(indio_dev, wai);
> +	if (err < 0)
> +		goto st_sensors_iio_probe_error;
> +
> +	indio_dev->info = &sensor_info;
> +	adata->multiread_bit = adata->st_sensors[adata->index].multi_read_bit;
Is it worth keeping a copy of this?

> +	indio_dev->channels = adata->st_sensors[adata->index].ch;
> +	indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
> +
> +	adata->fullscale = adata->st_sensors[adata->index].fs.fs_avl[0].num;
> +	adata->odr = adata->st_sensors[adata->index].odr.odr_avl[0].hz;
> +
> +	err = st_sensors_set_enable(indio_dev, false);
> +	if (err < 0)
> +		goto st_sensors_iio_probe_error;
> +
> +	err = st_sensors_set_axis_enable(indio_dev,
> +						ST_SENSORS_ENABLE_ALL_CHANNELS);
> +	if (err < 0)
> +		goto st_sensors_iio_probe_error;
> +
> +	st_sensors_match_fs(&adata->st_sensors[adata->index],
> +						adata->fullscale, &fs_out);
> +	err = st_sensors_set_fullscale(indio_dev, &fs_out);
> +	if (err < 0)
> +		goto st_sensors_iio_probe_error;
> +
> +	st_sensors_match_odr(&adata->st_sensors[adata->index],
> +							adata->odr, &odr_out);
> +	err = st_sensors_set_odr(indio_dev, &odr_out);
> +	if (err < 0)
> +		goto st_sensors_iio_probe_error;
> +
> +	err = st_sensors_set_bdu(indio_dev,
> +				&adata->st_sensors[adata->index].bdu, true);
> +
> +	err = st_sensors_allocate_ring(indio_dev);
> +	if (err < 0)
> +		goto st_sensors_iio_probe_error;
> +
> +	if (irq > 0) {
> +		err = st_sensors_probe_trigger(indio_dev, irq);
> +		if (err < 0)
> +			goto acc_probe_trigger_error;
> +	}
> +
> +	err = iio_device_register(indio_dev);
> +	if (err)
> +		goto iio_device_register_error;
> +
> +	return err;
> +
> +iio_device_register_error:
> +	st_sensors_remove_trigger(indio_dev, irq);
> +acc_probe_trigger_error:
> +	st_sensors_deallocate_ring(indio_dev);
> +st_sensors_iio_probe_error:
> +	return err;
> +}
> +EXPORT_SYMBOL(st_sensors_iio_probe);
> +
> +void st_sensors_iio_remove(struct iio_dev *indio_dev, int irq)
> +{
> +	iio_device_unregister(indio_dev);
> +	st_sensors_remove_trigger(indio_dev, irq);
> +	st_sensors_deallocate_ring(indio_dev);
> +	iio_device_free(indio_dev);
> +}
> +EXPORT_SYMBOL(st_sensors_iio_remove);
> +
> +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@xxxxxx>");
> +MODULE_DESCRIPTION("STMicroelectronics sensors core driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/iio/common/st-sensors/st_sensors_i2c.c b/drivers/iio/common/st-sensors/st_sensors_i2c.c
> new file mode 100644
> index 0000000..2d2d5ee
> --- /dev/null
> +++ b/drivers/iio/common/st-sensors/st_sensors_i2c.c
> @@ -0,0 +1,137 @@
> +/*
> + * STMicroelectronics sensors driver
> + *
> + * Copyright 2012 STMicroelectronics Inc.
> + *
> + * Denis Ciocca <denis.ciocca@xxxxxx>
> + *
> + * Licensed under the GPL-2.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/trigger.h>
> +
> +#include "st_sensors.h"
> +
> +#define ST_SENSORS_I2C_MULTIREAD		0x80
> +
> +static int st_sensors_i2c_read_byte(struct st_sensors_data *adata,
> +						u8 reg_addr, u8 *res_byte)
> +{
> +	int err;
> +
> +	err = i2c_smbus_read_byte_data(to_i2c_client(adata->dev), reg_addr);
> +	if (err < 0)
> +		goto st_sensors_i2c_read_byte_error;
> +
> +	*res_byte = err & 0xff;
> +
> +st_sensors_i2c_read_byte_error:
> +	return err < 0 ? err : 0;
> +}
> +
> +static int st_sensors_i2c_read_multiple_byte(struct st_sensors_data *adata,
> +						u8 reg_addr, int len, u8 *data)
> +{
> +	if (adata->multiread_bit == true)
> +		reg_addr |= ST_SENSORS_I2C_MULTIREAD;
> +
> +	return i2c_smbus_read_i2c_block_data(to_i2c_client(adata->dev),
> +							reg_addr, len, data);
> +}
> +
> +static int st_sensors_i2c_write_byte(struct st_sensors_data *adata,
> +							u8 reg_addr, u8 data)
> +{
> +	return i2c_smbus_write_byte_data(to_i2c_client(adata->dev),
> +								reg_addr, data);
> +}
> +
> +static int __devinit st_sensors_i2c_probe(struct i2c_client *client,
> +				const struct i2c_device_id *id)
> +{
> +	struct iio_dev *indio_dev;
> +	struct st_sensors_data *adata;
> +	int err;
> +
> +	indio_dev = iio_device_alloc(sizeof(*adata));
> +	if (indio_dev == NULL) {
> +		err = -ENOMEM;
> +		goto iio_device_alloc_error;
> +	}
> +
> +	adata = iio_priv(indio_dev);
> +	adata->dev = &client->dev;
> +	i2c_set_clientdata(client, indio_dev);
> +
> +	indio_dev->dev.parent = &client->dev;
> +	indio_dev->name = client->name;
> +
> +	adata->read_byte = st_sensors_i2c_read_byte;
> +	adata->write_byte = st_sensors_i2c_write_byte;
> +	adata->read_multiple_byte = st_sensors_i2c_read_multiple_byte;
> +
> +	err = st_sensors_iio_probe(indio_dev, client->irq);
> +	if (err < 0)
> +		goto acc_iio_default_error;
> +
> +	return 0;
> +
> +acc_iio_default_error:
> +	iio_device_free(indio_dev);
> +iio_device_alloc_error:
> +	return err;
> +}
> +
> +static int st_sensors_i2c_remove(struct i2c_client *client)
> +{
> +	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> +	st_sensors_iio_remove(indio_dev, client->irq);
> +
> +	return 0;
> +}
> +
> +static const struct i2c_device_id st_sensors_id_table[] = {
> +	{ LSM303DLH_ACCEL_DEV_NAME },
> +	{ LSM303DLHC_ACCEL_DEV_NAME },
> +	{ LIS3DH_ACCEL_DEV_NAME },
> +	{ LSM330D_ACCEL_DEV_NAME },
> +	{ LSM330DL_ACCEL_DEV_NAME },
> +	{ LSM330DLC_ACCEL_DEV_NAME },
> +	{ LSM303D_ACCEL_DEV_NAME },
> +	{ LSM9DS0_ACCEL_DEV_NAME },
> +	{ LIS331DLH_ACCEL_DEV_NAME },
> +	{ LSM303DL_ACCEL_DEV_NAME },
> +	{ LSM303DLM_ACCEL_DEV_NAME },
> +	{ LSM330_ACCEL_DEV_NAME },
> +	{ L3G4200D_GYRO_DEV_NAME },
> +	{ LSM330DL_GYRO_DEV_NAME },
> +	{ L3GD20_GYRO_DEV_NAME },
> +	{ L3GD20H_GYRO_DEV_NAME },
> +	{ LSM330D_GYRO_DEV_NAME },
> +	{ LSM330DLC_GYRO_DEV_NAME },
> +	{ LSM9DS0_GYRO_DEV_NAME },
> +	{ L3G4IS_GYRO_DEV_NAME },
> +	{ LSM330_GYRO_DEV_NAME },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(i2c, st_sensors_id_table);
> +
> +static struct i2c_driver st_sensors_driver = {
> +	.driver = {
> +		.owner = THIS_MODULE,
> +		.name = "st-sensors-i2c",
> +	},
> +	.probe = st_sensors_i2c_probe,
> +	.remove = st_sensors_i2c_remove,
> +	.id_table = st_sensors_id_table,
> +};
> +module_i2c_driver(st_sensors_driver);
> +
> +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@xxxxxx>");
> +MODULE_DESCRIPTION("STMicroelectronics sensors i2c driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/iio/common/st-sensors/st_sensors_spi.c b/drivers/iio/common/st-sensors/st_sensors_spi.c
> new file mode 100644
> index 0000000..1df0c80
> --- /dev/null
> +++ b/drivers/iio/common/st-sensors/st_sensors_spi.c
> @@ -0,0 +1,183 @@
> +/*
> + * STMicroelectronics sensors driver
> + *
> + * Copyright 2012 STMicroelectronics Inc.
> + *
> + * Denis Ciocca <denis.ciocca@xxxxxx>
> + *
> + * Licensed under the GPL-2.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/spi/spi.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/trigger.h>
> +
> +#include "st_sensors.h"
> +
> +
> +#define ST_SENSORS_SPI_READ		0x80;
> +#define ST_SENSORS_SPI_MULTIREAD	0xc0
> +
> +static int st_sensors_spi_read(struct st_sensors_data *adata,
> +						u8 reg_addr, int len, u8 *data)
> +{
> +	struct spi_message msg;
> +	int err;
> +
> +	struct spi_transfer xfers[] = {
> +		{
> +			.tx_buf = adata->tx_buf,
> +			.bits_per_word = 8,
> +			.len = 1,
> +		},
> +		{
> +			.rx_buf = adata->rx_buf,
> +			.bits_per_word = 8,
> +			.len = len,
> +		}
> +	};
> +
> +	mutex_lock(&adata->buf_lock);
> +	if ((adata->multiread_bit == true) && (len > 1))
> +		adata->tx_buf[0] = reg_addr | ST_SENSORS_SPI_MULTIREAD;
> +	else
> +		adata->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ;
> +
> +	spi_message_init(&msg);
> +	spi_message_add_tail(&xfers[0], &msg);
> +	spi_message_add_tail(&xfers[1], &msg);
> +	err = spi_sync(to_spi_device(adata->dev), &msg);
> +	if (err)
> +		goto acc_spi_read_error;
> +
> +	memcpy(data, adata->rx_buf, len*sizeof(u8));
> +	mutex_unlock(&adata->buf_lock);
> +	return len;
> +
> +acc_spi_read_error:
> +	return err;
> +}
> +
> +static int st_sensors_spi_read_byte(struct st_sensors_data *adata,
> +						u8 reg_addr, u8 *res_byte)
> +{
> +	return st_sensors_spi_read(adata, reg_addr, 1, res_byte);
> +}
> +
> +static int st_sensors_spi_read_multiple_byte(struct st_sensors_data *adata,
> +						u8 reg_addr, int len, u8 *data)
> +{
> +	return st_sensors_spi_read(adata, reg_addr, len, data);
> +}
> +
> +static int st_sensors_spi_write_byte(struct st_sensors_data *adata,
> +							u8 reg_addr, u8 data)
> +{
> +	struct spi_message msg;
> +	int err;
> +
> +	struct spi_transfer xfers = {
> +		.tx_buf = adata->tx_buf,
> +		.bits_per_word = 8,
> +		.len = 2,
> +	};
> +
> +	mutex_lock(&adata->buf_lock);
> +	adata->tx_buf[0] = reg_addr;
> +	adata->tx_buf[1] = data;
> +
> +	spi_message_init(&msg);
> +	spi_message_add_tail(&xfers, &msg);
> +	err = spi_sync(to_spi_device(adata->dev), &msg);
> +	mutex_unlock(&adata->buf_lock);
> +
> +	return err;
> +}
> +
> +static int __devinit st_sensors_spi_probe(struct spi_device *spi)
> +{
> +	struct iio_dev *indio_dev;
> +	struct st_sensors_data *adata;
> +	int err;
> +
> +	indio_dev = iio_device_alloc(sizeof(*adata));
> +	if (indio_dev == NULL) {
> +		err = -ENOMEM;
> +		goto iio_device_alloc_error;
> +	}
> +
> +	adata = iio_priv(indio_dev);
> +	adata->dev = &spi->dev;
> +	spi_set_drvdata(spi, indio_dev);
> +
> +	indio_dev->dev.parent = &spi->dev;
> +	indio_dev->name = spi->modalias;
> +
> +	mutex_init(&adata->buf_lock);
> +	adata->read_byte = st_sensors_spi_read_byte;
> +	adata->write_byte = st_sensors_spi_write_byte;
> +	adata->read_multiple_byte = st_sensors_spi_read_multiple_byte;
> +
> +	err = st_sensors_iio_probe(indio_dev, spi->irq);
> +	if (err < 0)
> +		goto acc_iio_default_error;
> +
> +	return 0;
> +
> +acc_iio_default_error:
> +	iio_device_free(indio_dev);
> +iio_device_alloc_error:
> +	return err;
> +}
> +
> +static int st_sensors_spi_remove(struct spi_device *spi)
> +{
> +	struct iio_dev *indio_dev = spi_get_drvdata(spi);
> +	st_sensors_iio_remove(indio_dev, spi->irq);
st_sensors_iio_remove(spi_get_drvdata(spi), spi->irq);


> +
> +	return 0;
> +}
> +
> +static const struct spi_device_id st_sensors_id_table[] = {
> +	{ LSM303DLH_ACCEL_DEV_NAME },
> +	{ LSM303DLHC_ACCEL_DEV_NAME },
> +	{ LIS3DH_ACCEL_DEV_NAME },
> +	{ LSM330D_ACCEL_DEV_NAME },
> +	{ LSM330DL_ACCEL_DEV_NAME },
> +	{ LSM330DLC_ACCEL_DEV_NAME },
> +	{ LSM303D_ACCEL_DEV_NAME },
> +	{ LSM9DS0_ACCEL_DEV_NAME },
> +	{ LIS331DLH_ACCEL_DEV_NAME },
> +	{ LSM303DL_ACCEL_DEV_NAME },
> +	{ LSM303DLM_ACCEL_DEV_NAME },
> +	{ LSM330_ACCEL_DEV_NAME },
> +	{ L3G4200D_GYRO_DEV_NAME },
> +	{ LSM330DL_GYRO_DEV_NAME },
> +	{ L3GD20_GYRO_DEV_NAME },
> +	{ L3GD20H_GYRO_DEV_NAME },
> +	{ LSM330D_GYRO_DEV_NAME },
> +	{ LSM330DLC_GYRO_DEV_NAME },
> +	{ LSM9DS0_GYRO_DEV_NAME },
> +	{ L3G4IS_GYRO_DEV_NAME },
> +	{ LSM330_GYRO_DEV_NAME },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(spi, st_sensors_id_table);
> +
> +static struct spi_driver st_sensors_driver = {
> +	.driver = {
> +		.owner = THIS_MODULE,
> +		.name = "st-sensors-spi",
> +	},
> +	.probe = st_sensors_spi_probe,
> +	.remove = st_sensors_spi_remove,
> +	.id_table = st_sensors_id_table,
> +};
> +module_spi_driver(st_sensors_driver);
> +
> +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@xxxxxx>");
> +MODULE_DESCRIPTION("STMicroelectronics sensors spi driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/iio/common/st-sensors/st_sensors_trigger.c b/drivers/iio/common/st-sensors/st_sensors_trigger.c
> new file mode 100644
> index 0000000..37dadc2
> --- /dev/null
> +++ b/drivers/iio/common/st-sensors/st_sensors_trigger.c
> @@ -0,0 +1,83 @@
> +/*
> + * STMicroelectronics sensors driver
> + *
> + * Copyright 2012 STMicroelectronics Inc.
> + *
> + * Denis Ciocca <denis.ciocca@xxxxxx>
> + *
> + * Licensed under the GPL-2.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/stat.h>
> +#include <linux/interrupt.h>
> +#include <linux/i2c.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/trigger.h>
> +
> +#include "st_sensors.h"
> +
> +static int st_sensors_trig_acc_set_state(struct iio_trigger *trig, bool state)
> +{
> +	struct iio_dev *indio_dev = trig->private_data;
> +	return st_sensors_set_dataready_irq(indio_dev, state);
> +}
> +
> +static const struct iio_trigger_ops st_sensors_trigger_ops = {
> +	.owner = THIS_MODULE,
> +	.set_trigger_state = &st_sensors_trig_acc_set_state,
> +};
> +
> +int st_sensors_probe_trigger(struct iio_dev *indio_dev, int irq)
> +{
> +	int err;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	adata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
> +	if (adata->trig == NULL) {
> +		err = -ENOMEM;
> +		dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
> +		goto iio_trigger_alloc_error;
> +	}
> +
> +	err = request_threaded_irq(irq,
> +			iio_trigger_generic_data_rdy_poll,
> +			NULL,
> +			IRQF_TRIGGER_RISING,
> +			adata->trig->name,
> +			adata->trig);
> +	if (err)
> +		goto request_irq_error;
> +
> +	adata->trig->private_data = indio_dev;
> +	adata->trig->ops = &st_sensors_trigger_ops;
> +	adata->trig->dev.parent = adata->dev;
> +
> +	err = iio_trigger_register(adata->trig);
> +	if (err < 0) {
> +		dev_err(&indio_dev->dev, "failed to register iio trigger.\n");
> +		goto iio_trigger_register_error;
> +	}
> +	indio_dev->trig = adata->trig;
> +
> +	return 0;
> +
> +iio_trigger_register_error:
> +	free_irq(irq, adata->trig);
> +request_irq_error:
> +	iio_trigger_free(adata->trig);
> +iio_trigger_alloc_error:
> +	return err;
> +}
> +EXPORT_SYMBOL(st_sensors_probe_trigger);
> +
> +void st_sensors_remove_trigger(struct iio_dev *indio_dev, int irq)
> +{
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +
> +	iio_trigger_unregister(adata->trig);
> +	free_irq(irq, adata->trig);
> +	iio_trigger_free(adata->trig);
> +}
> +EXPORT_SYMBOL(st_sensors_remove_trigger);
> diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
> index 21e27e2..3e8b746 100644
> --- a/drivers/iio/gyro/Kconfig
> +++ b/drivers/iio/gyro/Kconfig
> @@ -13,4 +13,18 @@ config HID_SENSOR_GYRO_3D
>  	  Say yes here to build support for the HID SENSOR
>  	  Gyroscope 3D.
>
> +config ST_GYRO_3D
> +	tristate "STMicroelectronics gyroscopes 3-Axis Driver"
> +	depends on (I2C || SPI_MASTER) && SYSFS
> +	select IIO_BUFFER
> +	select IIO_TRIGGERED_BUFFER
> +	select ST_SENSORS_IIO_COMMON
> +	help
> +	  Say yes here to build support for STMicroelectronics gyroscopes:
> +	  L3G4200D, LSM330DL, L3GD20, L3GD20H, LSM330D, LSM330DL, LSM330DLC,
> +	  LSM9DS0, L3G4IS, LSM330.
> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called st_gyro.
> +
>  endmenu
> diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile
> index 8a895d9..6a0a0d1 100644
> --- a/drivers/iio/gyro/Makefile
> +++ b/drivers/iio/gyro/Makefile
> @@ -3,3 +3,4 @@
>  #
>
>  obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
> +obj-$(CONFIG_ST_GYRO_3D) += st_gyro.o
> diff --git a/drivers/iio/gyro/st_gyro.c b/drivers/iio/gyro/st_gyro.c
> new file mode 100644
> index 0000000..a483f19
> --- /dev/null
> +++ b/drivers/iio/gyro/st_gyro.c
> @@ -0,0 +1,252 @@
> +/*
> + * STMicroelectronics gyroscopes driver
> + *
> + * Copyright 2012 STMicroelectronics Inc.
> + *
> + * Denis Ciocca <denis.ciocca@xxxxxx>
> + *
> + * Licensed under the GPL-2.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/mutex.h>
> +#include <linux/interrupt.h>
> +#include <linux/i2c.h>
> +#include <linux/gpio.h>
> +#include <linux/irq.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <linux/iio/buffer.h>
> +
> +#include "../common/st-sensors/st_sensors.h"
> +
1 blank line is almost always enough.
> +
> +/* FULLSCALE */
> +#define ST_GYRO_FS_AVL_250DPS			250
> +#define ST_GYRO_FS_AVL_500DPS			500
> +#define ST_GYRO_FS_AVL_2000DPS			2000
> +
> +/* CUSTOM VALUES FOR SENSOR 1 */
> +#define ST_GYRO_1_WAI_EXP			0xd3
> +#define ST_GYRO_1_ODR_ADDR			0x20
> +#define ST_GYRO_1_ODR_MASK			0xc0
> +#define ST_GYRO_1_ODR_N_BIT			2
> +#define ST_GYRO_1_ODR_AVL_100HZ_VAL		0x00
> +#define ST_GYRO_1_ODR_AVL_200HZ_VAL		0x01
> +#define ST_GYRO_1_ODR_AVL_400HZ_VAL		0x02
> +#define ST_GYRO_1_ODR_AVL_800HZ_VAL		0x03
> +#define ST_GYRO_1_PW_ADDR			0x20
> +#define ST_GYRO_1_PW_MASK			0x08
> +#define ST_GYRO_1_PW_N_BIT			1
> +#define ST_GYRO_1_FS_N_BIT			2
> +#define ST_GYRO_1_FS_ADDR			0x23
> +#define ST_GYRO_1_FS_MASK			0x30
> +#define ST_GYRO_1_FS_AVL_250_VAL		0x00
> +#define ST_GYRO_1_FS_AVL_500_VAL		0x01
> +#define ST_GYRO_1_FS_AVL_2000_VAL		0x02
> +#define ST_GYRO_1_FS_AVL_250_GAIN		IIO_DEGREE_TO_RAD(8750)
> +#define ST_GYRO_1_FS_AVL_500_GAIN		IIO_DEGREE_TO_RAD(17500)
> +#define ST_GYRO_1_FS_AVL_2000_GAIN		IIO_DEGREE_TO_RAD(70000)
> +#define ST_GYRO_1_BDU_ADDR			0x23
> +#define ST_GYRO_1_BDU_MASK			0x80
> +#define ST_GYRO_1_DRDY_IRQ_ADDR			0x22
> +#define ST_GYRO_1_DRDY_IRQ_MASK			0x08
> +#define ST_GYRO_1_MULTIREAD_BIT			true
> +
> +/* CUSTOM VALUES FOR SENSOR 2 */
> +#define ST_GYRO_2_WAI_EXP			0xd4
> +#define ST_GYRO_2_ODR_ADDR			0x20
> +#define ST_GYRO_2_ODR_MASK			0xc0
> +#define ST_GYRO_2_ODR_N_BIT			2
> +#define ST_GYRO_2_ODR_AVL_95HZ_VAL		0x00
> +#define ST_GYRO_2_ODR_AVL_190HZ_VAL		0x01
> +#define ST_GYRO_2_ODR_AVL_380HZ_VAL		0x02
> +#define ST_GYRO_2_ODR_AVL_760HZ_VAL		0x03
> +#define ST_GYRO_2_PW_ADDR			0x20
> +#define ST_GYRO_2_PW_MASK			0x08
> +#define ST_GYRO_2_PW_N_BIT			1
> +#define ST_GYRO_2_FS_N_BIT			2
> +#define ST_GYRO_2_FS_ADDR			0x23
> +#define ST_GYRO_2_FS_MASK			0x30
> +#define ST_GYRO_2_FS_AVL_250_VAL		0x00
> +#define ST_GYRO_2_FS_AVL_500_VAL		0x01
> +#define ST_GYRO_2_FS_AVL_2000_VAL		0x02
> +#define ST_GYRO_2_FS_AVL_250_GAIN		IIO_DEGREE_TO_RAD(8750)
> +#define ST_GYRO_2_FS_AVL_500_GAIN		IIO_DEGREE_TO_RAD(17500)
> +#define ST_GYRO_2_FS_AVL_2000_GAIN		IIO_DEGREE_TO_RAD(70000)
> +#define ST_GYRO_2_BDU_ADDR			0x23
> +#define ST_GYRO_2_BDU_MASK			0x80
> +#define ST_GYRO_2_DRDY_IRQ_ADDR			0x22
> +#define ST_GYRO_2_DRDY_IRQ_MASK			0x08
> +#define ST_GYRO_2_MULTIREAD_BIT			true
> +
> +const struct iio_chan_spec st_gyro_16bit_channels[] = {
> +	ST_LSM_CHANNELS(IIO_ANGL_VEL, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
> +		ST_SENSORS_DEF_16_REALBITS, ST_SENSORS_DEF_OUT_X_L_ADDR),
> +	ST_LSM_CHANNELS(IIO_ANGL_VEL, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
> +		ST_SENSORS_DEF_16_REALBITS, ST_SENSORS_DEF_OUT_Y_L_ADDR),
> +	ST_LSM_CHANNELS(IIO_ANGL_VEL, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
> +		ST_SENSORS_DEF_16_REALBITS, ST_SENSORS_DEF_OUT_Z_L_ADDR),
> +	IIO_CHAN_SOFT_TIMESTAMP(3)
> +};
> +
> +const struct st_sensors st_gyro_sensors[] = {
> +	{
> +		.wai = ST_GYRO_1_WAI_EXP,
> +		.ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
> +		.odr = {
> +			.addr = ST_GYRO_1_ODR_ADDR,
> +			.mask = ST_GYRO_1_ODR_MASK,
> +			.num_bit = ST_GYRO_1_ODR_N_BIT,
> +			.odr_avl = {
> +				{ 100, ST_GYRO_1_ODR_AVL_100HZ_VAL, },
> +				{ 200, ST_GYRO_1_ODR_AVL_200HZ_VAL, },
> +				{ 400, ST_GYRO_1_ODR_AVL_400HZ_VAL, },
> +				{ 800, ST_GYRO_1_ODR_AVL_800HZ_VAL, },
> +			},
> +		},
> +		.pw = {
> +			.addr = ST_GYRO_1_PW_ADDR,
> +			.mask = ST_GYRO_1_PW_MASK,
> +			.num_bit = ST_GYRO_1_PW_N_BIT,
> +			.value_on = ST_SENSORS_DEF_POWER_ON_VALUE,
> +			.value_off = ST_SENSORS_DEF_POWER_OFF_VALUE,
> +		},
> +		.enable_axis = {
> +			.addr = ST_SENSORS_DEF_AXIS_ADDR,
> +			.mask = ST_SENSORS_DEF_AXIS_MASK,
> +		},
> +		.fs = {
> +			.addr = ST_GYRO_1_FS_ADDR,
> +			.mask = ST_GYRO_1_FS_MASK,
> +			.num_bit = ST_GYRO_1_FS_N_BIT,
> +			.fs_avl = {
> +				[0] = {
> +					.num = ST_GYRO_FS_AVL_250DPS,
> +					.value = ST_GYRO_1_FS_AVL_250_VAL,
> +					.gain = ST_GYRO_1_FS_AVL_250_GAIN,
> +				},
> +				[1] = {
> +					.num = ST_GYRO_FS_AVL_500DPS,
> +					.value = ST_GYRO_1_FS_AVL_500_VAL,
> +					.gain = ST_GYRO_1_FS_AVL_500_GAIN,
> +				},
> +				[2] = {
> +					.num = ST_GYRO_FS_AVL_2000DPS,
> +					.value = ST_GYRO_1_FS_AVL_2000_VAL,
> +					.gain = ST_GYRO_1_FS_AVL_2000_GAIN,
> +				},
> +			},
> +		},
> +		.bdu = {
> +			.addr = ST_GYRO_1_BDU_ADDR,
> +			.mask = ST_GYRO_1_BDU_MASK,
> +		},
> +		.drdy_irq = {
> +			.addr = ST_GYRO_1_DRDY_IRQ_ADDR,
> +			.mask = ST_GYRO_1_DRDY_IRQ_MASK,
> +		},
> +		.multi_read_bit = ST_GYRO_1_MULTIREAD_BIT,
> +	},
> +	{
> +		.wai = ST_GYRO_2_WAI_EXP,
> +		.ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
> +		.odr = {
> +			.addr = ST_GYRO_2_ODR_ADDR,
> +			.mask = ST_GYRO_2_ODR_MASK,
> +			.num_bit = ST_GYRO_2_ODR_N_BIT,
> +			.odr_avl = {
> +				{ 95, ST_GYRO_2_ODR_AVL_95HZ_VAL, },
> +				{ 190, ST_GYRO_2_ODR_AVL_190HZ_VAL, },
> +				{ 380, ST_GYRO_2_ODR_AVL_380HZ_VAL, },
> +				{ 760, ST_GYRO_2_ODR_AVL_760HZ_VAL, },
> +			},
> +		},
> +		.pw = {
> +			.addr = ST_GYRO_2_PW_ADDR,
> +			.mask = ST_GYRO_2_PW_MASK,
> +			.num_bit = ST_GYRO_2_PW_N_BIT,
> +			.value_on = ST_SENSORS_DEF_POWER_ON_VALUE,
> +			.value_off = ST_SENSORS_DEF_POWER_OFF_VALUE,
> +		},
> +		.enable_axis = {
> +			.addr = ST_SENSORS_DEF_AXIS_ADDR,
> +			.mask = ST_SENSORS_DEF_AXIS_MASK,
> +		},
> +		.fs = {
> +			.addr = ST_GYRO_2_FS_ADDR,
> +			.mask = ST_GYRO_2_FS_MASK,
> +			.num_bit = ST_GYRO_2_FS_N_BIT,
> +			.fs_avl = {
> +				[0] = {
> +					.num = ST_GYRO_FS_AVL_250DPS,
> +					.value = ST_GYRO_2_FS_AVL_250_VAL,
> +					.gain = ST_GYRO_2_FS_AVL_250_GAIN,
> +				},
> +				[1] = {
> +					.num = ST_GYRO_FS_AVL_500DPS,
> +					.value = ST_GYRO_2_FS_AVL_500_VAL,
> +					.gain = ST_GYRO_2_FS_AVL_500_GAIN,
> +				},
> +				[2] = {
> +					.num = ST_GYRO_FS_AVL_2000DPS,
> +					.value = ST_GYRO_2_FS_AVL_2000_VAL,
> +					.gain = ST_GYRO_2_FS_AVL_2000_GAIN,
> +				},
> +			},
> +		},
> +		.bdu = {
> +			.addr = ST_GYRO_2_BDU_ADDR,
> +			.mask = ST_GYRO_2_BDU_MASK,
> +		},
> +		.drdy_irq = {
> +			.addr = ST_GYRO_2_DRDY_IRQ_ADDR,
> +			.mask = ST_GYRO_2_DRDY_IRQ_MASK,
> +		},
> +		.multi_read_bit = ST_GYRO_2_MULTIREAD_BIT,
> +	},
> +};
> +
> +static int st_gyro_check_device_list(struct st_sensors_data *adata, u8 wai)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(st_gyro_sensors); i++) {
> +		if (st_gyro_sensors[i].wai == wai)
> +			break;
> +	}
> +	if (i == ARRAY_SIZE(st_gyro_sensors))
> +		goto check_device_error;
> +
> +	adata->index = i;
> +
> +	return i;
> +
> +check_device_error:
> +	return -ENODEV;
> +}
> +
> +int st_gyro_init_sensor(struct iio_dev *indio_dev, u8 wai)
> +{
> +	int err;
> +	struct st_sensors_data *adata = iio_priv(indio_dev);
> +

You should verify that the device is the one that was registered, not
merely that it is a supported device.  If it isn't it is an error
and driver probe should return such and clean up.

> +	err = st_gyro_check_device_list(adata, wai);
> +	if (err < 0)
> +		goto init_error;
> +
> +	adata->st_sensors = (const struct st_sensors *)st_gyro_sensors;
> +
> +init_error:
> +	return err;
> +}
> +EXPORT_SYMBOL(st_gyro_init_sensor);
> +
> +MODULE_AUTHOR("Denis Ciocca <denis.ciocca@xxxxxx>");
> +MODULE_DESCRIPTION("STMicroelectronics gyroscopes driver");
> +MODULE_LICENSE("GPL v2");
>
--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

  Powered by Linux