media: ov6650: Fix clock not released on subdev unregister

Message ID 20200503221826.28906-1-jmkrzyszt@gmail.com (mailing list archive)
State New
Delegated to: Sakari Ailus
Headers
Series media: ov6650: Fix clock not released on subdev unregister |

Commit Message

Janusz Krzysztofik May 3, 2020, 10:18 p.m. UTC
  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@gmail.com>
---
 drivers/media/i2c/ov6650.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
  

Patch

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;