From patchwork Mon Apr 14 10:36:42 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Dooks X-Patchwork-Id: 3979331 Return-Path: X-Original-To: patchwork-linux-sh@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id E529D9F2BA for ; Mon, 14 Apr 2014 10:37:16 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E532A201ED for ; Mon, 14 Apr 2014 10:37:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E841720148 for ; Mon, 14 Apr 2014 10:37:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753004AbaDNKhO (ORCPT ); Mon, 14 Apr 2014 06:37:14 -0400 Received: from ducie-dc1.codethink.co.uk ([185.25.241.215]:33659 "EHLO ducie-dc1.codethink.co.uk" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1752322AbaDNKhN (ORCPT ); Mon, 14 Apr 2014 06:37:13 -0400 Received: from localhost (localhost [127.0.0.1]) by ducie-dc1.codethink.co.uk (Postfix) with ESMTP id D2DE7468094; Mon, 14 Apr 2014 11:37:12 +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 ClqXyPZPiMAp; Mon, 14 Apr 2014 11:37:07 +0100 (BST) Received: from rainbowdash.ducie.codethink.co.uk (rainbowdash.dyn.ducie.codethink.co.uk [10.24.1.133]) by ducie-dc1.codethink.co.uk (Postfix) with ESMTPS id 81CC04671B6; Mon, 14 Apr 2014 11:36:45 +0100 (BST) Received: from ben by rainbowdash.ducie.codethink.co.uk with local (Exim 4.82) (envelope-from ) id 1WZeFp-00076M-5P; Mon, 14 Apr 2014 11:36:45 +0100 From: Ben Dooks To: linux-sh@vger.kernel.org, linux-kernel@lists.codethink.co.uk Cc: g.liakhovetski@gmx.de, josh.wu@atmel.com, cooloney@gmail.com, laurent.pinchart@ideasonboard.com, magnus.damm@opensource.se, ian.molton@codethink.co.uk, Ben Dooks Subject: [PATCH v3 7/7] soc_camera: initial of code Date: Mon, 14 Apr 2014 11:36:42 +0100 Message-Id: <1397471802-27216-8-git-send-email-ben.dooks@codethink.co.uk> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1397471802-27216-1-git-send-email-ben.dooks@codethink.co.uk> References: <1397471802-27216-1-git-send-email-ben.dooks@codethink.co.uk> Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Spam-Status: No, score=-7.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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. Signed-off-by: Ben Dooks Tested-by: Josh Wu --- Changes since v1: - Updated to make the i2c mclk name compatible with other drivers. The issue of having mclk which is not part of the drivers/clk interface is something that can be dealt with separately. --- drivers/media/platform/soc_camera/soc_camera.c | 117 ++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 4b8c024..c50ec5c 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 @@ -1579,6 +1580,118 @@ 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; + + /* alloacte 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 = v4l2_of_get_next_endpoint(np, epn); + if (!epn) + break; + + ren = v4l2_of_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); + } +} + +#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) @@ -1830,7 +1943,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