From patchwork Mon Feb 17 15:20:41 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 3663431 Return-Path: X-Original-To: patchwork-linux-arm@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 6BABF9F1EE for ; Mon, 17 Feb 2014 15:22:15 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2A5C6200FE for ; Mon, 17 Feb 2014 15:22:14 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C7716200D0 for ; Mon, 17 Feb 2014 15:22:12 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WFQ0b-00016U-My; Mon, 17 Feb 2014 15:21:25 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WFQ0R-00018n-Qh; Mon, 17 Feb 2014 15:21:15 +0000 Received: from mail-lb0-f178.google.com ([209.85.217.178]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WFQ0N-000173-GL for linux-arm-kernel@lists.infradead.org; Mon, 17 Feb 2014 15:21:12 +0000 Received: by mail-lb0-f178.google.com with SMTP id u14so11157375lbd.23 for ; Mon, 17 Feb 2014 07:20:46 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=bQVwiD4bPEvoBY2g+Cwn4ntGfDITKVuZP74LOG/MrN8=; b=eD1qmFeR4M/1G6dmz+dFYtxa5aa2O4P7fGBg2RZKTXJYAp539LHdm2e/BFOWnnBRx0 rRviRQc2nr8H3DFYjnI6Mg7wZ8yF3WqvYk0zG46sc4h7PNyqGq3GdqA3+QhZQ0LSUodd JJ0ogREKxYP8rl8qD1VXS9OiQjfT3/ONFpNu3ZCoJPFwCqfIypf3n6AsWc+bWGHsCsR1 Po6lqNvatrrzHScN2YV9o+5kGaa9YWIOg+WOl2zRtXRFeZ09XgcYEFO0upW4H9bRgLxk i1DjI4VGHX0R7VDTCSLD6QNmAQ2p70ReV4c6j0ppMRk67m13hTKG2VDPKeBMnF8hnN4+ gPbA== X-Gm-Message-State: ALoCoQkSYdO/gB2hOxiJ3YcwCpUkOrQ3GICLa2iVe7x+I1OLnJvMAOHAYI6dHRhmK1mO8ZH90EnU X-Received: by 10.112.142.100 with SMTP id rv4mr14595lbb.78.1392650446075; Mon, 17 Feb 2014 07:20:46 -0800 (PST) Received: from linaro-ulf.lan (90-231-160-185-no158.tbcn.telia.com. [90.231.160.185]) by mx.google.com with ESMTPSA id e1sm26240692laa.8.2014.02.17.07.20.44 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 17 Feb 2014 07:20:45 -0800 (PST) From: Ulf Hansson To: Alessandro Rubini , Linus Walleij , Wolfram Sang , linux-i2c@vger.kernel.org Subject: [PATCH V3 14/17] i2c: nomadik: Fixup deployment of runtime PM Date: Mon, 17 Feb 2014 16:20:41 +0100 Message-Id: <1392650441-14890-1-git-send-email-ulf.hansson@linaro.org> X-Mailer: git-send-email 1.7.9.5 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140217_102111_882020_36230EBC X-CRM114-Status: GOOD ( 17.19 ) X-Spam-Score: -2.6 (--) Cc: Ulf Hansson , Mark Brown , Russell King , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.8 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, 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 Since the runtime PM state is expected to be active according to the amba bus, we must align our behaviour while probing to it. Moreover, this is needed to be able to have the driver fully functional without depending on CONFIG_RUNTIME_PM. Since the device is active while a successful probe has been completed, the reference counting for the clock will be screwed up and never reach zero. We resolve this by implementing runtime PM callbacks and let them handle the resources accordingly, including the clock. Cc: Alessandro Rubini Cc: Linus Walleij Cc: Wolfram Sang Signed-off-by: Ulf Hansson --- drivers/i2c/busses/i2c-nomadik.c | 77 +++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 26 deletions(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 5fdfc97..3e08ba1 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -666,7 +666,7 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num_msgs) { - int status; + int status = 0; int i; struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); int j; @@ -675,19 +675,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, pm_runtime_get_sync(&dev->adev->dev); - status = clk_prepare_enable(dev->clk); - if (status) { - dev_err(&dev->adev->dev, "can't prepare_enable clock\n"); - goto out_clk; - } - - /* Optionaly enable pins to be muxed in and configured */ - pinctrl_pm_select_default_state(&dev->adev->dev); - - status = init_hw(dev); - if (status) - goto out; - /* Attempt three times to send the message queue */ for (j = 0; j < 3; j++) { /* setup the i2c controller */ @@ -708,12 +695,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, break; } -out: - clk_disable_unprepare(dev->clk); -out_clk: - /* Optionally let pins go into idle state */ - pinctrl_pm_select_idle_state(&dev->adev->dev); - pm_runtime_put_sync(&dev->adev->dev); dev->busy = false; @@ -930,6 +911,41 @@ static int nmk_i2c_resume(struct device *dev) #define nmk_i2c_resume NULL #endif +#if CONFIG_PM +static int nmk_i2c_runtime_suspend(struct device *dev) +{ + struct amba_device *adev = to_amba_device(dev); + struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev); + + clk_disable_unprepare(nmk_i2c->clk); + pinctrl_pm_select_idle_state(dev); + return 0; +} + +static int nmk_i2c_runtime_resume(struct device *dev) +{ + struct amba_device *adev = to_amba_device(dev); + struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev); + int ret; + + ret = clk_prepare_enable(nmk_i2c->clk); + if (ret) { + dev_err(dev, "can't prepare_enable clock\n"); + return ret; + } + + pinctrl_pm_select_default_state(dev); + + ret = init_hw(nmk_i2c); + if (ret) { + clk_disable_unprepare(nmk_i2c->clk); + pinctrl_pm_select_idle_state(dev); + } + + return ret; +} +#endif + /* * We use noirq so that we suspend late and resume before the wakeup interrupt * to ensure that we do the !pm_runtime_suspended() check in resume before @@ -938,6 +954,9 @@ static int nmk_i2c_resume(struct device *dev) static const struct dev_pm_ops nmk_i2c_pm = { .suspend_noirq = nmk_i2c_suspend, .resume_noirq = nmk_i2c_resume, + SET_PM_RUNTIME_PM_OPS(nmk_i2c_runtime_suspend, + nmk_i2c_runtime_resume, + NULL) }; static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap) @@ -1006,11 +1025,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) amba_set_drvdata(adev, dev); - /* Select default pin state */ - pinctrl_pm_select_default_state(&adev->dev); - /* If possible, let's go to idle until the first transfer */ - pinctrl_pm_select_idle_state(&adev->dev); - dev->virtbase = devm_ioremap(&adev->dev, adev->res.start, resource_size(&adev->res)); if (IS_ERR(dev->virtbase)) { @@ -1035,6 +1049,14 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) goto err_no_mem; } + ret = clk_prepare_enable(dev->clk); + if (ret) { + dev_err(&adev->dev, "can't prepare_enable clock\n"); + goto err_no_mem; + } + + init_hw(dev); + adap = &dev->adap; adap->dev.of_node = np; adap->dev.parent = &adev->dev; @@ -1054,13 +1076,15 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) ret = i2c_add_adapter(adap); if (ret) { dev_err(&adev->dev, "failed to add adapter\n"); - goto err_no_mem; + goto err_no_adap; } pm_runtime_put(&adev->dev); return 0; + err_no_adap: + clk_disable_unprepare(dev->clk); err_no_mem: return ret; @@ -1077,6 +1101,7 @@ static int nmk_i2c_remove(struct amba_device *adev) clear_all_interrupts(dev); /* disable the controller */ i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE); + clk_disable_unprepare(dev->clk); if (res) release_mem_region(res->start, resource_size(res));