aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Kepplinger <martink@posteo.de>2016-04-25 08:08:25 -0400
committerJonathan Cameron <jic23@kernel.org>2016-05-04 06:46:39 -0400
commited859fc17d67f4c0ade6f5a58365e621f88de3cf (patch)
treefe48dab9c9e9d23e26e719606fe0a8f30ef04971
parent6994aea7842d824a8cc38c950ddcab3f8a75c278 (diff)
iio: mma8452: add support for oversampling ratio
This adds the following sysfs files according to the iio ABI: -rw-r--r-- 4096 in_accel_oversampling_ratio -r--r--r-- 4096 in_accel_oversampling_ratio_available Internally, the device knows about 4 different power modes that differ in oversampling ratio (and power consumption). We just show the user what oversampling ratio(s) is/are available, depending on the current frequency. The referenced table in the datasheets makes it easier to understand. Signed-off-by: Martin Kepplinger <martink@posteo.de> Signed-off-by: Christoph Muellner <christoph.muellner@theobroma-systems.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r--drivers/iio/accel/mma8452.c185
1 files changed, 160 insertions, 25 deletions
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index e225d3c53bd5..458c82715427 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -76,6 +76,8 @@
76#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ 76#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */
77#define MMA8452_CTRL_REG2 0x2b 77#define MMA8452_CTRL_REG2 0x2b
78#define MMA8452_CTRL_REG2_RST BIT(6) 78#define MMA8452_CTRL_REG2_RST BIT(6)
79#define MMA8452_CTRL_REG2_MODS_SHIFT 3
80#define MMA8452_CTRL_REG2_MODS_MASK 0x1b
79#define MMA8452_CTRL_REG4 0x2d 81#define MMA8452_CTRL_REG4 0x2d
80#define MMA8452_CTRL_REG5 0x2e 82#define MMA8452_CTRL_REG5 0x2e
81#define MMA8452_OFF_X 0x2f 83#define MMA8452_OFF_X 0x2f
@@ -257,20 +259,17 @@ static const int mma8452_samp_freq[8][2] = {
257 {6, 250000}, {1, 560000} 259 {6, 250000}, {1, 560000}
258}; 260};
259 261
260/* Datasheet table 35 (step time vs sample frequency) */ 262/* Datasheet table: step time "Relationship with the ODR" (sample frequency) */
261static const int mma8452_transient_time_step_us[8] = { 263static const int mma8452_transient_time_step_us[4][8] = {
262 1250, 264 { 1250, 2500, 5000, 10000, 20000, 20000, 20000, 20000 }, /* normal */
263 2500, 265 { 1250, 2500, 5000, 10000, 20000, 80000, 80000, 80000 }, /* l p l n */
264 5000, 266 { 1250, 2500, 2500, 2500, 2500, 2500, 2500, 2500 }, /* high res*/
265 10000, 267 { 1250, 2500, 5000, 10000, 20000, 80000, 160000, 160000 } /* l p */
266 20000,
267 20000,
268 20000,
269 20000
270}; 268};
271 269
272/* Datasheet table 18 (normal mode) */ 270/* Datasheet table "High-Pass Filter Cutoff Options" */
273static const int mma8452_hp_filter_cutoff[8][4][2] = { 271static const int mma8452_hp_filter_cutoff[4][8][4][2] = {
272 { /* normal */
274 { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 800 Hz sample */ 273 { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 800 Hz sample */
275 { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 400 Hz sample */ 274 { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 400 Hz sample */
276 { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, /* 200 Hz sample */ 275 { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, /* 200 Hz sample */
@@ -279,8 +278,61 @@ static const int mma8452_hp_filter_cutoff[8][4][2] = {
279 { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 12.5 Hz sample */ 278 { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 12.5 Hz sample */
280 { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 6.25 Hz sample */ 279 { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 6.25 Hz sample */
281 { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} } /* 1.56 Hz sample */ 280 { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} } /* 1.56 Hz sample */
281 },
282 { /* low noise low power */
283 { {16, 0}, {8, 0}, {4, 0}, {2, 0} },
284 { {16, 0}, {8, 0}, {4, 0}, {2, 0} },
285 { {8, 0}, {4, 0}, {2, 0}, {1, 0} },
286 { {4, 0}, {2, 0}, {1, 0}, {0, 500000} },
287 { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },
288 { {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} },
289 { {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} },
290 { {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} }
291 },
292 { /* high resolution */
293 { {16, 0}, {8, 0}, {4, 0}, {2, 0} },
294 { {16, 0}, {8, 0}, {4, 0}, {2, 0} },
295 { {16, 0}, {8, 0}, {4, 0}, {2, 0} },
296 { {16, 0}, {8, 0}, {4, 0}, {2, 0} },
297 { {16, 0}, {8, 0}, {4, 0}, {2, 0} },
298 { {16, 0}, {8, 0}, {4, 0}, {2, 0} },
299 { {16, 0}, {8, 0}, {4, 0}, {2, 0} },
300 { {16, 0}, {8, 0}, {4, 0}, {2, 0} }
301 },
302 { /* low power */
303 { {16, 0}, {8, 0}, {4, 0}, {2, 0} },
304 { {8, 0}, {4, 0}, {2, 0}, {1, 0} },
305 { {4, 0}, {2, 0}, {1, 0}, {0, 500000} },
306 { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },
307 { {1, 0}, {0, 500000}, {0, 250000}, {0, 125000} },
308 { {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} },
309 { {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} },
310 { {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} }
311 }
282}; 312};
283 313
314/* Datasheet table "MODS Oversampling modes averaging values at each ODR" */
315static const u16 mma8452_os_ratio[4][8] = {
316 /* 800 Hz, 400 Hz, ... , 1.56 Hz */
317 { 2, 4, 4, 4, 4, 16, 32, 128 }, /* normal */
318 { 2, 4, 4, 4, 4, 4, 8, 32 }, /* low power low noise */
319 { 2, 4, 8, 16, 32, 128, 256, 1024 }, /* high resolution */
320 { 2, 2, 2, 2, 2, 2, 4, 16 } /* low power */
321};
322
323static int mma8452_get_power_mode(struct mma8452_data *data)
324{
325 int reg;
326
327 reg = i2c_smbus_read_byte_data(data->client,
328 MMA8452_CTRL_REG2);
329 if (reg < 0)
330 return reg;
331
332 return ((reg & MMA8452_CTRL_REG2_MODS_MASK) >>
333 MMA8452_CTRL_REG2_MODS_SHIFT);
334}
335
284static ssize_t mma8452_show_samp_freq_avail(struct device *dev, 336static ssize_t mma8452_show_samp_freq_avail(struct device *dev,
285 struct device_attribute *attr, 337 struct device_attribute *attr,
286 char *buf) 338 char *buf)
@@ -306,10 +358,39 @@ static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
306{ 358{
307 struct iio_dev *indio_dev = dev_to_iio_dev(dev); 359 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
308 struct mma8452_data *data = iio_priv(indio_dev); 360 struct mma8452_data *data = iio_priv(indio_dev);
361 int i, j;
362
363 i = mma8452_get_odr_index(data);
364 j = mma8452_get_power_mode(data);
365 if (j < 0)
366 return j;
367
368 return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[j][i],
369 ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0]));
370}
371
372static ssize_t mma8452_show_os_ratio_avail(struct device *dev,
373 struct device_attribute *attr,
374 char *buf)
375{
376 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
377 struct mma8452_data *data = iio_priv(indio_dev);
309 int i = mma8452_get_odr_index(data); 378 int i = mma8452_get_odr_index(data);
379 int j;
380 u16 val = 0;
381 size_t len = 0;
382
383 for (j = 0; j < ARRAY_SIZE(mma8452_os_ratio); j++) {
384 if (val == mma8452_os_ratio[j][i])
385 continue;
386
387 val = mma8452_os_ratio[j][i];
388
389 len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", val);
390 }
391 buf[len - 1] = '\n';
310 392
311 return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[i], 393 return len;
312 ARRAY_SIZE(mma8452_hp_filter_cutoff[0]));
313} 394}
314 395
315static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail); 396static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail);
@@ -317,6 +398,8 @@ static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO,
317 mma8452_show_scale_avail, NULL, 0); 398 mma8452_show_scale_avail, NULL, 0);
318static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available, 399static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available,
319 S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0); 400 S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0);
401static IIO_DEVICE_ATTR(in_accel_oversampling_ratio_available, S_IRUGO,
402 mma8452_show_os_ratio_avail, NULL, 0);
320 403
321static int mma8452_get_samp_freq_index(struct mma8452_data *data, 404static int mma8452_get_samp_freq_index(struct mma8452_data *data,
322 int val, int val2) 405 int val, int val2)
@@ -335,24 +418,33 @@ static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2)
335static int mma8452_get_hp_filter_index(struct mma8452_data *data, 418static int mma8452_get_hp_filter_index(struct mma8452_data *data,
336 int val, int val2) 419 int val, int val2)
337{ 420{
338 int i = mma8452_get_odr_index(data); 421 int i, j;
422
423 i = mma8452_get_odr_index(data);
424 j = mma8452_get_power_mode(data);
425 if (j < 0)
426 return j;
339 427
340 return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i], 428 return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[j][i],
341 ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2); 429 ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0]), val, val2);
342} 430}
343 431
344static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz) 432static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz)
345{ 433{
346 int i, ret; 434 int j, i, ret;
347 435
348 ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF); 436 ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF);
349 if (ret < 0) 437 if (ret < 0)
350 return ret; 438 return ret;
351 439
352 i = mma8452_get_odr_index(data); 440 i = mma8452_get_odr_index(data);
441 j = mma8452_get_power_mode(data);
442 if (j < 0)
443 return j;
444
353 ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK; 445 ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
354 *hz = mma8452_hp_filter_cutoff[i][ret][0]; 446 *hz = mma8452_hp_filter_cutoff[j][i][ret][0];
355 *uHz = mma8452_hp_filter_cutoff[i][ret][1]; 447 *uHz = mma8452_hp_filter_cutoff[j][i][ret][1];
356 448
357 return 0; 449 return 0;
358} 450}
@@ -414,6 +506,15 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
414 } 506 }
415 507
416 return IIO_VAL_INT_PLUS_MICRO; 508 return IIO_VAL_INT_PLUS_MICRO;
509 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
510 ret = mma8452_get_power_mode(data);
511 if (ret < 0)
512 return ret;
513
514 i = mma8452_get_odr_index(data);
515
516 *val = mma8452_os_ratio[ret][i];
517 return IIO_VAL_INT;
417 } 518 }
418 519
419 return -EINVAL; 520 return -EINVAL;
@@ -480,6 +581,21 @@ fail:
480 return ret; 581 return ret;
481} 582}
482 583
584static int mma8452_set_power_mode(struct mma8452_data *data, u8 mode)
585{
586 int reg;
587
588 reg = i2c_smbus_read_byte_data(data->client,
589 MMA8452_CTRL_REG2);
590 if (reg < 0)
591 return reg;
592
593 reg &= ~MMA8452_CTRL_REG2_MODS_MASK;
594 reg |= mode << MMA8452_CTRL_REG2_MODS_SHIFT;
595
596 return mma8452_change_config(data, MMA8452_CTRL_REG2, reg);
597}
598
483/* returns >0 if in freefall mode, 0 if not or <0 if an error occurred */ 599/* returns >0 if in freefall mode, 0 if not or <0 if an error occurred */
484static int mma8452_freefall_mode_enabled(struct mma8452_data *data) 600static int mma8452_freefall_mode_enabled(struct mma8452_data *data)
485{ 601{
@@ -597,6 +713,14 @@ static int mma8452_write_raw(struct iio_dev *indio_dev,
597 return mma8452_change_config(data, MMA8452_DATA_CFG, 713 return mma8452_change_config(data, MMA8452_DATA_CFG,
598 data->data_cfg); 714 data->data_cfg);
599 715
716 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
717 ret = mma8452_get_odr_index(data);
718
719 for (i = 0; i < ARRAY_SIZE(mma8452_os_ratio); i++) {
720 if (mma8452_os_ratio[i][ret] == val)
721 return mma8452_set_power_mode(data, i);
722 }
723
600 default: 724 default:
601 return -EINVAL; 725 return -EINVAL;
602 } 726 }
@@ -610,7 +734,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
610 int *val, int *val2) 734 int *val, int *val2)
611{ 735{
612 struct mma8452_data *data = iio_priv(indio_dev); 736 struct mma8452_data *data = iio_priv(indio_dev);
613 int ret, us; 737 int ret, us, power_mode;
614 738
615 switch (info) { 739 switch (info) {
616 case IIO_EV_INFO_VALUE: 740 case IIO_EV_INFO_VALUE:
@@ -629,7 +753,11 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
629 if (ret < 0) 753 if (ret < 0)
630 return ret; 754 return ret;
631 755
632 us = ret * mma8452_transient_time_step_us[ 756 power_mode = mma8452_get_power_mode(data);
757 if (power_mode < 0)
758 return power_mode;
759
760 us = ret * mma8452_transient_time_step_us[power_mode][
633 mma8452_get_odr_index(data)]; 761 mma8452_get_odr_index(data)];
634 *val = us / USEC_PER_SEC; 762 *val = us / USEC_PER_SEC;
635 *val2 = us % USEC_PER_SEC; 763 *val2 = us % USEC_PER_SEC;
@@ -677,8 +805,12 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev,
677 val); 805 val);
678 806
679 case IIO_EV_INFO_PERIOD: 807 case IIO_EV_INFO_PERIOD:
808 ret = mma8452_get_power_mode(data);
809 if (ret < 0)
810 return ret;
811
680 steps = (val * USEC_PER_SEC + val2) / 812 steps = (val * USEC_PER_SEC + val2) /
681 mma8452_transient_time_step_us[ 813 mma8452_transient_time_step_us[ret][
682 mma8452_get_odr_index(data)]; 814 mma8452_get_odr_index(data)];
683 815
684 if (steps < 0 || steps > 0xff) 816 if (steps < 0 || steps > 0xff)
@@ -978,7 +1110,8 @@ static struct attribute_group mma8452_event_attribute_group = {
978 BIT(IIO_CHAN_INFO_CALIBBIAS), \ 1110 BIT(IIO_CHAN_INFO_CALIBBIAS), \
979 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 1111 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
980 BIT(IIO_CHAN_INFO_SCALE) | \ 1112 BIT(IIO_CHAN_INFO_SCALE) | \
981 BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ 1113 BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) | \
1114 BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
982 .scan_index = idx, \ 1115 .scan_index = idx, \
983 .scan_type = { \ 1116 .scan_type = { \
984 .sign = 's', \ 1117 .sign = 's', \
@@ -998,7 +1131,8 @@ static struct attribute_group mma8452_event_attribute_group = {
998 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 1131 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
999 BIT(IIO_CHAN_INFO_CALIBBIAS), \ 1132 BIT(IIO_CHAN_INFO_CALIBBIAS), \
1000 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 1133 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
1001 BIT(IIO_CHAN_INFO_SCALE), \ 1134 BIT(IIO_CHAN_INFO_SCALE) | \
1135 BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
1002 .scan_index = idx, \ 1136 .scan_index = idx, \
1003 .scan_type = { \ 1137 .scan_type = { \
1004 .sign = 's', \ 1138 .sign = 's', \
@@ -1171,6 +1305,7 @@ static struct attribute *mma8452_attributes[] = {
1171 &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 1305 &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
1172 &iio_dev_attr_in_accel_scale_available.dev_attr.attr, 1306 &iio_dev_attr_in_accel_scale_available.dev_attr.attr,
1173 &iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available.dev_attr.attr, 1307 &iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available.dev_attr.attr,
1308 &iio_dev_attr_in_accel_oversampling_ratio_available.dev_attr.attr,
1174 NULL 1309 NULL
1175}; 1310};
1176 1311