From patchwork Wed Apr 15 12:17:26 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guennadi Liakhovetski X-Patchwork-Id: 18349 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n3FCHMFY014014 for ; Wed, 15 Apr 2009 12:17:23 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757945AbZDOMRW (ORCPT ); Wed, 15 Apr 2009 08:17:22 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1758731AbZDOMRW (ORCPT ); Wed, 15 Apr 2009 08:17:22 -0400 Received: from mail.gmx.net ([213.165.64.20]:60099 "HELO mail.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1757945AbZDOMRV (ORCPT ); Wed, 15 Apr 2009 08:17:21 -0400 Received: (qmail invoked by alias); 15 Apr 2009 12:17:19 -0000 Received: from p57BD1D49.dip0.t-ipconnect.de (EHLO axis700.grange) [87.189.29.73] by mail.gmx.net (mp069) with SMTP; 15 Apr 2009 14:17:19 +0200 X-Authenticated: #20450766 X-Provags-ID: V01U2FsdGVkX18NsrkGunMN4guXvA7OQ1DIXkz0FF2DK9syb04zDq Y2ZNfUZ6a0kOzS Received: from lyakh (helo=localhost) by axis700.grange with local-esmtp (Exim 4.63) (envelope-from ) id 1Lu43S-0001ww-B7; Wed, 15 Apr 2009 14:17:26 +0200 Date: Wed, 15 Apr 2009 14:17:26 +0200 (CEST) From: Guennadi Liakhovetski To: Linux Media Mailing List cc: Sascha Hauer , eric miao , Robert Jarzmik Subject: [PATCH 1/5] soc-camera: add a free_bus method to struct soc_camera_link In-Reply-To: Message-ID: References: MIME-Version: 1.0 X-Y-GMX-Trusted: 0 X-FuHaFi: 0.45 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org 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 Acked-by: Eric Miao --- Eric, need your ack for the arch/arm/mach-pxa part. Sascha's wouldn't hurt either:-) arch/arm/mach-pxa/pcm990-baseboard.c | 23 ++++++++++++++++------- drivers/media/video/mt9m001.c | 3 +++ drivers/media/video/mt9v022.c | 3 +++ include/media/soc_camera.h | 1 + 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 6c12b5a..9ce1ef2 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 684f62f..3838ff7 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 4d3b481..412b399 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 3701368..396c325 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)