#include <linux/module.h>
 
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 
 /* IMX074 registers */
 struct imx074 {
        struct v4l2_subdev              subdev;
        const struct imx074_datafmt     *fmt;
+       struct v4l2_clk                 *clk;
 };
 
 static const struct imx074_datafmt imx074_colour_fmts[] = {
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct imx074 *priv = to_imx074(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 static int imx074_g_mbus_config(struct v4l2_subdev *sd,
        struct imx074 *priv;
        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       int ret;
 
        if (!ssdd) {
                dev_err(&client->dev, "IMX074: missing platform data!\n");
 
        priv->fmt       = &imx074_colour_fmts[0];
 
-       return imx074_video_probe(client);
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk))
+               return PTR_ERR(priv->clk);
+
+       ret = imx074_video_probe(client);
+       if (ret < 0)
+               v4l2_clk_put(priv->clk);
+
+       return ret;
 }
 
 static int imx074_remove(struct i2c_client *client)
 {
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct imx074 *priv = to_imx074(client);
 
+       v4l2_clk_put(priv->clk);
        if (ssdd->free_bus)
                ssdd->free_bus(ssdd);
 
 
 
 #include <media/soc_camera.h>
 #include <media/soc_mediabus.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-ctrls.h>
 
                struct v4l2_ctrl *exposure;
        };
        struct v4l2_rect rect;  /* Sensor window */
+       struct v4l2_clk *clk;
        const struct mt9m001_datafmt *fmt;
        const struct mt9m001_datafmt *fmts;
        int num_fmts;
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct mt9m001 *mt9m001 = to_mt9m001(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, mt9m001->clk, on);
 }
 
 static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
        mt9m001->rect.width     = MT9M001_MAX_WIDTH;
        mt9m001->rect.height    = MT9M001_MAX_HEIGHT;
 
+       mt9m001->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(mt9m001->clk)) {
+               ret = PTR_ERR(mt9m001->clk);
+               goto eclkget;
+       }
+
        ret = mt9m001_video_probe(ssdd, client);
-       if (ret)
+       if (ret) {
+               v4l2_clk_put(mt9m001->clk);
+eclkget:
                v4l2_ctrl_handler_free(&mt9m001->hdl);
+       }
 
        return ret;
 }
        struct mt9m001 *mt9m001 = to_mt9m001(client);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
 
+       v4l2_clk_put(mt9m001->clk);
        v4l2_device_unregister_subdev(&mt9m001->subdev);
        v4l2_ctrl_handler_free(&mt9m001->hdl);
        mt9m001_video_remove(ssdd);
 
 #include <linux/module.h>
 
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
 
        struct v4l2_ctrl *gain;
        struct mt9m111_context *ctx;
        struct v4l2_rect rect;  /* cropping rectangle */
+       struct v4l2_clk *clk;
        int width;              /* output */
        int height;             /* sizes */
        struct mutex power_lock; /* lock to protect power_count */
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
        int ret;
 
-       ret = soc_camera_power_on(&client->dev, ssdd);
+       ret = soc_camera_power_on(&client->dev, ssdd, mt9m111->clk);
        if (ret < 0)
                return ret;
 
        ret = mt9m111_resume(mt9m111);
        if (ret < 0) {
                dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret);
-               soc_camera_power_off(&client->dev, ssdd);
+               soc_camera_power_off(&client->dev, ssdd, mt9m111->clk);
        }
 
        return ret;
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
 
        mt9m111_suspend(mt9m111);
-       soc_camera_power_off(&client->dev, ssdd);
+       soc_camera_power_off(&client->dev, ssdd, mt9m111->clk);
 }
 
 static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
        mt9m111->lastpage       = -1;
        mutex_init(&mt9m111->power_lock);
 
+       mt9m111->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(mt9m111->clk)) {
+               ret = PTR_ERR(mt9m111->clk);
+               goto eclkget;
+       }
+
        ret = mt9m111_video_probe(client);
