mirror of https://github.com/torvalds/linux.git
USB fixes for 6.14-rc6
Here are some small USB driver fixes for some reported issues for 6.14-rc6. These contain: - typec driver fixes - dwc3 driver fixes - xhci driver fixes - renesas controller fixes - gadget driver fixes - a new USB quirk added All of these have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZ83RpQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ykjuwCgtiIGxLWcgV/ZjynWswrovKFX3akAnAh6kW1G +E7ta+MbasbGhI/Kp5pD =iCYy -----END PGP SIGNATURE----- Merge tag 'usb-6.14-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here are some small USB driver fixes for some reported issues. These contain: - typec driver fixes - dwc3 driver fixes - xhci driver fixes - renesas controller fixes - gadget driver fixes - a new USB quirk added All of these have been in linux-next with no reported issues" * tag 'usb-6.14-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: usb: typec: ucsi: Fix NULL pointer access usb: quirks: Add DELAY_INIT and NO_LPM for Prolific Mass Storage Card Reader usb: xhci: Fix host controllers "dying" after suspend and resume usb: dwc3: Set SUSPENDENABLE soon after phy init usb: hub: lack of clearing xHC resources usb: renesas_usbhs: Flush the notify_hotplug_work usb: renesas_usbhs: Use devm_usb_get_phy() usb: renesas_usbhs: Call clk_put() usb: dwc3: gadget: Prevent irq storm when TH re-executes usb: gadget: Check bmAttributes only if configuration is valid xhci: Restrict USB4 tunnel detection for USB3 devices to Intel hosts usb: xhci: Enable the TRB overfetch quirk on VIA VL805 usb: gadget: Fix setting self-powered state on suspend usb: typec: ucsi: increase timeout for PPM reset operations acpi: typec: ucsi: Introduce a ->poll_cci method usb: typec: tcpci_rt1711h: Unmask alert interrupts to fix functionality usb: gadget: Set self-powered based on MaxPower and bmAttributes usb: gadget: u_ether: Set is_suspend flag if remote wakeup fails usb: atm: cxacru: fix a flaw in existing endpoint checks
This commit is contained in:
commit
0dc1f314f8
|
|
@ -1131,7 +1131,10 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
|
||||||
struct cxacru_data *instance;
|
struct cxacru_data *instance;
|
||||||
struct usb_device *usb_dev = interface_to_usbdev(intf);
|
struct usb_device *usb_dev = interface_to_usbdev(intf);
|
||||||
struct usb_host_endpoint *cmd_ep = usb_dev->ep_in[CXACRU_EP_CMD];
|
struct usb_host_endpoint *cmd_ep = usb_dev->ep_in[CXACRU_EP_CMD];
|
||||||
struct usb_endpoint_descriptor *in, *out;
|
static const u8 ep_addrs[] = {
|
||||||
|
CXACRU_EP_CMD + USB_DIR_IN,
|
||||||
|
CXACRU_EP_CMD + USB_DIR_OUT,
|
||||||
|
0};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* instance init */
|
/* instance init */
|
||||||
|
|
@ -1179,13 +1182,11 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usb_endpoint_xfer_int(&cmd_ep->desc))
|
if (usb_endpoint_xfer_int(&cmd_ep->desc))
|
||||||
ret = usb_find_common_endpoints(intf->cur_altsetting,
|
ret = usb_check_int_endpoints(intf, ep_addrs);
|
||||||
NULL, NULL, &in, &out);
|
|
||||||
else
|
else
|
||||||
ret = usb_find_common_endpoints(intf->cur_altsetting,
|
ret = usb_check_bulk_endpoints(intf, ep_addrs);
|
||||||
&in, &out, NULL, NULL);
|
|
||||||
|
|
||||||
if (ret) {
|
if (!ret) {
|
||||||
usb_err(usbatm_instance, "cxacru_bind: interface has incorrect endpoints\n");
|
usb_err(usbatm_instance, "cxacru_bind: interface has incorrect endpoints\n");
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
||||||
|
|
@ -6065,6 +6065,36 @@ void usb_hub_cleanup(void)
|
||||||
usb_deregister(&hub_driver);
|
usb_deregister(&hub_driver);
|
||||||
} /* usb_hub_cleanup() */
|
} /* usb_hub_cleanup() */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hub_hc_release_resources - clear resources used by host controller
|
||||||
|
* @udev: pointer to device being released
|
||||||
|
*
|
||||||
|
* Context: task context, might sleep
|
||||||
|
*
|
||||||
|
* Function releases the host controller resources in correct order before
|
||||||
|
* making any operation on resuming usb device. The host controller resources
|
||||||
|
* allocated for devices in tree should be released starting from the last
|
||||||
|
* usb device in tree toward the root hub. This function is used only during
|
||||||
|
* resuming device when usb device require reinitialization – that is, when
|
||||||
|
* flag udev->reset_resume is set.
|
||||||
|
*
|
||||||
|
* This call is synchronous, and may not be used in an interrupt context.
|
||||||
|
*/
|
||||||
|
static void hub_hc_release_resources(struct usb_device *udev)
|
||||||
|
{
|
||||||
|
struct usb_hub *hub = usb_hub_to_struct_hub(udev);
|
||||||
|
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Release up resources for all children before this device */
|
||||||
|
for (i = 0; i < udev->maxchild; i++)
|
||||||
|
if (hub->ports[i]->child)
|
||||||
|
hub_hc_release_resources(hub->ports[i]->child);
|
||||||
|
|
||||||
|
if (hcd->driver->reset_device)
|
||||||
|
hcd->driver->reset_device(hcd, udev);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* usb_reset_and_verify_device - perform a USB port reset to reinitialize a device
|
* usb_reset_and_verify_device - perform a USB port reset to reinitialize a device
|
||||||
* @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
|
* @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
|
||||||
|
|
@ -6129,6 +6159,9 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
|
||||||
bos = udev->bos;
|
bos = udev->bos;
|
||||||
udev->bos = NULL;
|
udev->bos = NULL;
|
||||||
|
|
||||||
|
if (udev->reset_resume)
|
||||||
|
hub_hc_release_resources(udev);
|
||||||
|
|
||||||
mutex_lock(hcd->address0_mutex);
|
mutex_lock(hcd->address0_mutex);
|
||||||
|
|
||||||
for (i = 0; i < PORT_INIT_TRIES; ++i) {
|
for (i = 0; i < PORT_INIT_TRIES; ++i) {
|
||||||
|
|
|
||||||
|
|
@ -341,6 +341,10 @@ static const struct usb_device_id usb_quirk_list[] = {
|
||||||
{ USB_DEVICE(0x0638, 0x0a13), .driver_info =
|
{ USB_DEVICE(0x0638, 0x0a13), .driver_info =
|
||||||
USB_QUIRK_STRING_FETCH_255 },
|
USB_QUIRK_STRING_FETCH_255 },
|
||||||
|
|
||||||
|
/* Prolific Single-LUN Mass Storage Card Reader */
|
||||||
|
{ USB_DEVICE(0x067b, 0x2731), .driver_info = USB_QUIRK_DELAY_INIT |
|
||||||
|
USB_QUIRK_NO_LPM },
|
||||||
|
|
||||||
/* Saitek Cyborg Gold Joystick */
|
/* Saitek Cyborg Gold Joystick */
|
||||||
{ USB_DEVICE(0x06a3, 0x0006), .driver_info =
|
{ USB_DEVICE(0x06a3, 0x0006), .driver_info =
|
||||||
USB_QUIRK_CONFIG_INTF_STRINGS },
|
USB_QUIRK_CONFIG_INTF_STRINGS },
|
||||||
|
|
|
||||||
|
|
@ -131,11 +131,24 @@ void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
|
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy)
|
||||||
{
|
{
|
||||||
|
unsigned int hw_mode;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
|
||||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE and
|
||||||
|
* GUSB2PHYCFG.SUSPHY should be cleared during mode switching,
|
||||||
|
* and they can be set after core initialization.
|
||||||
|
*/
|
||||||
|
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
|
||||||
|
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && !ignore_susphy) {
|
||||||
|
if (DWC3_GCTL_PRTCAP(reg) != mode)
|
||||||
|
dwc3_enable_susphy(dwc, false);
|
||||||
|
}
|
||||||
|
|
||||||
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
|
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
|
||||||
reg |= DWC3_GCTL_PRTCAPDIR(mode);
|
reg |= DWC3_GCTL_PRTCAPDIR(mode);
|
||||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||||
|
|
@ -216,7 +229,7 @@ static void __dwc3_set_mode(struct work_struct *work)
|
||||||
|
|
||||||
spin_lock_irqsave(&dwc->lock, flags);
|
spin_lock_irqsave(&dwc->lock, flags);
|
||||||
|
|
||||||
dwc3_set_prtcap(dwc, desired_dr_role);
|
dwc3_set_prtcap(dwc, desired_dr_role, false);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||||
|
|
||||||
|
|
@ -658,16 +671,7 @@ static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index)
|
||||||
*/
|
*/
|
||||||
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
|
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
|
||||||
|
|
||||||
/*
|
/* Ensure the GUSB3PIPECTL.SUSPENDENABLE is cleared prior to phy init. */
|
||||||
* Above DWC_usb3.0 1.94a, it is recommended to set
|
|
||||||
* DWC3_GUSB3PIPECTL_SUSPHY to '0' during coreConsultant configuration.
|
|
||||||
* So default value will be '0' when the core is reset. Application
|
|
||||||
* needs to set it to '1' after the core initialization is completed.
|
|
||||||
*
|
|
||||||
* Similarly for DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be
|
|
||||||
* cleared after power-on reset, and it can be set after core
|
|
||||||
* initialization.
|
|
||||||
*/
|
|
||||||
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
|
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
|
||||||
|
|
||||||
if (dwc->u2ss_inp3_quirk)
|
if (dwc->u2ss_inp3_quirk)
|
||||||
|
|
@ -747,15 +751,7 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Ensure the GUSB2PHYCFG.SUSPHY is cleared prior to phy init. */
|
||||||
* Above DWC_usb3.0 1.94a, it is recommended to set
|
|
||||||
* DWC3_GUSB2PHYCFG_SUSPHY to '0' during coreConsultant configuration.
|
|
||||||
* So default value will be '0' when the core is reset. Application
|
|
||||||
* needs to set it to '1' after the core initialization is completed.
|
|
||||||
*
|
|
||||||
* Similarly for DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared
|
|
||||||
* after power-on reset, and it can be set after core initialization.
|
|
||||||
*/
|
|
||||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||||
|
|
||||||
if (dwc->dis_enblslpm_quirk)
|
if (dwc->dis_enblslpm_quirk)
|
||||||
|
|
@ -830,6 +826,25 @@ static int dwc3_phy_init(struct dwc3 *dwc)
|
||||||
goto err_exit_usb3_phy;
|
goto err_exit_usb3_phy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Above DWC_usb3.0 1.94a, it is recommended to set
|
||||||
|
* DWC3_GUSB3PIPECTL_SUSPHY and DWC3_GUSB2PHYCFG_SUSPHY to '0' during
|
||||||
|
* coreConsultant configuration. So default value will be '0' when the
|
||||||
|
* core is reset. Application needs to set it to '1' after the core
|
||||||
|
* initialization is completed.
|
||||||
|
*
|
||||||
|
* Certain phy requires to be in P0 power state during initialization.
|
||||||
|
* Make sure GUSB3PIPECTL.SUSPENDENABLE and GUSB2PHYCFG.SUSPHY are clear
|
||||||
|
* prior to phy init to maintain in the P0 state.
|
||||||
|
*
|
||||||
|
* After phy initialization, some phy operations can only be executed
|
||||||
|
* while in lower P states. Ensure GUSB3PIPECTL.SUSPENDENABLE and
|
||||||
|
* GUSB2PHYCFG.SUSPHY are set soon after initialization to avoid
|
||||||
|
* blocking phy ops.
|
||||||
|
*/
|
||||||
|
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
|
||||||
|
dwc3_enable_susphy(dwc, true);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_exit_usb3_phy:
|
err_exit_usb3_phy:
|
||||||
|
|
@ -1588,7 +1603,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
||||||
|
|
||||||
switch (dwc->dr_mode) {
|
switch (dwc->dr_mode) {
|
||||||
case USB_DR_MODE_PERIPHERAL:
|
case USB_DR_MODE_PERIPHERAL:
|
||||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, false);
|
||||||
|
|
||||||
if (dwc->usb2_phy)
|
if (dwc->usb2_phy)
|
||||||
otg_set_vbus(dwc->usb2_phy->otg, false);
|
otg_set_vbus(dwc->usb2_phy->otg, false);
|
||||||
|
|
@ -1600,7 +1615,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
||||||
return dev_err_probe(dev, ret, "failed to initialize gadget\n");
|
return dev_err_probe(dev, ret, "failed to initialize gadget\n");
|
||||||
break;
|
break;
|
||||||
case USB_DR_MODE_HOST:
|
case USB_DR_MODE_HOST:
|
||||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
|
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST, false);
|
||||||
|
|
||||||
if (dwc->usb2_phy)
|
if (dwc->usb2_phy)
|
||||||
otg_set_vbus(dwc->usb2_phy->otg, true);
|
otg_set_vbus(dwc->usb2_phy->otg, true);
|
||||||
|
|
@ -1645,7 +1660,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* de-assert DRVVBUS for HOST and OTG mode */
|
/* de-assert DRVVBUS for HOST and OTG mode */
|
||||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dwc3_get_software_properties(struct dwc3 *dwc)
|
static void dwc3_get_software_properties(struct dwc3 *dwc)
|
||||||
|
|
@ -1835,8 +1850,6 @@ static void dwc3_get_properties(struct dwc3 *dwc)
|
||||||
dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd;
|
dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd;
|
||||||
dwc->tx_max_burst_prd = tx_max_burst_prd;
|
dwc->tx_max_burst_prd = tx_max_burst_prd;
|
||||||
|
|
||||||
dwc->imod_interval = 0;
|
|
||||||
|
|
||||||
dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num;
|
dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1854,21 +1867,19 @@ static void dwc3_check_params(struct dwc3 *dwc)
|
||||||
unsigned int hwparam_gen =
|
unsigned int hwparam_gen =
|
||||||
DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3);
|
DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3);
|
||||||
|
|
||||||
/* Check for proper value of imod_interval */
|
|
||||||
if (dwc->imod_interval && !dwc3_has_imod(dwc)) {
|
|
||||||
dev_warn(dwc->dev, "Interrupt moderation not supported\n");
|
|
||||||
dwc->imod_interval = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* Enable IMOD for all supporting controllers.
|
||||||
|
*
|
||||||
|
* Particularly, DWC_usb3 v3.00a must enable this feature for
|
||||||
|
* the following reason:
|
||||||
|
*
|
||||||
* Workaround for STAR 9000961433 which affects only version
|
* Workaround for STAR 9000961433 which affects only version
|
||||||
* 3.00a of the DWC_usb3 core. This prevents the controller
|
* 3.00a of the DWC_usb3 core. This prevents the controller
|
||||||
* interrupt from being masked while handling events. IMOD
|
* interrupt from being masked while handling events. IMOD
|
||||||
* allows us to work around this issue. Enable it for the
|
* allows us to work around this issue. Enable it for the
|
||||||
* affected version.
|
* affected version.
|
||||||
*/
|
*/
|
||||||
if (!dwc->imod_interval &&
|
if (dwc3_has_imod((dwc)))
|
||||||
DWC3_VER_IS(DWC3, 300A))
|
|
||||||
dwc->imod_interval = 1;
|
dwc->imod_interval = 1;
|
||||||
|
|
||||||
/* Check the maximum_speed parameter */
|
/* Check the maximum_speed parameter */
|
||||||
|
|
@ -2457,7 +2468,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, true);
|
||||||
dwc3_gadget_resume(dwc);
|
dwc3_gadget_resume(dwc);
|
||||||
break;
|
break;
|
||||||
case DWC3_GCTL_PRTCAP_HOST:
|
case DWC3_GCTL_PRTCAP_HOST:
|
||||||
|
|
@ -2465,7 +2476,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
||||||
ret = dwc3_core_init_for_resume(dwc);
|
ret = dwc3_core_init_for_resume(dwc);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
|
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Restore GUSB2PHYCFG bits that were modified in suspend */
|
/* Restore GUSB2PHYCFG bits that were modified in suspend */
|
||||||
|
|
@ -2494,7 +2505,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
dwc3_set_prtcap(dwc, dwc->current_dr_role);
|
dwc3_set_prtcap(dwc, dwc->current_dr_role, true);
|
||||||
|
|
||||||
dwc3_otg_init(dwc);
|
dwc3_otg_init(dwc);
|
||||||
if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) {
|
if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) {
|
||||||
|
|
|
||||||
|
|
@ -1558,7 +1558,7 @@ struct dwc3_gadget_ep_cmd_params {
|
||||||
#define DWC3_HAS_OTG BIT(3)
|
#define DWC3_HAS_OTG BIT(3)
|
||||||
|
|
||||||
/* prototypes */
|
/* prototypes */
|
||||||
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
|
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy);
|
||||||
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
|
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
|
||||||
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
|
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ void dwc3_otg_init(struct dwc3 *dwc)
|
||||||
* block "Initialize GCTL for OTG operation".
|
* block "Initialize GCTL for OTG operation".
|
||||||
*/
|
*/
|
||||||
/* GCTL.PrtCapDir=2'b11 */
|
/* GCTL.PrtCapDir=2'b11 */
|
||||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
|
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);
|
||||||
/* GUSB2PHYCFG0.SusPHY=0 */
|
/* GUSB2PHYCFG0.SusPHY=0 */
|
||||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||||
|
|
@ -556,7 +556,7 @@ int dwc3_drd_init(struct dwc3 *dwc)
|
||||||
|
|
||||||
dwc3_drd_update(dwc);
|
dwc3_drd_update(dwc);
|
||||||
} else {
|
} else {
|
||||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
|
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);
|
||||||
|
|
||||||
/* use OTG block to get ID event */
|
/* use OTG block to get ID event */
|
||||||
irq = dwc3_otg_get_irq(dwc);
|
irq = dwc3_otg_get_irq(dwc);
|
||||||
|
|
|
||||||
|
|
@ -4501,14 +4501,18 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
|
||||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
|
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
|
||||||
DWC3_GEVNTSIZ_SIZE(evt->length));
|
DWC3_GEVNTSIZ_SIZE(evt->length));
|
||||||
|
|
||||||
|
evt->flags &= ~DWC3_EVENT_PENDING;
|
||||||
|
/*
|
||||||
|
* Add an explicit write memory barrier to make sure that the update of
|
||||||
|
* clearing DWC3_EVENT_PENDING is observed in dwc3_check_event_buf()
|
||||||
|
*/
|
||||||
|
wmb();
|
||||||
|
|
||||||
if (dwc->imod_interval) {
|
if (dwc->imod_interval) {
|
||||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
|
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
|
||||||
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
|
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep the clearing of DWC3_EVENT_PENDING at the end */
|
|
||||||
evt->flags &= ~DWC3_EVENT_PENDING;
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1050,10 +1050,11 @@ static int set_config(struct usb_composite_dev *cdev,
|
||||||
else
|
else
|
||||||
usb_gadget_set_remote_wakeup(gadget, 0);
|
usb_gadget_set_remote_wakeup(gadget, 0);
|
||||||
done:
|
done:
|
||||||
if (power <= USB_SELF_POWER_VBUS_MAX_DRAW)
|
if (power > USB_SELF_POWER_VBUS_MAX_DRAW ||
|
||||||
usb_gadget_set_selfpowered(gadget);
|
(c && !(c->bmAttributes & USB_CONFIG_ATT_SELFPOWER)))
|
||||||
else
|
|
||||||
usb_gadget_clear_selfpowered(gadget);
|
usb_gadget_clear_selfpowered(gadget);
|
||||||
|
else
|
||||||
|
usb_gadget_set_selfpowered(gadget);
|
||||||
|
|
||||||
usb_gadget_vbus_draw(gadget, power);
|
usb_gadget_vbus_draw(gadget, power);
|
||||||
if (result >= 0 && cdev->delayed_status)
|
if (result >= 0 && cdev->delayed_status)
|
||||||
|
|
@ -2615,7 +2616,10 @@ void composite_suspend(struct usb_gadget *gadget)
|
||||||
|
|
||||||
cdev->suspended = 1;
|
cdev->suspended = 1;
|
||||||
|
|
||||||
usb_gadget_set_selfpowered(gadget);
|
if (cdev->config &&
|
||||||
|
cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER)
|
||||||
|
usb_gadget_set_selfpowered(gadget);
|
||||||
|
|
||||||
usb_gadget_vbus_draw(gadget, 2);
|
usb_gadget_vbus_draw(gadget, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2649,8 +2653,11 @@ void composite_resume(struct usb_gadget *gadget)
|
||||||
else
|
else
|
||||||
maxpower = min(maxpower, 900U);
|
maxpower = min(maxpower, 900U);
|
||||||
|
|
||||||
if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW)
|
if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW ||
|
||||||
|
!(cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER))
|
||||||
usb_gadget_clear_selfpowered(gadget);
|
usb_gadget_clear_selfpowered(gadget);
|
||||||
|
else
|
||||||
|
usb_gadget_set_selfpowered(gadget);
|
||||||
|
|
||||||
usb_gadget_vbus_draw(gadget, maxpower);
|
usb_gadget_vbus_draw(gadget, maxpower);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1052,8 +1052,8 @@ void gether_suspend(struct gether *link)
|
||||||
* There is a transfer in progress. So we trigger a remote
|
* There is a transfer in progress. So we trigger a remote
|
||||||
* wakeup to inform the host.
|
* wakeup to inform the host.
|
||||||
*/
|
*/
|
||||||
ether_wakeup_host(dev->port_usb);
|
if (!ether_wakeup_host(dev->port_usb))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
spin_lock_irqsave(&dev->lock, flags);
|
spin_lock_irqsave(&dev->lock, flags);
|
||||||
link->is_suspend = true;
|
link->is_suspend = true;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/unaligned.h>
|
#include <linux/unaligned.h>
|
||||||
#include <linux/bitfield.h>
|
#include <linux/bitfield.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
|
||||||
#include "xhci.h"
|
#include "xhci.h"
|
||||||
#include "xhci-trace.h"
|
#include "xhci-trace.h"
|
||||||
|
|
@ -770,9 +771,16 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
|
||||||
enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
|
enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
|
||||||
struct xhci_port *port)
|
struct xhci_port *port)
|
||||||
{
|
{
|
||||||
|
struct usb_hcd *hcd;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
u32 offset;
|
u32 offset;
|
||||||
|
|
||||||
|
/* Don't try and probe this capability for non-Intel hosts */
|
||||||
|
hcd = xhci_to_hcd(xhci);
|
||||||
|
if (!dev_is_pci(hcd->self.controller) ||
|
||||||
|
to_pci_dev(hcd->self.controller)->vendor != PCI_VENDOR_ID_INTEL)
|
||||||
|
return USB_LINK_UNKNOWN;
|
||||||
|
|
||||||
base = &xhci->cap_regs->hc_capbase;
|
base = &xhci->cap_regs->hc_capbase;
|
||||||
offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_INTEL_SPR_SHADOW);
|
offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_INTEL_SPR_SHADOW);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2437,7 +2437,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||||
* and our use of dma addresses in the trb_address_map radix tree needs
|
* and our use of dma addresses in the trb_address_map radix tree needs
|
||||||
* TRB_SEGMENT_SIZE alignment, so we pick the greater alignment need.
|
* TRB_SEGMENT_SIZE alignment, so we pick the greater alignment need.
|
||||||
*/
|
*/
|
||||||
if (xhci->quirks & XHCI_ZHAOXIN_TRB_FETCH)
|
if (xhci->quirks & XHCI_TRB_OVERFETCH)
|
||||||
|
/* Buggy HC prefetches beyond segment bounds - allocate dummy space at the end */
|
||||||
xhci->segment_pool = dma_pool_create("xHCI ring segments", dev,
|
xhci->segment_pool = dma_pool_create("xHCI ring segments", dev,
|
||||||
TRB_SEGMENT_SIZE * 2, TRB_SEGMENT_SIZE * 2, xhci->page_size * 2);
|
TRB_SEGMENT_SIZE * 2, TRB_SEGMENT_SIZE * 2, xhci->page_size * 2);
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@
|
||||||
#define PCI_DEVICE_ID_ETRON_EJ168 0x7023
|
#define PCI_DEVICE_ID_ETRON_EJ168 0x7023
|
||||||
#define PCI_DEVICE_ID_ETRON_EJ188 0x7052
|
#define PCI_DEVICE_ID_ETRON_EJ188 0x7052
|
||||||
|
|
||||||
|
#define PCI_DEVICE_ID_VIA_VL805 0x3483
|
||||||
|
|
||||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31
|
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31
|
||||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
|
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
|
||||||
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI 0x9cb1
|
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI 0x9cb1
|
||||||
|
|
@ -418,8 +420,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||||
pdev->device == 0x3432)
|
pdev->device == 0x3432)
|
||||||
xhci->quirks |= XHCI_BROKEN_STREAMS;
|
xhci->quirks |= XHCI_BROKEN_STREAMS;
|
||||||
|
|
||||||
if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483)
|
if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) {
|
||||||
xhci->quirks |= XHCI_LPM_SUPPORT;
|
xhci->quirks |= XHCI_LPM_SUPPORT;
|
||||||
|
xhci->quirks |= XHCI_TRB_OVERFETCH;
|
||||||
|
}
|
||||||
|
|
||||||
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
|
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
|
||||||
pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI) {
|
pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI) {
|
||||||
|
|
@ -467,11 +471,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||||
|
|
||||||
if (pdev->device == 0x9202) {
|
if (pdev->device == 0x9202) {
|
||||||
xhci->quirks |= XHCI_RESET_ON_RESUME;
|
xhci->quirks |= XHCI_RESET_ON_RESUME;
|
||||||
xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH;
|
xhci->quirks |= XHCI_TRB_OVERFETCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdev->device == 0x9203)
|
if (pdev->device == 0x9203)
|
||||||
xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH;
|
xhci->quirks |= XHCI_TRB_OVERFETCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdev->vendor == PCI_VENDOR_ID_CDNS &&
|
if (pdev->vendor == PCI_VENDOR_ID_CDNS &&
|
||||||
|
|
|
||||||
|
|
@ -780,8 +780,12 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
|
||||||
struct xhci_segment *seg;
|
struct xhci_segment *seg;
|
||||||
|
|
||||||
ring = xhci->cmd_ring;
|
ring = xhci->cmd_ring;
|
||||||
xhci_for_each_ring_seg(ring->first_seg, seg)
|
xhci_for_each_ring_seg(ring->first_seg, seg) {
|
||||||
|
/* erase all TRBs before the link */
|
||||||
memset(seg->trbs, 0, sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1));
|
memset(seg->trbs, 0, sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1));
|
||||||
|
/* clear link cycle bit */
|
||||||
|
seg->trbs[TRBS_PER_SEGMENT - 1].link.control &= cpu_to_le32(~TRB_CYCLE);
|
||||||
|
}
|
||||||
|
|
||||||
xhci_initialize_ring_info(ring);
|
xhci_initialize_ring_info(ring);
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -1632,7 +1632,7 @@ struct xhci_hcd {
|
||||||
#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(42)
|
#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(42)
|
||||||
#define XHCI_SUSPEND_RESUME_CLKS BIT_ULL(43)
|
#define XHCI_SUSPEND_RESUME_CLKS BIT_ULL(43)
|
||||||
#define XHCI_RESET_TO_DEFAULT BIT_ULL(44)
|
#define XHCI_RESET_TO_DEFAULT BIT_ULL(44)
|
||||||
#define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(45)
|
#define XHCI_TRB_OVERFETCH BIT_ULL(45)
|
||||||
#define XHCI_ZHAOXIN_HOST BIT_ULL(46)
|
#define XHCI_ZHAOXIN_HOST BIT_ULL(46)
|
||||||
#define XHCI_WRITE_64_HI_LO BIT_ULL(47)
|
#define XHCI_WRITE_64_HI_LO BIT_ULL(47)
|
||||||
#define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48)
|
#define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48)
|
||||||
|
|
|
||||||
|
|
@ -312,8 +312,10 @@ static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv)
|
||||||
priv->clks[1] = of_clk_get(dev_of_node(dev), 1);
|
priv->clks[1] = of_clk_get(dev_of_node(dev), 1);
|
||||||
if (PTR_ERR(priv->clks[1]) == -ENOENT)
|
if (PTR_ERR(priv->clks[1]) == -ENOENT)
|
||||||
priv->clks[1] = NULL;
|
priv->clks[1] = NULL;
|
||||||
else if (IS_ERR(priv->clks[1]))
|
else if (IS_ERR(priv->clks[1])) {
|
||||||
|
clk_put(priv->clks[0]);
|
||||||
return PTR_ERR(priv->clks[1]);
|
return PTR_ERR(priv->clks[1]);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -779,6 +781,8 @@ static void usbhs_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
dev_dbg(&pdev->dev, "usb remove\n");
|
dev_dbg(&pdev->dev, "usb remove\n");
|
||||||
|
|
||||||
|
flush_delayed_work(&priv->notify_hotplug_work);
|
||||||
|
|
||||||
/* power off */
|
/* power off */
|
||||||
if (!usbhs_get_dparam(priv, runtime_pwctrl))
|
if (!usbhs_get_dparam(priv, runtime_pwctrl))
|
||||||
usbhsc_power_ctrl(priv, 0);
|
usbhsc_power_ctrl(priv, 0);
|
||||||
|
|
|
||||||
|
|
@ -1094,7 +1094,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
|
||||||
goto usbhs_mod_gadget_probe_err_gpriv;
|
goto usbhs_mod_gadget_probe_err_gpriv;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED);
|
gpriv->transceiver = devm_usb_get_phy(dev, USB_PHY_TYPE_UNDEFINED);
|
||||||
dev_info(dev, "%stransceiver found\n",
|
dev_info(dev, "%stransceiver found\n",
|
||||||
!IS_ERR(gpriv->transceiver) ? "" : "no ");
|
!IS_ERR(gpriv->transceiver) ? "" : "no ");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -334,6 +334,11 @@ static int rt1711h_probe(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct rt1711h_chip *chip;
|
struct rt1711h_chip *chip;
|
||||||
|
const u16 alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED |
|
||||||
|
TCPC_ALERT_TX_FAILED | TCPC_ALERT_RX_HARD_RST |
|
||||||
|
TCPC_ALERT_RX_STATUS | TCPC_ALERT_POWER_STATUS |
|
||||||
|
TCPC_ALERT_CC_STATUS | TCPC_ALERT_RX_BUF_OVF |
|
||||||
|
TCPC_ALERT_FAULT;
|
||||||
|
|
||||||
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
|
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
|
||||||
if (!chip)
|
if (!chip)
|
||||||
|
|
@ -382,6 +387,12 @@ static int rt1711h_probe(struct i2c_client *client)
|
||||||
dev_name(chip->dev), chip);
|
dev_name(chip->dev), chip);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
/* Enable alert interrupts */
|
||||||
|
ret = rt1711h_write16(chip, TCPC_ALERT_MASK, alert_mask);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
enable_irq_wake(client->irq);
|
enable_irq_wake(client->irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
* difficult to estimate the time it takes for the system to process the command
|
* difficult to estimate the time it takes for the system to process the command
|
||||||
* before it is actually passed to the PPM.
|
* before it is actually passed to the PPM.
|
||||||
*/
|
*/
|
||||||
#define UCSI_TIMEOUT_MS 5000
|
#define UCSI_TIMEOUT_MS 10000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* UCSI_SWAP_TIMEOUT_MS - Timeout for role swap requests
|
* UCSI_SWAP_TIMEOUT_MS - Timeout for role swap requests
|
||||||
|
|
@ -1346,7 +1346,7 @@ static int ucsi_reset_ppm(struct ucsi *ucsi)
|
||||||
|
|
||||||
mutex_lock(&ucsi->ppm_lock);
|
mutex_lock(&ucsi->ppm_lock);
|
||||||
|
|
||||||
ret = ucsi->ops->read_cci(ucsi, &cci);
|
ret = ucsi->ops->poll_cci(ucsi, &cci);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -1364,7 +1364,7 @@ static int ucsi_reset_ppm(struct ucsi *ucsi)
|
||||||
|
|
||||||
tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS);
|
tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS);
|
||||||
do {
|
do {
|
||||||
ret = ucsi->ops->read_cci(ucsi, &cci);
|
ret = ucsi->ops->poll_cci(ucsi, &cci);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
if (cci & UCSI_CCI_COMMAND_COMPLETE)
|
if (cci & UCSI_CCI_COMMAND_COMPLETE)
|
||||||
|
|
@ -1393,7 +1393,7 @@ static int ucsi_reset_ppm(struct ucsi *ucsi)
|
||||||
/* Give the PPM time to process a reset before reading CCI */
|
/* Give the PPM time to process a reset before reading CCI */
|
||||||
msleep(20);
|
msleep(20);
|
||||||
|
|
||||||
ret = ucsi->ops->read_cci(ucsi, &cci);
|
ret = ucsi->ops->poll_cci(ucsi, &cci);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -1825,11 +1825,11 @@ static int ucsi_init(struct ucsi *ucsi)
|
||||||
|
|
||||||
err_unregister:
|
err_unregister:
|
||||||
for (con = connector; con->port; con++) {
|
for (con = connector; con->port; con++) {
|
||||||
|
if (con->wq)
|
||||||
|
destroy_workqueue(con->wq);
|
||||||
ucsi_unregister_partner(con);
|
ucsi_unregister_partner(con);
|
||||||
ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON);
|
ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON);
|
||||||
ucsi_unregister_port_psy(con);
|
ucsi_unregister_port_psy(con);
|
||||||
if (con->wq)
|
|
||||||
destroy_workqueue(con->wq);
|
|
||||||
|
|
||||||
usb_power_delivery_unregister_capabilities(con->port_sink_caps);
|
usb_power_delivery_unregister_capabilities(con->port_sink_caps);
|
||||||
con->port_sink_caps = NULL;
|
con->port_sink_caps = NULL;
|
||||||
|
|
@ -1929,8 +1929,8 @@ struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops)
|
||||||
struct ucsi *ucsi;
|
struct ucsi *ucsi;
|
||||||
|
|
||||||
if (!ops ||
|
if (!ops ||
|
||||||
!ops->read_version || !ops->read_cci || !ops->read_message_in ||
|
!ops->read_version || !ops->read_cci || !ops->poll_cci ||
|
||||||
!ops->sync_control || !ops->async_control)
|
!ops->read_message_in || !ops->sync_control || !ops->async_control)
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
ucsi = kzalloc(sizeof(*ucsi), GFP_KERNEL);
|
ucsi = kzalloc(sizeof(*ucsi), GFP_KERNEL);
|
||||||
|
|
@ -2013,10 +2013,6 @@ void ucsi_unregister(struct ucsi *ucsi)
|
||||||
|
|
||||||
for (i = 0; i < ucsi->cap.num_connectors; i++) {
|
for (i = 0; i < ucsi->cap.num_connectors; i++) {
|
||||||
cancel_work_sync(&ucsi->connector[i].work);
|
cancel_work_sync(&ucsi->connector[i].work);
|
||||||
ucsi_unregister_partner(&ucsi->connector[i]);
|
|
||||||
ucsi_unregister_altmodes(&ucsi->connector[i],
|
|
||||||
UCSI_RECIPIENT_CON);
|
|
||||||
ucsi_unregister_port_psy(&ucsi->connector[i]);
|
|
||||||
|
|
||||||
if (ucsi->connector[i].wq) {
|
if (ucsi->connector[i].wq) {
|
||||||
struct ucsi_work *uwork;
|
struct ucsi_work *uwork;
|
||||||
|
|
@ -2032,6 +2028,11 @@ void ucsi_unregister(struct ucsi *ucsi)
|
||||||
destroy_workqueue(ucsi->connector[i].wq);
|
destroy_workqueue(ucsi->connector[i].wq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ucsi_unregister_partner(&ucsi->connector[i]);
|
||||||
|
ucsi_unregister_altmodes(&ucsi->connector[i],
|
||||||
|
UCSI_RECIPIENT_CON);
|
||||||
|
ucsi_unregister_port_psy(&ucsi->connector[i]);
|
||||||
|
|
||||||
usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_sink_caps);
|
usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_sink_caps);
|
||||||
ucsi->connector[i].port_sink_caps = NULL;
|
ucsi->connector[i].port_sink_caps = NULL;
|
||||||
usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_source_caps);
|
usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_source_caps);
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ struct dentry;
|
||||||
* struct ucsi_operations - UCSI I/O operations
|
* struct ucsi_operations - UCSI I/O operations
|
||||||
* @read_version: Read implemented UCSI version
|
* @read_version: Read implemented UCSI version
|
||||||
* @read_cci: Read CCI register
|
* @read_cci: Read CCI register
|
||||||
|
* @poll_cci: Read CCI register while polling with notifications disabled
|
||||||
* @read_message_in: Read message data from UCSI
|
* @read_message_in: Read message data from UCSI
|
||||||
* @sync_control: Blocking control operation
|
* @sync_control: Blocking control operation
|
||||||
* @async_control: Non-blocking control operation
|
* @async_control: Non-blocking control operation
|
||||||
|
|
@ -76,6 +77,7 @@ struct dentry;
|
||||||
struct ucsi_operations {
|
struct ucsi_operations {
|
||||||
int (*read_version)(struct ucsi *ucsi, u16 *version);
|
int (*read_version)(struct ucsi *ucsi, u16 *version);
|
||||||
int (*read_cci)(struct ucsi *ucsi, u32 *cci);
|
int (*read_cci)(struct ucsi *ucsi, u32 *cci);
|
||||||
|
int (*poll_cci)(struct ucsi *ucsi, u32 *cci);
|
||||||
int (*read_message_in)(struct ucsi *ucsi, void *val, size_t val_len);
|
int (*read_message_in)(struct ucsi *ucsi, void *val, size_t val_len);
|
||||||
int (*sync_control)(struct ucsi *ucsi, u64 command);
|
int (*sync_control)(struct ucsi *ucsi, u64 command);
|
||||||
int (*async_control)(struct ucsi *ucsi, u64 command);
|
int (*async_control)(struct ucsi *ucsi, u64 command);
|
||||||
|
|
|
||||||
|
|
@ -59,19 +59,24 @@ static int ucsi_acpi_read_version(struct ucsi *ucsi, u16 *version)
|
||||||
static int ucsi_acpi_read_cci(struct ucsi *ucsi, u32 *cci)
|
static int ucsi_acpi_read_cci(struct ucsi *ucsi, u32 *cci)
|
||||||
{
|
{
|
||||||
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) {
|
|
||||||
ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(cci, ua->base + UCSI_CCI, sizeof(*cci));
|
memcpy(cci, ua->base + UCSI_CCI, sizeof(*cci));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ucsi_acpi_poll_cci(struct ucsi *ucsi, u32 *cci)
|
||||||
|
{
|
||||||
|
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return ucsi_acpi_read_cci(ucsi, cci);
|
||||||
|
}
|
||||||
|
|
||||||
static int ucsi_acpi_read_message_in(struct ucsi *ucsi, void *val, size_t val_len)
|
static int ucsi_acpi_read_message_in(struct ucsi *ucsi, void *val, size_t val_len)
|
||||||
{
|
{
|
||||||
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
||||||
|
|
@ -94,6 +99,7 @@ static int ucsi_acpi_async_control(struct ucsi *ucsi, u64 command)
|
||||||
static const struct ucsi_operations ucsi_acpi_ops = {
|
static const struct ucsi_operations ucsi_acpi_ops = {
|
||||||
.read_version = ucsi_acpi_read_version,
|
.read_version = ucsi_acpi_read_version,
|
||||||
.read_cci = ucsi_acpi_read_cci,
|
.read_cci = ucsi_acpi_read_cci,
|
||||||
|
.poll_cci = ucsi_acpi_poll_cci,
|
||||||
.read_message_in = ucsi_acpi_read_message_in,
|
.read_message_in = ucsi_acpi_read_message_in,
|
||||||
.sync_control = ucsi_sync_control_common,
|
.sync_control = ucsi_sync_control_common,
|
||||||
.async_control = ucsi_acpi_async_control
|
.async_control = ucsi_acpi_async_control
|
||||||
|
|
@ -142,6 +148,7 @@ static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command)
|
||||||
static const struct ucsi_operations ucsi_gram_ops = {
|
static const struct ucsi_operations ucsi_gram_ops = {
|
||||||
.read_version = ucsi_acpi_read_version,
|
.read_version = ucsi_acpi_read_version,
|
||||||
.read_cci = ucsi_acpi_read_cci,
|
.read_cci = ucsi_acpi_read_cci,
|
||||||
|
.poll_cci = ucsi_acpi_poll_cci,
|
||||||
.read_message_in = ucsi_gram_read_message_in,
|
.read_message_in = ucsi_gram_read_message_in,
|
||||||
.sync_control = ucsi_gram_sync_control,
|
.sync_control = ucsi_gram_sync_control,
|
||||||
.async_control = ucsi_acpi_async_control
|
.async_control = ucsi_acpi_async_control
|
||||||
|
|
|
||||||
|
|
@ -664,6 +664,7 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command)
|
||||||
static const struct ucsi_operations ucsi_ccg_ops = {
|
static const struct ucsi_operations ucsi_ccg_ops = {
|
||||||
.read_version = ucsi_ccg_read_version,
|
.read_version = ucsi_ccg_read_version,
|
||||||
.read_cci = ucsi_ccg_read_cci,
|
.read_cci = ucsi_ccg_read_cci,
|
||||||
|
.poll_cci = ucsi_ccg_read_cci,
|
||||||
.read_message_in = ucsi_ccg_read_message_in,
|
.read_message_in = ucsi_ccg_read_message_in,
|
||||||
.sync_control = ucsi_ccg_sync_control,
|
.sync_control = ucsi_ccg_sync_control,
|
||||||
.async_control = ucsi_ccg_async_control,
|
.async_control = ucsi_ccg_async_control,
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,7 @@ static void pmic_glink_ucsi_connector_status(struct ucsi_connector *con)
|
||||||
static const struct ucsi_operations pmic_glink_ucsi_ops = {
|
static const struct ucsi_operations pmic_glink_ucsi_ops = {
|
||||||
.read_version = pmic_glink_ucsi_read_version,
|
.read_version = pmic_glink_ucsi_read_version,
|
||||||
.read_cci = pmic_glink_ucsi_read_cci,
|
.read_cci = pmic_glink_ucsi_read_cci,
|
||||||
|
.poll_cci = pmic_glink_ucsi_read_cci,
|
||||||
.read_message_in = pmic_glink_ucsi_read_message_in,
|
.read_message_in = pmic_glink_ucsi_read_message_in,
|
||||||
.sync_control = ucsi_sync_control_common,
|
.sync_control = ucsi_sync_control_common,
|
||||||
.async_control = pmic_glink_ucsi_async_control,
|
.async_control = pmic_glink_ucsi_async_control,
|
||||||
|
|
|
||||||
|
|
@ -424,6 +424,7 @@ static irqreturn_t ucsi_stm32g0_irq_handler(int irq, void *data)
|
||||||
static const struct ucsi_operations ucsi_stm32g0_ops = {
|
static const struct ucsi_operations ucsi_stm32g0_ops = {
|
||||||
.read_version = ucsi_stm32g0_read_version,
|
.read_version = ucsi_stm32g0_read_version,
|
||||||
.read_cci = ucsi_stm32g0_read_cci,
|
.read_cci = ucsi_stm32g0_read_cci,
|
||||||
|
.poll_cci = ucsi_stm32g0_read_cci,
|
||||||
.read_message_in = ucsi_stm32g0_read_message_in,
|
.read_message_in = ucsi_stm32g0_read_message_in,
|
||||||
.sync_control = ucsi_sync_control_common,
|
.sync_control = ucsi_sync_control_common,
|
||||||
.async_control = ucsi_stm32g0_async_control,
|
.async_control = ucsi_stm32g0_async_control,
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ static int yoga_c630_ucsi_async_control(struct ucsi *ucsi, u64 command)
|
||||||
static const struct ucsi_operations yoga_c630_ucsi_ops = {
|
static const struct ucsi_operations yoga_c630_ucsi_ops = {
|
||||||
.read_version = yoga_c630_ucsi_read_version,
|
.read_version = yoga_c630_ucsi_read_version,
|
||||||
.read_cci = yoga_c630_ucsi_read_cci,
|
.read_cci = yoga_c630_ucsi_read_cci,
|
||||||
|
.poll_cci = yoga_c630_ucsi_read_cci,
|
||||||
.read_message_in = yoga_c630_ucsi_read_message_in,
|
.read_message_in = yoga_c630_ucsi_read_message_in,
|
||||||
.sync_control = ucsi_sync_control_common,
|
.sync_control = ucsi_sync_control_common,
|
||||||
.async_control = yoga_c630_ucsi_async_control,
|
.async_control = yoga_c630_ucsi_async_control,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue