Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

phy: exynos5-usbdrd: allow DWC3 runtime suspend with UDC bound (E850+)

To make USB runtime suspend work when a UDC has been bound, the phy
needs to inform the USBDRD controller (DWC3) that Vbus and bvalid are
gone, so that it can in turn raise the respective gadget interrupt with
event == DWC3_DEVICE_EVENT_DISCONNECT, which will cause the USB stack
to clean up, allowing DWC3 to enter runtime suspend.

On e850 and gs101 this isn't working, as the respective signals are not
directly connected, and instead this driver uses override bits in the
PHY IP to set those signals. It currently forcefully sets them to 'on',
so the above mentioned interrupt will not be raised, preventing runtime
suspend.

To detect that state, update this driver to act on the TCPC's
orientation signal - when orientation == NONE, Vbus is gone and we can
clear the respective bits. Similarly, for other orientation values we
re-enable them.

This makes runtime suspend work on platforms with a TCPC (like Pixel6),
while keeping compatibility with platforms without (e850-96).

With runtime suspend working, USB-C cable orientation detection now
also fully works on such platforms, and the link comes up as Superspeed
as expected irrespective of the cable orientation and whether UDC /
gadget are configured and active.

Signed-off-by: André Draszik <andre.draszik@linaro.org>
Tested-by: Will McVicker <willmcvicker@google.com>
Link: https://lore.kernel.org/r/20241206-gs101-phy-lanes-orientation-phy-v4-7-f5961268b149@linaro.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

André Draszik and committed by
Vinod Koul
f4fb9c4d 09dc6742

+41 -7
+41 -7
drivers/phy/samsung/phy-exynos5-usbdrd.c
··· 1137 1137 reg |= LINKCTRL_BUS_FILTER_BYPASS(0xf); 1138 1138 writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL); 1139 1139 1140 - reg = readl(regs_base + EXYNOS850_DRD_UTMI); 1141 - reg |= UTMI_FORCE_BVALID | UTMI_FORCE_VBUSVALID; 1142 - writel(reg, regs_base + EXYNOS850_DRD_UTMI); 1140 + if (!phy_drd->sw) { 1141 + reg = readl(regs_base + EXYNOS850_DRD_UTMI); 1142 + reg |= UTMI_FORCE_BVALID | UTMI_FORCE_VBUSVALID; 1143 + writel(reg, regs_base + EXYNOS850_DRD_UTMI); 1143 1144 1144 - reg = readl(regs_base + EXYNOS850_DRD_HSP); 1145 - reg |= HSP_VBUSVLDEXT | HSP_VBUSVLDEXTSEL; 1146 - writel(reg, regs_base + EXYNOS850_DRD_HSP); 1145 + reg = readl(regs_base + EXYNOS850_DRD_HSP); 1146 + reg |= HSP_VBUSVLDEXT | HSP_VBUSVLDEXTSEL; 1147 + writel(reg, regs_base + EXYNOS850_DRD_HSP); 1148 + } 1147 1149 1148 1150 reg = readl(regs_base + EXYNOS850_DRD_SSPPLLCTL); 1149 1151 reg &= ~SSPPLLCTL_FSEL; ··· 1406 1404 enum typec_orientation orientation) 1407 1405 { 1408 1406 struct exynos5_usbdrd_phy *phy_drd = typec_switch_get_drvdata(sw); 1407 + int ret; 1409 1408 1410 - scoped_guard(mutex, &phy_drd->phy_mutex) 1409 + ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks); 1410 + if (ret) { 1411 + dev_err(phy_drd->dev, "Failed to enable PHY clocks(s)\n"); 1412 + return ret; 1413 + } 1414 + 1415 + scoped_guard(mutex, &phy_drd->phy_mutex) { 1416 + void __iomem * const regs_base = phy_drd->reg_phy; 1417 + unsigned int reg; 1418 + 1419 + if (orientation == TYPEC_ORIENTATION_NONE) { 1420 + reg = readl(regs_base + EXYNOS850_DRD_UTMI); 1421 + reg &= ~(UTMI_FORCE_VBUSVALID | UTMI_FORCE_BVALID); 1422 + writel(reg, regs_base + EXYNOS850_DRD_UTMI); 1423 + 1424 + reg = readl(regs_base + EXYNOS850_DRD_HSP); 1425 + reg |= HSP_VBUSVLDEXTSEL; 1426 + reg &= ~HSP_VBUSVLDEXT; 1427 + writel(reg, regs_base + EXYNOS850_DRD_HSP); 1428 + } else { 1429 + reg = readl(regs_base + EXYNOS850_DRD_UTMI); 1430 + reg |= UTMI_FORCE_VBUSVALID | UTMI_FORCE_BVALID; 1431 + writel(reg, regs_base + EXYNOS850_DRD_UTMI); 1432 + 1433 + reg = readl(regs_base + EXYNOS850_DRD_HSP); 1434 + reg |= HSP_VBUSVLDEXTSEL | HSP_VBUSVLDEXT; 1435 + writel(reg, regs_base + EXYNOS850_DRD_HSP); 1436 + } 1437 + 1411 1438 phy_drd->orientation = orientation; 1439 + } 1440 + 1441 + clk_bulk_disable(phy_drd->drv_data->n_clks, phy_drd->clks); 1412 1442 1413 1443 return 0; 1414 1444 }