From 442353acf1ced035d7f19ce84cae15771cb85a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= Date: Thu, 10 Feb 2022 02:09:24 +0100 Subject: [PATCH 394/464] iio: af8133j: Add runtime power management Power down the sensor when not in use and during system sleep. Signed-off-by: Ondrej Jirman --- 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 5fc684802663..5b84859a85ea 100644 --- a/drivers/iio/magnetometer/af8133j.c +++ b/drivers/iio/magnetometer/af8133j.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -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: @@ -238,18 +264,19 @@ static const struct regmap_config af8133j_regmap_config = { static int af8133j_probe(struct i2c_client *client) { + 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); @@ -258,20 +285,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"); /* @@ -281,17 +308,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; } @@ -299,10 +332,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", }, { } @@ -319,10 +380,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.34.1