Commit 0d75f508 authored by Wesley Cheng's avatar Wesley Cheng Committed by Vinod Koul

phy: qcom-snps: Add runtime suspend and resume handlers

Allow for the PHY to be put into a powered down state when possible.
Add the required suspend and resume callbacks, which will determine
what resources can be turned off depending on the cable status.
Signed-off-by: default avatarWesley Cheng <wcheng@codeaurora.org>
Link: https://lore.kernel.org/r/20200625195444.15130-2-wcheng@codeaurora.orgSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent 90b65347
...@@ -104,6 +104,63 @@ static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset, ...@@ -104,6 +104,63 @@ static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset,
readl_relaxed(base + offset); readl_relaxed(base + offset);
} }
static int qcom_snps_hsphy_suspend(struct qcom_snps_hsphy *hsphy)
{
dev_dbg(&hsphy->phy->dev, "Suspend QCOM SNPS PHY\n");
if (hsphy->mode == PHY_MODE_USB_HOST) {
/* Enable auto-resume to meet remote wakeup timing */
qcom_snps_hsphy_write_mask(hsphy->base,
USB2_PHY_USB_PHY_HS_PHY_CTRL2,
USB2_AUTO_RESUME,
USB2_AUTO_RESUME);
usleep_range(500, 1000);
qcom_snps_hsphy_write_mask(hsphy->base,
USB2_PHY_USB_PHY_HS_PHY_CTRL2,
0, USB2_AUTO_RESUME);
}
clk_disable_unprepare(hsphy->cfg_ahb_clk);
return 0;
}
static int qcom_snps_hsphy_resume(struct qcom_snps_hsphy *hsphy)
{
int ret;
dev_dbg(&hsphy->phy->dev, "Resume QCOM SNPS PHY, mode\n");
ret = clk_prepare_enable(hsphy->cfg_ahb_clk);
if (ret) {
dev_err(&hsphy->phy->dev, "failed to enable cfg ahb clock\n");
return ret;
}
return 0;
}
static int __maybe_unused qcom_snps_hsphy_runtime_suspend(struct device *dev)
{
struct qcom_snps_hsphy *hsphy = dev_get_drvdata(dev);
if (!hsphy->phy_initialized)
return 0;
qcom_snps_hsphy_suspend(hsphy);
return 0;
}
static int __maybe_unused qcom_snps_hsphy_runtime_resume(struct device *dev)
{
struct qcom_snps_hsphy *hsphy = dev_get_drvdata(dev);
if (!hsphy->phy_initialized)
return 0;
qcom_snps_hsphy_resume(hsphy);
return 0;
}
static int qcom_snps_hsphy_init(struct phy *phy) static int qcom_snps_hsphy_init(struct phy *phy)
{ {
struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy); struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
...@@ -212,6 +269,11 @@ static const struct of_device_id qcom_snps_hsphy_of_match_table[] = { ...@@ -212,6 +269,11 @@ static const struct of_device_id qcom_snps_hsphy_of_match_table[] = {
}; };
MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_of_match_table); MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_of_match_table);
static const struct dev_pm_ops qcom_snps_hsphy_pm_ops = {
SET_RUNTIME_PM_OPS(qcom_snps_hsphy_runtime_suspend,
qcom_snps_hsphy_runtime_resume, NULL)
};
static int qcom_snps_hsphy_probe(struct platform_device *pdev) static int qcom_snps_hsphy_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -255,6 +317,14 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev) ...@@ -255,6 +317,14 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)
return ret; return ret;
} }
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
/*
* Prevent runtime pm from being ON by default. Users can enable
* it using power/control in sysfs.
*/
pm_runtime_forbid(dev);
generic_phy = devm_phy_create(dev, NULL, &qcom_snps_hsphy_gen_ops); generic_phy = devm_phy_create(dev, NULL, &qcom_snps_hsphy_gen_ops);
if (IS_ERR(generic_phy)) { if (IS_ERR(generic_phy)) {
ret = PTR_ERR(generic_phy); ret = PTR_ERR(generic_phy);
...@@ -269,6 +339,8 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev) ...@@ -269,6 +339,8 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (!IS_ERR(phy_provider)) if (!IS_ERR(phy_provider))
dev_dbg(dev, "Registered Qcom-SNPS HS phy\n"); dev_dbg(dev, "Registered Qcom-SNPS HS phy\n");
else
pm_runtime_disable(dev);
return PTR_ERR_OR_ZERO(phy_provider); return PTR_ERR_OR_ZERO(phy_provider);
} }
...@@ -277,6 +349,7 @@ static struct platform_driver qcom_snps_hsphy_driver = { ...@@ -277,6 +349,7 @@ static struct platform_driver qcom_snps_hsphy_driver = {
.probe = qcom_snps_hsphy_probe, .probe = qcom_snps_hsphy_probe,
.driver = { .driver = {
.name = "qcom-snps-hs-femto-v2-phy", .name = "qcom-snps-hs-femto-v2-phy",
.pm = &qcom_snps_hsphy_pm_ops,
.of_match_table = qcom_snps_hsphy_of_match_table, .of_match_table = qcom_snps_hsphy_of_match_table,
}, },
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment