diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-04-05 15:18:00 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-04-05 15:18:00 -0700 |
commit | 64dc9e2e7320f079b97c46b106133b58b8e18d40 (patch) | |
tree | ab010dc1337d44e29c2b32b7f11788620a91fe4f /drivers/usb/dwc3/core.c | |
parent | 01a60e76b6392547ad3dca3ac05b9c886fa5da45 (diff) | |
parent | 9b192de60b5a584ee4ed967fb6758773c75e4643 (diff) |
Merge tag 'usb-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes:
usb: patches for v3.10 merge window
Here is the big Gadget & PHY pull request. Many of us have
been really busy lately getting multiple drivers to a better
position.
Since this pull request is so large, I will divide it in sections
so it's easier to grasp what's included.
- cleanups:
. UDC drivers no longer touch gadget->dev, that's now udc-core
responsibility
. Many more UDC drivers converted to usb_gadget_map/unmap_request()
. UDC drivers no longer initialize DMA-related fields from gadget's
device structure
. UDC drivers don't touch gadget.dev.driver directly
. UDC drivers don't assign gadget.dev.release directly
. Removal of some unused DMA_ADDR_INVALID
. Introduction of CONFIG_USB_PHY
. All phy drivers have been moved to drivers/usb/phy and renamed to
a common naming scheme
. Fix PHY layer so it never returns a NULL pointer, also fix all
callers to avoid using IS_ERR_OR_NULL()
. Sparse fixes all over the place
. drivers/usb/otg/ has been deleted
. Marvel drivers (mv_udc, ehci-mv, mv_otg and mv_u3d) improved clock
usage
- new features:
. UDC core now provides a generic way for tracking and reporting
UDC's state (not attached, resuming, suspended, addressed,
default, etc)
. twl4030-usb learned that it shouldn't be enabled during init
. Full DT support for DWC3 has been implemented
. ab8500-usb learned about pinctrl framework
. nop PHY learned about DeviceTree and regulators
. DWC3 learned about suspend/resume
. DWC3 can now be compiled in host-only and gadget-only (as well as
DRD) configurations
. UVC now enables streaming endpoint based on negotiated speed
. isp1301 now implements the PHY API properly
. configfs-based interface for gadget drivers which will lead to
the removal of all code which just combines functions together
to build functional gadget drivers.
. f_serial and f_obex were converted to new configfs interface while
maintaining old interface around.
- non-critical fixes:
. UVC gadget driver got fixes for Endpoint usage and stream calculation
. ab8500-usb fixed unbalanced clock and regulator API usage
. twl4030-usb got a fix for when OMAP3 is booted with cable connected
. fusb300_udc got a fix for DMA usage
. UVC got fixes for two assertions of the USB Video Class Compliance
specification revision 1.1
. build warning issues caused by recent addition of __must_check to
regulator API
These are all changes which deserve a mention, all other changes are related
to these one or minor spelling fixes and other similar tasks.
Signed-of-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/dwc3/core.c')
-rw-r--r-- | drivers/usb/dwc3/core.c | 201 |
1 files changed, 182 insertions, 19 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ffa6b004a84..c35d49d39b7 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -140,7 +140,8 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc, * Returns a pointer to the allocated event buffer structure on success * otherwise ERR_PTR(errno). */ -static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length) +static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, + unsigned length) { struct dwc3_event_buffer *evt; @@ -259,6 +260,17 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) } } +static void dwc3_core_num_eps(struct dwc3 *dwc) +{ + struct dwc3_hwparams *parms = &dwc->hwparams; + + dwc->num_in_eps = DWC3_NUM_IN_EPS(parms); + dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps; + + dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n", + dwc->num_in_eps, dwc->num_out_eps); +} + static void dwc3_cache_hwparams(struct dwc3 *dwc) { struct dwc3_hwparams *parms = &dwc->hwparams; @@ -335,13 +347,9 @@ static int dwc3_core_init(struct dwc3 *dwc) if (dwc->revision < DWC3_REVISION_190A) reg |= DWC3_GCTL_U2RSTECN; - dwc3_writel(dwc->regs, DWC3_GCTL, reg); + dwc3_core_num_eps(dwc); - ret = dwc3_event_buffers_setup(dwc); - if (ret) { - dev_err(dwc->dev, "failed to setup event buffers\n"); - goto err0; - } + dwc3_writel(dwc->regs, DWC3_GCTL, reg); return 0; @@ -351,8 +359,6 @@ err0: static void dwc3_core_exit(struct dwc3 *dwc) { - dwc3_event_buffers_cleanup(dwc); - usb_phy_shutdown(dwc->usb2_phy); usb_phy_shutdown(dwc->usb3_phy); } @@ -428,12 +434,32 @@ static int dwc3_probe(struct platform_device *pdev) dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); } - if (IS_ERR_OR_NULL(dwc->usb2_phy)) { + if (IS_ERR(dwc->usb2_phy)) { + ret = PTR_ERR(dwc->usb2_phy); + + /* + * if -ENXIO is returned, it means PHY layer wasn't + * enabled, so it makes no sense to return -EPROBE_DEFER + * in that case, since no PHY driver will ever probe. + */ + if (ret == -ENXIO) + return ret; + dev_err(dev, "no usb2 phy configured\n"); return -EPROBE_DEFER; } - if (IS_ERR_OR_NULL(dwc->usb3_phy)) { + if (IS_ERR(dwc->usb3_phy)) { + ret = PTR_ERR(dwc->usb2_phy); + + /* + * if -ENXIO is returned, it means PHY layer wasn't + * enabled, so it makes no sense to return -EPROBE_DEFER + * in that case, since no PHY driver will ever probe. + */ + if (ret == -ENXIO) + return ret; + dev_err(dev, "no usb3 phy configured\n"); return -EPROBE_DEFER; } @@ -448,6 +474,10 @@ static int dwc3_probe(struct platform_device *pdev) dwc->regs_size = resource_size(res); dwc->dev = dev; + dev->dma_mask = dev->parent->dma_mask; + dev->dma_parms = dev->parent->dma_parms; + dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); + if (!strncmp("super", maximum_speed, 5)) dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; else if (!strncmp("high", maximum_speed, 4)) @@ -480,7 +510,18 @@ static int dwc3_probe(struct platform_device *pdev) goto err0; } - mode = DWC3_MODE(dwc->hwparams.hwparams0); + ret = dwc3_event_buffers_setup(dwc); + if (ret) { + dev_err(dwc->dev, "failed to setup event buffers\n"); + goto err1; + } + + if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) + mode = DWC3_MODE_HOST; + else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) + mode = DWC3_MODE_DEVICE; + else + mode = DWC3_MODE_DRD; switch (mode) { case DWC3_MODE_DEVICE: @@ -488,7 +529,7 @@ static int dwc3_probe(struct platform_device *pdev) ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); - goto err1; + goto err2; } break; case DWC3_MODE_HOST: @@ -496,7 +537,7 @@ static int dwc3_probe(struct platform_device *pdev) ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); - goto err1; + goto err2; } break; case DWC3_MODE_DRD: @@ -504,32 +545,32 @@ static int dwc3_probe(struct platform_device *pdev) ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); - goto err1; + goto err2; } ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); - goto err1; + goto err2; } break; default: dev_err(dev, "Unsupported mode of operation %d\n", mode); - goto err1; + goto err2; } dwc->mode = mode; ret = dwc3_debugfs_init(dwc); if (ret) { dev_err(dev, "failed to initialize debugfs\n"); - goto err2; + goto err3; } pm_runtime_allow(dev); return 0; -err2: +err3: switch (mode) { case DWC3_MODE_DEVICE: dwc3_gadget_exit(dwc); @@ -546,6 +587,9 @@ err2: break; } +err2: + dwc3_event_buffers_cleanup(dwc); + err1: dwc3_core_exit(dwc); @@ -583,12 +627,130 @@ static int dwc3_remove(struct platform_device *pdev) break; } + dwc3_event_buffers_cleanup(dwc); dwc3_free_event_buffers(dwc); dwc3_core_exit(dwc); return 0; } +#ifdef CONFIG_PM_SLEEP +static int dwc3_prepare(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&dwc->lock, flags); + + switch (dwc->mode) { + case DWC3_MODE_DEVICE: + case DWC3_MODE_DRD: + dwc3_gadget_prepare(dwc); + /* FALLTHROUGH */ + case DWC3_MODE_HOST: + default: + dwc3_event_buffers_cleanup(dwc); + break; + } + + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static void dwc3_complete(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&dwc->lock, flags); + + switch (dwc->mode) { + case DWC3_MODE_DEVICE: + case DWC3_MODE_DRD: + dwc3_gadget_complete(dwc); + /* FALLTHROUGH */ + case DWC3_MODE_HOST: + default: + dwc3_event_buffers_setup(dwc); + break; + } + + spin_unlock_irqrestore(&dwc->lock, flags); +} + +static int dwc3_suspend(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&dwc->lock, flags); + + switch (dwc->mode) { + case DWC3_MODE_DEVICE: + case DWC3_MODE_DRD: + dwc3_gadget_suspend(dwc); + /* FALLTHROUGH */ + case DWC3_MODE_HOST: + default: + /* do nothing */ + break; + } + + dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL); + spin_unlock_irqrestore(&dwc->lock, flags); + + usb_phy_shutdown(dwc->usb3_phy); + usb_phy_shutdown(dwc->usb2_phy); + + return 0; +} + +static int dwc3_resume(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + unsigned long flags; + + usb_phy_init(dwc->usb3_phy); + usb_phy_init(dwc->usb2_phy); + msleep(100); + + spin_lock_irqsave(&dwc->lock, flags); + + dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl); + + switch (dwc->mode) { + case DWC3_MODE_DEVICE: + case DWC3_MODE_DRD: + dwc3_gadget_resume(dwc); + /* FALLTHROUGH */ + case DWC3_MODE_HOST: + default: + /* do nothing */ + break; + } + + spin_unlock_irqrestore(&dwc->lock, flags); + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + +static const struct dev_pm_ops dwc3_dev_pm_ops = { + .prepare = dwc3_prepare, + .complete = dwc3_complete, + + SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume) +}; + +#define DWC3_PM_OPS &(dwc3_dev_pm_ops) +#else +#define DWC3_PM_OPS NULL +#endif + #ifdef CONFIG_OF static const struct of_device_id of_dwc3_match[] = { { @@ -605,6 +767,7 @@ static struct platform_driver dwc3_driver = { .driver = { .name = "dwc3", .of_match_table = of_match_ptr(of_dwc3_match), + .pm = DWC3_PM_OPS, }, }; |