From patchwork Sun Mar 27 20:32:43 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amit Daniel Kachhap X-Patchwork-Id: 801 Return-Path: Delivered-To: unknown Received: from imap.gmail.com (74.125.159.109) by localhost6.localdomain6 with IMAP4-SSL; 08 Jun 2011 14:45:58 -0000 Delivered-To: patches@linaro.org Received: by 10.42.161.68 with SMTP id s4cs16140icx; Sun, 27 Mar 2011 04:03:11 -0700 (PDT) Received: by 10.204.10.81 with SMTP id o17mr2526150bko.94.1301223790682; Sun, 27 Mar 2011 04:03:10 -0700 (PDT) Received: from mail-fx0-f50.google.com (mail-fx0-f50.google.com [209.85.161.50]) by mx.google.com with ESMTPS id f19si803849bkf.17.2011.03.27.04.03.01 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 27 Mar 2011 04:03:09 -0700 (PDT) Received-SPF: pass (google.com: domain of amitdanielk@gmail.com designates 209.85.161.50 as permitted sender) client-ip=209.85.161.50; Authentication-Results: mx.google.com; spf=pass (google.com: domain of amitdanielk@gmail.com designates 209.85.161.50 as permitted sender) smtp.mail=amitdanielk@gmail.com; dkim=pass (test mode) header.i=@gmail.com Received: by fxm16 with SMTP id 16so2519921fxm.37 for ; Sun, 27 Mar 2011 04:03:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:sender:from:to:cc:subject:date:message-id :x-mailer; bh=NWz96BAW/XOK51qYQufeqKFVXZLgXabVicqiBHT6vk8=; b=Zcp+P0DYaB9XSRXwQsZEXnFec++FJHDBymMQW7aDVoBE0j1Fvyef6LK4tJj3P//Kfh KYCl2p6rC0CfLD+l7oLPEpmpdiZ3nyDnM47MpPCFThnOyeBjaANmAL/5CBzAaaGMaskx xHr9O3VhahXrzDnqmjLbcq7v7xs/tJ+fCAVpM= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:from:to:cc:subject:date:message-id:x-mailer; b=ieJwcb0ZTDD8iujaXlgLarBXvWe+cLpSNKUOqqEfhV813bBWMnUzb5L1I2DeE+C6yo KuxiMbhnUHDqblsKQB2lvez7pbSaBI3f71d0HwfNputOoUbTMyWcnptT1tfNslo2OOPf zkU1FCByw9Yq0dFbLGKI+F6P+aT/tqb2VkMi4= Received: by 10.223.6.11 with SMTP id 11mr3153388fax.99.1301223781133; Sun, 27 Mar 2011 04:03:01 -0700 (PDT) Received: from localhost.localdomain ([115.113.119.130]) by mx.google.com with ESMTPS id 17sm1051059far.19.2011.03.27.04.02.55 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 27 Mar 2011 04:02:59 -0700 (PDT) Sender: amit kachhap From: Amit Daniel Kachhap To: linux-samsung-soc@vger.kernel.org, linux-i2c@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, ben-linux@fluff.org, kgene.kim@samsung.com, amit.kachhap@linaro.org, patches@linaro.org Subject: [PATCH] I2C: Samsung: Add support for PM_runtime in the I2C driver. Date: Sun, 27 Mar 2011 16:32:43 -0400 Message-Id: <1301257963-17196-1-git-send-email-amit.kachhap@linaro.org> X-Mailer: git-send-email 1.7.1 This patch adds PM runtime management support in the I2C driver. The functionality of the driver is not modified much but some extra I2C states are added for PM runtime. The runtime suspend keeps the interrupt for the I2C interface disabled. Signed-off-by: Amit Daniel Kachhap --- drivers/i2c/busses/i2c-s3c2410.c | 61 +++++++++++++++++++++++++++++++++----- 1 files changed, 53 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 6c00c10..8ebe621 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -48,7 +49,9 @@ enum s3c24xx_i2c_state { STATE_START, STATE_READ, STATE_WRITE, - STATE_STOP + STATE_STOP, + STATE_STANDBY, + STATE_SUSPEND }; enum s3c24xx_i2c_type { @@ -59,7 +62,6 @@ enum s3c24xx_i2c_type { struct s3c24xx_i2c { spinlock_t lock; wait_queue_head_t wait; - unsigned int suspended:1; struct i2c_msg *msg; unsigned int msg_num; @@ -400,8 +402,13 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) i2c->msg++; } } + break; + default: + dev_err(i2c->dev, "%s: called with invalid state\n", __func__); + goto out; break; + } /* acknowlegde the IRQ and get back on with the work */ @@ -485,7 +492,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, int spins = 20; int ret; - if (i2c->suspended) + if (i2c->state == STATE_SUSPEND) return -EIO; ret = s3c24xx_i2c_set_master(i2c); @@ -555,12 +562,14 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, int ret; clk_enable(i2c->clk); + pm_runtime_get_sync(i2c->dev); for (retry = 0; retry < adap->retries; retry++) { ret = s3c24xx_i2c_doxfer(i2c, msgs, num); if (ret != -EAGAIN) { + pm_runtime_put_sync(i2c->dev); clk_disable(i2c->clk); return ret; } @@ -570,6 +579,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, udelay(100); } + pm_runtime_put_sync(i2c->dev); clk_disable(i2c->clk); return -EREMOTEIO; } @@ -912,10 +922,14 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) goto err_cpufreq; } + /*Set Initial I2C state*/ + i2c->state = STATE_STANDBY; + platform_set_drvdata(pdev, i2c); dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); clk_disable(i2c->clk); + pm_runtime_enable(&pdev->dev); return 0; err_cpufreq: @@ -956,6 +970,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) clk_disable(i2c->clk); clk_put(i2c->clk); + pm_runtime_disable(&pdev->dev); iounmap(i2c->regs); @@ -972,9 +987,9 @@ static int s3c24xx_i2c_suspend_noirq(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); - i2c->suspended = 1; - + i2c->state = STATE_SUSPEND; return 0; + } static int s3c24xx_i2c_resume(struct device *dev) @@ -982,17 +997,47 @@ static int s3c24xx_i2c_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); - i2c->suspended = 0; clk_enable(i2c->clk); s3c24xx_i2c_init(i2c); + i2c->state = STATE_STANDBY; clk_disable(i2c->clk); return 0; } +static int s3c_i2c_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); + + i2c->state = STATE_STANDBY; + s3c24xx_i2c_disable_irq(i2c); + s3c24xx_i2c_disable_ack(i2c); + + return 0; +} + +static int s3c_i2c_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); + + if (i2c->state != STATE_STANDBY) + return 0; + + /*No major activity in runtime resume because all the registers are + re-initialised for each i2c transfer, so just changing the state*/ + i2c->state = STATE_IDLE; + + return 0; +} + + static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = { - .suspend_noirq = s3c24xx_i2c_suspend_noirq, - .resume = s3c24xx_i2c_resume, + .suspend_noirq = s3c24xx_i2c_suspend_noirq, + .resume = s3c24xx_i2c_resume, + .runtime_suspend = s3c_i2c_runtime_suspend, + .runtime_resume = s3c_i2c_runtime_resume, }; #define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops)