250 lines
7.2 KiB
Diff
250 lines
7.2 KiB
Diff
|
From 290ae9f5020dc9c98043f6670fc9d07ec8954373 Mon Sep 17 00:00:00 2001
|
||
|
From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= <megi@xff.cz>
|
||
|
Date: Thu, 10 Feb 2022 02:09:24 +0100
|
||
|
Subject: [PATCH 385/391] iio: af8133j: Add runtime power management
|
||
|
|
||
|
Power down the sensor when not in use and during system sleep.
|
||
|
|
||
|
Signed-off-by: Ondrej Jirman <megi@xff.cz>
|
||
|
---
|
||
|
drivers/iio/magnetometer/af8133j.c | 100 +++++++++++++++++++++++------
|
||
|
1 file changed, 81 insertions(+), 19 deletions(-)
|
||
|
|
||
|
diff --git a/drivers/iio/magnetometer/af8133j.c b/drivers/iio/magnetometer/af8133j.c
|
||
|
index 3ec4a405c..ef74b4c7a 100644
|
||
|
--- a/drivers/iio/magnetometer/af8133j.c
|
||
|
+++ b/drivers/iio/magnetometer/af8133j.c
|
||
|
@@ -11,6 +11,7 @@
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/regmap.h>
|
||
|
#include <linux/gpio/consumer.h>
|
||
|
+#include <linux/pm_runtime.h>
|
||
|
#include <linux/regulator/consumer.h>
|
||
|
|
||
|
#include <linux/iio/iio.h>
|
||
|
@@ -54,6 +55,7 @@ struct af8133j_data {
|
||
|
struct gpio_desc *reset_gpiod;
|
||
|
struct iio_mount_matrix orientation;
|
||
|
struct regulator_bulk_data supplies[AF8133J_NUM_SUPPLIES];
|
||
|
+ bool powered;
|
||
|
};
|
||
|
|
||
|
enum af8133j_axis {
|
||
|
@@ -97,6 +99,9 @@ static int af8133j_power_up(struct af8133j_data *data)
|
||
|
unsigned int val;
|
||
|
int ret;
|
||
|
|
||
|
+ if (data->powered)
|
||
|
+ return 0;
|
||
|
+
|
||
|
ret = regulator_bulk_enable(AF8133J_NUM_SUPPLIES, data->supplies);
|
||
|
if (ret) {
|
||
|
dev_err(dev, "Could not enable regulators\n");
|
||
|
@@ -144,6 +149,7 @@ static int af8133j_power_up(struct af8133j_data *data)
|
||
|
goto out_assert_reset;
|
||
|
}
|
||
|
|
||
|
+ data->powered = true;
|
||
|
return 0;
|
||
|
|
||
|
out_assert_reset:
|
||
|
@@ -154,8 +160,14 @@ static int af8133j_power_up(struct af8133j_data *data)
|
||
|
|
||
|
static void af8133j_power_down(struct af8133j_data *data)
|
||
|
{
|
||
|
+ struct device *dev = &data->client->dev;
|
||
|
+
|
||
|
+ if (!data->powered)
|
||
|
+ return;
|
||
|
+
|
||
|
gpiod_set_value_cansleep(data->reset_gpiod, 1);
|
||
|
regulator_bulk_disable(AF8133J_NUM_SUPPLIES, data->supplies);
|
||
|
+ data->powered = false;
|
||
|
}
|
||
|
|
||
|
static int af8133j_take_measurement(struct af8133j_data *data)
|
||
|
@@ -185,14 +197,29 @@ static int af8133j_take_measurement(struct af8133j_data *data)
|
||
|
|
||
|
static int af8133j_read_measurement(struct af8133j_data *data, __le16 buf[3])
|
||
|
{
|
||
|
+ struct device *dev = &data->client->dev;
|
||
|
int ret;
|
||
|
|
||
|
- ret = af8133j_take_measurement(data);
|
||
|
- if (ret < 0)
|
||
|
+ ret = pm_runtime_resume_and_get(dev);
|
||
|
+ if (ret) {
|
||
|
+ dev_err(dev, "failed to power on\n");
|
||
|
return ret;
|
||
|
+ }
|
||
|
|
||
|
- return regmap_bulk_read(data->regmap, AF8133J_REG_OUT, buf,
|
||
|
- 3 * sizeof(__le16));
|
||
|
+ mutex_lock(&data->mutex);
|
||
|
+
|
||
|
+ ret = af8133j_take_measurement(data);
|
||
|
+ if (ret == 0)
|
||
|
+ ret = regmap_bulk_read(data->regmap, AF8133J_REG_OUT, buf,
|
||
|
+ 3 * sizeof(__le16));
|
||
|
+
|
||
|
+ mutex_unlock(&data->mutex);
|
||
|
+
|
||
|
+ pm_runtime_mark_last_busy(dev);
|
||
|
+ if (pm_runtime_put_autosuspend(dev))
|
||
|
+ dev_err(dev, "failed to power off\n");
|
||
|
+
|
||
|
+ return ret;
|
||
|
}
|
||
|
|
||
|
static int af8133j_read_raw(struct iio_dev *indio_dev,
|
||
|
@@ -200,16 +227,15 @@ static int af8133j_read_raw(struct iio_dev *indio_dev,
|
||
|
int *val2, long mask)
|
||
|
{
|
||
|
struct af8133j_data *data = iio_priv(indio_dev);
|
||
|
- int ret;
|
||
|
__le16 buf[3];
|
||
|
+ int ret;
|
||
|
|
||
|
switch (mask) {
|
||
|
case IIO_CHAN_INFO_RAW:
|
||
|
- mutex_lock(&data->mutex);
|
||
|
ret = af8133j_read_measurement(data, buf);
|
||
|
- mutex_unlock(&data->mutex);
|
||
|
if (ret < 0)
|
||
|
return ret;
|
||
|
+
|
||
|
*val = sign_extend32(le16_to_cpu(buf[chan->address]), 15);
|
||
|
return IIO_VAL_INT;
|
||
|
case IIO_CHAN_INFO_SCALE:
|
||
|
@@ -239,18 +265,19 @@ static const struct regmap_config af8133j_regmap_config = {
|
||
|
static int af8133j_probe(struct i2c_client *client,
|
||
|
const struct i2c_device_id *id)
|
||
|
{
|
||
|
+ struct device *dev = &client->dev;
|
||
|
struct af8133j_data *data;
|
||
|
struct iio_dev *indio_dev;
|
||
|
struct regmap *regmap;
|
||
|
int ret, i;
|
||
|
|
||
|
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||
|
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||
|
if (!indio_dev)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
regmap = devm_regmap_init_i2c(client, &af8133j_regmap_config);
|
||
|
if (IS_ERR(regmap))
|
||
|
- return dev_err_probe(&client->dev, PTR_ERR(regmap),
|
||
|
+ return dev_err_probe(dev, PTR_ERR(regmap),
|
||
|
"regmap initialization failed\n");
|
||
|
|
||
|
data = iio_priv(indio_dev);
|
||
|
@@ -259,20 +286,20 @@ static int af8133j_probe(struct i2c_client *client,
|
||
|
data->regmap = regmap;
|
||
|
mutex_init(&data->mutex);
|
||
|
|
||
|
- data->reset_gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
|
||
|
+ data->reset_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
||
|
if (IS_ERR(data->reset_gpiod))
|
||
|
- return dev_err_probe(&client->dev, PTR_ERR(data->reset_gpiod),
|
||
|
+ return dev_err_probe(dev, PTR_ERR(data->reset_gpiod),
|
||
|
"Failed to get reset gpio\n");
|
||
|
|
||
|
for (i = 0; i < AF8133J_NUM_SUPPLIES; i++)
|
||
|
data->supplies[i].supply = af8133j_supply_names[i];
|
||
|
- ret = devm_regulator_bulk_get(&client->dev, AF8133J_NUM_SUPPLIES, data->supplies);
|
||
|
+ ret = devm_regulator_bulk_get(dev, AF8133J_NUM_SUPPLIES, data->supplies);
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
|
||
|
- ret = iio_read_mount_matrix(&client->dev, &data->orientation);
|
||
|
+ ret = iio_read_mount_matrix(dev, &data->orientation);
|
||
|
if (ret)
|
||
|
- return dev_err_probe(&client->dev, ret,
|
||
|
+ return dev_err_probe(dev, ret,
|
||
|
"Failed to read mount matrix\n");
|
||
|
|
||
|
/*
|
||
|
@@ -282,17 +309,23 @@ static int af8133j_probe(struct i2c_client *client,
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
|
||
|
+ af8133j_power_down(data);
|
||
|
+
|
||
|
indio_dev->info = &af8133j_info;
|
||
|
indio_dev->name = AF8133J_DRV_NAME;
|
||
|
indio_dev->channels = af8133j_channels;
|
||
|
indio_dev->num_channels = ARRAY_SIZE(af8133j_channels);
|
||
|
indio_dev->modes = INDIO_DIRECT_MODE;
|
||
|
|
||
|
- ret = devm_iio_device_register(&client->dev, indio_dev);
|
||
|
+ ret = devm_iio_device_register(dev, indio_dev);
|
||
|
if (ret)
|
||
|
- return dev_err_probe(&client->dev, ret,
|
||
|
+ return dev_err_probe(dev, ret,
|
||
|
"Failed to register iio device");
|
||
|
|
||
|
+ pm_runtime_enable(dev);
|
||
|
+ pm_runtime_set_autosuspend_delay(dev, 500);
|
||
|
+ pm_runtime_use_autosuspend(dev);
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -300,10 +333,38 @@ static void af8133j_remove(struct i2c_client *client)
|
||
|
{
|
||
|
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||
|
struct af8133j_data *data = iio_priv(indio_dev);
|
||
|
+ struct device *dev = &data->client->dev;
|
||
|
+
|
||
|
+ pm_runtime_disable(dev);
|
||
|
+ pm_runtime_set_suspended(dev);
|
||
|
+ pm_runtime_put_noidle(dev);
|
||
|
+
|
||
|
+ af8133j_power_down(data);
|
||
|
+}
|
||
|
+
|
||
|
+static int __maybe_unused af8133j_runtime_suspend(struct device *dev)
|
||
|
+{
|
||
|
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||
|
+ struct af8133j_data *data = iio_priv(indio_dev);
|
||
|
|
||
|
af8133j_power_down(data);
|
||
|
+
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
+static int __maybe_unused af8133j_runtime_resume(struct device *dev)
|
||
|
+{
|
||
|
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||
|
+ struct af8133j_data *data = iio_priv(indio_dev);
|
||
|
+
|
||
|
+ return af8133j_power_up(data);
|
||
|
+}
|
||
|
+
|
||
|
+const struct dev_pm_ops af8133j_pm_ops = {
|
||
|
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
|
||
|
+ SET_RUNTIME_PM_OPS(af8133j_runtime_suspend, af8133j_runtime_resume, NULL)
|
||
|
+};
|
||
|
+
|
||
|
static const struct of_device_id af8133j_of_match[] = {
|
||
|
{ .compatible = "voltafield,af8133j", },
|
||
|
{ }
|
||
|
@@ -320,10 +381,11 @@ static struct i2c_driver af8133j_driver = {
|
||
|
.driver = {
|
||
|
.name = AF8133J_DRV_NAME,
|
||
|
.of_match_table = af8133j_of_match,
|
||
|
+ .pm = &af8133j_pm_ops,
|
||
|
},
|
||
|
- .probe = af8133j_probe,
|
||
|
- .remove = af8133j_remove,
|
||
|
- .id_table = af8133j_id,
|
||
|
+ .probe = af8133j_probe,
|
||
|
+ .remove = af8133j_remove,
|
||
|
+ .id_table = af8133j_id,
|
||
|
};
|
||
|
|
||
|
module_i2c_driver(af8133j_driver);
|
||
|
--
|
||
|
2.35.3
|
||
|
|