From 28406648ba42b583cd393772b0dbeafddb6b495c Mon Sep 17 00:00:00 2001
From: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Date: Tue, 29 Oct 2013 14:46:46 +0100
Subject: [PATCH 4/4] soc-camera: add a flag to explicitly specify a probing
 mode

This eliminates the need to reallocate subdevice platform data in the
synchronous probing mode.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
 drivers/media/platform/soc_camera/soc_camera.c | 34 +++++++++-----------------
 include/media/soc_camera.h                     | 11 +++++++++
 2 files changed, 22 insertions(+), 23 deletions(-)

diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index 4b8c024..57e4b24 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -146,9 +146,15 @@ EXPORT_SYMBOL(soc_camera_power_off);
 
 int soc_camera_power_init(struct device *dev, struct soc_camera_subdev_desc *ssdd)
 {
-	/* Should not have any effect in synchronous case */
-	return devm_regulator_bulk_get(dev, ssdd->sd_pdata.num_regulators,
-				       ssdd->sd_pdata.regulators);
+	/*
+	 * 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;
 }
 EXPORT_SYMBOL(soc_camera_power_init);
 
@@ -1321,7 +1327,7 @@ eusrfmt:
 static int soc_camera_i2c_init(struct soc_camera_device *icd,
 			       struct soc_camera_desc *sdesc)
 {
-	struct soc_camera_subdev_desc *ssdd;
+	struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc;
 	struct i2c_client *client;
 	struct soc_camera_host *ici;
 	struct soc_camera_host_desc *shd = &sdesc->host_desc;
@@ -1344,20 +1350,6 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
 		return -ENODEV;
 	}
 
-	ssdd = kzalloc(sizeof(*ssdd), GFP_KERNEL);
-	if (!ssdd) {
-		ret = -ENOMEM;
-		goto ealloc;
-	}
-
-	memcpy(ssdd, &sdesc->subdev_desc, sizeof(*ssdd));
-	/*
-	 * In synchronous case we request regulators ourselves in
-	 * soc_camera_pdrv_probe(), make sure the subdevice driver doesn't try
-	 * to allocate them again.
-	 */
-	ssdd->sd_pdata.num_regulators = 0;
-	ssdd->sd_pdata.regulators = NULL;
 	shd->board_info->platform_data = ssdd;
 
 	snprintf(clk_name, sizeof(clk_name), "%d-%04x",
@@ -1386,8 +1378,6 @@ ei2cnd:
 	v4l2_clk_unregister(icd->clk);
 	icd->clk = NULL;
 eclkreg:
-	kfree(ssdd);
-ealloc:
 	i2c_put_adapter(adap);
 	return ret;
 }
@@ -1397,18 +1387,15 @@ static void soc_camera_i2c_free(struct soc_camera_device *icd)
 	struct i2c_client *client =
 		to_i2c_client(to_soc_camera_control(icd));
 	struct i2c_adapter *adap;
-	struct soc_camera_subdev_desc *ssdd;
 
 	icd->control = NULL;
 	if (icd->sasc)
 		return;
 
 	adap = client->adapter;
-	ssdd = client->dev.platform_data;
 	v4l2_device_unregister_subdev(i2c_get_clientdata(client));
 	i2c_unregister_device(client);
 	i2c_put_adapter(adap);
-	kfree(ssdd);
 	v4l2_clk_unregister(icd->clk);
 	icd->clk = NULL;
 }
@@ -1519,6 +1506,7 @@ static int scan_async_group(struct soc_camera_host *ici,
 
 	/* HACK: just need a != NULL */
 	sdesc.host_desc.board_info = ERR_PTR(-ENODATA);
+	sdesc.subdev_desc.probing_mode = SOC_CAMERA_ASYNC;
 
 	ret = soc_camera_dyn_pdev(&sdesc, sasc);
 	if (ret < 0)
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 865246b..5bdbba7 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -139,6 +139,12 @@ struct soc_camera_host_ops {
 struct i2c_board_info;
 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_ASYNC,
+};
+
 struct soc_camera_subdev_desc {
 	/* Per camera SOCAM_SENSOR_* bus flags */
 	unsigned long flags;
@@ -155,6 +161,9 @@ struct soc_camera_subdev_desc {
 	bool unbalanced_power;
 	unsigned long clock_state;
 
+	/* Probing method: synchronous, asynchronous, possibly DT */
+	enum soc_camera_probing_mode probing_mode;
+
 	/* Optional callbacks to power on or off and reset the sensor */
 	int (*power)(struct device *, int);
 	int (*reset)(struct device *);
@@ -215,6 +224,8 @@ struct soc_camera_link {
 	/* Used by soc-camera helper functions */
 	unsigned long clock_state;
 
+	enum soc_camera_probing_mode probing_mode;
+
 	/* Optional callbacks to power on or off and reset the sensor */
 	int (*power)(struct device *, int);
 	int (*reset)(struct device *);
-- 
1.9.3

