]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
media: atomisp: gc0310: runtime-PM fixes
authorHans de Goede <hansg@kernel.org>
Sat, 17 May 2025 11:41:03 +0000 (13:41 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Tue, 8 Jul 2025 06:43:31 +0000 (08:43 +0200)
The i2c-client's power-domain has already been powered up when probe()
gets called. So e.g. ACPI resources for regulators and clks have
already been enabled and only the GPIOs need to be set to the on state.

Instead of calling pm_runtime_set_suspended() while the domain is
already powered up and then have detect() do a pm_runtime_get()
to set the GPIOs do the following:

1. Call gc0310_power_on() to only set the GPIOs
2. Set the device's runtime-PM state to active instead of suspended
3. Avoid the device getting suspended as soon as pm_runtime_enable()
   gets called by calling pm_runtime_get() before _enable(), this means
   moving the pm_runtime_get() / _put() from detect() to probe ()

This fixes power_on() not getting called when runtime-PM is not
enabled in the Kconfig and this keeps the sensor powered-up while
registering it avoiding unnecessary power cycles.

Also modify gc0310_remove() to power-off the device if it is in
active state when gc0310_remove() runs.

Signed-off-by: Hans de Goede <hansg@kernel.org>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Link: https://lore.kernel.org/r/20250517114106.43494-21-hansg@kernel.org
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/staging/media/atomisp/i2c/atomisp-gc0310.c

index c4d85d65737c6482ae4623285f1c7eaa442e18b6..173ddf41ad4771feb5eea4f6180c0ce046e6ae58 100644 (file)
@@ -416,11 +416,7 @@ static int gc0310_detect(struct gc0310_device *sensor)
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
                return -ENODEV;
 
-       ret = pm_runtime_get_sync(&client->dev);
-       if (ret >= 0)
-               ret = cci_read(sensor->regmap, GC0310_SC_CMMN_CHIP_ID_REG,
-                              &val, NULL);
-       pm_runtime_put(&client->dev);
+       ret = cci_read(sensor->regmap, GC0310_SC_CMMN_CHIP_ID_REG, &val, NULL);
        if (ret < 0) {
                dev_err(&client->dev, "read sensor_id failed: %d\n", ret);
                return -ENODEV;
@@ -650,13 +646,15 @@ static void gc0310_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
        struct gc0310_device *sensor = to_gc0310_sensor(sd);
 
-       dev_dbg(&client->dev, "gc0310_remove...\n");
-
        v4l2_async_unregister_subdev(sd);
        v4l2_subdev_cleanup(sd);
        media_entity_cleanup(&sensor->sd.entity);
        v4l2_ctrl_handler_free(&sensor->ctrls.handler);
        pm_runtime_disable(&client->dev);
+       if (!pm_runtime_status_suspended(&client->dev)) {
+               gc0310_power_off(&client->dev);
+               pm_runtime_set_suspended(&client->dev);
+       }
 }
 
 static int gc0310_check_hwcfg(struct device *dev)
@@ -744,16 +742,15 @@ static int gc0310_probe(struct i2c_client *client)
        if (IS_ERR(sensor->regmap))
                return PTR_ERR(sensor->regmap);
 
-       pm_runtime_set_suspended(&client->dev);
+       gc0310_power_on(&client->dev);
+
+       pm_runtime_set_active(&client->dev);
+       pm_runtime_get_noresume(&client->dev);
        pm_runtime_enable(&client->dev);
-       pm_runtime_set_autosuspend_delay(&client->dev, 1000);
-       pm_runtime_use_autosuspend(&client->dev);
 
        ret = gc0310_detect(sensor);
-       if (ret) {
-               gc0310_remove(client);
-               return ret;
-       }
+       if (ret)
+               goto err_power_down;
 
        sensor->sd.internal_ops = &gc0310_internal_ops;
        sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -761,31 +758,32 @@ static int gc0310_probe(struct i2c_client *client)
        sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
 
        ret = gc0310_init_controls(sensor);
-       if (ret) {
-               gc0310_remove(client);
-               return ret;
-       }
+       if (ret)
+               goto err_power_down;
 
        ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
-       if (ret) {
-               gc0310_remove(client);
-               return ret;
-       }
+       if (ret)
+               goto err_power_down;
 
        sensor->sd.state_lock = sensor->ctrls.handler.lock;
        ret = v4l2_subdev_init_finalize(&sensor->sd);
-       if (ret) {
-               gc0310_remove(client);
-               return ret;
-       }
+       if (ret)
+               goto err_power_down;
 
        ret = v4l2_async_register_subdev_sensor(&sensor->sd);
-       if (ret) {
-               gc0310_remove(client);
-               return ret;
-       }
+       if (ret)
+               goto err_power_down;
+
+       pm_runtime_set_autosuspend_delay(&client->dev, 1000);
+       pm_runtime_use_autosuspend(&client->dev);
+       pm_runtime_put_autosuspend(&client->dev);
 
        return 0;
+
+err_power_down:
+       pm_runtime_put_noidle(&client->dev);
+       gc0310_remove(client);
+       return ret;
 }
 
 static DEFINE_RUNTIME_DEV_PM_OPS(gc0310_pm_ops,