mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 15:40:56 +07:00
USB fixes for 4.7-rc4
Here are a bunch (65) of USB fixes for 4.7-rc4. Sorry about the quantity, I've been slow in getting these out. The majority are the "normal" gadget, musb, and xhci fixes, that we all are used to. There are also a few other tiny fixes resolving a number of reported issues that showed up in 4.7-rc1. All of these have been in linux-next. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAldlbRgACgkQMUfUDdst+ynNQACeMwami14392grxjLQvhCtR29u ekkAoMK+vLu79mbLPhoBmPo4YCUvSptw =1X1d -----END PGP SIGNATURE----- Merge tag 'usb-4.7-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here are a bunch (65) of USB fixes for 4.7-rc4. Sorry about the quantity, I've been slow in getting these out. The majority are the "normal" gadget, musb, and xhci fixes, that we all are used to. There are also a few other tiny fixes resolving a number of reported issues that showed up in 4.7-rc1. All of these have been in linux-next" * tag 'usb-4.7-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (65 commits) usbip: rate limit get_frame_number message usb: musb: sunxi: Remove bogus "Frees glue" comment usb: musb: sunxi: Fix NULL ptr deref when gadget is registered before musb usb: echi-hcd: Add ehci_setup check before echi_shutdown usb: host: ehci-msm: Conditionally call ehci suspend/resume MAINTAINERS: Add file patterns for usb device tree bindings usb: host: ehci-tegra: Avoid getting the same reset twice usb: host: ehci-tegra: Grab the correct UTMI pads reset USB: mos7720: delete parport USB: OHCI: Don't mark EDs as ED_OPER if scheduling fails phy: ti-pipe3: Program the DPLL even if it was already locked usb: musb: Stop bulk endpoint while queue is rotated usb: musb: Ensure rx reinit occurs for shared_fifo endpoints usb: musb: host: correct cppi dma channel for isoch transfer usb: musb: only restore devctl when session was set in backup usb: phy: Check initial state for twl6030 usb: musb: Use normal module_init for 2430 glue usb: musb: Remove pm_runtime_set_irq_safe usb: musb: Remove extra PM runtime calls from 2430 glue layer usb: musb: Return error value from musb_mailbox ...
This commit is contained in:
commit
e80dac114c
@ -1,6 +1,6 @@
|
|||||||
What: /config/usb-gadget/gadget/functions/uvc.name
|
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:
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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:
|
||||||
|
@ -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(¶ms, 0, sizeof(params));
|
||||||
|
|
||||||
|
return dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
|
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, ¶ms);
|
|
||||||
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(¶ms, 0, sizeof(params));
|
ret = dwc3_send_clear_stall_ep_cmd(dep);
|
||||||
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
|
|
||||||
DWC3_DEPCMD_CLEARSTALL, ¶ms);
|
|
||||||
WARN_ON_ONCE(ret);
|
WARN_ON_ONCE(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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 */
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user