From patchwork Fri Aug 9 19:24:04 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Sylwester Nawrocki/Kernel \\(PLT\\) /SRPOL/Staff Engineer/Samsung Electronics" X-Patchwork-Id: 2842104 Return-Path: X-Original-To: patchwork-linux-media@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 F04129F271 for ; Fri, 9 Aug 2013 19:26:37 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E63362039D for ; Fri, 9 Aug 2013 19:26:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D1BBE203C4 for ; Fri, 9 Aug 2013 19:26:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1030843Ab3HIT0c (ORCPT ); Fri, 9 Aug 2013 15:26:32 -0400 Received: from mailout2.samsung.com ([203.254.224.25]:24103 "EHLO mailout2.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1030765Ab3HITZW (ORCPT ); Fri, 9 Aug 2013 15:25:22 -0400 Received: from epcpsbgm1.samsung.com (epcpsbgm1 [203.254.230.26]) by mailout2.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MRA00BYO3A6OZ30@mailout2.samsung.com>; Sat, 10 Aug 2013 04:25:21 +0900 (KST) X-AuditID: cbfee61a-b7f196d000007dfa-0d-52054221e51c Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 29.E9.32250.12245025; Sat, 10 Aug 2013 04:25:21 +0900 (KST) Received: from amdc1344.digital.local ([106.116.147.32]) by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MRA006PU38GMW10@mmp1.samsung.com>; Sat, 10 Aug 2013 04:25:21 +0900 (KST) From: Sylwester Nawrocki To: linux-media@vger.kernel.org Cc: a.hajda@samsung.com, arun.kk@samsung.com, linux-samsung-soc@vger.kernel.org, Sylwester Nawrocki , Kyungmin Park Subject: [PATCH 02/10] V4L: s5k6a3: Add support for asynchronous subdev registration Date: Fri, 09 Aug 2013 21:24:04 +0200 Message-id: <1376076252-30150-2-git-send-email-s.nawrocki@samsung.com> X-Mailer: git-send-email 1.7.9.5 In-reply-to: <1376076252-30150-1-git-send-email-s.nawrocki@samsung.com> References: <1376076122-29963-1-git-send-email-s.nawrocki@samsung.com> <1376076252-30150-1-git-send-email-s.nawrocki@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrPJMWRmVeSWpSXmKPExsVy+t9jAV1FJ9Ygg+YlQha31p1jtfh46jar xdmmN+wWPRu2slrMOL+PyeLwm3ZWBzaPvi2rGD0+b5ILYIrisklJzcksSy3St0vgyji89RN7 wV6liiWrUhoYH0p3MXJySAiYSPz+PZEVwhaTuHBvPVsXIxeHkMAiRokP675BOR1MEkeW3mMB qWITMJToPdrHCGKLCMhLPOm9AVbELLCWUWLx1ydsIAlhgTCJX5dfMYPYLAKqErv2TQBbwSvg JvHtxwz2LkYOoHUKEnMm2YCEOQXcJSY9mg3WKiTQzCjx5oPyBEbeBYwMqxhFUwuSC4qT0nMN 9YoTc4tL89L1kvNzNzGCg+WZ1A7GlQ0WhxgFOBiVeHgn/GIJEmJNLCuuzD3EKMHBrCTC+5qL NUiINyWxsiq1KD++qDQntfgQozQHi5I474FW60AhgfTEktTs1NSC1CKYLBMHp1QDY/IaR5t3 LpsF+8PXxW8Xvxewr+HQlG3Plzgudz3N5mE26U3ziSXhXn/qnwfP0T53n0V1Tkzi3F/lR7nP H1x2cNr81PONwVOkLpQqZPttaG11NdHglmK7XbR01iWpGZ/LO77JxUpsXdt6bZd0p5r3Au4+ mYetu39GnZkzQ9XN99ve8qQ9U38s2KrEUpyRaKjFXFScCAA27jCTEgIAAA== Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable 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 This patch converts the driver to use v4l2 asynchronous subdev registration API an the common clock API. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Changes since v1: - clock-frequency property is now optional and a default frequency value will be used when it is missing, rather than bailing out. --- drivers/media/i2c/s5k6a3.c | 63 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index 0817664..d396cfe 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c @@ -34,6 +34,8 @@ #define S5K6A3_DEFAULT_HEIGHT 732 #define S5K6A3_DRV_NAME "S5K6A3" +#define S5K6A3_CLK_NAME "mclk" +#define S5K6A3_DEFAULT_CLK_FREQ 24000000U #define S5K6A3_NUM_SUPPLIES 2 @@ -55,6 +57,7 @@ struct s5k6a3 { int gpio_reset; struct mutex lock; struct v4l2_mbus_framefmt format; + struct clk *clock; u32 clock_frequency; }; @@ -180,19 +183,29 @@ static int s5k6a3_s_power(struct v4l2_subdev *sd, int on) { struct s5k6a3 *sensor = sd_to_s5k6a3(sd); int gpio = sensor->gpio_reset; - int ret; + int ret = 0; if (on) { + sensor->clock = clk_get(sensor->dev, S5K6A3_CLK_NAME); + if (IS_ERR(sensor->clock)) + return PTR_ERR(sensor->clock); + + ret = clk_set_rate(sensor->clock, sensor->clock_frequency); + if (ret < 0) + goto clk_put; + ret = pm_runtime_get(sensor->dev); if (ret < 0) - return ret; + goto clk_put; ret = regulator_bulk_enable(S5K6A3_NUM_SUPPLIES, sensor->supplies); - if (ret < 0) { - pm_runtime_put(sensor->dev); - return ret; - } + if (ret < 0) + goto rpm_put; + + ret = clk_prepare_enable(sensor->clock); + if (ret < 0) + goto reg_dis; if (gpio_is_valid(gpio)) { gpio_set_value(gpio, 1); @@ -208,10 +221,14 @@ static int s5k6a3_s_power(struct v4l2_subdev *sd, int on) if (gpio_is_valid(gpio)) gpio_set_value(gpio, 0); - ret = regulator_bulk_disable(S5K6A3_NUM_SUPPLIES, - sensor->supplies); - if (!ret) - pm_runtime_put(sensor->dev); + clk_disable_unprepare(sensor->clock); +reg_dis: + regulator_bulk_disable(S5K6A3_NUM_SUPPLIES, + sensor->supplies); +rpm_put: + pm_runtime_put(sensor->dev); +clk_put: + clk_put(sensor->clock); } return ret; } @@ -239,6 +256,7 @@ static int s5k6a3_probe(struct i2c_client *client, mutex_init(&sensor->lock); sensor->gpio_reset = -EINVAL; + sensor->clock = ERR_PTR(-EINVAL); sensor->dev = dev; gpio = of_get_gpio_flags(dev->of_node, 0, NULL); @@ -250,6 +268,13 @@ static int s5k6a3_probe(struct i2c_client *client, } sensor->gpio_reset = gpio; + if (of_property_read_u32(dev->of_node, "clock-frequency", + &sensor->clock_frequency)) { + sensor->clock_frequency = S5K6A3_DEFAULT_CLK_FREQ; + dev_info(dev, "using default %u Hz clock frequency\n", + sensor->clock_frequency); + } + for (i = 0; i < S5K6A3_NUM_SUPPLIES; i++) sensor->supplies[i].supply = s5k6a3_supply_names[i]; @@ -258,6 +283,11 @@ static int s5k6a3_probe(struct i2c_client *client, if (ret < 0) return ret; + /* Defer probing if the clock is not available yet */ + sensor->clock = clk_get(dev, S5K6A3_CLK_NAME); + if (IS_ERR(sensor->clock)) + return -EPROBE_DEFER; + sd = &sensor->subdev; v4l2_i2c_subdev_init(sd, client, &s5k6a3_subdev_ops); sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; @@ -274,7 +304,17 @@ static int s5k6a3_probe(struct i2c_client *client, pm_runtime_no_callbacks(dev); pm_runtime_enable(dev); - return 0; + ret = v4l2_async_register_subdev(sd); + + /* + * Don't hold reference to the clock to avoid circular dependency + * between the subdev and the host driver, in case the host is + * a supplier of the clock. + * clk_get()/clk_put() will be called in s_power callback. + */ + clk_put(sensor->clock); + + return ret; } static int s5k6a3_remove(struct i2c_client *client) @@ -282,6 +322,7 @@ static int s5k6a3_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); pm_runtime_disable(&client->dev); + v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); return 0; }