From patchwork Mon Oct 16 01:31:17 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Rafael J. Wysocki" X-Patchwork-Id: 10007349 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id AD0B3601E9 for ; Mon, 16 Oct 2017 01:43:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9D2A52623C for ; Mon, 16 Oct 2017 01:43:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 91C97269B2; Mon, 16 Oct 2017 01:43:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 301A32623C for ; Mon, 16 Oct 2017 01:43:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751839AbdJPBnK (ORCPT ); Sun, 15 Oct 2017 21:43:10 -0400 Received: from cloudserver094114.home.net.pl ([79.96.170.134]:59694 "EHLO cloudserver094114.home.net.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751671AbdJPBnC (ORCPT ); Sun, 15 Oct 2017 21:43:02 -0400 Received: from 79.184.255.244.ipv4.supernova.orange.pl (79.184.255.244) (HELO aspire.rjw.lan) by serwer1319399.home.pl (79.96.170.134) with SMTP (IdeaSmtpServer 0.82) id 45faa96915c29648; Mon, 16 Oct 2017 03:43:00 +0200 From: "Rafael J. Wysocki" To: Linux PM Cc: Bjorn Helgaas , Alan Stern , Greg Kroah-Hartman , LKML , Linux ACPI , Linux PCI , Linux Documentation , Mika Westerberg , Ulf Hansson , Andy Shevchenko , Kevin Hilman , Wolfram Sang , linux-i2c@vger.kernel.org, Lee Jones Subject: [PATCH 11/12] PM: i2c-designware-platdrv: Optimize power management Date: Mon, 16 Oct 2017 03:31:17 +0200 Message-ID: <2298462.BTY6P2Oy1l@aspire.rjw.lan> In-Reply-To: <3806130.B2KCK0tvef@aspire.rjw.lan> References: <3806130.B2KCK0tvef@aspire.rjw.lan> MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Rafael J. Wysocki Optimize the power management in i2c-designware-platdrv by making it set the DPM_FLAG_SMART_SUSPEND and DPM_FLAG_LEAVE_SUSPENDED which allows some code to be dropped from its PM callbacks. First, setting DPM_FLAG_SMART_SUSPEND causes the intel-lpss driver to avoid resuming i2c-designware-platdrv devices in its ->prepare callback, so they can stay in runtime suspend after that point even if the direct-complete feature is not used for them. It also causes the PM core to avoid invoking "late" and "noirq" suspend callbacks for these devices if they are in runtime suspend at the beginning of the "late" phase of device suspend during system suspend. That guarantees dw_i2c_plat_suspend() to be called for a device only if it is not in runtime suspend. Moreover, it also causes the PM core to set the device's runtime PM status to "active" after calling dw_i2c_plat_resume() for it, so the driver doesn't need internal flags to avoid invoking either dw_i2c_plat_suspend() or dw_i2c_plat_resume() twice in a row. Second, setting DPM_FLAG_LEAVE_SUSPENDED enables the optimization allowing the device to stay suspended after system resume under suitable conditions, so again the driver doesn't need to take care of that by itself. Accordingly, the internal "suspended" and "skip_resume" flags used by the driver are not necessary any more, so drop them and simplify the driver's PM callbacks. Additionally, notice that dw_i2c_plat_complete() only needs to schedule runtime PM for the device if platform firmware has been involved in resuming the system, so make it call pm_resume_via_firmware() to check that. Signed-off-by: Rafael J. Wysocki --- drivers/i2c/busses/i2c-designware-core.h | 2 -- drivers/i2c/busses/i2c-designware-platdrv.c | 25 ++++++------------------- 2 files changed, 6 insertions(+), 21 deletions(-) Index: linux-pm/drivers/i2c/busses/i2c-designware-core.h =================================================================== --- linux-pm.orig/drivers/i2c/busses/i2c-designware-core.h +++ linux-pm/drivers/i2c/busses/i2c-designware-core.h @@ -280,8 +280,6 @@ struct dw_i2c_dev { int (*acquire_lock)(struct dw_i2c_dev *dev); void (*release_lock)(struct dw_i2c_dev *dev); bool pm_disabled; - bool suspended; - bool skip_resume; void (*disable)(struct dw_i2c_dev *dev); void (*disable_int)(struct dw_i2c_dev *dev); int (*init)(struct dw_i2c_dev *dev); Index: linux-pm/drivers/i2c/busses/i2c-designware-platdrv.c =================================================================== --- linux-pm.orig/drivers/i2c/busses/i2c-designware-platdrv.c +++ linux-pm/drivers/i2c/busses/i2c-designware-platdrv.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "i2c-designware-core.h" @@ -370,7 +371,10 @@ static int dw_i2c_plat_probe(struct plat ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); adap->dev.of_node = pdev->dev.of_node; - dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_SMART_PREPARE); + dev_pm_set_driver_flags(&pdev->dev, + DPM_FLAG_SMART_PREPARE | + DPM_FLAG_SMART_SUSPEND | + DPM_FLAG_LEAVE_SUSPENDED); /* The code below assumes runtime PM to be disabled. */ WARN_ON(pm_runtime_enabled(&pdev->dev)); @@ -446,7 +450,7 @@ static int dw_i2c_plat_prepare(struct de static void dw_i2c_plat_complete(struct device *dev) { - if (dev->power.direct_complete) + if (dev->power.direct_complete && pm_resume_via_firmware()) pm_request_resume(dev); } #else @@ -459,16 +463,9 @@ static int dw_i2c_plat_suspend(struct de { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - if (i_dev->suspended) { - i_dev->skip_resume = true; - return 0; - } - i_dev->disable(i_dev); i2c_dw_plat_prepare_clk(i_dev, false); - i_dev->suspended = true; - return 0; } @@ -476,19 +473,9 @@ static int dw_i2c_plat_resume(struct dev { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - if (!i_dev->suspended) - return 0; - - if (i_dev->skip_resume) { - i_dev->skip_resume = false; - return 0; - } - i2c_dw_plat_prepare_clk(i_dev, true); i_dev->init(i_dev); - i_dev->suspended = false; - return 0; }