aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGregor Boirie <gregor.boirie@parrot.com>2016-04-19 05:18:33 -0400
committerJonathan Cameron <jic23@kernel.org>2016-05-29 10:48:54 -0400
commitd43a41152f8e9e4c0d19850884d1fada076dee10 (patch)
tree777f99636f04437df85119a9283020e382b4ca1f
parent37b1ba2c68cfbe37f5f45bb91bcfaf2b016ae6a1 (diff)
iio:st_pressure: fix sampling gains (bring inline with ABI)
Temperature channels report scaled samples in Celsius although expected as milli degree Celsius in Documentation/ABI/testing/sysfs-bus-iio. Gains are not implemented at all for LPS001WP pressure and temperature channels. This patch ensures that proper offsets and scales are exposed to userpace for both pressure and temperature channels. Also fix a NULL pointer exception when userspace reads content of sysfs scale attribute when gains are not defined. Signed-off-by: Gregor Boirie <gregor.boirie@parrot.com> Cc: <Stable@vger.kernel.org> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r--drivers/iio/pressure/st_pressure_core.c80
1 files changed, 50 insertions, 30 deletions
diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c
index 9e9b72a8f18f..257b58ac6779 100644
--- a/drivers/iio/pressure/st_pressure_core.c
+++ b/drivers/iio/pressure/st_pressure_core.c
@@ -28,15 +28,21 @@
28#include <linux/iio/common/st_sensors.h> 28#include <linux/iio/common/st_sensors.h>
29#include "st_pressure.h" 29#include "st_pressure.h"
30 30
31#define MCELSIUS_PER_CELSIUS 1000
32
33/* Default pressure sensitivity */
31#define ST_PRESS_LSB_PER_MBAR 4096UL 34#define ST_PRESS_LSB_PER_MBAR 4096UL
32#define ST_PRESS_KPASCAL_NANO_SCALE (100000000UL / \ 35#define ST_PRESS_KPASCAL_NANO_SCALE (100000000UL / \
33 ST_PRESS_LSB_PER_MBAR) 36 ST_PRESS_LSB_PER_MBAR)
37
38/* Default temperature sensitivity */
34#define ST_PRESS_LSB_PER_CELSIUS 480UL 39#define ST_PRESS_LSB_PER_CELSIUS 480UL
35#define ST_PRESS_CELSIUS_NANO_SCALE (1000000000UL / \ 40#define ST_PRESS_MILLI_CELSIUS_OFFSET 42500UL
36 ST_PRESS_LSB_PER_CELSIUS) 41
37#define ST_PRESS_NUMBER_DATA_CHANNELS 1 42#define ST_PRESS_NUMBER_DATA_CHANNELS 1
38 43
39/* FULLSCALE */ 44/* FULLSCALE */
45#define ST_PRESS_FS_AVL_1100MB 1100
40#define ST_PRESS_FS_AVL_1260MB 1260 46#define ST_PRESS_FS_AVL_1260MB 1260
41 47
42#define ST_PRESS_1_OUT_XL_ADDR 0x28 48#define ST_PRESS_1_OUT_XL_ADDR 0x28
@@ -54,9 +60,6 @@
54#define ST_PRESS_LPS331AP_PW_MASK 0x80 60#define ST_PRESS_LPS331AP_PW_MASK 0x80
55#define ST_PRESS_LPS331AP_FS_ADDR 0x23 61#define ST_PRESS_LPS331AP_FS_ADDR 0x23
56#define ST_PRESS_LPS331AP_FS_MASK 0x30 62#define ST_PRESS_LPS331AP_FS_MASK 0x30
57#define ST_PRESS_LPS331AP_FS_AVL_1260_VAL 0x00
58#define ST_PRESS_LPS331AP_FS_AVL_1260_GAIN ST_PRESS_KPASCAL_NANO_SCALE
59#define ST_PRESS_LPS331AP_FS_AVL_TEMP_GAIN ST_PRESS_CELSIUS_NANO_SCALE
60#define ST_PRESS_LPS331AP_BDU_ADDR 0x20 63#define ST_PRESS_LPS331AP_BDU_ADDR 0x20
61#define ST_PRESS_LPS331AP_BDU_MASK 0x04 64#define ST_PRESS_LPS331AP_BDU_MASK 0x04
62#define ST_PRESS_LPS331AP_DRDY_IRQ_ADDR 0x22 65#define ST_PRESS_LPS331AP_DRDY_IRQ_ADDR 0x22
@@ -67,9 +70,14 @@
67#define ST_PRESS_LPS331AP_OD_IRQ_ADDR 0x22 70#define ST_PRESS_LPS331AP_OD_IRQ_ADDR 0x22
68#define ST_PRESS_LPS331AP_OD_IRQ_MASK 0x40 71#define ST_PRESS_LPS331AP_OD_IRQ_MASK 0x40
69#define ST_PRESS_LPS331AP_MULTIREAD_BIT true 72#define ST_PRESS_LPS331AP_MULTIREAD_BIT true
70#define ST_PRESS_LPS331AP_TEMP_OFFSET 42500
71 73
72/* CUSTOM VALUES FOR LPS001WP SENSOR */ 74/* CUSTOM VALUES FOR LPS001WP SENSOR */
75
76/* LPS001WP pressure resolution */
77#define ST_PRESS_LPS001WP_LSB_PER_MBAR 16UL
78/* LPS001WP temperature resolution */
79#define ST_PRESS_LPS001WP_LSB_PER_CELSIUS 64UL
80
73#define ST_PRESS_LPS001WP_WAI_EXP 0xba 81#define ST_PRESS_LPS001WP_WAI_EXP 0xba
74#define ST_PRESS_LPS001WP_ODR_ADDR 0x20 82#define ST_PRESS_LPS001WP_ODR_ADDR 0x20
75#define ST_PRESS_LPS001WP_ODR_MASK 0x30 83#define ST_PRESS_LPS001WP_ODR_MASK 0x30
@@ -78,6 +86,8 @@
78#define ST_PRESS_LPS001WP_ODR_AVL_13HZ_VAL 0x03 86#define ST_PRESS_LPS001WP_ODR_AVL_13HZ_VAL 0x03
79#define ST_PRESS_LPS001WP_PW_ADDR 0x20 87#define ST_PRESS_LPS001WP_PW_ADDR 0x20
80#define ST_PRESS_LPS001WP_PW_MASK 0x40 88#define ST_PRESS_LPS001WP_PW_MASK 0x40
89#define ST_PRESS_LPS001WP_FS_AVL_PRESS_GAIN \
90 (100000000UL / ST_PRESS_LPS001WP_LSB_PER_MBAR)
81#define ST_PRESS_LPS001WP_BDU_ADDR 0x20 91#define ST_PRESS_LPS001WP_BDU_ADDR 0x20
82#define ST_PRESS_LPS001WP_BDU_MASK 0x04 92#define ST_PRESS_LPS001WP_BDU_MASK 0x04
83#define ST_PRESS_LPS001WP_MULTIREAD_BIT true 93#define ST_PRESS_LPS001WP_MULTIREAD_BIT true
@@ -94,11 +104,6 @@
94#define ST_PRESS_LPS25H_ODR_AVL_25HZ_VAL 0x04 104#define ST_PRESS_LPS25H_ODR_AVL_25HZ_VAL 0x04
95#define ST_PRESS_LPS25H_PW_ADDR 0x20 105#define ST_PRESS_LPS25H_PW_ADDR 0x20
96#define ST_PRESS_LPS25H_PW_MASK 0x80 106#define ST_PRESS_LPS25H_PW_MASK 0x80
97#define ST_PRESS_LPS25H_FS_ADDR 0x00
98#define ST_PRESS_LPS25H_FS_MASK 0x00
99#define ST_PRESS_LPS25H_FS_AVL_1260_VAL 0x00
100#define ST_PRESS_LPS25H_FS_AVL_1260_GAIN ST_PRESS_KPASCAL_NANO_SCALE
101#define ST_PRESS_LPS25H_FS_AVL_TEMP_GAIN ST_PRESS_CELSIUS_NANO_SCALE
102#define ST_PRESS_LPS25H_BDU_ADDR 0x20 107#define ST_PRESS_LPS25H_BDU_ADDR 0x20
103#define ST_PRESS_LPS25H_BDU_MASK 0x04 108#define ST_PRESS_LPS25H_BDU_MASK 0x04
104#define ST_PRESS_LPS25H_DRDY_IRQ_ADDR 0x23 109#define ST_PRESS_LPS25H_DRDY_IRQ_ADDR 0x23
@@ -109,7 +114,6 @@
109#define ST_PRESS_LPS25H_OD_IRQ_ADDR 0x22 114#define ST_PRESS_LPS25H_OD_IRQ_ADDR 0x22
110#define ST_PRESS_LPS25H_OD_IRQ_MASK 0x40 115#define ST_PRESS_LPS25H_OD_IRQ_MASK 0x40
111#define ST_PRESS_LPS25H_MULTIREAD_BIT true 116#define ST_PRESS_LPS25H_MULTIREAD_BIT true
112#define ST_PRESS_LPS25H_TEMP_OFFSET 42500
113#define ST_PRESS_LPS25H_OUT_XL_ADDR 0x28 117#define ST_PRESS_LPS25H_OUT_XL_ADDR 0x28
114#define ST_TEMP_LPS25H_OUT_L_ADDR 0x2b 118#define ST_TEMP_LPS25H_OUT_L_ADDR 0x2b
115 119
@@ -161,7 +165,9 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = {
161 .storagebits = 16, 165 .storagebits = 16,
162 .endianness = IIO_LE, 166 .endianness = IIO_LE,
163 }, 167 },
164 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 168 .info_mask_separate =
169 BIT(IIO_CHAN_INFO_RAW) |
170 BIT(IIO_CHAN_INFO_SCALE),
165 .modified = 0, 171 .modified = 0,
166 }, 172 },
167 { 173 {
@@ -177,7 +183,7 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = {
177 }, 183 },
178 .info_mask_separate = 184 .info_mask_separate =
179 BIT(IIO_CHAN_INFO_RAW) | 185 BIT(IIO_CHAN_INFO_RAW) |
180 BIT(IIO_CHAN_INFO_OFFSET), 186 BIT(IIO_CHAN_INFO_SCALE),
181 .modified = 0, 187 .modified = 0,
182 }, 188 },
183 IIO_CHAN_SOFT_TIMESTAMP(1) 189 IIO_CHAN_SOFT_TIMESTAMP(1)
@@ -212,11 +218,14 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
212 .addr = ST_PRESS_LPS331AP_FS_ADDR, 218 .addr = ST_PRESS_LPS331AP_FS_ADDR,
213 .mask = ST_PRESS_LPS331AP_FS_MASK, 219 .mask = ST_PRESS_LPS331AP_FS_MASK,
214 .fs_avl = { 220 .fs_avl = {
221 /*
222 * Pressure and temperature sensitivity values
223 * as defined in table 3 of LPS331AP datasheet.
224 */
215 [0] = { 225 [0] = {
216 .num = ST_PRESS_FS_AVL_1260MB, 226 .num = ST_PRESS_FS_AVL_1260MB,
217 .value = ST_PRESS_LPS331AP_FS_AVL_1260_VAL, 227 .gain = ST_PRESS_KPASCAL_NANO_SCALE,
218 .gain = ST_PRESS_LPS331AP_FS_AVL_1260_GAIN, 228 .gain2 = ST_PRESS_LSB_PER_CELSIUS,
219 .gain2 = ST_PRESS_LPS331AP_FS_AVL_TEMP_GAIN,
220 }, 229 },
221 }, 230 },
222 }, 231 },
@@ -261,7 +270,17 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
261 .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, 270 .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
262 }, 271 },
263 .fs = { 272 .fs = {
264 .addr = 0, 273 .fs_avl = {
274 /*
275 * Pressure and temperature resolution values
276 * as defined in table 3 of LPS001WP datasheet.
277 */
278 [0] = {
279 .num = ST_PRESS_FS_AVL_1100MB,
280 .gain = ST_PRESS_LPS001WP_FS_AVL_PRESS_GAIN,
281 .gain2 = ST_PRESS_LPS001WP_LSB_PER_CELSIUS,
282 },
283 },
265 }, 284 },
266 .bdu = { 285 .bdu = {
267 .addr = ST_PRESS_LPS001WP_BDU_ADDR, 286 .addr = ST_PRESS_LPS001WP_BDU_ADDR,
@@ -298,14 +317,15 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
298 .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, 317 .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
299 }, 318 },
300 .fs = { 319 .fs = {
301 .addr = ST_PRESS_LPS25H_FS_ADDR,
302 .mask = ST_PRESS_LPS25H_FS_MASK,
303 .fs_avl = { 320 .fs_avl = {
321 /*
322 * Pressure and temperature sensitivity values
323 * as defined in table 3 of LPS25H datasheet.
324 */
304 [0] = { 325 [0] = {
305 .num = ST_PRESS_FS_AVL_1260MB, 326 .num = ST_PRESS_FS_AVL_1260MB,
306 .value = ST_PRESS_LPS25H_FS_AVL_1260_VAL, 327 .gain = ST_PRESS_KPASCAL_NANO_SCALE,
307 .gain = ST_PRESS_LPS25H_FS_AVL_1260_GAIN, 328 .gain2 = ST_PRESS_LSB_PER_CELSIUS,
308 .gain2 = ST_PRESS_LPS25H_FS_AVL_TEMP_GAIN,
309 }, 329 },
310 }, 330 },
311 }, 331 },
@@ -364,26 +384,26 @@ static int st_press_read_raw(struct iio_dev *indio_dev,
364 384
365 return IIO_VAL_INT; 385 return IIO_VAL_INT;
366 case IIO_CHAN_INFO_SCALE: 386 case IIO_CHAN_INFO_SCALE:
367 *val = 0;
368
369 switch (ch->type) { 387 switch (ch->type) {
370 case IIO_PRESSURE: 388 case IIO_PRESSURE:
389 *val = 0;
371 *val2 = press_data->current_fullscale->gain; 390 *val2 = press_data->current_fullscale->gain;
372 break; 391 return IIO_VAL_INT_PLUS_NANO;
373 case IIO_TEMP: 392 case IIO_TEMP:
393 *val = MCELSIUS_PER_CELSIUS;
374 *val2 = press_data->current_fullscale->gain2; 394 *val2 = press_data->current_fullscale->gain2;
375 break; 395 return IIO_VAL_FRACTIONAL;
376 default: 396 default:
377 err = -EINVAL; 397 err = -EINVAL;
378 goto read_error; 398 goto read_error;
379 } 399 }
380 400
381 return IIO_VAL_INT_PLUS_NANO;
382 case IIO_CHAN_INFO_OFFSET: 401 case IIO_CHAN_INFO_OFFSET:
383 switch (ch->type) { 402 switch (ch->type) {
384 case IIO_TEMP: 403 case IIO_TEMP:
385 *val = 425; 404 *val = ST_PRESS_MILLI_CELSIUS_OFFSET *
386 *val2 = 10; 405 press_data->current_fullscale->gain2;
406 *val2 = MCELSIUS_PER_CELSIUS;
387 break; 407 break;
388 default: 408 default:
389 err = -EINVAL; 409 err = -EINVAL;