diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-02-21 08:32:37 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-02-21 08:32:37 +0300 |
commit | 780607b9731feef575514108fc7956c54180f16e (patch) | |
tree | 873d8203bd441f6494bbd3f57a9f6371b2ea1973 /drivers/usb/phy/phy-tegra-usb.c | |
parent | e4286926abbbaab9b047c8bc25cae78ec990928f (diff) | |
parent | b5a12546e779d4f5586f58e60e0ef5070a833a64 (diff) | |
download | linux-780607b9731feef575514108fc7956c54180f16e.tar.xz |
Merge tag 'usb-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB and Thunderbolt updates from Greg KH:
"Here is the big set of USB and Thunderbolt driver changes for
5.12-rc1.
It's been an active set of development in these subsystems for the
past few months:
- loads of typec features added for new hardware
- xhci features and bugfixes
- dwc3 features added for more hardware support
- dwc2 fixes and new hardware support
- cdns3 driver updates for more hardware support
- gadget driver cleanups and minor fixes
- usb-serial fixes, new driver, and more devices supported
- thunderbolt feature additions for new hardware
- lots of other tiny fixups and additions
The chrome driver changes are in here as well, as they depended on
some of the typec changes, and the maintainer acked them.
All of these have been in linux-next for a while with no reported
issues"
* tag 'usb-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (300 commits)
dt-bindings: usb: mediatek: musb: add mt8516 compatbile
dt-bindings: usb: mtk-xhci: add compatible for mt2701 and mt7623
dt-bindings: usb: mtk-xhci: add optional assigned clock properties
Documentation: connector: Update the description of sink-vdos
usb: misc: usb3503: Fix logic in usb3503_init()
dt-bindings: usb: usb-device: fix typo in required properties
usb: Replace lkml.org links with lore
dt-bindings: usb: dwc3: add description for rk3328
dt-bindings: usb: convert rockchip,dwc3.txt to yaml
usb: quirks: add quirk to start video capture on ELMO L-12F document camera reliable
USB: quirks: sort quirk entries
USB: serial: drop bogus to_usb_serial_port() checks
USB: serial: make remove callback return void
USB: serial: drop if with an always false condition
usb: gadget: Assign boolean values to a bool variable
usb: typec: tcpm: Get Sink VDO from fwnode
dt-bindings: connector: Add SVDM VDO properties
usb: typec: displayport: Fill the negotiated SVDM Version in the header
usb: typec: ucsi: Determine common SVDM Version
usb: typec: tcpm: Determine common SVDM Version
...
Diffstat (limited to 'drivers/usb/phy/phy-tegra-usb.c')
-rw-r--r-- | drivers/usb/phy/phy-tegra-usb.c | 103 |
1 files changed, 92 insertions, 11 deletions
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 03a333797382..a48452a6172b 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -45,6 +45,7 @@ #define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) #define USB_SUSP_CTRL 0x400 +#define USB_WAKE_ON_RESUME_EN BIT(2) #define USB_WAKE_ON_CNNT_EN_DEV BIT(3) #define USB_WAKE_ON_DISCON_EN_DEV BIT(4) #define USB_SUSP_CLR BIT(5) @@ -56,6 +57,15 @@ #define USB_SUSP_SET BIT(14) #define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16) +#define USB_PHY_VBUS_SENSORS 0x404 +#define B_SESS_VLD_WAKEUP_EN BIT(6) +#define B_VBUS_VLD_WAKEUP_EN BIT(14) +#define A_SESS_VLD_WAKEUP_EN BIT(22) +#define A_VBUS_VLD_WAKEUP_EN BIT(30) + +#define USB_PHY_VBUS_WAKEUP_ID 0x408 +#define VBUS_WAKEUP_WAKEUP_EN BIT(30) + #define USB1_LEGACY_CTRL 0x410 #define USB1_NO_LEGACY_MODE BIT(0) #define USB1_VBUS_SENSE_CTL_MASK (3 << 1) @@ -334,6 +344,11 @@ static int utmip_pad_power_on(struct tegra_usb_phy *phy) writel_relaxed(val, base + UTMIP_BIAS_CFG0); } + if (phy->pad_wakeup) { + phy->pad_wakeup = false; + utmip_pad_count--; + } + spin_unlock(&utmip_pad_lock); clk_disable_unprepare(phy->pad_clk); @@ -359,6 +374,17 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy) goto ulock; } + /* + * In accordance to TRM, OTG and Bias pad circuits could be turned off + * to save power if wake is enabled, but the VBUS-change detection + * method is board-specific and these circuits may need to be enabled + * to generate wakeup event, hence we will just keep them both enabled. + */ + if (phy->wakeup_enabled) { + phy->pad_wakeup = true; + utmip_pad_count++; + } + if (--utmip_pad_count == 0) { val = readl_relaxed(base + UTMIP_BIAS_CFG0); val |= UTMIP_OTGPD | UTMIP_BIASPD; @@ -503,11 +529,24 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) writel_relaxed(val, base + UTMIP_PLL_CFG1); } + val = readl_relaxed(base + USB_SUSP_CTRL); + val &= ~USB_WAKE_ON_RESUME_EN; + writel_relaxed(val, base + USB_SUSP_CTRL); + if (phy->mode == USB_DR_MODE_PERIPHERAL) { val = readl_relaxed(base + USB_SUSP_CTRL); val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV); writel_relaxed(val, base + USB_SUSP_CTRL); + val = readl_relaxed(base + USB_PHY_VBUS_WAKEUP_ID); + val &= ~VBUS_WAKEUP_WAKEUP_EN; + writel_relaxed(val, base + USB_PHY_VBUS_WAKEUP_ID); + + val = readl_relaxed(base + USB_PHY_VBUS_SENSORS); + val &= ~(A_VBUS_VLD_WAKEUP_EN | A_SESS_VLD_WAKEUP_EN); + val &= ~(B_VBUS_VLD_WAKEUP_EN | B_SESS_VLD_WAKEUP_EN); + writel_relaxed(val, base + USB_PHY_VBUS_SENSORS); + val = readl_relaxed(base + UTMIP_BAT_CHRG_CFG0); val &= ~UTMIP_PD_CHRG; writel_relaxed(val, base + UTMIP_BAT_CHRG_CFG0); @@ -605,31 +644,51 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) utmi_phy_clk_disable(phy); - if (phy->mode == USB_DR_MODE_PERIPHERAL) { + /* PHY won't resume if reset is asserted */ + if (!phy->wakeup_enabled) { val = readl_relaxed(base + USB_SUSP_CTRL); - val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); - val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5); + val |= UTMIP_RESET; writel_relaxed(val, base + USB_SUSP_CTRL); } - val = readl_relaxed(base + USB_SUSP_CTRL); - val |= UTMIP_RESET; - writel_relaxed(val, base + USB_SUSP_CTRL); - val = readl_relaxed(base + UTMIP_BAT_CHRG_CFG0); val |= UTMIP_PD_CHRG; writel_relaxed(val, base + UTMIP_BAT_CHRG_CFG0); - val = readl_relaxed(base + UTMIP_XCVR_CFG0); - val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | - UTMIP_FORCE_PDZI_POWERDOWN; - writel_relaxed(val, base + UTMIP_XCVR_CFG0); + if (!phy->wakeup_enabled) { + val = readl_relaxed(base + UTMIP_XCVR_CFG0); + val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | + UTMIP_FORCE_PDZI_POWERDOWN; + writel_relaxed(val, base + UTMIP_XCVR_CFG0); + } val = readl_relaxed(base + UTMIP_XCVR_CFG1); val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | UTMIP_FORCE_PDDR_POWERDOWN; writel_relaxed(val, base + UTMIP_XCVR_CFG1); + if (phy->wakeup_enabled) { + val = readl_relaxed(base + USB_SUSP_CTRL); + val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); + val |= USB_WAKEUP_DEBOUNCE_COUNT(5); + val |= USB_WAKE_ON_RESUME_EN; + writel_relaxed(val, base + USB_SUSP_CTRL); + + /* + * Ask VBUS sensor to generate wake event once cable is + * connected. + */ + if (phy->mode == USB_DR_MODE_PERIPHERAL) { + val = readl_relaxed(base + USB_PHY_VBUS_WAKEUP_ID); + val |= VBUS_WAKEUP_WAKEUP_EN; + writel_relaxed(val, base + USB_PHY_VBUS_WAKEUP_ID); + + val = readl_relaxed(base + USB_PHY_VBUS_SENSORS); + val |= A_VBUS_VLD_WAKEUP_EN; + writel_relaxed(val, base + USB_PHY_VBUS_SENSORS); + } + } + return utmip_pad_power_off(phy); } @@ -765,6 +824,15 @@ static int ulpi_phy_power_off(struct tegra_usb_phy *phy) usleep_range(5000, 6000); clk_disable_unprepare(phy->clk); + /* + * Wakeup currently unimplemented for ULPI, thus PHY needs to be + * force-resumed. + */ + if (WARN_ON_ONCE(phy->wakeup_enabled)) { + ulpi_phy_power_on(phy); + return -EOPNOTSUPP; + } + return 0; } @@ -784,6 +852,9 @@ static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) phy->powered_on = true; + /* Let PHY settle down */ + usleep_range(2000, 2500); + return 0; } @@ -824,6 +895,15 @@ static void tegra_usb_phy_shutdown(struct usb_phy *u_phy) phy->freq = NULL; } +static int tegra_usb_phy_set_wakeup(struct usb_phy *u_phy, bool enable) +{ + struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy); + + phy->wakeup_enabled = enable; + + return 0; +} + static int tegra_usb_phy_set_suspend(struct usb_phy *u_phy, int suspend) { struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy); @@ -1195,6 +1275,7 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->u_phy.dev = &pdev->dev; tegra_phy->u_phy.init = tegra_usb_phy_init; tegra_phy->u_phy.shutdown = tegra_usb_phy_shutdown; + tegra_phy->u_phy.set_wakeup = tegra_usb_phy_set_wakeup; tegra_phy->u_phy.set_suspend = tegra_usb_phy_set_suspend; platform_set_drvdata(pdev, tegra_phy); |