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

usb: phy: tegra: Support waking up from a low power mode

Support programming of waking up from a low power mode by implementing the
generic set_wakeup() callback of the USB PHY API.

Tested-by: Matt Merhar <mattmerhar@protonmail.com>
Tested-by: Nicolas Chauvet <kwizart@gmail.com>
Tested-by: Peter Geis <pgwipeout@gmail.com>
Tested-by: Ion Agorria <ion@agorria.com>
Acked-by: Thierry Reding <treding@nvidia.com>
Acked-by: Peter Chen <peter.chen@kernel.org>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Link: https://lore.kernel.org/r/20201218120246.7759-3-digetx@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Dmitry Osipenko and committed by
Greg Kroah-Hartman
35192007 b100402e

+91 -11
+89 -11
drivers/usb/phy/phy-tegra-usb.c
··· 45 45 #define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) 46 46 47 47 #define USB_SUSP_CTRL 0x400 48 + #define USB_WAKE_ON_RESUME_EN BIT(2) 48 49 #define USB_WAKE_ON_CNNT_EN_DEV BIT(3) 49 50 #define USB_WAKE_ON_DISCON_EN_DEV BIT(4) 50 51 #define USB_SUSP_CLR BIT(5) ··· 56 55 #define ULPI_PHY_ENABLE BIT(13) 57 56 #define USB_SUSP_SET BIT(14) 58 57 #define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16) 58 + 59 + #define USB_PHY_VBUS_SENSORS 0x404 60 + #define B_SESS_VLD_WAKEUP_EN BIT(6) 61 + #define B_VBUS_VLD_WAKEUP_EN BIT(14) 62 + #define A_SESS_VLD_WAKEUP_EN BIT(22) 63 + #define A_VBUS_VLD_WAKEUP_EN BIT(30) 64 + 65 + #define USB_PHY_VBUS_WAKEUP_ID 0x408 66 + #define VBUS_WAKEUP_WAKEUP_EN BIT(30) 59 67 60 68 #define USB1_LEGACY_CTRL 0x410 61 69 #define USB1_NO_LEGACY_MODE BIT(0) ··· 344 334 writel_relaxed(val, base + UTMIP_BIAS_CFG0); 345 335 } 346 336 337 + if (phy->pad_wakeup) { 338 + phy->pad_wakeup = false; 339 + utmip_pad_count--; 340 + } 341 + 347 342 spin_unlock(&utmip_pad_lock); 348 343 349 344 clk_disable_unprepare(phy->pad_clk); ··· 372 357 dev_err(phy->u_phy.dev, "UTMIP pad already powered off\n"); 373 358 ret = -EINVAL; 374 359 goto ulock; 360 + } 361 + 362 + /* 363 + * In accordance to TRM, OTG and Bias pad circuits could be turned off 364 + * to save power if wake is enabled, but the VBUS-change detection 365 + * method is board-specific and these circuits may need to be enabled 366 + * to generate wakeup event, hence we will just keep them both enabled. 367 + */ 368 + if (phy->wakeup_enabled) { 369 + phy->pad_wakeup = true; 370 + utmip_pad_count++; 375 371 } 376 372 377 373 if (--utmip_pad_count == 0) { ··· 529 503 writel_relaxed(val, base + UTMIP_PLL_CFG1); 530 504 } 531 505 506 + val = readl_relaxed(base + USB_SUSP_CTRL); 507 + val &= ~USB_WAKE_ON_RESUME_EN; 508 + writel_relaxed(val, base + USB_SUSP_CTRL); 509 + 532 510 if (phy->mode == USB_DR_MODE_PERIPHERAL) { 533 511 val = readl_relaxed(base + USB_SUSP_CTRL); 534 512 val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV); 535 513 writel_relaxed(val, base + USB_SUSP_CTRL); 514 + 515 + val = readl_relaxed(base + USB_PHY_VBUS_WAKEUP_ID); 516 + val &= ~VBUS_WAKEUP_WAKEUP_EN; 517 + writel_relaxed(val, base + USB_PHY_VBUS_WAKEUP_ID); 518 + 519 + val = readl_relaxed(base + USB_PHY_VBUS_SENSORS); 520 + val &= ~(A_VBUS_VLD_WAKEUP_EN | A_SESS_VLD_WAKEUP_EN); 521 + val &= ~(B_VBUS_VLD_WAKEUP_EN | B_SESS_VLD_WAKEUP_EN); 522 + writel_relaxed(val, base + USB_PHY_VBUS_SENSORS); 536 523 537 524 val = readl_relaxed(base + UTMIP_BAT_CHRG_CFG0); 538 525 val &= ~UTMIP_PD_CHRG; ··· 644 605 645 606 utmi_phy_clk_disable(phy); 646 607 647 - if (phy->mode == USB_DR_MODE_PERIPHERAL) { 608 + /* PHY won't resume if reset is asserted */ 609 + if (!phy->wakeup_enabled) { 648 610 val = readl_relaxed(base + USB_SUSP_CTRL); 649 - val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); 650 - val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5); 611 + val |= UTMIP_RESET; 651 612 writel_relaxed(val, base + USB_SUSP_CTRL); 652 613 } 653 - 654 - val = readl_relaxed(base + USB_SUSP_CTRL); 655 - val |= UTMIP_RESET; 656 - writel_relaxed(val, base + USB_SUSP_CTRL); 657 614 658 615 val = readl_relaxed(base + UTMIP_BAT_CHRG_CFG0); 659 616 val |= UTMIP_PD_CHRG; 660 617 writel_relaxed(val, base + UTMIP_BAT_CHRG_CFG0); 661 618 662 - val = readl_relaxed(base + UTMIP_XCVR_CFG0); 663 - val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | 664 - UTMIP_FORCE_PDZI_POWERDOWN; 665 - writel_relaxed(val, base + UTMIP_XCVR_CFG0); 619 + if (!phy->wakeup_enabled) { 620 + val = readl_relaxed(base + UTMIP_XCVR_CFG0); 621 + val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | 622 + UTMIP_FORCE_PDZI_POWERDOWN; 623 + writel_relaxed(val, base + UTMIP_XCVR_CFG0); 624 + } 666 625 667 626 val = readl_relaxed(base + UTMIP_XCVR_CFG1); 668 627 val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | 669 628 UTMIP_FORCE_PDDR_POWERDOWN; 670 629 writel_relaxed(val, base + UTMIP_XCVR_CFG1); 630 + 631 + if (phy->wakeup_enabled) { 632 + val = readl_relaxed(base + USB_SUSP_CTRL); 633 + val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); 634 + val |= USB_WAKEUP_DEBOUNCE_COUNT(5); 635 + val |= USB_WAKE_ON_RESUME_EN; 636 + writel_relaxed(val, base + USB_SUSP_CTRL); 637 + 638 + /* 639 + * Ask VBUS sensor to generate wake event once cable is 640 + * connected. 641 + */ 642 + if (phy->mode == USB_DR_MODE_PERIPHERAL) { 643 + val = readl_relaxed(base + USB_PHY_VBUS_WAKEUP_ID); 644 + val |= VBUS_WAKEUP_WAKEUP_EN; 645 + writel_relaxed(val, base + USB_PHY_VBUS_WAKEUP_ID); 646 + 647 + val = readl_relaxed(base + USB_PHY_VBUS_SENSORS); 648 + val |= A_VBUS_VLD_WAKEUP_EN; 649 + writel_relaxed(val, base + USB_PHY_VBUS_SENSORS); 650 + } 651 + } 671 652 672 653 return utmip_pad_power_off(phy); 673 654 } ··· 824 765 usleep_range(5000, 6000); 825 766 clk_disable_unprepare(phy->clk); 826 767 768 + /* 769 + * Wakeup currently unimplemented for ULPI, thus PHY needs to be 770 + * force-resumed. 771 + */ 772 + if (WARN_ON_ONCE(phy->wakeup_enabled)) { 773 + ulpi_phy_power_on(phy); 774 + return -EOPNOTSUPP; 775 + } 776 + 827 777 return 0; 828 778 } 829 779 ··· 893 825 clk_disable_unprepare(phy->pll_u); 894 826 895 827 phy->freq = NULL; 828 + } 829 + 830 + static int tegra_usb_phy_set_wakeup(struct usb_phy *u_phy, bool enable) 831 + { 832 + struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy); 833 + 834 + phy->wakeup_enabled = enable; 835 + 836 + return 0; 896 837 } 897 838 898 839 static int tegra_usb_phy_set_suspend(struct usb_phy *u_phy, int suspend) ··· 1275 1198 tegra_phy->u_phy.dev = &pdev->dev; 1276 1199 tegra_phy->u_phy.init = tegra_usb_phy_init; 1277 1200 tegra_phy->u_phy.shutdown = tegra_usb_phy_shutdown; 1201 + tegra_phy->u_phy.set_wakeup = tegra_usb_phy_set_wakeup; 1278 1202 tegra_phy->u_phy.set_suspend = tegra_usb_phy_set_suspend; 1279 1203 1280 1204 platform_set_drvdata(pdev, tegra_phy);
+2
include/linux/usb/tegra_usb_phy.h
··· 79 79 bool is_ulpi_phy; 80 80 struct gpio_desc *reset_gpio; 81 81 struct reset_control *pad_rst; 82 + bool wakeup_enabled; 83 + bool pad_wakeup; 82 84 bool powered_on; 83 85 }; 84 86