-       if (ret)
+       if (ret) {
+               v4l2_clk_put(mt9m111->clk);
+eclkget:
                v4l2_ctrl_handler_free(&mt9m111->hdl);
+       }
 
        return ret;
 }
 {
        struct mt9m111 *mt9m111 = to_mt9m111(client);
 
+       v4l2_clk_put(mt9m111->clk);
        v4l2_device_unregister_subdev(&mt9m111->subdev);
        v4l2_ctrl_handler_free(&mt9m111->hdl);
 
 
 #include <linux/module.h>
 
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-ctrls.h>
 
                struct v4l2_ctrl *exposure;
        };
        struct v4l2_rect rect;  /* Sensor window */
+       struct v4l2_clk *clk;
        u16 xskip;
        u16 yskip;
        unsigned int total_h;
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
        struct video_device *vdev = soc_camera_i2c_to_vdev(client);
+       struct mt9t031 *mt9t031 = to_mt9t031(client);
        int ret;
 
        if (on) {
-               ret = soc_camera_power_on(&client->dev, ssdd);
+               ret = soc_camera_power_on(&client->dev, ssdd, mt9t031->clk);
                if (ret < 0)
                        return ret;
                vdev->dev.type = &mt9t031_dev_type;
        } else {
                vdev->dev.type = NULL;
-               soc_camera_power_off(&client->dev, ssdd);
+               soc_camera_power_off(&client->dev, ssdd, mt9t031->clk);
        }
 
        return 0;
        mt9t031->xskip = 1;
        mt9t031->yskip = 1;
 
+       mt9t031->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(mt9t031->clk)) {
+               ret = PTR_ERR(mt9t031->clk);
+               goto eclkget;
+       }
+
        ret = mt9t031_video_probe(client);
-       if (ret)
+       if (ret) {
+               v4l2_clk_put(mt9t031->clk);
+eclkget:
                v4l2_ctrl_handler_free(&mt9t031->hdl);
+       }
 
        return ret;
 }
 {
        struct mt9t031 *mt9t031 = to_mt9t031(client);
 
+       v4l2_clk_put(mt9t031->clk);
        v4l2_device_unregister_subdev(&mt9t031->subdev);
        v4l2_ctrl_handler_free(&mt9t031->hdl);
 
 
 
 #include <media/mt9t112.h>
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
 
 /* you can check PLL/clock info */
        struct mt9t112_camera_info      *info;
        struct i2c_client               *client;
        struct v4l2_rect                 frame;
+       struct v4l2_clk                 *clk;
        const struct mt9t112_format     *format;
        int                              num_formats;
        u32                              flags;
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct mt9t112_priv *priv = to_mt9t112(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
 
        v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
 
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk))
+               return PTR_ERR(priv->clk);
+
        ret = mt9t112_camera_probe(client);
-       if (ret)
-               return ret;
 
        /* Cannot fail: using the default supported pixel code */
-       mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8);
+       if (!ret)
+               mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8);
+       else
+               v4l2_clk_put(priv->clk);
 
        return ret;
 }
 
+static int mt9t112_remove(struct i2c_client *client)
+{
+       struct mt9t112_priv *priv = to_mt9t112(client);
+
+       v4l2_clk_put(priv->clk);
+       return 0;
+}
+
 static const struct i2c_device_id mt9t112_id[] = {
        { "mt9t112", 0 },
        { }
                .name = "mt9t112",
        },
        .probe    = mt9t112_probe,
+       .remove   = mt9t112_remove,
        .id_table = mt9t112_id,
 };
 
 
 #include <media/soc_camera.h>
 #include <media/soc_mediabus.h>
 #include <media/v4l2-subdev.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-ctrls.h>
 
 /*
        struct v4l2_ctrl *hblank;
        struct v4l2_ctrl *vblank;
        struct v4l2_rect rect;  /* Sensor window */
+       struct v4l2_clk *clk;
        const struct mt9v022_datafmt *fmt;
        const struct mt9v022_datafmt *fmts;
        const struct mt9v02x_register *reg;
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, mt9v022->clk, on);
 }
 
 static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
        mt9v022->rect.width     = MT9V022_MAX_WIDTH;
        mt9v022->rect.height    = MT9V022_MAX_HEIGHT;
 
+       mt9v022->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(mt9v022->clk)) {
+               ret = PTR_ERR(mt9v022->clk);
+               goto eclkget;
+       }
+
        ret = mt9v022_video_probe(client);
