Commit c62b96050bee ("media: ov6650: Register with asynchronous subdevice framework") introduced an asymmetry in master clock get/put operations. A reference to the clock is taken as late as on V4L2 subdevice registration but released only on I2C device removal. If the subdevice is ever unregistered by its parent V4L2 device and re- registered again without the driver being unbound and rebound back to the I2C device, the clock reference will be taken multiple times and never released. As a fix, implement .unregistered() subdevice internal operation and release the reference to the master clock from there. Fixes: c62b96050bee ("media: ov6650: Register with asynchronous subdevice framework") Signed-off-by: Janusz Krzysztofik <jmkrzyszt@xxxxxxxxx> --- drivers/media/i2c/ov6650.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 91906b94f978..218c7af7a13a 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -986,8 +986,17 @@ static const struct v4l2_subdev_ops ov6650_subdev_ops = { .pad = &ov6650_pad_ops, }; +static void ov6650_unregistered(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov6650 *priv = to_ov6650(client); + + v4l2_clk_put(priv->clk); +} + static const struct v4l2_subdev_internal_ops ov6650_internal_ops = { .registered = ov6650_video_probe, + .unregistered = ov6650_unregistered, }; /* @@ -1068,7 +1077,6 @@ static int ov6650_remove(struct i2c_client *client) { struct ov6650 *priv = to_ov6650(client); - v4l2_clk_put(priv->clk); v4l2_async_unregister_subdev(&priv->subdev); v4l2_ctrl_handler_free(&priv->hdl); return 0; -- 2.24.1