Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: imu: st_lsm6dsx: Decouple sensor ODR from FIFO batch data rate

The rate at which accelerometer or gyroscope sensor samples are fed
to the hardware FIFO (batch data rate, or BDR) does not have to
coincide with the sensor sampling frequency (output data rate, or
ODR); the only requirement is for the BDR to not be greater than
the ODR. Having a BDR lower than the ODR is useful in cases where
an application requires a high sampling rate for accurate detection
of motion events (e.g. wakeup events), but wants to read sensor
sample values from the hardware FIFO at a lower data rate (e.g. to
minimize the amount of I2C or SPI traffic and the rate of periodic
interrupts).
To support the above use case, add a sampling_frequency sysfs
attribute to the buffer directory of st_lsm6dsx IIO devices, which
controls the BDR for a given sensor independently from the "main"
sampling_frequency attribute (which controls the ODR); introduce a
new `hwfifo_odr_mHz` field in struct st_lsm6dsx_sensor to keep
track of the current BDR value, and use this field instead of the
`odr` field in the code that deals with the FIFO data rate. In the
sensor hub driver, make the hwfifo_odr_mHz value always mirror the
odr value, since there is no separate configuration setting to
control the BDR for data produced by the sensor hub functionality.
For backwards compatibility, set the buffer frequency equal to the
main frequency whenever the latter is updated via sysfs; if
userspace wants a different buffer frequency, it has to write to
the relevant sysfs attribute after any writes to the main frequency
attribute.

Signed-off-by: Francesco Lavra <flavra@baylibre.com>
Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Francesco Lavra and committed by
Jonathan Cameron
6b648a36 c6d702f2

