summaryrefslogtreecommitdiffstats
path: root/drivers/iio/pressure/bmp280-core.c
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2016-06-30 03:48:53 +0200
committerJonathan Cameron <jic23@kernel.org>2016-07-03 11:32:14 +0100
commit3d838118c6aa73ae28e49bd9a014e2e9bd6ed3ab (patch)
treefd7be968315ad6ba5922a49a6e441b8858fac80d /drivers/iio/pressure/bmp280-core.c
parentaae9539496510a728bfe7d555b3ecfd5a146359a (diff)
downloadlinux-3d838118c6aa73ae28e49bd9a014e2e9bd6ed3ab.tar.gz
linux-3d838118c6aa73ae28e49bd9a014e2e9bd6ed3ab.tar.bz2
linux-3d838118c6aa73ae28e49bd9a014e2e9bd6ed3ab.zip
iio: pressure: bmp280: add power management
The PM280 has an internal standby-mode, but to really save power we should shut the sensor down and disconnect the power. With the proper .pm hooks we can enable both runtime and system power management of the sensor. We use the *force callbacks from the system PM hooks. When the sensor comes back we always reconfigure it to make sure it is ready to roll as expected. Cc: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/pressure/bmp280-core.c')
-rw-r--r--drivers/iio/pressure/bmp280-core.c65
1 files changed, 64 insertions, 1 deletions
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 3ebd84f06e36..f25df7f32ac8 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -30,6 +30,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h> /* For irq_get_irq_data() */
#include <linux/completion.h>
+#include <linux/pm_runtime.h>
#include "bmp280.h"
@@ -336,6 +337,7 @@ static int bmp280_read_raw(struct iio_dev *indio_dev,
int ret;
struct bmp280_data *data = iio_priv(indio_dev);
+ pm_runtime_get_sync(data->dev);
mutex_lock(&data->lock);
switch (mask) {
@@ -380,6 +382,8 @@ static int bmp280_read_raw(struct iio_dev *indio_dev,
}
mutex_unlock(&data->lock);
+ pm_runtime_mark_last_busy(data->dev);
+ pm_runtime_put_autosuspend(data->dev);
return ret;
}
@@ -444,6 +448,7 @@ static int bmp280_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ pm_runtime_get_sync(data->dev);
mutex_lock(&data->lock);
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
@@ -460,6 +465,8 @@ static int bmp280_write_raw(struct iio_dev *indio_dev,
break;
}
mutex_unlock(&data->lock);
+ pm_runtime_mark_last_busy(data->dev);
+ pm_runtime_put_autosuspend(data->dev);
break;
default:
return -EINVAL;
@@ -1021,12 +1028,29 @@ int bmp280_common_probe(struct device *dev,
goto out_disable_vdda;
}
+ /* Enable runtime PM */
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ /*
+ * Set autosuspend to two orders of magnitude larger than the
+ * start-up time.
+ */
+ pm_runtime_set_autosuspend_delay(dev, data->start_up_time *100);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_put(dev);
+
ret = iio_device_register(indio_dev);
if (ret)
- goto out_disable_vdda;
+ goto out_runtime_pm_disable;
+
return 0;
+out_runtime_pm_disable:
+ pm_runtime_get_sync(data->dev);
+ pm_runtime_put_noidle(data->dev);
+ pm_runtime_disable(data->dev);
out_disable_vdda:
regulator_disable(data->vdda);
out_disable_vddd:
@@ -1041,12 +1065,51 @@ int bmp280_common_remove(struct device *dev)
struct bmp280_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
+ pm_runtime_get_sync(data->dev);
+ pm_runtime_put_noidle(data->dev);
+ pm_runtime_disable(data->dev);
regulator_disable(data->vdda);
regulator_disable(data->vddd);
return 0;
}
EXPORT_SYMBOL(bmp280_common_remove);
+#ifdef CONFIG_PM
+static int bmp280_runtime_suspend(struct device *dev)
+{
+ struct bmp280_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regulator_disable(data->vdda);
+ if (ret)
+ return ret;
+ return regulator_disable(data->vddd);
+}
+
+static int bmp280_runtime_resume(struct device *dev)
+{
+ struct bmp280_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regulator_enable(data->vddd);
+ if (ret)
+ return ret;
+ ret = regulator_enable(data->vdda);
+ if (ret)
+ return ret;
+ msleep(data->start_up_time);
+ return data->chip_info->chip_config(data);
+}
+#endif /* CONFIG_PM */
+
+const struct dev_pm_ops bmp280_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(bmp280_runtime_suspend,
+ bmp280_runtime_resume, NULL)
+};
+EXPORT_SYMBOL(bmp280_dev_pm_ops);
+
MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP180/BMP280 pressure and temperature sensor");
MODULE_LICENSE("GPL v2");