2013-06-03 14:58:00 +00:00
|
|
|
/*
|
|
|
|
* STMicroelectronics pressures driver
|
|
|
|
*
|
|
|
|
* Copyright 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/delay.h>
|
|
|
|
#include <linux/iio/iio.h>
|
|
|
|
#include <linux/iio/sysfs.h>
|
|
|
|
#include <linux/iio/trigger.h>
|
|
|
|
#include <linux/iio/buffer.h>
|
|
|
|
#include <asm/unaligned.h>
|
|
|
|
|
|
|
|
#include <linux/iio/common/st_sensors.h>
|
|
|
|
#include "st_pressure.h"
|
|
|
|
|
2016-04-19 09:18:33 +00:00
|
|
|
#define MCELSIUS_PER_CELSIUS 1000
|
|
|
|
|
|
|
|
/* Default pressure sensitivity */
|
2013-07-02 10:13:00 +00:00
|
|
|
#define ST_PRESS_LSB_PER_MBAR 4096UL
|
|
|
|
#define ST_PRESS_KPASCAL_NANO_SCALE (100000000UL / \
|
|
|
|
ST_PRESS_LSB_PER_MBAR)
|
2016-04-19 09:18:33 +00:00
|
|
|
|
|
|
|
/* Default temperature sensitivity */
|
2013-07-02 10:13:00 +00:00
|
|
|
#define ST_PRESS_LSB_PER_CELSIUS 480UL
|
2016-04-19 09:18:33 +00:00
|
|
|
#define ST_PRESS_MILLI_CELSIUS_OFFSET 42500UL
|
|
|
|
|
2013-06-03 14:58:00 +00:00
|
|
|
#define ST_PRESS_NUMBER_DATA_CHANNELS 1
|
|
|
|
|
|
|
|
/* FULLSCALE */
|
2016-04-19 09:18:33 +00:00
|
|
|
#define ST_PRESS_FS_AVL_1100MB 1100
|
2013-06-03 14:58:00 +00:00
|
|
|
#define ST_PRESS_FS_AVL_1260MB 1260
|
|
|
|
|
2014-02-20 17:49:00 +00:00
|
|
|
#define ST_PRESS_1_OUT_XL_ADDR 0x28
|
|
|
|
#define ST_TEMP_1_OUT_L_ADDR 0x2b
|
|
|
|
|
2013-09-10 12:49:00 +00:00
|
|
|
/* CUSTOM VALUES FOR LPS331AP SENSOR */
|
|
|
|
#define ST_PRESS_LPS331AP_WAI_EXP 0xbb
|
|
|
|
#define ST_PRESS_LPS331AP_ODR_ADDR 0x20
|
|
|
|
#define ST_PRESS_LPS331AP_ODR_MASK 0x70
|
|
|
|
#define ST_PRESS_LPS331AP_ODR_AVL_1HZ_VAL 0x01
|
|
|
|
#define ST_PRESS_LPS331AP_ODR_AVL_7HZ_VAL 0x05
|
|
|
|
#define ST_PRESS_LPS331AP_ODR_AVL_13HZ_VAL 0x06
|
|
|
|
#define ST_PRESS_LPS331AP_ODR_AVL_25HZ_VAL 0x07
|
|
|
|
#define ST_PRESS_LPS331AP_PW_ADDR 0x20
|
|
|
|
#define ST_PRESS_LPS331AP_PW_MASK 0x80
|
|
|
|
#define ST_PRESS_LPS331AP_FS_ADDR 0x23
|
|
|
|
#define ST_PRESS_LPS331AP_FS_MASK 0x30
|
|
|
|
#define ST_PRESS_LPS331AP_BDU_ADDR 0x20
|
|
|
|
#define ST_PRESS_LPS331AP_BDU_MASK 0x04
|
|
|
|
#define ST_PRESS_LPS331AP_DRDY_IRQ_ADDR 0x22
|
|
|
|
#define ST_PRESS_LPS331AP_DRDY_IRQ_INT1_MASK 0x04
|
|
|
|
#define ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK 0x20
|
2015-11-19 09:15:17 +00:00
|
|
|
#define ST_PRESS_LPS331AP_IHL_IRQ_ADDR 0x22
|
|
|
|
#define ST_PRESS_LPS331AP_IHL_IRQ_MASK 0x80
|
2016-04-14 08:45:21 +00:00
|
|
|
#define ST_PRESS_LPS331AP_OD_IRQ_ADDR 0x22
|
|
|
|
#define ST_PRESS_LPS331AP_OD_IRQ_MASK 0x40
|
2013-09-10 12:49:00 +00:00
|
|
|
#define ST_PRESS_LPS331AP_MULTIREAD_BIT true
|
2013-06-03 14:58:00 +00:00
|
|
|
|
2013-09-16 16:02:00 +00:00
|
|
|
/* CUSTOM VALUES FOR LPS001WP SENSOR */
|
2016-04-19 09:18:33 +00:00
|
|
|
|
|
|
|
/* LPS001WP pressure resolution */
|
|
|
|
#define ST_PRESS_LPS001WP_LSB_PER_MBAR 16UL
|
|
|
|
/* LPS001WP temperature resolution */
|
|
|
|
#define ST_PRESS_LPS001WP_LSB_PER_CELSIUS 64UL
|
|
|
|
|
2013-09-16 16:02:00 +00:00
|
|
|
#define ST_PRESS_LPS001WP_WAI_EXP 0xba
|
|
|
|
#define ST_PRESS_LPS001WP_ODR_ADDR 0x20
|
|
|
|
#define ST_PRESS_LPS001WP_ODR_MASK 0x30
|
|
|
|
#define ST_PRESS_LPS001WP_ODR_AVL_1HZ_VAL 0x01
|
|
|
|
#define ST_PRESS_LPS001WP_ODR_AVL_7HZ_VAL 0x02
|
|
|
|
#define ST_PRESS_LPS001WP_ODR_AVL_13HZ_VAL 0x03
|
|
|
|
#define ST_PRESS_LPS001WP_PW_ADDR 0x20
|
|
|
|
#define ST_PRESS_LPS001WP_PW_MASK 0x40
|
2016-04-19 09:18:33 +00:00
|
|
|
#define ST_PRESS_LPS001WP_FS_AVL_PRESS_GAIN \
|
|
|
|
(100000000UL / ST_PRESS_LPS001WP_LSB_PER_MBAR)
|
2013-09-16 16:02:00 +00:00
|
|
|
#define ST_PRESS_LPS001WP_BDU_ADDR 0x20
|
|
|
|
#define ST_PRESS_LPS001WP_BDU_MASK 0x04
|
|
|
|
#define ST_PRESS_LPS001WP_MULTIREAD_BIT true
|
|
|
|
#define ST_PRESS_LPS001WP_OUT_L_ADDR 0x28
|
|
|
|
#define ST_TEMP_LPS001WP_OUT_L_ADDR 0x2a
|
|
|
|
|
2014-02-20 17:49:00 +00:00
|
|
|
/* CUSTOM VALUES FOR LPS25H SENSOR */
|
|
|
|
#define ST_PRESS_LPS25H_WAI_EXP 0xbd
|
|
|
|
#define ST_PRESS_LPS25H_ODR_ADDR 0x20
|
|
|
|
#define ST_PRESS_LPS25H_ODR_MASK 0x70
|
|
|
|
#define ST_PRESS_LPS25H_ODR_AVL_1HZ_VAL 0x01
|
|
|
|
#define ST_PRESS_LPS25H_ODR_AVL_7HZ_VAL 0x02
|
|
|
|
#define ST_PRESS_LPS25H_ODR_AVL_13HZ_VAL 0x03
|
|
|
|
#define ST_PRESS_LPS25H_ODR_AVL_25HZ_VAL 0x04
|
|
|
|
#define ST_PRESS_LPS25H_PW_ADDR 0x20
|
|
|
|
#define ST_PRESS_LPS25H_PW_MASK 0x80
|
|
|
|
#define ST_PRESS_LPS25H_BDU_ADDR 0x20
|
|
|
|
#define ST_PRESS_LPS25H_BDU_MASK 0x04
|
|
|
|
#define ST_PRESS_LPS25H_DRDY_IRQ_ADDR 0x23
|
|
|
|
#define ST_PRESS_LPS25H_DRDY_IRQ_INT1_MASK 0x01
|
|
|
|
#define ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK 0x10
|
2015-11-19 09:15:17 +00:00
|
|
|
#define ST_PRESS_LPS25H_IHL_IRQ_ADDR 0x22
|
|
|
|
#define ST_PRESS_LPS25H_IHL_IRQ_MASK 0x80
|
2016-04-14 08:45:21 +00:00
|
|
|
#define ST_PRESS_LPS25H_OD_IRQ_ADDR 0x22
|
|
|
|
#define ST_PRESS_LPS25H_OD_IRQ_MASK 0x40
|
2014-02-20 17:49:00 +00:00
|
|
|
#define ST_PRESS_LPS25H_MULTIREAD_BIT true
|
|
|
|
#define ST_PRESS_LPS25H_OUT_XL_ADDR 0x28
|
|
|
|
#define ST_TEMP_LPS25H_OUT_L_ADDR 0x2b
|
|
|
|
|
2016-04-19 09:18:32 +00:00
|
|
|
/* CUSTOM VALUES FOR LPS22HB SENSOR */
|
|
|
|
#define ST_PRESS_LPS22HB_WAI_EXP 0xb1
|
|
|
|
#define ST_PRESS_LPS22HB_ODR_ADDR 0x10
|
|
|
|
#define ST_PRESS_LPS22HB_ODR_MASK 0x70
|
|
|
|
#define ST_PRESS_LPS22HB_ODR_AVL_1HZ_VAL 0x01
|
|
|
|
#define ST_PRESS_LPS22HB_ODR_AVL_10HZ_VAL 0x02
|
|
|
|
#define ST_PRESS_LPS22HB_ODR_AVL_25HZ_VAL 0x03
|
|
|
|
#define ST_PRESS_LPS22HB_ODR_AVL_50HZ_VAL 0x04
|
|
|
|
#define ST_PRESS_LPS22HB_ODR_AVL_75HZ_VAL 0x05
|
|
|
|
#define ST_PRESS_LPS22HB_PW_ADDR 0x10
|
|
|
|
#define ST_PRESS_LPS22HB_PW_MASK 0x70
|
|
|
|
#define ST_PRESS_LPS22HB_BDU_ADDR 0x10
|
|
|
|
#define ST_PRESS_LPS22HB_BDU_MASK 0x02
|
|
|
|
#define ST_PRESS_LPS22HB_DRDY_IRQ_ADDR 0x12
|
|
|
|
#define ST_PRESS_LPS22HB_DRDY_IRQ_INT1_MASK 0x04
|
|
|
|
#define ST_PRESS_LPS22HB_DRDY_IRQ_INT2_MASK 0x08
|
|
|
|
#define ST_PRESS_LPS22HB_IHL_IRQ_ADDR 0x12
|
|
|
|
#define ST_PRESS_LPS22HB_IHL_IRQ_MASK 0x80
|
|
|
|
#define ST_PRESS_LPS22HB_MULTIREAD_BIT true
|
|
|
|
|
2014-02-20 17:49:00 +00:00
|
|
|
static const struct iio_chan_spec st_press_1_channels[] = {
|
2013-09-10 12:49:00 +00:00
|
|
|
{
|
|
|
|
.type = IIO_PRESSURE,
|
|
|
|
.channel2 = IIO_NO_MOD,
|
2014-02-20 17:49:00 +00:00
|
|
|
.address = ST_PRESS_1_OUT_XL_ADDR,
|
2013-09-10 12:49:00 +00:00
|
|
|
.scan_index = ST_SENSORS_SCAN_X,
|
|
|
|
.scan_type = {
|
|
|
|
.sign = 'u',
|
|
|
|
.realbits = 24,
|
|
|
|
.storagebits = 24,
|
|
|
|
.endianness = IIO_LE,
|
|
|
|
},
|
|
|
|
.info_mask_separate =
|
2013-06-03 14:58:00 +00:00
|
|
|
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
2013-09-10 12:49:00 +00:00
|
|
|
.modified = 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.type = IIO_TEMP,
|
|
|
|
.channel2 = IIO_NO_MOD,
|
2014-02-20 17:49:00 +00:00
|
|
|
.address = ST_TEMP_1_OUT_L_ADDR,
|
2013-09-10 12:49:00 +00:00
|
|
|
.scan_index = -1,
|
|
|
|
.scan_type = {
|
|
|
|
.sign = 'u',
|
|
|
|
.realbits = 16,
|
|
|
|
.storagebits = 16,
|
|
|
|
.endianness = IIO_LE,
|
|
|
|
},
|
|
|
|
.info_mask_separate =
|
|
|
|
BIT(IIO_CHAN_INFO_RAW) |
|
|
|
|
BIT(IIO_CHAN_INFO_SCALE) |
|
|
|
|
BIT(IIO_CHAN_INFO_OFFSET),
|
|
|
|
.modified = 0,
|
|
|
|
},
|
2013-06-03 14:58:00 +00:00
|
|
|
IIO_CHAN_SOFT_TIMESTAMP(1)
|
|
|
|
};
|
|
|
|
|
2013-09-16 16:02:00 +00:00
|
|
|
static const struct iio_chan_spec st_press_lps001wp_channels[] = {
|
|
|
|
{
|
|
|
|
.type = IIO_PRESSURE,
|
|
|
|
.channel2 = IIO_NO_MOD,
|
|
|
|
.address = ST_PRESS_LPS001WP_OUT_L_ADDR,
|
|
|
|
.scan_index = ST_SENSORS_SCAN_X,
|
|
|
|
.scan_type = {
|
|
|
|
.sign = 'u',
|
|
|
|
.realbits = 16,
|
|
|
|
.storagebits = 16,
|
|
|
|
.endianness = IIO_LE,
|
|
|
|
},
|
2016-04-19 09:18:33 +00:00
|
|
|
.info_mask_separate =
|
|
|
|
BIT(IIO_CHAN_INFO_RAW) |
|
|
|
|
BIT(IIO_CHAN_INFO_SCALE),
|
2013-09-16 16:02:00 +00:00
|
|
|
.modified = 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.type = IIO_TEMP,
|
|
|
|
.channel2 = IIO_NO_MOD,
|
|
|
|
.address = ST_TEMP_LPS001WP_OUT_L_ADDR,
|
|
|
|
.scan_index = -1,
|
|
|
|
.scan_type = {
|
|
|
|
.sign = 'u',
|
|
|
|
.realbits = 16,
|
|
|
|
.storagebits = 16,
|
|
|
|
.endianness = IIO_LE,
|
|
|
|
},
|
|
|
|
.info_mask_separate =
|
|
|
|
BIT(IIO_CHAN_INFO_RAW) |
|
2016-04-19 09:18:33 +00:00
|
|
|
BIT(IIO_CHAN_INFO_SCALE),
|
2013-09-16 16:02:00 +00:00
|
|
|
.modified = 0,
|
|
|
|
},
|
|
|
|
IIO_CHAN_SOFT_TIMESTAMP(1)
|
|
|
|
};
|
|
|
|
|
2016-04-19 09:18:32 +00:00
|
|
|
static const struct iio_chan_spec st_press_lps22hb_channels[] = {
|
|
|
|
{
|
|
|
|
.type = IIO_PRESSURE,
|
|
|
|
.channel2 = IIO_NO_MOD,
|
|
|
|
.address = ST_PRESS_1_OUT_XL_ADDR,
|
|
|
|
.scan_index = 0,
|
|
|
|
.scan_type = {
|
|
|
|
.sign = 'u',
|
|
|
|
.realbits = 24,
|
|
|
|
.storagebits = 24,
|
|
|
|
.endianness = IIO_LE,
|
|
|
|
},
|
|
|
|
.info_mask_separate =
|
|
|
|
BIT(IIO_CHAN_INFO_RAW) |
|
|
|
|
BIT(IIO_CHAN_INFO_SCALE),
|
|
|
|
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
|
|
|
.modified = 0,
|
|
|
|
},
|
|
|
|
IIO_CHAN_SOFT_TIMESTAMP(1)
|
|
|
|
};
|
|
|
|
|
2014-10-03 15:35:35 +00:00
|
|
|
static const struct st_sensor_settings st_press_sensors_settings[] = {
|
2013-06-03 14:58:00 +00:00
|
|
|
{
|
2013-09-10 12:49:00 +00:00
|
|
|
.wai = ST_PRESS_LPS331AP_WAI_EXP,
|
2015-07-21 08:35:41 +00:00
|
|
|
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
2013-06-03 14:58:00 +00:00
|
|
|
.sensors_supported = {
|
|
|
|
[0] = LPS331AP_PRESS_DEV_NAME,
|
|
|
|
},
|
2014-02-20 17:49:00 +00:00
|
|
|
.ch = (struct iio_chan_spec *)st_press_1_channels,
|
|
|
|
.num_ch = ARRAY_SIZE(st_press_1_channels),
|
2013-06-03 14:58:00 +00:00
|
|
|
.odr = {
|
2013-09-10 12:49:00 +00:00
|
|
|
.addr = ST_PRESS_LPS331AP_ODR_ADDR,
|
|
|
|
.mask = ST_PRESS_LPS331AP_ODR_MASK,
|
2013-06-03 14:58:00 +00:00
|
|
|
.odr_avl = {
|
2013-09-10 12:49:00 +00:00
|
|
|
{ 1, ST_PRESS_LPS331AP_ODR_AVL_1HZ_VAL, },
|
|
|
|
{ 7, ST_PRESS_LPS331AP_ODR_AVL_7HZ_VAL, },
|
|
|
|
{ 13, ST_PRESS_LPS331AP_ODR_AVL_13HZ_VAL, },
|
|
|
|
{ 25, ST_PRESS_LPS331AP_ODR_AVL_25HZ_VAL, },
|
2013-06-03 14:58:00 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
.pw = {
|
2013-09-10 12:49:00 +00:00
|
|
|
.addr = ST_PRESS_LPS331AP_PW_ADDR,
|
|
|
|
.mask = ST_PRESS_LPS331AP_PW_MASK,
|
2013-06-03 14:58:00 +00:00
|
|
|
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
|
|
|
|
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
|
|
|
|
},
|
|
|
|
.fs = {
|
2013-09-10 12:49:00 +00:00
|
|
|
.addr = ST_PRESS_LPS331AP_FS_ADDR,
|
|
|
|
.mask = ST_PRESS_LPS331AP_FS_MASK,
|
2013-06-03 14:58:00 +00:00
|
|
|
.fs_avl = {
|
2016-04-19 09:18:33 +00:00
|
|
|
/*
|
|
|
|
* Pressure and temperature sensitivity values
|
|
|
|
* as defined in table 3 of LPS331AP datasheet.
|
|
|
|
*/
|
2013-06-03 14:58:00 +00:00
|
|
|
[0] = {
|
|
|
|
.num = ST_PRESS_FS_AVL_1260MB,
|
2016-04-19 09:18:33 +00:00
|
|
|
.gain = ST_PRESS_KPASCAL_NANO_SCALE,
|
|
|
|
.gain2 = ST_PRESS_LSB_PER_CELSIUS,
|
2013-06-03 14:58:00 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.bdu = {
|
2013-09-10 12:49:00 +00:00
|
|
|
.addr = ST_PRESS_LPS331AP_BDU_ADDR,
|
|
|
|
.mask = ST_PRESS_LPS331AP_BDU_MASK,
|
2013-06-03 14:58:00 +00:00
|
|
|
},
|
|
|
|
.drdy_irq = {
|
2013-09-10 12:49:00 +00:00
|
|
|
.addr = ST_PRESS_LPS331AP_DRDY_IRQ_ADDR,
|
|
|
|
.mask_int1 = ST_PRESS_LPS331AP_DRDY_IRQ_INT1_MASK,
|
|
|
|
.mask_int2 = ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK,
|
2015-11-19 09:15:17 +00:00
|
|
|
.addr_ihl = ST_PRESS_LPS331AP_IHL_IRQ_ADDR,
|
|
|
|
.mask_ihl = ST_PRESS_LPS331AP_IHL_IRQ_MASK,
|
2016-04-14 08:45:21 +00:00
|
|
|
.addr_od = ST_PRESS_LPS331AP_OD_IRQ_ADDR,
|
|
|
|
.mask_od = ST_PRESS_LPS331AP_OD_IRQ_MASK,
|
2016-03-24 13:18:05 +00:00
|
|
|
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
|
2013-06-03 14:58:00 +00:00
|
|
|
},
|
2013-09-10 12:49:00 +00:00
|
|
|
.multi_read_bit = ST_PRESS_LPS331AP_MULTIREAD_BIT,
|
2013-06-03 14:58:00 +00:00
|
|
|
.bootime = 2,
|
|
|
|
},
|
2013-09-16 16:02:00 +00:00
|
|
|
{
|
|
|
|
.wai = ST_PRESS_LPS001WP_WAI_EXP,
|
2015-07-21 08:35:41 +00:00
|
|
|
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
2013-09-16 16:02:00 +00:00
|
|
|
.sensors_supported = {
|
|
|
|
[0] = LPS001WP_PRESS_DEV_NAME,
|
|
|
|
},
|
|
|
|
.ch = (struct iio_chan_spec *)st_press_lps001wp_channels,
|
|
|
|
.num_ch = ARRAY_SIZE(st_press_lps001wp_channels),
|
|
|
|
.odr = {
|
|
|
|
.addr = ST_PRESS_LPS001WP_ODR_ADDR,
|
|
|
|
.mask = ST_PRESS_LPS001WP_ODR_MASK,
|
|
|
|
.odr_avl = {
|
|
|
|
{ 1, ST_PRESS_LPS001WP_ODR_AVL_1HZ_VAL, },
|
|
|
|
{ 7, ST_PRESS_LPS001WP_ODR_AVL_7HZ_VAL, },
|
|
|
|
{ 13, ST_PRESS_LPS001WP_ODR_AVL_13HZ_VAL, },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.pw = {
|
|
|
|
.addr = ST_PRESS_LPS001WP_PW_ADDR,
|
|
|
|
.mask = ST_PRESS_LPS001WP_PW_MASK,
|
|
|
|
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
|
|
|
|
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
|
|
|
|
},
|
|
|
|
.fs = {
|
2016-04-19 09:18:33 +00:00
|
|
|
.fs_avl = {
|
|
|
|
/*
|
|
|
|
* Pressure and temperature resolution values
|
|
|
|
* as defined in table 3 of LPS001WP datasheet.
|
|
|
|
*/
|
|
|
|
[0] = {
|
|
|
|
.num = ST_PRESS_FS_AVL_1100MB,
|
|
|
|
.gain = ST_PRESS_LPS001WP_FS_AVL_PRESS_GAIN,
|
|
|
|
.gain2 = ST_PRESS_LPS001WP_LSB_PER_CELSIUS,
|
|
|
|
},
|
|
|
|
},
|
2013-09-16 16:02:00 +00:00
|
|
|
},
|
|
|
|
.bdu = {
|
|
|
|
.addr = ST_PRESS_LPS001WP_BDU_ADDR,
|
|
|
|
.mask = ST_PRESS_LPS001WP_BDU_MASK,
|
|
|
|
},
|
|
|
|
.drdy_irq = {
|
|
|
|
.addr = 0,
|
|
|
|
},
|
|
|
|
.multi_read_bit = ST_PRESS_LPS001WP_MULTIREAD_BIT,
|
|
|
|
.bootime = 2,
|
|
|
|
},
|
2014-02-20 17:49:00 +00:00
|
|
|
{
|
|
|
|
.wai = ST_PRESS_LPS25H_WAI_EXP,
|
2015-07-21 08:35:41 +00:00
|
|
|
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
2014-02-20 17:49:00 +00:00
|
|
|
.sensors_supported = {
|
|
|
|
[0] = LPS25H_PRESS_DEV_NAME,
|
|
|
|
},
|
|
|
|
.ch = (struct iio_chan_spec *)st_press_1_channels,
|
|
|
|
.num_ch = ARRAY_SIZE(st_press_1_channels),
|
|
|
|
.odr = {
|
|
|
|
.addr = ST_PRESS_LPS25H_ODR_ADDR,
|
|
|
|
.mask = ST_PRESS_LPS25H_ODR_MASK,
|
|
|
|
.odr_avl = {
|
|
|
|
{ 1, ST_PRESS_LPS25H_ODR_AVL_1HZ_VAL, },
|
|
|
|
{ 7, ST_PRESS_LPS25H_ODR_AVL_7HZ_VAL, },
|
|
|
|
{ 13, ST_PRESS_LPS25H_ODR_AVL_13HZ_VAL, },
|
|
|
|
{ 25, ST_PRESS_LPS25H_ODR_AVL_25HZ_VAL, },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.pw = {
|
|
|
|
.addr = ST_PRESS_LPS25H_PW_ADDR,
|
|
|
|
.mask = ST_PRESS_LPS25H_PW_MASK,
|
|
|
|
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
|
|
|
|
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
|
|
|
|
},
|
|
|
|
.fs = {
|
|
|
|
.fs_avl = {
|
2016-04-19 09:18:33 +00:00
|
|
|
/*
|
|
|
|
* Pressure and temperature sensitivity values
|
|
|
|
* as defined in table 3 of LPS25H datasheet.
|
|
|
|
*/
|
2014-02-20 17:49:00 +00:00
|
|
|
[0] = {
|
|
|
|
.num = ST_PRESS_FS_AVL_1260MB,
|
2016-04-19 09:18:33 +00:00
|
|
|
.gain = ST_PRESS_KPASCAL_NANO_SCALE,
|
|
|
|
.gain2 = ST_PRESS_LSB_PER_CELSIUS,
|
2014-02-20 17:49:00 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.bdu = {
|
|
|
|
.addr = ST_PRESS_LPS25H_BDU_ADDR,
|
|
|
|
.mask = ST_PRESS_LPS25H_BDU_MASK,
|
|
|
|
},
|
|
|
|
.drdy_irq = {
|
|
|
|
.addr = ST_PRESS_LPS25H_DRDY_IRQ_ADDR,
|
|
|
|
.mask_int1 = ST_PRESS_LPS25H_DRDY_IRQ_INT1_MASK,
|
|
|
|
.mask_int2 = ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK,
|
2015-11-19 09:15:17 +00:00
|
|
|
.addr_ihl = ST_PRESS_LPS25H_IHL_IRQ_ADDR,
|
|
|
|
.mask_ihl = ST_PRESS_LPS25H_IHL_IRQ_MASK,
|
2016-04-14 08:45:21 +00:00
|
|
|
.addr_od = ST_PRESS_LPS25H_OD_IRQ_ADDR,
|
|
|
|
.mask_od = ST_PRESS_LPS25H_OD_IRQ_MASK,
|
2016-03-24 13:18:05 +00:00
|
|
|
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
|
2014-02-20 17:49:00 +00:00
|
|
|
},
|
|
|
|
.multi_read_bit = ST_PRESS_LPS25H_MULTIREAD_BIT,
|
|
|
|
.bootime = 2,
|
|
|
|
},
|
2016-04-19 09:18:32 +00:00
|
|
|
{
|
|
|
|
.wai = ST_PRESS_LPS22HB_WAI_EXP,
|
|
|
|
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
|
|
|
.sensors_supported = {
|
|
|
|
[0] = LPS22HB_PRESS_DEV_NAME,
|
|
|
|
},
|
|
|
|
.ch = (struct iio_chan_spec *)st_press_lps22hb_channels,
|
|
|
|
.num_ch = ARRAY_SIZE(st_press_lps22hb_channels),
|
|
|
|
.odr = {
|
|
|
|
.addr = ST_PRESS_LPS22HB_ODR_ADDR,
|
|
|
|
.mask = ST_PRESS_LPS22HB_ODR_MASK,
|
|
|
|
.odr_avl = {
|
|
|
|
{ 1, ST_PRESS_LPS22HB_ODR_AVL_1HZ_VAL, },
|
|
|
|
{ 10, ST_PRESS_LPS22HB_ODR_AVL_10HZ_VAL, },
|
|
|
|
{ 25, ST_PRESS_LPS22HB_ODR_AVL_25HZ_VAL, },
|
|
|
|
{ 50, ST_PRESS_LPS22HB_ODR_AVL_50HZ_VAL, },
|
|
|
|
{ 75, ST_PRESS_LPS22HB_ODR_AVL_75HZ_VAL, },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.pw = {
|
|
|
|
.addr = ST_PRESS_LPS22HB_PW_ADDR,
|
|
|
|
.mask = ST_PRESS_LPS22HB_PW_MASK,
|
|
|
|
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
|
|
|
|
},
|
|
|
|
.fs = {
|
|
|
|
.fs_avl = {
|
|
|
|
[0] = {
|
|
|
|
.num = ST_PRESS_FS_AVL_1260MB,
|
|
|
|
.gain = ST_PRESS_KPASCAL_NANO_SCALE,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.bdu = {
|
|
|
|
.addr = ST_PRESS_LPS22HB_BDU_ADDR,
|
|
|
|
.mask = ST_PRESS_LPS22HB_BDU_MASK,
|
|
|
|
},
|
|
|
|
.drdy_irq = {
|
|
|
|
.addr = ST_PRESS_LPS22HB_DRDY_IRQ_ADDR,
|
|
|
|
.mask_int1 = ST_PRESS_LPS22HB_DRDY_IRQ_INT1_MASK,
|
|
|
|
.mask_int2 = ST_PRESS_LPS22HB_DRDY_IRQ_INT2_MASK,
|
|
|
|
.addr_ihl = ST_PRESS_LPS22HB_IHL_IRQ_ADDR,
|
|
|
|
.mask_ihl = ST_PRESS_LPS22HB_IHL_IRQ_MASK,
|
|
|
|
},
|
|
|
|
.multi_read_bit = ST_PRESS_LPS22HB_MULTIREAD_BIT,
|
|
|
|
},
|
2013-06-03 14:58:00 +00:00
|
|
|
};
|
|
|
|
|
2014-06-22 19:59:00 +00:00
|
|
|
static int st_press_write_raw(struct iio_dev *indio_dev,
|
|
|
|
struct iio_chan_spec const *ch,
|
|
|
|
int val,
|
|
|
|
int val2,
|
|
|
|
long mask)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
switch (mask) {
|
|
|
|
case IIO_CHAN_INFO_SAMP_FREQ:
|
|
|
|
if (val2)
|
|
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&indio_dev->mlock);
|
|
|
|
err = st_sensors_set_odr(indio_dev, val);
|
|
|
|
mutex_unlock(&indio_dev->mlock);
|
|
|
|
return err;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-03 14:58:00 +00:00
|
|
|
static int st_press_read_raw(struct iio_dev *indio_dev,
|
|
|
|
struct iio_chan_spec const *ch, int *val,
|
|
|
|
int *val2, long mask)
|
|
|
|
{
|
|
|
|
int err;
|
2014-10-03 15:35:40 +00:00
|
|
|
struct st_sensor_data *press_data = iio_priv(indio_dev);
|
2013-06-03 14:58:00 +00:00
|
|
|
|
|
|
|
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:
|
|
|
|
switch (ch->type) {
|
|
|
|
case IIO_PRESSURE:
|
2016-04-19 09:18:33 +00:00
|
|
|
*val = 0;
|
2014-10-03 15:35:40 +00:00
|
|
|
*val2 = press_data->current_fullscale->gain;
|
2016-04-19 09:18:33 +00:00
|
|
|
return IIO_VAL_INT_PLUS_NANO;
|
2013-06-03 14:58:00 +00:00
|
|
|
case IIO_TEMP:
|
2016-04-19 09:18:33 +00:00
|
|
|
*val = MCELSIUS_PER_CELSIUS;
|
2014-10-03 15:35:40 +00:00
|
|
|
*val2 = press_data->current_fullscale->gain2;
|
2016-04-19 09:18:33 +00:00
|
|
|
return IIO_VAL_FRACTIONAL;
|
2013-06-03 14:58:00 +00:00
|
|
|
default:
|
|
|
|
err = -EINVAL;
|
|
|
|
goto read_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
case IIO_CHAN_INFO_OFFSET:
|
|
|
|
switch (ch->type) {
|
|
|
|
case IIO_TEMP:
|
2016-04-19 09:18:33 +00:00
|
|
|
*val = ST_PRESS_MILLI_CELSIUS_OFFSET *
|
|
|
|
press_data->current_fullscale->gain2;
|
|
|
|
*val2 = MCELSIUS_PER_CELSIUS;
|
2013-06-03 14:58:00 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
err = -EINVAL;
|
|
|
|
goto read_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return IIO_VAL_FRACTIONAL;
|
2014-06-22 19:59:00 +00:00
|
|
|
case IIO_CHAN_INFO_SAMP_FREQ:
|
2014-10-03 15:35:40 +00:00
|
|
|
*val = press_data->odr;
|
2014-06-22 19:59:00 +00:00
|
|
|
return IIO_VAL_INT;
|
2013-06-03 14:58:00 +00:00
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
read_error:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
|
|
|
|
|
|
|
|
static struct attribute *st_press_attributes[] = {
|
|
|
|
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct attribute_group st_press_attribute_group = {
|
|
|
|
.attrs = st_press_attributes,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct iio_info press_info = {
|
|
|
|
.driver_module = THIS_MODULE,
|
|
|
|
.attrs = &st_press_attribute_group,
|
|
|
|
.read_raw = &st_press_read_raw,
|
2014-06-22 19:59:00 +00:00
|
|
|
.write_raw = &st_press_write_raw,
|
2015-08-12 08:22:41 +00:00
|
|
|
.debugfs_reg_access = &st_sensors_debugfs_reg_access,
|
2013-06-03 14:58:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef CONFIG_IIO_TRIGGER
|
|
|
|
static const struct iio_trigger_ops st_press_trigger_ops = {
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.set_trigger_state = ST_PRESS_TRIGGER_SET_STATE,
|
iio: st_sensors: switch to a threaded interrupt
commit 98ad8b41f58dff6b30713d7f09ae3834b8df7ded
("iio: st_sensors: verify interrupt event to status") caused
a regression when reading ST sensors from a HRTimer trigger
rather than the intrinsic interrupts: the HRTimer may
trigger faster than the sensor provides new values, and
as the check against new values available as a cause of
the interrupt trigger was done in the poll function,
this would bail out of the HRTimer interrupt with
IRQ_NONE.
So clearly we need to only check the new values available
from the proper interrupt handler and not from the poll
function, which should rather just read the raw values
from the registers, put them into the buffer and be happy.
To achieve this: switch the ST Sensors over to using a true
threaded interrupt handler.
In the interrupt thread, check if new values are available,
else yield to the (potential) next device on the same
interrupt line to check the registers. If the interrupt
was ours, proceed to poll the values.
Instead of relying on iio_trigger_generic_data_rdy_poll() as
a top half to wake up the thread that polls the sensor for
new data, have the thread call iio_trigger_poll_chained()
after determining that is is the proper source of the
interrupt. This is modelled on drivers/iio/accel/mma8452.c
which is already using a properly threaded interrupt handler.
In order to get the same precision in timestamps as
previously, where samples would be timestamped in the
poll function pf->timestamp when calling
iio_trigger_generic_data_rdy_poll() we introduce a
local timestamp in the sensor data, set it in the top half
(fastpath) of the interrupt handler and provide that to the
core when calling iio_push_to_buffers_with_timestamp().
Additionally: if the active scanmask is not set for the
sensor no IRQs should be enabled and we need to bail out
with IRQ_NONE. This can happen if spurious IRQs fire when
installing the threaded interrupt handler.
Tested with hard interrupt triggers on LIS331DL, then also
tested with hrtimers on the same sensor by creating a 75Hz
HRTimer and using it to poll the sensor.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Cc: Giuseppe Barba <giuseppe.barba@st.com>
Cc: Denis Ciocca <denis.ciocca@st.com>
Reported-by: Crestez Dan Leonard <cdleonard@gmail.com>
Tested-by: Crestez Dan Leonard <cdleonard@gmail.com>
Tested-by: Jonathan Cameron <jic23@kernel.org>
Fixes: 97865fe41322 ("iio: st_sensors: verify interrupt event to status")
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
2016-05-21 18:43:16 +00:00
|
|
|
.validate_device = st_sensors_validate_device,
|
2013-06-03 14:58:00 +00:00
|
|
|
};
|
|
|
|
#define ST_PRESS_TRIGGER_OPS (&st_press_trigger_ops)
|
|
|
|
#else
|
|
|
|
#define ST_PRESS_TRIGGER_OPS NULL
|
|
|
|
#endif
|
|
|
|
|
2014-10-03 15:35:39 +00:00
|
|
|
int st_press_common_probe(struct iio_dev *indio_dev)
|
2013-06-03 14:58:00 +00:00
|
|
|
{
|
2014-10-03 15:35:40 +00:00
|
|
|
struct st_sensor_data *press_data = iio_priv(indio_dev);
|
|
|
|
int irq = press_data->get_irq_data_ready(indio_dev);
|
2013-09-16 16:02:00 +00:00
|
|
|
int err;
|
2013-06-03 14:58:00 +00:00
|
|
|
|
|
|
|
indio_dev->modes = INDIO_DIRECT_MODE;
|
|
|
|
indio_dev->info = &press_info;
|
2015-04-20 11:57:18 +00:00
|
|
|
mutex_init(&press_data->tb.buf_lock);
|
2013-06-03 14:58:00 +00:00
|
|
|
|
2016-04-19 09:18:40 +00:00
|
|
|
err = st_sensors_power_enable(indio_dev);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2013-09-16 16:02:00 +00:00
|
|
|
|
2013-06-03 14:58:00 +00:00
|
|
|
err = st_sensors_check_device_support(indio_dev,
|
2014-10-03 15:35:35 +00:00
|
|
|
ARRAY_SIZE(st_press_sensors_settings),
|
|
|
|
st_press_sensors_settings);
|
2013-06-03 14:58:00 +00:00
|
|
|
if (err < 0)
|
2016-04-19 09:18:40 +00:00
|
|
|
goto st_press_power_off;
|
2013-06-03 14:58:00 +00:00
|
|
|
|
2014-10-03 15:35:40 +00:00
|
|
|
press_data->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS;
|
|
|
|
press_data->multiread_bit = press_data->sensor_settings->multi_read_bit;
|
|
|
|
indio_dev->channels = press_data->sensor_settings->ch;
|
|
|
|
indio_dev->num_channels = press_data->sensor_settings->num_ch;
|
2013-06-03 14:58:00 +00:00
|
|
|
|
2016-04-19 09:18:32 +00:00
|
|
|
press_data->current_fullscale =
|
|
|
|
(struct st_sensor_fullscale_avl *)
|
|
|
|
&press_data->sensor_settings->fs.fs_avl[0];
|
2013-09-10 12:49:00 +00:00
|
|
|
|
2014-10-03 15:35:40 +00:00
|
|
|
press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz;
|
2013-06-03 14:58:00 +00:00
|
|
|
|
2013-09-16 16:02:00 +00:00
|
|
|
/* Some devices don't support a data ready pin. */
|
2014-10-03 15:35:40 +00:00
|
|
|
if (!press_data->dev->platform_data &&
|
|
|
|
press_data->sensor_settings->drdy_irq.addr)
|
|
|
|
press_data->dev->platform_data =
|
2013-06-19 08:28:00 +00:00
|
|
|
(struct st_sensors_platform_data *)&default_press_pdata;
|
|
|
|
|
2014-10-03 15:35:40 +00:00
|
|
|
err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data);
|
2013-06-03 14:58:00 +00:00
|
|
|
if (err < 0)
|
2016-04-19 09:18:40 +00:00
|
|
|
goto st_press_power_off;
|
2013-06-03 14:58:00 +00:00
|
|
|
|
2013-09-18 09:00:00 +00:00
|
|
|
err = st_press_allocate_ring(indio_dev);
|
|
|
|
if (err < 0)
|
2016-04-19 09:18:40 +00:00
|
|
|
goto st_press_power_off;
|
2013-06-03 14:58:00 +00:00
|
|
|
|
2013-09-18 09:00:00 +00:00
|
|
|
if (irq > 0) {
|
2013-06-03 14:58:00 +00:00
|
|
|
err = st_sensors_allocate_trigger(indio_dev,
|
2013-09-16 16:02:00 +00:00
|
|
|
ST_PRESS_TRIGGER_OPS);
|
2013-06-03 14:58:00 +00:00
|
|
|
if (err < 0)
|
|
|
|
goto st_press_probe_trigger_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = iio_device_register(indio_dev);
|
|
|
|
if (err)
|
|
|
|
goto st_press_device_register_error;
|
|
|
|
|
2014-04-13 19:08:00 +00:00
|
|
|
dev_info(&indio_dev->dev, "registered pressure sensor %s\n",
|
|
|
|
indio_dev->name);
|
|
|
|
|
2013-06-03 14:58:00 +00:00
|
|
|
return err;
|
|
|
|
|
|
|
|
st_press_device_register_error:
|
2013-09-16 16:02:00 +00:00
|
|
|
if (irq > 0)
|
2013-06-03 14:58:00 +00:00
|
|
|
st_sensors_deallocate_trigger(indio_dev);
|
|
|
|
st_press_probe_trigger_error:
|
2013-09-18 09:00:00 +00:00
|
|
|
st_press_deallocate_ring(indio_dev);
|
2016-04-19 09:18:40 +00:00
|
|
|
st_press_power_off:
|
|
|
|
st_sensors_power_disable(indio_dev);
|
2013-09-16 16:02:00 +00:00
|
|
|
|
2013-06-03 14:58:00 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(st_press_common_probe);
|
|
|
|
|
|
|
|
void st_press_common_remove(struct iio_dev *indio_dev)
|
|
|
|
{
|
2014-10-03 15:35:40 +00:00
|
|
|
struct st_sensor_data *press_data = iio_priv(indio_dev);
|
2013-06-03 14:58:00 +00:00
|
|
|
|
2014-04-13 19:08:00 +00:00
|
|
|
st_sensors_power_disable(indio_dev);
|
2013-09-16 16:02:00 +00:00
|
|
|
|
2013-06-03 14:58:00 +00:00
|
|
|
iio_device_unregister(indio_dev);
|
2014-10-03 15:35:40 +00:00
|
|
|
if (press_data->get_irq_data_ready(indio_dev) > 0)
|
2013-06-03 14:58:00 +00:00
|
|
|
st_sensors_deallocate_trigger(indio_dev);
|
2013-09-18 09:00:00 +00:00
|
|
|
|
|
|
|
st_press_deallocate_ring(indio_dev);
|
2013-06-03 14:58:00 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(st_press_common_remove);
|
|
|
|
|
|
|
|
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
|
|
|
|
MODULE_DESCRIPTION("STMicroelectronics pressures driver");
|
|
|
|
MODULE_LICENSE("GPL v2");
|