summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Kconfig2
-rw-r--r--drivers/usb/Makefile4
-rw-r--r--drivers/usb/chipidea/udc.c27
-rw-r--r--drivers/usb/dwc3/Kconfig1
-rw-r--r--drivers/usb/dwc3/core.c201
-rw-r--r--drivers/usb/dwc3/core.h72
-rw-r--r--drivers/usb/dwc3/debugfs.c52
-rw-r--r--drivers/usb/dwc3/dwc3-exynos.c98
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c245
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c38
-rw-r--r--drivers/usb/dwc3/ep0.c33
-rw-r--r--drivers/usb/dwc3/gadget.c321
-rw-r--r--drivers/usb/gadget/Kconfig18
-rw-r--r--drivers/usb/gadget/Makefile13
-rw-r--r--drivers/usb/gadget/acm_ms.c15
-rw-r--r--drivers/usb/gadget/amd5536udc.c16
-rw-r--r--drivers/usb/gadget/amd5536udc.h1
-rw-r--r--drivers/usb/gadget/at91_udc.c14
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c44
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.h6
-rw-r--r--drivers/usb/gadget/bcm63xx_udc.c23
-rw-r--r--drivers/usb/gadget/cdc2.c27
-rw-r--r--drivers/usb/gadget/composite.c1
-rw-r--r--drivers/usb/gadget/configfs.c1003
-rw-r--r--drivers/usb/gadget/dummy_hcd.c19
-rw-r--r--drivers/usb/gadget/ether.c20
-rw-r--r--drivers/usb/gadget/f_acm.c137
-rw-r--r--drivers/usb/gadget/f_ecm.c4
-rw-r--r--drivers/usb/gadget/f_eem.c3
-rw-r--r--drivers/usb/gadget/f_ncm.c4
-rw-r--r--drivers/usb/gadget/f_obex.c226
-rw-r--r--drivers/usb/gadget/f_rndis.c3
-rw-r--r--drivers/usb/gadget/f_serial.c174
-rw-r--r--drivers/usb/gadget/f_subset.c4
-rw-r--r--drivers/usb/gadget/f_uvc.c262
-rw-r--r--drivers/usb/gadget/f_uvc.h12
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c18
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c83
-rw-r--r--drivers/usb/gadget/fusb300_udc.c46
-rw-r--r--drivers/usb/gadget/fusb300_udc.h2
-rw-r--r--drivers/usb/gadget/g_ffs.c35
-rw-r--r--drivers/usb/gadget/goku_udc.c20
-rw-r--r--drivers/usb/gadget/goku_udc.h3
-rw-r--r--drivers/usb/gadget/imx_udc.c16
-rw-r--r--drivers/usb/gadget/lpc32xx_udc.c51
-rw-r--r--drivers/usb/gadget/m66592-udc.c17
-rw-r--r--drivers/usb/gadget/multi.c29
-rw-r--r--drivers/usb/gadget/mv_u3d_core.c65
-rw-r--r--drivers/usb/gadget/mv_udc.h3
-rw-r--r--drivers/usb/gadget/mv_udc_core.c117
-rw-r--r--drivers/usb/gadget/ncm.c13
-rw-r--r--drivers/usb/gadget/net2272.c25
-rw-r--r--drivers/usb/gadget/net2280.c25
-rw-r--r--drivers/usb/gadget/nokia.c95
-rw-r--r--drivers/usb/gadget/omap_udc.c21
-rw-r--r--drivers/usb/gadget/pch_udc.c21
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c16
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c51
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c14
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c78
-rw-r--r--drivers/usb/gadget/s3c-hsudc.c16
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c15
-rw-r--r--drivers/usb/gadget/serial.c59
-rw-r--r--drivers/usb/gadget/u_ether.c32
-rw-r--r--drivers/usb/gadget/u_ether.h27
-rw-r--r--drivers/usb/gadget/u_serial.h1
-rw-r--r--drivers/usb/gadget/udc-core.c90
-rw-r--r--drivers/usb/gadget/uvc.h3
-rw-r--r--drivers/usb/gadget/uvc_queue.c538
-rw-r--r--drivers/usb/gadget/uvc_queue.h32
-rw-r--r--drivers/usb/gadget/uvc_v4l2.c71
-rw-r--r--drivers/usb/gadget/uvc_video.c31
-rw-r--r--drivers/usb/host/Kconfig2
-rw-r--r--drivers/usb/host/ehci-msm.c2
-rw-r--r--drivers/usb/host/ehci-mv.c54
-rw-r--r--drivers/usb/host/ehci-s5p.c2
-rw-r--r--drivers/usb/host/ehci-tegra.c12
-rw-r--r--drivers/usb/host/ohci-exynos.c2
-rw-r--r--drivers/usb/musb/Kconfig6
-rw-r--r--drivers/usb/musb/am35x.c8
-rw-r--r--drivers/usb/musb/blackfin.c6
-rw-r--r--drivers/usb/musb/cppi_dma.c17
-rw-r--r--drivers/usb/musb/da8xx.c8
-rw-r--r--drivers/usb/musb/davinci.c4
-rw-r--r--drivers/usb/musb/musb_core.c71
-rw-r--r--drivers/usb/musb/musb_dsps.c14
-rw-r--r--drivers/usb/musb/musb_gadget.c156
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c6
-rw-r--r--drivers/usb/musb/musb_host.c119
-rw-r--r--drivers/usb/musb/musb_virthub.c4
-rw-r--r--drivers/usb/musb/omap2430.c32
-rw-r--r--drivers/usb/musb/tusb6010.c14
-rw-r--r--drivers/usb/musb/ux500.c106
-rw-r--r--drivers/usb/musb/ux500_dma.c24
-rw-r--r--drivers/usb/otg/Kconfig141
-rw-r--r--drivers/usb/otg/Makefile24
-rw-r--r--drivers/usb/otg/ab8500-usb.c596
-rw-r--r--drivers/usb/phy/Kconfig180
-rw-r--r--drivers/usb/phy/Makefile35
-rw-r--r--drivers/usb/phy/isp1301.c71
-rw-r--r--drivers/usb/phy/phy-ab8500-usb.c924
-rw-r--r--drivers/usb/phy/phy-fsl-usb.c (renamed from drivers/usb/otg/fsl_otg.c)34
-rw-r--r--drivers/usb/phy/phy-fsl-usb.h (renamed from drivers/usb/otg/fsl_otg.h)0
-rw-r--r--drivers/usb/phy/phy-fsm-usb.c (renamed from drivers/usb/otg/otg_fsm.c)4
-rw-r--r--drivers/usb/phy/phy-fsm-usb.h (renamed from drivers/usb/otg/otg_fsm.h)0
-rw-r--r--drivers/usb/phy/phy-gpio-vbus-usb.c (renamed from drivers/usb/otg/gpio_vbus.c)9
-rw-r--r--drivers/usb/phy/phy-isp1301-omap.c (renamed from drivers/usb/otg/isp1301_omap.c)6
-rw-r--r--drivers/usb/phy/phy-isp1301.c162
-rw-r--r--drivers/usb/phy/phy-msm-usb.c (renamed from drivers/usb/otg/msm_otg.c)0
-rw-r--r--drivers/usb/phy/phy-mv-u3d-usb.c (renamed from drivers/usb/phy/mv_u3d_phy.c)2
-rw-r--r--drivers/usb/phy/phy-mv-u3d-usb.h (renamed from drivers/usb/phy/mv_u3d_phy.h)0
-rw-r--r--drivers/usb/phy/phy-mv-usb.c (renamed from drivers/usb/otg/mv_otg.c)30
-rw-r--r--drivers/usb/phy/phy-mv-usb.h (renamed from drivers/usb/otg/mv_otg.h)3
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c (renamed from drivers/usb/otg/mxs-phy.c)41
-rw-r--r--drivers/usb/phy/phy-nop.c (renamed from drivers/usb/otg/nop-usb-xceiv.c)143
-rw-r--r--drivers/usb/phy/phy-omap-control.c (renamed from drivers/usb/phy/omap-control-usb.c)0
-rw-r--r--drivers/usb/phy/phy-omap-usb2.c (renamed from drivers/usb/phy/omap-usb2.c)0
-rw-r--r--drivers/usb/phy/phy-omap-usb3.c (renamed from drivers/usb/phy/omap-usb3.c)0
-rw-r--r--drivers/usb/phy/phy-rcar-usb.c (renamed from drivers/usb/phy/rcar-phy.c)0
-rw-r--r--drivers/usb/phy/phy-samsung-usb.c236
-rw-r--r--drivers/usb/phy/phy-samsung-usb.h327
-rw-r--r--drivers/usb/phy/phy-samsung-usb2.c509
-rw-r--r--drivers/usb/phy/phy-samsung-usb3.c347
-rw-r--r--drivers/usb/phy/phy-tegra-usb.c (renamed from drivers/usb/phy/tegra_usb_phy.c)0
-rw-r--r--drivers/usb/phy/phy-twl4030-usb.c (renamed from drivers/usb/otg/twl4030-usb.c)174
-rw-r--r--drivers/usb/phy/phy-twl6030-usb.c (renamed from drivers/usb/otg/twl6030-usb.c)11
-rw-r--r--drivers/usb/phy/phy-ulpi-viewport.c (renamed from drivers/usb/otg/ulpi_viewport.c)0
-rw-r--r--drivers/usb/phy/phy-ulpi.c (renamed from drivers/usb/otg/ulpi.c)0
-rw-r--r--drivers/usb/phy/phy.c (renamed from drivers/usb/otg/otg.c)62
-rw-r--r--drivers/usb/phy/samsung-usbphy.c928
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c1
-rw-r--r--drivers/usb/renesas_usbhs/fifo.h2
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c24
-rw-r--r--drivers/usb/usb-common.c47
134 files changed, 6364 insertions, 4300 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 640ae6c6d2d2..2c481b808276 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -186,6 +186,4 @@ source "drivers/usb/atm/Kconfig"
source "drivers/usb/gadget/Kconfig"
-source "drivers/usb/otg/Kconfig"
-
endif # USB_SUPPORT
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 8f5ebced5df0..c41feba8d5c0 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -6,8 +6,6 @@
obj-$(CONFIG_USB) += core/
-obj-$(CONFIG_USB_OTG_UTILS) += otg/
-
obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_MON) += mon/
@@ -46,7 +44,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB) += misc/
-obj-$(CONFIG_USB_OTG_UTILS) += phy/
+obj-$(CONFIG_USB_PHY) += phy/
obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
obj-$(CONFIG_USB_ATM) += atm/
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 3d90e6189731..519ead2443c5 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1639,16 +1639,6 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
}
/**
- * udc_release: driver release function
- * @dev: device
- *
- * Currently does nothing
- */
-static void udc_release(struct device *dev)
-{
-}
-
-/**
* udc_start: initialize gadget role
* @ci: chipidea controller
*/
@@ -1667,12 +1657,6 @@ static int udc_start(struct ci13xxx *ci)
INIT_LIST_HEAD(&ci->gadget.ep_list);
- dev_set_name(&ci->gadget.dev, "gadget");
- ci->gadget.dev.dma_mask = dev->dma_mask;
- ci->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
- ci->gadget.dev.parent = dev;
- ci->gadget.dev.release = udc_release;
-
/* alloc resources */
ci->qh_pool = dma_pool_create("ci13xxx_qh", dev,
sizeof(struct ci13xxx_qh),
@@ -1710,17 +1694,11 @@ static int udc_start(struct ci13xxx *ci)
goto put_transceiver;
}
- retval = device_register(&ci->gadget.dev);
- if (retval) {
- put_device(&ci->gadget.dev);
- goto put_transceiver;
- }
-
if (!IS_ERR_OR_NULL(ci->transceiver)) {
retval = otg_set_peripheral(ci->transceiver->otg,
&ci->gadget);
if (retval)
- goto unreg_device;
+ goto put_transceiver;
}
retval = usb_add_gadget_udc(dev, &ci->gadget);
@@ -1740,8 +1718,6 @@ remove_trans:
}
dev_err(dev, "error = %i\n", retval);
-unreg_device:
- device_unregister(&ci->gadget.dev);
put_transceiver:
if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy)
usb_put_phy(ci->transceiver);
@@ -1776,7 +1752,6 @@ static void udc_stop(struct ci13xxx *ci)
if (ci->global_phy)
usb_put_phy(ci->transceiver);
}
- device_unregister(&ci->gadget.dev);
/* my kobject is dynamic, I swear! */
memset(&ci->gadget, 0, sizeof(ci->gadget));
}
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 68e9a2c5a01a..ea5ee9c21c35 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -1,7 +1,6 @@
config USB_DWC3
tristate "DesignWare USB3 DRD Core Support"
depends on (USB || USB_GADGET) && GENERIC_HARDIRQS
- select USB_OTG_UTILS
select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
help
Say Y or M here if your system has a Dual Role SuperSpeed
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index ffa6b004a84b..c35d49d39b76 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,
},
};
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index b41750660235..b69d322e3cab 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -154,8 +154,9 @@
/* OTG Registers */
#define DWC3_OCFG 0xcc00
#define DWC3_OCTL 0xcc04
-#define DWC3_OEVTEN 0xcc08
-#define DWC3_OSTS 0xcc0C
+#define DWC3_OEVT 0xcc08
+#define DWC3_OEVTEN 0xcc0C
+#define DWC3_OSTS 0xcc10
/* Bit fields */
@@ -369,6 +370,9 @@ struct dwc3_trb;
* @list: a list of event buffers
* @buf: _THE_ buffer
* @length: size of this buffer
+ * @lpos: event offset
+ * @count: cache of last read event count register
+ * @flags: flags related to this event buffer
* @dma: dma_addr_t
* @dwc: pointer to DWC controller
*/
@@ -376,6 +380,10 @@ struct dwc3_event_buffer {
void *buf;
unsigned length;
unsigned int lpos;
+ unsigned int count;
+ unsigned int flags;
+
+#define DWC3_EVENT_PENDING BIT(0)
dma_addr_t dma;
@@ -487,12 +495,6 @@ enum dwc3_link_state {
DWC3_LINK_STATE_MASK = 0x0f,
};
-enum dwc3_device_state {
- DWC3_DEFAULT_STATE,
- DWC3_ADDRESS_STATE,
- DWC3_CONFIGURED_STATE,
-};
-
/* TRB Length, PCM and Status */
#define DWC3_TRB_SIZE_MASK (0x00ffffff)
#define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK)
@@ -574,6 +576,14 @@ struct dwc3_hwparams {
/* HWPARAMS1 */
#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15)
+/* HWPARAMS3 */
+#define DWC3_NUM_IN_EPS_MASK (0x1f << 18)
+#define DWC3_NUM_EPS_MASK (0x3f << 12)
+#define DWC3_NUM_EPS(p) (((p)->hwparams3 & \
+ (DWC3_NUM_EPS_MASK)) >> 12)
+#define DWC3_NUM_IN_EPS(p) (((p)->hwparams3 & \
+ (DWC3_NUM_IN_EPS_MASK)) >> 18)
+
/* HWPARAMS7 */
#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff)
@@ -618,7 +628,6 @@ struct dwc3_scratchpad_array {
* @gadget_driver: pointer to the gadget driver
* @regs: base address for our registers
* @regs_size: address space size
- * @irq: IRQ number
* @num_event_buffers: calculated number of event buffers
* @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes)
@@ -626,6 +635,8 @@ struct dwc3_scratchpad_array {
* @mode: mode of operation
* @usb2_phy: pointer to USB2 PHY
* @usb3_phy: pointer to USB3 PHY
+ * @dcfg: saved contents of DCFG register
+ * @gctl: saved contents of GCTL register
* @is_selfpowered: true when we are selfpowered
* @three_stage_setup: set if we perform a three phase setup
* @ep0_bounced: true when we used bounce buffer
@@ -639,6 +650,8 @@ struct dwc3_scratchpad_array {
* @u2pel: parameter from Set SEL request.
* @u1sel: parameter from Set SEL request.
* @u1pel: parameter from Set SEL request.
+ * @num_out_eps: number of out endpoints
+ * @num_in_eps: number of in endpoints
* @ep0_next_event: hold the next expected event
* @ep0state: state of endpoint zero
* @link_state: link state
@@ -656,8 +669,10 @@ struct dwc3 {
dma_addr_t ep0_trb_addr;
dma_addr_t ep0_bounce_addr;
struct dwc3_request ep0_usb_req;
+
/* device lock */
spinlock_t lock;
+
struct device *dev;
struct platform_device *xhci;
@@ -675,6 +690,10 @@ struct dwc3 {
void __iomem *regs;
size_t regs_size;
+ /* used for suspend/resume */
+ u32 dcfg;
+ u32 gctl;
+
u32 num_event_buffers;
u32 u1u2;
u32 maximum_speed;
@@ -694,6 +713,9 @@ struct dwc3 {
#define DWC3_REVISION_202A 0x5533202a
#define DWC3_REVISION_210A 0x5533210a
#define DWC3_REVISION_220A 0x5533220a
+#define DWC3_REVISION_230A 0x5533230a
+#define DWC3_REVISION_240A 0x5533240a
+#define DWC3_REVISION_250A 0x5533250a
unsigned is_selfpowered:1;
unsigned three_stage_setup:1;
@@ -704,11 +726,11 @@ struct dwc3 {
unsigned delayed_status:1;
unsigned needs_fifo_resize:1;
unsigned resize_fifos:1;
+ unsigned pullups_connected:1;
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
enum dwc3_link_state link_state;
- enum dwc3_device_state dev_state;
u16 isoch_delay;
u16 u2sel;
@@ -718,6 +740,9 @@ struct dwc3 {
u8 speed;
+ u8 num_out_eps;
+ u8 num_in_eps;
+
void *mem;
struct dwc3_hwparams hwparams;
@@ -884,4 +909,31 @@ static inline void dwc3_gadget_exit(struct dwc3 *dwc)
{ }
#endif
+/* power management interface */
+#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
+int dwc3_gadget_prepare(struct dwc3 *dwc);
+void dwc3_gadget_complete(struct dwc3 *dwc);
+int dwc3_gadget_suspend(struct dwc3 *dwc);
+int dwc3_gadget_resume(struct dwc3 *dwc);
+#else
+static inline int dwc3_gadget_prepare(struct dwc3 *dwc)
+{
+ return 0;
+}
+
+static inline void dwc3_gadget_complete(struct dwc3 *dwc)
+{
+}
+
+static inline int dwc3_gadget_suspend(struct dwc3 *dwc)
+{
+ return 0;
+}
+
+static inline int dwc3_gadget_resume(struct dwc3 *dwc)
+{
+ return 0;
+}
+#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */
+
#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 4a752e730c5f..9e9f122162f2 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -59,7 +59,7 @@
.offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \
}
-static struct debugfs_reg32 dwc3_regs[] = {
+static const struct debugfs_reg32 dwc3_regs[] = {
dump_register(GSBUSCFG0),
dump_register(GSBUSCFG1),
dump_register(GTXTHRCFG),
@@ -372,6 +372,7 @@ static struct debugfs_reg32 dwc3_regs[] = {
dump_register(OCFG),
dump_register(OCTL),
+ dump_register(OEVT),
dump_register(OEVTEN),
dump_register(OSTS),
};
@@ -577,8 +578,14 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
case DWC3_LINK_STATE_LPBK:
seq_printf(s, "Loopback\n");
break;
+ case DWC3_LINK_STATE_RESET:
+ seq_printf(s, "Reset\n");
+ break;
+ case DWC3_LINK_STATE_RESUME:
+ seq_printf(s, "Resume\n");
+ break;
default:
- seq_printf(s, "UNKNOWN %d\n", reg);
+ seq_printf(s, "UNKNOWN %d\n", state);
}
return 0;
@@ -661,28 +668,31 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
goto err1;
}
-#if IS_ENABLED(CONFIG_USB_DWC3_GADGET)
- file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
- dwc, &dwc3_mode_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
- dwc, &dwc3_testmode_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
+ if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
+ file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
+ dwc, &dwc3_mode_fops);
+ if (!file) {
+ ret = -ENOMEM;
+ goto err1;
+ }
}
- file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
- dwc, &dwc3_link_state_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
+ if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) ||
+ IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
+ file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
+ dwc, &dwc3_testmode_fops);
+ if (!file) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
+ dwc, &dwc3_link_state_fops);
+ if (!file) {
+ ret = -ENOMEM;
+ goto err1;
+ }
}
-#endif
return 0;
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index b082bec7343e..a8afe6e26621 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -22,9 +22,9 @@
#include <linux/usb/otg.h>
#include <linux/usb/nop-usb-xceiv.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
struct dwc3_exynos {
- struct platform_device *dwc3;
struct platform_device *usb2_phy;
struct platform_device *usb3_phy;
struct device *dev;
@@ -86,21 +86,30 @@ err1:
return ret;
}
+static int dwc3_exynos_remove_child(struct device *dev, void *unused)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ platform_device_unregister(pdev);
+
+ return 0;
+}
+
static u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32);
static int dwc3_exynos_probe(struct platform_device *pdev)
{
- struct platform_device *dwc3;
struct dwc3_exynos *exynos;
struct clk *clk;
struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
int ret = -ENOMEM;
exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
if (!exynos) {
dev_err(dev, "not enough memory\n");
- return -ENOMEM;
+ goto err1;
}
/*
@@ -108,21 +117,15 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
* Since shared usb code relies on it, set it here for now.
* Once we move to full device tree support this will vanish off.
*/
- if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &dwc3_exynos_dma_mask;
+ if (!dev->dma_mask)
+ dev->dma_mask = &dwc3_exynos_dma_mask;
platform_set_drvdata(pdev, exynos);
ret = dwc3_exynos_register_phys(exynos);
if (ret) {
dev_err(dev, "couldn't register PHYs\n");
- return ret;
- }
-
- dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
- if (!dwc3) {
- dev_err(dev, "couldn't allocate dwc3 device\n");
- return -ENOMEM;
+ goto err1;
}
clk = devm_clk_get(dev, "usbdrd30");
@@ -132,37 +135,28 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
goto err1;
}
- dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
-
- dwc3->dev.parent = dev;
- dwc3->dev.dma_mask = dev->dma_mask;
- dwc3->dev.dma_parms = dev->dma_parms;
- exynos->dwc3 = dwc3;
exynos->dev = dev;
exynos->clk = clk;
- clk_enable(exynos->clk);
-
- ret = platform_device_add_resources(dwc3, pdev->resource,
- pdev->num_resources);
- if (ret) {
- dev_err(dev, "couldn't add resources to dwc3 device\n");
- goto err2;
- }
-
- ret = platform_device_add(dwc3);
- if (ret) {
- dev_err(dev, "failed to register dwc3 device\n");
+ clk_prepare_enable(exynos->clk);
+
+ if (node) {
+ ret = of_platform_populate(node, NULL, NULL, dev);
+ if (ret) {
+ dev_err(dev, "failed to add dwc3 core\n");
+ goto err2;
+ }
+ } else {
+ dev_err(dev, "no device node, failed to add dwc3 core\n");
+ ret = -ENODEV;
goto err2;
}
return 0;
err2:
- clk_disable(clk);
+ clk_disable_unprepare(clk);
err1:
- platform_device_put(dwc3);
-
return ret;
}
@@ -170,11 +164,11 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
{
struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
- platform_device_unregister(exynos->dwc3);
platform_device_unregister(exynos->usb2_phy);
platform_device_unregister(exynos->usb3_phy);
+ device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
- clk_disable(exynos->clk);
+ clk_disable_unprepare(exynos->clk);
return 0;
}
@@ -187,12 +181,46 @@ static const struct of_device_id exynos_dwc3_match[] = {
MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
#endif
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_exynos_suspend(struct device *dev)
+{
+ struct dwc3_exynos *exynos = dev_get_drvdata(dev);
+
+ clk_disable(exynos->clk);
+
+ return 0;
+}
+
+static int dwc3_exynos_resume(struct device *dev)
+{
+ struct dwc3_exynos *exynos = dev_get_drvdata(dev);
+
+ clk_enable(exynos->clk);
+
+ /* runtime set active to reflect active state. */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops dwc3_exynos_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(dwc3_exynos_suspend, dwc3_exynos_resume)
+};
+
+#define DEV_PM_OPS (&dwc3_exynos_dev_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
static struct platform_driver dwc3_exynos_driver = {
.probe = dwc3_exynos_probe,
.remove = dwc3_exynos_remove,
.driver = {
.name = "exynos-dwc3",
.of_match_table = of_match_ptr(exynos_dwc3_match),
+ .pm = DEV_PM_OPS,
},
};
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index afa05e3c9cf4..34638b92500d 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -52,7 +52,6 @@
#include <linux/of_platform.h>
#include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
/*
* All these registers belong to OMAP's Wrapper around the
@@ -117,20 +116,17 @@ struct dwc3_omap {
/* device lock */
spinlock_t lock;
- struct platform_device *usb2_phy;
- struct platform_device *usb3_phy;
struct device *dev;
int irq;
void __iomem *base;
- void *context;
- u32 resource_size;
+ u32 utmi_otg_status;
u32 dma_status:1;
};
-struct dwc3_omap *_omap;
+static struct dwc3_omap *_omap;
static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
{
@@ -142,11 +138,14 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
writel(value, base + offset);
}
-void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
+int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
{
u32 val;
struct dwc3_omap *omap = _omap;
+ if (!omap)
+ return -EPROBE_DEFER;
+
switch (status) {
case OMAP_DWC3_ID_GROUND:
dev_dbg(omap->dev, "ID GND\n");
@@ -189,63 +188,9 @@ void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
dev_dbg(omap->dev, "ID float\n");
}
- return;
-}
-EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
-
-static int dwc3_omap_register_phys(struct dwc3_omap *omap)
-{
- struct nop_usb_xceiv_platform_data pdata;
- struct platform_device *pdev;
- int ret;
-
- memset(&pdata, 0x00, sizeof(pdata));
-
- pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
- if (!pdev)
- return -ENOMEM;
-
- omap->usb2_phy = pdev;
- pdata.type = USB_PHY_TYPE_USB2;
-
- ret = platform_device_add_data(omap->usb2_phy, &pdata, sizeof(pdata));
- if (ret)
- goto err1;
-
- pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
- if (!pdev) {
- ret = -ENOMEM;
- goto err1;
- }
-
- omap->usb3_phy = pdev;
- pdata.type = USB_PHY_TYPE_USB3;
-
- ret = platform_device_add_data(omap->usb3_phy, &pdata, sizeof(pdata));
- if (ret)
- goto err2;
-
- ret = platform_device_add(omap->usb2_phy);
- if (ret)
- goto err2;
-
- ret = platform_device_add(omap->usb3_phy);
- if (ret)
- goto err3;
-
return 0;
-
-err3:
- platform_device_del(omap->usb2_phy);
-
-err2:
- platform_device_put(omap->usb3_phy);
-
-err1:
- platform_device_put(omap->usb2_phy);
-
- return ret;
}
+EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
{
@@ -307,24 +252,57 @@ static int dwc3_omap_remove_core(struct device *dev, void *c)
return 0;
}
+static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
+{
+ u32 reg;
+
+ /* enable all IRQs */
+ reg = USBOTGSS_IRQO_COREIRQ_ST;
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+
+ reg = (USBOTGSS_IRQ1_OEVT |
+ USBOTGSS_IRQ1_DRVVBUS_RISE |
+ USBOTGSS_IRQ1_CHRGVBUS_RISE |
+ USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
+ USBOTGSS_IRQ1_IDPULLUP_RISE |
+ USBOTGSS_IRQ1_DRVVBUS_FALL |
+ USBOTGSS_IRQ1_CHRGVBUS_FALL |
+ USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
+ USBOTGSS_IRQ1_IDPULLUP_FALL);
+
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+}
+
+static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
+{
+ /* disable all IRQs */
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, 0x00);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, 0x00);
+}
+
+static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
+
static int dwc3_omap_probe(struct platform_device *pdev)
{
- struct dwc3_omap_data *pdata = pdev->dev.platform_data;
struct device_node *node = pdev->dev.of_node;
struct dwc3_omap *omap;
struct resource *res;
struct device *dev = &pdev->dev;
- int size;
int ret = -ENOMEM;
int irq;
- const u32 *utmi_mode;
+ int utmi_mode = 0;
+
u32 reg;
void __iomem *base;
- void *context;
+
+ if (!node) {
+ dev_err(dev, "device node not found\n");
+ return -EINVAL;
+ }
omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
if (!omap) {
@@ -334,13 +312,13 @@ static int dwc3_omap_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, omap);
- irq = platform_get_irq(pdev, 1);
+ irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "missing IRQ resource\n");
return -EINVAL;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "missing memory base resource\n");
return -EINVAL;
@@ -352,25 +330,12 @@ static int dwc3_omap_probe(struct platform_device *pdev)
return -ENOMEM;
}
- ret = dwc3_omap_register_phys(omap);
- if (ret) {
- dev_err(dev, "couldn't register PHYs\n");
- return ret;
- }
-
- context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
- if (!context) {
- dev_err(dev, "couldn't allocate dwc3 context memory\n");
- return -ENOMEM;
- }
-
spin_lock_init(&omap->lock);
- omap->resource_size = resource_size(res);
- omap->context = context;
omap->dev = dev;
omap->irq = irq;
omap->base = base;
+ dev->dma_mask = &dwc3_omap_dma_mask;
/*
* REVISIT if we ever have two instances of the wrapper, we will be
@@ -387,25 +352,17 @@ static int dwc3_omap_probe(struct platform_device *pdev)
reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
- utmi_mode = of_get_property(node, "utmi-mode", &size);
- if (utmi_mode && size == sizeof(*utmi_mode)) {
- reg |= *utmi_mode;
- } else {
- if (!pdata) {
- dev_dbg(dev, "missing platform data\n");
- } else {
- switch (pdata->utmi_mode) {
- case DWC3_OMAP_UTMI_MODE_SW:
- reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
- break;
- case DWC3_OMAP_UTMI_MODE_HW:
- reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
- break;
- default:
- dev_dbg(dev, "UNKNOWN utmi mode %d\n",
- pdata->utmi_mode);
- }
- }
+ of_property_read_u32(node, "utmi-mode", &utmi_mode);
+
+ switch (utmi_mode) {
+ case DWC3_OMAP_UTMI_MODE_SW:
+ reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+ break;
+ case DWC3_OMAP_UTMI_MODE_HW:
+ reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+ break;
+ default:
+ dev_dbg(dev, "UNKNOWN utmi mode %d\n", utmi_mode);
}
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
@@ -422,29 +379,12 @@ static int dwc3_omap_probe(struct platform_device *pdev)
return ret;
}
- /* enable all IRQs */
- reg = USBOTGSS_IRQO_COREIRQ_ST;
- dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+ dwc3_omap_enable_irqs(omap);
- reg = (USBOTGSS_IRQ1_OEVT |
- USBOTGSS_IRQ1_DRVVBUS_RISE |
- USBOTGSS_IRQ1_CHRGVBUS_RISE |
- USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
- USBOTGSS_IRQ1_IDPULLUP_RISE |
- USBOTGSS_IRQ1_DRVVBUS_FALL |
- USBOTGSS_IRQ1_CHRGVBUS_FALL |
- USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
- USBOTGSS_IRQ1_IDPULLUP_FALL);
-
- dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
-
- if (node) {
- ret = of_platform_populate(node, NULL, NULL, dev);
- if (ret) {
- dev_err(&pdev->dev,
- "failed to add create dwc3 core\n");
- return ret;
- }
+ ret = of_platform_populate(node, NULL, NULL, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to create dwc3 core\n");
+ return ret;
}
return 0;
@@ -454,8 +394,7 @@ static int dwc3_omap_remove(struct platform_device *pdev)
{
struct dwc3_omap *omap = platform_get_drvdata(pdev);
- platform_device_unregister(omap->usb2_phy);
- platform_device_unregister(omap->usb3_phy);
+ dwc3_omap_disable_irqs(omap);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
@@ -465,18 +404,72 @@ static int dwc3_omap_remove(struct platform_device *pdev)
static const struct of_device_id of_dwc3_match[] = {
{
- "ti,dwc3",
+ .compatible = "ti,dwc3"
},
{ },
};
MODULE_DEVICE_TABLE(of, of_dwc3_match);
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_omap_prepare(struct device *dev)
+{
+ struct dwc3_omap *omap = dev_get_drvdata(dev);
+
+ dwc3_omap_disable_irqs(omap);
+
+ return 0;
+}
+
+static void dwc3_omap_complete(struct device *dev)
+{
+ struct dwc3_omap *omap = dev_get_drvdata(dev);
+
+ dwc3_omap_enable_irqs(omap);
+}
+
+static int dwc3_omap_suspend(struct device *dev)
+{
+ struct dwc3_omap *omap = dev_get_drvdata(dev);
+
+ omap->utmi_otg_status = dwc3_omap_readl(omap->base,
+ USBOTGSS_UTMI_OTG_STATUS);
+
+ return 0;
+}
+
+static int dwc3_omap_resume(struct device *dev)
+{
+ struct dwc3_omap *omap = dev_get_drvdata(dev);
+
+ dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS,
+ omap->utmi_otg_status);
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops dwc3_omap_dev_pm_ops = {
+ .prepare = dwc3_omap_prepare,
+ .complete = dwc3_omap_complete,
+
+ SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume)
+};
+
+#define DEV_PM_OPS (&dwc3_omap_dev_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
static struct platform_driver dwc3_omap_driver = {
.probe = dwc3_omap_probe,
.remove = dwc3_omap_remove,
.driver = {
.name = "omap-dwc3",
.of_match_table = of_dwc3_match,
+ .pm = DEV_PM_OPS,
},
};
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index e8d77689a322..227d4a7acad7 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -212,11 +212,49 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
};
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
+#ifdef CONFIG_PM
+static int dwc3_pci_suspend(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+
+ pci_disable_device(pci);
+
+ return 0;
+}
+
+static int dwc3_pci_resume(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+ int ret;
+
+ ret = pci_enable_device(pci);
+ if (ret) {
+ dev_err(dev, "can't re-enable device --> %d\n", ret);
+ return ret;
+ }
+
+ pci_set_master(pci);
+
+ return 0;
+}
+
+static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
+};
+
+#define DEV_PM_OPS (&dwc3_pci_dev_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
static struct pci_driver dwc3_pci_driver = {
.name = "dwc3-pci",
.id_table = dwc3_pci_id_table,
.probe = dwc3_pci_probe,
.remove = dwc3_pci_remove,
+ .driver = {
+ .pm = DEV_PM_OPS,
+ },
};
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 1d139ca05ef1..5acbb948b704 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -394,10 +394,13 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
u32 wIndex;
u32 reg;
int ret;
+ enum usb_device_state state;
wValue = le16_to_cpu(ctrl->wValue);
wIndex = le16_to_cpu(ctrl->wIndex);
recip = ctrl->bRequestType & USB_RECIP_MASK;
+ state = dwc->gadget.state;
+
switch (recip) {
case USB_RECIP_DEVICE:
@@ -409,7 +412,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
* default control pipe
*/
case USB_DEVICE_U1_ENABLE:
- if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+ if (state != USB_STATE_CONFIGURED)
return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL;
@@ -423,7 +426,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
break;
case USB_DEVICE_U2_ENABLE:
- if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+ if (state != USB_STATE_CONFIGURED)
return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL;
@@ -493,6 +496,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
+ enum usb_device_state state = dwc->gadget.state;
u32 addr;
u32 reg;
@@ -502,7 +506,7 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
return -EINVAL;
}
- if (dwc->dev_state == DWC3_CONFIGURED_STATE) {
+ if (state == USB_STATE_CONFIGURED) {
dev_dbg(dwc->dev, "trying to set address when configured\n");
return -EINVAL;
}
@@ -513,9 +517,9 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
if (addr)
- dwc->dev_state = DWC3_ADDRESS_STATE;
+ usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS);
else
- dwc->dev_state = DWC3_DEFAULT_STATE;
+ usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
return 0;
}
@@ -532,6 +536,7 @@ static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
+ enum usb_device_state state = dwc->gadget.state;
u32 cfg;
int ret;
u32 reg;
@@ -539,16 +544,18 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dwc->start_config_issued = false;
cfg = le16_to_cpu(ctrl->wValue);
- switch (dwc->dev_state) {
- case DWC3_DEFAULT_STATE:
+ switch (state) {
+ case USB_STATE_DEFAULT:
return -EINVAL;
break;
- case DWC3_ADDRESS_STATE:
+ case USB_STATE_ADDRESS:
ret = dwc3_ep0_delegate_req(dwc, ctrl);
/* if the cfg matches and the cfg is non zero */
if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
- dwc->dev_state = DWC3_CONFIGURED_STATE;
+ usb_gadget_set_state(&dwc->gadget,
+ USB_STATE_CONFIGURED);
+
/*
* Enable transition to U1/U2 state when
* nothing is pending from application.
@@ -562,10 +569,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
}
break;
- case DWC3_CONFIGURED_STATE:
+ case USB_STATE_CONFIGURED:
ret = dwc3_ep0_delegate_req(dwc, ctrl);
if (!cfg)
- dwc->dev_state = DWC3_ADDRESS_STATE;
+ usb_gadget_set_state(&dwc->gadget,
+ USB_STATE_ADDRESS);
break;
default:
ret = -EINVAL;
@@ -620,10 +628,11 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
struct dwc3_ep *dep;
+ enum usb_device_state state = dwc->gadget.state;
u16 wLength;
u16 wValue;
- if (dwc->dev_state == DWC3_DEFAULT_STATE)
+ if (state == USB_STATE_DEFAULT)
return -EINVAL;
wValue = le16_to_cpu(ctrl->wValue);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 82e160e96fca..2b6e7e001207 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1425,8 +1425,10 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
if (dwc->revision >= DWC3_REVISION_194A)
reg &= ~DWC3_DCTL_KEEP_CONNECT;
reg |= DWC3_DCTL_RUN_STOP;
+ dwc->pullups_connected = true;
} else {
reg &= ~DWC3_DCTL_RUN_STOP;
+ dwc->pullups_connected = false;
}
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
@@ -1469,6 +1471,33 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
return ret;
}
+static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ /* Enable all but Start and End of Frame IRQs */
+ reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
+ DWC3_DEVTEN_EVNTOVERFLOWEN |
+ DWC3_DEVTEN_CMDCMPLTEN |
+ DWC3_DEVTEN_ERRTICERREN |
+ DWC3_DEVTEN_WKUPEVTEN |
+ DWC3_DEVTEN_ULSTCNGEN |
+ DWC3_DEVTEN_CONNECTDONEEN |
+ DWC3_DEVTEN_USBRSTEN |
+ DWC3_DEVTEN_DISCONNEVTEN);
+
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
+}
+
+static void dwc3_gadget_disable_irq(struct dwc3 *dwc)
+{
+ /* mask all interrupts */
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+}
+
+static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
+
static int dwc3_gadget_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
@@ -1476,6 +1505,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
struct dwc3_ep *dep;
unsigned long flags;
int ret = 0;
+ int irq;
u32 reg;
spin_lock_irqsave(&dwc->lock, flags);
@@ -1489,7 +1519,6 @@ static int dwc3_gadget_start(struct usb_gadget *g,
}
dwc->gadget_driver = driver;
- dwc->gadget.dev.driver = &driver->driver;
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK);
@@ -1536,6 +1565,17 @@ static int dwc3_gadget_start(struct usb_gadget *g,
dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_out_start(dwc);
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+ ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
+ IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+ irq, ret);
+ goto err1;
+ }
+
+ dwc3_gadget_enable_irq(dwc);
+
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
@@ -1554,14 +1594,18 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
+ int irq;
spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_gadget_disable_irq(dwc);
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+ free_irq(irq, dwc);
+
__dwc3_gadget_ep_disable(dwc->eps[0]);
__dwc3_gadget_ep_disable(dwc->eps[1]);
dwc->gadget_driver = NULL;
- dwc->gadget.dev.driver = NULL;
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1579,14 +1623,15 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
/* -------------------------------------------------------------------------- */
-static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
+static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
+ u8 num, u32 direction)
{
struct dwc3_ep *dep;
- u8 epnum;
+ u8 i;
- INIT_LIST_HEAD(&dwc->gadget.ep_list);
+ for (i = 0; i < num; i++) {
+ u8 epnum = (i << 1) | (!!direction);
- for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
dep = kzalloc(sizeof(*dep), GFP_KERNEL);
if (!dep) {
dev_err(dwc->dev, "can't allocate endpoint %d\n",
@@ -1600,6 +1645,7 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
(epnum & 1) ? "in" : "out");
+
dep->endpoint.name = dep->name;
dep->direction = (epnum & 1);
@@ -1630,6 +1676,27 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
return 0;
}
+static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
+{
+ int ret;
+
+ INIT_LIST_HEAD(&dwc->gadget.ep_list);
+
+ ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
+ if (ret < 0) {
+ dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n");
+ return ret;
+ }
+
+ ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
+ if (ret < 0) {
+ dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
{
struct dwc3_ep *dep;
@@ -1637,6 +1704,9 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
dep = dwc->eps[epnum];
+ if (!dep)
+ continue;
+
dwc3_free_trb_pool(dep);
if (epnum != 0 && epnum != 1)
@@ -1646,12 +1716,8 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
}
}
-static void dwc3_gadget_release(struct device *dev)
-{
- dev_dbg(dev, "%s\n", __func__);
-}
-
/* -------------------------------------------------------------------------- */
+
static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
struct dwc3_request *req, struct dwc3_trb *trb,
const struct dwc3_event_depevt *event, int status)
@@ -1975,6 +2041,9 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
struct dwc3_ep *dep;
dep = dwc->eps[epnum];
+ if (!dep)
+ continue;
+
if (!(dep->flags & DWC3_EP_ENABLED))
continue;
@@ -1992,6 +2061,8 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
int ret;
dep = dwc->eps[epnum];
+ if (!dep)
+ continue;
if (!(dep->flags & DWC3_EP_STALL))
continue;
@@ -2091,7 +2162,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
}
/* after reset -> Default State */
- dwc->dev_state = DWC3_DEFAULT_STATE;
+ usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
/* Recent versions support automatic phy suspend and don't need this */
if (dwc->revision < DWC3_REVISION_194A) {
@@ -2277,6 +2348,34 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
unsigned int evtinfo)
{
enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
+ unsigned int pwropt;
+
+ /*
+ * WORKAROUND: DWC3 < 2.50a have an issue when configured without
+ * Hibernation mode enabled which would show up when device detects
+ * host-initiated U3 exit.
+ *
+ * In that case, device will generate a Link State Change Interrupt
+ * from U3 to RESUME which is only necessary if Hibernation is
+ * configured in.
+ *
+ * There are no functional changes due to such spurious event and we
+ * just need to ignore it.
+ *
+ * Refers to:
+ *
+ * STAR#9000570034 RTL: SS Resume event generated in non-Hibernation
+ * operational mode
+ */
+ pwropt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1);
+ if ((dwc->revision < DWC3_REVISION_250A) &&
+ (pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
+ if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
+ (next == DWC3_LINK_STATE_RESUME)) {
+ dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n");
+ return;
+ }
+ }
/*
* WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
@@ -2387,40 +2486,73 @@ static void dwc3_process_event_entry(struct dwc3 *dwc,
}
}
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
+{
+ struct dwc3 *dwc = _dwc;
+ unsigned long flags;
+ irqreturn_t ret = IRQ_NONE;
+ int i;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ for (i = 0; i < dwc->num_event_buffers; i++) {
+ struct dwc3_event_buffer *evt;
+ int left;
+
+ evt = dwc->ev_buffs[i];
+ left = evt->count;
+
+ if (!(evt->flags & DWC3_EVENT_PENDING))
+ continue;
+
+ while (left > 0) {
+ union dwc3_event event;
+
+ event.raw = *(u32 *) (evt->buf + evt->lpos);
+
+ dwc3_process_event_entry(dwc, &event);
+
+ /*
+ * FIXME we wrap around correctly to the next entry as
+ * almost all entries are 4 bytes in size. There is one
+ * entry which has 12 bytes which is a regular entry
+ * followed by 8 bytes data. ATM I don't know how
+ * things are organized if we get next to the a
+ * boundary so I worry about that once we try to handle
+ * that.
+ */
+ evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
+ left -= 4;
+
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4);
+ }
+
+ evt->count = 0;
+ evt->flags &= ~DWC3_EVENT_PENDING;
+ ret = IRQ_HANDLED;
+ }
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
{
struct dwc3_event_buffer *evt;
- int left;
u32 count;
+ evt = dwc->ev_buffs[buf];
+
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
count &= DWC3_GEVNTCOUNT_MASK;
if (!count)
return IRQ_NONE;
- evt = dwc->ev_buffs[buf];
- left = count;
-
- while (left > 0) {
- union dwc3_event event;
-
- event.raw = *(u32 *) (evt->buf + evt->lpos);
+ evt->count = count;
+ evt->flags |= DWC3_EVENT_PENDING;
- dwc3_process_event_entry(dwc, &event);
- /*
- * XXX we wrap around correctly to the next entry as almost all
- * entries are 4 bytes in size. There is one entry which has 12
- * bytes which is a regular entry followed by 8 bytes data. ATM
- * I don't know how things are organized if were get next to the
- * a boundary so I worry about that once we try to handle that.
- */
- evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
- left -= 4;
-
- dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
- }
-
- return IRQ_HANDLED;
+ return IRQ_WAKE_THREAD;
}
static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
@@ -2435,7 +2567,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
irqreturn_t status;
status = dwc3_process_event_buf(dwc, i);
- if (status == IRQ_HANDLED)
+ if (status == IRQ_WAKE_THREAD)
ret = status;
}
@@ -2454,7 +2586,6 @@ int dwc3_gadget_init(struct dwc3 *dwc)
{
u32 reg;
int ret;
- int irq;
dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
&dwc->ctrl_req_addr, GFP_KERNEL);
@@ -2488,19 +2619,10 @@ int dwc3_gadget_init(struct dwc3 *dwc)
goto err3;
}
- dev_set_name(&dwc->gadget.dev, "gadget");
-
dwc->gadget.ops = &dwc3_gadget_ops;
dwc->gadget.max_speed = USB_SPEED_SUPER;
dwc->gadget.speed = USB_SPEED_UNKNOWN;
- dwc->gadget.dev.parent = dwc->dev;
dwc->gadget.sg_supported = true;
-
- dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
-
- dwc->gadget.dev.dma_parms = dwc->dev->dma_parms;
- dwc->gadget.dev.dma_mask = dwc->dev->dma_mask;
- dwc->gadget.dev.release = dwc3_gadget_release;
dwc->gadget.name = "dwc3-gadget";
/*
@@ -2512,60 +2634,24 @@ int dwc3_gadget_init(struct dwc3 *dwc)
if (ret)
goto err4;
- irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-
- ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED,
- "dwc3", dwc);
- if (ret) {
- dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
- irq, ret);
- goto err5;
- }
-
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg |= DWC3_DCFG_LPM_CAP;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
- /* Enable all but Start and End of Frame IRQs */
- reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
- DWC3_DEVTEN_EVNTOVERFLOWEN |
- DWC3_DEVTEN_CMDCMPLTEN |
- DWC3_DEVTEN_ERRTICERREN |
- DWC3_DEVTEN_WKUPEVTEN |
- DWC3_DEVTEN_ULSTCNGEN |
- DWC3_DEVTEN_CONNECTDONEEN |
- DWC3_DEVTEN_USBRSTEN |
- DWC3_DEVTEN_DISCONNEVTEN);
- dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
-
- /* automatic phy suspend only on recent versions */
+ /* Enable USB2 LPM and automatic phy suspend only on recent versions */
if (dwc->revision >= DWC3_REVISION_194A) {
dwc3_gadget_usb2_phy_suspend(dwc, false);
dwc3_gadget_usb3_phy_suspend(dwc, false);
}
- ret = device_register(&dwc->gadget.dev);
- if (ret) {
- dev_err(dwc->dev, "failed to register gadget device\n");
- put_device(&dwc->gadget.dev);
- goto err6;
- }
-
ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
if (ret) {
dev_err(dwc->dev, "failed to register udc\n");
- goto err7;
+ goto err5;
}
return 0;
-err7:
- device_unregister(&dwc->gadget.dev);
-
-err6:
- dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
- free_irq(irq, dwc);
-
err5:
dwc3_gadget_free_endpoints(dwc);
@@ -2588,15 +2674,11 @@ err0:
return ret;
}
+/* -------------------------------------------------------------------------- */
+
void dwc3_gadget_exit(struct dwc3 *dwc)
{
- int irq;
-
usb_del_gadget_udc(&dwc->gadget);
- irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-
- dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
- free_irq(irq, dwc);
dwc3_gadget_free_endpoints(dwc);
@@ -2610,6 +2692,63 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
dwc->ctrl_req, dwc->ctrl_req_addr);
+}
- device_unregister(&dwc->gadget.dev);
+int dwc3_gadget_prepare(struct dwc3 *dwc)
+{
+ if (dwc->pullups_connected)
+ dwc3_gadget_disable_irq(dwc);
+
+ return 0;
+}
+
+void dwc3_gadget_complete(struct dwc3 *dwc)
+{
+ if (dwc->pullups_connected) {
+ dwc3_gadget_enable_irq(dwc);
+ dwc3_gadget_run_stop(dwc, true);
+ }
+}
+
+int dwc3_gadget_suspend(struct dwc3 *dwc)
+{
+ __dwc3_gadget_ep_disable(dwc->eps[0]);
+ __dwc3_gadget_ep_disable(dwc->eps[1]);
+
+ dwc->dcfg = dwc3_readl(dwc->regs, DWC3_DCFG);
+
+ return 0;
+}
+
+int dwc3_gadget_resume(struct dwc3 *dwc)
+{
+ struct dwc3_ep *dep;
+ int ret;
+
+ /* Start with SuperSpeed Default */
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+
+ dep = dwc->eps[0];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+ if (ret)
+ goto err0;
+
+ dep = dwc->eps[1];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+ if (ret)
+ goto err1;
+
+ /* begin to receive SETUP packets */
+ dwc->ep0state = EP0_SETUP_PHASE;
+ dwc3_ep0_out_start(dwc);
+
+ dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg);
+
+ return 0;
+
+err1:
+ __dwc3_gadget_ep_disable(dwc->eps[0]);
+
+err0:
+ return ret;
}
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index c7525b1cad74..a61d981cbd15 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -196,7 +196,6 @@ config USB_OMAP
tristate "OMAP USB Device Controller"
depends on ARCH_OMAP1
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
- select USB_OTG_UTILS if ARCH_OMAP
help
Many Texas Instruments OMAP processors have flexible full
speed USB device controllers, with support for up to 30
@@ -211,7 +210,6 @@ config USB_OMAP
config USB_PXA25X
tristate "PXA 25x or IXP 4xx"
depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
- select USB_OTG_UTILS
help
Intel's PXA 25x series XScale ARM-5TE processors include
an integrated full speed USB 1.1 device controller. The
@@ -259,8 +257,6 @@ config USB_RENESAS_USBHS_UDC
config USB_PXA27X
tristate "PXA 27x"
- depends on ARCH_PXA && (PXA27x || PXA3xx)
- select USB_OTG_UTILS
help
Intel's PXA 27x series XScale ARM v5TE processors include
an integrated full speed USB 1.1 device controller.
@@ -329,9 +325,6 @@ config USB_MV_UDC
config USB_MV_U3D
tristate "MARVELL PXA2128 USB 3.0 controller"
- depends on CPU_MMP3
- select USB_GADGET_DUALSPEED
- select USB_GADGET_SUPERSPEED
help
MARVELL PXA2128 Processor series include a super speed USB3.0 device
controller, which support super speed USB peripheral.
@@ -501,6 +494,7 @@ endmenu
# composite based drivers
config USB_LIBCOMPOSITE
tristate
+ select CONFIGFS_FS
depends on USB_GADGET
config USB_F_ACM
@@ -512,6 +506,12 @@ config USB_F_SS_LB
config USB_U_SERIAL
tristate
+config USB_F_SERIAL
+ tristate
+
+config USB_F_OBEX
+ tristate
+
choice
tristate "USB Gadget Drivers"
default USB_ETH
@@ -766,6 +766,8 @@ config USB_G_SERIAL
depends on TTY
select USB_U_SERIAL
select USB_F_ACM
+ select USB_F_SERIAL
+ select USB_F_OBEX
select USB_LIBCOMPOSITE
help
The Serial Gadget talks to the Linux-USB generic serial driver.
@@ -839,6 +841,7 @@ config USB_G_NOKIA
depends on PHONET
select USB_LIBCOMPOSITE
select USB_U_SERIAL
+ select USB_F_ACM
help
The Nokia composite gadget provides support for acm, obex
and phonet in only one composite gadget driver.
@@ -957,6 +960,7 @@ config USB_G_WEBCAM
tristate "USB Webcam Gadget"
depends on VIDEO_DEV
select USB_LIBCOMPOSITE
+ select VIDEOBUF2_VMALLOC
help
The Webcam Gadget acts as a composite USB Audio and Video Class
device. It provides a userspace API to process UVC control requests
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 82fb22511356..6afd16659e78 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
obj-$(CONFIG_USB_GADGET) += udc-core.o
obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o
libcomposite-y := usbstring.o config.o epautoconf.o
-libcomposite-y += composite.o functions.o
+libcomposite-y += composite.o functions.o configfs.o
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2272) += net2272.o
obj-$(CONFIG_USB_NET2280) += net2280.o
@@ -36,10 +36,15 @@ obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
# USB Functions
-obj-$(CONFIG_USB_F_ACM) += f_acm.o
-f_ss_lb-y := f_loopback.o f_sourcesink.o
-obj-$(CONFIG_USB_F_SS_LB) += f_ss_lb.o
+usb_f_acm-y := f_acm.o
+obj-$(CONFIG_USB_F_ACM) += usb_f_acm.o
+usb_f_ss_lb-y := f_loopback.o f_sourcesink.o
+obj-$(CONFIG_USB_F_SS_LB) += usb_f_ss_lb.o
obj-$(CONFIG_USB_U_SERIAL) += u_serial.o
+usb_f_serial-y := f_serial.o
+obj-$(CONFIG_USB_F_SERIAL) += usb_f_serial.o
+usb_f_obex-y := f_obex.o
+obj-$(CONFIG_USB_F_OBEX) += usb_f_obex.o
#
# USB gadget drivers
diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c
index 8f2b0e391534..4b947bb50f62 100644
--- a/drivers/usb/gadget/acm_ms.c
+++ b/drivers/usb/gadget/acm_ms.c
@@ -109,7 +109,6 @@ FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
static struct fsg_common fsg_common;
/*-------------------------------------------------------------------------*/
-static unsigned char tty_line;
static struct usb_function *f_acm;
static struct usb_function_instance *f_acm_inst;
/*
@@ -117,7 +116,6 @@ static struct usb_function_instance *f_acm_inst;
*/
static int __init acm_ms_do_config(struct usb_configuration *c)
{
- struct f_serial_opts *opts;
int status;
if (gadget_is_otg(c->cdev->gadget)) {
@@ -129,9 +127,6 @@ static int __init acm_ms_do_config(struct usb_configuration *c)
if (IS_ERR(f_acm_inst))
return PTR_ERR(f_acm_inst);
- opts = container_of(f_acm_inst, struct f_serial_opts, func_inst);
- opts->port_num = tty_line;
-
f_acm = usb_get_function(f_acm_inst);
if (IS_ERR(f_acm)) {
status = PTR_ERR(f_acm);
@@ -171,16 +166,11 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
int status;
void *retp;
- /* set up serial link layer */
- status = gserial_alloc_line(&tty_line);
- if (status < 0)
- return status;
-
/* set up mass storage function */
retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
if (IS_ERR(retp)) {
status = PTR_ERR(retp);
- goto fail0;
+ return PTR_ERR(retp);
}
/*
@@ -207,8 +197,6 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
/* error recovery */
fail1:
fsg_common_put(&fsg_common);
-fail0:
- gserial_free_line(tty_line);
return status;
}
@@ -216,7 +204,6 @@ static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
{
usb_put_function(f_acm);
usb_put_function_instance(f_acm_inst);
- gserial_free_line(tty_line);
return 0;
}
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 75973f33a4c8..f52dcfe8f545 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -1922,7 +1922,6 @@ static int amd5536_udc_start(struct usb_gadget *g,
driver->driver.bus = NULL;
dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
/* Some gadget drivers use both ep0 directions.
* NOTE: to gadget driver, ep0 is just one endpoint...
@@ -1973,7 +1972,6 @@ static int amd5536_udc_stop(struct usb_gadget *g,
shutdown(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
- dev->gadget.dev.driver = NULL;
dev->driver = NULL;
/* set SD */
@@ -3080,7 +3078,6 @@ static void udc_pci_remove(struct pci_dev *pdev)
if (dev->active)
pci_disable_device(pdev);
- device_unregister(&dev->gadget.dev);
pci_set_drvdata(pdev, NULL);
udc_remove(dev);
@@ -3245,8 +3242,6 @@ static int udc_pci_probe(
dev->phys_addr = resource;
dev->irq = pdev->irq;
dev->pdev = pdev;
- dev->gadget.dev.parent = &pdev->dev;
- dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
/* general probing */
if (udc_probe(dev) == 0)
@@ -3273,7 +3268,6 @@ static int udc_probe(struct udc *dev)
dev->gadget.ops = &udc_ops;
dev_set_name(&dev->gadget.dev, "gadget");
- dev->gadget.dev.release = gadget_release;
dev->gadget.name = name;
dev->gadget.max_speed = USB_SPEED_HIGH;
@@ -3297,17 +3291,11 @@ static int udc_probe(struct udc *dev)
"driver version: %s(for Geode5536 B1)\n", tmp);
udc = dev;
- retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget);
+ retval = usb_add_gadget_udc_release(&udc->pdev->dev, &dev->gadget,
+ gadget_release);
if (retval)
goto finished;
- retval = device_register(&dev->gadget.dev);
- if (retval) {
- usb_del_gadget_udc(&dev->gadget);
- put_device(&dev->gadget.dev);
- goto finished;
- }
-
/* timer init */
init_timer(&udc_timer);
udc_timer.function = udc_timer_function;
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
index f1bf32e6b8d8..6744d3b83109 100644
--- a/drivers/usb/gadget/amd5536udc.h
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -472,7 +472,6 @@ struct udc_request {
/* flags */
unsigned dma_going : 1,
- dma_mapping : 1,
dma_done : 1;
/* phys. address */
dma_addr_t td_phys;
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 45dd2929a671..a690d64217f4 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -1631,7 +1631,6 @@ static int at91_start(struct usb_gadget *gadget,
udc = container_of(gadget, struct at91_udc, gadget);
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
udc->gadget.dev.of_node = udc->pdev->dev.of_node;
udc->enabled = 1;
udc->selfpowered = 1;
@@ -1652,7 +1651,6 @@ static int at91_stop(struct usb_gadget *gadget,
at91_udp_write(udc, AT91_UDP_IDR, ~0);
spin_unlock_irqrestore(&udc->lock, flags);
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
DBG("unbound from %s\n", driver->driver.name);
@@ -1780,13 +1778,7 @@ static int at91udc_probe(struct platform_device *pdev)
DBG("clocks missing\n");
retval = -ENODEV;
/* NOTE: we "know" here that refcounts on these are NOPs */
- goto fail0b;
- }
-
- retval = device_register(&udc->gadget.dev);
- if (retval < 0) {
- put_device(&udc->gadget.dev);
- goto fail0b;
+ goto fail1;
}
/* don't do anything until we have both gadget driver and VBUS */
@@ -1857,8 +1849,6 @@ fail3:
fail2:
free_irq(udc->udp_irq, udc);
fail1:
- device_unregister(&udc->gadget.dev);
-fail0b:
iounmap(udc->udp_baseaddr);
fail0a:
if (cpu_is_at91rm9200())
@@ -1892,8 +1882,6 @@ static int __exit at91udc_remove(struct platform_device *pdev)
gpio_free(udc->board.vbus_pin);
}
free_irq(udc->udp_irq, udc);
- device_unregister(&udc->gadget.dev);
-
iounmap(udc->udp_baseaddr);
if (cpu_is_at91rm9200())
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index b66130c97269..f2a970f75bfa 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -489,13 +489,8 @@ request_complete(struct usba_ep *ep, struct usba_request *req, int status)
if (req->req.status == -EINPROGRESS)
req->req.status = status;
- if (req->mapped) {
- dma_unmap_single(
- &udc->pdev->dev, req->req.dma, req->req.length,
- ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- }
+ if (req->using_dma)
+ usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in);
DBG(DBG_GADGET | DBG_REQ,
"%s: req %p complete: status %d, actual %u\n",
@@ -684,7 +679,6 @@ usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
return NULL;
INIT_LIST_HEAD(&req->queue);
- req->req.dma = DMA_ADDR_INVALID;
return &req->req;
}
@@ -717,20 +711,11 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
return -EINVAL;
}
- req->using_dma = 1;
-
- if (req->req.dma == DMA_ADDR_INVALID) {
- req->req.dma = dma_map_single(
- &udc->pdev->dev, req->req.buf, req->req.length,
- ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 1;
- } else {
- dma_sync_single_for_device(
- &udc->pdev->dev, req->req.dma, req->req.length,
- ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 0;
- }
+ ret = usb_gadget_map_request(&udc->gadget, &req->req, ep->is_in);
+ if (ret)
+ return ret;
+ req->using_dma = 1;
req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
| USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
| USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
@@ -1799,7 +1784,6 @@ static int atmel_usba_start(struct usb_gadget *gadget,
udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc->lock, flags);
clk_enable(udc->pclk);
@@ -1841,7 +1825,6 @@ static int atmel_usba_stop(struct usb_gadget *gadget,
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
clk_disable(udc->hclk);
@@ -1900,10 +1883,6 @@ static int __init usba_udc_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
(unsigned long)fifo->start, udc->fifo);
- device_initialize(&udc->gadget.dev);
- udc->gadget.dev.parent = &pdev->dev;
- udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
platform_set_drvdata(pdev, udc);
/* Make sure we start from a clean slate */
@@ -1962,12 +1941,6 @@ static int __init usba_udc_probe(struct platform_device *pdev)
}
udc->irq = irq;
- ret = device_add(&udc->gadget.dev);
- if (ret) {
- dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
- goto err_device_add;
- }
-
if (gpio_is_valid(pdata->vbus_pin)) {
if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
udc->vbus_pin = pdata->vbus_pin;
@@ -2007,9 +1980,6 @@ err_add_udc:
gpio_free(udc->vbus_pin);
}
- device_unregister(&udc->gadget.dev);
-
-err_device_add:
free_irq(irq, udc);
err_request_irq:
kfree(usba_ep);
@@ -2053,8 +2023,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
clk_put(udc->hclk);
clk_put(udc->pclk);
- device_unregister(&udc->gadget.dev);
-
return 0;
}
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
index 9791259cbda7..d65a61851d3d 100644
--- a/drivers/usb/gadget/atmel_usba_udc.h
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -216,12 +216,6 @@
#define EP0_EPT_SIZE USBA_EPT_SIZE_64
#define EP0_NR_BANKS 1
-/*
- * REVISIT: Try to eliminate this value. Can we rely on req->mapped to
- * provide this information?
- */
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
#define FIFO_IOMEM_ID 0
#define CTRL_IOMEM_ID 1
diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c
index 8cc8253f1100..6e6518264c42 100644
--- a/drivers/usb/gadget/bcm63xx_udc.c
+++ b/drivers/usb/gadget/bcm63xx_udc.c
@@ -1819,7 +1819,6 @@ static int bcm63xx_udc_start(struct usb_gadget *gadget,
udc->driver = driver;
driver->driver.bus = NULL;
- udc->gadget.dev.driver = &driver->driver;
udc->gadget.dev.of_node = udc->dev->of_node;
spin_unlock_irqrestore(&udc->lock, flags);
@@ -1841,7 +1840,6 @@ static int bcm63xx_udc_stop(struct usb_gadget *gadget,
spin_lock_irqsave(&udc->lock, flags);
udc->driver = NULL;
- udc->gadget.dev.driver = NULL;
/*
* If we switch the PHY too abruptly after dropping D+, the host
@@ -2306,17 +2304,6 @@ static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc)
***********************************************************************/
/**
- * bcm63xx_udc_gadget_release - Called from device_release().
- * @dev: Unused.
- *
- * We get a warning if this function doesn't exist, but it's empty because
- * we don't have to free any of the memory allocated with the devm_* APIs.
- */
-static void bcm63xx_udc_gadget_release(struct device *dev)
-{
-}
-
-/**
* bcm63xx_udc_probe - Initialize a new instance of the UDC.
* @pdev: Platform device struct from the bcm63xx BSP code.
*
@@ -2368,13 +2355,9 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
spin_lock_init(&udc->lock);
INIT_WORK(&udc->ep0_wq, bcm63xx_ep0_process);
- dev_set_name(&udc->gadget.dev, "gadget");
udc->gadget.ops = &bcm63xx_udc_ops;
udc->gadget.name = dev_name(dev);
- udc->gadget.dev.parent = dev;
- udc->gadget.dev.release = bcm63xx_udc_gadget_release;
- udc->gadget.dev.dma_mask = dev->dma_mask;
if (!pd->use_fullspeed && !use_fullspeed)
udc->gadget.max_speed = USB_SPEED_HIGH;
@@ -2414,17 +2397,12 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
}
}
- rc = device_register(&udc->gadget.dev);
- if (rc)
- goto out_uninit;
-
bcm63xx_udc_init_debugfs(udc);
rc = usb_add_gadget_udc(dev, &udc->gadget);
if (!rc)
return 0;
bcm63xx_udc_cleanup_debugfs(udc);
- device_unregister(&udc->gadget.dev);
out_uninit:
bcm63xx_uninit_udc_hw(udc);
return rc;
@@ -2440,7 +2418,6 @@ static int bcm63xx_udc_remove(struct platform_device *pdev)
bcm63xx_udc_cleanup_debugfs(udc);
usb_del_gadget_udc(&udc->gadget);
- device_unregister(&udc->gadget.dev);
BUG_ON(udc->driver);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c
index a7d6f7026757..c6ee6f1558c3 100644
--- a/drivers/usb/gadget/cdc2.c
+++ b/drivers/usb/gadget/cdc2.c
@@ -103,18 +103,16 @@ static struct usb_gadget_strings *dev_strings[] = {
};
static u8 hostaddr[ETH_ALEN];
-
+static struct eth_dev *the_dev;
/*-------------------------------------------------------------------------*/
static struct usb_function *f_acm;
static struct usb_function_instance *fi_serial;
-static unsigned char tty_line;
/*
* We _always_ have both CDC ECM and CDC ACM functions.
*/
static int __init cdc_do_config(struct usb_configuration *c)
{
- struct f_serial_opts *opts;
int status;
if (gadget_is_otg(c->cdev->gadget)) {
@@ -122,7 +120,7 @@ static int __init cdc_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- status = ecm_bind_config(c, hostaddr);
+ status = ecm_bind_config(c, hostaddr, the_dev);
if (status < 0)
return status;
@@ -130,9 +128,6 @@ static int __init cdc_do_config(struct usb_configuration *c)
if (IS_ERR(fi_serial))
return PTR_ERR(fi_serial);
- opts = container_of(fi_serial, struct f_serial_opts, func_inst);
- opts->port_num = tty_line;
-
f_acm = usb_get_function(fi_serial);
if (IS_ERR(f_acm))
goto err_func_acm;
@@ -169,14 +164,9 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
}
/* set up network link layer */
- status = gether_setup(cdev->gadget, hostaddr);
- if (status < 0)
- return status;
-
- /* set up serial link layer */
- status = gserial_alloc_line(&tty_line);
- if (status < 0)
- goto fail0;
+ the_dev = gether_setup(cdev->gadget, hostaddr);
+ if (IS_ERR(the_dev))
+ return PTR_ERR(the_dev);
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
@@ -200,9 +190,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
return 0;
fail1:
- gserial_free_line(tty_line);
-fail0:
- gether_cleanup();
+ gether_cleanup(the_dev);
return status;
}
@@ -210,8 +198,7 @@ static int __exit cdc_unbind(struct usb_composite_dev *cdev)
{
usb_put_function(f_acm);
usb_put_function_instance(fi_serial);
- gserial_free_line(tty_line);
- gether_cleanup();
+ gether_cleanup(the_dev);
return 0;
}
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index c0d62b278610..55f4df60f327 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1637,6 +1637,7 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
kfree(cdev->req->buf);
usb_ep_free_request(cdev->gadget->ep0, cdev->req);
}
+ cdev->next_string_id = 0;
device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
}
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
new file mode 100644
index 000000000000..a34633a898a1
--- /dev/null
+++ b/drivers/usb/gadget/configfs.c
@@ -0,0 +1,1003 @@
+#include <linux/configfs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget_configfs.h>
+
+int check_user_usb_string(const char *name,
+ struct usb_gadget_strings *stringtab_dev)
+{
+ unsigned primary_lang;
+ unsigned sub_lang;
+ u16 num;
+ int ret;
+
+ ret = kstrtou16(name, 0, &num);
+ if (ret)
+ return ret;
+
+ primary_lang = num & 0x3ff;
+ sub_lang = num >> 10;
+
+ /* simple sanity check for valid langid */
+ switch (primary_lang) {
+ case 0:
+ case 0x62 ... 0xfe:
+ case 0x100 ... 0x3ff:
+ return -EINVAL;
+ }
+ if (!sub_lang)
+ return -EINVAL;
+
+ stringtab_dev->language = num;
+ return 0;
+}
+
+#define MAX_NAME_LEN 40
+#define MAX_USB_STRING_LANGS 2
+
+struct gadget_info {
+ struct config_group group;
+ struct config_group functions_group;
+ struct config_group configs_group;
+ struct config_group strings_group;
+ struct config_group *default_groups[4];
+
+ struct mutex lock;
+ struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
+ struct list_head string_list;
+ struct list_head available_func;
+
+ const char *udc_name;
+#ifdef CONFIG_USB_OTG
+ struct usb_otg_descriptor otg;
+#endif
+ struct usb_composite_driver composite;
+ struct usb_composite_dev cdev;
+};
+
+struct config_usb_cfg {
+ struct config_group group;
+ struct config_group strings_group;
+ struct config_group *default_groups[2];
+ struct list_head string_list;
+ struct usb_configuration c;
+ struct list_head func_list;
+ struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
+};
+
+struct gadget_strings {
+ struct usb_gadget_strings stringtab_dev;
+ struct usb_string strings[USB_GADGET_FIRST_AVAIL_IDX];
+ char *manufacturer;
+ char *product;
+ char *serialnumber;
+
+ struct config_group group;
+ struct list_head list;
+};
+
+struct gadget_config_name {
+ struct usb_gadget_strings stringtab_dev;
+ struct usb_string strings;
+ char *configuration;
+
+ struct config_group group;
+ struct list_head list;
+};
+
+static int usb_string_copy(const char *s, char **s_copy)
+{
+ int ret;
+ char *str;
+ char *copy = *s_copy;
+ ret = strlen(s);
+ if (ret > 126)
+ return -EOVERFLOW;
+
+ str = kstrdup(s, GFP_KERNEL);
+ if (!str)
+ return -ENOMEM;
+ if (str[ret - 1] == '\n')
+ str[ret - 1] = '\0';
+ kfree(copy);
+ *s_copy = str;
+ return 0;
+}
+
+CONFIGFS_ATTR_STRUCT(gadget_info);
+CONFIGFS_ATTR_STRUCT(config_usb_cfg);
+
+#define GI_DEVICE_DESC_ITEM_ATTR(name) \
+ static struct gadget_info_attribute gadget_cdev_desc_##name = \
+ __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \
+ gadget_dev_desc_##name##_show, \
+ gadget_dev_desc_##name##_store)
+
+#define GI_DEVICE_DESC_SIMPLE_R_u8(__name) \
+ static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \
+ char *page) \
+{ \
+ return sprintf(page, "0x%02x\n", gi->cdev.desc.__name); \
+}
+
+#define GI_DEVICE_DESC_SIMPLE_R_u16(__name) \
+ static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \
+ char *page) \
+{ \
+ return sprintf(page, "0x%04x\n", le16_to_cpup(&gi->cdev.desc.__name)); \
+}
+
+
+#define GI_DEVICE_DESC_SIMPLE_W_u8(_name) \
+ static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \
+ const char *page, size_t len) \
+{ \
+ u8 val; \
+ int ret; \
+ ret = kstrtou8(page, 0, &val); \
+ if (ret) \
+ return ret; \
+ gi->cdev.desc._name = val; \
+ return len; \
+}
+
+#define GI_DEVICE_DESC_SIMPLE_W_u16(_name) \
+ static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \
+ const char *page, size_t len) \
+{ \
+ u16 val; \
+ int ret; \
+ ret = kstrtou16(page, 0, &val); \
+ if (ret) \
+ return ret; \
+ gi->cdev.desc._name = cpu_to_le16p(&val); \
+ return len; \
+}
+
+#define GI_DEVICE_DESC_SIMPLE_RW(_name, _type) \
+ GI_DEVICE_DESC_SIMPLE_R_##_type(_name) \
+ GI_DEVICE_DESC_SIMPLE_W_##_type(_name)
+
+GI_DEVICE_DESC_SIMPLE_R_u16(bcdUSB);
+GI_DEVICE_DESC_SIMPLE_RW(bDeviceClass, u8);
+GI_DEVICE_DESC_SIMPLE_RW(bDeviceSubClass, u8);
+GI_DEVICE_DESC_SIMPLE_RW(bDeviceProtocol, u8);
+GI_DEVICE_DESC_SIMPLE_RW(bMaxPacketSize0, u8);
+GI_DEVICE_DESC_SIMPLE_RW(idVendor, u16);
+GI_DEVICE_DESC_SIMPLE_RW(idProduct, u16);
+GI_DEVICE_DESC_SIMPLE_R_u16(bcdDevice);
+
+static ssize_t is_valid_bcd(u16 bcd_val)
+{
+ if ((bcd_val & 0xf) > 9)
+ return -EINVAL;
+ if (((bcd_val >> 4) & 0xf) > 9)
+ return -EINVAL;
+ if (((bcd_val >> 8) & 0xf) > 9)
+ return -EINVAL;
+ if (((bcd_val >> 12) & 0xf) > 9)
+ return -EINVAL;
+ return 0;
+}
+
+static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi,
+ const char *page, size_t len)
+{
+ u16 bcdDevice;
+ int ret;
+
+ ret = kstrtou16(page, 0, &bcdDevice);
+ if (ret)
+ return ret;
+ ret = is_valid_bcd(bcdDevice);
+ if (ret)
+ return ret;
+
+ gi->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice);
+ return len;
+}
+
+static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi,
+ const char *page, size_t len)
+{
+ u16 bcdUSB;
+ int ret;
+
+ ret = kstrtou16(page, 0, &bcdUSB);
+ if (ret)
+ return ret;
+ ret = is_valid_bcd(bcdUSB);
+ if (ret)
+ return ret;
+
+ gi->cdev.desc.bcdUSB = cpu_to_le16(bcdUSB);
+ return len;
+}
+
+static ssize_t gadget_dev_desc_UDC_show(struct gadget_info *gi, char *page)
+{
+ return sprintf(page, "%s\n", gi->udc_name ?: "");
+}
+
+static int unregister_gadget(struct gadget_info *gi)
+{
+ int ret;
+
+ if (!gi->udc_name)
+ return -ENODEV;
+
+ ret = usb_gadget_unregister_driver(&gi->composite.gadget_driver);
+ if (ret)
+ return ret;
+ kfree(gi->udc_name);
+ gi->udc_name = NULL;
+ return 0;
+}
+
+static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi,
+ const char *page, size_t len)
+{
+ char *name;
+ int ret;
+
+ name = kstrdup(page, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+ if (name[len - 1] == '\n')
+ name[len - 1] = '\0';
+
+ mutex_lock(&gi->lock);
+
+ if (!strlen(name)) {
+ ret = unregister_gadget(gi);
+ if (ret)
+ goto err;
+ } else {
+ if (gi->udc_name) {
+ ret = -EBUSY;
+ goto err;
+ }
+ ret = udc_attach_driver(name, &gi->composite.gadget_driver);
+ if (ret)
+ goto err;
+ gi->udc_name = name;
+ }
+ mutex_unlock(&gi->lock);
+ return len;
+err:
+ kfree(name);
+ mutex_unlock(&gi->lock);
+ return ret;
+}
+
+GI_DEVICE_DESC_ITEM_ATTR(bDeviceClass);
+GI_DEVICE_DESC_ITEM_ATTR(bDeviceSubClass);
+GI_DEVICE_DESC_ITEM_ATTR(bDeviceProtocol);
+GI_DEVICE_DESC_ITEM_ATTR(bMaxPacketSize0);
+GI_DEVICE_DESC_ITEM_ATTR(idVendor);
+GI_DEVICE_DESC_ITEM_ATTR(idProduct);
+GI_DEVICE_DESC_ITEM_ATTR(bcdDevice);
+GI_DEVICE_DESC_ITEM_ATTR(bcdUSB);
+GI_DEVICE_DESC_ITEM_ATTR(UDC);
+
+static struct configfs_attribute *gadget_root_attrs[] = {
+ &gadget_cdev_desc_bDeviceClass.attr,
+ &gadget_cdev_desc_bDeviceSubClass.attr,
+ &gadget_cdev_desc_bDeviceProtocol.attr,
+ &gadget_cdev_desc_bMaxPacketSize0.attr,
+ &gadget_cdev_desc_idVendor.attr,
+ &gadget_cdev_desc_idProduct.attr,
+ &gadget_cdev_desc_bcdDevice.attr,
+ &gadget_cdev_desc_bcdUSB.attr,
+ &gadget_cdev_desc_UDC.attr,
+ NULL,
+};
+
+static inline struct gadget_info *to_gadget_info(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct gadget_info, group);
+}
+
+static inline struct gadget_strings *to_gadget_strings(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct gadget_strings,
+ group);
+}
+
+static inline struct gadget_config_name *to_gadget_config_name(
+ struct config_item *item)
+{
+ return container_of(to_config_group(item), struct gadget_config_name,
+ group);
+}
+
+static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct config_usb_cfg,
+ group);
+}
+
+static inline struct usb_function_instance *to_usb_function_instance(
+ struct config_item *item)
+{
+ return container_of(to_config_group(item),
+ struct usb_function_instance, group);
+}
+
+static void gadget_info_attr_release(struct config_item *item)
+{
+ struct gadget_info *gi = to_gadget_info(item);
+
+ WARN_ON(!list_empty(&gi->cdev.configs));
+ WARN_ON(!list_empty(&gi->string_list));
+ WARN_ON(!list_empty(&gi->available_func));
+ kfree(gi->composite.gadget_driver.function);
+ kfree(gi);
+}
+
+CONFIGFS_ATTR_OPS(gadget_info);
+
+static struct configfs_item_operations gadget_root_item_ops = {
+ .release = gadget_info_attr_release,
+ .show_attribute = gadget_info_attr_show,
+ .store_attribute = gadget_info_attr_store,
+};
+
+static void gadget_config_attr_release(struct config_item *item)
+{
+ struct config_usb_cfg *cfg = to_config_usb_cfg(item);
+
+ WARN_ON(!list_empty(&cfg->c.functions));
+ list_del(&cfg->c.list);
+ kfree(cfg->c.label);
+ kfree(cfg);
+}
+
+static int config_usb_cfg_link(
+ struct config_item *usb_cfg_ci,
+ struct config_item *usb_func_ci)
+{
+ struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci);
+ struct usb_composite_dev *cdev = cfg->c.cdev;
+ struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
+
+ struct config_group *group = to_config_group(usb_func_ci);
+ struct usb_function_instance *fi = container_of(group,
+ struct usb_function_instance, group);
+ struct usb_function_instance *a_fi;
+ struct usb_function *f;
+ int ret;
+
+ mutex_lock(&gi->lock);
+ /*
+ * Make sure this function is from within our _this_ gadget and not
+ * from another gadget or a random directory.
+ * Also a function instance can only be linked once.
+ */
+ list_for_each_entry(a_fi, &gi->available_func, cfs_list) {
+ if (a_fi == fi)
+ break;
+ }
+ if (a_fi != fi) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ list_for_each_entry(f, &cfg->func_list, list) {
+ if (f->fi == fi) {
+ ret = -EEXIST;
+ goto out;
+ }
+ }
+
+ f = usb_get_function(fi);
+ if (IS_ERR(f)) {
+ ret = PTR_ERR(f);
+ goto out;
+ }
+
+ /* stash the function until we bind it to the gadget */
+ list_add_tail(&f->list, &cfg->func_list);
+ ret = 0;
+out:
+ mutex_unlock(&gi->lock);
+ return ret;
+}
+
+static int config_usb_cfg_unlink(
+ struct config_item *usb_cfg_ci,
+ struct config_item *usb_func_ci)
+{
+ struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci);
+ struct usb_composite_dev *cdev = cfg->c.cdev;
+ struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
+
+ struct config_group *group = to_config_group(usb_func_ci);
+ struct usb_function_instance *fi = container_of(group,
+ struct usb_function_instance, group);
+ struct usb_function *f;
+
+ /*
+ * ideally I would like to forbid to unlink functions while a gadget is
+ * bound to an UDC. Since this isn't possible at the moment, we simply
+ * force an unbind, the function is available here and then we can
+ * remove the function.
+ */
+ mutex_lock(&gi->lock);
+ if (gi->udc_name)
+ unregister_gadget(gi);
+ WARN_ON(gi->udc_name);
+
+ list_for_each_entry(f, &cfg->func_list, list) {
+ if (f->fi == fi) {
+ list_del(&f->list);
+ usb_put_function(f);
+ mutex_unlock(&gi->lock);
+ return 0;
+ }
+ }
+ mutex_unlock(&gi->lock);
+ __WARN_printf("Unable to locate function to unbind\n");
+ return 0;
+}
+
+CONFIGFS_ATTR_OPS(config_usb_cfg);
+
+static struct configfs_item_operations gadget_config_item_ops = {
+ .release = gadget_config_attr_release,
+ .show_attribute = config_usb_cfg_attr_show,
+ .store_attribute = config_usb_cfg_attr_store,
+ .allow_link = config_usb_cfg_link,
+ .drop_link = config_usb_cfg_unlink,
+};
+
+
+static ssize_t gadget_config_desc_MaxPower_show(struct config_usb_cfg *cfg,
+ char *page)
+{
+ return sprintf(page, "%u\n", cfg->c.MaxPower);
+}
+
+static ssize_t gadget_config_desc_MaxPower_store(struct config_usb_cfg *cfg,
+ const char *page, size_t len)
+{
+ u16 val;
+ int ret;
+ ret = kstrtou16(page, 0, &val);
+ if (ret)
+ return ret;
+ if (DIV_ROUND_UP(val, 8) > 0xff)
+ return -ERANGE;
+ cfg->c.MaxPower = val;
+ return len;
+}
+
+static ssize_t gadget_config_desc_bmAttributes_show(struct config_usb_cfg *cfg,
+ char *page)
+{
+ return sprintf(page, "0x%02x\n", cfg->c.bmAttributes);
+}
+
+static ssize_t gadget_config_desc_bmAttributes_store(struct config_usb_cfg *cfg,
+ const char *page, size_t len)
+{
+ u8 val;
+ int ret;
+ ret = kstrtou8(page, 0, &val);
+ if (ret)
+ return ret;
+ if (!(val & USB_CONFIG_ATT_ONE))
+ return -EINVAL;
+ if (val & ~(USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER |
+ USB_CONFIG_ATT_WAKEUP))
+ return -EINVAL;
+ cfg->c.bmAttributes = val;
+ return len;
+}
+
+#define CFG_CONFIG_DESC_ITEM_ATTR(name) \
+ static struct config_usb_cfg_attribute gadget_usb_cfg_##name = \
+ __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \
+ gadget_config_desc_##name##_show, \
+ gadget_config_desc_##name##_store)
+
+CFG_CONFIG_DESC_ITEM_ATTR(MaxPower);
+CFG_CONFIG_DESC_ITEM_ATTR(bmAttributes);
+
+static struct configfs_attribute *gadget_config_attrs[] = {
+ &gadget_usb_cfg_MaxPower.attr,
+ &gadget_usb_cfg_bmAttributes.attr,
+ NULL,
+};
+
+static struct config_item_type gadget_config_type = {
+ .ct_item_ops = &gadget_config_item_ops,
+ .ct_attrs = gadget_config_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type gadget_root_type = {
+ .ct_item_ops = &gadget_root_item_ops,
+ .ct_attrs = gadget_root_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static void composite_init_dev(struct usb_composite_dev *cdev)
+{
+ spin_lock_init(&cdev->lock);
+ INIT_LIST_HEAD(&cdev->configs);
+ INIT_LIST_HEAD(&cdev->gstrings);
+}
+
+static struct config_group *function_make(
+ struct config_group *group,
+ const char *name)
+{
+ struct gadget_info *gi;
+ struct usb_function_instance *fi;
+ char buf[MAX_NAME_LEN];
+ char *func_name;
+ char *instance_name;
+ int ret;
+
+ ret = snprintf(buf, MAX_NAME_LEN, "%s", name);
+ if (ret >= MAX_NAME_LEN)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ func_name = buf;
+ instance_name = strchr(func_name, '.');
+ if (!instance_name) {
+ pr_err("Unable to locate . in FUNC.INSTANCE\n");
+ return ERR_PTR(-EINVAL);
+ }
+ *instance_name = '\0';
+ instance_name++;
+
+ fi = usb_get_function_instance(func_name);
+ if (IS_ERR(fi))
+ return ERR_PTR(PTR_ERR(fi));
+
+ ret = config_item_set_name(&fi->group.cg_item, name);
+ if (ret) {
+ usb_put_function_instance(fi);
+ return ERR_PTR(ret);
+ }
+
+ gi = container_of(group, struct gadget_info, functions_group);
+
+ mutex_lock(&gi->lock);
+ list_add_tail(&fi->cfs_list, &gi->available_func);
+ mutex_unlock(&gi->lock);
+ return &fi->group;
+}
+
+static void function_drop(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct usb_function_instance *fi = to_usb_function_instance(item);
+ struct gadget_info *gi;
+
+ gi = container_of(group, struct gadget_info, functions_group);
+
+ mutex_lock(&gi->lock);
+ list_del(&fi->cfs_list);
+ mutex_unlock(&gi->lock);
+ config_item_put(item);
+}
+
+static struct configfs_group_operations functions_ops = {
+ .make_group = &function_make,
+ .drop_item = &function_drop,
+};
+
+static struct config_item_type functions_type = {
+ .ct_group_ops = &functions_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+CONFIGFS_ATTR_STRUCT(gadget_config_name);
+GS_STRINGS_RW(gadget_config_name, configuration);
+
+static struct configfs_attribute *gadget_config_name_langid_attrs[] = {
+ &gadget_config_name_configuration.attr,
+ NULL,
+};
+
+static void gadget_config_name_attr_release(struct config_item *item)
+{
+ struct gadget_config_name *cn = to_gadget_config_name(item);
+
+ kfree(cn->configuration);
+
+ list_del(&cn->list);
+ kfree(cn);
+}
+
+USB_CONFIG_STRING_RW_OPS(gadget_config_name);
+USB_CONFIG_STRINGS_LANG(gadget_config_name, config_usb_cfg);
+
+static struct config_group *config_desc_make(
+ struct config_group *group,
+ const char *name)
+{
+ struct gadget_info *gi;
+ struct config_usb_cfg *cfg;
+ char buf[MAX_NAME_LEN];
+ char *num_str;
+ u8 num;
+ int ret;
+
+ gi = container_of(group, struct gadget_info, configs_group);
+ ret = snprintf(buf, MAX_NAME_LEN, "%s", name);
+ if (ret >= MAX_NAME_LEN)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ num_str = strchr(buf, '.');
+ if (!num_str) {
+ pr_err("Unable to locate . in name.bConfigurationValue\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ *num_str = '\0';
+ num_str++;
+
+ if (!strlen(buf))
+ return ERR_PTR(-EINVAL);
+
+ ret = kstrtou8(num_str, 0, &num);
+ if (ret)
+ return ERR_PTR(ret);
+
+ cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return ERR_PTR(-ENOMEM);
+ cfg->c.label = kstrdup(buf, GFP_KERNEL);
+ if (!cfg->c.label) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ cfg->c.bConfigurationValue = num;
+ cfg->c.MaxPower = CONFIG_USB_GADGET_VBUS_DRAW;
+ cfg->c.bmAttributes = USB_CONFIG_ATT_ONE;
+ INIT_LIST_HEAD(&cfg->string_list);
+ INIT_LIST_HEAD(&cfg->func_list);
+
+ cfg->group.default_groups = cfg->default_groups;
+ cfg->default_groups[0] = &cfg->strings_group;
+
+ config_group_init_type_name(&cfg->group, name,
+ &gadget_config_type);
+ config_group_init_type_name(&cfg->strings_group, "strings",
+ &gadget_config_name_strings_type);
+
+ ret = usb_add_config_only(&gi->cdev, &cfg->c);
+ if (ret)
+ goto err;
+
+ return &cfg->group;
+err:
+ kfree(cfg->c.label);
+ kfree(cfg);
+ return ERR_PTR(ret);
+}
+
+static void config_desc_drop(
+ struct config_group *group,
+ struct config_item *item)
+{
+ config_item_put(item);
+}
+
+static struct configfs_group_operations config_desc_ops = {
+ .make_group = &config_desc_make,
+ .drop_item = &config_desc_drop,
+};
+
+static struct config_item_type config_desc_type = {
+ .ct_group_ops = &config_desc_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+CONFIGFS_ATTR_STRUCT(gadget_strings);
+GS_STRINGS_RW(gadget_strings, manufacturer);
+GS_STRINGS_RW(gadget_strings, product);
+GS_STRINGS_RW(gadget_strings, serialnumber);
+
+static struct configfs_attribute *gadget_strings_langid_attrs[] = {
+ &gadget_strings_manufacturer.attr,
+ &gadget_strings_product.attr,
+ &gadget_strings_serialnumber.attr,
+ NULL,
+};
+
+static void gadget_strings_attr_release(struct config_item *item)
+{
+ struct gadget_strings *gs = to_gadget_strings(item);
+
+ kfree(gs->manufacturer);
+ kfree(gs->product);
+ kfree(gs->serialnumber);
+
+ list_del(&gs->list);
+ kfree(gs);
+}
+
+USB_CONFIG_STRING_RW_OPS(gadget_strings);
+USB_CONFIG_STRINGS_LANG(gadget_strings, gadget_info);
+
+static int configfs_do_nothing(struct usb_composite_dev *cdev)
+{
+ __WARN();
+ return -EINVAL;
+}
+
+int composite_dev_prepare(struct usb_composite_driver *composite,
+ struct usb_composite_dev *dev);
+
+static void purge_configs_funcs(struct gadget_info *gi)
+{
+ struct usb_configuration *c;
+
+ list_for_each_entry(c, &gi->cdev.configs, list) {
+ struct usb_function *f, *tmp;
+ struct config_usb_cfg *cfg;
+
+ cfg = container_of(c, struct config_usb_cfg, c);
+
+ list_for_each_entry_safe(f, tmp, &c->functions, list) {
+
+ list_move_tail(&f->list, &cfg->func_list);
+ if (f->unbind) {
+ dev_err(&gi->cdev.gadget->dev, "unbind function"
+ " '%s'/%p\n", f->name, f);
+ f->unbind(c, f);
+ }
+ }
+ c->next_interface_id = 0;
+ c->superspeed = 0;
+ c->highspeed = 0;
+ c->fullspeed = 0;
+ }
+}
+
+static int configfs_composite_bind(struct usb_gadget *gadget,
+ struct usb_gadget_driver *gdriver)
+{
+ struct usb_composite_driver *composite = to_cdriver(gdriver);
+ struct gadget_info *gi = container_of(composite,
+ struct gadget_info, composite);
+ struct usb_composite_dev *cdev = &gi->cdev;
+ struct usb_configuration *c;
+ struct usb_string *s;
+ unsigned i;
+ int ret;
+
+ /* the gi->lock is hold by the caller */
+ cdev->gadget = gadget;
+ set_gadget_data(gadget, cdev);
+ ret = composite_dev_prepare(composite, cdev);
+ if (ret)
+ return ret;
+ /* and now the gadget bind */
+ ret = -EINVAL;
+
+ if (list_empty(&gi->cdev.configs)) {
+ pr_err("Need atleast one configuration in %s.\n",
+ gi->composite.name);
+ goto err_comp_cleanup;
+ }
+
+
+ list_for_each_entry(c, &gi->cdev.configs, list) {
+ struct config_usb_cfg *cfg;
+
+ cfg = container_of(c, struct config_usb_cfg, c);
+ if (list_empty(&cfg->func_list)) {
+ pr_err("Config %s/%d of %s needs atleast one function.\n",
+ c->label, c->bConfigurationValue,
+ gi->composite.name);
+ goto err_comp_cleanup;
+ }
+ }
+
+ /* init all strings */
+ if (!list_empty(&gi->string_list)) {
+ struct gadget_strings *gs;
+
+ i = 0;
+ list_for_each_entry(gs, &gi->string_list, list) {
+
+ gi->gstrings[i] = &gs->stringtab_dev;
+ gs->stringtab_dev.strings = gs->strings;
+ gs->strings[USB_GADGET_MANUFACTURER_IDX].s =
+ gs->manufacturer;
+ gs->strings[USB_GADGET_PRODUCT_IDX].s = gs->product;
+ gs->strings[USB_GADGET_SERIAL_IDX].s = gs->serialnumber;
+ i++;
+ }
+ gi->gstrings[i] = NULL;
+ s = usb_gstrings_attach(&gi->cdev, gi->gstrings,
+ USB_GADGET_FIRST_AVAIL_IDX);
+ if (IS_ERR(s))
+ goto err_comp_cleanup;
+
+ gi->cdev.desc.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id;
+ gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id;
+ gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id;
+ }
+
+ /* Go through all configs, attach all functions */
+ list_for_each_entry(c, &gi->cdev.configs, list) {
+ struct config_usb_cfg *cfg;
+ struct usb_function *f;
+ struct usb_function *tmp;
+ struct gadget_config_name *cn;
+
+ cfg = container_of(c, struct config_usb_cfg, c);
+ if (!list_empty(&cfg->string_list)) {
+ i = 0;
+ list_for_each_entry(cn, &cfg->string_list, list) {
+ cfg->gstrings[i] = &cn->stringtab_dev;
+ cn->stringtab_dev.strings = &cn->strings;
+ cn->strings.s = cn->configuration;
+ i++;
+ }
+ cfg->gstrings[i] = NULL;
+ s = usb_gstrings_attach(&gi->cdev, cfg->gstrings, 1);
+ if (IS_ERR(s))
+ goto err_comp_cleanup;
+ c->iConfiguration = s[0].id;
+ }
+
+ list_for_each_entry_safe(f, tmp, &cfg->func_list, list) {
+ list_del(&f->list);
+ ret = usb_add_function(c, f);
+ if (ret)
+ goto err_purge_funcs;
+ }
+ usb_ep_autoconfig_reset(cdev->gadget);
+ }
+ usb_ep_autoconfig_reset(cdev->gadget);
+ return 0;
+
+err_purge_funcs:
+ purge_configs_funcs(gi);
+err_comp_cleanup:
+ composite_dev_cleanup(cdev);
+ return ret;
+}
+
+static void configfs_composite_unbind(struct usb_gadget *gadget)
+{
+ struct usb_composite_dev *cdev;
+ struct gadget_info *gi;
+
+ /* the gi->lock is hold by the caller */
+
+ cdev = get_gadget_data(gadget);
+ gi = container_of(cdev, struct gadget_info, cdev);
+
+ purge_configs_funcs(gi);
+ composite_dev_cleanup(cdev);
+ usb_ep_autoconfig_reset(cdev->gadget);
+ cdev->gadget = NULL;
+ set_gadget_data(gadget, NULL);
+}
+
+static const struct usb_gadget_driver configfs_driver_template = {
+ .bind = configfs_composite_bind,
+ .unbind = configfs_composite_unbind,
+
+ .setup = composite_setup,
+ .disconnect = composite_disconnect,
+
+ .max_speed = USB_SPEED_SUPER,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "configfs-gadget",
+ },
+};
+
+static struct config_group *gadgets_make(
+ struct config_group *group,
+ const char *name)
+{
+ struct gadget_info *gi;
+
+ gi = kzalloc(sizeof(*gi), GFP_KERNEL);
+ if (!gi)
+ return ERR_PTR(-ENOMEM);
+
+ gi->group.default_groups = gi->default_groups;
+ gi->group.default_groups[0] = &gi->functions_group;
+ gi->group.default_groups[1] = &gi->configs_group;
+ gi->group.default_groups[2] = &gi->strings_group;
+
+ config_group_init_type_name(&gi->functions_group, "functions",
+ &functions_type);
+ config_group_init_type_name(&gi->configs_group, "configs",
+ &config_desc_type);
+ config_group_init_type_name(&gi->strings_group, "strings",
+ &gadget_strings_strings_type);
+
+ gi->composite.bind = configfs_do_nothing;
+ gi->composite.unbind = configfs_do_nothing;
+ gi->composite.suspend = NULL;
+ gi->composite.resume = NULL;
+ gi->composite.max_speed = USB_SPEED_SUPER;
+
+ mutex_init(&gi->lock);
+ INIT_LIST_HEAD(&gi->string_list);
+ INIT_LIST_HEAD(&gi->available_func);
+
+ composite_init_dev(&gi->cdev);
+ gi->cdev.desc.bLength = USB_DT_DEVICE_SIZE;
+ gi->cdev.desc.bDescriptorType = USB_DT_DEVICE;
+ gi->cdev.desc.bcdDevice = cpu_to_le16(get_default_bcdDevice());
+
+ gi->composite.gadget_driver = configfs_driver_template;
+
+ gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL);
+ gi->composite.name = gi->composite.gadget_driver.function;
+
+ if (!gi->composite.gadget_driver.function)
+ goto err;
+
+#ifdef CONFIG_USB_OTG
+ gi->otg.bLength = sizeof(struct usb_otg_descriptor);
+ gi->otg.bDescriptorType = USB_DT_OTG;
+ gi->otg.bmAttributes = USB_OTG_SRP | USB_OTG_HNP;
+#endif
+
+ config_group_init_type_name(&gi->group, name,
+ &gadget_root_type);
+ return &gi->group;
+err:
+ kfree(gi);
+ return ERR_PTR(-ENOMEM);
+}
+
+static void gadgets_drop(struct config_group *group, struct config_item *item)
+{
+ config_item_put(item);
+}
+
+static struct configfs_group_operations gadgets_ops = {
+ .make_group = &gadgets_make,
+ .drop_item = &gadgets_drop,
+};
+
+static struct config_item_type gadgets_type = {
+ .ct_group_ops = &gadgets_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct configfs_subsystem gadget_subsys = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = "usb_gadget",
+ .ci_type = &gadgets_type,
+ },
+ },
+ .su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex),
+};
+
+static int __init gadget_cfs_init(void)
+{
+ int ret;
+
+ config_group_init(&gadget_subsys.su_group);
+
+ ret = configfs_register_subsystem(&gadget_subsys);
+ return ret;
+}
+module_init(gadget_cfs_init);
+
+static void __exit gadget_cfs_exit(void)
+{
+ configfs_unregister_subsystem(&gadget_subsys);
+}
+module_exit(gadget_cfs_exit);
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 8cf0c0f6fa1f..a792e322f4f1 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -912,7 +912,6 @@ static int dummy_udc_start(struct usb_gadget *g,
dum->devstatus = 0;
dum->driver = driver;
- dum->gadget.dev.driver = &driver->driver;
dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n",
driver->driver.name);
return 0;
@@ -927,7 +926,6 @@ static int dummy_udc_stop(struct usb_gadget *g,
dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n",
driver->driver.name);
- dum->gadget.dev.driver = NULL;
dum->driver = NULL;
return 0;
@@ -937,11 +935,6 @@ static int dummy_udc_stop(struct usb_gadget *g,
/* The gadget structure is stored inside the hcd structure and will be
* released along with it. */
-static void dummy_gadget_release(struct device *dev)
-{
- return;
-}
-
static void init_dummy_udc_hw(struct dummy *dum)
{
int i;
@@ -984,15 +977,7 @@ static int dummy_udc_probe(struct platform_device *pdev)
dum->gadget.ops = &dummy_ops;
dum->gadget.max_speed = USB_SPEED_SUPER;
- dev_set_name(&dum->gadget.dev, "gadget");
dum->gadget.dev.parent = &pdev->dev;
- dum->gadget.dev.release = dummy_gadget_release;
- rc = device_register(&dum->gadget.dev);
- if (rc < 0) {
- put_device(&dum->gadget.dev);
- return rc;
- }
-
init_dummy_udc_hw(dum);
rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
@@ -1008,7 +993,6 @@ static int dummy_udc_probe(struct platform_device *pdev)
err_dev:
usb_del_gadget_udc(&dum->gadget);
err_udc:
- device_unregister(&dum->gadget.dev);
return rc;
}
@@ -1019,7 +1003,6 @@ static int dummy_udc_remove(struct platform_device *pdev)
usb_del_gadget_udc(&dum->gadget);
platform_set_drvdata(pdev, NULL);
device_remove_file(&dum->gadget.dev, &dev_attr_function);
- device_unregister(&dum->gadget.dev);
return 0;
}
@@ -1923,7 +1906,7 @@ done:
}
/* usb 3.0 root hub device descriptor */
-struct {
+static struct {
struct usb_bos_descriptor bos;
struct usb_ss_cap_descriptor ss_cap;
} __packed usb3_bos_desc = {
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 18c3f423706e..56c8ecae9bc3 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -207,7 +207,7 @@ static struct usb_gadget_strings *dev_strings[] = {
};
static u8 hostaddr[ETH_ALEN];
-
+static struct eth_dev *the_dev;
/*-------------------------------------------------------------------------*/
/*
@@ -224,7 +224,7 @@ static int __init rndis_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- return rndis_bind_config(c, hostaddr);
+ return rndis_bind_config(c, hostaddr, the_dev);
}
static struct usb_configuration rndis_config_driver = {
@@ -257,11 +257,11 @@ static int __init eth_do_config(struct usb_configuration *c)
}
if (use_eem)
- return eem_bind_config(c);
+ return eem_bind_config(c, the_dev);
else if (can_support_ecm(c->cdev->gadget))
- return ecm_bind_config(c, hostaddr);
+ return ecm_bind_config(c, hostaddr, the_dev);
else
- return geth_bind_config(c, hostaddr);
+ return geth_bind_config(c, hostaddr, the_dev);
}
static struct usb_configuration eth_config_driver = {
@@ -279,9 +279,9 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
int status;
/* set up network link layer */
- status = gether_setup(cdev->gadget, hostaddr);
- if (status < 0)
- return status;
+ the_dev = gether_setup(cdev->gadget, hostaddr);
+ if (IS_ERR(the_dev))
+ return PTR_ERR(the_dev);
/* set up main config label and device descriptor */
if (use_eem) {
@@ -338,13 +338,13 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
return 0;
fail:
- gether_cleanup();
+ gether_cleanup(the_dev);
return status;
}
static int __exit eth_unbind(struct usb_composite_dev *cdev)
{
- gether_cleanup();
+ gether_cleanup(the_dev);
return 0;
}
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 1ae180baa597..4b7e33e5d9c6 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -715,13 +715,31 @@ fail:
return status;
}
-static struct f_acm *acm_alloc_basic_func(void)
+static void acm_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_acm *acm = func_to_acm(f);
+
+ acm_string_defs[0].id = 0;
+ usb_free_all_descriptors(f);
+ if (acm->notify_req)
+ gs_free_req(acm->notify, acm->notify_req);
+}
+
+static void acm_free_func(struct usb_function *f)
+{
+ struct f_acm *acm = func_to_acm(f);
+
+ kfree(acm);
+}
+
+static struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
{
- struct f_acm *acm;
+ struct f_serial_opts *opts;
+ struct f_acm *acm;
acm = kzalloc(sizeof(*acm), GFP_KERNEL);
if (!acm)
- return NULL;
+ return ERR_PTR(-ENOMEM);
spin_lock_init(&acm->lock);
@@ -730,109 +748,100 @@ static struct f_acm *acm_alloc_basic_func(void)
acm->port.send_break = acm_send_break;
acm->port.func.name = "acm";
+ acm->port.func.strings = acm_strings;
/* descriptors are per-instance copies */
acm->port.func.bind = acm_bind;
acm->port.func.set_alt = acm_set_alt;
acm->port.func.setup = acm_setup;
acm->port.func.disable = acm_disable;
- return acm;
+ opts = container_of(fi, struct f_serial_opts, func_inst);
+ acm->port_num = opts->port_num;
+ acm->port.func.unbind = acm_unbind;
+ acm->port.func.free_func = acm_free_func;
+
+ return &acm->port.func;
}
-#ifdef USB_FACM_INCLUDED
-static void
-acm_old_unbind(struct usb_configuration *c, struct usb_function *f)
+static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
{
- struct f_acm *acm = func_to_acm(f);
-
- usb_free_all_descriptors(f);
- if (acm->notify_req)
- gs_free_req(acm->notify, acm->notify_req);
- kfree(acm);
+ return container_of(to_config_group(item), struct f_serial_opts,
+ func_inst.group);
}
-/**
- * acm_bind_config - add a CDC ACM function to a configuration
- * @c: the configuration to support the CDC ACM instance
- * @port_num: /dev/ttyGS* port this interface will use
- * Context: single threaded during gadget setup
- *
- * Returns zero on success, else negative errno.
- *
- */
-int acm_bind_config(struct usb_configuration *c, u8 port_num)
+CONFIGFS_ATTR_STRUCT(f_serial_opts);
+static ssize_t f_acm_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
{
- struct f_acm *acm;
- int status;
-
- /* allocate and initialize one new instance */
- acm = acm_alloc_basic_func();
- if (!acm)
- return -ENOMEM;
-
- acm->port_num = port_num;
- acm->port.func.unbind = acm_old_unbind;
-
- status = usb_add_function(c, &acm->port.func);
- if (status)
- kfree(acm);
- return status;
+ struct f_serial_opts *opts = to_f_serial_opts(item);
+ struct f_serial_opts_attribute *f_serial_opts_attr =
+ container_of(attr, struct f_serial_opts_attribute, attr);
+ ssize_t ret = 0;
+
+ if (f_serial_opts_attr->show)
+ ret = f_serial_opts_attr->show(opts, page);
+ return ret;
}
-#else
-
-static void acm_unbind(struct usb_configuration *c, struct usb_function *f)
+static void acm_attr_release(struct config_item *item)
{
- struct f_acm *acm = func_to_acm(f);
+ struct f_serial_opts *opts = to_f_serial_opts(item);
- acm_string_defs[0].id = 0;
- usb_free_all_descriptors(f);
- if (acm->notify_req)
- gs_free_req(acm->notify, acm->notify_req);
+ usb_put_function_instance(&opts->func_inst);
}
-static void acm_free_func(struct usb_function *f)
-{
- struct f_acm *acm = func_to_acm(f);
+static struct configfs_item_operations acm_item_ops = {
+ .release = acm_attr_release,
+ .show_attribute = f_acm_attr_show,
+};
- kfree(acm);
+static ssize_t f_acm_port_num_show(struct f_serial_opts *opts, char *page)
+{
+ return sprintf(page, "%u\n", opts->port_num);
}
-static struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
-{
- struct f_serial_opts *opts;
- struct f_acm *acm;
+static struct f_serial_opts_attribute f_acm_port_num =
+ __CONFIGFS_ATTR_RO(port_num, f_acm_port_num_show);
- acm = acm_alloc_basic_func();
- if (!acm)
- return ERR_PTR(-ENOMEM);
- opts = container_of(fi, struct f_serial_opts, func_inst);
- acm->port_num = opts->port_num;
- acm->port.func.unbind = acm_unbind;
- acm->port.func.free_func = acm_free_func;
+static struct configfs_attribute *acm_attrs[] = {
+ &f_acm_port_num.attr,
+ NULL,
+};
- return &acm->port.func;
-}
+static struct config_item_type acm_func_type = {
+ .ct_item_ops = &acm_item_ops,
+ .ct_attrs = acm_attrs,
+ .ct_owner = THIS_MODULE,
+};
static void acm_free_instance(struct usb_function_instance *fi)
{
struct f_serial_opts *opts;
opts = container_of(fi, struct f_serial_opts, func_inst);
+ gserial_free_line(opts->port_num);
kfree(opts);
}
static struct usb_function_instance *acm_alloc_instance(void)
{
struct f_serial_opts *opts;
+ int ret;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
opts->func_inst.free_func_inst = acm_free_instance;
+ ret = gserial_alloc_line(&opts->port_num);
+ if (ret) {
+ kfree(opts);
+ return ERR_PTR(ret);
+ }
+ config_group_init_type_name(&opts->func_inst.group, "",
+ &acm_func_type);
return &opts->func_inst;
}
DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);
MODULE_LICENSE("GPL");
-#endif
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 83420a310fb7..d893d6929079 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -824,7 +824,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)
* for calling @gether_cleanup() before module unload.
*/
int
-ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev)
{
struct f_ecm *ecm;
int status;
@@ -852,6 +853,7 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr);
ecm_string_defs[1].s = ecm->ethaddr;
+ ecm->port.ioport = dev;
ecm->port.cdc_filter = DEFAULT_FILTER;
ecm->port.func.name = "cdc_ethernet";
diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c
index cf0ebee85563..f4e0bbef602a 100644
--- a/drivers/usb/gadget/f_eem.c
+++ b/drivers/usb/gadget/f_eem.c
@@ -528,7 +528,7 @@ error:
* Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload.
*/
-int __init eem_bind_config(struct usb_configuration *c)
+int __init eem_bind_config(struct usb_configuration *c, struct eth_dev *dev)
{
struct f_eem *eem;
int status;
@@ -549,6 +549,7 @@ int __init eem_bind_config(struct usb_configuration *c)
if (!eem)
return -ENOMEM;
+ eem->port.ioport = dev;
eem->port.cdc_filter = DEFAULT_FILTER;
eem->port.func.name = "cdc_eem";
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index 5e7557e23ecc..ee19bc8d0040 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -1287,7 +1287,8 @@ ncm_unbind(struct usb_configuration *c, struct usb_function *f)
* Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload.
*/
-int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev)
{
struct f_ncm *ncm;
int status;
@@ -1321,6 +1322,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
spin_lock_init(&ncm->lock);
ncm_reset_values(ncm);
+ ncm->port.ioport = dev;
ncm->port.is_fixed = true;
ncm->port.func.name = "cdc_network";
diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c
index 36a004563b82..29a348a2a294 100644
--- a/drivers/usb/gadget/f_obex.c
+++ b/drivers/usb/gadget/f_obex.c
@@ -72,7 +72,7 @@ static struct usb_gadget_strings *obex_strings[] = {
/*-------------------------------------------------------------------------*/
-static struct usb_interface_descriptor obex_control_intf __initdata = {
+static struct usb_interface_descriptor obex_control_intf = {
.bLength = sizeof(obex_control_intf),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
@@ -83,7 +83,7 @@ static struct usb_interface_descriptor obex_control_intf __initdata = {
.bInterfaceSubClass = USB_CDC_SUBCLASS_OBEX,
};
-static struct usb_interface_descriptor obex_data_nop_intf __initdata = {
+static struct usb_interface_descriptor obex_data_nop_intf = {
.bLength = sizeof(obex_data_nop_intf),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 1,
@@ -93,7 +93,7 @@ static struct usb_interface_descriptor obex_data_nop_intf __initdata = {
.bInterfaceClass = USB_CLASS_CDC_DATA,
};
-static struct usb_interface_descriptor obex_data_intf __initdata = {
+static struct usb_interface_descriptor obex_data_intf = {
.bLength = sizeof(obex_data_intf),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 2,
@@ -103,14 +103,14 @@ static struct usb_interface_descriptor obex_data_intf __initdata = {
.bInterfaceClass = USB_CLASS_CDC_DATA,
};
-static struct usb_cdc_header_desc obex_cdc_header_desc __initdata = {
+static struct usb_cdc_header_desc obex_cdc_header_desc = {
.bLength = sizeof(obex_cdc_header_desc),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
.bcdCDC = cpu_to_le16(0x0120),
};
-static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = {
+static struct usb_cdc_union_desc obex_cdc_union_desc = {
.bLength = sizeof(obex_cdc_union_desc),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_UNION_TYPE,
@@ -118,7 +118,7 @@ static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = {
.bSlaveInterface0 = 2,
};
-static struct usb_cdc_obex_desc obex_desc __initdata = {
+static struct usb_cdc_obex_desc obex_desc = {
.bLength = sizeof(obex_desc),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_OBEX_TYPE,
@@ -127,7 +127,7 @@ static struct usb_cdc_obex_desc obex_desc __initdata = {
/* High-Speed Support */
-static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = {
+static struct usb_endpoint_descriptor obex_hs_ep_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -136,7 +136,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = {
+static struct usb_endpoint_descriptor obex_hs_ep_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -145,7 +145,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_descriptor_header *hs_function[] __initdata = {
+static struct usb_descriptor_header *hs_function[] = {
(struct usb_descriptor_header *) &obex_control_intf,
(struct usb_descriptor_header *) &obex_cdc_header_desc,
(struct usb_descriptor_header *) &obex_desc,
@@ -160,7 +160,7 @@ static struct usb_descriptor_header *hs_function[] __initdata = {
/* Full-Speed Support */
-static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = {
+static struct usb_endpoint_descriptor obex_fs_ep_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -168,7 +168,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = {
+static struct usb_endpoint_descriptor obex_fs_ep_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -176,7 +176,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_descriptor_header *fs_function[] __initdata = {
+static struct usb_descriptor_header *fs_function[] = {
(struct usb_descriptor_header *) &obex_control_intf,
(struct usb_descriptor_header *) &obex_cdc_header_desc,
(struct usb_descriptor_header *) &obex_desc,
@@ -290,14 +290,43 @@ static void obex_disconnect(struct gserial *g)
/*-------------------------------------------------------------------------*/
-static int __init
-obex_bind(struct usb_configuration *c, struct usb_function *f)
+/* Some controllers can't support CDC OBEX ... */
+static inline bool can_support_obex(struct usb_configuration *c)
+{
+ /* Since the first interface is a NOP, we can ignore the
+ * issue of multi-interface support on most controllers.
+ *
+ * Altsettings are mandatory, however...
+ */
+ if (!gadget_supports_altsettings(c->cdev->gadget))
+ return false;
+
+ /* everything else is *probably* fine ... */
+ return true;
+}
+
+static int obex_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_obex *obex = func_to_obex(f);
int status;
struct usb_ep *ep;
+ if (!can_support_obex(c))
+ return -EINVAL;
+
+ if (obex_string_defs[OBEX_CTRL_IDX].id == 0) {
+ status = usb_string_ids_tab(c->cdev, obex_string_defs);
+ if (status < 0)
+ return status;
+ obex_control_intf.iInterface =
+ obex_string_defs[OBEX_CTRL_IDX].id;
+
+ status = obex_string_defs[OBEX_DATA_IDX].id;
+ obex_data_nop_intf.iInterface = status;
+ obex_data_intf.iInterface = status;
+ }
+
/* allocate instance-specific interface IDs, and patch descriptors */
status = usb_interface_id(c, f);
@@ -376,29 +405,16 @@ fail:
return status;
}
+#ifdef USBF_OBEX_INCLUDED
+
static void
-obex_unbind(struct usb_configuration *c, struct usb_function *f)
+obex_old_unbind(struct usb_configuration *c, struct usb_function *f)
{
obex_string_defs[OBEX_CTRL_IDX].id = 0;
usb_free_all_descriptors(f);
kfree(func_to_obex(f));
}
-/* Some controllers can't support CDC OBEX ... */
-static inline bool can_support_obex(struct usb_configuration *c)
-{
- /* Since the first interface is a NOP, we can ignore the
- * issue of multi-interface support on most controllers.
- *
- * Altsettings are mandatory, however...
- */
- if (!gadget_supports_altsettings(c->cdev->gadget))
- return false;
-
- /* everything else is *probably* fine ... */
- return true;
-}
-
/**
* obex_bind_config - add a CDC OBEX function to a configuration
* @c: the configuration to support the CDC OBEX instance
@@ -412,21 +428,6 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
struct f_obex *obex;
int status;
- if (!can_support_obex(c))
- return -EINVAL;
-
- if (obex_string_defs[OBEX_CTRL_IDX].id == 0) {
- status = usb_string_ids_tab(c->cdev, obex_string_defs);
- if (status < 0)
- return status;
- obex_control_intf.iInterface =
- obex_string_defs[OBEX_CTRL_IDX].id;
-
- status = obex_string_defs[OBEX_DATA_IDX].id;
- obex_data_nop_intf.iInterface = status;
- obex_data_intf.iInterface = status;
- }
-
/* allocate and initialize one new instance */
obex = kzalloc(sizeof *obex, GFP_KERNEL);
if (!obex)
@@ -441,7 +442,7 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
obex->port.func.strings = obex_strings;
/* descriptors are per-instance copies */
obex->port.func.bind = obex_bind;
- obex->port.func.unbind = obex_unbind;
+ obex->port.func.unbind = obex_old_unbind;
obex->port.func.set_alt = obex_set_alt;
obex->port.func.get_alt = obex_get_alt;
obex->port.func.disable = obex_disable;
@@ -453,5 +454,138 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
return status;
}
+#else
+
+static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct f_serial_opts,
+ func_inst.group);
+}
+
+CONFIGFS_ATTR_STRUCT(f_serial_opts);
+static ssize_t f_obex_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
+{
+ struct f_serial_opts *opts = to_f_serial_opts(item);
+ struct f_serial_opts_attribute *f_serial_opts_attr =
+ container_of(attr, struct f_serial_opts_attribute, attr);
+ ssize_t ret = 0;
+
+ if (f_serial_opts_attr->show)
+ ret = f_serial_opts_attr->show(opts, page);
+
+ return ret;
+}
+
+static void obex_attr_release(struct config_item *item)
+{
+ struct f_serial_opts *opts = to_f_serial_opts(item);
+
+ usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations obex_item_ops = {
+ .release = obex_attr_release,
+ .show_attribute = f_obex_attr_show,
+};
+
+static ssize_t f_obex_port_num_show(struct f_serial_opts *opts, char *page)
+{
+ return sprintf(page, "%u\n", opts->port_num);
+}
+
+static struct f_serial_opts_attribute f_obex_port_num =
+ __CONFIGFS_ATTR_RO(port_num, f_obex_port_num_show);
+
+static struct configfs_attribute *acm_attrs[] = {
+ &f_obex_port_num.attr,
+ NULL,
+};
+
+static struct config_item_type obex_func_type = {
+ .ct_item_ops = &obex_item_ops,
+ .ct_attrs = acm_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static void obex_free_inst(struct usb_function_instance *f)
+{
+ struct f_serial_opts *opts;
+
+ opts = container_of(f, struct f_serial_opts, func_inst);
+ gserial_free_line(opts->port_num);
+ kfree(opts);
+}
+
+static struct usb_function_instance *obex_alloc_inst(void)
+{
+ struct f_serial_opts *opts;
+ int ret;
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return ERR_PTR(-ENOMEM);
+
+ opts->func_inst.free_func_inst = obex_free_inst;
+ ret = gserial_alloc_line(&opts->port_num);
+ if (ret) {
+ kfree(opts);
+ return ERR_PTR(ret);
+ }
+ config_group_init_type_name(&opts->func_inst.group, "",
+ &obex_func_type);
+
+ return &opts->func_inst;
+}
+
+static void obex_free(struct usb_function *f)
+{
+ struct f_obex *obex;
+
+ obex = func_to_obex(f);
+ kfree(obex);
+}
+
+static void obex_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ obex_string_defs[OBEX_CTRL_IDX].id = 0;
+ usb_free_all_descriptors(f);
+}
+
+struct usb_function *obex_alloc(struct usb_function_instance *fi)
+{
+ struct f_obex *obex;
+ struct f_serial_opts *opts;
+
+ /* allocate and initialize one new instance */
+ obex = kzalloc(sizeof(*obex), GFP_KERNEL);
+ if (!obex)
+ return ERR_PTR(-ENOMEM);
+
+ opts = container_of(fi, struct f_serial_opts, func_inst);
+
+ obex->port_num = opts->port_num;
+
+ obex->port.connect = obex_connect;
+ obex->port.disconnect = obex_disconnect;
+
+ obex->port.func.name = "obex";
+ obex->port.func.strings = obex_strings;
+ /* descriptors are per-instance copies */
+ obex->port.func.bind = obex_bind;
+ obex->port.func.unbind = obex_unbind;
+ obex->port.func.set_alt = obex_set_alt;
+ obex->port.func.get_alt = obex_get_alt;
+ obex->port.func.disable = obex_disable;
+ obex->port.func.free_func = obex_free;
+
+ return &obex->port.func;
+}
+
+DECLARE_USB_FUNCTION_INIT(obex, obex_alloc_inst, obex_alloc);
+
+#endif
+
MODULE_AUTHOR("Felipe Balbi");
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index cc9c49c57c80..36e8c44d8e5e 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -813,7 +813,7 @@ static inline bool can_support_rndis(struct usb_configuration *c)
int
rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
- u32 vendorID, const char *manufacturer)
+ u32 vendorID, const char *manufacturer, struct eth_dev *dev)
{
struct f_rndis *rndis;
int status;
@@ -846,6 +846,7 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
rndis->vendorID = vendorID;
rndis->manufacturer = manufacturer;
+ rndis->port.ioport = dev;
/* RNDIS activates when the host changes this filter */
rndis->port.cdc_filter = 0;
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index da33cfb3031d..981113c9924d 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/device.h>
#include "u_serial.h"
@@ -42,7 +43,7 @@ static inline struct f_gser *func_to_gser(struct usb_function *f)
/* interface descriptor: */
-static struct usb_interface_descriptor gser_interface_desc __initdata = {
+static struct usb_interface_descriptor gser_interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
/* .bInterfaceNumber = DYNAMIC */
@@ -55,21 +56,21 @@ static struct usb_interface_descriptor gser_interface_desc __initdata = {
/* full speed support: */
-static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = {
+static struct usb_endpoint_descriptor gser_fs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_endpoint_descriptor gser_fs_out_desc __initdata = {
+static struct usb_endpoint_descriptor gser_fs_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_descriptor_header *gser_fs_function[] __initdata = {
+static struct usb_descriptor_header *gser_fs_function[] = {
(struct usb_descriptor_header *) &gser_interface_desc,
(struct usb_descriptor_header *) &gser_fs_in_desc,
(struct usb_descriptor_header *) &gser_fs_out_desc,
@@ -78,47 +79,47 @@ static struct usb_descriptor_header *gser_fs_function[] __initdata = {
/* high speed support: */
-static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = {
+static struct usb_endpoint_descriptor gser_hs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = {
+static struct usb_endpoint_descriptor gser_hs_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_descriptor_header *gser_hs_function[] __initdata = {
+static struct usb_descriptor_header *gser_hs_function[] = {
(struct usb_descriptor_header *) &gser_interface_desc,
(struct usb_descriptor_header *) &gser_hs_in_desc,
(struct usb_descriptor_header *) &gser_hs_out_desc,
NULL,
};
-static struct usb_endpoint_descriptor gser_ss_in_desc __initdata = {
+static struct usb_endpoint_descriptor gser_ss_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
-static struct usb_endpoint_descriptor gser_ss_out_desc __initdata = {
+static struct usb_endpoint_descriptor gser_ss_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
-static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc __initdata = {
+static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc = {
.bLength = sizeof gser_ss_bulk_comp_desc,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
};
-static struct usb_descriptor_header *gser_ss_function[] __initdata = {
+static struct usb_descriptor_header *gser_ss_function[] = {
(struct usb_descriptor_header *) &gser_interface_desc,
(struct usb_descriptor_header *) &gser_ss_in_desc,
(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
@@ -183,14 +184,25 @@ static void gser_disable(struct usb_function *f)
/* serial function driver setup/binding */
-static int __init
-gser_bind(struct usb_configuration *c, struct usb_function *f)
+static int gser_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_gser *gser = func_to_gser(f);
int status;
struct usb_ep *ep;
+ /* REVISIT might want instance-specific strings to help
+ * distinguish instances ...
+ */
+
+ /* maybe allocate device-global string ID */
+ if (gser_string_defs[0].id == 0) {
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ gser_string_defs[0].id = status;
+ }
+
/* allocate instance-specific interface IDs */
status = usb_interface_id(c, f);
if (status < 0)
@@ -246,44 +258,115 @@ fail:
return status;
}
-static void
-gser_unbind(struct usb_configuration *c, struct usb_function *f)
+static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
{
- usb_free_all_descriptors(f);
- kfree(func_to_gser(f));
+ return container_of(to_config_group(item), struct f_serial_opts,
+ func_inst.group);
}
-/**
- * gser_bind_config - add a generic serial function to a configuration
- * @c: the configuration to support the serial instance
- * @port_num: /dev/ttyGS* port this interface will use
- * Context: single threaded during gadget setup
- *
- * Returns zero on success, else negative errno.
- */
-int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
+CONFIGFS_ATTR_STRUCT(f_serial_opts);
+static ssize_t f_serial_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
{
- struct f_gser *gser;
- int status;
+ struct f_serial_opts *opts = to_f_serial_opts(item);
+ struct f_serial_opts_attribute *f_serial_opts_attr =
+ container_of(attr, struct f_serial_opts_attribute, attr);
+ ssize_t ret = 0;
- /* REVISIT might want instance-specific strings to help
- * distinguish instances ...
- */
+ if (f_serial_opts_attr->show)
+ ret = f_serial_opts_attr->show(opts, page);
- /* maybe allocate device-global string ID */
- if (gser_string_defs[0].id == 0) {
- status = usb_string_id(c->cdev);
- if (status < 0)
- return status;
- gser_string_defs[0].id = status;
+ return ret;
+}
+
+static void serial_attr_release(struct config_item *item)
+{
+ struct f_serial_opts *opts = to_f_serial_opts(item);
+
+ usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations serial_item_ops = {
+ .release = serial_attr_release,
+ .show_attribute = f_serial_attr_show,
+};
+
+static ssize_t f_serial_port_num_show(struct f_serial_opts *opts, char *page)
+{
+ return sprintf(page, "%u\n", opts->port_num);
+}
+
+static struct f_serial_opts_attribute f_serial_port_num =
+ __CONFIGFS_ATTR_RO(port_num, f_serial_port_num_show);
+
+static struct configfs_attribute *acm_attrs[] = {
+ &f_serial_port_num.attr,
+ NULL,
+};
+
+static struct config_item_type serial_func_type = {
+ .ct_item_ops = &serial_item_ops,
+ .ct_attrs = acm_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static void gser_free_inst(struct usb_function_instance *f)
+{
+ struct f_serial_opts *opts;
+
+ opts = container_of(f, struct f_serial_opts, func_inst);
+ gserial_free_line(opts->port_num);
+ kfree(opts);
+}
+
+static struct usb_function_instance *gser_alloc_inst(void)
+{
+ struct f_serial_opts *opts;
+ int ret;
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return ERR_PTR(-ENOMEM);
+
+ opts->func_inst.free_func_inst = gser_free_inst;
+ ret = gserial_alloc_line(&opts->port_num);
+ if (ret) {
+ kfree(opts);
+ return ERR_PTR(ret);
}
+ config_group_init_type_name(&opts->func_inst.group, "",
+ &serial_func_type);
+
+ return &opts->func_inst;
+}
+
+static void gser_free(struct usb_function *f)
+{
+ struct f_gser *serial;
+
+ serial = func_to_gser(f);
+ kfree(serial);
+}
+
+static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ usb_free_all_descriptors(f);
+}
+
+struct usb_function *gser_alloc(struct usb_function_instance *fi)
+{
+ struct f_gser *gser;
+ struct f_serial_opts *opts;
/* allocate and initialize one new instance */
- gser = kzalloc(sizeof *gser, GFP_KERNEL);
+ gser = kzalloc(sizeof(*gser), GFP_KERNEL);
if (!gser)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
- gser->port_num = port_num;
+ opts = container_of(fi, struct f_serial_opts, func_inst);
+
+ gser->port_num = opts->port_num;
gser->port.func.name = "gser";
gser->port.func.strings = gser_strings;
@@ -291,9 +374,12 @@ int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
gser->port.func.unbind = gser_unbind;
gser->port.func.set_alt = gser_set_alt;
gser->port.func.disable = gser_disable;
+ gser->port.func.free_func = gser_free;
- status = usb_add_function(c, &gser->port.func);
- if (status)
- kfree(gser);
- return status;
+ return &gser->port.func;
}
+
+DECLARE_USB_FUNCTION_INIT(gser, gser_alloc_inst, gser_alloc);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Al Borchers");
+MODULE_AUTHOR("David Brownell");
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index f172bd152fbb..185d6f5e4e4d 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -380,7 +380,8 @@ geth_unbind(struct usb_configuration *c, struct usb_function *f)
* Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload.
*/
-int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev)
{
struct f_gether *geth;
int status;
@@ -406,6 +407,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr);
geth_string_defs[1].s = geth->ethaddr;
+ geth->port.ioport = dev;
geth->port.cdc_filter = DEFAULT_FILTER;
geth->port.func.name = "cdc_subset";
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c
index 92efd6ec48af..38dcedddc52c 100644
--- a/drivers/usb/gadget/f_uvc.c
+++ b/drivers/usb/gadget/f_uvc.c
@@ -33,19 +33,15 @@ unsigned int uvc_gadget_trace_param;
/*-------------------------------------------------------------------------*/
/* module parameters specific to the Video streaming endpoint */
-static unsigned streaming_interval = 1;
+static unsigned int streaming_interval = 1;
module_param(streaming_interval, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(streaming_interval, "1 - 16");
-static unsigned streaming_maxpacket = 1024;
+static unsigned int streaming_maxpacket = 1024;
module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(streaming_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
+MODULE_PARM_DESC(streaming_maxpacket, "1 - 1023 (FS), 1 - 3072 (hs/ss)");
-static unsigned streaming_mult;
-module_param(streaming_mult, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(streaming_mult, "0 - 2 (hs/ss only)");
-
-static unsigned streaming_maxburst;
+static unsigned int streaming_maxburst;
module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
@@ -55,13 +51,11 @@ MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
/* string IDs are assigned dynamically */
-#define UVC_STRING_ASSOCIATION_IDX 0
-#define UVC_STRING_CONTROL_IDX 1
-#define UVC_STRING_STREAMING_IDX 2
+#define UVC_STRING_CONTROL_IDX 0
+#define UVC_STRING_STREAMING_IDX 1
static struct usb_string uvc_en_us_strings[] = {
- [UVC_STRING_ASSOCIATION_IDX].s = "UVC Camera",
- [UVC_STRING_CONTROL_IDX].s = "Video Control",
+ [UVC_STRING_CONTROL_IDX].s = "UVC Camera",
[UVC_STRING_STREAMING_IDX].s = "Video Streaming",
{ }
};
@@ -79,7 +73,7 @@ static struct usb_gadget_strings *uvc_function_strings[] = {
#define UVC_INTF_VIDEO_CONTROL 0
#define UVC_INTF_VIDEO_STREAMING 1
-#define STATUS_BYTECOUNT 16 /* 16 bytes status */
+#define UVC_STATUS_MAX_PACKET_SIZE 16 /* 16 bytes status */
static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
.bLength = sizeof(uvc_iad),
@@ -104,20 +98,29 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = {
.iInterface = 0,
};
-static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = {
+static struct usb_endpoint_descriptor uvc_control_ep __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
+ .wMaxPacketSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
.bInterval = 8,
};
+static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = {
+ .bLength = sizeof(uvc_ss_control_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ /* The following 3 values can be tweaked if necessary. */
+ .bMaxBurst = 0,
+ .bmAttributes = 0,
+ .wBytesPerInterval = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
+};
+
static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = {
.bLength = UVC_DT_CONTROL_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_CS_ENDPOINT,
.bDescriptorSubType = UVC_EP_INTERRUPT,
- .wMaxTransferSize = cpu_to_le16(STATUS_BYTECOUNT),
+ .wMaxTransferSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
};
static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = {
@@ -144,63 +147,53 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = {
.iInterface = 0,
};
-static struct usb_endpoint_descriptor uvc_fs_streaming_ep = {
+static struct usb_endpoint_descriptor uvc_fs_streaming_ep __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = cpu_to_le16(512),
- .bInterval = 1,
+ .bmAttributes = USB_ENDPOINT_SYNC_ASYNC
+ | USB_ENDPOINT_XFER_ISOC,
+ /* The wMaxPacketSize and bInterval values will be initialized from
+ * module parameters.
+ */
+ .wMaxPacketSize = 0,
+ .bInterval = 0,
};
-static struct usb_endpoint_descriptor uvc_hs_streaming_ep = {
+static struct usb_endpoint_descriptor uvc_hs_streaming_ep __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = cpu_to_le16(1024),
- .bInterval = 1,
-};
-
-/* super speed support */
-static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
- .bInterval = 8,
-};
-
-static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = {
- .bLength = sizeof uvc_ss_control_comp,
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-
- /* the following 3 values can be tweaked if necessary */
- /* .bMaxBurst = 0, */
- /* .bmAttributes = 0, */
- .wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT),
+ .bmAttributes = USB_ENDPOINT_SYNC_ASYNC
+ | USB_ENDPOINT_XFER_ISOC,
+ /* The wMaxPacketSize and bInterval values will be initialized from
+ * module parameters.
+ */
+ .wMaxPacketSize = 0,
+ .bInterval = 0,
};
static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = cpu_to_le16(1024),
- .bInterval = 4,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_SYNC_ASYNC
+ | USB_ENDPOINT_XFER_ISOC,
+ /* The wMaxPacketSize and bInterval values will be initialized from
+ * module parameters.
+ */
+ .wMaxPacketSize = 0,
+ .bInterval = 0,
};
-static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = {
- .bLength = sizeof uvc_ss_streaming_comp,
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-
- /* the following 3 values can be tweaked if necessary */
- .bMaxBurst = 0,
- .bmAttributes = 0,
- .wBytesPerInterval = cpu_to_le16(1024),
+static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp __initdata = {
+ .bLength = sizeof(uvc_ss_streaming_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ /* The following 3 values can be tweaked if necessary. */
+ .bMaxBurst = 0,
+ .bmAttributes = 0,
+ .wBytesPerInterval = cpu_to_le16(1024),
};
static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
@@ -273,6 +266,13 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
return 0;
}
+void uvc_function_setup_continue(struct uvc_device *uvc)
+{
+ struct usb_composite_dev *cdev = uvc->func.config->cdev;
+
+ usb_composite_setup_continue(cdev);
+}
+
static int
uvc_function_get_alt(struct usb_function *f, unsigned interface)
{
@@ -335,7 +335,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
v4l2_event_queue(uvc->vdev, &v4l2_event);
uvc->state = UVC_STATE_CONNECTED;
- break;
+ return 0;
case 1:
if (uvc->state != UVC_STATE_CONNECTED)
@@ -352,15 +352,11 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMON;
v4l2_event_queue(uvc->vdev, &v4l2_event);
-
- uvc->state = UVC_STATE_STREAMING;
- break;
+ return USB_GADGET_DELAYED_STATUS;
default:
return -EINVAL;
}
-
- return 0;
}
static void
@@ -454,7 +450,6 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
const struct uvc_descriptor_header * const *uvc_streaming_cls;
const struct usb_descriptor_header * const *uvc_streaming_std;
const struct usb_descriptor_header * const *src;
- static struct usb_endpoint_descriptor *uvc_control_ep;
struct usb_descriptor_header **dst;
struct usb_descriptor_header **hdr;
unsigned int control_size;
@@ -468,14 +463,12 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
uvc_control_desc = uvc->desc.ss_control;
uvc_streaming_cls = uvc->desc.ss_streaming;
uvc_streaming_std = uvc_ss_streaming;
- uvc_control_ep = &uvc_ss_control_ep;
break;
case USB_SPEED_HIGH:
uvc_control_desc = uvc->desc.fs_control;
uvc_streaming_cls = uvc->desc.hs_streaming;
uvc_streaming_std = uvc_hs_streaming;
- uvc_control_ep = &uvc_fs_control_ep;
break;
case USB_SPEED_FULL:
@@ -483,7 +476,6 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
uvc_control_desc = uvc->desc.fs_control;
uvc_streaming_cls = uvc->desc.fs_streaming;
uvc_streaming_std = uvc_fs_streaming;
- uvc_control_ep = &uvc_fs_control_ep;
break;
}
@@ -494,6 +486,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
* Class-specific UVC control descriptors
* uvc_control_ep
* uvc_control_cs_ep
+ * uvc_ss_control_comp (for SS only)
* uvc_streaming_intf_alt0
* Class-specific UVC streaming descriptors
* uvc_{fs|hs}_streaming
@@ -503,7 +496,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
control_size = 0;
streaming_size = 0;
bytes = uvc_iad.bLength + uvc_control_intf.bLength
- + uvc_control_ep->bLength + uvc_control_cs_ep.bLength
+ + uvc_control_ep.bLength + uvc_control_cs_ep.bLength
+ uvc_streaming_intf_alt0.bLength;
if (speed == USB_SPEED_SUPER) {
@@ -514,13 +507,13 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
}
for (src = (const struct usb_descriptor_header **)uvc_control_desc;
- *src; ++src) {
+ *src; ++src) {
control_size += (*src)->bLength;
bytes += (*src)->bLength;
n_desc++;
}
for (src = (const struct usb_descriptor_header **)uvc_streaming_cls;
- *src; ++src) {
+ *src; ++src) {
streaming_size += (*src)->bLength;
bytes += (*src)->bLength;
n_desc++;
@@ -549,7 +542,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
uvc_control_header->bInCollection = 1;
uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
- UVC_COPY_DESCRIPTOR(mem, dst, uvc_control_ep);
+ UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
if (speed == USB_SPEED_SUPER)
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp);
@@ -560,8 +553,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
UVC_COPY_DESCRIPTORS(mem, dst,
(const struct usb_descriptor_header**)uvc_streaming_cls);
uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
- uvc_streaming_header->bEndpointAddress =
- uvc_fs_streaming_ep.bEndpointAddress;
+ uvc_streaming_header->bEndpointAddress = uvc->video.ep->address;
UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
@@ -581,7 +573,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
uvc->control_ep->driver_data = NULL;
uvc->video.ep->driver_data = NULL;
- uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = 0;
+ uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = 0;
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
kfree(uvc->control_buf);
@@ -595,31 +587,52 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct uvc_device *uvc = to_uvc(f);
+ unsigned int max_packet_mult;
+ unsigned int max_packet_size;
struct usb_ep *ep;
int ret = -EINVAL;
INFO(cdev, "uvc_function_bind\n");
- /* sanity check the streaming endpoint module parameters */
- if (streaming_interval < 1)
- streaming_interval = 1;
- if (streaming_interval > 16)
- streaming_interval = 16;
- if (streaming_mult > 2)
- streaming_mult = 2;
- if (streaming_maxburst > 15)
- streaming_maxburst = 15;
-
- /*
- * fill in the FS video streaming specific descriptors from the
- * module parameters
+ /* Sanity check the streaming endpoint module parameters.
*/
- uvc_fs_streaming_ep.wMaxPacketSize = streaming_maxpacket > 1023 ?
- 1023 : streaming_maxpacket;
+ streaming_interval = clamp(streaming_interval, 1U, 16U);
+ streaming_maxpacket = clamp(streaming_maxpacket, 1U, 3072U);
+ streaming_maxburst = min(streaming_maxburst, 15U);
+
+ /* Fill in the FS/HS/SS Video Streaming specific descriptors from the
+ * module parameters.
+ *
+ * NOTE: We assume that the user knows what they are doing and won't
+ * give parameters that their UDC doesn't support.
+ */
+ if (streaming_maxpacket <= 1024) {
+ max_packet_mult = 1;
+ max_packet_size = streaming_maxpacket;
+ } else if (streaming_maxpacket <= 2048) {
+ max_packet_mult = 2;
+ max_packet_size = streaming_maxpacket / 2;
+ } else {
+ max_packet_mult = 3;
+ max_packet_size = streaming_maxpacket / 3;
+ }
+
+ uvc_fs_streaming_ep.wMaxPacketSize = min(streaming_maxpacket, 1023U);
uvc_fs_streaming_ep.bInterval = streaming_interval;
+ uvc_hs_streaming_ep.wMaxPacketSize = max_packet_size;
+ uvc_hs_streaming_ep.wMaxPacketSize |= ((max_packet_mult - 1) << 11);
+ uvc_hs_streaming_ep.bInterval = streaming_interval;
+
+ uvc_ss_streaming_ep.wMaxPacketSize = max_packet_size;
+ uvc_ss_streaming_ep.bInterval = streaming_interval;
+ uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1;
+ uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
+ uvc_ss_streaming_comp.wBytesPerInterval =
+ max_packet_size * max_packet_mult * streaming_maxburst;
+
/* Allocate endpoints. */
- ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_control_ep);
+ ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
if (!ep) {
INFO(cdev, "Unable to allocate control EP\n");
goto error;
@@ -627,7 +640,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc->control_ep = ep;
ep->driver_data = uvc;
- ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
+ if (gadget_is_superspeed(c->cdev->gadget))
+ ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
+ &uvc_ss_streaming_comp);
+ else if (gadget_is_dualspeed(cdev->gadget))
+ ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep);
+ else
+ ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
+
if (!ep) {
INFO(cdev, "Unable to allocate streaming EP\n");
goto error;
@@ -635,6 +655,10 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc->video.ep = ep;
ep->driver_data = uvc;
+ uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
+ uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
+ uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
+
/* Allocate interface IDs. */
if ((ret = usb_interface_id(c, f)) < 0)
goto error;
@@ -648,37 +672,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc_streaming_intf_alt1.bInterfaceNumber = ret;
uvc->streaming_intf = ret;
- /* sanity check the streaming endpoint module parameters */
- if (streaming_maxpacket > 1024)
- streaming_maxpacket = 1024;
- /*
- * Fill in the HS descriptors from the module parameters for the Video
- * Streaming endpoint.
- * NOTE: We assume that the user knows what they are doing and won't
- * give parameters that their UDC doesn't support.
- */
- uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket;
- uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11;
- uvc_hs_streaming_ep.bInterval = streaming_interval;
- uvc_hs_streaming_ep.bEndpointAddress =
- uvc_fs_streaming_ep.bEndpointAddress;
-
- /*
- * Fill in the SS descriptors from the module parameters for the Video
- * Streaming endpoint.
- * NOTE: We assume that the user knows what they are doing and won't
- * give parameters that their UDC doesn't support.
- */
- uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket;
- uvc_ss_streaming_ep.bInterval = streaming_interval;
- uvc_ss_streaming_comp.bmAttributes = streaming_mult;
- uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
- uvc_ss_streaming_comp.wBytesPerInterval =
- streaming_maxpacket * (streaming_mult + 1) *
- (streaming_maxburst + 1);
- uvc_ss_streaming_ep.bEndpointAddress =
- uvc_fs_streaming_ep.bEndpointAddress;
-
/* Copy descriptors */
f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
if (gadget_is_dualspeed(cdev->gadget))
@@ -775,23 +768,23 @@ uvc_bind_config(struct usb_configuration *c,
/* Validate the descriptors. */
if (fs_control == NULL || fs_control[0] == NULL ||
- fs_control[0]->bDescriptorSubType != UVC_VC_HEADER)
+ fs_control[0]->bDescriptorSubType != UVC_VC_HEADER)
goto error;
if (ss_control == NULL || ss_control[0] == NULL ||
- ss_control[0]->bDescriptorSubType != UVC_VC_HEADER)
+ ss_control[0]->bDescriptorSubType != UVC_VC_HEADER)
goto error;
if (fs_streaming == NULL || fs_streaming[0] == NULL ||
- fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
+ fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
goto error;
if (hs_streaming == NULL || hs_streaming[0] == NULL ||
- hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
+ hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
goto error;
if (ss_streaming == NULL || ss_streaming[0] == NULL ||
- ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
+ ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
goto error;
uvc->desc.fs_control = fs_control;
@@ -800,13 +793,16 @@ uvc_bind_config(struct usb_configuration *c,
uvc->desc.hs_streaming = hs_streaming;
uvc->desc.ss_streaming = ss_streaming;
- /* Allocate string descriptor numbers. */
- if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) {
+ /* String descriptors are global, we only need to allocate string IDs
+ * for the first UVC function. UVC functions beyond the first (if any)
+ * will reuse the same IDs.
+ */
+ if (uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id == 0) {
ret = usb_string_ids_tab(c->cdev, uvc_en_us_strings);
if (ret)
goto error;
uvc_iad.iFunction =
- uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id;
+ uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id;
uvc_control_intf.iInterface =
uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id;
ret = uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id;
diff --git a/drivers/usb/gadget/f_uvc.h b/drivers/usb/gadget/f_uvc.h
index c3d258d30188..ec52752f7326 100644
--- a/drivers/usb/gadget/f_uvc.h
+++ b/drivers/usb/gadget/f_uvc.h
@@ -16,12 +16,12 @@
#include <linux/usb/composite.h>
#include <linux/usb/video.h>
-extern int uvc_bind_config(struct usb_configuration *c,
- const struct uvc_descriptor_header * const *fs_control,
- const struct uvc_descriptor_header * const *hs_control,
- const struct uvc_descriptor_header * const *fs_streaming,
- const struct uvc_descriptor_header * const *hs_streaming,
- const struct uvc_descriptor_header * const *ss_streaming);
+int uvc_bind_config(struct usb_configuration *c,
+ const struct uvc_descriptor_header * const *fs_control,
+ const struct uvc_descriptor_header * const *hs_control,
+ const struct uvc_descriptor_header * const *fs_streaming,
+ const struct uvc_descriptor_header * const *hs_streaming,
+ const struct uvc_descriptor_header * const *ss_streaming);
#endif /* _F_UVC_H_ */
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index 034477ce77c6..9a7ee3347e4d 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -2296,7 +2296,6 @@ static int fsl_qe_start(struct usb_gadget *gadget,
driver->driver.bus = NULL;
/* hook up the driver */
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
udc->gadget.speed = driver->max_speed;
/* Enable IRQ reg and Set usbcmd reg EN bit */
@@ -2338,7 +2337,6 @@ static int fsl_qe_stop(struct usb_gadget *gadget,
nuke(loop_ep, -ESHUTDOWN);
spin_unlock_irqrestore(&udc->lock, flags);
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
dev_info(udc->dev, "unregistered gadget driver '%s'\r\n",
@@ -2523,12 +2521,6 @@ static int qe_udc_probe(struct platform_device *ofdev)
/* name: Identifies the controller hardware type. */
udc->gadget.name = driver_name;
-
- device_initialize(&udc->gadget.dev);
-
- dev_set_name(&udc->gadget.dev, "gadget");
-
- udc->gadget.dev.release = qe_udc_release;
udc->gadget.dev.parent = &ofdev->dev;
/* initialize qe_ep struct */
@@ -2592,22 +2584,17 @@ static int qe_udc_probe(struct platform_device *ofdev)
goto err5;
}
- ret = device_add(&udc->gadget.dev);
+ ret = usb_add_gadget_udc_release(&ofdev->dev, &udc->gadget,
+ qe_udc_release);
if (ret)
goto err6;
- ret = usb_add_gadget_udc(&ofdev->dev, &udc->gadget);
- if (ret)
- goto err7;
-
dev_set_drvdata(&ofdev->dev, udc);
dev_info(udc->dev,
"%s USB controller initialized as device\n",
(udc->soc_type == PORT_QE) ? "QE" : "CPM");
return 0;
-err7:
- device_unregister(&udc->gadget.dev);
err6:
free_irq(udc->usb_irq, udc);
err5:
@@ -2702,7 +2689,6 @@ static int qe_udc_remove(struct platform_device *ofdev)
iounmap(udc->usb_regs);
- device_unregister(&udc->gadget.dev);
/* wait for release() of gadget.dev to free udc */
wait_for_completion(&done);
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 04d5fef1440c..7c2a101d19ac 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -185,20 +185,7 @@ static void done(struct fsl_ep *ep, struct fsl_req *req, int status)
dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
}
- if (req->mapped) {
- dma_unmap_single(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ep_is_in(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- } else
- dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ep_is_in(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
+ usb_gadget_unmap_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
if (status && (status != -ESHUTDOWN))
VDBG("complete %s req %p stat %d len %u/%u",
@@ -888,6 +875,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
struct fsl_req *req = container_of(_req, struct fsl_req, req);
struct fsl_udc *udc;
unsigned long flags;
+ int ret;
/* catch various bogus parameters */
if (!_req || !req->req.complete || !req->req.buf
@@ -910,22 +898,9 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req->ep = ep;
- /* map virtual address to hardware */
- if (req->req.dma == DMA_ADDR_INVALID) {
- req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
- req->req.buf,
- req->req.length, ep_is_in(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->mapped = 1;
- } else {
- dma_sync_single_for_device(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ep_is_in(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->mapped = 0;
- }
+ ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
+ if (ret)
+ return ret;
req->req.status = -EINPROGRESS;
req->req.actual = 0;
@@ -1290,6 +1265,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
{
struct fsl_req *req = udc->status_req;
struct fsl_ep *ep;
+ int ret;
if (direction == EP_DIR_IN)
udc->ep0_dir = USB_DIR_IN;
@@ -1307,10 +1283,9 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
req->req.complete = NULL;
req->dtd_count = 0;
- req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
- req->req.buf, req->req.length,
- ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 1;
+ ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
+ if (ret)
+ return ret;
if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0)
fsl_queue_td(ep, req);
@@ -1353,6 +1328,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
u16 tmp = 0; /* Status, cpu endian */
struct fsl_req *req;
struct fsl_ep *ep;
+ int ret;
ep = &udc->eps[0];
@@ -1390,10 +1366,9 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
req->req.complete = NULL;
req->dtd_count = 0;
- req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
- req->req.buf, req->req.length,
- ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 1;
+ ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
+ if (ret)
+ goto stall;
/* prime the data phase */
if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0))
@@ -1964,7 +1939,6 @@ static int fsl_udc_start(struct usb_gadget *g,
driver->driver.bus = NULL;
/* hook up the driver */
udc_controller->driver = driver;
- udc_controller->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc_controller->lock, flags);
if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
@@ -1980,7 +1954,6 @@ static int fsl_udc_start(struct usb_gadget *g,
if (retval < 0) {
ERR("can't bind to transceiver\n");
driver->unbind(&udc_controller->gadget);
- udc_controller->gadget.dev.driver = 0;
udc_controller->driver = 0;
return retval;
}
@@ -2023,7 +1996,6 @@ static int fsl_udc_stop(struct usb_gadget *g,
nuke(loop_ep, -ESHUTDOWN);
spin_unlock_irqrestore(&udc_controller->lock, flags);
- udc_controller->gadget.dev.driver = NULL;
udc_controller->driver = NULL;
return 0;
@@ -2521,12 +2493,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
/* Setup gadget.dev and register with kernel */
dev_set_name(&udc_controller->gadget.dev, "gadget");
- udc_controller->gadget.dev.release = fsl_udc_release;
- udc_controller->gadget.dev.parent = &pdev->dev;
udc_controller->gadget.dev.of_node = pdev->dev.of_node;
- ret = device_register(&udc_controller->gadget.dev);
- if (ret < 0)
- goto err_free_irq;
if (!IS_ERR_OR_NULL(udc_controller->transceiver))
udc_controller->gadget.is_otg = 1;
@@ -2559,10 +2526,11 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
DTD_ALIGNMENT, UDC_DMA_BOUNDARY);
if (udc_controller->td_pool == NULL) {
ret = -ENOMEM;
- goto err_unregister;
+ goto err_free_irq;
}
- ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget);
+ ret = usb_add_gadget_udc_release(&pdev->dev, &udc_controller->gadget,
+ fsl_udc_release);
if (ret)
goto err_del_udc;
@@ -2571,8 +2539,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
err_del_udc:
dma_pool_destroy(udc_controller->td_pool);
-err_unregister:
- device_unregister(&udc_controller->gadget.dev);
err_free_irq:
free_irq(udc_controller->irq, udc_controller);
err_iounmap:
@@ -2622,7 +2588,6 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
release_mem_region(res->start, resource_size(res));
- device_unregister(&udc_controller->gadget.dev);
/* free udc --wait for the release() finished */
wait_for_completion(&done);
@@ -2747,21 +2712,7 @@ static struct platform_driver udc_driver = {
},
};
-static int __init udc_init(void)
-{
- printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION);
- return platform_driver_probe(&udc_driver, fsl_udc_probe);
-}
-
-module_init(udc_init);
-
-static void __exit udc_exit(void)
-{
- platform_driver_unregister(&udc_driver);
- printk(KERN_WARNING "%s unregistered\n", driver_desc);
-}
-
-module_exit(udc_exit);
+module_platform_driver_probe(udc_driver, fsl_udc_probe);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c
index 066cb89376de..cec8871b77f9 100644
--- a/drivers/usb/gadget/fusb300_udc.c
+++ b/drivers/usb/gadget/fusb300_udc.c
@@ -394,7 +394,7 @@ static void fusb300_clear_epnstall(struct fusb300 *fusb300, u8 ep)
if (reg & FUSB300_EPSET0_STL) {
printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep);
- reg &= ~FUSB300_EPSET0_STL;
+ reg |= FUSB300_EPSET0_STL_CLR;
iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
}
}
@@ -930,33 +930,33 @@ static void fusb300_wait_idma_finished(struct fusb300_ep *ep)
fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0,
FUSB300_IGR0_EPn_PRD_INT(ep->epnum));
+ return;
+
IDMA_RESET:
- fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGER0,
- FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
+ reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGER0);
+ reg &= ~FUSB300_IGER0_EEPn_PRD_INT(ep->epnum);
+ iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_IGER0);
}
-static void fusb300_set_idma(struct fusb300_ep *ep,
+static void fusb300_set_idma(struct fusb300_ep *ep,
struct fusb300_request *req)
{
- dma_addr_t d;
-
- d = dma_map_single(NULL, req->req.buf, req->req.length, DMA_TO_DEVICE);
+ int ret;
- if (dma_mapping_error(NULL, d)) {
- printk(KERN_DEBUG "dma_mapping_error\n");
+ ret = usb_gadget_map_request(&ep->fusb300->gadget,
+ &req->req, DMA_TO_DEVICE);
+ if (ret)
return;
- }
-
- dma_sync_single_for_device(NULL, d, req->req.length, DMA_TO_DEVICE);
fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0,
FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
- fusb300_fill_idma_prdtbl(ep, d, req->req.length);
+ fusb300_fill_idma_prdtbl(ep, req->req.dma, req->req.length);
/* check idma is done */
fusb300_wait_idma_finished(ep);
- dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE);
+ usb_gadget_unmap_request(&ep->fusb300->gadget,
+ &req->req, DMA_TO_DEVICE);
}
static void in_ep_fifo_handler(struct fusb300_ep *ep)
@@ -1316,7 +1316,6 @@ static int fusb300_udc_start(struct usb_gadget *g,
/* hook up the driver */
driver->driver.bus = NULL;
fusb300->driver = driver;
- fusb300->gadget.dev.driver = &driver->driver;
return 0;
}
@@ -1327,7 +1326,6 @@ static int fusb300_udc_stop(struct usb_gadget *g,
struct fusb300 *fusb300 = to_fusb300(g);
driver->unbind(&fusb300->gadget);
- fusb300->gadget.dev.driver = NULL;
init_controller(fusb300);
fusb300->driver = NULL;
@@ -1422,14 +1420,7 @@ static int __init fusb300_probe(struct platform_device *pdev)
fusb300->gadget.ops = &fusb300_gadget_ops;
- device_initialize(&fusb300->gadget.dev);
-
- dev_set_name(&fusb300->gadget.dev, "gadget");
-
fusb300->gadget.max_speed = USB_SPEED_HIGH;
- fusb300->gadget.dev.parent = &pdev->dev;
- fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask;
- fusb300->gadget.dev.release = pdev->dev.release;
fusb300->gadget.name = udc_name;
fusb300->reg = reg;
@@ -1478,19 +1469,10 @@ static int __init fusb300_probe(struct platform_device *pdev)
if (ret)
goto err_add_udc;
- ret = device_add(&fusb300->gadget.dev);
- if (ret) {
- pr_err("device_add error (%d)\n", ret);
- goto err_add_device;
- }
-
dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
return 0;
-err_add_device:
- usb_del_gadget_udc(&fusb300->gadget);
-
err_add_udc:
fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
diff --git a/drivers/usb/gadget/fusb300_udc.h b/drivers/usb/gadget/fusb300_udc.h
index 6ba444ae8dd5..ae811d8d38b4 100644
--- a/drivers/usb/gadget/fusb300_udc.h
+++ b/drivers/usb/gadget/fusb300_udc.h
@@ -111,8 +111,8 @@
/*
* * EPn Setting 0 (EPn_SET0, offset = 020H+(n-1)*30H, n=1~15 )
* */
+#define FUSB300_EPSET0_STL_CLR (1 << 3)
#define FUSB300_EPSET0_CLRSEQNUM (1 << 2)
-#define FUSB300_EPSET0_EPn_TX0BYTE (1 << 1)
#define FUSB300_EPSET0_STL (1 << 0)
/*
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index 3b343b23e4b0..787a78e92aa2 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -13,7 +13,6 @@
#define pr_fmt(fmt) "g_ffs: " fmt
#include <linux/module.h>
-
/*
* kbuild is not very cooperative with respect to linking separately
* compiled library objects into one module. So for now we won't use
@@ -38,13 +37,16 @@
# include "u_ether.c"
static u8 gfs_hostaddr[ETH_ALEN];
+static struct eth_dev *the_dev;
# ifdef CONFIG_USB_FUNCTIONFS_ETH
-static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev);
# endif
#else
-# define gether_cleanup() do { } while (0)
-# define gether_setup(gadget, hostaddr) ((int)0)
+# define the_dev NULL
+# define gether_cleanup(dev) do { } while (0)
# define gfs_hostaddr NULL
+struct eth_dev;
#endif
#include "f_fs.c"
@@ -137,7 +139,8 @@ static struct usb_gadget_strings *gfs_dev_strings[] = {
struct gfs_configuration {
struct usb_configuration c;
- int (*eth)(struct usb_configuration *c, u8 *ethaddr);
+ int (*eth)(struct usb_configuration *c, u8 *ethaddr,
+ struct eth_dev *dev);
} gfs_configurations[] = {
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
{
@@ -346,10 +349,13 @@ static int gfs_bind(struct usb_composite_dev *cdev)
if (missing_funcs)
return -ENODEV;
-
- ret = gether_setup(cdev->gadget, gfs_hostaddr);
- if (unlikely(ret < 0))
+#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
+ the_dev = gether_setup(cdev->gadget, gfs_hostaddr);
+#endif
+ if (IS_ERR(the_dev)) {
+ ret = PTR_ERR(the_dev);
goto error_quick;
+ }
gfs_ether_setup = true;
ret = usb_string_ids_tab(cdev, gfs_strings);
@@ -386,7 +392,7 @@ error_unbind:
for (i = 0; i < func_num; i++)
functionfs_unbind(ffs_tab[i].ffs_data);
error:
- gether_cleanup();
+ gether_cleanup(the_dev);
error_quick:
gfs_ether_setup = false;
return ret;
@@ -410,7 +416,7 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
* do...?
*/
if (gfs_ether_setup)
- gether_cleanup();
+ gether_cleanup(the_dev);
gfs_ether_setup = false;
for (i = func_num; i--; )
@@ -440,7 +446,7 @@ static int gfs_do_config(struct usb_configuration *c)
}
if (gc->eth) {
- ret = gc->eth(c, gfs_hostaddr);
+ ret = gc->eth(c, gfs_hostaddr, the_dev);
if (unlikely(ret < 0))
return ret;
}
@@ -469,11 +475,12 @@ static int gfs_do_config(struct usb_configuration *c)
#ifdef CONFIG_USB_FUNCTIONFS_ETH
-static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev)
{
return can_support_ecm(c->cdev->gadget)
- ? ecm_bind_config(c, ethaddr)
- : geth_bind_config(c, ethaddr);
+ ? ecm_bind_config(c, ethaddr, dev)
+ : geth_bind_config(c, ethaddr, dev);
}
#endif
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 85742d4c67df..991aba390d9d 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -51,8 +51,6 @@
#define DRIVER_DESC "TC86C001 USB Device Controller"
#define DRIVER_VERSION "30-Oct 2003"
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
static const char driver_name [] = "goku_udc";
static const char driver_desc [] = DRIVER_DESC;
@@ -275,7 +273,6 @@ goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
if (!req)
return NULL;
- req->req.dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD(&req->queue);
return &req->req;
}
@@ -1354,7 +1351,6 @@ static int goku_udc_start(struct usb_gadget *g,
/* hook up the driver */
driver->driver.bus = NULL;
dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
/*
* then enable host detection and ep0; and we're ready
@@ -1394,7 +1390,6 @@ static int goku_udc_stop(struct usb_gadget *g,
dev->driver = NULL;
stop_activity(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
- dev->gadget.dev.driver = NULL;
return 0;
}
@@ -1716,8 +1711,6 @@ static void goku_remove(struct pci_dev *pdev)
pci_resource_len (pdev, 0));
if (dev->enabled)
pci_disable_device(pdev);
- if (dev->registered)
- device_unregister(&dev->gadget.dev);
pci_set_drvdata(pdev, NULL);
dev->regs = NULL;
@@ -1756,10 +1749,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev->gadget.max_speed = USB_SPEED_FULL;
/* the "gadget" abstracts/virtualizes the controller */
- dev_set_name(&dev->gadget.dev, "gadget");
- dev->gadget.dev.parent = &pdev->dev;
- dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
- dev->gadget.dev.release = gadget_release;
dev->gadget.name = driver_name;
/* now all the pci goodies ... */
@@ -1810,13 +1799,8 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev);
#endif
- retval = device_register(&dev->gadget.dev);
- if (retval) {
- put_device(&dev->gadget.dev);
- goto err;
- }
- dev->registered = 1;
- retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+ retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
+ gadget_release);
if (retval)
goto err;
diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h
index b4470d2b1d86..86d2adafe149 100644
--- a/drivers/usb/gadget/goku_udc.h
+++ b/drivers/usb/gadget/goku_udc.h
@@ -250,8 +250,7 @@ struct goku_udc {
got_region:1,
req_config:1,
configured:1,
- enabled:1,
- registered:1;
+ enabled:1;
/* pci state used to access those endpoints */
struct pci_dev *pdev;
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
index 5bd930d779b9..b5cebd6b0d7a 100644
--- a/drivers/usb/gadget/imx_udc.c
+++ b/drivers/usb/gadget/imx_udc.c
@@ -1338,7 +1338,6 @@ static int imx_udc_start(struct usb_gadget *gadget,
imx_usb = container_of(gadget, struct imx_udc_struct, gadget);
/* first hook up the driver ... */
imx_usb->driver = driver;
- imx_usb->gadget.dev.driver = &driver->driver;
D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n",
__func__, driver->driver.name);
@@ -1358,7 +1357,6 @@ static int imx_udc_stop(struct usb_gadget *gadget,
imx_udc_disable(imx_usb);
del_timer(&imx_usb->timer);
- imx_usb->gadget.dev.driver = NULL;
imx_usb->driver = NULL;
D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n",
@@ -1461,15 +1459,6 @@ static int __init imx_udc_probe(struct platform_device *pdev)
imx_usb->clk = clk;
imx_usb->dev = &pdev->dev;
- device_initialize(&imx_usb->gadget.dev);
-
- imx_usb->gadget.dev.parent = &pdev->dev;
- imx_usb->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
- ret = device_add(&imx_usb->gadget.dev);
- if (retval)
- goto fail4;
-
platform_set_drvdata(pdev, imx_usb);
usb_init_data(imx_usb);
@@ -1481,11 +1470,9 @@ static int __init imx_udc_probe(struct platform_device *pdev)
ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget);
if (ret)
- goto fail5;
+ goto fail4;
return 0;
-fail5:
- device_unregister(&imx_usb->gadget.dev);
fail4:
for (i = 0; i < IMX_USB_NB_EP + 1; i++)
free_irq(imx_usb->usbd_int[i], imx_usb);
@@ -1509,7 +1496,6 @@ static int __exit imx_udc_remove(struct platform_device *pdev)
int i;
usb_del_gadget_udc(&imx_usb->gadget);
- device_unregister(&imx_usb->gadget.dev);
imx_udc_disable(imx_usb);
del_timer(&imx_usb->timer);
diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c
index aa04089d6899..b943d8cdfbf7 100644
--- a/drivers/usb/gadget/lpc32xx_udc.c
+++ b/drivers/usb/gadget/lpc32xx_udc.c
@@ -1469,23 +1469,7 @@ static void done(struct lpc32xx_ep *ep, struct lpc32xx_request *req, int status)
status = req->req.status;
if (ep->lep) {
- enum dma_data_direction direction;
-
- if (ep->is_in)
- direction = DMA_TO_DEVICE;
- else
- direction = DMA_FROM_DEVICE;
-
- if (req->mapped) {
- dma_unmap_single(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- direction);
- req->req.dma = 0;
- req->mapped = 0;
- } else
- dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- direction);
+ usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in);
/* Free DDs */
udc_dd_free(udc, req->dd_desc_ptr);
@@ -1841,26 +1825,11 @@ static int lpc32xx_ep_queue(struct usb_ep *_ep,
}
if (ep->lep) {
- enum dma_data_direction direction;
struct lpc32xx_usbd_dd_gad *dd;
- /* Map DMA pointer */
- if (ep->is_in)
- direction = DMA_TO_DEVICE;
- else
- direction = DMA_FROM_DEVICE;
-
- if (req->req.dma == 0) {
- req->req.dma = dma_map_single(
- ep->udc->gadget.dev.parent,
- req->req.buf, req->req.length, direction);
- req->mapped = 1;
- } else {
- dma_sync_single_for_device(
- ep->udc->gadget.dev.parent, req->req.dma,
- req->req.length, direction);
- req->mapped = 0;
- }
+ status = usb_gadget_map_request(&udc->gadget, _req, ep->is_in);
+ if (status)
+ return status;
/* For the request, build a list of DDs */
dd = udc_dd_alloc(udc);
@@ -2977,7 +2946,6 @@ static int lpc32xx_start(struct usb_gadget *gadget,
}
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
udc->gadget.dev.of_node = udc->dev->of_node;
udc->enabled = 1;
udc->selfpowered = 1;
@@ -3026,7 +2994,6 @@ static int lpc32xx_stop(struct usb_gadget *gadget,
}
udc->enabled = 0;
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
return 0;
@@ -3248,12 +3215,6 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
udc_disable(udc);
udc_reinit(udc);
- retval = device_register(&udc->gadget.dev);
- if (retval < 0) {
- dev_err(udc->dev, "Device registration failure\n");
- goto dev_register_fail;
- }
-
/* Request IRQs - low and high priority USB device IRQs are routed to
* the same handler, while the DMA interrupt is routed elsewhere */
retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq,
@@ -3320,8 +3281,6 @@ irq_dev_fail:
irq_hp_fail:
free_irq(udc->udp_irq[IRQ_USB_LP], udc);
irq_lp_fail:
- device_unregister(&udc->gadget.dev);
-dev_register_fail:
dma_pool_destroy(udc->dd_cache);
dma_alloc_fail:
dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
@@ -3376,8 +3335,6 @@ static int lpc32xx_udc_remove(struct platform_device *pdev)
free_irq(udc->udp_irq[IRQ_USB_HP], udc);
free_irq(udc->udp_irq[IRQ_USB_LP], udc);
- device_unregister(&udc->gadget.dev);
-
clk_disable(udc->usb_otg_clk);
clk_put(udc->usb_otg_clk);
clk_disable(udc->usb_slv_clk);
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index c1b8c2dd808d..866ef0999247 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -1471,7 +1471,6 @@ static int m66592_udc_start(struct usb_gadget *g,
/* hook up the driver */
driver->driver.bus = NULL;
m66592->driver = driver;
- m66592->gadget.dev.driver = &driver->driver;
m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) {
@@ -1494,7 +1493,6 @@ static int m66592_udc_stop(struct usb_gadget *g,
m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
driver->unbind(&m66592->gadget);
- m66592->gadget.dev.driver = NULL;
init_controller(m66592);
disable_controller(m66592);
@@ -1538,7 +1536,6 @@ static int __exit m66592_remove(struct platform_device *pdev)
struct m66592 *m66592 = dev_get_drvdata(&pdev->dev);
usb_del_gadget_udc(&m66592->gadget);
- device_del(&m66592->gadget.dev);
del_timer_sync(&m66592->timer);
iounmap(m66592->reg);
@@ -1608,12 +1605,7 @@ static int __init m66592_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, m66592);
m66592->gadget.ops = &m66592_gadget_ops;
- device_initialize(&m66592->gadget.dev);
- dev_set_name(&m66592->gadget.dev, "gadget");
m66592->gadget.max_speed = USB_SPEED_HIGH;
- m66592->gadget.dev.parent = &pdev->dev;
- m66592->gadget.dev.dma_mask = pdev->dev.dma_mask;
- m66592->gadget.dev.release = pdev->dev.release;
m66592->gadget.name = udc_name;
init_timer(&m66592->timer);
@@ -1674,12 +1666,6 @@ static int __init m66592_probe(struct platform_device *pdev)
init_controller(m66592);
- ret = device_add(&m66592->gadget.dev);
- if (ret) {
- pr_err("device_add error (%d)\n", ret);
- goto err_device_add;
- }
-
ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget);
if (ret)
goto err_add_udc;
@@ -1688,9 +1674,6 @@ static int __init m66592_probe(struct platform_device *pdev)
return 0;
err_add_udc:
- device_del(&m66592->gadget.dev);
-
-err_device_add:
m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
clean_up3:
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index 20bbbf917fc2..a74ebefc7682 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -135,8 +135,8 @@ static struct fsg_common fsg_common;
static u8 hostaddr[ETH_ALEN];
-static unsigned char tty_line;
static struct usb_function_instance *fi_acm;
+static struct eth_dev *the_dev;
/********** RNDIS **********/
@@ -152,7 +152,7 @@ static __init int rndis_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- ret = rndis_bind_config(c, hostaddr);
+ ret = rndis_bind_config(c, hostaddr, the_dev);
if (ret < 0)
return ret;
@@ -214,7 +214,7 @@ static __init int cdc_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- ret = ecm_bind_config(c, hostaddr);
+ ret = ecm_bind_config(c, hostaddr, the_dev);
if (ret < 0)
return ret;
@@ -269,7 +269,6 @@ static int cdc_config_register(struct usb_composite_dev *cdev)
static int __ref multi_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
- struct f_serial_opts *opts;
int status;
if (!can_support_ecm(cdev->gadget)) {
@@ -279,24 +278,17 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
}
/* set up network link layer */
- status = gether_setup(cdev->gadget, hostaddr);
- if (status < 0)
- return status;
+ the_dev = gether_setup(cdev->gadget, hostaddr);
+ if (IS_ERR(the_dev))
+ return PTR_ERR(the_dev);
/* set up serial link layer */
- status = gserial_alloc_line(&tty_line);
- if (status < 0)
- goto fail0;
-
fi_acm = usb_get_function_instance("acm");
if (IS_ERR(fi_acm)) {
status = PTR_ERR(fi_acm);
- goto fail0dot5;
+ goto fail0;
}
- opts = container_of(fi_acm, struct f_serial_opts, func_inst);
- opts->port_num = tty_line;
-
/* set up mass storage function */
{
void *retp;
@@ -334,10 +326,8 @@ fail2:
fsg_common_put(&fsg_common);
fail1:
usb_put_function_instance(fi_acm);
-fail0dot5:
- gserial_free_line(tty_line);
fail0:
- gether_cleanup();
+ gether_cleanup(the_dev);
return status;
}
@@ -350,8 +340,7 @@ static int __exit multi_unbind(struct usb_composite_dev *cdev)
usb_put_function(f_acm_rndis);
#endif
usb_put_function_instance(fi_acm);
- gserial_free_line(tty_line);
- gether_cleanup();
+ gether_cleanup(the_dev);
return 0;
}
diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c
index b5cea273c957..58288e9cf728 100644
--- a/drivers/usb/gadget/mv_u3d_core.c
+++ b/drivers/usb/gadget/mv_u3d_core.c
@@ -30,9 +30,6 @@
#include <linux/platform_device.h>
#include <linux/platform_data/mv_usb.h>
#include <linux/clk.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
#include "mv_u3d.h"
@@ -125,7 +122,7 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
struct mv_u3d_trb *curr_trb;
dma_addr_t cur_deq_lo;
struct mv_u3d_ep_context *curr_ep_context;
- int trb_complete, actual, remaining_length;
+ int trb_complete, actual, remaining_length = 0;
int direction, ep_num;
int retval = 0;
u32 tmp, status, length;
@@ -189,6 +186,8 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
*/
static
void mv_u3d_done(struct mv_u3d_ep *ep, struct mv_u3d_req *req, int status)
+ __releases(&ep->udc->lock)
+ __acquires(&ep->udc->lock)
{
struct mv_u3d *u3d = (struct mv_u3d *)ep->u3d;
@@ -812,19 +811,19 @@ mv_u3d_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return 0;
}
- dev_dbg(u3d->dev, "%s: %s, req: 0x%x\n",
- __func__, _ep->name, (u32)req);
+ dev_dbg(u3d->dev, "%s: %s, req: 0x%p\n",
+ __func__, _ep->name, req);
/* catch various bogus parameters */
if (!req->req.complete || !req->req.buf
|| !list_empty(&req->queue)) {
dev_err(u3d->dev,
- "%s, bad params, _req: 0x%x,"
- "req->req.complete: 0x%x, req->req.buf: 0x%x,"
+ "%s, bad params, _req: 0x%p,"
+ "req->req.complete: 0x%p, req->req.buf: 0x%p,"
"list_empty: 0x%x\n",
- __func__, (u32)_req,
- (u32)req->req.complete, (u32)req->req.buf,
- (u32)list_empty(&req->queue));
+ __func__, _req,
+ req->req.complete, req->req.buf,
+ list_empty(&req->queue));
return -EINVAL;
}
if (unlikely(!ep->ep.desc)) {
@@ -905,7 +904,7 @@ static int mv_u3d_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
struct mv_u3d_req, queue);
/* Point first TRB of next request to the EP context. */
- iowrite32((u32) next_req->trb_head,
+ iowrite32((unsigned long) next_req->trb_head,
&ep_context->trb_addr_lo);
} else {
struct mv_u3d_ep_context *ep_context;
@@ -1264,7 +1263,6 @@ static int mv_u3d_start(struct usb_gadget *g,
/* hook up the driver ... */
driver->driver.bus = NULL;
u3d->driver = driver;
- u3d->gadget.dev.driver = &driver->driver;
u3d->ep0_dir = USB_DIR_OUT;
@@ -1302,7 +1300,6 @@ static int mv_u3d_stop(struct usb_gadget *g,
spin_unlock_irqrestore(&u3d->lock, flags);
- u3d->gadget.dev.driver = NULL;
u3d->driver = NULL;
return 0;
@@ -1525,6 +1522,8 @@ static int mv_u3d_is_set_configuration(struct usb_ctrlrequest *setup)
static void mv_u3d_handle_setup_packet(struct mv_u3d *u3d, u8 ep_num,
struct usb_ctrlrequest *setup)
+ __releases(&u3c->lock)
+ __acquires(&u3c->lock)
{
bool delegate = false;
@@ -1758,11 +1757,6 @@ static irqreturn_t mv_u3d_irq(int irq, void *dev)
return IRQ_HANDLED;
}
-static void mv_u3d_gadget_release(struct device *dev)
-{
- dev_dbg(dev, "%s\n", __func__);
-}
-
static int mv_u3d_remove(struct platform_device *dev)
{
struct mv_u3d *u3d = platform_get_drvdata(dev);
@@ -1792,8 +1786,6 @@ static int mv_u3d_remove(struct platform_device *dev)
clk_put(u3d->clk);
- device_unregister(&u3d->gadget.dev);
-
platform_set_drvdata(dev, NULL);
kfree(u3d);
@@ -1829,7 +1821,7 @@ static int mv_u3d_probe(struct platform_device *dev)
u3d->dev = &dev->dev;
u3d->vbus = pdata->vbus;
- u3d->clk = clk_get(&dev->dev, pdata->clkname[0]);
+ u3d->clk = clk_get(&dev->dev, NULL);
if (IS_ERR(u3d->clk)) {
retval = PTR_ERR(u3d->clk);
goto err_get_clk;
@@ -1849,8 +1841,9 @@ static int mv_u3d_probe(struct platform_device *dev)
retval = -EBUSY;
goto err_map_cap_regs;
} else {
- dev_dbg(&dev->dev, "cap_regs address: 0x%x/0x%x\n",
- (unsigned int)r->start, (unsigned int)u3d->cap_regs);
+ dev_dbg(&dev->dev, "cap_regs address: 0x%lx/0x%lx\n",
+ (unsigned long) r->start,
+ (unsigned long) u3d->cap_regs);
}
/* we will access controller register, so enable the u3d controller */
@@ -1864,10 +1857,10 @@ static int mv_u3d_probe(struct platform_device *dev)
}
}
- u3d->op_regs = (struct mv_u3d_op_regs __iomem *)((u32)u3d->cap_regs
+ u3d->op_regs = (struct mv_u3d_op_regs __iomem *)(u3d->cap_regs
+ MV_U3D_USB3_OP_REGS_OFFSET);
- u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)((u32)u3d->cap_regs
+ u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)(u3d->cap_regs
+ ioread32(&u3d->cap_regs->vuoff));
u3d->max_eps = 16;
@@ -1957,16 +1950,8 @@ static int mv_u3d_probe(struct platform_device *dev)
u3d->gadget.speed = USB_SPEED_UNKNOWN; /* speed */
/* the "gadget" abstracts/virtualizes the controller */
- dev_set_name(&u3d->gadget.dev, "gadget");
- u3d->gadget.dev.parent = &dev->dev;
- u3d->gadget.dev.dma_mask = dev->dev.dma_mask;
- u3d->gadget.dev.release = mv_u3d_gadget_release;
u3d->gadget.name = driver_name; /* gadget name */
- retval = device_register(&u3d->gadget.dev);
- if (retval)
- goto err_register_gadget_device;
-
mv_u3d_eps_init(u3d);
/* external vbus detection */
@@ -1991,8 +1976,6 @@ static int mv_u3d_probe(struct platform_device *dev)
return 0;
err_unregister:
- device_unregister(&u3d->gadget.dev);
-err_register_gadget_device:
free_irq(u3d->irq, &dev->dev);
err_request_irq:
err_get_irq:
@@ -2021,7 +2004,7 @@ err_pdata:
return retval;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int mv_u3d_suspend(struct device *dev)
{
struct mv_u3d *u3d = dev_get_drvdata(dev);
@@ -2064,10 +2047,10 @@ static int mv_u3d_resume(struct device *dev)
return 0;
}
-
-SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume);
#endif
+static SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume);
+
static void mv_u3d_shutdown(struct platform_device *dev)
{
struct mv_u3d *u3d = dev_get_drvdata(&dev->dev);
@@ -2080,14 +2063,12 @@ static void mv_u3d_shutdown(struct platform_device *dev)
static struct platform_driver mv_u3d_driver = {
.probe = mv_u3d_probe,
- .remove = __exit_p(mv_u3d_remove),
+ .remove = mv_u3d_remove,
.shutdown = mv_u3d_shutdown,
.driver = {
.owner = THIS_MODULE,
.name = "mv-u3d",
-#ifdef CONFIG_PM
.pm = &mv_u3d_pm_ops,
-#endif
},
};
diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h
index 9073436d8b24..be77f207dbaf 100644
--- a/drivers/usb/gadget/mv_udc.h
+++ b/drivers/usb/gadget/mv_udc.h
@@ -222,8 +222,7 @@ struct mv_udc {
struct mv_usb_platform_data *pdata;
/* some SOC has mutiple clock sources for USB*/
- unsigned int clknum;
- struct clk *clk[0];
+ struct clk *clk;
};
/* endpoint data structure */
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index c8cf959057fe..c2a57023e467 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -212,6 +212,8 @@ static int process_ep_req(struct mv_udc *udc, int index,
* request is still in progress.
*/
static void done(struct mv_ep *ep, struct mv_req *req, int status)
+ __releases(&ep->udc->lock)
+ __acquires(&ep->udc->lock)
{
struct mv_udc *udc = NULL;
unsigned char stopped = ep->stopped;
@@ -237,18 +239,7 @@ static void done(struct mv_ep *ep, struct mv_req *req, int status)
dma_pool_free(udc->dtd_pool, curr_td, curr_td->td_dma);
}
- if (req->mapped) {
- dma_unmap_single(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ((ep_dir(ep) == EP_DIR_IN) ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE));
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- } else
- dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ((ep_dir(ep) == EP_DIR_IN) ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE));
+ usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep));
if (status && (status != -ESHUTDOWN))
dev_info(&udc->dev->dev, "complete %s req %p stat %d len %u/%u",
@@ -732,21 +723,9 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req->ep = ep;
/* map virtual address to hardware */
- if (req->req.dma == DMA_ADDR_INVALID) {
- req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
- req->req.buf,
- req->req.length, ep_dir(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->mapped = 1;
- } else {
- dma_sync_single_for_device(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ep_dir(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->mapped = 0;
- }
+ retval = usb_gadget_map_request(&udc->gadget, _req, ep_dir(ep));
+ if (retval)
+ return retval;
req->req.status = -EINPROGRESS;
req->req.actual = 0;
@@ -780,18 +759,7 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return 0;
err_unmap_dma:
- if (req->mapped) {
- dma_unmap_single(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ((ep_dir(ep) == EP_DIR_IN) ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE));
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- } else
- dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ((ep_dir(ep) == EP_DIR_IN) ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE));
+ usb_gadget_unmap_request(&udc->gadget, _req, ep_dir(ep));
return retval;
}
@@ -1006,18 +974,12 @@ static struct usb_ep_ops mv_ep_ops = {
static void udc_clock_enable(struct mv_udc *udc)
{
- unsigned int i;
-
- for (i = 0; i < udc->clknum; i++)
- clk_prepare_enable(udc->clk[i]);
+ clk_prepare_enable(udc->clk);
}
static void udc_clock_disable(struct mv_udc *udc)
{
- unsigned int i;
-
- for (i = 0; i < udc->clknum; i++)
- clk_disable_unprepare(udc->clk[i]);
+ clk_disable_unprepare(udc->clk);
}
static void udc_stop(struct mv_udc *udc)
@@ -1386,7 +1348,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
/* hook up the driver ... */
driver->driver.bus = NULL;
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
udc->usb_state = USB_STATE_ATTACHED;
udc->ep0_state = WAIT_FOR_SETUP;
@@ -1401,7 +1362,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
dev_err(&udc->dev->dev,
"unable to register peripheral to otg\n");
udc->driver = NULL;
- udc->gadget.dev.driver = NULL;
return retval;
}
}
@@ -1437,7 +1397,6 @@ static int mv_udc_stop(struct usb_gadget *gadget,
spin_unlock_irqrestore(&udc->lock, flags);
/* unbind gadget driver */
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
return 0;
@@ -1528,14 +1487,7 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
return 0;
out:
- if (req->mapped) {
- dma_unmap_single(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ((ep_dir(ep) == EP_DIR_IN) ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE));
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- }
+ usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep));
return retval;
}
@@ -1695,6 +1647,8 @@ out:
static void handle_setup_packet(struct mv_udc *udc, u8 ep_num,
struct usb_ctrlrequest *setup)
+ __releases(&ep->udc->lock)
+ __acquires(&ep->udc->lock)
{
bool delegate = false;
@@ -1891,7 +1845,7 @@ static void irq_process_tr_complete(struct mv_udc *udc)
}
}
-void irq_process_reset(struct mv_udc *udc)
+static void irq_process_reset(struct mv_udc *udc)
{
u32 tmp;
unsigned int loops;
@@ -2138,8 +2092,6 @@ static int mv_udc_remove(struct platform_device *pdev)
mv_udc_disable(udc);
- device_unregister(&udc->gadget.dev);
-
/* free dev, wait for the release() finished */
wait_for_completion(udc->done);
@@ -2151,7 +2103,6 @@ static int mv_udc_probe(struct platform_device *pdev)
struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
struct mv_udc *udc;
int retval = 0;
- int clk_i = 0;
struct resource *r;
size_t size;
@@ -2160,8 +2111,7 @@ static int mv_udc_probe(struct platform_device *pdev)
return -ENODEV;
}
- size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum;
- udc = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL);
if (udc == NULL) {
dev_err(&pdev->dev, "failed to allocate memory for udc\n");
return -ENOMEM;
@@ -2173,26 +2123,24 @@ static int mv_udc_probe(struct platform_device *pdev)
udc->dev = pdev;
-#ifdef CONFIG_USB_OTG_UTILS
if (pdata->mode == MV_USB_MODE_OTG) {
udc->transceiver = devm_usb_get_phy(&pdev->dev,
USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(udc->transceiver)) {
+ if (IS_ERR(udc->transceiver)) {
+ retval = PTR_ERR(udc->transceiver);
+
+ if (retval == -ENXIO)
+ return retval;
+
udc->transceiver = NULL;
- return -ENODEV;
+ return -EPROBE_DEFER;
}
}
-#endif
- udc->clknum = pdata->clknum;
- for (clk_i = 0; clk_i < udc->clknum; clk_i++) {
- udc->clk[clk_i] = devm_clk_get(&pdev->dev,
- pdata->clkname[clk_i]);
- if (IS_ERR(udc->clk[clk_i])) {
- retval = PTR_ERR(udc->clk[clk_i]);
- return retval;
- }
- }
+ /* udc only have one sysclk. */
+ udc->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(udc->clk))
+ return PTR_ERR(udc->clk);
r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs");
if (r == NULL) {
@@ -2311,16 +2259,8 @@ static int mv_udc_probe(struct platform_device *pdev)
udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */
/* the "gadget" abstracts/virtualizes the controller */
- dev_set_name(&udc->gadget.dev, "gadget");
- udc->gadget.dev.parent = &pdev->dev;
- udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
- udc->gadget.dev.release = gadget_release;
udc->gadget.name = driver_name; /* gadget name */
- retval = device_register(&udc->gadget.dev);
- if (retval)
- goto err_destroy_dma;
-
eps_init(udc);
/* VBUS detect: we can disable/enable clock on demand.*/
@@ -2342,7 +2282,7 @@ static int mv_udc_probe(struct platform_device *pdev)
if (!udc->qwork) {
dev_err(&pdev->dev, "cannot create workqueue\n");
retval = -ENOMEM;
- goto err_unregister;
+ goto err_destroy_dma;
}
INIT_WORK(&udc->vbus_work, mv_udc_vbus_work);
@@ -2358,7 +2298,8 @@ static int mv_udc_probe(struct platform_device *pdev)
else
udc->vbus_active = 1;
- retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+ retval = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
+ gadget_release);
if (retval)
goto err_create_workqueue;
@@ -2370,8 +2311,6 @@ static int mv_udc_probe(struct platform_device *pdev)
err_create_workqueue:
destroy_workqueue(udc->qwork);
-err_unregister:
- device_unregister(&udc->gadget.dev);
err_destroy_dma:
dma_pool_destroy(udc->dtd_pool);
err_free_dma:
diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c
index a22ad9af0565..3b02fd4649ce 100644
--- a/drivers/usb/gadget/ncm.c
+++ b/drivers/usb/gadget/ncm.c
@@ -111,6 +111,7 @@ static struct usb_gadget_strings *dev_strings[] = {
NULL,
};
+struct eth_dev *the_dev;
static u8 hostaddr[ETH_ALEN];
/*-------------------------------------------------------------------------*/
@@ -124,7 +125,7 @@ static int __init ncm_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- return ncm_bind_config(c, hostaddr);
+ return ncm_bind_config(c, hostaddr, the_dev);
}
static struct usb_configuration ncm_config_driver = {
@@ -143,9 +144,9 @@ static int __init gncm_bind(struct usb_composite_dev *cdev)
int status;
/* set up network link layer */
- status = gether_setup(cdev->gadget, hostaddr);
- if (status < 0)
- return status;
+ the_dev = gether_setup(cdev->gadget, hostaddr);
+ if (IS_ERR(the_dev))
+ return PTR_ERR(the_dev);
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
@@ -168,13 +169,13 @@ static int __init gncm_bind(struct usb_composite_dev *cdev)
return 0;
fail:
- gether_cleanup();
+ gether_cleanup(the_dev);
return status;
}
static int __exit gncm_unbind(struct usb_composite_dev *cdev)
{
- gether_cleanup();
+ gether_cleanup(the_dev);
return 0;
}
diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c
index 32524b631959..f1e50a3e322d 100644
--- a/drivers/usb/gadget/net2272.c
+++ b/drivers/usb/gadget/net2272.c
@@ -58,7 +58,6 @@ static const char * const ep_name[] = {
"ep-a", "ep-b", "ep-c",
};
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#ifdef CONFIG_USB_NET2272_DMA
/*
* use_dma: the NET2272 can use an external DMA controller.
@@ -341,7 +340,6 @@ net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
if (!req)
return NULL;
- req->req.dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD(&req->queue);
return &req->req;
@@ -913,7 +911,7 @@ net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
}
}
}
- if (likely(req != 0))
+ if (likely(req))
list_add_tail(&req->queue, &ep->queue);
if (likely(!list_empty(&ep->queue)))
@@ -1467,7 +1465,6 @@ static int net2272_start(struct usb_gadget *_gadget,
dev->softconnect = 1;
driver->driver.bus = NULL;
dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
/* ... then enable host detection and ep0; and we're ready
* for set_configuration as well as eventual disconnect.
@@ -1517,7 +1514,6 @@ static int net2272_stop(struct usb_gadget *_gadget,
stop_activity(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
- dev->gadget.dev.driver = NULL;
dev->driver = NULL;
dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name);
@@ -1549,7 +1545,7 @@ net2272_handle_dma(struct net2272_ep *ep)
| (ep->dev->dma_eot_polarity << EOT_POLARITY)
| (ep->dev->dma_dack_polarity << DACK_POLARITY)
| (ep->dev->dma_dreq_polarity << DREQ_POLARITY)
- | ((ep->dma >> 1) << DMA_ENDPOINT_SELECT));
+ | (ep->dma << DMA_ENDPOINT_SELECT));
ep->dev->dma_busy = 0;
@@ -1622,7 +1618,7 @@ net2272_handle_ep(struct net2272_ep *ep)
ep->irqs++;
dev_vdbg(ep->dev->dev, "%s ack ep_stat0 %02x, ep_stat1 %02x, req %p\n",
- ep->ep.name, stat0, stat1, req ? &req->req : 0);
+ ep->ep.name, stat0, stat1, req ? &req->req : NULL);
net2272_ep_write(ep, EP_STAT0, stat0 &
~((1 << NAK_OUT_PACKETS)
@@ -2216,7 +2212,6 @@ net2272_remove(struct net2272 *dev)
free_irq(dev->irq, dev);
iounmap(dev->base_addr);
- device_unregister(&dev->gadget.dev);
device_remove_file(dev->dev, &dev_attr_registers);
dev_info(dev->dev, "unbind\n");
@@ -2243,10 +2238,6 @@ static struct net2272 *net2272_probe_init(struct device *dev, unsigned int irq)
ret->gadget.max_speed = USB_SPEED_HIGH;
/* the "gadget" abstracts/virtualizes the controller */
- dev_set_name(&ret->gadget.dev, "gadget");
- ret->gadget.dev.parent = dev;
- ret->gadget.dev.dma_mask = dev->dma_mask;
- ret->gadget.dev.release = net2272_gadget_release;
ret->gadget.name = driver_name;
return ret;
@@ -2282,14 +2273,12 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
dma_mode_string());
dev_info(dev->dev, "version: %s\n", driver_vers);
- ret = device_register(&dev->gadget.dev);
- if (ret)
- goto err_irq;
ret = device_create_file(dev->dev, &dev_attr_registers);
if (ret)
- goto err_dev_reg;
+ goto err_irq;
- ret = usb_add_gadget_udc(dev->dev, &dev->gadget);
+ ret = usb_add_gadget_udc_release(dev->dev, &dev->gadget,
+ net2272_gadget_release);
if (ret)
goto err_add_udc;
@@ -2297,8 +2286,6 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
err_add_udc:
device_remove_file(dev->dev, &dev_attr_registers);
- err_dev_reg:
- device_unregister(&dev->gadget.dev);
err_irq:
free_irq(dev->irq, dev);
err:
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 3bd0f992fb49..fbd006ab31d3 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -65,7 +65,6 @@
#define DRIVER_DESC "PLX NET228x USB Peripheral Controller"
#define DRIVER_VERSION "2005 Sept 27"
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define EP_DONTUSE 13 /* nonzero */
#define USE_RDK_LEDS /* GPIO pins control three LEDs */
@@ -406,7 +405,6 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
if (!req)
return NULL;
- req->req.dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD (&req->queue);
/* this dma descriptor may be swapped with the previous dummy */
@@ -420,7 +418,6 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
return NULL;
}
td->dmacount = 0; /* not VALID */
- td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
td->dmadesc = td->dmaaddr;
req->td = td;
}
@@ -1896,7 +1893,6 @@ static int net2280_start(struct usb_gadget *_gadget,
dev->softconnect = 1;
driver->driver.bus = NULL;
dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
retval = device_create_file (&dev->pdev->dev, &dev_attr_function);
if (retval) goto err_unbind;
@@ -1924,7 +1920,6 @@ static int net2280_start(struct usb_gadget *_gadget,
err_func:
device_remove_file (&dev->pdev->dev, &dev_attr_function);
err_unbind:
- dev->gadget.dev.driver = NULL;
dev->driver = NULL;
return retval;
}
@@ -1967,7 +1962,6 @@ static int net2280_stop(struct usb_gadget *_gadget,
stop_activity (dev, driver);
spin_unlock_irqrestore (&dev->lock, flags);
- dev->gadget.dev.driver = NULL;
dev->driver = NULL;
net2280_led_active (dev, 0);
@@ -2072,7 +2066,7 @@ static void handle_ep_small (struct net2280_ep *ep)
return;
/* manual DMA queue advance after short OUT */
- if (likely (ep->dma != 0)) {
+ if (likely (ep->dma)) {
if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) {
u32 count;
int stopped = ep->stopped;
@@ -2330,7 +2324,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
/* hw handles device and interface status */
if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
goto delegate;
- if ((e = get_ep_by_addr (dev, w_index)) == 0
+ if ((e = get_ep_by_addr (dev, w_index)) == NULL
|| w_length > 2)
goto do_stall;
@@ -2358,7 +2352,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
if (w_value != USB_ENDPOINT_HALT
|| w_length != 0)
goto do_stall;
- if ((e = get_ep_by_addr (dev, w_index)) == 0)
+ if ((e = get_ep_by_addr (dev, w_index)) == NULL)
goto do_stall;
if (e->wedged) {
VDEBUG(dev, "%s wedged, halt not cleared\n",
@@ -2380,7 +2374,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
if (w_value != USB_ENDPOINT_HALT
|| w_length != 0)
goto do_stall;
- if ((e = get_ep_by_addr (dev, w_index)) == 0)
+ if ((e = get_ep_by_addr (dev, w_index)) == NULL)
goto do_stall;
if (e->ep.name == ep0name)
goto do_stall;
@@ -2685,7 +2679,6 @@ static void net2280_remove (struct pci_dev *pdev)
pci_resource_len (pdev, 0));
if (dev->enabled)
pci_disable_device (pdev);
- device_unregister (&dev->gadget.dev);
device_remove_file (&pdev->dev, &dev_attr_registers);
pci_set_drvdata (pdev, NULL);
@@ -2717,10 +2710,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
dev->gadget.max_speed = USB_SPEED_HIGH;
/* the "gadget" abstracts/virtualizes the controller */
- dev_set_name(&dev->gadget.dev, "gadget");
- dev->gadget.dev.parent = &pdev->dev;
- dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
- dev->gadget.dev.release = gadget_release;
dev->gadget.name = driver_name;
/* now all the pci goodies ... */
@@ -2802,7 +2791,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
goto done;
}
td->dmacount = 0; /* not VALID */
- td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
td->dmadesc = td->dmaaddr;
dev->ep [i].dummy = td;
}
@@ -2829,12 +2817,11 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
use_dma
? (use_dma_chaining ? "chaining" : "enabled")
: "disabled");
- retval = device_register (&dev->gadget.dev);
- if (retval) goto done;
retval = device_create_file (&pdev->dev, &dev_attr_registers);
if (retval) goto done;
- retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+ retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
+ gadget_release);
if (retval)
goto done;
return 0;
diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c
index def37403989a..3b344b41a167 100644
--- a/drivers/usb/gadget/nokia.c
+++ b/drivers/usb/gadget/nokia.c
@@ -37,11 +37,9 @@
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
-#define USB_FACM_INCLUDED
-#include "f_acm.c"
+#define USBF_OBEX_INCLUDED
#include "f_ecm.c"
#include "f_obex.c"
-#include "f_serial.c"
#include "f_phonet.c"
#include "u_ether.c"
@@ -98,20 +96,40 @@ MODULE_AUTHOR("Felipe Balbi");
MODULE_LICENSE("GPL");
/*-------------------------------------------------------------------------*/
-
+static struct usb_function *f_acm_cfg1;
+static struct usb_function *f_acm_cfg2;
static u8 hostaddr[ETH_ALEN];
+static struct eth_dev *the_dev;
enum {
TTY_PORT_OBEX0,
TTY_PORT_OBEX1,
- TTY_PORT_ACM,
TTY_PORTS_MAX,
};
static unsigned char tty_lines[TTY_PORTS_MAX];
+static struct usb_configuration nokia_config_500ma_driver = {
+ .label = "Bus Powered",
+ .bConfigurationValue = 1,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_ONE,
+ .MaxPower = 500,
+};
+
+static struct usb_configuration nokia_config_100ma_driver = {
+ .label = "Self Powered",
+ .bConfigurationValue = 2,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+ .MaxPower = 100,
+};
+
+static struct usb_function_instance *fi_acm;
+
static int __init nokia_bind_config(struct usb_configuration *c)
{
+ struct usb_function *f_acm;
int status = 0;
status = phonet_bind_config(c);
@@ -126,33 +144,32 @@ static int __init nokia_bind_config(struct usb_configuration *c)
if (status)
printk(KERN_DEBUG "could not bind obex config %d\n", 0);
- status = acm_bind_config(c, tty_lines[TTY_PORT_ACM]);
- if (status)
- printk(KERN_DEBUG "could not bind acm config\n");
+ f_acm = usb_get_function(fi_acm);
+ if (IS_ERR(f_acm))
+ return PTR_ERR(f_acm);
- status = ecm_bind_config(c, hostaddr);
+ status = usb_add_function(c, f_acm);
if (status)
- printk(KERN_DEBUG "could not bind ecm config\n");
+ goto err_conf;
+
+ status = ecm_bind_config(c, hostaddr, the_dev);
+ if (status) {
+ pr_debug("could not bind ecm config %d\n", status);
+ goto err_ecm;
+ }
+ if (c == &nokia_config_500ma_driver)
+ f_acm_cfg1 = f_acm;
+ else
+ f_acm_cfg2 = f_acm;
return status;
+err_ecm:
+ usb_remove_function(c, f_acm);
+err_conf:
+ usb_put_function(f_acm);
+ return status;
}
-static struct usb_configuration nokia_config_500ma_driver = {
- .label = "Bus Powered",
- .bConfigurationValue = 1,
- /* .iConfiguration = DYNAMIC */
- .bmAttributes = USB_CONFIG_ATT_ONE,
- .MaxPower = 500,
-};
-
-static struct usb_configuration nokia_config_100ma_driver = {
- .label = "Self Powered",
- .bConfigurationValue = 2,
- /* .iConfiguration = DYNAMIC */
- .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
- .MaxPower = 100,
-};
-
static int __init nokia_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
@@ -169,9 +186,11 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
goto err_ether;
}
- status = gether_setup(cdev->gadget, hostaddr);
- if (status < 0)
+ the_dev = gether_setup(cdev->gadget, hostaddr);
+ if (IS_ERR(the_dev)) {
+ status = PTR_ERR(the_dev);
goto err_ether;
+ }
status = usb_string_ids_tab(cdev, strings_dev);
if (status < 0)
@@ -185,24 +204,32 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
if (!gadget_supports_altsettings(gadget))
goto err_usb;
+ fi_acm = usb_get_function_instance("acm");
+ if (IS_ERR(fi_acm))
+ goto err_usb;
+
/* finally register the configuration */
status = usb_add_config(cdev, &nokia_config_500ma_driver,
nokia_bind_config);
if (status < 0)
- goto err_usb;
+ goto err_acm_inst;
status = usb_add_config(cdev, &nokia_config_100ma_driver,
nokia_bind_config);
if (status < 0)
- goto err_usb;
+ goto err_put_cfg1;
usb_composite_overwrite_options(cdev, &coverwrite);
dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
return 0;
+err_put_cfg1:
+ usb_put_function(f_acm_cfg1);
+err_acm_inst:
+ usb_put_function_instance(fi_acm);
err_usb:
- gether_cleanup();
+ gether_cleanup(the_dev);
err_ether:
cur_line--;
while (cur_line >= 0)
@@ -217,12 +244,15 @@ static int __exit nokia_unbind(struct usb_composite_dev *cdev)
{
int i;
+ usb_put_function(f_acm_cfg1);
+ usb_put_function(f_acm_cfg2);
+ usb_put_function_instance(fi_acm);
gphonet_cleanup();
for (i = 0; i < TTY_PORTS_MAX; i++)
gserial_free_line(tty_lines[i]);
- gether_cleanup();
+ gether_cleanup(the_dev);
return 0;
}
@@ -247,4 +277,3 @@ static void __exit nokia_cleanup(void)
usb_composite_unregister(&nokia_driver);
}
module_exit(nokia_cleanup);
-
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index f8445653577f..b8ed74a823cb 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -2067,7 +2067,6 @@ static int omap_udc_start(struct usb_gadget *g,
/* hook up the driver */
driver->driver.bus = NULL;
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc->lock, flags);
if (udc->dc_clk != NULL)
@@ -2083,7 +2082,6 @@ static int omap_udc_start(struct usb_gadget *g,
ERR("can't bind to transceiver\n");
if (driver->unbind) {
driver->unbind(&udc->gadget);
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
}
goto done;
@@ -2129,7 +2127,6 @@ static int omap_udc_stop(struct usb_gadget *g,
udc_quiesce(udc);
spin_unlock_irqrestore(&udc->lock, flags);
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
if (udc->dc_clk != NULL)
@@ -2631,14 +2628,6 @@ omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
udc->gadget.speed = USB_SPEED_UNKNOWN;
udc->gadget.max_speed = USB_SPEED_FULL;
udc->gadget.name = driver_name;
-
- device_initialize(&udc->gadget.dev);
- dev_set_name(&udc->gadget.dev, "gadget");
- udc->gadget.dev.release = omap_udc_release;
- udc->gadget.dev.parent = &odev->dev;
- if (use_dma)
- udc->gadget.dev.dma_mask = odev->dev.dma_mask;
-
udc->transceiver = xceiv;
/* ep0 is special; put it right after the SETUP buffer */
@@ -2912,14 +2901,13 @@ bad_on_1710:
}
create_proc_file();
- status = device_add(&udc->gadget.dev);
+ status = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
+ omap_udc_release);
if (status)
goto cleanup4;
- status = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
- if (!status)
- return status;
- /* If fail, fall through */
+ return 0;
+
cleanup4:
remove_proc_file();
@@ -2990,7 +2978,6 @@ static int omap_udc_remove(struct platform_device *pdev)
release_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1);
- device_unregister(&udc->gadget.dev);
wait_for_completion(&done);
return 0;
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index a787a8ef672b..24174e1d1564 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -358,7 +358,6 @@ struct pch_udc_dev {
prot_stall:1,
irq_registered:1,
mem_region:1,
- registered:1,
suspended:1,
connected:1,
vbus_session:1,
@@ -1441,6 +1440,8 @@ static void pch_vbus_gpio_free(struct pch_udc_dev *dev)
*/
static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
int status)
+ __releases(&dev->lock)
+ __acquires(&dev->lock)
{
struct pch_udc_dev *dev;
unsigned halted = ep->halted;
@@ -2382,6 +2383,8 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev)
* @dev: Reference to the device structure
*/
static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
+ __releases(&dev->lock)
+ __acquires(&dev->lock)
{
u32 stat;
int setup_supported;
@@ -2989,7 +2992,6 @@ static int pch_udc_start(struct usb_gadget *g,
driver->driver.bus = NULL;
dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
/* get ready for ep0 traffic */
pch_udc_setup_ep0(dev);
@@ -3010,7 +3012,6 @@ static int pch_udc_stop(struct usb_gadget *g,
pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
/* Assures that there are no pending requests with this driver */
- dev->gadget.dev.driver = NULL;
dev->driver = NULL;
dev->connected = 0;
@@ -3078,8 +3079,6 @@ static void pch_udc_remove(struct pci_dev *pdev)
pci_resource_len(pdev, PCH_UDC_PCI_BAR));
if (dev->active)
pci_disable_device(pdev);
- if (dev->registered)
- device_unregister(&dev->gadget.dev);
kfree(dev);
pci_set_drvdata(pdev, NULL);
}
@@ -3196,21 +3195,13 @@ static int pch_udc_probe(struct pci_dev *pdev,
if (retval)
goto finished;
- dev_set_name(&dev->gadget.dev, "gadget");
- dev->gadget.dev.parent = &pdev->dev;
- dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
- dev->gadget.dev.release = gadget_release;
dev->gadget.name = KBUILD_MODNAME;
dev->gadget.max_speed = USB_SPEED_HIGH;
- retval = device_register(&dev->gadget.dev);
- if (retval)
- goto finished;
- dev->registered = 1;
-
/* Put the device in disconnected state till a driver is bound */
pch_udc_set_disconnect(dev);
- retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+ retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
+ gadget_release);
if (retval)
goto finished;
return 0;
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index d0f37484b6b0..ef47495dec8f 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -1263,7 +1263,6 @@ static int pxa25x_udc_start(struct usb_gadget *g,
/* first hook up the driver ... */
dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
dev->pullup = 1;
/* ... then enable host detection and ep0; and we're ready
@@ -1325,7 +1324,6 @@ static int pxa25x_udc_stop(struct usb_gadget*g,
if (!IS_ERR_OR_NULL(dev->transceiver))
(void) otg_set_peripheral(dev->transceiver->otg, NULL);
- dev->gadget.dev.driver = NULL;
dev->driver = NULL;
dump_state(dev);
@@ -2138,17 +2136,6 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
dev->timer.function = udc_watchdog;
dev->timer.data = (unsigned long) dev;
- device_initialize(&dev->gadget.dev);
- dev->gadget.dev.parent = &pdev->dev;
- dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
- retval = device_add(&dev->gadget.dev);
- if (retval) {
- dev->driver = NULL;
- dev->gadget.dev.driver = NULL;
- goto err_device_add;
- }
-
the_controller = dev;
platform_set_drvdata(pdev, dev);
@@ -2199,8 +2186,6 @@ lubbock_fail0:
free_irq(irq, dev);
#endif
err_irq1:
- device_unregister(&dev->gadget.dev);
- err_device_add:
if (gpio_is_valid(dev->mach->gpio_pullup))
gpio_free(dev->mach->gpio_pullup);
err_gpio_pullup:
@@ -2226,7 +2211,6 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
return -EBUSY;
usb_del_gadget_udc(&dev->gadget);
- device_unregister(&dev->gadget.dev);
dev->pullup = 0;
pullup(dev);
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 2fc867652ef5..6b4c7d95853f 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -24,14 +24,12 @@
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/prefetch.h>
-
-#include <asm/byteorder.h>
-#include <mach/hardware.h>
+#include <linux/byteorder/generic.h>
+#include <linux/platform_data/pxa2xx_udc.h>
#include <linux/usb.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
-#include <mach/udc.h>
#include "pxa27x_udc.h"
@@ -611,7 +609,7 @@ static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in)
*
* Find the physical pxa27x ep, and setup its UDCCR
*/
-static __init void pxa_ep_setup(struct pxa_ep *ep)
+static void pxa_ep_setup(struct pxa_ep *ep)
{
u32 new_udccr;
@@ -633,7 +631,7 @@ static __init void pxa_ep_setup(struct pxa_ep *ep)
*
* Setup all pxa physical endpoints, except ep0
*/
-static __init void pxa_eps_setup(struct pxa_udc *dev)
+static void pxa_eps_setup(struct pxa_udc *dev)
{
unsigned int i;
@@ -1718,7 +1716,7 @@ static void udc_disable(struct pxa_udc *udc)
* Initializes gadget endpoint list, endpoints locks. No action is taken
* on the hardware.
*/
-static __init void udc_init_data(struct pxa_udc *dev)
+static void udc_init_data(struct pxa_udc *dev)
{
int i;
struct pxa_ep *ep;
@@ -1811,7 +1809,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
/* first hook up the driver ... */
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
dplus_pullup(udc, 1);
if (!IS_ERR_OR_NULL(udc->transceiver)) {
@@ -1829,7 +1826,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
fail:
udc->driver = NULL;
- udc->gadget.dev.driver = NULL;
return retval;
}
@@ -1871,7 +1867,6 @@ static int pxa27x_udc_stop(struct usb_gadget *g,
udc->driver = NULL;
-
if (!IS_ERR_OR_NULL(udc->transceiver))
return otg_set_peripheral(udc->transceiver->otg, NULL);
return 0;
@@ -2413,7 +2408,7 @@ static struct pxa_udc memory = {
* Perform basic init : allocates udc clock, creates sysfs files, requests
* irq.
*/
-static int __init pxa_udc_probe(struct platform_device *pdev)
+static int pxa_udc_probe(struct platform_device *pdev)
{
struct resource *regs;
struct pxa_udc *udc = &memory;
@@ -2456,9 +2451,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
goto err_map;
}
- device_initialize(&udc->gadget.dev);
- udc->gadget.dev.parent = &pdev->dev;
- udc->gadget.dev.dma_mask = NULL;
udc->vbus_sensed = 0;
the_controller = udc;
@@ -2475,12 +2467,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
goto err_irq;
}
- retval = device_add(&udc->gadget.dev);
- if (retval) {
- dev_err(udc->dev, "device_add error %d\n", retval);
- goto err_dev_add;
- }
-
retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
if (retval)
goto err_add_udc;
@@ -2490,8 +2476,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
return 0;
err_add_udc:
- device_unregister(&udc->gadget.dev);
-err_dev_add:
free_irq(udc->irq, udc);
err_irq:
iounmap(udc->regs);
@@ -2506,13 +2490,12 @@ err_clk:
* pxa_udc_remove - removes the udc device driver
* @_dev: platform device
*/
-static int __exit pxa_udc_remove(struct platform_device *_dev)
+static int pxa_udc_remove(struct platform_device *_dev)
{
struct pxa_udc *udc = platform_get_drvdata(_dev);
int gpio = udc->mach->gpio_pullup;
usb_del_gadget_udc(&udc->gadget);
- device_del(&udc->gadget.dev);
usb_gadget_unregister_driver(udc->driver);
free_irq(udc->irq, udc);
pxa_cleanup_debugfs(udc);
@@ -2625,7 +2608,8 @@ static struct platform_driver udc_driver = {
.name = "pxa27x-udc",
.owner = THIS_MODULE,
},
- .remove = __exit_p(pxa_udc_remove),
+ .probe = pxa_udc_probe,
+ .remove = pxa_udc_remove,
.shutdown = pxa_udc_shutdown,
#ifdef CONFIG_PM
.suspend = pxa_udc_suspend,
@@ -2633,22 +2617,7 @@ static struct platform_driver udc_driver = {
#endif
};
-static int __init udc_init(void)
-{
- if (!cpu_is_pxa27x() && !cpu_is_pxa3xx())
- return -ENODEV;
-
- printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
- return platform_driver_probe(&udc_driver, pxa_udc_probe);
-}
-module_init(udc_init);
-
-
-static void __exit udc_exit(void)
-{
- platform_driver_unregister(&udc_driver);
-}
-module_exit(udc_exit);
+module_platform_driver(udc_driver);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Robert Jarzmik");
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index f46a1b77ce3e..0b742d171843 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -1837,7 +1837,6 @@ static int __exit r8a66597_remove(struct platform_device *pdev)
clk_put(r8a66597->clk);
}
- device_unregister(&r8a66597->gadget.dev);
kfree(r8a66597);
return 0;
}
@@ -1915,17 +1914,8 @@ static int __init r8a66597_probe(struct platform_device *pdev)
r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
r8a66597->gadget.ops = &r8a66597_gadget_ops;
- dev_set_name(&r8a66597->gadget.dev, "gadget");
r8a66597->gadget.max_speed = USB_SPEED_HIGH;
- r8a66597->gadget.dev.parent = &pdev->dev;
- r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask;
- r8a66597->gadget.dev.release = pdev->dev.release;
r8a66597->gadget.name = udc_name;
- ret = device_register(&r8a66597->gadget.dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "device_register failed\n");
- goto clean_up;
- }
init_timer(&r8a66597->timer);
r8a66597->timer.function = r8a66597_timer;
@@ -1939,7 +1929,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "cannot get clock \"%s\"\n",
clk_name);
ret = PTR_ERR(r8a66597->clk);
- goto clean_up_dev;
+ goto clean_up;
}
clk_enable(r8a66597->clk);
}
@@ -2007,8 +1997,6 @@ clean_up2:
clk_disable(r8a66597->clk);
clk_put(r8a66597->clk);
}
-clean_up_dev:
- device_unregister(&r8a66597->gadget.dev);
clean_up:
if (r8a66597) {
if (r8a66597->sudmac_reg)
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index c26564f29a2c..a3cdc32115d5 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -39,8 +39,6 @@
#include "s3c-hsotg.h"
-#define DMA_ADDR_INVALID (~((dma_addr_t)0))
-
static const char * const s3c_hsotg_supply_names[] = {
"vusb_d", /* digital USB supply, 1.2V */
"vusb_a", /* analog USB supply, 1.1V */
@@ -405,7 +403,6 @@ static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep,
INIT_LIST_HEAD(&req->queue);
- req->req.dma = DMA_ADDR_INVALID;
return &req->req;
}
@@ -435,24 +432,12 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
struct s3c_hsotg_req *hs_req)
{
struct usb_request *req = &hs_req->req;
- enum dma_data_direction dir;
-
- dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
/* ignore this if we're not moving any data */
if (hs_req->req.length == 0)
return;
- if (hs_req->mapped) {
- /* we mapped this, so unmap and remove the dma */
-
- dma_unmap_single(hsotg->dev, req->dma, req->length, dir);
-
- req->dma = DMA_ADDR_INVALID;
- hs_req->mapped = 0;
- } else {
- dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
- }
+ usb_gadget_unmap_request(&hsotg->gadget, hs_req, hs_ep->dir_in);
}
/**
@@ -852,37 +837,16 @@ static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct usb_request *req)
{
- enum dma_data_direction dir;
struct s3c_hsotg_req *hs_req = our_req(req);
-
- dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+ int ret;
/* if the length is zero, ignore the DMA data */
if (hs_req->req.length == 0)
return 0;
- if (req->dma == DMA_ADDR_INVALID) {
- dma_addr_t dma;
-
- dma = dma_map_single(hsotg->dev, req->buf, req->length, dir);
-
- if (unlikely(dma_mapping_error(hsotg->dev, dma)))
- goto dma_error;
-
- if (dma & 3) {
- dev_err(hsotg->dev, "%s: unaligned dma buffer\n",
- __func__);
-
- dma_unmap_single(hsotg->dev, dma, req->length, dir);
- return -EINVAL;
- }
-
- hs_req->mapped = 1;
- req->dma = dma;
- } else {
- dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
- hs_req->mapped = 0;
- }
+ ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in);
+ if (ret)
+ goto dma_error;
return 0;
@@ -2961,9 +2925,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
driver->driver.bus = NULL;
hsotg->driver = driver;
- hsotg->gadget.dev.driver = &driver->driver;
hsotg->gadget.dev.of_node = hsotg->dev->of_node;
- hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
@@ -2979,7 +2941,6 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
err:
hsotg->driver = NULL;
- hsotg->gadget.dev.driver = NULL;
return ret;
}
@@ -3014,7 +2975,6 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
hsotg->driver = NULL;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
- hsotg->gadget.dev.driver = NULL;
spin_unlock_irqrestore(&hsotg->lock, flags);
@@ -3484,16 +3444,6 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
}
/**
- * s3c_hsotg_release - release callback for hsotg device
- * @dev: Device to for which release is called
- *
- * Nothing to do as the resource is allocated using devm_ API.
- */
-static void s3c_hsotg_release(struct device *dev)
-{
-}
-
-/**
* s3c_hsotg_probe - probe function for hsotg driver
* @pdev: The platform information for the driver
*/
@@ -3517,7 +3467,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
}
phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(phy)) {
+ if (IS_ERR(phy)) {
/* Fallback for pdata */
plat = pdev->dev.platform_data;
if (!plat) {
@@ -3567,18 +3517,10 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq);
- device_initialize(&hsotg->gadget.dev);
-
- dev_set_name(&hsotg->gadget.dev, "gadget");
-
hsotg->gadget.max_speed = USB_SPEED_HIGH;
hsotg->gadget.ops = &s3c_hsotg_gadget_ops;
hsotg->gadget.name = dev_name(dev);
- hsotg->gadget.dev.parent = dev;
- hsotg->gadget.dev.dma_mask = dev->dma_mask;
- hsotg->gadget.dev.release = s3c_hsotg_release;
-
/* reset the system */
clk_prepare_enable(hsotg->clk);
@@ -3658,12 +3600,6 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
s3c_hsotg_phy_disable(hsotg);
- ret = device_add(&hsotg->gadget.dev);
- if (ret) {
- put_device(&hsotg->gadget.dev);
- goto err_ep_mem;
- }
-
ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
if (ret)
goto err_ep_mem;
@@ -3702,10 +3638,8 @@ static int s3c_hsotg_remove(struct platform_device *pdev)
}
s3c_hsotg_phy_disable(hsotg);
-
clk_disable_unprepare(hsotg->clk);
- device_unregister(&hsotg->gadget.dev);
return 0;
}
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index 458965a1b138..b1f0771fbd3d 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -283,7 +283,6 @@ static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status)
/**
* s3c_hsudc_stop_activity - Stop activity on all endpoints.
* @hsudc: Device controller for which EP activity is to be stopped.
- * @driver: Reference to the gadget driver which is currently active.
*
* All the endpoints are stopped and any pending transfer requests if any on
* the endpoint are terminated.
@@ -1154,7 +1153,6 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
return -EBUSY;
hsudc->driver = driver;
- hsudc->gadget.dev.driver = &driver->driver;
ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies),
hsudc->supplies);
@@ -1190,7 +1188,6 @@ err_otg:
regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
err_supplies:
hsudc->driver = NULL;
- hsudc->gadget.dev.driver = NULL;
return ret;
}
@@ -1208,7 +1205,6 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget,
spin_lock_irqsave(&hsudc->lock, flags);
hsudc->driver = NULL;
- hsudc->gadget.dev.driver = NULL;
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
s3c_hsudc_uninit_phy();
@@ -1303,15 +1299,10 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
spin_lock_init(&hsudc->lock);
- dev_set_name(&hsudc->gadget.dev, "gadget");
-
hsudc->gadget.max_speed = USB_SPEED_HIGH;
hsudc->gadget.ops = &s3c_hsudc_gadget_ops;
hsudc->gadget.name = dev_name(dev);
- hsudc->gadget.dev.parent = dev;
- hsudc->gadget.dev.dma_mask = dev->dma_mask;
hsudc->gadget.ep0 = &hsudc->ep[0].ep;
-
hsudc->gadget.is_otg = 0;
hsudc->gadget.is_a_peripheral = 0;
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
@@ -1345,12 +1336,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
disable_irq(hsudc->irq);
local_irq_enable();
- ret = device_register(&hsudc->gadget.dev);
- if (ret) {
- put_device(&hsudc->gadget.dev);
- goto err_add_device;
- }
-
ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
if (ret)
goto err_add_udc;
@@ -1359,7 +1344,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
return 0;
err_add_udc:
- device_unregister(&hsudc->gadget.dev);
err_add_device:
clk_disable(hsudc->uclk);
err_res:
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 08f89652533b..d0e75e1b3ccb 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1674,7 +1674,6 @@ static int s3c2410_udc_start(struct usb_gadget *g,
/* Hook the driver */
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
/* Enable udc */
s3c2410_udc_enable(udc);
@@ -1824,17 +1823,6 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
goto err_mem;
}
- device_initialize(&udc->gadget.dev);
- udc->gadget.dev.parent = &pdev->dev;
- udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
- /* Bind the driver */
- retval = device_add(&udc->gadget.dev);
- if (retval) {
- dev_err(&udc->gadget.dev, "Error in device_add() : %d\n", retval);
- goto err_device_add;
- }
-
the_controller = udc;
platform_set_drvdata(pdev, udc);
@@ -1923,8 +1911,6 @@ err_gpio_claim:
err_int:
free_irq(IRQ_USBD, udc);
err_map:
- device_unregister(&udc->gadget.dev);
-err_device_add:
iounmap(base_addr);
err_mem:
release_mem_region(rsrc_start, rsrc_len);
@@ -1946,7 +1932,6 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
return -EBUSY;
usb_del_gadget_udc(&udc->gadget);
- device_unregister(&udc->gadget.dev);
debugfs_remove(udc->regs_info);
if (udc_info && !udc_info->udc_command &&
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 68d7bb06ebcb..1f5f978d35d5 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/device.h>
+#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -28,18 +29,6 @@
#define GS_VERSION_NAME GS_LONG_NAME " " GS_VERSION_STR
/*-------------------------------------------------------------------------*/
-
-/*
- * Kbuild is not very cooperative with respect to linking separately
- * compiled library objects into one module. So for now we won't use
- * separate compilation ... ensuring init/exit sections work to shrink
- * the runtime footprint, and giving us at least some parts of what
- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
- */
-#include "f_obex.c"
-#include "f_serial.c"
-
-/*-------------------------------------------------------------------------*/
USB_GADGET_COMPOSITE_OPTIONS();
/* Thanks to NetChip Technologies for donating this product ID.
@@ -126,27 +115,6 @@ module_param(n_ports, uint, 0);
MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
/*-------------------------------------------------------------------------*/
-static unsigned char tty_lines[MAX_U_SERIAL_PORTS];
-
-static int __init serial_bind_obex_config(struct usb_configuration *c)
-{
- unsigned i;
- int status = 0;
-
- for (i = 0; i < n_ports && status == 0; i++)
- status = obex_bind_config(c, tty_lines[i]);
- return status;
-}
-
-static int __init serial_bind_gser_config(struct usb_configuration *c)
-{
- unsigned i;
- int status = 0;
-
- for (i = 0; i < n_ports && status == 0; i++)
- status = gser_bind_config(c, tty_lines[i]);
- return status;
-}
static struct usb_configuration serial_config_driver = {
/* .label = f(use_acm) */
@@ -169,15 +137,12 @@ static int serial_register_ports(struct usb_composite_dev *cdev,
goto out;
for (i = 0; i < n_ports; i++) {
- struct f_serial_opts *opts;
fi_serial[i] = usb_get_function_instance(f_name);
if (IS_ERR(fi_serial[i])) {
ret = PTR_ERR(fi_serial[i]);
goto fail;
}
- opts = container_of(fi_serial[i], struct f_serial_opts, func_inst);
- opts->port_num = tty_lines[i];
f_serial[i] = usb_get_function(fi_serial[i]);
if (IS_ERR(f_serial[i])) {
@@ -212,13 +177,6 @@ out:
static int __init gs_bind(struct usb_composite_dev *cdev)
{
int status;
- int cur_line;
-
- for (cur_line = 0; cur_line < n_ports; cur_line++) {
- status = gserial_alloc_line(&tty_lines[cur_line]);
- if (status)
- goto fail;
- }
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
@@ -243,11 +201,12 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
"acm");
usb_ep_autoconfig_reset(cdev->gadget);
} else if (use_obex)
- status = usb_add_config(cdev, &serial_config_driver,
- serial_bind_obex_config);
- else
- status = usb_add_config(cdev, &serial_config_driver,
- serial_bind_gser_config);
+ status = serial_register_ports(cdev, &serial_config_driver,
+ "obex");
+ else {
+ status = serial_register_ports(cdev, &serial_config_driver,
+ "gser");
+ }
if (status < 0)
goto fail;
@@ -257,9 +216,6 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
return 0;
fail:
- cur_line--;
- while (cur_line >= 0)
- gserial_free_line(tty_lines[cur_line--]);
return status;
}
@@ -270,7 +226,6 @@ static int gs_unbind(struct usb_composite_dev *cdev)
for (i = 0; i < n_ports; i++) {
usb_put_function(f_serial[i]);
usb_put_function_instance(fi_serial[i]);
- gserial_free_line(tty_lines[i]);
}
return 0;
}
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index a0aa721d8b21..4b76124ce96b 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -50,7 +50,6 @@
struct eth_dev {
/* lock is held while accessing port_usb
- * or updating its backlink port_usb->ioport
*/
spinlock_t lock;
struct gether *port_usb;
@@ -729,8 +728,6 @@ static int get_ether_addr(const char *str, u8 *dev_addr)
return 1;
}
-static struct eth_dev *the_dev;
-
static const struct net_device_ops eth_netdev_ops = {
.ndo_open = eth_open,
.ndo_stop = eth_stop,
@@ -758,19 +755,16 @@ static struct device_type gadget_type = {
*
* Returns negative errno, or zero on success
*/
-int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
const char *netname)
{
struct eth_dev *dev;
struct net_device *net;
int status;
- if (the_dev)
- return -EBUSY;
-
net = alloc_etherdev(sizeof *dev);
if (!net)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
dev = netdev_priv(net);
spin_lock_init(&dev->lock);
@@ -807,12 +801,11 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
if (status < 0) {
dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
free_netdev(net);
+ dev = ERR_PTR(status);
} else {
INFO(dev, "MAC %pM\n", net->dev_addr);
INFO(dev, "HOST MAC %pM\n", dev->host_mac);
- the_dev = dev;
-
/* two kinds of host-initiated state changes:
* - iff DATA transfer is active, carrier is "on"
* - tx queueing enabled if open *and* carrier is "on"
@@ -820,7 +813,7 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
netif_carrier_off(net);
}
- return status;
+ return dev;
}
/**
@@ -829,19 +822,16 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
*
* This is called to free all resources allocated by @gether_setup().
*/
-void gether_cleanup(void)
+void gether_cleanup(struct eth_dev *dev)
{
- if (!the_dev)
+ if (!dev)
return;
- unregister_netdev(the_dev->net);
- flush_work(&the_dev->work);
- free_netdev(the_dev->net);
-
- the_dev = NULL;
+ unregister_netdev(dev->net);
+ flush_work(&dev->work);
+ free_netdev(dev->net);
}
-
/**
* gether_connect - notify network layer that USB link is active
* @link: the USB link, set up with endpoints, descriptors matching
@@ -860,7 +850,7 @@ void gether_cleanup(void)
*/
struct net_device *gether_connect(struct gether *link)
{
- struct eth_dev *dev = the_dev;
+ struct eth_dev *dev = link->ioport;
int result = 0;
if (!dev)
@@ -895,7 +885,6 @@ struct net_device *gether_connect(struct gether *link)
spin_lock(&dev->lock);
dev->port_usb = link;
- link->ioport = dev;
if (netif_running(dev->net)) {
if (link->open)
link->open(link);
@@ -989,6 +978,5 @@ void gether_disconnect(struct gether *link)
spin_lock(&dev->lock);
dev->port_usb = NULL;
- link->ioport = NULL;
spin_unlock(&dev->lock);
}
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 6f4a1623d854..02522338a708 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -21,6 +21,7 @@
#include "gadget_chips.h"
+struct eth_dev;
/*
* This represents the USB side of an "ethernet" link, managed by a USB
@@ -70,7 +71,7 @@ struct gether {
|USB_CDC_PACKET_TYPE_DIRECTED)
/* variant of gether_setup that allows customizing network device name */
-int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
const char *netname);
/* netdev setup/teardown as directed by the gadget driver */
@@ -86,12 +87,13 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
*
* Returns negative errno, or zero on success
*/
-static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
+static inline struct eth_dev *gether_setup(struct usb_gadget *g,
+ u8 ethaddr[ETH_ALEN])
{
return gether_setup_name(g, ethaddr, "usb");
}
-void gether_cleanup(void);
+void gether_cleanup(struct eth_dev *dev);
/* connect/disconnect is handled by individual functions */
struct net_device *gether_connect(struct gether *);
@@ -111,21 +113,24 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
}
/* each configuration may bind one instance of an ethernet link */
-int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int eem_bind_config(struct usb_configuration *c);
+int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev);
+int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev);
+int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev);
+int eem_bind_config(struct usb_configuration *c, struct eth_dev *dev);
#ifdef USB_ETH_RNDIS
int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
- u32 vendorID, const char *manufacturer);
+ u32 vendorID, const char *manufacturer, struct eth_dev *dev);
#else
static inline int
rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
- u32 vendorID, const char *manufacturer)
+ u32 vendorID, const char *manufacturer, struct eth_dev *dev)
{
return 0;
}
@@ -145,9 +150,9 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
* for calling @gether_cleanup() before module unload.
*/
static inline int rndis_bind_config(struct usb_configuration *c,
- u8 ethaddr[ETH_ALEN])
+ u8 ethaddr[ETH_ALEN], struct eth_dev *dev)
{
- return rndis_bind_config_vendor(c, ethaddr, 0, NULL);
+ return rndis_bind_config_vendor(c, ethaddr, 0, NULL, dev);
}
diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h
index 66ce73a00509..c20210c0babd 100644
--- a/drivers/usb/gadget/u_serial.h
+++ b/drivers/usb/gadget/u_serial.h
@@ -65,7 +65,6 @@ int gserial_connect(struct gserial *, u8 port_num);
void gserial_disconnect(struct gserial *);
/* functions are bound to configurations by a config or gadget driver */
-int acm_bind_config(struct usb_configuration *c, u8 port_num);
int gser_bind_config(struct usb_configuration *c, u8 port_num);
int obex_bind_config(struct usb_configuration *c, u8 port_num);
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index f8f62c3ed65e..ffd8fa541101 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -101,6 +101,16 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
/* ------------------------------------------------------------------------- */
+void usb_gadget_set_state(struct usb_gadget *gadget,
+ enum usb_device_state state)
+{
+ gadget->state = state;
+ sysfs_notify(&gadget->dev.kobj, NULL, "status");
+}
+EXPORT_SYMBOL_GPL(usb_gadget_set_state);
+
+/* ------------------------------------------------------------------------- */
+
/**
* usb_gadget_udc_start - tells usb device controller to start up
* @gadget: The gadget we want to get started
@@ -156,15 +166,23 @@ static void usb_udc_release(struct device *dev)
}
static const struct attribute_group *usb_udc_attr_groups[];
+
+static void usb_udc_nop_release(struct device *dev)
+{
+ dev_vdbg(dev, "%s\n", __func__);
+}
+
/**
- * usb_add_gadget_udc - adds a new gadget to the udc class driver list
- * @parent: the parent device to this udc. Usually the controller
- * driver's device.
- * @gadget: the gadget to be added to the list
+ * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller driver's
+ * device.
+ * @gadget: the gadget to be added to the list.
+ * @release: a gadget release function.
*
* Returns zero on success, negative errno otherwise.
*/
-int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
+ void (*release)(struct device *dev))
{
struct usb_udc *udc;
int ret = -ENOMEM;
@@ -173,6 +191,22 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
if (!udc)
goto err1;
+ dev_set_name(&gadget->dev, "gadget");
+ gadget->dev.parent = parent;
+
+ dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
+ gadget->dev.dma_parms = parent->dma_parms;
+ gadget->dev.dma_mask = parent->dma_mask;
+
+ if (release)
+ gadget->dev.release = release;
+ else
+ gadget->dev.release = usb_udc_nop_release;
+
+ ret = device_register(&gadget->dev);
+ if (ret)
+ goto err2;
+
device_initialize(&udc->dev);
udc->dev.release = usb_udc_release;
udc->dev.class = udc_class;
@@ -180,7 +214,7 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
udc->dev.parent = parent;
ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
if (ret)
- goto err2;
+ goto err3;
udc->gadget = gadget;
@@ -189,21 +223,42 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
ret = device_add(&udc->dev);
if (ret)
- goto err3;
+ goto err4;
+
+ usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
mutex_unlock(&udc_lock);
return 0;
-err3:
+
+err4:
list_del(&udc->list);
mutex_unlock(&udc_lock);
-err2:
+err3:
put_device(&udc->dev);
+err2:
+ put_device(&gadget->dev);
+ kfree(udc);
+
err1:
return ret;
}
+EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
+
+/**
+ * usb_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ *
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+{
+ return usb_add_gadget_udc_release(parent, gadget, NULL);
+}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
static void usb_gadget_remove_driver(struct usb_udc *udc)
@@ -220,6 +275,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
udc->driver = NULL;
udc->dev.driver = NULL;
+ udc->gadget->dev.driver = NULL;
}
/**
@@ -254,6 +310,7 @@ found:
kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
device_unregister(&udc->dev);
+ device_unregister(&gadget->dev);
}
EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
@@ -268,6 +325,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
udc->driver = driver;
udc->dev.driver = &driver->driver;
+ udc->gadget->dev.driver = &driver->driver;
ret = driver->bind(udc->gadget, driver);
if (ret)
@@ -286,6 +344,7 @@ err1:
udc->driver->function, ret);
udc->driver = NULL;
udc->dev.driver = NULL;
+ udc->gadget->dev.driver = NULL;
return ret;
}
@@ -395,6 +454,16 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
}
static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
+static ssize_t usb_gadget_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
+ struct usb_gadget *gadget = udc->gadget;
+
+ return sprintf(buf, "%s\n", usb_state_string(gadget->state));
+}
+static DEVICE_ATTR(state, S_IRUGO, usb_gadget_state_show, NULL);
+
#define USB_UDC_SPEED_ATTR(name, param) \
ssize_t usb_udc_##param##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
@@ -403,7 +472,7 @@ ssize_t usb_udc_##param##_show(struct device *dev, \
return snprintf(buf, PAGE_SIZE, "%s\n", \
usb_speed_string(udc->gadget->param)); \
} \
-static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL)
+static DEVICE_ATTR(name, S_IRUGO, usb_udc_##param##_show, NULL)
static USB_UDC_SPEED_ATTR(current_speed, speed);
static USB_UDC_SPEED_ATTR(maximum_speed, max_speed);
@@ -428,6 +497,7 @@ static USB_UDC_ATTR(a_alt_hnp_support);
static struct attribute *usb_udc_attrs[] = {
&dev_attr_srp.attr,
&dev_attr_soft_connect.attr,
+ &dev_attr_state.attr,
&dev_attr_current_speed.attr,
&dev_attr_maximum_speed.attr,
diff --git a/drivers/usb/gadget/uvc.h b/drivers/usb/gadget/uvc.h
index 93b0c1191115..817e9e19cecf 100644
--- a/drivers/usb/gadget/uvc.h
+++ b/drivers/usb/gadget/uvc.h
@@ -98,8 +98,6 @@ extern unsigned int uvc_gadget_trace_param;
#define DRIVER_VERSION "0.1.0"
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0)
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
#define UVC_NUM_REQUESTS 4
#define UVC_MAX_REQUEST_SIZE 64
#define UVC_MAX_EVENTS 4
@@ -190,6 +188,7 @@ struct uvc_file_handle
* Functions
*/
+extern void uvc_function_setup_continue(struct uvc_device *uvc);
extern void uvc_endpoint_stream(struct uvc_device *dev);
extern void uvc_function_connect(struct uvc_device *uvc);
diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c
index 104ae9c81251..7ce27e35550b 100644
--- a/drivers/usb/gadget/uvc_queue.c
+++ b/drivers/usb/gadget/uvc_queue.c
@@ -10,6 +10,7 @@
* (at your option) any later version.
*/
+#include <linux/atomic.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/list.h>
@@ -18,7 +19,8 @@
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
-#include <linux/atomic.h>
+
+#include <media/videobuf2-vmalloc.h>
#include "uvc.h"
@@ -28,330 +30,175 @@
* Video queues is initialized by uvc_queue_init(). The function performs
* basic initialization of the uvc_video_queue struct and never fails.
*
- * Video buffer allocation and freeing are performed by uvc_alloc_buffers and
- * uvc_free_buffers respectively. The former acquires the video queue lock,
- * while the later must be called with the lock held (so that allocation can
- * free previously allocated buffers). Trying to free buffers that are mapped
- * to user space will return -EBUSY.
- *
- * Video buffers are managed using two queues. However, unlike most USB video
- * drivers that use an in queue and an out queue, we use a main queue to hold
- * all queued buffers (both 'empty' and 'done' buffers), and an irq queue to
- * hold empty buffers. This design (copied from video-buf) minimizes locking
- * in interrupt, as only one queue is shared between interrupt and user
- * contexts.
- *
- * Use cases
- * ---------
- *
- * Unless stated otherwise, all operations that modify the irq buffers queue
- * are protected by the irq spinlock.
- *
- * 1. The user queues the buffers, starts streaming and dequeues a buffer.
- *
- * The buffers are added to the main and irq queues. Both operations are
- * protected by the queue lock, and the later is protected by the irq
- * spinlock as well.
- *
- * The completion handler fetches a buffer from the irq queue and fills it
- * with video data. If no buffer is available (irq queue empty), the handler
- * returns immediately.
- *
- * When the buffer is full, the completion handler removes it from the irq
- * queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue.
- * At that point, any process waiting on the buffer will be woken up. If a
- * process tries to dequeue a buffer after it has been marked ready, the
- * dequeing will succeed immediately.
- *
- * 2. Buffers are queued, user is waiting on a buffer and the device gets
- * disconnected.
- *
- * When the device is disconnected, the kernel calls the completion handler
- * with an appropriate status code. The handler marks all buffers in the
- * irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so
- * that any process waiting on a buffer gets woken up.
- *
- * Waking up up the first buffer on the irq list is not enough, as the
- * process waiting on the buffer might restart the dequeue operation
- * immediately.
- *
+ * Video buffers are managed by videobuf2. The driver uses a mutex to protect
+ * the videobuf2 queue operations by serializing calls to videobuf2 and a
+ * spinlock to protect the IRQ queue that holds the buffers to be processed by
+ * the driver.
*/
-static void
-uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
-{
- mutex_init(&queue->mutex);
- spin_lock_init(&queue->irqlock);
- INIT_LIST_HEAD(&queue->mainqueue);
- INIT_LIST_HEAD(&queue->irqqueue);
- queue->type = type;
-}
-
-/*
- * Free the video buffers.
- *
- * This function must be called with the queue lock held.
+/* -----------------------------------------------------------------------------
+ * videobuf2 queue operations
*/
-static int uvc_free_buffers(struct uvc_video_queue *queue)
+
+static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- unsigned int i;
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
+ struct uvc_video *video = container_of(queue, struct uvc_video, queue);
- for (i = 0; i < queue->count; ++i) {
- if (queue->buffer[i].vma_use_count != 0)
- return -EBUSY;
- }
+ if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
+ *nbuffers = UVC_MAX_VIDEO_BUFFERS;
- if (queue->count) {
- vfree(queue->mem);
- queue->count = 0;
- }
+ *nplanes = 1;
+
+ sizes[0] = video->imagesize;
return 0;
}
-/*
- * Allocate the video buffers.
- *
- * Pages are reserved to make sure they will not be swapped, as they will be
- * filled in the URB completion handler.
- *
- * Buffers will be individually mapped, so they must all be page aligned.
- */
-static int
-uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
- unsigned int buflength)
+static int uvc_buffer_prepare(struct vb2_buffer *vb)
{
- unsigned int bufsize = PAGE_ALIGN(buflength);
- unsigned int i;
- void *mem = NULL;
- int ret;
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+ struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
- if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
- nbuffers = UVC_MAX_VIDEO_BUFFERS;
+ if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
+ return -EINVAL;
+ }
- mutex_lock(&queue->mutex);
+ if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED))
+ return -ENODEV;
- if ((ret = uvc_free_buffers(queue)) < 0)
- goto done;
+ buf->state = UVC_BUF_STATE_QUEUED;
+ buf->mem = vb2_plane_vaddr(vb, 0);
+ buf->length = vb2_plane_size(vb, 0);
+ if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ buf->bytesused = 0;
+ else
+ buf->bytesused = vb2_get_plane_payload(vb, 0);
- /* Bail out if no buffers should be allocated. */
- if (nbuffers == 0)
- goto done;
+ return 0;
+}
- /* Decrement the number of buffers until allocation succeeds. */
- for (; nbuffers > 0; --nbuffers) {
- mem = vmalloc_32(nbuffers * bufsize);
- if (mem != NULL)
- break;
- }
+static void uvc_buffer_queue(struct vb2_buffer *vb)
+{
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+ struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
+ unsigned long flags;
- if (mem == NULL) {
- ret = -ENOMEM;
- goto done;
- }
+ spin_lock_irqsave(&queue->irqlock, flags);
- for (i = 0; i < nbuffers; ++i) {
- memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
- queue->buffer[i].buf.index = i;
- queue->buffer[i].buf.m.offset = i * bufsize;
- queue->buffer[i].buf.length = buflength;
- queue->buffer[i].buf.type = queue->type;
- queue->buffer[i].buf.sequence = 0;
- queue->buffer[i].buf.field = V4L2_FIELD_NONE;
- queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
- queue->buffer[i].buf.flags = 0;
- init_waitqueue_head(&queue->buffer[i].wait);
+ if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
+ list_add_tail(&buf->queue, &queue->irqqueue);
+ } else {
+ /* If the device is disconnected return the buffer to userspace
+ * directly. The next QBUF call will fail with -ENODEV.
+ */
+ buf->state = UVC_BUF_STATE_ERROR;
+ vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
}
- queue->mem = mem;
- queue->count = nbuffers;
- queue->buf_size = bufsize;
- ret = nbuffers;
-
-done:
- mutex_unlock(&queue->mutex);
- return ret;
+ spin_unlock_irqrestore(&queue->irqlock, flags);
}
-static void __uvc_query_buffer(struct uvc_buffer *buf,
- struct v4l2_buffer *v4l2_buf)
-{
- memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
-
- if (buf->vma_use_count)
- v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
-
- switch (buf->state) {
- case UVC_BUF_STATE_ERROR:
- case UVC_BUF_STATE_DONE:
- v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
- break;
- case UVC_BUF_STATE_QUEUED:
- case UVC_BUF_STATE_ACTIVE:
- v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
- break;
- case UVC_BUF_STATE_IDLE:
- default:
- break;
- }
-}
+static struct vb2_ops uvc_queue_qops = {
+ .queue_setup = uvc_queue_setup,
+ .buf_prepare = uvc_buffer_prepare,
+ .buf_queue = uvc_buffer_queue,
+};
-static int
-uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf)
+static int uvc_queue_init(struct uvc_video_queue *queue,
+ enum v4l2_buf_type type)
{
- int ret = 0;
+ int ret;
- mutex_lock(&queue->mutex);
- if (v4l2_buf->index >= queue->count) {
- ret = -EINVAL;
- goto done;
- }
+ queue->queue.type = type;
+ queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
+ queue->queue.drv_priv = queue;
+ queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
+ queue->queue.ops = &uvc_queue_qops;
+ queue->queue.mem_ops = &vb2_vmalloc_memops;
+ ret = vb2_queue_init(&queue->queue);
+ if (ret)
+ return ret;
+
+ mutex_init(&queue->mutex);
+ spin_lock_init(&queue->irqlock);
+ INIT_LIST_HEAD(&queue->irqqueue);
+ queue->flags = 0;
- __uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
+ return 0;
+}
-done:
+/*
+ * Free the video buffers.
+ */
+static void uvc_free_buffers(struct uvc_video_queue *queue)
+{
+ mutex_lock(&queue->mutex);
+ vb2_queue_release(&queue->queue);
mutex_unlock(&queue->mutex);
- return ret;
}
/*
- * Queue a video buffer. Attempting to queue a buffer that has already been
- * queued will return -EINVAL.
+ * Allocate the video buffers.
*/
-static int
-uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf)
+static int uvc_alloc_buffers(struct uvc_video_queue *queue,
+ struct v4l2_requestbuffers *rb)
{
- struct uvc_buffer *buf;
- unsigned long flags;
- int ret = 0;
+ int ret;
- uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
+ mutex_lock(&queue->mutex);
+ ret = vb2_reqbufs(&queue->queue, rb);
+ mutex_unlock(&queue->mutex);
- if (v4l2_buf->type != queue->type ||
- v4l2_buf->memory != V4L2_MEMORY_MMAP) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
- "and/or memory (%u).\n", v4l2_buf->type,
- v4l2_buf->memory);
- return -EINVAL;
- }
+ return ret ? ret : rb->count;
+}
- mutex_lock(&queue->mutex);
- if (v4l2_buf->index >= queue->count) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
- ret = -EINVAL;
- goto done;
- }
+static int uvc_query_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *buf)
+{
+ int ret;
- buf = &queue->buffer[v4l2_buf->index];
- if (buf->state != UVC_BUF_STATE_IDLE) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
- "(%u).\n", buf->state);
- ret = -EINVAL;
- goto done;
- }
+ mutex_lock(&queue->mutex);
+ ret = vb2_querybuf(&queue->queue, buf);
+ mutex_unlock(&queue->mutex);
- if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- v4l2_buf->bytesused > buf->buf.length) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
- ret = -EINVAL;
- goto done;
- }
+ return ret;
+}
- if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- buf->buf.bytesused = 0;
- else
- buf->buf.bytesused = v4l2_buf->bytesused;
+static int uvc_queue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *buf)
+{
+ unsigned long flags;
+ int ret;
+ mutex_lock(&queue->mutex);
+ ret = vb2_qbuf(&queue->queue, buf);
spin_lock_irqsave(&queue->irqlock, flags);
- if (queue->flags & UVC_QUEUE_DISCONNECTED) {
- spin_unlock_irqrestore(&queue->irqlock, flags);
- ret = -ENODEV;
- goto done;
- }
- buf->state = UVC_BUF_STATE_QUEUED;
-
ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
queue->flags &= ~UVC_QUEUE_PAUSED;
-
- list_add_tail(&buf->stream, &queue->mainqueue);
- list_add_tail(&buf->queue, &queue->irqqueue);
spin_unlock_irqrestore(&queue->irqlock, flags);
-
-done:
mutex_unlock(&queue->mutex);
- return ret;
-}
-static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
-{
- if (nonblocking) {
- return (buf->state != UVC_BUF_STATE_QUEUED &&
- buf->state != UVC_BUF_STATE_ACTIVE)
- ? 0 : -EAGAIN;
- }
-
- return wait_event_interruptible(buf->wait,
- buf->state != UVC_BUF_STATE_QUEUED &&
- buf->state != UVC_BUF_STATE_ACTIVE);
+ return ret;
}
/*
* Dequeue a video buffer. If nonblocking is false, block until a buffer is
* available.
*/
-static int
-uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf,
- int nonblocking)
+static int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *buf, int nonblocking)
{
- struct uvc_buffer *buf;
- int ret = 0;
-
- if (v4l2_buf->type != queue->type ||
- v4l2_buf->memory != V4L2_MEMORY_MMAP) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
- "and/or memory (%u).\n", v4l2_buf->type,
- v4l2_buf->memory);
- return -EINVAL;
- }
+ int ret;
mutex_lock(&queue->mutex);
- if (list_empty(&queue->mainqueue)) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
- ret = -EINVAL;
- goto done;
- }
-
- buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
- if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0)
- goto done;
-
- uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n",
- buf->buf.index, buf->state, buf->buf.bytesused);
-
- switch (buf->state) {
- case UVC_BUF_STATE_ERROR:
- uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data "
- "(transmission error).\n");
- ret = -EIO;
- case UVC_BUF_STATE_DONE:
- buf->state = UVC_BUF_STATE_IDLE;
- break;
-
- case UVC_BUF_STATE_IDLE:
- case UVC_BUF_STATE_QUEUED:
- case UVC_BUF_STATE_ACTIVE:
- default:
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
- "(driver bug?).\n", buf->state);
- ret = -EINVAL;
- goto done;
- }
-
- list_del(&buf->stream);
- __uvc_query_buffer(buf, v4l2_buf);
-
-done:
+ ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
mutex_unlock(&queue->mutex);
+
return ret;
}
@@ -361,105 +208,47 @@ done:
* This function implements video queue polling and is intended to be used by
* the device poll handler.
*/
-static unsigned int
-uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
- poll_table *wait)
+static unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
+ struct file *file, poll_table *wait)
{
- struct uvc_buffer *buf;
- unsigned int mask = 0;
+ unsigned int ret;
mutex_lock(&queue->mutex);
- if (list_empty(&queue->mainqueue))
- goto done;
-
- buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
-
- poll_wait(file, &buf->wait, wait);
- if (buf->state == UVC_BUF_STATE_DONE ||
- buf->state == UVC_BUF_STATE_ERROR)
- mask |= POLLOUT | POLLWRNORM;
-
-done:
+ ret = vb2_poll(&queue->queue, file, wait);
mutex_unlock(&queue->mutex);
- return mask;
-}
-/*
- * VMA operations.
- */
-static void uvc_vm_open(struct vm_area_struct *vma)
-{
- struct uvc_buffer *buffer = vma->vm_private_data;
- buffer->vma_use_count++;
+ return ret;
}
-static void uvc_vm_close(struct vm_area_struct *vma)
+static int uvc_queue_mmap(struct uvc_video_queue *queue,
+ struct vm_area_struct *vma)
{
- struct uvc_buffer *buffer = vma->vm_private_data;
- buffer->vma_use_count--;
-}
+ int ret;
-static struct vm_operations_struct uvc_vm_ops = {
- .open = uvc_vm_open,
- .close = uvc_vm_close,
-};
+ mutex_lock(&queue->mutex);
+ ret = vb2_mmap(&queue->queue, vma);
+ mutex_unlock(&queue->mutex);
+
+ return ret;
+}
+#ifndef CONFIG_MMU
/*
- * Memory-map a buffer.
+ * Get unmapped area.
*
- * This function implements video buffer memory mapping and is intended to be
- * used by the device mmap handler.
+ * NO-MMU arch need this function to make mmap() work correctly.
*/
-static int
-uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
+static unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+ unsigned long pgoff)
{
- struct uvc_buffer *uninitialized_var(buffer);
- struct page *page;
- unsigned long addr, start, size;
- unsigned int i;
- int ret = 0;
-
- start = vma->vm_start;
- size = vma->vm_end - vma->vm_start;
+ unsigned long ret;
mutex_lock(&queue->mutex);
-
- for (i = 0; i < queue->count; ++i) {
- buffer = &queue->buffer[i];
- if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
-
- if (i == queue->count || size != queue->buf_size) {
- ret = -EINVAL;
- goto done;
- }
-
- /*
- * VM_IO marks the area as being an mmaped region for I/O to a
- * device. It also prevents the region from being core dumped.
- */
- vma->vm_flags |= VM_IO;
-
- addr = (unsigned long)queue->mem + buffer->buf.m.offset;
- while (size > 0) {
- page = vmalloc_to_page((void *)addr);
- if ((ret = vm_insert_page(vma, start, page)) < 0)
- goto done;
-
- start += PAGE_SIZE;
- addr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- vma->vm_ops = &uvc_vm_ops;
- vma->vm_private_data = buffer;
- uvc_vm_open(vma);
-
-done:
+ ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
mutex_unlock(&queue->mutex);
return ret;
}
+#endif
/*
* Cancel the video buffers queue.
@@ -484,7 +273,7 @@ static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
queue);
list_del(&buf->queue);
buf->state = UVC_BUF_STATE_ERROR;
- wake_up(&buf->wait);
+ vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
}
/* This must be protected by the irqlock spinlock to avoid race
* conditions between uvc_queue_buffer and the disconnection event that
@@ -516,26 +305,33 @@ static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
*/
static int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
{
- unsigned int i;
+ unsigned long flags;
int ret = 0;
mutex_lock(&queue->mutex);
if (enable) {
- if (uvc_queue_streaming(queue)) {
- ret = -EBUSY;
+ ret = vb2_streamon(&queue->queue, queue->queue.type);
+ if (ret < 0)
goto done;
- }
+
queue->sequence = 0;
- queue->flags |= UVC_QUEUE_STREAMING;
queue->buf_used = 0;
} else {
- uvc_queue_cancel(queue, 0);
- INIT_LIST_HEAD(&queue->mainqueue);
+ ret = vb2_streamoff(&queue->queue, queue->queue.type);
+ if (ret < 0)
+ goto done;
- for (i = 0; i < queue->count; ++i)
- queue->buffer[i].state = UVC_BUF_STATE_IDLE;
+ spin_lock_irqsave(&queue->irqlock, flags);
+ INIT_LIST_HEAD(&queue->irqqueue);
- queue->flags &= ~UVC_QUEUE_STREAMING;
+ /*
+ * FIXME: We need to clear the DISCONNECTED flag to ensure that
+ * applications will be able to queue buffers for the next
+ * streaming run. However, clearing it here doesn't guarantee
+ * that the device will be reconnected in the meantime.
+ */
+ queue->flags &= ~UVC_QUEUE_DISCONNECTED;
+ spin_unlock_irqrestore(&queue->irqlock, flags);
}
done:
@@ -544,15 +340,15 @@ done:
}
/* called with &queue_irqlock held.. */
-static struct uvc_buffer *
-uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf)
+static struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+ struct uvc_buffer *buf)
{
struct uvc_buffer *nextbuf;
if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
- buf->buf.length != buf->buf.bytesused) {
+ buf->length != buf->bytesused) {
buf->state = UVC_BUF_STATE_QUEUED;
- buf->buf.bytesused = 0;
+ vb2_set_plane_payload(&buf->buf, 0, 0);
return buf;
}
@@ -563,10 +359,18 @@ uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf)
else
nextbuf = NULL;
- buf->buf.sequence = queue->sequence++;
- do_gettimeofday(&buf->buf.timestamp);
+ /*
+ * FIXME: with videobuf2, the sequence number or timestamp fields
+ * are valid only for video capture devices and the UVC gadget usually
+ * is a video output device. Keeping these until the specs are clear on
+ * this aspect.
+ */
+ buf->buf.v4l2_buf.sequence = queue->sequence++;
+ do_gettimeofday(&buf->buf.v4l2_buf.timestamp);
+
+ vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);
+ vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
- wake_up(&buf->wait);
return nextbuf;
}
diff --git a/drivers/usb/gadget/uvc_queue.h b/drivers/usb/gadget/uvc_queue.h
index 1812a8ecc5d0..8e76ce982f1e 100644
--- a/drivers/usb/gadget/uvc_queue.h
+++ b/drivers/usb/gadget/uvc_queue.h
@@ -6,6 +6,7 @@
#include <linux/kernel.h>
#include <linux/poll.h>
#include <linux/videodev2.h>
+#include <media/videobuf2-core.h>
/* Maximum frame size in bytes, for sanity checking. */
#define UVC_MAX_FRAME_SIZE (16*1024*1024)
@@ -25,42 +26,35 @@ enum uvc_buffer_state {
};
struct uvc_buffer {
- unsigned long vma_use_count;
- struct list_head stream;
-
- /* Touched by interrupt handler. */
- struct v4l2_buffer buf;
+ struct vb2_buffer buf;
struct list_head queue;
- wait_queue_head_t wait;
+
enum uvc_buffer_state state;
+ void *mem;
+ unsigned int length;
+ unsigned int bytesused;
};
-#define UVC_QUEUE_STREAMING (1 << 0)
-#define UVC_QUEUE_DISCONNECTED (1 << 1)
-#define UVC_QUEUE_DROP_INCOMPLETE (1 << 2)
-#define UVC_QUEUE_PAUSED (1 << 3)
+#define UVC_QUEUE_DISCONNECTED (1 << 0)
+#define UVC_QUEUE_DROP_INCOMPLETE (1 << 1)
+#define UVC_QUEUE_PAUSED (1 << 2)
struct uvc_video_queue {
- enum v4l2_buf_type type;
+ struct vb2_queue queue;
+ struct mutex mutex; /* Protects queue */
- void *mem;
unsigned int flags;
__u32 sequence;
- unsigned int count;
- unsigned int buf_size;
unsigned int buf_used;
- struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
- struct mutex mutex; /* protects buffers and mainqueue */
- spinlock_t irqlock; /* protects irqqueue */
- struct list_head mainqueue;
+ spinlock_t irqlock; /* Protects flags and irqqueue */
struct list_head irqqueue;
};
static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
{
- return queue->flags & UVC_QUEUE_STREAMING;
+ return vb2_is_streaming(&queue->queue);
}
#endif /* __KERNEL__ */
diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c
index 2ca9386d655b..ad48e81155e2 100644
--- a/drivers/usb/gadget/uvc_v4l2.c
+++ b/drivers/usb/gadget/uvc_v4l2.c
@@ -41,9 +41,8 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
req->length = min_t(unsigned int, uvc->event_length, data->length);
req->zero = data->length < uvc->event_length;
- req->dma = DMA_ADDR_INVALID;
- memcpy(req->buf, data->data, data->length);
+ memcpy(req->buf, data->data, req->length);
return usb_ep_queue(cdev->gadget->ep0, req, GFP_KERNEL);
}
@@ -148,16 +147,13 @@ uvc_v4l2_release(struct file *file)
uvc_function_disconnect(uvc);
uvc_video_enable(video, 0);
- mutex_lock(&video->queue.mutex);
- if (uvc_free_buffers(&video->queue) < 0)
- printk(KERN_ERR "uvc_v4l2_release: Unable to free "
- "buffers.\n");
- mutex_unlock(&video->queue.mutex);
+ uvc_free_buffers(&video->queue);
file->private_data = NULL;
v4l2_fh_del(&handle->vfh);
v4l2_fh_exit(&handle->vfh);
kfree(handle);
+
return 0;
}
@@ -178,9 +174,9 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_capability *cap = arg;
memset(cap, 0, sizeof *cap);
- strncpy(cap->driver, "g_uvc", sizeof(cap->driver));
- strncpy(cap->card, cdev->gadget->name, sizeof(cap->card));
- strncpy(cap->bus_info, dev_name(&cdev->gadget->dev),
+ strlcpy(cap->driver, "g_uvc", sizeof(cap->driver));
+ strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
+ strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
sizeof cap->bus_info);
cap->version = DRIVER_VERSION_NUMBER;
cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
@@ -192,7 +188,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct v4l2_format *fmt = arg;
- if (fmt->type != video->queue.type)
+ if (fmt->type != video->queue.queue.type)
return -EINVAL;
return uvc_v4l2_get_format(video, fmt);
@@ -202,7 +198,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct v4l2_format *fmt = arg;
- if (fmt->type != video->queue.type)
+ if (fmt->type != video->queue.queue.type)
return -EINVAL;
return uvc_v4l2_set_format(video, fmt);
@@ -213,16 +209,13 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct v4l2_requestbuffers *rb = arg;
- if (rb->type != video->queue.type ||
- rb->memory != V4L2_MEMORY_MMAP)
+ if (rb->type != video->queue.queue.type)
return -EINVAL;
- ret = uvc_alloc_buffers(&video->queue, rb->count,
- video->imagesize);
+ ret = uvc_alloc_buffers(&video->queue, rb);
if (ret < 0)
return ret;
- rb->count = ret;
ret = 0;
break;
}
@@ -231,9 +224,6 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct v4l2_buffer *buf = arg;
- if (buf->type != video->queue.type)
- return -EINVAL;
-
return uvc_query_buffer(&video->queue, buf);
}
@@ -251,24 +241,36 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
int *type = arg;
- if (*type != video->queue.type)
+ if (*type != video->queue.queue.type)
return -EINVAL;
- return uvc_video_enable(video, 1);
+ /* Enable UVC video. */
+ ret = uvc_video_enable(video, 1);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Complete the alternate setting selection setup phase now that
+ * userspace is ready to provide video frames.
+ */
+ uvc_function_setup_continue(uvc);
+ uvc->state = UVC_STATE_STREAMING;
+
+ return 0;
}
case VIDIOC_STREAMOFF:
{
int *type = arg;
- if (*type != video->queue.type)
+ if (*type != video->queue.queue.type)
return -EINVAL;
return uvc_video_enable(video, 0);
}
/* Events */
- case VIDIOC_DQEVENT:
+ case VIDIOC_DQEVENT:
{
struct v4l2_event *event = arg;
@@ -333,17 +335,21 @@ uvc_v4l2_poll(struct file *file, poll_table *wait)
{
struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev);
- struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
- unsigned int mask = 0;
- poll_wait(file, &handle->vfh.wait, wait);
- if (v4l2_event_pending(&handle->vfh))
- mask |= POLLPRI;
+ return uvc_queue_poll(&uvc->video.queue, file, wait);
+}
- mask |= uvc_queue_poll(&uvc->video.queue, file, wait);
+#ifndef CONFIG_MMU
+static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_device *uvc = video_get_drvdata(vdev);
- return mask;
+ return uvc_queue_get_unmapped_area(&uvc->video.queue, pgoff);
}
+#endif
static struct v4l2_file_operations uvc_v4l2_fops = {
.owner = THIS_MODULE,
@@ -352,5 +358,8 @@ static struct v4l2_file_operations uvc_v4l2_fops = {
.ioctl = uvc_v4l2_ioctl,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
+#ifndef CONFIG_MMU
+ .get_unmapped_area = uvc_v4l2_get_unmapped_area,
+#endif
};
diff --git a/drivers/usb/gadget/uvc_video.c b/drivers/usb/gadget/uvc_video.c
index b0e53a8ea4f7..71e896d4c5ae 100644
--- a/drivers/usb/gadget/uvc_video.c
+++ b/drivers/usb/gadget/uvc_video.c
@@ -32,7 +32,7 @@ uvc_video_encode_header(struct uvc_video *video, struct uvc_buffer *buf,
data[0] = 2;
data[1] = UVC_STREAM_EOH | video->fid;
- if (buf->buf.bytesused - video->queue.buf_used <= len - 2)
+ if (buf->bytesused - video->queue.buf_used <= len - 2)
data[1] |= UVC_STREAM_EOF;
return 2;
@@ -47,8 +47,8 @@ uvc_video_encode_data(struct uvc_video *video, struct uvc_buffer *buf,
void *mem;
/* Copy video data to the USB buffer. */
- mem = queue->mem + buf->buf.m.offset + queue->buf_used;
- nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
+ mem = buf->mem + queue->buf_used;
+ nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used);
memcpy(data, mem, nbytes);
queue->buf_used += nbytes;
@@ -82,7 +82,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
req->length = video->req_size - len;
req->zero = video->payload_size == video->max_payload_size;
- if (buf->buf.bytesused == video->queue.buf_used) {
+ if (buf->bytesused == video->queue.buf_used) {
video->queue.buf_used = 0;
buf->state = UVC_BUF_STATE_DONE;
uvc_queue_next_buffer(&video->queue, buf);
@@ -92,7 +92,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
}
if (video->payload_size == video->max_payload_size ||
- buf->buf.bytesused == video->queue.buf_used)
+ buf->bytesused == video->queue.buf_used)
video->payload_size = 0;
}
@@ -115,7 +115,7 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
req->length = video->req_size - len;
- if (buf->buf.bytesused == video->queue.buf_used) {
+ if (buf->bytesused == video->queue.buf_used) {
video->queue.buf_used = 0;
buf->state = UVC_BUF_STATE_DONE;
uvc_queue_next_buffer(&video->queue, buf);
@@ -161,6 +161,7 @@ static void
uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
{
struct uvc_video *video = req->context;
+ struct uvc_video_queue *queue = &video->queue;
struct uvc_buffer *buf;
unsigned long flags;
int ret;
@@ -169,13 +170,15 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
case 0:
break;
- case -ESHUTDOWN:
+ case -ESHUTDOWN: /* disconnect from host. */
printk(KERN_INFO "VS request cancelled.\n");
+ uvc_queue_cancel(queue, 1);
goto requeue;
default:
printk(KERN_INFO "VS request completed with status %d.\n",
req->status);
+ uvc_queue_cancel(queue, 0);
goto requeue;
}
@@ -229,13 +232,18 @@ uvc_video_free_requests(struct uvc_video *video)
static int
uvc_video_alloc_requests(struct uvc_video *video)
{
+ unsigned int req_size;
unsigned int i;
int ret = -ENOMEM;
BUG_ON(video->req_size);
+ req_size = video->ep->maxpacket
+ * max_t(unsigned int, video->ep->maxburst, 1)
+ * (video->ep->mult + 1);
+
for (i = 0; i < UVC_NUM_REQUESTS; ++i) {
- video->req_buffer[i] = kmalloc(video->ep->maxpacket, GFP_KERNEL);
+ video->req_buffer[i] = kmalloc(req_size, GFP_KERNEL);
if (video->req_buffer[i] == NULL)
goto error;
@@ -245,14 +253,14 @@ uvc_video_alloc_requests(struct uvc_video *video)
video->req[i]->buf = video->req_buffer[i];
video->req[i]->length = 0;
- video->req[i]->dma = DMA_ADDR_INVALID;
video->req[i]->complete = uvc_video_complete;
video->req[i]->context = video;
list_add_tail(&video->req[i]->list, &video->req_free);
}
- video->req_size = video->ep->maxpacket;
+ video->req_size = req_size;
+
return 0;
error:
@@ -309,7 +317,8 @@ uvc_video_pump(struct uvc_video *video)
video->encode(req, video, buf);
/* Queue the USB request */
- if ((ret = usb_ep_queue(video->ep, req, GFP_KERNEL)) < 0) {
+ ret = usb_ep_queue(video->ep, req, GFP_ATOMIC);
+ if (ret < 0) {
printk(KERN_INFO "Failed to queue request (%d)\n", ret);
usb_ep_set_halt(video->ep);
spin_unlock_irqrestore(&video->queue.irqlock, flags);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 2f682219e257..f7af0984743b 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -180,6 +180,7 @@ config USB_EHCI_TEGRA
boolean "NVIDIA Tegra HCD support"
depends on USB_EHCI_HCD && ARCH_TEGRA
select USB_EHCI_ROOT_HUB_TT
+ select USB_PHY
help
This driver enables support for the internal USB Host Controllers
found in NVIDIA Tegra SoCs. The controllers are EHCI compliant.
@@ -301,7 +302,6 @@ config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
- select USB_OTG_UTILS if ARCH_OMAP
depends on USB_ISP1301 || !ARCH_LPC32XX
---help---
The Open Host Controller Interface (OHCI) is a standard for accessing
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 88a49c87e748..ebf410311957 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -145,7 +145,7 @@ static int ehci_msm_probe(struct platform_device *pdev)
* management.
*/
phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(phy)) {
+ if (IS_ERR(phy)) {
dev_err(&pdev->dev, "unable to find transceiver\n");
ret = -ENODEV;
goto put_hcd;
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index 5cd9f96ed92d..402062973f03 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -33,25 +33,17 @@ struct ehci_hcd_mv {
struct mv_usb_platform_data *pdata;
- /* clock source and total clock number */
- unsigned int clknum;
- struct clk *clk[0];
+ struct clk *clk;
};
static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv)
{
- unsigned int i;
-
- for (i = 0; i < ehci_mv->clknum; i++)
- clk_prepare_enable(ehci_mv->clk[i]);
+ clk_prepare_enable(ehci_mv->clk);
}
static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv)
{
- unsigned int i;
-
- for (i = 0; i < ehci_mv->clknum; i++)
- clk_disable_unprepare(ehci_mv->clk[i]);
+ clk_disable_unprepare(ehci_mv->clk);
}
static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
@@ -144,9 +136,8 @@ static int mv_ehci_probe(struct platform_device *pdev)
struct ehci_hcd *ehci;
struct ehci_hcd_mv *ehci_mv;
struct resource *r;
- int clk_i, retval = -ENODEV;
+ int retval = -ENODEV;
u32 offset;
- size_t size;
if (!pdata) {
dev_err(&pdev->dev, "missing platform_data\n");
@@ -160,8 +151,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
if (!hcd)
return -ENOMEM;
- size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum;
- ehci_mv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ ehci_mv = devm_kzalloc(&pdev->dev, sizeof(*ehci_mv), GFP_KERNEL);
if (ehci_mv == NULL) {
dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n");
retval = -ENOMEM;
@@ -172,16 +162,11 @@ static int mv_ehci_probe(struct platform_device *pdev)
ehci_mv->pdata = pdata;
ehci_mv->hcd = hcd;
- ehci_mv->clknum = pdata->clknum;
- for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) {
- ehci_mv->clk[clk_i] =
- devm_clk_get(&pdev->dev, pdata->clkname[clk_i]);
- if (IS_ERR(ehci_mv->clk[clk_i])) {
- dev_err(&pdev->dev, "error get clck \"%s\"\n",
- pdata->clkname[clk_i]);
- retval = PTR_ERR(ehci_mv->clk[clk_i]);
- goto err_clear_drvdata;
- }
+ ehci_mv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(ehci_mv->clk)) {
+ dev_err(&pdev->dev, "error getting clock\n");
+ retval = PTR_ERR(ehci_mv->clk);
+ goto err_clear_drvdata;
}
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs");
@@ -240,12 +225,16 @@ static int mv_ehci_probe(struct platform_device *pdev)
ehci_mv->mode = pdata->mode;
if (ehci_mv->mode == MV_USB_MODE_OTG) {
-#ifdef CONFIG_USB_OTG_UTILS
ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(ehci_mv->otg)) {
- dev_err(&pdev->dev,
- "unable to find transceiver\n");
- retval = -ENODEV;
+ if (IS_ERR(ehci_mv->otg)) {
+ retval = PTR_ERR(ehci_mv->otg);
+
+ if (retval == -ENXIO)
+ dev_info(&pdev->dev, "MV_USB_MODE_OTG "
+ "must have CONFIG_USB_PHY enabled\n");
+ else
+ dev_err(&pdev->dev,
+ "unable to find transceiver\n");
goto err_disable_clk;
}
@@ -258,11 +247,6 @@ static int mv_ehci_probe(struct platform_device *pdev)
}
/* otg will enable clock before use as host */
mv_ehci_disable(ehci_mv);
-#else
- dev_info(&pdev->dev, "MV_USB_MODE_OTG "
- "must have CONFIG_USB_OTG_UTILS enabled\n");
- goto err_disable_clk;
-#endif
} else {
if (pdata->set_vbus)
pdata->set_vbus(1);
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index 738490e6d429..43a2a16732f5 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -140,7 +140,7 @@ static int s5p_ehci_probe(struct platform_device *pdev)
return -ENOMEM;
phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(phy)) {
+ if (IS_ERR(phy)) {
/* Fallback to pdata */
if (!pdata) {
dev_warn(&pdev->dev, "no platform data or transceiver defined\n");
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 4f3cfb83f862..ed201ae879cb 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -773,16 +773,14 @@ static int tegra_ehci_probe(struct platform_device *pdev)
goto fail_phy;
}
-#ifdef CONFIG_USB_OTG_UTILS
if (pdata->operating_mode == TEGRA_USB_OTG) {
tegra->transceiver =
devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
- if (!IS_ERR_OR_NULL(tegra->transceiver))
+ if (!IS_ERR(tegra->transceiver))
otg_set_host(tegra->transceiver->otg, &hcd->self);
} else {
tegra->transceiver = ERR_PTR(-ENODEV);
}
-#endif
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
@@ -801,10 +799,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
return err;
fail:
-#ifdef CONFIG_USB_OTG_UTILS
- if (!IS_ERR_OR_NULL(tegra->transceiver))
+ if (!IS_ERR(tegra->transceiver))
otg_set_host(tegra->transceiver->otg, NULL);
-#endif
fail_phy:
usb_phy_shutdown(hcd->phy);
fail_io:
@@ -823,10 +819,8 @@ static int tegra_ehci_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
-#ifdef CONFIG_USB_OTG_UTILS
- if (!IS_ERR_OR_NULL(tegra->transceiver))
+ if (!IS_ERR(tegra->transceiver))
otg_set_host(tegra->transceiver->otg, NULL);
-#endif
usb_phy_shutdown(hcd->phy);
usb_remove_hcd(hcd);
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index e3b7e85120e4..4b469e050208 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -128,7 +128,7 @@ static int exynos_ohci_probe(struct platform_device *pdev)
return -ENOMEM;
phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(phy)) {
+ if (IS_ERR(phy)) {
/* Fallback to pdata */
if (!pdata) {
dev_warn(&pdev->dev, "no platform data or transceiver defined\n");
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 05e51432dd2f..47442d35b6fc 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -7,7 +7,6 @@
config USB_MUSB_HDRC
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
depends on USB && USB_GADGET
- select USB_OTG_UTILS
help
Say Y here if your system has a dual role high speed USB
controller based on the Mentor Graphics silicon IP. Then
@@ -34,10 +33,12 @@ choice
config USB_MUSB_DAVINCI
tristate "DaVinci"
depends on ARCH_DAVINCI_DMx
+ depends on BROKEN
config USB_MUSB_DA8XX
tristate "DA8xx/OMAP-L1x"
depends on ARCH_DAVINCI_DA8XX
+ depends on BROKEN
config USB_MUSB_TUSB6010
tristate "TUSB6010"
@@ -53,7 +54,6 @@ config USB_MUSB_AM35X
config USB_MUSB_DSPS
tristate "TI DSPS platforms"
- depends on SOC_TI81XX || SOC_AM33XX
config USB_MUSB_BLACKFIN
tristate "Blackfin"
@@ -61,12 +61,12 @@ config USB_MUSB_BLACKFIN
config USB_MUSB_UX500
tristate "U8500 and U5500"
- depends on (ARCH_U8500 && AB8500_USB)
endchoice
choice
prompt 'MUSB DMA mode'
+ default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM
default USB_UX500_DMA if USB_MUSB_UX500
default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index 59eea219034a..2231850c0625 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -149,7 +149,7 @@ static void otg_timer(unsigned long _musb)
*/
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) {
@@ -195,7 +195,7 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
if (musb->is_active || (musb->a_wait_bcon == 0 &&
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&otg_workaround);
last_timer = jiffies;
return;
@@ -208,7 +208,7 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies));
mod_timer(&otg_workaround, timeout);
}
@@ -298,7 +298,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
/* NOTE: this must complete power-on within 100 ms. */
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "",
devctl);
ret = IRQ_HANDLED;
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index dbb31b30c7fa..5e63b160db0c 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -280,13 +280,13 @@ static void musb_conn_timer_handler(unsigned long _musb)
break;
default:
dev_dbg(musb->controller, "%s state not handled\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
break;
}
spin_unlock_irqrestore(&musb->lock, flags);
dev_dbg(musb->controller, "state is %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
static void bfin_musb_enable(struct musb *musb)
@@ -307,7 +307,7 @@ static void bfin_musb_set_vbus(struct musb *musb, int is_on)
dev_dbg(musb->controller, "VBUS %s, devctl %02x "
/* otg %3x conf %08x prcm %08x */ "\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
musb_readb(musb->mregs, MUSB_DEVCTL));
}
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index f522000e8f06..9db211ee15b5 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -435,7 +435,6 @@ cppi_rndis_update(struct cppi_channel *c, int is_rx,
}
}
-#ifdef CONFIG_USB_MUSB_DEBUG
static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
{
pr_debug("RXBD/%s %08x: "
@@ -444,21 +443,16 @@ static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
bd->hw_next, bd->hw_bufp, bd->hw_off_len,
bd->hw_options);
}
-#endif
static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx)
{
-#ifdef CONFIG_USB_MUSB_DEBUG
struct cppi_descriptor *bd;
- if (!_dbg_level(level))
- return;
cppi_dump_rx(level, rx, tag);
if (rx->last_processed)
cppi_dump_rxbd("last", rx->last_processed);
for (bd = rx->head; bd; bd = bd->next)
cppi_dump_rxbd("active", bd);
-#endif
}
@@ -784,6 +778,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
void __iomem *tibase = musb->ctrl_base;
int is_rndis = 0;
struct cppi_rx_stateram __iomem *rx_ram = rx->state_ram;
+ struct cppi_descriptor *d;
if (onepacket) {
/* almost every USB driver, host or peripheral side */
@@ -897,14 +892,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
bd->hw_options |= CPPI_SOP_SET;
tail->hw_options |= CPPI_EOP_SET;
-#ifdef CONFIG_USB_MUSB_DEBUG
- if (_dbg_level(5)) {
- struct cppi_descriptor *d;
-
- for (d = rx->head; d; d = d->next)
- cppi_dump_rxbd("S", d);
- }
-#endif
+ for (d = rx->head; d; d = d->next)
+ cppi_dump_rxbd("S", d);
/* in case the preceding transfer left some state... */
tail = rx->last_processed;
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 41613a2b35e8..b903b744a224 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -198,7 +198,7 @@ static void otg_timer(unsigned long _musb)
*/
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) {
@@ -267,7 +267,7 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
if (musb->is_active || (musb->a_wait_bcon == 0 &&
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&otg_workaround);
last_timer = jiffies;
return;
@@ -280,7 +280,7 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies));
mod_timer(&otg_workaround, timeout);
}
@@ -360,7 +360,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "",
devctl);
ret = IRQ_HANDLED;
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index e040d9103735..bea6cc35471c 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -215,7 +215,7 @@ static void otg_timer(unsigned long _musb)
*/
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl,
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) {
@@ -349,7 +349,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
davinci_musb_source_power(musb, drvvbus, 0);
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "",
devctl);
retval = IRQ_HANDLED;
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index daec6e0f7e38..37a261a6bb6a 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -372,13 +372,13 @@ static void musb_otg_timer_func(unsigned long data)
case OTG_STATE_A_SUSPEND:
case OTG_STATE_A_WAIT_BCON:
dev_dbg(musb->controller, "HNP: %s timeout\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
musb_platform_set_vbus(musb, 0);
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
break;
default:
dev_dbg(musb->controller, "HNP: Unhandled mode %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
musb->ignore_disconnect = 0;
spin_unlock_irqrestore(&musb->lock, flags);
@@ -393,13 +393,14 @@ void musb_hnp_stop(struct musb *musb)
void __iomem *mbase = musb->mregs;
u8 reg;
- dev_dbg(musb->controller, "HNP: stop from %s\n", otg_state_string(musb->xceiv->state));
+ dev_dbg(musb->controller, "HNP: stop from %s\n",
+ usb_otg_state_string(musb->xceiv->state));
switch (musb->xceiv->state) {
case OTG_STATE_A_PERIPHERAL:
musb_g_disconnect(musb);
dev_dbg(musb->controller, "HNP: back to %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
break;
case OTG_STATE_B_HOST:
dev_dbg(musb->controller, "HNP: Disabling HR\n");
@@ -413,7 +414,7 @@ void musb_hnp_stop(struct musb *musb)
break;
default:
dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
/*
@@ -451,7 +452,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
*/
if (int_usb & MUSB_INTR_RESUME) {
handled = IRQ_HANDLED;
- dev_dbg(musb->controller, "RESUME (%s)\n", otg_state_string(musb->xceiv->state));
+ dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->state));
if (devctl & MUSB_DEVCTL_HM) {
void __iomem *mbase = musb->mregs;
@@ -493,7 +494,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
default:
WARNING("bogus %s RESUME (%s)\n",
"host",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
} else {
switch (musb->xceiv->state) {
@@ -522,7 +523,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
default:
WARNING("bogus %s RESUME (%s)\n",
"peripheral",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
}
@@ -538,7 +539,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
}
dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
/* IRQ arrives from ID pin sense or (later, if VBUS power
* is removed) SRP. responses are time critical:
@@ -602,8 +603,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
break;
}
- dev_dbg(musb->controller, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
- otg_state_string(musb->xceiv->state),
+ dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller,
+ "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
+ usb_otg_state_string(musb->xceiv->state),
devctl,
({ char *s;
switch (devctl & MUSB_DEVCTL_VBUS) {
@@ -628,7 +630,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
if (int_usb & MUSB_INTR_SUSPEND) {
dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n",
- otg_state_string(musb->xceiv->state), devctl);
+ usb_otg_state_string(musb->xceiv->state), devctl);
handled = IRQ_HANDLED;
switch (musb->xceiv->state) {
@@ -745,12 +747,12 @@ b_host:
usb_hcd_resume_root_hub(hcd);
dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n",
- otg_state_string(musb->xceiv->state), devctl);
+ usb_otg_state_string(musb->xceiv->state), devctl);
}
if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
MUSB_MODE(musb), devctl);
handled = IRQ_HANDLED;
@@ -787,7 +789,7 @@ b_host:
break;
default:
WARNING("unhandled DISCONNECT transition (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
break;
}
}
@@ -813,7 +815,7 @@ b_host:
}
} else {
dev_dbg(musb->controller, "BUS RESET as %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
switch (musb->xceiv->state) {
case OTG_STATE_A_SUSPEND:
/* We need to ignore disconnect on suspend
@@ -826,7 +828,7 @@ b_host:
case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */
/* never use invalid T(a_wait_bcon) */
dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
TA_WAIT_BCON(musb));
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(TA_WAIT_BCON(musb)));
@@ -838,7 +840,7 @@ b_host:
break;
case OTG_STATE_B_WAIT_ACON:
dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
musb_g_reset(musb);
break;
@@ -850,7 +852,7 @@ b_host:
break;
default:
dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
}
@@ -1632,7 +1634,7 @@ musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
int ret = -EINVAL;
spin_lock_irqsave(&musb->lock, flags);
- ret = sprintf(buf, "%s\n", otg_state_string(musb->xceiv->state));
+ ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->state));
spin_unlock_irqrestore(&musb->lock, flags);
return ret;
@@ -1951,9 +1953,13 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
musb_write_ulpi_buscontrol(musb->mregs, busctl);
}
- MUSB_DEV_MODE(musb);
- musb->xceiv->otg->default_a = 0;
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ if (musb->xceiv->otg->default_a) {
+ MUSB_HST_MODE(musb);
+ musb->xceiv->state = OTG_STATE_A_IDLE;
+ } else {
+ MUSB_DEV_MODE(musb);
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ }
status = musb_gadget_setup(musb);
@@ -2008,7 +2014,6 @@ static int musb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int irq = platform_get_irq_byname(pdev, "mc");
- int status;
struct resource *iomem;
void __iomem *base;
@@ -2016,24 +2021,17 @@ static int musb_probe(struct platform_device *pdev)
if (!iomem || irq <= 0)
return -ENODEV;
- base = ioremap(iomem->start, resource_size(iomem));
- if (!base) {
- dev_err(dev, "ioremap failed\n");
- return -ENOMEM;
- }
+ base = devm_ioremap_resource(dev, iomem);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
- status = musb_init_controller(dev, irq, base);
- if (status < 0)
- iounmap(base);
-
- return status;
+ return musb_init_controller(dev, irq, base);
}
static int musb_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct musb *musb = dev_to_musb(dev);
- void __iomem *ctrl_base = musb->ctrl_base;
/* this gets called on rmmod.
* - Host mode: host may still be active
@@ -2044,7 +2042,6 @@ static int musb_remove(struct platform_device *pdev)
musb_shutdown(pdev);
musb_free(musb);
- iounmap(ctrl_base);
device_init_wakeup(dev, 0);
#ifndef CONFIG_MUSB_PIO_ONLY
dma_set_mask(dev, *dev->parent->dma_mask);
@@ -2293,8 +2290,6 @@ static int __init musb_init(void)
if (usb_disabled())
return 0;
- pr_info("%s: version " MUSB_VERSION ", ?dma?, otg (peripheral+host)\n",
- musb_driver_name);
return platform_driver_register(&musb_driver);
}
module_init(musb_init);
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 6bb89715b637..3a18e44e9391 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -38,6 +38,7 @@
#include <linux/module.h>
#include <linux/usb/nop-usb-xceiv.h>
#include <linux/platform_data/usb-omap.h>
+#include <linux/sizes.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -224,7 +225,7 @@ static void otg_timer(unsigned long _musb)
*/
devctl = dsps_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) {
@@ -273,7 +274,7 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
if (musb->is_active || (musb->a_wait_bcon == 0 &&
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&glue->timer[pdev->id]);
glue->last_timer[pdev->id] = jiffies;
return;
@@ -288,7 +289,7 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
glue->last_timer[pdev->id] = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies));
mod_timer(&glue->timer[pdev->id], timeout);
}
@@ -334,7 +335,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
* value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
* Also, DRVVBUS pulses for SRP (but not at 5V) ...
*/
- if (usbintr & MUSB_INTR_BABBLE)
+ if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE)
pr_info("CAUTION: musb: Babble Interrupt Occurred\n");
if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
@@ -377,7 +378,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
/* NOTE: this must complete power-on within 100 ms. */
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "",
devctl);
ret = IRQ_HANDLED;
@@ -596,14 +597,13 @@ err0:
static int dsps_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
const struct dsps_musb_wrapper *wrp;
struct dsps_glue *glue;
struct resource *iomem;
int ret, i;
- match = of_match_node(musb_dsps_of_match, np);
+ match = of_match_node(musb_dsps_of_match, pdev->dev.of_node);
if (!match) {
dev_err(&pdev->dev, "fail to get matching of_match struct\n");
ret = -EINVAL;
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 83eddedcd9be..ba7092349fa9 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -46,48 +46,6 @@
#include "musb_core.h"
-/* MUSB PERIPHERAL status 3-mar-2006:
- *
- * - EP0 seems solid. It passes both USBCV and usbtest control cases.
- * Minor glitches:
- *
- * + remote wakeup to Linux hosts work, but saw USBCV failures;
- * in one test run (operator error?)
- * + endpoint halt tests -- in both usbtest and usbcv -- seem
- * to break when dma is enabled ... is something wrongly
- * clearing SENDSTALL?
- *
- * - Mass storage behaved ok when last tested. Network traffic patterns
- * (with lots of short transfers etc) need retesting; they turn up the
- * worst cases of the DMA, since short packets are typical but are not
- * required.
- *
- * - TX/IN
- * + both pio and dma behave in with network and g_zero tests
- * + no cppi throughput issues other than no-hw-queueing
- * + failed with FLAT_REG (DaVinci)
- * + seems to behave with double buffering, PIO -and- CPPI
- * + with gadgetfs + AIO, requests got lost?
- *
- * - RX/OUT
- * + both pio and dma behave in with network and g_zero tests
- * + dma is slow in typical case (short_not_ok is clear)
- * + double buffering ok with PIO
- * + double buffering *FAILS* with CPPI, wrong data bytes sometimes
- * + request lossage observed with gadgetfs
- *
- * - ISO not tested ... might work, but only weakly isochronous
- *
- * - Gadget driver disabling of softconnect during bind() is ignored; so
- * drivers can't hold off host requests until userspace is ready.
- * (Workaround: they can turn it off later.)
- *
- * - PORTABILITY (assumes PIO works):
- * + DaVinci, basically works with cppi dma
- * + OMAP 2430, ditto with mentor dma
- * + TUSB 6010, platform-specific dma in the works
- */
-
/* ----------------------------------------------------------------------- */
#define is_buffer_mapped(req) (is_dma_capable() && \
@@ -280,41 +238,6 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep)
return ep->packet_sz;
}
-
-#ifdef CONFIG_USB_INVENTRA_DMA
-
-/* Peripheral tx (IN) using Mentor DMA works as follows:
- Only mode 0 is used for transfers <= wPktSize,
- mode 1 is used for larger transfers,
-
- One of the following happens:
- - Host sends IN token which causes an endpoint interrupt
- -> TxAvail
- -> if DMA is currently busy, exit.
- -> if queue is non-empty, txstate().
-
- - Request is queued by the gadget driver.
- -> if queue was previously empty, txstate()
-
- txstate()
- -> start
- /\ -> setup DMA
- | (data is transferred to the FIFO, then sent out when
- | IN token(s) are recd from Host.
- | -> DMA interrupt on completion
- | calls TxAvail.
- | -> stop DMA, ~DMAENAB,
- | -> set TxPktRdy for last short pkt or zlp
- | -> Complete Request
- | -> Continue next request (call txstate)
- |___________________________________|
-
- * Non-Mentor DMA engines can of course work differently, such as by
- * upleveling from irq-per-packet to irq-per-buffer.
- */
-
-#endif
-
/*
* An endpoint is transmitting data. This can be called either from
* the IRQ routine or from ep.queue() to kickstart a request on an
@@ -621,37 +544,6 @@ void musb_g_tx(struct musb *musb, u8 epnum)
/* ------------------------------------------------------------ */
-#ifdef CONFIG_USB_INVENTRA_DMA
-
-/* Peripheral rx (OUT) using Mentor DMA works as follows:
- - Only mode 0 is used.
-
- - Request is queued by the gadget class driver.
- -> if queue was previously empty, rxstate()
-
- - Host sends OUT token which causes an endpoint interrupt
- /\ -> RxReady
- | -> if request queued, call rxstate
- | /\ -> setup DMA
- | | -> DMA interrupt on completion
- | | -> RxReady
- | | -> stop DMA
- | | -> ack the read
- | | -> if data recd = max expected
- | | by the request, or host
- | | sent a short packet,
- | | complete the request,
- | | and start the next one.
- | |_____________________________________|
- | else just wait for the host
- | to send the next OUT token.
- |__________________________________________________|
-
- * Non-Mentor DMA engines can of course work differently.
- */
-
-#endif
-
/*
* Context: controller locked, IRQs blocked, endpoint selected
*/
@@ -740,7 +632,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
struct dma_controller *c;
struct dma_channel *channel;
int use_dma = 0;
- int transfer_size;
+ unsigned int transfer_size;
c = musb->dma_controller;
channel = musb_ep->dma;
@@ -782,10 +674,11 @@ static void rxstate(struct musb *musb, struct musb_request *req)
csr | MUSB_RXCSR_DMAMODE);
musb_writew(epio, MUSB_RXCSR, csr);
- transfer_size = min(request->length - request->actual,
+ transfer_size = min_t(unsigned int,
+ request->length -
+ request->actual,
channel->max_len);
musb_ep->dma->desired_mode = 1;
-
} else {
if (!musb_ep->hb_mult &&
musb_ep->hw_ep->rx_double_buffered)
@@ -815,7 +708,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
struct dma_controller *c;
struct dma_channel *channel;
- int transfer_size = 0;
+ unsigned int transfer_size = 0;
c = musb->dma_controller;
channel = musb_ep->dma;
@@ -824,11 +717,13 @@ static void rxstate(struct musb *musb, struct musb_request *req)
if (fifo_count < musb_ep->packet_sz)
transfer_size = fifo_count;
else if (request->short_not_ok)
- transfer_size = min(request->length -
+ transfer_size = min_t(unsigned int,
+ request->length -
request->actual,
channel->max_len);
else
- transfer_size = min(request->length -
+ transfer_size = min_t(unsigned int,
+ request->length -
request->actual,
(unsigned)fifo_count);
@@ -1681,7 +1576,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
goto done;
default:
dev_dbg(musb->controller, "Unhandled wake: %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
goto done;
}
@@ -1801,13 +1696,6 @@ static const struct usb_gadget_ops musb_gadget_operations = {
* all peripheral ports are external...
*/
-static void musb_gadget_release(struct device *dev)
-{
- /* kref_put(WHAT) */
- dev_dbg(dev, "%s\n", __func__);
-}
-
-
static void
init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
{
@@ -1892,12 +1780,7 @@ int musb_gadget_setup(struct musb *musb)
musb->g.speed = USB_SPEED_UNKNOWN;
/* this "gadget" abstracts/virtualizes the controller */
- dev_set_name(&musb->g.dev, "gadget");
- musb->g.dev.parent = musb->controller;
- musb->g.dev.dma_mask = musb->controller->dma_mask;
- musb->g.dev.release = musb_gadget_release;
musb->g.name = musb_driver_name;
-
musb->g.is_otg = 1;
musb_g_init_endpoints(musb);
@@ -1905,11 +1788,6 @@ int musb_gadget_setup(struct musb *musb)
musb->is_active = 0;
musb_platform_try_idle(musb, 0);
- status = device_register(&musb->g.dev);
- if (status != 0) {
- put_device(&musb->g.dev);
- return status;
- }
status = usb_add_gadget_udc(musb->controller, &musb->g);
if (status)
goto err;
@@ -1924,8 +1802,6 @@ err:
void musb_gadget_cleanup(struct musb *musb)
{
usb_del_gadget_udc(&musb->g);
- if (musb->g.dev.parent)
- device_unregister(&musb->g.dev);
}
/*
@@ -1977,9 +1853,8 @@ static int musb_gadget_start(struct usb_gadget *g,
goto err;
}
- if ((musb->xceiv->last_event == USB_EVENT_ID)
- && otg->set_vbus)
- otg_set_vbus(otg, 1);
+ if (musb->xceiv->last_event == USB_EVENT_ID)
+ musb_platform_set_vbus(musb, 1);
hcd->self.uses_pio_for_control = 1;
@@ -2063,6 +1938,7 @@ static int musb_gadget_stop(struct usb_gadget *g,
dev_dbg(musb->controller, "unregistering driver %s\n", driver->function);
musb->is_active = 0;
+ musb->gadget_driver = NULL;
musb_platform_try_idle(musb, 0);
spin_unlock_irqrestore(&musb->lock, flags);
@@ -2099,7 +1975,7 @@ void musb_g_resume(struct musb *musb)
break;
default:
WARNING("unhandled RESUME transition (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
@@ -2129,7 +2005,7 @@ void musb_g_suspend(struct musb *musb)
* A_PERIPHERAL may need care too
*/
WARNING("unhandled SUSPEND transition (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
@@ -2163,7 +2039,7 @@ void musb_g_disconnect(struct musb *musb)
switch (musb->xceiv->state) {
default:
dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
musb->xceiv->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
break;
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index c9c1ac4e075f..2af45a0c8930 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -505,8 +505,10 @@ static void ep0_rxstate(struct musb *musb)
req->status = -EOVERFLOW;
count = len;
}
- musb_read_fifo(&musb->endpoints[0], count, buf);
- req->actual += count;
+ if (count > 0) {
+ musb_read_fifo(&musb->endpoints[0], count, buf);
+ req->actual += count;
+ }
csr = MUSB_CSR0_P_SVDRXPKTRDY;
if (count < 64 || req->actual == req->length) {
musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 1ce1fcf3f3e7..8914dec49f01 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -2453,7 +2453,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
if (musb->is_active) {
WARNING("trying to suspend as %s while active\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
return -EBUSY;
} else
return 0;
@@ -2465,6 +2465,118 @@ static int musb_bus_resume(struct usb_hcd *hcd)
return 0;
}
+
+#ifndef CONFIG_MUSB_PIO_ONLY
+
+#define MUSB_USB_DMA_ALIGN 4
+
+struct musb_temp_buffer {
+ void *kmalloc_ptr;
+ void *old_xfer_buffer;
+ u8 data[0];
+};
+
+static void musb_free_temp_buffer(struct urb *urb)
+{
+ enum dma_data_direction dir;
+ struct musb_temp_buffer *temp;
+
+ if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
+ return;
+
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+ temp = container_of(urb->transfer_buffer, struct musb_temp_buffer,
+ data);
+
+ if (dir == DMA_FROM_DEVICE) {
+ memcpy(temp->old_xfer_buffer, temp->data,
+ urb->transfer_buffer_length);
+ }
+ urb->transfer_buffer = temp->old_xfer_buffer;
+ kfree(temp->kmalloc_ptr);
+
+ urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
+}
+
+static int musb_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
+{
+ enum dma_data_direction dir;
+ struct musb_temp_buffer *temp;
+ void *kmalloc_ptr;
+ size_t kmalloc_size;
+
+ if (urb->num_sgs || urb->sg ||
+ urb->transfer_buffer_length == 0 ||
+ !((uintptr_t)urb->transfer_buffer & (MUSB_USB_DMA_ALIGN - 1)))
+ return 0;
+
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+ /* Allocate a buffer with enough padding for alignment */
+ kmalloc_size = urb->transfer_buffer_length +
+ sizeof(struct musb_temp_buffer) + MUSB_USB_DMA_ALIGN - 1;
+
+ kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
+ if (!kmalloc_ptr)
+ return -ENOMEM;
+
+ /* Position our struct temp_buffer such that data is aligned */
+ temp = PTR_ALIGN(kmalloc_ptr, MUSB_USB_DMA_ALIGN);
+
+
+ temp->kmalloc_ptr = kmalloc_ptr;
+ temp->old_xfer_buffer = urb->transfer_buffer;
+ if (dir == DMA_TO_DEVICE)
+ memcpy(temp->data, urb->transfer_buffer,
+ urb->transfer_buffer_length);
+ urb->transfer_buffer = temp->data;
+
+ urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
+
+ return 0;
+}
+
+static int musb_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct musb *musb = hcd_to_musb(hcd);
+ int ret;
+
+ /*
+ * The DMA engine in RTL1.8 and above cannot handle
+ * DMA addresses that are not aligned to a 4 byte boundary.
+ * For such engine implemented (un)map_urb_for_dma hooks.
+ * Do not use these hooks for RTL<1.8
+ */
+ if (musb->hwvers < MUSB_HWVERS_1800)
+ return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+
+ ret = musb_alloc_temp_buffer(urb, mem_flags);
+ if (ret)
+ return ret;
+
+ ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+ if (ret)
+ musb_free_temp_buffer(urb);
+
+ return ret;
+}
+
+static void musb_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ struct musb *musb = hcd_to_musb(hcd);
+
+ usb_hcd_unmap_urb_for_dma(hcd, urb);
+
+ /* Do not use this hook for RTL<1.8 (see description above) */
+ if (musb->hwvers < MUSB_HWVERS_1800)
+ return;
+
+ musb_free_temp_buffer(urb);
+}
+#endif /* !CONFIG_MUSB_PIO_ONLY */
+
const struct hc_driver musb_hc_driver = {
.description = "musb-hcd",
.product_desc = "MUSB HDRC host driver",
@@ -2484,6 +2596,11 @@ const struct hc_driver musb_hc_driver = {
.urb_dequeue = musb_urb_dequeue,
.endpoint_disable = musb_h_disable,
+#ifndef CONFIG_MUSB_PIO_ONLY
+ .map_urb_for_dma = musb_map_urb_for_dma,
+ .unmap_urb_for_dma = musb_unmap_urb_for_dma,
+#endif
+
.hub_status_data = musb_hub_status_data,
.hub_control = musb_hub_control,
.bus_suspend = musb_bus_suspend,
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index f70579154ded..ef7d11045f56 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -95,7 +95,7 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
break;
default:
dev_dbg(musb->controller, "bogus rh suspend? %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
} else if (power & MUSB_POWER_SUSPENDM) {
power &= ~MUSB_POWER_SUSPENDM;
@@ -203,7 +203,7 @@ void musb_root_disconnect(struct musb *musb)
break;
default:
dev_dbg(musb->controller, "host disconnect (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 1a42a458f2c4..3551f1a30c65 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -117,7 +117,7 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
if (musb->is_active || ((musb->a_wait_bcon == 0)
&& (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&musb_idle_timer);
last_timer = jiffies;
return;
@@ -134,7 +134,7 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
(unsigned long)jiffies_to_msecs(timeout - jiffies));
mod_timer(&musb_idle_timer, timeout);
}
@@ -174,8 +174,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
}
}
- if (otg->set_vbus)
- otg_set_vbus(otg, 1);
+ otg_set_vbus(otg, 1);
} else {
musb->is_active = 1;
otg->default_a = 1;
@@ -200,7 +199,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
dev_dbg(musb->controller, "VBUS %s, devctl %02x "
/* otg %3x conf %08x prcm %08x */ "\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
musb_readb(musb->mregs, MUSB_DEVCTL));
}
@@ -292,14 +291,14 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
musb->xceiv->last_event = USB_EVENT_NONE;
if (musb->gadget_driver) {
+ omap2430_musb_set_vbus(musb, 0);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
}
- if (data->interface_type == MUSB_INTERFACE_UTMI) {
- if (musb->xceiv->otg->set_vbus)
- otg_set_vbus(musb->xceiv->otg, 0);
- }
+ if (data->interface_type == MUSB_INTERFACE_UTMI)
+ otg_set_vbus(musb->xceiv->otg, 0);
+
omap_control_usb_set_mode(glue->control_otghs,
USB_MODE_DISCONNECT);
break;
@@ -355,7 +354,12 @@ static int omap2430_musb_init(struct musb *musb)
else
musb->xceiv = devm_usb_get_phy_dev(dev, 0);
- if (IS_ERR_OR_NULL(musb->xceiv)) {
+ if (IS_ERR(musb->xceiv)) {
+ status = PTR_ERR(musb->xceiv);
+
+ if (status == -ENXIO)
+ return status;
+
pr_err("HS USB OTG: no transceiver configured\n");
return -EPROBE_DEFER;
}
@@ -393,6 +397,8 @@ static int omap2430_musb_init(struct musb *musb)
if (glue->status != OMAP_MUSB_UNKNOWN)
omap_musb_set_mailbox(glue);
+ usb_phy_init(musb->xceiv);
+
pm_runtime_put_noidle(musb->controller);
return 0;
@@ -526,10 +532,10 @@ static int omap2430_probe(struct platform_device *pdev)
}
of_property_read_u32(np, "mode", (u32 *)&pdata->mode);
- of_property_read_u32(np, "interface_type",
+ of_property_read_u32(np, "interface-type",
(u32 *)&data->interface_type);
- of_property_read_u32(np, "num_eps", (u32 *)&config->num_eps);
- of_property_read_u32(np, "ram_bits", (u32 *)&config->ram_bits);
+ of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
+ of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
of_property_read_u32(np, "power", (u32 *)&pdata->power);
config->multipoint = of_property_read_bool(np, "multipoint");
pdata->has_mailbox = of_property_read_bool(np,
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 464bd23cccda..7369ba33c94f 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -423,7 +423,7 @@ static void musb_do_idle(unsigned long _musb)
&& (musb->idle_timeout == 0
|| time_after(jiffies, musb->idle_timeout))) {
dev_dbg(musb->controller, "Nothing connected %s, turning off VBUS\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
/* FALLTHROUGH */
case OTG_STATE_A_IDLE:
@@ -478,7 +478,7 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)
if (musb->is_active || ((musb->a_wait_bcon == 0)
&& (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&musb_idle_timer);
last_timer = jiffies;
return;
@@ -495,7 +495,7 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
(unsigned long)jiffies_to_msecs(timeout - jiffies));
mod_timer(&musb_idle_timer, timeout);
}
@@ -571,7 +571,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
dev_dbg(musb->controller, "VBUS %s, devctl %02x otg %3x conf %08x prcm %08x\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
musb_readb(musb->mregs, MUSB_DEVCTL),
musb_readl(tbase, TUSB_DEV_OTG_STAT),
conf, prcm);
@@ -678,13 +678,13 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
musb->is_active = 0;
}
dev_dbg(musb->controller, "vbus change, %s, otg %03x\n",
- otg_state_string(musb->xceiv->state), otg_stat);
+ usb_otg_state_string(musb->xceiv->state), otg_stat);
idle_timeout = jiffies + (1 * HZ);
schedule_work(&musb->irq_work);
} else /* A-dev state machine */ {
dev_dbg(musb->controller, "vbus change, %s, otg %03x\n",
- otg_state_string(musb->xceiv->state), otg_stat);
+ usb_otg_state_string(musb->xceiv->state), otg_stat);
switch (musb->xceiv->state) {
case OTG_STATE_A_IDLE:
@@ -733,7 +733,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
u8 devctl;
dev_dbg(musb->controller, "%s timer, %03x\n",
- otg_state_string(musb->xceiv->state), otg_stat);
+ usb_otg_state_string(musb->xceiv->state), otg_stat);
switch (musb->xceiv->state) {
case OTG_STATE_A_WAIT_VRISE:
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index 13a392913769..2c80004e0a83 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -26,6 +26,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/usb/musb-ux500.h>
#include "musb_core.h"
@@ -36,6 +37,98 @@ struct ux500_glue {
};
#define glue_to_musb(g) platform_get_drvdata(g->musb)
+static void ux500_musb_set_vbus(struct musb *musb, int is_on)
+{
+ u8 devctl;
+ unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+ /* HDRC controls CPEN, but beware current surges during device
+ * connect. They can trigger transient overcurrent conditions
+ * that must be ignored.
+ */
+
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+ if (is_on) {
+ if (musb->xceiv->state == OTG_STATE_A_IDLE) {
+ /* start the session */
+ devctl |= MUSB_DEVCTL_SESSION;
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+ /*
+ * Wait for the musb to set as A device to enable the
+ * VBUS
+ */
+ while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(musb->controller,
+ "configured as A device timeout");
+ break;
+ }
+ }
+
+ } else {
+ musb->is_active = 1;
+ musb->xceiv->otg->default_a = 1;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ devctl |= MUSB_DEVCTL_SESSION;
+ MUSB_HST_MODE(musb);
+ }
+ } else {
+ musb->is_active = 0;
+
+ /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and jumping
+ * right to B_IDLE...
+ */
+ musb->xceiv->otg->default_a = 0;
+ devctl &= ~MUSB_DEVCTL_SESSION;
+ MUSB_DEV_MODE(musb);
+ }
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+ /*
+ * Devctl values will be updated after vbus goes below
+ * session_valid. The time taken depends on the capacitance
+ * on VBUS line. The max discharge time can be upto 1 sec
+ * as per the spec. Typically on our platform, it is 200ms
+ */
+ if (!is_on)
+ mdelay(200);
+
+ dev_dbg(musb->controller, "VBUS %s, devctl %02x\n",
+ usb_otg_state_string(musb->xceiv->state),
+ musb_readb(musb->mregs, MUSB_DEVCTL));
+}
+
+static int musb_otg_notifications(struct notifier_block *nb,
+ unsigned long event, void *unused)
+{
+ struct musb *musb = container_of(nb, struct musb, nb);
+
+ dev_dbg(musb->controller, "musb_otg_notifications %ld %s\n",
+ event, usb_otg_state_string(musb->xceiv->state));
+
+ switch (event) {
+ case UX500_MUSB_ID:
+ dev_dbg(musb->controller, "ID GND\n");
+ ux500_musb_set_vbus(musb, 1);
+ break;
+ case UX500_MUSB_VBUS:
+ dev_dbg(musb->controller, "VBUS Connect\n");
+ break;
+ case UX500_MUSB_NONE:
+ dev_dbg(musb->controller, "VBUS Disconnect\n");
+ if (is_host_active(musb))
+ ux500_musb_set_vbus(musb, 0);
+ else
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ break;
+ default:
+ dev_dbg(musb->controller, "ID float\n");
+ return NOTIFY_DONE;
+ }
+ return NOTIFY_OK;
+}
+
static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
{
unsigned long flags;
@@ -58,12 +151,21 @@ static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
static int ux500_musb_init(struct musb *musb)
{
+ int status;
+
musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (IS_ERR_OR_NULL(musb->xceiv)) {
pr_err("HS USB OTG: no transceiver configured\n");
return -EPROBE_DEFER;
}
+ musb->nb.notifier_call = musb_otg_notifications;
+ status = usb_register_notifier(musb->xceiv, &musb->nb);
+ if (status < 0) {
+ dev_dbg(musb->controller, "notification register failed\n");
+ return status;
+ }
+
musb->isr = ux500_musb_interrupt;
return 0;
@@ -71,6 +173,8 @@ static int ux500_musb_init(struct musb *musb)
static int ux500_musb_exit(struct musb *musb)
{
+ usb_unregister_notifier(musb->xceiv, &musb->nb);
+
usb_put_phy(musb->xceiv);
return 0;
@@ -79,6 +183,8 @@ static int ux500_musb_exit(struct musb *musb)
static const struct musb_platform_ops ux500_ops = {
.init = ux500_musb_init,
.exit = ux500_musb_exit,
+
+ .set_vbus = ux500_musb_set_vbus,
};
static int ux500_probe(struct platform_device *pdev)
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index 039e567dd3b6..338120641145 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -1,7 +1,7 @@
/*
* drivers/usb/musb/ux500_dma.c
*
- * U8500 and U5500 DMA support code
+ * U8500 DMA support code
*
* Copyright (C) 2009 STMicroelectronics
* Copyright (C) 2011 ST-Ericsson SA
@@ -30,6 +30,7 @@
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/pfn.h>
+#include <linux/sizes.h>
#include <linux/platform_data/usb-musb-ux500.h>
#include "musb_core.h"
@@ -56,7 +57,7 @@ struct ux500_dma_controller {
};
/* Work function invoked from DMA callback to handle rx transfers. */
-void ux500_dma_callback(void *private_data)
+static void ux500_dma_callback(void *private_data)
{
struct dma_channel *channel = private_data;
struct ux500_dma_channel *ux500_channel = channel->private_data;
@@ -93,8 +94,9 @@ static bool ux500_configure_channel(struct dma_channel *channel,
struct musb *musb = ux500_channel->controller->private_data;
dev_dbg(musb->controller,
- "packet_sz=%d, mode=%d, dma_addr=0x%x, len=%d is_tx=%d\n",
- packet_sz, mode, dma_addr, len, ux500_channel->is_tx);
+ "packet_sz=%d, mode=%d, dma_addr=0x%llu, len=%d is_tx=%d\n",
+ packet_sz, mode, (unsigned long long) dma_addr,
+ len, ux500_channel->is_tx);
ux500_channel->cur_len = len;
@@ -191,7 +193,7 @@ static int ux500_dma_is_compatible(struct dma_channel *channel,
u16 maxpacket, void *buf, u32 length)
{
if ((maxpacket & 0x3) ||
- ((int)buf & 0x3) ||
+ ((unsigned long int) buf & 0x3) ||
(length < 512) ||
(length & 0x3))
return false;
@@ -372,12 +374,17 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
controller = kzalloc(sizeof(*controller), GFP_KERNEL);
if (!controller)
- return NULL;
+ goto kzalloc_fail;
controller->private_data = musb;
/* Save physical address for DMA controller. */
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iomem) {
+ dev_err(musb->controller, "no memory resource defined\n");
+ goto plat_get_fail;
+ }
+
controller->phy_base = (dma_addr_t) iomem->start;
controller->controller.start = ux500_dma_controller_start;
@@ -389,4 +396,9 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
controller->controller.is_compatible = ux500_dma_is_compatible;
return &controller->controller;
+
+plat_get_fail:
+ kfree(controller);
+kzalloc_fail:
+ return NULL;
}
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
deleted file mode 100644
index 37962c99ff1e..000000000000
--- a/drivers/usb/otg/Kconfig
+++ /dev/null
@@ -1,141 +0,0 @@
-#
-# USB OTG infrastructure may be needed for peripheral-only, host-only,
-# or OTG-capable configurations when OTG transceivers or controllers
-# are used.
-#
-
-comment "OTG and related infrastructure"
-
-config USB_OTG_UTILS
- bool
- help
- Select this to make sure the build includes objects from
- the OTG infrastructure directory.
-
-if USB || USB_GADGET
-
-#
-# USB Transceiver Drivers
-#
-config USB_GPIO_VBUS
- tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
- depends on GENERIC_GPIO
- select USB_OTG_UTILS
- help
- Provides simple GPIO VBUS sensing for controllers with an
- internal transceiver via the usb_phy interface, and
- optionally control of a D+ pullup GPIO as well as a VBUS
- current limit regulator.
-
-config ISP1301_OMAP
- tristate "Philips ISP1301 with OMAP OTG"
- depends on I2C && ARCH_OMAP_OTG
- select USB_OTG_UTILS
- help
- If you say yes here you get support for the Philips ISP1301
- USB-On-The-Go transceiver working with the OMAP OTG controller.
- The ISP1301 is a full speed USB transceiver which is used in
- products including H2, H3, and H4 development boards for Texas
- Instruments OMAP processors.
-
- This driver can also be built as a module. If so, the module
- will be called isp1301_omap.
-
-config USB_ULPI
- bool "Generic ULPI Transceiver Driver"
- depends on ARM
- select USB_OTG_UTILS
- help
- Enable this to support ULPI connected USB OTG transceivers which
- are likely found on embedded boards.
-
-config USB_ULPI_VIEWPORT
- bool
- depends on USB_ULPI
- help
- Provides read/write operations to the ULPI phy register set for
- controllers with a viewport register (e.g. Chipidea/ARC controllers).
-
-config TWL4030_USB
- tristate "TWL4030 USB Transceiver Driver"
- depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
- select USB_OTG_UTILS
- help
- Enable this to support the USB OTG transceiver on TWL4030
- family chips (including the TWL5030 and TPS659x0 devices).
- This transceiver supports high and full speed devices plus,
- in host mode, low speed.
-
-config TWL6030_USB
- tristate "TWL6030 USB Transceiver Driver"
- depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS
- select USB_OTG_UTILS
- help
- Enable this to support the USB OTG transceiver on TWL6030
- family chips. This TWL6030 transceiver has the VBUS and ID GND
- and OTG SRP events capabilities. For all other transceiver functionality
- UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs
- are hooked to this driver through platform_data structure.
- The definition of internal PHY APIs are in the mach-omap2 layer.
-
-config NOP_USB_XCEIV
- tristate "NOP USB Transceiver Driver"
- select USB_OTG_UTILS
- help
- This driver is to be used by all the usb transceiver which are either
- built-in with usb ip or which are autonomous and doesn't require any
- phy programming such as ISP1x04 etc.
-
-config USB_MSM_OTG
- tristate "OTG support for Qualcomm on-chip USB controller"
- depends on (USB || USB_GADGET) && ARCH_MSM
- select USB_OTG_UTILS
- help
- Enable this to support the USB OTG transceiver on MSM chips. It
- handles PHY initialization, clock management, and workarounds
- required after resetting the hardware and power management.
- This driver is required even for peripheral only or host only
- mode configurations.
- This driver is not supported on boards like trout which
- has an external PHY.
-
-config AB8500_USB
- tristate "AB8500 USB Transceiver Driver"
- depends on AB8500_CORE
- select USB_OTG_UTILS
- help
- Enable this to support the USB OTG transceiver in AB8500 chip.
- This transceiver supports high and full speed devices plus,
- in host mode, low speed.
-
-config FSL_USB2_OTG
- bool "Freescale USB OTG Transceiver Driver"
- depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND
- select USB_OTG
- select USB_OTG_UTILS
- help
- Enable this to support Freescale USB OTG transceiver.
-
-config USB_MXS_PHY
- tristate "Freescale MXS USB PHY support"
- depends on ARCH_MXC || ARCH_MXS
- select STMP_DEVICE
- select USB_OTG_UTILS
- help
- Enable this to support the Freescale MXS USB PHY.
-
- MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x.
-
-config USB_MV_OTG
- tristate "Marvell USB OTG support"
- depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND
- select USB_OTG
- select USB_OTG_UTILS
- help
- Say Y here if you want to build Marvell USB OTG transciever
- driver in kernel (including PXA and MMP series). This driver
- implements role switch between EHCI host driver and gadget driver.
-
- To compile this driver as a module, choose M here.
-
-endif # USB || OTG
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
deleted file mode 100644
index a844b8d35d14..000000000000
--- a/drivers/usb/otg/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# OTG infrastructure and transceiver drivers
-#
-
-ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
-ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG
-
-# infrastructure
-obj-$(CONFIG_USB_OTG_UTILS) += otg.o
-
-# transceiver drivers
-obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
-obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
-obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
-obj-$(CONFIG_TWL6030_USB) += twl6030-usb.o
-obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o
-obj-$(CONFIG_USB_ULPI) += ulpi.o
-obj-$(CONFIG_USB_ULPI_VIEWPORT) += ulpi_viewport.o
-obj-$(CONFIG_USB_MSM_OTG) += msm_otg.o
-obj-$(CONFIG_AB8500_USB) += ab8500-usb.o
-fsl_usb2_otg-objs := fsl_otg.o otg_fsm.o
-obj-$(CONFIG_FSL_USB2_OTG) += fsl_usb2_otg.o
-obj-$(CONFIG_USB_MXS_PHY) += mxs-phy.o
-obj-$(CONFIG_USB_MV_OTG) += mv_otg.o
diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c
deleted file mode 100644
index 2d86f26a0183..000000000000
--- a/drivers/usb/otg/ab8500-usb.c
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * drivers/usb/otg/ab8500_usb.c
- *
- * USB transceiver driver for AB8500 chip
- *
- * Copyright (C) 2010 ST-Ericsson AB
- * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/usb/otg.h>
-#include <linux/slab.h>
-#include <linux/notifier.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/abx500/ab8500.h>
-
-#define AB8500_MAIN_WD_CTRL_REG 0x01
-#define AB8500_USB_LINE_STAT_REG 0x80
-#define AB8500_USB_PHY_CTRL_REG 0x8A
-
-#define AB8500_BIT_OTG_STAT_ID (1 << 0)
-#define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0)
-#define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1)
-#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0)
-#define AB8500_BIT_WD_CTRL_KICK (1 << 1)
-
-#define AB8500_V1x_LINK_STAT_WAIT (HZ/10)
-#define AB8500_WD_KICK_DELAY_US 100 /* usec */
-#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */
-#define AB8500_WD_V10_DISABLE_DELAY_MS 100 /* ms */
-
-/* Usb line status register */
-enum ab8500_usb_link_status {
- USB_LINK_NOT_CONFIGURED = 0,
- USB_LINK_STD_HOST_NC,
- USB_LINK_STD_HOST_C_NS,
- USB_LINK_STD_HOST_C_S,
- USB_LINK_HOST_CHG_NM,
- USB_LINK_HOST_CHG_HS,
- USB_LINK_HOST_CHG_HS_CHIRP,
- USB_LINK_DEDICATED_CHG,
- USB_LINK_ACA_RID_A,
- USB_LINK_ACA_RID_B,
- USB_LINK_ACA_RID_C_NM,
- USB_LINK_ACA_RID_C_HS,
- USB_LINK_ACA_RID_C_HS_CHIRP,
- USB_LINK_HM_IDGND,
- USB_LINK_RESERVED,
- USB_LINK_NOT_VALID_LINK
-};
-
-struct ab8500_usb {
- struct usb_phy phy;
- struct device *dev;
- int irq_num_id_rise;
- int irq_num_id_fall;
- int irq_num_vbus_rise;
- int irq_num_vbus_fall;
- int irq_num_link_status;
- unsigned vbus_draw;
- struct delayed_work dwork;
- struct work_struct phy_dis_work;
- unsigned long link_status_wait;
- int rev;
-};
-
-static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x)
-{
- return container_of(x, struct ab8500_usb, phy);
-}
-
-static void ab8500_usb_wd_workaround(struct ab8500_usb *ab)
-{
- abx500_set_register_interruptible(ab->dev,
- AB8500_SYS_CTRL2_BLOCK,
- AB8500_MAIN_WD_CTRL_REG,
- AB8500_BIT_WD_CTRL_ENABLE);
-
- udelay(AB8500_WD_KICK_DELAY_US);
-
- abx500_set_register_interruptible(ab->dev,
- AB8500_SYS_CTRL2_BLOCK,
- AB8500_MAIN_WD_CTRL_REG,
- (AB8500_BIT_WD_CTRL_ENABLE
- | AB8500_BIT_WD_CTRL_KICK));
-
- if (ab->rev > 0x10) /* v1.1 v2.0 */
- udelay(AB8500_WD_V11_DISABLE_DELAY_US);
- else /* v1.0 */
- msleep(AB8500_WD_V10_DISABLE_DELAY_MS);
-
- abx500_set_register_interruptible(ab->dev,
- AB8500_SYS_CTRL2_BLOCK,
- AB8500_MAIN_WD_CTRL_REG,
- 0);
-}
-
-static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host,
- bool enable)
-{
- u8 ctrl_reg;
- abx500_get_register_interruptible(ab->dev,
- AB8500_USB,
- AB8500_USB_PHY_CTRL_REG,
- &ctrl_reg);
- if (sel_host) {
- if (enable)
- ctrl_reg |= AB8500_BIT_PHY_CTRL_HOST_EN;
- else
- ctrl_reg &= ~AB8500_BIT_PHY_CTRL_HOST_EN;
- } else {
- if (enable)
- ctrl_reg |= AB8500_BIT_PHY_CTRL_DEVICE_EN;
- else
- ctrl_reg &= ~AB8500_BIT_PHY_CTRL_DEVICE_EN;
- }
-
- abx500_set_register_interruptible(ab->dev,
- AB8500_USB,
- AB8500_USB_PHY_CTRL_REG,
- ctrl_reg);
-
- /* Needed to enable the phy.*/
- if (enable)
- ab8500_usb_wd_workaround(ab);
-}
-
-#define ab8500_usb_host_phy_en(ab) ab8500_usb_phy_ctrl(ab, true, true)
-#define ab8500_usb_host_phy_dis(ab) ab8500_usb_phy_ctrl(ab, true, false)
-#define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_ctrl(ab, false, true)
-#define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_ctrl(ab, false, false)
-
-static int ab8500_usb_link_status_update(struct ab8500_usb *ab)
-{
- u8 reg;
- enum ab8500_usb_link_status lsts;
- void *v = NULL;
- enum usb_phy_events event;
-
- abx500_get_register_interruptible(ab->dev,
- AB8500_USB,
- AB8500_USB_LINE_STAT_REG,
- &reg);
-
- lsts = (reg >> 3) & 0x0F;
-
- switch (lsts) {
- case USB_LINK_NOT_CONFIGURED:
- case USB_LINK_RESERVED:
- case USB_LINK_NOT_VALID_LINK:
- /* TODO: Disable regulators. */
- ab8500_usb_host_phy_dis(ab);
- ab8500_usb_peri_phy_dis(ab);
- ab->phy.state = OTG_STATE_B_IDLE;
- ab->phy.otg->default_a = false;
- ab->vbus_draw = 0;
- event = USB_EVENT_NONE;
- break;
-
- case USB_LINK_STD_HOST_NC:
- case USB_LINK_STD_HOST_C_NS:
- case USB_LINK_STD_HOST_C_S:
- case USB_LINK_HOST_CHG_NM:
- case USB_LINK_HOST_CHG_HS:
- case USB_LINK_HOST_CHG_HS_CHIRP:
- if (ab->phy.otg->gadget) {
- /* TODO: Enable regulators. */
- ab8500_usb_peri_phy_en(ab);
- v = ab->phy.otg->gadget;
- }
- event = USB_EVENT_VBUS;
- break;
-
- case USB_LINK_HM_IDGND:
- if (ab->phy.otg->host) {
- /* TODO: Enable regulators. */
- ab8500_usb_host_phy_en(ab);
- v = ab->phy.otg->host;
- }
- ab->phy.state = OTG_STATE_A_IDLE;
- ab->phy.otg->default_a = true;
- event = USB_EVENT_ID;
- break;
-
- case USB_LINK_ACA_RID_A:
- case USB_LINK_ACA_RID_B:
- /* TODO */
- case USB_LINK_ACA_RID_C_NM:
- case USB_LINK_ACA_RID_C_HS:
- case USB_LINK_ACA_RID_C_HS_CHIRP:
- case USB_LINK_DEDICATED_CHG:
- /* TODO: vbus_draw */
- event = USB_EVENT_CHARGER;
- break;
- }
-
- atomic_notifier_call_chain(&ab->phy.notifier, event, v);
-
- return 0;
-}
-
-static void ab8500_usb_delayed_work(struct work_struct *work)
-{
- struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
- dwork.work);
-
- ab8500_usb_link_status_update(ab);
-}
-
-static irqreturn_t ab8500_usb_v1x_common_irq(int irq, void *data)
-{
- struct ab8500_usb *ab = (struct ab8500_usb *) data;
-
- /* Wait for link status to become stable. */
- schedule_delayed_work(&ab->dwork, ab->link_status_wait);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t ab8500_usb_v1x_vbus_fall_irq(int irq, void *data)
-{
- struct ab8500_usb *ab = (struct ab8500_usb *) data;
-
- /* Link status will not be updated till phy is disabled. */
- ab8500_usb_peri_phy_dis(ab);
-
- /* Wait for link status to become stable. */
- schedule_delayed_work(&ab->dwork, ab->link_status_wait);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t ab8500_usb_v20_irq(int irq, void *data)
-{
- struct ab8500_usb *ab = (struct ab8500_usb *) data;
-
- ab8500_usb_link_status_update(ab);
-
- return IRQ_HANDLED;
-}
-
-static void ab8500_usb_phy_disable_work(struct work_struct *work)
-{
- struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
- phy_dis_work);
-
- if (!ab->phy.otg->host)
- ab8500_usb_host_phy_dis(ab);
-
- if (!ab->phy.otg->gadget)
- ab8500_usb_peri_phy_dis(ab);
-}
-
-static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA)
-{
- struct ab8500_usb *ab;
-
- if (!phy)
- return -ENODEV;
-
- ab = phy_to_ab(phy);
-
- ab->vbus_draw = mA;
-
- if (mA)
- atomic_notifier_call_chain(&ab->phy.notifier,
- USB_EVENT_ENUMERATED, ab->phy.otg->gadget);
- return 0;
-}
-
-/* TODO: Implement some way for charging or other drivers to read
- * ab->vbus_draw.
- */
-
-static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend)
-{
- /* TODO */
- return 0;
-}
-
-static int ab8500_usb_set_peripheral(struct usb_otg *otg,
- struct usb_gadget *gadget)
-{
- struct ab8500_usb *ab;
-
- if (!otg)
- return -ENODEV;
-
- ab = phy_to_ab(otg->phy);
-
- /* Some drivers call this function in atomic context.
- * Do not update ab8500 registers directly till this
- * is fixed.
- */
-
- if (!gadget) {
- /* TODO: Disable regulators. */
- otg->gadget = NULL;
- schedule_work(&ab->phy_dis_work);
- } else {
- otg->gadget = gadget;
- otg->phy->state = OTG_STATE_B_IDLE;
-
- /* Phy will not be enabled if cable is already
- * plugged-in. Schedule to enable phy.
- * Use same delay to avoid any race condition.
- */
- schedule_delayed_work(&ab->dwork, ab->link_status_wait);
- }
-
- return 0;
-}
-
-static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
- struct ab8500_usb *ab;
-
- if (!otg)
- return -ENODEV;
-
- ab = phy_to_ab(otg->phy);
-
- /* Some drivers call this function in atomic context.
- * Do not update ab8500 registers directly till this
- * is fixed.
- */
-
- if (!host) {
- /* TODO: Disable regulators. */
- otg->host = NULL;
- schedule_work(&ab->phy_dis_work);
- } else {
- otg->host = host;
- /* Phy will not be enabled if cable is already
- * plugged-in. Schedule to enable phy.
- * Use same delay to avoid any race condition.
- */
- schedule_delayed_work(&ab->dwork, ab->link_status_wait);
- }
-
- return 0;
-}
-
-static void ab8500_usb_irq_free(struct ab8500_usb *ab)
-{
- if (ab->rev < 0x20) {
- free_irq(ab->irq_num_id_rise, ab);
- free_irq(ab->irq_num_id_fall, ab);
- free_irq(ab->irq_num_vbus_rise, ab);
- free_irq(ab->irq_num_vbus_fall, ab);
- } else {
- free_irq(ab->irq_num_link_status, ab);
- }
-}
-
-static int ab8500_usb_v1x_res_setup(struct platform_device *pdev,
- struct ab8500_usb *ab)
-{
- int err;
-
- ab->irq_num_id_rise = platform_get_irq_byname(pdev, "ID_WAKEUP_R");
- if (ab->irq_num_id_rise < 0) {
- dev_err(&pdev->dev, "ID rise irq not found\n");
- return ab->irq_num_id_rise;
- }
- err = request_threaded_irq(ab->irq_num_id_rise, NULL,
- ab8500_usb_v1x_common_irq,
- IRQF_NO_SUSPEND | IRQF_SHARED,
- "usb-id-rise", ab);
- if (err < 0) {
- dev_err(ab->dev, "request_irq failed for ID rise irq\n");
- goto fail0;
- }
-
- ab->irq_num_id_fall = platform_get_irq_byname(pdev, "ID_WAKEUP_F");
- if (ab->irq_num_id_fall < 0) {
- dev_err(&pdev->dev, "ID fall irq not found\n");
- return ab->irq_num_id_fall;
- }
- err = request_threaded_irq(ab->irq_num_id_fall, NULL,
- ab8500_usb_v1x_common_irq,
- IRQF_NO_SUSPEND | IRQF_SHARED,
- "usb-id-fall", ab);
- if (err < 0) {
- dev_err(ab->dev, "request_irq failed for ID fall irq\n");
- goto fail1;
- }
-
- ab->irq_num_vbus_rise = platform_get_irq_byname(pdev, "VBUS_DET_R");
- if (ab->irq_num_vbus_rise < 0) {
- dev_err(&pdev->dev, "VBUS rise irq not found\n");
- return ab->irq_num_vbus_rise;
- }
- err = request_threaded_irq(ab->irq_num_vbus_rise, NULL,
- ab8500_usb_v1x_common_irq,
- IRQF_NO_SUSPEND | IRQF_SHARED,
- "usb-vbus-rise", ab);
- if (err < 0) {
- dev_err(ab->dev, "request_irq failed for Vbus rise irq\n");
- goto fail2;
- }
-
- ab->irq_num_vbus_fall = platform_get_irq_byname(pdev, "VBUS_DET_F");
- if (ab->irq_num_vbus_fall < 0) {
- dev_err(&pdev->dev, "VBUS fall irq not found\n");
- return ab->irq_num_vbus_fall;
- }
- err = request_threaded_irq(ab->irq_num_vbus_fall, NULL,
- ab8500_usb_v1x_vbus_fall_irq,
- IRQF_NO_SUSPEND | IRQF_SHARED,
- "usb-vbus-fall", ab);
- if (err < 0) {
- dev_err(ab->dev, "request_irq failed for Vbus fall irq\n");
- goto fail3;
- }
-
- return 0;
-fail3:
- free_irq(ab->irq_num_vbus_rise, ab);
-fail2:
- free_irq(ab->irq_num_id_fall, ab);
-fail1:
- free_irq(ab->irq_num_id_rise, ab);
-fail0:
- return err;
-}
-
-static int ab8500_usb_v2_res_setup(struct platform_device *pdev,
- struct ab8500_usb *ab)
-{
- int err;
-
- ab->irq_num_link_status = platform_get_irq_byname(pdev,
- "USB_LINK_STATUS");
- if (ab->irq_num_link_status < 0) {
- dev_err(&pdev->dev, "Link status irq not found\n");
- return ab->irq_num_link_status;
- }
-
- err = request_threaded_irq(ab->irq_num_link_status, NULL,
- ab8500_usb_v20_irq,
- IRQF_NO_SUSPEND | IRQF_SHARED,
- "usb-link-status", ab);
- if (err < 0) {
- dev_err(ab->dev,
- "request_irq failed for link status irq\n");
- return err;
- }
-
- return 0;
-}
-
-static int ab8500_usb_probe(struct platform_device *pdev)
-{
- struct ab8500_usb *ab;
- struct usb_otg *otg;
- int err;
- int rev;
-
- rev = abx500_get_chip_id(&pdev->dev);
- if (rev < 0) {
- dev_err(&pdev->dev, "Chip id read failed\n");
- return rev;
- } else if (rev < 0x10) {
- dev_err(&pdev->dev, "Unsupported AB8500 chip\n");
- return -ENODEV;
- }
-
- ab = kzalloc(sizeof *ab, GFP_KERNEL);
- if (!ab)
- return -ENOMEM;
-
- otg = kzalloc(sizeof *otg, GFP_KERNEL);
- if (!otg) {
- kfree(ab);
- return -ENOMEM;
- }
-
- ab->dev = &pdev->dev;
- ab->rev = rev;
- ab->phy.dev = ab->dev;
- ab->phy.otg = otg;
- ab->phy.label = "ab8500";
- ab->phy.set_suspend = ab8500_usb_set_suspend;
- ab->phy.set_power = ab8500_usb_set_power;
- ab->phy.state = OTG_STATE_UNDEFINED;
-
- otg->phy = &ab->phy;
- otg->set_host = ab8500_usb_set_host;
- otg->set_peripheral = ab8500_usb_set_peripheral;
-
- platform_set_drvdata(pdev, ab);
-
- ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier);
-
- /* v1: Wait for link status to become stable.
- * all: Updates form set_host and set_peripheral as they are atomic.
- */
- INIT_DELAYED_WORK(&ab->dwork, ab8500_usb_delayed_work);
-
- /* all: Disable phy when called from set_host and set_peripheral */
- INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
-
- if (ab->rev < 0x20) {
- err = ab8500_usb_v1x_res_setup(pdev, ab);
- ab->link_status_wait = AB8500_V1x_LINK_STAT_WAIT;
- } else {
- err = ab8500_usb_v2_res_setup(pdev, ab);
- }
-
- if (err < 0)
- goto fail0;
-
- err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2);
- if (err) {
- dev_err(&pdev->dev, "Can't register transceiver\n");
- goto fail1;
- }
-
- dev_info(&pdev->dev, "AB8500 usb driver initialized\n");
-
- return 0;
-fail1:
- ab8500_usb_irq_free(ab);
-fail0:
- kfree(otg);
- kfree(ab);
- return err;
-}
-
-static int ab8500_usb_remove(struct platform_device *pdev)
-{
- struct ab8500_usb *ab = platform_get_drvdata(pdev);
-
- ab8500_usb_irq_free(ab);
-
- cancel_delayed_work_sync(&ab->dwork);
-
- cancel_work_sync(&ab->phy_dis_work);
-
- usb_remove_phy(&ab->phy);
-
- ab8500_usb_host_phy_dis(ab);
- ab8500_usb_peri_phy_dis(ab);
-
- platform_set_drvdata(pdev, NULL);
-
- kfree(ab->phy.otg);
- kfree(ab);
-
- return 0;
-}
-
-static struct platform_driver ab8500_usb_driver = {
- .probe = ab8500_usb_probe,
- .remove = ab8500_usb_remove,
- .driver = {
- .name = "ab8500-usb",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init ab8500_usb_init(void)
-{
- return platform_driver_register(&ab8500_usb_driver);
-}
-subsys_initcall(ab8500_usb_init);
-
-static void __exit ab8500_usb_exit(void)
-{
- platform_driver_unregister(&ab8500_usb_driver);
-}
-module_exit(ab8500_usb_exit);
-
-MODULE_ALIAS("platform:ab8500_usb");
-MODULE_AUTHOR("ST-Ericsson AB");
-MODULE_DESCRIPTION("AB8500 usb transceiver driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 90549382eba5..3a7fec957ca7 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -1,13 +1,74 @@
#
# Physical Layer USB driver configuration
#
-comment "USB Physical Layer drivers"
- depends on USB || USB_GADGET
+menuconfig USB_PHY
+ tristate "USB Physical Layer drivers"
+ help
+ USB controllers (those which are host, device or DRD) need a
+ device to handle the physical layer signalling, commonly called
+ a PHY.
+
+ The following drivers add support for such PHY devices.
+
+if USB_PHY
+
+#
+# USB Transceiver Drivers
+#
+config AB8500_USB
+ tristate "AB8500 USB Transceiver Driver"
+ depends on AB8500_CORE
+ help
+ Enable this to support the USB OTG transceiver in AB8500 chip.
+ This transceiver supports high and full speed devices plus,
+ in host mode, low speed.
+
+config FSL_USB2_OTG
+ bool "Freescale USB OTG Transceiver Driver"
+ depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND
+ select USB_OTG
+ help
+ Enable this to support Freescale USB OTG transceiver.
+
+config ISP1301_OMAP
+ tristate "Philips ISP1301 with OMAP OTG"
+ depends on I2C && ARCH_OMAP_OTG
+ help
+ If you say yes here you get support for the Philips ISP1301
+ USB-On-The-Go transceiver working with the OMAP OTG controller.
+ The ISP1301 is a full speed USB transceiver which is used in
+ products including H2, H3, and H4 development boards for Texas
+ Instruments OMAP processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called isp1301_omap.
+
+config MV_U3D_PHY
+ bool "Marvell USB 3.0 PHY controller Driver"
+ depends on CPU_MMP3
+ help
+ Enable this to support Marvell USB 3.0 phy controller for Marvell
+ SoC.
+
+config NOP_USB_XCEIV
+ tristate "NOP USB Transceiver Driver"
+ help
+ This driver is to be used by all the usb transceiver which are either
+ built-in with usb ip or which are autonomous and doesn't require any
+ phy programming such as ISP1x04 etc.
+
+config OMAP_CONTROL_USB
+ tristate "OMAP CONTROL USB Driver"
+ help
+ Enable this to add support for the USB part present in the control
+ module. This driver has API to power on the USB2 PHY and to write to
+ the mailbox. The mailbox is present only in omap4 and the register to
+ power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
+ additional register to power on USB3 PHY.
config OMAP_USB2
tristate "OMAP USB2 PHY Driver"
depends on ARCH_OMAP2PLUS
- select USB_OTG_UTILS
select OMAP_CONTROL_USB
help
Enable this to support the transceiver that is part of SOC. This
@@ -17,7 +78,6 @@ config OMAP_USB2
config OMAP_USB3
tristate "OMAP USB3 PHY Driver"
- select USB_OTG_UTILS
select OMAP_CONTROL_USB
help
Enable this to support the USB3 PHY that is part of SOC. This
@@ -25,14 +85,55 @@ config OMAP_USB3
This driver interacts with the "OMAP Control USB Driver" to power
on/off the PHY.
-config OMAP_CONTROL_USB
- tristate "OMAP CONTROL USB Driver"
+config SAMSUNG_USBPHY
+ tristate "Samsung USB PHY Driver"
help
- Enable this to add support for the USB part present in the control
- module. This driver has API to power on the USB2 PHY and to write to
- the mailbox. The mailbox is present only in omap4 and the register to
- power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
- additional register to power on USB3 PHY.
+ Enable this to support Samsung USB phy helper driver for Samsung SoCs.
+ This driver provides common interface to interact, for Samsung USB 2.0 PHY
+ driver and later for Samsung USB 3.0 PHY driver.
+
+config SAMSUNG_USB2PHY
+ tristate "Samsung USB 2.0 PHY controller Driver"
+ select SAMSUNG_USBPHY
+ help
+ Enable this to support Samsung USB 2.0 (High Speed) PHY controller
+ driver for Samsung SoCs.
+
+config SAMSUNG_USB3PHY
+ tristate "Samsung USB 3.0 PHY controller Driver"
+ select SAMSUNG_USBPHY
+ help
+ Enable this to support Samsung USB 3.0 (Super Speed) phy controller
+ for samsung SoCs.
+
+config TWL4030_USB
+ tristate "TWL4030 USB Transceiver Driver"
+ depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
+ help
+ Enable this to support the USB OTG transceiver on TWL4030
+ family chips (including the TWL5030 and TPS659x0 devices).
+ This transceiver supports high and full speed devices plus,
+ in host mode, low speed.
+
+config TWL6030_USB
+ tristate "TWL6030 USB Transceiver Driver"
+ depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS
+ help
+ Enable this to support the USB OTG transceiver on TWL6030
+ family chips. This TWL6030 transceiver has the VBUS and ID GND
+ and OTG SRP events capabilities. For all other transceiver functionality
+ UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs
+ are hooked to this driver through platform_data structure.
+ The definition of internal PHY APIs are in the mach-omap2 layer.
+
+config USB_GPIO_VBUS
+ tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
+ depends on GENERIC_GPIO
+ help
+ Provides simple GPIO VBUS sensing for controllers with an
+ internal transceiver via the usb_phy interface, and
+ optionally control of a D+ pullup GPIO as well as a VBUS
+ current limit regulator.
config USB_ISP1301
tristate "NXP ISP1301 USB transceiver support"
@@ -47,18 +148,41 @@ config USB_ISP1301
To compile this driver as a module, choose M here: the
module will be called isp1301.
-config MV_U3D_PHY
- bool "Marvell USB 3.0 PHY controller Driver"
- depends on USB_MV_U3D
- select USB_OTG_UTILS
+config USB_MSM_OTG
+ tristate "OTG support for Qualcomm on-chip USB controller"
+ depends on (USB || USB_GADGET) && ARCH_MSM
help
- Enable this to support Marvell USB 3.0 phy controller for Marvell
- SoC.
+ Enable this to support the USB OTG transceiver on MSM chips. It
+ handles PHY initialization, clock management, and workarounds
+ required after resetting the hardware and power management.
+ This driver is required even for peripheral only or host only
+ mode configurations.
+ This driver is not supported on boards like trout which
+ has an external PHY.
+
+config USB_MV_OTG
+ tristate "Marvell USB OTG support"
+ depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND
+ select USB_OTG
+ help
+ Say Y here if you want to build Marvell USB OTG transciever
+ driver in kernel (including PXA and MMP series). This driver
+ implements role switch between EHCI host driver and gadget driver.
+
+ To compile this driver as a module, choose M here.
+
+config USB_MXS_PHY
+ tristate "Freescale MXS USB PHY support"
+ depends on ARCH_MXC || ARCH_MXS
+ select STMP_DEVICE
+ help
+ Enable this to support the Freescale MXS USB PHY.
+
+ MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x.
config USB_RCAR_PHY
tristate "Renesas R-Car USB phy support"
depends on USB || USB_GADGET
- select USB_OTG_UTILS
help
Say Y here to add support for the Renesas R-Car USB phy driver.
This chip is typically used as USB phy for USB host, gadget.
@@ -67,10 +191,18 @@ config USB_RCAR_PHY
To compile this driver as a module, choose M here: the
module will be called rcar-phy.
-config SAMSUNG_USBPHY
- bool "Samsung USB PHY controller Driver"
- depends on USB_S3C_HSOTG || USB_EHCI_S5P || USB_OHCI_EXYNOS
- select USB_OTG_UTILS
+config USB_ULPI
+ bool "Generic ULPI Transceiver Driver"
+ depends on ARM
+ help
+ Enable this to support ULPI connected USB OTG transceivers which
+ are likely found on embedded boards.
+
+config USB_ULPI_VIEWPORT
+ bool
+ depends on USB_ULPI
help
- Enable this to support Samsung USB phy controller for samsung
- SoCs.
+ Provides read/write operations to the ULPI phy register set for
+ controllers with a viewport register (e.g. Chipidea/ARC controllers).
+
+endif # USB_PHY
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index b13faa193e0c..33863c09f3dc 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -4,11 +4,30 @@
ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
-obj-$(CONFIG_OMAP_USB2) += omap-usb2.o
-obj-$(CONFIG_OMAP_USB3) += omap-usb3.o
-obj-$(CONFIG_OMAP_CONTROL_USB) += omap-control-usb.o
-obj-$(CONFIG_USB_ISP1301) += isp1301.o
-obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o
-obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o
-obj-$(CONFIG_USB_RCAR_PHY) += rcar-phy.o
-obj-$(CONFIG_SAMSUNG_USBPHY) += samsung-usbphy.o
+obj-$(CONFIG_USB_PHY) += phy.o
+
+# transceiver drivers, keep the list sorted
+
+obj-$(CONFIG_AB8500_USB) += phy-ab8500-usb.o
+phy-fsl-usb2-objs := phy-fsl-usb.o phy-fsm-usb.o
+obj-$(CONFIG_FSL_USB2_OTG) += phy-fsl-usb2.o
+obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301.omap.o
+obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o
+obj-$(CONFIG_NOP_USB_XCEIV) += phy-nop.o
+obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o
+obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o
+obj-$(CONFIG_OMAP_USB3) += phy-omap-usb3.o
+obj-$(CONFIG_SAMSUNG_USBPHY) += phy-samsung-usb.o
+obj-$(CONFIG_SAMSUNG_USB2PHY) += phy-samsung-usb2.o
+obj-$(CONFIG_SAMSUNG_USB3PHY) += phy-samsung-usb3.o
+obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
+obj-$(CONFIG_TWL6030_USB) += phy-twl6030-usb.o
+obj-$(CONFIG_USB_EHCI_TEGRA) += phy-tegra-usb.o
+obj-$(CONFIG_USB_GPIO_VBUS) += phy-gpio-vbus-usb.o
+obj-$(CONFIG_USB_ISP1301) += phy-isp1301.o
+obj-$(CONFIG_USB_MSM_OTG) += phy-msm-usb.o
+obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o
+obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o
+obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o
+obj-$(CONFIG_USB_ULPI) += phy-ulpi.o
+obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o
diff --git a/drivers/usb/phy/isp1301.c b/drivers/usb/phy/isp1301.c
deleted file mode 100644
index 18dbf7e37607..000000000000
--- a/drivers/usb/phy/isp1301.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * NXP ISP1301 USB transceiver driver
- *
- * Copyright (C) 2012 Roland Stigge
- *
- * Author: Roland Stigge <stigge@antcom.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/i2c.h>
-
-#define DRV_NAME "isp1301"
-
-static const struct i2c_device_id isp1301_id[] = {
- { "isp1301", 0 },
- { }
-};
-
-static struct i2c_client *isp1301_i2c_client;
-
-static int isp1301_probe(struct i2c_client *client,
- const struct i2c_device_id *i2c_id)
-{
- isp1301_i2c_client = client;
- return 0;
-}
-
-static int isp1301_remove(struct i2c_client *client)
-{
- return 0;
-}
-
-static struct i2c_driver isp1301_driver = {
- .driver = {
- .name = DRV_NAME,
- },
- .probe = isp1301_probe,
- .remove = isp1301_remove,
- .id_table = isp1301_id,
-};
-
-module_i2c_driver(isp1301_driver);
-
-static int match(struct device *dev, void *data)
-{
- struct device_node *node = (struct device_node *)data;
- return (dev->of_node == node) &&
- (dev->driver == &isp1301_driver.driver);
-}
-
-struct i2c_client *isp1301_get_client(struct device_node *node)
-{
- if (node) { /* reference of ISP1301 I2C node via DT */
- struct device *dev = bus_find_device(&i2c_bus_type, NULL,
- node, match);
- if (!dev)
- return NULL;
- return to_i2c_client(dev);
- } else { /* non-DT: only one ISP1301 chip supported */
- return isp1301_i2c_client;
- }
-}
-EXPORT_SYMBOL_GPL(isp1301_get_client);
-
-MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
-MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c
new file mode 100644
index 000000000000..4acef26a2ef5
--- /dev/null
+++ b/drivers/usb/phy/phy-ab8500-usb.c
@@ -0,0 +1,924 @@
+/*
+ * drivers/usb/otg/ab8500_usb.c
+ *
+ * USB transceiver driver for AB8500 chip
+ *
+ * Copyright (C) 2010 ST-Ericsson AB
+ * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/usb/otg.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/usb/musb-ux500.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
+
+/* Bank AB8500_SYS_CTRL2_BLOCK */
+#define AB8500_MAIN_WD_CTRL_REG 0x01
+
+/* Bank AB8500_USB */
+#define AB8500_USB_LINE_STAT_REG 0x80
+#define AB8505_USB_LINE_STAT_REG 0x94
+#define AB8500_USB_PHY_CTRL_REG 0x8A
+
+/* Bank AB8500_DEVELOPMENT */
+#define AB8500_BANK12_ACCESS 0x00
+
+/* Bank AB8500_DEBUG */
+#define AB8500_USB_PHY_TUNE1 0x05
+#define AB8500_USB_PHY_TUNE2 0x06
+#define AB8500_USB_PHY_TUNE3 0x07
+
+#define AB8500_BIT_OTG_STAT_ID (1 << 0)
+#define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0)
+#define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1)
+#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0)
+#define AB8500_BIT_WD_CTRL_KICK (1 << 1)
+
+#define AB8500_WD_KICK_DELAY_US 100 /* usec */
+#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */
+#define AB8500_V20_31952_DISABLE_DELAY_US 100 /* usec */
+
+/* Usb line status register */
+enum ab8500_usb_link_status {
+ USB_LINK_NOT_CONFIGURED_8500 = 0,
+ USB_LINK_STD_HOST_NC_8500,
+ USB_LINK_STD_HOST_C_NS_8500,
+ USB_LINK_STD_HOST_C_S_8500,
+ USB_LINK_HOST_CHG_NM_8500,
+ USB_LINK_HOST_CHG_HS_8500,
+ USB_LINK_HOST_CHG_HS_CHIRP_8500,
+ USB_LINK_DEDICATED_CHG_8500,
+ USB_LINK_ACA_RID_A_8500,
+ USB_LINK_ACA_RID_B_8500,
+ USB_LINK_ACA_RID_C_NM_8500,
+ USB_LINK_ACA_RID_C_HS_8500,
+ USB_LINK_ACA_RID_C_HS_CHIRP_8500,
+ USB_LINK_HM_IDGND_8500,
+ USB_LINK_RESERVED_8500,
+ USB_LINK_NOT_VALID_LINK_8500,
+};
+
+enum ab8505_usb_link_status {
+ USB_LINK_NOT_CONFIGURED_8505 = 0,
+ USB_LINK_STD_HOST_NC_8505,
+ USB_LINK_STD_HOST_C_NS_8505,
+ USB_LINK_STD_HOST_C_S_8505,
+ USB_LINK_CDP_8505,
+ USB_LINK_RESERVED0_8505,
+ USB_LINK_RESERVED1_8505,
+ USB_LINK_DEDICATED_CHG_8505,
+ USB_LINK_ACA_RID_A_8505,
+ USB_LINK_ACA_RID_B_8505,
+ USB_LINK_ACA_RID_C_NM_8505,
+ USB_LINK_RESERVED2_8505,
+ USB_LINK_RESERVED3_8505,
+ USB_LINK_HM_IDGND_8505,
+ USB_LINK_CHARGERPORT_NOT_OK_8505,
+ USB_LINK_CHARGER_DM_HIGH_8505,
+ USB_LINK_PHYEN_NO_VBUS_NO_IDGND_8505,
+ USB_LINK_STD_UPSTREAM_NO_IDGNG_NO_VBUS_8505,
+ USB_LINK_STD_UPSTREAM_8505,
+ USB_LINK_CHARGER_SE1_8505,
+ USB_LINK_CARKIT_CHGR_1_8505,
+ USB_LINK_CARKIT_CHGR_2_8505,
+ USB_LINK_ACA_DOCK_CHGR_8505,
+ USB_LINK_SAMSUNG_BOOT_CBL_PHY_EN_8505,
+ USB_LINK_SAMSUNG_BOOT_CBL_PHY_DISB_8505,
+ USB_LINK_SAMSUNG_UART_CBL_PHY_EN_8505,
+ USB_LINK_SAMSUNG_UART_CBL_PHY_DISB_8505,
+ USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_8505,
+};
+
+enum ab8500_usb_mode {
+ USB_IDLE = 0,
+ USB_PERIPHERAL,
+ USB_HOST,
+ USB_DEDICATED_CHG
+};
+
+struct ab8500_usb {
+ struct usb_phy phy;
+ struct device *dev;
+ struct ab8500 *ab8500;
+ unsigned vbus_draw;
+ struct work_struct phy_dis_work;
+ enum ab8500_usb_mode mode;
+ struct regulator *v_ape;
+ struct regulator *v_musb;
+ struct regulator *v_ulpi;
+ int saved_v_ulpi;
+ int previous_link_status_state;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_sleep;
+};
+
+static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x)
+{
+ return container_of(x, struct ab8500_usb, phy);
+}
+
+static void ab8500_usb_wd_workaround(struct ab8500_usb *ab)
+{
+ abx500_set_register_interruptible(ab->dev,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WD_CTRL_REG,
+ AB8500_BIT_WD_CTRL_ENABLE);
+
+ udelay(AB8500_WD_KICK_DELAY_US);
+
+ abx500_set_register_interruptible(ab->dev,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WD_CTRL_REG,
+ (AB8500_BIT_WD_CTRL_ENABLE
+ | AB8500_BIT_WD_CTRL_KICK));
+
+ udelay(AB8500_WD_V11_DISABLE_DELAY_US);
+
+ abx500_set_register_interruptible(ab->dev,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WD_CTRL_REG,
+ 0);
+}
+
+static void ab8500_usb_regulator_enable(struct ab8500_usb *ab)
+{
+ int ret, volt;
+
+ ret = regulator_enable(ab->v_ape);
+ if (ret)
+ dev_err(ab->dev, "Failed to enable v-ape\n");
+
+ if (!is_ab8500_2p0_or_earlier(ab->ab8500)) {
+ ab->saved_v_ulpi = regulator_get_voltage(ab->v_ulpi);
+ if (ab->saved_v_ulpi < 0)
+ dev_err(ab->dev, "Failed to get v_ulpi voltage\n");
+
+ ret = regulator_set_voltage(ab->v_ulpi, 1300000, 1350000);
+ if (ret < 0)
+ dev_err(ab->dev, "Failed to set the Vintcore to 1.3V, ret=%d\n",
+ ret);
+
+ ret = regulator_set_optimum_mode(ab->v_ulpi, 28000);
+ if (ret < 0)
+ dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n",
+ ret);
+ }
+
+ ret = regulator_enable(ab->v_ulpi);
+ if (ret)
+ dev_err(ab->dev, "Failed to enable vddulpivio18\n");
+
+ if (!is_ab8500_2p0_or_earlier(ab->ab8500)) {
+ volt = regulator_get_voltage(ab->v_ulpi);
+ if ((volt != 1300000) && (volt != 1350000))
+ dev_err(ab->dev, "Vintcore is not set to 1.3V volt=%d\n",
+ volt);
+ }
+
+ ret = regulator_enable(ab->v_musb);
+ if (ret)
+ dev_err(ab->dev, "Failed to enable musb_1v8\n");
+}
+
+static void ab8500_usb_regulator_disable(struct ab8500_usb *ab)
+{
+ int ret;
+
+ regulator_disable(ab->v_musb);
+
+ regulator_disable(ab->v_ulpi);
+
+ /* USB is not the only consumer of Vintcore, restore old settings */
+ if (!is_ab8500_2p0_or_earlier(ab->ab8500)) {
+ if (ab->saved_v_ulpi > 0) {
+ ret = regulator_set_voltage(ab->v_ulpi,
+ ab->saved_v_ulpi, ab->saved_v_ulpi);
+ if (ret < 0)
+ dev_err(ab->dev, "Failed to set the Vintcore to %duV, ret=%d\n",
+ ab->saved_v_ulpi, ret);
+ }
+
+ ret = regulator_set_optimum_mode(ab->v_ulpi, 0);
+ if (ret < 0)
+ dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n",
+ ret);
+ }
+
+ regulator_disable(ab->v_ape);
+}
+
+static void ab8500_usb_wd_linkstatus(struct ab8500_usb *ab, u8 bit)
+{
+ /* Workaround for v2.0 bug # 31952 */
+ if (is_ab8500_2p0(ab->ab8500)) {
+ abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+ bit, bit);
+ udelay(AB8500_V20_31952_DISABLE_DELAY_US);
+ }
+}
+
+static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host)
+{
+ u8 bit;
+ bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN :
+ AB8500_BIT_PHY_CTRL_DEVICE_EN;
+
+ /* mux and configure USB pins to DEFAULT state */
+ ab->pinctrl = pinctrl_get_select(ab->dev, PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(ab->pinctrl))
+ dev_err(ab->dev, "could not get/set default pinstate\n");
+
+ ab8500_usb_regulator_enable(ab);
+
+ abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+ bit, bit);
+}
+
+static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host)
+{
+ u8 bit;
+ bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN :
+ AB8500_BIT_PHY_CTRL_DEVICE_EN;
+
+ ab8500_usb_wd_linkstatus(ab, bit);
+
+ abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+ bit, 0);
+
+ /* Needed to disable the phy.*/
+ ab8500_usb_wd_workaround(ab);
+
+ ab8500_usb_regulator_disable(ab);
+
+ if (!IS_ERR(ab->pinctrl)) {
+ /* configure USB pins to SLEEP state */
+ ab->pins_sleep = pinctrl_lookup_state(ab->pinctrl,
+ PINCTRL_STATE_SLEEP);
+
+ if (IS_ERR(ab->pins_sleep))
+ dev_dbg(ab->dev, "could not get sleep pinstate\n");
+ else if (pinctrl_select_state(ab->pinctrl, ab->pins_sleep))
+ dev_err(ab->dev, "could not set pins to sleep state\n");
+
+ /* as USB pins are shared with idddet, release them to allow
+ * iddet to request them
+ */
+ pinctrl_put(ab->pinctrl);
+ }
+}
+
+#define ab8500_usb_host_phy_en(ab) ab8500_usb_phy_enable(ab, true)
+#define ab8500_usb_host_phy_dis(ab) ab8500_usb_phy_disable(ab, true)
+#define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_enable(ab, false)
+#define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_disable(ab, false)
+
+static int ab8505_usb_link_status_update(struct ab8500_usb *ab,
+ enum ab8505_usb_link_status lsts)
+{
+ enum ux500_musb_vbus_id_status event = 0;
+
+ dev_dbg(ab->dev, "ab8505_usb_link_status_update %d\n", lsts);
+
+ /*
+ * Spurious link_status interrupts are seen at the time of
+ * disconnection of a device in RIDA state
+ */
+ if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8505 &&
+ (lsts == USB_LINK_STD_HOST_NC_8505))
+ return 0;
+
+ ab->previous_link_status_state = lsts;
+
+ switch (lsts) {
+ case USB_LINK_ACA_RID_B_8505:
+ event = UX500_MUSB_RIDB;
+ case USB_LINK_NOT_CONFIGURED_8505:
+ case USB_LINK_RESERVED0_8505:
+ case USB_LINK_RESERVED1_8505:
+ case USB_LINK_RESERVED2_8505:
+ case USB_LINK_RESERVED3_8505:
+ ab->mode = USB_IDLE;
+ ab->phy.otg->default_a = false;
+ ab->vbus_draw = 0;
+ if (event != UX500_MUSB_RIDB)
+ event = UX500_MUSB_NONE;
+ /*
+ * Fallback to default B_IDLE as nothing
+ * is connected
+ */
+ ab->phy.state = OTG_STATE_B_IDLE;
+ break;
+
+ case USB_LINK_ACA_RID_C_NM_8505:
+ event = UX500_MUSB_RIDC;
+ case USB_LINK_STD_HOST_NC_8505:
+ case USB_LINK_STD_HOST_C_NS_8505:
+ case USB_LINK_STD_HOST_C_S_8505:
+ case USB_LINK_CDP_8505:
+ if (ab->mode == USB_IDLE) {
+ ab->mode = USB_PERIPHERAL;
+ ab8500_usb_peri_phy_en(ab);
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ UX500_MUSB_PREPARE, &ab->vbus_draw);
+ }
+ if (event != UX500_MUSB_RIDC)
+ event = UX500_MUSB_VBUS;
+ break;
+
+ case USB_LINK_ACA_RID_A_8505:
+ case USB_LINK_ACA_DOCK_CHGR_8505:
+ event = UX500_MUSB_RIDA;
+ case USB_LINK_HM_IDGND_8505:
+ if (ab->mode == USB_IDLE) {
+ ab->mode = USB_HOST;
+ ab8500_usb_host_phy_en(ab);
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ UX500_MUSB_PREPARE, &ab->vbus_draw);
+ }
+ ab->phy.otg->default_a = true;
+ if (event != UX500_MUSB_RIDA)
+ event = UX500_MUSB_ID;
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ event, &ab->vbus_draw);
+ break;
+
+ case USB_LINK_DEDICATED_CHG_8505:
+ ab->mode = USB_DEDICATED_CHG;
+ event = UX500_MUSB_CHARGER;
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ event, &ab->vbus_draw);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int ab8500_usb_link_status_update(struct ab8500_usb *ab,
+ enum ab8500_usb_link_status lsts)
+{
+ enum ux500_musb_vbus_id_status event = 0;
+
+ dev_dbg(ab->dev, "ab8500_usb_link_status_update %d\n", lsts);
+
+ /*
+ * Spurious link_status interrupts are seen in case of a
+ * disconnection of a device in IDGND and RIDA stage
+ */
+ if (ab->previous_link_status_state == USB_LINK_HM_IDGND_8500 &&
+ (lsts == USB_LINK_STD_HOST_C_NS_8500 ||
+ lsts == USB_LINK_STD_HOST_NC_8500))
+ return 0;
+
+ if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8500 &&
+ lsts == USB_LINK_STD_HOST_NC_8500)
+ return 0;
+
+ ab->previous_link_status_state = lsts;
+
+ switch (lsts) {
+ case USB_LINK_ACA_RID_B_8500:
+ event = UX500_MUSB_RIDB;
+ case USB_LINK_NOT_CONFIGURED_8500:
+ case USB_LINK_NOT_VALID_LINK_8500:
+ ab->mode = USB_IDLE;
+ ab->phy.otg->default_a = false;
+ ab->vbus_draw = 0;
+ if (event != UX500_MUSB_RIDB)
+ event = UX500_MUSB_NONE;
+ /* Fallback to default B_IDLE as nothing is connected */
+ ab->phy.state = OTG_STATE_B_IDLE;
+ break;
+
+ case USB_LINK_ACA_RID_C_NM_8500:
+ case USB_LINK_ACA_RID_C_HS_8500:
+ case USB_LINK_ACA_RID_C_HS_CHIRP_8500:
+ event = UX500_MUSB_RIDC;
+ case USB_LINK_STD_HOST_NC_8500:
+ case USB_LINK_STD_HOST_C_NS_8500:
+ case USB_LINK_STD_HOST_C_S_8500:
+ case USB_LINK_HOST_CHG_NM_8500:
+ case USB_LINK_HOST_CHG_HS_8500:
+ case USB_LINK_HOST_CHG_HS_CHIRP_8500:
+ if (ab->mode == USB_IDLE) {
+ ab->mode = USB_PERIPHERAL;
+ ab8500_usb_peri_phy_en(ab);
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ UX500_MUSB_PREPARE, &ab->vbus_draw);
+ }
+ if (event != UX500_MUSB_RIDC)
+ event = UX500_MUSB_VBUS;
+ break;
+
+ case USB_LINK_ACA_RID_A_8500:
+ event = UX500_MUSB_RIDA;
+ case USB_LINK_HM_IDGND_8500:
+ if (ab->mode == USB_IDLE) {
+ ab->mode = USB_HOST;
+ ab8500_usb_host_phy_en(ab);
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ UX500_MUSB_PREPARE, &ab->vbus_draw);
+ }
+ ab->phy.otg->default_a = true;
+ if (event != UX500_MUSB_RIDA)
+ event = UX500_MUSB_ID;
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ event, &ab->vbus_draw);
+ break;
+
+ case USB_LINK_DEDICATED_CHG_8500:
+ ab->mode = USB_DEDICATED_CHG;
+ event = UX500_MUSB_CHARGER;
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ event, &ab->vbus_draw);
+ break;
+
+ case USB_LINK_RESERVED_8500:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Connection Sequence:
+ * 1. Link Status Interrupt
+ * 2. Enable AB clock
+ * 3. Enable AB regulators
+ * 4. Enable USB phy
+ * 5. Reset the musb controller
+ * 6. Switch the ULPI GPIO pins to fucntion mode
+ * 7. Enable the musb Peripheral5 clock
+ * 8. Restore MUSB context
+ */
+static int abx500_usb_link_status_update(struct ab8500_usb *ab)
+{
+ u8 reg;
+ int ret = 0;
+
+ if (is_ab8500(ab->ab8500)) {
+ enum ab8500_usb_link_status lsts;
+
+ abx500_get_register_interruptible(ab->dev,
+ AB8500_USB, AB8500_USB_LINE_STAT_REG, &reg);
+ lsts = (reg >> 3) & 0x0F;
+ ret = ab8500_usb_link_status_update(ab, lsts);
+ } else if (is_ab8505(ab->ab8500)) {
+ enum ab8505_usb_link_status lsts;
+
+ abx500_get_register_interruptible(ab->dev,
+ AB8500_USB, AB8505_USB_LINE_STAT_REG, &reg);
+ lsts = (reg >> 3) & 0x1F;
+ ret = ab8505_usb_link_status_update(ab, lsts);
+ }
+
+ return ret;
+}
+
+/*
+ * Disconnection Sequence:
+ * 1. Disconect Interrupt
+ * 2. Disable regulators
+ * 3. Disable AB clock
+ * 4. Disable the Phy
+ * 5. Link Status Interrupt
+ * 6. Disable Musb Clock
+ */
+static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data)
+{
+ struct ab8500_usb *ab = (struct ab8500_usb *) data;
+ enum usb_phy_events event = UX500_MUSB_NONE;
+
+ /* Link status will not be updated till phy is disabled. */
+ if (ab->mode == USB_HOST) {
+ ab->phy.otg->default_a = false;
+ ab->vbus_draw = 0;
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ event, &ab->vbus_draw);
+ ab8500_usb_host_phy_dis(ab);
+ ab->mode = USB_IDLE;
+ }
+
+ if (ab->mode == USB_PERIPHERAL) {
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ event, &ab->vbus_draw);
+ ab8500_usb_peri_phy_dis(ab);
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ UX500_MUSB_CLEAN, &ab->vbus_draw);
+ ab->mode = USB_IDLE;
+ ab->phy.otg->default_a = false;
+ ab->vbus_draw = 0;
+ }
+
+ if (is_ab8500_2p0(ab->ab8500)) {
+ if (ab->mode == USB_DEDICATED_CHG) {
+ ab8500_usb_wd_linkstatus(ab,
+ AB8500_BIT_PHY_CTRL_DEVICE_EN);
+ abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+ AB8500_BIT_PHY_CTRL_DEVICE_EN, 0);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ab8500_usb_link_status_irq(int irq, void *data)
+{
+ struct ab8500_usb *ab = (struct ab8500_usb *) data;
+
+ abx500_usb_link_status_update(ab);
+
+ return IRQ_HANDLED;
+}
+
+static void ab8500_usb_phy_disable_work(struct work_struct *work)
+{
+ struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
+ phy_dis_work);
+
+ if (!ab->phy.otg->host)
+ ab8500_usb_host_phy_dis(ab);
+
+ if (!ab->phy.otg->gadget)
+ ab8500_usb_peri_phy_dis(ab);
+}
+
+static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA)
+{
+ /*
+ * AB8500 V2 has eye diagram issues when drawing more than 100mA from
+ * VBUS. Set charging current to 100mA in case of standard host
+ */
+ if (is_ab8500_2p0_or_earlier(ab->ab8500))
+ if (mA > 100)
+ mA = 100;
+
+ return mA;
+}
+
+static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA)
+{
+ struct ab8500_usb *ab;
+
+ if (!phy)
+ return -ENODEV;
+
+ ab = phy_to_ab(phy);
+
+ mA = ab8500_eyediagram_workaroud(ab, mA);
+
+ ab->vbus_draw = mA;
+
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ UX500_MUSB_VBUS, &ab->vbus_draw);
+
+ return 0;
+}
+
+static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend)
+{
+ /* TODO */
+ return 0;
+}
+
+static int ab8500_usb_set_peripheral(struct usb_otg *otg,
+ struct usb_gadget *gadget)
+{
+ struct ab8500_usb *ab;
+
+ if (!otg)
+ return -ENODEV;
+
+ ab = phy_to_ab(otg->phy);
+
+ ab->phy.otg->gadget = gadget;
+
+ /* Some drivers call this function in atomic context.
+ * Do not update ab8500 registers directly till this
+ * is fixed.
+ */
+
+ if ((ab->mode != USB_IDLE) && (!gadget)) {
+ ab->mode = USB_IDLE;
+ schedule_work(&ab->phy_dis_work);
+ }
+
+ return 0;
+}
+
+static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+ struct ab8500_usb *ab;
+
+ if (!otg)
+ return -ENODEV;
+
+ ab = phy_to_ab(otg->phy);
+
+ ab->phy.otg->host = host;
+
+ /* Some drivers call this function in atomic context.
+ * Do not update ab8500 registers directly till this
+ * is fixed.
+ */
+
+ if ((ab->mode != USB_IDLE) && (!host)) {
+ ab->mode = USB_IDLE;
+ schedule_work(&ab->phy_dis_work);
+ }
+
+ return 0;
+}
+
+static int ab8500_usb_regulator_get(struct ab8500_usb *ab)
+{
+ int err;
+
+ ab->v_ape = devm_regulator_get(ab->dev, "v-ape");
+ if (IS_ERR(ab->v_ape)) {
+ dev_err(ab->dev, "Could not get v-ape supply\n");
+ err = PTR_ERR(ab->v_ape);
+ return err;
+ }
+
+ ab->v_ulpi = devm_regulator_get(ab->dev, "vddulpivio18");
+ if (IS_ERR(ab->v_ulpi)) {
+ dev_err(ab->dev, "Could not get vddulpivio18 supply\n");
+ err = PTR_ERR(ab->v_ulpi);
+ return err;
+ }
+
+ ab->v_musb = devm_regulator_get(ab->dev, "musb_1v8");
+ if (IS_ERR(ab->v_musb)) {
+ dev_err(ab->dev, "Could not get musb_1v8 supply\n");
+ err = PTR_ERR(ab->v_musb);
+ return err;
+ }
+
+ return 0;
+}
+
+static int ab8500_usb_irq_setup(struct platform_device *pdev,
+ struct ab8500_usb *ab)
+{
+ int err;
+ int irq;
+
+ irq = platform_get_irq_byname(pdev, "USB_LINK_STATUS");
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Link status irq not found\n");
+ return irq;
+ }
+ err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ ab8500_usb_link_status_irq,
+ IRQF_NO_SUSPEND | IRQF_SHARED, "usb-link-status", ab);
+ if (err < 0) {
+ dev_err(ab->dev, "request_irq failed for link status irq\n");
+ return err;
+ }
+
+ irq = platform_get_irq_byname(pdev, "ID_WAKEUP_F");
+ if (irq < 0) {
+ dev_err(&pdev->dev, "ID fall irq not found\n");
+ return irq;
+ }
+ err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ ab8500_usb_disconnect_irq,
+ IRQF_NO_SUSPEND | IRQF_SHARED, "usb-id-fall", ab);
+ if (err < 0) {
+ dev_err(ab->dev, "request_irq failed for ID fall irq\n");
+ return err;
+ }
+
+ irq = platform_get_irq_byname(pdev, "VBUS_DET_F");
+ if (irq < 0) {
+ dev_err(&pdev->dev, "VBUS fall irq not found\n");
+ return irq;
+ }
+ err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ ab8500_usb_disconnect_irq,
+ IRQF_NO_SUSPEND | IRQF_SHARED, "usb-vbus-fall", ab);
+ if (err < 0) {
+ dev_err(ab->dev, "request_irq failed for Vbus fall irq\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int ab8500_usb_probe(struct platform_device *pdev)
+{
+ struct ab8500_usb *ab;
+ struct ab8500 *ab8500;
+ struct usb_otg *otg;
+ int err;
+ int rev;
+
+ ab8500 = dev_get_drvdata(pdev->dev.parent);
+ rev = abx500_get_chip_id(&pdev->dev);
+
+ if (is_ab8500_1p1_or_earlier(ab8500)) {
+ dev_err(&pdev->dev, "Unsupported AB8500 chip rev=%d\n", rev);
+ return -ENODEV;
+ }
+
+ ab = devm_kzalloc(&pdev->dev, sizeof(*ab), GFP_KERNEL);
+ if (!ab)
+ return -ENOMEM;
+
+ otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
+ if (!otg)
+ return -ENOMEM;
+
+ ab->dev = &pdev->dev;
+ ab->ab8500 = ab8500;
+ ab->phy.dev = ab->dev;
+ ab->phy.otg = otg;
+ ab->phy.label = "ab8500";
+ ab->phy.set_suspend = ab8500_usb_set_suspend;
+ ab->phy.set_power = ab8500_usb_set_power;
+ ab->phy.state = OTG_STATE_UNDEFINED;
+
+ otg->phy = &ab->phy;
+ otg->set_host = ab8500_usb_set_host;
+ otg->set_peripheral = ab8500_usb_set_peripheral;
+
+ platform_set_drvdata(pdev, ab);
+
+ ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier);
+
+ /* all: Disable phy when called from set_host and set_peripheral */
+ INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
+
+ err = ab8500_usb_regulator_get(ab);
+ if (err)
+ return err;
+
+ err = ab8500_usb_irq_setup(pdev, ab);
+ if (err < 0)
+ return err;
+
+ err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2);
+ if (err) {
+ dev_err(&pdev->dev, "Can't register transceiver\n");
+ return err;
+ }
+
+ /* Phy tuning values for AB8500 */
+ if (!is_ab8500_2p0_or_earlier(ab->ab8500)) {
+ /* Enable the PBT/Bank 0x12 access */
+ err = abx500_set_register_interruptible(ab->dev,
+ AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x01);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to enable bank12 access err=%d\n",
+ err);
+
+ err = abx500_set_register_interruptible(ab->dev,
+ AB8500_DEBUG, AB8500_USB_PHY_TUNE1, 0xC8);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to set PHY_TUNE1 register err=%d\n",
+ err);
+
+ err = abx500_set_register_interruptible(ab->dev,
+ AB8500_DEBUG, AB8500_USB_PHY_TUNE2, 0x00);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to set PHY_TUNE2 register err=%d\n",
+ err);
+
+ err = abx500_set_register_interruptible(ab->dev,
+ AB8500_DEBUG, AB8500_USB_PHY_TUNE3, 0x78);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n",
+ err);
+
+ /* Switch to normal mode/disable Bank 0x12 access */
+ err = abx500_set_register_interruptible(ab->dev,
+ AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x00);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to switch bank12 access err=%d\n",
+ err);
+ }
+
+ /* Phy tuning values for AB8505 */
+ if (is_ab8505(ab->ab8500)) {
+ /* Enable the PBT/Bank 0x12 access */
+ err = abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS,
+ 0x01, 0x01);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to enable bank12 access err=%d\n",
+ err);
+
+ err = abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_DEBUG, AB8500_USB_PHY_TUNE1,
+ 0xC8, 0xC8);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to set PHY_TUNE1 register err=%d\n",
+ err);
+
+ err = abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_DEBUG, AB8500_USB_PHY_TUNE2,
+ 0x60, 0x60);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to set PHY_TUNE2 register err=%d\n",
+ err);
+
+ err = abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_DEBUG, AB8500_USB_PHY_TUNE3,
+ 0xFC, 0x80);
+
+ if (err < 0)
+ dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n",
+ err);
+
+ /* Switch to normal mode/disable Bank 0x12 access */
+ err = abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS,
+ 0x00, 0x00);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to switch bank12 access err=%d\n",
+ err);
+ }
+
+ /* Needed to enable ID detection. */
+ ab8500_usb_wd_workaround(ab);
+
+ abx500_usb_link_status_update(ab);
+
+ dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", rev);
+
+ return 0;
+}
+
+static int ab8500_usb_remove(struct platform_device *pdev)
+{
+ struct ab8500_usb *ab = platform_get_drvdata(pdev);
+
+ cancel_work_sync(&ab->phy_dis_work);
+
+ usb_remove_phy(&ab->phy);
+
+ if (ab->mode == USB_HOST)
+ ab8500_usb_host_phy_dis(ab);
+ else if (ab->mode == USB_PERIPHERAL)
+ ab8500_usb_peri_phy_dis(ab);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver ab8500_usb_driver = {
+ .probe = ab8500_usb_probe,
+ .remove = ab8500_usb_remove,
+ .driver = {
+ .name = "ab8500-usb",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ab8500_usb_init(void)
+{
+ return platform_driver_register(&ab8500_usb_driver);
+}
+subsys_initcall(ab8500_usb_init);
+
+static void __exit ab8500_usb_exit(void)
+{
+ platform_driver_unregister(&ab8500_usb_driver);
+}
+module_exit(ab8500_usb_exit);
+
+MODULE_ALIAS("platform:ab8500_usb");
+MODULE_AUTHOR("ST-Ericsson AB");
+MODULE_DESCRIPTION("AB8500 usb transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/phy/phy-fsl-usb.c
index d16adb41eb21..97b9308507c3 100644
--- a/drivers/usb/otg/fsl_otg.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -43,7 +43,7 @@
#include <asm/unaligned.h>
-#include "fsl_otg.h"
+#include "phy-fsl-usb.h"
#define DRIVER_VERSION "Rev. 1.55"
#define DRIVER_AUTHOR "Jerry Huang/Li Yang"
@@ -361,28 +361,18 @@ int fsl_otg_init_timers(struct otg_fsm *fsm)
void fsl_otg_uninit_timers(void)
{
/* FSM used timers */
- if (a_wait_vrise_tmr != NULL)
- kfree(a_wait_vrise_tmr);
- if (a_wait_bcon_tmr != NULL)
- kfree(a_wait_bcon_tmr);
- if (a_aidl_bdis_tmr != NULL)
- kfree(a_aidl_bdis_tmr);
- if (b_ase0_brst_tmr != NULL)
- kfree(b_ase0_brst_tmr);
- if (b_se0_srp_tmr != NULL)
- kfree(b_se0_srp_tmr);
- if (b_srp_fail_tmr != NULL)
- kfree(b_srp_fail_tmr);
- if (a_wait_enum_tmr != NULL)
- kfree(a_wait_enum_tmr);
+ kfree(a_wait_vrise_tmr);
+ kfree(a_wait_bcon_tmr);
+ kfree(a_aidl_bdis_tmr);
+ kfree(b_ase0_brst_tmr);
+ kfree(b_se0_srp_tmr);
+ kfree(b_srp_fail_tmr);
+ kfree(a_wait_enum_tmr);
/* device driver used timers */
- if (b_srp_wait_tmr != NULL)
- kfree(b_srp_wait_tmr);
- if (b_data_pulse_tmr != NULL)
- kfree(b_data_pulse_tmr);
- if (b_vbus_pulse_tmr != NULL)
- kfree(b_vbus_pulse_tmr);
+ kfree(b_srp_wait_tmr);
+ kfree(b_data_pulse_tmr);
+ kfree(b_vbus_pulse_tmr);
}
/* Add timer to timer list */
@@ -1002,7 +992,7 @@ static int show_fsl_usb2_otg_state(struct device *dev,
/* State */
t = scnprintf(next, size,
"OTG state: %s\n\n",
- otg_state_string(fsl_otg_dev->phy.state));
+ usb_otg_state_string(fsl_otg_dev->phy.state));
size -= t;
next += t;
diff --git a/drivers/usb/otg/fsl_otg.h b/drivers/usb/phy/phy-fsl-usb.h
index ca266280895d..ca266280895d 100644
--- a/drivers/usb/otg/fsl_otg.h
+++ b/drivers/usb/phy/phy-fsl-usb.h
diff --git a/drivers/usb/otg/otg_fsm.c b/drivers/usb/phy/phy-fsm-usb.c
index ade131a8ae5e..c520b3548e7c 100644
--- a/drivers/usb/otg/otg_fsm.c
+++ b/drivers/usb/phy/phy-fsm-usb.c
@@ -29,7 +29,7 @@
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
-#include "otg_fsm.h"
+#include "phy-otg-fsm.h"
/* Change USB protocol when there is a protocol change */
static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
@@ -119,7 +119,7 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
state_changed = 1;
if (fsm->otg->phy->state == new_state)
return 0;
- VDBG("Set state: %s\n", otg_state_string(new_state));
+ VDBG("Set state: %s\n", usb_otg_state_string(new_state));
otg_leave_state(fsm, fsm->otg->phy->state);
switch (new_state) {
case OTG_STATE_B_IDLE:
diff --git a/drivers/usb/otg/otg_fsm.h b/drivers/usb/phy/phy-fsm-usb.h
index c30a2e1d9e46..c30a2e1d9e46 100644
--- a/drivers/usb/otg/otg_fsm.h
+++ b/drivers/usb/phy/phy-fsm-usb.h
diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/phy/phy-gpio-vbus-usb.c
index a7d4ac591982..4c76074e518d 100644
--- a/drivers/usb/otg/gpio_vbus.c
+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c
@@ -61,6 +61,7 @@ static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
{
struct regulator *vbus_draw = gpio_vbus->vbus_draw;
int enabled;
+ int ret;
if (!vbus_draw)
return;
@@ -69,12 +70,16 @@ static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
if (mA) {
regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
if (!enabled) {
- regulator_enable(vbus_draw);
+ ret = regulator_enable(vbus_draw);
+ if (ret < 0)
+ return;
gpio_vbus->vbus_draw_enabled = 1;
}
} else {
if (enabled) {
- regulator_disable(vbus_draw);
+ ret = regulator_disable(vbus_draw);
+ if (ret < 0)
+ return;
gpio_vbus->vbus_draw_enabled = 0;
}
}
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/phy/phy-isp1301-omap.c
index 8b9de9581319..ae481afcb3ec 100644
--- a/drivers/usb/otg/isp1301_omap.c
+++ b/drivers/usb/phy/phy-isp1301-omap.c
@@ -236,7 +236,7 @@ isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
static inline const char *state_name(struct isp1301 *isp)
{
- return otg_state_string(isp->phy.state);
+ return usb_otg_state_string(isp->phy.state);
}
/*-------------------------------------------------------------------------*/
@@ -481,7 +481,7 @@ static void check_state(struct isp1301 *isp, const char *tag)
if (isp->phy.state == state && !extra)
return;
pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag,
- otg_state_string(state), fsm, state_name(isp),
+ usb_otg_state_string(state), fsm, state_name(isp),
omap_readl(OTG_CTRL));
}
@@ -1077,7 +1077,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
if (state != isp->phy.state)
pr_debug(" isp, %s -> %s\n",
- otg_state_string(state), state_name(isp));
+ usb_otg_state_string(state), state_name(isp));
#ifdef CONFIG_USB_OTG
/* update the OTG controller state to match the isp1301; may
diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c
new file mode 100644
index 000000000000..225ae6c97eeb
--- /dev/null
+++ b/drivers/usb/phy/phy-isp1301.c
@@ -0,0 +1,162 @@
+/*
+ * NXP ISP1301 USB transceiver driver
+ *
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * Author: Roland Stigge <stigge@antcom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/usb/phy.h>
+#include <linux/usb/isp1301.h>
+
+#define DRV_NAME "isp1301"
+
+struct isp1301 {
+ struct usb_phy phy;
+ struct mutex mutex;
+
+ struct i2c_client *client;
+};
+
+#define phy_to_isp(p) (container_of((p), struct isp1301, phy))
+
+static const struct i2c_device_id isp1301_id[] = {
+ { "isp1301", 0 },
+ { }
+};
+
+static struct i2c_client *isp1301_i2c_client;
+
+static int __isp1301_write(struct isp1301 *isp, u8 reg, u8 value, u8 clear)
+{
+ return i2c_smbus_write_byte_data(isp->client, reg | clear, value);
+}
+
+static int isp1301_write(struct isp1301 *isp, u8 reg, u8 value)
+{
+ return __isp1301_write(isp, reg, value, 0);
+}
+
+static int isp1301_clear(struct isp1301 *isp, u8 reg, u8 value)
+{
+ return __isp1301_write(isp, reg, value, ISP1301_I2C_REG_CLEAR_ADDR);
+}
+
+static int isp1301_phy_init(struct usb_phy *phy)
+{
+ struct isp1301 *isp = phy_to_isp(phy);
+
+ /* Disable transparent UART mode first */
+ isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_UART_EN);
+ isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_1, ~MC1_SPEED_REG);
+ isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_SPEED_REG);
+ isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_2, ~0);
+ isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_2, (MC2_BI_DI | MC2_PSW_EN
+ | MC2_SPD_SUSP_CTRL));
+
+ isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, ~0);
+ isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0);
+ isp1301_write(isp, ISP1301_I2C_OTG_CONTROL_1, (OTG1_DM_PULLDOWN
+ | OTG1_DP_PULLDOWN));
+ isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, (OTG1_DM_PULLUP
+ | OTG1_DP_PULLUP));
+
+ /* mask all interrupts */
+ isp1301_clear(isp, ISP1301_I2C_INTERRUPT_LATCH, ~0);
+ isp1301_clear(isp, ISP1301_I2C_INTERRUPT_FALLING, ~0);
+ isp1301_clear(isp, ISP1301_I2C_INTERRUPT_RISING, ~0);
+
+ return 0;
+}
+
+static int isp1301_phy_set_vbus(struct usb_phy *phy, int on)
+{
+ struct isp1301 *isp = phy_to_isp(phy);
+
+ if (on)
+ isp1301_write(isp, ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV);
+ else
+ isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV);
+
+ return 0;
+}
+
+static int isp1301_probe(struct i2c_client *client,
+ const struct i2c_device_id *i2c_id)
+{
+ struct isp1301 *isp;
+ struct usb_phy *phy;
+
+ isp = devm_kzalloc(&client->dev, sizeof(*isp), GFP_KERNEL);
+ if (!isp)
+ return -ENOMEM;
+
+ isp->client = client;
+ mutex_init(&isp->mutex);
+
+ phy = &isp->phy;
+ phy->label = DRV_NAME;
+ phy->init = isp1301_phy_init;
+ phy->set_vbus = isp1301_phy_set_vbus;
+ phy->type = USB_PHY_TYPE_USB2;
+
+ i2c_set_clientdata(client, isp);
+ usb_add_phy_dev(phy);
+
+ isp1301_i2c_client = client;
+
+ return 0;
+}
+
+static int isp1301_remove(struct i2c_client *client)
+{
+ struct isp1301 *isp = i2c_get_clientdata(client);
+
+ usb_remove_phy(&isp->phy);
+ isp1301_i2c_client = NULL;
+
+ return 0;
+}
+
+static struct i2c_driver isp1301_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ },
+ .probe = isp1301_probe,
+ .remove = isp1301_remove,
+ .id_table = isp1301_id,
+};
+
+module_i2c_driver(isp1301_driver);
+
+static int match(struct device *dev, void *data)
+{
+ struct device_node *node = (struct device_node *)data;
+ return (dev->of_node == node) &&
+ (dev->driver == &isp1301_driver.driver);
+}
+
+struct i2c_client *isp1301_get_client(struct device_node *node)
+{
+ if (node) { /* reference of ISP1301 I2C node via DT */
+ struct device *dev = bus_find_device(&i2c_bus_type, NULL,
+ node, match);
+ if (!dev)
+ return NULL;
+ return to_i2c_client(dev);
+ } else { /* non-DT: only one ISP1301 chip supported */
+ return isp1301_i2c_client;
+ }
+}
+EXPORT_SYMBOL_GPL(isp1301_get_client);
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/phy/phy-msm-usb.c
index 749fbf41fb6f..749fbf41fb6f 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/phy/phy-msm-usb.c
diff --git a/drivers/usb/phy/mv_u3d_phy.c b/drivers/usb/phy/phy-mv-u3d-usb.c
index bafd67f1f134..f7838a43347c 100644
--- a/drivers/usb/phy/mv_u3d_phy.c
+++ b/drivers/usb/phy/phy-mv-u3d-usb.c
@@ -15,7 +15,7 @@
#include <linux/usb/otg.h>
#include <linux/platform_data/mv_usb.h>
-#include "mv_u3d_phy.h"
+#include "phy-mv-u3d-usb.h"
/*
* struct mv_u3d_phy - transceiver driver state
diff --git a/drivers/usb/phy/mv_u3d_phy.h b/drivers/usb/phy/phy-mv-u3d-usb.h
index 2a658cb9a527..2a658cb9a527 100644
--- a/drivers/usb/phy/mv_u3d_phy.h
+++ b/drivers/usb/phy/phy-mv-u3d-usb.h
diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/phy/phy-mv-usb.c
index b6a9be31133b..c987bbe27851 100644
--- a/drivers/usb/otg/mv_otg.c
+++ b/drivers/usb/phy/phy-mv-usb.c
@@ -27,7 +27,7 @@
#include <linux/usb/hcd.h>
#include <linux/platform_data/mv_usb.h>
-#include "mv_otg.h"
+#include "phy-mv-usb.h"
#define DRIVER_DESC "Marvell USB OTG transceiver driver"
#define DRIVER_VERSION "Jan 20, 2010"
@@ -237,18 +237,12 @@ static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on)
static void otg_clock_enable(struct mv_otg *mvotg)
{
- unsigned int i;
-
- for (i = 0; i < mvotg->clknum; i++)
- clk_prepare_enable(mvotg->clk[i]);
+ clk_prepare_enable(mvotg->clk);
}
static void otg_clock_disable(struct mv_otg *mvotg)
{
- unsigned int i;
-
- for (i = 0; i < mvotg->clknum; i++)
- clk_disable_unprepare(mvotg->clk[i]);
+ clk_disable_unprepare(mvotg->clk);
}
static int mv_otg_enable_internal(struct mv_otg *mvotg)
@@ -684,16 +678,14 @@ static int mv_otg_probe(struct platform_device *pdev)
struct mv_otg *mvotg;
struct usb_otg *otg;
struct resource *r;
- int retval = 0, clk_i, i;
- size_t size;
+ int retval = 0, i;
if (pdata == NULL) {
dev_err(&pdev->dev, "failed to get platform data\n");
return -ENODEV;
}
- size = sizeof(*mvotg) + sizeof(struct clk *) * pdata->clknum;
- mvotg = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ mvotg = devm_kzalloc(&pdev->dev, sizeof(*mvotg), GFP_KERNEL);
if (!mvotg) {
dev_err(&pdev->dev, "failed to allocate memory!\n");
return -ENOMEM;
@@ -708,15 +700,9 @@ static int mv_otg_probe(struct platform_device *pdev)
mvotg->pdev = pdev;
mvotg->pdata = pdata;
- mvotg->clknum = pdata->clknum;
- for (clk_i = 0; clk_i < mvotg->clknum; clk_i++) {
- mvotg->clk[clk_i] = devm_clk_get(&pdev->dev,
- pdata->clkname[clk_i]);
- if (IS_ERR(mvotg->clk[clk_i])) {
- retval = PTR_ERR(mvotg->clk[clk_i]);
- return retval;
- }
- }
+ mvotg->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(mvotg->clk))
+ return PTR_ERR(mvotg->clk);
mvotg->qwork = create_singlethread_workqueue("mv_otg_queue");
if (!mvotg->qwork) {
diff --git a/drivers/usb/otg/mv_otg.h b/drivers/usb/phy/phy-mv-usb.h
index 8a9e351b36ba..551da6eb0ba8 100644
--- a/drivers/usb/otg/mv_otg.h
+++ b/drivers/usb/phy/phy-mv-usb.h
@@ -158,8 +158,7 @@ struct mv_otg {
unsigned int active;
unsigned int clock_gating;
- unsigned int clknum;
- struct clk *clk[0];
+ struct clk *clk;
};
#endif
diff --git a/drivers/usb/otg/mxs-phy.c b/drivers/usb/phy/phy-mxs-usb.c
index b0d9f119c749..9d4381e64d51 100644
--- a/drivers/usb/otg/mxs-phy.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -48,12 +48,12 @@ static void mxs_phy_hw_init(struct mxs_phy *mxs_phy)
stmp_reset_block(base + HW_USBPHY_CTRL);
/* Power up the PHY */
- writel_relaxed(0, base + HW_USBPHY_PWD);
+ writel(0, base + HW_USBPHY_PWD);
/* enable FS/LS device */
- writel_relaxed(BM_USBPHY_CTRL_ENUTMILEVEL2 |
- BM_USBPHY_CTRL_ENUTMILEVEL3,
- base + HW_USBPHY_CTRL_SET);
+ writel(BM_USBPHY_CTRL_ENUTMILEVEL2 |
+ BM_USBPHY_CTRL_ENUTMILEVEL3,
+ base + HW_USBPHY_CTRL_SET);
}
static int mxs_phy_init(struct usb_phy *phy)
@@ -70,8 +70,8 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
{
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
- writel_relaxed(BM_USBPHY_CTRL_CLKGATE,
- phy->io_priv + HW_USBPHY_CTRL_SET);
+ writel(BM_USBPHY_CTRL_CLKGATE,
+ phy->io_priv + HW_USBPHY_CTRL_SET);
clk_disable_unprepare(mxs_phy->clk);
}
@@ -81,15 +81,15 @@ static int mxs_phy_suspend(struct usb_phy *x, int suspend)
struct mxs_phy *mxs_phy = to_mxs_phy(x);
if (suspend) {
- writel_relaxed(0xffffffff, x->io_priv + HW_USBPHY_PWD);
- writel_relaxed(BM_USBPHY_CTRL_CLKGATE,
- x->io_priv + HW_USBPHY_CTRL_SET);
+ writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
+ writel(BM_USBPHY_CTRL_CLKGATE,
+ x->io_priv + HW_USBPHY_CTRL_SET);
clk_disable_unprepare(mxs_phy->clk);
} else {
clk_prepare_enable(mxs_phy->clk);
- writel_relaxed(BM_USBPHY_CTRL_CLKGATE,
- x->io_priv + HW_USBPHY_CTRL_CLR);
- writel_relaxed(0, x->io_priv + HW_USBPHY_PWD);
+ writel(BM_USBPHY_CTRL_CLKGATE,
+ x->io_priv + HW_USBPHY_CTRL_CLR);
+ writel(0, x->io_priv + HW_USBPHY_PWD);
}
return 0;
@@ -102,8 +102,8 @@ static int mxs_phy_on_connect(struct usb_phy *phy,
(speed == USB_SPEED_HIGH) ? "high" : "non-high");
if (speed == USB_SPEED_HIGH)
- writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
- phy->io_priv + HW_USBPHY_CTRL_SET);
+ writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ phy->io_priv + HW_USBPHY_CTRL_SET);
return 0;
}
@@ -115,8 +115,8 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy,
(speed == USB_SPEED_HIGH) ? "high" : "non-high");
if (speed == USB_SPEED_HIGH)
- writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
- phy->io_priv + HW_USBPHY_CTRL_CLR);
+ writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ phy->io_priv + HW_USBPHY_CTRL_CLR);
return 0;
}
@@ -127,6 +127,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
void __iomem *base;
struct clk *clk;
struct mxs_phy *mxs_phy;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -166,11 +167,19 @@ static int mxs_phy_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, &mxs_phy->phy);
+ ret = usb_add_phy_dev(&mxs_phy->phy);
+ if (ret)
+ return ret;
+
return 0;
}
static int mxs_phy_remove(struct platform_device *pdev)
{
+ struct mxs_phy *mxs_phy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(&mxs_phy->phy);
+
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/phy/phy-nop.c
index a3ce24b94a73..2b10cc969bbb 100644
--- a/drivers/usb/otg/nop-usb-xceiv.c
+++ b/drivers/usb/phy/phy-nop.c
@@ -32,10 +32,16 @@
#include <linux/usb/otg.h>
#include <linux/usb/nop-usb-xceiv.h>
#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
struct nop_usb_xceiv {
- struct usb_phy phy;
- struct device *dev;
+ struct usb_phy phy;
+ struct device *dev;
+ struct clk *clk;
+ struct regulator *vcc;
+ struct regulator *reset;
};
static struct platform_device *pd;
@@ -64,6 +70,46 @@ static int nop_set_suspend(struct usb_phy *x, int suspend)
return 0;
}
+static int nop_init(struct usb_phy *phy)
+{
+ struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+
+ if (!IS_ERR(nop->vcc)) {
+ if (regulator_enable(nop->vcc))
+ dev_err(phy->dev, "Failed to enable power\n");
+ }
+
+ if (!IS_ERR(nop->clk))
+ clk_enable(nop->clk);
+
+ if (!IS_ERR(nop->reset)) {
+ /* De-assert RESET */
+ if (regulator_enable(nop->reset))
+ dev_err(phy->dev, "Failed to de-assert reset\n");
+ }
+
+ return 0;
+}
+
+static void nop_shutdown(struct usb_phy *phy)
+{
+ struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+
+ if (!IS_ERR(nop->reset)) {
+ /* Assert RESET */
+ if (regulator_disable(nop->reset))
+ dev_err(phy->dev, "Failed to assert reset\n");
+ }
+
+ if (!IS_ERR(nop->clk))
+ clk_disable(nop->clk);
+
+ if (!IS_ERR(nop->vcc)) {
+ if (regulator_disable(nop->vcc))
+ dev_err(phy->dev, "Failed to disable power\n");
+ }
+}
+
static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
{
if (!otg)
@@ -95,39 +141,96 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
static int nop_usb_xceiv_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data;
struct nop_usb_xceiv *nop;
enum usb_phy_type type = USB_PHY_TYPE_USB2;
int err;
+ u32 clk_rate = 0;
+ bool needs_vcc = false;
+ bool needs_reset = false;
- nop = kzalloc(sizeof *nop, GFP_KERNEL);
+ nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL);
if (!nop)
return -ENOMEM;
- nop->phy.otg = kzalloc(sizeof *nop->phy.otg, GFP_KERNEL);
- if (!nop->phy.otg) {
- kfree(nop);
+ nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg),
+ GFP_KERNEL);
+ if (!nop->phy.otg)
return -ENOMEM;
- }
- if (pdata)
+ if (dev->of_node) {
+ struct device_node *node = dev->of_node;
+
+ if (of_property_read_u32(node, "clock-frequency", &clk_rate))
+ clk_rate = 0;
+
+ needs_vcc = of_property_read_bool(node, "vcc-supply");
+ needs_reset = of_property_read_bool(node, "reset-supply");
+
+ } else if (pdata) {
type = pdata->type;
+ clk_rate = pdata->clk_rate;
+ needs_vcc = pdata->needs_vcc;
+ needs_reset = pdata->needs_reset;
+ }
+
+ nop->clk = devm_clk_get(&pdev->dev, "main_clk");
+ if (IS_ERR(nop->clk)) {
+ dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n",
+ PTR_ERR(nop->clk));
+ }
+
+ if (!IS_ERR(nop->clk) && clk_rate) {
+ err = clk_set_rate(nop->clk, clk_rate);
+ if (err) {
+ dev_err(&pdev->dev, "Error setting clock rate\n");
+ return err;
+ }
+ }
+
+ if (!IS_ERR(nop->clk)) {
+ err = clk_prepare(nop->clk);
+ if (err) {
+ dev_err(&pdev->dev, "Error preparing clock\n");
+ return err;
+ }
+ }
+
+ nop->vcc = devm_regulator_get(&pdev->dev, "vcc");
+ if (IS_ERR(nop->vcc)) {
+ dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n",
+ PTR_ERR(nop->vcc));
+ if (needs_vcc)
+ return -EPROBE_DEFER;
+ }
+
+ nop->reset = devm_regulator_get(&pdev->dev, "reset");
+ if (IS_ERR(nop->reset)) {
+ dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n",
+ PTR_ERR(nop->reset));
+ if (needs_reset)
+ return -EPROBE_DEFER;
+ }
nop->dev = &pdev->dev;
nop->phy.dev = nop->dev;
nop->phy.label = "nop-xceiv";
nop->phy.set_suspend = nop_set_suspend;
+ nop->phy.init = nop_init;
+ nop->phy.shutdown = nop_shutdown;
nop->phy.state = OTG_STATE_UNDEFINED;
+ nop->phy.type = type;
nop->phy.otg->phy = &nop->phy;
nop->phy.otg->set_host = nop_set_host;
nop->phy.otg->set_peripheral = nop_set_peripheral;
- err = usb_add_phy(&nop->phy, type);
+ err = usb_add_phy_dev(&nop->phy);
if (err) {
dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
err);
- goto exit;
+ goto err_add;
}
platform_set_drvdata(pdev, nop);
@@ -135,9 +238,10 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev)
ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
return 0;
-exit:
- kfree(nop->phy.otg);
- kfree(nop);
+
+err_add:
+ if (!IS_ERR(nop->clk))
+ clk_unprepare(nop->clk);
return err;
}
@@ -145,21 +249,30 @@ static int nop_usb_xceiv_remove(struct platform_device *pdev)
{
struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
+ if (!IS_ERR(nop->clk))
+ clk_unprepare(nop->clk);
+
usb_remove_phy(&nop->phy);
platform_set_drvdata(pdev, NULL);
- kfree(nop->phy.otg);
- kfree(nop);
return 0;
}
+static const struct of_device_id nop_xceiv_dt_ids[] = {
+ { .compatible = "usb-nop-xceiv" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
+
static struct platform_driver nop_usb_xceiv_driver = {
.probe = nop_usb_xceiv_probe,
.remove = nop_usb_xceiv_remove,
.driver = {
.name = "nop_usb_xceiv",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(nop_xceiv_dt_ids),
},
};
diff --git a/drivers/usb/phy/omap-control-usb.c b/drivers/usb/phy/phy-omap-control.c
index 1419ceda9759..1419ceda9759 100644
--- a/drivers/usb/phy/omap-control-usb.c
+++ b/drivers/usb/phy/phy-omap-control.c
diff --git a/drivers/usb/phy/omap-usb2.c b/drivers/usb/phy/phy-omap-usb2.c
index 844ab68f08d0..844ab68f08d0 100644
--- a/drivers/usb/phy/omap-usb2.c
+++ b/drivers/usb/phy/phy-omap-usb2.c
diff --git a/drivers/usb/phy/omap-usb3.c b/drivers/usb/phy/phy-omap-usb3.c
index a6e60b1e102e..a6e60b1e102e 100644
--- a/drivers/usb/phy/omap-usb3.c
+++ b/drivers/usb/phy/phy-omap-usb3.c
diff --git a/drivers/usb/phy/rcar-phy.c b/drivers/usb/phy/phy-rcar-usb.c
index a35681b0c501..a35681b0c501 100644
--- a/drivers/usb/phy/rcar-phy.c
+++ b/drivers/usb/phy/phy-rcar-usb.c
diff --git a/drivers/usb/phy/phy-samsung-usb.c b/drivers/usb/phy/phy-samsung-usb.c
new file mode 100644
index 000000000000..7b118ee5f5e4
--- /dev/null
+++ b/drivers/usb/phy/phy-samsung-usb.c
@@ -0,0 +1,236 @@
+/* linux/drivers/usb/phy/phy-samsung-usb.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Praveen Paneri <p.paneri@samsung.com>
+ *
+ * Samsung USB-PHY helper driver with common function calls;
+ * interacts with Samsung USB 2.0 PHY controller driver and later
+ * with Samsung USB 3.0 PHY driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/usb/samsung_usb_phy.h>
+
+#include "phy-samsung-usb.h"
+
+int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
+{
+ struct device_node *usbphy_sys;
+
+ /* Getting node for system controller interface for usb-phy */
+ usbphy_sys = of_get_child_by_name(sphy->dev->of_node, "usbphy-sys");
+ if (!usbphy_sys) {
+ dev_err(sphy->dev, "No sys-controller interface for usb-phy\n");
+ return -ENODEV;
+ }
+
+ sphy->pmuregs = of_iomap(usbphy_sys, 0);
+
+ if (sphy->pmuregs == NULL) {
+ dev_err(sphy->dev, "Can't get usb-phy pmu control register\n");
+ goto err0;
+ }
+
+ sphy->sysreg = of_iomap(usbphy_sys, 1);
+
+ /*
+ * Not returning error code here, since this situation is not fatal.
+ * Few SoCs may not have this switch available
+ */
+ if (sphy->sysreg == NULL)
+ dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n");
+
+ of_node_put(usbphy_sys);
+
+ return 0;
+
+err0:
+ of_node_put(usbphy_sys);
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_parse_dt);
+
+/*
+ * Set isolation here for phy.
+ * Here 'on = true' would mean USB PHY block is isolated, hence
+ * de-activated and vice-versa.
+ */
+void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on)
+{
+ void __iomem *reg = NULL;
+ u32 reg_val;
+ u32 en_mask = 0;
+
+ if (!sphy->pmuregs) {
+ dev_warn(sphy->dev, "Can't set pmu isolation\n");
+ return;
+ }
+
+ switch (sphy->drv_data->cpu_type) {
+ case TYPE_S3C64XX:
+ /*
+ * Do nothing: We will add here once S3C64xx goes for DT support
+ */
+ break;
+ case TYPE_EXYNOS4210:
+ /*
+ * Fall through since exynos4210 and exynos5250 have similar
+ * register architecture: two separate registers for host and
+ * device phy control with enable bit at position 0.
+ */
+ case TYPE_EXYNOS5250:
+ if (sphy->phy_type == USB_PHY_TYPE_DEVICE) {
+ reg = sphy->pmuregs +
+ sphy->drv_data->devphy_reg_offset;
+ en_mask = sphy->drv_data->devphy_en_mask;
+ } else if (sphy->phy_type == USB_PHY_TYPE_HOST) {
+ reg = sphy->pmuregs +
+ sphy->drv_data->hostphy_reg_offset;
+ en_mask = sphy->drv_data->hostphy_en_mask;
+ }
+ break;
+ default:
+ dev_err(sphy->dev, "Invalid SoC type\n");
+ return;
+ }
+
+ reg_val = readl(reg);
+
+ if (on)
+ reg_val &= ~en_mask;
+ else
+ reg_val |= en_mask;
+
+ writel(reg_val, reg);
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_set_isolation);
+
+/*
+ * Configure the mode of working of usb-phy here: HOST/DEVICE.
+ */
+void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy)
+{
+ u32 reg;
+
+ if (!sphy->sysreg) {
+ dev_warn(sphy->dev, "Can't configure specified phy mode\n");
+ return;
+ }
+
+ reg = readl(sphy->sysreg);
+
+ if (sphy->phy_type == USB_PHY_TYPE_DEVICE)
+ reg &= ~EXYNOS_USB20PHY_CFG_HOST_LINK;
+ else if (sphy->phy_type == USB_PHY_TYPE_HOST)
+ reg |= EXYNOS_USB20PHY_CFG_HOST_LINK;
+
+ writel(reg, sphy->sysreg);
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_cfg_sel);
+
+/*
+ * PHYs are different for USB Device and USB Host.
+ * This make sure that correct PHY type is selected before
+ * any operation on PHY.
+ */
+int samsung_usbphy_set_type(struct usb_phy *phy,
+ enum samsung_usb_phy_type phy_type)
+{
+ struct samsung_usbphy *sphy = phy_to_sphy(phy);
+
+ sphy->phy_type = phy_type;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_set_type);
+
+/*
+ * Returns reference clock frequency selection value
+ */
+int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+ struct clk *ref_clk;
+ int refclk_freq = 0;
+
+ /*
+ * In exynos5250 USB host and device PHY use
+ * external crystal clock XXTI
+ */
+ if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
+ ref_clk = devm_clk_get(sphy->dev, "ext_xtal");
+ else
+ ref_clk = devm_clk_get(sphy->dev, "xusbxti");
+ if (IS_ERR(ref_clk)) {
+ dev_err(sphy->dev, "Failed to get reference clock\n");
+ return PTR_ERR(ref_clk);
+ }
+
+ if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) {
+ /* set clock frequency for PLL */
+ switch (clk_get_rate(ref_clk)) {
+ case 9600 * KHZ:
+ refclk_freq = FSEL_CLKSEL_9600K;
+ break;
+ case 10 * MHZ:
+ refclk_freq = FSEL_CLKSEL_10M;
+ break;
+ case 12 * MHZ:
+ refclk_freq = FSEL_CLKSEL_12M;
+ break;
+ case 19200 * KHZ:
+ refclk_freq = FSEL_CLKSEL_19200K;
+ break;
+ case 20 * MHZ:
+ refclk_freq = FSEL_CLKSEL_20M;
+ break;
+ case 50 * MHZ:
+ refclk_freq = FSEL_CLKSEL_50M;
+ break;
+ case 24 * MHZ:
+ default:
+ /* default reference clock */
+ refclk_freq = FSEL_CLKSEL_24M;
+ break;
+ }
+ } else {
+ switch (clk_get_rate(ref_clk)) {
+ case 12 * MHZ:
+ refclk_freq = PHYCLK_CLKSEL_12M;
+ break;
+ case 24 * MHZ:
+ refclk_freq = PHYCLK_CLKSEL_24M;
+ break;
+ case 48 * MHZ:
+ refclk_freq = PHYCLK_CLKSEL_48M;
+ break;
+ default:
+ if (sphy->drv_data->cpu_type == TYPE_S3C64XX)
+ refclk_freq = PHYCLK_CLKSEL_48M;
+ else
+ refclk_freq = PHYCLK_CLKSEL_24M;
+ break;
+ }
+ }
+ clk_put(ref_clk);
+
+ return refclk_freq;
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_get_refclk_freq);
diff --git a/drivers/usb/phy/phy-samsung-usb.h b/drivers/usb/phy/phy-samsung-usb.h
new file mode 100644
index 000000000000..70a9cae5e37f
--- /dev/null
+++ b/drivers/usb/phy/phy-samsung-usb.h
@@ -0,0 +1,327 @@
+/* linux/drivers/usb/phy/phy-samsung-usb.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Samsung USB-PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and
+ * OHCI-EXYNOS controllers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/usb/phy.h>
+
+/* Register definitions */
+
+#define SAMSUNG_PHYPWR (0x00)
+
+#define PHYPWR_NORMAL_MASK (0x19 << 0)
+#define PHYPWR_OTG_DISABLE (0x1 << 4)
+#define PHYPWR_ANALOG_POWERDOWN (0x1 << 3)
+#define PHYPWR_FORCE_SUSPEND (0x1 << 1)
+/* For Exynos4 */
+#define PHYPWR_NORMAL_MASK_PHY0 (0x39 << 0)
+#define PHYPWR_SLEEP_PHY0 (0x1 << 5)
+
+#define SAMSUNG_PHYCLK (0x04)
+
+#define PHYCLK_MODE_USB11 (0x1 << 6)
+#define PHYCLK_EXT_OSC (0x1 << 5)
+#define PHYCLK_COMMON_ON_N (0x1 << 4)
+#define PHYCLK_ID_PULL (0x1 << 2)
+#define PHYCLK_CLKSEL_MASK (0x3 << 0)
+#define PHYCLK_CLKSEL_48M (0x0 << 0)
+#define PHYCLK_CLKSEL_12M (0x2 << 0)
+#define PHYCLK_CLKSEL_24M (0x3 << 0)
+
+#define SAMSUNG_RSTCON (0x08)
+
+#define RSTCON_PHYLINK_SWRST (0x1 << 2)
+#define RSTCON_HLINK_SWRST (0x1 << 1)
+#define RSTCON_SWRST (0x1 << 0)
+
+/* EXYNOS5 */
+#define EXYNOS5_PHY_HOST_CTRL0 (0x00)
+
+#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31)
+
+#define HOST_CTRL0_REFCLKSEL_MASK (0x3 << 19)
+#define HOST_CTRL0_REFCLKSEL_XTAL (0x0 << 19)
+#define HOST_CTRL0_REFCLKSEL_EXTL (0x1 << 19)
+#define HOST_CTRL0_REFCLKSEL_CLKCORE (0x2 << 19)
+
+#define HOST_CTRL0_FSEL_MASK (0x7 << 16)
+#define HOST_CTRL0_FSEL(_x) ((_x) << 16)
+
+#define FSEL_CLKSEL_50M (0x7)
+#define FSEL_CLKSEL_24M (0x5)
+#define FSEL_CLKSEL_20M (0x4)
+#define FSEL_CLKSEL_19200K (0x3)
+#define FSEL_CLKSEL_12M (0x2)
+#define FSEL_CLKSEL_10M (0x1)
+#define FSEL_CLKSEL_9600K (0x0)
+
+#define HOST_CTRL0_TESTBURNIN (0x1 << 11)
+#define HOST_CTRL0_RETENABLE (0x1 << 10)
+#define HOST_CTRL0_COMMONON_N (0x1 << 9)
+#define HOST_CTRL0_SIDDQ (0x1 << 6)
+#define HOST_CTRL0_FORCESLEEP (0x1 << 5)
+#define HOST_CTRL0_FORCESUSPEND (0x1 << 4)
+#define HOST_CTRL0_WORDINTERFACE (0x1 << 3)
+#define HOST_CTRL0_UTMISWRST (0x1 << 2)
+#define HOST_CTRL0_LINKSWRST (0x1 << 1)
+#define HOST_CTRL0_PHYSWRST (0x1 << 0)
+
+#define EXYNOS5_PHY_HOST_TUNE0 (0x04)
+
+#define EXYNOS5_PHY_HSIC_CTRL1 (0x10)
+
+#define EXYNOS5_PHY_HSIC_TUNE1 (0x14)
+
+#define EXYNOS5_PHY_HSIC_CTRL2 (0x20)
+
+#define EXYNOS5_PHY_HSIC_TUNE2 (0x24)
+
+#define HSIC_CTRL_REFCLKSEL_MASK (0x3 << 23)
+#define HSIC_CTRL_REFCLKSEL (0x2 << 23)
+
+#define HSIC_CTRL_REFCLKDIV_MASK (0x7f << 16)
+#define HSIC_CTRL_REFCLKDIV(_x) ((_x) << 16)
+#define HSIC_CTRL_REFCLKDIV_12 (0x24 << 16)
+#define HSIC_CTRL_REFCLKDIV_15 (0x1c << 16)
+#define HSIC_CTRL_REFCLKDIV_16 (0x1a << 16)
+#define HSIC_CTRL_REFCLKDIV_19_2 (0x15 << 16)
+#define HSIC_CTRL_REFCLKDIV_20 (0x14 << 16)
+
+#define HSIC_CTRL_SIDDQ (0x1 << 6)
+#define HSIC_CTRL_FORCESLEEP (0x1 << 5)
+#define HSIC_CTRL_FORCESUSPEND (0x1 << 4)
+#define HSIC_CTRL_WORDINTERFACE (0x1 << 3)
+#define HSIC_CTRL_UTMISWRST (0x1 << 2)
+#define HSIC_CTRL_PHYSWRST (0x1 << 0)
+
+#define EXYNOS5_PHY_HOST_EHCICTRL (0x30)
+
+#define HOST_EHCICTRL_ENAINCRXALIGN (0x1 << 29)
+#define HOST_EHCICTRL_ENAINCR4 (0x1 << 28)
+#define HOST_EHCICTRL_ENAINCR8 (0x1 << 27)
+#define HOST_EHCICTRL_ENAINCR16 (0x1 << 26)
+
+#define EXYNOS5_PHY_HOST_OHCICTRL (0x34)
+
+#define HOST_OHCICTRL_SUSPLGCY (0x1 << 3)
+#define HOST_OHCICTRL_APPSTARTCLK (0x1 << 2)
+#define HOST_OHCICTRL_CNTSEL (0x1 << 1)
+#define HOST_OHCICTRL_CLKCKTRST (0x1 << 0)
+
+#define EXYNOS5_PHY_OTG_SYS (0x38)
+
+#define OTG_SYS_PHYLINK_SWRESET (0x1 << 14)
+#define OTG_SYS_LINKSWRST_UOTG (0x1 << 13)
+#define OTG_SYS_PHY0_SWRST (0x1 << 12)
+
+#define OTG_SYS_REFCLKSEL_MASK (0x3 << 9)
+#define OTG_SYS_REFCLKSEL_XTAL (0x0 << 9)
+#define OTG_SYS_REFCLKSEL_EXTL (0x1 << 9)
+#define OTG_SYS_REFCLKSEL_CLKCORE (0x2 << 9)
+
+#define OTG_SYS_IDPULLUP_UOTG (0x1 << 8)
+#define OTG_SYS_COMMON_ON (0x1 << 7)
+
+#define OTG_SYS_FSEL_MASK (0x7 << 4)
+#define OTG_SYS_FSEL(_x) ((_x) << 4)
+
+#define OTG_SYS_FORCESLEEP (0x1 << 3)
+#define OTG_SYS_OTGDISABLE (0x1 << 2)
+#define OTG_SYS_SIDDQ_UOTG (0x1 << 1)
+#define OTG_SYS_FORCESUSPEND (0x1 << 0)
+
+#define EXYNOS5_PHY_OTG_TUNE (0x40)
+
+/* EXYNOS5: USB 3.0 DRD */
+#define EXYNOS5_DRD_LINKSYSTEM (0x04)
+
+#define LINKSYSTEM_FLADJ_MASK (0x3f << 1)
+#define LINKSYSTEM_FLADJ(_x) ((_x) << 1)
+#define LINKSYSTEM_XHCI_VERSION_CONTROL (0x1 << 27)
+
+#define EXYNOS5_DRD_PHYUTMI (0x08)
+
+#define PHYUTMI_OTGDISABLE (0x1 << 6)
+#define PHYUTMI_FORCESUSPEND (0x1 << 1)
+#define PHYUTMI_FORCESLEEP (0x1 << 0)
+
+#define EXYNOS5_DRD_PHYPIPE (0x0c)
+
+#define EXYNOS5_DRD_PHYCLKRST (0x10)
+
+#define PHYCLKRST_SSC_REFCLKSEL_MASK (0xff << 23)
+#define PHYCLKRST_SSC_REFCLKSEL(_x) ((_x) << 23)
+
+#define PHYCLKRST_SSC_RANGE_MASK (0x03 << 21)
+#define PHYCLKRST_SSC_RANGE(_x) ((_x) << 21)
+
+#define PHYCLKRST_SSC_EN (0x1 << 20)
+#define PHYCLKRST_REF_SSP_EN (0x1 << 19)
+#define PHYCLKRST_REF_CLKDIV2 (0x1 << 18)
+
+#define PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF (0x19 << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF (0x02 << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF (0x68 << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF (0x7d << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF (0x02 << 11)
+
+#define PHYCLKRST_FSEL_MASK (0x3f << 5)
+#define PHYCLKRST_FSEL(_x) ((_x) << 5)
+#define PHYCLKRST_FSEL_PAD_100MHZ (0x27 << 5)
+#define PHYCLKRST_FSEL_PAD_24MHZ (0x2a << 5)
+#define PHYCLKRST_FSEL_PAD_20MHZ (0x31 << 5)
+#define PHYCLKRST_FSEL_PAD_19_2MHZ (0x38 << 5)
+
+#define PHYCLKRST_RETENABLEN (0x1 << 4)
+
+#define PHYCLKRST_REFCLKSEL_MASK (0x03 << 2)
+#define PHYCLKRST_REFCLKSEL_PAD_REFCLK (0x2 << 2)
+#define PHYCLKRST_REFCLKSEL_EXT_REFCLK (0x3 << 2)
+
+#define PHYCLKRST_PORTRESET (0x1 << 1)
+#define PHYCLKRST_COMMONONN (0x1 << 0)
+
+#define EXYNOS5_DRD_PHYREG0 (0x14)
+#define EXYNOS5_DRD_PHYREG1 (0x18)
+
+#define EXYNOS5_DRD_PHYPARAM0 (0x1c)
+
+#define PHYPARAM0_REF_USE_PAD (0x1 << 31)
+#define PHYPARAM0_REF_LOSLEVEL_MASK (0x1f << 26)
+#define PHYPARAM0_REF_LOSLEVEL (0x9 << 26)
+
+#define EXYNOS5_DRD_PHYPARAM1 (0x20)
+
+#define PHYPARAM1_PCS_TXDEEMPH_MASK (0x1f << 0)
+#define PHYPARAM1_PCS_TXDEEMPH (0x1c)
+
+#define EXYNOS5_DRD_PHYTERM (0x24)
+
+#define EXYNOS5_DRD_PHYTEST (0x28)
+
+#define PHYTEST_POWERDOWN_SSP (0x1 << 3)
+#define PHYTEST_POWERDOWN_HSP (0x1 << 2)
+
+#define EXYNOS5_DRD_PHYADP (0x2c)
+
+#define EXYNOS5_DRD_PHYBATCHG (0x30)
+
+#define PHYBATCHG_UTMI_CLKSEL (0x1 << 2)
+
+#define EXYNOS5_DRD_PHYRESUME (0x34)
+#define EXYNOS5_DRD_LINKPORT (0x44)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+#ifndef KHZ
+#define KHZ (1000)
+#endif
+
+#define EXYNOS_USBHOST_PHY_CTRL_OFFSET (0x4)
+#define S3C64XX_USBPHY_ENABLE (0x1 << 16)
+#define EXYNOS_USBPHY_ENABLE (0x1 << 0)
+#define EXYNOS_USB20PHY_CFG_HOST_LINK (0x1 << 0)
+
+enum samsung_cpu_type {
+ TYPE_S3C64XX,
+ TYPE_EXYNOS4210,
+ TYPE_EXYNOS5250,
+};
+
+/*
+ * struct samsung_usbphy_drvdata - driver data for various SoC variants
+ * @cpu_type: machine identifier
+ * @devphy_en_mask: device phy enable mask for PHY CONTROL register
+ * @hostphy_en_mask: host phy enable mask for PHY CONTROL register
+ * @devphy_reg_offset: offset to DEVICE PHY CONTROL register from
+ * mapped address of system controller.
+ * @hostphy_reg_offset: offset to HOST PHY CONTROL register from
+ * mapped address of system controller.
+ *
+ * Here we have a separate mask for device type phy.
+ * Having different masks for host and device type phy helps
+ * in setting independent masks in case of SoCs like S5PV210,
+ * in which PHY0 and PHY1 enable bits belong to same register
+ * placed at position 0 and 1 respectively.
+ * Although for newer SoCs like exynos these bits belong to
+ * different registers altogether placed at position 0.
+ */
+struct samsung_usbphy_drvdata {
+ int cpu_type;
+ int devphy_en_mask;
+ int hostphy_en_mask;
+ u32 devphy_reg_offset;
+ u32 hostphy_reg_offset;
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy controller registers memory base
+ * @pmuregs: USB device PHY_CONTROL register memory base
+ * @sysreg: USB2.0 PHY_CFG register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @drv_data: driver data available for different SoCs
+ * @phy_type: Samsung SoCs specific phy types: #HOST
+ * #DEVICE
+ * @phy_usage: usage count for phy
+ * @lock: lock for phy operations
+ */
+struct samsung_usbphy {
+ struct usb_phy phy;
+ struct samsung_usbphy_data *plat;
+ struct device *dev;
+ struct clk *clk;
+ void __iomem *regs;
+ void __iomem *pmuregs;
+ void __iomem *sysreg;
+ int ref_clk_freq;
+ const struct samsung_usbphy_drvdata *drv_data;
+ enum samsung_usb_phy_type phy_type;
+ atomic_t phy_usage;
+ spinlock_t lock;
+};
+
+#define phy_to_sphy(x) container_of((x), struct samsung_usbphy, phy)
+
+static const struct of_device_id samsung_usbphy_dt_match[];
+
+static inline const struct samsung_usbphy_drvdata
+*samsung_usbphy_get_driver_data(struct platform_device *pdev)
+{
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(samsung_usbphy_dt_match,
+ pdev->dev.of_node);
+ return match->data;
+ }
+
+ return (struct samsung_usbphy_drvdata *)
+ platform_get_device_id(pdev)->driver_data;
+}
+
+extern int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy);
+extern void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on);
+extern void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy);
+extern int samsung_usbphy_set_type(struct usb_phy *phy,
+ enum samsung_usb_phy_type phy_type);
+extern int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy);
diff --git a/drivers/usb/phy/phy-samsung-usb2.c b/drivers/usb/phy/phy-samsung-usb2.c
new file mode 100644
index 000000000000..45ffe036dacc
--- /dev/null
+++ b/drivers/usb/phy/phy-samsung-usb2.c
@@ -0,0 +1,509 @@
+/* linux/drivers/usb/phy/phy-samsung-usb2.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Praveen Paneri <p.paneri@samsung.com>
+ *
+ * Samsung USB2.0 PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and
+ * OHCI-EXYNOS controllers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/samsung_usb_phy.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+#include "phy-samsung-usb.h"
+
+static int samsung_usbphy_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+ if (!otg)
+ return -ENODEV;
+
+ if (!otg->host)
+ otg->host = host;
+
+ return 0;
+}
+
+static bool exynos5_phyhost_is_on(void __iomem *regs)
+{
+ u32 reg;
+
+ reg = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
+
+ return !(reg & HOST_CTRL0_SIDDQ);
+}
+
+static void samsung_exynos5_usb2phy_enable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phyclk = sphy->ref_clk_freq;
+ u32 phyhost;
+ u32 phyotg;
+ u32 phyhsic;
+ u32 ehcictrl;
+ u32 ohcictrl;
+
+ /*
+ * phy_usage helps in keeping usage count for phy
+ * so that the first consumer enabling the phy is also
+ * the last consumer to disable it.
+ */
+
+ atomic_inc(&sphy->phy_usage);
+
+ if (exynos5_phyhost_is_on(regs)) {
+ dev_info(sphy->dev, "Already power on PHY\n");
+ return;
+ }
+
+ /* Host configuration */
+ phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
+
+ /* phy reference clock configuration */
+ phyhost &= ~HOST_CTRL0_FSEL_MASK;
+ phyhost |= HOST_CTRL0_FSEL(phyclk);
+
+ /* host phy reset */
+ phyhost &= ~(HOST_CTRL0_PHYSWRST |
+ HOST_CTRL0_PHYSWRSTALL |
+ HOST_CTRL0_SIDDQ |
+ /* Enable normal mode of operation */
+ HOST_CTRL0_FORCESUSPEND |
+ HOST_CTRL0_FORCESLEEP);
+
+ /* Link reset */
+ phyhost |= (HOST_CTRL0_LINKSWRST |
+ HOST_CTRL0_UTMISWRST |
+ /* COMMON Block configuration during suspend */
+ HOST_CTRL0_COMMONON_N);
+ writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
+ udelay(10);
+ phyhost &= ~(HOST_CTRL0_LINKSWRST |
+ HOST_CTRL0_UTMISWRST);
+ writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
+
+ /* OTG configuration */
+ phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
+
+ /* phy reference clock configuration */
+ phyotg &= ~OTG_SYS_FSEL_MASK;
+ phyotg |= OTG_SYS_FSEL(phyclk);
+
+ /* Enable normal mode of operation */
+ phyotg &= ~(OTG_SYS_FORCESUSPEND |
+ OTG_SYS_SIDDQ_UOTG |
+ OTG_SYS_FORCESLEEP |
+ OTG_SYS_REFCLKSEL_MASK |
+ /* COMMON Block configuration during suspend */
+ OTG_SYS_COMMON_ON);
+
+ /* OTG phy & link reset */
+ phyotg |= (OTG_SYS_PHY0_SWRST |
+ OTG_SYS_LINKSWRST_UOTG |
+ OTG_SYS_PHYLINK_SWRESET |
+ OTG_SYS_OTGDISABLE |
+ /* Set phy refclk */
+ OTG_SYS_REFCLKSEL_CLKCORE);
+
+ writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
+ udelay(10);
+ phyotg &= ~(OTG_SYS_PHY0_SWRST |
+ OTG_SYS_LINKSWRST_UOTG |
+ OTG_SYS_PHYLINK_SWRESET);
+ writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
+
+ /* HSIC phy configuration */
+ phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
+ HSIC_CTRL_REFCLKSEL |
+ HSIC_CTRL_PHYSWRST);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
+ udelay(10);
+ phyhsic &= ~HSIC_CTRL_PHYSWRST;
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
+
+ udelay(80);
+
+ /* enable EHCI DMA burst */
+ ehcictrl = readl(regs + EXYNOS5_PHY_HOST_EHCICTRL);
+ ehcictrl |= (HOST_EHCICTRL_ENAINCRXALIGN |
+ HOST_EHCICTRL_ENAINCR4 |
+ HOST_EHCICTRL_ENAINCR8 |
+ HOST_EHCICTRL_ENAINCR16);
+ writel(ehcictrl, regs + EXYNOS5_PHY_HOST_EHCICTRL);
+
+ /* set ohci_suspend_on_n */
+ ohcictrl = readl(regs + EXYNOS5_PHY_HOST_OHCICTRL);
+ ohcictrl |= HOST_OHCICTRL_SUSPLGCY;
+ writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL);
+}
+
+static void samsung_usb2phy_enable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phypwr;
+ u32 phyclk;
+ u32 rstcon;
+
+ /* set clock frequency for PLL */
+ phyclk = sphy->ref_clk_freq;
+ phypwr = readl(regs + SAMSUNG_PHYPWR);
+ rstcon = readl(regs + SAMSUNG_RSTCON);
+
+ switch (sphy->drv_data->cpu_type) {
+ case TYPE_S3C64XX:
+ phyclk &= ~PHYCLK_COMMON_ON_N;
+ phypwr &= ~PHYPWR_NORMAL_MASK;
+ rstcon |= RSTCON_SWRST;
+ break;
+ case TYPE_EXYNOS4210:
+ phypwr &= ~PHYPWR_NORMAL_MASK_PHY0;
+ rstcon |= RSTCON_SWRST;
+ default:
+ break;
+ }
+
+ writel(phyclk, regs + SAMSUNG_PHYCLK);
+ /* Configure PHY0 for normal operation*/
+ writel(phypwr, regs + SAMSUNG_PHYPWR);
+ /* reset all ports of PHY and Link */
+ writel(rstcon, regs + SAMSUNG_RSTCON);
+ udelay(10);
+ rstcon &= ~RSTCON_SWRST;
+ writel(rstcon, regs + SAMSUNG_RSTCON);
+}
+
+static void samsung_exynos5_usb2phy_disable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phyhost;
+ u32 phyotg;
+ u32 phyhsic;
+
+ if (atomic_dec_return(&sphy->phy_usage) > 0) {
+ dev_info(sphy->dev, "still being used\n");
+ return;
+ }
+
+ phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
+ HSIC_CTRL_REFCLKSEL |
+ HSIC_CTRL_SIDDQ |
+ HSIC_CTRL_FORCESLEEP |
+ HSIC_CTRL_FORCESUSPEND);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
+
+ phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
+ phyhost |= (HOST_CTRL0_SIDDQ |
+ HOST_CTRL0_FORCESUSPEND |
+ HOST_CTRL0_FORCESLEEP |
+ HOST_CTRL0_PHYSWRST |
+ HOST_CTRL0_PHYSWRSTALL);
+ writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
+
+ phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
+ phyotg |= (OTG_SYS_FORCESUSPEND |
+ OTG_SYS_SIDDQ_UOTG |
+ OTG_SYS_FORCESLEEP);
+ writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
+}
+
+static void samsung_usb2phy_disable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phypwr;
+
+ phypwr = readl(regs + SAMSUNG_PHYPWR);
+
+ switch (sphy->drv_data->cpu_type) {
+ case TYPE_S3C64XX:
+ phypwr |= PHYPWR_NORMAL_MASK;
+ break;
+ case TYPE_EXYNOS4210:
+ phypwr |= PHYPWR_NORMAL_MASK_PHY0;
+ default:
+ break;
+ }
+
+ /* Disable analog and otg block power */
+ writel(phypwr, regs + SAMSUNG_PHYPWR);
+}
+
+/*
+ * The function passed to the usb driver for phy initialization
+ */
+static int samsung_usb2phy_init(struct usb_phy *phy)
+{
+ struct samsung_usbphy *sphy;
+ struct usb_bus *host = NULL;
+ unsigned long flags;
+ int ret = 0;
+
+ sphy = phy_to_sphy(phy);
+
+ host = phy->otg->host;
+
+ /* Enable the phy clock */
+ ret = clk_prepare_enable(sphy->clk);
+ if (ret) {
+ dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+ return ret;
+ }
+
+ spin_lock_irqsave(&sphy->lock, flags);
+
+ if (host) {
+ /* setting default phy-type for USB 2.0 */
+ if (!strstr(dev_name(host->controller), "ehci") ||
+ !strstr(dev_name(host->controller), "ohci"))
+ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
+ } else {
+ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
+ }
+
+ /* Disable phy isolation */
+ if (sphy->plat && sphy->plat->pmu_isolation)
+ sphy->plat->pmu_isolation(false);
+ else
+ samsung_usbphy_set_isolation(sphy, false);
+
+ /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */
+ samsung_usbphy_cfg_sel(sphy);
+
+ /* Initialize usb phy registers */
+ if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
+ samsung_exynos5_usb2phy_enable(sphy);
+ else
+ samsung_usb2phy_enable(sphy);
+
+ spin_unlock_irqrestore(&sphy->lock, flags);
+
+ /* Disable the phy clock */
+ clk_disable_unprepare(sphy->clk);
+
+ return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usb2phy_shutdown(struct usb_phy *phy)
+{
+ struct samsung_usbphy *sphy;
+ struct usb_bus *host = NULL;
+ unsigned long flags;
+
+ sphy = phy_to_sphy(phy);
+
+ host = phy->otg->host;
+
+ if (clk_prepare_enable(sphy->clk)) {
+ dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+ return;
+ }
+
+ spin_lock_irqsave(&sphy->lock, flags);
+
+ if (host) {
+ /* setting default phy-type for USB 2.0 */
+ if (!strstr(dev_name(host->controller), "ehci") ||
+ !strstr(dev_name(host->controller), "ohci"))
+ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
+ } else {
+ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
+ }
+
+ /* De-initialize usb phy registers */
+ if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
+ samsung_exynos5_usb2phy_disable(sphy);
+ else
+ samsung_usb2phy_disable(sphy);
+
+ /* Enable phy isolation */
+ if (sphy->plat && sphy->plat->pmu_isolation)
+ sphy->plat->pmu_isolation(true);
+ else
+ samsung_usbphy_set_isolation(sphy, true);
+
+ spin_unlock_irqrestore(&sphy->lock, flags);
+
+ clk_disable_unprepare(sphy->clk);
+}
+
+static int samsung_usb2phy_probe(struct platform_device *pdev)
+{
+ struct samsung_usbphy *sphy;
+ struct usb_otg *otg;
+ struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
+ const struct samsung_usbphy_drvdata *drv_data;
+ struct device *dev = &pdev->dev;
+ struct resource *phy_mem;
+ void __iomem *phy_base;
+ struct clk *clk;
+ int ret;
+
+ phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!phy_mem) {
+ dev_err(dev, "%s: missing mem resource\n", __func__);
+ return -ENODEV;
+ }
+
+ phy_base = devm_ioremap_resource(dev, phy_mem);
+ if (IS_ERR(phy_base))
+ return PTR_ERR(phy_base);
+
+ sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+ if (!sphy)
+ return -ENOMEM;
+
+ otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL);
+ if (!otg)
+ return -ENOMEM;
+
+ drv_data = samsung_usbphy_get_driver_data(pdev);
+
+ if (drv_data->cpu_type == TYPE_EXYNOS5250)
+ clk = devm_clk_get(dev, "usbhost");
+ else
+ clk = devm_clk_get(dev, "otg");
+
+ if (IS_ERR(clk)) {
+ dev_err(dev, "Failed to get otg clock\n");
+ return PTR_ERR(clk);
+ }
+
+ sphy->dev = dev;
+
+ if (dev->of_node) {
+ ret = samsung_usbphy_parse_dt(sphy);
+ if (ret < 0)
+ return ret;
+ } else {
+ if (!pdata) {
+ dev_err(dev, "no platform data specified\n");
+ return -EINVAL;
+ }
+ }
+
+ sphy->plat = pdata;
+ sphy->regs = phy_base;
+ sphy->clk = clk;
+ sphy->drv_data = drv_data;
+ sphy->phy.dev = sphy->dev;
+ sphy->phy.label = "samsung-usb2phy";
+ sphy->phy.init = samsung_usb2phy_init;
+ sphy->phy.shutdown = samsung_usb2phy_shutdown;
+ sphy->ref_clk_freq = samsung_usbphy_get_refclk_freq(sphy);
+
+ sphy->phy.otg = otg;
+ sphy->phy.otg->phy = &sphy->phy;
+ sphy->phy.otg->set_host = samsung_usbphy_set_host;
+
+ spin_lock_init(&sphy->lock);
+
+ platform_set_drvdata(pdev, sphy);
+
+ return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
+}
+
+static int samsung_usb2phy_remove(struct platform_device *pdev)
+{
+ struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(&sphy->phy);
+
+ if (sphy->pmuregs)
+ iounmap(sphy->pmuregs);
+ if (sphy->sysreg)
+ iounmap(sphy->sysreg);
+
+ return 0;
+}
+
+static const struct samsung_usbphy_drvdata usb2phy_s3c64xx = {
+ .cpu_type = TYPE_S3C64XX,
+ .devphy_en_mask = S3C64XX_USBPHY_ENABLE,
+};
+
+static const struct samsung_usbphy_drvdata usb2phy_exynos4 = {
+ .cpu_type = TYPE_EXYNOS4210,
+ .devphy_en_mask = EXYNOS_USBPHY_ENABLE,
+ .hostphy_en_mask = EXYNOS_USBPHY_ENABLE,
+};
+
+static struct samsung_usbphy_drvdata usb2phy_exynos5 = {
+ .cpu_type = TYPE_EXYNOS5250,
+ .hostphy_en_mask = EXYNOS_USBPHY_ENABLE,
+ .hostphy_reg_offset = EXYNOS_USBHOST_PHY_CTRL_OFFSET,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+ {
+ .compatible = "samsung,s3c64xx-usb2phy",
+ .data = &usb2phy_s3c64xx,
+ }, {
+ .compatible = "samsung,exynos4210-usb2phy",
+ .data = &usb2phy_exynos4,
+ }, {
+ .compatible = "samsung,exynos5250-usb2phy",
+ .data = &usb2phy_exynos5
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+ {
+ .name = "s3c64xx-usb2phy",
+ .driver_data = (unsigned long)&usb2phy_s3c64xx,
+ }, {
+ .name = "exynos4210-usb2phy",
+ .driver_data = (unsigned long)&usb2phy_exynos4,
+ }, {
+ .name = "exynos5250-usb2phy",
+ .driver_data = (unsigned long)&usb2phy_exynos5,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usb2phy_driver = {
+ .probe = samsung_usb2phy_probe,
+ .remove = samsung_usb2phy_remove,
+ .id_table = samsung_usbphy_driver_ids,
+ .driver = {
+ .name = "samsung-usb2phy",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(samsung_usbphy_dt_match),
+ },
+};
+
+module_platform_driver(samsung_usb2phy_driver);
+
+MODULE_DESCRIPTION("Samsung USB 2.0 phy controller");
+MODULE_AUTHOR("Praveen Paneri <p.paneri@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usb2phy");
diff --git a/drivers/usb/phy/phy-samsung-usb3.c b/drivers/usb/phy/phy-samsung-usb3.c
new file mode 100644
index 000000000000..133f3d0c554f
--- /dev/null
+++ b/drivers/usb/phy/phy-samsung-usb3.c
@@ -0,0 +1,347 @@
+/* linux/drivers/usb/phy/phy-samsung-usb3.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Vivek Gautam <gautam.vivek@samsung.com>
+ *
+ * Samsung USB 3.0 PHY transceiver; talks to DWC3 controller.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/samsung_usb_phy.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+#include "phy-samsung-usb.h"
+
+/*
+ * Sets the phy clk as EXTREFCLK (XXTI) which is internal clock from clock core.
+ */
+static u32 samsung_usb3phy_set_refclk(struct samsung_usbphy *sphy)
+{
+ u32 reg;
+ u32 refclk;
+
+ refclk = sphy->ref_clk_freq;
+
+ reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK |
+ PHYCLKRST_FSEL(refclk);
+
+ switch (refclk) {
+ case FSEL_CLKSEL_50M:
+ reg |= (PHYCLKRST_MPLL_MULTIPLIER_50M_REF |
+ PHYCLKRST_SSC_REFCLKSEL(0x00));
+ break;
+ case FSEL_CLKSEL_20M:
+ reg |= (PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF |
+ PHYCLKRST_SSC_REFCLKSEL(0x00));
+ break;
+ case FSEL_CLKSEL_19200K:
+ reg |= (PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF |
+ PHYCLKRST_SSC_REFCLKSEL(0x88));
+ break;
+ case FSEL_CLKSEL_24M:
+ default:
+ reg |= (PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
+ PHYCLKRST_SSC_REFCLKSEL(0x88));
+ break;
+ }
+
+ return reg;
+}
+
+static int samsung_exynos5_usb3phy_enable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phyparam0;
+ u32 phyparam1;
+ u32 linksystem;
+ u32 phybatchg;
+ u32 phytest;
+ u32 phyclkrst;
+
+ /* Reset USB 3.0 PHY */
+ writel(0x0, regs + EXYNOS5_DRD_PHYREG0);
+
+ phyparam0 = readl(regs + EXYNOS5_DRD_PHYPARAM0);
+ /* Select PHY CLK source */
+ phyparam0 &= ~PHYPARAM0_REF_USE_PAD;
+ /* Set Loss-of-Signal Detector sensitivity */
+ phyparam0 &= ~PHYPARAM0_REF_LOSLEVEL_MASK;
+ phyparam0 |= PHYPARAM0_REF_LOSLEVEL;
+ writel(phyparam0, regs + EXYNOS5_DRD_PHYPARAM0);
+
+ writel(0x0, regs + EXYNOS5_DRD_PHYRESUME);
+
+ /*
+ * Setting the Frame length Adj value[6:1] to default 0x20
+ * See xHCI 1.0 spec, 5.2.4
+ */
+ linksystem = LINKSYSTEM_XHCI_VERSION_CONTROL |
+ LINKSYSTEM_FLADJ(0x20);
+ writel(linksystem, regs + EXYNOS5_DRD_LINKSYSTEM);
+
+ phyparam1 = readl(regs + EXYNOS5_DRD_PHYPARAM1);
+ /* Set Tx De-Emphasis level */
+ phyparam1 &= ~PHYPARAM1_PCS_TXDEEMPH_MASK;
+ phyparam1 |= PHYPARAM1_PCS_TXDEEMPH;
+ writel(phyparam1, regs + EXYNOS5_DRD_PHYPARAM1);
+
+ phybatchg = readl(regs + EXYNOS5_DRD_PHYBATCHG);
+ phybatchg |= PHYBATCHG_UTMI_CLKSEL;
+ writel(phybatchg, regs + EXYNOS5_DRD_PHYBATCHG);
+
+ /* PHYTEST POWERDOWN Control */
+ phytest = readl(regs + EXYNOS5_DRD_PHYTEST);
+ phytest &= ~(PHYTEST_POWERDOWN_SSP |
+ PHYTEST_POWERDOWN_HSP);
+ writel(phytest, regs + EXYNOS5_DRD_PHYTEST);
+
+ /* UTMI Power Control */
+ writel(PHYUTMI_OTGDISABLE, regs + EXYNOS5_DRD_PHYUTMI);
+
+ phyclkrst = samsung_usb3phy_set_refclk(sphy);
+
+ phyclkrst |= PHYCLKRST_PORTRESET |
+ /* Digital power supply in normal operating mode */
+ PHYCLKRST_RETENABLEN |
+ /* Enable ref clock for SS function */
+ PHYCLKRST_REF_SSP_EN |
+ /* Enable spread spectrum */
+ PHYCLKRST_SSC_EN |
+ /* Power down HS Bias and PLL blocks in suspend mode */
+ PHYCLKRST_COMMONONN;
+
+ writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST);
+
+ udelay(10);
+
+ phyclkrst &= ~(PHYCLKRST_PORTRESET);
+ writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST);
+
+ return 0;
+}
+
+static void samsung_exynos5_usb3phy_disable(struct samsung_usbphy *sphy)
+{
+ u32 phyutmi;
+ u32 phyclkrst;
+ u32 phytest;
+ void __iomem *regs = sphy->regs;
+
+ phyutmi = PHYUTMI_OTGDISABLE |
+ PHYUTMI_FORCESUSPEND |
+ PHYUTMI_FORCESLEEP;
+ writel(phyutmi, regs + EXYNOS5_DRD_PHYUTMI);
+
+ /* Resetting the PHYCLKRST enable bits to reduce leakage current */
+ phyclkrst = readl(regs + EXYNOS5_DRD_PHYCLKRST);
+ phyclkrst &= ~(PHYCLKRST_REF_SSP_EN |
+ PHYCLKRST_SSC_EN |
+ PHYCLKRST_COMMONONN);
+ writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST);
+
+ /* Control PHYTEST to remove leakage current */
+ phytest = readl(regs + EXYNOS5_DRD_PHYTEST);
+ phytest |= (PHYTEST_POWERDOWN_SSP |
+ PHYTEST_POWERDOWN_HSP);
+ writel(phytest, regs + EXYNOS5_DRD_PHYTEST);
+}
+
+static int samsung_usb3phy_init(struct usb_phy *phy)
+{
+ struct samsung_usbphy *sphy;
+ unsigned long flags;
+ int ret = 0;
+
+ sphy = phy_to_sphy(phy);
+
+ /* Enable the phy clock */
+ ret = clk_prepare_enable(sphy->clk);
+ if (ret) {
+ dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+ return ret;
+ }
+
+ spin_lock_irqsave(&sphy->lock, flags);
+
+ /* setting default phy-type for USB 3.0 */
+ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
+
+ /* Disable phy isolation */
+ samsung_usbphy_set_isolation(sphy, false);
+
+ /* Initialize usb phy registers */
+ samsung_exynos5_usb3phy_enable(sphy);
+
+ spin_unlock_irqrestore(&sphy->lock, flags);
+
+ /* Disable the phy clock */
+ clk_disable_unprepare(sphy->clk);
+
+ return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usb3phy_shutdown(struct usb_phy *phy)
+{
+ struct samsung_usbphy *sphy;
+ unsigned long flags;
+
+ sphy = phy_to_sphy(phy);
+
+ if (clk_prepare_enable(sphy->clk)) {
+ dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+ return;
+ }
+
+ spin_lock_irqsave(&sphy->lock, flags);
+
+ /* setting default phy-type for USB 3.0 */
+ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
+
+ /* De-initialize usb phy registers */
+ samsung_exynos5_usb3phy_disable(sphy);
+
+ /* Enable phy isolation */
+ samsung_usbphy_set_isolation(sphy, true);
+
+ spin_unlock_irqrestore(&sphy->lock, flags);
+
+ clk_disable_unprepare(sphy->clk);
+}
+
+static int samsung_usb3phy_probe(struct platform_device *pdev)
+{
+ struct samsung_usbphy *sphy;
+ struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+ struct resource *phy_mem;
+ void __iomem *phy_base;
+ struct clk *clk;
+ int ret;
+
+ phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!phy_mem) {
+ dev_err(dev, "%s: missing mem resource\n", __func__);
+ return -ENODEV;
+ }
+
+ phy_base = devm_ioremap_resource(dev, phy_mem);
+ if (IS_ERR(phy_base))
+ return PTR_ERR(phy_base);
+
+ sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+ if (!sphy)
+ return -ENOMEM;
+
+ clk = devm_clk_get(dev, "usbdrd30");
+ if (IS_ERR(clk)) {
+ dev_err(dev, "Failed to get device clock\n");
+ return PTR_ERR(clk);
+ }
+
+ sphy->dev = dev;
+
+ if (dev->of_node) {
+ ret = samsung_usbphy_parse_dt(sphy);
+ if (ret < 0)
+ return ret;
+ } else {
+ if (!pdata) {
+ dev_err(dev, "no platform data specified\n");
+ return -EINVAL;
+ }
+ }
+
+ sphy->plat = pdata;
+ sphy->regs = phy_base;
+ sphy->clk = clk;
+ sphy->phy.dev = sphy->dev;
+ sphy->phy.label = "samsung-usb3phy";
+ sphy->phy.init = samsung_usb3phy_init;
+ sphy->phy.shutdown = samsung_usb3phy_shutdown;
+ sphy->drv_data = samsung_usbphy_get_driver_data(pdev);
+ sphy->ref_clk_freq = samsung_usbphy_get_refclk_freq(sphy);
+
+ spin_lock_init(&sphy->lock);
+
+ platform_set_drvdata(pdev, sphy);
+
+ return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB3);
+}
+
+static int samsung_usb3phy_remove(struct platform_device *pdev)
+{
+ struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(&sphy->phy);
+
+ if (sphy->pmuregs)
+ iounmap(sphy->pmuregs);
+ if (sphy->sysreg)
+ iounmap(sphy->sysreg);
+
+ return 0;
+}
+
+static struct samsung_usbphy_drvdata usb3phy_exynos5 = {
+ .cpu_type = TYPE_EXYNOS5250,
+ .devphy_en_mask = EXYNOS_USBPHY_ENABLE,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+ {
+ .compatible = "samsung,exynos5250-usb3phy",
+ .data = &usb3phy_exynos5
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+ {
+ .name = "exynos5250-usb3phy",
+ .driver_data = (unsigned long)&usb3phy_exynos5,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usb3phy_driver = {
+ .probe = samsung_usb3phy_probe,
+ .remove = samsung_usb3phy_remove,
+ .id_table = samsung_usbphy_driver_ids,
+ .driver = {
+ .name = "samsung-usb3phy",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(samsung_usbphy_dt_match),
+ },
+};
+
+module_platform_driver(samsung_usb3phy_driver);
+
+MODULE_DESCRIPTION("Samsung USB 3.0 phy controller");
+MODULE_AUTHOR("Vivek Gautam <gautam.vivek@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usb3phy");
diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/phy-tegra-usb.c
index 5487d38481af..5487d38481af 100644
--- a/drivers/usb/phy/tegra_usb_phy.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/phy/phy-twl4030-usb.c
index 24d573a134b1..8f78d2d40722 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/phy/phy-twl4030-usb.c
@@ -163,6 +163,8 @@ struct twl4030_usb {
bool vbus_supplied;
u8 asleep;
bool irq_enabled;
+
+ struct delayed_work id_workaround_work;
};
/* internal define on top of container_of */
@@ -246,6 +248,25 @@ twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
/*-------------------------------------------------------------------------*/
+static bool twl4030_is_driving_vbus(struct twl4030_usb *twl)
+{
+ int ret;
+
+ ret = twl4030_usb_read(twl, PHY_CLK_CTRL_STS);
+ if (ret < 0 || !(ret & PHY_DPLL_CLK))
+ /*
+ * if clocks are off, registers are not updated,
+ * but we can assume we don't drive VBUS in this case
+ */
+ return false;
+
+ ret = twl4030_usb_read(twl, ULPI_OTG_CTRL);
+ if (ret < 0)
+ return false;
+
+ return (ret & (ULPI_OTG_DRVVBUS | ULPI_OTG_CHRGVBUS)) ? true : false;
+}
+
static enum omap_musb_vbus_id_status
twl4030_usb_linkstat(struct twl4030_usb *twl)
{
@@ -268,13 +289,19 @@ static enum omap_musb_vbus_id_status
if (status < 0)
dev_err(twl->dev, "USB link status err %d\n", status);
else if (status & (BIT(7) | BIT(2))) {
- if (status & (BIT(7)))
- twl->vbus_supplied = true;
+ if (status & BIT(7)) {
+ if (twl4030_is_driving_vbus(twl))
+ status &= ~BIT(7);
+ else
+ twl->vbus_supplied = true;
+ }
if (status & BIT(2))
linkstat = OMAP_MUSB_ID_GROUND;
- else
+ else if (status & BIT(7))
linkstat = OMAP_MUSB_VBUS_VALID;
+ else
+ linkstat = OMAP_MUSB_VBUS_OFF;
} else {
if (twl->linkstat != OMAP_MUSB_UNKNOWN)
linkstat = OMAP_MUSB_VBUS_OFF;
@@ -287,10 +314,6 @@ static enum omap_musb_vbus_id_status
* are registered, and that both are active...
*/
- spin_lock_irq(&twl->lock);
- twl->linkstat = linkstat;
- spin_unlock_irq(&twl->lock);
-
return linkstat;
}
@@ -361,9 +384,17 @@ static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
static void twl4030_phy_power(struct twl4030_usb *twl, int on)
{
+ int ret;
+
if (on) {
- regulator_enable(twl->usb3v1);
- regulator_enable(twl->usb1v8);
+ ret = regulator_enable(twl->usb3v1);
+ if (ret)
+ dev_err(twl->dev, "Failed to enable usb3v1\n");
+
+ ret = regulator_enable(twl->usb1v8);
+ if (ret)
+ dev_err(twl->dev, "Failed to enable usb1v8\n");
+
/*
* Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP
* in twl4030) resets the VUSB_DEDICATED2 register. This reset
@@ -372,7 +403,11 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on)
* is re-activated. This ensures that VUSB3V1 is really active.
*/
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);
- regulator_enable(twl->usb1v5);
+
+ ret = regulator_enable(twl->usb1v5);
+ if (ret)
+ dev_err(twl->dev, "Failed to enable usb1v5\n");
+
__twl4030_phy_power(twl, 1);
twl4030_usb_write(twl, PHY_CLK_CTRL,
twl4030_usb_read(twl, PHY_CLK_CTRL) |
@@ -412,6 +447,16 @@ static void twl4030_phy_resume(struct twl4030_usb *twl)
__twl4030_phy_resume(twl);
twl->asleep = 0;
dev_dbg(twl->dev, "%s\n", __func__);
+
+ /*
+ * XXX When VBUS gets driven after musb goes to A mode,
+ * ID_PRES related interrupts no longer arrive, why?
+ * Register itself is updated fine though, so we must poll.
+ */
+ if (twl->linkstat == OMAP_MUSB_ID_GROUND) {
+ cancel_delayed_work(&twl->id_workaround_work);
+ schedule_delayed_work(&twl->id_workaround_work, HZ);
+ }
}
static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
@@ -432,7 +477,7 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
/* Initialize 3.1V regulator */
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP);
- twl->usb3v1 = regulator_get(twl->dev, "usb3v1");
+ twl->usb3v1 = devm_regulator_get(twl->dev, "usb3v1");
if (IS_ERR(twl->usb3v1))
return -ENODEV;
@@ -441,18 +486,18 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
/* Initialize 1.5V regulator */
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP);
- twl->usb1v5 = regulator_get(twl->dev, "usb1v5");
+ twl->usb1v5 = devm_regulator_get(twl->dev, "usb1v5");
if (IS_ERR(twl->usb1v5))
- goto fail1;
+ return -ENODEV;
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
/* Initialize 1.8V regulator */
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP);
- twl->usb1v8 = regulator_get(twl->dev, "usb1v8");
+ twl->usb1v8 = devm_regulator_get(twl->dev, "usb1v8");
if (IS_ERR(twl->usb1v8))
- goto fail2;
+ return -ENODEV;
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
@@ -461,14 +506,6 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
TWL4030_PM_MASTER_PROTECT_KEY);
return 0;
-
-fail2:
- regulator_put(twl->usb1v5);
- twl->usb1v5 = NULL;
-fail1:
- regulator_put(twl->usb3v1);
- twl->usb3v1 = NULL;
- return -ENODEV;
}
static ssize_t twl4030_usb_vbus_show(struct device *dev,
@@ -491,9 +528,18 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
{
struct twl4030_usb *twl = _twl;
enum omap_musb_vbus_id_status status;
+ bool status_changed = false;
status = twl4030_usb_linkstat(twl);
- if (status > 0) {
+
+ spin_lock_irq(&twl->lock);
+ if (status >= 0 && status != twl->linkstat) {
+ twl->linkstat = status;
+ status_changed = true;
+ }
+ spin_unlock_irq(&twl->lock);
+
+ if (status_changed) {
/* FIXME add a set_power() method so that B-devices can
* configure the charger appropriately. It's not always
* correct to consume VBUS power, and how much current to
@@ -505,37 +551,62 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
* USB_LINK_VBUS state. musb_hdrc won't care until it
* starts to handle softconnect right.
*/
- if (status == OMAP_MUSB_VBUS_OFF ||
- status == OMAP_MUSB_ID_FLOAT)
- twl4030_phy_suspend(twl, 0);
- else
- twl4030_phy_resume(twl);
-
- omap_musb_mailbox(twl->linkstat);
+ omap_musb_mailbox(status);
}
sysfs_notify(&twl->dev->kobj, NULL, "vbus");
return IRQ_HANDLED;
}
-static void twl4030_usb_phy_init(struct twl4030_usb *twl)
+static void twl4030_id_workaround_work(struct work_struct *work)
{
+ struct twl4030_usb *twl = container_of(work, struct twl4030_usb,
+ id_workaround_work.work);
enum omap_musb_vbus_id_status status;
+ bool status_changed = false;
status = twl4030_usb_linkstat(twl);
- if (status > 0) {
- if (status == OMAP_MUSB_VBUS_OFF ||
- status == OMAP_MUSB_ID_FLOAT) {
- __twl4030_phy_power(twl, 0);
- twl->asleep = 1;
- } else {
- __twl4030_phy_resume(twl);
- twl->asleep = 0;
- }
- omap_musb_mailbox(twl->linkstat);
+ spin_lock_irq(&twl->lock);
+ if (status >= 0 && status != twl->linkstat) {
+ twl->linkstat = status;
+ status_changed = true;
+ }
+ spin_unlock_irq(&twl->lock);
+
+ if (status_changed) {
+ dev_dbg(twl->dev, "handle missing status change to %d\n",
+ status);
+ omap_musb_mailbox(status);
}
+
+ /* don't schedule during sleep - irq works right then */
+ if (status == OMAP_MUSB_ID_GROUND && !twl->asleep) {
+ cancel_delayed_work(&twl->id_workaround_work);
+ schedule_delayed_work(&twl->id_workaround_work, HZ);
+ }
+}
+
+static int twl4030_usb_phy_init(struct usb_phy *phy)
+{
+ struct twl4030_usb *twl = phy_to_twl(phy);
+ enum omap_musb_vbus_id_status status;
+
+ /*
+ * Start in sleep state, we'll get called through set_suspend()
+ * callback when musb is runtime resumed and it's time to start.
+ */
+ __twl4030_phy_power(twl, 0);
+ twl->asleep = 1;
+
+ status = twl4030_usb_linkstat(twl);
+ twl->linkstat = status;
+
+ if (status == OMAP_MUSB_ID_GROUND || status == OMAP_MUSB_VBUS_VALID)
+ omap_musb_mailbox(twl->linkstat);
+
sysfs_notify(&twl->dev->kobj, NULL, "vbus");
+ return 0;
}
static int twl4030_set_suspend(struct usb_phy *x, int suspend)
@@ -612,6 +683,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
twl->phy.otg = otg;
twl->phy.type = USB_PHY_TYPE_USB2;
twl->phy.set_suspend = twl4030_set_suspend;
+ twl->phy.init = twl4030_usb_phy_init;
otg->phy = &twl->phy;
otg->set_host = twl4030_set_host;
@@ -620,6 +692,8 @@ static int twl4030_usb_probe(struct platform_device *pdev)
/* init spinlock for workqueue */
spin_lock_init(&twl->lock);
+ INIT_DELAYED_WORK(&twl->id_workaround_work, twl4030_id_workaround_work);
+
err = twl4030_usb_ldo_init(twl);
if (err) {
dev_err(&pdev->dev, "ldo init failed\n");
@@ -640,20 +714,15 @@ static int twl4030_usb_probe(struct platform_device *pdev)
* need both handles, otherwise just one suffices.
*/
twl->irq_enabled = true;
- status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
- IRQF_ONESHOT, "twl4030_usb", twl);
+ status = devm_request_threaded_irq(twl->dev, twl->irq, NULL,
+ twl4030_usb_irq, IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT, "twl4030_usb", twl);
if (status < 0) {
dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
twl->irq, status);
return status;
}
- /* Power down phy or make it work according to
- * current link state.
- */
- twl4030_usb_phy_init(twl);
-
dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
return 0;
}
@@ -663,7 +732,7 @@ static int twl4030_usb_remove(struct platform_device *pdev)
struct twl4030_usb *twl = platform_get_drvdata(pdev);
int val;
- free_irq(twl->irq, twl);
+ cancel_delayed_work(&twl->id_workaround_work);
device_remove_file(twl->dev, &dev_attr_vbus);
/* set transceiver mode to power on defaults */
@@ -685,9 +754,6 @@ static int twl4030_usb_remove(struct platform_device *pdev)
if (!twl->asleep)
twl4030_phy_power(twl, 0);
- regulator_put(twl->usb1v5);
- regulator_put(twl->usb1v8);
- regulator_put(twl->usb3v1);
return 0;
}
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c
index 7f3c5b0e3f66..9de7ada90a8b 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/phy/phy-twl6030-usb.c
@@ -211,6 +211,7 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
struct twl6030_usb *twl = _twl;
enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
u8 vbus_state, hw_state;
+ int ret;
hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
@@ -218,7 +219,10 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
CONTROLLER_STAT1);
if (!(hw_state & STS_USB_ID)) {
if (vbus_state & VBUS_DET) {
- regulator_enable(twl->usb3v3);
+ ret = regulator_enable(twl->usb3v3);
+ if (ret)
+ dev_err(twl->dev, "Failed to enable usb3v3\n");
+
twl->asleep = 1;
status = OMAP_MUSB_VBUS_VALID;
twl->linkstat = status;
@@ -245,12 +249,15 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
struct twl6030_usb *twl = _twl;
enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
u8 hw_state;
+ int ret;
hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
if (hw_state & STS_USB_ID) {
+ ret = regulator_enable(twl->usb3v3);
+ if (ret)
+ dev_err(twl->dev, "Failed to enable usb3v3\n");
- regulator_enable(twl->usb3v3);
twl->asleep = 1;
twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
diff --git a/drivers/usb/otg/ulpi_viewport.c b/drivers/usb/phy/phy-ulpi-viewport.c
index c5ba7e5423fc..c5ba7e5423fc 100644
--- a/drivers/usb/otg/ulpi_viewport.c
+++ b/drivers/usb/phy/phy-ulpi-viewport.c
diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/phy/phy-ulpi.c
index 217339dd7a90..217339dd7a90 100644
--- a/drivers/usb/otg/ulpi.c
+++ b/drivers/usb/phy/phy-ulpi.c
diff --git a/drivers/usb/otg/otg.c b/drivers/usb/phy/phy.c
index 2bd03d261a50..f52c006417ff 100644
--- a/drivers/usb/otg/otg.c
+++ b/drivers/usb/phy/phy.c
@@ -1,14 +1,13 @@
/*
- * otg.c -- USB OTG utility code
+ * phy.c -- USB phy handling
*
- * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2004-2013 Texas Instruments
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
-
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/err.h>
@@ -17,7 +16,7 @@
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/usb/otg.h>
+#include <linux/usb/phy.h>
static LIST_HEAD(phy_list);
static LIST_HEAD(phy_bind_list);
@@ -110,7 +109,7 @@ struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type)
return phy;
}
-EXPORT_SYMBOL(devm_usb_get_phy);
+EXPORT_SYMBOL_GPL(devm_usb_get_phy);
/**
* usb_get_phy - find the USB PHY
@@ -143,7 +142,7 @@ err0:
return phy;
}
-EXPORT_SYMBOL(usb_get_phy);
+EXPORT_SYMBOL_GPL(usb_get_phy);
/**
* devm_usb_get_phy_by_phandle - find the USB PHY by phandle
@@ -207,7 +206,7 @@ err0:
return phy;
}
-EXPORT_SYMBOL(devm_usb_get_phy_by_phandle);
+EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle);
/**
* usb_get_phy_dev - find the USB PHY
@@ -240,7 +239,7 @@ err0:
return phy;
}
-EXPORT_SYMBOL(usb_get_phy_dev);
+EXPORT_SYMBOL_GPL(usb_get_phy_dev);
/**
* devm_usb_get_phy_dev - find the USB PHY using device ptr and index
@@ -270,7 +269,7 @@ struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index)
return phy;
}
-EXPORT_SYMBOL(devm_usb_get_phy_dev);
+EXPORT_SYMBOL_GPL(devm_usb_get_phy_dev);
/**
* devm_usb_put_phy - release the USB PHY
@@ -289,7 +288,7 @@ void devm_usb_put_phy(struct device *dev, struct usb_phy *phy)
r = devres_destroy(dev, devm_usb_phy_release, devm_usb_phy_match, phy);
dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
}
-EXPORT_SYMBOL(devm_usb_put_phy);
+EXPORT_SYMBOL_GPL(devm_usb_put_phy);
/**
* usb_put_phy - release the USB PHY
@@ -308,7 +307,7 @@ void usb_put_phy(struct usb_phy *x)
module_put(owner);
}
}
-EXPORT_SYMBOL(usb_put_phy);
+EXPORT_SYMBOL_GPL(usb_put_phy);
/**
* usb_add_phy - declare the USB PHY
@@ -348,7 +347,7 @@ out:
spin_unlock_irqrestore(&phy_lock, flags);
return ret;
}
-EXPORT_SYMBOL(usb_add_phy);
+EXPORT_SYMBOL_GPL(usb_add_phy);
/**
* usb_add_phy_dev - declare the USB PHY
@@ -378,7 +377,7 @@ int usb_add_phy_dev(struct usb_phy *x)
spin_unlock_irqrestore(&phy_lock, flags);
return 0;
}
-EXPORT_SYMBOL(usb_add_phy_dev);
+EXPORT_SYMBOL_GPL(usb_add_phy_dev);
/**
* usb_remove_phy - remove the OTG PHY
@@ -400,7 +399,7 @@ void usb_remove_phy(struct usb_phy *x)
}
spin_unlock_irqrestore(&phy_lock, flags);
}
-EXPORT_SYMBOL(usb_remove_phy);
+EXPORT_SYMBOL_GPL(usb_remove_phy);
/**
* usb_bind_phy - bind the phy and the controller that uses the phy
@@ -437,38 +436,3 @@ int __init usb_bind_phy(const char *dev_name, u8 index,
return 0;
}
EXPORT_SYMBOL_GPL(usb_bind_phy);
-
-const char *otg_state_string(enum usb_otg_state state)
-{
- switch (state) {
- case OTG_STATE_A_IDLE:
- return "a_idle";
- case OTG_STATE_A_WAIT_VRISE:
- return "a_wait_vrise";
- case OTG_STATE_A_WAIT_BCON:
- return "a_wait_bcon";
- case OTG_STATE_A_HOST:
- return "a_host";
- case OTG_STATE_A_SUSPEND:
- return "a_suspend";
- case OTG_STATE_A_PERIPHERAL:
- return "a_peripheral";
- case OTG_STATE_A_WAIT_VFALL:
- return "a_wait_vfall";
- case OTG_STATE_A_VBUS_ERR:
- return "a_vbus_err";
- case OTG_STATE_B_IDLE:
- return "b_idle";
- case OTG_STATE_B_SRP_INIT:
- return "b_srp_init";
- case OTG_STATE_B_PERIPHERAL:
- return "b_peripheral";
- case OTG_STATE_B_WAIT_ACON:
- return "b_wait_acon";
- case OTG_STATE_B_HOST:
- return "b_host";
- default:
- return "UNDEFINED";
- }
-}
-EXPORT_SYMBOL(otg_state_string);
diff --git a/drivers/usb/phy/samsung-usbphy.c b/drivers/usb/phy/samsung-usbphy.c
deleted file mode 100644
index 967101ec15fd..000000000000
--- a/drivers/usb/phy/samsung-usbphy.c
+++ /dev/null
@@ -1,928 +0,0 @@
-/* linux/drivers/usb/phy/samsung-usbphy.c
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * Author: Praveen Paneri <p.paneri@samsung.com>
- *
- * Samsung USB2.0 PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and
- * OHCI-EXYNOS controllers.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/samsung_usb_phy.h>
-#include <linux/platform_data/samsung-usbphy.h>
-
-/* Register definitions */
-
-#define SAMSUNG_PHYPWR (0x00)
-
-#define PHYPWR_NORMAL_MASK (0x19 << 0)
-#define PHYPWR_OTG_DISABLE (0x1 << 4)
-#define PHYPWR_ANALOG_POWERDOWN (0x1 << 3)
-#define PHYPWR_FORCE_SUSPEND (0x1 << 1)
-/* For Exynos4 */
-#define PHYPWR_NORMAL_MASK_PHY0 (0x39 << 0)
-#define PHYPWR_SLEEP_PHY0 (0x1 << 5)
-
-#define SAMSUNG_PHYCLK (0x04)
-
-#define PHYCLK_MODE_USB11 (0x1 << 6)
-#define PHYCLK_EXT_OSC (0x1 << 5)
-#define PHYCLK_COMMON_ON_N (0x1 << 4)
-#define PHYCLK_ID_PULL (0x1 << 2)
-#define PHYCLK_CLKSEL_MASK (0x3 << 0)
-#define PHYCLK_CLKSEL_48M (0x0 << 0)
-#define PHYCLK_CLKSEL_12M (0x2 << 0)
-#define PHYCLK_CLKSEL_24M (0x3 << 0)
-
-#define SAMSUNG_RSTCON (0x08)
-
-#define RSTCON_PHYLINK_SWRST (0x1 << 2)
-#define RSTCON_HLINK_SWRST (0x1 << 1)
-#define RSTCON_SWRST (0x1 << 0)
-
-/* EXYNOS5 */
-#define EXYNOS5_PHY_HOST_CTRL0 (0x00)
-
-#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31)
-
-#define HOST_CTRL0_REFCLKSEL_MASK (0x3 << 19)
-#define HOST_CTRL0_REFCLKSEL_XTAL (0x0 << 19)
-#define HOST_CTRL0_REFCLKSEL_EXTL (0x1 << 19)
-#define HOST_CTRL0_REFCLKSEL_CLKCORE (0x2 << 19)
-
-#define HOST_CTRL0_FSEL_MASK (0x7 << 16)
-#define HOST_CTRL0_FSEL(_x) ((_x) << 16)
-
-#define FSEL_CLKSEL_50M (0x7)
-#define FSEL_CLKSEL_24M (0x5)
-#define FSEL_CLKSEL_20M (0x4)
-#define FSEL_CLKSEL_19200K (0x3)
-#define FSEL_CLKSEL_12M (0x2)
-#define FSEL_CLKSEL_10M (0x1)
-#define FSEL_CLKSEL_9600K (0x0)
-
-#define HOST_CTRL0_TESTBURNIN (0x1 << 11)
-#define HOST_CTRL0_RETENABLE (0x1 << 10)
-#define HOST_CTRL0_COMMONON_N (0x1 << 9)
-#define HOST_CTRL0_SIDDQ (0x1 << 6)
-#define HOST_CTRL0_FORCESLEEP (0x1 << 5)
-#define HOST_CTRL0_FORCESUSPEND (0x1 << 4)
-#define HOST_CTRL0_WORDINTERFACE (0x1 << 3)
-#define HOST_CTRL0_UTMISWRST (0x1 << 2)
-#define HOST_CTRL0_LINKSWRST (0x1 << 1)
-#define HOST_CTRL0_PHYSWRST (0x1 << 0)
-
-#define EXYNOS5_PHY_HOST_TUNE0 (0x04)
-
-#define EXYNOS5_PHY_HSIC_CTRL1 (0x10)
-
-#define EXYNOS5_PHY_HSIC_TUNE1 (0x14)
-
-#define EXYNOS5_PHY_HSIC_CTRL2 (0x20)
-
-#define EXYNOS5_PHY_HSIC_TUNE2 (0x24)
-
-#define HSIC_CTRL_REFCLKSEL_MASK (0x3 << 23)
-#define HSIC_CTRL_REFCLKSEL (0x2 << 23)
-
-#define HSIC_CTRL_REFCLKDIV_MASK (0x7f << 16)
-#define HSIC_CTRL_REFCLKDIV(_x) ((_x) << 16)
-#define HSIC_CTRL_REFCLKDIV_12 (0x24 << 16)
-#define HSIC_CTRL_REFCLKDIV_15 (0x1c << 16)
-#define HSIC_CTRL_REFCLKDIV_16 (0x1a << 16)
-#define HSIC_CTRL_REFCLKDIV_19_2 (0x15 << 16)
-#define HSIC_CTRL_REFCLKDIV_20 (0x14 << 16)
-
-#define HSIC_CTRL_SIDDQ (0x1 << 6)
-#define HSIC_CTRL_FORCESLEEP (0x1 << 5)
-#define HSIC_CTRL_FORCESUSPEND (0x1 << 4)
-#define HSIC_CTRL_WORDINTERFACE (0x1 << 3)
-#define HSIC_CTRL_UTMISWRST (0x1 << 2)
-#define HSIC_CTRL_PHYSWRST (0x1 << 0)
-
-#define EXYNOS5_PHY_HOST_EHCICTRL (0x30)
-
-#define HOST_EHCICTRL_ENAINCRXALIGN (0x1 << 29)
-#define HOST_EHCICTRL_ENAINCR4 (0x1 << 28)
-#define HOST_EHCICTRL_ENAINCR8 (0x1 << 27)
-#define HOST_EHCICTRL_ENAINCR16 (0x1 << 26)
-
-#define EXYNOS5_PHY_HOST_OHCICTRL (0x34)
-
-#define HOST_OHCICTRL_SUSPLGCY (0x1 << 3)
-#define HOST_OHCICTRL_APPSTARTCLK (0x1 << 2)
-#define HOST_OHCICTRL_CNTSEL (0x1 << 1)
-#define HOST_OHCICTRL_CLKCKTRST (0x1 << 0)
-
-#define EXYNOS5_PHY_OTG_SYS (0x38)
-
-#define OTG_SYS_PHYLINK_SWRESET (0x1 << 14)
-#define OTG_SYS_LINKSWRST_UOTG (0x1 << 13)
-#define OTG_SYS_PHY0_SWRST (0x1 << 12)
-
-#define OTG_SYS_REFCLKSEL_MASK (0x3 << 9)
-#define OTG_SYS_REFCLKSEL_XTAL (0x0 << 9)
-#define OTG_SYS_REFCLKSEL_EXTL (0x1 << 9)
-#define OTG_SYS_REFCLKSEL_CLKCORE (0x2 << 9)
-
-#define OTG_SYS_IDPULLUP_UOTG (0x1 << 8)
-#define OTG_SYS_COMMON_ON (0x1 << 7)
-
-#define OTG_SYS_FSEL_MASK (0x7 << 4)
-#define OTG_SYS_FSEL(_x) ((_x) << 4)
-
-#define OTG_SYS_FORCESLEEP (0x1 << 3)
-#define OTG_SYS_OTGDISABLE (0x1 << 2)
-#define OTG_SYS_SIDDQ_UOTG (0x1 << 1)
-#define OTG_SYS_FORCESUSPEND (0x1 << 0)
-
-#define EXYNOS5_PHY_OTG_TUNE (0x40)
-
-#ifndef MHZ
-#define MHZ (1000*1000)
-#endif
-
-#ifndef KHZ
-#define KHZ (1000)
-#endif
-
-#define EXYNOS_USBHOST_PHY_CTRL_OFFSET (0x4)
-#define S3C64XX_USBPHY_ENABLE (0x1 << 16)
-#define EXYNOS_USBPHY_ENABLE (0x1 << 0)
-#define EXYNOS_USB20PHY_CFG_HOST_LINK (0x1 << 0)
-
-enum samsung_cpu_type {
- TYPE_S3C64XX,
- TYPE_EXYNOS4210,
- TYPE_EXYNOS5250,
-};
-
-/*
- * struct samsung_usbphy_drvdata - driver data for various SoC variants
- * @cpu_type: machine identifier
- * @devphy_en_mask: device phy enable mask for PHY CONTROL register
- * @hostphy_en_mask: host phy enable mask for PHY CONTROL register
- * @devphy_reg_offset: offset to DEVICE PHY CONTROL register from
- * mapped address of system controller.
- * @hostphy_reg_offset: offset to HOST PHY CONTROL register from
- * mapped address of system controller.
- *
- * Here we have a separate mask for device type phy.
- * Having different masks for host and device type phy helps
- * in setting independent masks in case of SoCs like S5PV210,
- * in which PHY0 and PHY1 enable bits belong to same register
- * placed at position 0 and 1 respectively.
- * Although for newer SoCs like exynos these bits belong to
- * different registers altogether placed at position 0.
- */
-struct samsung_usbphy_drvdata {
- int cpu_type;
- int devphy_en_mask;
- int hostphy_en_mask;
- u32 devphy_reg_offset;
- u32 hostphy_reg_offset;
-};
-
-/*
- * struct samsung_usbphy - transceiver driver state
- * @phy: transceiver structure
- * @plat: platform data
- * @dev: The parent device supplied to the probe function
- * @clk: usb phy clock
- * @regs: usb phy controller registers memory base
- * @pmuregs: USB device PHY_CONTROL register memory base
- * @sysreg: USB2.0 PHY_CFG register memory base
- * @ref_clk_freq: reference clock frequency selection
- * @drv_data: driver data available for different SoCs
- * @phy_type: Samsung SoCs specific phy types: #HOST
- * #DEVICE
- * @phy_usage: usage count for phy
- * @lock: lock for phy operations
- */
-struct samsung_usbphy {
- struct usb_phy phy;
- struct samsung_usbphy_data *plat;
- struct device *dev;
- struct clk *clk;
- void __iomem *regs;
- void __iomem *pmuregs;
- void __iomem *sysreg;
- int ref_clk_freq;
- const struct samsung_usbphy_drvdata *drv_data;
- enum samsung_usb_phy_type phy_type;
- atomic_t phy_usage;
- spinlock_t lock;
-};
-
-#define phy_to_sphy(x) container_of((x), struct samsung_usbphy, phy)
-
-int samsung_usbphy_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
- if (!otg)
- return -ENODEV;
-
- if (!otg->host)
- otg->host = host;
-
- return 0;
-}
-
-static int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
-{
- struct device_node *usbphy_sys;
-
- /* Getting node for system controller interface for usb-phy */
- usbphy_sys = of_get_child_by_name(sphy->dev->of_node, "usbphy-sys");
- if (!usbphy_sys) {
- dev_err(sphy->dev, "No sys-controller interface for usb-phy\n");
- return -ENODEV;
- }
-
- sphy->pmuregs = of_iomap(usbphy_sys, 0);
-
- if (sphy->pmuregs == NULL) {
- dev_err(sphy->dev, "Can't get usb-phy pmu control register\n");
- goto err0;
- }
-
- sphy->sysreg = of_iomap(usbphy_sys, 1);
-
- /*
- * Not returning error code here, since this situation is not fatal.
- * Few SoCs may not have this switch available
- */
- if (sphy->sysreg == NULL)
- dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n");
-
- of_node_put(usbphy_sys);
-
- return 0;
-
-err0:
- of_node_put(usbphy_sys);
- return -ENXIO;
-}
-
-/*
- * Set isolation here for phy.
- * Here 'on = true' would mean USB PHY block is isolated, hence
- * de-activated and vice-versa.
- */
-static void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on)
-{
- void __iomem *reg = NULL;
- u32 reg_val;
- u32 en_mask = 0;
-
- if (!sphy->pmuregs) {
- dev_warn(sphy->dev, "Can't set pmu isolation\n");
- return;
- }
-
- switch (sphy->drv_data->cpu_type) {
- case TYPE_S3C64XX:
- /*
- * Do nothing: We will add here once S3C64xx goes for DT support
- */
- break;
- case TYPE_EXYNOS4210:
- /*
- * Fall through since exynos4210 and exynos5250 have similar
- * register architecture: two separate registers for host and
- * device phy control with enable bit at position 0.
- */
- case TYPE_EXYNOS5250:
- if (sphy->phy_type == USB_PHY_TYPE_DEVICE) {
- reg = sphy->pmuregs +
- sphy->drv_data->devphy_reg_offset;
- en_mask = sphy->drv_data->devphy_en_mask;
- } else if (sphy->phy_type == USB_PHY_TYPE_HOST) {
- reg = sphy->pmuregs +
- sphy->drv_data->hostphy_reg_offset;
- en_mask = sphy->drv_data->hostphy_en_mask;
- }
- break;
- default:
- dev_err(sphy->dev, "Invalid SoC type\n");
- return;
- }
-
- reg_val = readl(reg);
-
- if (on)
- reg_val &= ~en_mask;
- else
- reg_val |= en_mask;
-
- writel(reg_val, reg);
-}
-
-/*
- * Configure the mode of working of usb-phy here: HOST/DEVICE.
- */
-static void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy)
-{
- u32 reg;
-
- if (!sphy->sysreg) {
- dev_warn(sphy->dev, "Can't configure specified phy mode\n");
- return;
- }
-
- reg = readl(sphy->sysreg);
-
- if (sphy->phy_type == USB_PHY_TYPE_DEVICE)
- reg &= ~EXYNOS_USB20PHY_CFG_HOST_LINK;
- else if (sphy->phy_type == USB_PHY_TYPE_HOST)
- reg |= EXYNOS_USB20PHY_CFG_HOST_LINK;
-
- writel(reg, sphy->sysreg);
-}
-
-/*
- * PHYs are different for USB Device and USB Host.
- * This make sure that correct PHY type is selected before
- * any operation on PHY.
- */
-static int samsung_usbphy_set_type(struct usb_phy *phy,
- enum samsung_usb_phy_type phy_type)
-{
- struct samsung_usbphy *sphy = phy_to_sphy(phy);
-
- sphy->phy_type = phy_type;
-
- return 0;
-}
-
-/*
- * Returns reference clock frequency selection value
- */
-static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
-{
- struct clk *ref_clk;
- int refclk_freq = 0;
-
- /*
- * In exynos5250 USB host and device PHY use
- * external crystal clock XXTI
- */
- if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
- ref_clk = clk_get(sphy->dev, "ext_xtal");
- else
- ref_clk = clk_get(sphy->dev, "xusbxti");
- if (IS_ERR(ref_clk)) {
- dev_err(sphy->dev, "Failed to get reference clock\n");
- return PTR_ERR(ref_clk);
- }
-
- if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) {
- /* set clock frequency for PLL */
- switch (clk_get_rate(ref_clk)) {
- case 9600 * KHZ:
- refclk_freq = FSEL_CLKSEL_9600K;
- break;
- case 10 * MHZ:
- refclk_freq = FSEL_CLKSEL_10M;
- break;
- case 12 * MHZ:
- refclk_freq = FSEL_CLKSEL_12M;
- break;
- case 19200 * KHZ:
- refclk_freq = FSEL_CLKSEL_19200K;
- break;
- case 20 * MHZ:
- refclk_freq = FSEL_CLKSEL_20M;
- break;
- case 50 * MHZ:
- refclk_freq = FSEL_CLKSEL_50M;
- break;
- case 24 * MHZ:
- default:
- /* default reference clock */
- refclk_freq = FSEL_CLKSEL_24M;
- break;
- }
- } else {
- switch (clk_get_rate(ref_clk)) {
- case 12 * MHZ:
- refclk_freq = PHYCLK_CLKSEL_12M;
- break;
- case 24 * MHZ:
- refclk_freq = PHYCLK_CLKSEL_24M;
- break;
- case 48 * MHZ:
- refclk_freq = PHYCLK_CLKSEL_48M;
- break;
- default:
- if (sphy->drv_data->cpu_type == TYPE_S3C64XX)
- refclk_freq = PHYCLK_CLKSEL_48M;
- else
- refclk_freq = PHYCLK_CLKSEL_24M;
- break;
- }
- }
- clk_put(ref_clk);
-
- return refclk_freq;
-}
-
-static bool exynos5_phyhost_is_on(void *regs)
-{
- u32 reg;
-
- reg = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
-
- return !(reg & HOST_CTRL0_SIDDQ);
-}
-
-static void samsung_exynos5_usbphy_enable(struct samsung_usbphy *sphy)
-{
- void __iomem *regs = sphy->regs;
- u32 phyclk = sphy->ref_clk_freq;
- u32 phyhost;
- u32 phyotg;
- u32 phyhsic;
- u32 ehcictrl;
- u32 ohcictrl;
-
- /*
- * phy_usage helps in keeping usage count for phy
- * so that the first consumer enabling the phy is also
- * the last consumer to disable it.
- */
-
- atomic_inc(&sphy->phy_usage);
-
- if (exynos5_phyhost_is_on(regs)) {
- dev_info(sphy->dev, "Already power on PHY\n");
- return;
- }
-
- /* Host configuration */
- phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
-
- /* phy reference clock configuration */
- phyhost &= ~HOST_CTRL0_FSEL_MASK;
- phyhost |= HOST_CTRL0_FSEL(phyclk);
-
- /* host phy reset */
- phyhost &= ~(HOST_CTRL0_PHYSWRST |
- HOST_CTRL0_PHYSWRSTALL |
- HOST_CTRL0_SIDDQ |
- /* Enable normal mode of operation */
- HOST_CTRL0_FORCESUSPEND |
- HOST_CTRL0_FORCESLEEP);
-
- /* Link reset */
- phyhost |= (HOST_CTRL0_LINKSWRST |
- HOST_CTRL0_UTMISWRST |
- /* COMMON Block configuration during suspend */
- HOST_CTRL0_COMMONON_N);
- writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
- udelay(10);
- phyhost &= ~(HOST_CTRL0_LINKSWRST |
- HOST_CTRL0_UTMISWRST);
- writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
-
- /* OTG configuration */
- phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
-
- /* phy reference clock configuration */
- phyotg &= ~OTG_SYS_FSEL_MASK;
- phyotg |= OTG_SYS_FSEL(phyclk);
-
- /* Enable normal mode of operation */
- phyotg &= ~(OTG_SYS_FORCESUSPEND |
- OTG_SYS_SIDDQ_UOTG |
- OTG_SYS_FORCESLEEP |
- OTG_SYS_REFCLKSEL_MASK |
- /* COMMON Block configuration during suspend */
- OTG_SYS_COMMON_ON);
-
- /* OTG phy & link reset */
- phyotg |= (OTG_SYS_PHY0_SWRST |
- OTG_SYS_LINKSWRST_UOTG |
- OTG_SYS_PHYLINK_SWRESET |
- OTG_SYS_OTGDISABLE |
- /* Set phy refclk */
- OTG_SYS_REFCLKSEL_CLKCORE);
-
- writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
- udelay(10);
- phyotg &= ~(OTG_SYS_PHY0_SWRST |
- OTG_SYS_LINKSWRST_UOTG |
- OTG_SYS_PHYLINK_SWRESET);
- writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
-
- /* HSIC phy configuration */
- phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
- HSIC_CTRL_REFCLKSEL |
- HSIC_CTRL_PHYSWRST);
- writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
- writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
- udelay(10);
- phyhsic &= ~HSIC_CTRL_PHYSWRST;
- writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
- writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
-
- udelay(80);
-
- /* enable EHCI DMA burst */
- ehcictrl = readl(regs + EXYNOS5_PHY_HOST_EHCICTRL);
- ehcictrl |= (HOST_EHCICTRL_ENAINCRXALIGN |
- HOST_EHCICTRL_ENAINCR4 |
- HOST_EHCICTRL_ENAINCR8 |
- HOST_EHCICTRL_ENAINCR16);
- writel(ehcictrl, regs + EXYNOS5_PHY_HOST_EHCICTRL);
-
- /* set ohci_suspend_on_n */
- ohcictrl = readl(regs + EXYNOS5_PHY_HOST_OHCICTRL);
- ohcictrl |= HOST_OHCICTRL_SUSPLGCY;
- writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL);
-}
-
-static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
-{
- void __iomem *regs = sphy->regs;
- u32 phypwr;
- u32 phyclk;
- u32 rstcon;
-
- /* set clock frequency for PLL */
- phyclk = sphy->ref_clk_freq;
- phypwr = readl(regs + SAMSUNG_PHYPWR);
- rstcon = readl(regs + SAMSUNG_RSTCON);
-
- switch (sphy->drv_data->cpu_type) {
- case TYPE_S3C64XX:
- phyclk &= ~PHYCLK_COMMON_ON_N;
- phypwr &= ~PHYPWR_NORMAL_MASK;
- rstcon |= RSTCON_SWRST;
- break;
- case TYPE_EXYNOS4210:
- phypwr &= ~PHYPWR_NORMAL_MASK_PHY0;
- rstcon |= RSTCON_SWRST;
- default:
- break;
- }
-
- writel(phyclk, regs + SAMSUNG_PHYCLK);
- /* Configure PHY0 for normal operation*/
- writel(phypwr, regs + SAMSUNG_PHYPWR);
- /* reset all ports of PHY and Link */
- writel(rstcon, regs + SAMSUNG_RSTCON);
- udelay(10);
- rstcon &= ~RSTCON_SWRST;
- writel(rstcon, regs + SAMSUNG_RSTCON);
-}
-
-static void samsung_exynos5_usbphy_disable(struct samsung_usbphy *sphy)
-{
- void __iomem *regs = sphy->regs;
- u32 phyhost;
- u32 phyotg;
- u32 phyhsic;
-
- if (atomic_dec_return(&sphy->phy_usage) > 0) {
- dev_info(sphy->dev, "still being used\n");
- return;
- }
-
- phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
- HSIC_CTRL_REFCLKSEL |
- HSIC_CTRL_SIDDQ |
- HSIC_CTRL_FORCESLEEP |
- HSIC_CTRL_FORCESUSPEND);
- writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
- writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
-
- phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
- phyhost |= (HOST_CTRL0_SIDDQ |
- HOST_CTRL0_FORCESUSPEND |
- HOST_CTRL0_FORCESLEEP |
- HOST_CTRL0_PHYSWRST |
- HOST_CTRL0_PHYSWRSTALL);
- writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
-
- phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
- phyotg |= (OTG_SYS_FORCESUSPEND |
- OTG_SYS_SIDDQ_UOTG |
- OTG_SYS_FORCESLEEP);
- writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
-}
-
-static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
-{
- void __iomem *regs = sphy->regs;
- u32 phypwr;
-
- phypwr = readl(regs + SAMSUNG_PHYPWR);
-
- switch (sphy->drv_data->cpu_type) {
- case TYPE_S3C64XX:
- phypwr |= PHYPWR_NORMAL_MASK;
- break;
- case TYPE_EXYNOS4210:
- phypwr |= PHYPWR_NORMAL_MASK_PHY0;
- default:
- break;
- }
-
- /* Disable analog and otg block power */
- writel(phypwr, regs + SAMSUNG_PHYPWR);
-}
-
-/*
- * The function passed to the usb driver for phy initialization
- */
-static int samsung_usbphy_init(struct usb_phy *phy)
-{
- struct samsung_usbphy *sphy;
- struct usb_bus *host = NULL;
- unsigned long flags;
- int ret = 0;
-
- sphy = phy_to_sphy(phy);
-
- host = phy->otg->host;
-
- /* Enable the phy clock */
- ret = clk_prepare_enable(sphy->clk);
- if (ret) {
- dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
- return ret;
- }
-
- spin_lock_irqsave(&sphy->lock, flags);
-
- if (host) {
- /* setting default phy-type for USB 2.0 */
- if (!strstr(dev_name(host->controller), "ehci") ||
- !strstr(dev_name(host->controller), "ohci"))
- samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
- } else {
- samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
- }
-
- /* Disable phy isolation */
- if (sphy->plat && sphy->plat->pmu_isolation)
- sphy->plat->pmu_isolation(false);
- else
- samsung_usbphy_set_isolation(sphy, false);
-
- /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */
- samsung_usbphy_cfg_sel(sphy);
-
- /* Initialize usb phy registers */
- if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
- samsung_exynos5_usbphy_enable(sphy);
- else
- samsung_usbphy_enable(sphy);
-
- spin_unlock_irqrestore(&sphy->lock, flags);
-
- /* Disable the phy clock */
- clk_disable_unprepare(sphy->clk);
-
- return ret;
-}
-
-/*
- * The function passed to the usb driver for phy shutdown
- */
-static void samsung_usbphy_shutdown(struct usb_phy *phy)
-{
- struct samsung_usbphy *sphy;
- struct usb_bus *host = NULL;
- unsigned long flags;
-
- sphy = phy_to_sphy(phy);
-
- host = phy->otg->host;
-
- if (clk_prepare_enable(sphy->clk)) {
- dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
- return;
- }
-
- spin_lock_irqsave(&sphy->lock, flags);
-
- if (host) {
- /* setting default phy-type for USB 2.0 */
- if (!strstr(dev_name(host->controller), "ehci") ||
- !strstr(dev_name(host->controller), "ohci"))
- samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
- } else {
- samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
- }
-
- /* De-initialize usb phy registers */
- if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
- samsung_exynos5_usbphy_disable(sphy);
- else
- samsung_usbphy_disable(sphy);
-
- /* Enable phy isolation */
- if (sphy->plat && sphy->plat->pmu_isolation)
- sphy->plat->pmu_isolation(true);
- else
- samsung_usbphy_set_isolation(sphy, true);
-
- spin_unlock_irqrestore(&sphy->lock, flags);
-
- clk_disable_unprepare(sphy->clk);
-}
-
-static const struct of_device_id samsung_usbphy_dt_match[];
-
-static inline const struct samsung_usbphy_drvdata
-*samsung_usbphy_get_driver_data(struct platform_device *pdev)
-{
- if (pdev->dev.of_node) {
- const struct of_device_id *match;
- match = of_match_node(samsung_usbphy_dt_match,
- pdev->dev.of_node);
- return match->data;
- }
-
- return (struct samsung_usbphy_drvdata *)
- platform_get_device_id(pdev)->driver_data;
-}
-
-static int samsung_usbphy_probe(struct platform_device *pdev)
-{
- struct samsung_usbphy *sphy;
- struct usb_otg *otg;
- struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
- const struct samsung_usbphy_drvdata *drv_data;
- struct device *dev = &pdev->dev;
- struct resource *phy_mem;
- void __iomem *phy_base;
- struct clk *clk;
- int ret;
-
- phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!phy_mem) {
- dev_err(dev, "%s: missing mem resource\n", __func__);
- return -ENODEV;
- }
-
- phy_base = devm_ioremap_resource(dev, phy_mem);
- if (IS_ERR(phy_base))
- return PTR_ERR(phy_base);
-
- sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
- if (!sphy)
- return -ENOMEM;
-
- otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL);
- if (!otg)
- return -ENOMEM;
-
- drv_data = samsung_usbphy_get_driver_data(pdev);
-
- if (drv_data->cpu_type == TYPE_EXYNOS5250)
- clk = devm_clk_get(dev, "usbhost");
- else
- clk = devm_clk_get(dev, "otg");
-
- if (IS_ERR(clk)) {
- dev_err(dev, "Failed to get otg clock\n");
- return PTR_ERR(clk);
- }
-
- sphy->dev = dev;
-
- if (dev->of_node) {
- ret = samsung_usbphy_parse_dt(sphy);
- if (ret < 0)
- return ret;
- } else {
- if (!pdata) {
- dev_err(dev, "no platform data specified\n");
- return -EINVAL;
- }
- }
-
- sphy->plat = pdata;
- sphy->regs = phy_base;
- sphy->clk = clk;
- sphy->drv_data = drv_data;
- sphy->phy.dev = sphy->dev;
- sphy->phy.label = "samsung-usbphy";
- sphy->phy.init = samsung_usbphy_init;
- sphy->phy.shutdown = samsung_usbphy_shutdown;
- sphy->ref_clk_freq = samsung_usbphy_get_refclk_freq(sphy);
-
- sphy->phy.otg = otg;
- sphy->phy.otg->phy = &sphy->phy;
- sphy->phy.otg->set_host = samsung_usbphy_set_host;
-
- spin_lock_init(&sphy->lock);
-
- platform_set_drvdata(pdev, sphy);
-
- return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
-}
-
-static int samsung_usbphy_remove(struct platform_device *pdev)
-{
- struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
-
- usb_remove_phy(&sphy->phy);
-
- if (sphy->pmuregs)
- iounmap(sphy->pmuregs);
- if (sphy->sysreg)
- iounmap(sphy->sysreg);
-
- return 0;
-}
-
-static const struct samsung_usbphy_drvdata usbphy_s3c64xx = {
- .cpu_type = TYPE_S3C64XX,
- .devphy_en_mask = S3C64XX_USBPHY_ENABLE,
-};
-
-static const struct samsung_usbphy_drvdata usbphy_exynos4 = {
- .cpu_type = TYPE_EXYNOS4210,
- .devphy_en_mask = EXYNOS_USBPHY_ENABLE,
- .hostphy_en_mask = EXYNOS_USBPHY_ENABLE,
-};
-
-static struct samsung_usbphy_drvdata usbphy_exynos5 = {
- .cpu_type = TYPE_EXYNOS5250,
- .hostphy_en_mask = EXYNOS_USBPHY_ENABLE,
- .hostphy_reg_offset = EXYNOS_USBHOST_PHY_CTRL_OFFSET,
-};
-
-#ifdef CONFIG_OF
-static const struct of_device_id samsung_usbphy_dt_match[] = {
- {
- .compatible = "samsung,s3c64xx-usbphy",
- .data = &usbphy_s3c64xx,
- }, {
- .compatible = "samsung,exynos4210-usbphy",
- .data = &usbphy_exynos4,
- }, {
- .compatible = "samsung,exynos5250-usbphy",
- .data = &usbphy_exynos5
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
-#endif
-
-static struct platform_device_id samsung_usbphy_driver_ids[] = {
- {
- .name = "s3c64xx-usbphy",
- .driver_data = (unsigned long)&usbphy_s3c64xx,
- }, {
- .name = "exynos4210-usbphy",
- .driver_data = (unsigned long)&usbphy_exynos4,
- }, {
- .name = "exynos5250-usbphy",
- .driver_data = (unsigned long)&usbphy_exynos5,
- },
- {},
-};
-
-MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
-
-static struct platform_driver samsung_usbphy_driver = {
- .probe = samsung_usbphy_probe,
- .remove = samsung_usbphy_remove,
- .id_table = samsung_usbphy_driver_ids,
- .driver = {
- .name = "samsung-usbphy",
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(samsung_usbphy_dt_match),
- },
-};
-
-module_platform_driver(samsung_usbphy_driver);
-
-MODULE_DESCRIPTION("Samsung USB phy controller");
-MODULE_AUTHOR("Praveen Paneri <p.paneri@samsung.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-usbphy");
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 9538f0feafe2..45b94019aec8 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -32,7 +32,6 @@
*/
void usbhs_pkt_init(struct usbhs_pkt *pkt)
{
- pkt->dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD(&pkt->node);
}
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h
index c31731a843d1..a168a1760fce 100644
--- a/drivers/usb/renesas_usbhs/fifo.h
+++ b/drivers/usb/renesas_usbhs/fifo.h
@@ -23,8 +23,6 @@
#include <asm/dma.h>
#include "pipe.h"
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
struct usbhs_fifo {
char *name;
u32 port; /* xFIFO */
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 78fca978b2d0..ed4949faa70d 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -230,7 +230,7 @@ static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv,
return 0;
}
-struct usbhsg_recip_handle req_clear_feature = {
+static struct usbhsg_recip_handle req_clear_feature = {
.name = "clear feature",
.device = usbhsg_recip_handler_std_control_done,
.interface = usbhsg_recip_handler_std_control_done,
@@ -271,7 +271,7 @@ static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv,
return 0;
}
-struct usbhsg_recip_handle req_set_feature = {
+static struct usbhsg_recip_handle req_set_feature = {
.name = "set feature",
.device = usbhsg_recip_handler_std_set_device,
.interface = usbhsg_recip_handler_std_control_done,
@@ -372,7 +372,7 @@ static int usbhsg_recip_handler_std_get_endpoint(struct usbhs_priv *priv,
return 0;
}
-struct usbhsg_recip_handle req_get_status = {
+static struct usbhsg_recip_handle req_get_status = {
.name = "get status",
.device = usbhsg_recip_handler_std_get_device,
.interface = usbhsg_recip_handler_std_get_interface,
@@ -845,7 +845,6 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget,
/* first hook up the driver ... */
gpriv->driver = driver;
- gpriv->gadget.dev.driver = &driver->driver;
return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD);
}
@@ -861,7 +860,6 @@ static int usbhsg_gadget_stop(struct usb_gadget *gadget,
return -EINVAL;
usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD);
- gpriv->gadget.dev.driver = NULL;
gpriv->driver = NULL;
return 0;
@@ -925,11 +923,6 @@ static int usbhsg_stop(struct usbhs_priv *priv)
return usbhsg_try_stop(priv, USBHSG_STATUS_STARTED);
}
-static void usbhs_mod_gadget_release(struct device *pdev)
-{
- /* do nothing */
-}
-
int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
{
struct usbhsg_gpriv *gpriv;
@@ -976,15 +969,10 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
/*
* init gadget
*/
- dev_set_name(&gpriv->gadget.dev, "gadget");
gpriv->gadget.dev.parent = dev;
- gpriv->gadget.dev.release = usbhs_mod_gadget_release;
gpriv->gadget.name = "renesas_usbhs_udc";
gpriv->gadget.ops = &usbhsg_gadget_ops;
gpriv->gadget.max_speed = USB_SPEED_HIGH;
- ret = device_register(&gpriv->gadget.dev);
- if (ret < 0)
- goto err_add_udc;
INIT_LIST_HEAD(&gpriv->gadget.ep_list);
@@ -1014,15 +1002,13 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
ret = usb_add_gadget_udc(dev, &gpriv->gadget);
if (ret)
- goto err_register;
+ goto err_add_udc;
dev_info(dev, "gadget probed\n");
return 0;
-err_register:
- device_unregister(&gpriv->gadget.dev);
err_add_udc:
kfree(gpriv->uep);
@@ -1038,8 +1024,6 @@ void usbhs_mod_gadget_remove(struct usbhs_priv *priv)
usb_del_gadget_udc(&gpriv->gadget);
- device_unregister(&gpriv->gadget.dev);
-
kfree(gpriv->uep);
kfree(gpriv);
}
diff --git a/drivers/usb/usb-common.c b/drivers/usb/usb-common.c
index d29503e954ab..0db0a919d72b 100644
--- a/drivers/usb/usb-common.c
+++ b/drivers/usb/usb-common.c
@@ -14,6 +14,32 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+
+const char *usb_otg_state_string(enum usb_otg_state state)
+{
+ static const char *const names[] = {
+ [OTG_STATE_A_IDLE] = "a_idle",
+ [OTG_STATE_A_WAIT_VRISE] = "a_wait_vrise",
+ [OTG_STATE_A_WAIT_BCON] = "a_wait_bcon",
+ [OTG_STATE_A_HOST] = "a_host",
+ [OTG_STATE_A_SUSPEND] = "a_suspend",
+ [OTG_STATE_A_PERIPHERAL] = "a_peripheral",
+ [OTG_STATE_A_WAIT_VFALL] = "a_wait_vfall",
+ [OTG_STATE_A_VBUS_ERR] = "a_vbus_err",
+ [OTG_STATE_B_IDLE] = "b_idle",
+ [OTG_STATE_B_SRP_INIT] = "b_srp_init",
+ [OTG_STATE_B_PERIPHERAL] = "b_peripheral",
+ [OTG_STATE_B_WAIT_ACON] = "b_wait_acon",
+ [OTG_STATE_B_HOST] = "b_host",
+ };
+
+ if (state < 0 || state >= ARRAY_SIZE(names))
+ return "UNDEFINED";
+
+ return names[state];
+}
+EXPORT_SYMBOL_GPL(usb_otg_state_string);
const char *usb_speed_string(enum usb_device_speed speed)
{
@@ -32,4 +58,25 @@ const char *usb_speed_string(enum usb_device_speed speed)
}
EXPORT_SYMBOL_GPL(usb_speed_string);
+const char *usb_state_string(enum usb_device_state state)
+{
+ static const char *const names[] = {
+ [USB_STATE_NOTATTACHED] = "not attached",
+ [USB_STATE_ATTACHED] = "attached",
+ [USB_STATE_POWERED] = "powered",
+ [USB_STATE_RECONNECTING] = "reconnecting",
+ [USB_STATE_UNAUTHENTICATED] = "unauthenticated",
+ [USB_STATE_DEFAULT] = "default",
+ [USB_STATE_ADDRESS] = "addresssed",
+ [USB_STATE_CONFIGURED] = "configured",
+ [USB_STATE_SUSPENDED] = "suspended",
+ };
+
+ if (state < 0 || state >= ARRAY_SIZE(names))
+ return "UNKNOWN";
+
+ return names[state];
+}
+EXPORT_SYMBOL_GPL(usb_state_string);
+
MODULE_LICENSE("GPL");
OpenPOWER on IntegriCloud