From patchwork Sun Jun 15 19:56:32 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Dooks X-Patchwork-Id: 24387 X-Patchwork-Delegate: g.liakhovetski@gmx.de Received: from mail.tu-berlin.de ([130.149.7.33]) by www.linuxtv.org with esmtp (Exim 4.72) (envelope-from ) id 1WwGYC-0004G4-Mt; Sun, 15 Jun 2014 21:57:12 +0200 X-tubIT-Incoming-IP: 209.132.180.67 Received: from vger.kernel.org ([209.132.180.67]) by mail.tu-berlin.de (exim-4.72/mailfrontend-7) with esmtp id 1WwGYA-0000c0-1p; Sun, 15 Jun 2014 21:57:12 +0200 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752094AbaFOT5G (ORCPT + 1 other); Sun, 15 Jun 2014 15:57:06 -0400 Received: from ducie-dc1.codethink.co.uk ([185.25.241.215]:38741 "EHLO ducie-dc1.codethink.co.uk" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1752073AbaFOT5E (ORCPT ); Sun, 15 Jun 2014 15:57:04 -0400 Received: from localhost (localhost [127.0.0.1]) by ducie-dc1.codethink.co.uk (Postfix) with ESMTP id 45943478737; Sun, 15 Jun 2014 20:57:03 +0100 (BST) X-Virus-Scanned: Debian amavisd-new at ducie-dc1.codethink.co.uk Received: from ducie-dc1.codethink.co.uk ([127.0.0.1]) by localhost (ducie-dc1.codethink.co.uk [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id xaa4Se76Yw7j; Sun, 15 Jun 2014 20:56:57 +0100 (BST) Received: from rainbowdash.ducie.codethink.co.uk (rainbowdash.dyn.ducie.codethink.co.uk [10.24.1.179]) by ducie-dc1.codethink.co.uk (Postfix) with ESMTPS id 0D46C47870B; Sun, 15 Jun 2014 20:56:37 +0100 (BST) Received: from ben by rainbowdash.ducie.codethink.co.uk with local (Exim 4.82_1-5b7a7c0-XX) (envelope-from ) id 1WwGXc-0004dP-NN; Sun, 15 Jun 2014 20:56:36 +0100 From: Ben Dooks To: linux-kernel@lists.codethink.co.uk, linux-sh@vger.kernel.org, linux-media@vger.kernel.org Cc: robert.jarzmik@free.fr, g.liakhovetski@gmx.de, magnus.damm@opensource.se, horms@verge.net.au, ian.molton@codethink.co.uk, william.towle@codethink.co.uk, Ben Dooks Subject: [PATCH 7/9] soc_camera: add support for dt binding soc_camera drivers Date: Sun, 15 Jun 2014 20:56:32 +0100 Message-Id: <1402862194-17743-8-git-send-email-ben.dooks@codethink.co.uk> X-Mailer: git-send-email 2.0.0 In-Reply-To: <1402862194-17743-1-git-send-email-ben.dooks@codethink.co.uk> References: <1402862194-17743-1-git-send-email-ben.dooks@codethink.co.uk> Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-PMX-Version: 6.0.0.2142326, Antispam-Engine: 2.7.2.2107409, Antispam-Data: 2014.6.15.194519 X-PMX-Spam: Gauge=IIIIIIII, Probability=8%, Report=' MULTIPLE_RCPTS 0.1, HTML_00_01 0.05, HTML_00_10 0.05, BODY_SIZE_4000_4999 0, BODY_SIZE_5000_LESS 0, BODY_SIZE_7000_LESS 0, URI_ENDS_IN_HTML 0, __ANY_URI 0, __CP_URI_IN_BODY 0, __HAS_FROM 0, __HAS_MSGID 0, __HAS_X_MAILER 0, __HAS_X_MAILING_LIST 0, __IN_REP_TO 0, __MIME_TEXT_ONLY 0, __MULTIPLE_RCPTS_CC_X2 0, __SANE_MSGID 0, __STOCK_PHRASE_7 0, __SUBJ_ALPHA_END 0, __TO_MALFORMED_2 0, __TO_NO_NAME 0, __URI_NO_WWW 0, __URI_NS ' Add initial support for OF based soc-camera devices that may be used by any of the soc-camera drivers. The driver itself will need converting to use OF. These changes allow the soc-camera driver to do the connecting of any async capable v4l2 device to the soc-camera driver. This has currently been tested on the Renesas Lager board. It currently only supports one input device per driver as this seems to be the standard connection for these devices. Signed-off-by: Ben Dooks --- Fixes since v1: - Fix i2c mclk name compatible with other drivers - Ensure of_node is put after use --- drivers/media/platform/soc_camera/soc_camera.c | 120 ++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 7fec8cd..eda67d7 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -1581,6 +1582,121 @@ static void scan_async_host(struct soc_camera_host *ici) #define scan_async_host(ici) do {} while (0) #endif +#ifdef CONFIG_OF +static int soc_of_bind(struct soc_camera_host *ici, + struct device_node *ep, + struct device_node *remote) +{ + struct soc_camera_device *icd; + struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,}; + struct soc_camera_async_client *sasc; + struct soc_camera_async_subdev *sasd; + struct v4l2_async_subdev **asd_array; + struct i2c_client *client; + char clk_name[V4L2_SUBDEV_NAME_SIZE]; + int ret; + + /* allocate a new subdev and add match info to it */ + sasd = devm_kzalloc(ici->v4l2_dev.dev, sizeof(*sasd), GFP_KERNEL); + if (!sasd) + return -ENOMEM; + + asd_array = devm_kzalloc(ici->v4l2_dev.dev, + sizeof(struct v4l2_async_subdev **), + GFP_KERNEL); + if (!asd_array) + return -ENOMEM; + + sasd->asd.match.of.node = remote; + sasd->asd.match_type = V4L2_ASYNC_MATCH_OF; + asd_array[0] = &sasd->asd; + + /* Or shall this be managed by the soc-camera device? */ + sasc = devm_kzalloc(ici->v4l2_dev.dev, sizeof(*sasc), GFP_KERNEL); + if (!sasc) + return -ENOMEM; + + /* HACK: just need a != NULL */ + sdesc.host_desc.board_info = ERR_PTR(-ENODATA); + + ret = soc_camera_dyn_pdev(&sdesc, sasc); + if (ret < 0) + return ret; + + sasc->sensor = &sasd->asd; + + icd = soc_camera_add_pdev(sasc); + if (!icd) { + platform_device_put(sasc->pdev); + return -ENOMEM; + } + + sasc->notifier.subdevs = asd_array; + sasc->notifier.num_subdevs = 1; + sasc->notifier.bound = soc_camera_async_bound; + sasc->notifier.unbind = soc_camera_async_unbind; + sasc->notifier.complete = soc_camera_async_complete; + + icd->sasc = sasc; + icd->parent = ici->v4l2_dev.dev; + + client = of_find_i2c_device_by_node(remote); + + if (client) + snprintf(clk_name, sizeof(clk_name), "%d-%04x", + client->adapter->nr, client->addr); + else + snprintf(clk_name, sizeof(clk_name), "of-%s", + of_node_full_name(remote)); + + icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd); + if (IS_ERR(icd->clk)) { + ret = PTR_ERR(icd->clk); + goto eclkreg; + } + + ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier); + if (!ret) + return 0; + +eclkreg: + icd->clk = NULL; + platform_device_unregister(sasc->pdev); + dev_err(ici->v4l2_dev.dev, "group probe failed: %d\n", ret); + + return ret; +} + +static inline void scan_of_host(struct soc_camera_host *ici) +{ + struct device_node *np = ici->v4l2_dev.dev->of_node; + struct device_node *epn = NULL; + struct device_node *ren; + + while (true) { + epn = of_graph_get_next_endpoint(np, epn); + if (!epn) + break; + + ren = of_graph_get_remote_port(epn); + if (!ren) { + pr_info("%s: no remote for %s\n", + __func__, of_node_full_name(epn)); + continue; + } + + /* so we now have a remote node to connect */ + soc_of_bind(ici, epn, ren->parent); + + of_node_put(epn); + of_node_put(ren); + } +} + +#else +static inline void scan_of_host(struct soc_camera_host *ici) { } +#endif + /* Called during host-driver probe */ static int soc_camera_probe(struct soc_camera_host *ici, struct soc_camera_device *icd) @@ -1832,7 +1948,9 @@ int soc_camera_host_register(struct soc_camera_host *ici) mutex_init(&ici->host_lock); mutex_init(&ici->clk_lock); - if (ici->asd_sizes) + if (ici->v4l2_dev.dev->of_node) + scan_of_host(ici); + else if (ici->asd_sizes) /* * No OF, host with a list of subdevices. Don't try to mix * modes by initialising some groups statically and some