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:
Linus Torvalds 2016-06-18 06:06:49 -10:00
commit e80dac114c
42 changed files with 573 additions and 447 deletions

View File

@ -1,6 +1,6 @@
What: /config/usb-gadget/gadget/functions/uvc.name What: /config/usb-gadget/gadget/functions/uvc.name
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: UVC function directory Description: UVC function directory
streaming_maxburst - 0..15 (ss only) streaming_maxburst - 0..15 (ss only)
@ -9,37 +9,37 @@ Description: UVC function directory
What: /config/usb-gadget/gadget/functions/uvc.name/control What: /config/usb-gadget/gadget/functions/uvc.name/control
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Control descriptors Description: Control descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/class What: /config/usb-gadget/gadget/functions/uvc.name/control/class
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Class descriptors Description: Class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/class/ss What: /config/usb-gadget/gadget/functions/uvc.name/control/class/ss
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Super speed control class descriptors Description: Super speed control class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/class/fs What: /config/usb-gadget/gadget/functions/uvc.name/control/class/fs
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Full speed control class descriptors Description: Full speed control class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Terminal descriptors Description: Terminal descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/output What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/output
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Output terminal descriptors Description: Output terminal descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/output/default What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/output/default
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Default output terminal descriptors Description: Default output terminal descriptors
All attributes read only: All attributes read only:
@ -53,12 +53,12 @@ Description: Default output terminal descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/camera What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/camera
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Camera terminal descriptors Description: Camera terminal descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/camera/default What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/camera/default
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Default camera terminal descriptors Description: Default camera terminal descriptors
All attributes read only: All attributes read only:
@ -75,12 +75,12 @@ Description: Default camera terminal descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/processing What: /config/usb-gadget/gadget/functions/uvc.name/control/processing
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Processing unit descriptors Description: Processing unit descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/processing/default What: /config/usb-gadget/gadget/functions/uvc.name/control/processing/default
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Default processing unit descriptors Description: Default processing unit descriptors
All attributes read only: All attributes read only:
@ -94,49 +94,49 @@ Description: Default processing unit descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/header What: /config/usb-gadget/gadget/functions/uvc.name/control/header
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Control header descriptors Description: Control header descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/header/name What: /config/usb-gadget/gadget/functions/uvc.name/control/header/name
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Specific control header descriptors Description: Specific control header descriptors
dwClockFrequency dwClockFrequency
bcdUVC bcdUVC
What: /config/usb-gadget/gadget/functions/uvc.name/streaming What: /config/usb-gadget/gadget/functions/uvc.name/streaming
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Streaming descriptors Description: Streaming descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Streaming class descriptors Description: Streaming class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/ss What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/ss
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Super speed streaming class descriptors Description: Super speed streaming class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/hs What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/hs
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: High speed streaming class descriptors Description: High speed streaming class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/fs What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/fs
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Full speed streaming class descriptors Description: Full speed streaming class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching What: /config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Color matching descriptors Description: Color matching descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching/default What: /config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching/default
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Default color matching descriptors Description: Default color matching descriptors
All attributes read only: All attributes read only:
@ -150,12 +150,12 @@ Description: Default color matching descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg What: /config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: MJPEG format descriptors Description: MJPEG format descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg/name What: /config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg/name
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Specific MJPEG format descriptors Description: Specific MJPEG format descriptors
All attributes read only, 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 What: /config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg/name/name
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Specific MJPEG frame descriptors Description: Specific MJPEG frame descriptors
dwFrameInterval - indicates how frame interval can be 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 What: /config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Uncompressed format descriptors Description: Uncompressed format descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed/name What: /config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed/name
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Specific uncompressed format descriptors Description: Specific uncompressed format descriptors
bmaControls - this format's data for bmaControls in 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 What: /config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed/name/name
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Specific uncompressed frame descriptors Description: Specific uncompressed frame descriptors
dwFrameInterval - indicates how frame interval can be 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 What: /config/usb-gadget/gadget/functions/uvc.name/streaming/header
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Streaming header descriptors Description: Streaming header descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/header/name What: /config/usb-gadget/gadget/functions/uvc.name/streaming/header/name
Date: Dec 2014 Date: Dec 2014
KernelVersion: 3.20 KernelVersion: 4.0
Description: Specific streaming header descriptors Description: Specific streaming header descriptors
All attributes read only: All attributes read only:

View File

@ -11975,6 +11975,7 @@ L: linux-usb@vger.kernel.org
W: http://www.linux-usb.org W: http://www.linux-usb.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
S: Supported S: Supported
F: Documentation/devicetree/bindings/usb/
F: Documentation/usb/ F: Documentation/usb/
F: drivers/usb/ F: drivers/usb/
F: include/linux/usb.h F: include/linux/usb.h

View File

@ -233,8 +233,12 @@ static inline int __is_running(const struct exynos_mipi_phy_desc *data,
struct exynos_mipi_video_phy *state) struct exynos_mipi_video_phy *state)
{ {
u32 val; 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; return val & data->resetn_val;
} }

View File

@ -293,11 +293,18 @@ static int ti_pipe3_init(struct phy *x)
ret = ti_pipe3_dpll_wait_lock(phy); 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); val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
if (!(val & PLL_LOCK)) if ((val & PLL_LOCK) && of_device_is_compatible(phy->dev->of_node,
if (ti_pipe3_dpll_program(phy)) "ti,phy-pipe3-sata"))
return -EINVAL; return ret;
/* Program the DPLL */
ret = ti_pipe3_dpll_program(phy);
if (ret) {
ti_pipe3_disable_clocks(phy);
return -EINVAL;
}
return ret; return ret;
} }

View File

@ -463,7 +463,8 @@ static int twl4030_phy_power_on(struct phy *phy)
twl4030_usb_set_mode(twl, twl->usb_mode); twl4030_usb_set_mode(twl, twl->usb_mode);
if (twl->usb_mode == T2_USB_MODE_ULPI) if (twl->usb_mode == T2_USB_MODE_ULPI)
twl4030_i2c_access(twl, 0); 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; return 0;
} }
@ -537,6 +538,7 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
struct twl4030_usb *twl = _twl; struct twl4030_usb *twl = _twl;
enum musb_vbus_id_status status; enum musb_vbus_id_status status;
bool status_changed = false; bool status_changed = false;
int err;
status = twl4030_usb_linkstat(twl); 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_mark_last_busy(twl->dev);
pm_runtime_put_autosuspend(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 */ /* 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); struct twl4030_usb *twl = phy_get_drvdata(phy);
pm_runtime_get_sync(twl->dev); 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_mark_last_busy(twl->dev);
pm_runtime_put_autosuspend(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)) if (cable_present(twl->linkstat))
pm_runtime_put_noidle(twl->dev); pm_runtime_put_noidle(twl->dev);
pm_runtime_mark_last_busy(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); pm_runtime_disable(twl->dev);
/* autogate 60MHz ULPI clock, /* autogate 60MHz ULPI clock,

View File

@ -44,6 +44,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Creative SB Audigy 2 NX */ /* Creative SB Audigy 2 NX */
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, { 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 */ /* Microsoft Wireless Laser Mouse 6000 Receiver */
{ USB_DEVICE(0x045e, 0x00e1), .driver_info = USB_QUIRK_RESET_RESUME }, { 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 */ /* MAYA44USB sound device */
{ USB_DEVICE(0x0a92, 0x0091), .driver_info = USB_QUIRK_RESET_RESUME }, { 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 */ /* Action Semiconductor flash disk */
{ USB_DEVICE(0x10d6, 0x2200), .driver_info = { USB_DEVICE(0x10d6, 0x2200), .driver_info =
USB_QUIRK_STRING_FETCH_255 }, 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_DEVICE(0x1908, 0x1315), .driver_info =
USB_QUIRK_HONOR_BNUMINTERFACES }, 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 */ /* Protocol and OTG Electrical Test Device */
{ USB_DEVICE(0x1a0a, 0x0200), .driver_info = { USB_DEVICE(0x1a0a, 0x0200), .driver_info =
USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
/* Acer C120 LED Projector */
{ USB_DEVICE(0x1de1, 0xc102), .driver_info = USB_QUIRK_NO_LPM },
/* Blackmagic Design Intensity Shuttle */ /* Blackmagic Design Intensity Shuttle */
{ USB_DEVICE(0x1edb, 0xbd3b), .driver_info = USB_QUIRK_NO_LPM }, { USB_DEVICE(0x1edb, 0xbd3b), .driver_info = USB_QUIRK_NO_LPM },
/* Blackmagic Design UltraStudio SDI */ /* Blackmagic Design UltraStudio SDI */
{ USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM }, { 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 */ { } /* terminating entry must be last */
}; };

View File

@ -64,6 +64,17 @@
DWC2_TRACE_SCHEDULER_VB(pr_fmt("%s: SCH: " fmt), \ DWC2_TRACE_SCHEDULER_VB(pr_fmt("%s: SCH: " fmt), \
dev_name(hsotg->dev), ##__VA_ARGS__) 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) static inline u32 dwc2_readl(const void __iomem *addr)
{ {
u32 value = __raw_readl(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); pr_info("INFO:: wrote %08x to %p\n", value, addr);
#endif #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 */ /* Maximum number of Endpoints/HostChannels */
#define MAX_EPS_CHANNELS 16 #define MAX_EPS_CHANNELS 16

View File

@ -1018,7 +1018,7 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg,
return 1; 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 * 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: case USB_ENDPOINT_HALT:
halted = ep->halted; 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); ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0);
if (ret) { 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 * dwc2_hsotg_ep_sethalt - set halt on a given endpoint
* @ep: The endpoint to set halt. * @ep: The endpoint to set halt.
* @value: Set or unset the 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_ep *hs_ep = our_ep(ep);
struct dwc2_hsotg *hs = hs_ep->parent; 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; 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) { if (hs_ep->dir_in) {
epreg = DIEPCTL(index); epreg = DIEPCTL(index);
epctl = dwc2_readl(hs->regs + epreg); 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; int ret = 0;
spin_lock_irqsave(&hs->lock, flags); 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); spin_unlock_irqrestore(&hs->lock, flags);
return ret; return ret;

View File

@ -402,6 +402,7 @@
#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f) #define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
#define DWC3_DEPCMD_STATUS(x) (((x) >> 12) & 0x0F) #define DWC3_DEPCMD_STATUS(x) (((x) >> 12) & 0x0F)
#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11) #define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
#define DWC3_DEPCMD_CLEARPENDIN (1 << 11)
#define DWC3_DEPCMD_CMDACT (1 << 10) #define DWC3_DEPCMD_CMDACT (1 << 10)
#define DWC3_DEPCMD_CMDIOC (1 << 8) #define DWC3_DEPCMD_CMDIOC (1 << 8)

View File

@ -128,12 +128,6 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, exynos); 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->dev = dev;
exynos->clk = devm_clk_get(dev, "usbdrd30"); exynos->clk = devm_clk_get(dev, "usbdrd30");
@ -183,20 +177,29 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
goto err3; goto err3;
} }
ret = dwc3_exynos_register_phys(exynos);
if (ret) {
dev_err(dev, "couldn't register PHYs\n");
goto err4;
}
if (node) { if (node) {
ret = of_platform_populate(node, NULL, NULL, dev); ret = of_platform_populate(node, NULL, NULL, dev);
if (ret) { if (ret) {
dev_err(dev, "failed to add dwc3 core\n"); dev_err(dev, "failed to add dwc3 core\n");
goto err4; goto err5;
} }
} else { } else {
dev_err(dev, "no device node, failed to add dwc3 core\n"); dev_err(dev, "no device node, failed to add dwc3 core\n");
ret = -ENODEV; ret = -ENODEV;
goto err4; goto err5;
} }
return 0; return 0;
err5:
platform_device_unregister(exynos->usb2_phy);
platform_device_unregister(exynos->usb3_phy);
err4: err4:
regulator_disable(exynos->vdd10); regulator_disable(exynos->vdd10);
err3: err3:

View File

@ -129,12 +129,18 @@ static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data)
switch (dwc3_data->dr_mode) { switch (dwc3_data->dr_mode) {
case USB_DR_MODE_PERIPHERAL: 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_OPMODE | USB3_FORCE_OPMODE(0x3)
| USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2 | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2
| USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2); | 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; break;
case USB_DR_MODE_HOST: case USB_DR_MODE_HOST:

View File

@ -347,6 +347,28 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
return ret; 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(&params, 0, sizeof(params));
return dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
}
static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
struct dwc3_trb *trb) struct dwc3_trb *trb)
{ {
@ -1314,8 +1336,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
else else
dep->flags |= DWC3_EP_STALL; dep->flags |= DWC3_EP_STALL;
} else { } else {
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, ret = dwc3_send_clear_stall_ep_cmd(dep);
DWC3_DEPCMD_CLEARSTALL, &params);
if (ret) if (ret)
dev_err(dwc->dev, "failed to clear STALL on %s\n", dev_err(dwc->dev, "failed to clear STALL on %s\n",
dep->name); dep->name);
@ -2247,7 +2268,6 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) { for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
struct dwc3_ep *dep; struct dwc3_ep *dep;
struct dwc3_gadget_ep_cmd_params params;
int ret; int ret;
dep = dwc->eps[epnum]; dep = dwc->eps[epnum];
@ -2259,9 +2279,7 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
dep->flags &= ~DWC3_EP_STALL; dep->flags &= ~DWC3_EP_STALL;
memset(&params, 0, sizeof(params)); ret = dwc3_send_clear_stall_ep_cmd(dep);
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
DWC3_DEPCMD_CLEARSTALL, &params);
WARN_ON_ONCE(ret); WARN_ON_ONCE(ret);
} }
} }

View File

@ -1868,14 +1868,19 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
} }
break; break;
} }
req->length = value;
req->context = cdev; if (value >= 0) {
req->zero = value < w_length; req->length = value;
value = composite_ep0_queue(cdev, req, GFP_ATOMIC); req->context = cdev;
if (value < 0) { req->zero = value < w_length;
DBG(cdev, "ep_queue --> %d\n", value); value = composite_ep0_queue(cdev, req,
req->status = 0; GFP_ATOMIC);
composite_setup_complete(gadget->ep0, req); if (value < 0) {
DBG(cdev, "ep_queue --> %d\n", value);
req->status = 0;
composite_setup_complete(gadget->ep0,
req);
}
} }
return value; return value;
} }

