diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-10-20 00:10:27 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-10-20 00:10:27 -0300 |
commit | d0b2f91bede3bd5e3d24dd6803e56eee959c1797 (patch) | |
tree | 7fee4ab0509879c373c4f2cbd5b8a5be5b4041ee /drivers/iio/pressure/st_pressure_core.c | |
parent | e914f8eb445e8f74b00303c19c2ffceaedd16a05 (diff) |
Linux-libre 4.8.2-gnupck-4.8.2-gnu
Diffstat (limited to 'drivers/iio/pressure/st_pressure_core.c')
-rw-r--r-- | drivers/iio/pressure/st_pressure_core.c | 252 |
1 files changed, 222 insertions, 30 deletions
diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 92a118c3c..55df9a75e 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -28,6 +28,72 @@ #include <linux/iio/common/st_sensors.h> #include "st_pressure.h" +/* + * About determining pressure scaling factors + * ------------------------------------------ + * + * Datasheets specify typical pressure sensitivity so that pressure is computed + * according to the following equation : + * pressure[mBar] = raw / sensitivity + * where : + * raw the 24 bits long raw sampled pressure + * sensitivity a scaling factor specified by the datasheet in LSB/mBar + * + * IIO ABI expects pressure to be expressed as kPascal, hence pressure should be + * computed according to : + * pressure[kPascal] = pressure[mBar] / 10 + * = raw / (sensitivity * 10) (1) + * + * Finally, st_press_read_raw() returns pressure scaling factor as an + * IIO_VAL_INT_PLUS_NANO with a zero integral part and "gain" as decimal part. + * Therefore, from (1), "gain" becomes : + * gain = 10^9 / (sensitivity * 10) + * = 10^8 / sensitivity + * + * About determining temperature scaling factors and offsets + * --------------------------------------------------------- + * + * Datasheets specify typical temperature sensitivity and offset so that + * temperature is computed according to the following equation : + * temp[Celsius] = offset[Celsius] + (raw / sensitivity) + * where : + * raw the 16 bits long raw sampled temperature + * offset a constant specified by the datasheet in degree Celsius + * (sometimes zero) + * sensitivity a scaling factor specified by the datasheet in LSB/Celsius + * + * IIO ABI expects temperature to be expressed as milli degree Celsius such as + * user space should compute temperature according to : + * temp[mCelsius] = temp[Celsius] * 10^3 + * = (offset[Celsius] + (raw / sensitivity)) * 10^3 + * = ((offset[Celsius] * sensitivity) + raw) * + * (10^3 / sensitivity) (2) + * + * IIO ABI expects user space to apply offset and scaling factors to raw samples + * according to : + * temp[mCelsius] = (OFFSET + raw) * SCALE + * where : + * OFFSET an arbitrary constant exposed by device + * SCALE an arbitrary scaling factor exposed by device + * + * Matching OFFSET and SCALE with members of (2) gives : + * OFFSET = offset[Celsius] * sensitivity (3) + * SCALE = 10^3 / sensitivity (4) + * + * st_press_read_raw() returns temperature scaling factor as an + * IIO_VAL_FRACTIONAL with a 10^3 numerator and "gain2" as denominator. + * Therefore, from (3), "gain2" becomes : + * gain2 = sensitivity + * + * When declared within channel, i.e. for a non zero specified offset, + * st_press_read_raw() will return the latter as an IIO_VAL_FRACTIONAL such as : + * numerator = OFFSET * 10^3 + * denominator = 10^3 + * giving from (4): + * numerator = offset[Celsius] * 10^3 * sensitivity + * = offset[mCelsius] * gain2 + */ + #define MCELSIUS_PER_CELSIUS 1000 /* Default pressure sensitivity */ @@ -39,8 +105,6 @@ #define ST_PRESS_LSB_PER_CELSIUS 480UL #define ST_PRESS_MILLI_CELSIUS_OFFSET 42500UL -#define ST_PRESS_NUMBER_DATA_CHANNELS 1 - /* FULLSCALE */ #define ST_PRESS_FS_AVL_1100MB 1100 #define ST_PRESS_FS_AVL_1260MB 1260 @@ -48,7 +112,11 @@ #define ST_PRESS_1_OUT_XL_ADDR 0x28 #define ST_TEMP_1_OUT_L_ADDR 0x2b -/* CUSTOM VALUES FOR LPS331AP SENSOR */ +/* + * CUSTOM VALUES FOR LPS331AP SENSOR + * See LPS331AP datasheet: + * http://www2.st.com/resource/en/datasheet/lps331ap.pdf + */ #define ST_PRESS_LPS331AP_WAI_EXP 0xbb #define ST_PRESS_LPS331AP_ODR_ADDR 0x20 #define ST_PRESS_LPS331AP_ODR_MASK 0x70 @@ -71,7 +139,9 @@ #define ST_PRESS_LPS331AP_OD_IRQ_MASK 0x40 #define ST_PRESS_LPS331AP_MULTIREAD_BIT true -/* CUSTOM VALUES FOR LPS001WP SENSOR */ +/* + * CUSTOM VALUES FOR THE OBSOLETE LPS001WP SENSOR + */ /* LPS001WP pressure resolution */ #define ST_PRESS_LPS001WP_LSB_PER_MBAR 16UL @@ -94,7 +164,11 @@ #define ST_PRESS_LPS001WP_OUT_L_ADDR 0x28 #define ST_TEMP_LPS001WP_OUT_L_ADDR 0x2a -/* CUSTOM VALUES FOR LPS25H SENSOR */ +/* + * CUSTOM VALUES FOR LPS25H SENSOR + * See LPS25H datasheet: + * http://www2.st.com/resource/en/datasheet/lps25h.pdf + */ #define ST_PRESS_LPS25H_WAI_EXP 0xbd #define ST_PRESS_LPS25H_ODR_ADDR 0x20 #define ST_PRESS_LPS25H_ODR_MASK 0x70 @@ -117,27 +191,54 @@ #define ST_PRESS_LPS25H_OUT_XL_ADDR 0x28 #define ST_TEMP_LPS25H_OUT_L_ADDR 0x2b +/* + * CUSTOM VALUES FOR LPS22HB SENSOR + * See LPS22HB datasheet: + * http://www2.st.com/resource/en/datasheet/lps22hb.pdf + */ + +/* LPS22HB temperature sensitivity */ +#define ST_PRESS_LPS22HB_LSB_PER_CELSIUS 100UL + +#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_OD_IRQ_ADDR 0x12 +#define ST_PRESS_LPS22HB_OD_IRQ_MASK 0x40 +#define ST_PRESS_LPS22HB_MULTIREAD_BIT true + static const struct iio_chan_spec st_press_1_channels[] = { { .type = IIO_PRESSURE, - .channel2 = IIO_NO_MOD, .address = ST_PRESS_1_OUT_XL_ADDR, - .scan_index = ST_SENSORS_SCAN_X, + .scan_index = 0, .scan_type = { .sign = 'u', .realbits = 24, - .storagebits = 24, + .storagebits = 32, .endianness = IIO_LE, }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), - .modified = 0, }, { .type = IIO_TEMP, - .channel2 = IIO_NO_MOD, .address = ST_TEMP_1_OUT_L_ADDR, - .scan_index = -1, + .scan_index = 1, .scan_type = { .sign = 'u', .realbits = 16, @@ -148,17 +249,15 @@ static const struct iio_chan_spec st_press_1_channels[] = { BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), - .modified = 0, }, - IIO_CHAN_SOFT_TIMESTAMP(1) + IIO_CHAN_SOFT_TIMESTAMP(2) }; 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_index = 0, .scan_type = { .sign = 'u', .realbits = 16, @@ -168,13 +267,11 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), - .modified = 0, }, { .type = IIO_TEMP, - .channel2 = IIO_NO_MOD, .address = ST_TEMP_LPS001WP_OUT_L_ADDR, - .scan_index = -1, + .scan_index = 1, .scan_type = { .sign = 'u', .realbits = 16, @@ -184,9 +281,42 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), - .modified = 0, }, - IIO_CHAN_SOFT_TIMESTAMP(1) + IIO_CHAN_SOFT_TIMESTAMP(2) +}; + +static const struct iio_chan_spec st_press_lps22hb_channels[] = { + { + .type = IIO_PRESSURE, + .address = ST_PRESS_1_OUT_XL_ADDR, + .scan_index = 0, + .scan_type = { + .sign = 'u', + .realbits = 24, + .storagebits = 32, + .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), + }, + { + .type = IIO_TEMP, + .address = ST_TEMP_1_OUT_L_ADDR, + .scan_index = 1, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .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), + }, + IIO_CHAN_SOFT_TIMESTAMP(2) }; static const struct st_sensor_settings st_press_sensors_settings[] = { @@ -346,6 +476,59 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { .multi_read_bit = ST_PRESS_LPS25H_MULTIREAD_BIT, .bootime = 2, }, + { + .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 = { + /* + * Pressure and temperature sensitivity values + * as defined in table 3 of LPS22HB datasheet. + */ + [0] = { + .num = ST_PRESS_FS_AVL_1260MB, + .gain = ST_PRESS_KPASCAL_NANO_SCALE, + .gain2 = ST_PRESS_LPS22HB_LSB_PER_CELSIUS, + }, + }, + }, + .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, + .addr_od = ST_PRESS_LPS22HB_OD_IRQ_ADDR, + .mask_od = ST_PRESS_LPS22HB_OD_IRQ_MASK, + .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + }, + .multi_read_bit = ST_PRESS_LPS22HB_MULTIREAD_BIT, + }, }; static int st_press_write_raw(struct iio_dev *indio_dev, @@ -462,23 +645,30 @@ int st_press_common_probe(struct iio_dev *indio_dev) indio_dev->info = &press_info; mutex_init(&press_data->tb.buf_lock); - st_sensors_power_enable(indio_dev); + err = st_sensors_power_enable(indio_dev); + if (err) + return err; err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_press_sensors_settings), st_press_sensors_settings); if (err < 0) - return err; - - press_data->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS; + goto st_press_power_off; + + /* + * Skip timestamping channel while declaring available channels to + * common st_sensor layer. Look at st_sensors_get_buffer_element() to + * see how timestamps are explicitly pushed as last samples block + * element. + */ + press_data->num_data_channels = press_data->sensor_settings->num_ch - 1; 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; - if (press_data->sensor_settings->fs.addr != 0) - press_data->current_fullscale = - (struct st_sensor_fullscale_avl *) - &press_data->sensor_settings->fs.fs_avl[0]; + press_data->current_fullscale = + (struct st_sensor_fullscale_avl *) + &press_data->sensor_settings->fs.fs_avl[0]; press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz; @@ -490,11 +680,11 @@ int st_press_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data); if (err < 0) - return err; + goto st_press_power_off; err = st_press_allocate_ring(indio_dev); if (err < 0) - return err; + goto st_press_power_off; if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, @@ -517,6 +707,8 @@ st_press_device_register_error: st_sensors_deallocate_trigger(indio_dev); st_press_probe_trigger_error: st_press_deallocate_ring(indio_dev); +st_press_power_off: + st_sensors_power_disable(indio_dev); return err; } |