summaryrefslogtreecommitdiff
path: root/drivers/ufs/host
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-08-01 12:31:50 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2025-08-01 12:31:50 -0700
commit8582976acc8504cec53a7b6fed493435eba8437f (patch)
tree89cb6cb51e944fc75d0321989c3bf713f30c50dc /drivers/ufs/host
parent7a64bdfaf3e641862e8088a19205692b8b229753 (diff)
parent4a3556b81b99f0c8c0358f7cc6801a62b4538fe2 (diff)
Merge tag 'phy-for-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy
Pull phy updates from Vinod Koul: "New Support: - Qualcomm Milos Synopsys eUSB2 PHY, SM8750 QMP phy support, M31 eUSB2 PHY driver - Samsung Exynos990 usbdrd phy, Exynos7870 MIPI phy support - Renesas RZ/V2N usb2-phy support Updates: - Bulk Yaml binding conversion By Rob H (too many to be listed) - cadence: Sierra PCIe, USB PHY multilink configuration support - Qualcomm refactoring of UFS PHY reset and UFS driver support for phy calibrate API" * tag 'phy-for-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (74 commits) phy: qcom: phy-qcom-m31: Update IPQ5332 M31 USB phy initialization sequence dt-bindings: phy: Convert brcm,sr-usb-combo-phy to DT schema dt-bindings: phy: Convert ti,da830-usb-phy to DT schema dt-bindings: phy: marvell,mmp2-usb-phy: Drop status from the example dt-bindings: phy: mixel, mipi-dsi-phy: Allow assigned-clock* properties phy: exynos-mipi-video: correct cam0 sysreg property name for exynos7870 phy: qcom: phy-qcom-snps-eusb2: Update init sequence per HPG 1.0.2 phy: qcom: phy-qcom-snps-eusb2: Add missing write from init sequence dt-bindings: phy: qcom,snps-eusb2: document the Milos Synopsys eUSB2 PHY dt-bindings: usb: qcom,snps-dwc3: Add Milos compatible phy: rockchip-pcie: Properly disable TEST_WRITE strobe signal phy: rockchip-pcie: Enable all four lanes if required dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Update pcie phy bindings for QCS615 phy: qcom: qmp-combo: Add missing PLL (VCO) configuration on SM8750 phy: qcom: m31-eusb2: drop registration printk phy: qcom: m31-eusb2: fix match data santity check phy: qcom: qmp-pcie: Update PHY settings for QCS8300 & SA8775P phy: qualcomm: phy-qcom-eusb2-repeater: Don't zero-out registers dt-bindings: phy: qcom,snps-eusb2-repeater: Remove default tuning values phy: mediatek: tphy: Cleanup and document slew calibration ...
Diffstat (limited to 'drivers/ufs/host')
-rw-r--r--drivers/ufs/host/ufs-qcom.c66
1 files changed, 35 insertions, 31 deletions
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 2a72e7c1d131..4bbe4de1679b 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -532,6 +532,12 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
goto out_disable_phy;
}
+ ret = phy_calibrate(phy);
+ if (ret) {
+ dev_err(hba->dev, "Failed to calibrate PHY: %d\n", ret);
+ goto out_disable_phy;
+ }
+
ufs_qcom_select_unipro_mode(host);
return 0;
@@ -726,26 +732,17 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
enum ufs_notify_change_status status)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct phy *phy = host->generic_phy;
if (status == PRE_CHANGE)
return 0;
- if (ufs_qcom_is_link_off(hba)) {
- /*
- * Disable the tx/rx lane symbol clocks before PHY is
- * powered down as the PLL source should be disabled
- * after downstream clocks are disabled.
- */
+ if (!ufs_qcom_is_link_active(hba))
ufs_qcom_disable_lane_clks(host);
- phy_power_off(phy);
- /* reset the connected UFS device during power down */
- ufs_qcom_device_reset_ctrl(hba, true);
- } else if (!ufs_qcom_is_link_active(hba)) {
- ufs_qcom_disable_lane_clks(host);
- }
+ /* reset the connected UFS device during power down */
+ if (ufs_qcom_is_link_off(hba) && host->device_reset)
+ ufs_qcom_device_reset_ctrl(hba, true);
return ufs_qcom_ice_suspend(host);
}
@@ -753,26 +750,11 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct phy *phy = host->generic_phy;
int err;
- if (ufs_qcom_is_link_off(hba)) {
- err = phy_power_on(phy);
- if (err) {
- dev_err(hba->dev, "%s: failed PHY power on: %d\n",
- __func__, err);
- return err;
- }
-
- err = ufs_qcom_enable_lane_clks(host);
- if (err)
- return err;
-
- } else if (!ufs_qcom_is_link_active(hba)) {
- err = ufs_qcom_enable_lane_clks(host);
- if (err)
- return err;
- }
+ err = ufs_qcom_enable_lane_clks(host);
+ if (err)
+ return err;
return ufs_qcom_ice_resume(host);
}
@@ -1151,12 +1133,20 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba)
* @on: If true, enable clocks else disable them.
* @status: PRE_CHANGE or POST_CHANGE notify
*
+ * There are certain clocks which comes from the PHY so it needs
+ * to be managed together along with controller clocks which also
+ * provides a better power saving. Hence keep phy_power_off/on calls
+ * in ufs_qcom_setup_clocks, so that PHY's regulators & clks can be
+ * turned on/off along with UFS's clocks.
+ *
* Return: 0 on success, non-zero on failure.
*/
static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
enum ufs_notify_change_status status)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ struct phy *phy;
+ int err;
/*
* In case ufs_qcom_init() is not yet done, simply ignore.
@@ -1166,6 +1156,8 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
if (!host)
return 0;
+ phy = host->generic_phy;
+
switch (status) {
case PRE_CHANGE:
if (on) {
@@ -1175,10 +1167,22 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
/* disable device ref_clk */
ufs_qcom_dev_ref_clk_ctrl(host, false);
}
+
+ err = phy_power_off(phy);
+ if (err) {
+ dev_err(hba->dev, "phy power off failed, ret=%d\n", err);
+ return err;
+ }
}
break;
case POST_CHANGE:
if (on) {
+ err = phy_power_on(phy);
+ if (err) {
+ dev_err(hba->dev, "phy power on failed, ret = %d\n", err);
+ return err;
+ }
+
/* enable the device ref clock for HS mode*/
if (ufshcd_is_hs_mode(&hba->pwr_info))
ufs_qcom_dev_ref_clk_ctrl(host, true);