usb: dwc3: rockchip: support type-c data role swap

This patch supports fusb302 to do data role swap for
Type-C Dongle with PD adapter.

The test case is:

- Use a Type-C Dongle (PD adapter & USB & HDMI)
- Plug a PD adapter into Type-C Dongle first, then
  connect the Dongle with RK3399 Type-C0 port.
- Check if Type-C Dongle can fetch 5V with the following log:
  "fusb302 4-0022: PD connected as UFP, fetching 5V"
- Wait for the data role swap completion (hundreds of
  milliseconds), then check if the Type-C USB can work
  in DFP mode.

Without this patch, the DWC3 can't switch to DFP mode
after the data role swap completion. It's because that
when the fusb302 do data role swap, it only sends extcon
notifier with EXTCON_USB true or EXTCON_USB_HOST true.
Generally, the sequence of the extcon notifier sent from
fusb302 is:

- send "EXTCON_USB = true" and "EXTCON_USB_HOST=false"
  to DWC3 driver, then DWC3 switch to UFP, and set the
  connected flag to true.

- After swap completion, send "EXTCON_USB = false" and
  "EXTCON_USB_HOST = true" to DWC3 driver. Because the
  connected flag is true, the DWC3 is unable to switch
  to DFP mode.

This patch forces DWC3 to do disconnection if it detects
the connected flag is true and the DWC3 mode is UFP.

Change-Id: I470187823708e6fb8bb8869bca3b475850a8c2e7
Signed-off-by: William Wu <william.wu@rock-chips.com>
This commit is contained in:
William Wu
2018-03-28 18:14:19 +08:00
committed by Tao Huang
parent cde0be2ecb
commit 199fae2be8

View File

@@ -457,8 +457,21 @@ static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work)
} else if (rockchip->edev ?
extcon_get_cable_state_(edev, EXTCON_USB_HOST) :
(dwc->dr_mode == USB_DR_MODE_HOST)) {
if (rockchip->connected)
goto out;
if (rockchip->connected) {
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
/*
* If the connected flag is true, and the DWC3 is
* is in device mode, it means that the Type-C Dongle
* is doing data role swap (UFP -> DFP), so we need
* to disconnect UFP first, and then swich DWC3 to
* DFP depends on the next extcon notifier.
*/
if (DWC3_GCTL_PRTCAP(reg) == DWC3_GCTL_PRTCAP_DEVICE)
goto disconnect;
else
goto out;
}
if (rockchip->skip_suspend) {
pm_runtime_put(dwc->dev);
@@ -538,6 +551,7 @@ static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work)
if (!rockchip->connected)
goto out;
disconnect:
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
/*