View File

@ -1401,6 +1401,7 @@ static const struct usb_gadget_driver configfs_driver_template = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "configfs-gadget", .name = "configfs-gadget",
}, },
.match_existing_only = 1,
}; };
static struct config_group *gadgets_make( static struct config_group *gadgets_make(

View File

@ -2051,7 +2051,7 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
if (len < sizeof(*d) || if (len < sizeof(*d) ||
d->bFirstInterfaceNumber >= ffs->interfaces_count || d->bFirstInterfaceNumber >= ffs->interfaces_count ||
d->Reserved1) !d->Reserved1)
return -EINVAL; return -EINVAL;
for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i) for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i)
if (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; func->ffs->ss_descs_count;
int fs_len, hs_len, ss_len, ret, i; int fs_len, hs_len, ss_len, ret, i;
struct ffs_ep *eps_ptr;
/* Make it a single chunk, less management later on */ /* Make it a single chunk, less management later on */
vla_group(d); vla_group(d);
@ -2777,12 +2778,9 @@ static int _ffs_func_bind(struct usb_configuration *c,
ffs->raw_descs_length); ffs->raw_descs_length);
memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz); memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
for (ret = ffs->eps_count; ret; --ret) { eps_ptr = vla_ptr(vlabuf, d, eps);
struct ffs_ep *ptr; for (i = 0; i < ffs->eps_count; i++)
eps_ptr[i].num = -1;
ptr = vla_ptr(vlabuf, d, eps);
ptr[ret].num = -1;
}
/* Save pointers /* Save pointers
* d_eps == vlabuf, func->eps used to kfree vlabuf later * 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; goto error;
func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table); 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) { for (i = 0; i < ffs->interfaces_count; ++i) {
struct usb_os_desc *desc; 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; vla_ptr(vlabuf, d, ext_compat) + i * 16;
INIT_LIST_HEAD(&desc->ext_prop); INIT_LIST_HEAD(&desc->ext_prop);
} }
ret = ffs_do_os_descs(ffs->ms_os_descs_count, ret = ffs_do_os_descs(ffs->ms_os_descs_count,
vla_ptr(vlabuf, d, raw_descs) + vla_ptr(vlabuf, d, raw_descs) +
fs_len + hs_len + ss_len, fs_len + hs_len + ss_len,
d_raw_descs__sz - fs_len - hs_len - ss_len, d_raw_descs__sz - fs_len - hs_len -
__ffs_func_bind_do_os_desc, func); ss_len,
if (unlikely(ret < 0)) __ffs_func_bind_do_os_desc, func);
goto error; if (unlikely(ret < 0))
goto error;
}
func->function.os_desc_n = func->function.os_desc_n =
c->cdev->use_os_string ? ffs->interfaces_count : 0; c->cdev->use_os_string ? ffs->interfaces_count : 0;

View File

@ -161,14 +161,6 @@ static struct usb_endpoint_descriptor hs_ep_out_desc = {
.wMaxPacketSize = cpu_to_le16(512) .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[] = { static struct usb_descriptor_header *hs_printer_function[] = {
(struct usb_descriptor_header *) &intf_desc, (struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &hs_ep_in_desc, (struct usb_descriptor_header *) &hs_ep_in_desc,

View File

@ -1445,16 +1445,18 @@ static void usbg_drop_tpg(struct se_portal_group *se_tpg)
for (i = 0; i < TPG_INSTANCES; ++i) for (i = 0; i < TPG_INSTANCES; ++i)
if (tpg_instances[i].tpg == tpg) if (tpg_instances[i].tpg == tpg)
break; break;
if (i < TPG_INSTANCES) if (i < TPG_INSTANCES) {
tpg_instances[i].tpg = NULL; tpg_instances[i].tpg = NULL;
opts = container_of(tpg_instances[i].func_inst, opts = container_of(tpg_instances[i].func_inst,
struct f_tcm_opts, func_inst); struct f_tcm_opts, func_inst);
mutex_lock(&opts->dep_lock); mutex_lock(&opts->dep_lock);
if (opts->has_dep) if (opts->has_dep)
module_put(opts->dependent); module_put(opts->dependent);
else else
configfs_undepend_item_unlocked(&opts->func_inst.group.cg_item); configfs_undepend_item_unlocked(
mutex_unlock(&opts->dep_lock); &opts->func_inst.group.cg_item);
mutex_unlock(&opts->dep_lock);
}
mutex_unlock(&tpg_instances_lock); mutex_unlock(&tpg_instances_lock);
kfree(tpg); kfree(tpg);

View File

@ -598,18 +598,6 @@ static struct usb_gadget_strings *fn_strings[] = {
NULL, 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 = { static struct usb_interface_assoc_descriptor iad_desc = {
.bLength = sizeof iad_desc, .bLength = sizeof iad_desc,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, .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) { if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
struct cntrl_cur_lay3 c; struct cntrl_cur_lay3 c;
memset(&c, 0, sizeof(struct cntrl_cur_lay3));
if (entity_id == USB_IN_CLK_ID) if (entity_id == USB_IN_CLK_ID)
c.dCUR = p_srate; c.dCUR = p_srate;

View File

@ -83,9 +83,7 @@ EXPORT_SYMBOL_GPL(fsg_fs_function);
* USB 2.0 devices need to expose both high speed and full speed * USB 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed. * descriptors, unless they only run at full speed.
* *
* That means alternate endpoint descriptors (bigger packets) * That means alternate endpoint descriptors (bigger packets).
* and a "device qualifier" ... plus more construction options
* for the configuration descriptor.
*/ */
struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = { struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,

View File

@ -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_ep *ep = dev->gadget->ep0;
struct usb_request *req = dev->req; struct usb_request *req = dev->req;
if ((retval = setup_req (ep, req, 0)) == 0) if ((retval = setup_req (ep, req, 0)) == 0) {
retval = usb_ep_queue (ep, req, GFP_ATOMIC); spin_unlock_irq (&dev->lock);
retval = usb_ep_queue (ep, req, GFP_KERNEL);
spin_lock_irq (&dev->lock);
}
dev->state = STATE_DEV_CONNECTED; dev->state = STATE_DEV_CONNECTED;
/* assume that was SET_CONFIGURATION */ /* assume that was SET_CONFIGURATION */
@ -1457,8 +1460,11 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
w_length); w_length);
if (value < 0) if (value < 0)
break; break;
spin_unlock (&dev->lock);
value = usb_ep_queue (gadget->ep0, dev->req, value = usb_ep_queue (gadget->ep0, dev->req,
GFP_ATOMIC); GFP_KERNEL);
spin_lock (&dev->lock);
if (value < 0) { if (value < 0) {
clean_req (gadget->ep0, dev->req); clean_req (gadget->ep0, dev->req);
break; break;
@ -1481,11 +1487,14 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (value >= 0 && dev->state != STATE_DEV_SETUP) { if (value >= 0 && dev->state != STATE_DEV_SETUP) {
req->length = value; req->length = value;
req->zero = value < w_length; 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) { if (value < 0) {
DBG (dev, "ep_queue --> %d\n", value); DBG (dev, "ep_queue --> %d\n", value);
req->status = 0; req->status = 0;
} }
return value;
} }
/* device stalls when value < 0 */ /* device stalls when value < 0 */

View File

@ -603,11 +603,15 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
} }
} }
list_add_tail(&driver->pending, &gadget_driver_pending_list); if (!driver->match_existing_only) {
pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n", list_add_tail(&driver->pending, &gadget_driver_pending_list);
driver->function); 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); mutex_unlock(&udc_lock);
return 0; return ret;
found: found:
ret = udc_bind_to_driver(udc, driver); ret = udc_bind_to_driver(udc, driver);
mutex_unlock(&udc_lock); mutex_unlock(&udc_lock);

View File

@ -368,6 +368,15 @@ static void ehci_shutdown(struct usb_hcd *hcd)
{ {
struct ehci_hcd *ehci = hcd_to_ehci(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); spin_lock_irq(&ehci->lock);
ehci->shutdown = true; ehci->shutdown = true;
ehci->rh_state = EHCI_RH_STOPPING; ehci->rh_state = EHCI_RH_STOPPING;

View File

@ -872,14 +872,22 @@ int ehci_hub_control(
) { ) {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int ports = HCS_N_PORTS (ehci->hcs_params); int ports = HCS_N_PORTS (ehci->hcs_params);
u32 __iomem *status_reg = &ehci->regs->port_status[ u32 __iomem *status_reg, *hostpc_reg;
(wIndex & 0xff) - 1];
u32 __iomem *hostpc_reg = &ehci->regs->hostpc[(wIndex & 0xff) - 1];
u32 temp, temp1, status; u32 temp, temp1, status;
unsigned long flags; unsigned long flags;
int retval = 0; int retval = 0;
unsigned selector; 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. * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
* HCS_INDICATOR may say we can change LEDs to off/amber/green. * HCS_INDICATOR may say we can change LEDs to off/amber/green.

View File

@ -179,22 +179,32 @@ static int ehci_msm_remove(struct platform_device *pdev)
static int ehci_msm_pm_suspend(struct device *dev) static int ehci_msm_pm_suspend(struct device *dev)
{ {
struct usb_hcd *hcd = dev_get_drvdata(dev); struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
bool do_wakeup = device_may_wakeup(dev); bool do_wakeup = device_may_wakeup(dev);
dev_dbg(dev, "ehci-msm PM suspend\n"); 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) static int ehci_msm_pm_resume(struct device *dev)
{ {
struct usb_hcd *hcd = dev_get_drvdata(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"); 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; return 0;
} }
#else #else
#define ehci_msm_pm_suspend NULL #define ehci_msm_pm_suspend NULL
#define ehci_msm_pm_resume NULL #define ehci_msm_pm_resume NULL

View File

@ -81,15 +81,23 @@ static int tegra_reset_usb_controller(struct platform_device *pdev)
struct usb_hcd *hcd = platform_get_drvdata(pdev); struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct tegra_ehci_hcd *tegra = struct tegra_ehci_hcd *tegra =
(struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv; (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); phy_np = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0);
if (!phy_np) if (!phy_np)
return -ENOENT; return -ENOENT;
if (of_property_read_bool(phy_np, "nvidia,has-utmi-pad-registers"))
has_utmi_pad_registers = true;
if (!usb1_reset_attempted) { if (!usb1_reset_attempted) {
struct reset_control *usb1_reset; 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)) { if (IS_ERR(usb1_reset)) {
dev_warn(&pdev->dev, dev_warn(&pdev->dev,
"can't get utmi-pads reset from the PHY\n"); "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); reset_control_assert(usb1_reset);
udelay(1); udelay(1);
reset_control_deassert(usb1_reset); reset_control_deassert(usb1_reset);
if (!has_utmi_pad_registers)
reset_control_put(usb1_reset);
} }
reset_control_put(usb1_reset);
usb1_reset_attempted = true; 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); reset_control_assert(tegra->rst);
udelay(1); udelay(1);
reset_control_deassert(tegra->rst); reset_control_deassert(tegra->rst);

View File

@ -183,7 +183,6 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
{ {
int branch; int branch;
ed->state = ED_OPER;
ed->ed_prev = NULL; ed->ed_prev = NULL;
ed->ed_next = NULL; ed->ed_next = NULL;
ed->hwNextED = 0; 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 /* the HC may not see the schedule updates yet, but if it does
* then they'll be properly ordered. * then they'll be properly ordered.
*/ */
ed->state = ED_OPER;
return 0; return 0;
} }

View File

@ -37,6 +37,7 @@
/* Device for a quirk */ /* Device for a quirk */
#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 #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_DEVICE_ID_FRESCO_LOGIC_FL1400 0x1400
#define PCI_VENDOR_ID_ETRON 0x1b6f #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; 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) if (pdev->vendor == PCI_VENDOR_ID_NEC)
xhci->quirks |= XHCI_NEC_HOST; xhci->quirks |= XHCI_NEC_HOST;

View File

@ -196,6 +196,9 @@ static int xhci_plat_probe(struct platform_device *pdev)
ret = clk_prepare_enable(clk); ret = clk_prepare_enable(clk);
if (ret) if (ret)
goto put_hcd; goto put_hcd;
} else if (PTR_ERR(clk) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto put_hcd;
} }
xhci = hcd_to_xhci(hcd); xhci = hcd_to_xhci(hcd);

View File

@ -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); temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
xhci->cmd_ring_state = CMD_RING_STATE_ABORTED; 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_write_64(xhci, temp_64 | CMD_RING_ABORT,
&xhci->op_regs->cmd_ring); &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, " xhci_err(xhci, "Stopped the command ring failed, "
"maybe the host is dead\n"); "maybe the host is dead\n");
del_timer(&xhci->cmd_timer);
xhci->xhc_state |= XHCI_STATE_DYING; xhci->xhc_state |= XHCI_STATE_DYING;
xhci_quiesce(xhci); xhci_quiesce(xhci);
xhci_halt(xhci); xhci_halt(xhci);
@ -1246,22 +1255,21 @@ void xhci_handle_command_timeout(unsigned long data)
int ret; int ret;
unsigned long flags; unsigned long flags;
u64 hw_ring_state; u64 hw_ring_state;
struct xhci_command *cur_cmd = NULL; bool second_timeout = false;
xhci = (struct xhci_hcd *) data; xhci = (struct xhci_hcd *) data;
/* mark this command to be cancelled */ /* mark this command to be cancelled */
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
if (xhci->current_cmd) { if (xhci->current_cmd) {
cur_cmd = xhci->current_cmd; if (xhci->current_cmd->status == COMP_CMD_ABORT)
cur_cmd->status = COMP_CMD_ABORT; second_timeout = true;
xhci->current_cmd->status = COMP_CMD_ABORT;
} }
/* Make sure command ring is running before aborting it */ /* Make sure command ring is running before aborting it */
hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) && if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) &&
(hw_ring_state & CMD_RING_RUNNING)) { (hw_ring_state & CMD_RING_RUNNING)) {
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "Command timeout\n"); xhci_dbg(xhci, "Command timeout\n");
ret = xhci_abort_cmd_ring(xhci); ret = xhci_abort_cmd_ring(xhci);
@ -1273,6 +1281,15 @@ void xhci_handle_command_timeout(unsigned long data)
} }
return; 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 */ /* command timeout on stopped ring, ring can't be aborted */
xhci_dbg(xhci, "Command timeout on stopped ring\n"); xhci_dbg(xhci, "Command timeout on stopped ring\n");
xhci_handle_stopped_cmd_ring(xhci, xhci->current_cmd); 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); 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. " xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
"Shouldn't IRQs be disabled?\n"); "Shouldn't IRQs be disabled?\n");
/* Clear the event handler busy flag (RW1C); /* Clear the event handler busy flag (RW1C);

View File

@ -685,20 +685,23 @@ void xhci_stop(struct usb_hcd *hcd)
u32 temp; u32 temp;
struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_hcd *xhci = hcd_to_xhci(hcd);
if (xhci->xhc_state & XHCI_STATE_HALTED)
return;
mutex_lock(&xhci->mutex); 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 if (!(xhci->xhc_state & XHCI_STATE_HALTED)) {
* (xhci_stop() could be called as part of failed init). spin_lock_irq(&xhci->lock);
*/
xhci_halt(xhci); xhci->xhc_state |= XHCI_STATE_HALTED;
xhci_reset(xhci); xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
spin_unlock_irq(&xhci->lock); 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); 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->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
xhci_print_registers(xhci); xhci_print_registers(xhci);
xhci->quirks = quirks; xhci->quirks |= quirks;
get_quirks(dev, xhci); get_quirks(dev, xhci);

View File

@ -1090,29 +1090,6 @@ void musb_stop(struct musb *musb)
musb_platform_try_idle(musb, 0); 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 #define use_dma 0
#endif #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 * 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 * 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. * 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) if (musb_phy_callback)
musb_phy_callback(status); return musb_phy_callback(status);
return -ENODEV;
}; };
EXPORT_SYMBOL_GPL(musb_mailbox); 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_readl = musb_default_readl;
musb_writel = musb_default_writel; 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: /* The musb_platform_init() call:
* - adjusts musb->mregs * - adjusts musb->mregs
* - sets the musb->isr * - sets the musb->isr
@ -2134,6 +2107,16 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
if (musb->ops->phy_callback) if (musb->ops->phy_callback)
musb_phy_callback = 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); pm_runtime_get_sync(musb->controller);
status = usb_phy_init(musb->xceiv); status = usb_phy_init(musb->xceiv);
@ -2237,13 +2220,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
if (status) if (status)
goto fail5; goto fail5;
pm_runtime_put(musb->controller); pm_runtime_mark_last_busy(musb->controller);
pm_runtime_put_autosuspend(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);
return 0; return 0;
@ -2265,7 +2243,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
usb_phy_shutdown(musb->xceiv); usb_phy_shutdown(musb->xceiv);
err_usb_phy_init: err_usb_phy_init:
pm_runtime_dont_use_autosuspend(musb->controller);
pm_runtime_put_sync(musb->controller); pm_runtime_put_sync(musb->controller);
pm_runtime_disable(musb->controller);
fail2: fail2:
if (musb->irq_wake) if (musb->irq_wake)
@ -2273,7 +2253,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
musb_platform_exit(musb); musb_platform_exit(musb);
fail1: fail1:
pm_runtime_disable(musb->controller);
dev_err(musb->controller, dev_err(musb->controller,
"musb_init_controller failed with status %d\n", status); "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 device *dev = &pdev->dev;
struct musb *musb = dev_to_musb(dev); struct musb *musb = dev_to_musb(dev);
unsigned long flags;
/* this gets called on rmmod. /* this gets called on rmmod.
* - Host mode: host may still be active * - 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) * - OTG mode: both roles are deactivated (or never-activated)
*/ */
musb_exit_debugfs(musb); 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_work_sync(&musb->irq_work);
cancel_delayed_work_sync(&musb->finish_resume_work); cancel_delayed_work_sync(&musb->finish_resume_work);
cancel_delayed_work_sync(&musb->deassert_reset_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); musb_free(musb);
device_init_wakeup(dev, 0); device_init_wakeup(dev, 0);
return 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_INTRTXE, musb->intrtxe);
musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe); musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe);
musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe); 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) { for (i = 0; i < musb->config->num_eps; ++i) {
struct musb_hw_ep *hw_ep; struct musb_hw_ep *hw_ep;
@ -2612,7 +2602,6 @@ static struct platform_driver musb_driver = {
}, },
.probe = musb_probe, .probe = musb_probe,
.remove = musb_remove, .remove = musb_remove,
.shutdown = musb_shutdown,
}; };
module_platform_driver(musb_driver); module_platform_driver(musb_driver);

View File

@ -215,7 +215,7 @@ struct musb_platform_ops {
dma_addr_t *dma_addr, u32 *len); dma_addr_t *dma_addr, u32 *len);
void (*pre_root_reset_end)(struct musb *musb); void (*pre_root_reset_end)(struct musb *musb);
void (*post_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 work_struct irq_work;
struct delayed_work deassert_reset_work; struct delayed_work deassert_reset_work;
struct delayed_work finish_resume_work; struct delayed_work finish_resume_work;
struct delayed_work gadget_work;
u16 hwvers; u16 hwvers;
u16 intrrxe; u16 intrrxe;

View File

@ -1656,6 +1656,20 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
return usb_phy_set_power(musb->xceiv, 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) static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
{ {
struct musb *musb = gadget_to_musb(gadget); 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; is_on = !!is_on;
pm_runtime_get_sync(musb->controller);
/* NOTE: this assumes we are sensing vbus; we'd rather /* NOTE: this assumes we are sensing vbus; we'd rather
* not pullup unless the B-session is active. * not pullup unless the B-session is active.
*/ */
spin_lock_irqsave(&musb->lock, flags); spin_lock_irqsave(&musb->lock, flags);
if (is_on != musb->softconnect) { if (is_on != musb->softconnect) {
musb->softconnect = is_on; musb->softconnect = is_on;
musb_pullup(musb, is_on); schedule_delayed_work(&musb->gadget_work, 0);
} }
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
pm_runtime_put(musb->controller);
return 0; return 0;
} }
@ -1845,7 +1855,7 @@ int musb_gadget_setup(struct musb *musb)
#elif IS_ENABLED(CONFIG_USB_MUSB_GADGET) #elif IS_ENABLED(CONFIG_USB_MUSB_GADGET)
musb->g.is_otg = 0; musb->g.is_otg = 0;
#endif #endif
INIT_DELAYED_WORK(&musb->gadget_work, musb_gadget_work);
musb_g_init_endpoints(musb); musb_g_init_endpoints(musb);
musb->is_active = 0; musb->is_active = 0;
@ -1866,6 +1876,8 @@ void musb_gadget_cleanup(struct musb *musb)
{ {
if (musb->port_mode == MUSB_PORT_MODE_HOST) if (musb->port_mode == MUSB_PORT_MODE_HOST)
return; return;
cancel_delayed_work_sync(&musb->gadget_work);
usb_del_gadget_udc(&musb->g); 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) if (musb->xceiv->last_event == USB_EVENT_ID)
musb_platform_set_vbus(musb, 1); musb_platform_set_vbus(musb, 1);
if (musb->xceiv->last_event == USB_EVENT_NONE) pm_runtime_mark_last_busy(musb->controller);
pm_runtime_put(musb->controller); pm_runtime_put_autosuspend(musb->controller);
return 0; return 0;
@ -1934,8 +1946,7 @@ static int musb_gadget_stop(struct usb_gadget *g)
struct musb *musb = gadget_to_musb(g); struct musb *musb = gadget_to_musb(g);
unsigned long flags; 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; * REVISIT always use otg_set_peripheral() here too;
@ -1963,7 +1974,8 @@ static int musb_gadget_stop(struct usb_gadget *g)
* that currently misbehaves. * that currently misbehaves.
*/ */
pm_runtime_put(musb->controller); pm_runtime_mark_last_busy(musb->controller);
pm_runtime_put_autosuspend(musb->controller);
return 0; return 0;
} }

View File

@ -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", dev_dbg(musb->controller, "... next ep%d %cX urb %p\n",
hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh)); hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh));
musb_start_urb(musb, is_in, 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); musb_writew(ep->regs, MUSB_TXCSR, 0);
/* scrub all previous state, clearing toggle */ /* 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 */ /* target addr and (for multipoint) hub addr/port */
if (musb->is_multipoint) { if (musb->is_multipoint) {
@ -627,7 +632,7 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, u8 epnum)
ep->rx_reinit = 0; 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 musb_hw_ep *hw_ep, struct musb_qh *qh,
struct urb *urb, u32 offset, struct urb *urb, u32 offset,
u32 *length, u8 *mode) u32 *length, u8 *mode)
@ -664,23 +669,18 @@ static int musb_tx_dma_set_mode_mentor(struct dma_controller *dma,
} }
channel->desired_mode = *mode; channel->desired_mode = *mode;
musb_writew(epio, MUSB_TXCSR, csr); musb_writew(epio, MUSB_TXCSR, csr);
return 0;
} }
static int musb_tx_dma_set_mode_cppi_tusb(struct dma_controller *dma, static void musb_tx_dma_set_mode_cppi_tusb(struct dma_controller *dma,
struct musb_hw_ep *hw_ep, struct musb_hw_ep *hw_ep,
struct musb_qh *qh, struct musb_qh *qh,
struct urb *urb, struct urb *urb,
u32 offset, u32 offset,
u32 *length, u32 *length,
u8 *mode) u8 *mode)
{ {
struct dma_channel *channel = hw_ep->tx_channel; 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; 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. * to identify the zero-length-final-packet case.
*/ */
*mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0; *mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0;
return 0;
} }
static bool musb_tx_dma_program(struct dma_controller *dma, 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; struct dma_channel *channel = hw_ep->tx_channel;
u16 pkt_size = qh->maxpacket; u16 pkt_size = qh->maxpacket;
u8 mode; u8 mode;
int res;
if (musb_dma_inventra(hw_ep->musb) || musb_dma_ux500(hw_ep->musb)) 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, musb_tx_dma_set_mode_mentor(dma, hw_ep, qh, urb, offset,
offset, &length, &mode); &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 else
res = musb_tx_dma_set_mode_cppi_tusb(dma, hw_ep, qh, urb,
offset, &length, &mode);
if (res)
return false; return false;
qh->segsize = length; qh->segsize = length;
@ -995,9 +992,15 @@ static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep,
if (is_in) { if (is_in) {
dma = is_dma_capable() ? ep->rx_channel : NULL; 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_readw(epio, MUSB_RXCSR);
rx_csr |= MUSB_RXCSR_H_WZC_BITS; 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; rx_csr &= ~MUSB_RXCSR_DATAERROR;
musb_writew(epio, MUSB_RXCSR, rx_csr); 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, struct urb *urb,
size_t len) 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; void __iomem *epio = hw_ep->regs;
dma_addr_t *buf; dma_addr_t *buf;
u32 length, res; u32 length, res;
@ -1870,6 +1873,9 @@ void musb_host_rx(struct musb *musb, u8 epnum)
status = -EPROTO; status = -EPROTO;
musb_writeb(epio, MUSB_RXINTERVAL, 0); 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) { } else if (rx_csr & MUSB_RXCSR_DATAERROR) {
if (USB_ENDPOINT_XFER_ISOC != qh->type) { if (USB_ENDPOINT_XFER_ISOC != qh->type) {

View File

@ -49,97 +49,14 @@ struct omap2430_glue {
enum musb_vbus_id_status status; enum musb_vbus_id_status status;
struct work_struct omap_musb_mailbox_work; struct work_struct omap_musb_mailbox_work;
struct device *control_otghs; struct device *control_otghs;
bool cable_connected;
bool enabled;
bool powered;
}; };
#define glue_to_musb(g) platform_get_drvdata(g->musb) #define glue_to_musb(g) platform_get_drvdata(g->musb)
static struct omap2430_glue *_glue; 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) static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
{ {
struct usb_otg *otg = musb->xceiv->otg; 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)); 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) static inline void omap2430_low_level_exit(struct musb *musb)
{ {
u32 l; u32 l;
@ -234,22 +141,63 @@ static inline void omap2430_low_level_init(struct musb *musb)
musb_writel(musb->mregs, OTG_FORCESTDBY, l); 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; struct omap2430_glue *glue = _glue;
if (!glue) { if (!glue) {
pr_err("%s: musb core is not yet initialized\n", __func__); pr_err("%s: musb core is not yet initialized\n", __func__);
return; return -EPROBE_DEFER;
} }
glue->status = status; glue->status = status;
if (!glue_to_musb(glue)) { if (!glue_to_musb(glue)) {
pr_err("%s: musb core is not yet ready\n", __func__); pr_err("%s: musb core is not yet ready\n", __func__);
return; return -EPROBE_DEFER;
} }
schedule_work(&glue->omap_musb_mailbox_work); schedule_work(&glue->omap_musb_mailbox_work);
return 0;
} }
static void omap_musb_set_mailbox(struct omap2430_glue *glue) 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 musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
struct omap_musb_board_data *data = pdata->board_data; struct omap_musb_board_data *data = pdata->board_data;
struct usb_otg *otg = musb->xceiv->otg; 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) { switch (glue->status) {
case MUSB_ID_GROUND: 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->otg->state = OTG_STATE_A_IDLE;
musb->xceiv->last_event = USB_EVENT_ID; musb->xceiv->last_event = USB_EVENT_ID;
if (musb->gadget_driver) { if (musb->gadget_driver) {
pm_runtime_get_sync(dev);
omap_control_usb_set_mode(glue->control_otghs, omap_control_usb_set_mode(glue->control_otghs,
USB_MODE_HOST); USB_MODE_HOST);
omap2430_musb_set_vbus(musb, 1); omap2430_musb_set_vbus(musb, 1);
@ -281,8 +235,6 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
otg->default_a = false; otg->default_a = false;
musb->xceiv->otg->state = OTG_STATE_B_IDLE; musb->xceiv->otg->state = OTG_STATE_B_IDLE;
musb->xceiv->last_event = USB_EVENT_VBUS; 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); omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE);
break; break;
@ -291,11 +243,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
dev_dbg(dev, "VBUS Disconnect\n"); dev_dbg(dev, "VBUS Disconnect\n");
musb->xceiv->last_event = USB_EVENT_NONE; musb->xceiv->last_event = USB_EVENT_NONE;
if (musb->gadget_driver) { if (musb->gadget_driver)
omap2430_musb_set_vbus(musb, 0); omap2430_musb_set_vbus(musb, 0);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
}
if (data->interface_type == MUSB_INTERFACE_UTMI) if (data->interface_type == MUSB_INTERFACE_UTMI)
otg_set_vbus(musb->xceiv->otg, 0); 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"); dev_dbg(dev, "ID float\n");
} }
if (!cable_connected)
omap2430_set_power(musb, glue->enabled, cable_connected);
atomic_notifier_call_chain(&musb->xceiv->notifier, atomic_notifier_call_chain(&musb->xceiv->notifier,
musb->xceiv->last_event, NULL); 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 *glue = container_of(mailbox_work,
struct omap2430_glue, omap_musb_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); 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) 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); return PTR_ERR(musb->phy);
} }
musb->isr = omap2430_musb_interrupt; musb->isr = omap2430_musb_interrupt;
phy_init(musb->phy);
/*
* 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;
}
l = musb_readl(musb->mregs, OTG_INTERFSEL); 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_INTERFSEL),
musb_readl(musb->mregs, OTG_SIMENABLE)); musb_readl(musb->mregs, OTG_SIMENABLE));
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
if (glue->status != MUSB_UNKNOWN) if (glue->status != MUSB_UNKNOWN)
omap_musb_set_mailbox(glue); 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; return 0;
err1:
return status;
} }
static void omap2430_musb_enable(struct musb *musb) 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 musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
struct omap_musb_board_data *data = pdata->board_data; 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) { switch (glue->status) {
case MUSB_ID_GROUND: case MUSB_ID_GROUND:
@ -487,18 +413,25 @@ static void omap2430_musb_disable(struct musb *musb)
struct device *dev = musb->controller; struct device *dev = musb->controller;
struct omap2430_glue *glue = dev_get_drvdata(dev->parent); struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
if (!WARN_ON(!musb->phy))
phy_power_off(musb->phy);
if (glue->status != MUSB_UNKNOWN) if (glue->status != MUSB_UNKNOWN)
omap_control_usb_set_mode(glue->control_otghs, omap_control_usb_set_mode(glue->control_otghs,
USB_MODE_DISCONNECT); USB_MODE_DISCONNECT);
omap2430_set_power(musb, false, glue->cable_connected);
} }
static int omap2430_musb_exit(struct musb *musb) 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); omap2430_low_level_exit(musb);
phy_power_off(musb->phy);
phy_exit(musb->phy); phy_exit(musb->phy);
musb->phy = NULL;
cancel_work_sync(&glue->omap_musb_mailbox_work);
return 0; return 0;
} }
@ -512,9 +445,6 @@ static const struct musb_platform_ops omap2430_ops = {
.init = omap2430_musb_init, .init = omap2430_musb_init,
.exit = omap2430_musb_exit, .exit = omap2430_musb_exit,
.set_mode = omap2430_musb_set_mode,
.try_idle = omap2430_musb_try_idle,
.set_vbus = omap2430_musb_set_vbus, .set_vbus = omap2430_musb_set_vbus,
.enable = omap2430_musb_enable, .enable = omap2430_musb_enable,
@ -639,11 +569,9 @@ static int omap2430_probe(struct platform_device *pdev)
goto err2; goto err2;
} }
/* pm_runtime_enable(glue->dev);
* Note that we cannot enable PM runtime yet for this pm_runtime_use_autosuspend(glue->dev);
* driver as we need struct musb initialized first. pm_runtime_set_autosuspend_delay(glue->dev, 500);
* See omap2430_musb_init above.
*/
ret = platform_device_add(musb); ret = platform_device_add(musb);
if (ret) { if (ret) {
@ -662,12 +590,14 @@ static int omap2430_probe(struct platform_device *pdev)
static int omap2430_remove(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); pm_runtime_get_sync(glue->dev);
cancel_work_sync(&glue->omap_musb_mailbox_work);
platform_device_unregister(glue->musb); platform_device_unregister(glue->musb);
omap2430_set_power(musb, false, false);
pm_runtime_put_sync(glue->dev); pm_runtime_put_sync(glue->dev);
pm_runtime_dont_use_autosuspend(glue->dev);
pm_runtime_disable(glue->dev); pm_runtime_disable(glue->dev);
return 0; return 0;
@ -680,12 +610,13 @@ static int omap2430_runtime_suspend(struct device *dev)
struct omap2430_glue *glue = dev_get_drvdata(dev); struct omap2430_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue); struct musb *musb = glue_to_musb(glue);
if (musb) { if (!musb)
musb->context.otg_interfsel = musb_readl(musb->mregs, return 0;
OTG_INTERFSEL);
omap2430_low_level_exit(musb); musb->context.otg_interfsel = musb_readl(musb->mregs,
} OTG_INTERFSEL);
omap2430_low_level_exit(musb);
return 0; return 0;
} }
@ -696,7 +627,7 @@ static int omap2430_runtime_resume(struct device *dev)
struct musb *musb = glue_to_musb(glue); struct musb *musb = glue_to_musb(glue);
if (!musb) if (!musb)
return -EPROBE_DEFER; return 0;
omap2430_low_level_init(musb); omap2430_low_level_init(musb);
musb_writel(musb->mregs, OTG_INTERFSEL, 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_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("GPL v2"); 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);

View File

@ -80,7 +80,8 @@ static struct musb *sunxi_musb;
struct sunxi_glue { struct sunxi_glue {
struct device *dev; struct device *dev;
struct platform_device *musb; struct musb *musb;
struct platform_device *musb_pdev;
struct clk *clk; struct clk *clk;
struct reset_control *rst; struct reset_control *rst;
struct phy *phy; struct phy *phy;
@ -102,7 +103,7 @@ static void sunxi_musb_work(struct work_struct *work)
return; return;
if (test_and_clear_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags)) { 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; unsigned long flags;
u8 devctl; u8 devctl;
@ -112,7 +113,7 @@ static void sunxi_musb_work(struct work_struct *work)
if (test_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags)) { if (test_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags)) {
set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
musb->xceiv->otg->default_a = 1; 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); MUSB_HST_MODE(musb);
devctl |= MUSB_DEVCTL_SESSION; devctl |= MUSB_DEVCTL_SESSION;
} else { } 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); 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); 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); clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
}
schedule_work(&glue->work); schedule_work(&glue->work);
} }
@ -264,15 +267,6 @@ static int sunxi_musb_init(struct musb *musb)
if (ret) if (ret)
goto error_unregister_notifier; 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; musb->isr = sunxi_musb_interrupt;
/* Stop the musb-core from doing runtime pm (not supported on sunxi) */ /* 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; return 0;
error_phy_exit:
phy_exit(glue->phy);
error_unregister_notifier: error_unregister_notifier:
if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
@ -323,10 +315,31 @@ static int sunxi_musb_exit(struct musb *musb)
return 0; 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) static void sunxi_musb_enable(struct musb *musb)
{ {
struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
glue->musb = musb;
/* musb_core does not call us in a balanced manner */ /* musb_core does not call us in a balanced manner */
if (test_and_set_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags)) if (test_and_set_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags))
return; return;
@ -569,6 +582,7 @@ static const struct musb_platform_ops sunxi_musb_ops = {
.exit = sunxi_musb_exit, .exit = sunxi_musb_exit,
.enable = sunxi_musb_enable, .enable = sunxi_musb_enable,
.disable = sunxi_musb_disable, .disable = sunxi_musb_disable,
.set_mode = sunxi_set_mode,
.fifo_offset = sunxi_musb_fifo_offset, .fifo_offset = sunxi_musb_fifo_offset,
.ep_offset = sunxi_musb_ep_offset, .ep_offset = sunxi_musb_ep_offset,
.busctl_offset = sunxi_musb_busctl_offset, .busctl_offset = sunxi_musb_busctl_offset,
@ -721,9 +735,9 @@ static int sunxi_musb_probe(struct platform_device *pdev)
pinfo.data = &pdata; pinfo.data = &pdata;
pinfo.size_data = sizeof(pdata); pinfo.size_data = sizeof(pdata);
glue->musb = platform_device_register_full(&pinfo); glue->musb_pdev = platform_device_register_full(&pinfo);
if (IS_ERR(glue->musb)) { if (IS_ERR(glue->musb_pdev)) {
ret = PTR_ERR(glue->musb); ret = PTR_ERR(glue->musb_pdev);
dev_err(&pdev->dev, "Error registering musb dev: %d\n", ret); dev_err(&pdev->dev, "Error registering musb dev: %d\n", ret);
goto err_unregister_usb_phy; 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 sunxi_glue *glue = platform_get_drvdata(pdev);
struct platform_device *usb_phy = glue->usb_phy; 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); usb_phy_generic_unregister(usb_phy);
return 0; return 0;

View File

@ -97,6 +97,9 @@ struct twl6030_usb {
struct regulator *usb3v3; struct regulator *usb3v3;
/* used to check initial cable status after probe */
struct delayed_work get_status_work;
/* used to set vbus, in atomic path */ /* used to set vbus, in atomic path */
struct work_struct set_vbus_work; struct work_struct set_vbus_work;
@ -227,12 +230,16 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
twl->asleep = 1; twl->asleep = 1;
status = MUSB_VBUS_VALID; status = MUSB_VBUS_VALID;
twl->linkstat = status; twl->linkstat = status;
musb_mailbox(status); ret = musb_mailbox(status);
if (ret)
twl->linkstat = MUSB_UNKNOWN;
} else { } else {
if (twl->linkstat != MUSB_UNKNOWN) { if (twl->linkstat != MUSB_UNKNOWN) {
status = MUSB_VBUS_OFF; status = MUSB_VBUS_OFF;
twl->linkstat = status; twl->linkstat = status;
musb_mailbox(status); ret = musb_mailbox(status);
if (ret)
twl->linkstat = MUSB_UNKNOWN;
if (twl->asleep) { if (twl->asleep) {
regulator_disable(twl->usb3v3); regulator_disable(twl->usb3v3);
twl->asleep = 0; 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); twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
status = MUSB_ID_GROUND; status = MUSB_ID_GROUND;
twl->linkstat = status; twl->linkstat = status;
musb_mailbox(status); ret = musb_mailbox(status);
if (ret)
twl->linkstat = MUSB_UNKNOWN;
} else { } else {
twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR); 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); 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; 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) static int twl6030_enable_irq(struct twl6030_usb *twl)
{ {
twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET); 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); REG_INT_MSK_LINE_C);
twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
REG_INT_MSK_STS_C); REG_INT_MSK_STS_C);
twl6030_usb_irq(twl->irq2, twl);
twl6030_usbotg_irq(twl->irq1, twl);
return 0; 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"); dev_warn(&pdev->dev, "could not create sysfs file\n");
INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work); 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, status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
@ -395,6 +412,7 @@ static int twl6030_usb_probe(struct platform_device *pdev)
twl->asleep = 0; twl->asleep = 0;
twl6030_enable_irq(twl); twl6030_enable_irq(twl);
schedule_delayed_work(&twl->get_status_work, HZ);
dev_info(&pdev->dev, "Initialized TWL6030 USB module\n"); dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
return 0; return 0;
@ -404,6 +422,7 @@ static int twl6030_usb_remove(struct platform_device *pdev)
{ {
struct twl6030_usb *twl = platform_get_drvdata(pdev); struct twl6030_usb *twl = platform_get_drvdata(pdev);
cancel_delayed_work(&twl->get_status_work);
twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
REG_INT_MSK_LINE_C); REG_INT_MSK_LINE_C);
twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,

View File

@ -2007,6 +2007,7 @@ static void mos7720_release(struct usb_serial *serial)
urblist_entry) urblist_entry)
usb_unlink_urb(urbtrack->urb); usb_unlink_urb(urbtrack->urb);
spin_unlock_irqrestore(&mos_parport->listlock, flags); spin_unlock_irqrestore(&mos_parport->listlock, flags);
parport_del_port(mos_parport->pp);
kref_put(&mos_parport->ref_count, destroy_mos_parport); kref_put(&mos_parport->ref_count, destroy_mos_parport);
} }

View File

@ -836,6 +836,7 @@ static int uas_slave_configure(struct scsi_device *sdev)
if (devinfo->flags & US_FL_BROKEN_FUA) if (devinfo->flags & US_FL_BROKEN_FUA)
sdev->broken_fua = 1; sdev->broken_fua = 1;
scsi_change_queue_depth(sdev, devinfo->qdepth - 2);
return 0; return 0;
} }
@ -848,7 +849,6 @@ static struct scsi_host_template uas_host_template = {
.slave_configure = uas_slave_configure, .slave_configure = uas_slave_configure,
.eh_abort_handler = uas_eh_abort_handler, .eh_abort_handler = uas_eh_abort_handler,
.eh_bus_reset_handler = uas_eh_bus_reset_handler, .eh_bus_reset_handler = uas_eh_bus_reset_handler,
.can_queue = MAX_CMNDS,
.this_id = -1, .this_id = -1,
.sg_tablesize = SG_NONE, .sg_tablesize = SG_NONE,
.skip_settle_delay = 1, .skip_settle_delay = 1,

View File

@ -941,7 +941,7 @@ static void vhci_stop(struct usb_hcd *hcd)
static int vhci_get_frame_number(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; return 0;
} }

View File

@ -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, * @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. * this driver will be bound to any available UDC.
* @pending: UDC core private data used for deferred probe of this driver. * @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 * Devices are disabled till a gadget driver successfully bind()s, which
* means the driver will handle setup() requests needed to enumerate (and * means the driver will handle setup() requests needed to enumerate (and
@ -1097,6 +1099,7 @@ struct usb_gadget_driver {
char *udc_name; char *udc_name;
struct list_head pending; struct list_head pending;
unsigned match_existing_only:1;
}; };

View File

@ -142,10 +142,11 @@ enum musb_vbus_id_status {
}; };
#if IS_ENABLED(CONFIG_USB_MUSB_HDRC) #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 #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 #endif