summaryrefslogtreecommitdiffstats
path: root/drivers/media/i2c/dw9768.c
diff options
context:
space:
mode:
authorSakari Ailus <sakari.ailus@linux.intel.com>2022-10-17 10:23:28 +0300
committerSakari Ailus <sakari.ailus@linux.intel.com>2022-10-27 14:38:03 +0300
commit5f9a089b6de34655318afe8e544d9a9cc0fc1d29 (patch)
treea3948daf941c16d417b5bda099dd99d3f4250e70 /drivers/media/i2c/dw9768.c
parent3dd10515a1d9de734e2ec57f837b9f1e510c5363 (diff)
downloadlinux-5f9a089b6de34655318afe8e544d9a9cc0fc1d29.tar.bz2
dw9768: Enable low-power probe on ACPI
Add support for low-power probe to the driver. Also fix runtime PM API usage in the driver. Much of the hassle comes from different factors affecting device power states during probe for ACPI and DT. Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Fixes: 859891228e56 ("media: i2c: dw9768: Add DW9768 VCM driver")
Diffstat (limited to 'drivers/media/i2c/dw9768.c')
-rw-r--r--drivers/media/i2c/dw9768.c33
1 files changed, 25 insertions, 8 deletions
diff --git a/drivers/media/i2c/dw9768.c b/drivers/media/i2c/dw9768.c
index 0f47ef015a1d..83a3ee275bbe 100644
--- a/drivers/media/i2c/dw9768.c
+++ b/drivers/media/i2c/dw9768.c
@@ -414,6 +414,7 @@ static int dw9768_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct dw9768 *dw9768;
+ bool full_power;
unsigned int i;
int ret;
@@ -469,13 +470,23 @@ static int dw9768_probe(struct i2c_client *client)
dw9768->sd.entity.function = MEDIA_ENT_F_LENS;
+ /*
+ * Figure out whether we're going to power up the device here. Generally
+ * this is done if CONFIG_PM is disabled in a DT system or the device is
+ * to be powered on in an ACPI system. Similarly for power off in
+ * remove.
+ */
pm_runtime_enable(dev);
- if (!pm_runtime_enabled(dev)) {
+ full_power = (is_acpi_node(dev_fwnode(dev)) &&
+ acpi_dev_state_d0(dev)) ||
+ (is_of_node(dev_fwnode(dev)) && !pm_runtime_enabled(dev));
+ if (full_power) {
ret = dw9768_runtime_resume(dev);
if (ret < 0) {
dev_err(dev, "failed to power on: %d\n", ret);
goto err_clean_entity;
}
+ pm_runtime_set_active(dev);
}
ret = v4l2_async_register_subdev(&dw9768->sd);
@@ -484,14 +495,17 @@ static int dw9768_probe(struct i2c_client *client)
goto err_power_off;
}
+ pm_runtime_idle(dev);
+
return 0;
err_power_off:
- if (pm_runtime_enabled(dev))
- pm_runtime_disable(dev);
- else
+ if (full_power) {
dw9768_runtime_suspend(dev);
+ pm_runtime_set_suspended(dev);
+ }
err_clean_entity:
+ pm_runtime_disable(dev);
media_entity_cleanup(&dw9768->sd.entity);
err_free_handler:
v4l2_ctrl_handler_free(&dw9768->ctrls);
@@ -503,14 +517,17 @@ static void dw9768_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct dw9768 *dw9768 = sd_to_dw9768(sd);
+ struct device *dev = &client->dev;
v4l2_async_unregister_subdev(&dw9768->sd);
v4l2_ctrl_handler_free(&dw9768->ctrls);
media_entity_cleanup(&dw9768->sd.entity);
- pm_runtime_disable(&client->dev);
- if (!pm_runtime_status_suspended(&client->dev))
- dw9768_runtime_suspend(&client->dev);
- pm_runtime_set_suspended(&client->dev);
+ if ((is_acpi_node(dev_fwnode(dev)) && acpi_dev_state_d0(dev)) ||
+ (is_of_node(dev_fwnode(dev)) && !pm_runtime_enabled(dev))) {
+ dw9768_runtime_suspend(dev);
+ pm_runtime_set_suspended(dev);
+ }
+ pm_runtime_disable(dev);
}
static const struct of_device_id dw9768_of_table[] = {