From patchwork Thu Sep 27 14:07:25 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guennadi Liakhovetski X-Patchwork-Id: 1514431 Return-Path: X-Original-To: patchwork-linux-sh@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id B69BE40B2A for ; Thu, 27 Sep 2012 14:08:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753484Ab2I0OH6 (ORCPT ); Thu, 27 Sep 2012 10:07:58 -0400 Received: from moutng.kundenserver.de ([212.227.126.187]:52398 "EHLO moutng.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752619Ab2I0OHu (ORCPT ); Thu, 27 Sep 2012 10:07:50 -0400 Received: from axis700.grange (dslb-178-001-228-192.pools.arcor-ip.net [178.1.228.192]) by mrelayeu.kundenserver.de (node=mrbap0) with ESMTP (Nemesis) id 0MGXOi-1TCr1s2HSq-00DfIL; Thu, 27 Sep 2012 16:07:37 +0200 Received: from 6a.grange (6a.grange [192.168.1.11]) by axis700.grange (Postfix) with ESMTPS id AC0F1189B0F; Thu, 27 Sep 2012 16:07:34 +0200 (CEST) Received: from lyakh by 6a.grange with local (Exim 4.72) (envelope-from ) id 1THEkY-0007SK-82; Thu, 27 Sep 2012 16:07:34 +0200 From: Guennadi Liakhovetski To: linux-media@vger.kernel.org Cc: devicetree-discuss@lists.ozlabs.org, Sylwester Nawrocki , Laurent Pinchart , Hans Verkuil , Magnus Damm , linux-sh@vger.kernel.org, Mark Brown , Stephen Warren , Arnd Bergmann , Grant Likely Subject: [PATCH 06/14] media: soc-camera: prepare for asynchronous client probing Date: Thu, 27 Sep 2012 16:07:25 +0200 Message-Id: <1348754853-28619-7-git-send-email-g.liakhovetski@gmx.de> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1348754853-28619-1-git-send-email-g.liakhovetski@gmx.de> References: <1348754853-28619-1-git-send-email-g.liakhovetski@gmx.de> X-Provags-ID: V02:K0:cje5z7SkIGntQMO8EK27Jft7Ns4eUM1FhKXto4TyLlk b/r2aZ5LoRALZTTmbG5QmwD1pXByXPlSGJxmFwD2PD54/lAM2P 5tTeE21cwtYgcmTOvfEMN4VVWNAypJ/kM70vxEI2RsnfYIROUH owwOfx4jcoHVnBAKXsQEpsvowOWzz8KRMj+5TPXMogw09uV94F rFp2arzqxHVAGSuFC82hXpuiIoipc+eK0iZyHzdXJJcWio9dXX M3or26TGpC2VZNdGKwIwVWt3RDK5DLV4Fgs3mrk+lKU8OgmFXT 7qtv8A6cml2tThpgjzq+xj9tvkw6FB+GoXIYoPBQNSXcZpr7tH nsCrOHaWv2E243p/uBEAOAwKqHlzzG+t6EbxRUpjJpBcX0xdqI DeJqND5YfQVAQ== Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org Currently the soc-camera core uses the fact, that client's .probe() method is run inside of soc_camera_probe(). In such a case, the core can first attach the client to a host, then trigger client's probing, check its result and detach the client from the host to allow further clients to be probed and / or used with it. However, if a client probes at a different time, there is no way to know when to attach it to and when to detach it from the host. To solve this we allow the client to decide itself, when it hae to be attached and detached. Signed-off-by: Guennadi Liakhovetski --- drivers/media/i2c/soc_camera/mt9t112.c | 13 ++++- drivers/media/platform/soc_camera/soc_camera.c | 70 +++++++++++++++++++++--- include/media/soc_camera.h | 3 + 3 files changed, 75 insertions(+), 11 deletions(-) diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index de7cd83..dfa03f0 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -1036,17 +1036,22 @@ static struct v4l2_subdev_ops mt9t112_subdev_ops = { .video = &mt9t112_subdev_video_ops, }; -static int mt9t112_camera_probe(struct i2c_client *client) +static int mt9t112_camera_probe(struct i2c_client *client, + struct soc_camera_link *icl) { struct mt9t112_priv *priv = to_mt9t112(client); const char *devname; int chipid; int ret; - ret = mt9t112_s_power(&priv->subdev, 1); + ret = soc_camera_device_attach(icl); if (ret < 0) return ret; + ret = mt9t112_s_power(&priv->subdev, 1); + if (ret < 0) + goto detach; + /* * check and show chip ID */ @@ -1071,6 +1076,8 @@ static int mt9t112_camera_probe(struct i2c_client *client) done: mt9t112_s_power(&priv->subdev, 0); +detach: + soc_camera_device_detach(icl); return ret; } @@ -1100,7 +1107,7 @@ static int mt9t112_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); - ret = mt9t112_camera_probe(client); + ret = mt9t112_camera_probe(client, icl); if (ret) { kfree(priv); return ret; diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 2f31ca0..b98e602 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -50,6 +50,58 @@ static LIST_HEAD(hosts); static LIST_HEAD(devices); static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ +static struct soc_camera_device *soc_camera_device_find(struct soc_camera_link *icl) +{ + struct soc_camera_device *icd; + + mutex_lock(&list_lock); + + list_for_each_entry(icd, &devices, list) + if (icd->link == icl) + break; + + mutex_unlock(&list_lock); + + if (&icd->list == &devices) + return NULL; + + return icd; +} + +int soc_camera_device_attach(struct soc_camera_link *icl) +{ + struct soc_camera_device *icd = soc_camera_device_find(icl); + if (icd) { + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + bool must_lock = icd->vdev != NULL && video_is_registered(icd->vdev); + int ret; + + if (must_lock) + mutex_lock(&ici->host_lock); + /* device must be linked to a host by now */ + ret = ici->ops->add(icd); + if (must_lock) + mutex_unlock(&ici->host_lock); + return ret; + } + + return -ENODEV; +} +EXPORT_SYMBOL(soc_camera_device_attach); + +void soc_camera_device_detach(struct soc_camera_link *icl) +{ + struct soc_camera_device *icd = soc_camera_device_find(icl); + + if (icd) { + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + + /* device must be linked to a host by now */ + ici->ops->remove(icd); + } +} +EXPORT_SYMBOL(soc_camera_device_detach); + int soc_camera_power_on(struct device *dev, struct soc_camera_link *icl) { int ret = regulator_bulk_enable(icl->num_regulators, @@ -1142,10 +1194,6 @@ static int soc_camera_probe(struct soc_camera_device *icd) if (icl->reset) icl->reset(icd->pdev); - ret = ici->ops->add(icd); - if (ret < 0) - goto eadd; - /* Must have icd->vdev before registering the device */ ret = video_dev_create(icd); if (ret < 0) @@ -1206,6 +1254,9 @@ static int soc_camera_probe(struct soc_camera_device *icd) goto evidstart; /* Try to improve our guess of a reasonable window format */ + ret = ici->ops->add(icd); + if (ret < 0) + goto eadd; if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { icd->user_width = mf.width; icd->user_height = mf.height; @@ -1219,6 +1270,9 @@ static int soc_camera_probe(struct soc_camera_device *icd) return 0; +eadd: + video_unregister_device(icd->vdev); + icd->vdev = NULL; evidstart: mutex_unlock(&icd->video_lock); soc_camera_free_user_formats(icd); @@ -1232,11 +1286,11 @@ ectrl: } enodrv: eadddev: - video_device_release(icd->vdev); - icd->vdev = NULL; + if (icd->vdev) { + video_device_release(icd->vdev); + icd->vdev = NULL; + } evdc: - ici->ops->remove(icd); -eadd: regulator_bulk_free(icl->num_regulators, icl->regulators); ereg: v4l2_ctrl_handler_free(&icd->ctrl_handler); diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 6442edc..72342fe 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -259,6 +259,9 @@ unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, int soc_camera_power_on(struct device *dev, struct soc_camera_link *icl); int soc_camera_power_off(struct device *dev, struct soc_camera_link *icl); +int soc_camera_device_attach(struct soc_camera_link *icl); +void soc_camera_device_detach(struct soc_camera_link *icl); + static inline int soc_camera_set_power(struct device *dev, struct soc_camera_link *icl, bool on) {