mirror of
https://github.com/torvalds/linux.git
synced 2026-01-25 15:03:52 +08:00
scsi: ufs: host: mediatek: Support UFS PHY runtime PM and correct sequence
Add support for UFS PHY runtime power management by probing the PHY device and enabling its runtime PM. Ensure the correct sequence of operations during suspend and resume: PHY suspend -> UFS suspend -> UFS resume -> PHY resume. Improve power management efficiency and system stability with this enhancement. Signed-off-by: Peter Wang <peter.wang@mediatek.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
committed by
Martin K. Petersen
parent
b2f8abadab
commit
c73cd5e298
@@ -2243,10 +2243,12 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = {
|
||||
static int ufs_mtk_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *reset_node;
|
||||
struct platform_device *reset_pdev;
|
||||
struct device *dev = &pdev->dev, *phy_dev = NULL;
|
||||
struct device_node *reset_node, *phy_node = NULL;
|
||||
struct platform_device *reset_pdev, *phy_pdev = NULL;
|
||||
struct device_link *link;
|
||||
struct ufs_hba *hba;
|
||||
struct ufs_mtk_host *host;
|
||||
|
||||
reset_node = of_find_compatible_node(NULL, NULL,
|
||||
"ti,syscon-reset");
|
||||
@@ -2273,13 +2275,44 @@ static int ufs_mtk_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
skip_reset:
|
||||
/* find phy node */
|
||||
phy_node = of_parse_phandle(dev->of_node, "phys", 0);
|
||||
|
||||
if (phy_node) {
|
||||
phy_pdev = of_find_device_by_node(phy_node);
|
||||
if (!phy_pdev)
|
||||
goto skip_phy;
|
||||
phy_dev = &phy_pdev->dev;
|
||||
|
||||
pm_runtime_set_active(phy_dev);
|
||||
pm_runtime_enable(phy_dev);
|
||||
pm_runtime_get_sync(phy_dev);
|
||||
|
||||
put_device(phy_dev);
|
||||
dev_info(dev, "phys node found\n");
|
||||
} else {
|
||||
dev_notice(dev, "phys node not found\n");
|
||||
}
|
||||
|
||||
skip_phy:
|
||||
/* perform generic probe */
|
||||
err = ufshcd_pltfrm_init(pdev, &ufs_hba_mtk_vops);
|
||||
if (err) {
|
||||
dev_err(dev, "probe failed %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
hba = platform_get_drvdata(pdev);
|
||||
if (!hba)
|
||||
goto out;
|
||||
|
||||
if (phy_node && phy_dev) {
|
||||
host = ufshcd_get_variant(hba);
|
||||
host->phy_dev = phy_dev;
|
||||
}
|
||||
|
||||
out:
|
||||
if (err)
|
||||
dev_err(dev, "probe failed %d\n", err);
|
||||
|
||||
of_node_put(phy_node);
|
||||
of_node_put(reset_node);
|
||||
return err;
|
||||
}
|
||||
@@ -2343,6 +2376,7 @@ out:
|
||||
static int ufs_mtk_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
|
||||
struct arm_smccc_res res;
|
||||
int ret = 0;
|
||||
|
||||
@@ -2355,17 +2389,24 @@ static int ufs_mtk_runtime_suspend(struct device *dev)
|
||||
if (ufs_mtk_is_rtff_mtcmos(hba))
|
||||
ufs_mtk_mtcmos_ctrl(false, res);
|
||||
|
||||
if (host->phy_dev)
|
||||
pm_runtime_put_sync(host->phy_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ufs_mtk_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
|
||||
struct arm_smccc_res res;
|
||||
|
||||
if (ufs_mtk_is_rtff_mtcmos(hba))
|
||||
ufs_mtk_mtcmos_ctrl(true, res);
|
||||
|
||||
if (host->phy_dev)
|
||||
pm_runtime_get_sync(host->phy_dev);
|
||||
|
||||
ufs_mtk_dev_vreg_set_lpm(hba, false);
|
||||
|
||||
return ufshcd_runtime_resume(dev);
|
||||
|
||||
@@ -193,6 +193,7 @@ struct ufs_mtk_host {
|
||||
bool is_mcq_intr_enabled;
|
||||
int mcq_nr_intr;
|
||||
struct ufs_mtk_mcq_intr_info mcq_intr_info[UFSHCD_MAX_Q_NR];
|
||||
struct device *phy_dev;
|
||||
};
|
||||
|
||||
/* MTK delay of autosuspend: 500 ms */
|
||||
|
||||
Reference in New Issue
Block a user