-       if (ret)
+       if (ret) {
+               v4l2_clk_put(mt9v022->clk);
+eclkget:
                v4l2_ctrl_handler_free(&mt9v022->hdl);
+       }
 
        return ret;
 }
        struct mt9v022 *mt9v022 = to_mt9v022(client);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
 
+       v4l2_clk_put(mt9v022->clk);
        v4l2_device_unregister_subdev(&mt9v022->subdev);
        if (ssdd->free_bus)
                ssdd->free_bus(ssdd);
 
 #include <linux/videodev2.h>
 
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-ctrls.h>
 
        struct v4l2_subdev              subdev;
        struct v4l2_ctrl_handler        hdl;
        enum v4l2_mbus_pixelcode        cfmt_code;
+       struct v4l2_clk                 *clk;
        const struct ov2640_win_size    *win;
 };
 
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov2640_priv *priv = to_ov2640(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 /* Select the nearest higher resolution for capture */
        if (priv->hdl.error)
                return priv->hdl.error;
 
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto eclkget;
+       }
+
        ret = ov2640_video_probe(client);
-       if (ret)
+       if (ret) {
+               v4l2_clk_put(priv->clk);
+eclkget:
                v4l2_ctrl_handler_free(&priv->hdl);
-       else
+       } else {
                dev_info(&adapter->dev, "OV2640 Probed\n");
+       }
 
        return ret;
 }
 {
        struct ov2640_priv       *priv = to_ov2640(client);
 
+       v4l2_clk_put(priv->clk);
        v4l2_device_unregister_subdev(&priv->subdev);
        v4l2_ctrl_handler_free(&priv->hdl);
        return 0;
 
 #include <linux/v4l2-mediabus.h>
 
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 
 /* OV5642 registers */
        struct v4l2_subdev              subdev;
        const struct ov5642_datafmt     *fmt;
        struct v4l2_rect                crop_rect;
+       struct v4l2_clk                 *clk;
 
        /* blanking information */
        int total_width;
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov5642 *priv = to_ov5642(client);
        int ret;
 
        if (!on)
-               return soc_camera_power_off(&client->dev, ssdd);
+               return soc_camera_power_off(&client->dev, ssdd, priv->clk);
 
-       ret = soc_camera_power_on(&client->dev, ssdd);
+       ret = soc_camera_power_on(&client->dev, ssdd, priv->clk);
        if (ret < 0)
                return ret;
 
 {
        struct ov5642 *priv;
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       int ret;
 
        if (!ssdd) {
                dev_err(&client->dev, "OV5642: missing platform data!\n");
        priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH;
        priv->total_height = BLANKING_MIN_HEIGHT;
 
-       return ov5642_video_probe(client);
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk))
+               return PTR_ERR(priv->clk);
+
+       ret = ov5642_video_probe(client);
+       if (ret < 0)
+               v4l2_clk_put(priv->clk);
+
+       return ret;
 }
 
 static int ov5642_remove(struct i2c_client *client)
 {
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov5642 *priv = to_ov5642(client);
 
+       v4l2_clk_put(priv->clk);
        if (ssdd->free_bus)
                ssdd->free_bus(ssdd);
 
 
 #include <linux/module.h>
 
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-ctrls.h>
 
 /* Register definitions */
                struct v4l2_ctrl *blue;
                struct v4l2_ctrl *red;
        };
+       struct v4l2_clk         *clk;
        bool                    half_scale;     /* scale down output by 2 */
        struct v4l2_rect        rect;           /* sensor cropping window */
        unsigned long           pclk_limit;     /* from host */
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov6650 *priv = to_ov6650(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
        priv->code        = V4L2_MBUS_FMT_YUYV8_2X8;
        priv->colorspace  = V4L2_COLORSPACE_JPEG;
 
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto eclkget;
+       }
+
        ret = ov6650_video_probe(client);
-       if (ret)
+       if (ret) {
+               v4l2_clk_put(priv->clk);
+eclkget:
                v4l2_ctrl_handler_free(&priv->hdl);
+       }
 
        return ret;
 }
 {
        struct ov6650 *priv = to_ov6650(client);
 
+       v4l2_clk_put(priv->clk);
        v4l2_device_unregister_subdev(&priv->subdev);
        v4l2_ctrl_handler_free(&priv->hdl);
        return 0;
 
 
 #include <media/ov772x.h>
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-subdev.h>
 
 struct ov772x_priv {
        struct v4l2_subdev                subdev;
        struct v4l2_ctrl_handler          hdl;
+       struct v4l2_clk                  *clk;
        struct ov772x_camera_info        *info;
        const struct ov772x_color_format *cfmt;
        const struct ov772x_win_size     *win;
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov772x_priv *priv = to_ov772x(sd);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
        if (priv->hdl.error)
                return priv->hdl.error;
 
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto eclkget;
+       }
+
        ret = ov772x_video_probe(priv);
        if (ret < 0) {
+               v4l2_clk_put(priv->clk);
+eclkget:
                v4l2_ctrl_handler_free(&priv->hdl);
        } else {
                priv->cfmt = &ov772x_cfmts[0];
                priv->win = &ov772x_win_sizes[0];
        }
+
        return ret;
 }
 
 {
        struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client));
 
+       v4l2_clk_put(priv->clk);
        v4l2_device_unregister_subdev(&priv->subdev);
        v4l2_ctrl_handler_free(&priv->hdl);
        return 0;
 
 #include <linux/videodev2.h>
 
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
 
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov9640_priv *priv = to_ov9640_sensor(sd);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 /* select nearest higher resolution for capture */
        if (priv->hdl.error)
                return priv->hdl.error;
 
-       ret = ov9640_video_probe(client);
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto eclkget;
+       }
 
-       if (ret)
+       ret = ov9640_video_probe(client);
+       if (ret) {
+               v4l2_clk_put(priv->clk);
+eclkget:
                v4l2_ctrl_handler_free(&priv->hdl);
+       }
 
        return ret;
 }
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
        struct ov9640_priv *priv = to_ov9640_sensor(sd);
 
+       v4l2_clk_put(priv->clk);
        v4l2_device_unregister_subdev(&priv->subdev);
        v4l2_ctrl_handler_free(&priv->hdl);
        return 0;
 
 struct ov9640_priv {
        struct v4l2_subdev              subdev;
        struct v4l2_ctrl_handler        hdl;
+       struct v4l2_clk                 *clk;
 
        int                             model;
        int                             revision;
 
 #include <linux/v4l2-mediabus.h>
 
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-ctrls.h>
 
 #define to_ov9740(sd)          container_of(sd, struct ov9740_priv, subdev)
 struct ov9740_priv {
        struct v4l2_subdev              subdev;
        struct v4l2_ctrl_handler        hdl;
+       struct v4l2_clk                 *clk;
 
        u16                             model;
        u8                              revision;
        int ret;
 
        if (on) {
-               ret = soc_camera_power_on(&client->dev, ssdd);
+               ret = soc_camera_power_on(&client->dev, ssdd, priv->clk);
                if (ret < 0)
                        return ret;
 
                        priv->current_enable = true;
                }
 
-               soc_camera_power_off(&client->dev, ssdd);
+               soc_camera_power_off(&client->dev, ssdd, priv->clk);
        }
 
        return 0;
        if (priv->hdl.error)
                return priv->hdl.error;
 
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto eclkget;
+       }
+
        ret = ov9740_video_probe(client);
-       if (ret < 0)
+       if (ret < 0) {
+               v4l2_clk_put(priv->clk);
+eclkget:
                v4l2_ctrl_handler_free(&priv->hdl);
+       }
 
        return ret;
 }
 {
        struct ov9740_priv *priv = i2c_get_clientdata(client);
 
+       v4l2_clk_put(priv->clk);
        v4l2_device_unregister_subdev(&priv->subdev);
        v4l2_ctrl_handler_free(&priv->hdl);
        return 0;
 
 
 #include <media/rj54n1cb0c.h>
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-ctrls.h>
 
 struct rj54n1 {
        struct v4l2_subdev subdev;
        struct v4l2_ctrl_handler hdl;
+       struct v4l2_clk *clk;
        struct rj54n1_clock_div clk_div;
        const struct rj54n1_datafmt *fmt;
        struct v4l2_rect rect;  /* Sensor window */
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, rj54n1->clk, on);
 }
 
 static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl)
        rj54n1->tgclk_mhz       = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) /
                (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1);
 
+       rj54n1->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(rj54n1->clk)) {
+               ret = PTR_ERR(rj54n1->clk);
+               goto eclkget;
+       }
+
        ret = rj54n1_video_probe(client, rj54n1_priv);
-       if (ret < 0)
+       if (ret < 0) {
+               v4l2_clk_put(rj54n1->clk);
+eclkget:
                v4l2_ctrl_handler_free(&rj54n1->hdl);
+       }
 
        return ret;
 }
        struct rj54n1 *rj54n1 = to_rj54n1(client);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
 
+       v4l2_clk_put(rj54n1->clk);
        v4l2_device_unregister_subdev(&rj54n1->subdev);
        if (ssdd->free_bus)
                ssdd->free_bus(ssdd);
 
 
 #include <media/soc_camera.h>
 #include <media/tw9910.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-subdev.h>
 
 #define GET_ID(val)  ((val & 0xF8) >> 3)
 
 struct tw9910_priv {
        struct v4l2_subdev              subdev;
+       struct v4l2_clk                 *clk;
        struct tw9910_video_info        *info;
        const struct tw9910_scale_ctrl  *scale;
        v4l2_std_id                     norm;
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct tw9910_priv *priv = to_tw9910(client);
 
-       return soc_camera_set_power(&client->dev, ssdd, on);
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
 }
 
 static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height)
        struct i2c_adapter              *adapter =
                to_i2c_adapter(client->dev.parent);
        struct soc_camera_subdev_desc   *ssdd = soc_camera_i2c_to_desc(client);
+       int ret;
 
        if (!ssdd || !ssdd->drv_priv) {
                dev_err(&client->dev, "TW9910: missing platform data!\n");
 
        v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
 
-       return tw9910_video_probe(client);
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk))
+               return PTR_ERR(priv->clk);
+
+       ret = tw9910_video_probe(client);
+       if (ret < 0)
+               v4l2_clk_put(priv->clk);
+
+       return ret;
+}
+
+static int tw9910_remove(struct i2c_client *client)
+{
+       struct tw9910_priv *priv = to_tw9910(client);
+       v4l2_clk_put(priv->clk);
+       return 0;
 }
 
 static const struct i2c_device_id tw9910_id[] = {
                .name = "tw9910",
        },
        .probe    = tw9910_probe,
+       .remove   = tw9910_remove,
        .id_table = tw9910_id,
 };
 
 
 #include <linux/vmalloc.h>
 
 #include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-dev.h>
 static LIST_HEAD(devices);
 static DEFINE_MUTEX(list_lock);                /* Protects the list of hosts */
 
-int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd)
+int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd,
+                       struct v4l2_clk *clk)
 {
-       int ret = regulator_bulk_enable(ssdd->num_regulators,
+       int ret = clk ? v4l2_clk_enable(clk) : 0;
+       if (ret < 0) {
+               dev_err(dev, "Cannot enable clock\n");
+               return ret;
+       }
+       ret = regulator_bulk_enable(ssdd->num_regulators,
                                        ssdd->regulators);
        if (ret < 0) {
                dev_err(dev, "Cannot enable regulators\n");
-               return ret;
+               goto eregenable;;
        }
 
        if (ssdd->power) {
                if (ret < 0) {
                        dev_err(dev,
                                "Platform failed to power-on the camera.\n");
-                       regulator_bulk_disable(ssdd->num_regulators,
-                                              ssdd->regulators);
+                       goto epwron;
                }
        }
 
+       return 0;
+
+epwron:
+       regulator_bulk_disable(ssdd->num_regulators,
+                              ssdd->regulators);
+eregenable:
+       if (clk)
+               v4l2_clk_disable(clk);
+
        return ret;
 }
 EXPORT_SYMBOL(soc_camera_power_on);
 
-int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd)
+int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd,
+                        struct v4l2_clk *clk)
 {
        int ret = 0;
        int err;
                ret = ret ? : err;
        }
 
+       if (clk)
+               v4l2_clk_disable(clk);
+
        return ret;
 }
 EXPORT_SYMBOL(soc_camera_power_off);
        if (ici->icd)
                return -EBUSY;
 
-       ret = ici->ops->clock_start(ici);
-       if (ret < 0)
-               return ret;
+       if (!icd->clk) {
+               ret = ici->ops->clock_start(ici);
+               if (ret < 0)
+                       return ret;
+       }
 
        if (ici->ops->add) {
                ret = ici->ops->add(icd);
        return 0;
 
 eadd:
-       ici->ops->clock_stop(ici);
+       if (!icd->clk)
+               ici->ops->clock_stop(ici);
        return ret;
 }
 
 
        if (ici->ops->remove)
                ici->ops->remove(icd);
-       ici->ops->clock_stop(ici);
+       if (!icd->clk)
+               ici->ops->clock_stop(ici);
        ici->icd = NULL;
 }
 
        mutex_unlock(&list_lock);
 }
 
+/*
+ * It is invalid to call v4l2_clk_enable() after a successful probing
+ * asynchronously outside of V4L2 operations, i.e. with .host_lock not held.
+ */
+static int soc_camera_clk_enable(struct v4l2_clk *clk)
+{
+       struct soc_camera_device *icd = clk->priv;
+       struct soc_camera_host *ici;
+
+       if (!icd || !icd->parent)
+               return -ENODEV;
+
+       ici = to_soc_camera_host(icd->parent);
+
+       if (!try_module_get(ici->ops->owner))
+               return -ENODEV;
+
+       /*
+        * If a different client is currently being probed, the host will tell
+        * you to go
+        */
+       return ici->ops->clock_start(ici);
+}
+
+static void soc_camera_clk_disable(struct v4l2_clk *clk)
+{
+       struct soc_camera_device *icd = clk->priv;
+       struct soc_camera_host *ici;
+
+       if (!icd || !icd->parent)
+               return;
+
+       ici = to_soc_camera_host(icd->parent);
+
+       ici->ops->clock_stop(ici);
+
+       module_put(ici->ops->owner);
+}
+
+/*
+ * Eventually, it would be more logical to make the respective host the clock
+ * owner, but then we would have to copy this struct for each ici. Besides, it
+ * would introduce the circular dependency problem, unless we port all client
+ * drivers to release the clock, when not in use.
+ */
+static const struct v4l2_clk_ops soc_camera_clk_ops = {
+       .owner = THIS_MODULE,
+       .enable = soc_camera_clk_enable,
+       .disable = soc_camera_clk_disable,
+};
+
 #ifdef CONFIG_I2C_BOARDINFO
 static int soc_camera_init_i2c(struct soc_camera_device *icd,
                               struct soc_camera_desc *sdesc)
        struct soc_camera_host_desc *shd = &sdesc->host_desc;
        struct i2c_adapter *adap = i2c_get_adapter(shd->i2c_adapter_id);
        struct v4l2_subdev *subdev;
+       char clk_name[V4L2_SUBDEV_NAME_SIZE];
+       int ret;
 
        if (!adap) {
                dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n",
                        shd->i2c_adapter_id);
-               goto ei2cga;
+               return -ENODEV;
        }
 
        shd->board_info->platform_data = &sdesc->subdev_desc;
 
+       snprintf(clk_name, sizeof(clk_name), "%d-%04x",
+                shd->i2c_adapter_id, shd->board_info->addr);
+
+       icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
+       if (IS_ERR(icd->clk)) {
+               ret = PTR_ERR(icd->clk);
+               goto eclkreg;
+       }
+
        subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
                                shd->board_info, NULL);
-       if (!subdev)
+       if (!subdev) {
+               ret = -ENODEV;
                goto ei2cnd;
+       }
 
        client = v4l2_get_subdevdata(subdev);
 
 
        return 0;
 ei2cnd:
+       v4l2_clk_unregister(icd->clk);
+       icd->clk = NULL;
+eclkreg:
        i2c_put_adapter(adap);
-ei2cga:
-       return -ENODEV;
+       return ret;
 }
 
 static void soc_camera_free_i2c(struct soc_camera_device *icd)
        v4l2_device_unregister_subdev(i2c_get_clientdata(client));
        i2c_unregister_device(client);
        i2c_put_adapter(adap);