+72 -10
+2
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
··· 366 366 * @hw: Pointer to instance of struct st_lsm6dsx_hw. 367 367 * @gain: Configured sensor sensitivity. 368 368 * @odr: Output data rate of the sensor [mHz]. 369 + * hwfifo_odr_mHz: Batch data rate for hardware FIFO [mHz] 369 370 * @samples_to_discard: Number of samples to discard for filters settling time. 370 371 * @watermark: Sensor watermark level. 371 372 * @decimator: Sensor decimation factor. ··· 381 380 382 381 u32 gain; 383 382 u32 odr; 383 + u32 hwfifo_odr_mHz; 384 384 385 385 u16 samples_to_discard; 386 386 u16 watermark;
+63 -8
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
··· 56 56 #include <linux/iio/kfifo_buf.h> 57 57 #include <linux/iio/iio.h> 58 58 #include <linux/iio/buffer.h> 59 + #include <linux/iio/sysfs.h> 59 60 #include <linux/regmap.h> 60 61 #include <linux/bitfield.h> 61 62 ··· 106 105 st_lsm6dsx_get_decimator_val(struct st_lsm6dsx_sensor *sensor, u32 max_odr) 107 106 { 108 107 const int max_size = ARRAY_SIZE(st_lsm6dsx_decimator_table); 109 - u32 decimator = max_odr / sensor->odr; 108 + u32 decimator = max_odr / sensor->hwfifo_odr_mHz; 110 109 int i; 111 110 112 111 if (decimator > 1) ··· 137 136 if (!(hw->enable_mask & BIT(sensor->id))) 138 137 continue; 139 138 140 - *max_odr = max_t(u32, *max_odr, sensor->odr); 141 - *min_odr = min_t(u32, *min_odr, sensor->odr); 139 + *max_odr = max(*max_odr, sensor->hwfifo_odr_mHz); 140 + *min_odr = min(*min_odr, sensor->hwfifo_odr_mHz); 142 141 } 143 142 } 144 143 145 144 static u8 st_lsm6dsx_get_sip(struct st_lsm6dsx_sensor *sensor, u32 min_odr) 146 145 { 147 - u8 sip = sensor->odr / min_odr; 146 + u8 sip = sensor->hwfifo_odr_mHz / min_odr; 148 147 149 148 return sip > 1 ? round_down(sip, 2) : sip; 150 149 } ··· 232 231 if (enable) { 233 232 int err; 234 233 235 - err = st_lsm6dsx_check_odr(sensor, sensor->odr, 234 + err = st_lsm6dsx_check_odr(sensor, sensor->hwfifo_odr_mHz, 236 235 &data); 237 236 if (err < 0) 238 237 return err; ··· 714 713 715 714 data = &hw->settings->samples_to_discard[sensor->id]; 716 715 for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) { 717 - if (data->val[i].milli_hz == sensor->odr) { 716 + if (data->val[i].milli_hz == sensor->hwfifo_odr_mHz) { 718 717 sensor->samples_to_discard = data->val[i].samples; 719 718 return; 720 719 } ··· 800 799 .postdisable = st_lsm6dsx_buffer_postdisable, 801 800 }; 802 801 802 + static ssize_t st_lsm6dsx_hwfifo_odr_show(struct device *dev, 803 + struct device_attribute *attr, char *buf) 804 + { 805 + struct st_lsm6dsx_sensor *sensor = iio_priv(dev_to_iio_dev(dev)); 806 + 807 + return sysfs_emit(buf, "%d.%03d\n", sensor->hwfifo_odr_mHz / 1000, 808 + sensor->hwfifo_odr_mHz % 1000); 809 + } 810 + 811 + static ssize_t st_lsm6dsx_hwfifo_odr_store(struct device *dev, 812 + struct device_attribute *attr, 813 + const char *buf, size_t len) 814 + { 815 + struct iio_dev *iio_dev = dev_to_iio_dev(dev); 816 + struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 817 + int integer, milli; 818 + int ret; 819 + u32 hwfifo_odr; 820 + u8 data; 821 + 822 + if (!iio_device_claim_direct(iio_dev)) 823 + return -EBUSY; 824 + 825 + ret = iio_str_to_fixpoint(buf, 100, &integer, &milli); 826 + if (ret) 827 + goto out; 828 + 829 + hwfifo_odr = integer * 1000 + milli; 830 + ret = st_lsm6dsx_check_odr(sensor, hwfifo_odr, &data); 831 + if (ret < 0) 832 + goto out; 833 + 834 + hwfifo_odr = ret; 835 + 836 + /* the batch data rate must not exceed the sensor output data rate */ 837 + if (hwfifo_odr <= sensor->odr) 838 + sensor->hwfifo_odr_mHz = hwfifo_odr; 839 + else 840 + ret = -EINVAL; 841 + 842 + out: 843 + iio_device_release_direct(iio_dev); 844 + 845 + return ret < 0 ? ret : len; 846 + } 847 + 848 + static IIO_DEV_ATTR_SAMP_FREQ(0664, st_lsm6dsx_hwfifo_odr_show, st_lsm6dsx_hwfifo_odr_store); 849 + 850 + static const struct iio_dev_attr *st_lsm6dsx_buffer_attrs[] = { 851 + &iio_dev_attr_sampling_frequency, 852 + NULL 853 + }; 854 + 803 855 int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw) 804 856 { 805 857 int i, ret; ··· 861 807 if (!hw->iio_devs[i]) 862 808 continue; 863 809 864 - ret = devm_iio_kfifo_buffer_setup(hw->dev, hw->iio_devs[i], 865 - &st_lsm6dsx_buffer_ops); 810 + ret = devm_iio_kfifo_buffer_setup_ext(hw->dev, hw->iio_devs[i], 811 + &st_lsm6dsx_buffer_ops, 812 + st_lsm6dsx_buffer_attrs); 866 813 if (ret) 867 814 return ret; 868 815 }
+5 -2
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
··· 1847 1847 1848 1848 val = val * 1000 + val2 / 1000; 1849 1849 val = st_lsm6dsx_check_odr(sensor, val, &data); 1850 - if (val < 0) 1850 + if (val < 0) { 1851 1851 err = val; 1852 - else 1852 + } else { 1853 1853 sensor->odr = val; 1854 + sensor->hwfifo_odr_mHz = val; 1855 + } 1854 1856 break; 1855 1857 } 1856 1858 default: ··· 2386 2384 sensor->id = id; 2387 2385 sensor->hw = hw; 2388 2386 sensor->odr = hw->settings->odr_table[id].odr_avl[0].milli_hz; 2387 + sensor->hwfifo_odr_mHz = sensor->odr; 2389 2388 sensor->gain = hw->settings->fs_table[id].fs_avl[0].gain; 2390 2389 sensor->watermark = 1; 2391 2390
+2
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
··· 640 640 641 641 sensor->ext_info.slv_odr = val; 642 642 sensor->odr = odr; 643 + sensor->hwfifo_odr_mHz = odr; 643 644 return 0; 644 645 } 645 646 case IIO_CHAN_INFO_SCALE: ··· 747 746 sensor->id = id; 748 747 sensor->hw = hw; 749 748 sensor->odr = hw->settings->odr_table[ref_id].odr_avl[0].milli_hz; 749 + sensor->hwfifo_odr_mHz = sensor->odr; 750 750 sensor->ext_info.slv_odr = info->odr_table.odr_avl[0].milli_hz; 751 751 sensor->gain = info->fs_table.fs_avl[0].gain; 752 752 sensor->ext_info.settings = info;