aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2009-04-24 11:53:51 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-06-16 17:20:43 -0400
commit594bb46dbc63934bc65fa95743f83204bd26a641 (patch)
tree7901c5c70a18777d74276784219848b4e32abb80
parent84d728c3df9931d1937e4a76324838ce065c521e (diff)
V4L/DVB (11607): soc-camera: add a free_bus method to struct soc_camera_link
Currently pcm990 camera bus-width management functions request a GPIO and never free it again. With this approach the GPIO extender driver cannot be unloaded once camera drivers have been loaded, also unloading theb i2c-pxa bus driver produces errors, because the GPIO extender driver cannot unregister properly. Another problem is, that if camera drivers are once loaded before the GPIO extender driver, the platform code marks the GPIO unavailable and only a reboot helps to recover. Adding an explicit free_bus method and using it in mt9m001 and mt9v022 drivers fixes these problems. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Acked-by: Eric Miao <eric.miao@marvell.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-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 = {
380 .gpio_base = NR_BUILTIN_GPIO, 380 .gpio_base = NR_BUILTIN_GPIO,
381}; 381};
382 382
383static int gpio_bus_switch; 383static int gpio_bus_switch = -EINVAL;
384 384
385static int pcm990_camera_set_bus_param(struct soc_camera_link *link, 385static int pcm990_camera_set_bus_param(struct soc_camera_link *link,
386 unsigned long flags) 386 unsigned long flags)
387{ 387{
388 if (gpio_bus_switch <= 0) { 388 if (gpio_bus_switch < 0) {
389 if (flags == SOCAM_DATAWIDTH_10) 389 if (flags == SOCAM_DATAWIDTH_10)
390 return 0; 390 return 0;
391 else 391 else
@@ -404,25 +404,34 @@ static unsigned long pcm990_camera_query_bus_param(struct soc_camera_link *link)
404{ 404{
405 int ret; 405 int ret;
406 406
407 if (!gpio_bus_switch) { 407 if (gpio_bus_switch < 0) {
408 ret = gpio_request(NR_BUILTIN_GPIO, "camera"); 408 ret = gpio_request(NR_BUILTIN_GPIO, "camera");
409 if (!ret) { 409 if (!ret) {
410 gpio_bus_switch = NR_BUILTIN_GPIO; 410 gpio_bus_switch = NR_BUILTIN_GPIO;
411 gpio_direction_output(gpio_bus_switch, 0); 411 gpio_direction_output(gpio_bus_switch, 0);
412 } else 412 }
413 gpio_bus_switch = -EINVAL;
414 } 413 }
415 414
416 if (gpio_bus_switch > 0) 415 if (gpio_bus_switch >= 0)
417 return SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_10; 416 return SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_10;
418 else 417 else
419 return SOCAM_DATAWIDTH_10; 418 return SOCAM_DATAWIDTH_10;
420} 419}
421 420
421static void pcm990_camera_free_bus(struct soc_camera_link *link)
422{
423 if (gpio_bus_switch < 0)
424 return;
425
426 gpio_free(gpio_bus_switch);
427 gpio_bus_switch = -EINVAL;
428}
429
422static struct soc_camera_link iclink = { 430static struct soc_camera_link iclink = {
423 .bus_id = 0, /* Must match with the camera ID above */ 431 .bus_id = 0, /* Must match with the camera ID above */
424 .query_bus_param = pcm990_camera_query_bus_param, 432 .query_bus_param = pcm990_camera_query_bus_param,
425 .set_bus_param = pcm990_camera_set_bus_param, 433 .set_bus_param = pcm990_camera_set_bus_param,
434 .free_bus = pcm990_camera_free_bus,
426}; 435};
427 436
428/* Board I2C devices. */ 437/* 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:
604static void mt9m001_video_remove(struct soc_camera_device *icd) 604static void mt9m001_video_remove(struct soc_camera_device *icd)
605{ 605{
606 struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); 606 struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
607 struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
607 608
608 dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr, 609 dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr,
609 icd->dev.parent, icd->vdev); 610 icd->dev.parent, icd->vdev);
610 soc_camera_video_stop(icd); 611 soc_camera_video_stop(icd);
612 if (icl->free_bus)
613 icl->free_bus(icl);
611} 614}
612 615
613static int mt9m001_probe(struct i2c_client *client, 616static 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:
735static void mt9v022_video_remove(struct soc_camera_device *icd) 735static void mt9v022_video_remove(struct soc_camera_device *icd)
736{ 736{
737 struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); 737 struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
738 struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
738 739
739 dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr, 740 dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr,
740 icd->dev.parent, icd->vdev); 741 icd->dev.parent, icd->vdev);
741 soc_camera_video_stop(icd); 742 soc_camera_video_stop(icd);
743 if (icl->free_bus)
744 icl->free_bus(icl);
742} 745}
743 746
744static int mt9v022_probe(struct i2c_client *client, 747static 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 {
107 */ 107 */
108 int (*set_bus_param)(struct soc_camera_link *, unsigned long flags); 108 int (*set_bus_param)(struct soc_camera_link *, unsigned long flags);
109 unsigned long (*query_bus_param)(struct soc_camera_link *); 109 unsigned long (*query_bus_param)(struct soc_camera_link *);
110 void (*free_bus)(struct soc_camera_link *);
110}; 111};
111 112
112static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev) 113static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev)