diff --git a/arch/arm/mach-imx/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c
index 6c19eb1..7231c63 100644
--- a/arch/arm/mach-imx/mach-pcm037.c
+++ b/arch/arm/mach-imx/mach-pcm037.c
@@ -35,6 +35,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
 
+#include <media/mt9v022.h>
 #include <media/soc_camera.h>
 
 #include <asm/mach-types.h>
@@ -330,18 +331,33 @@ static struct i2c_board_info pcm037_i2c_camera[] = {
 	},
 };
 
-static struct soc_camera_link iclink_mt9v022 = {
-	.bus_id		= 0,		/* Must match with the camera ID */
-	.board_info	= &pcm037_i2c_camera[1],
-	.i2c_adapter_id	= 2,
+static struct mt9v022_platform_data mt9v022_pdata = {
+	.sdesc = {
+		.subdev_desc	= {
+			.drv_priv		= &mt9v022_pdata,
+			.sd_pdata.host_priv	= &mt9v022_pdata.sdesc.host_desc,
+		},
+		.host_desc	= {
+			.bus_id			= 0, /* Must match with the camera ID */
+			.board_info		= &pcm037_i2c_camera[1],
+			.i2c_adapter_id		= 2,
+		},
+	},
 };
 
-static struct soc_camera_link iclink_mt9t031 = {
-	.bus_id		= 0,		/* Must match with the camera ID */
-	.num_regulators	= ARRAY_SIZE(cam_supply),
-	.regulators	= cam_supply,
-	.board_info	= &pcm037_i2c_camera[0],
-	.i2c_adapter_id	= 2,
+static struct soc_camera_desc mt9t031_pdata = {
+	.subdev_desc	= {
+		.sd_pdata	= {
+			.num_regulators	= ARRAY_SIZE(cam_supply),
+			.regulators	= cam_supply,
+			.host_priv	= &mt9t031_pdata.host_desc,
+		},
+	},
+	.host_desc	= {
+		.bus_id		= 0,		/* Must match with the camera ID */
+		.board_info	= &pcm037_i2c_camera[0],
+		.i2c_adapter_id	= 2,
+	},
 };
 
 static struct i2c_board_info pcm037_i2c_devices[] = {
@@ -357,7 +373,7 @@ static struct platform_device pcm037_mt9t031 = {
 	.name	= "soc-camera-pdrv",
 	.id	= 0,
 	.dev	= {
-		.platform_data = &iclink_mt9t031,
+		.platform_data = &mt9t031_pdata,
 	},
 };
 
@@ -365,7 +381,7 @@ static struct platform_device pcm037_mt9v022 = {
 	.name	= "soc-camera-pdrv",
 	.id	= 1,
 	.dev	= {
-		.platform_data = &iclink_mt9v022,
+		.platform_data = &mt9v022_pdata.sdesc,
 	},
 };
 
diff --git a/arch/arm/mach-omap2/board-omap3beagle-camera.c b/arch/arm/mach-omap2/board-omap3beagle-camera.c
index b5299db..87f337f 100644
--- a/arch/arm/mach-omap2/board-omap3beagle-camera.c
+++ b/arch/arm/mach-omap2/board-omap3beagle-camera.c
@@ -6,6 +6,11 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/regulator/machine.h>
+
 #include <asm/mach-types.h>
 #include <plat/cpu.h>
 #include <plat/i2c.h>
@@ -15,22 +20,49 @@
 #include <media/ov772x.h>
 
 #include "devices.h"
-#include "../../../drivers/media/platform/omap3isp/isp.h"
+#include "soc.h"
+//#include "../../../drivers/media/platform/omap3isp/isp.h"
+
+int beagle_gpio_camera_en = -EINVAL;
+/*#define OV772X_RESET_GPIO	98
+#define OV772X_XCLK		ISP_XCLK_A
+#define OV772X_EXT_FREQ	21000000*/
 
-#define MT9P031_RESET_GPIO	98
-#define MT9P031_XCLK		ISP_XCLK_A
-#define MT9P031_EXT_FREQ	21000000
+//#define BEAGLE_MT9P031
+#define BEAGLE_OV772X
 
-static int beagle_cam_set_xclk(struct v4l2_subdev *subdev, int hz)
+/*static int beagle_cam_set_xclk(struct v4l2_subdev *subdev, int hz)
 {
 	struct isp_device *isp = v4l2_dev_to_isp_device(subdev->v4l2_dev);
 
-	return isp->platform_cb.set_xclk(isp, hz, MT9P031_XCLK);
-}
+	return isp->platform_cb.set_xclk(isp, hz, OV772X_XCLK);
+}*/
+
+#ifdef BEAGLE_OV772X
+static struct regulator_bulk_data cam_supply[] = {
+	{
+		.supply = "cam_core",
+	}, {
+		.supply = "cam_io",
+//	}, {
+//		.supply = "cam_ana",
+	},
+};
 
-static struct ov772x_camera_info beagle_mt9p031_platform_data = { // adapted ov772x
-	.set_xclk	= beagle_cam_set_xclk,
+static struct ov772x_camera_info beagle_ov772x_pdata = { // adapted ov772x
+	.sdesc = {
+		.subdev_desc	= {
+			.drv_priv	= &beagle_ov772x_pdata,
+			.probing_mode	= SOC_CAMERA_SYNC,
+//			.clock_rate	= 20000000,
+			.sd_pdata	= {
+				.num_regulators	= ARRAY_SIZE(cam_supply),
+				.regulators	= cam_supply,
+			},
+		},
+	},
 	.flags		= 0,  // no flip
+//	.set_xclk	= beagle_cam_set_xclk,
 	.edgectrl	= {
 		.strength 	= 0,
 		.threshold	= 0,
@@ -39,14 +71,26 @@ static struct ov772x_camera_info beagle_mt9p031_platform_data = { // adapted ov7
 	},
 };
 
-static struct i2c_board_info mt9p031_camera_i2c_device = {
+static struct i2c_board_info camera_i2c_device = {
 	I2C_BOARD_INFO("ov772x", 0x21),
+	.platform_data = &beagle_ov772x_pdata,
+};
+#else
+static struct mt9p031_platform_data beagle_mt9p031_platform_data = {
+	.reset		= -EINVAL,
+	.ext_freq	= 21000000,
+	.target_freq	= 48000000,
+};
+
+static struct i2c_board_info camera_i2c_device = {
+	I2C_BOARD_INFO("mt9p031", 0x48),
 	.platform_data = &beagle_mt9p031_platform_data,
 };
+#endif
 
-static struct isp_subdev_i2c_board_info mt9p031_camera_subdevs[] = {
+static struct isp_subdev_i2c_board_info ov772x_camera_subdevs[] = {
 	{
-		.board_info = &mt9p031_camera_i2c_device,
+		.board_info = &camera_i2c_device,
 		.i2c_adapter_id = 2,
 	},
 	{ NULL, 0, },
@@ -54,29 +98,59 @@ static struct isp_subdev_i2c_board_info mt9p031_camera_subdevs[] = {
 
 static struct isp_v4l2_subdevs_group beagle_camera_subdevs[] = {
 	{
-		.subdevs = mt9p031_camera_subdevs,
+		.subdevs = ov772x_camera_subdevs,
 		.interface = ISP_INTERFACE_PARALLEL,
 		.bus = {
 			.parallel = {
 				.data_lane_shift = ISP_LANE_SHIFT_0,
 				.align_width = 10,
 				.clk_pol = 0,
-			}
+			},
 		},
 	},
 	{ },
 };
 
 static struct isp_platform_data beagle_isp_platform_data = {
+	.xclks = {
+		[0] = {
+			.con_id = "mclk",
+#ifdef BEAGLE_OV772X
+			.dev_id = "2-0021",
+#else
+			.dev_id = "2-0048",
+#endif
+		},
+	},
 	.subdevs = beagle_camera_subdevs,
 };
 
 static int __init beagle_camera_init(void)
 {
+	int r;
+
 	if (!machine_is_omap3_beagle() || !cpu_is_omap3630())
 		return 0;
 
-	omap_register_i2c_bus(2, 100, NULL, 0);
+	r = gpio_request_one(98, GPIOF_OUT_INIT_HIGH, "CAM_RES");
+	if (r)
+		pr_err("%s: unable to configure camera reset GPIO\n",
+		       __func__);
+#ifdef BEAGLE_OV772X
+	r = gpio_request_one(beagle_gpio_camera_en, GPIOF_OUT_INIT_LOW, "CAM_EN");
+	if (r) {
+		pr_err("%s: unable to configure camera enable GPIO\n",
+		       __func__);
+	} else {
+		usleep_range(1000, 2000);
+		gpio_set_value_cansleep(98, 0);
+		usleep_range(1000, 2000);
+		gpio_set_value_cansleep(98, 1);
+		usleep_range(1000, 2000);
+	}
+#else
+	beagle_mt9p031_platform_data.reset = beagle_gpio_camera_en;
+#endif
 	omap3_init_camera(&beagle_isp_platform_data);
 
 	return 0;
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 80e1441..fa6cb55 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -35,6 +35,7 @@
 #include <linux/usb/phy.h>
 #include <linux/usb/usb_phy_gen_xceiv.h>
 
+#include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
 
@@ -293,11 +294,34 @@ static struct usbhs_phy_data phy_data[] = {
 	{
 		.port = 2,
 		.reset_gpio = 147,
-		.vcc_gpio = -1,		/* updated in beagle_twl_gpio_setup */
+		.vcc_gpio = -EINVAL,	/* updated in beagle_twl_gpio_setup */
 		.vcc_polarity = 1,	/* updated in beagle_twl_gpio_setup */
 	},
 };
 
+static struct regulator_consumer_supply tl1963a_consumers[] =
+{
+	REGULATOR_SUPPLY("vcc", "usb_phy_gen_xceiv.2"),
+	REGULATOR_SUPPLY("cam_ana", "2-0021"),
+};
+
+static struct regulator_init_data tl1963a_init_data = {
+	.constraints = {
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies  = ARRAY_SIZE(tl1963a_consumers),
+	.consumer_supplies      = tl1963a_consumers,
+};
+
+static struct fixed_voltage_config tl1963a_info = {
+	.supply_name = "USB & Cam 3.3V",
+	.microvolts = 3300000,
+	.startup_delay = 70000, /* 70msec */
+	.init_data = &tl1963a_init_data,
+};
+
+extern int beagle_gpio_camera_en;
+
 static int beagle_twl_gpio_setup(struct device *dev,
 		unsigned gpio, unsigned ngpio)
 {
@@ -308,6 +332,19 @@ static int beagle_twl_gpio_setup(struct device *dev,
 	mmc[0].gpio_cd = gpio + 0;
 	omap_hsmmc_late_init(mmc);
 
+	if (omap3_beagle_version >= OMAP3BEAGLE_BOARD_XM) {
+		/*
+		 * Power on camera interface - only on pre-production, not
+		 * needed on production boards
+		 */
+/*		r = gpio_request_one(gpio + 2, GPIOF_OUT_INIT_HIGH, "CAM_EN");
+		if (r)
+			pr_err("%s: unable to configure camera reset GPIO\n",
+				__func__);
+		else
+*/			beagle_gpio_camera_en = gpio + 2;
+	}
+
 	/*
 	 * TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
 	 * high / others active low)
@@ -344,6 +381,12 @@ static int beagle_twl_gpio_setup(struct device *dev,
 	platform_device_register(&beagle_tv_connector_device);
 
 	/* TWL4030_GPIO_MAX i.e. LED_GPO controls HS USB Port 2 power */
+	tl1963a_info.gpio = gpio + TWL4030_GPIO_MAX;
+	tl1963a_info.enable_high = beagle_config.usb_pwr_level;
+//	platform_device_register_data(&platform_bus, "reg-fixed-voltage", 1,
+//				      &tl1963a_info, sizeof(tl1963a_info));
+
+//	phy_data[0].vcc_gpio = -EEXIST;
 	phy_data[0].vcc_gpio = gpio + TWL4030_GPIO_MAX;
 	phy_data[0].vcc_polarity = beagle_config.usb_pwr_level;
 
@@ -390,11 +433,14 @@ static struct regulator_init_data beagle_vsim = {
 };
 
 static struct regulator_consumer_supply beagle_vaux3_supply[] = {
-	{ .supply = "cam_core" },
+	REGULATOR_SUPPLY("cam_core", "2-0021"),
+	REGULATOR_SUPPLY("vdd", "2-0048"),
+	REGULATOR_SUPPLY("vaa", "2-0048"),
 };
 
 static struct regulator_consumer_supply beagle_vaux4_supply[] = {
-	{ .supply = "cam_io" },
+	REGULATOR_SUPPLY("cam_io", "2-0021"),
+	REGULATOR_SUPPLY("vdd_io", "2-0048"),
 };
 
 /* VAUX3 for CAM_1V8 */
@@ -402,6 +448,7 @@ static struct regulator_init_data beagle_vaux3 = {
 	.constraints = {
 		.min_uV			= 1800000,
 		.max_uV			= 1800000,
+		.boot_on		= true,
 		.apply_uV		= true,
 		.valid_modes_mask	= REGULATOR_MODE_NORMAL
 					| REGULATOR_MODE_STANDBY,
@@ -452,6 +499,7 @@ static int __init omap3_beagle_i2c_init(void)
 	beagle_twldata.vpll2->constraints.name = "VDVI";
 
 	omap3_pmic_init("twl4030", &beagle_twldata);
+	omap_register_i2c_bus(2, 100, NULL, 0);
 	/* Bus 3 is attached to the DVI port where devices like the pico DLP
 	 * projector don't work reliably with 400kHz */
 	omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom));
@@ -525,6 +573,35 @@ static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
 
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+	/* Camera */
+	OMAP3_MUX(CAM_HS, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(CAM_VS, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(CAM_XCLKA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(CAM_PCLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+//	OMAP3_MUX(CAM_FLD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(CAM_D0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(CAM_D1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(CAM_D2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(CAM_D3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(CAM_D4, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(CAM_D5, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(CAM_D6, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(CAM_D7, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+	OMAP3_MUX(CAM_D8, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
+	OMAP3_MUX(CAM_D9, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
+	OMAP3_MUX(CAM_STROBE, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+
+	OMAP3_MUX(CAM_D10, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLDOWN),
+	OMAP3_MUX(CAM_D11, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLDOWN),
+
+	/* I2C 2 */
+	OMAP3_MUX(I2C2_SCL, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+	OMAP3_MUX(I2C2_SDA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+
+	/* TPS IRQ */
+	OMAP3_MUX(SYS_NIRQ, OMAP_MUX_MODE0 | OMAP_WAKEUP_EN |
+		  OMAP_PIN_INPUT_PULLUP),
+
 	{ .reg_offset = OMAP_MUX_TERMINATOR },
 };
 #endif
diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c
index 10855eb..1c64b9a 100644
--- a/arch/arm/mach-omap2/usb-host.c
+++ b/arch/arm/mach-omap2/usb-host.c
@@ -458,7 +458,7 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys)
 
 		/* set platform data */
 		memset(&nop_pdata, 0, sizeof(nop_pdata));
-		if (gpio_is_valid(phy->vcc_gpio))
+		if (gpio_is_valid(phy->vcc_gpio) || phy->vcc_gpio == -EEXIST)
 			nop_pdata.needs_vcc = true;
 		nop_pdata.gpio_reset = phy->reset_gpio;
 		nop_pdata.type = USB_PHY_TYPE_USB2;
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index 5864a76..8009ee3 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -223,7 +223,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031)
 	struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
 	struct mt9p031_platform_data *pdata = mt9p031->pdata;
 
-	mt9p031->clk = devm_clk_get(&client->dev, NULL);
+	mt9p031->clk = devm_clk_get(&client->dev, "mclk");
 	if (IS_ERR(mt9p031->clk))
 		return PTR_ERR(mt9p031->clk);
 
diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c
index 5b91593..305d2e2 100644
--- a/drivers/media/i2c/soc_camera/imx074.c
+++ b/drivers/media/i2c/soc_camera/imx074.c
@@ -434,6 +434,7 @@ static int imx074_probe(struct i2c_client *client,
 		return -ENOMEM;
 
 	v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops);
+	priv->subdev.pdata = &ssdd->sd_pdata;
 
 	priv->fmt	= &imx074_colour_fmts[0];
 
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
index f9f95f8..98b56d1 100644
--- a/drivers/media/i2c/soc_camera/mt9v022.c
+++ b/drivers/media/i2c/soc_camera/mt9v022.c
@@ -170,6 +170,12 @@ static struct mt9v022 *to_mt9v022(const struct i2c_client *client)
 	return container_of(i2c_get_clientdata(client), struct mt9v022, subdev);
 }
 
+static struct soc_camera_subdev_desc *to_sddesc(struct i2c_client *client)
+{
+	struct mt9v022_platform_data *pdata = client->dev.platform_data;
+	return &pdata->sdesc.subdev_desc;
+}
+
 static int reg_read(struct i2c_client *client, const u8 reg)
 {
 	return i2c_smbus_read_word_swapped(client, reg);
@@ -499,7 +505,7 @@ static int mt9v022_s_register(struct v4l2_subdev *sd,
 static int mt9v022_s_power(struct v4l2_subdev *sd, int on)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
-	struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+	struct soc_camera_subdev_desc *ssdd = to_sddesc(client);
 	struct mt9v022 *mt9v022 = to_mt9v022(client);
 
 	return soc_camera_set_power(&client->dev, ssdd, mt9v022->clk, on);
@@ -647,7 +653,7 @@ static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
 static int mt9v022_video_probe(struct i2c_client *client)
 {
 	struct mt9v022 *mt9v022 = to_mt9v022(client);
-	struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+	struct soc_camera_subdev_desc *ssdd = to_sddesc(client);
 	s32 data;
 	int ret;
 	unsigned long flags;
@@ -775,7 +781,7 @@ static int mt9v022_g_mbus_config(struct v4l2_subdev *sd,
 				struct v4l2_mbus_config *cfg)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
-	struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+	struct soc_camera_subdev_desc *ssdd = to_sddesc(client);
 
 	cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE |
 		V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
@@ -792,7 +798,7 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd,
 				 const struct v4l2_mbus_config *cfg)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
-	struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+	struct soc_camera_subdev_desc *ssdd = to_sddesc(client);
 	struct mt9v022 *mt9v022 = to_mt9v022(client);
 	unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg);
 	unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample;
@@ -864,16 +870,18 @@ static int mt9v022_probe(struct i2c_client *client,
 			 const struct i2c_device_id *did)
 {
 	struct mt9v022 *mt9v022;
-	struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+	struct mt9v022_platform_data *pdata = client->dev.platform_data;
+	struct soc_camera_subdev_desc *ssdd;
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
-	struct mt9v022_platform_data *pdata;
 	int ret;
 
-	if (!ssdd) {
+	if (!pdata) {
 		dev_err(&client->dev, "MT9V022 driver needs platform data\n");
 		return -EINVAL;
 	}
 
+	ssdd = &pdata->sdesc.subdev_desc;
+
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
 		dev_warn(&adapter->dev,
 			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
@@ -884,7 +892,6 @@ static int mt9v022_probe(struct i2c_client *client,
 	if (!mt9v022)
 		return -ENOMEM;
 
-	pdata = ssdd->drv_priv;
 	v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops);
 	v4l2_ctrl_handler_init(&mt9v022->hdl, 6);
 	v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
@@ -916,6 +923,7 @@ static int mt9v022_probe(struct i2c_client *client,
 			MT9V022_VERTICAL_BLANKING_MAX, 1,
 			MT9V022_VERTICAL_BLANKING_DEF);
 
+	mt9v022->subdev.pdata = &ssdd->sd_pdata;
 	mt9v022->subdev.ctrl_handler = &mt9v022->hdl;
 	if (mt9v022->hdl.error) {
 		int err = mt9v022->hdl.error;
@@ -933,7 +941,7 @@ static int mt9v022_probe(struct i2c_client *client,
 	 * On some platforms the first read out line is corrupted.
 	 * Workaround it by skipping if indicated by platform data.
 	 */
-	mt9v022->y_skip_top	= pdata ? pdata->y_skip_top : 0;
+	mt9v022->y_skip_top	= pdata->y_skip_top;
 	mt9v022->rect.left	= MT9V022_COLUMN_SKIP;
 	mt9v022->rect.top	= MT9V022_ROW_SKIP;
 	mt9v022->rect.width	= MT9V022_MAX_WIDTH;
@@ -958,7 +966,7 @@ eclkget:
 static int mt9v022_remove(struct i2c_client *client)
 {
 	struct mt9v022 *mt9v022 = to_mt9v022(client);
-	struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+	struct soc_camera_subdev_desc *ssdd = to_sddesc(client);
 
 	v4l2_clk_put(mt9v022->clk);
 	v4l2_device_unregister_subdev(&mt9v022->subdev);
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c
index 7f2b3c8..9c57d22 100644
--- a/drivers/media/i2c/soc_camera/ov772x.c
+++ b/drivers/media/i2c/soc_camera/ov772x.c
@@ -394,16 +394,21 @@ struct ov772x_win_size {
 };
 
 struct ov772x_priv {
-	struct v4l2_subdev                subdev;
+	struct v4l2_subdev		  subdev;
+	struct media_pad		  pad;
 	struct v4l2_ctrl_handler	  hdl;
 	struct v4l2_clk			 *clk;
-	struct ov772x_camera_info        *info;
+	struct ov772x_camera_info	 *info;
 	const struct ov772x_color_format *cfmt;
-	const struct ov772x_win_size     *win;
-	unsigned short                    flag_vflip:1;
-	unsigned short                    flag_hflip:1;
+	const struct ov772x_win_size	 *win;
+	unsigned short			  flag_vflip:1;
+	unsigned short			  flag_hflip:1;
 	/* band_filter = COM8[5] ? 256 - BDBASE : 0 */
-	unsigned short                    band_filter;
+	unsigned short			  band_filter;
+	struct mutex			  power_lock; /* protects power_count */
+	int				  power_count;
+
+	struct v4l2_mbus_framefmt	  format;
 };
 
 /*
@@ -507,6 +512,10 @@ static const struct ov772x_win_size ov772x_win_sizes[] = {
 	},
 };
 
+static int ov772x_set_params(struct ov772x_priv *priv,
+			     const struct ov772x_color_format *cfmt,
+			     const struct ov772x_win_size *win);
+
 /*
  * general function
  */
@@ -516,6 +525,12 @@ static struct ov772x_priv *to_ov772x(struct v4l2_subdev *sd)
 	return container_of(sd, struct ov772x_priv, subdev);
 }
 
+static struct soc_camera_subdev_desc *to_sddesc(struct i2c_client *client)
+{
+	struct ov772x_camera_info *pdata = client->dev.platform_data;
+	return &pdata->sdesc.subdev_desc;
+}
+
 static inline int ov772x_read(struct i2c_client *client, u8 addr)
 {
 	return i2c_smbus_read_byte_data(client, addr);
@@ -560,12 +575,20 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct ov772x_priv *priv = to_ov772x(sd);
+	unsigned int clkrate;
+	int ret;
 
 	if (!enable) {
 		ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
 		return 0;
 	}
 
+	clkrate = priv->cfmt->dsp4 == DSP_OFMT_YUV ? 12000000 : 24000000;
+//	ret = priv->info->set_xclk(&priv->subdev, clkrate);
+	ret = v4l2_clk_set_rate(priv->clk, clkrate);
+	if (ret < 0)
+		return ret;
+
 	ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0);
 
 	dev_dbg(&client->dev, "format %d, win %s\n",
@@ -653,13 +676,59 @@ static int ov772x_s_register(struct v4l2_subdev *sd,
 }
 #endif
 
+static int __ov772x_set_power(struct ov772x_priv *priv, bool on)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+	struct soc_camera_subdev_desc *ssdd = to_sddesc(client);
+	int ret;
+
+	if (on) {
+//		ret = priv->info->set_xclk(&priv->subdev, 24000000);
+		ret = v4l2_clk_set_rate(priv->clk, 24000000);
+		if (ret < 0)
+			return ret;
+
+		ret = soc_camera_power_on(&client->dev, ssdd, priv->clk);
+		if (ret < 0)
+			return ret;
+
+		usleep_range(1000, 1500);
+
+		ret = ov772x_set_params(priv, priv->cfmt, priv->win);
+		if (ret < 0)
+			return ret;
+	} else {
+//		priv->info->set_xclk(&priv->subdev, 0);
+//		ret = v4l2_clk_set_rate(priv->clk, 1000);
+		soc_camera_power_off(&client->dev, ssdd, priv->clk);
+	}
+
+	return 0;
+}
+
 static int ov772x_s_power(struct v4l2_subdev *sd, int on)
 {
-	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);
+	int ret = 0;
+
+	mutex_lock(&priv->power_lock);
 
-	return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
+	/* If the power count is modified from 0 to != 0 or from != 0 to 0,
+	 * update the power state.
+	 */
+	if (priv->power_count == !on) {
+		ret = __ov772x_set_power(priv, !!on);
+		if (ret < 0)
+			goto out;
+	}
+
+	/* Update the power count. */
+	priv->power_count += on ? 1 : -1;
+	WARN_ON(priv->power_count < 0);
+
+out:
+	mutex_unlock(&priv->power_lock);
+	return ret;
 }
 
 static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
@@ -884,11 +953,7 @@ static int ov772x_g_fmt(struct v4l2_subdev *sd,
 {
 	struct ov772x_priv *priv = to_ov772x(sd);
 
-	mf->width	= priv->win->rect.width;
-	mf->height	= priv->win->rect.height;
-	mf->code	= priv->cfmt->code;
-	mf->colorspace	= priv->cfmt->colorspace;
-	mf->field	= V4L2_FIELD_NONE;
+	*mf = priv->format;
 
 	return 0;
 }
@@ -909,11 +974,12 @@ static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
 	priv->win = win;
 	priv->cfmt = cfmt;
 
-	mf->code = cfmt->code;
-	mf->width = win->rect.width;
-	mf->height = win->rect.height;
-	mf->field = V4L2_FIELD_NONE;
-	mf->colorspace = cfmt->colorspace;
+	priv->format.code = cfmt->code;
+	priv->format.width = win->rect.width;
+	priv->format.height = win->rect.height;
+	priv->format.colorspace = cfmt->colorspace;
+
+	*mf = priv->format;
 
 	return 0;
 }
@@ -1006,7 +1072,7 @@ static int ov772x_g_mbus_config(struct v4l2_subdev *sd,
 				struct v4l2_mbus_config *cfg)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
-	struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+	struct soc_camera_subdev_desc *ssdd = to_sddesc(client);
 
 	cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
 		V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
@@ -1028,9 +1094,196 @@ static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
 	.g_mbus_config	= ov772x_g_mbus_config,
 };
 
+/* -----------------------------------------------------------------------------
+ * Pad operations
+ */
+
+static int ov772x_enum_mbus_code(struct v4l2_subdev *subdev,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts))
+		return -EINVAL;
+
+	code->code = ov772x_cfmts[code->index].code;
+	return 0;
+}
+
+static int ov772x_enum_frame_size(struct v4l2_subdev *subdev,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_frame_size_enum *fse)
+{
+	unsigned int i;
+
+	if (fse->pad || fse->index >= ARRAY_SIZE(ov772x_win_sizes))
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); ++i) {
+		if (fse->code == ov772x_cfmts[i].code)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(ov772x_cfmts))
+		return -EINVAL;
+
+	fse->min_width = ov772x_win_sizes[fse->index].rect.width;
+	fse->max_width = fse->min_width;
+	fse->min_height = ov772x_win_sizes[fse->index].rect.height;
+	fse->max_height = fse->min_height;
+
+	return 0;
+}
+
+static struct v4l2_mbus_framefmt *__ov772x_get_pad_format(
+			struct ov772x_priv *priv, struct v4l2_subdev_fh *fh,
+			unsigned int pad, u32 which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_format(fh, pad);
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &priv->format;
+	default:
+		return NULL;
+	}
+}
+
+static int ov772x_get_pad_format(struct v4l2_subdev *subdev,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_format *fmt)
+{
+	struct ov772x_priv *priv = to_ov772x(subdev);
+
+	if (fmt->pad)
+		return -EINVAL;
+
+	fmt->format = *__ov772x_get_pad_format(priv, fh, fmt->pad, fmt->which);
+	return 0;
+}
+
+static int ov772x_set_pad_format(struct v4l2_subdev *subdev,
+				 struct v4l2_subdev_fh *fh,
+				 struct v4l2_subdev_format *fmt)
+{
+	struct ov772x_priv *priv = to_ov772x(subdev);
+	const struct ov772x_color_format *cfmt;
+	const struct ov772x_win_size *win;
+	struct v4l2_mbus_framefmt *format;
+	int ret;
+
+	if (fmt->pad)
+		return -EINVAL;
+
+	format = __ov772x_get_pad_format(priv, fh, fmt->pad, fmt->which);
+	if (format == NULL)
+		return -EINVAL;
+
+	ov772x_select_params(&fmt->format, &cfmt, &win);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		ret = ov772x_set_params(priv, cfmt, win);
+		if (ret < 0)
+			return ret;
+	}
+
+	priv->win = win;
+	priv->cfmt = cfmt;
+
+	format->code = cfmt->code;
+	format->width = win->rect.width;
+	format->height = win->rect.height;
+	format->field = V4L2_FIELD_NONE;
+	format->colorspace = cfmt->colorspace;
+
+	fmt->format = *format;
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Subdev operations
+ */
+
+static int ov772x_registered(struct v4l2_subdev *sd)
+{
+	struct i2c_client  *client = v4l2_get_subdevdata(sd);
+	struct ov772x_priv *priv = to_ov772x(sd);
+	u8                  pid, ver;
+	const char         *devname;
+	int		    ret;
+
+	ret = __ov772x_set_power(priv, 1);
+	if (ret < 0)
+		return ret;
+
+	/* Check and show product ID and manufacturer ID. */
+	pid = ov772x_read(client, PID);
+	ver = ov772x_read(client, VER);
+
+	switch (VERSION(pid, ver)) {
+	case OV7720:
+		devname     = "ov7720";
+//		priv->model = V4L2_IDENT_OV7720;
+		break;
+	case OV7725:
+		devname     = "ov7725";
+//		priv->model = V4L2_IDENT_OV7725;
+		break;
+	default:
+		dev_err(&client->dev,
+			"Product ID error %x:%x\n", pid, ver);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	dev_info(&client->dev,
+		 "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+		 devname, pid, ver, ov772x_read(client, MIDH),
+		 ov772x_read(client, MIDL));
+
+	ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+	__ov772x_set_power(priv, 0);
+	return ret;
+}
+
+static int ov772x_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_mbus_framefmt *format;
+
+	format = v4l2_subdev_get_try_format(fh, 0);
+
+	format->code = V4L2_MBUS_FMT_YUYV8_2X8;
+	format->width = ov772x_win_sizes[0].rect.width;
+	format->height = ov772x_win_sizes[0].rect.height;
+	format->field = V4L2_FIELD_NONE;
+	format->colorspace = V4L2_COLORSPACE_JPEG;
+
+	return ov772x_s_power(sd, 1);
+}
+
+static int ov772x_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	return ov772x_s_power(sd, 0);
+}
+
+static const struct v4l2_subdev_internal_ops ov772x_subdev_internal_ops = {
+	.registered = ov772x_registered,
+	.open = ov772x_open,
+	.close = ov772x_close,
+};
+
+static struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = {
+	.enum_mbus_code = ov772x_enum_mbus_code,
+	.enum_frame_size = ov772x_enum_frame_size,
+	.get_fmt = ov772x_get_pad_format,
+	.set_fmt = ov772x_set_pad_format,
+};
+
 static struct v4l2_subdev_ops ov772x_subdev_ops = {
 	.core	= &ov772x_subdev_core_ops,
 	.video	= &ov772x_subdev_video_ops,
+	.pad	= &ov772x_subdev_pad_ops,
 };
 
 /*
@@ -1041,11 +1294,11 @@ static int ov772x_probe(struct i2c_client *client,
 			const struct i2c_device_id *did)
 {
 	struct ov772x_priv	*priv;
-	struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+	struct ov772x_camera_info *pdata = client->dev.platform_data;
 	struct i2c_adapter	*adapter = to_i2c_adapter(client->dev.parent);
 	int			ret;
 
-	if (!ssdd || !ssdd->drv_priv) {
+	if (!pdata) {
 		dev_err(&client->dev, "OV772X: missing platform data!\n");
 		return -EINVAL;
 	}
@@ -1057,23 +1310,44 @@ static int ov772x_probe(struct i2c_client *client,
 		return -EIO;
 	}
 
+	client->flags |= I2C_CLIENT_SCCB;
+
 	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
-	priv->info = ssdd->drv_priv;
+	priv->info = pdata;
 
+	mutex_init(&priv->power_lock);
 	v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
-	v4l2_ctrl_handler_init(&priv->hdl, 3);
+	priv->subdev.internal_ops = &ov772x_subdev_internal_ops;
+
+	priv->pad.flags = MEDIA_PAD_FL_SOURCE;
+	priv->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+	ret = media_entity_init(&priv->subdev.entity, 1, &priv->pad, 0);
+	if (ret < 0)
+		return ret;
+
+	priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	v4l2_ctrl_handler_init(&priv->hdl, 4);
 	v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
 			V4L2_CID_VFLIP, 0, 1, 1, 0);
 	v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
 			V4L2_CID_HFLIP, 0, 1, 1, 0);
 	v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
 			V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0);
+	v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
+			  V4L2_CID_PIXEL_RATE, 48000000,
+			  48000000, 1, 48000000);
+
 	priv->subdev.ctrl_handler = &priv->hdl;
-	if (priv->hdl.error)
-		return priv->hdl.error;
+	if (priv->hdl.error) {
+		ret = priv->hdl.error;
+		goto ectrlhdl;
+	}
+
+	dev_info(&client->dev, "%s().%d\n", __func__, __LINE__);
 
 	priv->clk = v4l2_clk_get(&client->dev, "mclk");
 	if (IS_ERR(priv->clk)) {
@@ -1081,16 +1355,35 @@ static int ov772x_probe(struct i2c_client *client,
 		goto eclkget;
 	}
 
+	dev_info(&client->dev, "%s().%d\n", __func__, __LINE__);
+
+	priv->cfmt = &ov772x_cfmts[0];
+	priv->win = &ov772x_win_sizes[0];
+
+	priv->format.code = priv->cfmt->code;
+	priv->format.width = priv->win->rect.width;
+	priv->format.height = priv->win->rect.height;
+	priv->format.field = V4L2_FIELD_NONE;
+	priv->format.colorspace = priv->cfmt->colorspace;
+
+	ret = soc_camera_power_init(&client->dev, &pdata->sdesc.subdev_desc);
+	if (ret < 0)
+		goto epwrinit;
+
+	dev_info(&client->dev, "%s().%d\n", __func__, __LINE__);
+
 	ret = ov772x_video_probe(priv);
 	if (ret < 0) {
+epwrinit:
 		v4l2_clk_put(priv->clk);
 eclkget:
 		v4l2_ctrl_handler_free(&priv->hdl);
-	} else {
-		priv->cfmt = &ov772x_cfmts[0];
-		priv->win = &ov772x_win_sizes[0];
+ectrlhdl:
+		media_entity_cleanup(&priv->subdev.entity);
 	}
 
+	dev_info(&client->dev, "%s().%d: %d\n", __func__, __LINE__, ret);
+
 	return ret;
 }
 
@@ -1101,6 +1394,7 @@ static int ov772x_remove(struct i2c_client *client)
 	v4l2_clk_put(priv->clk);
 	v4l2_device_unregister_subdev(&priv->subdev);
 	v4l2_ctrl_handler_free(&priv->hdl);
+	media_entity_cleanup(&priv->subdev.entity);
 	return 0;
 }
 
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index 57e4b24..e9cb346 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -16,6 +16,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
@@ -74,25 +75,28 @@ int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd,
 	int ret;
 	bool clock_toggle;
 
+	ret = regulator_bulk_enable(ssdd->sd_pdata.num_regulators,
+				    ssdd->sd_pdata.regulators);
+	if (ret < 0) {
+		dev_err(dev, "Cannot enable regulators\n");
+		return ret;
+	}
+
+	usleep_range(5000, 6000);
 	if (clk && (!ssdd->unbalanced_power ||
 		    !test_and_set_bit(0, &ssdd->clock_state))) {
+//		if (ssdd->clock_rate)
+//			v4l2_clk_set_rate(clk, ssdd->clock_rate);
 		ret = v4l2_clk_enable(clk);
 		if (ret < 0) {
 			dev_err(dev, "Cannot enable clock: %d\n", ret);
-			return ret;
+			goto eclken;
 		}
 		clock_toggle = true;
 	} else {
 		clock_toggle = false;
 	}
 
-	ret = regulator_bulk_enable(ssdd->sd_pdata.num_regulators,
-				    ssdd->sd_pdata.regulators);
-	if (ret < 0) {
-		dev_err(dev, "Cannot enable regulators\n");
-		goto eregenable;
-	}
-
 	if (ssdd->power) {
 		ret = ssdd->power(dev, 1);
 		if (ret < 0) {
@@ -105,11 +109,11 @@ int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd,
 	return 0;
 
 epwron:
-	regulator_bulk_disable(ssdd->sd_pdata.num_regulators,
-			       ssdd->sd_pdata.regulators);
-eregenable:
 	if (clock_toggle)
 		v4l2_clk_disable(clk);
+eclken:
+	regulator_bulk_disable(ssdd->sd_pdata.num_regulators,
+				     ssdd->sd_pdata.regulators);
 
 	return ret;
 }
@@ -146,15 +150,22 @@ EXPORT_SYMBOL(soc_camera_power_off);
 
 int soc_camera_power_init(struct device *dev, struct soc_camera_subdev_desc *ssdd)
 {
+	int ret;
 	/*
 	 * In synchronous case we request regulators ourselves in
 	 * soc_camera_pdrv_probe(), make sure the subdevice driver doesn't try
 	 * to allocate them again.
 	 */
-	return ssdd->probing_mode == SOC_CAMERA_ASYNC ?
-		devm_regulator_bulk_get(dev, ssdd->sd_pdata.num_regulators,
-					ssdd->sd_pdata.regulators) :
-		0;
+	if (ssdd->probing_mode == SOC_CAMERA_LEGACY)
+		return 0;
+
+	ret = devm_regulator_bulk_get(dev, ssdd->sd_pdata.num_regulators,
+					ssdd->sd_pdata.regulators);
+	if (!ret)
+		regulator_bulk_disable(ssdd->sd_pdata.num_regulators,
+					ssdd->sd_pdata.regulators);
+
+	return ret;
 }
 EXPORT_SYMBOL(soc_camera_power_init);
 
@@ -1330,6 +1351,7 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
 	struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc;
 	struct i2c_client *client;
 	struct soc_camera_host *ici;
+	/* Alternatively ssdd->sd_pdata.host_priv could be used for shd */
 	struct soc_camera_host_desc *shd = &sdesc->host_desc;
 	struct i2c_adapter *adap;
 	struct v4l2_subdev *subdev;
@@ -1350,7 +1372,7 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
 		return -ENODEV;
 	}
 
-	shd->board_info->platform_data = ssdd;
+	shd->board_info->platform_data = ssdd->drv_priv;
 
 	snprintf(clk_name, sizeof(clk_name), "%d-%04x",
 		 shd->i2c_adapter_id, shd->board_info->addr);
@@ -1388,6 +1410,9 @@ static void soc_camera_i2c_free(struct soc_camera_device *icd)
 		to_i2c_client(to_soc_camera_control(icd));
 	struct i2c_adapter *adap;
 
+	if (!icd->control)
+		return;
+
 	icd->control = NULL;
 	if (icd->sasc)
 		return;
@@ -1426,7 +1451,7 @@ static int soc_camera_async_bound(struct v4l2_async_notifier *notifier,
 		if (client) {
 			struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
 			struct soc_camera_subdev_desc *ssdd =
-				soc_camera_i2c_to_desc(client);
+				soc_camera_sd_to_desc(sd);
 			if (ssdd) {
 				memcpy(&sdesc->subdev_desc, ssdd,
 				       sizeof(sdesc->subdev_desc));
diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c
index e18cc04..3b6dd2f 100644
--- a/drivers/media/v4l2-core/v4l2-clk.c
+++ b/drivers/media/v4l2-core/v4l2-clk.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/atomic.h>
+#include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/list.h>
@@ -23,6 +24,70 @@
 static DEFINE_MUTEX(clk_lock);
 static LIST_HEAD(clk_list);
 
+/* V4L2 CCF Clock driver */
+
+static int v4l2_clk_ccf_enable(struct v4l2_clk *clk)
+{
+	return clk_prepare_enable(clk->priv);
+}
+
+static void v4l2_clk_ccf_disable(struct v4l2_clk *clk)
+{
+	clk_disable_unprepare(clk->priv);
+}
+
+static unsigned long v4l2_clk_ccf_get_rate(struct v4l2_clk *clk)
+{
+	return clk_get_rate(clk->priv);
+}
+
+static int v4l2_clk_ccf_set_rate(struct v4l2_clk *clk, unsigned long rate)
+{
+	rate = clk_round_rate(clk->priv, rate);
+	return clk_set_rate(clk->priv, rate);
+}
+
+static const struct v4l2_clk_ops v4l2_clk_ccf = {
+	.enable = v4l2_clk_ccf_enable,
+	.disable = v4l2_clk_ccf_disable,
+	.get_rate = v4l2_clk_ccf_get_rate,
+	.set_rate = v4l2_clk_ccf_set_rate,
+};
+
+static struct v4l2_clk *v4l2_clk_ccf_get(struct device *dev, const char *id)
+{
+	struct clk *clk = clk_get(dev, id);
+	struct v4l2_clk *vclk, *v;
+
+	if (IS_ERR(clk))
+		return ERR_PTR(PTR_ERR(clk));
+
+	vclk = v4l2_clk_register(&v4l2_clk_ccf, dev_name(dev), id, clk);
+	if (IS_ERR(vclk)) {
+		v = vclk;
+		goto e_clkput;
+	}
+
+	v = v4l2_clk_get(dev, id);
+	if (IS_ERR(v)) {
+		v4l2_clk_unregister(vclk);
+e_clkput:
+		clk_put(clk);
+	}
+
+	return v;
+}
+
+static void v4l2_clk_ccf_put(struct v4l2_clk *vclk)
+{
+	struct clk *clk = vclk->priv;
+
+	v4l2_clk_unregister(vclk);
+	clk_put(clk);
+}
+
+/* V4L2 Clock API core implementation */
+
 static struct v4l2_clk *v4l2_clk_find(const char *dev_id, const char *id)
 {
 	struct v4l2_clk *clk;
@@ -45,6 +110,12 @@ struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id)
 	mutex_lock(&clk_lock);
 	clk = v4l2_clk_find(dev_name(dev), id);
 
+	if (IS_ERR(clk)) {
+		mutex_unlock(&clk_lock);
+		clk = v4l2_clk_ccf_get(dev, id);
+		mutex_lock(&clk_lock);
+	}
+
 	if (!IS_ERR(clk))
 		atomic_inc(&clk->use_count);
 	mutex_unlock(&clk_lock);
@@ -56,6 +127,7 @@ EXPORT_SYMBOL(v4l2_clk_get);
 void v4l2_clk_put(struct v4l2_clk *clk)
 {
 	struct v4l2_clk *tmp;
+	bool ccf_put = false;
 
 	if (IS_ERR(clk))
 		return;
@@ -63,10 +135,18 @@ void v4l2_clk_put(struct v4l2_clk *clk)
 	mutex_lock(&clk_lock);
 
 	list_for_each_entry(tmp, &clk_list, list)
-		if (tmp == clk)
+		if (tmp == clk) {
 			atomic_dec(&clk->use_count);
+			if (clk->ops == &v4l2_clk_ccf &&
+			    !atomic_read(&clk->use_count))
+				ccf_put = true;
+			break;
+		}
 
 	mutex_unlock(&clk_lock);
+
+	if (ccf_put)
+		v4l2_clk_ccf_put(clk);
 }
 EXPORT_SYMBOL(v4l2_clk_put);
 
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9888f26..a6e57d6 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1911,6 +1911,9 @@ static int _regulator_disable(struct regulator_dev *rdev)
 {
 	int ret = 0;
 
+	if (!rdev->use_count)
+		return 0;
+
 	if (WARN(rdev->use_count <= 0,
 		 "unbalanced disables for %s\n", rdev_get_name(rdev)))
 		return -EIO;
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index bb39498..30e010d 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -206,7 +206,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
 
 	nop->vcc = devm_regulator_get(dev, "vcc");
 	if (IS_ERR(nop->vcc)) {
-		dev_dbg(dev, "Error getting vcc regulator: %ld\n",
+		dev_err(dev, "Error getting vcc regulator: %ld\n",
 					PTR_ERR(nop->vcc));
 		if (needs_vcc)
 			return -EPROBE_DEFER;
diff --git a/include/media/ov772x.h b/include/media/ov772x.h
index f295388..33eb1eb 100644
--- a/include/media/ov772x.h
+++ b/include/media/ov772x.h
@@ -50,6 +50,8 @@ struct ov772x_edge_ctrl {
 	.threshold = (t & OV772X_EDGE_THRESHOLD_MASK),	\
 }
 
+struct v4l2_subdev;
+
 /*
  * ov772x camera info
  */
@@ -57,6 +59,7 @@ struct ov772x_camera_info {
 	struct soc_camera_desc	sdesc;
 	unsigned long		flags;
 	struct ov772x_edge_ctrl	edgectrl;
+//	int (*set_xclk)(struct v4l2_subdev *subdev, int hz);
 };
 
 #endif /* __OV772X_H__ */
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 5bdbba7..e64578e 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -141,8 +141,9 @@ struct regulator_bulk_data;
 
 /* We might also need SOC_CAMERA_DT in the future */
 enum soc_camera_probing_mode {
-	SOC_CAMERA_SYNC = 0, /* 0: backwards compatibility */
+	SOC_CAMERA_LEGACY = 0, /* 0: backwards compatibility */
 	SOC_CAMERA_ASYNC,
+	SOC_CAMERA_SYNC,
 };
 
 struct soc_camera_subdev_desc {
@@ -161,6 +162,9 @@ struct soc_camera_subdev_desc {
 	bool unbalanced_power;
 	unsigned long clock_state;
 
+	/* Target master clock rate */
+//	unsigned long clock_rate;
+
 	/* Probing method: synchronous, asynchronous, possibly DT */
 	enum soc_camera_probing_mode probing_mode;
 
@@ -399,6 +403,11 @@ static inline struct soc_camera_subdev_desc *soc_camera_i2c_to_desc(const struct
 	return client->dev.platform_data;
 }
 
+static inline struct soc_camera_subdev_desc *soc_camera_sd_to_desc(struct v4l2_subdev *sd)
+{
+	return container_of(sd->pdata, struct soc_camera_subdev_desc, sd_pdata);
+}
+
 static inline struct v4l2_subdev *soc_camera_vdev_to_subdev(struct video_device *vdev)
 {
 	struct soc_camera_device *icd = video_get_drvdata(vdev);
