build/patch/kernel/archive/sunxi-6.1/patches.megous/iio-af8133j-Add-runtime-power-management.patch

250 lines
7.2 KiB
Diff
Raw Permalink Normal View History

From 270b914c83f8302189d52a28f60d908581f37378 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 336/389] 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 3ec4a405cc8e..ef74b4c7ae4e 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