Merge tag 'iio-for-3.9c' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

Jonathan writes:

"Third set of IIO new drivers, cleanups and fixes for the 3.9 cycle

New drivers
1) A driver for ST microelectronics sensors.  This driver already covers
   a large set of new parts (20 gyros, accelerometer and magnetometers)
   not currently covered by the existing drivers.  The intent moving forward
   is to merge this with the other drivers for similar parts already in tree.
   The lis3l02dq driver currently in staging/iio will be trivial, the lis3
   driver in misc more complex as it has a number of additional interfaces.
   Any merging in of the lis3 driver will rely on the not currently
   merged iio_input bridge driver and handling of freefall notifications
   etc.

2) A driver for the itg3200 gyroscope.

Graduations from staging
1) Cleanup and move out of staging of the adxrs450 gyroscope driver.  The
   cleanup required was all minor but there were a couple of fixes hidden in
   there.

Core and driver additions
1) Initial work from Guenter Roeck on device tree support for IIO's provider/
   consumer code. Focuses on the iio_hwmon driver and the max1363 adc driver.
   The full device tree syntax is currently under discussion but should
   follow shortly.

Cleanups and fixes
1) Remove a noop function __iio_update_buffer
2) Couple of small fixes and cleanups for the max1363
"
This commit is contained in:
Greg Kroah-Hartman
2013-02-05 11:25:37 -08:00
49 changed files with 4455 additions and 259 deletions
+31
View File
@@ -21,4 +21,35 @@ config KXSD9
Say yes here to build support for the Kionix KXSD9 accelerometer.
Currently this only supports the device via an SPI interface.
config IIO_ST_ACCEL_3AXIS
tristate "STMicroelectronics accelerometers 3-Axis Driver"
depends on (I2C || SPI_MASTER) && SYSFS
select IIO_ST_SENSORS_CORE
select IIO_ST_ACCEL_I2C_3AXIS if (I2C)
select IIO_ST_ACCEL_SPI_3AXIS if (SPI_MASTER)
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
select IIO_ST_ACCEL_BUFFER if (IIO_TRIGGERED_BUFFER)
help
Say yes here to build support for STMicroelectronics accelerometers:
LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
LIS331DLH, LSM303DL, LSM303DLM, LSM330.
This driver can also be built as a module. If so, will be created
these modules:
- st_accel (core functions for the driver [it is mandatory]);
- st_accel_i2c (necessary for the I2C devices [optional*]);
- st_accel_spi (necessary for the SPI devices [optional*]);
(*) one of these is necessary to do something.
config IIO_ST_ACCEL_I2C_3AXIS
tristate
depends on IIO_ST_ACCEL_3AXIS
depends on IIO_ST_SENSORS_I2C
config IIO_ST_ACCEL_SPI_3AXIS
tristate
depends on IIO_ST_ACCEL_3AXIS
depends on IIO_ST_SENSORS_SPI
endmenu
+8
View File
@@ -3,4 +3,12 @@
#
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
st_accel-y := st_accel_core.o
st_accel-$(CONFIG_IIO_BUFFER) += st_accel_buffer.o
obj-$(CONFIG_IIO_ST_ACCEL_I2C_3AXIS) += st_accel_i2c.o
obj-$(CONFIG_IIO_ST_ACCEL_SPI_3AXIS) += st_accel_spi.o
obj-$(CONFIG_KXSD9) += kxsd9.o
+47
View File
@@ -0,0 +1,47 @@
/*
* STMicroelectronics accelerometers driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
* v. 1.0.0
* Licensed under the GPL-2.
*/
#ifndef ST_ACCEL_H
#define ST_ACCEL_H
#include <linux/types.h>
#include <linux/iio/common/st_sensors.h>
#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 LIS331DLH_ACCEL_DEV_NAME "lis331dlh"
#define LSM303DL_ACCEL_DEV_NAME "lsm303dl_accel"
#define LSM303DLH_ACCEL_DEV_NAME "lsm303dlh_accel"
#define LSM303DLM_ACCEL_DEV_NAME "lsm303dlm_accel"
#define LSM330_ACCEL_DEV_NAME "lsm330_accel"
int st_accel_common_probe(struct iio_dev *indio_dev);
void st_accel_common_remove(struct iio_dev *indio_dev);
#ifdef CONFIG_IIO_BUFFER
int st_accel_allocate_ring(struct iio_dev *indio_dev);
void st_accel_deallocate_ring(struct iio_dev *indio_dev);
int st_accel_trig_set_state(struct iio_trigger *trig, bool state);
#define ST_ACCEL_TRIGGER_SET_STATE (&st_accel_trig_set_state)
#else /* CONFIG_IIO_BUFFER */
static inline int st_accel_allocate_ring(struct iio_dev *indio_dev)
{
return 0;
}
static inline void st_accel_deallocate_ring(struct iio_dev *indio_dev)
{
}
#define ST_ACCEL_TRIGGER_SET_STATE NULL
#endif /* CONFIG_IIO_BUFFER */
#endif /* ST_ACCEL_H */
+114
View File
@@ -0,0 +1,114 @@
/*
* STMicroelectronics accelerometers driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* 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/i2c.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/common/st_sensors.h>
#include "st_accel.h"
int st_accel_trig_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 int st_accel_buffer_preenable(struct iio_dev *indio_dev)
{
int err;
err = st_sensors_set_enable(indio_dev, true);
if (err < 0)
goto st_accel_set_enable_error;
err = iio_sw_buffer_preenable(indio_dev);
st_accel_set_enable_error:
return err;
}
static int st_accel_buffer_postenable(struct iio_dev *indio_dev)
{
int err;
struct st_sensor_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;
}
err = st_sensors_set_axis_enable(indio_dev,
(u8)indio_dev->active_scan_mask[0]);
if (err < 0)
goto st_accel_buffer_postenable_error;
err = iio_triggered_buffer_postenable(indio_dev);
if (err < 0)
goto st_accel_buffer_postenable_error;
return err;
st_accel_buffer_postenable_error:
kfree(adata->buffer_data);
allocate_memory_error:
return err;
}
static int st_accel_buffer_predisable(struct iio_dev *indio_dev)
{
int err;
struct st_sensor_data *adata = iio_priv(indio_dev);
err = iio_triggered_buffer_predisable(indio_dev);
if (err < 0)
goto st_accel_buffer_predisable_error;
err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
if (err < 0)
goto st_accel_buffer_predisable_error;
err = st_sensors_set_enable(indio_dev, false);
st_accel_buffer_predisable_error:
kfree(adata->buffer_data);
return err;
}
static const struct iio_buffer_setup_ops st_accel_buffer_setup_ops = {
.preenable = &st_accel_buffer_preenable,
.postenable = &st_accel_buffer_postenable,
.predisable = &st_accel_buffer_predisable,
};
int st_accel_allocate_ring(struct iio_dev *indio_dev)
{
return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
&st_sensors_trigger_handler, &st_accel_buffer_setup_ops);
}
void st_accel_deallocate_ring(struct iio_dev *indio_dev)
{
iio_triggered_buffer_cleanup(indio_dev);
}
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics accelerometers buffer");
MODULE_LICENSE("GPL v2");
+495
View File
@@ -0,0 +1,495 @@
/*
* STMicroelectronics accelerometers driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* 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 <linux/iio/common/st_sensors.h>
#include "st_accel.h"
/* DEFAULT VALUE FOR SENSORS */
#define ST_ACCEL_DEFAULT_OUT_X_L_ADDR 0x28
#define ST_ACCEL_DEFAULT_OUT_Y_L_ADDR 0x2a
#define ST_ACCEL_DEFAULT_OUT_Z_L_ADDR 0x2c
/* 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_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_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 0x32
#define ST_ACCEL_2_ODR_ADDR 0x20
#define ST_ACCEL_2_ODR_MASK 0x18
#define ST_ACCEL_2_ODR_AVL_50HZ_VAL 0x00
#define ST_ACCEL_2_ODR_AVL_100HZ_VAL 0x01
#define ST_ACCEL_2_ODR_AVL_400HZ_VAL 0x02
#define ST_ACCEL_2_ODR_AVL_1000HZ_VAL 0x03
#define ST_ACCEL_2_PW_ADDR 0x20
#define ST_ACCEL_2_PW_MASK 0xe0
#define ST_ACCEL_2_FS_ADDR 0x23
#define ST_ACCEL_2_FS_MASK 0x30
#define ST_ACCEL_2_FS_AVL_2_VAL 0X00
#define ST_ACCEL_2_FS_AVL_4_VAL 0X01
#define ST_ACCEL_2_FS_AVL_8_VAL 0x03
#define ST_ACCEL_2_FS_AVL_2_GAIN IIO_G_TO_M_S_2(1000)
#define ST_ACCEL_2_FS_AVL_4_GAIN IIO_G_TO_M_S_2(2000)
#define ST_ACCEL_2_FS_AVL_8_GAIN IIO_G_TO_M_S_2(3900)
#define ST_ACCEL_2_BDU_ADDR 0x23
#define ST_ACCEL_2_BDU_MASK 0x80
#define ST_ACCEL_2_DRDY_IRQ_ADDR 0x22
#define ST_ACCEL_2_DRDY_IRQ_MASK 0x02
#define ST_ACCEL_2_MULTIREAD_BIT true
/* CUSTOM VALUES FOR SENSOR 3 */
#define ST_ACCEL_3_WAI_EXP 0x40
#define ST_ACCEL_3_ODR_ADDR 0x20
#define ST_ACCEL_3_ODR_MASK 0xf0
#define ST_ACCEL_3_ODR_AVL_3HZ_VAL 0x01
#define ST_ACCEL_3_ODR_AVL_6HZ_VAL 0x02
#define ST_ACCEL_3_ODR_AVL_12HZ_VAL 0x03
#define ST_ACCEL_3_ODR_AVL_25HZ_VAL 0x04
#define ST_ACCEL_3_ODR_AVL_50HZ_VAL 0x05
#define ST_ACCEL_3_ODR_AVL_100HZ_VAL 0x06
#define ST_ACCEL_3_ODR_AVL_200HZ_VAL 0x07
#define ST_ACCEL_3_ODR_AVL_400HZ_VAL 0x08
#define ST_ACCEL_3_ODR_AVL_800HZ_VAL 0x09
#define ST_ACCEL_3_ODR_AVL_1600HZ_VAL 0x0a
#define ST_ACCEL_3_FS_ADDR 0x24
#define ST_ACCEL_3_FS_MASK 0x38
#define ST_ACCEL_3_FS_AVL_2_VAL 0X00
#define ST_ACCEL_3_FS_AVL_4_VAL 0X01
#define ST_ACCEL_3_FS_AVL_6_VAL 0x02
#define ST_ACCEL_3_FS_AVL_8_VAL 0x03
#define ST_ACCEL_3_FS_AVL_16_VAL 0x04
#define ST_ACCEL_3_FS_AVL_2_GAIN IIO_G_TO_M_S_2(61)
#define ST_ACCEL_3_FS_AVL_4_GAIN IIO_G_TO_M_S_2(122)
#define ST_ACCEL_3_FS_AVL_6_GAIN IIO_G_TO_M_S_2(183)
#define ST_ACCEL_3_FS_AVL_8_GAIN IIO_G_TO_M_S_2(244)
#define ST_ACCEL_3_FS_AVL_16_GAIN IIO_G_TO_M_S_2(732)
#define ST_ACCEL_3_BDU_ADDR 0x20
#define ST_ACCEL_3_BDU_MASK 0x08
#define ST_ACCEL_3_DRDY_IRQ_ADDR 0x23
#define ST_ACCEL_3_DRDY_IRQ_MASK 0x80
#define ST_ACCEL_3_IG1_EN_ADDR 0x23
#define ST_ACCEL_3_IG1_EN_MASK 0x08
#define ST_ACCEL_3_MULTIREAD_BIT false
static const struct iio_chan_spec st_accel_12bit_channels[] = {
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct iio_chan_spec st_accel_16bit_channels[] = {
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
ST_SENSORS_DEFAULT_16_REALBITS, ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
ST_SENSORS_DEFAULT_16_REALBITS, ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
ST_SENSORS_DEFAULT_16_REALBITS, ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct st_sensors st_accel_sensors[] = {
{
.wai = ST_ACCEL_1_WAI_EXP,
.sensors_supported = {
[0] = LIS3DH_ACCEL_DEV_NAME,
[1] = LSM303DLHC_ACCEL_DEV_NAME,
[2] = LSM330D_ACCEL_DEV_NAME,
[3] = LSM330DL_ACCEL_DEV_NAME,
[4] = LSM330DLC_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
.odr = {
.addr = ST_ACCEL_1_ODR_ADDR,
.mask = ST_ACCEL_1_ODR_MASK,
.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,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.enable_axis = {
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
},
.fs = {
.addr = ST_ACCEL_1_FS_ADDR,
.mask = ST_ACCEL_1_FS_MASK,
.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,
.bootime = 2,
},
{
.wai = ST_ACCEL_2_WAI_EXP,
.sensors_supported = {
[0] = LIS331DLH_ACCEL_DEV_NAME,
[1] = LSM303DL_ACCEL_DEV_NAME,
[2] = LSM303DLH_ACCEL_DEV_NAME,
[3] = LSM303DLM_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
.odr = {
.addr = ST_ACCEL_2_ODR_ADDR,
.mask = ST_ACCEL_2_ODR_MASK,
.odr_avl = {
{ 50, ST_ACCEL_2_ODR_AVL_50HZ_VAL, },
{ 100, ST_ACCEL_2_ODR_AVL_100HZ_VAL, },
{ 400, ST_ACCEL_2_ODR_AVL_400HZ_VAL, },
{ 1000, ST_ACCEL_2_ODR_AVL_1000HZ_VAL, },
},
},
.pw = {
.addr = ST_ACCEL_2_PW_ADDR,
.mask = ST_ACCEL_2_PW_MASK,
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.enable_axis = {
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
},
.fs = {
.addr = ST_ACCEL_2_FS_ADDR,
.mask = ST_ACCEL_2_FS_MASK,
.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_8G,
.value = ST_ACCEL_2_FS_AVL_8_VAL,
.gain = ST_ACCEL_2_FS_AVL_8_GAIN,
},
},
},
.bdu = {
.addr = ST_ACCEL_2_BDU_ADDR,
.mask = ST_ACCEL_2_BDU_MASK,
},
.drdy_irq = {
.addr = ST_ACCEL_2_DRDY_IRQ_ADDR,
.mask = ST_ACCEL_2_DRDY_IRQ_MASK,
},
.multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
.bootime = 2,
},
{
.wai = ST_ACCEL_3_WAI_EXP,
.sensors_supported = {
[0] = LSM330_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_16bit_channels,
.odr = {
.addr = ST_ACCEL_3_ODR_ADDR,
.mask = ST_ACCEL_3_ODR_MASK,
.odr_avl = {
{ 3, ST_ACCEL_3_ODR_AVL_3HZ_VAL },
{ 6, ST_ACCEL_3_ODR_AVL_6HZ_VAL, },
{ 12, ST_ACCEL_3_ODR_AVL_12HZ_VAL, },
{ 25, ST_ACCEL_3_ODR_AVL_25HZ_VAL, },
{ 50, ST_ACCEL_3_ODR_AVL_50HZ_VAL, },
{ 100, ST_ACCEL_3_ODR_AVL_100HZ_VAL, },
{ 200, ST_ACCEL_3_ODR_AVL_200HZ_VAL, },
{ 400, ST_ACCEL_3_ODR_AVL_400HZ_VAL, },
{ 800, ST_ACCEL_3_ODR_AVL_800HZ_VAL, },
{ 1600, ST_ACCEL_3_ODR_AVL_1600HZ_VAL, },
},
},
.pw = {
.addr = ST_ACCEL_3_ODR_ADDR,
.mask = ST_ACCEL_3_ODR_MASK,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.enable_axis = {
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
},
.fs = {
.addr = ST_ACCEL_3_FS_ADDR,
.mask = ST_ACCEL_3_FS_MASK,
.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_6G,
.value = ST_ACCEL_3_FS_AVL_6_VAL,
.gain = ST_ACCEL_3_FS_AVL_6_GAIN,
},
[3] = {
.num = ST_ACCEL_FS_AVL_8G,
.value = ST_ACCEL_3_FS_AVL_8_VAL,
.gain = ST_ACCEL_3_FS_AVL_8_GAIN,
},
[4] = {
.num = ST_ACCEL_FS_AVL_16G,
.value = ST_ACCEL_3_FS_AVL_16_VAL,
.gain = ST_ACCEL_3_FS_AVL_16_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,
.ig1 = {
.en_addr = ST_ACCEL_3_IG1_EN_ADDR,
.en_mask = ST_ACCEL_3_IG1_EN_MASK,
},
},
.multi_read_bit = ST_ACCEL_3_MULTIREAD_BIT,
.bootime = 2,
},
};
static int st_accel_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *ch, int *val,
int *val2, long mask)
{
int err;
struct st_sensor_data *adata = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
err = st_sensors_read_info_raw(indio_dev, ch, val);
if (err < 0)
goto read_error;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = adata->current_fullscale->gain;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
read_error:
return err;
}
static int st_accel_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
int err;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
break;
default:
return -EINVAL;
}
return err;
}
static ST_SENSOR_DEV_ATTR_SAMP_FREQ();
static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_accel_scale_available);
static struct attribute *st_accel_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr,
NULL,
};
static const struct attribute_group st_accel_attribute_group = {
.attrs = st_accel_attributes,
};
static const struct iio_info accel_info = {
.driver_module = THIS_MODULE,
.attrs = &st_accel_attribute_group,
.read_raw = &st_accel_read_raw,
.write_raw = &st_accel_write_raw,
};
static const struct iio_trigger_ops st_accel_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = ST_ACCEL_TRIGGER_SET_STATE,
};
int st_accel_common_probe(struct iio_dev *indio_dev)
{
int err;
struct st_sensor_data *adata = iio_priv(indio_dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &accel_info;
err = st_sensors_check_device_support(indio_dev,
ARRAY_SIZE(st_accel_sensors), st_accel_sensors);
if (err < 0)
goto st_accel_common_probe_error;
adata->multiread_bit = adata->sensor->multi_read_bit;
indio_dev->channels = adata->sensor->ch;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
adata->current_fullscale = (struct st_sensor_fullscale_avl *)
&adata->sensor->fs.fs_avl[0];
adata->odr = adata->sensor->odr.odr_avl[0].hz;
err = st_sensors_init_sensor(indio_dev);
if (err < 0)
goto st_accel_common_probe_error;
if (adata->get_irq_data_ready(indio_dev) > 0) {
err = st_accel_allocate_ring(indio_dev);
if (err < 0)
goto st_accel_common_probe_error;
err = st_sensors_allocate_trigger(indio_dev,
&st_accel_trigger_ops);
if (err < 0)
goto st_accel_probe_trigger_error;
}
err = iio_device_register(indio_dev);
if (err)
goto st_accel_device_register_error;
return err;
st_accel_device_register_error:
if (adata->get_irq_data_ready(indio_dev) > 0)
st_sensors_deallocate_trigger(indio_dev);
st_accel_probe_trigger_error:
if (adata->get_irq_data_ready(indio_dev) > 0)
st_accel_deallocate_ring(indio_dev);
st_accel_common_probe_error:
return err;
}
EXPORT_SYMBOL(st_accel_common_probe);
void st_accel_common_remove(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (adata->get_irq_data_ready(indio_dev) > 0) {
st_sensors_deallocate_trigger(indio_dev);
st_accel_deallocate_ring(indio_dev);
}
iio_device_free(indio_dev);
}
EXPORT_SYMBOL(st_accel_common_remove);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics accelerometers driver");
MODULE_LICENSE("GPL v2");
+87
View File
@@ -0,0 +1,87 @@
/*
* STMicroelectronics accelerometers driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* 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 <linux/iio/common/st_sensors.h>
#include <linux/iio/common/st_sensors_i2c.h>
#include "st_accel.h"
static int st_accel_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct st_sensor_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;
st_sensors_i2c_configure(indio_dev, client, adata);
err = st_accel_common_probe(indio_dev);
if (err < 0)
goto st_accel_common_probe_error;
return 0;
st_accel_common_probe_error:
iio_device_free(indio_dev);
iio_device_alloc_error:
return err;
}
static int st_accel_i2c_remove(struct i2c_client *client)
{
st_accel_common_remove(i2c_get_clientdata(client));
return 0;
}
static const struct i2c_device_id st_accel_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 },
{ LIS331DLH_ACCEL_DEV_NAME },
{ LSM303DL_ACCEL_DEV_NAME },
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
static struct i2c_driver st_accel_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "st-accel-i2c",
},
.probe = st_accel_i2c_probe,
.remove = st_accel_i2c_remove,
.id_table = st_accel_id_table,
};
module_i2c_driver(st_accel_driver);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics accelerometers i2c driver");
MODULE_LICENSE("GPL v2");
+86
View File
@@ -0,0 +1,86 @@
/*
* STMicroelectronics accelerometers driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* 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 <linux/iio/common/st_sensors.h>
#include <linux/iio/common/st_sensors_spi.h>
#include "st_accel.h"
static int st_accel_spi_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct st_sensor_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;
st_sensors_spi_configure(indio_dev, spi, adata);
err = st_accel_common_probe(indio_dev);
if (err < 0)
goto st_accel_common_probe_error;
return 0;
st_accel_common_probe_error:
iio_device_free(indio_dev);
iio_device_alloc_error:
return err;
}
static int st_accel_spi_remove(struct spi_device *spi)
{
st_accel_common_remove(spi_get_drvdata(spi));
return 0;
}
static const struct spi_device_id st_accel_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 },
{ LIS331DLH_ACCEL_DEV_NAME },
{ LSM303DL_ACCEL_DEV_NAME },
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
static struct spi_driver st_accel_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "st-accel-spi",
},
.probe = st_accel_spi_probe,
.remove = st_accel_spi_remove,
.id_table = st_accel_id_table,
};
module_spi_driver(st_accel_driver);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics accelerometers spi driver");
MODULE_LICENSE("GPL v2");
+3 -9
View File
@@ -187,12 +187,6 @@ static int lp8788_iio_map_register(struct iio_dev *indio_dev,
return 0;
}
static inline void lp8788_iio_map_unregister(struct iio_dev *indio_dev,
struct lp8788_adc *adc)
{
iio_map_array_unregister(indio_dev, adc->map);
}
static int lp8788_adc_probe(struct platform_device *pdev)
{
struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
@@ -208,6 +202,7 @@ static int lp8788_adc_probe(struct platform_device *pdev)
adc->lp = lp;
platform_set_drvdata(pdev, indio_dev);
indio_dev->dev.of_node = pdev->dev.of_node;
ret = lp8788_iio_map_register(indio_dev, lp->pdata, adc);
if (ret)
goto err_iio_map;
@@ -230,7 +225,7 @@ static int lp8788_adc_probe(struct platform_device *pdev)
return 0;
err_iio_device:
lp8788_iio_map_unregister(indio_dev, adc);
iio_map_array_unregister(indio_dev);
err_iio_map:
iio_device_free(indio_dev);
return ret;
@@ -239,10 +234,9 @@ err_iio_map:
static int lp8788_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct lp8788_adc *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
lp8788_iio_map_unregister(indio_dev, adc);
iio_map_array_unregister(indio_dev);
iio_device_free(indio_dev);
return 0;
+6 -6
View File
@@ -335,7 +335,7 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev,
{
int ret = 0;
s32 data;
char rxbuf[2];
u8 rxbuf[2];
struct max1363_state *st = iio_priv(indio_dev);
struct i2c_client *client = st->client;
@@ -367,7 +367,8 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev,
ret = data;
goto error_ret;
}
data = (s32)(rxbuf[1]) | ((s32)(rxbuf[0] & 0x0F)) << 8;
data = (rxbuf[1] | rxbuf[0] << 8) &
((1 << st->chip_info->bits) - 1);
} else {
/* Get reading */
data = i2c_master_recv(client, rxbuf, 1);
@@ -1496,6 +1497,7 @@ static int max1363_probe(struct i2c_client *client,
goto error_out;
}
indio_dev->dev.of_node = client->dev.of_node;
ret = iio_map_array_register(indio_dev, client->dev.platform_data);
if (ret < 0)
goto error_free_device;
@@ -1529,8 +1531,6 @@ static int max1363_probe(struct i2c_client *client,
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->info = st->chip_info->info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
ret = max1363_initial_setup(st);
if (ret < 0)
goto error_free_available_scan_masks;
@@ -1569,7 +1569,7 @@ error_disable_reg:
error_put_reg:
regulator_put(st->reg);
error_unregister_map:
iio_map_array_unregister(indio_dev, client->dev.platform_data);
iio_map_array_unregister(indio_dev);
error_free_device:
iio_device_free(indio_dev);
error_out:
@@ -1588,7 +1588,7 @@ static int max1363_remove(struct i2c_client *client)
kfree(indio_dev->available_scan_masks);
regulator_disable(st->reg);
regulator_put(st->reg);
iio_map_array_unregister(indio_dev, client->dev.platform_data);
iio_map_array_unregister(indio_dev);
iio_device_free(indio_dev);
return 0;
+2 -2
View File
@@ -25,7 +25,7 @@ static struct iio_buffer_access_funcs iio_cb_access = {
.store_to = &iio_buffer_cb_store_to,
};
struct iio_cb_buffer *iio_channel_get_all_cb(const char *name,
struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
int (*cb)(u8 *data,
void *private),
void *private)
@@ -46,7 +46,7 @@ struct iio_cb_buffer *iio_channel_get_all_cb(const char *name,
cb_buff->buffer.access = &iio_cb_access;
INIT_LIST_HEAD(&cb_buff->buffer.demux_list);
cb_buff->channels = iio_channel_get_all(name);
cb_buff->channels = iio_channel_get_all(dev);
if (IS_ERR(cb_buff->channels)) {
ret = PTR_ERR(cb_buff->channels);
goto error_free_cb_buff;
+1
View File
@@ -3,3 +3,4 @@
#
source "drivers/iio/common/hid-sensors/Kconfig"
source "drivers/iio/common/st_sensors/Kconfig"
+1
View File
@@ -7,3 +7,4 @@
#
obj-y += hid-sensors/
obj-y += st_sensors/
+14
View File
@@ -0,0 +1,14 @@
#
# STMicroelectronics sensors common library
#
config IIO_ST_SENSORS_I2C
tristate
config IIO_ST_SENSORS_SPI
tristate
config IIO_ST_SENSORS_CORE
tristate
select IIO_ST_SENSORS_I2C if I2C
select IIO_ST_SENSORS_SPI if SPI_MASTER
+10
View File
@@ -0,0 +1,10 @@
#
# Makefile for the STMicroelectronics sensor common modules.
#
obj-$(CONFIG_IIO_ST_SENSORS_I2C) += st_sensors_i2c.o
obj-$(CONFIG_IIO_ST_SENSORS_SPI) += st_sensors_spi.o
obj-$(CONFIG_IIO_ST_SENSORS_CORE) += st_sensors.o
st_sensors-y := st_sensors_core.o
st_sensors-$(CONFIG_IIO_BUFFER) += st_sensors_buffer.o
st_sensors-$(CONFIG_IIO_TRIGGER) += st_sensors_trigger.o
@@ -0,0 +1,116 @@
/*
* STMicroelectronics sensors buffer library driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/interrupt.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/irqreturn.h>
#include <linux/iio/common/st_sensors.h>
int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
{
int i, n = 0, len;
u8 addr[ST_SENSORS_NUMBER_DATA_CHANNELS];
struct st_sensor_data *sdata = iio_priv(indio_dev);
for (i = 0; i < ST_SENSORS_NUMBER_DATA_CHANNELS; i++) {
if (test_bit(i, indio_dev->active_scan_mask)) {
addr[n] = indio_dev->channels[i].address;
n++;
}
}
switch (n) {
case 1:
len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
addr[0], ST_SENSORS_BYTE_FOR_CHANNEL, buf,
sdata->multiread_bit);
break;
case 2:
if ((addr[1] - addr[0]) == ST_SENSORS_BYTE_FOR_CHANNEL) {
len = sdata->tf->read_multiple_byte(&sdata->tb,
sdata->dev, addr[0],
ST_SENSORS_BYTE_FOR_CHANNEL*n,
buf, sdata->multiread_bit);
} else {
u8 rx_array[ST_SENSORS_BYTE_FOR_CHANNEL*
ST_SENSORS_NUMBER_DATA_CHANNELS];
len = sdata->tf->read_multiple_byte(&sdata->tb,
sdata->dev, addr[0],
ST_SENSORS_BYTE_FOR_CHANNEL*
ST_SENSORS_NUMBER_DATA_CHANNELS,
rx_array, sdata->multiread_bit);
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_FOR_CHANNEL*n;
}
break;
case 3:
len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
addr[0], ST_SENSORS_BYTE_FOR_CHANNEL*
ST_SENSORS_NUMBER_DATA_CHANNELS,
buf, sdata->multiread_bit);
break;
default:
len = -EINVAL;
goto read_data_channels_error;
}
if (len != ST_SENSORS_BYTE_FOR_CHANNEL*n) {
len = -EIO;
goto read_data_channels_error;
}
read_data_channels_error:
return len;
}
EXPORT_SYMBOL(st_sensors_get_buffer_element);
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_sensor_data *sdata = iio_priv(indio_dev);
len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data);
if (len < 0)
goto st_sensors_get_buffer_element_error;
if (indio_dev->scan_timestamp)
*(s64 *)((u8 *)sdata->buffer_data +
ALIGN(len, sizeof(s64))) = pf->timestamp;
iio_push_to_buffers(indio_dev, sdata->buffer_data);
st_sensors_get_buffer_element_error:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
EXPORT_SYMBOL(st_sensors_trigger_handler);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors buffer");
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,446 @@
/*
* STMicroelectronics sensors core library driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <asm/unaligned.h>
#include <linux/iio/common/st_sensors.h>
#define ST_SENSORS_WAI_ADDRESS 0x0f
static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
u8 reg_addr, u8 mask, u8 data)
{
int err;
u8 new_data;
struct st_sensor_data *sdata = iio_priv(indio_dev);
err = sdata->tf->read_byte(&sdata->tb, sdata->dev, 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 = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data);
st_sensors_write_data_with_mask_error:
return err;
}
static int st_sensors_match_odr(struct st_sensors *sensor,
unsigned int odr, struct st_sensor_odr_avl *odr_out)
{
int i, ret = -EINVAL;
for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
if (sensor->odr.odr_avl[i].hz == 0)
goto st_sensors_match_odr_error;
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;
}
}
st_sensors_match_odr_error:
return ret;
}
int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
{
int err;
struct st_sensor_odr_avl odr_out;
struct st_sensor_data *sdata = iio_priv(indio_dev);
err = st_sensors_match_odr(sdata->sensor, odr, &odr_out);
if (err < 0)
goto st_sensors_match_odr_error;
if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
(sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
if (sdata->enabled == true) {
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->odr.addr,
sdata->sensor->odr.mask,
odr_out.value);
} else {
err = 0;
}
} else {
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->odr.addr, sdata->sensor->odr.mask,
odr_out.value);
}
if (err >= 0)
sdata->odr = odr_out.hz;
st_sensors_match_odr_error:
return err;
}
EXPORT_SYMBOL(st_sensors_set_odr);
static int st_sensors_match_fs(struct st_sensors *sensor,
unsigned int fs, int *index_fs_avl)
{
int i, ret = -EINVAL;
for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
if (sensor->fs.fs_avl[i].num == 0)
goto st_sensors_match_odr_error;
if (sensor->fs.fs_avl[i].num == fs) {
*index_fs_avl = i;
ret = 0;
break;
}
}
st_sensors_match_odr_error:
return ret;
}
static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
{
int err, i;
struct st_sensor_data *sdata = iio_priv(indio_dev);
err = st_sensors_match_fs(sdata->sensor, fs, &i);
if (err < 0)
goto st_accel_set_fullscale_error;
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->fs.addr,
sdata->sensor->fs.mask,
sdata->sensor->fs.fs_avl[i].value);
if (err < 0)
goto st_accel_set_fullscale_error;
sdata->current_fullscale = (struct st_sensor_fullscale_avl *)
&sdata->sensor->fs.fs_avl[i];
return err;
st_accel_set_fullscale_error:
dev_err(&indio_dev->dev, "failed to set new fullscale.\n");
return err;
}
int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
{
bool found;
u8 tmp_value;
int err = -EINVAL;
struct st_sensor_odr_avl odr_out;
struct st_sensor_data *sdata = iio_priv(indio_dev);
if (enable) {
found = false;
tmp_value = sdata->sensor->pw.value_on;
if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
(sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
err = st_sensors_match_odr(sdata->sensor,
sdata->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,
sdata->sensor->pw.addr,
sdata->sensor->pw.mask, tmp_value);
if (err < 0)
goto set_enable_error;
sdata->enabled = true;
if (found)
sdata->odr = odr_out.hz;
} else {
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->pw.addr,
sdata->sensor->pw.mask,
sdata->sensor->pw.value_off);
if (err < 0)
goto set_enable_error;
sdata->enabled = false;
}
set_enable_error:
return err;
}
EXPORT_SYMBOL(st_sensors_set_enable);
int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
return st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->enable_axis.addr,
sdata->sensor->enable_axis.mask, axis_enable);
}
EXPORT_SYMBOL(st_sensors_set_axis_enable);
int st_sensors_init_sensor(struct iio_dev *indio_dev)
{
int err;
struct st_sensor_data *sdata = iio_priv(indio_dev);
mutex_init(&sdata->tb.buf_lock);
err = st_sensors_set_enable(indio_dev, false);
if (err < 0)
goto init_error;
err = st_sensors_set_fullscale(indio_dev,
sdata->current_fullscale->num);
if (err < 0)
goto init_error;
err = st_sensors_set_odr(indio_dev, sdata->odr);
if (err < 0)
goto init_error;
/* set BDU */
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true);
if (err < 0)
goto init_error;
err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
init_error:
return err;
}
EXPORT_SYMBOL(st_sensors_init_sensor);
int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
{
int err;
struct st_sensor_data *sdata = iio_priv(indio_dev);
/* Enable/Disable the interrupt generator 1. */
if (sdata->sensor->drdy_irq.ig1.en_addr > 0) {
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->drdy_irq.ig1.en_addr,
sdata->sensor->drdy_irq.ig1.en_mask, (int)enable);
if (err < 0)
goto st_accel_set_dataready_irq_error;
}
/* Enable/Disable the interrupt generator for data ready. */
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor->drdy_irq.addr,
sdata->sensor->drdy_irq.mask, (int)enable);
st_accel_set_dataready_irq_error:
return err;
}
EXPORT_SYMBOL(st_sensors_set_dataready_irq);
int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
{
int err = -EINVAL, i;
struct st_sensor_data *sdata = iio_priv(indio_dev);
for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
if ((sdata->sensor->fs.fs_avl[i].gain == scale) &&
(sdata->sensor->fs.fs_avl[i].gain != 0)) {
err = 0;
break;
}
}
if (err < 0)
goto st_sensors_match_scale_error;
err = st_sensors_set_fullscale(indio_dev,
sdata->sensor->fs.fs_avl[i].num);
st_sensors_match_scale_error:
return err;
}
EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain);
static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
u8 ch_addr, int *data)
{
int err;
u8 outdata[ST_SENSORS_BYTE_FOR_CHANNEL];
struct st_sensor_data *sdata = iio_priv(indio_dev);
err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
ch_addr, ST_SENSORS_BYTE_FOR_CHANNEL,
outdata, sdata->multiread_bit);
if (err < 0)
goto read_error;
*data = (s16)get_unaligned_le16(outdata);
read_error:
return err;
}
int st_sensors_read_info_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *ch, int *val)
{
int err;
struct st_sensor_data *sdata = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock);
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
err = -EBUSY;
goto read_error;
} else {
err = st_sensors_set_enable(indio_dev, true);
if (err < 0)
goto read_error;
msleep((sdata->sensor->bootime * 1000) / sdata->odr);
err = st_sensors_read_axis_data(indio_dev, ch->address, val);
if (err < 0)
goto read_error;
*val = *val >> ch->scan_type.shift;
}
mutex_unlock(&indio_dev->mlock);
return err;
read_error:
mutex_unlock(&indio_dev->mlock);
return err;
}
EXPORT_SYMBOL(st_sensors_read_info_raw);
int st_sensors_check_device_support(struct iio_dev *indio_dev,
int num_sensors_list, const struct st_sensors *sensors)
{
u8 wai;
int i, n, err;
struct st_sensor_data *sdata = iio_priv(indio_dev);
err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai);
if (err < 0) {
dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
goto read_wai_error;
}
for (i = 0; i < num_sensors_list; i++) {
if (sensors[i].wai == wai)
break;
}
if (i == num_sensors_list)
goto device_not_supported;
for (n = 0; n < ARRAY_SIZE(sensors[i].sensors_supported); n++) {
if (strcmp(indio_dev->name,
&sensors[i].sensors_supported[n][0]) == 0)
break;
}
if (n == ARRAY_SIZE(sensors[i].sensors_supported)) {
dev_err(&indio_dev->dev, "device name and WhoAmI mismatch.\n");
goto sensor_name_mismatch;
}
sdata->sensor = (struct st_sensors *)&sensors[i];
return i;
device_not_supported:
dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai);
sensor_name_mismatch:
err = -ENODEV;
read_wai_error:
return err;
}
EXPORT_SYMBOL(st_sensors_check_device_support);
ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct st_sensor_data *adata = iio_priv(dev_get_drvdata(dev));
return sprintf(buf, "%d\n", adata->odr);
}
EXPORT_SYMBOL(st_sensors_sysfs_get_sampling_frequency);
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 odr;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
err = kstrtoint(buf, 10, &odr);
if (err < 0)
goto conversion_error;
mutex_lock(&indio_dev->mlock);
err = st_sensors_set_odr(indio_dev, odr);
mutex_unlock(&indio_dev->mlock);
conversion_error:
return err < 0 ? err : size;
}
EXPORT_SYMBOL(st_sensors_sysfs_set_sampling_frequency);
ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
struct device_attribute *attr, char *buf)
{
int i, len = 0;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct st_sensor_data *sdata = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock);
for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
if (sdata->sensor->odr.odr_avl[i].hz == 0)
break;
len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
sdata->sensor->odr.odr_avl[i].hz);
}
mutex_unlock(&indio_dev->mlock);
buf[len - 1] = '\n';
return len;
}
EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail);
ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
struct device_attribute *attr, char *buf)
{
int i, len = 0;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct st_sensor_data *sdata = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock);
for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
if (sdata->sensor->fs.fs_avl[i].num == 0)
break;
len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
sdata->sensor->fs.fs_avl[i].gain);
}
mutex_unlock(&indio_dev->mlock);
buf[len - 1] = '\n';
return len;
}
EXPORT_SYMBOL(st_sensors_sysfs_scale_avail);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors core");
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,81 @@
/*
* STMicroelectronics sensors i2c library driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/iio/common/st_sensors_i2c.h>
#define ST_SENSORS_I2C_MULTIREAD 0x80
static unsigned int st_sensors_i2c_get_irq(struct iio_dev *indio_dev)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
return to_i2c_client(sdata->dev)->irq;
}
static int st_sensors_i2c_read_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 *res_byte)
{
int err;
err = i2c_smbus_read_byte_data(to_i2c_client(dev), reg_addr);
if (err < 0)
goto st_accel_i2c_read_byte_error;
*res_byte = err & 0xff;
st_accel_i2c_read_byte_error:
return err < 0 ? err : 0;
}
static int st_sensors_i2c_read_multiple_byte(
struct st_sensor_transfer_buffer *tb, struct device *dev,
u8 reg_addr, int len, u8 *data, bool multiread_bit)
{
if (multiread_bit)
reg_addr |= ST_SENSORS_I2C_MULTIREAD;
return i2c_smbus_read_i2c_block_data(to_i2c_client(dev),
reg_addr, len, data);
}
static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 data)
{
return i2c_smbus_write_byte_data(to_i2c_client(dev), reg_addr, data);
}
static const struct st_sensor_transfer_function st_sensors_tf_i2c = {
.read_byte = st_sensors_i2c_read_byte,
.write_byte = st_sensors_i2c_write_byte,
.read_multiple_byte = st_sensors_i2c_read_multiple_byte,
};
void st_sensors_i2c_configure(struct iio_dev *indio_dev,
struct i2c_client *client, struct st_sensor_data *sdata)
{
i2c_set_clientdata(client, indio_dev);
indio_dev->dev.parent = &client->dev;
indio_dev->name = client->name;
sdata->tf = &st_sensors_tf_i2c;
sdata->get_irq_data_ready = st_sensors_i2c_get_irq;
}
EXPORT_SYMBOL(st_sensors_i2c_configure);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver");
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,128 @@
/*
* STMicroelectronics sensors spi library driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/iio/common/st_sensors_spi.h>
#define ST_SENSORS_SPI_MULTIREAD 0xc0
#define ST_SENSORS_SPI_READ 0x80
static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
return to_spi_device(sdata->dev)->irq;
}
static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit)
{
struct spi_message msg;
int err;
struct spi_transfer xfers[] = {
{
.tx_buf = tb->tx_buf,
.bits_per_word = 8,
.len = 1,
},
{
.rx_buf = tb->rx_buf,
.bits_per_word = 8,
.len = len,
}
};
mutex_lock(&tb->buf_lock);
if ((multiread_bit) && (len > 1))
tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_MULTIREAD;
else
tb->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(dev), &msg);
if (err)
goto acc_spi_read_error;
memcpy(data, tb->rx_buf, len*sizeof(u8));
mutex_unlock(&tb->buf_lock);
return len;
acc_spi_read_error:
mutex_unlock(&tb->buf_lock);
return err;
}
static int st_sensors_spi_read_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 *res_byte)
{
return st_sensors_spi_read(tb, dev, reg_addr, 1, res_byte, false);
}
static int st_sensors_spi_read_multiple_byte(
struct st_sensor_transfer_buffer *tb, struct device *dev,
u8 reg_addr, int len, u8 *data, bool multiread_bit)
{
return st_sensors_spi_read(tb, dev, reg_addr, len, data, multiread_bit);
}
static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 data)
{
struct spi_message msg;
int err;
struct spi_transfer xfers = {
.tx_buf = tb->tx_buf,
.bits_per_word = 8,
.len = 2,
};
mutex_lock(&tb->buf_lock);
tb->tx_buf[0] = reg_addr;
tb->tx_buf[1] = data;
spi_message_init(&msg);
spi_message_add_tail(&xfers, &msg);
err = spi_sync(to_spi_device(dev), &msg);
mutex_unlock(&tb->buf_lock);
return err;
}
static const struct st_sensor_transfer_function st_sensors_tf_spi = {
.read_byte = st_sensors_spi_read_byte,
.write_byte = st_sensors_spi_write_byte,
.read_multiple_byte = st_sensors_spi_read_multiple_byte,
};
void st_sensors_spi_configure(struct iio_dev *indio_dev,
struct spi_device *spi, struct st_sensor_data *sdata)
{
spi_set_drvdata(spi, indio_dev);
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi->modalias;
sdata->tf = &st_sensors_tf_spi;
sdata->get_irq_data_ready = st_sensors_spi_get_irq;
}
EXPORT_SYMBOL(st_sensors_spi_configure);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors spi driver");
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,77 @@
/*
* STMicroelectronics sensors trigger library driver
*
* Copyright 2012-2013 STMicroelectronics Inc.
*
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/interrupt.h>
#include <linux/iio/common/st_sensors.h>
int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
const struct iio_trigger_ops *trigger_ops)
{
int err;
struct st_sensor_data *sdata = iio_priv(indio_dev);
sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
if (sdata->trig == NULL) {
err = -ENOMEM;
dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
goto iio_trigger_alloc_error;
}
err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
iio_trigger_generic_data_rdy_poll,
NULL,
IRQF_TRIGGER_RISING,
sdata->trig->name,
sdata->trig);
if (err)
goto request_irq_error;
sdata->trig->private_data = indio_dev;
sdata->trig->ops = trigger_ops;
sdata->trig->dev.parent = sdata->dev;
err = iio_trigger_register(sdata->trig);
if (err < 0) {
dev_err(&indio_dev->dev, "failed to register iio trigger.\n");
goto iio_trigger_register_error;
}
indio_dev->trig = sdata->trig;
return 0;
iio_trigger_register_error:
free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
request_irq_error:
iio_trigger_free(sdata->trig);
iio_trigger_alloc_error:
return err;
}
EXPORT_SYMBOL(st_sensors_allocate_trigger);
void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
iio_trigger_unregister(sdata->trig);
free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
iio_trigger_free(sdata->trig);
}
EXPORT_SYMBOL(st_sensors_deallocate_trigger);
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger");
MODULE_LICENSE("GPL v2");
+48
View File
@@ -19,6 +19,16 @@ config ADIS16136
Say yes here to build support for the Analog Devices ADIS16133, ADIS16135,
ADIS16136 gyroscope devices.
config ADXRS450
tristate "Analog Devices ADXRS450/3 Digital Output Gyroscope SPI driver"
depends on SPI
help
Say yes here to build support for Analog Devices ADXRS450 and ADXRS453
programmable digital output gyroscope.
This driver can also be built as a module. If so, the module
will be called adxrs450.
config HID_SENSOR_GYRO_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
@@ -30,4 +40,42 @@ config HID_SENSOR_GYRO_3D
Say yes here to build support for the HID SENSOR
Gyroscope 3D.
config IIO_ST_GYRO_3AXIS
tristate "STMicroelectronics gyroscopes 3-Axis Driver"
depends on (I2C || SPI_MASTER) && SYSFS
select IIO_ST_SENSORS_CORE
select IIO_ST_GYRO_I2C_3AXIS if (I2C)
select IIO_ST_GYRO_SPI_3AXIS if (SPI_MASTER)
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
select IIO_ST_GYRO_BUFFER if (IIO_TRIGGERED_BUFFER)
help
Say yes here to build support for STMicroelectronics gyroscopes:
L3G4200D, LSM330DL, L3GD20, L3GD20H, LSM330DLC, L3G4IS, LSM330.
This driver can also be built as a module. If so, will be created
these modules:
- st_gyro (core functions for the driver [it is mandatory]);
- st_gyro_i2c (necessary for the I2C devices [optional*]);
- st_gyro_spi (necessary for the SPI devices [optional*]);
(*) one of these is necessary to do something.
config IIO_ST_GYRO_I2C_3AXIS
tristate
depends on IIO_ST_GYRO_3AXIS
depends on IIO_ST_SENSORS_I2C
config IIO_ST_GYRO_SPI_3AXIS
tristate
depends on IIO_ST_GYRO_3AXIS
depends on IIO_ST_SENSORS_SPI
config ITG3200
tristate "InvenSense ITG3200 Digital 3-Axis Gyroscope I2C driver"
depends on I2C
select IIO_TRIGGERED_BUFFER if IIO_BUFFER
help
Say yes here to add support for the InvenSense ITG3200 digital
3-axis gyroscope sensor.
endmenu

Some files were not shown because too many files have changed in this diff Show More