+       v4l2_clk_unregister(icd->clk);
+       icd->clk = NULL;
 }
 #else
 #define soc_camera_init_i2c(icd, sdesc)        (-ENODEV)
        if (ssdd->reset)
                ssdd->reset(icd->pdev);
 
-       mutex_lock(&ici->host_lock);
-       ret = ici->ops->clock_start(ici);
-       mutex_unlock(&ici->host_lock);
-       if (ret < 0)
-               goto eadd;
-
        /* Must have icd->vdev before registering the device */
        ret = video_dev_create(icd);
        if (ret < 0)
                goto evdc;
 
+       /*
+        * ..._video_start() will create a device node, video_register_device()
+        * itself is protected against concurrent open() calls, but we also have
+        * to protect our data also during client probing.
+        */
+       mutex_lock(&ici->host_lock);
+
        /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
        if (shd->board_info) {
                ret = soc_camera_init_i2c(icd, sdesc);
                if (ret < 0)
-                       goto eadddev;
+                       goto eadd;
        } else if (!shd->add_device || !shd->del_device) {
                ret = -EINVAL;
-               goto eadddev;
+               goto eadd;
        } else {
+               ret = ici->ops->clock_start(ici);
+               if (ret < 0)
+                       goto eadd;
+
                if (shd->module_name)
                        ret = request_module(shd->module_name);
 
 
        icd->field = V4L2_FIELD_ANY;
 
-       /*
-        * ..._video_start() will create a device node, video_register_device()
-        * itself is protected against concurrent open() calls, but we also have
-        * to protect our data.
-        */
-       mutex_lock(&ici->host_lock);
-
        ret = soc_camera_video_start(icd);
        if (ret < 0)
                goto evidstart;
                icd->field              = mf.field;
        }
 
-       ici->ops->clock_stop(ici);
+       if (!shd->board_info)
+               ici->ops->clock_stop(ici);
 
        mutex_unlock(&ici->host_lock);
 
        return 0;
 
 evidstart:
-       mutex_unlock(&ici->host_lock);
        soc_camera_free_user_formats(icd);
 eiufmt:
 ectrl:
        } else {
                shd->del_device(icd);
                module_put(control->driver->owner);
-       }
 enodrv:
 eadddev:
+               ici->ops->clock_stop(ici);
+       }
+eadd:
        video_device_release(icd->vdev);
        icd->vdev = NULL;
-evdc:
-       mutex_lock(&ici->host_lock);
-       ici->ops->clock_stop(ici);
        mutex_unlock(&ici->host_lock);
-eadd:
+evdc:
        v4l2_ctrl_handler_free(&icd->ctrl_handler);
        return ret;
 }
 
 {
        struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
 
-       return soc_camera_set_power(p->icd->control, &p->icd->sdesc->subdev_desc, on);
+       return soc_camera_set_power(p->icd->control, &p->icd->sdesc->subdev_desc, NULL, on);
 }
 
 static struct v4l2_subdev_core_ops platform_subdev_core_ops = {
 
        /* soc_camera.c private count. Only accessed with .host_lock held */
        int use_count;
        struct file *streamer;          /* stream owner */
+       struct v4l2_clk *clk;
        union {
                struct videobuf_queue vb_vidq;
                struct vb2_queue vb2_vidq;
 unsigned long soc_camera_apply_board_flags(struct soc_camera_subdev_desc *ssdd,
                                           const struct v4l2_mbus_config *cfg);
 
-int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd);
-int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd);
+int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd,
+                       struct v4l2_clk *clk);
+int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd,
+                        struct v4l2_clk *clk);
 
 static inline int soc_camera_set_power(struct device *dev,
-                               struct soc_camera_subdev_desc *ssdd, bool on)
+               struct soc_camera_subdev_desc *ssdd, struct v4l2_clk *clk, bool on)
 {
-       return on ? soc_camera_power_on(dev, ssdd)
-                 : soc_camera_power_off(dev, ssdd);
+       return on ? soc_camera_power_on(dev, ssdd, clk)
+                 : soc_camera_power_off(dev, ssdd, clk);
 }
 
 /* This is only temporary here - until v4l2-subdev begins to link to video_device */