summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-pxa/pcm990-baseboard.c23
-rw-r--r--drivers/media/video/mt9m001.c3
-rw-r--r--drivers/media/video/mt9v022.c3
-rw-r--r--include/media/soc_camera.h1
4 files changed, 23 insertions, 7 deletions
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index 095521e9ee24..01791d74e08e 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -380,12 +380,12 @@ static struct pca953x_platform_data pca9536_data = {
 	.gpio_base	= NR_BUILTIN_GPIO,
 };
 
-static int gpio_bus_switch;
+static int gpio_bus_switch = -EINVAL;
 
 static int pcm990_camera_set_bus_param(struct soc_camera_link *link,
-		unsigned long flags)
+				       unsigned long flags)
 {
-	if (gpio_bus_switch <= 0) {
+	if (gpio_bus_switch < 0) {
 		if (flags == SOCAM_DATAWIDTH_10)
 			return 0;
 		else
@@ -404,25 +404,34 @@ static unsigned long pcm990_camera_query_bus_param(struct soc_camera_link *link)
 {
 	int ret;
 
-	if (!gpio_bus_switch) {
+	if (gpio_bus_switch < 0) {
 		ret = gpio_request(NR_BUILTIN_GPIO, "camera");
 		if (!ret) {
 			gpio_bus_switch = NR_BUILTIN_GPIO;
 			gpio_direction_output(gpio_bus_switch, 0);
-		} else
-			gpio_bus_switch = -EINVAL;
+		}
 	}
 
-	if (gpio_bus_switch > 0)
+	if (gpio_bus_switch >= 0)
 		return SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_10;
 	else
 		return SOCAM_DATAWIDTH_10;
 }
 
+static void pcm990_camera_free_bus(struct soc_camera_link *link)
+{
+	if (gpio_bus_switch < 0)
+		return;
+
+	gpio_free(gpio_bus_switch);
+	gpio_bus_switch = -EINVAL;
+}
+
 static struct soc_camera_link iclink = {
 	.bus_id	= 0, /* Must match with the camera ID above */
 	.query_bus_param = pcm990_camera_query_bus_param,
 	.set_bus_param = pcm990_camera_set_bus_param,
+	.free_bus = pcm990_camera_free_bus,
 };
 
 /* Board I2C devices. */
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 684f62fa7897..3838ff77381b 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -604,10 +604,13 @@ ei2c:
 static void mt9m001_video_remove(struct soc_camera_device *icd)
 {
 	struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+	struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
 
 	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr,
 		icd->dev.parent, icd->vdev);
 	soc_camera_video_stop(icd);
+	if (icl->free_bus)
+		icl->free_bus(icl);
 }
 
 static int mt9m001_probe(struct i2c_client *client,
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index 4d3b4813c322..412b399baca4 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -735,10 +735,13 @@ ei2c:
 static void mt9v022_video_remove(struct soc_camera_device *icd)
 {
 	struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+	struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
 
 	dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr,
 		icd->dev.parent, icd->vdev);
 	soc_camera_video_stop(icd);
+	if (icl->free_bus)
+		icl->free_bus(icl);
 }
 
 static int mt9v022_probe(struct i2c_client *client,
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 37013688af44..396c32550e04 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -107,6 +107,7 @@ struct soc_camera_link {
 	 */
 	int (*set_bus_param)(struct soc_camera_link *, unsigned long flags);
 	unsigned long (*query_bus_param)(struct soc_camera_link *);
+	void (*free_bus)(struct soc_camera_link *);
 };
 
 static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev)