From patchwork Wed Mar 2 12:04:07 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shubhrajyoti Datta X-Patchwork-Id: 590964 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 98716140BEA for ; Wed, 2 Mar 2016 23:04:21 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754483AbcCBMEV (ORCPT ); Wed, 2 Mar 2016 07:04:21 -0500 Received: from mail-bl2nam02on0076.outbound.protection.outlook.com ([104.47.38.76]:65216 "EHLO NAM02-BL2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753876AbcCBMEU (ORCPT ); Wed, 2 Mar 2016 07:04:20 -0500 Received: from CY1NAM02FT064.eop-nam02.prod.protection.outlook.com (10.152.74.55) by CY1NAM02HT137.eop-nam02.prod.protection.outlook.com (10.152.75.232) with Microsoft SMTP Server (TLS) id 15.1.422.5; Wed, 2 Mar 2016 12:04:17 +0000 Authentication-Results: spf=pass (sender IP is 149.199.60.83) smtp.mailfrom=xilinx.com; the-dreams.de; dkim=none (message not signed) header.d=none;the-dreams.de; dmarc=bestguesspass action=none header.from=xilinx.com; Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.60.83 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.60.83; helo=xsj-pvapsmtpgw01; Received: from xsj-pvapsmtpgw01 (149.199.60.83) by CY1NAM02FT064.mail.protection.outlook.com (10.152.74.64) with Microsoft SMTP Server (TLS) id 15.1.427.7 via Frontend Transport; Wed, 2 Mar 2016 12:04:17 +0000 Received: from unknown-38-66.xilinx.com ([149.199.38.66] helo=xsj-pvapsmtp01) by xsj-pvapsmtpgw01 with esmtp (Exim 4.63) (envelope-from ) id 1ab5Vo-00031b-J0; Wed, 02 Mar 2016 04:04:16 -0800 Received: from [127.0.0.1] (helo=localhost) by xsj-pvapsmtp01 with smtp (Exim 4.63) (envelope-from ) id 1ab5Vo-00087T-FH; Wed, 02 Mar 2016 04:04:16 -0800 Received: from [172.23.146.171] (helo=xhdl3763.xilinx.com) by xsj-pvapsmtp01 with esmtp (Exim 4.63) (envelope-from ) id 1ab5Vl-000866-9A; Wed, 02 Mar 2016 04:04:13 -0800 Received: by xhdl3763.xilinx.com (Postfix, from userid 9049) id 77EE92CE0511; Wed, 2 Mar 2016 17:34:12 +0530 (IST) From: Shubhrajyoti Datta To: CC: , , Shubhrajyoti Datta Subject: [PATCHv2 2/2] i2c: xiic: Implement Power management Date: Wed, 2 Mar 2016 17:34:07 +0530 Message-ID: <1456920247-37291-2-git-send-email-shubhraj@xilinx.com> X-Mailer: git-send-email 2.1.2 In-Reply-To: <1456920247-37291-1-git-send-email-shubhraj@xilinx.com> References: <1456920247-37291-1-git-send-email-shubhraj@xilinx.com> X-TM-AS-Product-Ver: IMSS-7.1.0.1224-8.0.0.1202-22166.006 X-TM-AS-User-Approved-Sender: Yes;Yes X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:149.199.60.83; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(2980300002)(438002)(199003)(189002)(5003940100001)(52956003)(48376002)(11100500001)(42186005)(2906002)(2950100001)(36756003)(189998001)(86362001)(4326007)(87936001)(2351001)(110136002)(107886002)(33646002)(36386004)(92566002)(63266004)(106466001)(229853001)(50466002)(6806005)(4001430100002)(103686003)(50226001)(50986999)(1096002)(5001960100004)(45336002)(47776003)(1220700001)(19580405001)(76176999)(46386002)(5008740100001)(586003)(81156009)(90966002)(19580395003)(107986001); DIR:OUT; SFP:1101; SCL:1; SRVR:CY1NAM02HT137; H:xsj-pvapsmtpgw01; FPR:; SPF:Pass; MLV:sfv; A:1; MX:1; LANG:en; MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: a57d5e38-ff3e-4a4f-e238-08d34292c7d1 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(8251501002); SRVR:CY1NAM02HT137; X-Microsoft-Antispam-PRVS: <6e6d7cb20f8f47f79c3c21001c029bf7@CY1NAM02HT137.eop-nam02.prod.protection.outlook.com> X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(5005006)(13018025)(13017025)(8121501046)(13015025)(13023025)(13024025)(3002001)(10201501046); SRVR:CY1NAM02HT137; BCL:0; PCL:0; RULEID:; SRVR:CY1NAM02HT137; X-Forefront-PRVS: 086943A159 X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 02 Mar 2016 12:04:17.1795 (UTC) X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c; Ip=[149.199.60.83]; Helo=[xsj-pvapsmtpgw01] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY1NAM02HT137 Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org Enable power management. This patch enables the clocks before transfer and disables after the transfer. Signed-off-by: Shubhrajyoti Datta --- drivers/i2c/busses/i2c-xiic.c | 88 +++++++++++++++++++++++++++++++++++++--- 1 files changed, 81 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 6efd200..74f54f2 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #define DRIVER_NAME "xiic-i2c" @@ -66,6 +68,7 @@ enum xiic_endian { * @endianness: big/little-endian byte order */ struct xiic_i2c { + struct device *dev; void __iomem *base; wait_queue_head_t wait; struct i2c_adapter adap; @@ -77,6 +80,7 @@ struct xiic_i2c { struct i2c_msg *rx_msg; int rx_pos; enum xiic_endian endianness; + struct clk *clk; }; @@ -164,6 +168,7 @@ struct xiic_i2c { #define XIIC_RESET_MASK 0xAUL +#define XIIC_PM_TIMEOUT 1000 /* ms */ /* * The following constant is used for the device global interrupt enable * register, to enable all interrupts for the device, this is the only bit @@ -676,9 +681,13 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) dev_dbg(adap->dev.parent, "%s entry SR: 0x%x\n", __func__, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET)); + err = pm_runtime_get_sync(i2c->dev); + if (err < 0) + return err; + err = xiic_busy(i2c); if (err) - return err; + goto out; i2c->tx_msg = msgs; i2c->nmsgs = num; @@ -686,14 +695,20 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) xiic_start_xfer(i2c); if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || - (i2c->state == STATE_DONE), HZ)) - return (i2c->state == STATE_DONE) ? num : -EIO; - else { + (i2c->state == STATE_DONE), HZ)) { + err = (i2c->state == STATE_DONE) ? num : -EIO; + goto out; + } else { i2c->tx_msg = NULL; i2c->rx_msg = NULL; i2c->nmsgs = 0; - return -ETIMEDOUT; + err = -ETIMEDOUT; + goto out; } +out: + pm_runtime_mark_last_busy(i2c->dev); + pm_runtime_put_autosuspend(i2c->dev); + return err; } static u32 xiic_func(struct i2c_adapter *adap) @@ -748,13 +763,28 @@ static int xiic_i2c_probe(struct platform_device *pdev) mutex_init(&i2c->lock); init_waitqueue_head(&i2c->wait); + i2c->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c->clk)) { + dev_err(&pdev->dev, "input clock not found.\n"); + return PTR_ERR(i2c->clk); + } + ret = clk_prepare_enable(i2c->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable clock.\n"); + return ret; + } + i2c->dev = &pdev->dev; + pm_runtime_enable(i2c->dev); + pm_runtime_set_autosuspend_delay(i2c->dev, XIIC_PM_TIMEOUT); + pm_runtime_use_autosuspend(i2c->dev); + pm_runtime_set_active(i2c->dev); ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr, xiic_process, IRQF_ONESHOT, pdev->name, i2c); if (ret < 0) { dev_err(&pdev->dev, "Cannot claim IRQ\n"); - return ret; + goto err_clk_dis; } /* @@ -776,7 +806,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Failed to add adapter\n"); xiic_deinit(i2c); - return ret; + goto err_clk_dis; } if (pdata) { @@ -786,16 +816,30 @@ static int xiic_i2c_probe(struct platform_device *pdev) } return 0; + +err_clk_dis: + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_disable(&pdev->dev); + clk_disable_unprepare(i2c->clk); + return ret; } static int xiic_i2c_remove(struct platform_device *pdev) { struct xiic_i2c *i2c = platform_get_drvdata(pdev); + int ret; /* remove adapter & data */ i2c_del_adapter(&i2c->adap); + ret = clk_prepare_enable(i2c->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable clock.\n"); + return ret; + } xiic_deinit(i2c); + clk_disable_unprepare(i2c->clk); + pm_runtime_disable(&pdev->dev); return 0; } @@ -808,12 +852,42 @@ static const struct of_device_id xiic_of_match[] = { MODULE_DEVICE_TABLE(of, xiic_of_match); #endif +static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xiic_i2c *i2c = platform_get_drvdata(pdev); + + clk_disable(i2c->clk); + + return 0; +} + +static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xiic_i2c *i2c = platform_get_drvdata(pdev); + int ret; + + ret = clk_enable(i2c->clk); + if (ret) { + dev_err(dev, "Cannot enable clock.\n"); + return ret; + } + + return 0; +} + +static const struct dev_pm_ops xiic_dev_pm_ops = { + SET_RUNTIME_PM_OPS(cdns_i2c_runtime_suspend, + cdns_i2c_runtime_resume, NULL) +}; static struct platform_driver xiic_i2c_driver = { .probe = xiic_i2c_probe, .remove = xiic_i2c_remove, .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(xiic_of_match), + .pm = &xiic_dev_pm_ops, }, };