Skip to content

Commit

Permalink
iio: pressure: bmp280: add power management
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
linusw authored and jic23 committed Jul 3, 2016
1 parent aae9539 commit 3d83811
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 1 deletion.
65 changes: 64 additions & 1 deletion drivers/iio/pressure/bmp280-core.c
Expand Up @@ -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"

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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:
Expand All @@ -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;
Expand Down Expand Up @@ -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:
Expand All @@ -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");
1 change: 1 addition & 0 deletions drivers/iio/pressure/bmp280-i2c.c
Expand Up @@ -78,6 +78,7 @@ static struct i2c_driver bmp280_i2c_driver = {
.name = "bmp280",
.acpi_match_table = ACPI_PTR(bmp280_acpi_i2c_match),
.of_match_table = of_match_ptr(bmp280_of_i2c_match),
.pm = &bmp280_dev_pm_ops,
},
.probe = bmp280_i2c_probe,
.remove = bmp280_i2c_remove,
Expand Down
1 change: 1 addition & 0 deletions drivers/iio/pressure/bmp280-spi.c
Expand Up @@ -113,6 +113,7 @@ static struct spi_driver bmp280_spi_driver = {
.driver = {
.name = "bmp280",
.of_match_table = bmp280_of_spi_match,
.pm = &bmp280_dev_pm_ops,
},
.id_table = bmp280_spi_id,
.probe = bmp280_spi_probe,
Expand Down
3 changes: 3 additions & 0 deletions drivers/iio/pressure/bmp280.h
Expand Up @@ -107,3 +107,6 @@ int bmp280_common_probe(struct device *dev,
const char *name,
int irq);
int bmp280_common_remove(struct device *dev);

/* PM ops */
extern const struct dev_pm_ops bmp280_dev_pm_ops;

0 comments on commit 3d83811

Please sign in to comment.