From patchwork Mon Sep 30 14:43:48 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Westerberg X-Patchwork-Id: 2965551 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id E2BA0BFF0B for ; Mon, 30 Sep 2013 14:45:09 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C15852022F for ; Mon, 30 Sep 2013 14:45:08 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 04A8A20164 for ; Mon, 30 Sep 2013 14:45:04 +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 1VQeiL-0001Z3-Ev; Mon, 30 Sep 2013 14:44:45 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VQeiD-0005W9-N3; Mon, 30 Sep 2013 14:44:37 +0000 Received: from mga01.intel.com ([192.55.52.88]) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VQei0-0005Te-7V for linux-arm-kernel@lists.infradead.org; Mon, 30 Sep 2013 14:44:25 +0000 Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga101.fm.intel.com with ESMTP; 30 Sep 2013 07:43:56 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="4.90,1008,1371106800"; d="scan'208"; a="403182556" Received: from blue.fi.intel.com ([10.237.72.156]) by fmsmga001.fm.intel.com with ESMTP; 30 Sep 2013 07:43:49 -0700 Received: by blue.fi.intel.com (Postfix, from userid 1004) id AD62BE008E; Mon, 30 Sep 2013 17:43:48 +0300 (EEST) From: Mika Westerberg To: linux-i2c@vger.kernel.org Subject: [PATCH v3] i2c: enable runtime PM for I2C adapter devices enumerated from ACPI Date: Mon, 30 Sep 2013 17:43:48 +0300 Message-Id: <1380552228-23329-2-git-send-email-mika.westerberg@linux.intel.com> X-Mailer: git-send-email 1.8.4.rc3 In-Reply-To: <1380552228-23329-1-git-send-email-mika.westerberg@linux.intel.com> References: <1380552228-23329-1-git-send-email-mika.westerberg@linux.intel.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130930_104424_424691_D9959295 X-CRM114-Status: GOOD ( 21.31 ) X-Spam-Score: -4.2 (----) Cc: Aaron Lu , Kevin Hilman , Wolfram Sang , rjw@rjwysocki.net, linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, Mark Brown , Lv Zheng , Sylwester Nawrocki , Mika Westerberg , 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=-1.4 required=5.0 tests=BAYES_00,KHOP_BIG_TO_CC, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=no 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 The ACPI specification requires the parent device to be powered on before any of its children. It can be only powered off when all the children are already off. Currently whenever there is no I2C traffic going on, the I2C controller driver can put the device into low power state transparently to its children (the I2C client devices). This violates the ACPI specification because now the parent device is in lower power state than its children. In order to keep ACPI happy we enable runtime PM for the I2C adapter device if we find out that the I2C controller was in fact an ACPI device. In addition to that we attach the I2C client devices to the ACPI power domain and make sure that they are powered on when the driver ->probe() is called. Non-ACPI devices are not affected by this change. This patch is based on the work by Aaron Lu and Lv Zheng. Signed-off-by: Mika Westerberg --- drivers/i2c/i2c-core.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 29d3f04..fa861ad 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -236,6 +236,27 @@ int i2c_recover_bus(struct i2c_adapter *adap) return adap->bus_recovery_info->recover_bus(adap); } +static void acpi_i2c_device_pm_get(struct i2c_client *client) +{ + struct i2c_adapter *adap = client->adapter; + + /* Make sure the adapter is active */ + if (ACPI_HANDLE(adap->dev.parent)) + pm_runtime_get_sync(&adap->dev); + if (ACPI_HANDLE(&client->dev)) + acpi_dev_pm_attach(&client->dev, true); +} + +static void acpi_i2c_device_pm_put(struct i2c_client *client, bool detach) +{ + struct i2c_adapter *adap = client->adapter; + + if (ACPI_HANDLE(&client->dev) && detach) + acpi_dev_pm_detach(&client->dev, true); + if (ACPI_HANDLE(adap->dev.parent)) + pm_runtime_put(&adap->dev); +} + static int i2c_device_probe(struct device *dev) { struct i2c_client *client = i2c_verify_client(dev); @@ -254,11 +275,15 @@ static int i2c_device_probe(struct device *dev) client->flags & I2C_CLIENT_WAKE); dev_dbg(dev, "probe\n"); + acpi_i2c_device_pm_get(client); + status = driver->probe(client, i2c_match_id(driver->id_table, client)); if (status) { client->driver = NULL; i2c_set_clientdata(client, NULL); } + + acpi_i2c_device_pm_put(client, !!status); return status; } @@ -271,6 +296,8 @@ static int i2c_device_remove(struct device *dev) if (!client || !dev->driver) return 0; + acpi_i2c_device_pm_get(client); + driver = to_i2c_driver(dev->driver); if (driver->remove) { dev_dbg(dev, "remove\n"); @@ -283,6 +310,8 @@ static int i2c_device_remove(struct device *dev) client->driver = NULL; i2c_set_clientdata(client, NULL); } + + acpi_i2c_device_pm_put(client, true); return status; } @@ -294,8 +323,11 @@ static void i2c_device_shutdown(struct device *dev) if (!client || !dev->driver) return; driver = to_i2c_driver(dev->driver); - if (driver->shutdown) + if (driver->shutdown) { + acpi_i2c_device_pm_get(client); driver->shutdown(client); + acpi_i2c_device_pm_put(client, false); + } } #ifdef CONFIG_PM_SLEEP @@ -1263,6 +1295,16 @@ exit_recovery: bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter); mutex_unlock(&core_lock); + /* + * For ACPI enumerated controllers we must make sure that the + * controller is powered on before its children. Runtime PM handles + * this for us once we have enabled it for the adapter device. + */ + if (ACPI_HANDLE(adap->dev.parent)) { + pm_runtime_no_callbacks(&adap->dev); + pm_runtime_enable(&adap->dev); + } + return 0; out_list: @@ -1427,6 +1469,9 @@ void i2c_del_adapter(struct i2c_adapter *adap) return; } + if (ACPI_HANDLE(adap->dev.parent)) + pm_runtime_disable(&adap->dev); + /* Tell drivers about this removal */ mutex_lock(&core_lock); bus_for_each_drv(&i2c_bus_type, NULL, adap,