USB fixes for 4.7-rc4
Here are a bunch (65) of USB fixes for 4.7-rc4. Sorry about the quantity, I've been slow in getting these out. The majority are the "normal" gadget, musb, and xhci fixes, that we all are used to. There are also a few other tiny fixes resolving a number of reported issues that showed up in 4.7-rc1. All of these have been in linux-next. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAldlbRgACgkQMUfUDdst+ynNQACeMwami14392grxjLQvhCtR29u ekkAoMK+vLu79mbLPhoBmPo4YCUvSptw =1X1d -----END PGP SIGNATURE----- Merge tag 'usb-4.7-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here are a bunch (65) of USB fixes for 4.7-rc4. Sorry about the quantity, I've been slow in getting these out. The majority are the "normal" gadget, musb, and xhci fixes, that we all are used to. There are also a few other tiny fixes resolving a number of reported issues that showed up in 4.7-rc1. All of these have been in linux-next" * tag 'usb-4.7-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (65 commits) usbip: rate limit get_frame_number message usb: musb: sunxi: Remove bogus "Frees glue" comment usb: musb: sunxi: Fix NULL ptr deref when gadget is registered before musb usb: echi-hcd: Add ehci_setup check before echi_shutdown usb: host: ehci-msm: Conditionally call ehci suspend/resume MAINTAINERS: Add file patterns for usb device tree bindings usb: host: ehci-tegra: Avoid getting the same reset twice usb: host: ehci-tegra: Grab the correct UTMI pads reset USB: mos7720: delete parport USB: OHCI: Don't mark EDs as ED_OPER if scheduling fails phy: ti-pipe3: Program the DPLL even if it was already locked usb: musb: Stop bulk endpoint while queue is rotated usb: musb: Ensure rx reinit occurs for shared_fifo endpoints usb: musb: host: correct cppi dma channel for isoch transfer usb: musb: only restore devctl when session was set in backup usb: phy: Check initial state for twl6030 usb: musb: Use normal module_init for 2430 glue usb: musb: Remove pm_runtime_set_irq_safe usb: musb: Remove extra PM runtime calls from 2430 glue layer usb: musb: Return error value from musb_mailbox ...
This commit is contained in:
commit
e80dac114c
|
@ -1,6 +1,6 @@
|
|||
What: /config/usb-gadget/gadget/functions/uvc.name
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: UVC function directory
|
||||
|
||||
streaming_maxburst - 0..15 (ss only)
|
||||
|
@ -9,37 +9,37 @@ Description: UVC function directory
|
|||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/control
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Control descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/control/class
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Class descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/control/class/ss
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Super speed control class descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/control/class/fs
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Full speed control class descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Terminal descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/output
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Output terminal descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/output/default
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Default output terminal descriptors
|
||||
|
||||
All attributes read only:
|
||||
|
@ -53,12 +53,12 @@ Description: Default output terminal descriptors
|
|||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/camera
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Camera terminal descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/camera/default
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Default camera terminal descriptors
|
||||
|
||||
All attributes read only:
|
||||
|
@ -75,12 +75,12 @@ Description: Default camera terminal descriptors
|
|||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/control/processing
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Processing unit descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/control/processing/default
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Default processing unit descriptors
|
||||
|
||||
All attributes read only:
|
||||
|
@ -94,49 +94,49 @@ Description: Default processing unit descriptors
|
|||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/control/header
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Control header descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/control/header/name
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Specific control header descriptors
|
||||
|
||||
dwClockFrequency
|
||||
bcdUVC
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Streaming descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Streaming class descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/ss
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Super speed streaming class descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/hs
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: High speed streaming class descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/fs
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Full speed streaming class descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Color matching descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching/default
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Default color matching descriptors
|
||||
|
||||
All attributes read only:
|
||||
|
@ -150,12 +150,12 @@ Description: Default color matching descriptors
|
|||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: MJPEG format descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg/name
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Specific MJPEG format descriptors
|
||||
|
||||
All attributes read only,
|
||||
|
@ -174,7 +174,7 @@ Description: Specific MJPEG format descriptors
|
|||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg/name/name
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Specific MJPEG frame descriptors
|
||||
|
||||
dwFrameInterval - indicates how frame interval can be
|
||||
|
@ -196,12 +196,12 @@ Description: Specific MJPEG frame descriptors
|
|||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Uncompressed format descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed/name
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Specific uncompressed format descriptors
|
||||
|
||||
bmaControls - this format's data for bmaControls in
|
||||
|
@ -221,7 +221,7 @@ Description: Specific uncompressed format descriptors
|
|||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed/name/name
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Specific uncompressed frame descriptors
|
||||
|
||||
dwFrameInterval - indicates how frame interval can be
|
||||
|
@ -243,12 +243,12 @@ Description: Specific uncompressed frame descriptors
|
|||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/header
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Streaming header descriptors
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/header/name
|
||||
Date: Dec 2014
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Description: Specific streaming header descriptors
|
||||
|
||||
All attributes read only:
|
||||
|
|
|
@ -11975,6 +11975,7 @@ L: linux-usb@vger.kernel.org
|
|||
W: http://www.linux-usb.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/usb/
|
||||
F: Documentation/usb/
|
||||
F: drivers/usb/
|
||||
F: include/linux/usb.h
|
||||
|
|
|
@ -233,8 +233,12 @@ static inline int __is_running(const struct exynos_mipi_phy_desc *data,
|
|||
struct exynos_mipi_video_phy *state)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val);
|
||||
return val & data->resetn_val;
|
||||
}
|
||||
|
||||
|
|
|
@ -293,11 +293,18 @@ static int ti_pipe3_init(struct phy *x)
|
|||
ret = ti_pipe3_dpll_wait_lock(phy);
|
||||
}
|
||||
|
||||
/* Program the DPLL only if not locked */
|
||||
/* SATA has issues if re-programmed when locked */
|
||||
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
|
||||
if (!(val & PLL_LOCK))
|
||||
if (ti_pipe3_dpll_program(phy))
|
||||
return -EINVAL;
|
||||
if ((val & PLL_LOCK) && of_device_is_compatible(phy->dev->of_node,
|
||||
"ti,phy-pipe3-sata"))
|
||||
return ret;
|
||||
|
||||
/* Program the DPLL */
|
||||
ret = ti_pipe3_dpll_program(phy);
|
||||
if (ret) {
|
||||
ti_pipe3_disable_clocks(phy);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -463,7 +463,8 @@ static int twl4030_phy_power_on(struct phy *phy)
|
|||
twl4030_usb_set_mode(twl, twl->usb_mode);
|
||||
if (twl->usb_mode == T2_USB_MODE_ULPI)
|
||||
twl4030_i2c_access(twl, 0);
|
||||
schedule_delayed_work(&twl->id_workaround_work, 0);
|
||||
twl->linkstat = MUSB_UNKNOWN;
|
||||
schedule_delayed_work(&twl->id_workaround_work, HZ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -537,6 +538,7 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
|
|||
struct twl4030_usb *twl = _twl;
|
||||
enum musb_vbus_id_status status;
|
||||
bool status_changed = false;
|
||||
int err;
|
||||
|
||||
status = twl4030_usb_linkstat(twl);
|
||||
|
||||
|
@ -567,7 +569,9 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
|
|||
pm_runtime_mark_last_busy(twl->dev);
|
||||
pm_runtime_put_autosuspend(twl->dev);
|
||||
}
|
||||
musb_mailbox(status);
|
||||
err = musb_mailbox(status);
|
||||
if (err)
|
||||
twl->linkstat = MUSB_UNKNOWN;
|
||||
}
|
||||
|
||||
/* don't schedule during sleep - irq works right then */
|
||||
|
@ -595,7 +599,8 @@ static int twl4030_phy_init(struct phy *phy)
|
|||
struct twl4030_usb *twl = phy_get_drvdata(phy);
|
||||
|
||||
pm_runtime_get_sync(twl->dev);
|
||||
schedule_delayed_work(&twl->id_workaround_work, 0);
|
||||
twl->linkstat = MUSB_UNKNOWN;
|
||||
schedule_delayed_work(&twl->id_workaround_work, HZ);
|
||||
pm_runtime_mark_last_busy(twl->dev);
|
||||
pm_runtime_put_autosuspend(twl->dev);
|
||||
|
||||
|
@ -763,7 +768,8 @@ static int twl4030_usb_remove(struct platform_device *pdev)
|
|||
if (cable_present(twl->linkstat))
|
||||
pm_runtime_put_noidle(twl->dev);
|
||||
pm_runtime_mark_last_busy(twl->dev);
|
||||
pm_runtime_put_sync_suspend(twl->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_put_sync(twl->dev);
|
||||
pm_runtime_disable(twl->dev);
|
||||
|
||||
/* autogate 60MHz ULPI clock,
|
||||
|
|
|
@ -44,6 +44,9 @@ static const struct usb_device_id usb_quirk_list[] = {
|
|||
/* Creative SB Audigy 2 NX */
|
||||
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
/* USB3503 */
|
||||
{ USB_DEVICE(0x0424, 0x3503), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
/* Microsoft Wireless Laser Mouse 6000 Receiver */
|
||||
{ USB_DEVICE(0x045e, 0x00e1), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
|
@ -173,6 +176,10 @@ static const struct usb_device_id usb_quirk_list[] = {
|
|||
/* MAYA44USB sound device */
|
||||
{ USB_DEVICE(0x0a92, 0x0091), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
/* ASUS Base Station(T100) */
|
||||
{ USB_DEVICE(0x0b05, 0x17e0), .driver_info =
|
||||
USB_QUIRK_IGNORE_REMOTE_WAKEUP },
|
||||
|
||||
/* Action Semiconductor flash disk */
|
||||
{ USB_DEVICE(0x10d6, 0x2200), .driver_info =
|
||||
USB_QUIRK_STRING_FETCH_255 },
|
||||
|
@ -188,26 +195,22 @@ static const struct usb_device_id usb_quirk_list[] = {
|
|||
{ USB_DEVICE(0x1908, 0x1315), .driver_info =
|
||||
USB_QUIRK_HONOR_BNUMINTERFACES },
|
||||
|
||||
/* INTEL VALUE SSD */
|
||||
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
/* USB3503 */
|
||||
{ USB_DEVICE(0x0424, 0x3503), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
/* ASUS Base Station(T100) */
|
||||
{ USB_DEVICE(0x0b05, 0x17e0), .driver_info =
|
||||
USB_QUIRK_IGNORE_REMOTE_WAKEUP },
|
||||
|
||||
/* Protocol and OTG Electrical Test Device */
|
||||
{ USB_DEVICE(0x1a0a, 0x0200), .driver_info =
|
||||
USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
|
||||
|
||||
/* Acer C120 LED Projector */
|
||||
{ USB_DEVICE(0x1de1, 0xc102), .driver_info = USB_QUIRK_NO_LPM },
|
||||
|
||||
/* Blackmagic Design Intensity Shuttle */
|
||||
{ USB_DEVICE(0x1edb, 0xbd3b), .driver_info = USB_QUIRK_NO_LPM },
|
||||
|
||||
/* Blackmagic Design UltraStudio SDI */
|
||||
{ USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM },
|
||||
|
||||
/* INTEL VALUE SSD */
|
||||
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
{ } /* terminating entry must be last */
|
||||
};
|
||||
|
||||
|
|
|
@ -64,6 +64,17 @@
|
|||
DWC2_TRACE_SCHEDULER_VB(pr_fmt("%s: SCH: " fmt), \
|
||||
dev_name(hsotg->dev), ##__VA_ARGS__)
|
||||
|
||||
#ifdef CONFIG_MIPS
|
||||
/*
|
||||
* There are some MIPS machines that can run in either big-endian
|
||||
* or little-endian mode and that use the dwc2 register without
|
||||
* a byteswap in both ways.
|
||||
* Unlike other architectures, MIPS apparently does not require a
|
||||
* barrier before the __raw_writel() to synchronize with DMA but does
|
||||
* require the barrier after the __raw_writel() to serialize a set of
|
||||
* writes. This set of operations was added specifically for MIPS and
|
||||
* should only be used there.
|
||||
*/
|
||||
static inline u32 dwc2_readl(const void __iomem *addr)
|
||||
{
|
||||
u32 value = __raw_readl(addr);
|
||||
|
@ -90,6 +101,22 @@ static inline void dwc2_writel(u32 value, void __iomem *addr)
|
|||
pr_info("INFO:: wrote %08x to %p\n", value, addr);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
/* Normal architectures just use readl/write */
|
||||
static inline u32 dwc2_readl(const void __iomem *addr)
|
||||
{
|
||||
return readl(addr);
|
||||
}
|
||||
|
||||
static inline void dwc2_writel(u32 value, void __iomem *addr)
|
||||
{
|
||||
writel(value, addr);
|
||||
|
||||
#ifdef DWC2_LOG_WRITES
|
||||
pr_info("info:: wrote %08x to %p\n", value, addr);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Maximum number of Endpoints/HostChannels */
|
||||
#define MAX_EPS_CHANNELS 16
|
||||
|
|
|
@ -1018,7 +1018,7 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value);
|
||||
static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now);
|
||||
|
||||
/**
|
||||
* get_ep_head - return the first request on the endpoint
|
||||
|
@ -1094,7 +1094,7 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
|
|||
case USB_ENDPOINT_HALT:
|
||||
halted = ep->halted;
|
||||
|
||||
dwc2_hsotg_ep_sethalt(&ep->ep, set);
|
||||
dwc2_hsotg_ep_sethalt(&ep->ep, set, true);
|
||||
|
||||
ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0);
|
||||
if (ret) {
|
||||
|
@ -2948,8 +2948,13 @@ static int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
|
|||
* dwc2_hsotg_ep_sethalt - set halt on a given endpoint
|
||||
* @ep: The endpoint to set halt.
|
||||
* @value: Set or unset the halt.
|
||||
* @now: If true, stall the endpoint now. Otherwise return -EAGAIN if
|
||||
* the endpoint is busy processing requests.
|
||||
*
|
||||
* We need to stall the endpoint immediately if request comes from set_feature
|
||||
* protocol command handler.
|
||||
*/
|
||||
static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value)
|
||||
static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now)
|
||||
{
|
||||
struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
|
||||
struct dwc2_hsotg *hs = hs_ep->parent;
|
||||
|
@ -2969,6 +2974,17 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (hs_ep->isochronous) {
|
||||
dev_err(hs->dev, "%s is Isochronous Endpoint\n", ep->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!now && value && !list_empty(&hs_ep->queue)) {
|
||||
dev_dbg(hs->dev, "%s request is pending, cannot halt\n",
|
||||
ep->name);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (hs_ep->dir_in) {
|
||||
epreg = DIEPCTL(index);
|
||||
epctl = dwc2_readl(hs->regs + epreg);
|
||||
|
@ -3020,7 +3036,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value)
|
|||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&hs->lock, flags);
|
||||
ret = dwc2_hsotg_ep_sethalt(ep, value);
|
||||
ret = dwc2_hsotg_ep_sethalt(ep, value, false);
|
||||
spin_unlock_irqrestore(&hs->lock, flags);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -402,6 +402,7 @@
|
|||
#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
|
||||
#define DWC3_DEPCMD_STATUS(x) (((x) >> 12) & 0x0F)
|
||||
#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
|
||||
#define DWC3_DEPCMD_CLEARPENDIN (1 << 11)
|
||||
#define DWC3_DEPCMD_CMDACT (1 << 10)
|
||||
#define DWC3_DEPCMD_CMDIOC (1 << 8)
|
||||
|
||||
|
|
|
@ -128,12 +128,6 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, exynos);
|
||||
|
||||
ret = dwc3_exynos_register_phys(exynos);
|
||||
if (ret) {
|
||||
dev_err(dev, "couldn't register PHYs\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
exynos->dev = dev;
|
||||
|
||||
exynos->clk = devm_clk_get(dev, "usbdrd30");
|
||||
|
@ -183,20 +177,29 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
|
|||
goto err3;
|
||||
}
|
||||
|
||||
ret = dwc3_exynos_register_phys(exynos);
|
||||
if (ret) {
|
||||
dev_err(dev, "couldn't register PHYs\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
ret = of_platform_populate(node, NULL, NULL, dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add dwc3 core\n");
|
||||
goto err4;
|
||||
goto err5;
|
||||
}
|
||||
} else {
|
||||
dev_err(dev, "no device node, failed to add dwc3 core\n");
|
||||
ret = -ENODEV;
|
||||
goto err4;
|
||||
goto err5;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err5:
|
||||
platform_device_unregister(exynos->usb2_phy);
|
||||
platform_device_unregister(exynos->usb3_phy);
|
||||
err4:
|
||||
regulator_disable(exynos->vdd10);
|
||||
err3:
|
||||
|
|
|
@ -129,12 +129,18 @@ static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data)
|
|||
switch (dwc3_data->dr_mode) {
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
|
||||
val &= ~(USB3_FORCE_VBUSVALID | USB3_DELAY_VBUSVALID
|
||||
val &= ~(USB3_DELAY_VBUSVALID
|
||||
| USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3)
|
||||
| USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2
|
||||
| USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);
|
||||
|
||||
val |= USB3_DEVICE_NOT_HOST;
|
||||
/*
|
||||
* USB3_PORT2_FORCE_VBUSVALID When '1' and when
|
||||
* USB3_PORT2_DEVICE_NOT_HOST = 1, forces VBUSVLDEXT2 input
|
||||
* of the pico PHY to 1.
|
||||
*/
|
||||
|
||||
val |= USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID;
|
||||
break;
|
||||
|
||||
case USB_DR_MODE_HOST:
|
||||
|
|
|
@ -347,6 +347,28 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
u32 cmd = DWC3_DEPCMD_CLEARSTALL;
|
||||
|
||||
/*
|
||||
* As of core revision 2.60a the recommended programming model
|
||||
* is to set the ClearPendIN bit when issuing a Clear Stall EP
|
||||
* command for IN endpoints. This is to prevent an issue where
|
||||
* some (non-compliant) hosts may not send ACK TPs for pending
|
||||
* IN transfers due to a mishandled error condition. Synopsys
|
||||
* STAR 9000614252.
|
||||
*/
|
||||
if (dep->direction && (dwc->revision >= DWC3_REVISION_260A))
|
||||
cmd |= DWC3_DEPCMD_CLEARPENDIN;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
return dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms);
|
||||
}
|
||||
|
||||
static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
|
||||
struct dwc3_trb *trb)
|
||||
{
|
||||
|
@ -1314,8 +1336,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
|
|||
else
|
||||
dep->flags |= DWC3_EP_STALL;
|
||||
} else {
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
|
||||
DWC3_DEPCMD_CLEARSTALL, ¶ms);
|
||||
ret = dwc3_send_clear_stall_ep_cmd(dep);
|
||||
if (ret)
|
||||
dev_err(dwc->dev, "failed to clear STALL on %s\n",
|
||||
dep->name);
|
||||
|
@ -2247,7 +2268,6 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
|
|||
|
||||
for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
|
||||
struct dwc3_ep *dep;
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
int ret;
|
||||
|
||||
dep = dwc->eps[epnum];
|
||||
|
@ -2259,9 +2279,7 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
|
|||
|
||||
dep->flags &= ~DWC3_EP_STALL;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
|
||||
DWC3_DEPCMD_CLEARSTALL, ¶ms);
|
||||
ret = dwc3_send_clear_stall_ep_cmd(dep);
|
||||
WARN_ON_ONCE(ret);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1868,14 +1868,19 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
}
|
||||
break;
|
||||
}
|
||||
req->length = value;
|
||||
req->context = cdev;
|
||||
req->zero = value < w_length;
|
||||
value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
|
||||
if (value < 0) {
|
||||
DBG(cdev, "ep_queue --> %d\n", value);
|
||||
req->status = 0;
|
||||
composite_setup_complete(gadget->ep0, req);
|
||||
|
||||
if (value >= 0) {
|
||||
req->length = value;
|
||||
req->context = cdev;
|
||||
req->zero = value < w_length;
|
||||
value = composite_ep0_queue(cdev, req,
|
||||
GFP_ATOMIC);
|
||||
if (value < 0) {
|
||||
DBG(cdev, "ep_queue --> %d\n", value);
|
||||
req->status = 0;
|
||||
composite_setup_complete(gadget->ep0,
|
||||
req);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -1401,6 +1401,7 @@ static const struct usb_gadget_driver configfs_driver_template = {
|
|||
.owner = THIS_MODULE,
|
||||
.name = "configfs-gadget",
|
||||
},
|
||||
.match_existing_only = 1,
|
||||
};
|
||||
|
||||
static struct config_group *gadgets_make(
|
||||
|
|
|
@ -2051,7 +2051,7 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
|
|||
|
||||
if (len < sizeof(*d) ||
|
||||
d->bFirstInterfaceNumber >= ffs->interfaces_count ||
|
||||
d->Reserved1)
|
||||
!d->Reserved1)
|
||||
return -EINVAL;
|
||||
for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i)
|
||||
if (d->Reserved2[i])
|
||||
|
@ -2729,6 +2729,7 @@ static int _ffs_func_bind(struct usb_configuration *c,
|
|||
func->ffs->ss_descs_count;
|
||||
|
||||
int fs_len, hs_len, ss_len, ret, i;
|
||||
struct ffs_ep *eps_ptr;
|
||||
|
||||
/* Make it a single chunk, less management later on */
|
||||
vla_group(d);
|
||||
|
@ -2777,12 +2778,9 @@ static int _ffs_func_bind(struct usb_configuration *c,
|
|||
ffs->raw_descs_length);
|
||||
|
||||
memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
|
||||
for (ret = ffs->eps_count; ret; --ret) {
|
||||
struct ffs_ep *ptr;
|
||||
|
||||
ptr = vla_ptr(vlabuf, d, eps);
|
||||
ptr[ret].num = -1;
|
||||
}
|
||||
eps_ptr = vla_ptr(vlabuf, d, eps);
|
||||
for (i = 0; i < ffs->eps_count; i++)
|
||||
eps_ptr[i].num = -1;
|
||||
|
||||
/* Save pointers
|
||||
* d_eps == vlabuf, func->eps used to kfree vlabuf later
|
||||
|
@ -2851,7 +2849,7 @@ static int _ffs_func_bind(struct usb_configuration *c,
|
|||
goto error;
|
||||
|
||||
func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table);
|
||||
if (c->cdev->use_os_string)
|
||||
if (c->cdev->use_os_string) {
|
||||
for (i = 0; i < ffs->interfaces_count; ++i) {
|
||||
struct usb_os_desc *desc;
|
||||
|
||||
|
@ -2862,13 +2860,15 @@ static int _ffs_func_bind(struct usb_configuration *c,
|
|||
vla_ptr(vlabuf, d, ext_compat) + i * 16;
|
||||
INIT_LIST_HEAD(&desc->ext_prop);
|
||||
}
|
||||
ret = ffs_do_os_descs(ffs->ms_os_descs_count,
|
||||
vla_ptr(vlabuf, d, raw_descs) +
|
||||
fs_len + hs_len + ss_len,
|
||||
d_raw_descs__sz - fs_len - hs_len - ss_len,
|
||||
__ffs_func_bind_do_os_desc, func);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
ret = ffs_do_os_descs(ffs->ms_os_descs_count,
|
||||
vla_ptr(vlabuf, d, raw_descs) +
|
||||
fs_len + hs_len + ss_len,
|
||||
d_raw_descs__sz - fs_len - hs_len -
|
||||
ss_len,
|
||||
__ffs_func_bind_do_os_desc, func);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
}
|
||||
func->function.os_desc_n =
|
||||
c->cdev->use_os_string ? ffs->interfaces_count : 0;
|
||||
|
||||
|
|
|
@ -161,14 +161,6 @@ static struct usb_endpoint_descriptor hs_ep_out_desc = {
|
|||
.wMaxPacketSize = cpu_to_le16(512)
|
||||
};
|
||||
|
||||
static struct usb_qualifier_descriptor dev_qualifier = {
|
||||
.bLength = sizeof(dev_qualifier),
|
||||
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
.bDeviceClass = USB_CLASS_PRINTER,
|
||||
.bNumConfigurations = 1
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *hs_printer_function[] = {
|
||||
(struct usb_descriptor_header *) &intf_desc,
|
||||
(struct usb_descriptor_header *) &hs_ep_in_desc,
|
||||
|
|
|
@ -1445,16 +1445,18 @@ static void usbg_drop_tpg(struct se_portal_group *se_tpg)
|
|||
for (i = 0; i < TPG_INSTANCES; ++i)
|
||||
if (tpg_instances[i].tpg == tpg)
|
||||
break;
|
||||
if (i < TPG_INSTANCES)
|
||||
if (i < TPG_INSTANCES) {
|
||||
tpg_instances[i].tpg = NULL;
|
||||
opts = container_of(tpg_instances[i].func_inst,
|
||||
struct f_tcm_opts, func_inst);
|
||||
mutex_lock(&opts->dep_lock);
|
||||
if (opts->has_dep)
|
||||
module_put(opts->dependent);
|
||||
else
|
||||
configfs_undepend_item_unlocked(&opts->func_inst.group.cg_item);
|
||||
mutex_unlock(&opts->dep_lock);
|
||||
opts = container_of(tpg_instances[i].func_inst,
|
||||
struct f_tcm_opts, func_inst);
|
||||
mutex_lock(&opts->dep_lock);
|
||||
if (opts->has_dep)
|
||||
module_put(opts->dependent);
|
||||
else
|
||||
configfs_undepend_item_unlocked(
|
||||
&opts->func_inst.group.cg_item);
|
||||
mutex_unlock(&opts->dep_lock);
|
||||
}
|
||||
mutex_unlock(&tpg_instances_lock);
|
||||
|
||||
kfree(tpg);
|
||||
|
|
|
@ -598,18 +598,6 @@ static struct usb_gadget_strings *fn_strings[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static struct usb_qualifier_descriptor devqual_desc = {
|
||||
.bLength = sizeof devqual_desc,
|
||||
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
|
||||
|
||||
.bcdUSB = cpu_to_le16(0x200),
|
||||
.bDeviceClass = USB_CLASS_MISC,
|
||||
.bDeviceSubClass = 0x02,
|
||||
.bDeviceProtocol = 0x01,
|
||||
.bNumConfigurations = 1,
|
||||
.bRESERVED = 0,
|
||||
};
|
||||
|
||||
static struct usb_interface_assoc_descriptor iad_desc = {
|
||||
.bLength = sizeof iad_desc,
|
||||
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
||||
|
@ -1292,6 +1280,7 @@ in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr)
|
|||
|
||||
if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
|
||||
struct cntrl_cur_lay3 c;
|
||||
memset(&c, 0, sizeof(struct cntrl_cur_lay3));
|
||||
|
||||
if (entity_id == USB_IN_CLK_ID)
|
||||
c.dCUR = p_srate;
|
||||
|
|
|
@ -83,9 +83,7 @@ EXPORT_SYMBOL_GPL(fsg_fs_function);
|
|||
* USB 2.0 devices need to expose both high speed and full speed
|
||||
* descriptors, unless they only run at full speed.
|
||||
*
|
||||
* That means alternate endpoint descriptors (bigger packets)
|
||||
* and a "device qualifier" ... plus more construction options
|
||||
* for the configuration descriptor.
|
||||
* That means alternate endpoint descriptors (bigger packets).
|
||||
*/
|
||||
struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
|
|
|
@ -938,8 +938,11 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
|||
struct usb_ep *ep = dev->gadget->ep0;
|
||||
struct usb_request *req = dev->req;
|
||||
|
||||
if ((retval = setup_req (ep, req, 0)) == 0)
|
||||
retval = usb_ep_queue (ep, req, GFP_ATOMIC);
|
||||
if ((retval = setup_req (ep, req, 0)) == 0) {
|
||||
spin_unlock_irq (&dev->lock);
|
||||
retval = usb_ep_queue (ep, req, GFP_KERNEL);
|
||||
spin_lock_irq (&dev->lock);
|
||||
}
|
||||
dev->state = STATE_DEV_CONNECTED;
|
||||
|
||||
/* assume that was SET_CONFIGURATION */
|
||||
|
@ -1457,8 +1460,11 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
w_length);
|
||||
if (value < 0)
|
||||
break;
|
||||
|
||||
spin_unlock (&dev->lock);
|
||||
value = usb_ep_queue (gadget->ep0, dev->req,
|
||||
GFP_ATOMIC);
|
||||
GFP_KERNEL);
|
||||
spin_lock (&dev->lock);
|
||||
if (value < 0) {
|
||||
clean_req (gadget->ep0, dev->req);
|
||||
break;
|
||||
|
@ -1481,11 +1487,14 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
if (value >= 0 && dev->state != STATE_DEV_SETUP) {
|
||||
req->length = value;
|
||||
req->zero = value < w_length;
|
||||
value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
|
||||
|
||||
spin_unlock (&dev->lock);
|
||||
value = usb_ep_queue (gadget->ep0, req, GFP_KERNEL);
|
||||
if (value < 0) {
|
||||
DBG (dev, "ep_queue --> %d\n", value);
|
||||
req->status = 0;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/* device stalls when value < 0 */
|
||||
|
|
|
@ -603,11 +603,15 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
|
|||
}
|
||||
}
|
||||
|
||||
list_add_tail(&driver->pending, &gadget_driver_pending_list);
|
||||
pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n",
|
||||
driver->function);
|
||||
if (!driver->match_existing_only) {
|
||||
list_add_tail(&driver->pending, &gadget_driver_pending_list);
|
||||
pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n",
|
||||
driver->function);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&udc_lock);
|
||||
return 0;
|
||||
return ret;
|
||||
found:
|
||||
ret = udc_bind_to_driver(udc, driver);
|
||||
mutex_unlock(&udc_lock);
|
||||
|
|
|
@ -368,6 +368,15 @@ static void ehci_shutdown(struct usb_hcd *hcd)
|
|||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
/**
|
||||
* Protect the system from crashing at system shutdown in cases where
|
||||
* usb host is not added yet from OTG controller driver.
|
||||
* As ehci_setup() not done yet, so stop accessing registers or
|
||||
* variables initialized in ehci_setup()
|
||||
*/
|
||||
if (!ehci->sbrn)
|
||||
return;
|
||||
|
||||
spin_lock_irq(&ehci->lock);
|
||||
ehci->shutdown = true;
|
||||
ehci->rh_state = EHCI_RH_STOPPING;
|
||||
|
|
|
@ -872,14 +872,22 @@ int ehci_hub_control(
|
|||
) {
|
||||
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
|
||||
int ports = HCS_N_PORTS (ehci->hcs_params);
|
||||
u32 __iomem *status_reg = &ehci->regs->port_status[
|
||||
(wIndex & 0xff) - 1];
|
||||
u32 __iomem *hostpc_reg = &ehci->regs->hostpc[(wIndex & 0xff) - 1];
|
||||
u32 __iomem *status_reg, *hostpc_reg;
|
||||
u32 temp, temp1, status;
|
||||
unsigned long flags;
|
||||
int retval = 0;
|
||||
unsigned selector;
|
||||
|
||||
/*
|
||||
* Avoid underflow while calculating (wIndex & 0xff) - 1.
|
||||
* The compiler might deduce that wIndex can never be 0 and then
|
||||
* optimize away the tests for !wIndex below.
|
||||
*/
|
||||
temp = wIndex & 0xff;
|
||||
temp -= (temp > 0);
|
||||
status_reg = &ehci->regs->port_status[temp];
|
||||
hostpc_reg = &ehci->regs->hostpc[temp];
|
||||
|
||||
/*
|
||||
* FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
|
||||
* HCS_INDICATOR may say we can change LEDs to off/amber/green.
|
||||
|
|
|
@ -179,22 +179,32 @@ static int ehci_msm_remove(struct platform_device *pdev)
|
|||
static int ehci_msm_pm_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
bool do_wakeup = device_may_wakeup(dev);
|
||||
|
||||
dev_dbg(dev, "ehci-msm PM suspend\n");
|
||||
|
||||
return ehci_suspend(hcd, do_wakeup);
|
||||
/* Only call ehci_suspend if ehci_setup has been done */
|
||||
if (ehci->sbrn)
|
||||
return ehci_suspend(hcd, do_wakeup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ehci_msm_pm_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
dev_dbg(dev, "ehci-msm PM resume\n");
|
||||
ehci_resume(hcd, false);
|
||||
|
||||
/* Only call ehci_resume if ehci_setup has been done */
|
||||
if (ehci->sbrn)
|
||||
ehci_resume(hcd, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define ehci_msm_pm_suspend NULL
|
||||
#define ehci_msm_pm_resume NULL
|
||||
|
|
|
@ -81,15 +81,23 @@ static int tegra_reset_usb_controller(struct platform_device *pdev)
|
|||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct tegra_ehci_hcd *tegra =
|
||||
(struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv;
|
||||
bool has_utmi_pad_registers = false;
|
||||
|
||||
phy_np = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0);
|
||||
if (!phy_np)
|
||||
return -ENOENT;
|
||||
|
||||
if (of_property_read_bool(phy_np, "nvidia,has-utmi-pad-registers"))
|
||||
has_utmi_pad_registers = true;
|
||||
|
||||
if (!usb1_reset_attempted) {
|
||||
struct reset_control *usb1_reset;
|
||||
|
||||
usb1_reset = of_reset_control_get(phy_np, "usb");
|
||||
if (!has_utmi_pad_registers)
|
||||
usb1_reset = of_reset_control_get(phy_np, "utmi-pads");
|
||||
else
|
||||
usb1_reset = tegra->rst;
|
||||
|
||||
if (IS_ERR(usb1_reset)) {
|
||||
dev_warn(&pdev->dev,
|
||||
"can't get utmi-pads reset from the PHY\n");
|
||||
|
@ -99,13 +107,15 @@ static int tegra_reset_usb_controller(struct platform_device *pdev)
|
|||
reset_control_assert(usb1_reset);
|
||||
udelay(1);
|
||||
reset_control_deassert(usb1_reset);
|
||||
|
||||
if (!has_utmi_pad_registers)
|
||||
reset_control_put(usb1_reset);
|
||||
}
|
||||
|
||||
reset_control_put(usb1_reset);
|
||||
usb1_reset_attempted = true;
|
||||
}
|
||||
|
||||
if (!of_property_read_bool(phy_np, "nvidia,has-utmi-pad-registers")) {
|
||||
if (!has_utmi_pad_registers) {
|
||||
reset_control_assert(tegra->rst);
|
||||
udelay(1);
|
||||
reset_control_deassert(tegra->rst);
|
||||
|
|
|
@ -183,7 +183,6 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
|
|||
{
|
||||
int branch;
|
||||
|
||||
ed->state = ED_OPER;
|
||||
ed->ed_prev = NULL;
|
||||
ed->ed_next = NULL;
|
||||
ed->hwNextED = 0;
|
||||
|
@ -259,6 +258,8 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
|
|||
/* the HC may not see the schedule updates yet, but if it does
|
||||
* then they'll be properly ordered.
|
||||
*/
|
||||
|
||||
ed->state = ED_OPER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
/* Device for a quirk */
|
||||
#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
|
||||
#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
|
||||
#define PCI_DEVICE_ID_FRESCO_LOGIC_FL1009 0x1009
|
||||
#define PCI_DEVICE_ID_FRESCO_LOGIC_FL1400 0x1400
|
||||
|
||||
#define PCI_VENDOR_ID_ETRON 0x1b6f
|
||||
|
@ -114,6 +115,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
|||
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
|
||||
}
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
|
||||
pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1009)
|
||||
xhci->quirks |= XHCI_BROKEN_STREAMS;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_NEC)
|
||||
xhci->quirks |= XHCI_NEC_HOST;
|
||||
|
||||
|
|
|
@ -196,6 +196,9 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
|||
ret = clk_prepare_enable(clk);
|
||||
if (ret)
|
||||
goto put_hcd;
|
||||
} else if (PTR_ERR(clk) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto put_hcd;
|
||||
}
|
||||
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
|
|
|
@ -290,6 +290,14 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
|
|||
|
||||
temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
|
||||
xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
|
||||
|
||||
/*
|
||||
* Writing the CMD_RING_ABORT bit should cause a cmd completion event,
|
||||
* however on some host hw the CMD_RING_RUNNING bit is correctly cleared
|
||||
* but the completion event in never sent. Use the cmd timeout timer to
|
||||
* handle those cases. Use twice the time to cover the bit polling retry
|
||||
*/
|
||||
mod_timer(&xhci->cmd_timer, jiffies + (2 * XHCI_CMD_DEFAULT_TIMEOUT));
|
||||
xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
|
||||
&xhci->op_regs->cmd_ring);
|
||||
|
||||
|
@ -314,6 +322,7 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
|
|||
|
||||
xhci_err(xhci, "Stopped the command ring failed, "
|
||||
"maybe the host is dead\n");
|
||||
del_timer(&xhci->cmd_timer);
|
||||
xhci->xhc_state |= XHCI_STATE_DYING;
|
||||
xhci_quiesce(xhci);
|
||||
xhci_halt(xhci);
|
||||
|
@ -1246,22 +1255,21 @@ void xhci_handle_command_timeout(unsigned long data)
|
|||
int ret;
|
||||
unsigned long flags;
|
||||
u64 hw_ring_state;
|
||||
struct xhci_command *cur_cmd = NULL;
|
||||
bool second_timeout = false;
|
||||
xhci = (struct xhci_hcd *) data;
|
||||
|
||||
/* mark this command to be cancelled */
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
if (xhci->current_cmd) {
|
||||
cur_cmd = xhci->current_cmd;
|
||||
cur_cmd->status = COMP_CMD_ABORT;
|
||||
if (xhci->current_cmd->status == COMP_CMD_ABORT)
|
||||
second_timeout = true;
|
||||
xhci->current_cmd->status = COMP_CMD_ABORT;
|
||||
}
|
||||
|
||||
|
||||
/* Make sure command ring is running before aborting it */
|
||||
hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
|
||||
if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) &&
|
||||
(hw_ring_state & CMD_RING_RUNNING)) {
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
xhci_dbg(xhci, "Command timeout\n");
|
||||
ret = xhci_abort_cmd_ring(xhci);
|
||||
|
@ -1273,6 +1281,15 @@ void xhci_handle_command_timeout(unsigned long data)
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* command ring failed to restart, or host removed. Bail out */
|
||||
if (second_timeout || xhci->xhc_state & XHCI_STATE_REMOVING) {
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
xhci_dbg(xhci, "command timed out twice, ring start fail?\n");
|
||||
xhci_cleanup_command_queue(xhci);
|
||||
return;
|
||||
}
|
||||
|
||||
/* command timeout on stopped ring, ring can't be aborted */
|
||||
xhci_dbg(xhci, "Command timeout on stopped ring\n");
|
||||
xhci_handle_stopped_cmd_ring(xhci, xhci->current_cmd);
|
||||
|
@ -2721,7 +2738,8 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
|||
writel(irq_pending, &xhci->ir_set->irq_pending);
|
||||
}
|
||||
|
||||
if (xhci->xhc_state & XHCI_STATE_DYING) {
|
||||
if (xhci->xhc_state & XHCI_STATE_DYING ||
|
||||
xhci->xhc_state & XHCI_STATE_HALTED) {
|
||||
xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
|
||||
"Shouldn't IRQs be disabled?\n");
|
||||
/* Clear the event handler busy flag (RW1C);
|
||||
|
|
|
@ -685,20 +685,23 @@ void xhci_stop(struct usb_hcd *hcd)
|
|||
u32 temp;
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
|
||||
if (xhci->xhc_state & XHCI_STATE_HALTED)
|
||||
return;
|
||||
|
||||
mutex_lock(&xhci->mutex);
|
||||
spin_lock_irq(&xhci->lock);
|
||||
xhci->xhc_state |= XHCI_STATE_HALTED;
|
||||
xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
|
||||
|
||||
/* Make sure the xHC is halted for a USB3 roothub
|
||||
* (xhci_stop() could be called as part of failed init).
|
||||
*/
|
||||
xhci_halt(xhci);
|
||||
xhci_reset(xhci);
|
||||
spin_unlock_irq(&xhci->lock);
|
||||
if (!(xhci->xhc_state & XHCI_STATE_HALTED)) {
|
||||
spin_lock_irq(&xhci->lock);
|
||||
|
||||
xhci->xhc_state |= XHCI_STATE_HALTED;
|
||||
xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
|
||||
xhci_halt(xhci);
|
||||
xhci_reset(xhci);
|
||||
|
||||
spin_unlock_irq(&xhci->lock);
|
||||
}
|
||||
|
||||
if (!usb_hcd_is_primary_hcd(hcd)) {
|
||||
mutex_unlock(&xhci->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
xhci_cleanup_msix(xhci);
|
||||
|
||||
|
@ -4886,7 +4889,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
|
|||
xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
|
||||
xhci_print_registers(xhci);
|
||||
|
||||
xhci->quirks = quirks;
|
||||
xhci->quirks |= quirks;
|
||||
|
||||
get_quirks(dev, xhci);
|
||||
|
||||
|
|
|
@ -1090,29 +1090,6 @@ void musb_stop(struct musb *musb)
|
|||
musb_platform_try_idle(musb, 0);
|
||||
}
|
||||
|
||||
static void musb_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct musb *musb = dev_to_musb(&pdev->dev);
|
||||
unsigned long flags;
|
||||
|
||||
pm_runtime_get_sync(musb->controller);
|
||||
|
||||
musb_host_cleanup(musb);
|
||||
musb_gadget_cleanup(musb);
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
musb_platform_disable(musb);
|
||||
musb_generic_disable(musb);
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
|
||||
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
|
||||
musb_platform_exit(musb);
|
||||
|
||||
pm_runtime_put(musb->controller);
|
||||
/* FIXME power down */
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
|
@ -1702,7 +1679,7 @@ EXPORT_SYMBOL_GPL(musb_dma_completion);
|
|||
#define use_dma 0
|
||||
#endif
|
||||
|
||||
static void (*musb_phy_callback)(enum musb_vbus_id_status status);
|
||||
static int (*musb_phy_callback)(enum musb_vbus_id_status status);
|
||||
|
||||
/*
|
||||
* musb_mailbox - optional phy notifier function
|
||||
|
@ -1711,11 +1688,12 @@ static void (*musb_phy_callback)(enum musb_vbus_id_status status);
|
|||
* Optionally gets called from the USB PHY. Note that the USB PHY must be
|
||||
* disabled at the point the phy_callback is registered or unregistered.
|
||||
*/
|
||||
void musb_mailbox(enum musb_vbus_id_status status)
|
||||
int musb_mailbox(enum musb_vbus_id_status status)
|
||||
{
|
||||
if (musb_phy_callback)
|
||||
musb_phy_callback(status);
|
||||
return musb_phy_callback(status);
|
||||
|
||||
return -ENODEV;
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(musb_mailbox);
|
||||
|
||||
|
@ -2028,11 +2006,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
|
|||
musb_readl = musb_default_readl;
|
||||
musb_writel = musb_default_writel;
|
||||
|
||||
/* We need musb_read/write functions initialized for PM */
|
||||
pm_runtime_use_autosuspend(musb->controller);
|
||||
pm_runtime_set_autosuspend_delay(musb->controller, 200);
|
||||
pm_runtime_enable(musb->controller);
|
||||
|
||||
/* The musb_platform_init() call:
|
||||
* - adjusts musb->mregs
|
||||
* - sets the musb->isr
|
||||
|
@ -2134,6 +2107,16 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
|
|||
if (musb->ops->phy_callback)
|
||||
musb_phy_callback = musb->ops->phy_callback;
|
||||
|
||||
/*
|
||||
* We need musb_read/write functions initialized for PM.
|
||||
* Note that at least 2430 glue needs autosuspend delay
|
||||
* somewhere above 300 ms for the hardware to idle properly
|
||||
* after disconnecting the cable in host mode. Let's use
|
||||
* 500 ms for some margin.
|
||||
*/
|
||||
pm_runtime_use_autosuspend(musb->controller);
|
||||
pm_runtime_set_autosuspend_delay(musb->controller, 500);
|
||||
pm_runtime_enable(musb->controller);
|
||||
pm_runtime_get_sync(musb->controller);
|
||||
|
||||
status = usb_phy_init(musb->xceiv);
|
||||
|
@ -2237,13 +2220,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
|
|||
if (status)
|
||||
goto fail5;
|
||||
|
||||
pm_runtime_put(musb->controller);
|
||||
|
||||
/*
|
||||
* For why this is currently needed, see commit 3e43a0725637
|
||||
* ("usb: musb: core: add pm_runtime_irq_safe()")
|
||||
*/
|
||||
pm_runtime_irq_safe(musb->controller);
|
||||
pm_runtime_mark_last_busy(musb->controller);
|
||||
pm_runtime_put_autosuspend(musb->controller);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -2265,7 +2243,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
|
|||
usb_phy_shutdown(musb->xceiv);
|
||||
|
||||
err_usb_phy_init:
|
||||
pm_runtime_dont_use_autosuspend(musb->controller);
|
||||
pm_runtime_put_sync(musb->controller);
|
||||
pm_runtime_disable(musb->controller);
|
||||
|
||||
fail2:
|
||||
if (musb->irq_wake)
|
||||
|
@ -2273,7 +2253,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
|
|||
musb_platform_exit(musb);
|
||||
|
||||
fail1:
|
||||
pm_runtime_disable(musb->controller);
|
||||
dev_err(musb->controller,
|
||||
"musb_init_controller failed with status %d\n", status);
|
||||
|
||||
|
@ -2312,6 +2291,7 @@ static int musb_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct musb *musb = dev_to_musb(dev);
|
||||
unsigned long flags;
|
||||
|
||||
/* this gets called on rmmod.
|
||||
* - Host mode: host may still be active
|
||||
|
@ -2319,17 +2299,26 @@ static int musb_remove(struct platform_device *pdev)
|
|||
* - OTG mode: both roles are deactivated (or never-activated)
|
||||
*/
|
||||
musb_exit_debugfs(musb);
|
||||
musb_shutdown(pdev);
|
||||
musb_phy_callback = NULL;
|
||||
|
||||
if (musb->dma_controller)
|
||||
musb_dma_controller_destroy(musb->dma_controller);
|
||||
|
||||
usb_phy_shutdown(musb->xceiv);
|
||||
|
||||
cancel_work_sync(&musb->irq_work);
|
||||
cancel_delayed_work_sync(&musb->finish_resume_work);
|
||||
cancel_delayed_work_sync(&musb->deassert_reset_work);
|
||||
pm_runtime_get_sync(musb->controller);
|
||||
musb_host_cleanup(musb);
|
||||
musb_gadget_cleanup(musb);
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
musb_platform_disable(musb);
|
||||
musb_generic_disable(musb);
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
|
||||
pm_runtime_dont_use_autosuspend(musb->controller);
|
||||
pm_runtime_put_sync(musb->controller);
|
||||
pm_runtime_disable(musb->controller);
|
||||
musb_platform_exit(musb);
|
||||
musb_phy_callback = NULL;
|
||||
if (musb->dma_controller)
|
||||
musb_dma_controller_destroy(musb->dma_controller);
|
||||
usb_phy_shutdown(musb->xceiv);
|
||||
musb_free(musb);
|
||||
device_init_wakeup(dev, 0);
|
||||
return 0;
|
||||
|
@ -2429,7 +2418,8 @@ static void musb_restore_context(struct musb *musb)
|
|||
musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe);
|
||||
musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe);
|
||||
musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe);
|
||||
musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl);
|
||||
if (musb->context.devctl & MUSB_DEVCTL_SESSION)
|
||||
musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl);
|
||||
|
||||
for (i = 0; i < musb->config->num_eps; ++i) {
|
||||
struct musb_hw_ep *hw_ep;
|
||||
|
@ -2612,7 +2602,6 @@ static struct platform_driver musb_driver = {
|
|||
},
|
||||
.probe = musb_probe,
|
||||
.remove = musb_remove,
|
||||
.shutdown = musb_shutdown,
|
||||
};
|
||||
|
||||
module_platform_driver(musb_driver);
|
||||
|
|
|
@ -215,7 +215,7 @@ struct musb_platform_ops {
|
|||
dma_addr_t *dma_addr, u32 *len);
|
||||
void (*pre_root_reset_end)(struct musb *musb);
|
||||
void (*post_root_reset_end)(struct musb *musb);
|
||||
void (*phy_callback)(enum musb_vbus_id_status status);
|
||||
int (*phy_callback)(enum musb_vbus_id_status status);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -312,6 +312,7 @@ struct musb {
|
|||
struct work_struct irq_work;
|
||||
struct delayed_work deassert_reset_work;
|
||||
struct delayed_work finish_resume_work;
|
||||
struct delayed_work gadget_work;
|
||||
u16 hwvers;
|
||||
|
||||
u16 intrrxe;
|
||||
|
|
|
@ -1656,6 +1656,20 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
|
|||
return usb_phy_set_power(musb->xceiv, mA);
|
||||
}
|
||||
|
||||
static void musb_gadget_work(struct work_struct *work)
|
||||
{
|
||||
struct musb *musb;
|
||||
unsigned long flags;
|
||||
|
||||
musb = container_of(work, struct musb, gadget_work.work);
|
||||
pm_runtime_get_sync(musb->controller);
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
musb_pullup(musb, musb->softconnect);
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
pm_runtime_mark_last_busy(musb->controller);
|
||||
pm_runtime_put_autosuspend(musb->controller);
|
||||
}
|
||||
|
||||
static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
|
||||
{
|
||||
struct musb *musb = gadget_to_musb(gadget);
|
||||
|
@ -1663,20 +1677,16 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
|
|||
|
||||
is_on = !!is_on;
|
||||
|
||||
pm_runtime_get_sync(musb->controller);
|
||||
|
||||
/* NOTE: this assumes we are sensing vbus; we'd rather
|
||||
* not pullup unless the B-session is active.
|
||||
*/
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
if (is_on != musb->softconnect) {
|
||||
musb->softconnect = is_on;
|
||||
musb_pullup(musb, is_on);
|
||||
schedule_delayed_work(&musb->gadget_work, 0);
|
||||
}
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
|
||||
pm_runtime_put(musb->controller);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1845,7 +1855,7 @@ int musb_gadget_setup(struct musb *musb)
|
|||
#elif IS_ENABLED(CONFIG_USB_MUSB_GADGET)
|
||||
musb->g.is_otg = 0;
|
||||
#endif
|
||||
|
||||
INIT_DELAYED_WORK(&musb->gadget_work, musb_gadget_work);
|
||||
musb_g_init_endpoints(musb);
|
||||
|
||||
musb->is_active = 0;
|
||||
|
@ -1866,6 +1876,8 @@ void musb_gadget_cleanup(struct musb *musb)
|
|||
{
|
||||
if (musb->port_mode == MUSB_PORT_MODE_HOST)
|
||||
return;
|
||||
|
||||
cancel_delayed_work_sync(&musb->gadget_work);
|
||||
usb_del_gadget_udc(&musb->g);
|
||||
}
|
||||
|
||||
|
@ -1914,8 +1926,8 @@ static int musb_gadget_start(struct usb_gadget *g,
|
|||
if (musb->xceiv->last_event == USB_EVENT_ID)
|
||||
musb_platform_set_vbus(musb, 1);
|
||||
|
||||
if (musb->xceiv->last_event == USB_EVENT_NONE)
|
||||
pm_runtime_put(musb->controller);
|
||||
pm_runtime_mark_last_busy(musb->controller);
|
||||
pm_runtime_put_autosuspend(musb->controller);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -1934,8 +1946,7 @@ static int musb_gadget_stop(struct usb_gadget *g)
|
|||
struct musb *musb = gadget_to_musb(g);
|
||||
unsigned long flags;
|
||||
|
||||
if (musb->xceiv->last_event == USB_EVENT_NONE)
|
||||
pm_runtime_get_sync(musb->controller);
|
||||
pm_runtime_get_sync(musb->controller);
|
||||
|
||||
/*
|
||||
* REVISIT always use otg_set_peripheral() here too;
|
||||
|
@ -1963,7 +1974,8 @@ static int musb_gadget_stop(struct usb_gadget *g)
|
|||
* that currently misbehaves.
|
||||
*/
|
||||
|
||||
pm_runtime_put(musb->controller);
|
||||
pm_runtime_mark_last_busy(musb->controller);
|
||||
pm_runtime_put_autosuspend(musb->controller);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -434,7 +434,13 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,
|
|||
}
|
||||
}
|
||||
|
||||
if (qh != NULL && qh->is_ready) {
|
||||
/*
|
||||
* The pipe must be broken if current urb->status is set, so don't
|
||||
* start next urb.
|
||||
* TODO: to minimize the risk of regression, only check urb->status
|
||||
* for RX, until we have a test case to understand the behavior of TX.
|
||||
*/
|
||||
if ((!status || !is_in) && qh && qh->is_ready) {
|
||||
dev_dbg(musb->controller, "... next ep%d %cX urb %p\n",
|
||||
hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh));
|
||||
musb_start_urb(musb, is_in, qh);
|
||||
|
@ -594,14 +600,13 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, u8 epnum)
|
|||
musb_writew(ep->regs, MUSB_TXCSR, 0);
|
||||
|
||||
/* scrub all previous state, clearing toggle */
|
||||
} else {
|
||||
csr = musb_readw(ep->regs, MUSB_RXCSR);
|
||||
if (csr & MUSB_RXCSR_RXPKTRDY)
|
||||
WARNING("rx%d, packet/%d ready?\n", ep->epnum,
|
||||
musb_readw(ep->regs, MUSB_RXCOUNT));
|
||||
|
||||
musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG);
|
||||
}
|
||||
csr = musb_readw(ep->regs, MUSB_RXCSR);
|
||||
if (csr & MUSB_RXCSR_RXPKTRDY)
|
||||
WARNING("rx%d, packet/%d ready?\n", ep->epnum,
|
||||
musb_readw(ep->regs, MUSB_RXCOUNT));
|
||||
|
||||
musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG);
|
||||
|
||||
/* target addr and (for multipoint) hub addr/port */
|
||||
if (musb->is_multipoint) {
|
||||
|
@ -627,7 +632,7 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, u8 epnum)
|
|||
ep->rx_reinit = 0;
|
||||
}
|
||||
|
||||
static int musb_tx_dma_set_mode_mentor(struct dma_controller *dma,
|
||||
static void musb_tx_dma_set_mode_mentor(struct dma_controller *dma,
|
||||
struct musb_hw_ep *hw_ep, struct musb_qh *qh,
|
||||
struct urb *urb, u32 offset,
|
||||
u32 *length, u8 *mode)
|
||||
|
@ -664,23 +669,18 @@ static int musb_tx_dma_set_mode_mentor(struct dma_controller *dma,
|
|||
}
|
||||
channel->desired_mode = *mode;
|
||||
musb_writew(epio, MUSB_TXCSR, csr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int musb_tx_dma_set_mode_cppi_tusb(struct dma_controller *dma,
|
||||
struct musb_hw_ep *hw_ep,
|
||||
struct musb_qh *qh,
|
||||
struct urb *urb,
|
||||
u32 offset,
|
||||
u32 *length,
|
||||
u8 *mode)
|
||||
static void musb_tx_dma_set_mode_cppi_tusb(struct dma_controller *dma,
|
||||
struct musb_hw_ep *hw_ep,
|
||||
struct musb_qh *qh,
|
||||
struct urb *urb,
|
||||
u32 offset,
|
||||
u32 *length,
|
||||
u8 *mode)
|
||||
{
|
||||
struct dma_channel *channel = hw_ep->tx_channel;
|
||||
|
||||
if (!is_cppi_enabled(hw_ep->musb) && !tusb_dma_omap(hw_ep->musb))
|
||||
return -ENODEV;
|
||||
|
||||
channel->actual_len = 0;
|
||||
|
||||
/*
|
||||
|
@ -688,8 +688,6 @@ static int musb_tx_dma_set_mode_cppi_tusb(struct dma_controller *dma,
|
|||
* to identify the zero-length-final-packet case.
|
||||
*/
|
||||
*mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool musb_tx_dma_program(struct dma_controller *dma,
|
||||
|
@ -699,15 +697,14 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
|
|||
struct dma_channel *channel = hw_ep->tx_channel;
|
||||
u16 pkt_size = qh->maxpacket;
|
||||
u8 mode;
|
||||
int res;
|
||||
|
||||
if (musb_dma_inventra(hw_ep->musb) || musb_dma_ux500(hw_ep->musb))
|
||||
res = musb_tx_dma_set_mode_mentor(dma, hw_ep, qh, urb,
|
||||
offset, &length, &mode);
|
||||
musb_tx_dma_set_mode_mentor(dma, hw_ep, qh, urb, offset,
|
||||
&length, &mode);
|
||||
else if (is_cppi_enabled(hw_ep->musb) || tusb_dma_omap(hw_ep->musb))
|
||||
musb_tx_dma_set_mode_cppi_tusb(dma, hw_ep, qh, urb, offset,
|
||||
&length, &mode);
|
||||
else
|
||||
res = musb_tx_dma_set_mode_cppi_tusb(dma, hw_ep, qh, urb,
|
||||
offset, &length, &mode);
|
||||
if (res)
|
||||
return false;
|
||||
|
||||
qh->segsize = length;
|
||||
|
@ -995,9 +992,15 @@ static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep,
|
|||
if (is_in) {
|
||||
dma = is_dma_capable() ? ep->rx_channel : NULL;
|
||||
|
||||
/* clear nak timeout bit */
|
||||
/*
|
||||
* Need to stop the transaction by clearing REQPKT first
|
||||
* then the NAK Timeout bit ref MUSBMHDRC USB 2.0 HIGH-SPEED
|
||||
* DUAL-ROLE CONTROLLER Programmer's Guide, section 9.2.2
|
||||
*/
|
||||
rx_csr = musb_readw(epio, MUSB_RXCSR);
|
||||
rx_csr |= MUSB_RXCSR_H_WZC_BITS;
|
||||
rx_csr &= ~MUSB_RXCSR_H_REQPKT;
|
||||
musb_writew(epio, MUSB_RXCSR, rx_csr);
|
||||
rx_csr &= ~MUSB_RXCSR_DATAERROR;
|
||||
musb_writew(epio, MUSB_RXCSR, rx_csr);
|
||||
|
||||
|
@ -1551,7 +1554,7 @@ static int musb_rx_dma_iso_cppi41(struct dma_controller *dma,
|
|||
struct urb *urb,
|
||||
size_t len)
|
||||
{
|
||||
struct dma_channel *channel = hw_ep->tx_channel;
|
||||
struct dma_channel *channel = hw_ep->rx_channel;
|
||||
void __iomem *epio = hw_ep->regs;
|
||||
dma_addr_t *buf;
|
||||
u32 length, res;
|
||||
|
@ -1870,6 +1873,9 @@ void musb_host_rx(struct musb *musb, u8 epnum)
|
|||
status = -EPROTO;
|
||||
musb_writeb(epio, MUSB_RXINTERVAL, 0);
|
||||
|
||||
rx_csr &= ~MUSB_RXCSR_H_ERROR;
|
||||
musb_writew(epio, MUSB_RXCSR, rx_csr);
|
||||
|
||||
} else if (rx_csr & MUSB_RXCSR_DATAERROR) {
|
||||
|
||||
if (USB_ENDPOINT_XFER_ISOC != qh->type) {
|
||||
|
|
|
@ -49,97 +49,14 @@ struct omap2430_glue {
|
|||
enum musb_vbus_id_status status;
|
||||
struct work_struct omap_musb_mailbox_work;
|
||||
struct device *control_otghs;
|
||||
bool cable_connected;
|
||||
bool enabled;
|
||||
bool powered;
|
||||
};
|
||||
#define glue_to_musb(g) platform_get_drvdata(g->musb)
|
||||
|
||||
static struct omap2430_glue *_glue;
|
||||
|
||||
static struct timer_list musb_idle_timer;
|
||||
|
||||
static void musb_do_idle(unsigned long _musb)
|
||||
{
|
||||
struct musb *musb = (void *)_musb;
|
||||
unsigned long flags;
|
||||
u8 power;
|
||||
u8 devctl;
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
|
||||
switch (musb->xceiv->otg->state) {
|
||||
case OTG_STATE_A_WAIT_BCON:
|
||||
|
||||
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
if (devctl & MUSB_DEVCTL_BDEVICE) {
|
||||
musb->xceiv->otg->state = OTG_STATE_B_IDLE;
|
||||
MUSB_DEV_MODE(musb);
|
||||
} else {
|
||||
musb->xceiv->otg->state = OTG_STATE_A_IDLE;
|
||||
MUSB_HST_MODE(musb);
|
||||
}
|
||||
break;
|
||||
case OTG_STATE_A_SUSPEND:
|
||||
/* finish RESUME signaling? */
|
||||
if (musb->port1_status & MUSB_PORT_STAT_RESUME) {
|
||||
power = musb_readb(musb->mregs, MUSB_POWER);
|
||||
power &= ~MUSB_POWER_RESUME;
|
||||
dev_dbg(musb->controller, "root port resume stopped, power %02x\n", power);
|
||||
musb_writeb(musb->mregs, MUSB_POWER, power);
|
||||
musb->is_active = 1;
|
||||
musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
|
||||
| MUSB_PORT_STAT_RESUME);
|
||||
musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
|
||||
usb_hcd_poll_rh_status(musb->hcd);
|
||||
/* NOTE: it might really be A_WAIT_BCON ... */
|
||||
musb->xceiv->otg->state = OTG_STATE_A_HOST;
|
||||
}
|
||||
break;
|
||||
case OTG_STATE_A_HOST:
|
||||
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
if (devctl & MUSB_DEVCTL_BDEVICE)
|
||||
musb->xceiv->otg->state = OTG_STATE_B_IDLE;
|
||||
else
|
||||
musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
}
|
||||
|
||||
|
||||
static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
|
||||
{
|
||||
unsigned long default_timeout = jiffies + msecs_to_jiffies(3);
|
||||
static unsigned long last_timer;
|
||||
|
||||
if (timeout == 0)
|
||||
timeout = default_timeout;
|
||||
|
||||
/* Never idle if active, or when VBUS timeout is not set as host */
|
||||
if (musb->is_active || ((musb->a_wait_bcon == 0)
|
||||
&& (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON))) {
|
||||
dev_dbg(musb->controller, "%s active, deleting timer\n",
|
||||
usb_otg_state_string(musb->xceiv->otg->state));
|
||||
del_timer(&musb_idle_timer);
|
||||
last_timer = jiffies;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time_after(last_timer, timeout)) {
|
||||
if (!timer_pending(&musb_idle_timer))
|
||||
last_timer = timeout;
|
||||
else {
|
||||
dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
last_timer = timeout;
|
||||
|
||||
dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
|
||||
usb_otg_state_string(musb->xceiv->otg->state),
|
||||
(unsigned long)jiffies_to_msecs(timeout - jiffies));
|
||||
mod_timer(&musb_idle_timer, timeout);
|
||||
}
|
||||
|
||||
static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
|
||||
{
|
||||
struct usb_otg *otg = musb->xceiv->otg;
|
||||
|
@ -205,16 +122,6 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
|
|||
musb_readb(musb->mregs, MUSB_DEVCTL));
|
||||
}
|
||||
|
||||
static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode)
|
||||
{
|
||||
u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
|
||||
devctl |= MUSB_DEVCTL_SESSION;
|
||||
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void omap2430_low_level_exit(struct musb *musb)
|
||||
{
|
||||
u32 l;
|
||||
|
@ -234,22 +141,63 @@ static inline void omap2430_low_level_init(struct musb *musb)
|
|||
musb_writel(musb->mregs, OTG_FORCESTDBY, l);
|
||||
}
|
||||
|
||||
static void omap2430_musb_mailbox(enum musb_vbus_id_status status)
|
||||
/*
|
||||
* We can get multiple cable events so we need to keep track
|
||||
* of the power state. Only keep power enabled if USB cable is
|
||||
* connected and a gadget is started.
|
||||
*/
|
||||
static void omap2430_set_power(struct musb *musb, bool enabled, bool cable)
|
||||
{
|
||||
struct device *dev = musb->controller;
|
||||
struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
|
||||
bool power_up;
|
||||
int res;
|
||||
|
||||
if (glue->enabled != enabled)
|
||||
glue->enabled = enabled;
|
||||
|
||||
if (glue->cable_connected != cable)
|
||||
glue->cable_connected = cable;
|
||||
|
||||
power_up = glue->enabled && glue->cable_connected;
|
||||
if (power_up == glue->powered) {
|
||||
dev_warn(musb->controller, "power state already %i\n",
|
||||
power_up);
|
||||
return;
|
||||
}
|
||||
|
||||
glue->powered = power_up;
|
||||
|
||||
if (power_up) {
|
||||
res = pm_runtime_get_sync(musb->controller);
|
||||
if (res < 0) {
|
||||
dev_err(musb->controller, "could not enable: %i", res);
|
||||
glue->powered = false;
|
||||
}
|
||||
} else {
|
||||
pm_runtime_mark_last_busy(musb->controller);
|
||||
pm_runtime_put_autosuspend(musb->controller);
|
||||
}
|
||||
}
|
||||
|
||||
static int omap2430_musb_mailbox(enum musb_vbus_id_status status)
|
||||
{
|
||||
struct omap2430_glue *glue = _glue;
|
||||
|
||||
if (!glue) {
|
||||
pr_err("%s: musb core is not yet initialized\n", __func__);
|
||||
return;
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
glue->status = status;
|
||||
|
||||
if (!glue_to_musb(glue)) {
|
||||
pr_err("%s: musb core is not yet ready\n", __func__);
|
||||
return;
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
schedule_work(&glue->omap_musb_mailbox_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_musb_set_mailbox(struct omap2430_glue *glue)
|
||||
|
@ -259,6 +207,13 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
|
|||
struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
|
||||
struct omap_musb_board_data *data = pdata->board_data;
|
||||
struct usb_otg *otg = musb->xceiv->otg;
|
||||
bool cable_connected;
|
||||
|
||||
cable_connected = ((glue->status == MUSB_ID_GROUND) ||
|
||||
(glue->status == MUSB_VBUS_VALID));
|
||||
|
||||
if (cable_connected)
|
||||
omap2430_set_power(musb, glue->enabled, cable_connected);
|
||||
|
||||
switch (glue->status) {
|
||||
case MUSB_ID_GROUND:
|
||||
|
@ -268,7 +223,6 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
|
|||
musb->xceiv->otg->state = OTG_STATE_A_IDLE;
|
||||
musb->xceiv->last_event = USB_EVENT_ID;
|
||||
if (musb->gadget_driver) {
|
||||
pm_runtime_get_sync(dev);
|
||||
omap_control_usb_set_mode(glue->control_otghs,
|
||||
USB_MODE_HOST);
|
||||
omap2430_musb_set_vbus(musb, 1);
|
||||
|
@ -281,8 +235,6 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
|
|||
otg->default_a = false;
|
||||
musb->xceiv->otg->state = OTG_STATE_B_IDLE;
|
||||
musb->xceiv->last_event = USB_EVENT_VBUS;
|
||||
if (musb->gadget_driver)
|
||||
pm_runtime_get_sync(dev);
|
||||
omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE);
|
||||
break;
|
||||
|
||||
|
@ -291,11 +243,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
|
|||
dev_dbg(dev, "VBUS Disconnect\n");
|
||||
|
||||
musb->xceiv->last_event = USB_EVENT_NONE;
|
||||
if (musb->gadget_driver) {
|
||||
if (musb->gadget_driver)
|
||||
omap2430_musb_set_vbus(musb, 0);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
}
|
||||
|
||||
if (data->interface_type == MUSB_INTERFACE_UTMI)
|
||||
otg_set_vbus(musb->xceiv->otg, 0);
|
||||
|
@ -307,6 +256,9 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
|
|||
dev_dbg(dev, "ID float\n");
|
||||
}
|
||||
|
||||
if (!cable_connected)
|
||||
omap2430_set_power(musb, glue->enabled, cable_connected);
|
||||
|
||||
atomic_notifier_call_chain(&musb->xceiv->notifier,
|
||||
musb->xceiv->last_event, NULL);
|
||||
}
|
||||
|
@ -316,13 +268,8 @@ static void omap_musb_mailbox_work(struct work_struct *mailbox_work)
|
|||
{
|
||||
struct omap2430_glue *glue = container_of(mailbox_work,
|
||||
struct omap2430_glue, omap_musb_mailbox_work);
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
struct device *dev = musb->controller;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
omap_musb_set_mailbox(glue);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
}
|
||||
|
||||
static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci)
|
||||
|
@ -389,23 +336,7 @@ static int omap2430_musb_init(struct musb *musb)
|
|||
return PTR_ERR(musb->phy);
|
||||
}
|
||||
musb->isr = omap2430_musb_interrupt;
|
||||
|
||||
/*
|
||||
* Enable runtime PM for musb parent (this driver). We can't
|
||||
* do it earlier as struct musb is not yet allocated and we
|
||||
* need to touch the musb registers for runtime PM.
|
||||
*/
|
||||
pm_runtime_enable(glue->dev);
|
||||
status = pm_runtime_get_sync(glue->dev);
|
||||
if (status < 0)
|
||||
goto err1;
|
||||
|
||||
status = pm_runtime_get_sync(dev);
|
||||
if (status < 0) {
|
||||
dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status);
|
||||
pm_runtime_put_sync(glue->dev);
|
||||
goto err1;
|
||||
}
|
||||
phy_init(musb->phy);
|
||||
|
||||
l = musb_readl(musb->mregs, OTG_INTERFSEL);
|
||||
|
||||
|
@ -427,20 +358,10 @@ static int omap2430_musb_init(struct musb *musb)
|
|||
musb_readl(musb->mregs, OTG_INTERFSEL),
|
||||
musb_readl(musb->mregs, OTG_SIMENABLE));
|
||||
|
||||
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
|
||||
|
||||
if (glue->status != MUSB_UNKNOWN)
|
||||
omap_musb_set_mailbox(glue);
|
||||
|
||||
phy_init(musb->phy);
|
||||
phy_power_on(musb->phy);
|
||||
|
||||
pm_runtime_put_noidle(musb->controller);
|
||||
pm_runtime_put_noidle(glue->dev);
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
return status;
|
||||
}
|
||||
|
||||
static void omap2430_musb_enable(struct musb *musb)
|
||||
|
@ -452,6 +373,11 @@ static void omap2430_musb_enable(struct musb *musb)
|
|||
struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
|
||||
struct omap_musb_board_data *data = pdata->board_data;
|
||||
|
||||
if (!WARN_ON(!musb->phy))
|
||||
phy_power_on(musb->phy);
|
||||
|
||||
omap2430_set_power(musb, true, glue->cable_connected);
|
||||
|
||||
switch (glue->status) {
|
||||
|
||||
case MUSB_ID_GROUND:
|
||||
|
@ -487,18 +413,25 @@ static void omap2430_musb_disable(struct musb *musb)
|
|||
struct device *dev = musb->controller;
|
||||
struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
|
||||
|
||||
if (!WARN_ON(!musb->phy))
|
||||
phy_power_off(musb->phy);
|
||||
|
||||
if (glue->status != MUSB_UNKNOWN)
|
||||
omap_control_usb_set_mode(glue->control_otghs,
|
||||
USB_MODE_DISCONNECT);
|
||||
|
||||
omap2430_set_power(musb, false, glue->cable_connected);
|
||||
}
|
||||
|
||||
static int omap2430_musb_exit(struct musb *musb)
|
||||
{
|
||||
del_timer_sync(&musb_idle_timer);
|
||||
struct device *dev = musb->controller;
|
||||
struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
|
||||
|
||||
omap2430_low_level_exit(musb);
|
||||
phy_power_off(musb->phy);
|
||||
phy_exit(musb->phy);
|
||||
musb->phy = NULL;
|
||||
cancel_work_sync(&glue->omap_musb_mailbox_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -512,9 +445,6 @@ static const struct musb_platform_ops omap2430_ops = {
|
|||
.init = omap2430_musb_init,
|
||||
.exit = omap2430_musb_exit,
|
||||
|
||||
.set_mode = omap2430_musb_set_mode,
|
||||
.try_idle = omap2430_musb_try_idle,
|
||||
|
||||
.set_vbus = omap2430_musb_set_vbus,
|
||||
|
||||
.enable = omap2430_musb_enable,
|
||||
|
@ -639,11 +569,9 @@ static int omap2430_probe(struct platform_device *pdev)
|
|||
goto err2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that we cannot enable PM runtime yet for this
|
||||
* driver as we need struct musb initialized first.
|
||||
* See omap2430_musb_init above.
|
||||
*/
|
||||
pm_runtime_enable(glue->dev);
|
||||
pm_runtime_use_autosuspend(glue->dev);
|
||||
pm_runtime_set_autosuspend_delay(glue->dev, 500);
|
||||
|
||||
ret = platform_device_add(musb);
|
||||
if (ret) {
|
||||
|
@ -662,12 +590,14 @@ static int omap2430_probe(struct platform_device *pdev)
|
|||
|
||||
static int omap2430_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap2430_glue *glue = platform_get_drvdata(pdev);
|
||||
struct omap2430_glue *glue = platform_get_drvdata(pdev);
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
|
||||
pm_runtime_get_sync(glue->dev);
|
||||
cancel_work_sync(&glue->omap_musb_mailbox_work);
|
||||
platform_device_unregister(glue->musb);
|
||||
omap2430_set_power(musb, false, false);
|
||||
pm_runtime_put_sync(glue->dev);
|
||||
pm_runtime_dont_use_autosuspend(glue->dev);
|
||||
pm_runtime_disable(glue->dev);
|
||||
|
||||
return 0;
|
||||
|
@ -680,12 +610,13 @@ static int omap2430_runtime_suspend(struct device *dev)
|
|||
struct omap2430_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
|
||||
if (musb) {
|
||||
musb->context.otg_interfsel = musb_readl(musb->mregs,
|
||||
OTG_INTERFSEL);
|
||||
if (!musb)
|
||||
return 0;
|
||||
|
||||
omap2430_low_level_exit(musb);
|
||||
}
|
||||
musb->context.otg_interfsel = musb_readl(musb->mregs,
|
||||
OTG_INTERFSEL);
|
||||
|
||||
omap2430_low_level_exit(musb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -696,7 +627,7 @@ static int omap2430_runtime_resume(struct device *dev)
|
|||
struct musb *musb = glue_to_musb(glue);
|
||||
|
||||
if (!musb)
|
||||
return -EPROBE_DEFER;
|
||||
return 0;
|
||||
|
||||
omap2430_low_level_init(musb);
|
||||
musb_writel(musb->mregs, OTG_INTERFSEL,
|
||||
|
@ -738,18 +669,8 @@ static struct platform_driver omap2430_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
module_platform_driver(omap2430_driver);
|
||||
|
||||
MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
|
||||
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static int __init omap2430_init(void)
|
||||
{
|
||||
return platform_driver_register(&omap2430_driver);
|
||||
}
|
||||
subsys_initcall(omap2430_init);
|
||||
|
||||
static void __exit omap2430_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&omap2430_driver);
|
||||
}
|
||||
module_exit(omap2430_exit);
|
||||
|
|
|
@ -80,7 +80,8 @@ static struct musb *sunxi_musb;
|
|||
|
||||
struct sunxi_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *musb;
|
||||
struct musb *musb;
|
||||
struct platform_device *musb_pdev;
|
||||
struct clk *clk;
|
||||
struct reset_control *rst;
|
||||
struct phy *phy;
|
||||
|
@ -102,7 +103,7 @@ static void sunxi_musb_work(struct work_struct *work)
|
|||
return;
|
||||
|
||||
if (test_and_clear_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags)) {
|
||||
struct musb *musb = platform_get_drvdata(glue->musb);
|
||||
struct musb *musb = glue->musb;
|
||||
unsigned long flags;
|
||||
u8 devctl;
|
||||
|
||||
|
@ -112,7 +113,7 @@ static void sunxi_musb_work(struct work_struct *work)
|
|||
if (test_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags)) {
|
||||
set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
|
||||
musb->xceiv->otg->default_a = 1;
|
||||
musb->xceiv->otg->state = OTG_STATE_A_IDLE;
|
||||
musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
|
||||
MUSB_HST_MODE(musb);
|
||||
devctl |= MUSB_DEVCTL_SESSION;
|
||||
} else {
|
||||
|
@ -145,10 +146,12 @@ static void sunxi_musb_set_vbus(struct musb *musb, int is_on)
|
|||
{
|
||||
struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
|
||||
|
||||
if (is_on)
|
||||
if (is_on) {
|
||||
set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
|
||||
else
|
||||
musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
|
||||
} else {
|
||||
clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
|
||||
}
|
||||
|
||||
schedule_work(&glue->work);
|
||||
}
|
||||
|
@ -264,15 +267,6 @@ static int sunxi_musb_init(struct musb *musb)
|
|||
if (ret)
|
||||
goto error_unregister_notifier;
|
||||
|
||||
if (musb->port_mode == MUSB_PORT_MODE_HOST) {
|
||||
ret = phy_power_on(glue->phy);
|
||||
if (ret)
|
||||
goto error_phy_exit;
|
||||
set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
|
||||
/* Stop musb work from turning vbus off again */
|
||||
set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
|
||||
}
|
||||
|
||||
musb->isr = sunxi_musb_interrupt;
|
||||
|
||||
/* Stop the musb-core from doing runtime pm (not supported on sunxi) */
|
||||
|
@ -280,8 +274,6 @@ static int sunxi_musb_init(struct musb *musb)
|
|||
|
||||
return 0;
|
||||
|
||||
error_phy_exit:
|
||||
phy_exit(glue->phy);
|
||||
error_unregister_notifier:
|
||||
if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
|
||||
extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
|
||||
|
@ -323,10 +315,31 @@ static int sunxi_musb_exit(struct musb *musb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_set_mode(struct musb *musb, u8 mode)
|
||||
{
|
||||
struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
|
||||
int ret;
|
||||
|
||||
if (mode == MUSB_HOST) {
|
||||
ret = phy_power_on(glue->phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
|
||||
/* Stop musb work from turning vbus off again */
|
||||
set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
|
||||
musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sunxi_musb_enable(struct musb *musb)
|
||||
{
|
||||
struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
|
||||
|
||||
glue->musb = musb;
|
||||
|
||||
/* musb_core does not call us in a balanced manner */
|
||||
if (test_and_set_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags))
|
||||
return;
|
||||
|
@ -569,6 +582,7 @@ static const struct musb_platform_ops sunxi_musb_ops = {
|
|||
.exit = sunxi_musb_exit,
|
||||
.enable = sunxi_musb_enable,
|
||||
.disable = sunxi_musb_disable,
|
||||
.set_mode = sunxi_set_mode,
|
||||
.fifo_offset = sunxi_musb_fifo_offset,
|
||||
.ep_offset = sunxi_musb_ep_offset,
|
||||
.busctl_offset = sunxi_musb_busctl_offset,
|
||||
|
@ -721,9 +735,9 @@ static int sunxi_musb_probe(struct platform_device *pdev)
|
|||
pinfo.data = &pdata;
|
||||
pinfo.size_data = sizeof(pdata);
|
||||
|
||||
glue->musb = platform_device_register_full(&pinfo);
|
||||
if (IS_ERR(glue->musb)) {
|
||||
ret = PTR_ERR(glue->musb);
|
||||
glue->musb_pdev = platform_device_register_full(&pinfo);
|
||||
if (IS_ERR(glue->musb_pdev)) {
|
||||
ret = PTR_ERR(glue->musb_pdev);
|
||||
dev_err(&pdev->dev, "Error registering musb dev: %d\n", ret);
|
||||
goto err_unregister_usb_phy;
|
||||
}
|
||||
|
@ -740,7 +754,7 @@ static int sunxi_musb_remove(struct platform_device *pdev)
|
|||
struct sunxi_glue *glue = platform_get_drvdata(pdev);
|
||||
struct platform_device *usb_phy = glue->usb_phy;
|
||||
|
||||
platform_device_unregister(glue->musb); /* Frees glue ! */
|
||||
platform_device_unregister(glue->musb_pdev);
|
||||
usb_phy_generic_unregister(usb_phy);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -97,6 +97,9 @@ struct twl6030_usb {
|
|||
|
||||
struct regulator *usb3v3;
|
||||
|
||||
/* used to check initial cable status after probe */
|
||||
struct delayed_work get_status_work;
|
||||
|
||||
/* used to set vbus, in atomic path */
|
||||
struct work_struct set_vbus_work;
|
||||
|
||||
|
@ -227,12 +230,16 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
|
|||
twl->asleep = 1;
|
||||
status = MUSB_VBUS_VALID;
|
||||
twl->linkstat = status;
|
||||
musb_mailbox(status);
|
||||
ret = musb_mailbox(status);
|
||||
if (ret)
|
||||
twl->linkstat = MUSB_UNKNOWN;
|
||||
} else {
|
||||
if (twl->linkstat != MUSB_UNKNOWN) {
|
||||
status = MUSB_VBUS_OFF;
|
||||
twl->linkstat = status;
|
||||
musb_mailbox(status);
|
||||
ret = musb_mailbox(status);
|
||||
if (ret)
|
||||
twl->linkstat = MUSB_UNKNOWN;
|
||||
if (twl->asleep) {
|
||||
regulator_disable(twl->usb3v3);
|
||||
twl->asleep = 0;
|
||||
|
@ -264,7 +271,9 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
|
|||
twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
|
||||
status = MUSB_ID_GROUND;
|
||||
twl->linkstat = status;
|
||||
musb_mailbox(status);
|
||||
ret = musb_mailbox(status);
|
||||
if (ret)
|
||||
twl->linkstat = MUSB_UNKNOWN;
|
||||
} else {
|
||||
twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
|
||||
twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
|
||||
|
@ -274,6 +283,15 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void twl6030_status_work(struct work_struct *work)
|
||||
{
|
||||
struct twl6030_usb *twl = container_of(work, struct twl6030_usb,
|
||||
get_status_work.work);
|
||||
|
||||
twl6030_usb_irq(twl->irq2, twl);
|
||||
twl6030_usbotg_irq(twl->irq1, twl);
|
||||
}
|
||||
|
||||
static int twl6030_enable_irq(struct twl6030_usb *twl)
|
||||
{
|
||||
twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
|
||||
|
@ -284,8 +302,6 @@ static int twl6030_enable_irq(struct twl6030_usb *twl)
|
|||
REG_INT_MSK_LINE_C);
|
||||
twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
|
||||
REG_INT_MSK_STS_C);
|
||||
twl6030_usb_irq(twl->irq2, twl);
|
||||
twl6030_usbotg_irq(twl->irq1, twl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -371,6 +387,7 @@ static int twl6030_usb_probe(struct platform_device *pdev)
|
|||
dev_warn(&pdev->dev, "could not create sysfs file\n");
|
||||
|
||||
INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work);
|
||||
INIT_DELAYED_WORK(&twl->get_status_work, twl6030_status_work);
|
||||
|
||||
status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
|
||||
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
|
@ -395,6 +412,7 @@ static int twl6030_usb_probe(struct platform_device *pdev)
|
|||
|
||||
twl->asleep = 0;
|
||||
twl6030_enable_irq(twl);
|
||||
schedule_delayed_work(&twl->get_status_work, HZ);
|
||||
dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
|
||||
|
||||
return 0;
|
||||
|
@ -404,6 +422,7 @@ static int twl6030_usb_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct twl6030_usb *twl = platform_get_drvdata(pdev);
|
||||
|
||||
cancel_delayed_work(&twl->get_status_work);
|
||||
twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
|
||||
REG_INT_MSK_LINE_C);
|
||||
twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
|
||||
|
|
|
@ -2007,6 +2007,7 @@ static void mos7720_release(struct usb_serial *serial)
|
|||
urblist_entry)
|
||||
usb_unlink_urb(urbtrack->urb);
|
||||
spin_unlock_irqrestore(&mos_parport->listlock, flags);
|
||||
parport_del_port(mos_parport->pp);
|
||||
|
||||
kref_put(&mos_parport->ref_count, destroy_mos_parport);
|
||||
}
|
||||
|
|
|
@ -836,6 +836,7 @@ static int uas_slave_configure(struct scsi_device *sdev)
|
|||
if (devinfo->flags & US_FL_BROKEN_FUA)
|
||||
sdev->broken_fua = 1;
|
||||
|
||||
scsi_change_queue_depth(sdev, devinfo->qdepth - 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -848,7 +849,6 @@ static struct scsi_host_template uas_host_template = {
|
|||
.slave_configure = uas_slave_configure,
|
||||
.eh_abort_handler = uas_eh_abort_handler,
|
||||
.eh_bus_reset_handler = uas_eh_bus_reset_handler,
|
||||
.can_queue = MAX_CMNDS,
|
||||
.this_id = -1,
|
||||
.sg_tablesize = SG_NONE,
|
||||
.skip_settle_delay = 1,
|
||||
|
|
|
@ -941,7 +941,7 @@ static void vhci_stop(struct usb_hcd *hcd)
|
|||
|
||||
static int vhci_get_frame_number(struct usb_hcd *hcd)
|
||||
{
|
||||
pr_err("Not yet implemented\n");
|
||||
dev_err_ratelimited(&hcd->self.root_hub->dev, "Not yet implemented\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1034,6 +1034,8 @@ static inline int usb_gadget_activate(struct usb_gadget *gadget)
|
|||
* @udc_name: A name of UDC this driver should be bound to. If udc_name is NULL,
|
||||
* this driver will be bound to any available UDC.
|
||||
* @pending: UDC core private data used for deferred probe of this driver.
|
||||
* @match_existing_only: If udc is not found, return an error and don't add this
|
||||
* gadget driver to list of pending driver
|
||||
*
|
||||
* Devices are disabled till a gadget driver successfully bind()s, which
|
||||
* means the driver will handle setup() requests needed to enumerate (and
|
||||
|
@ -1097,6 +1099,7 @@ struct usb_gadget_driver {
|
|||
|
||||
char *udc_name;
|
||||
struct list_head pending;
|
||||
unsigned match_existing_only:1;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -142,10 +142,11 @@ enum musb_vbus_id_status {
|
|||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_MUSB_HDRC)
|
||||
void musb_mailbox(enum musb_vbus_id_status status);
|
||||
int musb_mailbox(enum musb_vbus_id_status status);
|
||||
#else
|
||||
static inline void musb_mailbox(enum musb_vbus_id_status status)
|
||||
static inline int musb_mailbox(enum musb_vbus_id_status status)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue