From: Vasileios Amoiridis <vassilisamir@xxxxxxxxx> Add runtime power management to the device. To facilitate this, add also a struct dev * inside the bme680_data structure to have the device accesible from the data structure. Signed-off-by: Vasileios Amoiridis <vassilisamir@xxxxxxxxx> --- drivers/iio/chemical/bme680.h | 1 + drivers/iio/chemical/bme680_core.c | 100 +++++++++++++++++++++++++++-- 2 files changed, 95 insertions(+), 6 deletions(-) diff --git a/drivers/iio/chemical/bme680.h b/drivers/iio/chemical/bme680.h index e55a48982b3e..e9e3e08fa366 100644 --- a/drivers/iio/chemical/bme680.h +++ b/drivers/iio/chemical/bme680.h @@ -75,6 +75,7 @@ #define BME680_CALIB_RANGE_3_LEN 5 extern const struct regmap_config bme680_regmap_config; +extern const struct dev_pm_ops bmp280_dev_pm_ops; int bme680_core_probe(struct device *dev, struct regmap *regmap, const char *name); diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c index a2039b966f20..5fd5740bb7fe 100644 --- a/drivers/iio/chemical/bme680_core.c +++ b/drivers/iio/chemical/bme680_core.c @@ -14,6 +14,7 @@ #include <linux/device.h> #include <linux/log2.h> #include <linux/module.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -111,6 +112,7 @@ struct bme680_data { struct regmap *regmap; struct bme680_calib bme680; struct mutex lock; /* Protect multiple serial R/W ops to device. */ + struct device *dev; u8 oversampling_temp; u8 oversampling_press; u8 oversampling_humid; @@ -753,9 +755,9 @@ static int bme680_read_gas(struct bme680_data *data, int *val) return IIO_VAL_INT; } -static int bme680_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) +static int __bme680_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) { struct bme680_data *data = iio_priv(indio_dev); int ret; @@ -803,14 +805,29 @@ static int bme680_read_raw(struct iio_dev *indio_dev, } } +static int bme680_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct bme680_data *data = iio_priv(indio_dev); + int ret; + + pm_runtime_get_sync(data->dev); + ret = __bme680_read_raw(indio_dev, chan, val, val2, mask); + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + + return ret; +} + static bool bme680_is_valid_oversampling(int rate) { return (rate > 0 && rate <= 16 && is_power_of_2(rate)); } -static int bme680_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) +static int __bme680_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct bme680_data *data = iio_priv(indio_dev); @@ -846,6 +863,21 @@ static int bme680_write_raw(struct iio_dev *indio_dev, } } +static int bme680_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct bme680_data *data = iio_priv(indio_dev); + int ret; + + pm_runtime_get_sync(data->dev); + ret = __bme680_write_raw(indio_dev, chan, val, val2, mask); + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + + return ret; +} + static const char bme680_oversampling_ratio_show[] = "1 2 4 8 16"; static IIO_CONST_ATTR(oversampling_ratio_available, @@ -873,6 +905,15 @@ static void bme680_regulators_disable(void *data) regulator_bulk_disable(BME680_NUM_SUPPLIES, supplies); } +static void bme680_pm_disable(void *data) +{ + struct device *dev = data; + + pm_runtime_get_sync(dev); + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); +} + int bme680_core_probe(struct device *dev, struct regmap *regmap, const char *name) { @@ -887,6 +928,7 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap, data = iio_priv(indio_dev); mutex_init(&data->lock); dev_set_drvdata(dev, indio_dev); + data->dev = dev; data->regmap = regmap; indio_dev->name = name; indio_dev->channels = bme680_channels; @@ -947,10 +989,56 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap, return dev_err_probe(dev, ret, "failed to set gas config data\n"); + /* Enable runtime PM */ + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, BME680_STARTUP_TIME_US * 100); + pm_runtime_use_autosuspend(dev); + pm_runtime_put(dev); + + ret = devm_add_action_or_reset(dev, bme680_pm_disable, dev); + if (ret) + return ret; + return devm_iio_device_register(dev, indio_dev); } EXPORT_SYMBOL_NS_GPL(bme680_core_probe, IIO_BME680); +static int bme680_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct bme680_data *data = iio_priv(indio_dev); + + return regulator_bulk_disable(BME680_NUM_SUPPLIES, data->supplies); +} + +static int bme680_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct bme680_data *data = iio_priv(indio_dev); + int ret; + + ret = regulator_bulk_enable(BME680_NUM_SUPPLIES, data->supplies); + if (ret) + return ret; + + fsleep(BME680_STARTUP_TIME_US); + + ret = bme680_chip_config(data); + if (ret) + return ret; + + ret = bme680_gas_config(data); + if (ret) + return ret; + + return 0; +} + +EXPORT_RUNTIME_DEV_PM_OPS(bme680_dev_pm_ops, bme680_runtime_suspend, + bme680_runtime_resume, NULL); + MODULE_AUTHOR("Himanshu Jha <himanshujha199640@xxxxxxxxx>"); MODULE_DESCRIPTION("Bosch BME680 Driver"); MODULE_LICENSE("GPL v2"); -- 2.43.0