From patchwork Fri Jul 21 11:02:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Manu Gautam X-Patchwork-Id: 9856563 X-Patchwork-Delegate: agross@codeaurora.org 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 7A18B601C0 for ; Fri, 21 Jul 2017 11:03:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 689C4286D4 for ; Fri, 21 Jul 2017 11:03:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5D7AA287A1; Fri, 21 Jul 2017 11:03:11 +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.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID 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 F1028286D4 for ; Fri, 21 Jul 2017 11:03:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753480AbdGULDA (ORCPT ); Fri, 21 Jul 2017 07:03:00 -0400 Received: from smtp.codeaurora.org ([198.145.29.96]:58464 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753189AbdGULCz (ORCPT ); Fri, 21 Jul 2017 07:02:55 -0400 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 30E0D6071D; Fri, 21 Jul 2017 11:02:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1500634975; bh=8ITt5bH1VHQzrp5RSsG4rsw4iLaksqKJB5Tg1FgWsrM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lvGkCemQv71lmkm8cPQvYPD0noNggkBxSaiUXD+BvIpaWBkvjibEFNHgoAE+LA64P +ZgBzUga1Ca+FSmHWx4xNGokUt7uyIgDL4CU+/+G8jmRDMT1Dkml1ro7lguHmMtv+q BR2MPTYWTg7rOsFj9upJLUI8hTGrPpJaFpHvnGi0= Received: from mgautam-linux.qualcomm.com (blr-c-bdr-fw-01_globalnat_allzones-outside.qualcomm.com [103.229.19.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: mgautam@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 0E21A61112; Fri, 21 Jul 2017 11:02:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1500634974; bh=8ITt5bH1VHQzrp5RSsG4rsw4iLaksqKJB5Tg1FgWsrM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JyES7/hHg2LrUMyUoQrvDoafpgcLdnlT3YNpoEoWLuGJ3RDOpf/+NqpdCZtgMyT1u RwO+cMTaIDytekqzvKTDJpCheU7Tk+GZCbsGzmjNJ278EkfzW0AGcbPn3A89sPNCbK ytLYFuakIrJKQo3Db/+PKgDD8QnwMTtI6aAMI5KA= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 0E21A61112 Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=mgautam@codeaurora.org From: Manu Gautam To: Kishon Vijay Abraham I , Felipe Balbi Cc: linux-arm-msm@vger.kernel.org, Manu Gautam , Vivek Gautam , Krzysztof Kozlowski , Wei Yongjun , Fengguang Wu , linux-kernel@vger.kernel.org (open list:GENERIC PHY FRAMEWORK) Subject: [PATCH v1 5/6] phy: qcom-qmp: Add support for runtime PM Date: Fri, 21 Jul 2017 16:32:00 +0530 Message-Id: <1500634921-25914-6-git-send-email-mgautam@codeaurora.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1500634921-25914-1-git-send-email-mgautam@codeaurora.org> References: <1500634921-25914-1-git-send-email-mgautam@codeaurora.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Driver can turn off clocks during runtime suspend. Also, runtime suspend is not as a result of host mode selective suspend then PHY can be powered off as well. Signed-off-by: Manu Gautam diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index aefb853..8394e24 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -481,6 +481,8 @@ struct qcom_qmp { int init_count; bool power_enabled; bool clk_enabled; + bool phy_initialized; + enum phy_mode mode; }; static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) @@ -832,6 +834,7 @@ static int qcom_qmp_phy_init(struct phy *phy) dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret); goto err_pcs_ready; } + qmp->phy_initialized = true; return 0; @@ -874,6 +877,75 @@ static int qcom_qmp_phy_exit(struct phy *phy) qcom_qmp_phy_poweroff(qmp); + qmp->phy_initialized = false; + + return 0; +} + +static int qcom_qmp_phy_set_mode(struct phy *phy, enum phy_mode mode) +{ + struct qmp_phy *qphy = phy_get_drvdata(phy); + struct qcom_qmp *qmp = qphy->qmp; + + qmp->mode = mode; + + return 0; +} + +static int __maybe_unused qcom_qmp_phy_runtime_suspend(struct device *dev) +{ + struct qcom_qmp *qmp = dev_get_drvdata(dev); + struct qmp_phy *qphy = qmp->phys[0]; + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *pcs = qphy->pcs; + + dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode); + + if (!qmp->phy_initialized) { + dev_vdbg(dev, "PHY not initialized, bailing out\n"); + return 0; + } + + /* Power down PHY if not in session */ + if (qmp->mode == PHY_MODE_INVALID) + qphy_clrbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl); + + clk_disable_unprepare(qphy->pipe_clk); + qcom_qmp_phy_disable_clocks(qmp); + + if (qmp->mode == PHY_MODE_INVALID) + qcom_qmp_phy_poweroff(qmp); + + return 0; +} + +static int __maybe_unused qcom_qmp_phy_runtime_resume(struct device *dev) +{ + struct qcom_qmp *qmp = dev_get_drvdata(dev); + struct qmp_phy *qphy = qmp->phys[0]; + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *pcs = qphy->pcs; + int ret = 0; + + dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode); + + if (!qmp->phy_initialized) { + dev_vdbg(dev, "PHY not initialized, bailing out\n"); + return 0; + } + + qcom_qmp_phy_poweron(qmp); + + qcom_qmp_phy_enable_clocks(qmp); + + ret = clk_prepare_enable(qphy->pipe_clk); + if (ret) { + dev_err(dev, "pipe_clk enable failed, err=%d\n", ret); + return ret; + } + + qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl); + return 0; } @@ -999,6 +1071,7 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, int id) static const struct phy_ops qcom_qmp_phy_gen_ops = { .init = qcom_qmp_phy_init, .exit = qcom_qmp_phy_exit, + .set_mode = qcom_qmp_phy_set_mode, .owner = THIS_MODULE, }; @@ -1091,6 +1164,11 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id) }; MODULE_DEVICE_TABLE(of, qcom_qmp_phy_of_match_table); +static const struct dev_pm_ops qcom_qmp_phy_pm_ops = { + SET_RUNTIME_PM_OPS(qcom_qmp_phy_runtime_suspend, + qcom_qmp_phy_runtime_resume, NULL) +}; + static int qcom_qmp_phy_probe(struct platform_device *pdev) { struct qcom_qmp *qmp; @@ -1118,6 +1196,7 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) qmp->serdes = base; mutex_init(&qmp->phy_mutex); + qmp->mode = PHY_MODE_INVALID; /* Get the specific init parameters of QMP phy */ qmp->cfg = of_device_get_match_data(dev); @@ -1146,12 +1225,16 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) return -ENOMEM; id = 0; + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + for_each_available_child_of_node(dev->of_node, child) { /* Create per-lane phy */ ret = qcom_qmp_phy_create(dev, child, id); if (ret) { dev_err(dev, "failed to create lane%d phy, %d\n", id, ret); + pm_runtime_disable(dev); return ret; } @@ -1163,6 +1246,7 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) if (ret) { dev_err(qmp->dev, "failed to register pipe clock source\n"); + pm_runtime_disable(dev); return ret; } id++; @@ -1171,6 +1255,8 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); if (!IS_ERR(phy_provider)) dev_info(dev, "Registered Qcom-QMP phy\n"); + else + pm_runtime_disable(dev); return PTR_ERR_OR_ZERO(phy_provider); } @@ -1179,6 +1265,7 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) .probe = qcom_qmp_phy_probe, .driver = { .name = "qcom-qmp-phy", + .pm = &qcom_qmp_phy_pm_ops, .of_match_table = qcom_qmp_phy_of_match_table, }, };