The st_sensors_read_info_raw() implementation allows to get raw data from st_sensors, enabling and disabling the device at every read. This leads to delays in data access, caused by the msleep that waits the hardware to be ready after every read. Introduced always_on flag in st_sensor_data, to allow the user to keep the device always enabled. In this way, every data access to the device can be performed with no delays. Add always_on sysfs attribute. Signed-off-by: Massimo Toscanelli <massimo.toscanelli@xxxxxxxxxxxxxxxxxxxx> --- .../iio/common/st_sensors/st_sensors_core.c | 85 +++++++++++++++++-- include/linux/iio/common/st_sensors.h | 14 +++ 2 files changed, 94 insertions(+), 5 deletions(-) diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index eb452d0c423c..5d16eab30853 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -378,6 +378,8 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev, if (err < 0) return err; + sdata->always_on = false; + /* Disable DRDY, this might be still be enabled after reboot. */ err = st_sensors_set_dataready_irq(indio_dev, false); if (err < 0) @@ -554,18 +556,21 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev, err = -EBUSY; goto out; } else { - err = st_sensors_set_enable(indio_dev, true); - if (err < 0) - goto out; + if (!sdata->enabled) { + err = st_sensors_set_enable(indio_dev, true); + if (err < 0) + goto out; - msleep((sdata->sensor_settings->bootime * 1000) / sdata->odr); + msleep((sdata->sensor_settings->bootime * 1000) / sdata->odr); + } err = st_sensors_read_axis_data(indio_dev, ch, val); if (err < 0) goto out; *val = *val >> ch->scan_type.shift; - err = st_sensors_set_enable(indio_dev, false); + if (!sdata->always_on) + err = st_sensors_set_enable(indio_dev, false); } out: mutex_unlock(&indio_dev->mlock); @@ -680,6 +685,76 @@ ssize_t st_sensors_sysfs_scale_avail(struct device *dev, } EXPORT_SYMBOL(st_sensors_sysfs_scale_avail); +/* + * st_sensors_sysfs_show_always_on() - get the value of the always_on flag. + * + * @dev: device reference. + * @attr: device attribute. + * @buf: sysfs buffer. + * + * Return: Number of bytes printed into the buffer + */ +ssize_t st_sensors_sysfs_show_always_on(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct st_sensor_data *sdata = iio_priv(indio_dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", sdata->always_on); +} +EXPORT_SYMBOL(st_sensors_sysfs_show_always_on); + +/* + * st_sensors_sysfs_store_always_on() - set/unset always_on flag. + * Accepted values are: + * - 1: to set the flag and keep the + * device always enabled. + * - 0: to unset the flag and enable the + * device just during data access. + * + * @dev: device reference. + * @attr: device attribute. + * @buf: sysfs buffer. + * @count: number of bytes used from the buffer. + * + * Return: Either the number of bytes used from the buffer or an error code. + */ +ssize_t st_sensors_sysfs_store_always_on(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct st_sensor_data *sdata = iio_priv(indio_dev); + unsigned int val; + int ret; + + ret = kstrtouint(buf, 10, &val); + if (ret < 0) + return ret; + + if (val != 0 && val != 1) + return -EINVAL; + + if (!!val == sdata->always_on) + return count; + + sdata->always_on = !!val; + if (sdata->always_on) + ret = st_sensors_set_enable(indio_dev, true); + else + ret = st_sensors_set_enable(indio_dev, false); + + if (ret < 0) + return ret; + + if (sdata->always_on) + msleep((sdata->sensor_settings->bootime * 1000) / sdata->odr); + + return count; +} +EXPORT_SYMBOL(st_sensors_sysfs_store_always_on); + MODULE_AUTHOR("Denis Ciocca <denis.ciocca@xxxxxx>"); MODULE_DESCRIPTION("STMicroelectronics ST-sensors core"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 22f67845cdd3..a4d4f374487d 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -82,6 +82,10 @@ IIO_DEVICE_ATTR(name, S_IRUGO, \ st_sensors_sysfs_scale_avail, NULL , 0); +#define ST_SENSORS_DEV_ATTR_ALWAYS_ON() \ + IIO_DEVICE_ATTR(always_on, 0644, st_sensors_sysfs_show_always_on, \ + st_sensors_sysfs_store_always_on, 0) + struct st_sensor_odr_avl { unsigned int hz; u8 value; @@ -228,6 +232,7 @@ struct st_sensor_settings { * @vdd_io: Pointer to sensor's Vdd-IO power supply * @regmap: Pointer to specific sensor regmap configuration. * @enabled: Status of the sensor (false->off, true->on). + * @always_on: Flag to keep the sensor always enabled (false->off, true->on). * @odr: Output data rate of the sensor [Hz]. * num_data_channels: Number of data channels used in buffer. * @drdy_int_pin: Redirect DRDY on pin 1 (1) or pin 2 (2). @@ -248,6 +253,7 @@ struct st_sensor_data { struct regmap *regmap; bool enabled; + bool always_on; unsigned int odr; unsigned int num_data_channels; @@ -318,6 +324,14 @@ ssize_t st_sensors_sysfs_scale_avail(struct device *dev, void st_sensors_dev_name_probe(struct device *dev, char *name, int len); +ssize_t st_sensors_sysfs_show_always_on(struct device *dev, + struct device_attribute *attr, + char *buf); + +ssize_t st_sensors_sysfs_store_always_on(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + /* Accelerometer */ const struct st_sensor_settings *st_accel_get_settings(const char *name); int st_accel_common_probe(struct iio_dev *indio_dev); -- 2.25.1