summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/quirks.c20
-rw-r--r--drivers/phy/Kconfig23
-rw-r--r--drivers/phy/Makefile3
-rw-r--r--drivers/phy/phy-armada375-usb2.c158
-rw-r--r--drivers/phy/phy-bcm-kona-usb2.c2
-rw-r--r--drivers/phy/phy-berlin-sata.c36
-rw-r--r--drivers/phy/phy-berlin-usb.c223
-rw-r--r--drivers/phy/phy-core.c115
-rw-r--r--drivers/phy/phy-exynos-dp-video.c2
-rw-r--r--drivers/phy/phy-exynos-mipi-video.c2
-rw-r--r--drivers/phy/phy-exynos5-usbdrd.c139
-rw-r--r--drivers/phy/phy-exynos5250-sata.c2
-rw-r--r--drivers/phy/phy-hix5hd2-sata.c7
-rw-r--r--drivers/phy/phy-miphy28lp.c1283
-rw-r--r--drivers/phy/phy-miphy365x.c7
-rw-r--r--drivers/phy/phy-mvebu-sata.c2
-rw-r--r--drivers/phy/phy-omap-usb2.c16
-rw-r--r--drivers/phy/phy-qcom-apq8064-sata.c3
-rw-r--r--drivers/phy/phy-qcom-ipq806x-sata.c3
-rw-r--r--drivers/phy/phy-rcar-gen2.c2
-rw-r--r--drivers/phy/phy-samsung-usb2.c3
-rw-r--r--drivers/phy/phy-spear1310-miphy.c2
-rw-r--r--drivers/phy/phy-spear1340-miphy.c2
-rw-r--r--drivers/phy/phy-stih407-usb.c2
-rw-r--r--drivers/phy/phy-stih41x-usb.c7
-rw-r--r--drivers/phy/phy-sun4i-usb.c11
-rw-r--r--drivers/phy/phy-ti-pipe3.c2
-rw-r--r--drivers/phy/phy-twl4030-usb.c15
-rw-r--r--drivers/phy/phy-xgene.c2
-rw-r--r--drivers/pinctrl/pinctrl-tegra-xusb.c4
-rw-r--r--drivers/usb/chipidea/Makefile1
-rw-r--r--drivers/usb/chipidea/ci.h10
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c45
-rw-r--r--drivers/usb/chipidea/ci_hdrc_msm.c9
-rw-r--r--drivers/usb/chipidea/ci_hdrc_usb2.c115
-rw-r--r--drivers/usb/chipidea/core.c225
-rw-r--r--drivers/usb/chipidea/debug.c2
-rw-r--r--drivers/usb/chipidea/host.c78
-rw-r--r--drivers/usb/chipidea/otg_fsm.c41
-rw-r--r--drivers/usb/chipidea/udc.c22
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c6
-rw-r--r--drivers/usb/class/cdc-acm.c17
-rw-r--r--drivers/usb/class/cdc-acm.h1
-rw-r--r--drivers/usb/class/usbtmc.c4
-rw-r--r--drivers/usb/common/usb-otg-fsm.c8
-rw-r--r--drivers/usb/core/hcd.c7
-rw-r--r--drivers/usb/core/hub.c18
-rw-r--r--drivers/usb/dwc2/Kconfig68
-rw-r--r--drivers/usb/dwc2/Makefile32
-rw-r--r--drivers/usb/dwc2/core.c10
-rw-r--r--drivers/usb/dwc2/core.h197
-rw-r--r--drivers/usb/dwc2/core_intr.c17
-rw-r--r--drivers/usb/dwc2/gadget.c387
-rw-r--r--drivers/usb/dwc2/hcd.c94
-rw-r--r--drivers/usb/dwc2/hcd.h10
-rw-r--r--drivers/usb/dwc2/pci.c7
-rw-r--r--drivers/usb/dwc2/platform.c44
-rw-r--r--drivers/usb/dwc3/Kconfig2
-rw-r--r--drivers/usb/dwc3/core.c251
-rw-r--r--drivers/usb/dwc3/core.h89
-rw-r--r--drivers/usb/dwc3/dwc3-exynos.c44
-rw-r--r--drivers/usb/dwc3/dwc3-keystone.c6
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c20
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c35
-rw-r--r--drivers/usb/dwc3/dwc3-st.c2
-rw-r--r--drivers/usb/dwc3/ep0.c26
-rw-r--r--drivers/usb/dwc3/gadget.c68
-rw-r--r--drivers/usb/dwc3/host.c22
-rw-r--r--drivers/usb/dwc3/platform_data.h20
-rw-r--r--drivers/usb/dwc3/trace.h20
-rw-r--r--drivers/usb/gadget/Kconfig61
-rw-r--r--drivers/usb/gadget/composite.c64
-rw-r--r--drivers/usb/gadget/configfs.c5
-rw-r--r--drivers/usb/gadget/function/Makefile4
-rw-r--r--drivers/usb/gadget/function/f_hid.c374
-rw-r--r--drivers/usb/gadget/function/f_midi.c364
-rw-r--r--drivers/usb/gadget/function/f_ncm.c3
-rw-r--r--drivers/usb/gadget/function/f_rndis.c3
-rw-r--r--drivers/usb/gadget/function/u_hid.h42
-rw-r--r--drivers/usb/gadget/function/u_midi.h40
-rw-r--r--drivers/usb/gadget/function/u_uac1.c3
-rw-r--r--drivers/usb/gadget/legacy/Kconfig2
-rw-r--r--drivers/usb/gadget/legacy/dbgp.c26
-rw-r--r--drivers/usb/gadget/legacy/gmidi.c43
-rw-r--r--drivers/usb/gadget/legacy/hid.c79
-rw-r--r--drivers/usb/gadget/legacy/printer.c65
-rw-r--r--drivers/usb/gadget/udc/Kconfig2
-rw-r--r--drivers/usb/gadget/udc/Makefile1
-rw-r--r--drivers/usb/gadget/udc/amd5536udc.c12
-rw-r--r--drivers/usb/gadget/udc/at91_udc.c89
-rw-r--r--drivers/usb/gadget/udc/atmel_usba_udc.c25
-rw-r--r--drivers/usb/gadget/udc/bcm63xx_udc.c13
-rw-r--r--drivers/usb/gadget/udc/bdc/Kconfig21
-rw-r--r--drivers/usb/gadget/udc/bdc/Makefile8
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc.h490
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_cmd.c376
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_cmd.h29
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_core.c533
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_dbg.c123
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_dbg.h37
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_ep.c2024
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_ep.h22
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_pci.c132
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_udc.c587
-rw-r--r--drivers/usb/gadget/udc/dummy_hcd.c36
-rw-r--r--drivers/usb/gadget/udc/fotg210-udc.c3
-rw-r--r--drivers/usb/gadget/udc/fsl_qe_udc.c13
-rw-r--r--drivers/usb/gadget/udc/fsl_udc_core.c19
-rw-r--r--drivers/usb/gadget/udc/fusb300_udc.c3
-rw-r--r--drivers/usb/gadget/udc/goku_udc.c6
-rw-r--r--drivers/usb/gadget/udc/gr_udc.c8
-rw-r--r--drivers/usb/gadget/udc/lpc32xx_udc.c11
-rw-r--r--drivers/usb/gadget/udc/m66592-udc.c5
-rw-r--r--drivers/usb/gadget/udc/mv_u3d_core.c5
-rw-r--r--drivers/usb/gadget/udc/mv_udc_core.c32
-rw-r--r--drivers/usb/gadget/udc/net2272.c66
-rw-r--r--drivers/usb/gadget/udc/net2280.c65
-rw-r--r--drivers/usb/gadget/udc/omap_udc.c6
-rw-r--r--drivers/usb/gadget/udc/pch_udc.c11
-rw-r--r--drivers/usb/gadget/udc/pxa25x_udc.c43
-rw-r--r--drivers/usb/gadget/udc/pxa27x_udc.c152
-rw-r--r--drivers/usb/gadget/udc/pxa27x_udc.h6
-rw-r--r--drivers/usb/gadget/udc/r8a66597-udc.c10
-rw-r--r--drivers/usb/gadget/udc/s3c-hsudc.c16
-rw-r--r--drivers/usb/gadget/udc/s3c2410_udc.c6
-rw-r--r--drivers/usb/gadget/udc/udc-core.c28
-rw-r--r--drivers/usb/gadget/udc/udc-xilinx.c3
-rw-r--r--drivers/usb/host/Kconfig18
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-atmel.c13
-rw-r--r--drivers/usb/host/ehci-exynos.c12
-rw-r--r--drivers/usb/host/ehci-fsl.c12
-rw-r--r--drivers/usb/host/ehci-hcd.c14
-rw-r--r--drivers/usb/host/ehci-hub.c45
-rw-r--r--drivers/usb/host/ehci-msm.c10
-rw-r--r--drivers/usb/host/ehci-mv.c13
-rw-r--r--drivers/usb/host/ehci-mxc.c11
-rw-r--r--drivers/usb/host/ehci-octeon.c188
-rw-r--r--drivers/usb/host/ehci-orion.c14
-rw-r--r--drivers/usb/host/ehci-platform.c27
-rw-r--r--drivers/usb/host/ehci-sead3.c5
-rw-r--r--drivers/usb/host/ehci-sh.c16
-rw-r--r--drivers/usb/host/ehci-spear.c9
-rw-r--r--drivers/usb/host/ehci-tegra.c11
-rw-r--r--drivers/usb/host/ehci-w90x900.c17
-rw-r--r--drivers/usb/host/ehci.h2
-rw-r--r--drivers/usb/host/fotg210.h62
-rw-r--r--drivers/usb/host/fusbh200.h62
-rw-r--r--drivers/usb/host/imx21-hcd.c6
-rw-r--r--drivers/usb/host/octeon2-common.c200
-rw-r--r--drivers/usb/host/ohci-at91.c15
-rw-r--r--drivers/usb/host/ohci-da8xx.c7
-rw-r--r--drivers/usb/host/ohci-exynos.c11
-rw-r--r--drivers/usb/host/ohci-hcd.c5
-rw-r--r--drivers/usb/host/ohci-jz4740.c13
-rw-r--r--drivers/usb/host/ohci-octeon.c202
-rw-r--r--drivers/usb/host/ohci-omap.c2
-rw-r--r--drivers/usb/host/ohci-platform.c53
-rw-r--r--drivers/usb/host/ohci-pxa27x.c11
-rw-r--r--drivers/usb/host/ohci-spear.c11
-rw-r--r--drivers/usb/host/ohci.h19
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c1
-rw-r--r--drivers/usb/host/pci-quirks.c12
-rw-r--r--drivers/usb/host/uhci-platform.c6
-rw-r--r--drivers/usb/host/xhci-plat.c10
-rw-r--r--drivers/usb/host/xhci-ring.c113
-rw-r--r--drivers/usb/host/xhci.c7
-rw-r--r--drivers/usb/host/xhci.h4
-rw-r--r--drivers/usb/misc/adutux.c5
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c3
-rw-r--r--drivers/usb/misc/usb3503.c8
-rw-r--r--drivers/usb/misc/yurex.c6
-rw-r--r--drivers/usb/musb/Kconfig5
-rw-r--r--drivers/usb/musb/am35x.c32
-rw-r--r--drivers/usb/musb/blackfin.c74
-rw-r--r--drivers/usb/musb/da8xx.c30
-rw-r--r--drivers/usb/musb/davinci.c22
-rw-r--r--drivers/usb/musb/jz4740.c2
-rw-r--r--drivers/usb/musb/musb_core.c335
-rw-r--r--drivers/usb/musb/musb_core.h87
-rw-r--r--drivers/usb/musb/musb_cppi41.c10
-rw-r--r--drivers/usb/musb/musb_debugfs.c57
-rw-r--r--drivers/usb/musb/musb_dsps.c37
-rw-r--r--drivers/usb/musb/musb_gadget.c58
-rw-r--r--drivers/usb/musb/musb_host.c8
-rw-r--r--drivers/usb/musb/musb_io.h106
-rw-r--r--drivers/usb/musb/musb_regs.h26
-rw-r--r--drivers/usb/musb/musb_virthub.c23
-rw-r--r--drivers/usb/musb/musbhsdma.c7
-rw-r--r--drivers/usb/musb/omap2430.c52
-rw-r--r--drivers/usb/musb/tusb6010.c102
-rw-r--r--drivers/usb/musb/ux500.c16
-rw-r--r--drivers/usb/musb/ux500_dma.c11
-rw-r--r--drivers/usb/phy/phy-ab8500-usb.c33
-rw-r--r--drivers/usb/phy/phy-am335x-control.c4
-rw-r--r--drivers/usb/phy/phy-fsl-usb.c27
-rw-r--r--drivers/usb/phy/phy-fsl-usb.h2
-rw-r--r--drivers/usb/phy/phy-generic.c8
-rw-r--r--drivers/usb/phy/phy-gpio-vbus-usb.c16
-rw-r--r--drivers/usb/phy/phy-isp1301-omap.c104
-rw-r--r--drivers/usb/phy/phy-msm-usb.c107
-rw-r--r--drivers/usb/phy/phy-mv-usb.c56
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c4
-rw-r--r--drivers/usb/phy/phy-rcar-gen2-usb.c4
-rw-r--r--drivers/usb/phy/phy-rcar-usb.c12
-rw-r--r--drivers/usb/phy/phy-tahvo.c34
-rw-r--r--drivers/usb/phy/phy-tegra-usb.c9
-rw-r--r--drivers/usb/phy/phy-ulpi.c6
-rw-r--r--drivers/usb/phy/phy.c16
-rw-r--r--drivers/usb/renesas_usbhs/common.c14
-rw-r--r--drivers/usb/renesas_usbhs/common.h7
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c111
-rw-r--r--drivers/usb/renesas_usbhs/fifo.h10
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c41
-rw-r--r--drivers/usb/renesas_usbhs/mod_host.c2
-rw-r--r--drivers/usb/renesas_usbhs/pipe.c8
-rw-r--r--drivers/usb/renesas_usbhs/rcar2.c73
-rw-r--r--drivers/usb/serial/Kconfig5
-rw-r--r--drivers/usb/serial/keyspan_pda.c16
-rw-r--r--drivers/usb/serial/kobil_sct.c2
-rw-r--r--drivers/usb/serial/mos7720.c8
-rw-r--r--drivers/usb/serial/mos7840.c4
-rw-r--r--drivers/usb/serial/qcserial.c33
-rw-r--r--drivers/usb/serial/usb-serial-simple.c10
-rw-r--r--drivers/usb/storage/debug.c7
-rw-r--r--drivers/usb/storage/debug.h10
-rw-r--r--drivers/usb/storage/initializers.c3
-rw-r--r--drivers/usb/storage/transport.c17
-rw-r--r--drivers/usb/storage/uas.c64
-rw-r--r--drivers/usb/storage/usb.c36
-rw-r--r--drivers/usb/usbip/stub_dev.c26
-rw-r--r--drivers/usb/usbip/vhci_hcd.c9
-rw-r--r--drivers/usb/wusbcore/dev-sysfs.c2
-rw-r--r--drivers/usb/wusbcore/security.c8
-rw-r--r--drivers/uwb/rsv.c4
235 files changed, 10441 insertions, 3356 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 90acb32c85b1..ed6f89b6efe5 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -379,6 +379,26 @@ static void quirk_ati_exploding_mce(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce);
/*
+ * In the AMD NL platform, this device ([1022:7912]) has a class code of
+ * PCI_CLASS_SERIAL_USB_XHCI (0x0c0330), which means the xhci driver will
+ * claim it.
+ * But the dwc3 driver is a more specific driver for this device, and we'd
+ * prefer to use it instead of xhci. To prevent xhci from claiming the
+ * device, change the class code to 0x0c03fe, which the PCI r3.0 spec
+ * defines as "USB device (not host controller)". The dwc3 driver can then
+ * claim it based on its Vendor and Device ID.
+ */
+static void quirk_amd_nl_class(struct pci_dev *pdev)
+{
+ /*
+ * Use 'USB Device' (0x0c03fe) instead of PCI header provided
+ */
+ pdev->class = 0x0c03fe;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB,
+ quirk_amd_nl_class);
+
+/*
* Let's make the southbridge information explicit instead
* of having to worry about people probing the ACPI areas,
* for example.. (Yes, it happens, and if you read the wrong
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 2a436e607f99..ccad8809ecb1 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -15,6 +15,13 @@ config GENERIC_PHY
phy users can obtain reference to the PHY. All the users of this
framework should select this config.
+config PHY_BERLIN_USB
+ tristate "Marvell Berlin USB PHY Driver"
+ depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF
+ select GENERIC_PHY
+ help
+ Enable this to support the USB PHY on Marvell Berlin SoCs.
+
config PHY_BERLIN_SATA
tristate "Marvell Berlin SATA PHY driver"
depends on ARCH_BERLIN && HAS_IOMEM && OF
@@ -22,6 +29,12 @@ config PHY_BERLIN_SATA
help
Enable this to support the SATA PHY on Marvell Berlin SoCs.
+config ARMADA375_USBCLUSTER_PHY
+ def_bool y
+ depends on MACH_ARMADA_375 || COMPILE_TEST
+ depends on OF
+ select GENERIC_PHY
+
config PHY_EXYNOS_MIPI_VIDEO
tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver"
depends on HAS_IOMEM
@@ -38,6 +51,14 @@ config PHY_MVEBU_SATA
depends on OF
select GENERIC_PHY
+config PHY_MIPHY28LP
+ tristate "STMicroelectronics MIPHY28LP PHY driver for STiH407"
+ depends on ARCH_STI
+ select GENERIC_PHY
+ help
+ Enable this to support the miphy transceiver (for SATA/PCIE/USB3)
+ that is part of STMicroelectronics STiH407 SoC.
+
config PHY_MIPHY365X
tristate "STMicroelectronics MIPHY365X PHY driver for STiH41x series"
depends on ARCH_STI
@@ -193,7 +214,7 @@ config PHY_EXYNOS5250_USB2
config PHY_EXYNOS5_USBDRD
tristate "Exynos5 SoC series USB DRD PHY driver"
- depends on ARCH_EXYNOS5 && OF
+ depends on ARCH_EXYNOS && OF
depends on HAS_IOMEM
depends on USB_DWC3_EXYNOS
select GENERIC_PHY
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index c4590fce082f..aa74f961e44e 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -3,11 +3,14 @@
#
obj-$(CONFIG_GENERIC_PHY) += phy-core.o
+obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o
+obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o
obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o
obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o
obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o
obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
+obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o
obj-$(CONFIG_PHY_MIPHY365X) += phy-miphy365x.o
obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o
diff --git a/drivers/phy/phy-armada375-usb2.c b/drivers/phy/phy-armada375-usb2.c
new file mode 100644
index 000000000000..ac7d99d01cb3
--- /dev/null
+++ b/drivers/phy/phy-armada375-usb2.c
@@ -0,0 +1,158 @@
+/*
+ * USB cluster support for Armada 375 platform.
+ *
+ * Copyright (C) 2014 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2 or later. This program is licensed "as is"
+ * without any warranty of any kind, whether express or implied.
+ *
+ * Armada 375 comes with an USB2 host and device controller and an
+ * USB3 controller. The USB cluster control register allows to manage
+ * common features of both USB controllers.
+ */
+
+#include <dt-bindings/phy/phy.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+#define USB2_PHY_CONFIG_DISABLE BIT(0)
+
+struct armada375_cluster_phy {
+ struct phy *phy;
+ void __iomem *reg;
+ bool use_usb3;
+ int phy_provided;
+};
+
+static int armada375_usb_phy_init(struct phy *phy)
+{
+ struct armada375_cluster_phy *cluster_phy;
+ u32 reg;
+
+ cluster_phy = dev_get_drvdata(phy->dev.parent);
+ if (!cluster_phy)
+ return -ENODEV;
+
+ reg = readl(cluster_phy->reg);
+ if (cluster_phy->use_usb3)
+ reg |= USB2_PHY_CONFIG_DISABLE;
+ else
+ reg &= ~USB2_PHY_CONFIG_DISABLE;
+ writel(reg, cluster_phy->reg);
+
+ return 0;
+}
+
+static struct phy_ops armada375_usb_phy_ops = {
+ .init = armada375_usb_phy_init,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Only one controller can use this PHY. We shouldn't have the case
+ * when two controllers want to use this PHY. But if this case occurs
+ * then we provide a phy to the first one and return an error for the
+ * next one. This error has also to be an error returned by
+ * devm_phy_optional_get() so different from ENODEV for USB2. In the
+ * USB3 case it still optional and we use ENODEV.
+ */
+static struct phy *armada375_usb_phy_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct armada375_cluster_phy *cluster_phy = dev_get_drvdata(dev);
+
+ if (!cluster_phy)
+ return ERR_PTR(-ENODEV);
+
+ /*
+ * Either the phy had never been requested and then the first
+ * usb claiming it can get it, or it had already been
+ * requested in this case, we only allow to use it with the
+ * same configuration.
+ */
+ if (WARN_ON((cluster_phy->phy_provided != PHY_NONE) &&
+ (cluster_phy->phy_provided != args->args[0]))) {
+ dev_err(dev, "This PHY has already been provided!\n");
+ dev_err(dev, "Check your device tree, only one controller can use it\n.");
+ if (args->args[0] == PHY_TYPE_USB2)
+ return ERR_PTR(-EBUSY);
+ else
+ return ERR_PTR(-ENODEV);
+ }
+
+ if (args->args[0] == PHY_TYPE_USB2)
+ cluster_phy->use_usb3 = false;
+ else if (args->args[0] == PHY_TYPE_USB3)
+ cluster_phy->use_usb3 = true;
+ else {
+ dev_err(dev, "Invalid PHY mode\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ /* Store which phy mode is used for next test */
+ cluster_phy->phy_provided = args->args[0];
+
+ return cluster_phy->phy;
+}
+
+static int armada375_usb_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct phy *phy;
+ struct phy_provider *phy_provider;
+ void __iomem *usb_cluster_base;
+ struct resource *res;
+ struct armada375_cluster_phy *cluster_phy;
+
+ cluster_phy = devm_kzalloc(dev, sizeof(*cluster_phy), GFP_KERNEL);
+ if (!cluster_phy)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ usb_cluster_base = devm_ioremap_resource(&pdev->dev, res);
+ if (!usb_cluster_base)
+ return -ENOMEM;
+
+ phy = devm_phy_create(dev, NULL, &armada375_usb_phy_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "failed to create PHY\n");
+ return PTR_ERR(phy);
+ }
+
+ cluster_phy->phy = phy;
+ cluster_phy->reg = usb_cluster_base;
+
+ dev_set_drvdata(dev, cluster_phy);
+
+ phy_provider = devm_of_phy_provider_register(&pdev->dev,
+ armada375_usb_phy_xlate);
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id of_usb_cluster_table[] = {
+ { .compatible = "marvell,armada-375-usb-cluster", },
+ { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(of, of_usb_cluster_table);
+
+static struct platform_driver armada375_usb_phy_driver = {
+ .probe = armada375_usb_phy_probe,
+ .driver = {
+ .of_match_table = of_usb_cluster_table,
+ .name = "armada-375-usb-cluster",
+ .owner = THIS_MODULE,
+ }
+};
+module_platform_driver(armada375_usb_phy_driver);
+
+MODULE_DESCRIPTION("Armada 375 USB cluster driver");
+MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/phy-bcm-kona-usb2.c b/drivers/phy/phy-bcm-kona-usb2.c
index c1e0ca335c0e..ef2dc1aab2b9 100644
--- a/drivers/phy/phy-bcm-kona-usb2.c
+++ b/drivers/phy/phy-bcm-kona-usb2.c
@@ -117,7 +117,7 @@ static int bcm_kona_usb2_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, phy);
- gphy = devm_phy_create(dev, NULL, &ops, NULL);
+ gphy = devm_phy_create(dev, NULL, &ops);
if (IS_ERR(gphy))
return PTR_ERR(gphy);
diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c
index 69ced52d72aa..099eee8851e5 100644
--- a/drivers/phy/phy-berlin-sata.c
+++ b/drivers/phy/phy-berlin-sata.c
@@ -30,7 +30,8 @@
#define MBUS_WRITE_REQUEST_SIZE_128 (BIT(2) << 16)
#define MBUS_READ_REQUEST_SIZE_128 (BIT(2) << 19)
-#define PHY_BASE 0x200
+#define BG2_PHY_BASE 0x080
+#define BG2Q_PHY_BASE 0x200
/* register 0x01 */
#define REF_FREF_SEL_25 BIT(0)
@@ -61,15 +62,16 @@ struct phy_berlin_priv {
struct clk *clk;
struct phy_berlin_desc **phys;
unsigned nphys;
+ u32 phy_base;
};
-static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg, u32 reg,
- u32 mask, u32 val)
+static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg,
+ u32 phy_base, u32 reg, u32 mask, u32 val)
{
u32 regval;
/* select register */
- writel(PHY_BASE + reg, ctrl_reg + PORT_VSR_ADDR);
+ writel(phy_base + reg, ctrl_reg + PORT_VSR_ADDR);
/* set bits */
regval = readl(ctrl_reg + PORT_VSR_DATA);
@@ -103,17 +105,20 @@ static int phy_berlin_sata_power_on(struct phy *phy)
writel(regval, priv->base + HOST_VSA_DATA);
/* set PHY mode and ref freq to 25 MHz */
- phy_berlin_sata_reg_setbits(ctrl_reg, 0x1, 0xff,
- REF_FREF_SEL_25 | PHY_MODE_SATA);
+ phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x01,
+ 0x00ff, REF_FREF_SEL_25 | PHY_MODE_SATA);
/* set PHY up to 6 Gbps */
- phy_berlin_sata_reg_setbits(ctrl_reg, 0x25, 0xc00, PHY_GEN_MAX_6_0);
+ phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x25,
+ 0x0c00, PHY_GEN_MAX_6_0);
/* set 40 bits width */
- phy_berlin_sata_reg_setbits(ctrl_reg, 0x23, 0xc00, DATA_BIT_WIDTH_40);
+ phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x23,
+ 0x0c00, DATA_BIT_WIDTH_40);
/* use max pll rate */
- phy_berlin_sata_reg_setbits(ctrl_reg, 0x2, 0x0, USE_MAX_PLL_RATE);
+ phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x02,
+ 0x0000, USE_MAX_PLL_RATE);
/* set Gen3 controller speed */
regval = readl(ctrl_reg + PORT_SCR_CTL);
@@ -218,6 +223,11 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
if (!priv->phys)
return -ENOMEM;
+ if (of_device_is_compatible(dev->of_node, "marvell,berlin2-sata-phy"))
+ priv->phy_base = BG2_PHY_BASE;
+ else
+ priv->phy_base = BG2Q_PHY_BASE;
+
dev_set_drvdata(dev, priv);
spin_lock_init(&priv->lock);
@@ -239,7 +249,7 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
if (!phy_desc)
return -ENOMEM;
- phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops, NULL);
+ phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY %d\n", phy_id);
return PTR_ERR(phy);
@@ -258,13 +268,11 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
phy_provider =
devm_of_phy_provider_register(dev, phy_berlin_sata_phy_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
-
- return 0;
+ return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id phy_berlin_sata_of_match[] = {
+ { .compatible = "marvell,berlin2-sata-phy" },
{ .compatible = "marvell,berlin2q-sata-phy" },
{ },
};
diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c
new file mode 100644
index 000000000000..c8a8d53a6ece
--- /dev/null
+++ b/drivers/phy/phy-berlin-usb.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 Marvell Technology Group Ltd.
+ *
+ * Antoine Tenart <antoine.tenart@free-electrons.com>
+ * Jisheng Zhang <jszhang@marvell.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#define USB_PHY_PLL 0x04
+#define USB_PHY_PLL_CONTROL 0x08
+#define USB_PHY_TX_CTRL0 0x10
+#define USB_PHY_TX_CTRL1 0x14
+#define USB_PHY_TX_CTRL2 0x18
+#define USB_PHY_RX_CTRL 0x20
+#define USB_PHY_ANALOG 0x34
+
+/* USB_PHY_PLL */
+#define CLK_REF_DIV(x) ((x) << 4)
+#define FEEDBACK_CLK_DIV(x) ((x) << 8)
+
+/* USB_PHY_PLL_CONTROL */
+#define CLK_STABLE BIT(0)
+#define PLL_CTRL_PIN BIT(1)
+#define PLL_CTRL_REG BIT(2)
+#define PLL_ON BIT(3)
+#define PHASE_OFF_TOL_125 (0x0 << 5)
+#define PHASE_OFF_TOL_250 BIT(5)
+#define KVC0_CALIB (0x0 << 9)
+#define KVC0_REG_CTRL BIT(9)
+#define KVC0_HIGH (0x0 << 10)
+#define KVC0_LOW (0x3 << 10)
+#define CLK_BLK_EN BIT(13)
+
+/* USB_PHY_TX_CTRL0 */
+#define EXT_HS_RCAL_EN BIT(3)
+#define EXT_FS_RCAL_EN BIT(4)
+#define IMPCAL_VTH_DIV(x) ((x) << 5)
+#define EXT_RS_RCAL_DIV(x) ((x) << 8)
+#define EXT_FS_RCAL_DIV(x) ((x) << 12)
+
+/* USB_PHY_TX_CTRL1 */
+#define TX_VDD15_14 (0x0 << 4)
+#define TX_VDD15_15 BIT(4)
+#define TX_VDD15_16 (0x2 << 4)
+#define TX_VDD15_17 (0x3 << 4)
+#define TX_VDD12_VDD (0x0 << 6)
+#define TX_VDD12_11 BIT(6)
+#define TX_VDD12_12 (0x2 << 6)
+#define TX_VDD12_13 (0x3 << 6)
+#define LOW_VDD_EN BIT(8)
+#define TX_OUT_AMP(x) ((x) << 9)
+
+/* USB_PHY_TX_CTRL2 */
+#define TX_CHAN_CTRL_REG(x) ((x) << 0)
+#define DRV_SLEWRATE(x) ((x) << 4)
+#define IMP_CAL_FS_HS_DLY_0 (0x0 << 6)
+#define IMP_CAL_FS_HS_DLY_1 BIT(6)
+#define IMP_CAL_FS_HS_DLY_2 (0x2 << 6)
+#define IMP_CAL_FS_HS_DLY_3 (0x3 << 6)
+#define FS_DRV_EN_MASK(x) ((x) << 8)
+#define HS_DRV_EN_MASK(x) ((x) << 12)
+
+/* USB_PHY_RX_CTRL */
+#define PHASE_FREEZE_DLY_2_CL (0x0 << 0)
+#define PHASE_FREEZE_DLY_4_CL BIT(0)
+#define ACK_LENGTH_8_CL (0x0 << 2)
+#define ACK_LENGTH_12_CL BIT(2)
+#define ACK_LENGTH_16_CL (0x2 << 2)
+#define ACK_LENGTH_20_CL (0x3 << 2)
+#define SQ_LENGTH_3 (0x0 << 4)
+#define SQ_LENGTH_6 BIT(4)
+#define SQ_LENGTH_9 (0x2 << 4)
+#define SQ_LENGTH_12 (0x3 << 4)
+#define DISCON_THRESHOLD_260 (0x0 << 6)
+#define DISCON_THRESHOLD_270 BIT(6)
+#define DISCON_THRESHOLD_280 (0x2 << 6)
+#define DISCON_THRESHOLD_290 (0x3 << 6)
+#define SQ_THRESHOLD(x) ((x) << 8)
+#define LPF_COEF(x) ((x) << 12)
+#define INTPL_CUR_10 (0x0 << 14)
+#define INTPL_CUR_20 BIT(14)
+#define INTPL_CUR_30 (0x2 << 14)
+#define INTPL_CUR_40 (0x3 << 14)
+
+/* USB_PHY_ANALOG */
+#define ANA_PWR_UP BIT(1)
+#define ANA_PWR_DOWN BIT(2)
+#define V2I_VCO_RATIO(x) ((x) << 7)
+#define R_ROTATE_90 (0x0 << 10)
+#define R_ROTATE_0 BIT(10)
+#define MODE_TEST_EN BIT(11)
+#define ANA_TEST_DC_CTRL(x) ((x) << 12)
+
+#define to_phy_berlin_usb_priv(p) \
+ container_of((p), struct phy_berlin_usb_priv, phy)
+
+static const u32 phy_berlin_pll_dividers[] = {
+ /* Berlin 2 */
+ CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
+ /* Berlin 2CD */
+ CLK_REF_DIV(0x6) | FEEDBACK_CLK_DIV(0x55),
+};
+
+struct phy_berlin_usb_priv {
+ void __iomem *base;
+ struct phy *phy;
+ struct reset_control *rst_ctrl;
+ u32 pll_divider;
+};
+
+static int phy_berlin_usb_power_on(struct phy *phy)
+{
+ struct phy_berlin_usb_priv *priv = dev_get_drvdata(phy->dev.parent);
+
+ reset_control_reset(priv->rst_ctrl);
+
+ writel(priv->pll_divider,
+ priv->base + USB_PHY_PLL);
+ writel(CLK_STABLE | PLL_CTRL_REG | PHASE_OFF_TOL_250 | KVC0_REG_CTRL |
+ CLK_BLK_EN, priv->base + USB_PHY_PLL_CONTROL);
+ writel(V2I_VCO_RATIO(0x5) | R_ROTATE_0 | ANA_TEST_DC_CTRL(0x5),
+ priv->base + USB_PHY_ANALOG);
+ writel(PHASE_FREEZE_DLY_4_CL | ACK_LENGTH_16_CL | SQ_LENGTH_12 |
+ DISCON_THRESHOLD_260 | SQ_THRESHOLD(0xa) | LPF_COEF(0x2) |
+ INTPL_CUR_30, priv->base + USB_PHY_RX_CTRL);
+
+ writel(TX_VDD12_13 | TX_OUT_AMP(0x3), priv->base + USB_PHY_TX_CTRL1);
+ writel(EXT_HS_RCAL_EN | IMPCAL_VTH_DIV(0x3) | EXT_RS_RCAL_DIV(0x4),
+ priv->base + USB_PHY_TX_CTRL0);
+
+ writel(EXT_HS_RCAL_EN | IMPCAL_VTH_DIV(0x3) | EXT_RS_RCAL_DIV(0x4) |
+ EXT_FS_RCAL_DIV(0x2), priv->base + USB_PHY_TX_CTRL0);
+
+ writel(EXT_HS_RCAL_EN | IMPCAL_VTH_DIV(0x3) | EXT_RS_RCAL_DIV(0x4),
+ priv->base + USB_PHY_TX_CTRL0);
+ writel(TX_CHAN_CTRL_REG(0xf) | DRV_SLEWRATE(0x3) | IMP_CAL_FS_HS_DLY_3 |
+ FS_DRV_EN_MASK(0xd), priv->base + USB_PHY_TX_CTRL2);
+
+ return 0;
+}
+
+static struct phy_ops phy_berlin_usb_ops = {
+ .power_on = phy_berlin_usb_power_on,
+ .owner = THIS_MODULE,
+};
+
+static const struct of_device_id phy_berlin_sata_of_match[] = {
+ {
+ .compatible = "marvell,berlin2-usb-phy",
+ .data = &phy_berlin_pll_dividers[0],
+ },
+ {
+ .compatible = "marvell,berlin2cd-usb-phy",
+ .data = &phy_berlin_pll_dividers[1],
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, phy_berlin_sata_of_match);
+
+static int phy_berlin_usb_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match =
+ of_match_device(phy_berlin_sata_of_match, &pdev->dev);
+ struct phy_berlin_usb_priv *priv;
+ struct resource *res;
+ struct phy_provider *phy_provider;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->rst_ctrl = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->rst_ctrl))
+ return PTR_ERR(priv->rst_ctrl);
+
+ priv->pll_divider = *((u32 *)match->data);
+
+ priv->phy = devm_phy_create(&pdev->dev, NULL, &phy_berlin_usb_ops);
+ if (IS_ERR(priv->phy)) {
+ dev_err(&pdev->dev, "failed to create PHY\n");
+ return PTR_ERR(priv->phy);
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ phy_provider =
+ devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
+ return 0;
+}
+
+static struct platform_driver phy_berlin_usb_driver = {
+ .probe = phy_berlin_usb_probe,
+ .driver = {
+ .name = "phy-berlin-usb",
+ .owner = THIS_MODULE,
+ .of_match_table = phy_berlin_sata_of_match,
+ },
+};
+module_platform_driver(phy_berlin_usb_driver);
+
+MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell Berlin PHY driver for USB");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index ff5eec5af817..a12d35338313 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -26,6 +26,7 @@
static struct class *phy_class;
static DEFINE_MUTEX(phy_provider_mutex);
static LIST_HEAD(phy_provider_list);
+static LIST_HEAD(phys);
static DEFINE_IDA(phy_ida);
static void devm_phy_release(struct device *dev, void *res)
@@ -54,34 +55,79 @@ static int devm_phy_match(struct device *dev, void *res, void *match_data)
return res == match_data;
}
-static struct phy *phy_lookup(struct device *device, const char *port)
+/**
+ * phy_create_lookup() - allocate and register PHY/device association
+ * @phy: the phy of the association
+ * @con_id: connection ID string on device
+ * @dev_id: the device of the association
+ *
+ * Creates and registers phy_lookup entry.
+ */
+int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id)
{
- unsigned int count;
- struct phy *phy;
- struct device *dev;
- struct phy_consumer *consumers;
- struct class_dev_iter iter;
+ struct phy_lookup *pl;
- class_dev_iter_init(&iter, phy_class, NULL, NULL);
- while ((dev = class_dev_iter_next(&iter))) {
- phy = to_phy(dev);
+ if (!phy || !dev_id || !con_id)
+ return -EINVAL;
- if (!phy->init_data)
- continue;
- count = phy->init_data->num_consumers;
- consumers = phy->init_data->consumers;
- while (count--) {
- if (!strcmp(consumers->dev_name, dev_name(device)) &&
- !strcmp(consumers->port, port)) {
- class_dev_iter_exit(&iter);
- return phy;
- }
- consumers++;
+ pl = kzalloc(sizeof(*pl), GFP_KERNEL);
+ if (!pl)
+ return -ENOMEM;
+
+ pl->dev_id = dev_id;
+ pl->con_id = con_id;
+ pl->phy = phy;
+
+ mutex_lock(&phy_provider_mutex);
+ list_add_tail(&pl->node, &phys);
+ mutex_unlock(&phy_provider_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(phy_create_lookup);
+
+/**
+ * phy_remove_lookup() - find and remove PHY/device association
+ * @phy: the phy of the association
+ * @con_id: connection ID string on device
+ * @dev_id: the device of the association
+ *
+ * Finds and unregisters phy_lookup entry that was created with
+ * phy_create_lookup().
+ */
+void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id)
+{
+ struct phy_lookup *pl;
+
+ if (!phy || !dev_id || !con_id)
+ return;
+
+ mutex_lock(&phy_provider_mutex);
+ list_for_each_entry(pl, &phys, node)
+ if (pl->phy == phy && !strcmp(pl->dev_id, dev_id) &&
+ !strcmp(pl->con_id, con_id)) {
+ list_del(&pl->node);
+ kfree(pl);
+ break;
}
- }
+ mutex_unlock(&phy_provider_mutex);
+}
+EXPORT_SYMBOL_GPL(phy_remove_lookup);
- class_dev_iter_exit(&iter);
- return ERR_PTR(-ENODEV);
+static struct phy *phy_find(struct device *dev, const char *con_id)
+{
+ const char *dev_id = dev_name(dev);
+ struct phy_lookup *p, *pl = NULL;
+
+ mutex_lock(&phy_provider_mutex);
+ list_for_each_entry(p, &phys, node)
+ if (!strcmp(p->dev_id, dev_id) && !strcmp(p->con_id, con_id)) {
+ pl = p;
+ break;
+ }
+ mutex_unlock(&phy_provider_mutex);
+
+ return pl ? pl->phy : ERR_PTR(-ENODEV);
}
static struct phy_provider *of_phy_provider_lookup(struct device_node *node)
@@ -414,21 +460,13 @@ struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args
{
struct phy *phy;
struct class_dev_iter iter;
- struct device_node *node = dev->of_node;
- struct device_node *child;
class_dev_iter_init(&iter, phy_class, NULL, NULL);
while ((dev = class_dev_iter_next(&iter))) {
phy = to_phy(dev);
- if (node != phy->dev.of_node) {
- for_each_child_of_node(node, child) {
- if (child == phy->dev.of_node)
- goto phy_found;
- }
+ if (args->np != phy->dev.of_node)
continue;
- }
-phy_found:
class_dev_iter_exit(&iter);
return phy;
}
@@ -463,7 +501,7 @@ struct phy *phy_get(struct device *dev, const char *string)
string);
phy = _of_phy_get(dev->of_node, index);
} else {
- phy = phy_lookup(dev, string);
+ phy = phy_find(dev, string);
}
if (IS_ERR(phy))
return phy;
@@ -588,13 +626,11 @@ EXPORT_SYMBOL_GPL(devm_of_phy_get);
* @dev: device that is creating the new phy
* @node: device node of the phy
* @ops: function pointers for performing phy operations
- * @init_data: contains the list of PHY consumers or NULL
*
* Called to create a phy using phy framework.
*/
struct phy *phy_create(struct device *dev, struct device_node *node,
- const struct phy_ops *ops,
- struct phy_init_data *init_data)
+ const struct phy_ops *ops)
{
int ret;
int id;
@@ -632,7 +668,6 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
phy->dev.of_node = node ?: dev->of_node;
phy->id = id;
phy->ops = ops;
- phy->init_data = init_data;
ret = dev_set_name(&phy->dev, "phy-%s.%d", dev_name(dev), id);
if (ret)
@@ -667,7 +702,6 @@ EXPORT_SYMBOL_GPL(phy_create);
* @dev: device that is creating the new phy
* @node: device node of the phy
* @ops: function pointers for performing phy operations
- * @init_data: contains the list of PHY consumers or NULL
*
* Creates a new PHY device adding it to the PHY class.
* While at that, it also associates the device with the phy using devres.
@@ -675,8 +709,7 @@ EXPORT_SYMBOL_GPL(phy_create);
* then, devres data is freed.
*/
struct phy *devm_phy_create(struct device *dev, struct device_node *node,
- const struct phy_ops *ops,
- struct phy_init_data *init_data)
+ const struct phy_ops *ops)
{
struct phy **ptr, *phy;
@@ -684,7 +717,7 @@ struct phy *devm_phy_create(struct device *dev, struct device_node *node,
if (!ptr)
return ERR_PTR(-ENOMEM);
- phy = phy_create(dev, node, ops, init_data);
+ phy = phy_create(dev, node, ops);
if (!IS_ERR(phy)) {
*ptr = phy;
devres_add(dev, ptr);
diff --git a/drivers/phy/phy-exynos-dp-video.c b/drivers/phy/phy-exynos-dp-video.c
index 84f49e5a3f24..f86cbe68ddaf 100644
--- a/drivers/phy/phy-exynos-dp-video.c
+++ b/drivers/phy/phy-exynos-dp-video.c
@@ -112,7 +112,7 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)
match = of_match_node(exynos_dp_video_phy_of_match, dev->of_node);
state->drvdata = match->data;
- phy = devm_phy_create(dev, NULL, &exynos_dp_video_phy_ops, NULL);
+ phy = devm_phy_create(dev, NULL, &exynos_dp_video_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create Display Port PHY\n");
return PTR_ERR(phy);
diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c
index 6a9bef138617..943e0f88a120 100644
--- a/drivers/phy/phy-exynos-mipi-video.c
+++ b/drivers/phy/phy-exynos-mipi-video.c
@@ -137,7 +137,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
struct phy *phy = devm_phy_create(dev, NULL,
- &exynos_mipi_video_phy_ops, NULL);
+ &exynos_mipi_video_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY %d\n", i);
return PTR_ERR(phy);
diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c
index f756aca871db..04374018425f 100644
--- a/drivers/phy/phy-exynos5-usbdrd.c
+++ b/drivers/phy/phy-exynos5-usbdrd.c
@@ -141,6 +141,7 @@ struct exynos5_usbdrd_phy_drvdata {
const struct exynos5_usbdrd_phy_config *phy_cfg;
u32 pmu_offset_usbdrd0_phy;
u32 pmu_offset_usbdrd1_phy;
+ bool has_common_clk_gate;
};
/**
@@ -148,6 +149,9 @@ struct exynos5_usbdrd_phy_drvdata {
* @dev: pointer to device instance of this platform device
* @reg_phy: usb phy controller register memory base
* @clk: phy clock for register access
+ * @pipeclk: clock for pipe3 phy
+ * @utmiclk: clock for utmi+ phy
+ * @itpclk: clock for ITP generation
* @drv_data: pointer to SoC level driver data structure
* @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY
* instances each with its 'phy' and 'phy_cfg'.
@@ -155,12 +159,16 @@ struct exynos5_usbdrd_phy_drvdata {
* reference clocks' for SS and HS operations
* @ref_clk: reference clock to PHY block from which PHY's
* operational clocks are derived
- * @ref_rate: rate of above reference clock
+ * vbus: VBUS regulator for phy
+ * vbus_boost: Boost regulator for VBUS present on few Exynos boards
*/
struct exynos5_usbdrd_phy {
struct device *dev;
void __iomem *reg_phy;
struct clk *clk;
+ struct clk *pipeclk;
+ struct clk *utmiclk;
+ struct clk *itpclk;
const struct exynos5_usbdrd_phy_drvdata *drv_data;
struct phy_usb_instance {
struct phy *phy;
@@ -172,6 +180,7 @@ struct exynos5_usbdrd_phy {
u32 extrefclk;
struct clk *ref_clk;
struct regulator *vbus;
+ struct regulator *vbus_boost;
};
static inline
@@ -447,13 +456,27 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy)
dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n");
clk_prepare_enable(phy_drd->ref_clk);
+ if (!phy_drd->drv_data->has_common_clk_gate) {
+ clk_prepare_enable(phy_drd->pipeclk);
+ clk_prepare_enable(phy_drd->utmiclk);
+ clk_prepare_enable(phy_drd->itpclk);
+ }
/* Enable VBUS supply */
+ if (phy_drd->vbus_boost) {
+ ret = regulator_enable(phy_drd->vbus_boost);
+ if (ret) {
+ dev_err(phy_drd->dev,
+ "Failed to enable VBUS boost supply\n");
+ goto fail_vbus;
+ }
+ }
+
if (phy_drd->vbus) {
ret = regulator_enable(phy_drd->vbus);
if (ret) {
dev_err(phy_drd->dev, "Failed to enable VBUS supply\n");
- goto fail_vbus;
+ goto fail_vbus_boost;
}
}
@@ -462,8 +485,17 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy)
return 0;
+fail_vbus_boost:
+ if (phy_drd->vbus_boost)
+ regulator_disable(phy_drd->vbus_boost);
+
fail_vbus:
clk_disable_unprepare(phy_drd->ref_clk);
+ if (!phy_drd->drv_data->has_common_clk_gate) {
+ clk_disable_unprepare(phy_drd->itpclk);
+ clk_disable_unprepare(phy_drd->utmiclk);
+ clk_disable_unprepare(phy_drd->pipeclk);
+ }
return ret;
}
@@ -481,8 +513,15 @@ static int exynos5_usbdrd_phy_power_off(struct phy *phy)
/* Disable VBUS supply */
if (phy_drd->vbus)
regulator_disable(phy_drd->vbus);
+ if (phy_drd->vbus_boost)
+ regulator_disable(phy_drd->vbus_boost);
clk_disable_unprepare(phy_drd->ref_clk);
+ if (!phy_drd->drv_data->has_common_clk_gate) {
+ clk_disable_unprepare(phy_drd->itpclk);
+ clk_disable_unprepare(phy_drd->pipeclk);
+ clk_disable_unprepare(phy_drd->utmiclk);
+ }
return 0;
}
@@ -506,6 +545,57 @@ static struct phy_ops exynos5_usbdrd_phy_ops = {
.owner = THIS_MODULE,
};
+static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd)
+{
+ unsigned long ref_rate;
+ int ret;
+
+ phy_drd->clk = devm_clk_get(phy_drd->dev, "phy");
+ if (IS_ERR(phy_drd->clk)) {
+ dev_err(phy_drd->dev, "Failed to get phy clock\n");
+ return PTR_ERR(phy_drd->clk);
+ }
+
+ phy_drd->ref_clk = devm_clk_get(phy_drd->dev, "ref");
+ if (IS_ERR(phy_drd->ref_clk)) {
+ dev_err(phy_drd->dev, "Failed to get phy reference clock\n");
+ return PTR_ERR(phy_drd->ref_clk);
+ }
+ ref_rate = clk_get_rate(phy_drd->ref_clk);
+
+ ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk);
+ if (ret) {
+ dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n",
+ ref_rate);
+ return ret;
+ }
+
+ if (!phy_drd->drv_data->has_common_clk_gate) {
+ phy_drd->pipeclk = devm_clk_get(phy_drd->dev, "phy_pipe");
+ if (IS_ERR(phy_drd->pipeclk)) {
+ dev_info(phy_drd->dev,
+ "PIPE3 phy operational clock not specified\n");
+ phy_drd->pipeclk = NULL;
+ }
+
+ phy_drd->utmiclk = devm_clk_get(phy_drd->dev, "phy_utmi");
+ if (IS_ERR(phy_drd->utmiclk)) {
+ dev_info(phy_drd->dev,
+ "UTMI phy operational clock not specified\n");
+ phy_drd->utmiclk = NULL;
+ }
+
+ phy_drd->itpclk = devm_clk_get(phy_drd->dev, "itp");
+ if (IS_ERR(phy_drd->itpclk)) {
+ dev_info(phy_drd->dev,
+ "ITP clock from main OSC not specified\n");
+ phy_drd->itpclk = NULL;
+ }
+ }
+
+ return 0;
+}
+
static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = {
{
.id = EXYNOS5_DRDPHY_UTMI,
@@ -525,11 +615,19 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = {
.phy_cfg = phy_cfg_exynos5,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
.pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL,
+ .has_common_clk_gate = true,
};
static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = {
.phy_cfg = phy_cfg_exynos5,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
+ .has_common_clk_gate = true,
+};
+
+static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = {
+ .phy_cfg = phy_cfg_exynos5,
+ .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
+ .has_common_clk_gate = false,
};
static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
@@ -539,6 +637,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
}, {
.compatible = "samsung,exynos5420-usbdrd-phy",
.data = &exynos5420_usbdrd_phy
+ }, {
+ .compatible = "samsung,exynos7-usbdrd-phy",
+ .data = &exynos7_usbdrd_phy
},
{ },
};
@@ -555,7 +656,6 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
const struct exynos5_usbdrd_phy_drvdata *drv_data;
struct regmap *reg_pmu;
u32 pmu_offset;
- unsigned long ref_rate;
int i, ret;
int channel;
@@ -576,23 +676,9 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
drv_data = match->data;
phy_drd->drv_data = drv_data;
- phy_drd->clk = devm_clk_get(dev, "phy");
- if (IS_ERR(phy_drd->clk)) {
- dev_err(dev, "Failed to get clock of phy controller\n");
- return PTR_ERR(phy_drd->clk);
- }
-
- phy_drd->ref_clk = devm_clk_get(dev, "ref");
- if (IS_ERR(phy_drd->ref_clk)) {
- dev_err(dev, "Failed to get reference clock of usbdrd phy\n");
- return PTR_ERR(phy_drd->ref_clk);
- }
- ref_rate = clk_get_rate(phy_drd->ref_clk);
-
- ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk);
+ ret = exynos5_usbdrd_phy_clk_handle(phy_drd);
if (ret) {
- dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n",
- ref_rate);
+ dev_err(dev, "Failed to initialize clocks\n");
return ret;
}
@@ -622,7 +708,7 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
break;
}
- /* Get Vbus regulator */
+ /* Get Vbus regulators */
phy_drd->vbus = devm_regulator_get(dev, "vbus");
if (IS_ERR(phy_drd->vbus)) {
ret = PTR_ERR(phy_drd->vbus);
@@ -633,12 +719,21 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
phy_drd->vbus = NULL;
}
+ phy_drd->vbus_boost = devm_regulator_get(dev, "vbus-boost");
+ if (IS_ERR(phy_drd->vbus_boost)) {
+ ret = PTR_ERR(phy_drd->vbus_boost);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ dev_warn(dev, "Failed to get VBUS boost supply regulator\n");
+ phy_drd->vbus_boost = NULL;
+ }
+
dev_vdbg(dev, "Creating usbdrd_phy phy\n");
for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) {
struct phy *phy = devm_phy_create(dev, NULL,
- &exynos5_usbdrd_phy_ops,
- NULL);
+ &exynos5_usbdrd_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "Failed to create usbdrd_phy phy\n");
return PTR_ERR(phy);
diff --git a/drivers/phy/phy-exynos5250-sata.c b/drivers/phy/phy-exynos5250-sata.c
index 54cf4ae60d29..bc858cc800a1 100644
--- a/drivers/phy/phy-exynos5250-sata.c
+++ b/drivers/phy/phy-exynos5250-sata.c
@@ -210,7 +210,7 @@ static int exynos_sata_phy_probe(struct platform_device *pdev)
return ret;
}
- sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops, NULL);
+ sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops);
if (IS_ERR(sata_phy->phy)) {
clk_disable_unprepare(sata_phy->phyclk);
dev_err(dev, "failed to create PHY\n");
diff --git a/drivers/phy/phy-hix5hd2-sata.c b/drivers/phy/phy-hix5hd2-sata.c
index d5d978085c6d..34915b4202f1 100644
--- a/drivers/phy/phy-hix5hd2-sata.c
+++ b/drivers/phy/phy-hix5hd2-sata.c
@@ -156,7 +156,7 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev)
if (IS_ERR(priv->peri_ctrl))
priv->peri_ctrl = NULL;
- phy = devm_phy_create(dev, NULL, &hix5hd2_sata_phy_ops, NULL);
+ phy = devm_phy_create(dev, NULL, &hix5hd2_sata_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY\n");
return PTR_ERR(phy);
@@ -164,10 +164,7 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev)
phy_set_drvdata(phy, priv);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
-
- return 0;
+ return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id hix5hd2_sata_phy_of_match[] = {
diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c
new file mode 100644
index 000000000000..e34da13885e8
--- /dev/null
+++ b/drivers/phy/phy-miphy28lp.c
@@ -0,0 +1,1283 @@
+/*
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * STMicroelectronics PHY driver MiPHY28lp (for SoC STiH407).
+ *
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ *
+ * 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/platform_device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/phy/phy.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include <dt-bindings/phy/phy.h>
+
+/* MiPHY registers */
+#define MIPHY_CONF_RESET 0x00
+#define RST_APPLI_SW BIT(0)
+#define RST_CONF_SW BIT(1)
+#define RST_MACRO_SW BIT(2)
+
+#define MIPHY_RESET 0x01
+#define RST_PLL_SW BIT(0)
+#define RST_COMP_SW BIT(2)
+
+#define MIPHY_STATUS_1 0x02
+#define PHY_RDY BIT(0)
+#define HFC_RDY BIT(1)
+#define HFC_PLL BIT(2)
+
+#define MIPHY_CONTROL 0x04
+#define TERM_EN_SW BIT(2)
+#define DIS_LINK_RST BIT(3)
+#define AUTO_RST_RX BIT(4)
+#define PX_RX_POL BIT(5)
+
+#define MIPHY_BOUNDARY_SEL 0x0a
+#define TX_SEL BIT(6)
+#define SSC_SEL BIT(4)
+#define GENSEL_SEL BIT(0)
+
+#define MIPHY_BOUNDARY_1 0x0b
+#define MIPHY_BOUNDARY_2 0x0c
+#define SSC_EN_SW BIT(2)
+
+#define MIPHY_PLL_CLKREF_FREQ 0x0d
+#define MIPHY_SPEED 0x0e
+#define TX_SPDSEL_80DEC 0
+#define TX_SPDSEL_40DEC 1
+#define TX_SPDSEL_20DEC 2
+#define RX_SPDSEL_80DEC 0
+#define RX_SPDSEL_40DEC (1 << 2)
+#define RX_SPDSEL_20DEC (2 << 2)
+
+#define MIPHY_CONF 0x0f
+#define MIPHY_CTRL_TEST_SEL 0x20
+#define MIPHY_CTRL_TEST_1 0x21
+#define MIPHY_CTRL_TEST_2 0x22
+#define MIPHY_CTRL_TEST_3 0x23
+#define MIPHY_CTRL_TEST_4 0x24
+#define MIPHY_FEEDBACK_TEST 0x25
+#define MIPHY_DEBUG_BUS 0x26
+#define MIPHY_DEBUG_STATUS_MSB 0x27
+#define MIPHY_DEBUG_STATUS_LSB 0x28
+#define MIPHY_PWR_RAIL_1 0x29
+#define MIPHY_PWR_RAIL_2 0x2a
+#define MIPHY_SYNCHAR_CONTROL 0x30
+
+#define MIPHY_COMP_FSM_1 0x3a
+#define COMP_START BIT(6)
+
+#define MIPHY_COMP_FSM_6 0x3f
+#define COMP_DONE BIT(7)
+
+#define MIPHY_COMP_POSTP 0x42
+#define MIPHY_TX_CTRL_1 0x49
+#define TX_REG_STEP_0V 0
+#define TX_REG_STEP_P_25MV 1
+#define TX_REG_STEP_P_50MV 2
+#define TX_REG_STEP_N_25MV 7
+#define TX_REG_STEP_N_50MV 6
+#define TX_REG_STEP_N_75MV 5
+
+#define MIPHY_TX_CTRL_2 0x4a
+#define TX_SLEW_SW_40_PS 0
+#define TX_SLEW_SW_80_PS 1
+#define TX_SLEW_SW_120_PS 2
+
+#define MIPHY_TX_CTRL_3 0x4b
+#define MIPHY_TX_CAL_MAN 0x4e
+#define TX_SLEW_CAL_MAN_EN BIT(0)
+
+#define MIPHY_TST_BIAS_BOOST_2 0x62
+#define MIPHY_BIAS_BOOST_1 0x63
+#define MIPHY_BIAS_BOOST_2 0x64
+#define MIPHY_RX_DESBUFF_FDB_2 0x67
+#define MIPHY_RX_DESBUFF_FDB_3 0x68
+#define MIPHY_SIGDET_COMPENS1 0x69
+#define MIPHY_SIGDET_COMPENS2 0x6a
+#define MIPHY_JITTER_PERIOD 0x6b
+#define MIPHY_JITTER_AMPLITUDE_1 0x6c
+#define MIPHY_JITTER_AMPLITUDE_2 0x6d
+#define MIPHY_JITTER_AMPLITUDE_3 0x6e
+#define MIPHY_RX_K_GAIN 0x78
+#define MIPHY_RX_BUFFER_CTRL 0x7a
+#define VGA_GAIN BIT(0)
+#define EQ_DC_GAIN BIT(2)
+#define EQ_BOOST_GAIN BIT(3)
+
+#define MIPHY_RX_VGA_GAIN 0x7b
+#define MIPHY_RX_EQU_GAIN_1 0x7f
+#define MIPHY_RX_EQU_GAIN_2 0x80
+#define MIPHY_RX_EQU_GAIN_3 0x81
+#define MIPHY_RX_CAL_CTRL_1 0x97
+#define MIPHY_RX_CAL_CTRL_2 0x98
+
+#define MIPHY_RX_CAL_OFFSET_CTRL 0x99
+#define CAL_OFFSET_VGA_64 (0x03 << 0)
+#define CAL_OFFSET_THRESHOLD_64 (0x03 << 2)
+#define VGA_OFFSET_POLARITY BIT(4)
+#define OFFSET_COMPENSATION_EN BIT(6)
+
+#define MIPHY_RX_CAL_VGA_STEP 0x9a
+#define MIPHY_RX_CAL_EYE_MIN 0x9d
+#define MIPHY_RX_CAL_OPT_LENGTH 0x9f
+#define MIPHY_RX_LOCK_CTRL_1 0xc1
+#define MIPHY_RX_LOCK_SETTINGS_OPT 0xc2
+#define MIPHY_RX_LOCK_STEP 0xc4
+
+#define MIPHY_RX_SIGDET_SLEEP_OA 0xc9
+#define MIPHY_RX_SIGDET_SLEEP_SEL 0xca
+#define MIPHY_RX_SIGDET_WAIT_SEL 0xcb
+#define MIPHY_RX_SIGDET_DATA_SEL 0xcc
+#define EN_ULTRA_LOW_POWER BIT(0)
+#define EN_FIRST_HALF BIT(1)
+#define EN_SECOND_HALF BIT(2)
+#define EN_DIGIT_SIGNAL_CHECK BIT(3)
+
+#define MIPHY_RX_POWER_CTRL_1 0xcd
+#define MIPHY_RX_POWER_CTRL_2 0xce
+#define MIPHY_PLL_CALSET_CTRL 0xd3
+#define MIPHY_PLL_CALSET_1 0xd4
+#define MIPHY_PLL_CALSET_2 0xd5
+#define MIPHY_PLL_CALSET_3 0xd6
+#define MIPHY_PLL_CALSET_4 0xd7
+#define MIPHY_PLL_SBR_1 0xe3
+#define SET_NEW_CHANGE BIT(1)
+
+#define MIPHY_PLL_SBR_2 0xe4
+#define MIPHY_PLL_SBR_3 0xe5
+#define MIPHY_PLL_SBR_4 0xe6
+#define MIPHY_PLL_COMMON_MISC_2 0xe9
+#define START_ACT_FILT BIT(6)
+
+#define MIPHY_PLL_SPAREIN 0xeb
+
+/*
+ * On STiH407 the glue logic can be different among MiPHY devices; for example:
+ * MiPHY0: OSC_FORCE_EXT means:
+ * 0: 30MHz crystal clk - 1: 100MHz ext clk routed through MiPHY1
+ * MiPHY1: OSC_FORCE_EXT means:
+ * 1: 30MHz crystal clk - 0: 100MHz ext clk routed through MiPHY1
+ * Some devices have not the possibility to check if the osc is ready.
+ */
+#define MIPHY_OSC_FORCE_EXT BIT(3)
+#define MIPHY_OSC_RDY BIT(5)
+
+#define MIPHY_CTRL_MASK 0x0f
+#define MIPHY_CTRL_DEFAULT 0
+#define MIPHY_CTRL_SYNC_D_EN BIT(2)
+
+/* SATA / PCIe defines */
+#define SATA_CTRL_MASK 0x07
+#define PCIE_CTRL_MASK 0xff
+#define SATA_CTRL_SELECT_SATA 1
+#define SATA_CTRL_SELECT_PCIE 0
+#define SYSCFG_PCIE_PCIE_VAL 0x80
+#define SATA_SPDMODE 1
+
+#define MIPHY_SATA_BANK_NB 3
+#define MIPHY_PCIE_BANK_NB 2
+
+struct miphy28lp_phy {
+ struct phy *phy;
+ struct miphy28lp_dev *phydev;
+ void __iomem *base;
+ void __iomem *pipebase;
+
+ bool osc_force_ext;
+ bool osc_rdy;
+ bool px_rx_pol_inv;
+ bool ssc;
+ bool tx_impedance;
+
+ struct reset_control *miphy_rst;
+
+ u32 sata_gen;
+
+ /* Sysconfig registers offsets needed to configure the device */
+ u32 syscfg_miphy_ctrl;
+ u32 syscfg_miphy_status;
+ u32 syscfg_pci;
+ u32 syscfg_sata;
+ u8 type;
+};
+
+struct miphy28lp_dev {
+ struct device *dev;
+ struct regmap *regmap;
+ struct mutex miphy_mutex;
+ struct miphy28lp_phy **phys;
+};
+
+struct miphy_initval {
+ u16 reg;
+ u16 val;
+};
+
+enum miphy_sata_gen { SATA_GEN1, SATA_GEN2, SATA_GEN3 };
+
+static char *PHY_TYPE_name[] = { "sata-up", "pcie-up", "", "usb3-up" };
+
+struct pll_ratio {
+ int clk_ref;
+ int calset_1;
+ int calset_2;
+ int calset_3;
+ int calset_4;
+ int cal_ctrl;
+};
+
+static struct pll_ratio sata_pll_ratio = {
+ .clk_ref = 0x1e,
+ .calset_1 = 0xc8,
+ .calset_2 = 0x00,
+ .calset_3 = 0x00,
+ .calset_4 = 0x00,
+ .cal_ctrl = 0x00,
+};
+
+static struct pll_ratio pcie_pll_ratio = {
+ .clk_ref = 0x1e,
+ .calset_1 = 0xa6,
+ .calset_2 = 0xaa,
+ .calset_3 = 0xaa,
+ .calset_4 = 0x00,
+ .cal_ctrl = 0x00,
+};
+
+static struct pll_ratio usb3_pll_ratio = {
+ .clk_ref = 0x1e,
+ .calset_1 = 0xa6,
+ .calset_2 = 0xaa,
+ .calset_3 = 0xaa,
+ .calset_4 = 0x04,
+ .cal_ctrl = 0x00,
+};
+
+struct miphy28lp_pll_gen {
+ int bank;
+ int speed;
+ int bias_boost_1;
+ int bias_boost_2;
+ int tx_ctrl_1;
+ int tx_ctrl_2;
+ int tx_ctrl_3;
+ int rx_k_gain;
+ int rx_vga_gain;
+ int rx_equ_gain_1;
+ int rx_equ_gain_2;
+ int rx_equ_gain_3;
+ int rx_buff_ctrl;
+};
+
+static struct miphy28lp_pll_gen sata_pll_gen[] = {
+ {
+ .bank = 0x00,
+ .speed = TX_SPDSEL_80DEC | RX_SPDSEL_80DEC,
+ .bias_boost_1 = 0x00,
+ .bias_boost_2 = 0xae,
+ .tx_ctrl_2 = 0x53,
+ .tx_ctrl_3 = 0x00,
+ .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN,
+ .rx_vga_gain = 0x00,
+ .rx_equ_gain_1 = 0x7d,
+ .rx_equ_gain_2 = 0x56,
+ .rx_equ_gain_3 = 0x00,
+ },
+ {
+ .bank = 0x01,
+ .speed = TX_SPDSEL_40DEC | RX_SPDSEL_40DEC,
+ .bias_boost_1 = 0x00,
+ .bias_boost_2 = 0xae,
+ .tx_ctrl_2 = 0x72,
+ .tx_ctrl_3 = 0x20,
+ .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN,
+ .rx_vga_gain = 0x00,
+ .rx_equ_gain_1 = 0x7d,
+ .rx_equ_gain_2 = 0x56,
+ .rx_equ_gain_3 = 0x00,
+ },
+ {
+ .bank = 0x02,
+ .speed = TX_SPDSEL_20DEC | RX_SPDSEL_20DEC,
+ .bias_boost_1 = 0x00,
+ .bias_boost_2 = 0xae,
+ .tx_ctrl_2 = 0xc0,
+ .tx_ctrl_3 = 0x20,
+ .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN,
+ .rx_vga_gain = 0x00,
+ .rx_equ_gain_1 = 0x7d,
+ .rx_equ_gain_2 = 0x56,
+ .rx_equ_gain_3 = 0x00,
+ },
+};
+
+static struct miphy28lp_pll_gen pcie_pll_gen[] = {
+ {
+ .bank = 0x00,
+ .speed = TX_SPDSEL_40DEC | RX_SPDSEL_40DEC,
+ .bias_boost_1 = 0x00,
+ .bias_boost_2 = 0xa5,
+ .tx_ctrl_1 = TX_REG_STEP_N_25MV,
+ .tx_ctrl_2 = 0x71,
+ .tx_ctrl_3 = 0x60,
+ .rx_k_gain = 0x98,
+ .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN,
+ .rx_vga_gain = 0x00,
+ .rx_equ_gain_1 = 0x79,
+ .rx_equ_gain_2 = 0x56,
+ },
+ {
+ .bank = 0x01,
+ .speed = TX_SPDSEL_20DEC | RX_SPDSEL_20DEC,
+ .bias_boost_1 = 0x00,
+ .bias_boost_2 = 0xa5,
+ .tx_ctrl_1 = TX_REG_STEP_N_25MV,
+ .tx_ctrl_2 = 0x70,
+ .tx_ctrl_3 = 0x60,
+ .rx_k_gain = 0xcc,
+ .rx_buff_ctrl = EQ_BOOST_GAIN | EQ_DC_GAIN | VGA_GAIN,
+ .rx_vga_gain = 0x00,
+ .rx_equ_gain_1 = 0x78,
+ .rx_equ_gain_2 = 0x07,
+ },
+};
+
+static inline void miphy28lp_set_reset(struct miphy28lp_phy *miphy_phy)
+{
+ void *base = miphy_phy->base;
+ u8 val;
+
+ /* Putting Macro in reset */
+ writeb_relaxed(RST_APPLI_SW, base + MIPHY_CONF_RESET);
+
+ val = RST_APPLI_SW | RST_CONF_SW;
+ writeb_relaxed(val, base + MIPHY_CONF_RESET);
+
+ writeb_relaxed(RST_APPLI_SW, base + MIPHY_CONF_RESET);
+
+ /* Bringing the MIPHY-CPU registers out of reset */
+ if (miphy_phy->type == PHY_TYPE_PCIE) {
+ val = AUTO_RST_RX | TERM_EN_SW;
+ writeb_relaxed(val, base + MIPHY_CONTROL);
+ } else {
+ val = AUTO_RST_RX | TERM_EN_SW | DIS_LINK_RST;
+ writeb_relaxed(val, base + MIPHY_CONTROL);
+ }
+}
+
+static inline void miphy28lp_pll_calibration(struct miphy28lp_phy *miphy_phy,
+ struct pll_ratio *pll_ratio)
+{
+ void *base = miphy_phy->base;
+ u8 val;
+
+ /* Applying PLL Settings */
+ writeb_relaxed(0x1d, base + MIPHY_PLL_SPAREIN);
+ writeb_relaxed(pll_ratio->clk_ref, base + MIPHY_PLL_CLKREF_FREQ);
+
+ /* PLL Ratio */
+ writeb_relaxed(pll_ratio->calset_1, base + MIPHY_PLL_CALSET_1);
+ writeb_relaxed(pll_ratio->calset_2, base + MIPHY_PLL_CALSET_2);
+ writeb_relaxed(pll_ratio->calset_3, base + MIPHY_PLL_CALSET_3);
+ writeb_relaxed(pll_ratio->calset_4, base + MIPHY_PLL_CALSET_4);
+ writeb_relaxed(pll_ratio->cal_ctrl, base + MIPHY_PLL_CALSET_CTRL);
+
+ writeb_relaxed(TX_SEL, base + MIPHY_BOUNDARY_SEL);
+
+ val = (0x68 << 1) | TX_SLEW_CAL_MAN_EN;
+ writeb_relaxed(val, base + MIPHY_TX_CAL_MAN);
+
+ val = VGA_OFFSET_POLARITY | CAL_OFFSET_THRESHOLD_64 | CAL_OFFSET_VGA_64;
+
+ if (miphy_phy->type != PHY_TYPE_SATA)
+ val |= OFFSET_COMPENSATION_EN;
+
+ writeb_relaxed(val, base + MIPHY_RX_CAL_OFFSET_CTRL);
+
+ if (miphy_phy->type == PHY_TYPE_USB3) {
+ writeb_relaxed(0x00, base + MIPHY_CONF);
+ writeb_relaxed(0x70, base + MIPHY_RX_LOCK_STEP);
+ writeb_relaxed(EN_FIRST_HALF, base + MIPHY_RX_SIGDET_SLEEP_OA);
+ writeb_relaxed(EN_FIRST_HALF, base + MIPHY_RX_SIGDET_SLEEP_SEL);
+ writeb_relaxed(EN_FIRST_HALF, base + MIPHY_RX_SIGDET_WAIT_SEL);
+
+ val = EN_DIGIT_SIGNAL_CHECK | EN_FIRST_HALF;
+ writeb_relaxed(val, base + MIPHY_RX_SIGDET_DATA_SEL);
+ }
+
+}
+
+static inline void miphy28lp_sata_config_gen(struct miphy28lp_phy *miphy_phy)
+{
+ void __iomem *base = miphy_phy->base;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sata_pll_gen); i++) {
+ struct miphy28lp_pll_gen *gen = &sata_pll_gen[i];
+
+ /* Banked settings */
+ writeb_relaxed(gen->bank, base + MIPHY_CONF);
+ writeb_relaxed(gen->speed, base + MIPHY_SPEED);
+ writeb_relaxed(gen->bias_boost_1, base + MIPHY_BIAS_BOOST_1);
+ writeb_relaxed(gen->bias_boost_2, base + MIPHY_BIAS_BOOST_2);
+
+ /* TX buffer Settings */
+ writeb_relaxed(gen->tx_ctrl_2, base + MIPHY_TX_CTRL_2);
+ writeb_relaxed(gen->tx_ctrl_3, base + MIPHY_TX_CTRL_3);
+
+ /* RX Buffer Settings */
+ writeb_relaxed(gen->rx_buff_ctrl, base + MIPHY_RX_BUFFER_CTRL);
+ writeb_relaxed(gen->rx_vga_gain, base + MIPHY_RX_VGA_GAIN);
+ writeb_relaxed(gen->rx_equ_gain_1, base + MIPHY_RX_EQU_GAIN_1);
+ writeb_relaxed(gen->rx_equ_gain_2, base + MIPHY_RX_EQU_GAIN_2);
+ writeb_relaxed(gen->rx_equ_gain_3, base + MIPHY_RX_EQU_GAIN_3);
+ }
+}
+
+static inline void miphy28lp_pcie_config_gen(struct miphy28lp_phy *miphy_phy)
+{
+ void __iomem *base = miphy_phy->base;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pcie_pll_gen); i++) {
+ struct miphy28lp_pll_gen *gen = &pcie_pll_gen[i];
+
+ /* Banked settings */
+ writeb_relaxed(gen->bank, base + MIPHY_CONF);
+ writeb_relaxed(gen->speed, base + MIPHY_SPEED);
+ writeb_relaxed(gen->bias_boost_1, base + MIPHY_BIAS_BOOST_1);
+ writeb_relaxed(gen->bias_boost_2, base + MIPHY_BIAS_BOOST_2);
+
+ /* TX buffer Settings */
+ writeb_relaxed(gen->tx_ctrl_1, base + MIPHY_TX_CTRL_1);
+ writeb_relaxed(gen->tx_ctrl_2, base + MIPHY_TX_CTRL_2);
+ writeb_relaxed(gen->tx_ctrl_3, base + MIPHY_TX_CTRL_3);
+
+ writeb_relaxed(gen->rx_k_gain, base + MIPHY_RX_K_GAIN);
+
+ /* RX Buffer Settings */
+ writeb_relaxed(gen->rx_buff_ctrl, base + MIPHY_RX_BUFFER_CTRL);
+ writeb_relaxed(gen->rx_vga_gain, base + MIPHY_RX_VGA_GAIN);
+ writeb_relaxed(gen->rx_equ_gain_1, base + MIPHY_RX_EQU_GAIN_1);
+ writeb_relaxed(gen->rx_equ_gain_2, base + MIPHY_RX_EQU_GAIN_2);
+ }
+}
+
+static inline int miphy28lp_wait_compensation(struct miphy28lp_phy *miphy_phy)
+{
+ unsigned long finish = jiffies + 5 * HZ;
+ u8 val;
+
+ /* Waiting for Compensation to complete */
+ do {
+ val = readb_relaxed(miphy_phy->base + MIPHY_COMP_FSM_6);
+
+ if (time_after_eq(jiffies, finish))
+ return -EBUSY;
+ cpu_relax();
+ } while (!(val & COMP_DONE));
+
+ return 0;
+}
+
+
+static inline int miphy28lp_compensation(struct miphy28lp_phy *miphy_phy,
+ struct pll_ratio *pll_ratio)
+{
+ void __iomem *base = miphy_phy->base;
+
+ /* Poll for HFC ready after reset release */
+ /* Compensation measurement */
+ writeb_relaxed(RST_PLL_SW | RST_COMP_SW, base + MIPHY_RESET);
+
+ writeb_relaxed(0x00, base + MIPHY_PLL_COMMON_MISC_2);
+ writeb_relaxed(pll_ratio->clk_ref, base + MIPHY_PLL_CLKREF_FREQ);
+ writeb_relaxed(COMP_START, base + MIPHY_COMP_FSM_1);
+
+ if (miphy_phy->type == PHY_TYPE_PCIE)
+ writeb_relaxed(RST_PLL_SW, base + MIPHY_RESET);
+
+ writeb_relaxed(0x00, base + MIPHY_RESET);
+ writeb_relaxed(START_ACT_FILT, base + MIPHY_PLL_COMMON_MISC_2);
+ writeb_relaxed(SET_NEW_CHANGE, base + MIPHY_PLL_SBR_1);
+
+ /* TX compensation offset to re-center TX impedance */
+ writeb_relaxed(0x00, base + MIPHY_COMP_POSTP);
+
+ if (miphy_phy->type == PHY_TYPE_PCIE)
+ return miphy28lp_wait_compensation(miphy_phy);
+
+ return 0;
+}
+
+static inline void miphy28_usb3_miphy_reset(struct miphy28lp_phy *miphy_phy)
+{
+ void __iomem *base = miphy_phy->base;
+ u8 val;
+
+ /* MIPHY Reset */
+ writeb_relaxed(RST_APPLI_SW, base + MIPHY_CONF_RESET);
+ writeb_relaxed(0x00, base + MIPHY_CONF_RESET);
+ writeb_relaxed(RST_COMP_SW, base + MIPHY_RESET);
+
+ val = RST_COMP_SW | RST_PLL_SW;
+ writeb_relaxed(val, base + MIPHY_RESET);
+
+ writeb_relaxed(0x00, base + MIPHY_PLL_COMMON_MISC_2);
+ writeb_relaxed(0x1e, base + MIPHY_PLL_CLKREF_FREQ);
+ writeb_relaxed(COMP_START, base + MIPHY_COMP_FSM_1);
+ writeb_relaxed(RST_PLL_SW, base + MIPHY_RESET);
+ writeb_relaxed(0x00, base + MIPHY_RESET);
+ writeb_relaxed(START_ACT_FILT, base + MIPHY_PLL_COMMON_MISC_2);
+ writeb_relaxed(0x00, base + MIPHY_CONF);
+ writeb_relaxed(0x00, base + MIPHY_BOUNDARY_1);
+ writeb_relaxed(0x00, base + MIPHY_TST_BIAS_BOOST_2);
+ writeb_relaxed(0x00, base + MIPHY_CONF);
+ writeb_relaxed(SET_NEW_CHANGE, base + MIPHY_PLL_SBR_1);
+ writeb_relaxed(0xa5, base + MIPHY_DEBUG_BUS);
+ writeb_relaxed(0x00, base + MIPHY_CONF);
+}
+
+static void miphy_sata_tune_ssc(struct miphy28lp_phy *miphy_phy)
+{
+ void __iomem *base = miphy_phy->base;
+ u8 val;
+
+ /* Compensate Tx impedance to avoid out of range values */
+ /*
+ * Enable the SSC on PLL for all banks
+ * SSC Modulation @ 31 KHz and 4000 ppm modulation amp
+ */
+ val = readb_relaxed(base + MIPHY_BOUNDARY_2);
+ val |= SSC_EN_SW;
+ writeb_relaxed(val, base + MIPHY_BOUNDARY_2);
+
+ val = readb_relaxed(base + MIPHY_BOUNDARY_SEL);
+ val |= SSC_SEL;
+ writeb_relaxed(val, base + MIPHY_BOUNDARY_SEL);
+
+ for (val = 0; val < MIPHY_SATA_BANK_NB; val++) {
+ writeb_relaxed(val, base + MIPHY_CONF);
+
+ /* Add value to each reference clock cycle */
+ /* and define the period length of the SSC */
+ writeb_relaxed(0x3c, base + MIPHY_PLL_SBR_2);
+ writeb_relaxed(0x6c, base + MIPHY_PLL_SBR_3);
+ writeb_relaxed(0x81, base + MIPHY_PLL_SBR_4);
+
+ /* Clear any previous request */
+ writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1);
+
+ /* requests the PLL to take in account new parameters */
+ writeb_relaxed(SET_NEW_CHANGE, base + MIPHY_PLL_SBR_1);
+
+ /* To be sure there is no other pending requests */
+ writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1);
+ }
+}
+
+static void miphy_pcie_tune_ssc(struct miphy28lp_phy *miphy_phy)
+{
+ void __iomem *base = miphy_phy->base;
+ u8 val;
+
+ /* Compensate Tx impedance to avoid out of range values */
+ /*
+ * Enable the SSC on PLL for all banks
+ * SSC Modulation @ 31 KHz and 4000 ppm modulation amp
+ */
+ val = readb_relaxed(base + MIPHY_BOUNDARY_2);
+ val |= SSC_EN_SW;
+ writeb_relaxed(val, base + MIPHY_BOUNDARY_2);
+
+ val = readb_relaxed(base + MIPHY_BOUNDARY_SEL);
+ val |= SSC_SEL;
+ writeb_relaxed(val, base + MIPHY_BOUNDARY_SEL);
+
+ for (val = 0; val < MIPHY_PCIE_BANK_NB; val++) {
+ writeb_relaxed(val, base + MIPHY_CONF);
+
+ /* Validate Step component */
+ writeb_relaxed(0x69, base + MIPHY_PLL_SBR_3);
+ writeb_relaxed(0x21, base + MIPHY_PLL_SBR_4);
+
+ /* Validate Period component */
+ writeb_relaxed(0x3c, base + MIPHY_PLL_SBR_2);
+ writeb_relaxed(0x21, base + MIPHY_PLL_SBR_4);
+
+ /* Clear any previous request */
+ writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1);
+
+ /* requests the PLL to take in account new parameters */
+ writeb_relaxed(SET_NEW_CHANGE, base + MIPHY_PLL_SBR_1);
+
+ /* To be sure there is no other pending requests */
+ writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1);
+ }
+}
+
+static inline void miphy_tune_tx_impedance(struct miphy28lp_phy *miphy_phy)
+{
+ /* Compensate Tx impedance to avoid out of range values */
+ writeb_relaxed(0x02, miphy_phy->base + MIPHY_COMP_POSTP);
+}
+
+static inline int miphy28lp_configure_sata(struct miphy28lp_phy *miphy_phy)
+{
+ void __iomem *base = miphy_phy->base;
+ int err;
+ u8 val;
+
+ /* Putting Macro in reset */
+ miphy28lp_set_reset(miphy_phy);
+
+ /* PLL calibration */
+ miphy28lp_pll_calibration(miphy_phy, &sata_pll_ratio);
+
+ /* Banked settings Gen1/Gen2/Gen3 */
+ miphy28lp_sata_config_gen(miphy_phy);
+
+ /* Power control */
+ /* Input bridge enable, manual input bridge control */
+ writeb_relaxed(0x21, base + MIPHY_RX_POWER_CTRL_1);
+
+ /* Macro out of reset */
+ writeb_relaxed(0x00, base + MIPHY_CONF_RESET);
+
+ /* Poll for HFC ready after reset release */
+ /* Compensation measurement */
+ err = miphy28lp_compensation(miphy_phy, &sata_pll_ratio);
+ if (err)
+ return err;
+
+ if (miphy_phy->px_rx_pol_inv) {
+ /* Invert Rx polarity */
+ val = readb_relaxed(miphy_phy->base + MIPHY_CONTROL);
+ val |= PX_RX_POL;
+ writeb_relaxed(val, miphy_phy->base + MIPHY_CONTROL);
+ }
+
+ if (miphy_phy->ssc)
+ miphy_sata_tune_ssc(miphy_phy);
+
+ if (miphy_phy->tx_impedance)
+ miphy_tune_tx_impedance(miphy_phy);
+
+ return 0;
+}
+
+static inline int miphy28lp_configure_pcie(struct miphy28lp_phy *miphy_phy)
+{
+ void __iomem *base = miphy_phy->base;
+ int err;
+
+ /* Putting Macro in reset */
+ miphy28lp_set_reset(miphy_phy);
+
+ /* PLL calibration */
+ miphy28lp_pll_calibration(miphy_phy, &pcie_pll_ratio);
+
+ /* Banked settings Gen1/Gen2 */
+ miphy28lp_pcie_config_gen(miphy_phy);
+
+ /* Power control */
+ /* Input bridge enable, manual input bridge control */
+ writeb_relaxed(0x21, base + MIPHY_RX_POWER_CTRL_1);
+
+ /* Macro out of reset */
+ writeb_relaxed(0x00, base + MIPHY_CONF_RESET);
+
+ /* Poll for HFC ready after reset release */
+ /* Compensation measurement */
+ err = miphy28lp_compensation(miphy_phy, &pcie_pll_ratio);
+ if (err)
+ return err;
+
+ if (miphy_phy->ssc)
+ miphy_pcie_tune_ssc(miphy_phy);
+
+ if (miphy_phy->tx_impedance)
+ miphy_tune_tx_impedance(miphy_phy);
+
+ return 0;
+}
+
+
+static inline void miphy28lp_configure_usb3(struct miphy28lp_phy *miphy_phy)
+{
+ void __iomem *base = miphy_phy->base;
+ u8 val;
+
+ /* Putting Macro in reset */
+ miphy28lp_set_reset(miphy_phy);
+
+ /* PLL calibration */
+ miphy28lp_pll_calibration(miphy_phy, &usb3_pll_ratio);
+
+ /* Writing The Speed Rate */
+ writeb_relaxed(0x00, base + MIPHY_CONF);
+
+ val = RX_SPDSEL_20DEC | TX_SPDSEL_20DEC;
+ writeb_relaxed(val, base + MIPHY_SPEED);
+
+ /* RX Channel compensation and calibration */
+ writeb_relaxed(0x1c, base + MIPHY_RX_LOCK_SETTINGS_OPT);
+ writeb_relaxed(0x51, base + MIPHY_RX_CAL_CTRL_1);
+ writeb_relaxed(0x70, base + MIPHY_RX_CAL_CTRL_2);
+
+ val = OFFSET_COMPENSATION_EN | VGA_OFFSET_POLARITY |
+ CAL_OFFSET_THRESHOLD_64 | CAL_OFFSET_VGA_64;
+ writeb_relaxed(val, base + MIPHY_RX_CAL_OFFSET_CTRL);
+ writeb_relaxed(0x22, base + MIPHY_RX_CAL_VGA_STEP);
+ writeb_relaxed(0x0e, base + MIPHY_RX_CAL_OPT_LENGTH);
+
+ val = EQ_DC_GAIN | VGA_GAIN;
+ writeb_relaxed(val, base + MIPHY_RX_BUFFER_CTRL);
+ writeb_relaxed(0x78, base + MIPHY_RX_EQU_GAIN_1);
+ writeb_relaxed(0x1b, base + MIPHY_SYNCHAR_CONTROL);
+
+ /* TX compensation offset to re-center TX impedance */
+ writeb_relaxed(0x02, base + MIPHY_COMP_POSTP);
+
+ /* Enable GENSEL_SEL and SSC */
+ /* TX_SEL=0 swing preemp forced by pipe registres */
+ val = SSC_SEL | GENSEL_SEL;
+ writeb_relaxed(val, base + MIPHY_BOUNDARY_SEL);
+
+ /* MIPHY Bias boost */
+ writeb_relaxed(0x00, base + MIPHY_BIAS_BOOST_1);
+ writeb_relaxed(0xa7, base + MIPHY_BIAS_BOOST_2);
+
+ /* SSC modulation */
+ writeb_relaxed(SSC_EN_SW, base + MIPHY_BOUNDARY_2);
+
+ /* MIPHY TX control */
+ writeb_relaxed(0x00, base + MIPHY_CONF);
+
+ /* Validate Step component */
+ writeb_relaxed(0x5a, base + MIPHY_PLL_SBR_3);
+ writeb_relaxed(0xa0, base + MIPHY_PLL_SBR_4);
+
+ /* Validate Period component */
+ writeb_relaxed(0x3c, base + MIPHY_PLL_SBR_2);
+ writeb_relaxed(0xa1, base + MIPHY_PLL_SBR_4);
+
+ /* Clear any previous request */
+ writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1);
+
+ /* requests the PLL to take in account new parameters */
+ writeb_relaxed(0x02, base + MIPHY_PLL_SBR_1);
+
+ /* To be sure there is no other pending requests */
+ writeb_relaxed(0x00, base + MIPHY_PLL_SBR_1);
+
+ /* Rx PI controller settings */
+ writeb_relaxed(0xca, base + MIPHY_RX_K_GAIN);
+
+ /* MIPHY RX input bridge control */
+ /* INPUT_BRIDGE_EN_SW=1, manual input bridge control[0]=1 */
+ writeb_relaxed(0x21, base + MIPHY_RX_POWER_CTRL_1);
+ writeb_relaxed(0x29, base + MIPHY_RX_POWER_CTRL_1);
+ writeb_relaxed(0x1a, base + MIPHY_RX_POWER_CTRL_2);
+
+ /* MIPHY Reset for usb3 */
+ miphy28_usb3_miphy_reset(miphy_phy);
+}
+
+static inline int miphy_is_ready(struct miphy28lp_phy *miphy_phy)
+{
+ unsigned long finish = jiffies + 5 * HZ;
+ u8 mask = HFC_PLL | HFC_RDY;
+ u8 val;
+
+ /*
+ * For PCIe and USB3 check only that PLL and HFC are ready
+ * For SATA check also that phy is ready!
+ */
+ if (miphy_phy->type == PHY_TYPE_SATA)
+ mask |= PHY_RDY;
+
+ do {
+ val = readb_relaxed(miphy_phy->base + MIPHY_STATUS_1);
+ if ((val & mask) != mask)
+ cpu_relax();
+ else
+ return 0;
+ } while (!time_after_eq(jiffies, finish));
+
+ return -EBUSY;
+}
+
+static int miphy_osc_is_ready(struct miphy28lp_phy *miphy_phy)
+{
+ struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
+ unsigned long finish = jiffies + 5 * HZ;
+ u32 val;
+
+ if (!miphy_phy->osc_rdy)
+ return 0;
+
+ if (!miphy_phy->syscfg_miphy_status)
+ return -EINVAL;
+
+ do {
+ regmap_read(miphy_dev->regmap, miphy_phy->syscfg_miphy_status,
+ &val);
+
+ if ((val & MIPHY_OSC_RDY) != MIPHY_OSC_RDY)
+ cpu_relax();
+ else
+ return 0;
+ } while (!time_after_eq(jiffies, finish));
+
+ return -EBUSY;
+}
+
+static int miphy28lp_get_resource_byname(struct device_node *child,
+ char *rname, struct resource *res)
+{
+ int index;
+
+ index = of_property_match_string(child, "reg-names", rname);
+ if (index < 0)
+ return -ENODEV;
+
+ return of_address_to_resource(child, index, res);
+}
+
+static int miphy28lp_get_one_addr(struct device *dev,
+ struct device_node *child, char *rname,
+ void __iomem **base)
+{
+ struct resource res;
+ int ret;
+
+ ret = miphy28lp_get_resource_byname(child, rname, &res);
+ if (!ret) {
+ *base = devm_ioremap(dev, res.start, resource_size(&res));
+ if (!*base) {
+ dev_err(dev, "failed to ioremap %s address region\n"
+ , rname);
+ return -ENOENT;
+ }
+ }
+
+ return 0;
+}
+
+/* MiPHY reset and sysconf setup */
+static int miphy28lp_setup(struct miphy28lp_phy *miphy_phy, u32 miphy_val)
+{
+ int err;
+ struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
+
+ if (!miphy_phy->syscfg_miphy_ctrl)
+ return -EINVAL;
+
+ err = reset_control_assert(miphy_phy->miphy_rst);
+ if (err) {
+ dev_err(miphy_dev->dev, "unable to bring out of miphy reset\n");
+ return err;
+ }
+
+ if (miphy_phy->osc_force_ext)
+ miphy_val |= MIPHY_OSC_FORCE_EXT;
+
+ regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_miphy_ctrl,
+ MIPHY_CTRL_MASK, miphy_val);
+
+ err = reset_control_deassert(miphy_phy->miphy_rst);
+ if (err) {
+ dev_err(miphy_dev->dev, "unable to bring out of miphy reset\n");
+ return err;
+ }
+
+ return miphy_osc_is_ready(miphy_phy);
+}
+
+static int miphy28lp_init_sata(struct miphy28lp_phy *miphy_phy)
+{
+ struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
+ int err, sata_conf = SATA_CTRL_SELECT_SATA;
+
+ if ((!miphy_phy->syscfg_sata) || (!miphy_phy->syscfg_pci)
+ || (!miphy_phy->base))
+ return -EINVAL;
+
+ dev_info(miphy_dev->dev, "sata-up mode, addr 0x%p\n", miphy_phy->base);
+
+ /* Configure the glue-logic */
+ sata_conf |= ((miphy_phy->sata_gen - SATA_GEN1) << SATA_SPDMODE);
+
+ regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_sata,
+ SATA_CTRL_MASK, sata_conf);
+
+ regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_pci,
+ PCIE_CTRL_MASK, SATA_CTRL_SELECT_PCIE);
+
+ /* MiPHY path and clocking init */
+ err = miphy28lp_setup(miphy_phy, MIPHY_CTRL_DEFAULT);
+
+ if (err) {
+ dev_err(miphy_dev->dev, "SATA phy setup failed\n");
+ return err;
+ }
+
+ /* initialize miphy */
+ miphy28lp_configure_sata(miphy_phy);
+
+ return miphy_is_ready(miphy_phy);
+}
+
+static int miphy28lp_init_pcie(struct miphy28lp_phy *miphy_phy)
+{
+ struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
+ int err;
+
+ if ((!miphy_phy->syscfg_sata) || (!miphy_phy->syscfg_pci)
+ || (!miphy_phy->base) || (!miphy_phy->pipebase))
+ return -EINVAL;
+
+ dev_info(miphy_dev->dev, "pcie-up mode, addr 0x%p\n", miphy_phy->base);
+
+ /* Configure the glue-logic */
+ regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_sata,
+ SATA_CTRL_MASK, SATA_CTRL_SELECT_PCIE);
+
+ regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_pci,
+ PCIE_CTRL_MASK, SYSCFG_PCIE_PCIE_VAL);
+
+ /* MiPHY path and clocking init */
+ err = miphy28lp_setup(miphy_phy, MIPHY_CTRL_DEFAULT);
+
+ if (err) {
+ dev_err(miphy_dev->dev, "PCIe phy setup failed\n");
+ return err;
+ }
+
+ /* initialize miphy */
+ err = miphy28lp_configure_pcie(miphy_phy);
+ if (err)
+ return err;
+
+ /* PIPE Wrapper Configuration */
+ writeb_relaxed(0x68, miphy_phy->pipebase + 0x104); /* Rise_0 */
+ writeb_relaxed(0x61, miphy_phy->pipebase + 0x105); /* Rise_1 */
+ writeb_relaxed(0x68, miphy_phy->pipebase + 0x108); /* Fall_0 */
+ writeb_relaxed(0x61, miphy_phy->pipebase + 0x109); /* Fall-1 */
+ writeb_relaxed(0x68, miphy_phy->pipebase + 0x10c); /* Threshold_0 */
+ writeb_relaxed(0x60, miphy_phy->pipebase + 0x10d); /* Threshold_1 */
+
+ /* Wait for phy_ready */
+ return miphy_is_ready(miphy_phy);
+}
+
+static int miphy28lp_init_usb3(struct miphy28lp_phy *miphy_phy)
+{
+ struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
+ int err;
+
+ if ((!miphy_phy->base) || (!miphy_phy->pipebase))
+ return -EINVAL;
+
+ dev_info(miphy_dev->dev, "usb3-up mode, addr 0x%p\n", miphy_phy->base);
+
+ /* MiPHY path and clocking init */
+ err = miphy28lp_setup(miphy_phy, MIPHY_CTRL_SYNC_D_EN);
+ if (err) {
+ dev_err(miphy_dev->dev, "USB3 phy setup failed\n");
+ return err;
+ }
+
+ /* initialize miphy */
+ miphy28lp_configure_usb3(miphy_phy);
+
+ /* PIPE Wrapper Configuration */
+ writeb_relaxed(0x68, miphy_phy->pipebase + 0x23);
+ writeb_relaxed(0x61, miphy_phy->pipebase + 0x24);
+ writeb_relaxed(0x68, miphy_phy->pipebase + 0x26);
+ writeb_relaxed(0x61, miphy_phy->pipebase + 0x27);
+ writeb_relaxed(0x18, miphy_phy->pipebase + 0x29);
+ writeb_relaxed(0x61, miphy_phy->pipebase + 0x2a);
+
+ /* pipe Wrapper usb3 TX swing de-emph margin PREEMPH[7:4], SWING[3:0] */
+ writeb_relaxed(0X67, miphy_phy->pipebase + 0x68);
+ writeb_relaxed(0x0d, miphy_phy->pipebase + 0x69);
+ writeb_relaxed(0X67, miphy_phy->pipebase + 0x6a);
+ writeb_relaxed(0X0d, miphy_phy->pipebase + 0x6b);
+ writeb_relaxed(0X67, miphy_phy->pipebase + 0x6c);
+ writeb_relaxed(0X0d, miphy_phy->pipebase + 0x6d);
+ writeb_relaxed(0X67, miphy_phy->pipebase + 0x6e);
+ writeb_relaxed(0X0d, miphy_phy->pipebase + 0x6f);
+
+ return miphy_is_ready(miphy_phy);
+}
+
+static int miphy28lp_init(struct phy *phy)
+{
+ struct miphy28lp_phy *miphy_phy = phy_get_drvdata(phy);
+ struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
+ int ret;
+
+ mutex_lock(&miphy_dev->miphy_mutex);
+
+ switch (miphy_phy->type) {
+
+ case PHY_TYPE_SATA:
+ ret = miphy28lp_init_sata(miphy_phy);
+ break;
+ case PHY_TYPE_PCIE:
+ ret = miphy28lp_init_pcie(miphy_phy);
+ break;
+ case PHY_TYPE_USB3:
+ ret = miphy28lp_init_usb3(miphy_phy);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_unlock(&miphy_dev->miphy_mutex);
+
+ return ret;
+}
+
+static int miphy28lp_get_addr(struct miphy28lp_phy *miphy_phy)
+{
+ struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
+ struct device_node *phynode = miphy_phy->phy->dev.of_node;
+ int err;
+
+ if ((miphy_phy->type != PHY_TYPE_SATA) &&
+ (miphy_phy->type != PHY_TYPE_PCIE) &&
+ (miphy_phy->type != PHY_TYPE_USB3)) {
+ return -EINVAL;
+ }
+
+ err = miphy28lp_get_one_addr(miphy_dev->dev, phynode,
+ PHY_TYPE_name[miphy_phy->type - PHY_TYPE_SATA],
+ &miphy_phy->base);
+ if (err)
+ return err;
+
+ if ((miphy_phy->type == PHY_TYPE_PCIE) ||
+ (miphy_phy->type == PHY_TYPE_USB3)) {
+ err = miphy28lp_get_one_addr(miphy_dev->dev, phynode, "pipew",
+ &miphy_phy->pipebase);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static struct phy *miphy28lp_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct miphy28lp_dev *miphy_dev = dev_get_drvdata(dev);
+ struct miphy28lp_phy *miphy_phy = NULL;
+ struct device_node *phynode = args->np;
+ int ret, index = 0;
+
+ if (!of_device_is_available(phynode)) {
+ dev_warn(dev, "Requested PHY is disabled\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ if (args->args_count != 1) {
+ dev_err(dev, "Invalid number of cells in 'phy' property\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ for (index = 0; index < of_get_child_count(dev->of_node); index++)
+ if (phynode == miphy_dev->phys[index]->phy->dev.of_node) {
+ miphy_phy = miphy_dev->phys[index];
+ break;
+ }
+
+ if (!miphy_phy) {
+ dev_err(dev, "Failed to find appropriate phy\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ miphy_phy->type = args->args[0];
+
+ ret = miphy28lp_get_addr(miphy_phy);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ return miphy_phy->phy;
+}
+
+static struct phy_ops miphy28lp_ops = {
+ .init = miphy28lp_init,
+};
+
+static int miphy28lp_probe_resets(struct device_node *node,
+ struct miphy28lp_phy *miphy_phy)
+{
+ struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
+ int err;
+
+ miphy_phy->miphy_rst = of_reset_control_get(node, "miphy-sw-rst");
+
+ if (IS_ERR(miphy_phy->miphy_rst)) {
+ dev_err(miphy_dev->dev,
+ "miphy soft reset control not defined\n");
+ return PTR_ERR(miphy_phy->miphy_rst);
+ }
+
+ err = reset_control_deassert(miphy_phy->miphy_rst);
+ if (err) {
+ dev_err(miphy_dev->dev, "unable to bring out of miphy reset\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int miphy28lp_of_probe(struct device_node *np,
+ struct miphy28lp_phy *miphy_phy)
+{
+ struct resource res;
+
+ miphy_phy->osc_force_ext =
+ of_property_read_bool(np, "st,osc-force-ext");
+
+ miphy_phy->osc_rdy = of_property_read_bool(np, "st,osc-rdy");
+
+ miphy_phy->px_rx_pol_inv =
+ of_property_read_bool(np, "st,px_rx_pol_inv");
+
+ miphy_phy->ssc = of_property_read_bool(np, "st,ssc-on");
+
+ miphy_phy->tx_impedance =
+ of_property_read_bool(np, "st,tx-impedance-comp");
+
+ of_property_read_u32(np, "st,sata-gen", &miphy_phy->sata_gen);
+ if (!miphy_phy->sata_gen)
+ miphy_phy->sata_gen = SATA_GEN1;
+
+ if (!miphy28lp_get_resource_byname(np, "miphy-ctrl-glue", &res))
+ miphy_phy->syscfg_miphy_ctrl = res.start;
+
+ if (!miphy28lp_get_resource_byname(np, "miphy-status-glue", &res))
+ miphy_phy->syscfg_miphy_status = res.start;
+
+ if (!miphy28lp_get_resource_byname(np, "pcie-glue", &res))
+ miphy_phy->syscfg_pci = res.start;
+
+ if (!miphy28lp_get_resource_byname(np, "sata-glue", &res))
+ miphy_phy->syscfg_sata = res.start;
+
+
+ return 0;
+}
+
+static int miphy28lp_probe(struct platform_device *pdev)
+{
+ struct device_node *child, *np = pdev->dev.of_node;
+ struct miphy28lp_dev *miphy_dev;
+ struct phy_provider *provider;
+ struct phy *phy;
+ int chancount, port = 0;
+ int ret;
+
+ miphy_dev = devm_kzalloc(&pdev->dev, sizeof(*miphy_dev), GFP_KERNEL);
+ if (!miphy_dev)
+ return -ENOMEM;
+
+ chancount = of_get_child_count(np);
+ miphy_dev->phys = devm_kzalloc(&pdev->dev, sizeof(phy) * chancount,
+ GFP_KERNEL);
+ if (!miphy_dev->phys)
+ return -ENOMEM;
+
+ miphy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
+ if (IS_ERR(miphy_dev->regmap)) {
+ dev_err(miphy_dev->dev, "No syscfg phandle specified\n");
+ return PTR_ERR(miphy_dev->regmap);
+ }
+
+ miphy_dev->dev = &pdev->dev;
+
+ dev_set_drvdata(&pdev->dev, miphy_dev);
+
+ mutex_init(&miphy_dev->miphy_mutex);
+
+ for_each_child_of_node(np, child) {
+ struct miphy28lp_phy *miphy_phy;
+
+ miphy_phy = devm_kzalloc(&pdev->dev, sizeof(*miphy_phy),
+ GFP_KERNEL);
+ if (!miphy_phy)
+ return -ENOMEM;
+
+ miphy_dev->phys[port] = miphy_phy;
+
+ phy = devm_phy_create(&pdev->dev, child, &miphy28lp_ops);
+ if (IS_ERR(phy)) {
+ dev_err(&pdev->dev, "failed to create PHY\n");
+ return PTR_ERR(phy);
+ }
+
+ miphy_dev->phys[port]->phy = phy;
+ miphy_dev->phys[port]->phydev = miphy_dev;
+
+ ret = miphy28lp_of_probe(child, miphy_phy);
+ if (ret)
+ return ret;
+
+ ret = miphy28lp_probe_resets(child, miphy_dev->phys[port]);
+ if (ret)
+ return ret;
+
+ phy_set_drvdata(phy, miphy_dev->phys[port]);
+ port++;
+
+ }
+
+ provider = devm_of_phy_provider_register(&pdev->dev, miphy28lp_xlate);
+ if (IS_ERR(provider))
+ return PTR_ERR(provider);
+
+ return 0;
+}
+
+static const struct of_device_id miphy28lp_of_match[] = {
+ {.compatible = "st,miphy28lp-phy", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, miphy28lp_of_match);
+
+static struct platform_driver miphy28lp_driver = {
+ .probe = miphy28lp_probe,
+ .driver = {
+ .name = "miphy28lp-phy",
+ .owner = THIS_MODULE,
+ .of_match_table = miphy28lp_of_match,
+ }
+};
+
+module_platform_driver(miphy28lp_driver);
+
+MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics miphy28lp driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c
index 801afaf2d449..6ab43a814ad2 100644
--- a/drivers/phy/phy-miphy365x.c
+++ b/drivers/phy/phy-miphy365x.c
@@ -593,7 +593,7 @@ static int miphy365x_probe(struct platform_device *pdev)
miphy_dev->phys[port] = miphy_phy;
- phy = devm_phy_create(&pdev->dev, child, &miphy365x_ops, NULL);
+ phy = devm_phy_create(&pdev->dev, child, &miphy365x_ops);
if (IS_ERR(phy)) {
dev_err(&pdev->dev, "failed to create PHY\n");
return PTR_ERR(phy);
@@ -610,10 +610,7 @@ static int miphy365x_probe(struct platform_device *pdev)
}
provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate);
- if (IS_ERR(provider))
- return PTR_ERR(provider);
-
- return 0;
+ return PTR_ERR_OR_ZERO(provider);
}
static const struct of_device_id miphy365x_of_match[] = {
diff --git a/drivers/phy/phy-mvebu-sata.c b/drivers/phy/phy-mvebu-sata.c
index d395558cb12e..03b94f92e6f1 100644
--- a/drivers/phy/phy-mvebu-sata.c
+++ b/drivers/phy/phy-mvebu-sata.c
@@ -101,7 +101,7 @@ static int phy_mvebu_sata_probe(struct platform_device *pdev)
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
- phy = devm_phy_create(&pdev->dev, NULL, &phy_mvebu_sata_ops, NULL);
+ phy = devm_phy_create(&pdev->dev, NULL, &phy_mvebu_sata_ops);
if (IS_ERR(phy))
return PTR_ERR(phy);
diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index f091576b6449..4e489a8850e5 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -60,7 +60,7 @@ EXPORT_SYMBOL_GPL(omap_usb2_set_comparator);
static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled)
{
- struct omap_usb *phy = phy_to_omapusb(otg->phy);
+ struct omap_usb *phy = phy_to_omapusb(otg->usb_phy);
if (!phy->comparator)
return -ENODEV;
@@ -70,7 +70,7 @@ static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled)
static int omap_usb_start_srp(struct usb_otg *otg)
{
- struct omap_usb *phy = phy_to_omapusb(otg->phy);
+ struct omap_usb *phy = phy_to_omapusb(otg->usb_phy);
if (!phy->comparator)
return -ENODEV;
@@ -80,11 +80,9 @@ static int omap_usb_start_srp(struct usb_otg *otg)
static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- struct usb_phy *phy = otg->phy;
-
otg->host = host;
if (!host)
- phy->state = OTG_STATE_UNDEFINED;
+ otg->state = OTG_STATE_UNDEFINED;
return 0;
}
@@ -92,11 +90,9 @@ static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
static int omap_usb_set_peripheral(struct usb_otg *otg,
struct usb_gadget *gadget)
{
- struct usb_phy *phy = otg->phy;
-
otg->gadget = gadget;
if (!gadget)
- phy->state = OTG_STATE_UNDEFINED;
+ otg->state = OTG_STATE_UNDEFINED;
return 0;
}
@@ -255,12 +251,12 @@ static int omap_usb2_probe(struct platform_device *pdev)
otg->set_vbus = omap_usb_set_vbus;
if (phy_data->flags & OMAP_USB2_HAS_START_SRP)
otg->start_srp = omap_usb_start_srp;
- otg->phy = &phy->phy;
+ otg->usb_phy = &phy->phy;
platform_set_drvdata(pdev, phy);
pm_runtime_enable(phy->dev);
- generic_phy = devm_phy_create(phy->dev, NULL, &ops, NULL);
+ generic_phy = devm_phy_create(phy->dev, NULL, &ops);
if (IS_ERR(generic_phy)) {
pm_runtime_disable(phy->dev);
return PTR_ERR(generic_phy);
diff --git a/drivers/phy/phy-qcom-apq8064-sata.c b/drivers/phy/phy-qcom-apq8064-sata.c
index 7b3ddfb65898..4b243f7a10e4 100644
--- a/drivers/phy/phy-qcom-apq8064-sata.c
+++ b/drivers/phy/phy-qcom-apq8064-sata.c
@@ -228,8 +228,7 @@ static int qcom_apq8064_sata_phy_probe(struct platform_device *pdev)
if (IS_ERR(phy->mmio))
return PTR_ERR(phy->mmio);
- generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops,
- NULL);
+ generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops);
if (IS_ERR(generic_phy)) {
dev_err(dev, "%s: failed to create phy\n", __func__);
return PTR_ERR(generic_phy);
diff --git a/drivers/phy/phy-qcom-ipq806x-sata.c b/drivers/phy/phy-qcom-ipq806x-sata.c
index 759b0bf5b6b3..6f2fe2627916 100644
--- a/drivers/phy/phy-qcom-ipq806x-sata.c
+++ b/drivers/phy/phy-qcom-ipq806x-sata.c
@@ -150,8 +150,7 @@ static int qcom_ipq806x_sata_phy_probe(struct platform_device *pdev)
if (IS_ERR(phy->mmio))
return PTR_ERR(phy->mmio);
- generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops,
- NULL);
+ generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops);
if (IS_ERR(generic_phy)) {
dev_err(dev, "%s: failed to create phy\n", __func__);
return PTR_ERR(generic_phy);
diff --git a/drivers/phy/phy-rcar-gen2.c b/drivers/phy/phy-rcar-gen2.c
index 2793af17799f..778276aba3aa 100644
--- a/drivers/phy/phy-rcar-gen2.c
+++ b/drivers/phy/phy-rcar-gen2.c
@@ -304,7 +304,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
phy->select_value = select_value[channel_num][n];
phy->phy = devm_phy_create(dev, NULL,
- &rcar_gen2_phy_ops, NULL);
+ &rcar_gen2_phy_ops);
if (IS_ERR(phy->phy)) {
dev_err(dev, "Failed to create PHY\n");
return PTR_ERR(phy->phy);
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
index 908949dfb4db..4a12f66b7fb5 100644
--- a/drivers/phy/phy-samsung-usb2.c
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -202,8 +202,7 @@ static int samsung_usb2_phy_probe(struct platform_device *pdev)
struct samsung_usb2_phy_instance *p = &drv->instances[i];
dev_dbg(dev, "Creating phy \"%s\"\n", label);
- p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops,
- NULL);
+ p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops);
if (IS_ERR(p->phy)) {
dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n",
label);
diff --git a/drivers/phy/phy-spear1310-miphy.c b/drivers/phy/phy-spear1310-miphy.c
index 5f4c586ee951..9f47fae7eecb 100644
--- a/drivers/phy/phy-spear1310-miphy.c
+++ b/drivers/phy/phy-spear1310-miphy.c
@@ -227,7 +227,7 @@ static int spear1310_miphy_probe(struct platform_device *pdev)
return -EINVAL;
}
- priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops, NULL);
+ priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops);
if (IS_ERR(priv->phy)) {
dev_err(dev, "failed to create SATA PCIe PHY\n");
return PTR_ERR(priv->phy);
diff --git a/drivers/phy/phy-spear1340-miphy.c b/drivers/phy/phy-spear1340-miphy.c
index 1ecd0945bad3..e42bc200275f 100644
--- a/drivers/phy/phy-spear1340-miphy.c
+++ b/drivers/phy/phy-spear1340-miphy.c
@@ -259,7 +259,7 @@ static int spear1340_miphy_probe(struct platform_device *pdev)
return PTR_ERR(priv->misc);
}
- priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops, NULL);
+ priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops);
if (IS_ERR(priv->phy)) {
dev_err(dev, "failed to create SATA PCIe PHY\n");
return PTR_ERR(priv->phy);
diff --git a/drivers/phy/phy-stih407-usb.c b/drivers/phy/phy-stih407-usb.c
index 42428d4181ea..74f0fab3cd8a 100644
--- a/drivers/phy/phy-stih407-usb.c
+++ b/drivers/phy/phy-stih407-usb.c
@@ -137,7 +137,7 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev)
}
phy_dev->param = res->start;
- phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data, NULL);
+ phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create Display Port PHY\n");
return PTR_ERR(phy);
diff --git a/drivers/phy/phy-stih41x-usb.c b/drivers/phy/phy-stih41x-usb.c
index 9f16cb8e01f4..a603801293ff 100644
--- a/drivers/phy/phy-stih41x-usb.c
+++ b/drivers/phy/phy-stih41x-usb.c
@@ -148,7 +148,7 @@ static int stih41x_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(phy_dev->clk);
}
- phy = devm_phy_create(dev, NULL, &stih41x_usb_phy_ops, NULL);
+ phy = devm_phy_create(dev, NULL, &stih41x_usb_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create phy\n");
@@ -160,10 +160,7 @@ static int stih41x_usb_phy_probe(struct platform_device *pdev)
phy_set_drvdata(phy, phy_dev);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
-
- return 0;
+ return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id stih41x_usb_phy_of_match[] = {
diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
index 0baf5efc8a40..fb02a67c9181 100644
--- a/drivers/phy/phy-sun4i-usb.c
+++ b/drivers/phy/phy-sun4i-usb.c
@@ -157,6 +157,10 @@ static int sun4i_usb_phy_init(struct phy *_phy)
return ret;
}
+ /* Enable USB 45 Ohm resistor calibration */
+ if (phy->index == 0)
+ sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
+
/* Adjust PHY's magnitude and rate */
sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
@@ -213,7 +217,7 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev,
{
struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
- if (WARN_ON(args->args[0] == 0 || args->args[0] >= data->num_phys))
+ if (args->args[0] >= data->num_phys)
return ERR_PTR(-ENODEV);
return data->phys[args->args[0]].phy;
@@ -255,8 +259,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
if (IS_ERR(data->base))
return PTR_ERR(data->base);
- /* Skip 0, 0 is the phy for otg which is not yet supported. */
- for (i = 1; i < data->num_phys; i++) {
+ for (i = 0; i < data->num_phys; i++) {
struct sun4i_usb_phy *phy = data->phys + i;
char name[16];
@@ -295,7 +298,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(phy->pmu);
}
- phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops, NULL);
+ phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops);
if (IS_ERR(phy->phy)) {
dev_err(dev, "failed to create PHY %d\n", i);
return PTR_ERR(phy->phy);
diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
index ab1e22d9a1e8..c297b7a10d30 100644
--- a/drivers/phy/phy-ti-pipe3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -399,7 +399,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, phy);
pm_runtime_enable(phy->dev);
- generic_phy = devm_phy_create(phy->dev, NULL, &ops, NULL);
+ generic_phy = devm_phy_create(phy->dev, NULL, &ops);
if (IS_ERR(generic_phy))
return PTR_ERR(generic_phy);
diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index 7b04befd5271..8e87f54671f3 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -606,7 +606,7 @@ static int twl4030_set_peripheral(struct usb_otg *otg,
otg->gadget = gadget;
if (!gadget)
- otg->phy->state = OTG_STATE_UNDEFINED;
+ otg->state = OTG_STATE_UNDEFINED;
return 0;
}
@@ -618,7 +618,7 @@ static int twl4030_set_host(struct usb_otg *otg, struct usb_bus *host)
otg->host = host;
if (!host)
- otg->phy->state = OTG_STATE_UNDEFINED;
+ otg->state = OTG_STATE_UNDEFINED;
return 0;
}
@@ -644,7 +644,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
struct usb_otg *otg;
struct device_node *np = pdev->dev.of_node;
struct phy_provider *phy_provider;
- struct phy_init_data *init_data = NULL;
twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
if (!twl)
@@ -655,7 +654,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
(enum twl4030_usb_mode *)&twl->usb_mode);
else if (pdata) {
twl->usb_mode = pdata->usb_mode;
- init_data = pdata->init_data;
} else {
dev_err(&pdev->dev, "twl4030 initialized without pdata\n");
return -EINVAL;
@@ -676,11 +674,11 @@ static int twl4030_usb_probe(struct platform_device *pdev)
twl->phy.otg = otg;
twl->phy.type = USB_PHY_TYPE_USB2;
- otg->phy = &twl->phy;
+ otg->usb_phy = &twl->phy;
otg->set_host = twl4030_set_host;
otg->set_peripheral = twl4030_set_peripheral;
- phy = devm_phy_create(twl->dev, NULL, &ops, init_data);
+ phy = devm_phy_create(twl->dev, NULL, &ops);
if (IS_ERR(phy)) {
dev_dbg(&pdev->dev, "Failed to create PHY\n");
return PTR_ERR(phy);
@@ -733,6 +731,11 @@ static int twl4030_usb_probe(struct platform_device *pdev)
return status;
}
+ if (pdata)
+ err = phy_create_lookup(phy, "usb", "musb-hdrc.0");
+ if (err)
+ return err;
+
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(twl->dev);
diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c
index f8a51b16ade8..29214a36ea28 100644
--- a/drivers/phy/phy-xgene.c
+++ b/drivers/phy/phy-xgene.c
@@ -1707,7 +1707,7 @@ static int xgene_phy_probe(struct platform_device *pdev)
ctx->dev = &pdev->dev;
platform_set_drvdata(pdev, ctx);
- ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops, NULL);
+ ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops);
if (IS_ERR(ctx->phy)) {
dev_dbg(&pdev->dev, "Failed to create PHY\n");
rc = PTR_ERR(ctx->phy);
diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
index 080ec7723ef2..753d747d4261 100644
--- a/drivers/pinctrl/pinctrl-tegra-xusb.c
+++ b/drivers/pinctrl/pinctrl-tegra-xusb.c
@@ -915,7 +915,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
goto reset;
}
- phy = devm_phy_create(&pdev->dev, NULL, &pcie_phy_ops, NULL);
+ phy = devm_phy_create(&pdev->dev, NULL, &pcie_phy_ops);
if (IS_ERR(phy)) {
err = PTR_ERR(phy);
goto unregister;
@@ -924,7 +924,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy;
phy_set_drvdata(phy, padctl);
- phy = devm_phy_create(&pdev->dev, NULL, &sata_phy_ops, NULL);
+ phy = devm_phy_create(&pdev->dev, NULL, &sata_phy_ops);
if (IS_ERR(phy)) {
err = PTR_ERR(phy);
goto unregister;
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index 2f099c7df7b5..1fc86a2ca22d 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -10,6 +10,7 @@ ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o
# Glue/Bridge layers go here
+obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_usb2.o
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_msm.o
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_zevio.o
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index ea40626e0246..65913d48f0c8 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -161,7 +161,8 @@ struct hw_bank {
* @test_mode: the selected test mode
* @platdata: platform specific information supplied by parent device
* @vbus_active: is VBUS active
- * @transceiver: pointer to USB PHY, if any
+ * @phy: pointer to PHY, if any
+ * @usb_phy: pointer to USB PHY, if any and if using the USB PHY framework
* @hcd: pointer to usb_hcd for ehci host driver
* @debugfs: root dentry for this controller in debugfs
* @id_event: indicates there is an id event, and handled at ci_otg_work
@@ -177,6 +178,7 @@ struct ci_hdrc {
struct ci_role_driver *roles[CI_ROLE_END];
enum ci_role role;
bool is_otg;
+ struct usb_otg otg;
struct otg_fsm fsm;
struct ci_otg_fsm_timer_list *fsm_timer;
struct work_struct work;
@@ -201,7 +203,9 @@ struct ci_hdrc {
struct ci_hdrc_platform_data *platdata;
int vbus_active;
- struct usb_phy *transceiver;
+ struct phy *phy;
+ /* old usb_phy interface */
+ struct usb_phy *usb_phy;
struct usb_hcd *hcd;
struct dentry *debugfs;
bool id_event;
@@ -348,7 +352,7 @@ u32 hw_read_intr_enable(struct ci_hdrc *ci);
u32 hw_read_intr_status(struct ci_hdrc *ci);
-int hw_device_reset(struct ci_hdrc *ci, u32 mode);
+int hw_device_reset(struct ci_hdrc *ci);
int hw_port_test_set(struct ci_hdrc *ci, u8 mode);
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index a7ab0f15926e..450a168974d5 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -106,8 +106,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
struct ci_hdrc_platform_data pdata = {
.name = dev_name(&pdev->dev),
.capoffset = DEF_CAPOFFSET,
- .flags = CI_HDRC_REQUIRE_TRANSCEIVER |
- CI_HDRC_DISABLE_STREAMING,
+ .flags = CI_HDRC_DISABLE_STREAMING,
};
int ret;
const struct of_device_id *of_id =
@@ -115,10 +114,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
const struct ci_hdrc_imx_platform_flag *imx_platform_flag = of_id->data;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data) {
- dev_err(&pdev->dev, "Failed to allocate ci_hdrc-imx data!\n");
+ if (!data)
return -ENOMEM;
- }
data->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
if (IS_ERR(data->usbmisc_data))
@@ -147,7 +144,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
goto err_clk;
}
- pdata.phy = data->phy;
+ pdata.usb_phy = data->phy;
if (imx_platform_flag->flags & CI_HDRC_IMX_IMX28_WRITE_FIX)
pdata.flags |= CI_HDRC_IMX28_WRITE_FIX;
@@ -210,6 +207,41 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int imx_controller_suspend(struct device *dev)
+{
+ struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "at %s\n", __func__);
+
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static int imx_controller_resume(struct device *dev)
+{
+ struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "at %s\n", __func__);
+
+ return clk_prepare_enable(data->clk);
+}
+
+static int ci_hdrc_imx_suspend(struct device *dev)
+{
+ return imx_controller_suspend(dev);
+}
+
+static int ci_hdrc_imx_resume(struct device *dev)
+{
+ return imx_controller_resume(dev);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume)
+};
static struct platform_driver ci_hdrc_imx_driver = {
.probe = ci_hdrc_imx_probe,
.remove = ci_hdrc_imx_remove,
@@ -217,6 +249,7 @@ static struct platform_driver ci_hdrc_imx_driver = {
.name = "imx_usb",
.owner = THIS_MODULE,
.of_match_table = ci_hdrc_imx_dt_ids,
+ .pm = &ci_hdrc_imx_pm_ops,
},
};
diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c
index 4935ac38fd00..d79ecc08a1be 100644
--- a/drivers/usb/chipidea/ci_hdrc_msm.c
+++ b/drivers/usb/chipidea/ci_hdrc_msm.c
@@ -26,15 +26,15 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
writel(0, USB_AHBBURST);
writel(0, USB_AHBMODE);
- usb_phy_init(ci->transceiver);
+ usb_phy_init(ci->usb_phy);
break;
case CI_HDRC_CONTROLLER_STOPPED_EVENT:
dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n");
/*
- * Put the transceiver in non-driving mode. Otherwise host
+ * Put the phy in non-driving mode. Otherwise host
* may not detect soft-disconnection.
*/
- usb_phy_notify_disconnect(ci->transceiver, USB_SPEED_UNKNOWN);
+ usb_phy_notify_disconnect(ci->usb_phy, USB_SPEED_UNKNOWN);
break;
default:
dev_dbg(dev, "unknown ci_hdrc event\n");
@@ -46,7 +46,6 @@ static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = {
.name = "ci_hdrc_msm",
.capoffset = DEF_CAPOFFSET,
.flags = CI_HDRC_REGS_SHARED |
- CI_HDRC_REQUIRE_TRANSCEIVER |
CI_HDRC_DISABLE_STREAMING,
.notify_event = ci_hdrc_msm_notify_event,
@@ -68,7 +67,7 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
if (IS_ERR(phy))
return PTR_ERR(phy);
- ci_hdrc_msm_platdata.phy = phy;
+ ci_hdrc_msm_platdata.usb_phy = phy;
plat_ci = ci_hdrc_add_device(&pdev->dev,
pdev->resource, pdev->num_resources,
diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c
new file mode 100644
index 000000000000..45844c951788
--- /dev/null
+++ b/drivers/usb/chipidea/ci_hdrc_usb2.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 Marvell Technology Group Ltd.
+ *
+ * Antoine Tenart <antoine.tenart@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/usb/chipidea.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/ulpi.h>
+
+#include "ci.h"
+
+struct ci_hdrc_usb2_priv {
+ struct platform_device *ci_pdev;
+ struct clk *clk;
+};
+
+static struct ci_hdrc_platform_data ci_default_pdata = {
+ .capoffset = DEF_CAPOFFSET,
+ .flags = CI_HDRC_DISABLE_STREAMING,
+};
+
+static int ci_hdrc_usb2_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ci_hdrc_usb2_priv *priv;
+ struct ci_hdrc_platform_data *ci_pdata = dev_get_platdata(dev);
+ int ret;
+
+ if (!ci_pdata)
+ ci_pdata = &ci_default_pdata;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (!IS_ERR(priv->clk)) {
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable the clock: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ if (ret)
+ goto clk_err;
+
+ ci_pdata->name = dev_name(dev);
+
+ priv->ci_pdev = ci_hdrc_add_device(dev, pdev->resource,
+ pdev->num_resources, ci_pdata);
+ if (IS_ERR(priv->ci_pdev)) {
+ ret = PTR_ERR(priv->ci_pdev);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev,
+ "failed to register ci_hdrc platform device: %d\n",
+ ret);
+ goto clk_err;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ pm_runtime_no_callbacks(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+
+clk_err:
+ if (!IS_ERR(priv->clk))
+ clk_disable_unprepare(priv->clk);
+ return ret;
+}
+
+static int ci_hdrc_usb2_remove(struct platform_device *pdev)
+{
+ struct ci_hdrc_usb2_priv *priv = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+ ci_hdrc_remove_device(priv->ci_pdev);
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static const struct of_device_id ci_hdrc_usb2_of_match[] = {
+ { .compatible = "chipidea,usb2" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ci_hdrc_usb2_of_match);
+
+static struct platform_driver ci_hdrc_usb2_driver = {
+ .probe = ci_hdrc_usb2_probe,
+ .remove = ci_hdrc_usb2_remove,
+ .driver = {
+ .name = "chipidea-usb2",
+ .of_match_table = of_match_ptr(ci_hdrc_usb2_of_match),
+ },
+};
+module_platform_driver(ci_hdrc_usb2_driver);
+
+MODULE_DESCRIPTION("ChipIdea HDRC USB2 binding for ci13xxx");
+MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 9bdc6bd73432..e14eafb2a05e 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -47,6 +47,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
+#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/idr.h>
@@ -189,24 +190,29 @@ u8 hw_port_test_get(struct ci_hdrc *ci)
return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC);
}
+static void hw_wait_phy_stable(void)
+{
+ /*
+ * The phy needs some delay to output the stable status from low
+ * power mode. And for OTGSC, the status inputs are debounced
+ * using a 1 ms time constant, so, delay 2ms for controller to get
+ * the stable status, like vbus and id when the phy leaves low power.
+ */
+ usleep_range(2000, 2500);
+}
+
/* The PHY enters/leaves low power mode */
static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable)
{
enum ci_hw_regs reg = ci->hw_bank.lpm ? OP_DEVLC : OP_PORTSC;
bool lpm = !!(hw_read(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm)));
- if (enable && !lpm) {
+ if (enable && !lpm)
hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm),
PORTSC_PHCD(ci->hw_bank.lpm));
- } else if (!enable && lpm) {
+ else if (!enable && lpm)
hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm),
0);
- /*
- * the PHY needs some time (less
- * than 1ms) to leave low power mode.
- */
- usleep_range(1000, 1100);
- }
}
static int hw_device_init(struct ci_hdrc *ci, void __iomem *base)
@@ -299,6 +305,49 @@ static void hw_phymode_configure(struct ci_hdrc *ci)
}
/**
+ * _ci_usb_phy_init: initialize phy taking in account both phy and usb_phy
+ * interfaces
+ * @ci: the controller
+ *
+ * This function returns an error code if the phy failed to init
+ */
+static int _ci_usb_phy_init(struct ci_hdrc *ci)
+{
+ int ret;
+
+ if (ci->phy) {
+ ret = phy_init(ci->phy);
+ if (ret)
+ return ret;
+
+ ret = phy_power_on(ci->phy);
+ if (ret) {
+ phy_exit(ci->phy);
+ return ret;
+ }
+ } else {
+ ret = usb_phy_init(ci->usb_phy);
+ }
+
+ return ret;
+}
+
+/**
+ * _ci_usb_phy_exit: deinitialize phy taking in account both phy and usb_phy
+ * interfaces
+ * @ci: the controller
+ */
+static void ci_usb_phy_exit(struct ci_hdrc *ci)
+{
+ if (ci->phy) {
+ phy_power_off(ci->phy);
+ phy_exit(ci->phy);
+ } else {
+ usb_phy_shutdown(ci->usb_phy);
+ }
+}
+
+/**
* ci_usb_phy_init: initialize phy according to different phy type
* @ci: the controller
*
@@ -312,40 +361,68 @@ static int ci_usb_phy_init(struct ci_hdrc *ci)
case USBPHY_INTERFACE_MODE_UTMI:
case USBPHY_INTERFACE_MODE_UTMIW:
case USBPHY_INTERFACE_MODE_HSIC:
- ret = usb_phy_init(ci->transceiver);
- if (ret)
+ ret = _ci_usb_phy_init(ci);
+ if (!ret)
+ hw_wait_phy_stable();
+ else
return ret;
hw_phymode_configure(ci);
break;
case USBPHY_INTERFACE_MODE_ULPI:
case USBPHY_INTERFACE_MODE_SERIAL:
hw_phymode_configure(ci);
- ret = usb_phy_init(ci->transceiver);
+ ret = _ci_usb_phy_init(ci);
if (ret)
return ret;
break;
default:
- ret = usb_phy_init(ci->transceiver);
+ ret = _ci_usb_phy_init(ci);
+ if (!ret)
+ hw_wait_phy_stable();
}
return ret;
}
/**
- * hw_device_reset: resets chip (execute without interruption)
+ * hw_controller_reset: do controller reset
* @ci: the controller
*
* This function returns an error code
*/
-int hw_device_reset(struct ci_hdrc *ci, u32 mode)
+static int hw_controller_reset(struct ci_hdrc *ci)
{
+ int count = 0;
+
+ hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST);
+ while (hw_read(ci, OP_USBCMD, USBCMD_RST)) {
+ udelay(10);
+ if (count++ > 1000)
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+/**
+ * hw_device_reset: resets chip (execute without interruption)
+ * @ci: the controller
+ *
+ * This function returns an error code
+ */
+int hw_device_reset(struct ci_hdrc *ci)
+{
+ int ret;
+
/* should flush & stop before reset */
hw_write(ci, OP_ENDPTFLUSH, ~0, ~0);
hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
- hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST);
- while (hw_read(ci, OP_USBCMD, USBCMD_RST))
- udelay(10); /* not RTOS friendly */
+ ret = hw_controller_reset(ci);
+ if (ret) {
+ dev_err(ci->dev, "error resetting controller, ret=%d\n", ret);
+ return ret;
+ }
if (ci->platdata->notify_event)
ci->platdata->notify_event(ci,
@@ -363,12 +440,12 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode)
/* USBMODE should be configured step by step */
hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
- hw_write(ci, OP_USBMODE, USBMODE_CM, mode);
+ hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_DC);
/* HW >= 2.3 */
hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);
- if (hw_read(ci, OP_USBMODE, USBMODE_CM) != mode) {
- pr_err("cannot enter in %s mode", ci_role(ci)->name);
+ if (hw_read(ci, OP_USBMODE, USBMODE_CM) != USBMODE_CM_DC) {
+ pr_err("cannot enter in %s device mode", ci_role(ci)->name);
pr_err("lpm = %i", ci->hw_bank.lpm);
return -ENODEV;
}
@@ -472,7 +549,7 @@ static int ci_get_platdata(struct device *dev,
if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) {
return -EPROBE_DEFER;
} else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) {
- /* no vbus regualator is needed */
+ /* no vbus regulator is needed */
platdata->reg_vbus = NULL;
} else if (IS_ERR(platdata->reg_vbus)) {
dev_err(dev, "Getting regulator error: %ld\n",
@@ -589,11 +666,10 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return PTR_ERR(base);
ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL);
- if (!ci) {
- dev_err(dev, "can't allocate device\n");
+ if (!ci)
return -ENOMEM;
- }
+ platform_set_drvdata(pdev, ci);
ci->dev = dev;
ci->platdata = dev_get_platdata(dev);
ci->imx28_write_fix = !!(ci->platdata->flags &
@@ -605,36 +681,32 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return -ENODEV;
}
- if (ci->platdata->phy)
- ci->transceiver = ci->platdata->phy;
- else
- ci->transceiver = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
-
- if (IS_ERR(ci->transceiver)) {
- ret = PTR_ERR(ci->transceiver);
- /*
- * 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;
+ if (ci->platdata->phy) {
+ ci->phy = ci->platdata->phy;
+ } else if (ci->platdata->usb_phy) {
+ ci->usb_phy = ci->platdata->usb_phy;
+ } else {
+ ci->phy = devm_phy_get(dev->parent, "usb-phy");
+ ci->usb_phy = devm_usb_get_phy(dev->parent, USB_PHY_TYPE_USB2);
+
+ /* if both generic PHY and USB PHY layers aren't enabled */
+ if (PTR_ERR(ci->phy) == -ENOSYS &&
+ PTR_ERR(ci->usb_phy) == -ENXIO)
+ return -ENXIO;
+
+ if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy))
+ return -EPROBE_DEFER;
- dev_err(dev, "no usb2 phy configured\n");
- return -EPROBE_DEFER;
+ if (IS_ERR(ci->phy))
+ ci->phy = NULL;
+ else if (IS_ERR(ci->usb_phy))
+ ci->usb_phy = NULL;
}
ret = ci_usb_phy_init(ci);
if (ret) {
dev_err(dev, "unable to init phy: %d\n", ret);
return ret;
- } else {
- /*
- * The delay to sync PHY's status, the maximum delay is
- * 2ms since the otgsc uses 1ms timer to debounce the
- * PHY's input
- */
- usleep_range(2000, 2500);
}
ci->hw_bank.phys = res->start;
@@ -711,9 +783,8 @@ static int ci_hdrc_probe(struct platform_device *pdev)
}
}
- platform_set_drvdata(pdev, ci);
- ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->platdata->name,
- ci);
+ ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED,
+ ci->platdata->name, ci);
if (ret)
goto stop;
@@ -724,11 +795,10 @@ static int ci_hdrc_probe(struct platform_device *pdev)
if (!ret)
return 0;
- free_irq(ci->irq, ci);
stop:
ci_role_destroy(ci);
deinit_phy:
- usb_phy_shutdown(ci->transceiver);
+ ci_usb_phy_exit(ci);
return ret;
}
@@ -738,19 +808,66 @@ static int ci_hdrc_remove(struct platform_device *pdev)
struct ci_hdrc *ci = platform_get_drvdata(pdev);
dbg_remove_files(ci);
- free_irq(ci->irq, ci);
ci_role_destroy(ci);
ci_hdrc_enter_lpm(ci, true);
- usb_phy_shutdown(ci->transceiver);
+ ci_usb_phy_exit(ci);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static void ci_controller_suspend(struct ci_hdrc *ci)
+{
+ ci_hdrc_enter_lpm(ci, true);
+
+ if (ci->usb_phy)
+ usb_phy_set_suspend(ci->usb_phy, 1);
+}
+
+static int ci_controller_resume(struct device *dev)
+{
+ struct ci_hdrc *ci = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "at %s\n", __func__);
+
+ ci_hdrc_enter_lpm(ci, false);
+
+ if (ci->usb_phy) {
+ usb_phy_set_suspend(ci->usb_phy, 0);
+ usb_phy_set_wakeup(ci->usb_phy, false);
+ hw_wait_phy_stable();
+ }
return 0;
}
+static int ci_suspend(struct device *dev)
+{
+ struct ci_hdrc *ci = dev_get_drvdata(dev);
+
+ if (ci->wq)
+ flush_workqueue(ci->wq);
+
+ ci_controller_suspend(ci);
+
+ return 0;
+}
+
+static int ci_resume(struct device *dev)
+{
+ return ci_controller_resume(dev);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops ci_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ci_suspend, ci_resume)
+};
static struct platform_driver ci_hdrc_driver = {
.probe = ci_hdrc_probe,
.remove = ci_hdrc_remove,
.driver = {
.name = "ci_hdrc",
+ .pm = &ci_pm_ops,
.owner = THIS_MODULE,
},
};
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index 795d6538d630..268e4236e84c 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -220,7 +220,7 @@ static int ci_otg_show(struct seq_file *s, void *unused)
/* ------ State ----- */
seq_printf(s, "OTG state: %s\n\n",
- usb_otg_state_string(ci->transceiver->state));
+ usb_otg_state_string(ci->otg.state));
/* ------ State Machine Variables ----- */
seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop);
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index ebde7b6ce687..c1694cff1eaf 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -34,6 +34,44 @@
static struct hc_driver __read_mostly ci_ehci_hc_driver;
+struct ehci_ci_priv {
+ struct regulator *reg_vbus;
+};
+
+static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct ehci_ci_priv *priv = (struct ehci_ci_priv *)ehci->priv;
+ struct device *dev = hcd->self.controller;
+ struct ci_hdrc *ci = dev_get_drvdata(dev);
+ int ret = 0;
+ int port = HCS_N_PORTS(ehci->hcs_params);
+
+ if (priv->reg_vbus && !ci_otg_is_fsm_mode(ci)) {
+ if (port > 1) {
+ dev_warn(dev,
+ "Not support multi-port regulator control\n");
+ return 0;
+ }
+ if (enable)
+ ret = regulator_enable(priv->reg_vbus);
+ else
+ ret = regulator_disable(priv->reg_vbus);
+ if (ret) {
+ dev_err(dev,
+ "Failed to %s vbus regulator, ret=%d\n",
+ enable ? "enable" : "disable", ret);
+ return ret;
+ }
+ }
+ return 0;
+};
+
+static const struct ehci_driver_overrides ehci_ci_overrides = {
+ .extra_priv_size = sizeof(struct ehci_ci_priv),
+ .port_power = ehci_ci_portpower,
+};
+
static irqreturn_t host_irq(struct ci_hdrc *ci)
{
return usb_hcd_irq(ci->irq, ci->hcd);
@@ -43,6 +81,7 @@ static int host_start(struct ci_hdrc *ci)
{
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
+ struct ehci_ci_priv *priv;
int ret;
if (usb_disabled())
@@ -52,15 +91,17 @@ static int host_start(struct ci_hdrc *ci)
if (!hcd)
return -ENOMEM;
- dev_set_drvdata(ci->dev, ci);
hcd->rsrc_start = ci->hw_bank.phys;
hcd->rsrc_len = ci->hw_bank.size;
hcd->regs = ci->hw_bank.abs;
hcd->has_tt = 1;
hcd->power_budget = ci->platdata->power_budget;
- hcd->usb_phy = ci->transceiver;
hcd->tpl_support = ci->platdata->tpl_support;
+ if (ci->phy)
+ hcd->phy = ci->phy;
+ else
+ hcd->usb_phy = ci->usb_phy;
ehci = hcd_to_ehci(hcd);
ehci->caps = ci->hw_bank.cap;
@@ -68,28 +109,21 @@ static int host_start(struct ci_hdrc *ci)
ehci->has_tdi_phy_lpm = ci->hw_bank.lpm;
ehci->imx28_write_fix = ci->imx28_write_fix;
- /*
- * vbus is always on if host is not in OTG FSM mode,
- * otherwise should be controlled by OTG FSM
- */
- if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) {
- ret = regulator_enable(ci->platdata->reg_vbus);
- if (ret) {
- dev_err(ci->dev,
- "Failed to enable vbus regulator, ret=%d\n",
- ret);
- goto put_hcd;
- }
- }
+ priv = (struct ehci_ci_priv *)ehci->priv;
+ priv->reg_vbus = NULL;
+
+ if (ci->platdata->reg_vbus)
+ priv->reg_vbus = ci->platdata->reg_vbus;
ret = usb_add_hcd(hcd, 0, 0);
if (ret) {
- goto disable_reg;
+ goto put_hcd;
} else {
- struct usb_otg *otg = ci->transceiver->otg;
+ struct usb_otg *otg = &ci->otg;
ci->hcd = hcd;
- if (otg) {
+
+ if (ci_otg_is_fsm_mode(ci)) {
otg->host = &hcd->self;
hcd->self.otg_port = 1;
}
@@ -100,10 +134,6 @@ static int host_start(struct ci_hdrc *ci)
return ret;
-disable_reg:
- if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci))
- regulator_disable(ci->platdata->reg_vbus);
-
put_hcd:
usb_put_hcd(hcd);
@@ -117,8 +147,6 @@ static void host_stop(struct ci_hdrc *ci)
if (hcd) {
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
- if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci))
- regulator_disable(ci->platdata->reg_vbus);
}
}
@@ -146,7 +174,7 @@ int ci_hdrc_host_init(struct ci_hdrc *ci)
rdrv->name = "host";
ci->roles[CI_ROLE_HOST] = rdrv;
- ehci_init_driver(&ci_ehci_hc_driver, NULL);
+ ehci_init_driver(&ci_ehci_hc_driver, &ehci_ci_overrides);
return 0;
}
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index caaabc58021e..562e581f6765 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -303,7 +303,7 @@ static void a_wait_vfall_tmout_func(void *ptr, unsigned long indicator)
set_tmout(ci, indicator);
/* Disable port power */
hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, 0);
- /* Clear exsiting DP irq */
+ /* Clear existing DP irq */
hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS);
/* Enable data pulse irq */
hw_write_otgsc(ci, OTGSC_DPIE, OTGSC_DPIE);
@@ -328,7 +328,7 @@ static void b_ssend_srp_tmout_func(void *ptr, unsigned long indicator)
set_tmout(ci, indicator);
/* only vbus fall below B_sess_vld in b_idle state */
- if (ci->transceiver->state == OTG_STATE_B_IDLE)
+ if (ci->fsm.otg->state == OTG_STATE_B_IDLE)
ci_otg_queue_work(ci);
}
@@ -543,7 +543,7 @@ static int ci_otg_start_host(struct otg_fsm *fsm, int on)
ci_role_start(ci, CI_ROLE_HOST);
} else {
ci_role_stop(ci);
- hw_device_reset(ci, USBMODE_CM_DC);
+ hw_device_reset(ci);
ci_role_start(ci, CI_ROLE_GADGET);
}
mutex_lock(&fsm->lock);
@@ -582,11 +582,11 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
* when there is no gadget class driver
*/
if (ci->fsm.id && !(ci->driver) &&
- ci->transceiver->state < OTG_STATE_A_IDLE)
+ ci->fsm.otg->state < OTG_STATE_A_IDLE)
return 0;
if (otg_statemachine(&ci->fsm)) {
- if (ci->transceiver->state == OTG_STATE_A_IDLE) {
+ if (ci->fsm.otg->state == OTG_STATE_A_IDLE) {
/*
* Further state change for cases:
* a_idle to b_idle; or
@@ -600,7 +600,7 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
ci_otg_queue_work(ci);
if (ci->id_event)
ci->id_event = false;
- } else if (ci->transceiver->state == OTG_STATE_B_IDLE) {
+ } else if (ci->fsm.otg->state == OTG_STATE_B_IDLE) {
if (ci->fsm.b_sess_vld) {
ci->fsm.power_up = 0;
/*
@@ -627,7 +627,7 @@ static void ci_otg_fsm_event(struct ci_hdrc *ci)
otg_bsess_vld = hw_read_otgsc(ci, OTGSC_BSV);
port_conn = hw_read(ci, OP_PORTSC, PORTSC_CCS);
- switch (ci->transceiver->state) {
+ switch (ci->fsm.otg->state) {
case OTG_STATE_A_WAIT_BCON:
if (port_conn) {
fsm->b_conn = 1;
@@ -663,7 +663,7 @@ static void ci_otg_fsm_event(struct ci_hdrc *ci)
fsm->b_bus_suspend = 1;
/*
* Init a timer to know how long this suspend
- * will contine, if time out, indicates B no longer
+ * will continue, if time out, indicates B no longer
* wants to be host role
*/
ci_otg_add_timer(ci, A_BIDL_ADIS);
@@ -778,34 +778,25 @@ void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci)
int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
{
int retval = 0;
- struct usb_otg *otg;
- otg = devm_kzalloc(ci->dev,
- sizeof(struct usb_otg), GFP_KERNEL);
- if (!otg) {
- dev_err(ci->dev,
- "Failed to allocate usb_otg structure for ci hdrc otg!\n");
- return -ENOMEM;
- }
+ if (ci->phy)
+ ci->otg.phy = ci->phy;
+ else
+ ci->otg.usb_phy = ci->usb_phy;
- otg->phy = ci->transceiver;
- otg->gadget = &ci->gadget;
- ci->fsm.otg = otg;
- ci->transceiver->otg = ci->fsm.otg;
+ ci->otg.gadget = &ci->gadget;
+ ci->fsm.otg = &ci->otg;
ci->fsm.power_up = 1;
ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
- ci->transceiver->state = OTG_STATE_UNDEFINED;
+ ci->fsm.otg->state = OTG_STATE_UNDEFINED;
ci->fsm.ops = &ci_otg_ops;
mutex_init(&ci->fsm.lock);
ci->fsm_timer = devm_kzalloc(ci->dev,
sizeof(struct ci_otg_fsm_timer_list), GFP_KERNEL);
- if (!ci->fsm_timer) {
- dev_err(ci->dev,
- "Failed to allocate timer structure for ci hdrc otg!\n");
+ if (!ci->fsm_timer)
return -ENOMEM;
- }
INIT_LIST_HEAD(&ci->fsm_timer->active_timers);
retval = ci_otg_init_timers(ci);
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 0444d3f8971a..4fe18ce3bd5a 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -692,10 +692,8 @@ __acquires(ci->lock)
int retval;
spin_unlock(&ci->lock);
- if (ci->gadget.speed != USB_SPEED_UNKNOWN) {
- if (ci->driver)
- ci->driver->disconnect(&ci->gadget);
- }
+ if (ci->gadget.speed != USB_SPEED_UNKNOWN)
+ usb_gadget_udc_reset(&ci->gadget, ci->driver);
retval = _gadget_stop_activity(&ci->gadget);
if (retval)
@@ -709,8 +707,6 @@ __acquires(ci->lock)
if (ci->status == NULL)
retval = -ENOMEM;
- usb_gadget_set_state(&ci->gadget, USB_STATE_DEFAULT);
-
done:
spin_lock(&ci->lock);
@@ -1475,7 +1471,7 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
if (gadget_ready) {
if (is_active) {
pm_runtime_get_sync(&_gadget->dev);
- hw_device_reset(ci, USBMODE_CM_DC);
+ hw_device_reset(ci);
hw_device_state(ci, ci->ep0out->qh.dma);
usb_gadget_set_state(_gadget, USB_STATE_POWERED);
} else {
@@ -1519,8 +1515,8 @@ static int ci_udc_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
{
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
- if (ci->transceiver)
- return usb_phy_set_power(ci->transceiver, ma);
+ if (ci->usb_phy)
+ return usb_phy_set_power(ci->usb_phy, ma);
return -ENOTSUPP;
}
@@ -1544,8 +1540,7 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
static int ci_udc_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
-static int ci_udc_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver);
+static int ci_udc_stop(struct usb_gadget *gadget);
/**
* Device operations part of the API to the USB controller hardware,
* which don't involve endpoints (or i/o)
@@ -1665,7 +1660,7 @@ static int ci_udc_start(struct usb_gadget *gadget,
pm_runtime_get_sync(&ci->gadget.dev);
if (ci->vbus_active) {
spin_lock_irqsave(&ci->lock, flags);
- hw_device_reset(ci, USBMODE_CM_DC);
+ hw_device_reset(ci);
} else {
pm_runtime_put_sync(&ci->gadget.dev);
return retval;
@@ -1682,8 +1677,7 @@ static int ci_udc_start(struct usb_gadget *gadget,
/**
* ci_udc_stop: unregister a gadget driver
*/
-static int ci_udc_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static int ci_udc_stop(struct usb_gadget *gadget)
{
struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
unsigned long flags;
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index 926c997ef310..58591e9dcede 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -117,10 +117,9 @@ static int usbmisc_imx25_post(struct imx_usbmisc_data *data)
if (data->index > 2)
return -EINVAL;
- reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
-
if (data->evdo) {
spin_lock_irqsave(&usbmisc->lock, flags);
+ reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
val = readl(reg);
writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
spin_unlock_irqrestore(&usbmisc->lock, flags);
@@ -172,8 +171,7 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
return -EINVAL;
/* Select a 24 MHz reference clock for the PHY */
- reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET;
- val = readl(reg);
+ val = readl(usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK;
val |= MX53_USB_PLL_DIV_24_MHZ;
writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 077d58ac3dcb..546a17e8ad5b 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1157,8 +1157,6 @@ static int acm_probe(struct usb_interface *intf,
case USB_CDC_CALL_MANAGEMENT_TYPE:
call_management_function = buffer[3];
call_interface_num = buffer[4];
- if ((quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
- dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
break;
default:
/* there are LOTS more CDC descriptors that
@@ -1197,10 +1195,11 @@ next_desc:
} else {
control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
- if (!control_interface || !data_interface) {
- dev_dbg(&intf->dev, "no interfaces\n");
- return -ENODEV;
- }
+ }
+
+ if (!control_interface || !data_interface) {
+ dev_dbg(&intf->dev, "no interfaces\n");
+ return -ENODEV;
}
if (data_interface_num != call_interface_num)
@@ -1475,6 +1474,7 @@ alloc_fail8:
&dev_attr_wCountryCodes);
device_remove_file(&acm->control->dev,
&dev_attr_iCountryCodeRelDate);
+ kfree(acm->country_codes);
}
device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
alloc_fail7:
@@ -1813,11 +1813,6 @@ static const struct usb_device_id acm_ids[] = {
/* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
- /* Support Lego NXT using pbLua firmware */
- { USB_DEVICE(0x0694, 0xff00),
- .driver_info = NOT_A_MODEM,
- },
-
/* Support for Droids MuIn LCD */
{ USB_DEVICE(0x04d8, 0x000b),
.driver_info = NO_DATA_INTERFACE,
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index d3251ebd09e2..ffeb3c83941f 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -130,7 +130,6 @@ struct acm {
#define NO_UNION_NORMAL BIT(0)
#define SINGLE_RX_URB BIT(1)
#define NO_CAP_LINE BIT(2)
-#define NOT_A_MODEM BIT(3)
#define NO_DATA_INTERFACE BIT(4)
#define IGNORE_DEVICE BIT(5)
#define QUIRK_CONTROL_LINE_STATE BIT(6)
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index ec978408a2ee..960bc089111b 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -1104,10 +1104,8 @@ static int usbtmc_probe(struct usb_interface *intf,
dev_dbg(&intf->dev, "%s called\n", __func__);
data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
- if (!data) {
- dev_err(&intf->dev, "Unable to allocate kernel memory\n");
+ if (!data)
return -ENOMEM;
- }
data->intf = intf;
data->id = id;
diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 98e8340a5bb1..c6b35b77dab7 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -124,10 +124,10 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
{
state_changed = 1;
- if (fsm->otg->phy->state == new_state)
+ if (fsm->otg->state == new_state)
return 0;
VDBG("Set state: %s\n", usb_otg_state_string(new_state));
- otg_leave_state(fsm, fsm->otg->phy->state);
+ otg_leave_state(fsm, fsm->otg->state);
switch (new_state) {
case OTG_STATE_B_IDLE:
otg_drv_vbus(fsm, 0);
@@ -236,7 +236,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
break;
}
- fsm->otg->phy->state = new_state;
+ fsm->otg->state = new_state;
return 0;
}
@@ -247,7 +247,7 @@ int otg_statemachine(struct otg_fsm *fsm)
mutex_lock(&fsm->lock);
- state = fsm->otg->phy->state;
+ state = fsm->otg->state;
state_changed = 0;
/* State machine state change judgement */
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 278be0515e8e..11cee55ae397 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2646,7 +2646,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
}
}
- if (IS_ENABLED(CONFIG_GENERIC_PHY)) {
+ if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->phy) {
struct phy *phy = phy_get(hcd->self.controller, "usb");
if (IS_ERR(phy)) {
@@ -2666,6 +2666,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
goto err_phy;
}
hcd->phy = phy;
+ hcd->remove_phy = 1;
}
}
@@ -2812,7 +2813,7 @@ err_allocate_root_hub:
err_register_bus:
hcd_buffer_destroy(hcd);
err_create_buf:
- if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->phy) {
+ if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) {
phy_power_off(hcd->phy);
phy_exit(hcd->phy);
phy_put(hcd->phy);
@@ -2896,7 +2897,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
usb_deregister_bus(&hcd->self);
hcd_buffer_destroy(hcd);
- if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->phy) {
+ if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) {
phy_power_off(hcd->phy);
phy_exit(hcd->phy);
phy_put(hcd->phy);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index c9596525ba8c..aeb50bb6ba9c 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2543,11 +2543,14 @@ int usb_authorize_device(struct usb_device *usb_dev)
"can't autoresume for authorization: %d\n", result);
goto error_autoresume;
}
- result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
- if (result < 0) {
- dev_err(&usb_dev->dev, "can't re-read device descriptor for "
- "authorization: %d\n", result);
- goto error_device_descriptor;
+
+ if (usb_dev->wusb) {
+ result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
+ if (result < 0) {
+ dev_err(&usb_dev->dev, "can't re-read device descriptor for "
+ "authorization: %d\n", result);
+ goto error_device_descriptor;
+ }
}
usb_dev->authorized = 1;
@@ -3907,14 +3910,9 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
enum usb3_link_state state)
{
- int feature;
-
switch (state) {
case USB3_LPM_U1:
- feature = USB_PORT_FEAT_U1_TIMEOUT;
- break;
case USB3_LPM_U2:
- feature = USB_PORT_FEAT_U2_TIMEOUT;
break;
default:
dev_warn(&udev->dev, "%s: Can't disable non-U1 or U2 state.\n",
diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig
index f93807b3631a..b323c4c11b0a 100644
--- a/drivers/usb/dwc2/Kconfig
+++ b/drivers/usb/dwc2/Kconfig
@@ -1,6 +1,6 @@
config USB_DWC2
- bool "DesignWare USB2 DRD Core Support"
- depends on USB
+ tristate "DesignWare USB2 DRD Core Support"
+ depends on USB || USB_GADGET
help
Say Y here if your system has a Dual Role Hi-Speed USB
controller based on the DesignWare HSOTG IP Core.
@@ -10,49 +10,61 @@ config USB_DWC2
bus interface module (if you have a PCI bus system) will be
called dwc2_pci.ko, and the platform interface module (for
controllers directly connected to the CPU) will be called
- dwc2_platform.ko. For gadget mode, there will be a single
- module called dwc2_gadget.ko.
-
- NOTE: The s3c-hsotg driver is now renamed to dwc2_gadget. The
- host and gadget drivers are still currently separate drivers.
- There are plans to merge the dwc2_gadget driver with the dwc2
- host driver in the near future to create a dual-role driver.
+ dwc2_platform.ko. For all modes(host, gadget and dual-role), there
+ will be an additional module named dwc2.ko.
if USB_DWC2
+choice
+ bool "DWC2 Mode Selection"
+ default USB_DWC2_DUAL_ROLE if (USB && USB_GADGET)
+ default USB_DWC2_HOST if (USB && !USB_GADGET)
+ default USB_DWC2_PERIPHERAL if (!USB && USB_GADGET)
+
config USB_DWC2_HOST
- tristate "Host only mode"
+ bool "Host only mode"
depends on USB
help
The Designware USB2.0 high-speed host controller
- integrated into many SoCs.
+ integrated into many SoCs. Select this option if you want the
+ driver to operate in Host-only mode.
-config USB_DWC2_PLATFORM
- bool "DWC2 Platform"
- depends on USB_DWC2_HOST
- default USB_DWC2_HOST
+comment "Gadget/Dual-role mode requires USB Gadget support to be enabled"
+
+config USB_DWC2_PERIPHERAL
+ bool "Gadget only mode"
+ depends on USB_GADGET=y || USB_GADGET=USB_DWC2
help
- The Designware USB2.0 platform interface module for
- controllers directly connected to the CPU. This is only
- used for host mode.
+ The Designware USB2.0 high-speed gadget controller
+ integrated into many SoCs. Select this option if you want the
+ driver to operate in Peripheral-only mode. This option requires
+ USB_GADGET to be enabled.
+
+config USB_DWC2_DUAL_ROLE
+ bool "Dual Role mode"
+ depends on (USB=y || USB=USB_DWC2) && (USB_GADGET=y || USB_GADGET=USB_DWC2)
+ help
+ Select this option if you want the driver to work in a dual-role
+ mode. In this mode both host and gadget features are enabled, and
+ the role will be determined by the cable that gets plugged-in. This
+ option requires USB_GADGET to be enabled.
+endchoice
+
+config USB_DWC2_PLATFORM
+ tristate "DWC2 Platform"
+ default USB_DWC2_HOST || USB_DWC2_PERIPHERAL
+ help
+ The Designware USB2.0 platform interface module for
+ controllers directly connected to the CPU.
config USB_DWC2_PCI
- bool "DWC2 PCI"
+ tristate "DWC2 PCI"
depends on USB_DWC2_HOST && PCI
default USB_DWC2_HOST
help
The Designware USB2.0 PCI interface module for controllers
connected to a PCI bus. This is only used for host mode.
-comment "Gadget mode requires USB Gadget support to be enabled"
-
-config USB_DWC2_PERIPHERAL
- tristate "Gadget only mode"
- depends on USB_GADGET
- help
- The Designware USB2.0 high-speed gadget controller
- integrated into many SoCs.
-
config USB_DWC2_DEBUG
bool "Enable Debugging Messages"
help
diff --git a/drivers/usb/dwc2/Makefile b/drivers/usb/dwc2/Makefile
index b73d2a527970..8f752679752a 100644
--- a/drivers/usb/dwc2/Makefile
+++ b/drivers/usb/dwc2/Makefile
@@ -1,28 +1,28 @@
ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG
ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG
-obj-$(CONFIG_USB_DWC2_HOST) += dwc2.o
+obj-$(CONFIG_USB_DWC2) += dwc2.o
dwc2-y := core.o core_intr.o
-dwc2-y += hcd.o hcd_intr.o
-dwc2-y += hcd_queue.o hcd_ddma.o
+
+ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
+ dwc2-y += hcd.o hcd_intr.o
+ dwc2-y += hcd_queue.o hcd_ddma.o
+endif
+
+ifneq ($(filter y,$(CONFIG_USB_DWC2_PERIPHERAL) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
+ dwc2-y += gadget.o
+endif
# NOTE: The previous s3c-hsotg peripheral mode only driver has been moved to
# this location and renamed gadget.c. When building for dynamically linked
-# modules, dwc2_gadget.ko will get built for peripheral mode. For host mode,
-# the core module will be dwc2.ko, the PCI bus interface module will called
-# dwc2_pci.ko and the platform interface module will be called dwc2_platform.ko.
-# At present the host and gadget driver will be separate drivers, but there
-# are plans in the near future to create a dual-role driver.
+# modules, dwc2.ko will get built for host mode, peripheral mode, and dual-role
+# mode. The PCI bus interface module will called dwc2_pci.ko and the platform
+# interface module will be called dwc2_platform.ko.
ifneq ($(CONFIG_USB_DWC2_PCI),)
- obj-$(CONFIG_USB_DWC2_HOST) += dwc2_pci.o
+ obj-$(CONFIG_USB_DWC2) += dwc2_pci.o
dwc2_pci-y := pci.o
endif
-ifneq ($(CONFIG_USB_DWC2_PLATFORM),)
- obj-$(CONFIG_USB_DWC2_HOST) += dwc2_platform.o
- dwc2_platform-y := platform.o
-endif
-
-obj-$(CONFIG_USB_DWC2_PERIPHERAL) += dwc2_gadget.o
-dwc2_gadget-y := gadget.o
+obj-$(CONFIG_USB_DWC2_PLATFORM) += dwc2_platform.o
+dwc2_platform-y := platform.o
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index d9269459d481..7605850b7a9c 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -458,16 +458,6 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
/* Clear the SRP success bit for FS-I2c */
hsotg->srp_success = 0;
- if (irq >= 0) {
- dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
- irq);
- retval = devm_request_irq(hsotg->dev, irq,
- dwc2_handle_common_intr, IRQF_SHARED,
- dev_name(hsotg->dev), hsotg);
- if (retval)
- return retval;
- }
-
/* Enable common interrupts */
dwc2_enable_common_interrupts(hsotg);
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 55c90c53f2d6..7a70a1349334 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -84,7 +84,7 @@ static const char * const s3c_hsotg_supply_names[] = {
*/
#define EP0_MPS_LIMIT 64
-struct s3c_hsotg;
+struct dwc2_hsotg;
struct s3c_hsotg_req;
/**
@@ -130,7 +130,7 @@ struct s3c_hsotg_req;
struct s3c_hsotg_ep {
struct usb_ep ep;
struct list_head queue;
- struct s3c_hsotg *parent;
+ struct dwc2_hsotg *parent;
struct s3c_hsotg_req *req;
struct dentry *debugfs;
@@ -155,67 +155,6 @@ struct s3c_hsotg_ep {
};
/**
- * struct s3c_hsotg - driver state.
- * @dev: The parent device supplied to the probe function
- * @driver: USB gadget driver
- * @phy: The otg phy transceiver structure for phy control.
- * @uphy: The otg phy transceiver structure for old USB phy control.
- * @plat: The platform specific configuration data. This can be removed once
- * all SoCs support usb transceiver.
- * @regs: The memory area mapped for accessing registers.
- * @irq: The IRQ number we are using
- * @supplies: Definition of USB power supplies
- * @phyif: PHY interface width
- * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
- * @num_of_eps: Number of available EPs (excluding EP0)
- * @debug_root: root directrory for debugfs.
- * @debug_file: main status file for debugfs.
- * @debug_fifo: FIFO status file for debugfs.
- * @ep0_reply: Request used for ep0 reply.
- * @ep0_buff: Buffer for EP0 reply data, if needed.
- * @ctrl_buff: Buffer for EP0 control requests.
- * @ctrl_req: Request for EP0 control packets.
- * @setup: NAK management for EP0 SETUP
- * @last_rst: Time of last reset
- * @eps: The endpoints being supplied to the gadget framework
- */
-struct s3c_hsotg {
- struct device *dev;
- struct usb_gadget_driver *driver;
- struct phy *phy;
- struct usb_phy *uphy;
- struct s3c_hsotg_plat *plat;
-
- spinlock_t lock;
-
- void __iomem *regs;
- int irq;
- struct clk *clk;
-
- struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)];
-
- u32 phyif;
- int fifo_mem;
- unsigned int dedicated_fifos:1;
- unsigned char num_of_eps;
- u32 fifo_map;
-
- struct dentry *debug_root;
- struct dentry *debug_file;
- struct dentry *debug_fifo;
-
- struct usb_request *ep0_reply;
- struct usb_request *ctrl_req;
- u8 ep0_buff[8];
- u8 ctrl_buff[8];
-
- struct usb_gadget gadget;
- unsigned int setup;
- unsigned long last_rst;
- struct s3c_hsotg_ep *eps;
-};
-
-/**
* struct s3c_hsotg_req - data transfer request
* @req: The USB gadget request
* @queue: The list of requests for the endpoint this is queued for.
@@ -229,6 +168,7 @@ struct s3c_hsotg_req {
unsigned char mapped;
};
+#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
#define call_gadget(_hs, _entry) \
do { \
if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \
@@ -238,6 +178,9 @@ do { \
spin_lock(&_hs->lock); \
} \
} while (0)
+#else
+#define call_gadget(_hs, _entry) do {} while (0)
+#endif
struct dwc2_hsotg;
struct dwc2_host_chan;
@@ -495,11 +438,13 @@ struct dwc2_hw_params {
* struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
* and periodic schedules
*
+ * These are common for both host and peripheral modes:
+ *
* @dev: The struct device pointer
* @regs: Pointer to controller regs
- * @core_params: Parameters that define how the core should be configured
* @hw_params: Parameters that were autodetected from the
* hardware registers
+ * @core_params: Parameters that define how the core should be configured
* @op_state: The operational State, during transitions (a_host=>
* a_peripheral and b_device=>b_host) this may not match
* the core, but allows the software to determine
@@ -508,6 +453,8 @@ struct dwc2_hw_params {
* - USB_DR_MODE_PERIPHERAL
* - USB_DR_MODE_HOST
* - USB_DR_MODE_OTG
+ * @lock: Spinlock that protects all the driver data structures
+ * @priv: Stores a pointer to the struct usb_hcd
* @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
* transfer are in process of being queued
* @srp_success: Stores status of SRP request in the case of a FS PHY
@@ -517,6 +464,9 @@ struct dwc2_hw_params {
* interrupt
* @wkp_timer: Timer object for handling Wakeup Detected interrupt
* @lx_state: Lx state of connected device
+ *
+ * These are for host mode:
+ *
* @flags: Flags for handling root port state changes
* @non_periodic_sched_inactive: Inactive QHs in the non-periodic schedule.
* Transfers associated with these QHs are not currently
@@ -585,11 +535,31 @@ struct dwc2_hw_params {
* @status_buf_dma: DMA address for status_buf
* @start_work: Delayed work for handling host A-cable connection
* @reset_work: Delayed work for handling a port reset
- * @lock: Spinlock that protects all the driver data structures
- * @priv: Stores a pointer to the struct usb_hcd
* @otg_port: OTG port number
* @frame_list: Frame list
* @frame_list_dma: Frame list DMA address
+ *
+ * These are for peripheral mode:
+ *
+ * @driver: USB gadget driver
+ * @phy: The otg phy transceiver structure for phy control.
+ * @uphy: The otg phy transceiver structure for old USB phy control.
+ * @plat: The platform specific configuration data. This can be removed once
+ * all SoCs support usb transceiver.
+ * @supplies: Definition of USB power supplies
+ * @phyif: PHY interface width
+ * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
+ * @num_of_eps: Number of available EPs (excluding EP0)
+ * @debug_root: Root directrory for debugfs.
+ * @debug_file: Main status file for debugfs.
+ * @debug_fifo: FIFO status file for debugfs.
+ * @ep0_reply: Request used for ep0 reply.
+ * @ep0_buff: Buffer for EP0 reply data, if needed.
+ * @ctrl_buff: Buffer for EP0 control requests.
+ * @ctrl_req: Request for EP0 control packets.
+ * @setup: NAK management for EP0 SETUP
+ * @last_rst: Time of last reset
+ * @eps: The endpoints being supplied to the gadget framework
*/
struct dwc2_hsotg {
struct device *dev;
@@ -601,6 +571,16 @@ struct dwc2_hsotg {
enum usb_otg_state op_state;
enum usb_dr_mode dr_mode;
+ struct phy *phy;
+ struct usb_phy *uphy;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)];
+
+ spinlock_t lock;
+ struct mutex init_mutex;
+ void *priv;
+ int irq;
+ struct clk *clk;
+
unsigned int queuing_high_bandwidth:1;
unsigned int srp_success:1;
@@ -609,6 +589,18 @@ struct dwc2_hsotg {
struct timer_list wkp_timer;
enum dwc2_lx_state lx_state;
+ struct dentry *debug_root;
+ struct dentry *debug_file;
+ struct dentry *debug_fifo;
+
+ /* DWC OTG HW Release versions */
+#define DWC2_CORE_REV_2_71a 0x4f54271a
+#define DWC2_CORE_REV_2_90a 0x4f54290a
+#define DWC2_CORE_REV_2_92a 0x4f54292a
+#define DWC2_CORE_REV_2_94a 0x4f54294a
+#define DWC2_CORE_REV_3_00a 0x4f54300a
+
+#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
union dwc2_hcd_internal_flags {
u32 d32;
struct {
@@ -655,19 +647,10 @@ struct dwc2_hsotg {
struct delayed_work start_work;
struct delayed_work reset_work;
- spinlock_t lock;
- void *priv;
u8 otg_port;
u32 *frame_list;
dma_addr_t frame_list_dma;
- /* DWC OTG HW Release versions */
-#define DWC2_CORE_REV_2_71a 0x4f54271a
-#define DWC2_CORE_REV_2_90a 0x4f54290a
-#define DWC2_CORE_REV_2_92a 0x4f54292a
-#define DWC2_CORE_REV_2_94a 0x4f54294a
-#define DWC2_CORE_REV_3_00a 0x4f54300a
-
#ifdef DEBUG
u32 frrem_samples;
u64 frrem_accum;
@@ -686,6 +669,31 @@ struct dwc2_hsotg {
u32 hfnum_other_samples_b;
u64 hfnum_other_frrem_accum_b;
#endif
+#endif /* CONFIG_USB_DWC2_HOST || CONFIG_USB_DWC2_DUAL_ROLE */
+
+#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
+ /* Gadget structures */
+ struct usb_gadget_driver *driver;
+ struct s3c_hsotg_plat *plat;
+
+ u32 phyif;
+ int fifo_mem;
+ unsigned int dedicated_fifos:1;
+ unsigned char num_of_eps;
+ u32 fifo_map;
+
+ struct usb_request *ep0_reply;
+ struct usb_request *ctrl_req;
+ u8 ep0_buff[8];
+ u8 ctrl_buff[8];
+
+ struct usb_gadget gadget;
+ unsigned int enabled:1;
+ unsigned int connected:1;
+ unsigned int setup:1;
+ unsigned long last_rst;
+ struct s3c_hsotg_ep *eps;
+#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
};
/* Reasons for halting a host channel */
@@ -955,4 +963,43 @@ extern void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg);
*/
extern u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg);
+/* Gadget defines */
+#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
+extern int s3c_hsotg_remove(struct dwc2_hsotg *hsotg);
+extern int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2);
+extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2);
+extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq);
+extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2);
+extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
+extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
+#else
+static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2)
+{ return 0; }
+static inline int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2)
+{ return 0; }
+static inline int s3c_hsotg_resume(struct dwc2_hsotg *dwc2)
+{ return 0; }
+static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
+{ return 0; }
+static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2) {}
+static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
+static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
+#endif
+
+#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
+extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
+extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
+extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
+#else
+static inline void dwc2_set_all_params(struct dwc2_core_params *params, int value) {}
+static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
+{ return 0; }
+static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {}
+static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {}
+static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
+ const struct dwc2_core_params *params)
+{ return 0; }
+#endif
+
#endif /* __DWC2_CORE_H__ */
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index c93918b70d03..ad43c5bc1ef1 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -128,6 +128,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
dwc2_op_state_str(hsotg));
gotgctl = readl(hsotg->regs + GOTGCTL);
+ if (dwc2_is_device_mode(hsotg))
+ s3c_hsotg_disconnect(hsotg);
+
if (hsotg->op_state == OTG_STATE_B_HOST) {
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
} else {
@@ -287,9 +290,11 @@ static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
* Release lock before scheduling workq as it holds spinlock during
* scheduling.
*/
- spin_unlock(&hsotg->lock);
- queue_work(hsotg->wq_otg, &hsotg->wf_otg);
- spin_lock(&hsotg->lock);
+ if (hsotg->wq_otg) {
+ spin_unlock(&hsotg->lock);
+ queue_work(hsotg->wq_otg, &hsotg->wf_otg);
+ spin_lock(&hsotg->lock);
+ }
/* Clear interrupt */
writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
@@ -312,6 +317,12 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
/* Clear interrupt */
writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
+
+ /*
+ * Report disconnect if there is any previous session established
+ */
+ if (dwc2_is_device_mode(hsotg))
+ s3c_hsotg_disconnect(hsotg);
}
/*
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 8b5c079c7b7d..200168ec2d75 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/debugfs.h>
+#include <linux/mutex.h>
#include <linux/seq_file.h>
#include <linux/delay.h>
#include <linux/io.h>
@@ -36,6 +37,7 @@
#include <linux/platform_data/s3c-hsotg.h>
#include "core.h"
+#include "hw.h"
/* conversion functions */
static inline struct s3c_hsotg_req *our_req(struct usb_request *req)
@@ -48,9 +50,9 @@ static inline struct s3c_hsotg_ep *our_ep(struct usb_ep *ep)
return container_of(ep, struct s3c_hsotg_ep, ep);
}
-static inline struct s3c_hsotg *to_hsotg(struct usb_gadget *gadget)
+static inline struct dwc2_hsotg *to_hsotg(struct usb_gadget *gadget)
{
- return container_of(gadget, struct s3c_hsotg, gadget);
+ return container_of(gadget, struct dwc2_hsotg, gadget);
}
static inline void __orr32(void __iomem *ptr, u32 val)
@@ -64,7 +66,7 @@ static inline void __bic32(void __iomem *ptr, u32 val)
}
/* forward decleration of functions */
-static void s3c_hsotg_dump(struct s3c_hsotg *hsotg);
+static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg);
/**
* using_dma - return the DMA status of the driver.
@@ -85,7 +87,7 @@ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg);
*
* Until this issue is sorted out, we always return 'false'.
*/
-static inline bool using_dma(struct s3c_hsotg *hsotg)
+static inline bool using_dma(struct dwc2_hsotg *hsotg)
{
return false; /* support is not complete */
}
@@ -95,7 +97,7 @@ static inline bool using_dma(struct s3c_hsotg *hsotg)
* @hsotg: The device state
* @ints: A bitmask of the interrupts to enable
*/
-static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints)
+static void s3c_hsotg_en_gsint(struct dwc2_hsotg *hsotg, u32 ints)
{
u32 gsintmsk = readl(hsotg->regs + GINTMSK);
u32 new_gsintmsk;
@@ -113,7 +115,7 @@ static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints)
* @hsotg: The device state
* @ints: A bitmask of the interrupts to enable
*/
-static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints)
+static void s3c_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints)
{
u32 gsintmsk = readl(hsotg->regs + GINTMSK);
u32 new_gsintmsk;
@@ -134,7 +136,7 @@ static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints)
* Set or clear the mask for an individual endpoint's interrupt
* request.
*/
-static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg,
+static void s3c_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg,
unsigned int ep, unsigned int dir_in,
unsigned int en)
{
@@ -159,7 +161,7 @@ static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg,
* s3c_hsotg_init_fifo - initialise non-periodic FIFOs
* @hsotg: The device instance.
*/
-static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
{
unsigned int ep;
unsigned int addr;
@@ -283,7 +285,7 @@ static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep)
* This is the reverse of s3c_hsotg_map_dma(), called for the completion
* of a request to ensure the buffer is ready for access by the caller.
*/
-static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
+static void s3c_hsotg_unmap_dma(struct dwc2_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct s3c_hsotg_req *hs_req)
{
@@ -312,7 +314,7 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
*
* This routine is only needed for PIO
*/
-static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
+static int s3c_hsotg_write_fifo(struct dwc2_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct s3c_hsotg_req *hs_req)
{
@@ -517,7 +519,7 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep)
* Start the given request running by setting the endpoint registers
* appropriately, and writing any data to the FIFOs.
*/
-static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
+static void s3c_hsotg_start_req(struct dwc2_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct s3c_hsotg_req *hs_req,
bool continuing)
@@ -707,7 +709,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
* DMA memory, then we map the memory and mark our request to allow us to
* cleanup on completion.
*/
-static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg,
+static int s3c_hsotg_map_dma(struct dwc2_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct usb_request *req)
{
@@ -736,7 +738,7 @@ static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
{
struct s3c_hsotg_req *hs_req = our_req(req);
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
- struct s3c_hsotg *hs = hs_ep->parent;
+ struct dwc2_hsotg *hs = hs_ep->parent;
bool first;
dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n",
@@ -768,7 +770,7 @@ static int s3c_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req,
gfp_t gfp_flags)
{
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
- struct s3c_hsotg *hs = hs_ep->parent;
+ struct dwc2_hsotg *hs = hs_ep->parent;
unsigned long flags = 0;
int ret = 0;
@@ -799,7 +801,7 @@ static void s3c_hsotg_complete_oursetup(struct usb_ep *ep,
struct usb_request *req)
{
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
- struct s3c_hsotg *hsotg = hs_ep->parent;
+ struct dwc2_hsotg *hsotg = hs_ep->parent;
dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req);
@@ -814,7 +816,7 @@ static void s3c_hsotg_complete_oursetup(struct usb_ep *ep,
* Convert the given wIndex into a pointer to an driver endpoint
* structure, or return NULL if it is not a valid endpoint.
*/
-static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg,
+static struct s3c_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
u32 windex)
{
struct s3c_hsotg_ep *ep = &hsotg->eps[windex & 0x7F];
@@ -843,7 +845,7 @@ static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg,
* Create a request and queue it on the given endpoint. This is useful as
* an internal method of sending replies to certain control requests, etc.
*/
-static int s3c_hsotg_send_reply(struct s3c_hsotg *hsotg,
+static int s3c_hsotg_send_reply(struct dwc2_hsotg *hsotg,
struct s3c_hsotg_ep *ep,
void *buff,
int length)
@@ -884,7 +886,7 @@ static int s3c_hsotg_send_reply(struct s3c_hsotg *hsotg,
* @hsotg: The device state
* @ctrl: USB control request
*/
-static int s3c_hsotg_process_req_status(struct s3c_hsotg *hsotg,
+static int s3c_hsotg_process_req_status(struct dwc2_hsotg *hsotg,
struct usb_ctrlrequest *ctrl)
{
struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
@@ -955,7 +957,7 @@ static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep)
* @hsotg: The device state
* @ctrl: USB control request
*/
-static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,
+static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
struct usb_ctrlrequest *ctrl)
{
struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
@@ -1028,8 +1030,7 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,
return 1;
}
-static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg);
-static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg);
+static void s3c_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg);
/**
* s3c_hsotg_stall_ep0 - stall ep0
@@ -1037,7 +1038,7 @@ static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg);
*
* Set stall for ep0 as response for setup request.
*/
-static void s3c_hsotg_stall_ep0(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_stall_ep0(struct dwc2_hsotg *hsotg)
{
struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
u32 reg;
@@ -1076,7 +1077,7 @@ static void s3c_hsotg_stall_ep0(struct s3c_hsotg *hsotg)
* needs to work out what to do next (and whether to pass it on to the
* gadget driver).
*/
-static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
+static void s3c_hsotg_process_control(struct dwc2_hsotg *hsotg,
struct usb_ctrlrequest *ctrl)
{
struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
@@ -1107,7 +1108,6 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
switch (ctrl->bRequest) {
case USB_REQ_SET_ADDRESS:
- s3c_hsotg_disconnect(hsotg);
dcfg = readl(hsotg->regs + DCFG);
dcfg &= ~DCFG_DEVADDR_MASK;
dcfg |= (le16_to_cpu(ctrl->wValue) <<
@@ -1161,7 +1161,7 @@ static void s3c_hsotg_complete_setup(struct usb_ep *ep,
struct usb_request *req)
{
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
- struct s3c_hsotg *hsotg = hs_ep->parent;
+ struct dwc2_hsotg *hsotg = hs_ep->parent;
if (req->status < 0) {
dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status);
@@ -1183,7 +1183,7 @@ static void s3c_hsotg_complete_setup(struct usb_ep *ep,
* Enqueue a request on EP0 if necessary to received any SETUP packets
* received from the host.
*/
-static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg)
{
struct usb_request *req = hsotg->ctrl_req;
struct s3c_hsotg_req *hs_req = our_req(req);
@@ -1226,7 +1226,7 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg)
*
* Note, expects the ep to already be locked as appropriate.
*/
-static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
+static void s3c_hsotg_complete_request(struct dwc2_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct s3c_hsotg_req *hs_req,
int result)
@@ -1291,7 +1291,7 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
* endpoint, so sort out whether we need to read the data into a request
* that has been made for that endpoint.
*/
-static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
+static void s3c_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size)
{
struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx];
struct s3c_hsotg_req *hs_req = hs_ep->req;
@@ -1356,7 +1356,7 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
* currently believed that we do not need to wait for any space in
* the TxFIFO.
*/
-static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg,
+static void s3c_hsotg_send_zlp(struct dwc2_hsotg *hsotg,
struct s3c_hsotg_req *req)
{
u32 ctrl;
@@ -1398,7 +1398,7 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg,
* transfer for an OUT endpoint has been completed, either by a short
* packet or by the finish of a transfer.
*/
-static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
+static void s3c_hsotg_handle_outdone(struct dwc2_hsotg *hsotg,
int epnum, bool was_setup)
{
u32 epsize = readl(hsotg->regs + DOEPTSIZ(epnum));
@@ -1471,7 +1471,7 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
*
* Return the current frame number
*/
-static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg)
+static u32 s3c_hsotg_read_frameno(struct dwc2_hsotg *hsotg)
{
u32 dsts;
@@ -1498,7 +1498,7 @@ static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg)
* as the actual data should be sent to the memory directly and we turn
* on the completion interrupts to get notifications of transfer completion.
*/
-static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_handle_rx(struct dwc2_hsotg *hsotg)
{
u32 grxstsr = readl(hsotg->regs + GRXSTSP);
u32 epnum, status, size;
@@ -1590,7 +1590,7 @@ static u32 s3c_hsotg_ep0_mps(unsigned int mps)
* Configure the maximum packet size for the given endpoint, updating
* the hardware control registers to reflect this.
*/
-static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg,
+static void s3c_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg,
unsigned int ep, unsigned int mps)
{
struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep];
@@ -1645,7 +1645,7 @@ bad_mps:
* @hsotg: The driver state
* @idx: The index for the endpoint (0..15)
*/
-static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx)
+static void s3c_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx)
{
int timeout;
int val;
@@ -1681,7 +1681,7 @@ static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx)
* Check to see if there is a request that has data to send, and if so
* make an attempt to write data into the FIFO.
*/
-static int s3c_hsotg_trytx(struct s3c_hsotg *hsotg,
+static int s3c_hsotg_trytx(struct dwc2_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep)
{
struct s3c_hsotg_req *hs_req = hs_ep->req;
@@ -1714,7 +1714,7 @@ static int s3c_hsotg_trytx(struct s3c_hsotg *hsotg,
* An IN transfer has been completed, update the transfer's state and then
* call the relevant completion routines.
*/
-static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
+static void s3c_hsotg_complete_in(struct dwc2_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep)
{
struct s3c_hsotg_req *hs_req = hs_ep->req;
@@ -1791,7 +1791,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
*
* Process and clear any interrupt pending for an individual endpoint
*/
-static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
+static void s3c_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
int dir_in)
{
struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx];
@@ -1916,7 +1916,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
* Handle updating the device settings after the enumeration phase has
* been completed.
*/
-static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg)
{
u32 dsts = readl(hsotg->regs + DSTS);
int ep0_mps = 0, ep_mps = 8;
@@ -1993,7 +1993,7 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)
* Go through the requests on the given endpoint and mark them
* completed with the given result code.
*/
-static void kill_all_requests(struct s3c_hsotg *hsotg,
+static void kill_all_requests(struct dwc2_hsotg *hsotg,
struct s3c_hsotg_ep *ep,
int result, bool force)
{
@@ -2027,22 +2027,27 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
* transactions and signal the gadget driver that this
* has happened.
*/
-static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg)
+void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg)
{
unsigned ep;
+ if (!hsotg->connected)
+ return;
+
+ hsotg->connected = 0;
for (ep = 0; ep < hsotg->num_of_eps; ep++)
kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true);
call_gadget(hsotg, disconnect);
}
+EXPORT_SYMBOL_GPL(s3c_hsotg_disconnect);
/**
* s3c_hsotg_irq_fifoempty - TX FIFO empty interrupt handler
* @hsotg: The device state:
* @periodic: True if this is a periodic FIFO interrupt
*/
-static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic)
+static void s3c_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic)
{
struct s3c_hsotg_ep *ep;
int epno, ret;
@@ -2076,7 +2081,7 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic)
*
* Issue a soft reset to the core, and await the core finishing it.
*/
-static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
+static int s3c_hsotg_corereset(struct dwc2_hsotg *hsotg)
{
int timeout;
u32 grstctl;
@@ -2124,7 +2129,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
*
* Issue a soft reset to the core, and await the core finishing it.
*/
-static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg)
+void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg)
{
s3c_hsotg_corereset(hsotg);
@@ -2241,12 +2246,23 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg)
readl(hsotg->regs + DOEPCTL0));
/* clear global NAKs */
- writel(DCTL_CGOUTNAK | DCTL_CGNPINNAK,
+ writel(DCTL_CGOUTNAK | DCTL_CGNPINNAK | DCTL_SFTDISCON,
hsotg->regs + DCTL);
/* must be at-least 3ms to allow bus to see disconnect */
mdelay(3);
+ hsotg->last_rst = jiffies;
+}
+
+static void s3c_hsotg_core_disconnect(struct dwc2_hsotg *hsotg)
+{
+ /* set the soft-disconnect bit */
+ __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
+}
+
+void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg)
+{
/* remove the soft-disconnect and let's go */
__bic32(hsotg->regs + DCTL, DCTL_SFTDISCON);
}
@@ -2258,7 +2274,7 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg)
*/
static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
{
- struct s3c_hsotg *hsotg = pw;
+ struct dwc2_hsotg *hsotg = pw;
int retry_count = 8;
u32 gintsts;
u32 gintmsk;
@@ -2273,31 +2289,11 @@ irq_retry:
gintsts &= gintmsk;
- if (gintsts & GINTSTS_OTGINT) {
- u32 otgint = readl(hsotg->regs + GOTGINT);
-
- dev_info(hsotg->dev, "OTGInt: %08x\n", otgint);
-
- writel(otgint, hsotg->regs + GOTGINT);
- }
-
- if (gintsts & GINTSTS_SESSREQINT) {
- dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__);
- writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
- }
-
if (gintsts & GINTSTS_ENUMDONE) {
writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS);
s3c_hsotg_irq_enumdone(hsotg);
- }
-
- if (gintsts & GINTSTS_CONIDSTSCHNG) {
- dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n",
- readl(hsotg->regs + DSTS),
- readl(hsotg->regs + GOTGCTL));
-
- writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
+ hsotg->connected = 1;
}
if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) {
@@ -2340,8 +2336,8 @@ irq_retry:
kill_all_requests(hsotg, &hsotg->eps[0],
-ECONNRESET, true);
- s3c_hsotg_core_init(hsotg);
- hsotg->last_rst = jiffies;
+ s3c_hsotg_core_init_disconnected(hsotg);
+ s3c_hsotg_core_connect(hsotg);
}
}
}
@@ -2380,25 +2376,6 @@ irq_retry:
s3c_hsotg_handle_rx(hsotg);
}
- if (gintsts & GINTSTS_MODEMIS) {
- dev_warn(hsotg->dev, "warning, mode mismatch triggered\n");
- writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
- }
-
- if (gintsts & GINTSTS_USBSUSP) {
- dev_info(hsotg->dev, "GINTSTS_USBSusp\n");
- writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
-
- call_gadget(hsotg, suspend);
- }
-
- if (gintsts & GINTSTS_WKUPINT) {
- dev_info(hsotg->dev, "GINTSTS_WkUpIn\n");
- writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
-
- call_gadget(hsotg, resume);
- }
-
if (gintsts & GINTSTS_ERLYSUSP) {
dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n");
writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS);
@@ -2450,7 +2427,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc)
{
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
- struct s3c_hsotg *hsotg = hs_ep->parent;
+ struct dwc2_hsotg *hsotg = hs_ep->parent;
unsigned long flags;
int index = hs_ep->index;
u32 epctrl_reg;
@@ -2593,7 +2570,7 @@ error:
static int s3c_hsotg_ep_disable(struct usb_ep *ep)
{
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
- struct s3c_hsotg *hsotg = hs_ep->parent;
+ struct dwc2_hsotg *hsotg = hs_ep->parent;
int dir_in = hs_ep->dir_in;
int index = hs_ep->index;
unsigned long flags;
@@ -2658,7 +2635,7 @@ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
{
struct s3c_hsotg_req *hs_req = our_req(req);
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
- struct s3c_hsotg *hs = hs_ep->parent;
+ struct dwc2_hsotg *hs = hs_ep->parent;
unsigned long flags;
dev_dbg(hs->dev, "ep_dequeue(%p,%p)\n", ep, req);
@@ -2684,7 +2661,7 @@ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
{
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
- struct s3c_hsotg *hs = hs_ep->parent;
+ struct dwc2_hsotg *hs = hs_ep->parent;
int index = hs_ep->index;
u32 epreg;
u32 epctl;
@@ -2748,7 +2725,7 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
static int s3c_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value)
{
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
- struct s3c_hsotg *hs = hs_ep->parent;
+ struct dwc2_hsotg *hs = hs_ep->parent;
unsigned long flags = 0;
int ret = 0;
@@ -2777,7 +2754,7 @@ static struct usb_ep_ops s3c_hsotg_ep_ops = {
* A wrapper for platform code responsible for controlling
* low-level USB code
*/
-static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_phy_enable(struct dwc2_hsotg *hsotg)
{
struct platform_device *pdev = to_platform_device(hsotg->dev);
@@ -2800,7 +2777,7 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
* A wrapper for platform code responsible for controlling
* low-level USB code
*/
-static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_phy_disable(struct dwc2_hsotg *hsotg)
{
struct platform_device *pdev = to_platform_device(hsotg->dev);
@@ -2818,7 +2795,7 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
* s3c_hsotg_init - initalize the usb core
* @hsotg: The driver state
*/
-static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_init(struct dwc2_hsotg *hsotg)
{
/* unmask subset of endpoint interrupts */
@@ -2868,7 +2845,8 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
- struct s3c_hsotg *hsotg = to_hsotg(gadget);
+ struct dwc2_hsotg *hsotg = to_hsotg(gadget);
+ unsigned long flags;
int ret;
if (!hsotg) {
@@ -2889,6 +2867,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
return -EINVAL;
}
+ mutex_lock(&hsotg->init_mutex);
WARN_ON(hsotg->driver);
driver->driver.bus = NULL;
@@ -2905,11 +2884,22 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
goto err;
}
- hsotg->last_rst = jiffies;
+ s3c_hsotg_phy_enable(hsotg);
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ s3c_hsotg_init(hsotg);
+ s3c_hsotg_core_init_disconnected(hsotg);
+ hsotg->enabled = 0;
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+
dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
+
+ mutex_unlock(&hsotg->init_mutex);
+
return 0;
err:
+ mutex_unlock(&hsotg->init_mutex);
hsotg->driver = NULL;
return ret;
}
@@ -2921,16 +2911,17 @@ err:
*
* Stop udc hw block and stay tunned for future transmissions
*/
-static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static int s3c_hsotg_udc_stop(struct usb_gadget *gadget)
{
- struct s3c_hsotg *hsotg = to_hsotg(gadget);
+ struct dwc2_hsotg *hsotg = to_hsotg(gadget);
unsigned long flags = 0;
int ep;
if (!hsotg)
return -ENODEV;
+ mutex_lock(&hsotg->init_mutex);
+
/* all endpoints should be shutdown */
for (ep = 1; ep < hsotg->num_of_eps; ep++)
s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
@@ -2939,13 +2930,18 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
hsotg->driver = NULL;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
+ hsotg->enabled = 0;
spin_unlock_irqrestore(&hsotg->lock, flags);
+ s3c_hsotg_phy_disable(hsotg);
+
regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
clk_disable(hsotg->clk);
+ mutex_unlock(&hsotg->init_mutex);
+
return 0;
}
@@ -2969,23 +2965,26 @@ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
*/
static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on)
{
- struct s3c_hsotg *hsotg = to_hsotg(gadget);
+ struct dwc2_hsotg *hsotg = to_hsotg(gadget);
unsigned long flags = 0;
dev_dbg(hsotg->dev, "%s: is_on: %d\n", __func__, is_on);
+ mutex_lock(&hsotg->init_mutex);
spin_lock_irqsave(&hsotg->lock, flags);
if (is_on) {
- s3c_hsotg_phy_enable(hsotg);
clk_enable(hsotg->clk);
- s3c_hsotg_core_init(hsotg);
+ hsotg->enabled = 1;
+ s3c_hsotg_core_connect(hsotg);
} else {
+ s3c_hsotg_core_disconnect(hsotg);
+ hsotg->enabled = 0;
clk_disable(hsotg->clk);
- s3c_hsotg_phy_disable(hsotg);
}
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
spin_unlock_irqrestore(&hsotg->lock, flags);
+ mutex_unlock(&hsotg->init_mutex);
return 0;
}
@@ -3007,7 +3006,7 @@ static const struct usb_gadget_ops s3c_hsotg_gadget_ops = {
* creation) to give to the gadget driver. Setup the endpoint name, any
* direction information and other state that may be required.
*/
-static void s3c_hsotg_initep(struct s3c_hsotg *hsotg,
+static void s3c_hsotg_initep(struct dwc2_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
int epnum)
{
@@ -3056,7 +3055,7 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg,
*
* Read the USB core HW configuration registers
*/
-static void s3c_hsotg_hw_cfg(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_hw_cfg(struct dwc2_hsotg *hsotg)
{
u32 cfg2, cfg3, cfg4;
/* check hardware configuration */
@@ -3080,7 +3079,7 @@ static void s3c_hsotg_hw_cfg(struct s3c_hsotg *hsotg)
* s3c_hsotg_dump - dump state of the udc
* @param: The device state
*/
-static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg)
{
#ifdef DEBUG
struct device *dev = hsotg->dev;
@@ -3139,7 +3138,7 @@ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)
*/
static int state_show(struct seq_file *seq, void *v)
{
- struct s3c_hsotg *hsotg = seq->private;
+ struct dwc2_hsotg *hsotg = seq->private;
void __iomem *regs = hsotg->regs;
int idx;
@@ -3209,7 +3208,7 @@ static const struct file_operations state_fops = {
*/
static int fifo_show(struct seq_file *seq, void *v)
{
- struct s3c_hsotg *hsotg = seq->private;
+ struct dwc2_hsotg *hsotg = seq->private;
void __iomem *regs = hsotg->regs;
u32 val;
int idx;
@@ -3265,7 +3264,7 @@ static const char *decode_direction(int is_in)
static int ep_show(struct seq_file *seq, void *v)
{
struct s3c_hsotg_ep *ep = seq->private;
- struct s3c_hsotg *hsotg = ep->parent;
+ struct dwc2_hsotg *hsotg = ep->parent;
struct s3c_hsotg_req *req;
void __iomem *regs = hsotg->regs;
int index = ep->index;
@@ -3342,7 +3341,7 @@ static const struct file_operations ep_fops = {
* with the same name as the device itself, in case we end up
* with multiple blocks in future systems.
*/
-static void s3c_hsotg_create_debug(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
{
struct dentry *root;
unsigned epidx;
@@ -3388,7 +3387,7 @@ static void s3c_hsotg_create_debug(struct s3c_hsotg *hsotg)
*
* Cleanup (remove) the debugfs files for use on module exit.
*/
-static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_delete_debug(struct dwc2_hsotg *hsotg)
{
unsigned epidx;
@@ -3403,27 +3402,21 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
}
/**
- * s3c_hsotg_probe - probe function for hsotg driver
- * @pdev: The platform information for the driver
+ * dwc2_gadget_init - init function for gadget
+ * @dwc2: The data structure for the DWC2 driver.
+ * @irq: The IRQ number for the controller.
*/
-
-static int s3c_hsotg_probe(struct platform_device *pdev)
+int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
{
- struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
+ struct device *dev = hsotg->dev;
+ struct s3c_hsotg_plat *plat = dev->platform_data;
struct phy *phy;
struct usb_phy *uphy;
- struct device *dev = &pdev->dev;
struct s3c_hsotg_ep *eps;
- struct s3c_hsotg *hsotg;
- struct resource *res;
int epnum;
int ret;
int i;
- hsotg = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsotg), GFP_KERNEL);
- if (!hsotg)
- return -ENOMEM;
-
/* Set default UTMI width */
hsotg->phyif = GUSBCFG_PHYIF16;
@@ -3431,14 +3424,14 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
* Attempt to find a generic PHY, then look for an old style
* USB PHY, finally fall back to pdata
*/
- phy = devm_phy_get(&pdev->dev, "usb2-phy");
+ phy = devm_phy_get(dev, "usb2-phy");
if (IS_ERR(phy)) {
uphy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
if (IS_ERR(uphy)) {
/* Fallback for pdata */
- plat = dev_get_platdata(&pdev->dev);
+ plat = dev_get_platdata(dev);
if (!plat) {
- dev_err(&pdev->dev,
+ dev_err(dev,
"no platform data or transceiver defined\n");
return -EPROBE_DEFER;
}
@@ -3455,43 +3448,24 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
hsotg->phyif = GUSBCFG_PHYIF8;
}
- hsotg->dev = dev;
-
- hsotg->clk = devm_clk_get(&pdev->dev, "otg");
+ hsotg->clk = devm_clk_get(dev, "otg");
if (IS_ERR(hsotg->clk)) {
- dev_err(dev, "cannot get otg clock\n");
- return PTR_ERR(hsotg->clk);
- }
-
- platform_set_drvdata(pdev, hsotg);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- hsotg->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(hsotg->regs)) {
- ret = PTR_ERR(hsotg->regs);
- goto err_clk;
+ hsotg->clk = NULL;
+ dev_dbg(dev, "cannot get otg clock\n");
}
- ret = platform_get_irq(pdev, 0);
- if (ret < 0) {
- dev_err(dev, "cannot find IRQ\n");
- goto err_clk;
- }
-
- spin_lock_init(&hsotg->lock);
-
- hsotg->irq = ret;
-
- dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq);
-
hsotg->gadget.max_speed = USB_SPEED_HIGH;
hsotg->gadget.ops = &s3c_hsotg_gadget_ops;
hsotg->gadget.name = dev_name(dev);
/* reset the system */
- clk_prepare_enable(hsotg->clk);
+ ret = clk_prepare_enable(hsotg->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable otg clk\n");
+ goto err_clk;
+ }
+
/* regulators */
@@ -3509,7 +3483,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
hsotg->supplies);
if (ret) {
- dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret);
+ dev_err(dev, "failed to enable supplies: %d\n", ret);
goto err_supplies;
}
@@ -3520,14 +3494,14 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
s3c_hsotg_hw_cfg(hsotg);
s3c_hsotg_init(hsotg);
- ret = devm_request_irq(&pdev->dev, hsotg->irq, s3c_hsotg_irq, 0,
- dev_name(dev), hsotg);
+ ret = devm_request_irq(hsotg->dev, irq, s3c_hsotg_irq, IRQF_SHARED,
+ dev_name(hsotg->dev), hsotg);
if (ret < 0) {
s3c_hsotg_phy_disable(hsotg);
clk_disable_unprepare(hsotg->clk);
regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
- dev_err(dev, "cannot claim IRQ\n");
+ dev_err(dev, "cannot claim IRQ for gadget\n");
goto err_clk;
}
@@ -3573,11 +3547,11 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
if (ret) {
- dev_err(hsotg->dev, "failed to disable supplies: %d\n", ret);
+ dev_err(dev, "failed to disable supplies: %d\n", ret);
goto err_ep_mem;
}
- ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
+ ret = usb_add_gadget_udc(dev, &hsotg->gadget);
if (ret)
goto err_ep_mem;
@@ -3596,47 +3570,44 @@ err_clk:
return ret;
}
+EXPORT_SYMBOL_GPL(dwc2_gadget_init);
/**
* s3c_hsotg_remove - remove function for hsotg driver
* @pdev: The platform information for the driver
*/
-static int s3c_hsotg_remove(struct platform_device *pdev)
+int s3c_hsotg_remove(struct dwc2_hsotg *hsotg)
{
- struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
-
usb_del_gadget_udc(&hsotg->gadget);
-
s3c_hsotg_delete_debug(hsotg);
-
- if (hsotg->driver) {
- /* should have been done already by driver model core */
- usb_gadget_unregister_driver(hsotg->driver);
- }
-
clk_disable_unprepare(hsotg->clk);
return 0;
}
+EXPORT_SYMBOL_GPL(s3c_hsotg_remove);
-static int s3c_hsotg_suspend(struct platform_device *pdev, pm_message_t state)
+int s3c_hsotg_suspend(struct dwc2_hsotg *hsotg)
{
- struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
unsigned long flags;
int ret = 0;
- if (hsotg->driver)
+ mutex_lock(&hsotg->init_mutex);
+
+ if (hsotg->driver) {
+ int ep;
+
dev_info(hsotg->dev, "suspending usb gadget %s\n",
hsotg->driver->driver.name);
- spin_lock_irqsave(&hsotg->lock, flags);
- s3c_hsotg_disconnect(hsotg);
- s3c_hsotg_phy_disable(hsotg);
- hsotg->gadget.speed = USB_SPEED_UNKNOWN;
- spin_unlock_irqrestore(&hsotg->lock, flags);
+ spin_lock_irqsave(&hsotg->lock, flags);
+ if (hsotg->enabled)
+ s3c_hsotg_core_disconnect(hsotg);
+ s3c_hsotg_disconnect(hsotg);
+ hsotg->gadget.speed = USB_SPEED_UNKNOWN;
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+
+ s3c_hsotg_phy_disable(hsotg);
- if (hsotg->driver) {
- int ep;
for (ep = 0; ep < hsotg->num_of_eps; ep++)
s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
@@ -3645,57 +3616,37 @@ static int s3c_hsotg_suspend(struct platform_device *pdev, pm_message_t state)
clk_disable(hsotg->clk);
}
+ mutex_unlock(&hsotg->init_mutex);
+
return ret;
}
+EXPORT_SYMBOL_GPL(s3c_hsotg_suspend);
-static int s3c_hsotg_resume(struct platform_device *pdev)
+int s3c_hsotg_resume(struct dwc2_hsotg *hsotg)
{
- struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
unsigned long flags;
int ret = 0;
+ mutex_lock(&hsotg->init_mutex);
+
if (hsotg->driver) {
dev_info(hsotg->dev, "resuming usb gadget %s\n",
hsotg->driver->driver.name);
clk_enable(hsotg->clk);
ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
- hsotg->supplies);
- }
+ hsotg->supplies);
- spin_lock_irqsave(&hsotg->lock, flags);
- hsotg->last_rst = jiffies;
- s3c_hsotg_phy_enable(hsotg);
- s3c_hsotg_core_init(hsotg);
- spin_unlock_irqrestore(&hsotg->lock, flags);
+ s3c_hsotg_phy_enable(hsotg);
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ s3c_hsotg_core_init_disconnected(hsotg);
+ if (hsotg->enabled)
+ s3c_hsotg_core_connect(hsotg);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ }
+ mutex_unlock(&hsotg->init_mutex);
return ret;
}
-
-#ifdef CONFIG_OF
-static const struct of_device_id s3c_hsotg_of_ids[] = {
- { .compatible = "samsung,s3c6400-hsotg", },
- { .compatible = "snps,dwc2", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, s3c_hsotg_of_ids);
-#endif
-
-static struct platform_driver s3c_hsotg_driver = {
- .driver = {
- .name = "s3c-hsotg",
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(s3c_hsotg_of_ids),
- },
- .probe = s3c_hsotg_probe,
- .remove = s3c_hsotg_remove,
- .suspend = s3c_hsotg_suspend,
- .resume = s3c_hsotg_resume,
-};
-
-module_platform_driver(s3c_hsotg_driver);
-
-MODULE_DESCRIPTION("Samsung S3C USB High-speed/OtG device");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c-hsotg");
+EXPORT_SYMBOL_GPL(s3c_hsotg_resume);
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 0a0e6f0ad15f..a0cd9db6f4cd 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -1371,6 +1371,8 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
dwc2_core_init(hsotg, false, -1);
dwc2_enable_global_interrupts(hsotg);
+ s3c_hsotg_core_init_disconnected(hsotg);
+ s3c_hsotg_core_connect(hsotg);
} else {
/* A-Device connector (Host Mode) */
dev_dbg(hsotg->dev, "connId A\n");
@@ -1471,6 +1473,30 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
}
}
+static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
+{
+ u32 hprt0;
+
+ /* After clear the Stop PHY clock bit, we should wait for a moment
+ * for PLL work stable with clock output.
+ */
+ writel(0, hsotg->regs + PCGCTL);
+ usleep_range(2000, 4000);
+
+ hprt0 = dwc2_read_hprt0(hsotg);
+ hprt0 |= HPRT0_RES;
+ writel(hprt0, hsotg->regs + HPRT0);
+ hprt0 &= ~HPRT0_SUSP;
+ /* according to USB2.0 Spec 7.1.7.7, the host must send the resume
+ * signal for at least 20ms
+ */
+ usleep_range(20000, 25000);
+
+ hprt0 &= ~HPRT0_RES;
+ writel(hprt0, hsotg->regs + HPRT0);
+ hsotg->lx_state = DWC2_L0;
+}
+
/* Handles hub class-specific requests */
static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
u16 wvalue, u16 windex, char *buf, u16 wlength)
@@ -1516,17 +1542,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
case USB_PORT_FEAT_SUSPEND:
dev_dbg(hsotg->dev,
"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
- writel(0, hsotg->regs + PCGCTL);
- usleep_range(20000, 40000);
-
- hprt0 = dwc2_read_hprt0(hsotg);
- hprt0 |= HPRT0_RES;
- writel(hprt0, hsotg->regs + HPRT0);
- hprt0 &= ~HPRT0_SUSP;
- usleep_range(100000, 150000);
-
- hprt0 &= ~HPRT0_RES;
- writel(hprt0, hsotg->regs + HPRT0);
+ dwc2_port_resume(hsotg);
break;
case USB_PORT_FEAT_POWER:
@@ -2299,6 +2315,55 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
usleep_range(1000, 3000);
}
+static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
+{
+ struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+ u32 hprt0;
+
+ if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
+ (hsotg->op_state == OTG_STATE_A_HOST)))
+ return 0;
+
+ /* TODO: We get into suspend from 'on' state, maybe we need to do
+ * something if we get here from DWC2_L1(LPM sleep) state one day.
+ */
+ if (hsotg->lx_state != DWC2_L0)
+ return 0;
+
+ hprt0 = dwc2_read_hprt0(hsotg);
+ if (hprt0 & HPRT0_CONNSTS) {
+ dwc2_port_suspend(hsotg, 1);
+ } else {
+ u32 pcgctl = readl(hsotg->regs + PCGCTL);
+
+ pcgctl |= PCGCTL_STOPPCLK;
+ writel(pcgctl, hsotg->regs + PCGCTL);
+ }
+
+ return 0;
+}
+
+static int _dwc2_hcd_resume(struct usb_hcd *hcd)
+{
+ struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+ u32 hprt0;
+
+ if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
+ (hsotg->op_state == OTG_STATE_A_HOST)))
+ return 0;
+
+ if (hsotg->lx_state != DWC2_L2)
+ return 0;
+
+ hprt0 = dwc2_read_hprt0(hsotg);
+ if ((hprt0 & HPRT0_CONNSTS) && (hprt0 & HPRT0_SUSP))
+ dwc2_port_resume(hsotg);
+ else
+ writel(0, hsotg->regs + PCGCTL);
+
+ return 0;
+}
+
/* Returns the current frame number */
static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
{
@@ -2669,6 +2734,9 @@ static struct hc_driver dwc2_hc_driver = {
.hub_status_data = _dwc2_hcd_hub_status_data,
.hub_control = _dwc2_hcd_hub_control,
.clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,
+
+ .bus_suspend = _dwc2_hcd_suspend,
+ .bus_resume = _dwc2_hcd_resume,
};
/*
@@ -2778,6 +2846,9 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
int i, num_channels;
int retval;
+ if (usb_disabled())
+ return -ENODEV;
+
dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n");
/* Detect config values from hardware */
@@ -2839,7 +2910,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
hcd->has_tt = 1;
- spin_lock_init(&hsotg->lock);
((struct wrapper_priv_data *) &hcd->hcd_priv)->hsotg = hsotg;
hsotg->priv = hcd;
diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h
index a12bb1538666..e69a843d8928 100644
--- a/drivers/usb/dwc2/hcd.h
+++ b/drivers/usb/dwc2/hcd.h
@@ -668,9 +668,6 @@ extern irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg);
*/
extern void dwc2_hcd_stop(struct dwc2_hsotg *hsotg);
-extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
-extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
-
/**
* dwc2_hcd_is_b_host() - Returns 1 if core currently is acting as B host,
* and 0 otherwise
@@ -680,13 +677,6 @@ extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
extern int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg);
/**
- * dwc2_hcd_get_frame_number() - Returns current frame number
- *
- * @hsotg: The DWC2 HCD
- */
-extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
-
-/**
* dwc2_hcd_dump_state() - Dumps hsotg state
*
* @hsotg: The DWC2 HCD
diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c
index c291fca5d21f..a4e724b0a62e 100644
--- a/drivers/usb/dwc2/pci.c
+++ b/drivers/usb/dwc2/pci.c
@@ -141,6 +141,13 @@ static int dwc2_driver_probe(struct pci_dev *dev,
pci_set_master(dev);
+ retval = devm_request_irq(hsotg->dev, dev->irq,
+ dwc2_handle_common_intr, IRQF_SHARED,
+ dev_name(hsotg->dev), hsotg);
+ if (retval)
+ return retval;
+
+ spin_lock_init(&hsotg->lock);
retval = dwc2_hcd_init(hsotg, dev->irq, &dwc2_module_params);
if (retval) {
pci_disable_device(dev);
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 121dbdafc06b..6a795aa2ff05 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -40,6 +40,7 @@
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/usb/of.h>
@@ -121,6 +122,7 @@ static int dwc2_driver_remove(struct platform_device *dev)
struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
dwc2_hcd_remove(hsotg);
+ s3c_hsotg_remove(hsotg);
return 0;
}
@@ -129,6 +131,7 @@ static const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "brcm,bcm2835-usb", .data = &params_bcm2835 },
{ .compatible = "rockchip,rk3066-usb", .data = &params_rk3066 },
{ .compatible = "snps,dwc2", .data = NULL },
+ { .compatible = "samsung,s3c6400-hsotg", .data = NULL},
{},
};
MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
@@ -155,9 +158,6 @@ static int dwc2_driver_probe(struct platform_device *dev)
int retval;
int irq;
- if (usb_disabled())
- return -ENODEV;
-
match = of_match_device(dwc2_of_match_table, &dev->dev);
if (match && match->data) {
params = match->data;
@@ -194,6 +194,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
return irq;
}
+ dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
+ irq);
+ retval = devm_request_irq(hsotg->dev, irq,
+ dwc2_handle_common_intr, IRQF_SHARED,
+ dev_name(hsotg->dev), hsotg);
+ if (retval)
+ return retval;
+
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
hsotg->regs = devm_ioremap_resource(&dev->dev, res);
if (IS_ERR(hsotg->regs))
@@ -204,6 +212,11 @@ static int dwc2_driver_probe(struct platform_device *dev)
hsotg->dr_mode = of_usb_get_dr_mode(dev->dev.of_node);
+ spin_lock_init(&hsotg->lock);
+ mutex_init(&hsotg->init_mutex);
+ retval = dwc2_gadget_init(hsotg, irq);
+ if (retval)
+ return retval;
retval = dwc2_hcd_init(hsotg, irq, params);
if (retval)
return retval;
@@ -213,10 +226,35 @@ static int dwc2_driver_probe(struct platform_device *dev)
return retval;
}
+static int __maybe_unused dwc2_suspend(struct device *dev)
+{
+ struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (dwc2_is_device_mode(dwc2))
+ ret = s3c_hsotg_suspend(dwc2);
+ return ret;
+}
+
+static int __maybe_unused dwc2_resume(struct device *dev)
+{
+ struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (dwc2_is_device_mode(dwc2))
+ ret = s3c_hsotg_resume(dwc2);
+ return ret;
+}
+
+static const struct dev_pm_ops dwc2_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(dwc2_suspend, dwc2_resume)
+};
+
static struct platform_driver dwc2_platform_driver = {
.driver = {
.name = dwc2_driver_name,
.of_match_table = dwc2_of_match_table,
+ .pm = &dwc2_dev_pm_ops,
},
.probe = dwc2_driver_probe,
.remove = dwc2_driver_remove,
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index f4e5cc60db0b..58b5b2cde4c5 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -55,7 +55,7 @@ config USB_DWC3_OMAP
config USB_DWC3_EXYNOS
tristate "Samsung Exynos Platform"
- depends on ARCH_EXYNOS || COMPILE_TEST
+ depends on ARCH_EXYNOS && OF || COMPILE_TEST
default USB_DWC3
help
Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside,
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index b0f4d52b7f04..25ddc39efad8 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -19,6 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -32,6 +33,7 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
+#include <linux/acpi.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -363,6 +365,72 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
}
/**
+ * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
+ * @dwc: Pointer to our controller context structure
+ */
+static void dwc3_phy_setup(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+
+ /*
+ * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
+ * to '0' during coreConsultant configuration. So default value
+ * will be '0' when the core is reset. Application needs to set it
+ * to '1' after the core initialization is completed.
+ */
+ if (dwc->revision > DWC3_REVISION_194A)
+ reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+
+ if (dwc->u2ss_inp3_quirk)
+ reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
+
+ if (dwc->req_p1p2p3_quirk)
+ reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
+
+ if (dwc->del_p1p2p3_quirk)
+ reg |= DWC3_GUSB3PIPECTL_DEP1P2P3_EN;
+
+ if (dwc->del_phy_power_chg_quirk)
+ reg |= DWC3_GUSB3PIPECTL_DEPOCHANGE;
+
+ if (dwc->lfps_filter_quirk)
+ reg |= DWC3_GUSB3PIPECTL_LFPSFILT;
+
+ if (dwc->rx_detect_poll_quirk)
+ reg |= DWC3_GUSB3PIPECTL_RX_DETOPOLL;
+
+ if (dwc->tx_de_emphasis_quirk)
+ reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
+
+ if (dwc->dis_u3_susphy_quirk)
+ reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+ mdelay(100);
+
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+
+ /*
+ * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
+ * '0' during coreConsultant configuration. So default value will
+ * be '0' when the core is reset. Application needs to set it to
+ * '1' after the core initialization is completed.
+ */
+ if (dwc->revision > DWC3_REVISION_194A)
+ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+
+ if (dwc->dis_u2_susphy_quirk)
+ reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+ mdelay(100);
+}
+
+/**
* dwc3_core_init - Low-level initialization of DWC3 Core
* @dwc: Pointer to our controller context structure
*
@@ -384,6 +452,12 @@ static int dwc3_core_init(struct dwc3 *dwc)
}
dwc->revision = reg;
+ /*
+ * Write Linux Version Code to our GUID register so it's easy to figure
+ * out which kernel version a bug was found.
+ */
+ dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
+
/* Handle USB2.0-only core configuration */
if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
@@ -414,7 +488,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
- reg &= ~DWC3_GCTL_DISSCRAMBLE;
switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
@@ -441,11 +514,34 @@ static int dwc3_core_init(struct dwc3 *dwc)
case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
/* enable hibernation here */
dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
+
+ /*
+ * REVISIT Enabling this bit so that host-mode hibernation
+ * will work. Device-mode hibernation is not yet implemented.
+ */
+ reg |= DWC3_GCTL_GBLHIBERNATIONEN;
break;
default:
dev_dbg(dwc->dev, "No power optimization available\n");
}
+ /* check if current dwc3 is on simulation board */
+ if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
+ dev_dbg(dwc->dev, "it is on FPGA board\n");
+ dwc->is_fpga = true;
+ }
+
+ WARN_ONCE(dwc->disable_scramble_quirk && !dwc->is_fpga,
+ "disable_scramble cannot be used on non-FPGA builds\n");
+
+ if (dwc->disable_scramble_quirk && dwc->is_fpga)
+ reg |= DWC3_GCTL_DISSCRAMBLE;
+ else
+ reg &= ~DWC3_GCTL_DISSCRAMBLE;
+
+ if (dwc->u2exit_lfps_quirk)
+ reg |= DWC3_GCTL_U2EXIT_LFPS;
+
/*
* WORKAROUND: DWC3 revisions <1.90a have a bug
* where the device can fail to connect at SuperSpeed
@@ -459,6 +555,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ dwc3_phy_setup(dwc);
+
ret = dwc3_alloc_scratch_buffers(dwc);
if (ret)
goto err1;
@@ -630,6 +728,9 @@ static int dwc3_probe(struct platform_device *pdev)
struct device_node *node = dev->of_node;
struct resource *res;
struct dwc3 *dwc;
+ u8 lpm_nyet_threshold;
+ u8 tx_de_emphasis;
+ u8 hird_threshold;
int ret;
@@ -685,22 +786,96 @@ static int dwc3_probe(struct platform_device *pdev)
*/
res->start -= DWC3_GLOBALS_REGS_START;
+ /* default to highest possible threshold */
+ lpm_nyet_threshold = 0xff;
+
+ /* default to -3.5dB de-emphasis */
+ tx_de_emphasis = 1;
+
+ /*
+ * default to assert utmi_sleep_n and use maximum allowed HIRD
+ * threshold value of 0b1100
+ */
+ hird_threshold = 12;
+
if (node) {
dwc->maximum_speed = of_usb_get_maximum_speed(node);
-
- dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
+ dwc->has_lpm_erratum = of_property_read_bool(node,
+ "snps,has-lpm-erratum");
+ of_property_read_u8(node, "snps,lpm-nyet-threshold",
+ &lpm_nyet_threshold);
+ dwc->is_utmi_l1_suspend = of_property_read_bool(node,
+ "snps,is-utmi-l1-suspend");
+ of_property_read_u8(node, "snps,hird-threshold",
+ &hird_threshold);
+
+ dwc->needs_fifo_resize = of_property_read_bool(node,
+ "tx-fifo-resize");
dwc->dr_mode = of_usb_get_dr_mode(node);
+
+ dwc->disable_scramble_quirk = of_property_read_bool(node,
+ "snps,disable_scramble_quirk");
+ dwc->u2exit_lfps_quirk = of_property_read_bool(node,
+ "snps,u2exit_lfps_quirk");
+ dwc->u2ss_inp3_quirk = of_property_read_bool(node,
+ "snps,u2ss_inp3_quirk");
+ dwc->req_p1p2p3_quirk = of_property_read_bool(node,
+ "snps,req_p1p2p3_quirk");
+ dwc->del_p1p2p3_quirk = of_property_read_bool(node,
+ "snps,del_p1p2p3_quirk");
+ dwc->del_phy_power_chg_quirk = of_property_read_bool(node,
+ "snps,del_phy_power_chg_quirk");
+ dwc->lfps_filter_quirk = of_property_read_bool(node,
+ "snps,lfps_filter_quirk");
+ dwc->rx_detect_poll_quirk = of_property_read_bool(node,
+ "snps,rx_detect_poll_quirk");
+ dwc->dis_u3_susphy_quirk = of_property_read_bool(node,
+ "snps,dis_u3_susphy_quirk");
+ dwc->dis_u2_susphy_quirk = of_property_read_bool(node,
+ "snps,dis_u2_susphy_quirk");
+
+ dwc->tx_de_emphasis_quirk = of_property_read_bool(node,
+ "snps,tx_de_emphasis_quirk");
+ of_property_read_u8(node, "snps,tx_de_emphasis",
+ &tx_de_emphasis);
} else if (pdata) {
dwc->maximum_speed = pdata->maximum_speed;
+ dwc->has_lpm_erratum = pdata->has_lpm_erratum;
+ if (pdata->lpm_nyet_threshold)
+ lpm_nyet_threshold = pdata->lpm_nyet_threshold;
+ dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend;
+ if (pdata->hird_threshold)
+ hird_threshold = pdata->hird_threshold;
dwc->needs_fifo_resize = pdata->tx_fifo_resize;
dwc->dr_mode = pdata->dr_mode;
+
+ dwc->disable_scramble_quirk = pdata->disable_scramble_quirk;
+ dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk;
+ dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk;
+ dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk;
+ dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk;
+ dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk;
+ dwc->lfps_filter_quirk = pdata->lfps_filter_quirk;
+ dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk;
+ dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
+ dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
+
+ dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
+ if (pdata->tx_de_emphasis)
+ tx_de_emphasis = pdata->tx_de_emphasis;
}
/* default to superspeed if no maximum_speed passed */
if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
dwc->maximum_speed = USB_SPEED_SUPER;
+ dwc->lpm_nyet_threshold = lpm_nyet_threshold;
+ dwc->tx_de_emphasis = tx_de_emphasis;
+
+ dwc->hird_threshold = hird_threshold
+ | (dwc->is_utmi_l1_suspend << 4);
+
ret = dwc3_core_get_phy(dwc);
if (ret)
return ret;
@@ -708,9 +883,11 @@ static int dwc3_probe(struct platform_device *pdev)
spin_lock_init(&dwc->lock);
platform_set_drvdata(pdev, dwc);
- 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 (!dev->dma_mask) {
+ dev->dma_mask = dev->parent->dma_mask;
+ dev->dma_parms = dev->parent->dma_parms;
+ dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
+ }
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
@@ -815,50 +992,6 @@ static int dwc3_remove(struct platform_device *pdev)
}
#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->dr_mode) {
- case USB_DR_MODE_PERIPHERAL:
- case USB_DR_MODE_OTG:
- dwc3_gadget_prepare(dwc);
- /* FALLTHROUGH */
- case USB_DR_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);
-
- dwc3_event_buffers_setup(dwc);
- switch (dwc->dr_mode) {
- case USB_DR_MODE_PERIPHERAL:
- case USB_DR_MODE_OTG:
- dwc3_gadget_complete(dwc);
- /* FALLTHROUGH */
- case USB_DR_MODE_HOST:
- default:
- break;
- }
-
- spin_unlock_irqrestore(&dwc->lock, flags);
-}
-
static int dwc3_suspend(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
@@ -873,7 +1006,7 @@ static int dwc3_suspend(struct device *dev)
/* FALLTHROUGH */
case USB_DR_MODE_HOST:
default:
- /* do nothing */
+ dwc3_event_buffers_cleanup(dwc);
break;
}
@@ -906,6 +1039,7 @@ static int dwc3_resume(struct device *dev)
spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_event_buffers_setup(dwc);
dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
switch (dwc->dr_mode) {
@@ -934,9 +1068,6 @@ err_usb2phy_init:
}
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)
};
@@ -958,12 +1089,24 @@ static const struct of_device_id of_dwc3_match[] = {
MODULE_DEVICE_TABLE(of, of_dwc3_match);
#endif
+#ifdef CONFIG_ACPI
+
+#define ACPI_ID_INTEL_BSW "808622B7"
+
+static const struct acpi_device_id dwc3_acpi_match[] = {
+ { ACPI_ID_INTEL_BSW, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);
+#endif
+
static struct platform_driver dwc3_driver = {
.probe = dwc3_probe,
.remove = dwc3_remove,
.driver = {
.name = "dwc3",
.of_match_table = of_match_ptr(of_dwc3_match),
+ .acpi_match_table = ACPI_PTR(dwc3_acpi_match),
.pm = DWC3_PM_OPS,
},
};
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 66f62563bcf9..4bb9aa696ede 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -166,6 +166,7 @@
#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4)
#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
+#define DWC3_GCTL_U2EXIT_LFPS (1 << 2)
#define DWC3_GCTL_GBLHIBERNATIONEN (1 << 1)
#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
@@ -175,7 +176,17 @@
/* Global USB3 PIPE Control Register */
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
+#define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29)
+#define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24)
+#define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19)
+#define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7)
+#define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1)
+#define DWC3_GUSB3PIPECTL_DEPOCHANGE (1 << 18)
#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
+#define DWC3_GUSB3PIPECTL_LFPSFILT (1 << 9)
+#define DWC3_GUSB3PIPECTL_RX_DETOPOLL (1 << 8)
+#define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK DWC3_GUSB3PIPECTL_TX_DEEPH(3)
+#define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1)
/* Global TX Fifo Size Register */
#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
@@ -210,6 +221,9 @@
#define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n) (((n) & (0x0f << 13)) >> 13)
#define DWC3_MAX_HIBER_SCRATCHBUFS 15
+/* Global HWPARAMS6 Register */
+#define DWC3_GHWPARAMS6_EN_FPGA (1 << 7)
+
/* Device Configuration Register */
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
@@ -243,16 +257,19 @@
#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6))
/* These apply for core versions 1.94a and later */
-#define DWC3_DCTL_KEEP_CONNECT (1 << 19)
-#define DWC3_DCTL_L1_HIBER_EN (1 << 18)
-#define DWC3_DCTL_CRS (1 << 17)
-#define DWC3_DCTL_CSS (1 << 16)
+#define DWC3_DCTL_LPM_ERRATA_MASK DWC3_DCTL_LPM_ERRATA(0xf)
+#define DWC3_DCTL_LPM_ERRATA(n) ((n) << 20)
+
+#define DWC3_DCTL_KEEP_CONNECT (1 << 19)
+#define DWC3_DCTL_L1_HIBER_EN (1 << 18)
+#define DWC3_DCTL_CRS (1 << 17)
+#define DWC3_DCTL_CSS (1 << 16)
-#define DWC3_DCTL_INITU2ENA (1 << 12)
-#define DWC3_DCTL_ACCEPTU2ENA (1 << 11)
-#define DWC3_DCTL_INITU1ENA (1 << 10)
-#define DWC3_DCTL_ACCEPTU1ENA (1 << 9)
-#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1)
+#define DWC3_DCTL_INITU2ENA (1 << 12)
+#define DWC3_DCTL_ACCEPTU2ENA (1 << 11)
+#define DWC3_DCTL_INITU1ENA (1 << 10)
+#define DWC3_DCTL_ACCEPTU1ENA (1 << 9)
+#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1)
#define DWC3_DCTL_ULSTCHNGREQ_MASK (0x0f << 5)
#define DWC3_DCTL_ULSTCHNGREQ(n) (((n) << 5) & DWC3_DCTL_ULSTCHNGREQ_MASK)
@@ -657,17 +674,41 @@ struct dwc3_scratchpad_array {
* @regset: debugfs pointer to regdump file
* @test_mode: true when we're entering a USB test mode
* @test_mode_nr: test feature selector
+ * @lpm_nyet_threshold: LPM NYET response threshold
+ * @hird_threshold: HIRD threshold
* @delayed_status: true when gadget driver asks for delayed status
* @ep0_bounced: true when we used bounce buffer
* @ep0_expect_in: true when we expect a DATA IN transfer
* @has_hibernation: true when dwc3 was configured with Hibernation
+ * @has_lpm_erratum: true when core was configured with LPM Erratum. Note that
+ * there's now way for software to detect this in runtime.
+ * @is_utmi_l1_suspend: the core asserts output signal
+ * 0 - utmi_sleep_n
+ * 1 - utmi_l1_suspend_n
* @is_selfpowered: true when we are selfpowered
+ * @is_fpga: true when we are using the FPGA board
* @needs_fifo_resize: not all users might want fifo resizing, flag it
* @pullups_connected: true when Run/Stop bit is set
* @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
* @start_config_issued: true when StartConfig command has been issued
* @three_stage_setup: set if we perform a three phase setup
+ * @disable_scramble_quirk: set if we enable the disable scramble quirk
+ * @u2exit_lfps_quirk: set if we enable u2exit lfps quirk
+ * @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk
+ * @req_p1p2p3_quirk: set if we enable request p1p2p3 quirk
+ * @del_p1p2p3_quirk: set if we enable delay p1p2p3 quirk
+ * @del_phy_power_chg_quirk: set if we enable delay phy power change quirk
+ * @lfps_filter_quirk: set if we enable LFPS filter quirk
+ * @rx_detect_poll_quirk: set if we enable rx_detect to polling lfps quirk
+ * @dis_u3_susphy_quirk: set if we disable usb3 suspend phy
+ * @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
+ * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
+ * @tx_de_emphasis: Tx de-emphasis value
+ * 0 - -6dB de-emphasis
+ * 1 - -3.5dB de-emphasis
+ * 2 - No de-emphasis
+ * 3 - Reserved
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
@@ -759,18 +800,37 @@ struct dwc3 {
u8 test_mode;
u8 test_mode_nr;
+ u8 lpm_nyet_threshold;
+ u8 hird_threshold;
unsigned delayed_status:1;
unsigned ep0_bounced:1;
unsigned ep0_expect_in:1;
unsigned has_hibernation:1;
+ unsigned has_lpm_erratum:1;
+ unsigned is_utmi_l1_suspend:1;
unsigned is_selfpowered:1;
+ unsigned is_fpga:1;
unsigned needs_fifo_resize:1;
unsigned pullups_connected:1;
unsigned resize_fifos:1;
unsigned setup_packet_pending:1;
unsigned start_config_issued:1;
unsigned three_stage_setup:1;
+
+ unsigned disable_scramble_quirk:1;
+ unsigned u2exit_lfps_quirk:1;
+ unsigned u2ss_inp3_quirk:1;
+ unsigned req_p1p2p3_quirk:1;
+ unsigned del_p1p2p3_quirk:1;
+ unsigned del_phy_power_chg_quirk:1;
+ unsigned lfps_filter_quirk:1;
+ unsigned rx_detect_poll_quirk:1;
+ unsigned dis_u3_susphy_quirk:1;
+ unsigned dis_u2_susphy_quirk:1;
+
+ unsigned tx_de_emphasis_quirk:1;
+ unsigned tx_de_emphasis:2;
};
/* -------------------------------------------------------------------------- */
@@ -964,20 +1024,9 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
/* 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;
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index 3951a65fea04..7bd0a95b2815 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
-#include <linux/platform_data/dwc3-exynos.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/usb/otg.h>
@@ -35,6 +34,9 @@ struct dwc3_exynos {
struct device *dev;
struct clk *clk;
+ struct clk *susp_clk;
+ struct clk *axius_clk;
+
struct regulator *vdd33;
struct regulator *vdd10;
};
@@ -106,7 +108,6 @@ static int dwc3_exynos_remove_child(struct device *dev, void *unused)
static int dwc3_exynos_probe(struct platform_device *pdev)
{
struct dwc3_exynos *exynos;
- struct clk *clk;
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
@@ -133,16 +134,32 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
return ret;
}
- clk = devm_clk_get(dev, "usbdrd30");
- if (IS_ERR(clk)) {
+ exynos->dev = dev;
+
+ exynos->clk = devm_clk_get(dev, "usbdrd30");
+ if (IS_ERR(exynos->clk)) {
dev_err(dev, "couldn't get clock\n");
return -EINVAL;
}
+ clk_prepare_enable(exynos->clk);
- exynos->dev = dev;
- exynos->clk = clk;
+ exynos->susp_clk = devm_clk_get(dev, "usbdrd30_susp_clk");
+ if (IS_ERR(exynos->susp_clk)) {
+ dev_dbg(dev, "no suspend clk specified\n");
+ exynos->susp_clk = NULL;
+ }
+ clk_prepare_enable(exynos->susp_clk);
- clk_prepare_enable(exynos->clk);
+ if (of_device_is_compatible(node, "samsung,exynos7-dwusb3")) {
+ exynos->axius_clk = devm_clk_get(dev, "usbdrd30_axius_clk");
+ if (IS_ERR(exynos->axius_clk)) {
+ dev_err(dev, "no AXI UpScaler clk specified\n");
+ return -ENODEV;
+ }
+ clk_prepare_enable(exynos->axius_clk);
+ } else {
+ exynos->axius_clk = NULL;
+ }
exynos->vdd33 = devm_regulator_get(dev, "vdd33");
if (IS_ERR(exynos->vdd33)) {
@@ -185,7 +202,9 @@ err4:
err3:
regulator_disable(exynos->vdd33);
err2:
- clk_disable_unprepare(clk);
+ clk_disable_unprepare(exynos->axius_clk);
+ clk_disable_unprepare(exynos->susp_clk);
+ clk_disable_unprepare(exynos->clk);
return ret;
}
@@ -197,6 +216,8 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
platform_device_unregister(exynos->usb2_phy);
platform_device_unregister(exynos->usb3_phy);
+ clk_disable_unprepare(exynos->axius_clk);
+ clk_disable_unprepare(exynos->susp_clk);
clk_disable_unprepare(exynos->clk);
regulator_disable(exynos->vdd33);
@@ -205,19 +226,19 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_OF
static const struct of_device_id exynos_dwc3_match[] = {
{ .compatible = "samsung,exynos5250-dwusb3" },
+ { .compatible = "samsung,exynos7-dwusb3" },
{},
};
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->axius_clk);
clk_disable(exynos->clk);
regulator_disable(exynos->vdd33);
@@ -243,6 +264,7 @@ static int dwc3_exynos_resume(struct device *dev)
}
clk_enable(exynos->clk);
+ clk_enable(exynos->axius_clk);
/* runtime set active to reflect active state. */
pm_runtime_disable(dev);
@@ -266,7 +288,7 @@ static struct platform_driver dwc3_exynos_driver = {
.remove = dwc3_exynos_remove,
.driver = {
.name = "exynos-dwc3",
- .of_match_table = of_match_ptr(exynos_dwc3_match),
+ .of_match_table = exynos_dwc3_match,
.pm = DEV_PM_OPS,
},
};
diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c
index 7ec8495f4523..fe3b9335a74e 100644
--- a/drivers/usb/dwc3/dwc3-keystone.c
+++ b/drivers/usb/dwc3/dwc3-keystone.c
@@ -104,11 +104,6 @@ static int kdwc3_probe(struct platform_device *pdev)
kdwc->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "missing usbss resource\n");
- return -EINVAL;
- }
-
kdwc->usbss = devm_ioremap_resource(dev, res);
if (IS_ERR(kdwc->usbss))
return PTR_ERR(kdwc->usbss);
@@ -128,6 +123,7 @@ static int kdwc3_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "missing irq\n");
+ error = irq;
goto err_irq;
}
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index a0aa9f3da441..172d64e585b6 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -593,27 +593,12 @@ static const struct of_device_id of_dwc3_match[] = {
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_read_utmi_status(omap);
+ dwc3_omap_disable_irqs(omap);
return 0;
}
@@ -623,6 +608,7 @@ static int dwc3_omap_resume(struct device *dev)
struct dwc3_omap *omap = dev_get_drvdata(dev);
dwc3_omap_write_utmi_status(omap, omap->utmi_otg_status);
+ dwc3_omap_enable_irqs(omap);
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
@@ -632,8 +618,6 @@ static int dwc3_omap_resume(struct device *dev)
}
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)
};
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index a36cf66302fb..7c4faf738747 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -25,6 +25,8 @@
#include <linux/usb/otg.h>
#include <linux/usb/usb_phy_generic.h>
+#include "platform_data.h"
+
/* FIXME define these in <linux/pci_ids.h> */
#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
@@ -102,6 +104,9 @@ static int dwc3_pci_probe(struct pci_dev *pci,
struct dwc3_pci *glue;
int ret;
struct device *dev = &pci->dev;
+ struct dwc3_platform_data dwc3_pdata;
+
+ memset(&dwc3_pdata, 0x00, sizeof(dwc3_pdata));
glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
if (!glue)
@@ -140,6 +145,31 @@ static int dwc3_pci_probe(struct pci_dev *pci,
res[1].name = "dwc_usb3";
res[1].flags = IORESOURCE_IRQ;
+ if (pci->vendor == PCI_VENDOR_ID_AMD &&
+ pci->device == PCI_DEVICE_ID_AMD_NL_USB) {
+ dwc3_pdata.has_lpm_erratum = true;
+ dwc3_pdata.lpm_nyet_threshold = 0xf;
+
+ dwc3_pdata.u2exit_lfps_quirk = true;
+ dwc3_pdata.u2ss_inp3_quirk = true;
+ dwc3_pdata.req_p1p2p3_quirk = true;
+ dwc3_pdata.del_p1p2p3_quirk = true;
+ dwc3_pdata.del_phy_power_chg_quirk = true;
+ dwc3_pdata.lfps_filter_quirk = true;
+ dwc3_pdata.rx_detect_poll_quirk = true;
+
+ dwc3_pdata.tx_de_emphasis_quirk = true;
+ dwc3_pdata.tx_de_emphasis = 1;
+
+ /*
+ * FIXME these quirks should be removed when AMD NL
+ * taps out
+ */
+ dwc3_pdata.disable_scramble_quirk = true;
+ dwc3_pdata.dis_u3_susphy_quirk = true;
+ dwc3_pdata.dis_u2_susphy_quirk = true;
+ }
+
ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
if (ret) {
dev_err(dev, "couldn't add resources to dwc3 device\n");
@@ -148,6 +178,10 @@ static int dwc3_pci_probe(struct pci_dev *pci,
pci_set_drvdata(pci, glue);
+ ret = platform_device_add_data(dwc3, &dwc3_pdata, sizeof(dwc3_pdata));
+ if (ret)
+ goto err3;
+
dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
dwc3->dev.dma_mask = dev->dma_mask;
@@ -185,6 +219,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
{ } /* Terminating Entry */
};
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c
index c7602b5362ad..4a1a543deeda 100644
--- a/drivers/usb/dwc3/dwc3-st.c
+++ b/drivers/usb/dwc3/dwc3-st.c
@@ -243,7 +243,7 @@ static int st_dwc3_probe(struct platform_device *pdev)
dwc3_data->rstc_rst = devm_reset_control_get(dev, "softreset");
if (IS_ERR(dwc3_data->rstc_rst)) {
dev_err(&pdev->dev, "could not get reset controller\n");
- ret = PTR_ERR(dwc3_data->rstc_pwrdn);
+ ret = PTR_ERR(dwc3_data->rstc_rst);
goto undo_powerdown;
}
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index df38e7ef4976..1bc77a3b4997 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -86,6 +86,8 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
params.param0 = upper_32_bits(dwc->ep0_trb_addr);
params.param1 = lower_32_bits(dwc->ep0_trb_addr);
+ trace_dwc3_prepare_trb(dep, trb);
+
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
DWC3_DEPCMD_STARTTRANSFER, &params);
if (ret < 0) {
@@ -441,7 +443,6 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
case USB_DEVICE_LTM_ENABLE:
return -EINVAL;
- break;
case USB_DEVICE_TEST_MODE:
if ((wIndex & 0xff) != 0)
@@ -550,7 +551,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
switch (state) {
case USB_STATE_DEFAULT:
return -EINVAL;
- break;
case USB_STATE_ADDRESS:
ret = dwc3_ep0_delegate_req(dwc, ctrl);
@@ -700,35 +700,35 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
switch (ctrl->bRequest) {
case USB_REQ_GET_STATUS:
- dwc3_trace(trace_dwc3_ep0, "USB_REQ_GET_STATUS\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_GET_STATUS");
ret = dwc3_ep0_handle_status(dwc, ctrl);
break;
case USB_REQ_CLEAR_FEATURE:
- dwc3_trace(trace_dwc3_ep0, "USB_REQ_CLEAR_FEATURE\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_CLEAR_FEATURE");
ret = dwc3_ep0_handle_feature(dwc, ctrl, 0);
break;
case USB_REQ_SET_FEATURE:
- dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_FEATURE\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_FEATURE");
ret = dwc3_ep0_handle_feature(dwc, ctrl, 1);
break;
case USB_REQ_SET_ADDRESS:
- dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ADDRESS\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ADDRESS");
ret = dwc3_ep0_set_address(dwc, ctrl);
break;
case USB_REQ_SET_CONFIGURATION:
- dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_CONFIGURATION\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_CONFIGURATION");
ret = dwc3_ep0_set_config(dwc, ctrl);
break;
case USB_REQ_SET_SEL:
- dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_SEL\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_SEL");
ret = dwc3_ep0_set_sel(dwc, ctrl);
break;
case USB_REQ_SET_ISOCH_DELAY:
- dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY\n");
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY");
ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
break;
default:
- dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver\n");
+ dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver");
ret = dwc3_ep0_delegate_req(dwc, ctrl);
break;
}
@@ -791,6 +791,8 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
trb = dwc->ep0_trb;
+ trace_dwc3_complete_trb(ep0, trb);
+
r = next_request(&ep0->request_list);
if (!r)
return;
@@ -855,6 +857,8 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
dep = dwc->eps[0];
trb = dwc->ep0_trb;
+ trace_dwc3_complete_trb(dep, trb);
+
if (!list_empty(&dep->request_list)) {
r = next_request(&dep->request_list);
@@ -875,7 +879,7 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
status = DWC3_TRB_SIZE_TRBSTS(trb->size);
if (status == DWC3_TRBSTS_SETUP_PENDING)
- dwc3_trace(trace_dwc3_ep0, "Setup Pending received\n");
+ dwc3_trace(trace_dwc3_ep0, "Setup Pending received");
dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_out_start(dwc);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 546ea5431b8c..f03b136ecfce 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1140,8 +1140,14 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
if (!dep->endpoint.desc) {
dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
request, ep->name);
- spin_unlock_irqrestore(&dwc->lock, flags);
- return -ESHUTDOWN;
+ ret = -ESHUTDOWN;
+ goto out;
+ }
+
+ if (WARN(req->dep != dep, "request %p belongs to '%s'\n",
+ request, req->dep->name)) {
+ ret = -EINVAL;
+ goto out;
}
dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
@@ -1149,6 +1155,8 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
trace_dwc3_ep_queue(req);
ret = __dwc3_gadget_ep_queue(dep, req);
+
+out:
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
@@ -1622,8 +1630,7 @@ err0:
return ret;
}
-static int dwc3_gadget_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int dwc3_gadget_stop(struct usb_gadget *g)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
@@ -2034,6 +2041,17 @@ static void dwc3_resume_gadget(struct dwc3 *dwc)
if (dwc->gadget_driver && dwc->gadget_driver->resume) {
spin_unlock(&dwc->lock);
dwc->gadget_driver->resume(&dwc->gadget);
+ }
+}
+
+static void dwc3_reset_gadget(struct dwc3 *dwc)
+{
+ if (!dwc->gadget_driver)
+ return;
+
+ if (dwc->gadget.speed != USB_SPEED_UNKNOWN) {
+ spin_unlock(&dwc->lock);
+ usb_gadget_udc_reset(&dwc->gadget, dwc->gadget_driver);
spin_lock(&dwc->lock);
}
}
@@ -2140,6 +2158,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->setup_packet_pending = false;
+ usb_gadget_set_state(&dwc->gadget, USB_STATE_NOTATTACHED);
}
static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
@@ -2177,11 +2196,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
dwc3_gadget_disconnect_interrupt(dwc);
}
- /* after reset -> Default State */
- usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
-
- if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
- dwc3_disconnect_gadget(dwc);
+ dwc3_reset_gadget(dwc);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
@@ -2287,11 +2302,20 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
+ reg |= DWC3_DCTL_HIRD_THRES(dwc->hird_threshold);
+
/*
- * TODO: This should be configurable. For now using
- * maximum allowed HIRD threshold value of 0b1100
+ * When dwc3 revisions >= 2.40a, LPM Erratum is enabled and
+ * DCFG.LPMCap is set, core responses with an ACK and the
+ * BESL value in the LPM token is less than or equal to LPM
+ * NYET threshold.
*/
- reg |= DWC3_DCTL_HIRD_THRES(12);
+ WARN_ONCE(dwc->revision < DWC3_REVISION_240A
+ && dwc->has_lpm_erratum,
+ "LPM Erratum not available on dwc3 revisisions < 2.40a\n");
+
+ if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A)
+ reg |= DWC3_DCTL_LPM_ERRATA(dwc->lpm_nyet_threshold);
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
} else {
@@ -2744,26 +2768,13 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dwc->ctrl_req, dwc->ctrl_req_addr);
}
-int dwc3_gadget_prepare(struct dwc3 *dwc)
+int dwc3_gadget_suspend(struct dwc3 *dwc)
{
if (dwc->pullups_connected) {
dwc3_gadget_disable_irq(dwc);
dwc3_gadget_run_stop(dwc, true, true);
}
- return 0;
-}
-
-void dwc3_gadget_complete(struct dwc3 *dwc)
-{
- if (dwc->pullups_connected) {
- dwc3_gadget_enable_irq(dwc);
- dwc3_gadget_run_stop(dwc, true, false);
- }
-}
-
-int dwc3_gadget_suspend(struct dwc3 *dwc)
-{
__dwc3_gadget_ep_disable(dwc->eps[0]);
__dwc3_gadget_ep_disable(dwc->eps[1]);
@@ -2798,6 +2809,11 @@ int dwc3_gadget_resume(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg);
+ if (dwc->pullups_connected) {
+ dwc3_gadget_enable_irq(dwc);
+ dwc3_gadget_run_stop(dwc, true, false);
+ }
+
return 0;
err1:
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index dcb8ca084598..12bfd3c5405e 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -29,8 +29,7 @@ int dwc3_host_init(struct dwc3 *dwc)
xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
if (!xhci) {
dev_err(dwc->dev, "couldn't allocate xHCI device\n");
- ret = -ENOMEM;
- goto err0;
+ return -ENOMEM;
}
dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
@@ -60,22 +59,33 @@ int dwc3_host_init(struct dwc3 *dwc)
goto err1;
}
+ phy_create_lookup(dwc->usb2_generic_phy, "usb2-phy",
+ dev_name(&xhci->dev));
+ phy_create_lookup(dwc->usb3_generic_phy, "usb3-phy",
+ dev_name(&xhci->dev));
+
ret = platform_device_add(xhci);
if (ret) {
dev_err(dwc->dev, "failed to register xHCI device\n");
- goto err1;
+ goto err2;
}
return 0;
-
+err2:
+ phy_remove_lookup(dwc->usb2_generic_phy, "usb2-phy",
+ dev_name(&xhci->dev));
+ phy_remove_lookup(dwc->usb3_generic_phy, "usb3-phy",
+ dev_name(&xhci->dev));
err1:
platform_device_put(xhci);
-
-err0:
return ret;
}
void dwc3_host_exit(struct dwc3 *dwc)
{
+ phy_remove_lookup(dwc->usb2_generic_phy, "usb2-phy",
+ dev_name(&dwc->xhci->dev));
+ phy_remove_lookup(dwc->usb3_generic_phy, "usb3-phy",
+ dev_name(&dwc->xhci->dev));
platform_device_unregister(dwc->xhci);
}
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
index 7db34f00b89a..a3a3b6d5668c 100644
--- a/drivers/usb/dwc3/platform_data.h
+++ b/drivers/usb/dwc3/platform_data.h
@@ -24,4 +24,24 @@ struct dwc3_platform_data {
enum usb_device_speed maximum_speed;
enum usb_dr_mode dr_mode;
bool tx_fifo_resize;
+
+ unsigned is_utmi_l1_suspend:1;
+ u8 hird_threshold;
+
+ u8 lpm_nyet_threshold;
+
+ unsigned disable_scramble_quirk:1;
+ unsigned has_lpm_erratum:1;
+ unsigned u2exit_lfps_quirk:1;
+ unsigned u2ss_inp3_quirk:1;
+ unsigned req_p1p2p3_quirk:1;
+ unsigned del_p1p2p3_quirk:1;
+ unsigned del_phy_power_chg_quirk:1;
+ unsigned lfps_filter_quirk:1;
+ unsigned rx_detect_poll_quirk:1;
+ unsigned dis_u3_susphy_quirk:1;
+ unsigned dis_u2_susphy_quirk:1;
+
+ unsigned tx_de_emphasis_quirk:1;
+ unsigned tx_de_emphasis:2;
};
diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h
index 60b0f41eafc4..9fc20b33dd8e 100644
--- a/drivers/usb/dwc3/trace.h
+++ b/drivers/usb/dwc3/trace.h
@@ -61,7 +61,7 @@ DECLARE_EVENT_CLASS(dwc3_log_event,
TP_fast_assign(
__entry->event = event;
),
- TP_printk("event %08x\n", __entry->event)
+ TP_printk("event %08x", __entry->event)
);
DEFINE_EVENT(dwc3_log_event, dwc3_event,
@@ -157,7 +157,7 @@ DECLARE_EVENT_CLASS(dwc3_log_generic_cmd,
__entry->cmd = cmd;
__entry->param = param;
),
- TP_printk("cmd '%s' [%d] param %08x\n",
+ TP_printk("cmd '%s' [%d] param %08x",
dwc3_gadget_generic_cmd_string(__entry->cmd),
__entry->cmd, __entry->param
)
@@ -175,17 +175,21 @@ DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd,
TP_STRUCT__entry(
__dynamic_array(char, name, DWC3_MSG_MAX)
__field(unsigned int, cmd)
- __field(struct dwc3_gadget_ep_cmd_params *, params)
+ __field(u32, param0)
+ __field(u32, param1)
+ __field(u32, param2)
),
TP_fast_assign(
snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name);
__entry->cmd = cmd;
- __entry->params = params;
+ __entry->param0 = params->param0;
+ __entry->param1 = params->param1;
+ __entry->param2 = params->param2;
),
- TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x\n",
+ TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x",
__get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd),
- __entry->cmd, __entry->params->param0,
- __entry->params->param1, __entry->params->param2
+ __entry->cmd, __entry->param0,
+ __entry->param1, __entry->param2
)
);
@@ -214,7 +218,7 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
__entry->size = trb->size;
__entry->ctrl = trb->ctrl;
),
- TP_printk("%s: trb %p bph %08x bpl %08x size %08x ctrl %08x\n",
+ TP_printk("%s: trb %p bph %08x bpl %08x size %08x ctrl %08x",
__get_str(name), __entry->trb, __entry->bph, __entry->bpl,
__entry->size, __entry->ctrl
)
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index c4880fc0d86e..747ef53bda14 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -190,6 +190,12 @@ config USB_F_UAC2
config USB_F_UVC
tristate
+config USB_F_MIDI
+ tristate
+
+config USB_F_HID
+ tristate
+
choice
tristate "USB Gadget Drivers"
default USB_ETH
@@ -362,6 +368,61 @@ config USB_CONFIGFS_F_FS
implemented in kernel space (for instance Ethernet, serial or
mass storage) and other are implemented in user space.
+config USB_CONFIGFS_F_UAC1
+ boolean "Audio Class 1.0"
+ depends on USB_CONFIGFS
+ depends on SND
+ select USB_LIBCOMPOSITE
+ select SND_PCM
+ select USB_F_UAC1
+ help
+ This Audio function implements 1 AudioControl interface,
+ 1 AudioStreaming Interface each for USB-OUT and USB-IN.
+ This driver requires a real Audio codec to be present
+ on the device.
+
+config USB_CONFIGFS_F_UAC2
+ boolean "Audio Class 2.0"
+ depends on USB_CONFIGFS
+ depends on SND
+ select USB_LIBCOMPOSITE
+ select SND_PCM
+ select USB_F_UAC2
+ help
+ This Audio function is compatible with USB Audio Class
+ specification 2.0. It implements 1 AudioControl interface,
+ 1 AudioStreaming Interface each for USB-OUT and USB-IN.
+ This driver doesn't expect any real Audio codec to be present
+ on the device - the audio streams are simply sinked to and
+ sourced from a virtual ALSA sound card created. The user-space
+ application may choose to do whatever it wants with the data
+ received from the USB Host and choose to provide whatever it
+ wants as audio data to the USB Host.
+
+config USB_CONFIGFS_F_MIDI
+ boolean "MIDI function"
+ depends on USB_CONFIGFS
+ depends on SND
+ select USB_LIBCOMPOSITE
+ select SND_RAWMIDI
+ select USB_F_MIDI
+ help
+ The MIDI Function acts as a USB Audio device, with one MIDI
+ input and one MIDI output. These MIDI jacks appear as
+ a sound "card" in the ALSA sound system. Other MIDI
+ connections can then be made on the gadget system, using
+ ALSA's aconnect utility etc.
+
+config USB_CONFIGFS_F_HID
+ boolean "HID function"
+ depends on USB_CONFIGFS
+ select USB_F_HID
+ help
+ The HID function driver provides generic emulation of USB
+ Human Interface Devices (HID).
+
+ For more information, see Documentation/usb/gadget_hid.txt.
+
source "drivers/usb/gadget/legacy/Kconfig"
endchoice
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index f6a51fddd5b5..617835348569 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1246,10 +1246,49 @@ EXPORT_SYMBOL_GPL(usb_string_ids_n);
static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
{
+ struct usb_composite_dev *cdev;
+
if (req->status || req->actual != req->length)
DBG((struct usb_composite_dev *) ep->driver_data,
"setup complete --> %d, %d/%d\n",
req->status, req->actual, req->length);
+
+ /*
+ * REVIST The same ep0 requests are shared with function drivers
+ * so they don't have to maintain the same ->complete() stubs.
+ *
+ * Because of that, we need to check for the validity of ->context
+ * here, even though we know we've set it to something useful.
+ */
+ if (!req->context)
+ return;
+
+ cdev = req->context;
+
+ if (cdev->req == req)
+ cdev->setup_pending = false;
+ else if (cdev->os_desc_req == req)
+ cdev->os_desc_pending = false;
+ else
+ WARN(1, "unknown request %p\n", req);
+}
+
+static int composite_ep0_queue(struct usb_composite_dev *cdev,
+ struct usb_request *req, gfp_t gfp_flags)
+{
+ int ret;
+
+ ret = usb_ep_queue(cdev->gadget->ep0, req, gfp_flags);
+ if (ret == 0) {
+ if (cdev->req == req)
+ cdev->setup_pending = true;
+ else if (cdev->os_desc_req == req)
+ cdev->os_desc_pending = true;
+ else
+ WARN(1, "unknown request %p\n", req);
+ }
+
+ return ret;
}
static int count_ext_compat(struct usb_configuration *c)
@@ -1428,6 +1467,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
* when we delegate to it.
*/
req->zero = 0;
+ req->context = cdev;
req->complete = composite_setup_complete;
req->length = 0;
gadget->ep0->driver_data = cdev;
@@ -1624,6 +1664,7 @@ unknown:
int count = 0;
req = cdev->os_desc_req;
+ req->context = cdev;
req->complete = composite_setup_complete;
buf = req->buf;
os_desc_cfg = cdev->os_desc_config;
@@ -1686,8 +1727,9 @@ unknown:
break;
}
req->length = value;
+ req->context = cdev;
req->zero = value < w_length;
- value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+ value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
if (value < 0) {
DBG(cdev, "ep_queue --> %d\n", value);
req->status = 0;
@@ -1757,8 +1799,9 @@ unknown:
/* respond with data transfer before status phase? */
if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
req->length = value;
+ req->context = cdev;
req->zero = value < w_length;
- value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+ value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
if (value < 0) {
DBG(cdev, "ep_queue --> %d\n", value);
req->status = 0;
@@ -1893,6 +1936,7 @@ int composite_dev_prepare(struct usb_composite_driver *composite,
goto fail_dev;
cdev->req->complete = composite_setup_complete;
+ cdev->req->context = cdev;
gadget->ep0->driver_data = cdev;
cdev->driver = composite;
@@ -1937,6 +1981,7 @@ int composite_os_desc_req_prepare(struct usb_composite_dev *cdev,
kfree(cdev->os_desc_req);
goto end;
}
+ cdev->os_desc_req->context = cdev;
cdev->os_desc_req->complete = composite_setup_complete;
end:
return ret;
@@ -1951,10 +1996,16 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
kfree(uc);
}
if (cdev->os_desc_req) {
+ if (cdev->os_desc_pending)
+ usb_ep_dequeue(cdev->gadget->ep0, cdev->os_desc_req);
+
kfree(cdev->os_desc_req->buf);
usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req);
}
if (cdev->req) {
+ if (cdev->setup_pending)
+ usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
+
kfree(cdev->req->buf);
usb_ep_free_request(cdev->gadget->ep0, cdev->req);
}
@@ -2013,8 +2064,7 @@ fail:
/*-------------------------------------------------------------------------*/
-static void
-composite_suspend(struct usb_gadget *gadget)
+void composite_suspend(struct usb_gadget *gadget)
{
struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct usb_function *f;
@@ -2037,8 +2087,7 @@ composite_suspend(struct usb_gadget *gadget)
usb_gadget_vbus_draw(gadget, 2);
}
-static void
-composite_resume(struct usb_gadget *gadget)
+void composite_resume(struct usb_gadget *gadget)
{
struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct usb_function *f;
@@ -2158,7 +2207,8 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev)
} else if (--cdev->delayed_status == 0) {
DBG(cdev, "%s: Completing delayed status\n", __func__);
req->length = 0;
- value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ req->context = cdev;
+ value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
if (value < 0) {
DBG(cdev, "ep_queue --> %d\n", value);
req->status = 0;
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 34034333f7f6..75648145dc1b 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -271,7 +271,7 @@ static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi,
ret = -EBUSY;
goto err;
}
- ret = udc_attach_driver(name, &gi->composite.gadget_driver);
+ ret = usb_udc_attach_driver(name, &gi->composite.gadget_driver);
if (ret)
goto err;
gi->udc_name = name;
@@ -1453,6 +1453,9 @@ static const struct usb_gadget_driver configfs_driver_template = {
.reset = composite_disconnect,
.disconnect = composite_disconnect,
+ .suspend = composite_suspend,
+ .resume = composite_resume,
+
.max_speed = USB_SPEED_SUPER,
.driver = {
.owner = THIS_MODULE,
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile
index 90701aa5a826..dd68091d92f0 100644
--- a/drivers/usb/gadget/function/Makefile
+++ b/drivers/usb/gadget/function/Makefile
@@ -38,3 +38,7 @@ usb_f_uac2-y := f_uac2.o
obj-$(CONFIG_USB_F_UAC2) += usb_f_uac2.o
usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o
obj-$(CONFIG_USB_F_UVC) += usb_f_uvc.o
+usb_f_midi-y := f_midi.o
+obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o
+usb_f_hid-y := f_hid.o
+obj-$(CONFIG_USB_F_HID) += usb_f_hid.o
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index ea2b9c374305..6e04e302dc3a 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/hid.h>
+#include <linux/idr.h>
#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/poll.h>
@@ -21,9 +22,14 @@
#include <linux/usb/g_hid.h>
#include "u_f.h"
+#include "u_hid.h"
+
+#define HIDG_MINORS 4
static int major, minors;
static struct class *hidg_class;
+static DEFINE_IDA(hidg_ida);
+static DEFINE_MUTEX(hidg_ida_lock); /* protects access to hidg_ida */
/*-------------------------------------------------------------------------*/
/* HID gadget struct */
@@ -161,6 +167,26 @@ static struct usb_descriptor_header *hidg_fs_descriptors[] = {
};
/*-------------------------------------------------------------------------*/
+/* Strings */
+
+#define CT_FUNC_HID_IDX 0
+
+static struct usb_string ct_func_string_defs[] = {
+ [CT_FUNC_HID_IDX].s = "HID Interface",
+ {}, /* end of list */
+};
+
+static struct usb_gadget_strings ct_func_string_table = {
+ .language = 0x0409, /* en-US */
+ .strings = ct_func_string_defs,
+};
+
+static struct usb_gadget_strings *ct_func_strings[] = {
+ &ct_func_string_table,
+ NULL,
+};
+
+/*-------------------------------------------------------------------------*/
/* Char Device */
static ssize_t f_hidg_read(struct file *file, char __user *buffer,
@@ -552,13 +578,22 @@ const struct file_operations f_hidg_fops = {
.llseek = noop_llseek,
};
-static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
+static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_ep *ep;
struct f_hidg *hidg = func_to_hidg(f);
+ struct usb_string *us;
+ struct device *device;
int status;
dev_t dev;
+ /* maybe allocate device-global string IDs, and patch descriptors */
+ us = usb_gstrings_attach(c->cdev, ct_func_strings,
+ ARRAY_SIZE(ct_func_string_defs));
+ if (IS_ERR(us))
+ return PTR_ERR(us);
+ hidg_interface_desc.iInterface = us[CT_FUNC_HID_IDX].id;
+
/* allocate instance-specific interface IDs, and patch descriptors */
status = usb_interface_id(c, f);
if (status < 0)
@@ -623,10 +658,16 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
if (status)
goto fail_free_descs;
- device_create(hidg_class, NULL, dev, NULL, "%s%d", "hidg", hidg->minor);
+ device = device_create(hidg_class, NULL, dev, NULL,
+ "%s%d", "hidg", hidg->minor);
+ if (IS_ERR(device)) {
+ status = PTR_ERR(device);
+ goto del;
+ }
return 0;
-
+del:
+ cdev_del(&hidg->cdev);
fail_free_descs:
usb_free_all_descriptors(f);
fail:
@@ -640,116 +681,313 @@ fail:
return status;
}
-static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
+static inline int hidg_get_minor(void)
{
- struct f_hidg *hidg = func_to_hidg(f);
+ int ret;
- device_destroy(hidg_class, MKDEV(major, hidg->minor));
- cdev_del(&hidg->cdev);
+ ret = ida_simple_get(&hidg_ida, 0, 0, GFP_KERNEL);
- /* disable/free request and end point */
- usb_ep_disable(hidg->in_ep);
- usb_ep_dequeue(hidg->in_ep, hidg->req);
- kfree(hidg->req->buf);
- usb_ep_free_request(hidg->in_ep, hidg->req);
-
- usb_free_all_descriptors(f);
+ return ret;
+}
- kfree(hidg->report_desc);
- kfree(hidg);
+static inline struct f_hid_opts *to_f_hid_opts(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct f_hid_opts,
+ func_inst.group);
}
-/*-------------------------------------------------------------------------*/
-/* Strings */
+CONFIGFS_ATTR_STRUCT(f_hid_opts);
+CONFIGFS_ATTR_OPS(f_hid_opts);
-#define CT_FUNC_HID_IDX 0
+static void hid_attr_release(struct config_item *item)
+{
+ struct f_hid_opts *opts = to_f_hid_opts(item);
-static struct usb_string ct_func_string_defs[] = {
- [CT_FUNC_HID_IDX].s = "HID Interface",
- {}, /* end of list */
-};
+ usb_put_function_instance(&opts->func_inst);
+}
-static struct usb_gadget_strings ct_func_string_table = {
- .language = 0x0409, /* en-US */
- .strings = ct_func_string_defs,
+static struct configfs_item_operations hidg_item_ops = {
+ .release = hid_attr_release,
+ .show_attribute = f_hid_opts_attr_show,
+ .store_attribute = f_hid_opts_attr_store,
};
-static struct usb_gadget_strings *ct_func_strings[] = {
- &ct_func_string_table,
+#define F_HID_OPT(name, prec, limit) \
+static ssize_t f_hid_opts_##name##_show(struct f_hid_opts *opts, char *page)\
+{ \
+ int result; \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", opts->name); \
+ mutex_unlock(&opts->lock); \
+ \
+ return result; \
+} \
+ \
+static ssize_t f_hid_opts_##name##_store(struct f_hid_opts *opts, \
+ const char *page, size_t len) \
+{ \
+ int ret; \
+ u##prec num; \
+ \
+ mutex_lock(&opts->lock); \
+ if (opts->refcnt) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ ret = kstrtou##prec(page, 0, &num); \
+ if (ret) \
+ goto end; \
+ \
+ if (num > limit) { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
+ opts->name = num; \
+ ret = len; \
+ \
+end: \
+ mutex_unlock(&opts->lock); \
+ return ret; \
+} \
+ \
+static struct f_hid_opts_attribute f_hid_opts_##name = \
+ __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, f_hid_opts_##name##_show,\
+ f_hid_opts_##name##_store)
+
+F_HID_OPT(subclass, 8, 255);
+F_HID_OPT(protocol, 8, 255);
+F_HID_OPT(report_length, 16, 65536);
+
+static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page)
+{
+ int result;
+
+ mutex_lock(&opts->lock);
+ result = opts->report_desc_length;
+ memcpy(page, opts->report_desc, opts->report_desc_length);
+ mutex_unlock(&opts->lock);
+
+ return result;
+}
+
+static ssize_t f_hid_opts_report_desc_store(struct f_hid_opts *opts,
+ const char *page, size_t len)
+{
+ int ret = -EBUSY;
+ char *d;
+
+ mutex_lock(&opts->lock);
+
+ if (opts->refcnt)
+ goto end;
+ if (len > PAGE_SIZE) {
+ ret = -ENOSPC;
+ goto end;
+ }
+ d = kmemdup(page, len, GFP_KERNEL);
+ if (!d) {
+ ret = -ENOMEM;
+ goto end;
+ }
+ kfree(opts->report_desc);
+ opts->report_desc = d;
+ opts->report_desc_length = len;
+ opts->report_desc_alloc = true;
+ ret = len;
+end:
+ mutex_unlock(&opts->lock);
+ return ret;
+}
+
+static struct f_hid_opts_attribute f_hid_opts_report_desc =
+ __CONFIGFS_ATTR(report_desc, S_IRUGO | S_IWUSR,
+ f_hid_opts_report_desc_show,
+ f_hid_opts_report_desc_store);
+
+static struct configfs_attribute *hid_attrs[] = {
+ &f_hid_opts_subclass.attr,
+ &f_hid_opts_protocol.attr,
+ &f_hid_opts_report_length.attr,
+ &f_hid_opts_report_desc.attr,
NULL,
};
-/*-------------------------------------------------------------------------*/
-/* usb_configuration */
+static struct config_item_type hid_func_type = {
+ .ct_item_ops = &hidg_item_ops,
+ .ct_attrs = hid_attrs,
+ .ct_owner = THIS_MODULE,
+};
-int __init hidg_bind_config(struct usb_configuration *c,
- struct hidg_func_descriptor *fdesc, int index)
+static inline void hidg_put_minor(int minor)
{
- struct f_hidg *hidg;
- int status;
+ ida_simple_remove(&hidg_ida, minor);
+}
- if (index >= minors)
- return -ENOENT;
+static void hidg_free_inst(struct usb_function_instance *f)
+{
+ struct f_hid_opts *opts;
- /* maybe allocate device-global string IDs, and patch descriptors */
- if (ct_func_string_defs[CT_FUNC_HID_IDX].id == 0) {
- status = usb_string_id(c->cdev);
- if (status < 0)
- return status;
- ct_func_string_defs[CT_FUNC_HID_IDX].id = status;
- hidg_interface_desc.iInterface = status;
+ opts = container_of(f, struct f_hid_opts, func_inst);
+
+ mutex_lock(&hidg_ida_lock);
+
+ hidg_put_minor(opts->minor);
+ if (idr_is_empty(&hidg_ida.idr))
+ ghid_cleanup();
+
+ mutex_unlock(&hidg_ida_lock);
+
+ if (opts->report_desc_alloc)
+ kfree(opts->report_desc);
+
+ kfree(opts);
+}
+
+static struct usb_function_instance *hidg_alloc_inst(void)
+{
+ struct f_hid_opts *opts;
+ struct usb_function_instance *ret;
+ int status = 0;
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return ERR_PTR(-ENOMEM);
+ mutex_init(&opts->lock);
+ opts->func_inst.free_func_inst = hidg_free_inst;
+ ret = &opts->func_inst;
+
+ mutex_lock(&hidg_ida_lock);
+
+ if (idr_is_empty(&hidg_ida.idr)) {
+ status = ghid_setup(NULL, HIDG_MINORS);
+ if (status) {
+ ret = ERR_PTR(status);
+ kfree(opts);
+ goto unlock;
+ }
+ }
+
+ opts->minor = hidg_get_minor();
+ if (opts->minor < 0) {
+ ret = ERR_PTR(opts->minor);
+ kfree(opts);
+ if (idr_is_empty(&hidg_ida.idr))
+ ghid_cleanup();
+ goto unlock;
}
+ config_group_init_type_name(&opts->func_inst.group, "", &hid_func_type);
+
+unlock:
+ mutex_unlock(&hidg_ida_lock);
+ return ret;
+}
+
+static void hidg_free(struct usb_function *f)
+{
+ struct f_hidg *hidg;
+ struct f_hid_opts *opts;
+
+ hidg = func_to_hidg(f);
+ opts = container_of(f->fi, struct f_hid_opts, func_inst);
+ kfree(hidg->report_desc);
+ kfree(hidg);
+ mutex_lock(&opts->lock);
+ --opts->refcnt;
+ mutex_unlock(&opts->lock);
+}
+
+static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_hidg *hidg = func_to_hidg(f);
+
+ device_destroy(hidg_class, MKDEV(major, hidg->minor));
+ cdev_del(&hidg->cdev);
+
+ /* disable/free request and end point */
+ usb_ep_disable(hidg->in_ep);
+ usb_ep_dequeue(hidg->in_ep, hidg->req);
+ kfree(hidg->req->buf);
+ usb_ep_free_request(hidg->in_ep, hidg->req);
+
+ usb_free_all_descriptors(f);
+}
+
+static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
+{
+ struct f_hidg *hidg;
+ struct f_hid_opts *opts;
/* allocate and initialize one new instance */
- hidg = kzalloc(sizeof *hidg, GFP_KERNEL);
+ hidg = kzalloc(sizeof(*hidg), GFP_KERNEL);
if (!hidg)
- return -ENOMEM;
-
- hidg->minor = index;
- hidg->bInterfaceSubClass = fdesc->subclass;
- hidg->bInterfaceProtocol = fdesc->protocol;
- hidg->report_length = fdesc->report_length;
- hidg->report_desc_length = fdesc->report_desc_length;
- hidg->report_desc = kmemdup(fdesc->report_desc,
- fdesc->report_desc_length,
- GFP_KERNEL);
- if (!hidg->report_desc) {
- kfree(hidg);
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
+
+ opts = container_of(fi, struct f_hid_opts, func_inst);
+
+ mutex_lock(&opts->lock);
+ ++opts->refcnt;
+
+ hidg->minor = opts->minor;
+ hidg->bInterfaceSubClass = opts->subclass;
+ hidg->bInterfaceProtocol = opts->protocol;
+ hidg->report_length = opts->report_length;
+ hidg->report_desc_length = opts->report_desc_length;
+ if (opts->report_desc) {
+ hidg->report_desc = kmemdup(opts->report_desc,
+ opts->report_desc_length,
+ GFP_KERNEL);
+ if (!hidg->report_desc) {
+ kfree(hidg);
+ mutex_unlock(&opts->lock);
+ return ERR_PTR(-ENOMEM);
+ }
}
+ mutex_unlock(&opts->lock);
+
hidg->func.name = "hid";
- hidg->func.strings = ct_func_strings;
hidg->func.bind = hidg_bind;
hidg->func.unbind = hidg_unbind;
hidg->func.set_alt = hidg_set_alt;
hidg->func.disable = hidg_disable;
hidg->func.setup = hidg_setup;
+ hidg->func.free_func = hidg_free;
/* this could me made configurable at some point */
hidg->qlen = 4;
- status = usb_add_function(c, &hidg->func);
- if (status)
- kfree(hidg);
-
- return status;
+ return &hidg->func;
}
-int __init ghid_setup(struct usb_gadget *g, int count)
+DECLARE_USB_FUNCTION_INIT(hid, hidg_alloc_inst, hidg_alloc);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Fabien Chouteau");
+
+int ghid_setup(struct usb_gadget *g, int count)
{
int status;
dev_t dev;
hidg_class = class_create(THIS_MODULE, "hidg");
+ if (IS_ERR(hidg_class)) {
+ status = PTR_ERR(hidg_class);
+ hidg_class = NULL;
+ return status;
+ }
status = alloc_chrdev_region(&dev, 0, count, "hidg");
- if (!status) {
- major = MAJOR(dev);
- minors = count;
+ if (status) {
+ class_destroy(hidg_class);
+ hidg_class = NULL;
+ return status;
}
- return status;
+ major = MAJOR(dev);
+ minors = count;
+
+ return 0;
}
void ghid_cleanup(void)
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index 807b31c0edc3..a90440300735 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -20,6 +20,7 @@
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <linux/device.h>
@@ -33,6 +34,7 @@
#include <linux/usb/midi.h>
#include "u_f.h"
+#include "u_midi.h"
MODULE_AUTHOR("Ben Williamson");
MODULE_LICENSE("GPL v2");
@@ -99,7 +101,7 @@ DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16);
/* B.3.1 Standard AC Interface Descriptor */
-static struct usb_interface_descriptor ac_interface_desc __initdata = {
+static struct usb_interface_descriptor ac_interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
/* .bInterfaceNumber = DYNAMIC */
@@ -110,7 +112,7 @@ static struct usb_interface_descriptor ac_interface_desc __initdata = {
};
/* B.3.2 Class-Specific AC Interface Descriptor */
-static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = {
+static struct uac1_ac_header_descriptor_1 ac_header_desc = {
.bLength = UAC_DT_AC_HEADER_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = USB_MS_HEADER,
@@ -121,7 +123,7 @@ static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = {
};
/* B.4.1 Standard MS Interface Descriptor */
-static struct usb_interface_descriptor ms_interface_desc __initdata = {
+static struct usb_interface_descriptor ms_interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
/* .bInterfaceNumber = DYNAMIC */
@@ -132,7 +134,7 @@ static struct usb_interface_descriptor ms_interface_desc __initdata = {
};
/* B.4.2 Class-Specific MS Interface Descriptor */
-static struct usb_ms_header_descriptor ms_header_desc __initdata = {
+static struct usb_ms_header_descriptor ms_header_desc = {
.bLength = USB_DT_MS_HEADER_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = USB_MS_HEADER,
@@ -387,29 +389,6 @@ static void f_midi_disable(struct usb_function *f)
usb_ep_disable(midi->out_ep);
}
-static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
-{
- struct usb_composite_dev *cdev = f->config->cdev;
- struct f_midi *midi = func_to_midi(f);
- struct snd_card *card;
-
- DBG(cdev, "unbind\n");
-
- /* just to be sure */
- f_midi_disable(f);
-
- card = midi->card;
- midi->card = NULL;
- if (card)
- snd_card_free(card);
-
- kfree(midi->id);
- midi->id = NULL;
-
- usb_free_all_descriptors(f);
- kfree(midi);
-}
-
static int f_midi_snd_free(struct snd_device *device)
{
return 0;
@@ -654,6 +633,14 @@ static struct snd_rawmidi_ops gmidi_out_ops = {
.trigger = f_midi_out_trigger
};
+static inline void f_midi_unregister_card(struct f_midi *midi)
+{
+ if (midi->card) {
+ snd_card_free(midi->card);
+ midi->card = NULL;
+ }
+}
+
/* register as a sound "card" */
static int f_midi_register_card(struct f_midi *midi)
{
@@ -715,17 +702,13 @@ static int f_midi_register_card(struct f_midi *midi)
return 0;
fail:
- if (midi->card) {
- snd_card_free(midi->card);
- midi->card = NULL;
- }
+ f_midi_unregister_card(midi);
return err;
}
/* MIDI function driver setup/binding */
-static int __init
-f_midi_bind(struct usb_configuration *c, struct usb_function *f)
+static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_descriptor_header **midi_function;
struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS];
@@ -734,15 +717,23 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc[MAX_PORTS];
struct usb_composite_dev *cdev = c->cdev;
struct f_midi *midi = func_to_midi(f);
+ struct usb_string *us;
int status, n, jack = 1, i = 0;
+ midi->gadget = cdev->gadget;
+ tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi);
+ status = f_midi_register_card(midi);
+ if (status < 0)
+ goto fail_register;
+
/* maybe allocate device-global string ID */
- if (midi_string_defs[0].id == 0) {
- status = usb_string_id(c->cdev);
- if (status < 0)
- goto fail;
- midi_string_defs[0].id = status;
+ us = usb_gstrings_attach(c->cdev, midi_strings,
+ ARRAY_SIZE(midi_string_defs));
+ if (IS_ERR(us)) {
+ status = PTR_ERR(us);
+ goto fail;
}
+ ac_interface_desc.iInterface = us[STRING_FUNC_IDX].id;
/* We have two interfaces, AudioControl and MIDIStreaming */
status = usb_interface_id(c, f);
@@ -892,6 +883,8 @@ fail_f_midi:
kfree(midi_function);
usb_free_descriptors(f->hs_descriptors);
fail:
+ f_midi_unregister_card(midi);
+fail_register:
/* we might as well release our claims on endpoints */
if (midi->out_ep)
midi->out_ep->driver_data = NULL;
@@ -903,42 +896,235 @@ fail:
return status;
}
-/**
- * f_midi_bind_config - add USB MIDI function to a configuration
- * @c: the configuration to supcard the USB audio function
- * @index: the soundcard index to use for the ALSA device creation
- * @id: the soundcard id to use for the ALSA device creation
- * @buflen: the buffer length to use
- * @qlen the number of read requests to pre-allocate
- * Context: single threaded during gadget setup
- *
- * Returns zero on success, else negative errno.
- */
-int __init f_midi_bind_config(struct usb_configuration *c,
- int index, char *id,
- unsigned int in_ports,
- unsigned int out_ports,
- unsigned int buflen,
- unsigned int qlen)
+static inline struct f_midi_opts *to_f_midi_opts(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct f_midi_opts,
+ func_inst.group);
+}
+
+CONFIGFS_ATTR_STRUCT(f_midi_opts);
+CONFIGFS_ATTR_OPS(f_midi_opts);
+
+static void midi_attr_release(struct config_item *item)
+{
+ struct f_midi_opts *opts = to_f_midi_opts(item);
+
+ usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations midi_item_ops = {
+ .release = midi_attr_release,
+ .show_attribute = f_midi_opts_attr_show,
+ .store_attribute = f_midi_opts_attr_store,
+};
+
+#define F_MIDI_OPT(name, test_limit, limit) \
+static ssize_t f_midi_opts_##name##_show(struct f_midi_opts *opts, char *page) \
+{ \
+ int result; \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", opts->name); \
+ mutex_unlock(&opts->lock); \
+ \
+ return result; \
+} \
+ \
+static ssize_t f_midi_opts_##name##_store(struct f_midi_opts *opts, \
+ const char *page, size_t len) \
+{ \
+ int ret; \
+ u32 num; \
+ \
+ mutex_lock(&opts->lock); \
+ if (opts->refcnt) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ ret = kstrtou32(page, 0, &num); \
+ if (ret) \
+ goto end; \
+ \
+ if (test_limit && num > limit) { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
+ opts->name = num; \
+ ret = len; \
+ \
+end: \
+ mutex_unlock(&opts->lock); \
+ return ret; \
+} \
+ \
+static struct f_midi_opts_attribute f_midi_opts_##name = \
+ __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, f_midi_opts_##name##_show, \
+ f_midi_opts_##name##_store)
+
+F_MIDI_OPT(index, true, SNDRV_CARDS);
+F_MIDI_OPT(buflen, false, 0);
+F_MIDI_OPT(qlen, false, 0);
+F_MIDI_OPT(in_ports, true, MAX_PORTS);
+F_MIDI_OPT(out_ports, true, MAX_PORTS);
+
+static ssize_t f_midi_opts_id_show(struct f_midi_opts *opts, char *page)
+{
+ int result;
+
+ mutex_lock(&opts->lock);
+ result = strlcpy(page, opts->id, PAGE_SIZE);
+ mutex_unlock(&opts->lock);
+
+ return result;
+}
+
+static ssize_t f_midi_opts_id_store(struct f_midi_opts *opts,
+ const char *page, size_t len)
+{
+ int ret;
+ char *c;
+
+ mutex_lock(&opts->lock);
+ if (opts->refcnt) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ c = kstrndup(page, len, GFP_KERNEL);
+ if (!c) {
+ ret = -ENOMEM;
+ goto end;
+ }
+ if (opts->id_allocated)
+ kfree(opts->id);
+ opts->id = c;
+ opts->id_allocated = true;
+ ret = len;
+end:
+ mutex_unlock(&opts->lock);
+ return ret;
+}
+
+static struct f_midi_opts_attribute f_midi_opts_id =
+ __CONFIGFS_ATTR(id, S_IRUGO | S_IWUSR, f_midi_opts_id_show,
+ f_midi_opts_id_store);
+
+static struct configfs_attribute *midi_attrs[] = {
+ &f_midi_opts_index.attr,
+ &f_midi_opts_buflen.attr,
+ &f_midi_opts_qlen.attr,
+ &f_midi_opts_in_ports.attr,
+ &f_midi_opts_out_ports.attr,
+ &f_midi_opts_id.attr,
+ NULL,
+};
+
+static struct config_item_type midi_func_type = {
+ .ct_item_ops = &midi_item_ops,
+ .ct_attrs = midi_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static void f_midi_free_inst(struct usb_function_instance *f)
+{
+ struct f_midi_opts *opts;
+
+ opts = container_of(f, struct f_midi_opts, func_inst);
+
+ if (opts->id_allocated)
+ kfree(opts->id);
+
+ kfree(opts);
+}
+
+static struct usb_function_instance *f_midi_alloc_inst(void)
+{
+ struct f_midi_opts *opts;
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&opts->lock);
+ opts->func_inst.free_func_inst = f_midi_free_inst;
+ opts->index = SNDRV_DEFAULT_IDX1;
+ opts->id = SNDRV_DEFAULT_STR1;
+ opts->buflen = 256;
+ opts->qlen = 32;
+ opts->in_ports = 1;
+ opts->out_ports = 1;
+
+ config_group_init_type_name(&opts->func_inst.group, "",
+ &midi_func_type);
+
+ return &opts->func_inst;
+}
+
+static void f_midi_free(struct usb_function *f)
+{
+ struct f_midi *midi;
+ struct f_midi_opts *opts;
+ int i;
+
+ midi = func_to_midi(f);
+ opts = container_of(f->fi, struct f_midi_opts, func_inst);
+ kfree(midi->id);
+ mutex_lock(&opts->lock);
+ for (i = opts->in_ports - 1; i >= 0; --i)
+ kfree(midi->in_port[i]);
+ kfree(midi);
+ --opts->refcnt;
+ mutex_unlock(&opts->lock);
+}
+
+static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct f_midi *midi = func_to_midi(f);
+ struct snd_card *card;
+
+ DBG(cdev, "unbind\n");
+
+ /* just to be sure */
+ f_midi_disable(f);
+
+ card = midi->card;
+ midi->card = NULL;
+ if (card)
+ snd_card_free(card);
+
+ usb_free_all_descriptors(f);
+}
+
+static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
{
struct f_midi *midi;
+ struct f_midi_opts *opts;
int status, i;
+ opts = container_of(fi, struct f_midi_opts, func_inst);
+
+ mutex_lock(&opts->lock);
/* sanity check */
- if (in_ports > MAX_PORTS || out_ports > MAX_PORTS)
- return -EINVAL;
+ if (opts->in_ports > MAX_PORTS || opts->out_ports > MAX_PORTS) {
+ mutex_unlock(&opts->lock);
+ return ERR_PTR(-EINVAL);
+ }
/* allocate and initialize one new instance */
- midi = kzalloc(sizeof *midi, GFP_KERNEL);
+ midi = kzalloc(sizeof(*midi), GFP_KERNEL);
if (!midi) {
- status = -ENOMEM;
- goto fail;
+ mutex_unlock(&opts->lock);
+ return ERR_PTR(-ENOMEM);
}
- for (i = 0; i < in_ports; i++) {
+ for (i = 0; i < opts->in_ports; i++) {
struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL);
+
if (!port) {
status = -ENOMEM;
+ mutex_unlock(&opts->lock);
goto setup_fail;
}
@@ -948,39 +1134,37 @@ int __init f_midi_bind_config(struct usb_configuration *c,
midi->in_port[i] = port;
}
- midi->gadget = c->cdev->gadget;
- tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi);
-
/* set up ALSA midi devices */
- midi->in_ports = in_ports;
- midi->out_ports = out_ports;
- status = f_midi_register_card(midi);
- if (status < 0)
- goto setup_fail;
-
- midi->func.name = "gmidi function";
- midi->func.strings = midi_strings;
- midi->func.bind = f_midi_bind;
- midi->func.unbind = f_midi_unbind;
- midi->func.set_alt = f_midi_set_alt;
- midi->func.disable = f_midi_disable;
-
- midi->id = kstrdup(id, GFP_KERNEL);
- midi->index = index;
- midi->buflen = buflen;
- midi->qlen = qlen;
-
- status = usb_add_function(c, &midi->func);
- if (status)
- goto setup_fail;
-
- return 0;
-
+ midi->id = kstrdup(opts->id, GFP_KERNEL);
+ if (opts->id && !midi->id) {
+ status = -ENOMEM;
+ mutex_unlock(&opts->lock);
+ goto kstrdup_fail;
+ }
+ midi->in_ports = opts->in_ports;
+ midi->out_ports = opts->out_ports;
+ midi->index = opts->index;
+ midi->buflen = opts->buflen;
+ midi->qlen = opts->qlen;
+ ++opts->refcnt;
+ mutex_unlock(&opts->lock);
+
+ midi->func.name = "gmidi function";
+ midi->func.bind = f_midi_bind;
+ midi->func.unbind = f_midi_unbind;
+ midi->func.set_alt = f_midi_set_alt;
+ midi->func.disable = f_midi_disable;
+ midi->func.free_func = f_midi_free;
+
+ return &midi->func;
+
+kstrdup_fail:
+ f_midi_unregister_card(midi);
setup_fail:
for (--i; i >= 0; i--)
kfree(midi->in_port[i]);
kfree(midi);
-fail:
- return status;
+ return ERR_PTR(status);
}
+DECLARE_USB_FUNCTION_INIT(midi, f_midi_alloc_inst, f_midi_alloc);
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index 16361b0a8b46..bdcda9f5148e 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -1441,6 +1441,9 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function,
NULL);
+ if (status)
+ goto fail;
+
/*
* NOTE: all that is done without knowing or caring about
* the network link ... which is unavailable to this code
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index f13fc6a58565..829edf878dac 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -375,8 +375,7 @@ static struct sk_buff *rndis_add_header(struct gether *port,
struct sk_buff *skb2;
skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
- if (skb2)
- rndis_add_hdr(skb2);
+ rndis_add_hdr(skb2);
dev_kfree_skb(skb);
return skb2;
diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h
new file mode 100644
index 000000000000..aaa0e368a159
--- /dev/null
+++ b/drivers/usb/gadget/function/u_hid.h
@@ -0,0 +1,42 @@
+/*
+ * u_hid.h
+ *
+ * Utility definitions for the hid function
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef U_HID_H
+#define U_HID_H
+
+#include <linux/usb/composite.h>
+
+struct f_hid_opts {
+ struct usb_function_instance func_inst;
+ int minor;
+ unsigned char subclass;
+ unsigned char protocol;
+ unsigned short report_length;
+ unsigned short report_desc_length;
+ unsigned char *report_desc;
+ bool report_desc_alloc;
+
+ /*
+ * Protect the data form concurrent access by read/write
+ * and create symlink/remove symlink.
+ */
+ struct mutex lock;
+ int refcnt;
+};
+
+int ghid_setup(struct usb_gadget *g, int count);
+void ghid_cleanup(void);
+
+#endif /* U_HID_H */
diff --git a/drivers/usb/gadget/function/u_midi.h b/drivers/usb/gadget/function/u_midi.h
new file mode 100644
index 000000000000..22510189758e
--- /dev/null
+++ b/drivers/usb/gadget/function/u_midi.h
@@ -0,0 +1,40 @@
+/*
+ * u_midi.h
+ *
+ * Utility definitions for the midi function
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef U_MIDI_H
+#define U_MIDI_H
+
+#include <linux/usb/composite.h>
+
+struct f_midi_opts {
+ struct usb_function_instance func_inst;
+ int index;
+ char *id;
+ bool id_allocated;
+ unsigned int in_ports;
+ unsigned int out_ports;
+ unsigned int buflen;
+ unsigned int qlen;
+
+ /*
+ * Protect the data form concurrent access by read/write
+ * and create symlink/remove symlink.
+ */
+ struct mutex lock;
+ int refcnt;
+};
+
+#endif /* U_MIDI_H */
+
diff --git a/drivers/usb/gadget/function/u_uac1.c b/drivers/usb/gadget/function/u_uac1.c
index a44a07f30281..53842a1b947f 100644
--- a/drivers/usb/gadget/function/u_uac1.c
+++ b/drivers/usb/gadget/function/u_uac1.c
@@ -213,9 +213,6 @@ static int gaudio_open_snd_dev(struct gaudio *card)
fn_cap = opts->fn_cap;
fn_cntl = opts->fn_cntl;
- if (!card)
- return -ENODEV;
-
/* Open control device */
snd = &card->control;
snd->filp = filp_open(fn_cntl, O_RDWR, 0);
diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig
index 24392d269709..fd48ef3af4eb 100644
--- a/drivers/usb/gadget/legacy/Kconfig
+++ b/drivers/usb/gadget/legacy/Kconfig
@@ -287,6 +287,7 @@ config USB_MIDI_GADGET
depends on SND
select USB_LIBCOMPOSITE
select SND_RAWMIDI
+ select USB_F_MIDI
help
The MIDI Gadget acts as a USB Audio device, with one MIDI
input and one MIDI output. These MIDI jacks appear as
@@ -419,6 +420,7 @@ endif # TTY
config USB_G_HID
tristate "HID Gadget"
select USB_LIBCOMPOSITE
+ select USB_F_HID
help
The HID gadget driver provides generic emulation of USB
Human Interface Devices (HID).
diff --git a/drivers/usb/gadget/legacy/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c
index 1b075132f8f1..633683a72a11 100644
--- a/drivers/usb/gadget/legacy/dbgp.c
+++ b/drivers/usb/gadget/legacy/dbgp.c
@@ -237,7 +237,7 @@ static void dbgp_unbind(struct usb_gadget *gadget)
static unsigned char tty_line;
#endif
-static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
+static int dbgp_configure_endpoints(struct usb_gadget *gadget)
{
int stp;
@@ -273,19 +273,10 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
dbgp.serial->in->desc = &i_desc;
dbgp.serial->out->desc = &o_desc;
-
- if (gserial_alloc_line(&tty_line)) {
- stp = 3;
- goto fail_3;
- }
+#endif
return 0;
-fail_3:
- dbgp.o_ep->driver_data = NULL;
-#else
- return 0;
-#endif
fail_2:
dbgp.i_ep->driver_data = NULL;
fail_1:
@@ -324,10 +315,17 @@ static int __init dbgp_bind(struct usb_gadget *gadget,
err = -ENOMEM;
goto fail;
}
+
+ if (gserial_alloc_line(&tty_line)) {
+ stp = 4;
+ err = -ENODEV;
+ goto fail;
+ }
#endif
+
err = dbgp_configure_endpoints(gadget);
if (err < 0) {
- stp = 4;
+ stp = 5;
goto fail;
}
@@ -383,6 +381,10 @@ static int dbgp_setup(struct usb_gadget *gadget,
#ifdef CONFIG_USB_G_DBGP_PRINTK
err = dbgp_enable_ep();
#else
+ err = dbgp_configure_endpoints(gadget);
+ if (err < 0) {
+ goto fail;
+ }
err = gserial_connect(dbgp.serial, tty_line);
#endif
if (err < 0)
diff --git a/drivers/usb/gadget/legacy/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c
index 3d696b86ff76..e02a095294ac 100644
--- a/drivers/usb/gadget/legacy/gmidi.c
+++ b/drivers/usb/gadget/legacy/gmidi.c
@@ -37,7 +37,7 @@
#include "gadget_chips.h"
-#include "f_midi.c"
+#include "u_midi.h"
/*-------------------------------------------------------------------------*/
@@ -115,8 +115,13 @@ static struct usb_gadget_strings *dev_strings[] = {
NULL,
};
+static struct usb_function_instance *fi_midi;
+static struct usb_function *f_midi;
+
static int __exit midi_unbind(struct usb_composite_dev *dev)
{
+ usb_put_function(f_midi);
+ usb_put_function_instance(fi_midi);
return 0;
}
@@ -130,28 +135,54 @@ static struct usb_configuration midi_config = {
static int __init midi_bind_config(struct usb_configuration *c)
{
- return f_midi_bind_config(c, index, id,
- in_ports, out_ports,
- buflen, qlen);
+ int status;
+
+ f_midi = usb_get_function(fi_midi);
+ if (IS_ERR(f_midi))
+ return PTR_ERR(f_midi);
+
+ status = usb_add_function(c, f_midi);
+ if (status < 0) {
+ usb_put_function(f_midi);
+ return status;
+ }
+
+ return 0;
}
static int __init midi_bind(struct usb_composite_dev *cdev)
{
+ struct f_midi_opts *midi_opts;
int status;
+ fi_midi = usb_get_function_instance("midi");
+ if (IS_ERR(fi_midi))
+ return PTR_ERR(fi_midi);
+
+ midi_opts = container_of(fi_midi, struct f_midi_opts, func_inst);
+ midi_opts->index = index;
+ midi_opts->id = id;
+ midi_opts->in_ports = in_ports;
+ midi_opts->out_ports = out_ports;
+ midi_opts->buflen = buflen;
+ midi_opts->qlen = qlen;
+
status = usb_string_ids_tab(cdev, strings_dev);
if (status < 0)
- return status;
+ goto put;
device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
midi_config.iConfiguration = strings_dev[STRING_DESCRIPTION_IDX].id;
status = usb_add_config(cdev, &midi_config, midi_bind_config);
if (status < 0)
- return status;
+ goto put;
usb_composite_overwrite_options(cdev, &coverwrite);
pr_info("%s\n", longname);
return 0;
+put:
+ usb_put_function_instance(fi_midi);
+ return status;
}
static __refdata struct usb_composite_driver midi_driver = {
diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c
index 778613eb37af..633fe7e07688 100644
--- a/drivers/usb/gadget/legacy/hid.c
+++ b/drivers/usb/gadget/legacy/hid.c
@@ -17,11 +17,14 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/usb/composite.h>
+#include <linux/usb/g_hid.h>
#include "gadget_chips.h"
#define DRIVER_DESC "HID Gadget"
#define DRIVER_VERSION "2010/03/16"
+#include "u_hid.h"
+
/*-------------------------------------------------------------------------*/
#define HIDG_VENDOR_NUM 0x0525 /* XXX NetChip */
@@ -29,17 +32,9 @@
/*-------------------------------------------------------------------------*/
-/*
- * 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_hid.c"
-
-
struct hidg_func_node {
+ struct usb_function_instance *fi;
+ struct usb_function *f;
struct list_head node;
struct hidg_func_descriptor *func;
};
@@ -113,8 +108,8 @@ static struct usb_gadget_strings *dev_strings[] = {
static int __init do_config(struct usb_configuration *c)
{
- struct hidg_func_node *e;
- int func = 0, status = 0;
+ struct hidg_func_node *e, *n;
+ int status = 0;
if (gadget_is_otg(c->cdev->gadget)) {
c->descriptors = otg_desc;
@@ -122,11 +117,24 @@ static int __init do_config(struct usb_configuration *c)
}
list_for_each_entry(e, &hidg_func_list, node) {
- status = hidg_bind_config(c, e->func, func++);
- if (status)
- break;
+ e->f = usb_get_function(e->fi);
+ if (IS_ERR(e->f))
+ goto put;
+ status = usb_add_function(c, e->f);
+ if (status < 0) {
+ usb_put_function(e->f);
+ goto put;
+ }
}
+ return 0;
+put:
+ list_for_each_entry(n, &hidg_func_list, node) {
+ if (n == e)
+ break;
+ usb_remove_function(c, n->f);
+ usb_put_function(n->f);
+ }
return status;
}
@@ -143,6 +151,8 @@ static int __init hid_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
struct list_head *tmp;
+ struct hidg_func_node *n, *m;
+ struct f_hid_opts *hid_opts;
int status, funcs = 0;
list_for_each(tmp, &hidg_func_list)
@@ -151,10 +161,20 @@ static int __init hid_bind(struct usb_composite_dev *cdev)
if (!funcs)
return -ENODEV;
- /* set up HID */
- status = ghid_setup(cdev->gadget, funcs);
- if (status < 0)
- return status;
+ list_for_each_entry(n, &hidg_func_list, node) {
+ n->fi = usb_get_function_instance("hid");
+ if (IS_ERR(n->fi)) {
+ status = PTR_ERR(n->fi);
+ goto put;
+ }
+ hid_opts = container_of(n->fi, struct f_hid_opts, func_inst);
+ hid_opts->subclass = n->func->subclass;
+ hid_opts->protocol = n->func->protocol;
+ hid_opts->report_length = n->func->report_length;
+ hid_opts->report_desc_length = n->func->report_desc_length;
+ hid_opts->report_desc = n->func->report_desc;
+ }
+
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
@@ -162,24 +182,37 @@ static int __init hid_bind(struct usb_composite_dev *cdev)
status = usb_string_ids_tab(cdev, strings_dev);
if (status < 0)
- return status;
+ goto put;
device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
/* register our configuration */
status = usb_add_config(cdev, &config_driver, do_config);
if (status < 0)
- return status;
+ goto put;
usb_composite_overwrite_options(cdev, &coverwrite);
dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
return 0;
+
+put:
+ list_for_each_entry(m, &hidg_func_list, node) {
+ if (m == n)
+ break;
+ usb_put_function_instance(m->fi);
+ }
+ return status;
}
static int __exit hid_unbind(struct usb_composite_dev *cdev)
{
- ghid_cleanup();
+ struct hidg_func_node *n;
+
+ list_for_each_entry(n, &hidg_func_list, node) {
+ usb_put_function(n->f);
+ usb_put_function_instance(n->fi);
+ }
return 0;
}
@@ -260,7 +293,7 @@ module_init(hidg_init);
static void __exit hidg_cleanup(void)
{
- platform_driver_unregister(&hidg_plat_driver);
usb_composite_unregister(&hidg_driver);
+ platform_driver_unregister(&hidg_plat_driver);
}
module_exit(hidg_cleanup);
diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c
index 6474081dcbaf..90545980542f 100644
--- a/drivers/usb/gadget/legacy/printer.c
+++ b/drivers/usb/gadget/legacy/printer.c
@@ -208,6 +208,43 @@ static struct usb_descriptor_header *hs_printer_function[] = {
NULL
};
+/*
+ * Added endpoint descriptors for 3.0 devices
+ */
+
+static struct usb_endpoint_descriptor ss_ep_in_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 ss_ep_in_comp_desc = {
+ .bLength = sizeof(ss_ep_in_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_endpoint_descriptor ss_ep_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 ss_ep_out_comp_desc = {
+ .bLength = sizeof(ss_ep_out_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *ss_printer_function[] = {
+ (struct usb_descriptor_header *) &intf_desc,
+ (struct usb_descriptor_header *) &ss_ep_in_desc,
+ (struct usb_descriptor_header *) &ss_ep_in_comp_desc,
+ (struct usb_descriptor_header *) &ss_ep_out_desc,
+ (struct usb_descriptor_header *) &ss_ep_out_comp_desc,
+ NULL
+};
+
static struct usb_otg_descriptor otg_descriptor = {
.bLength = sizeof otg_descriptor,
.bDescriptorType = USB_DT_OTG,
@@ -220,7 +257,20 @@ static const struct usb_descriptor_header *otg_desc[] = {
};
/* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
+static inline struct usb_endpoint_descriptor *ep_desc(struct usb_gadget *gadget,
+ struct usb_endpoint_descriptor *fs,
+ struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *ss)
+{
+ switch (gadget->speed) {
+ case USB_SPEED_SUPER:
+ return ss;
+ case USB_SPEED_HIGH:
+ return hs;
+ default:
+ return fs;
+ }
+}
/*-------------------------------------------------------------------------*/
@@ -793,11 +843,12 @@ set_printer_interface(struct printer_dev *dev)
{
int result = 0;
- dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
+ dev->in_ep->desc = ep_desc(dev->gadget, &fs_ep_in_desc, &hs_ep_in_desc,
+ &ss_ep_in_desc);
dev->in_ep->driver_data = dev;
- dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc,
- &fs_ep_out_desc);
+ dev->out_ep->desc = ep_desc(dev->gadget, &fs_ep_out_desc,
+ &hs_ep_out_desc, &ss_ep_out_desc);
dev->out_ep->driver_data = dev;
result = usb_ep_enable(dev->in_ep);
@@ -1016,9 +1067,11 @@ autoconf_fail:
/* assumes that all endpoints are dual-speed */
hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
+ ss_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
+ ss_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
ret = usb_assign_descriptors(f, fs_printer_function,
- hs_printer_function, NULL);
+ hs_printer_function, ss_printer_function);
if (ret)
return ret;
@@ -1253,7 +1306,7 @@ static __refdata struct usb_composite_driver printer_driver = {
.name = shortname,
.dev = &device_desc,
.strings = dev_strings,
- .max_speed = USB_SPEED_HIGH,
+ .max_speed = USB_SPEED_SUPER,
.bind = printer_bind,
.unbind = printer_unbind,
};
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index 217365d35a25..b8e213eb36cc 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -241,6 +241,8 @@ config USB_M66592
dynamically linked module called "m66592_udc" and force all
gadget drivers to also be dynamically linked.
+source "drivers/usb/gadget/udc/bdc/Kconfig"
+
#
# Controllers available only in discrete form (and all PCI controllers)
#
diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile
index a7f4491593f1..fba2049bf985 100644
--- a/drivers/usb/gadget/udc/Makefile
+++ b/drivers/usb/gadget/udc/Makefile
@@ -30,3 +30,4 @@ obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
obj-$(CONFIG_USB_GR_UDC) += gr_udc.o
obj-$(CONFIG_USB_GADGET_XILINX) += udc-xilinx.o
+obj-$(CONFIG_USB_BDC_UDC) += bdc/
diff --git a/drivers/usb/gadget/udc/amd5536udc.c b/drivers/usb/gadget/udc/amd5536udc.c
index 3b9d13848a4f..de7e5e2ccf1c 100644
--- a/drivers/usb/gadget/udc/amd5536udc.c
+++ b/drivers/usb/gadget/udc/amd5536udc.c
@@ -1401,9 +1401,8 @@ static int udc_wakeup(struct usb_gadget *gadget)
static int amd5536_udc_start(struct usb_gadget *g,
struct usb_gadget_driver *driver);
-static int amd5536_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
-/* gadget operations */
+static int amd5536_udc_stop(struct usb_gadget *g);
+
static const struct usb_gadget_ops udc_ops = {
.wakeup = udc_wakeup,
.get_frame = udc_get_frame,
@@ -1962,8 +1961,7 @@ __acquires(dev->lock)
}
/* Called by gadget driver to unregister itself */
-static int amd5536_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int amd5536_udc_stop(struct usb_gadget *g)
{
struct udc *dev = to_amd5536_udc(g);
unsigned long flags;
@@ -1971,7 +1969,7 @@ static int amd5536_udc_stop(struct usb_gadget *g,
spin_lock_irqsave(&dev->lock, flags);
udc_mask_unused_interrupts(dev);
- shutdown(dev, driver);
+ shutdown(dev, NULL);
spin_unlock_irqrestore(&dev->lock, flags);
dev->driver = NULL;
@@ -2873,7 +2871,7 @@ __acquires(dev->lock)
dev->driver->resume(&dev->gadget);
dev->sys_suspended = 0;
}
- dev->driver->disconnect(&dev->gadget);
+ usb_gadget_udc_reset(&dev->gadget, dev->driver);
spin_lock(&dev->lock);
/* disable ep0 to empty req queue */
diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c
index 9968f5331fe4..eb2999c5d03c 100644
--- a/drivers/usb/gadget/udc/at91_udc.c
+++ b/drivers/usb/gadget/udc/at91_udc.c
@@ -840,6 +840,31 @@ static void udc_reinit(struct at91_udc *udc)
}
}
+static void reset_gadget(struct at91_udc *udc)
+{
+ struct usb_gadget_driver *driver = udc->driver;
+ int i;
+
+ if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+ driver = NULL;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->suspended = 0;
+
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ struct at91_ep *ep = &udc->ep[i];
+
+ ep->stopped = 1;
+ nuke(ep, -ESHUTDOWN);
+ }
+ if (driver) {
+ spin_unlock(&udc->lock);
+ usb_gadget_udc_reset(&udc->gadget, driver);
+ spin_lock(&udc->lock);
+ }
+
+ udc_reinit(udc);
+}
+
static void stop_activity(struct at91_udc *udc)
{
struct usb_gadget_driver *driver = udc->driver;
@@ -870,12 +895,10 @@ static void clk_on(struct at91_udc *udc)
return;
udc->clocked = 1;
- if (IS_ENABLED(CONFIG_COMMON_CLK)) {
- clk_set_rate(udc->uclk, 48000000);
- clk_prepare_enable(udc->uclk);
- }
- clk_prepare_enable(udc->iclk);
- clk_prepare_enable(udc->fclk);
+ if (IS_ENABLED(CONFIG_COMMON_CLK))
+ clk_enable(udc->uclk);
+ clk_enable(udc->iclk);
+ clk_enable(udc->fclk);
}
static void clk_off(struct at91_udc *udc)
@@ -884,10 +907,10 @@ static void clk_off(struct at91_udc *udc)
return;
udc->clocked = 0;
udc->gadget.speed = USB_SPEED_UNKNOWN;
- clk_disable_unprepare(udc->fclk);
- clk_disable_unprepare(udc->iclk);
+ clk_disable(udc->fclk);
+ clk_disable(udc->iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
- clk_disable_unprepare(udc->uclk);
+ clk_disable(udc->uclk);
}
/*
@@ -984,8 +1007,8 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
static int at91_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
-static int at91_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver);
+static int at91_stop(struct usb_gadget *gadget);
+
static const struct usb_gadget_ops at91_udc_ops = {
.get_frame = at91_get_frame,
.wakeup = at91_wakeup,
@@ -1426,7 +1449,7 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
VDBG("end bus reset\n");
udc->addr = 0;
- stop_activity(udc);
+ reset_gadget(udc);
/* enable ep0 */
at91_udp_write(udc, AT91_UDP_CSR(0),
@@ -1512,20 +1535,11 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
/*-------------------------------------------------------------------------*/
-static void nop_release(struct device *dev)
-{
- /* nothing to free */
-}
-
static struct at91_udc controller = {
.gadget = {
.ops = &at91_udc_ops,
.ep0 = &controller.ep[0].ep,
.name = driver_name,
- .dev = {
- .init_name = "gadget",
- .release = nop_release,
- }
},
.ep[0] = {
.ep = {
@@ -1641,12 +1655,10 @@ static int at91_start(struct usb_gadget *gadget,
udc->enabled = 1;
udc->selfpowered = 1;
- DBG("bound to %s\n", driver->driver.name);
return 0;
}
-static int at91_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static int at91_stop(struct usb_gadget *gadget)
{
struct at91_udc *udc;
unsigned long flags;
@@ -1659,7 +1671,6 @@ static int at91_stop(struct usb_gadget *gadget,
udc->driver = NULL;
- DBG("unbound from %s\n", driver->driver.name);
return 0;
}
@@ -1780,14 +1791,24 @@ static int at91udc_probe(struct platform_device *pdev)
}
/* don't do anything until we have both gadget driver and VBUS */
+ if (IS_ENABLED(CONFIG_COMMON_CLK)) {
+ clk_set_rate(udc->uclk, 48000000);
+ retval = clk_prepare(udc->uclk);
+ if (retval)
+ goto fail1;
+ }
+ retval = clk_prepare(udc->fclk);
+ if (retval)
+ goto fail1a;
+
retval = clk_prepare_enable(udc->iclk);
if (retval)
- goto fail1;
+ goto fail1b;
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff);
/* Clear all pending interrupts - UDP may be used by bootloader. */
at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff);
- clk_disable_unprepare(udc->iclk);
+ clk_disable(udc->iclk);
/* request UDC and maybe VBUS irqs */
udc->udp_irq = platform_get_irq(pdev, 0);
@@ -1795,7 +1816,7 @@ static int at91udc_probe(struct platform_device *pdev)
0, driver_name, udc);
if (retval < 0) {
DBG("request irq %d failed\n", udc->udp_irq);
- goto fail1;
+ goto fail1c;
}
if (gpio_is_valid(udc->board.vbus_pin)) {
retval = gpio_request(udc->board.vbus_pin, "udc_vbus");
@@ -1848,6 +1869,13 @@ fail3:
gpio_free(udc->board.vbus_pin);
fail2:
free_irq(udc->udp_irq, udc);
+fail1c:
+ clk_unprepare(udc->iclk);
+fail1b:
+ clk_unprepare(udc->fclk);
+fail1a:
+ if (IS_ENABLED(CONFIG_COMMON_CLK))
+ clk_unprepare(udc->uclk);
fail1:
if (IS_ENABLED(CONFIG_COMMON_CLK) && !IS_ERR(udc->uclk))
clk_put(udc->uclk);
@@ -1896,6 +1924,11 @@ static int __exit at91udc_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
+ if (IS_ENABLED(CONFIG_COMMON_CLK))
+ clk_unprepare(udc->uclk);
+ clk_unprepare(udc->fclk);
+ clk_unprepare(udc->iclk);
+
clk_put(udc->iclk);
clk_put(udc->fclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 1529926e20a0..b31747979c4a 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -987,8 +987,8 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
static int atmel_usba_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
-static int atmel_usba_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver);
+static int atmel_usba_stop(struct usb_gadget *gadget);
+
static const struct usb_gadget_ops usba_udc_ops = {
.get_frame = usba_udc_get_frame,
.wakeup = usba_udc_wakeup,
@@ -1007,19 +1007,10 @@ static struct usb_endpoint_descriptor usba_ep0_desc = {
.bInterval = 1,
};
-static void nop_release(struct device *dev)
-{
-
-}
-
static struct usb_gadget usba_gadget_template = {
.ops = &usba_udc_ops,
.max_speed = USB_SPEED_HIGH,
.name = "atmel_usba_udc",
- .dev = {
- .init_name = "gadget",
- .release = nop_release,
- },
};
/*
@@ -1685,11 +1676,10 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
reset_all_endpoints(udc);
- if (udc->gadget.speed != USB_SPEED_UNKNOWN
- && udc->driver && udc->driver->disconnect) {
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN && udc->driver) {
udc->gadget.speed = USB_SPEED_UNKNOWN;
spin_unlock(&udc->lock);
- udc->driver->disconnect(&udc->gadget);
+ usb_gadget_udc_reset(&udc->gadget, udc->driver);
spin_lock(&udc->lock);
}
@@ -1791,8 +1781,6 @@ static int atmel_usba_start(struct usb_gadget *gadget,
return ret;
}
- DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
-
udc->vbus_prev = 0;
if (gpio_is_valid(udc->vbus_pin))
enable_irq(gpio_to_irq(udc->vbus_pin));
@@ -1809,8 +1797,7 @@ static int atmel_usba_start(struct usb_gadget *gadget,
return 0;
}
-static int atmel_usba_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static int atmel_usba_stop(struct usb_gadget *gadget)
{
struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
unsigned long flags;
@@ -1830,8 +1817,6 @@ static int atmel_usba_stop(struct usb_gadget *gadget,
clk_disable_unprepare(udc->hclk);
clk_disable_unprepare(udc->pclk);
- DBG(DBG_GADGET, "unregistered driver `%s'\n", udc->driver->driver.name);
-
udc->driver = NULL;
return 0;
diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c
index 2235b8808700..c790918b337b 100644
--- a/drivers/usb/gadget/udc/bcm63xx_udc.c
+++ b/drivers/usb/gadget/udc/bcm63xx_udc.c
@@ -1836,8 +1836,7 @@ static int bcm63xx_udc_start(struct usb_gadget *gadget,
* @gadget: USB slave device.
* @driver: Driver for USB slave devices.
*/
-static int bcm63xx_udc_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static int bcm63xx_udc_stop(struct usb_gadget *gadget)
{
struct bcm63xx_udc *udc = gadget_to_udc(gadget);
unsigned long flags;
@@ -1963,7 +1962,7 @@ static irqreturn_t bcm63xx_udc_ctrl_isr(int irq, void *dev_id)
{
struct bcm63xx_udc *udc = dev_id;
u32 stat;
- bool disconnected = false;
+ bool disconnected = false, bus_reset = false;
stat = usbd_readl(udc, USBD_EVENT_IRQ_STATUS_REG) &
usbd_readl(udc, USBD_EVENT_IRQ_MASK_REG);
@@ -1991,7 +1990,7 @@ static irqreturn_t bcm63xx_udc_ctrl_isr(int irq, void *dev_id)
udc->ep0_req_reset = 1;
schedule_work(&udc->ep0_wq);
- disconnected = true;
+ bus_reset = true;
}
if (stat & BIT(USBD_EVENT_IRQ_SETUP)) {
if (bcm63xx_update_link_speed(udc)) {
@@ -2014,6 +2013,8 @@ static irqreturn_t bcm63xx_udc_ctrl_isr(int irq, void *dev_id)
if (disconnected && udc->driver)
udc->driver->disconnect(&udc->gadget);
+ else if (bus_reset && udc->driver)
+ usb_gadget_udc_reset(&udc->gadget, udc->driver);
return IRQ_HANDLED;
}
@@ -2324,10 +2325,8 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
int rc = -ENOMEM, i, irq;
udc = devm_kzalloc(dev, sizeof(*udc), GFP_KERNEL);
- if (!udc) {
- dev_err(dev, "cannot allocate memory\n");
+ if (!udc)
return -ENOMEM;
- }
platform_set_drvdata(pdev, udc);
udc->dev = dev;
diff --git a/drivers/usb/gadget/udc/bdc/Kconfig b/drivers/usb/gadget/udc/bdc/Kconfig
new file mode 100644
index 000000000000..0d7b8c9f72fd
--- /dev/null
+++ b/drivers/usb/gadget/udc/bdc/Kconfig
@@ -0,0 +1,21 @@
+config USB_BDC_UDC
+ tristate "Broadcom USB3.0 device controller IP driver(BDC)"
+ depends on USB_GADGET && HAS_DMA
+
+ help
+ BDC is Broadcom's USB3.0 device controller IP. If your SOC has a BDC IP
+ then select this driver.
+
+ Say "y" here to link the driver statically, or "m" to build a dynamically
+ linked module called "bdc".
+
+if USB_BDC_UDC
+
+comment "Platform Support"
+config USB_BDC_PCI
+ tristate "BDC support for PCIe based platforms"
+ depends on PCI
+ default USB_BDC_UDC
+ help
+ Enable support for platforms which have BDC connected through PCIe, such as Lego3 FPGA platform.
+endif
diff --git a/drivers/usb/gadget/udc/bdc/Makefile b/drivers/usb/gadget/udc/bdc/Makefile
new file mode 100644
index 000000000000..5cf6a3bcdf0f
--- /dev/null
+++ b/drivers/usb/gadget/udc/bdc/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_USB_BDC_UDC) += bdc.o
+bdc-y := bdc_core.o bdc_cmd.o bdc_ep.o bdc_udc.o
+
+ifneq ($(CONFIG_USB_GADGET_VERBOSE),)
+ bdc-y += bdc_dbg.o
+endif
+
+obj-$(CONFIG_USB_BDC_PCI) += bdc_pci.o
diff --git a/drivers/usb/gadget/udc/bdc/bdc.h b/drivers/usb/gadget/udc/bdc/bdc.h
new file mode 100644
index 000000000000..dc18a20bf040
--- /dev/null
+++ b/drivers/usb/gadget/udc/bdc/bdc.h
@@ -0,0 +1,490 @@
+/*
+ * bdc.h - header for the BRCM BDC USB3.0 device controller
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Author: Ashwini Pahuja
+ *
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_BDC_H__
+#define __LINUX_BDC_H__
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/debugfs.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <asm/unaligned.h>
+
+#define BRCM_BDC_NAME "bdc_usb3"
+#define BRCM_BDC_DESC "BDC device controller driver"
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+/* BDC command operation timeout in usec*/
+#define BDC_CMD_TIMEOUT 1000
+/* BDC controller operation timeout in usec*/
+#define BDC_COP_TIMEOUT 500
+
+/*
+ * Maximum size of ep0 response buffer for ch9 requests,
+ * the set_sel request uses 6 so far, the max.
+*/
+#define EP0_RESPONSE_BUFF 6
+/* Start with SS as default */
+#define EP0_MAX_PKT_SIZE 512
+
+/* 64 entries in a SRR */
+#define NUM_SR_ENTRIES 64
+
+/* Num of bds per table */
+#define NUM_BDS_PER_TABLE 32
+
+/* Num of tables in bd list for control,bulk and Int ep */
+#define NUM_TABLES 2
+
+/* Num of tables in bd list for Isoch ep */
+#define NUM_TABLES_ISOCH 6
+
+/* U1 Timeout default: 248usec */
+#define U1_TIMEOUT 0xf8
+
+/* Interrupt coalescence in usec */
+#define INT_CLS 500
+
+/* Register offsets */
+/* Configuration and Capability registers */
+#define BDC_BDCCFG0 0x00
+#define BDC_BDCCFG1 0x04
+#define BDC_BDCCAP0 0x08
+#define BDC_BDCCAP1 0x0c
+#define BDC_CMDPAR0 0x10
+#define BDC_CMDPAR1 0x14
+#define BDC_CMDPAR2 0x18
+#define BDC_CMDSC 0x1c
+#define BDC_USPC 0x20
+#define BDC_USPPMS 0x28
+#define BDC_USPPM2 0x2c
+#define BDC_SPBBAL 0x38
+#define BDC_SPBBAH 0x3c
+#define BDC_BDCSC 0x40
+#define BDC_XSFNTF 0x4c
+
+#define BDC_DVCSA 0x50
+#define BDC_DVCSB 0x54
+#define BDC_EPSTS0(n) (0x60 + (n * 0x10))
+#define BDC_EPSTS1(n) (0x64 + (n * 0x10))
+#define BDC_EPSTS2(n) (0x68 + (n * 0x10))
+#define BDC_EPSTS3(n) (0x6c + (n * 0x10))
+#define BDC_EPSTS4(n) (0x70 + (n * 0x10))
+#define BDC_EPSTS5(n) (0x74 + (n * 0x10))
+#define BDC_EPSTS6(n) (0x78 + (n * 0x10))
+#define BDC_EPSTS7(n) (0x7c + (n * 0x10))
+#define BDC_SRRBAL(n) (0x200 + (n * 0x10))
+#define BDC_SRRBAH(n) (0x204 + (n * 0x10))
+#define BDC_SRRINT(n) (0x208 + (n * 0x10))
+#define BDC_INTCTLS(n) (0x20c + (n * 0x10))
+
+/* Extended capability regs */
+#define BDC_FSCNOC 0xcd4
+#define BDC_FSCNIC 0xce4
+#define NUM_NCS(p) (p >> 28)
+
+/* Register bit fields and Masks */
+/* BDC Configuration 0 */
+#define BDC_PGS(p) (((p) & (0x7 << 8)) >> 8)
+#define BDC_SPB(p) (p & 0x7)
+
+/* BDC Capability1 */
+#define BDC_P64 (1 << 0)
+
+/* BDC Command register */
+#define BDC_CMD_FH 0xe
+#define BDC_CMD_DNC 0x6
+#define BDC_CMD_EPO 0x4
+#define BDC_CMD_BLA 0x3
+#define BDC_CMD_EPC 0x2
+#define BDC_CMD_DVC 0x1
+#define BDC_CMD_CWS (0x1 << 5)
+#define BDC_CMD_CST(p) (((p) & (0xf << 6))>>6)
+#define BDC_CMD_EPN(p) ((p & 0x1f) << 10)
+#define BDC_SUB_CMD_ADD (0x1 << 17)
+#define BDC_SUB_CMD_FWK (0x4 << 17)
+/* Reset sequence number */
+#define BDC_CMD_EPO_RST_SN (0x1 << 16)
+#define BDC_CMD_EP0_XSD (0x1 << 16)
+#define BDC_SUB_CMD_ADD_EP (0x1 << 17)
+#define BDC_SUB_CMD_DRP_EP (0x2 << 17)
+#define BDC_SUB_CMD_EP_STP (0x2 << 17)
+#define BDC_SUB_CMD_EP_STL (0x4 << 17)
+#define BDC_SUB_CMD_EP_RST (0x1 << 17)
+#define BDC_CMD_SRD (1 << 27)
+
+/* CMD completion status */
+#define BDC_CMDS_SUCC 0x1
+#define BDC_CMDS_PARA 0x3
+#define BDC_CMDS_STAT 0x4
+#define BDC_CMDS_FAIL 0x5
+#define BDC_CMDS_INTL 0x6
+#define BDC_CMDS_BUSY 0xf
+
+/* CMDSC Param 2 shifts */
+#define EPT_SHIFT 22
+#define MP_SHIFT 10
+#define MB_SHIFT 6
+#define EPM_SHIFT 4
+
+/* BDC USPSC */
+#define BDC_VBC (1 << 31)
+#define BDC_PRC (1 << 30)
+#define BDC_PCE (1 << 29)
+#define BDC_CFC (1 << 28)
+#define BDC_PCC (1 << 27)
+#define BDC_PSC (1 << 26)
+#define BDC_VBS (1 << 25)
+#define BDC_PRS (1 << 24)
+#define BDC_PCS (1 << 23)
+#define BDC_PSP(p) (((p) & (0x7 << 20))>>20)
+#define BDC_SCN (1 << 8)
+#define BDC_SDC (1 << 7)
+#define BDC_SWS (1 << 4)
+
+#define BDC_USPSC_RW (BDC_SCN|BDC_SDC|BDC_SWS|0xf)
+#define BDC_PSP(p) (((p) & (0x7 << 20))>>20)
+
+#define BDC_SPEED_FS 0x1
+#define BDC_SPEED_LS 0x2
+#define BDC_SPEED_HS 0x3
+#define BDC_SPEED_SS 0x4
+
+#define BDC_PST(p) (p & 0xf)
+#define BDC_PST_MASK 0xf
+
+/* USPPMS */
+#define BDC_U2E (0x1 << 31)
+#define BDC_U1E (0x1 << 30)
+#define BDC_U2A (0x1 << 29)
+#define BDC_PORT_W1S (0x1 << 17)
+#define BDC_U1T(p) ((p) & 0xff)
+#define BDC_U2T(p) (((p) & 0xff) << 8)
+#define BDC_U1T_MASK 0xff
+
+/* USBPM2 */
+/* Hardware LPM Enable */
+#define BDC_HLE (1 << 16)
+
+/* BDC Status and Control */
+#define BDC_COP_RST (1 << 29)
+#define BDC_COP_RUN (2 << 29)
+#define BDC_COP_STP (4 << 29)
+
+#define BDC_COP_MASK (BDC_COP_RST|BDC_COP_RUN|BDC_COP_STP)
+
+#define BDC_COS (1 << 28)
+#define BDC_CSTS(p) (((p) & (0x7 << 20)) >> 20)
+#define BDC_MASK_MCW (1 << 7)
+#define BDC_GIE (1 << 1)
+#define BDC_GIP (1 << 0)
+
+#define BDC_HLT 1
+#define BDC_NOR 2
+#define BDC_OIP 7
+
+/* Buffer descriptor and Status report bit fields and masks */
+#define BD_TYPE_BITMASK (0xf)
+#define BD_CHAIN 0xf
+
+#define BD_TFS_SHIFT 4
+#define BD_SOT (1 << 26)
+#define BD_EOT (1 << 27)
+#define BD_ISP (1 << 29)
+#define BD_IOC (1 << 30)
+#define BD_SBF (1 << 31)
+
+#define BD_INTR_TARGET(p) (((p) & 0x1f) << 27)
+
+#define BDC_SRR_RWS (1 << 4)
+#define BDC_SRR_RST (1 << 3)
+#define BDC_SRR_ISR (1 << 2)
+#define BDC_SRR_IE (1 << 1)
+#define BDC_SRR_IP (1 << 0)
+#define BDC_SRR_EPI(p) (((p) & (0xff << 24)) >> 24)
+#define BDC_SRR_DPI(p) (((p) & (0xff << 16)) >> 16)
+#define BDC_SRR_DPI_MASK 0x00ff0000
+
+#define MARK_CHAIN_BD (BD_CHAIN|BD_EOT|BD_SOT)
+
+/* Control transfer BD specific fields */
+#define BD_DIR_IN (1 << 25)
+
+#define BDC_PTC_MASK 0xf0000000
+
+/* status report defines */
+#define SR_XSF 0
+#define SR_USPC 4
+#define SR_BD_LEN(p) (p & 0xffffff)
+
+#define XSF_SUCC 0x1
+#define XSF_SHORT 0x3
+#define XSF_BABB 0x4
+#define XSF_SETUP_RECV 0x6
+#define XSF_DATA_START 0x7
+#define XSF_STATUS_START 0x8
+
+#define XSF_STS(p) (((p) >> 28) & 0xf)
+
+/* Transfer BD fields */
+#define BD_LEN(p) ((p) & 0x1ffff)
+#define BD_LTF (1 << 25)
+#define BD_TYPE_DS 0x1
+#define BD_TYPE_SS 0x2
+
+#define BDC_EP_ENABLED (1 << 0)
+#define BDC_EP_STALL (1 << 1)
+#define BDC_EP_STOP (1 << 2)
+
+/* One BD can transfer max 65536 bytes */
+#define BD_MAX_BUFF_SIZE (1 << 16)
+/* Maximum bytes in one XFR, Refer to BDC spec */
+#define MAX_XFR_LEN 16777215
+
+/* defines for Force Header command */
+#define DEV_NOTF_TYPE 6
+#define FWK_SUBTYPE 1
+#define TRA_PACKET 4
+
+#define to_bdc_ep(e) container_of(e, struct bdc_ep, usb_ep)
+#define to_bdc_req(r) container_of(r, struct bdc_req, usb_req)
+#define gadget_to_bdc(g) container_of(g, struct bdc, gadget)
+
+/* FUNCTION WAKE DEV NOTIFICATION interval, USB3 spec table 8.13 */
+#define BDC_TNOTIFY 2500 /*in ms*/
+/* Devstatus bitfields */
+#define REMOTE_WAKEUP_ISSUED (1 << 16)
+#define DEVICE_SUSPENDED (1 << 17)
+#define FUNC_WAKE_ISSUED (1 << 18)
+#define REMOTE_WAKE_ENABLE (1 << USB_DEVICE_REMOTE_WAKEUP)
+
+/* On disconnect, preserve these bits and clear rest */
+#define DEVSTATUS_CLEAR (1 << USB_DEVICE_SELF_POWERED)
+/* Hardware and software Data structures */
+
+/* Endpoint bd: buffer descriptor */
+struct bdc_bd {
+ __le32 offset[4];
+};
+
+/* Status report in Status report ring(srr) */
+struct bdc_sr {
+ __le32 offset[4];
+};
+
+/* bd_table: contigous bd's in a table */
+struct bd_table {
+ struct bdc_bd *start_bd;
+ /* dma address of start bd of table*/
+ dma_addr_t dma;
+};
+
+/*
+ * Each endpoint has a bdl(buffer descriptor list), bdl consists of 1 or more bd
+ * table's chained to each other through a chain bd, every table has equal
+ * number of bds. the software uses bdi(bd index) to refer to particular bd in
+ * the list.
+ */
+struct bd_list {
+ /* Array of bd table pointers*/
+ struct bd_table **bd_table_array;
+ /* How many tables chained to each other */
+ int num_tabs;
+ /* Max_bdi = num_tabs * num_bds_table - 1 */
+ int max_bdi;
+ /* current enq bdi from sw point of view */
+ int eqp_bdi;
+ /* current deq bdi from sw point of view */
+ int hwd_bdi;
+ /* numbers of bds per table */
+ int num_bds_table;
+};
+
+struct bdc_req;
+
+/* Representation of a transfer, one transfer can have multiple bd's */
+struct bd_transfer {
+ struct bdc_req *req;
+ /* start bd index */
+ int start_bdi;
+ /* this will be the next hw dqp when this transfer completes */
+ int next_hwd_bdi;
+ /* number of bds in this transfer */
+ int num_bds;
+};
+
+/*
+ * Representation of a gadget request, every gadget request is contained
+ * by 1 bd_transfer.
+ */
+struct bdc_req {
+ struct usb_request usb_req;
+ struct list_head queue;
+ struct bdc_ep *ep;
+ /* only one Transfer per request */
+ struct bd_transfer bd_xfr;
+ int epnum;
+};
+
+/* scratchpad buffer needed by bdc hardware */
+struct bdc_scratchpad {
+ dma_addr_t sp_dma;
+ void *buff;
+ u32 size;
+};
+
+/* endpoint representation */
+struct bdc_ep {
+ struct usb_ep usb_ep;
+ struct list_head queue;
+ struct bdc *bdc;
+ u8 ep_type;
+ u8 dir;
+ u8 ep_num;
+ const struct usb_ss_ep_comp_descriptor *comp_desc;
+ const struct usb_endpoint_descriptor *desc;
+ unsigned int flags;
+ char name[20];
+ /* endpoint bd list*/
+ struct bd_list bd_list;
+ /*
+ * HW generates extra event for multi bd tranfers, this flag helps in
+ * ignoring the extra event
+ */
+ bool ignore_next_sr;
+};
+
+/* bdc cmmand parameter structure */
+struct bdc_cmd_params {
+ u32 param2;
+ u32 param1;
+ u32 param0;
+};
+
+/* status report ring(srr), currently one srr is supported for entire system */
+struct srr {
+ struct bdc_sr *sr_bds;
+ u16 eqp_index;
+ u16 dqp_index;
+ dma_addr_t dma_addr;
+};
+
+/* EP0 states */
+enum bdc_ep0_state {
+ WAIT_FOR_SETUP = 0,
+ WAIT_FOR_DATA_START,
+ WAIT_FOR_DATA_XMIT,
+ WAIT_FOR_STATUS_START,
+ WAIT_FOR_STATUS_XMIT,
+ STATUS_PENDING
+};
+
+/* Link states */
+enum bdc_link_state {
+ BDC_LINK_STATE_U0 = 0x00,
+ BDC_LINK_STATE_U3 = 0x03,
+ BDC_LINK_STATE_RX_DET = 0x05,
+ BDC_LINK_STATE_RESUME = 0x0f
+};
+
+/* representation of bdc */
+struct bdc {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *gadget_driver;
+ struct device *dev;
+ /* device lock */
+ spinlock_t lock;
+
+ /* num of endpoints for a particular instantiation of IP */
+ unsigned int num_eps;
+ /*
+ * Array of ep's, it uses the same index covention as bdc hw i.e.
+ * 1 for ep0, 2 for 1out,3 for 1in ....
+ */
+ struct bdc_ep **bdc_ep_array;
+ void __iomem *regs;
+ struct bdc_scratchpad scratchpad;
+ u32 sp_buff_size;
+ /* current driver supports 1 status ring */
+ struct srr srr;
+ /* Last received setup packet */
+ struct usb_ctrlrequest setup_pkt;
+ struct bdc_req ep0_req;
+ struct bdc_req status_req;
+ enum bdc_ep0_state ep0_state;
+ bool delayed_status;
+ bool zlp_needed;
+ bool reinit;
+ bool pullup;
+ /* Bits 0-15 are standard and 16-31 for proprietary information */
+ u32 devstatus;
+ int irq;
+ void *mem;
+ u32 dev_addr;
+ /* DMA pools */
+ struct dma_pool *bd_table_pool;
+ u8 test_mode;
+ /* array of callbacks for various status report handlers */
+ void (*sr_handler[2])(struct bdc *, struct bdc_sr *);
+ /* ep0 callback handlers */
+ void (*sr_xsf_ep0[3])(struct bdc *, struct bdc_sr *);
+ /* ep0 response buffer for ch9 requests like GET_STATUS and SET_SEL */
+ unsigned char ep0_response_buff[EP0_RESPONSE_BUFF];
+ /*
+ * Timer to check if host resumed transfer after bdc sent Func wake
+ * notification packet after a remote wakeup. if not, then resend the
+ * Func Wake packet every 2.5 secs. Refer to USB3 spec section 8.5.6.4
+ */
+ struct delayed_work func_wake_notify;
+};
+
+static inline u32 bdc_readl(void __iomem *base, u32 offset)
+{
+ return readl(base + offset);
+}
+
+static inline void bdc_writel(void __iomem *base, u32 offset, u32 value)
+{
+ writel(value, base + offset);
+}
+
+/* Buffer descriptor list operations */
+void bdc_notify_xfr(struct bdc *, u32);
+void bdc_softconn(struct bdc *);
+void bdc_softdisconn(struct bdc *);
+int bdc_run(struct bdc *);
+int bdc_stop(struct bdc *);
+int bdc_reset(struct bdc *);
+int bdc_udc_init(struct bdc *);
+void bdc_udc_exit(struct bdc *);
+int bdc_reinit(struct bdc *);
+
+/* Status report handlers */
+/* Upstream port status change sr */
+void bdc_sr_uspc(struct bdc *, struct bdc_sr *);
+/* transfer sr */
+void bdc_sr_xsf(struct bdc *, struct bdc_sr *);
+/* EP0 XSF handlers */
+void bdc_xsf_ep0_setup_recv(struct bdc *, struct bdc_sr *);
+void bdc_xsf_ep0_data_start(struct bdc *, struct bdc_sr *);
+void bdc_xsf_ep0_status_start(struct bdc *, struct bdc_sr *);
+
+#endif /* __LINUX_BDC_H__ */
diff --git a/drivers/usb/gadget/udc/bdc/bdc_cmd.c b/drivers/usb/gadget/udc/bdc/bdc_cmd.c
new file mode 100644
index 000000000000..6a4155c4bd86
--- /dev/null
+++ b/drivers/usb/gadget/udc/bdc/bdc_cmd.c
@@ -0,0 +1,376 @@
+/*
+ * bdc_cmd.c - BRCM BDC USB3.0 device controller
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Author: Ashwini Pahuja
+ *
+ * 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/scatterlist.h>
+#include <linux/slab.h>
+
+#include "bdc.h"
+#include "bdc_cmd.h"
+#include "bdc_dbg.h"
+
+/* Issues a cmd to cmd processor and waits for cmd completion */
+static int bdc_issue_cmd(struct bdc *bdc, u32 cmd_sc, u32 param0,
+ u32 param1, u32 param2)
+{
+ u32 timeout = BDC_CMD_TIMEOUT;
+ u32 cmd_status;
+ u32 temp;
+
+ bdc_writel(bdc->regs, BDC_CMDPAR0, param0);
+ bdc_writel(bdc->regs, BDC_CMDPAR1, param1);
+ bdc_writel(bdc->regs, BDC_CMDPAR2, param2);
+
+ /* Issue the cmd */
+ /* Make sure the cmd params are written before asking HW to exec cmd */
+ wmb();
+ bdc_writel(bdc->regs, BDC_CMDSC, cmd_sc | BDC_CMD_CWS | BDC_CMD_SRD);
+ do {
+ temp = bdc_readl(bdc->regs, BDC_CMDSC);
+ dev_dbg_ratelimited(bdc->dev, "cmdsc=%x", temp);
+ cmd_status = BDC_CMD_CST(temp);
+ if (cmd_status != BDC_CMDS_BUSY) {
+ dev_dbg(bdc->dev,
+ "command completed cmd_sts:%x\n", cmd_status);
+ return cmd_status;
+ }
+ udelay(1);
+ } while (timeout--);
+
+ dev_err(bdc->dev,
+ "command operation timedout cmd_status=%d\n", cmd_status);
+
+ return cmd_status;
+}
+
+/* Submits cmd and analyze the return value of bdc_issue_cmd */
+static int bdc_submit_cmd(struct bdc *bdc, u32 cmd_sc,
+ u32 param0, u32 param1, u32 param2)
+{
+ u32 temp, cmd_status;
+ int reset_bdc = 0;
+ int ret;
+
+ temp = bdc_readl(bdc->regs, BDC_CMDSC);
+ dev_dbg(bdc->dev,
+ "%s:CMDSC:%08x cmdsc:%08x param0=%08x param1=%08x param2=%08x\n",
+ __func__, temp, cmd_sc, param0, param1, param2);
+
+ cmd_status = BDC_CMD_CST(temp);
+ if (cmd_status == BDC_CMDS_BUSY) {
+ dev_err(bdc->dev, "command processor busy: %x\n", cmd_status);
+ return -EBUSY;
+ }
+ ret = bdc_issue_cmd(bdc, cmd_sc, param0, param1, param2);
+ switch (ret) {
+ case BDC_CMDS_SUCC:
+ dev_dbg(bdc->dev, "command completed successfully\n");
+ ret = 0;
+ break;
+
+ case BDC_CMDS_PARA:
+ dev_err(bdc->dev, "command parameter error\n");
+ ret = -EINVAL;
+ break;
+
+ case BDC_CMDS_STAT:
+ dev_err(bdc->dev, "Invalid device/ep state\n");
+ ret = -EINVAL;
+ break;
+
+ case BDC_CMDS_FAIL:
+ dev_err(bdc->dev, "Command failed?\n");
+ ret = -EAGAIN;
+ break;
+
+ case BDC_CMDS_INTL:
+ dev_err(bdc->dev, "BDC Internal error\n");
+ reset_bdc = 1;
+ ret = -ECONNRESET;
+ break;
+
+ case BDC_CMDS_BUSY:
+ dev_err(bdc->dev,
+ "command timedout waited for %dusec\n",
+ BDC_CMD_TIMEOUT);
+ reset_bdc = 1;
+ ret = -ECONNRESET;
+ break;
+ default:
+ dev_dbg(bdc->dev, "Unknown command completion code:%x\n", ret);
+ }
+
+ return ret;
+}
+
+/* Deconfigure the endpoint from HW */
+int bdc_dconfig_ep(struct bdc *bdc, struct bdc_ep *ep)
+{
+ u32 cmd_sc;
+
+ cmd_sc = BDC_SUB_CMD_DRP_EP|BDC_CMD_EPN(ep->ep_num)|BDC_CMD_EPC;
+ dev_dbg(bdc->dev, "%s ep->ep_num =%d cmd_sc=%x\n", __func__,
+ ep->ep_num, cmd_sc);
+
+ return bdc_submit_cmd(bdc, cmd_sc, 0, 0, 0);
+}
+
+/* Reinitalize the bdlist after config ep command */
+static void ep_bd_list_reinit(struct bdc_ep *ep)
+{
+ struct bdc *bdc = ep->bdc;
+ struct bdc_bd *bd;
+
+ ep->bd_list.eqp_bdi = 0;
+ ep->bd_list.hwd_bdi = 0;
+ bd = ep->bd_list.bd_table_array[0]->start_bd;
+ dev_dbg(bdc->dev, "%s ep:%p bd:%p\n", __func__, ep, bd);
+ memset(bd, 0, sizeof(struct bdc_bd));
+ bd->offset[3] |= cpu_to_le32(BD_SBF);
+}
+
+/* Configure an endpoint */
+int bdc_config_ep(struct bdc *bdc, struct bdc_ep *ep)
+{
+ const struct usb_ss_ep_comp_descriptor *comp_desc;
+ const struct usb_endpoint_descriptor *desc;
+ u32 param0, param1, param2, cmd_sc;
+ u32 mps, mbs, mul, si;
+ int ret;
+
+ desc = ep->desc;
+ comp_desc = ep->comp_desc;
+ cmd_sc = mul = mbs = param2 = 0;
+ param0 = lower_32_bits(ep->bd_list.bd_table_array[0]->dma);
+ param1 = upper_32_bits(ep->bd_list.bd_table_array[0]->dma);
+ cpu_to_le32s(&param0);
+ cpu_to_le32s(&param1);
+
+ dev_dbg(bdc->dev, "%s: param0=%08x param1=%08x",
+ __func__, param0, param1);
+ si = desc->bInterval;
+ si = clamp_val(si, 1, 16) - 1;
+
+ mps = usb_endpoint_maxp(desc);
+ mps &= 0x7ff;
+ param2 |= mps << MP_SHIFT;
+ param2 |= usb_endpoint_type(desc) << EPT_SHIFT;
+
+ switch (bdc->gadget.speed) {
+ case USB_SPEED_SUPER:
+ if (usb_endpoint_xfer_int(desc) ||
+ usb_endpoint_xfer_isoc(desc)) {
+ param2 |= si;
+ if (usb_endpoint_xfer_isoc(desc) && comp_desc)
+ mul = comp_desc->bmAttributes;
+
+ }
+ param2 |= mul << EPM_SHIFT;
+ if (comp_desc)
+ mbs = comp_desc->bMaxBurst;
+ param2 |= mbs << MB_SHIFT;
+ break;
+
+ case USB_SPEED_HIGH:
+ if (usb_endpoint_xfer_isoc(desc) ||
+ usb_endpoint_xfer_int(desc)) {
+ param2 |= si;
+
+ mbs = (usb_endpoint_maxp(desc) & 0x1800) >> 11;
+ param2 |= mbs << MB_SHIFT;
+ }
+ break;
+
+ case USB_SPEED_FULL:
+ case USB_SPEED_LOW:
+ /* the hardware accepts SI in 125usec range */
+ if (usb_endpoint_xfer_isoc(desc))
+ si += 3;
+
+ /*
+ * FS Int endpoints can have si of 1-255ms but the controller
+ * accepts 2^bInterval*125usec, so convert ms to nearest power
+ * of 2
+ */
+ if (usb_endpoint_xfer_int(desc))
+ si = fls(desc->bInterval * 8) - 1;
+
+ param2 |= si;
+ break;
+ default:
+ dev_err(bdc->dev, "UNKNOWN speed ERR\n");
+ return -EINVAL;
+ }
+
+ cmd_sc |= BDC_CMD_EPC|BDC_CMD_EPN(ep->ep_num)|BDC_SUB_CMD_ADD_EP;
+
+ dev_dbg(bdc->dev, "cmd_sc=%x param2=%08x\n", cmd_sc, param2);
+ ret = bdc_submit_cmd(bdc, cmd_sc, param0, param1, param2);
+ if (ret) {
+ dev_err(bdc->dev, "command failed :%x\n", ret);
+ return ret;
+ }
+ ep_bd_list_reinit(ep);
+
+ return ret;
+}
+
+/*
+ * Change the HW deq pointer, if this command is successful, HW will start
+ * fetching the next bd from address dma_addr.
+ */
+int bdc_ep_bla(struct bdc *bdc, struct bdc_ep *ep, dma_addr_t dma_addr)
+{
+ u32 param0, param1;
+ u32 cmd_sc = 0;
+
+ dev_dbg(bdc->dev, "%s: add=%08llx\n", __func__,
+ (unsigned long long)(dma_addr));
+ param0 = lower_32_bits(dma_addr);
+ param1 = upper_32_bits(dma_addr);
+ cpu_to_le32s(&param0);
+ cpu_to_le32s(&param1);
+
+ cmd_sc |= BDC_CMD_EPN(ep->ep_num)|BDC_CMD_BLA;
+ dev_dbg(bdc->dev, "cmd_sc=%x\n", cmd_sc);
+
+ return bdc_submit_cmd(bdc, cmd_sc, param0, param1, 0);
+}
+
+/* Set the address sent bu Host in SET_ADD request */
+int bdc_address_device(struct bdc *bdc, u32 add)
+{
+ u32 cmd_sc = 0;
+ u32 param2;
+
+ dev_dbg(bdc->dev, "%s: add=%d\n", __func__, add);
+ cmd_sc |= BDC_SUB_CMD_ADD|BDC_CMD_DVC;
+ param2 = add & 0x7f;
+
+ return bdc_submit_cmd(bdc, cmd_sc, 0, 0, param2);
+}
+
+/* Send a Function Wake notification packet using FH command */
+int bdc_function_wake_fh(struct bdc *bdc, u8 intf)
+{
+ u32 param0, param1;
+ u32 cmd_sc = 0;
+
+ param0 = param1 = 0;
+ dev_dbg(bdc->dev, "%s intf=%d\n", __func__, intf);
+ cmd_sc |= BDC_CMD_FH;
+ param0 |= TRA_PACKET;
+ param0 |= (bdc->dev_addr << 25);
+ param1 |= DEV_NOTF_TYPE;
+ param1 |= (FWK_SUBTYPE<<4);
+ dev_dbg(bdc->dev, "param0=%08x param1=%08x\n", param0, param1);
+
+ return bdc_submit_cmd(bdc, cmd_sc, param0, param1, 0);
+}
+
+/* Send a Function Wake notification packet using DNC command */
+int bdc_function_wake(struct bdc *bdc, u8 intf)
+{
+ u32 cmd_sc = 0;
+ u32 param2 = 0;
+
+ dev_dbg(bdc->dev, "%s intf=%d", __func__, intf);
+ param2 |= intf;
+ cmd_sc |= BDC_SUB_CMD_FWK|BDC_CMD_DNC;
+
+ return bdc_submit_cmd(bdc, cmd_sc, 0, 0, param2);
+}
+
+/* Stall the endpoint */
+int bdc_ep_set_stall(struct bdc *bdc, int epnum)
+{
+ u32 cmd_sc = 0;
+
+ dev_dbg(bdc->dev, "%s epnum=%d\n", __func__, epnum);
+ /* issue a stall endpoint command */
+ cmd_sc |= BDC_SUB_CMD_EP_STL | BDC_CMD_EPN(epnum) | BDC_CMD_EPO;
+
+ return bdc_submit_cmd(bdc, cmd_sc, 0, 0, 0);
+}
+
+/* resets the endpoint, called when host sends CLEAR_FEATURE(HALT) */
+int bdc_ep_clear_stall(struct bdc *bdc, int epnum)
+{
+ struct bdc_ep *ep;
+ u32 cmd_sc = 0;
+ int ret;
+
+ dev_dbg(bdc->dev, "%s: epnum=%d\n", __func__, epnum);
+ ep = bdc->bdc_ep_array[epnum];
+ /*
+ * If we are not in stalled then stall Endpoint and issue clear stall,
+ * his will reset the seq number for non EP0.
+ */
+ if (epnum != 1) {
+ /* if the endpoint it not stallled */
+ if (!(ep->flags & BDC_EP_STALL)) {
+ ret = bdc_ep_set_stall(bdc, epnum);
+ if (ret)
+ return ret;
+ }
+ }
+ /* Preserve the seq number for ep0 only */
+ if (epnum != 1)
+ cmd_sc |= BDC_CMD_EPO_RST_SN;
+
+ /* issue a reset endpoint command */
+ cmd_sc |= BDC_SUB_CMD_EP_RST | BDC_CMD_EPN(epnum) | BDC_CMD_EPO;
+
+ ret = bdc_submit_cmd(bdc, cmd_sc, 0, 0, 0);
+ if (ret) {
+ dev_err(bdc->dev, "command failed:%x\n", ret);
+ return ret;
+ }
+ bdc_notify_xfr(bdc, epnum);
+
+ return ret;
+}
+
+/* Stop the endpoint, called when software wants to dequeue some request */
+int bdc_stop_ep(struct bdc *bdc, int epnum)
+{
+ struct bdc_ep *ep;
+ u32 cmd_sc = 0;
+ int ret;
+
+ ep = bdc->bdc_ep_array[epnum];
+ dev_dbg(bdc->dev, "%s: ep:%s ep->flags:%08x\n", __func__,
+ ep->name, ep->flags);
+ /* Endpoint has to be in running state to execute stop ep command */
+ if (!(ep->flags & BDC_EP_ENABLED)) {
+ dev_err(bdc->dev, "stop endpoint called for disabled ep\n");
+ return -EINVAL;
+ }
+ if ((ep->flags & BDC_EP_STALL) || (ep->flags & BDC_EP_STOP))
+ return 0;
+
+ /* issue a stop endpoint command */
+ cmd_sc |= BDC_CMD_EP0_XSD | BDC_SUB_CMD_EP_STP
+ | BDC_CMD_EPN(epnum) | BDC_CMD_EPO;
+
+ ret = bdc_submit_cmd(bdc, cmd_sc, 0, 0, 0);
+ if (ret) {
+ dev_err(bdc->dev,
+ "stop endpoint command didn't complete:%d ep:%s\n",
+ ret, ep->name);
+ return ret;
+ }
+ ep->flags |= BDC_EP_STOP;
+ bdc_dump_epsts(bdc);
+
+ return ret;
+}
diff --git a/drivers/usb/gadget/udc/bdc/bdc_cmd.h b/drivers/usb/gadget/udc/bdc/bdc_cmd.h
new file mode 100644
index 000000000000..61d0e3bf9853
--- /dev/null
+++ b/drivers/usb/gadget/udc/bdc/bdc_cmd.h
@@ -0,0 +1,29 @@
+/*
+ * bdc_cmd.h - header for the BDC debug functions
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Author: Ashwini Pahuja
+ *
+ * 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.
+ *
+ */
+#ifndef __LINUX_BDC_CMD_H__
+#define __LINUX_BDC_CMD_H__
+
+/* Command operations */
+int bdc_address_device(struct bdc *, u32);
+int bdc_config_ep(struct bdc *, struct bdc_ep *);
+int bdc_dconfig_ep(struct bdc *, struct bdc_ep *);
+int bdc_stop_ep(struct bdc *, int);
+int bdc_ep_set_stall(struct bdc *, int);
+int bdc_ep_clear_stall(struct bdc *, int);
+int bdc_ep_set_halt(struct bdc_ep *, u32 , int);
+int bdc_ep_bla(struct bdc *, struct bdc_ep *, dma_addr_t);
+int bdc_function_wake(struct bdc*, u8);
+int bdc_function_wake_fh(struct bdc*, u8);
+
+#endif /* __LINUX_BDC_CMD_H__ */
diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c
new file mode 100644
index 000000000000..c6dfef8c7bbc
--- /dev/null
+++ b/drivers/usb/gadget/udc/bdc/bdc_core.c
@@ -0,0 +1,533 @@
+/*
+ * bdc_core.c - BRCM BDC USB3.0 device controller core operations
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Author: Ashwini Pahuja
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/of.h>
+#include <linux/moduleparam.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "bdc.h"
+#include "bdc_dbg.h"
+
+/* Poll till controller status is not OIP */
+static int poll_oip(struct bdc *bdc, int usec)
+{
+ u32 status;
+ /* Poll till STS!= OIP */
+ while (usec) {
+ status = bdc_readl(bdc->regs, BDC_BDCSC);
+ if (BDC_CSTS(status) != BDC_OIP) {
+ dev_dbg(bdc->dev,
+ "poll_oip complete status=%d",
+ BDC_CSTS(status));
+ return 0;
+ }
+ udelay(10);
+ usec -= 10;
+ }
+ dev_err(bdc->dev, "Err: operation timedout BDCSC: 0x%08x\n", status);
+
+ return -ETIMEDOUT;
+}
+
+/* Stop the BDC controller */
+int bdc_stop(struct bdc *bdc)
+{
+ int ret;
+ u32 temp;
+
+ dev_dbg(bdc->dev, "%s ()\n\n", __func__);
+ temp = bdc_readl(bdc->regs, BDC_BDCSC);
+ /* Check if BDC is already halted */
+ if (BDC_CSTS(temp) == BDC_HLT) {
+ dev_vdbg(bdc->dev, "BDC already halted\n");
+ return 0;
+ }
+ temp &= ~BDC_COP_MASK;
+ temp |= BDC_COS|BDC_COP_STP;
+ bdc_writel(bdc->regs, BDC_BDCSC, temp);
+
+ ret = poll_oip(bdc, BDC_COP_TIMEOUT);
+ if (ret)
+ dev_err(bdc->dev, "bdc stop operation failed");
+
+ return ret;
+}
+
+/* Issue a reset to BDC controller */
+int bdc_reset(struct bdc *bdc)
+{
+ u32 temp;
+ int ret;
+
+ dev_dbg(bdc->dev, "%s ()\n", __func__);
+ /* First halt the controller */
+ ret = bdc_stop(bdc);
+ if (ret)
+ return ret;
+
+ temp = bdc_readl(bdc->regs, BDC_BDCSC);
+ temp &= ~BDC_COP_MASK;
+ temp |= BDC_COS|BDC_COP_RST;
+ bdc_writel(bdc->regs, BDC_BDCSC, temp);
+ ret = poll_oip(bdc, BDC_COP_TIMEOUT);
+ if (ret)
+ dev_err(bdc->dev, "bdc reset operation failed");
+
+ return ret;
+}
+
+/* Run the BDC controller */
+int bdc_run(struct bdc *bdc)
+{
+ u32 temp;
+ int ret;
+
+ dev_dbg(bdc->dev, "%s ()\n", __func__);
+ temp = bdc_readl(bdc->regs, BDC_BDCSC);
+ /* if BDC is already in running state then do not do anything */
+ if (BDC_CSTS(temp) == BDC_NOR) {
+ dev_warn(bdc->dev, "bdc is already in running state\n");
+ return 0;
+ }
+ temp &= ~BDC_COP_MASK;
+ temp |= BDC_COP_RUN;
+ temp |= BDC_COS;
+ bdc_writel(bdc->regs, BDC_BDCSC, temp);
+ ret = poll_oip(bdc, BDC_COP_TIMEOUT);
+ if (ret) {
+ dev_err(bdc->dev, "bdc run operation failed:%d", ret);
+ return ret;
+ }
+ temp = bdc_readl(bdc->regs, BDC_BDCSC);
+ if (BDC_CSTS(temp) != BDC_NOR) {
+ dev_err(bdc->dev, "bdc not in normal mode after RUN op :%d\n",
+ BDC_CSTS(temp));
+ return -ESHUTDOWN;
+ }
+
+ return 0;
+}
+
+/*
+ * Present the termination to the host, typically called from upstream port
+ * event with Vbus present =1
+ */
+void bdc_softconn(struct bdc *bdc)
+{
+ u32 uspc;
+
+ uspc = bdc_readl(bdc->regs, BDC_USPC);
+ uspc &= ~BDC_PST_MASK;
+ uspc |= BDC_LINK_STATE_RX_DET;
+ uspc |= BDC_SWS;
+ dev_dbg(bdc->dev, "%s () uspc=%08x\n", __func__, uspc);
+ bdc_writel(bdc->regs, BDC_USPC, uspc);
+}
+
+/* Remove the termination */
+void bdc_softdisconn(struct bdc *bdc)
+{
+ u32 uspc;
+
+ uspc = bdc_readl(bdc->regs, BDC_USPC);
+ uspc |= BDC_SDC;
+ uspc &= ~BDC_SCN;
+ dev_dbg(bdc->dev, "%s () uspc=%x\n", __func__, uspc);
+ bdc_writel(bdc->regs, BDC_USPC, uspc);
+}
+
+/* Set up the scratchpad buffer array and scratchpad buffers, if needed. */
+static int scratchpad_setup(struct bdc *bdc)
+{
+ int sp_buff_size;
+ u32 low32;
+ u32 upp32;
+
+ sp_buff_size = BDC_SPB(bdc_readl(bdc->regs, BDC_BDCCFG0));
+ dev_dbg(bdc->dev, "%s() sp_buff_size=%d\n", __func__, sp_buff_size);
+ if (!sp_buff_size) {
+ dev_dbg(bdc->dev, "Scratchpad buffer not needed\n");
+ return 0;
+ }
+ /* Refer to BDC spec, Table 4 for description of SPB */
+ sp_buff_size = 1 << (sp_buff_size + 5);
+ dev_dbg(bdc->dev, "Allocating %d bytes for scratchpad\n", sp_buff_size);
+ bdc->scratchpad.buff = dma_zalloc_coherent(bdc->dev, sp_buff_size,
+ &bdc->scratchpad.sp_dma, GFP_KERNEL);
+
+ if (!bdc->scratchpad.buff)
+ goto fail;
+
+ bdc->sp_buff_size = sp_buff_size;
+ bdc->scratchpad.size = sp_buff_size;
+ low32 = lower_32_bits(bdc->scratchpad.sp_dma);
+ upp32 = upper_32_bits(bdc->scratchpad.sp_dma);
+ cpu_to_le32s(&low32);
+ cpu_to_le32s(&upp32);
+ bdc_writel(bdc->regs, BDC_SPBBAL, low32);
+ bdc_writel(bdc->regs, BDC_SPBBAH, upp32);
+ return 0;
+
+fail:
+ bdc->scratchpad.buff = NULL;
+
+ return -ENOMEM;
+}
+
+/* Allocate the status report ring */
+static int setup_srr(struct bdc *bdc, int interrupter)
+{
+ dev_dbg(bdc->dev, "%s() NUM_SR_ENTRIES:%d\n", __func__, NUM_SR_ENTRIES);
+ /* Reset the SRR */
+ bdc_writel(bdc->regs, BDC_SRRINT(0), BDC_SRR_RWS | BDC_SRR_RST);
+ bdc->srr.dqp_index = 0;
+ /* allocate the status report descriptors */
+ bdc->srr.sr_bds = dma_zalloc_coherent(
+ bdc->dev,
+ NUM_SR_ENTRIES * sizeof(struct bdc_bd),
+ &bdc->srr.dma_addr,
+ GFP_KERNEL);
+ if (!bdc->srr.sr_bds)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/* Initialize the HW regs and internal data structures */
+static void bdc_mem_init(struct bdc *bdc, bool reinit)
+{
+ u8 size = 0;
+ u32 usb2_pm;
+ u32 low32;
+ u32 upp32;
+ u32 temp;
+
+ dev_dbg(bdc->dev, "%s ()\n", __func__);
+ bdc->ep0_state = WAIT_FOR_SETUP;
+ bdc->dev_addr = 0;
+ bdc->srr.eqp_index = 0;
+ bdc->srr.dqp_index = 0;
+ bdc->zlp_needed = false;
+ bdc->delayed_status = false;
+
+ bdc_writel(bdc->regs, BDC_SPBBAL, bdc->scratchpad.sp_dma);
+ /* Init the SRR */
+ temp = BDC_SRR_RWS | BDC_SRR_RST;
+ /* Reset the SRR */
+ bdc_writel(bdc->regs, BDC_SRRINT(0), temp);
+ dev_dbg(bdc->dev, "bdc->srr.sr_bds =%p\n", bdc->srr.sr_bds);
+ temp = lower_32_bits(bdc->srr.dma_addr);
+ size = fls(NUM_SR_ENTRIES) - 2;
+ temp |= size;
+ dev_dbg(bdc->dev, "SRRBAL[0]=%08x NUM_SR_ENTRIES:%d size:%d\n",
+ temp, NUM_SR_ENTRIES, size);
+
+ low32 = lower_32_bits(temp);
+ upp32 = upper_32_bits(bdc->srr.dma_addr);
+ cpu_to_le32s(&low32);
+ cpu_to_le32s(&upp32);
+
+ /* Write the dma addresses into regs*/
+ bdc_writel(bdc->regs, BDC_SRRBAL(0), low32);
+ bdc_writel(bdc->regs, BDC_SRRBAH(0), upp32);
+
+ temp = bdc_readl(bdc->regs, BDC_SRRINT(0));
+ temp |= BDC_SRR_IE;
+ temp &= ~(BDC_SRR_RST | BDC_SRR_RWS);
+ bdc_writel(bdc->regs, BDC_SRRINT(0), temp);
+
+ /* Set the Interrupt Coalescence ~500 usec */
+ temp = bdc_readl(bdc->regs, BDC_INTCTLS(0));
+ temp &= ~0xffff;
+ temp |= INT_CLS;
+ bdc_writel(bdc->regs, BDC_INTCTLS(0), temp);
+
+ usb2_pm = bdc_readl(bdc->regs, BDC_USPPM2);
+ dev_dbg(bdc->dev, "usb2_pm=%08x", usb2_pm);
+ /* Enable hardware LPM Enable */
+ usb2_pm |= BDC_HLE;
+ bdc_writel(bdc->regs, BDC_USPPM2, usb2_pm);
+
+ /* readback for debug */
+ usb2_pm = bdc_readl(bdc->regs, BDC_USPPM2);
+ dev_dbg(bdc->dev, "usb2_pm=%08x\n", usb2_pm);
+
+ /* Disable any unwanted SR's on SRR */
+ temp = bdc_readl(bdc->regs, BDC_BDCSC);
+ /* We don't want Microframe counter wrap SR */
+ temp |= BDC_MASK_MCW;
+ bdc_writel(bdc->regs, BDC_BDCSC, temp);
+
+ /*
+ * In some error cases, driver has to reset the entire BDC controller
+ * in that case reinit is passed as 1
+ */
+ if (reinit) {
+ /* Enable interrupts */
+ temp = bdc_readl(bdc->regs, BDC_BDCSC);
+ temp |= BDC_GIE;
+ bdc_writel(bdc->regs, BDC_BDCSC, temp);
+ /* Init scratchpad to 0 */
+ memset(bdc->scratchpad.buff, 0, bdc->sp_buff_size);
+ /* Initialize SRR to 0 */
+ memset(bdc->srr.sr_bds, 0,
+ NUM_SR_ENTRIES * sizeof(struct bdc_bd));
+ } else {
+ /* One time initiaization only */
+ /* Enable status report function pointers */
+ bdc->sr_handler[0] = bdc_sr_xsf;
+ bdc->sr_handler[1] = bdc_sr_uspc;
+
+ /* EP0 status report function pointers */
+ bdc->sr_xsf_ep0[0] = bdc_xsf_ep0_setup_recv;
+ bdc->sr_xsf_ep0[1] = bdc_xsf_ep0_data_start;
+ bdc->sr_xsf_ep0[2] = bdc_xsf_ep0_status_start;
+ }
+}
+
+/* Free the dynamic memory */
+static void bdc_mem_free(struct bdc *bdc)
+{
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ /* Free SRR */
+ if (bdc->srr.sr_bds)
+ dma_free_coherent(bdc->dev,
+ NUM_SR_ENTRIES * sizeof(struct bdc_bd),
+ bdc->srr.sr_bds, bdc->srr.dma_addr);
+
+ /* Free scratchpad */
+ if (bdc->scratchpad.buff)
+ dma_free_coherent(bdc->dev, bdc->sp_buff_size,
+ bdc->scratchpad.buff, bdc->scratchpad.sp_dma);
+
+ /* Destroy the dma pools */
+ if (bdc->bd_table_pool)
+ dma_pool_destroy(bdc->bd_table_pool);
+
+ /* Free the bdc_ep array */
+ kfree(bdc->bdc_ep_array);
+
+ bdc->srr.sr_bds = NULL;
+ bdc->scratchpad.buff = NULL;
+ bdc->bd_table_pool = NULL;
+ bdc->bdc_ep_array = NULL;
+}
+
+/*
+ * bdc reinit gives a controller reset and reinitialize the registers,
+ * called from disconnect/bus reset scenario's, to ensure proper HW cleanup
+ */
+int bdc_reinit(struct bdc *bdc)
+{
+ int ret;
+
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ ret = bdc_stop(bdc);
+ if (ret)
+ goto out;
+
+ ret = bdc_reset(bdc);
+ if (ret)
+ goto out;
+
+ /* the reinit flag is 1 */
+ bdc_mem_init(bdc, true);
+ ret = bdc_run(bdc);
+out:
+ bdc->reinit = false;
+
+ return ret;
+}
+
+/* Allocate all the dyanmic memory */
+static int bdc_mem_alloc(struct bdc *bdc)
+{
+ u32 page_size;
+ unsigned int num_ieps, num_oeps;
+
+ dev_dbg(bdc->dev,
+ "%s() NUM_BDS_PER_TABLE:%d\n", __func__,
+ NUM_BDS_PER_TABLE);
+ page_size = BDC_PGS(bdc_readl(bdc->regs, BDC_BDCCFG0));
+ /* page size is 2^pgs KB */
+ page_size = 1 << page_size;
+ /* KB */
+ page_size <<= 10;
+ dev_dbg(bdc->dev, "page_size=%d\n", page_size);
+
+ /* Create a pool of bd tables */
+ bdc->bd_table_pool =
+ dma_pool_create("BDC BD tables", bdc->dev, NUM_BDS_PER_TABLE * 16,
+ 16, page_size);
+
+ if (!bdc->bd_table_pool)
+ goto fail;
+
+ if (scratchpad_setup(bdc))
+ goto fail;
+
+ /* read from regs */
+ num_ieps = NUM_NCS(bdc_readl(bdc->regs, BDC_FSCNIC));
+ num_oeps = NUM_NCS(bdc_readl(bdc->regs, BDC_FSCNOC));
+ /* +2: 1 for ep0 and the other is rsvd i.e. bdc_ep[0] is rsvd */
+ bdc->num_eps = num_ieps + num_oeps + 2;
+ dev_dbg(bdc->dev,
+ "ieps:%d eops:%d num_eps:%d\n",
+ num_ieps, num_oeps, bdc->num_eps);
+ /* allocate array of ep pointers */
+ bdc->bdc_ep_array = kcalloc(bdc->num_eps, sizeof(struct bdc_ep *),
+ GFP_KERNEL);
+ if (!bdc->bdc_ep_array)
+ goto fail;
+
+ dev_dbg(bdc->dev, "Allocating sr report0\n");
+ if (setup_srr(bdc, 0))
+ goto fail;
+
+ return 0;
+fail:
+ dev_warn(bdc->dev, "Couldn't initialize memory\n");
+ bdc_mem_free(bdc);
+
+ return -ENOMEM;
+}
+
+/* opposite to bdc_hw_init */
+static void bdc_hw_exit(struct bdc *bdc)
+{
+ dev_dbg(bdc->dev, "%s ()\n", __func__);
+ bdc_mem_free(bdc);
+}
+
+/* Initialize the bdc HW and memory */
+static int bdc_hw_init(struct bdc *bdc)
+{
+ int ret;
+
+ dev_dbg(bdc->dev, "%s ()\n", __func__);
+ ret = bdc_reset(bdc);
+ if (ret) {
+ dev_err(bdc->dev, "err resetting bdc abort bdc init%d\n", ret);
+ return ret;
+ }
+ ret = bdc_mem_alloc(bdc);
+ if (ret) {
+ dev_err(bdc->dev, "Mem alloc failed, aborting\n");
+ return -ENOMEM;
+ }
+ bdc_mem_init(bdc, 0);
+ bdc_dbg_regs(bdc);
+ dev_dbg(bdc->dev, "HW Init done\n");
+
+ return 0;
+}
+
+static int bdc_probe(struct platform_device *pdev)
+{
+ struct bdc *bdc;
+ struct resource *res;
+ int ret = -ENOMEM;
+ int irq;
+ u32 temp;
+ struct device *dev = &pdev->dev;
+
+ dev_dbg(dev, "%s()\n", __func__);
+ bdc = devm_kzalloc(dev, sizeof(*bdc), GFP_KERNEL);
+ if (!bdc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ bdc->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(bdc->regs)) {
+ dev_err(dev, "ioremap error\n");
+ return -ENOMEM;
+ }
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "platform_get_irq failed:%d\n", irq);
+ return irq;
+ }
+ spin_lock_init(&bdc->lock);
+ platform_set_drvdata(pdev, bdc);
+ bdc->irq = irq;
+ bdc->dev = dev;
+ dev_dbg(bdc->dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq);
+
+ temp = bdc_readl(bdc->regs, BDC_BDCSC);
+ if ((temp & BDC_P64) &&
+ !dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) {
+ dev_dbg(bdc->dev, "Using 64-bit address\n");
+ } else {
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(bdc->dev, "No suitable DMA config available, abort\n");
+ return -ENOTSUPP;
+ }
+ dev_dbg(bdc->dev, "Using 32-bit address\n");
+ }
+ ret = bdc_hw_init(bdc);
+ if (ret) {
+ dev_err(bdc->dev, "BDC init failure:%d\n", ret);
+ return ret;
+ }
+ ret = bdc_udc_init(bdc);
+ if (ret) {
+ dev_err(bdc->dev, "BDC Gadget init failure:%d\n", ret);
+ goto cleanup;
+ }
+ return 0;
+
+cleanup:
+ bdc_hw_exit(bdc);
+
+ return ret;
+}
+
+static int bdc_remove(struct platform_device *pdev)
+{
+ struct bdc *bdc;
+
+ bdc = platform_get_drvdata(pdev);
+ dev_dbg(bdc->dev, "%s ()\n", __func__);
+ bdc_udc_exit(bdc);
+ bdc_hw_exit(bdc);
+
+ return 0;
+}
+
+static struct platform_driver bdc_driver = {
+ .driver = {
+ .name = BRCM_BDC_NAME,
+ .owner = THIS_MODULE
+ },
+ .probe = bdc_probe,
+ .remove = bdc_remove,
+};
+
+module_platform_driver(bdc_driver);
+MODULE_AUTHOR("Ashwini Pahuja <ashwini.linux@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(BRCM_BDC_DESC);
diff --git a/drivers/usb/gadget/udc/bdc/bdc_dbg.c b/drivers/usb/gadget/udc/bdc/bdc_dbg.c
new file mode 100644
index 000000000000..5945dbc47825
--- /dev/null
+++ b/drivers/usb/gadget/udc/bdc/bdc_dbg.c
@@ -0,0 +1,123 @@
+/*
+ * bdc_dbg.c - BRCM BDC USB3.0 device controller debug functions
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Author: Ashwini Pahuja
+ *
+ * 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 "bdc.h"
+#include "bdc_dbg.h"
+
+void bdc_dbg_regs(struct bdc *bdc)
+{
+ u32 temp;
+
+ dev_vdbg(bdc->dev, "bdc->regs:%p\n", bdc->regs);
+ temp = bdc_readl(bdc->regs, BDC_BDCCFG0);
+ dev_vdbg(bdc->dev, "bdccfg0:0x%08x\n", temp);
+ temp = bdc_readl(bdc->regs, BDC_BDCCFG1);
+ dev_vdbg(bdc->dev, "bdccfg1:0x%08x\n", temp);
+ temp = bdc_readl(bdc->regs, BDC_BDCCAP0);
+ dev_vdbg(bdc->dev, "bdccap0:0x%08x\n", temp);
+ temp = bdc_readl(bdc->regs, BDC_BDCCAP1);
+ dev_vdbg(bdc->dev, "bdccap1:0x%08x\n", temp);
+ temp = bdc_readl(bdc->regs, BDC_USPC);
+ dev_vdbg(bdc->dev, "uspc:0x%08x\n", temp);
+ temp = bdc_readl(bdc->regs, BDC_DVCSA);
+ dev_vdbg(bdc->dev, "dvcsa:0x%08x\n", temp);
+ temp = bdc_readl(bdc->regs, BDC_DVCSB);
+ dev_vdbg(bdc->dev, "dvcsb:0x%x08\n", temp);
+}
+
+void bdc_dump_epsts(struct bdc *bdc)
+{
+ u32 temp;
+
+ temp = bdc_readl(bdc->regs, BDC_EPSTS0(0));
+ dev_vdbg(bdc->dev, "BDC_EPSTS0:0x%08x\n", temp);
+
+ temp = bdc_readl(bdc->regs, BDC_EPSTS1(0));
+ dev_vdbg(bdc->dev, "BDC_EPSTS1:0x%x\n", temp);
+
+ temp = bdc_readl(bdc->regs, BDC_EPSTS2(0));
+ dev_vdbg(bdc->dev, "BDC_EPSTS2:0x%08x\n", temp);
+
+ temp = bdc_readl(bdc->regs, BDC_EPSTS3(0));
+ dev_vdbg(bdc->dev, "BDC_EPSTS3:0x%08x\n", temp);
+
+ temp = bdc_readl(bdc->regs, BDC_EPSTS4(0));
+ dev_vdbg(bdc->dev, "BDC_EPSTS4:0x%08x\n", temp);
+
+ temp = bdc_readl(bdc->regs, BDC_EPSTS5(0));
+ dev_vdbg(bdc->dev, "BDC_EPSTS5:0x%08x\n", temp);
+
+ temp = bdc_readl(bdc->regs, BDC_EPSTS6(0));
+ dev_vdbg(bdc->dev, "BDC_EPSTS6:0x%08x\n", temp);
+
+ temp = bdc_readl(bdc->regs, BDC_EPSTS7(0));
+ dev_vdbg(bdc->dev, "BDC_EPSTS7:0x%08x\n", temp);
+}
+
+void bdc_dbg_srr(struct bdc *bdc, u32 srr_num)
+{
+ struct bdc_sr *sr;
+ dma_addr_t addr;
+ int i;
+
+ sr = bdc->srr.sr_bds;
+ addr = bdc->srr.dma_addr;
+ dev_vdbg(bdc->dev, "bdc_dbg_srr sr:%p dqp_index:%d\n",
+ sr, bdc->srr.dqp_index);
+ for (i = 0; i < NUM_SR_ENTRIES; i++) {
+ sr = &bdc->srr.sr_bds[i];
+ dev_vdbg(bdc->dev, "%llx %08x %08x %08x %08x\n",
+ (unsigned long long)addr,
+ le32_to_cpu(sr->offset[0]),
+ le32_to_cpu(sr->offset[1]),
+ le32_to_cpu(sr->offset[2]),
+ le32_to_cpu(sr->offset[3]));
+ addr += sizeof(*sr);
+ }
+}
+
+void bdc_dbg_bd_list(struct bdc *bdc, struct bdc_ep *ep)
+{
+ struct bd_list *bd_list = &ep->bd_list;
+ struct bd_table *bd_table;
+ struct bdc_bd *bd;
+ int tbi, bdi, gbdi;
+ dma_addr_t dma;
+
+ gbdi = 0;
+ dev_vdbg(bdc->dev,
+ "Dump bd list for %s epnum:%d\n",
+ ep->name, ep->ep_num);
+
+ dev_vdbg(bdc->dev,
+ "tabs:%d max_bdi:%d eqp_bdi:%d hwd_bdi:%d num_bds_table:%d\n",
+ bd_list->num_tabs, bd_list->max_bdi, bd_list->eqp_bdi,
+ bd_list->hwd_bdi, bd_list->num_bds_table);
+
+ for (tbi = 0; tbi < bd_list->num_tabs; tbi++) {
+ bd_table = bd_list->bd_table_array[tbi];
+ for (bdi = 0; bdi < bd_list->num_bds_table; bdi++) {
+ bd = bd_table->start_bd + bdi;
+ dma = bd_table->dma + (sizeof(struct bdc_bd) * bdi);
+ dev_vdbg(bdc->dev,
+ "tbi:%2d bdi:%2d gbdi:%2d virt:%p phys:%llx %08x %08x %08x %08x\n",
+ tbi, bdi, gbdi++, bd, (unsigned long long)dma,
+ le32_to_cpu(bd->offset[0]),
+ le32_to_cpu(bd->offset[1]),
+ le32_to_cpu(bd->offset[2]),
+ le32_to_cpu(bd->offset[3]));
+ }
+ dev_vdbg(bdc->dev, "\n\n");
+ }
+}
diff --git a/drivers/usb/gadget/udc/bdc/bdc_dbg.h b/drivers/usb/gadget/udc/bdc/bdc_dbg.h
new file mode 100644
index 000000000000..338a6c701315
--- /dev/null
+++ b/drivers/usb/gadget/udc/bdc/bdc_dbg.h
@@ -0,0 +1,37 @@
+/*
+ * bdc_dbg.h - header for the BDC debug functions
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Author: Ashwini Pahuja
+ *
+ * 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.
+ *
+ */
+#ifndef __LINUX_BDC_DBG_H__
+#define __LINUX_BDC_DBG_H__
+
+#include "bdc.h"
+
+#ifdef CONFIG_USB_GADGET_VERBOSE
+void bdc_dbg_bd_list(struct bdc *, struct bdc_ep*);
+void bdc_dbg_srr(struct bdc *, u32);
+void bdc_dbg_regs(struct bdc *);
+void bdc_dump_epsts(struct bdc *);
+#else
+static inline void bdc_dbg_regs(struct bdc *bdc)
+{ }
+
+static inline void bdc_dbg_srr(struct bdc *bdc, u32 srr_num)
+{ }
+
+static inline void bdc_dbg_bd_list(struct bdc *bdc, struct bdc_ep *ep)
+{ }
+
+static inline void bdc_dump_epsts(struct bdc *bdc)
+{ }
+#endif /* CONFIG_USB_GADGET_VERBOSE */
+#endif /* __LINUX_BDC_DBG_H__ */
diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c
new file mode 100644
index 000000000000..ff67ceac77c4
--- /dev/null
+++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c
@@ -0,0 +1,2024 @@
+/*
+ * bdc_ep.c - BRCM BDC USB3.0 device controller endpoint related functions
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Author: Ashwini Pahuja
+ *
+ * Based on drivers under drivers/usb/
+ *
+ * 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/module.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/dmapool.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/pm.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <asm/unaligned.h>
+#include <linux/platform_device.h>
+#include <linux/usb/composite.h>
+
+#include "bdc.h"
+#include "bdc_ep.h"
+#include "bdc_cmd.h"
+#include "bdc_dbg.h"
+
+static const char * const ep0_state_string[] = {
+ "WAIT_FOR_SETUP",
+ "WAIT_FOR_DATA_START",
+ "WAIT_FOR_DATA_XMIT",
+ "WAIT_FOR_STATUS_START",
+ "WAIT_FOR_STATUS_XMIT",
+ "STATUS_PENDING"
+};
+
+/* Free the bdl during ep disable */
+static void ep_bd_list_free(struct bdc_ep *ep, u32 num_tabs)
+{
+ struct bd_list *bd_list = &ep->bd_list;
+ struct bdc *bdc = ep->bdc;
+ struct bd_table *bd_table;
+ int index;
+
+ dev_dbg(bdc->dev, "%s ep:%s num_tabs:%d\n",
+ __func__, ep->name, num_tabs);
+
+ if (!bd_list->bd_table_array) {
+ dev_dbg(bdc->dev, "%s already freed\n", ep->name);
+ return;
+ }
+ for (index = 0; index < num_tabs; index++) {
+ /*
+ * check if the bd_table struct is allocated ?
+ * if yes, then check if bd memory has been allocated, then
+ * free the dma_pool and also the bd_table struct memory
+ */
+ bd_table = bd_list->bd_table_array[index];
+ dev_dbg(bdc->dev, "bd_table:%p index:%d\n", bd_table, index);
+ if (!bd_table) {
+ dev_dbg(bdc->dev, "bd_table not allocated\n");
+ continue;
+ }
+ if (!bd_table->start_bd) {
+ dev_dbg(bdc->dev, "bd dma pool not allocted\n");
+ continue;
+ }
+
+ dev_dbg(bdc->dev,
+ "Free dma pool start_bd:%p dma:%llx\n",
+ bd_table->start_bd,
+ (unsigned long long)bd_table->dma);
+
+ dma_pool_free(bdc->bd_table_pool,
+ bd_table->start_bd,
+ bd_table->dma);
+ /* Free the bd_table structure */
+ kfree(bd_table);
+ }
+ /* Free the bd table array */
+ kfree(ep->bd_list.bd_table_array);
+}
+
+/*
+ * chain the tables, by insteting a chain bd at the end of prev_table, pointing
+ * to next_table
+ */
+static inline void chain_table(struct bd_table *prev_table,
+ struct bd_table *next_table,
+ u32 bd_p_tab)
+{
+ /* Chain the prev table to next table */
+ prev_table->start_bd[bd_p_tab-1].offset[0] =
+ cpu_to_le32(lower_32_bits(next_table->dma));
+
+ prev_table->start_bd[bd_p_tab-1].offset[1] =
+ cpu_to_le32(upper_32_bits(next_table->dma));
+
+ prev_table->start_bd[bd_p_tab-1].offset[2] =
+ 0x0;
+
+ prev_table->start_bd[bd_p_tab-1].offset[3] =
+ cpu_to_le32(MARK_CHAIN_BD);
+}
+
+/* Allocate the bdl for ep, during config ep */
+static int ep_bd_list_alloc(struct bdc_ep *ep)
+{
+ struct bd_table *prev_table = NULL;
+ int index, num_tabs, bd_p_tab;
+ struct bdc *bdc = ep->bdc;
+ struct bd_table *bd_table;
+ dma_addr_t dma;
+
+ if (usb_endpoint_xfer_isoc(ep->desc))
+ num_tabs = NUM_TABLES_ISOCH;
+ else
+ num_tabs = NUM_TABLES;
+
+ bd_p_tab = NUM_BDS_PER_TABLE;
+ /* if there is only 1 table in bd list then loop chain to self */
+ dev_dbg(bdc->dev,
+ "%s ep:%p num_tabs:%d\n",
+ __func__, ep, num_tabs);
+
+ /* Allocate memory for table array */
+ ep->bd_list.bd_table_array = kzalloc(
+ num_tabs * sizeof(struct bd_table *),
+ GFP_ATOMIC);
+ if (!ep->bd_list.bd_table_array)
+ return -ENOMEM;
+
+ /* Allocate memory for each table */
+ for (index = 0; index < num_tabs; index++) {
+ /* Allocate memory for bd_table structure */
+ bd_table = kzalloc(sizeof(struct bd_table), GFP_ATOMIC);
+ if (!bd_table)
+ goto fail;
+
+ bd_table->start_bd = dma_pool_alloc(bdc->bd_table_pool,
+ GFP_ATOMIC,
+ &dma);
+ if (!bd_table->start_bd)
+ goto fail;
+
+ bd_table->dma = dma;
+
+ dev_dbg(bdc->dev,
+ "index:%d start_bd:%p dma=%08llx prev_table:%p\n",
+ index, bd_table->start_bd,
+ (unsigned long long)bd_table->dma, prev_table);
+
+ ep->bd_list.bd_table_array[index] = bd_table;
+ memset(bd_table->start_bd, 0, bd_p_tab * sizeof(struct bdc_bd));
+ if (prev_table)
+ chain_table(prev_table, bd_table, bd_p_tab);
+
+ prev_table = bd_table;
+ }
+ chain_table(prev_table, ep->bd_list.bd_table_array[0], bd_p_tab);
+ /* Memory allocation is successful, now init the internal fields */
+ ep->bd_list.num_tabs = num_tabs;
+ ep->bd_list.max_bdi = (num_tabs * bd_p_tab) - 1;
+ ep->bd_list.num_tabs = num_tabs;
+ ep->bd_list.num_bds_table = bd_p_tab;
+ ep->bd_list.eqp_bdi = 0;
+ ep->bd_list.hwd_bdi = 0;
+
+ return 0;
+fail:
+ /* Free the bd_table_array, bd_table struct, bd's */
+ ep_bd_list_free(ep, num_tabs);
+
+ return -ENOMEM;
+}
+
+/* returns how many bd's are need for this transfer */
+static inline int bd_needed_req(struct bdc_req *req)
+{
+ int bd_needed = 0;
+ int remaining;
+
+ /* 1 bd needed for 0 byte transfer */
+ if (req->usb_req.length == 0)
+ return 1;
+
+ /* remaining bytes after tranfering all max BD size BD's */
+ remaining = req->usb_req.length % BD_MAX_BUFF_SIZE;
+ if (remaining)
+ bd_needed++;
+
+ /* How many maximum BUFF size BD's ? */
+ remaining = req->usb_req.length / BD_MAX_BUFF_SIZE;
+ bd_needed += remaining;
+
+ return bd_needed;
+}
+
+/* returns the bd index(bdi) corresponding to bd dma address */
+static int bd_add_to_bdi(struct bdc_ep *ep, dma_addr_t bd_dma_addr)
+{
+ struct bd_list *bd_list = &ep->bd_list;
+ dma_addr_t dma_first_bd, dma_last_bd;
+ struct bdc *bdc = ep->bdc;
+ struct bd_table *bd_table;
+ bool found = false;
+ int tbi, bdi;
+
+ dma_first_bd = dma_last_bd = 0;
+ dev_dbg(bdc->dev, "%s %llx\n",
+ __func__, (unsigned long long)bd_dma_addr);
+ /*
+ * Find in which table this bd_dma_addr belongs?, go through the table
+ * array and compare addresses of first and last address of bd of each
+ * table
+ */
+ for (tbi = 0; tbi < bd_list->num_tabs; tbi++) {
+ bd_table = bd_list->bd_table_array[tbi];
+ dma_first_bd = bd_table->dma;
+ dma_last_bd = bd_table->dma +
+ (sizeof(struct bdc_bd) *
+ (bd_list->num_bds_table - 1));
+ dev_dbg(bdc->dev, "dma_first_bd:%llx dma_last_bd:%llx\n",
+ (unsigned long long)dma_first_bd,
+ (unsigned long long)dma_last_bd);
+ if (bd_dma_addr >= dma_first_bd && bd_dma_addr <= dma_last_bd) {
+ found = true;
+ break;
+ }
+ }
+ if (unlikely(!found)) {
+ dev_err(bdc->dev, "%s FATAL err, bd not found\n", __func__);
+ return -EINVAL;
+ }
+ /* Now we know the table, find the bdi */
+ bdi = (bd_dma_addr - dma_first_bd) / sizeof(struct bdc_bd);
+
+ /* return the global bdi, to compare with ep eqp_bdi */
+ return (bdi + (tbi * bd_list->num_bds_table));
+}
+
+/* returns the table index(tbi) of the given bdi */
+static int bdi_to_tbi(struct bdc_ep *ep, int bdi)
+{
+ int tbi;
+
+ tbi = bdi / ep->bd_list.num_bds_table;
+ dev_vdbg(ep->bdc->dev,
+ "bdi:%d num_bds_table:%d tbi:%d\n",
+ bdi, ep->bd_list.num_bds_table, tbi);
+
+ return tbi;
+}
+
+/* Find the bdi last bd in the transfer */
+static inline int find_end_bdi(struct bdc_ep *ep, int next_hwd_bdi)
+{
+ int end_bdi;
+
+ end_bdi = next_hwd_bdi - 1;
+ if (end_bdi < 0)
+ end_bdi = ep->bd_list.max_bdi - 1;
+ else if ((end_bdi % (ep->bd_list.num_bds_table-1)) == 0)
+ end_bdi--;
+
+ return end_bdi;
+}
+
+/*
+ * How many transfer bd's are available on this ep bdl, chain bds are not
+ * counted in available bds
+ */
+static int bd_available_ep(struct bdc_ep *ep)
+{
+ struct bd_list *bd_list = &ep->bd_list;
+ int available1, available2;
+ struct bdc *bdc = ep->bdc;
+ int chain_bd1, chain_bd2;
+ int available_bd = 0;
+
+ available1 = available2 = chain_bd1 = chain_bd2 = 0;
+ /* if empty then we have all bd's available - number of chain bd's */
+ if (bd_list->eqp_bdi == bd_list->hwd_bdi)
+ return bd_list->max_bdi - bd_list->num_tabs;
+
+ /*
+ * Depending upon where eqp and dqp pointers are, caculate number
+ * of avaialble bd's
+ */
+ if (bd_list->hwd_bdi < bd_list->eqp_bdi) {
+ /* available bd's are from eqp..max_bds + 0..dqp - chain_bds */
+ available1 = bd_list->max_bdi - bd_list->eqp_bdi;
+ available2 = bd_list->hwd_bdi;
+ chain_bd1 = available1 / bd_list->num_bds_table;
+ chain_bd2 = available2 / bd_list->num_bds_table;
+ dev_vdbg(bdc->dev, "chain_bd1:%d chain_bd2:%d\n",
+ chain_bd1, chain_bd2);
+ available_bd = available1 + available2 - chain_bd1 - chain_bd2;
+ } else {
+ /* available bd's are from eqp..dqp - number of chain bd's */
+ available1 = bd_list->hwd_bdi - bd_list->eqp_bdi;
+ /* if gap between eqp and dqp is less than NUM_BDS_PER_TABLE */
+ if ((bd_list->hwd_bdi - bd_list->eqp_bdi)
+ <= bd_list->num_bds_table) {
+ /* If there any chain bd in between */
+ if (!(bdi_to_tbi(ep, bd_list->hwd_bdi)
+ == bdi_to_tbi(ep, bd_list->eqp_bdi))) {
+ available_bd = available1 - 1;
+ }
+ } else {
+ chain_bd1 = available1 / bd_list->num_bds_table;
+ available_bd = available1 - chain_bd1;
+ }
+ }
+ /*
+ * we need to keep one extra bd to check if ring is full or empty so
+ * reduce by 1
+ */
+ available_bd--;
+ dev_vdbg(bdc->dev, "available_bd:%d\n", available_bd);
+
+ return available_bd;
+}
+
+/* Notify the hardware after queueing the bd to bdl */
+void bdc_notify_xfr(struct bdc *bdc, u32 epnum)
+{
+ struct bdc_ep *ep = bdc->bdc_ep_array[epnum];
+
+ dev_vdbg(bdc->dev, "%s epnum:%d\n", __func__, epnum);
+ /*
+ * We don't have anyway to check if ep state is running,
+ * except the software flags.
+ */
+ if (unlikely(ep->flags & BDC_EP_STOP))
+ ep->flags &= ~BDC_EP_STOP;
+
+ bdc_writel(bdc->regs, BDC_XSFNTF, epnum);
+}
+
+/* returns the bd corresponding to bdi */
+static struct bdc_bd *bdi_to_bd(struct bdc_ep *ep, int bdi)
+{
+ int tbi = bdi_to_tbi(ep, bdi);
+ int local_bdi = 0;
+
+ local_bdi = bdi - (tbi * ep->bd_list.num_bds_table);
+ dev_vdbg(ep->bdc->dev,
+ "%s bdi:%d local_bdi:%d\n",
+ __func__, bdi, local_bdi);
+
+ return (ep->bd_list.bd_table_array[tbi]->start_bd + local_bdi);
+}
+
+/* Advance the enqueue pointer */
+static void ep_bdlist_eqp_adv(struct bdc_ep *ep)
+{
+ ep->bd_list.eqp_bdi++;
+ /* if it's chain bd, then move to next */
+ if (((ep->bd_list.eqp_bdi + 1) % ep->bd_list.num_bds_table) == 0)
+ ep->bd_list.eqp_bdi++;
+
+ /* if the eqp is pointing to last + 1 then move back to 0 */
+ if (ep->bd_list.eqp_bdi == (ep->bd_list.max_bdi + 1))
+ ep->bd_list.eqp_bdi = 0;
+}
+
+/* Setup the first bd for ep0 transfer */
+static int setup_first_bd_ep0(struct bdc *bdc, struct bdc_req *req, u32 *dword3)
+{
+ u16 wValue;
+ u32 req_len;
+
+ req->ep->dir = 0;
+ req_len = req->usb_req.length;
+ switch (bdc->ep0_state) {
+ case WAIT_FOR_DATA_START:
+ *dword3 |= BD_TYPE_DS;
+ if (bdc->setup_pkt.bRequestType & USB_DIR_IN)
+ *dword3 |= BD_DIR_IN;
+
+ /* check if zlp will be needed */
+ wValue = le16_to_cpu(bdc->setup_pkt.wValue);
+ if ((wValue > req_len) &&
+ (req_len % bdc->gadget.ep0->maxpacket == 0)) {
+ dev_dbg(bdc->dev, "ZLP needed wVal:%d len:%d MaxP:%d\n",
+ wValue, req_len,
+ bdc->gadget.ep0->maxpacket);
+ bdc->zlp_needed = true;
+ }
+ break;
+
+ case WAIT_FOR_STATUS_START:
+ *dword3 |= BD_TYPE_SS;
+ if (!le16_to_cpu(bdc->setup_pkt.wLength) ||
+ !(bdc->setup_pkt.bRequestType & USB_DIR_IN))
+ *dword3 |= BD_DIR_IN;
+ break;
+ default:
+ dev_err(bdc->dev,
+ "Unknown ep0 state for queueing bd ep0_state:%s\n",
+ ep0_state_string[bdc->ep0_state]);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Setup the bd dma descriptor for a given request */
+static int setup_bd_list_xfr(struct bdc *bdc, struct bdc_req *req, int num_bds)
+{
+ dma_addr_t buf_add = req->usb_req.dma;
+ u32 maxp, tfs, dword2, dword3;
+ struct bd_transfer *bd_xfr;
+ struct bd_list *bd_list;
+ struct bdc_ep *ep;
+ struct bdc_bd *bd;
+ int ret, bdnum;
+ u32 req_len;
+
+ ep = req->ep;
+ bd_list = &ep->bd_list;
+ bd_xfr = &req->bd_xfr;
+ bd_xfr->req = req;
+ bd_xfr->start_bdi = bd_list->eqp_bdi;
+ bd = bdi_to_bd(ep, bd_list->eqp_bdi);
+ req_len = req->usb_req.length;
+ maxp = usb_endpoint_maxp(ep->desc) & 0x7ff;
+ tfs = roundup(req->usb_req.length, maxp);
+ tfs = tfs/maxp;
+ dev_vdbg(bdc->dev, "%s ep:%s num_bds:%d tfs:%d r_len:%d bd:%p\n",
+ __func__, ep->name, num_bds, tfs, req_len, bd);
+
+ for (bdnum = 0; bdnum < num_bds; bdnum++) {
+ dword2 = dword3 = 0;
+ /* First bd */
+ if (!bdnum) {
+ dword3 |= BD_SOT|BD_SBF|(tfs<<BD_TFS_SHIFT);
+ dword2 |= BD_LTF;
+ /* format of first bd for ep0 is different than other */
+ if (ep->ep_num == 1) {
+ ret = setup_first_bd_ep0(bdc, req, &dword3);
+ if (ret)
+ return ret;
+ }
+ }
+ if (!req->ep->dir)
+ dword3 |= BD_ISP;
+
+ if (req_len > BD_MAX_BUFF_SIZE) {
+ dword2 |= BD_MAX_BUFF_SIZE;
+ req_len -= BD_MAX_BUFF_SIZE;
+ } else {
+ /* this should be the last bd */
+ dword2 |= req_len;
+ dword3 |= BD_IOC;
+ dword3 |= BD_EOT;
+ }
+ /* Currently only 1 INT target is supported */
+ dword2 |= BD_INTR_TARGET(0);
+ bd = bdi_to_bd(ep, ep->bd_list.eqp_bdi);
+ if (unlikely(!bd)) {
+ dev_err(bdc->dev, "Err bd pointing to wrong addr\n");
+ return -EINVAL;
+ }
+ /* write bd */
+ bd->offset[0] = cpu_to_le32(lower_32_bits(buf_add));
+ bd->offset[1] = cpu_to_le32(upper_32_bits(buf_add));
+ bd->offset[2] = cpu_to_le32(dword2);
+ bd->offset[3] = cpu_to_le32(dword3);
+ /* advance eqp pointer */
+ ep_bdlist_eqp_adv(ep);
+ /* advance the buff pointer */
+ buf_add += BD_MAX_BUFF_SIZE;
+ dev_vdbg(bdc->dev, "buf_add:%08llx req_len:%d bd:%p eqp:%d\n",
+ (unsigned long long)buf_add, req_len, bd,
+ ep->bd_list.eqp_bdi);
+ bd = bdi_to_bd(ep, ep->bd_list.eqp_bdi);
+ bd->offset[3] = cpu_to_le32(BD_SBF);
+ }
+ /* clear the STOP BD fetch bit from the first bd of this xfr */
+ bd = bdi_to_bd(ep, bd_xfr->start_bdi);
+ bd->offset[3] &= cpu_to_le32(~BD_SBF);
+ /* the new eqp will be next hw dqp */
+ bd_xfr->num_bds = num_bds;
+ bd_xfr->next_hwd_bdi = ep->bd_list.eqp_bdi;
+ /* everything is written correctly before notifying the HW */
+ wmb();
+
+ return 0;
+}
+
+/* Queue the xfr */
+static int bdc_queue_xfr(struct bdc *bdc, struct bdc_req *req)
+{
+ int num_bds, bd_available;
+ struct bdc_ep *ep;
+ int ret;
+
+ ep = req->ep;
+ dev_dbg(bdc->dev, "%s req:%p\n", __func__, req);
+ dev_dbg(bdc->dev, "eqp_bdi:%d hwd_bdi:%d\n",
+ ep->bd_list.eqp_bdi, ep->bd_list.hwd_bdi);
+
+ num_bds = bd_needed_req(req);
+ bd_available = bd_available_ep(ep);
+
+ /* how many bd's are avaialble on ep */
+ if (num_bds > bd_available)
+ return -ENOMEM;
+
+ ret = setup_bd_list_xfr(bdc, req, num_bds);
+ if (ret)
+ return ret;
+ list_add_tail(&req->queue, &ep->queue);
+ bdc_dbg_bd_list(bdc, ep);
+ bdc_notify_xfr(bdc, ep->ep_num);
+
+ return 0;
+}
+
+/* callback to gadget layer when xfr completes */
+static void bdc_req_complete(struct bdc_ep *ep, struct bdc_req *req,
+ int status)
+{
+ struct bdc *bdc = ep->bdc;
+
+ if (req == NULL || &req->queue == NULL || &req->usb_req == NULL)
+ return;
+
+ dev_dbg(bdc->dev, "%s ep:%s status:%d\n", __func__, ep->name, status);
+ list_del(&req->queue);
+ req->usb_req.status = status;
+ usb_gadget_unmap_request(&bdc->gadget, &req->usb_req, ep->dir);
+ if (req->usb_req.complete) {
+ spin_unlock(&bdc->lock);
+ usb_gadget_giveback_request(&ep->usb_ep, &req->usb_req);
+ spin_lock(&bdc->lock);
+ }
+}
+
+/* Disable the endpoint */
+int bdc_ep_disable(struct bdc_ep *ep)
+{
+ struct bdc_req *req;
+ struct bdc *bdc;
+ int ret;
+
+ ret = 0;
+ bdc = ep->bdc;
+ dev_dbg(bdc->dev, "%s() ep->ep_num=%d\n", __func__, ep->ep_num);
+ /* Stop the endpoint */
+ ret = bdc_stop_ep(bdc, ep->ep_num);
+
+ /*
+ * Intentionally don't check the ret value of stop, it can fail in
+ * disconnect scenarios, continue with dconfig
+ */
+ /* de-queue any pending requests */
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct bdc_req,
+ queue);
+ bdc_req_complete(ep, req, -ESHUTDOWN);
+ }
+ /* deconfigure the endpoint */
+ ret = bdc_dconfig_ep(bdc, ep);
+ if (ret)
+ dev_warn(bdc->dev,
+ "dconfig fail but continue with memory free");
+
+ ep->flags = 0;
+ /* ep0 memory is not freed, but reused on next connect sr */
+ if (ep->ep_num == 1)
+ return 0;
+
+ /* Free the bdl memory */
+ ep_bd_list_free(ep, ep->bd_list.num_tabs);
+ ep->desc = NULL;
+ ep->comp_desc = NULL;
+ ep->usb_ep.desc = NULL;
+ ep->ep_type = 0;
+
+ return ret;
+}
+
+/* Enable the ep */
+int bdc_ep_enable(struct bdc_ep *ep)
+{
+ struct bdc *bdc;
+ int ret = 0;
+
+ bdc = ep->bdc;
+ dev_dbg(bdc->dev, "%s NUM_TABLES:%d %d\n",
+ __func__, NUM_TABLES, NUM_TABLES_ISOCH);
+
+ ret = ep_bd_list_alloc(ep);
+ if (ret) {
+ dev_err(bdc->dev, "ep bd list allocation failed:%d\n", ret);
+ return -ENOMEM;
+ }
+ bdc_dbg_bd_list(bdc, ep);
+ /* only for ep0: config ep is called for ep0 from connect event */
+ ep->flags |= BDC_EP_ENABLED;
+ if (ep->ep_num == 1)
+ return ret;
+
+ /* Issue a configure endpoint command */
+ ret = bdc_config_ep(bdc, ep);
+ if (ret)
+ return ret;
+
+ ep->usb_ep.maxpacket = usb_endpoint_maxp(ep->desc);
+ ep->usb_ep.desc = ep->desc;
+ ep->usb_ep.comp_desc = ep->comp_desc;
+ ep->ep_type = usb_endpoint_type(ep->desc);
+ ep->flags |= BDC_EP_ENABLED;
+
+ return 0;
+}
+
+/* EP0 related code */
+
+/* Queue a status stage BD */
+static int ep0_queue_status_stage(struct bdc *bdc)
+{
+ struct bdc_req *status_req;
+ struct bdc_ep *ep;
+
+ status_req = &bdc->status_req;
+ ep = bdc->bdc_ep_array[1];
+ status_req->ep = ep;
+ status_req->usb_req.length = 0;
+ status_req->usb_req.status = -EINPROGRESS;
+ status_req->usb_req.actual = 0;
+ status_req->usb_req.complete = NULL;
+ bdc_queue_xfr(bdc, status_req);
+
+ return 0;
+}
+
+/* Queue xfr on ep0 */
+static int ep0_queue(struct bdc_ep *ep, struct bdc_req *req)
+{
+ struct bdc *bdc;
+ int ret;
+
+ bdc = ep->bdc;
+ dev_dbg(bdc->dev, "%s()\n", __func__);
+ req->usb_req.actual = 0;
+ req->usb_req.status = -EINPROGRESS;
+ req->epnum = ep->ep_num;
+
+ if (bdc->delayed_status) {
+ bdc->delayed_status = false;
+ /* if status stage was delayed? */
+ if (bdc->ep0_state == WAIT_FOR_STATUS_START) {
+ /* Queue a status stage BD */
+ ep0_queue_status_stage(bdc);
+ bdc->ep0_state = WAIT_FOR_STATUS_XMIT;
+ return 0;
+ }
+ } else {
+ /*
+ * if delayed status is false and 0 length transfer is requested
+ * i.e. for status stage of some setup request, then just
+ * return from here the status stage is queued independently
+ */
+ if (req->usb_req.length == 0)
+ return 0;
+
+ }
+ ret = usb_gadget_map_request(&bdc->gadget, &req->usb_req, ep->dir);
+ if (ret) {
+ dev_err(bdc->dev, "dma mapping failed %s\n", ep->name);
+ return ret;
+ }
+
+ return bdc_queue_xfr(bdc, req);
+}
+
+/* Queue data stage */
+static int ep0_queue_data_stage(struct bdc *bdc)
+{
+ struct usb_request *ep0_usb_req;
+ struct bdc_ep *ep;
+
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ ep0_usb_req = &bdc->ep0_req.usb_req;
+ ep = bdc->bdc_ep_array[1];
+ bdc->ep0_req.ep = ep;
+ bdc->ep0_req.usb_req.complete = NULL;
+
+ return ep0_queue(ep, &bdc->ep0_req);
+}
+
+/* Queue req on ep */
+static int ep_queue(struct bdc_ep *ep, struct bdc_req *req)
+{
+ struct bdc *bdc;
+ int ret = 0;
+
+ bdc = ep->bdc;
+ if (!req || !ep || !ep->usb_ep.desc)
+ return -EINVAL;
+
+ req->usb_req.actual = 0;
+ req->usb_req.status = -EINPROGRESS;
+ req->epnum = ep->ep_num;
+
+ ret = usb_gadget_map_request(&bdc->gadget, &req->usb_req, ep->dir);
+ if (ret) {
+ dev_err(bdc->dev, "dma mapping failed\n");
+ return ret;
+ }
+
+ return bdc_queue_xfr(bdc, req);
+}
+
+/* Dequeue a request from ep */
+static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req)
+{
+ int start_bdi, end_bdi, tbi, eqp_bdi, curr_hw_dqpi;
+ bool start_pending, end_pending;
+ bool first_remove = false;
+ struct bdc_req *first_req;
+ struct bdc_bd *bd_start;
+ struct bd_table *table;
+ dma_addr_t next_bd_dma;
+ u64 deq_ptr_64 = 0;
+ struct bdc *bdc;
+ u32 tmp_32;
+ int ret;
+
+ bdc = ep->bdc;
+ start_pending = end_pending = false;
+ eqp_bdi = ep->bd_list.eqp_bdi - 1;
+
+ if (eqp_bdi < 0)
+ eqp_bdi = ep->bd_list.max_bdi;
+
+ start_bdi = req->bd_xfr.start_bdi;
+ end_bdi = find_end_bdi(ep, req->bd_xfr.next_hwd_bdi);
+
+ dev_dbg(bdc->dev, "%s ep:%s start:%d end:%d\n",
+ __func__, ep->name, start_bdi, end_bdi);
+ dev_dbg(bdc->dev, "ep_dequeue ep=%p ep->desc=%p\n",
+ ep, (void *)ep->usb_ep.desc);
+ /* Stop the ep to see where the HW is ? */
+ ret = bdc_stop_ep(bdc, ep->ep_num);
+ /* if there is an issue with stopping ep, then no need to go further */
+ if (ret)
+ return 0;
+
+ /*
+ * After endpoint is stopped, there can be 3 cases, the request
+ * is processed, pending or in the middle of processing
+ */
+
+ /* The current hw dequeue pointer */
+ tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(0));
+ deq_ptr_64 = tmp_32;
+ tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(1));
+ deq_ptr_64 |= ((u64)tmp_32 << 32);
+
+ /* we have the dma addr of next bd that will be fetched by hardware */
+ curr_hw_dqpi = bd_add_to_bdi(ep, deq_ptr_64);
+ if (curr_hw_dqpi < 0)
+ return curr_hw_dqpi;
+
+ /*
+ * curr_hw_dqpi points to actual dqp of HW and HW owns bd's from
+ * curr_hw_dqbdi..eqp_bdi.
+ */
+
+ /* Check if start_bdi and end_bdi are in range of HW owned BD's */
+ if (curr_hw_dqpi > eqp_bdi) {
+ /* there is a wrap from last to 0 */
+ if (start_bdi >= curr_hw_dqpi || start_bdi <= eqp_bdi) {
+ start_pending = true;
+ end_pending = true;
+ } else if (end_bdi >= curr_hw_dqpi || end_bdi <= eqp_bdi) {
+ end_pending = true;
+ }
+ } else {
+ if (start_bdi >= curr_hw_dqpi) {
+ start_pending = true;
+ end_pending = true;
+ } else if (end_bdi >= curr_hw_dqpi) {
+ end_pending = true;
+ }
+ }
+ dev_dbg(bdc->dev,
+ "start_pending:%d end_pending:%d speed:%d\n",
+ start_pending, end_pending, bdc->gadget.speed);
+
+ /* If both start till end are processes, we cannot deq req */
+ if (!start_pending && !end_pending)
+ return -EINVAL;
+
+ /*
+ * if ep_dequeue is called after disconnect then just return
+ * success from here
+ */
+ if (bdc->gadget.speed == USB_SPEED_UNKNOWN)
+ return 0;
+ tbi = bdi_to_tbi(ep, req->bd_xfr.next_hwd_bdi);
+ table = ep->bd_list.bd_table_array[tbi];
+ next_bd_dma = table->dma +
+ sizeof(struct bdc_bd)*(req->bd_xfr.next_hwd_bdi -
+ tbi * ep->bd_list.num_bds_table);
+
+ first_req = list_first_entry(&ep->queue, struct bdc_req,
+ queue);
+
+ if (req == first_req)
+ first_remove = true;
+
+ /*
+ * Due to HW limitation we need to bypadd chain bd's and issue ep_bla,
+ * incase if start is pending this is the first request in the list
+ * then issue ep_bla instead of marking as chain bd
+ */
+ if (start_pending && !first_remove) {
+ /*
+ * Mark the start bd as Chain bd, and point the chain
+ * bd to next_bd_dma
+ */
+ bd_start = bdi_to_bd(ep, start_bdi);
+ bd_start->offset[0] = cpu_to_le32(lower_32_bits(next_bd_dma));
+ bd_start->offset[1] = cpu_to_le32(upper_32_bits(next_bd_dma));
+ bd_start->offset[2] = 0x0;
+ bd_start->offset[3] = cpu_to_le32(MARK_CHAIN_BD);
+ bdc_dbg_bd_list(bdc, ep);
+ } else if (end_pending) {
+ /*
+ * The transfer is stopped in the middle, move the
+ * HW deq pointer to next_bd_dma
+ */
+ ret = bdc_ep_bla(bdc, ep, next_bd_dma);
+ if (ret) {
+ dev_err(bdc->dev, "error in ep_bla:%d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* Halt/Clear the ep based on value */
+static int ep_set_halt(struct bdc_ep *ep, u32 value)
+{
+ struct bdc *bdc;
+ int ret;
+
+ bdc = ep->bdc;
+ dev_dbg(bdc->dev, "%s ep:%s value=%d\n", __func__, ep->name, value);
+
+ if (value) {
+ dev_dbg(bdc->dev, "Halt\n");
+ if (ep->ep_num == 1)
+ bdc->ep0_state = WAIT_FOR_SETUP;
+
+ ret = bdc_ep_set_stall(bdc, ep->ep_num);
+ if (ret)
+ dev_err(bdc->dev, "failed to %s STALL on %s\n",
+ value ? "set" : "clear", ep->name);
+ else
+ ep->flags |= BDC_EP_STALL;
+ } else {
+ /* Clear */
+ dev_dbg(bdc->dev, "Before Clear\n");
+ ret = bdc_ep_clear_stall(bdc, ep->ep_num);
+ if (ret)
+ dev_err(bdc->dev, "failed to %s STALL on %s\n",
+ value ? "set" : "clear", ep->name);
+ else
+ ep->flags &= ~BDC_EP_STALL;
+ dev_dbg(bdc->dev, "After Clear\n");
+ }
+
+ return ret;
+}
+
+/* Free all the ep */
+void bdc_free_ep(struct bdc *bdc)
+{
+ struct bdc_ep *ep;
+ u8 epnum;
+
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ for (epnum = 1; epnum < bdc->num_eps; epnum++) {
+ ep = bdc->bdc_ep_array[epnum];
+ if (!ep)
+ continue;
+
+ if (ep->flags & BDC_EP_ENABLED)
+ ep_bd_list_free(ep, ep->bd_list.num_tabs);
+
+ /* ep0 is not in this gadget list */
+ if (epnum != 1)
+ list_del(&ep->usb_ep.ep_list);
+
+ kfree(ep);
+ }
+}
+
+/* USB2 spec, section 7.1.20 */
+static int bdc_set_test_mode(struct bdc *bdc)
+{
+ u32 usb2_pm;
+
+ usb2_pm = bdc_readl(bdc->regs, BDC_USPPM2);
+ usb2_pm &= ~BDC_PTC_MASK;
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ switch (bdc->test_mode) {
+ case TEST_J:
+ case TEST_K:
+ case TEST_SE0_NAK:
+ case TEST_PACKET:
+ case TEST_FORCE_EN:
+ usb2_pm |= bdc->test_mode << 28;
+ break;
+ default:
+ return -EINVAL;
+ }
+ dev_dbg(bdc->dev, "usb2_pm=%08x", usb2_pm);
+ bdc_writel(bdc->regs, BDC_USPPM2, usb2_pm);
+
+ return 0;
+}
+
+/*
+ * Helper function to handle Transfer status report with status as either
+ * success or short
+ */
+static void handle_xsr_succ_status(struct bdc *bdc, struct bdc_ep *ep,
+ struct bdc_sr *sreport)
+{
+ int short_bdi, start_bdi, end_bdi, max_len_bds, chain_bds;
+ struct bd_list *bd_list = &ep->bd_list;
+ int actual_length, length_short;
+ struct bd_transfer *bd_xfr;
+ struct bdc_bd *short_bd;
+ struct bdc_req *req;
+ u64 deq_ptr_64 = 0;
+ int status = 0;
+ int sr_status;
+ u32 tmp_32;
+
+ dev_dbg(bdc->dev, "%s ep:%p\n", __func__, ep);
+ bdc_dbg_srr(bdc, 0);
+ /* do not process thie sr if ignore flag is set */
+ if (ep->ignore_next_sr) {
+ ep->ignore_next_sr = false;
+ return;
+ }
+
+ if (unlikely(list_empty(&ep->queue))) {
+ dev_warn(bdc->dev, "xfr srr with no BD's queued\n");
+ return;
+ }
+ req = list_entry(ep->queue.next, struct bdc_req,
+ queue);
+
+ bd_xfr = &req->bd_xfr;
+ sr_status = XSF_STS(le32_to_cpu(sreport->offset[3]));
+
+ /*
+ * sr_status is short and this transfer has more than 1 bd then it needs
+ * special handling, this is only applicable for bulk and ctrl
+ */
+ if (sr_status == XSF_SHORT && bd_xfr->num_bds > 1) {
+ /*
+ * This is multi bd xfr, lets see which bd
+ * caused short transfer and how many bytes have been
+ * transferred so far.
+ */
+ tmp_32 = le32_to_cpu(sreport->offset[0]);
+ deq_ptr_64 = tmp_32;
+ tmp_32 = le32_to_cpu(sreport->offset[1]);
+ deq_ptr_64 |= ((u64)tmp_32 << 32);
+ short_bdi = bd_add_to_bdi(ep, deq_ptr_64);
+ if (unlikely(short_bdi < 0))
+ dev_warn(bdc->dev, "bd doesn't exist?\n");
+
+ start_bdi = bd_xfr->start_bdi;
+ /*
+ * We know the start_bdi and short_bdi, how many xfr
+ * bds in between
+ */
+ if (start_bdi <= short_bdi) {
+ max_len_bds = short_bdi - start_bdi;
+ if (max_len_bds <= bd_list->num_bds_table) {
+ if (!(bdi_to_tbi(ep, start_bdi) ==
+ bdi_to_tbi(ep, short_bdi)))
+ max_len_bds--;
+ } else {
+ chain_bds = max_len_bds/bd_list->num_bds_table;
+ max_len_bds -= chain_bds;
+ }
+ } else {
+ /* there is a wrap in the ring within a xfr */
+ chain_bds = (bd_list->max_bdi - start_bdi)/
+ bd_list->num_bds_table;
+ chain_bds += short_bdi/bd_list->num_bds_table;
+ max_len_bds = bd_list->max_bdi - start_bdi;
+ max_len_bds += short_bdi;
+ max_len_bds -= chain_bds;
+ }
+ /* max_len_bds is the number of full length bds */
+ end_bdi = find_end_bdi(ep, bd_xfr->next_hwd_bdi);
+ if (!(end_bdi == short_bdi))
+ ep->ignore_next_sr = true;
+
+ actual_length = max_len_bds * BD_MAX_BUFF_SIZE;
+ short_bd = bdi_to_bd(ep, short_bdi);
+ /* length queued */
+ length_short = le32_to_cpu(short_bd->offset[2]) & 0x1FFFFF;
+ /* actual length trensfered */
+ length_short -= SR_BD_LEN(le32_to_cpu(sreport->offset[2]));
+ actual_length += length_short;
+ req->usb_req.actual = actual_length;
+ } else {
+ req->usb_req.actual = req->usb_req.length -
+ SR_BD_LEN(le32_to_cpu(sreport->offset[2]));
+ dev_dbg(bdc->dev,
+ "len=%d actual=%d bd_xfr->next_hwd_bdi:%d\n",
+ req->usb_req.length, req->usb_req.actual,
+ bd_xfr->next_hwd_bdi);
+ }
+
+ /* Update the dequeue pointer */
+ ep->bd_list.hwd_bdi = bd_xfr->next_hwd_bdi;
+ if (req->usb_req.actual < req->usb_req.length) {
+ dev_dbg(bdc->dev, "short xfr on %d\n", ep->ep_num);
+ if (req->usb_req.short_not_ok)
+ status = -EREMOTEIO;
+ }
+ bdc_req_complete(ep, bd_xfr->req, status);
+}
+
+/* EP0 setup related packet handlers */
+
+/*
+ * Setup packet received, just store the packet and process on next DS or SS
+ * started SR
+ */
+void bdc_xsf_ep0_setup_recv(struct bdc *bdc, struct bdc_sr *sreport)
+{
+ struct usb_ctrlrequest *setup_pkt;
+ u32 len;
+
+ dev_dbg(bdc->dev,
+ "%s ep0_state:%s\n",
+ __func__, ep0_state_string[bdc->ep0_state]);
+ /* Store received setup packet */
+ setup_pkt = &bdc->setup_pkt;
+ memcpy(setup_pkt, &sreport->offset[0], sizeof(*setup_pkt));
+ len = le16_to_cpu(setup_pkt->wLength);
+ if (!len)
+ bdc->ep0_state = WAIT_FOR_STATUS_START;
+ else
+ bdc->ep0_state = WAIT_FOR_DATA_START;
+
+
+ dev_dbg(bdc->dev,
+ "%s exit ep0_state:%s\n",
+ __func__, ep0_state_string[bdc->ep0_state]);
+}
+
+/* Stall ep0 */
+static void ep0_stall(struct bdc *bdc)
+{
+ struct bdc_ep *ep = bdc->bdc_ep_array[1];
+ struct bdc_req *req;
+
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ bdc->delayed_status = false;
+ ep_set_halt(ep, 1);
+
+ /* de-queue any pendig requests */
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct bdc_req,
+ queue);
+ bdc_req_complete(ep, req, -ESHUTDOWN);
+ }
+}
+
+/* SET_ADD handlers */
+static int ep0_set_address(struct bdc *bdc, struct usb_ctrlrequest *ctrl)
+{
+ enum usb_device_state state = bdc->gadget.state;
+ int ret = 0;
+ u32 addr;
+
+ addr = le16_to_cpu(ctrl->wValue);
+ dev_dbg(bdc->dev,
+ "%s addr:%d dev state:%d\n",
+ __func__, addr, state);
+
+ if (addr > 127)
+ return -EINVAL;
+
+ switch (state) {
+ case USB_STATE_DEFAULT:
+ case USB_STATE_ADDRESS:
+ /* Issue Address device command */
+ ret = bdc_address_device(bdc, addr);
+ if (ret)
+ return ret;
+
+ if (addr)
+ usb_gadget_set_state(&bdc->gadget, USB_STATE_ADDRESS);
+ else
+ usb_gadget_set_state(&bdc->gadget, USB_STATE_DEFAULT);
+
+ bdc->dev_addr = addr;
+ break;
+ default:
+ dev_warn(bdc->dev,
+ "SET Address in wrong device state %d\n",
+ state);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/* Handler for SET/CLEAR FEATURE requests for device */
+static int ep0_handle_feature_dev(struct bdc *bdc, u16 wValue,
+ u16 wIndex, bool set)
+{
+ enum usb_device_state state = bdc->gadget.state;
+ u32 usppms = 0;
+
+ dev_dbg(bdc->dev, "%s set:%d dev state:%d\n",
+ __func__, set, state);
+ switch (wValue) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ dev_dbg(bdc->dev, "USB_DEVICE_REMOTE_WAKEUP\n");
+ if (set)
+ bdc->devstatus |= REMOTE_WAKE_ENABLE;
+ else
+ bdc->devstatus &= ~REMOTE_WAKE_ENABLE;
+ break;
+
+ case USB_DEVICE_TEST_MODE:
+ dev_dbg(bdc->dev, "USB_DEVICE_TEST_MODE\n");
+ if ((wIndex & 0xFF) ||
+ (bdc->gadget.speed != USB_SPEED_HIGH) || !set)
+ return -EINVAL;
+
+ bdc->test_mode = wIndex >> 8;
+ break;
+
+ case USB_DEVICE_U1_ENABLE:
+ dev_dbg(bdc->dev, "USB_DEVICE_U1_ENABLE\n");
+
+ if (bdc->gadget.speed != USB_SPEED_SUPER ||
+ state != USB_STATE_CONFIGURED)
+ return -EINVAL;
+
+ usppms = bdc_readl(bdc->regs, BDC_USPPMS);
+ if (set) {
+ /* clear previous u1t */
+ usppms &= ~BDC_U1T(BDC_U1T_MASK);
+ usppms |= BDC_U1T(U1_TIMEOUT);
+ usppms |= BDC_U1E | BDC_PORT_W1S;
+ bdc->devstatus |= (1 << USB_DEV_STAT_U1_ENABLED);
+ } else {
+ usppms &= ~BDC_U1E;
+ usppms |= BDC_PORT_W1S;
+ bdc->devstatus &= ~(1 << USB_DEV_STAT_U1_ENABLED);
+ }
+ bdc_writel(bdc->regs, BDC_USPPMS, usppms);
+ break;
+
+ case USB_DEVICE_U2_ENABLE:
+ dev_dbg(bdc->dev, "USB_DEVICE_U2_ENABLE\n");
+
+ if (bdc->gadget.speed != USB_SPEED_SUPER ||
+ state != USB_STATE_CONFIGURED)
+ return -EINVAL;
+
+ usppms = bdc_readl(bdc->regs, BDC_USPPMS);
+ if (set) {
+ usppms |= BDC_U2E;
+ usppms |= BDC_U2A;
+ bdc->devstatus |= (1 << USB_DEV_STAT_U2_ENABLED);
+ } else {
+ usppms &= ~BDC_U2E;
+ usppms &= ~BDC_U2A;
+ bdc->devstatus &= ~(1 << USB_DEV_STAT_U2_ENABLED);
+ }
+ bdc_writel(bdc->regs, BDC_USPPMS, usppms);
+ break;
+
+ case USB_DEVICE_LTM_ENABLE:
+ dev_dbg(bdc->dev, "USB_DEVICE_LTM_ENABLE?\n");
+ if (bdc->gadget.speed != USB_SPEED_SUPER ||
+ state != USB_STATE_CONFIGURED)
+ return -EINVAL;
+ break;
+ default:
+ dev_err(bdc->dev, "Unknown wValue:%d\n", wValue);
+ return -EOPNOTSUPP;
+ } /* USB_RECIP_DEVICE end */
+
+ return 0;
+}
+
+/* SET/CLEAR FEATURE handler */
+static int ep0_handle_feature(struct bdc *bdc,
+ struct usb_ctrlrequest *setup_pkt, bool set)
+{
+ enum usb_device_state state = bdc->gadget.state;
+ struct bdc_ep *ep;
+ u16 wValue;
+ u16 wIndex;
+ int epnum;
+
+ wValue = le16_to_cpu(setup_pkt->wValue);
+ wIndex = le16_to_cpu(setup_pkt->wIndex);
+
+ dev_dbg(bdc->dev,
+ "%s wValue=%d wIndex=%d devstate=%08x speed=%d set=%d",
+ __func__, wValue, wIndex, state,
+ bdc->gadget.speed, set);
+
+ switch (setup_pkt->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ return ep0_handle_feature_dev(bdc, wValue, wIndex, set);
+ case USB_RECIP_INTERFACE:
+ dev_dbg(bdc->dev, "USB_RECIP_INTERFACE\n");
+ /* USB3 spec, sec 9.4.9 */
+ if (wValue != USB_INTRF_FUNC_SUSPEND)
+ return -EINVAL;
+ /* USB3 spec, Table 9-8 */
+ if (set) {
+ if (wIndex & USB_INTRF_FUNC_SUSPEND_RW) {
+ dev_dbg(bdc->dev, "SET REMOTE_WAKEUP\n");
+ bdc->devstatus |= REMOTE_WAKE_ENABLE;
+ } else {
+ dev_dbg(bdc->dev, "CLEAR REMOTE_WAKEUP\n");
+ bdc->devstatus &= ~REMOTE_WAKE_ENABLE;
+ }
+ }
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ dev_dbg(bdc->dev, "USB_RECIP_ENDPOINT\n");
+ if (wValue != USB_ENDPOINT_HALT)
+ return -EINVAL;
+
+ epnum = wIndex & USB_ENDPOINT_NUMBER_MASK;
+ if (epnum) {
+ if ((wIndex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+ epnum = epnum * 2 + 1;
+ else
+ epnum *= 2;
+ } else {
+ epnum = 1; /*EP0*/
+ }
+ /*
+ * If CLEAR_FEATURE on ep0 then don't do anything as the stall
+ * condition on ep0 has already been cleared when SETUP packet
+ * was received.
+ */
+ if (epnum == 1 && !set) {
+ dev_dbg(bdc->dev, "ep0 stall already cleared\n");
+ return 0;
+ }
+ dev_dbg(bdc->dev, "epnum=%d\n", epnum);
+ ep = bdc->bdc_ep_array[epnum];
+ if (!ep)
+ return -EINVAL;
+
+ return ep_set_halt(ep, set);
+ default:
+ dev_err(bdc->dev, "Unknown recipient\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* GET_STATUS request handler */
+static int ep0_handle_status(struct bdc *bdc,
+ struct usb_ctrlrequest *setup_pkt)
+{
+ enum usb_device_state state = bdc->gadget.state;
+ struct bdc_ep *ep;
+ u16 usb_status = 0;
+ u32 epnum;
+ u16 wIndex;
+
+ /* USB2.0 spec sec 9.4.5 */
+ if (state == USB_STATE_DEFAULT)
+ return -EINVAL;
+ wIndex = le16_to_cpu(setup_pkt->wIndex);
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ usb_status = bdc->devstatus;
+ switch (setup_pkt->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ dev_dbg(bdc->dev,
+ "USB_RECIP_DEVICE devstatus:%08x\n",
+ bdc->devstatus);
+ /* USB3 spec, sec 9.4.5 */
+ if (bdc->gadget.speed == USB_SPEED_SUPER)
+ usb_status &= ~REMOTE_WAKE_ENABLE;
+ break;
+
+ case USB_RECIP_INTERFACE:
+ dev_dbg(bdc->dev, "USB_RECIP_INTERFACE\n");
+ if (bdc->gadget.speed == USB_SPEED_SUPER) {
+ /*
+ * This should come from func for Func remote wkup
+ * usb_status |=1;
+ */
+ if (bdc->devstatus & REMOTE_WAKE_ENABLE)
+ usb_status |= REMOTE_WAKE_ENABLE;
+ } else {
+ usb_status = 0;
+ }
+
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ dev_dbg(bdc->dev, "USB_RECIP_ENDPOINT\n");
+ epnum = wIndex & USB_ENDPOINT_NUMBER_MASK;
+ if (epnum) {
+ if ((wIndex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+ epnum = epnum*2 + 1;
+ else
+ epnum *= 2;
+ } else {
+ epnum = 1; /* EP0 */
+ }
+
+ ep = bdc->bdc_ep_array[epnum];
+ if (!ep) {
+ dev_err(bdc->dev, "ISSUE, GET_STATUS for invalid EP ?");
+ return -EINVAL;
+ }
+ if (ep->flags & BDC_EP_STALL)
+ usb_status |= 1 << USB_ENDPOINT_HALT;
+
+ break;
+ default:
+ dev_err(bdc->dev, "Unknown recipient for get_status\n");
+ return -EINVAL;
+ }
+ /* prepare a data stage for GET_STATUS */
+ dev_dbg(bdc->dev, "usb_status=%08x\n", usb_status);
+ *(__le16 *)bdc->ep0_response_buff = cpu_to_le16(usb_status);
+ bdc->ep0_req.usb_req.length = 2;
+ bdc->ep0_req.usb_req.buf = &bdc->ep0_response_buff;
+ ep0_queue_data_stage(bdc);
+
+ return 0;
+}
+
+static void ep0_set_sel_cmpl(struct usb_ep *_ep, struct usb_request *_req)
+{
+ /* ep0_set_sel_cmpl */
+}
+
+/* Queue data stage to handle 6 byte SET_SEL request */
+static int ep0_set_sel(struct bdc *bdc,
+ struct usb_ctrlrequest *setup_pkt)
+{
+ struct bdc_ep *ep;
+ u16 wLength;
+ u16 wValue;
+
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ wValue = le16_to_cpu(setup_pkt->wValue);
+ wLength = le16_to_cpu(setup_pkt->wLength);
+ if (unlikely(wLength != 6)) {
+ dev_err(bdc->dev, "%s Wrong wLength:%d\n", __func__, wLength);
+ return -EINVAL;
+ }
+ ep = bdc->bdc_ep_array[1];
+ bdc->ep0_req.ep = ep;
+ bdc->ep0_req.usb_req.length = 6;
+ bdc->ep0_req.usb_req.buf = bdc->ep0_response_buff;
+ bdc->ep0_req.usb_req.complete = ep0_set_sel_cmpl;
+ ep0_queue_data_stage(bdc);
+
+ return 0;
+}
+
+/*
+ * Queue a 0 byte bd only if wLength is more than the length and and length is
+ * a multiple of MaxPacket then queue 0 byte BD
+ */
+static int ep0_queue_zlp(struct bdc *bdc)
+{
+ int ret;
+
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ bdc->ep0_req.ep = bdc->bdc_ep_array[1];
+ bdc->ep0_req.usb_req.length = 0;
+ bdc->ep0_req.usb_req.complete = NULL;
+ bdc->ep0_state = WAIT_FOR_DATA_START;
+ ret = bdc_queue_xfr(bdc, &bdc->ep0_req);
+ if (ret) {
+ dev_err(bdc->dev, "err queueing zlp :%d\n", ret);
+ return ret;
+ }
+ bdc->ep0_state = WAIT_FOR_DATA_XMIT;
+
+ return 0;
+}
+
+/* Control request handler */
+static int handle_control_request(struct bdc *bdc)
+{
+ enum usb_device_state state = bdc->gadget.state;
+ struct usb_ctrlrequest *setup_pkt;
+ int delegate_setup = 0;
+ int ret = 0;
+ int config = 0;
+
+ setup_pkt = &bdc->setup_pkt;
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ if ((setup_pkt->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+ switch (setup_pkt->bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ dev_dbg(bdc->dev, "USB_REQ_SET_ADDRESS\n");
+ ret = ep0_set_address(bdc, setup_pkt);
+ bdc->devstatus &= DEVSTATUS_CLEAR;
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ dev_dbg(bdc->dev, "USB_REQ_SET_CONFIGURATION\n");
+ if (state == USB_STATE_ADDRESS) {
+ usb_gadget_set_state(&bdc->gadget,
+ USB_STATE_CONFIGURED);
+ } else if (state == USB_STATE_CONFIGURED) {
+ /*
+ * USB2 spec sec 9.4.7, if wValue is 0 then dev
+ * is moved to addressed state
+ */
+ config = le16_to_cpu(setup_pkt->wValue);
+ if (!config)
+ usb_gadget_set_state(
+ &bdc->gadget,
+ USB_STATE_ADDRESS);
+ }
+ delegate_setup = 1;
+ break;
+
+ case USB_REQ_SET_FEATURE:
+ dev_dbg(bdc->dev, "USB_REQ_SET_FEATURE\n");
+ ret = ep0_handle_feature(bdc, setup_pkt, 1);
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+ dev_dbg(bdc->dev, "USB_REQ_CLEAR_FEATURE\n");
+ ret = ep0_handle_feature(bdc, setup_pkt, 0);
+ break;
+
+ case USB_REQ_GET_STATUS:
+ dev_dbg(bdc->dev, "USB_REQ_GET_STATUS\n");
+ ret = ep0_handle_status(bdc, setup_pkt);
+ break;
+
+ case USB_REQ_SET_SEL:
+ dev_dbg(bdc->dev, "USB_REQ_SET_SEL\n");
+ ret = ep0_set_sel(bdc, setup_pkt);
+ break;
+
+ case USB_REQ_SET_ISOCH_DELAY:
+ dev_warn(bdc->dev,
+ "USB_REQ_SET_ISOCH_DELAY not handled\n");
+ ret = 0;
+ break;
+ default:
+ delegate_setup = 1;
+ }
+ } else {
+ delegate_setup = 1;
+ }
+
+ if (delegate_setup) {
+ spin_unlock(&bdc->lock);
+ ret = bdc->gadget_driver->setup(&bdc->gadget, setup_pkt);
+ spin_lock(&bdc->lock);
+ }
+
+ return ret;
+}
+
+/* EP0: Data stage started */
+void bdc_xsf_ep0_data_start(struct bdc *bdc, struct bdc_sr *sreport)
+{
+ struct bdc_ep *ep;
+ int ret = 0;
+
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ ep = bdc->bdc_ep_array[1];
+ /* If ep0 was stalled, the clear it first */
+ if (ep->flags & BDC_EP_STALL) {
+ ret = ep_set_halt(ep, 0);
+ if (ret)
+ goto err;
+ }
+ if (bdc->ep0_state != WAIT_FOR_DATA_START)
+ dev_warn(bdc->dev,
+ "Data stage not expected ep0_state:%s\n",
+ ep0_state_string[bdc->ep0_state]);
+
+ ret = handle_control_request(bdc);
+ if (ret == USB_GADGET_DELAYED_STATUS) {
+ /*
+ * The ep0 state will remain WAIT_FOR_DATA_START till
+ * we received ep_queue on ep0
+ */
+ bdc->delayed_status = true;
+ return;
+ }
+ if (!ret) {
+ bdc->ep0_state = WAIT_FOR_DATA_XMIT;
+ dev_dbg(bdc->dev,
+ "ep0_state:%s", ep0_state_string[bdc->ep0_state]);
+ return;
+ }
+err:
+ ep0_stall(bdc);
+}
+
+/* EP0: status stage started */
+void bdc_xsf_ep0_status_start(struct bdc *bdc, struct bdc_sr *sreport)
+{
+ struct usb_ctrlrequest *setup_pkt;
+ struct bdc_ep *ep;
+ int ret = 0;
+
+ dev_dbg(bdc->dev,
+ "%s ep0_state:%s",
+ __func__, ep0_state_string[bdc->ep0_state]);
+ ep = bdc->bdc_ep_array[1];
+
+ /* check if ZLP was queued? */
+ if (bdc->zlp_needed)
+ bdc->zlp_needed = false;
+
+ if (ep->flags & BDC_EP_STALL) {
+ ret = ep_set_halt(ep, 0);
+ if (ret)
+ goto err;
+ }
+
+ if ((bdc->ep0_state != WAIT_FOR_STATUS_START) &&
+ (bdc->ep0_state != WAIT_FOR_DATA_XMIT))
+ dev_err(bdc->dev,
+ "Status stage recv but ep0_state:%s\n",
+ ep0_state_string[bdc->ep0_state]);
+
+ /* check if data stage is in progress ? */
+ if (bdc->ep0_state == WAIT_FOR_DATA_XMIT) {
+ bdc->ep0_state = STATUS_PENDING;
+ /* Status stage will be queued upon Data stage transmit event */
+ dev_dbg(bdc->dev,
+ "status started but data not transmitted yet\n");
+ return;
+ }
+ setup_pkt = &bdc->setup_pkt;
+
+ /*
+ * 2 stage setup then only process the setup, for 3 stage setup the date
+ * stage is already handled
+ */
+ if (!le16_to_cpu(setup_pkt->wLength)) {
+ ret = handle_control_request(bdc);
+ if (ret == USB_GADGET_DELAYED_STATUS) {
+ bdc->delayed_status = true;
+ /* ep0_state will remain WAIT_FOR_STATUS_START */
+ return;
+ }
+ }
+ if (!ret) {
+ /* Queue a status stage BD */
+ ep0_queue_status_stage(bdc);
+ bdc->ep0_state = WAIT_FOR_STATUS_XMIT;
+ dev_dbg(bdc->dev,
+ "ep0_state:%s", ep0_state_string[bdc->ep0_state]);
+ return;
+ }
+err:
+ ep0_stall(bdc);
+}
+
+/* Helper function to update ep0 upon SR with xsf_succ or xsf_short */
+static void ep0_xsf_complete(struct bdc *bdc, struct bdc_sr *sreport)
+{
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ switch (bdc->ep0_state) {
+ case WAIT_FOR_DATA_XMIT:
+ bdc->ep0_state = WAIT_FOR_STATUS_START;
+ break;
+ case WAIT_FOR_STATUS_XMIT:
+ bdc->ep0_state = WAIT_FOR_SETUP;
+ if (bdc->test_mode) {
+ int ret;
+
+ dev_dbg(bdc->dev, "test_mode:%d\n", bdc->test_mode);
+ ret = bdc_set_test_mode(bdc);
+ if (ret < 0) {
+ dev_err(bdc->dev, "Err in setting Test mode\n");
+ return;
+ }
+ bdc->test_mode = 0;
+ }
+ break;
+ case STATUS_PENDING:
+ bdc_xsf_ep0_status_start(bdc, sreport);
+ break;
+
+ default:
+ dev_err(bdc->dev,
+ "Unknown ep0_state:%s\n",
+ ep0_state_string[bdc->ep0_state]);
+
+ }
+}
+
+/* xfr completion status report handler */
+void bdc_sr_xsf(struct bdc *bdc, struct bdc_sr *sreport)
+{
+ struct bdc_ep *ep;
+ u32 sr_status;
+ u8 ep_num;
+
+ ep_num = (le32_to_cpu(sreport->offset[3])>>4) & 0x1f;
+ ep = bdc->bdc_ep_array[ep_num];
+ if (!ep || !(ep->flags & BDC_EP_ENABLED)) {
+ dev_err(bdc->dev, "xsf for ep not enabled\n");
+ return;
+ }
+ /*
+ * check if this transfer is after link went from U3->U0 due
+ * to remote wakeup
+ */
+ if (bdc->devstatus & FUNC_WAKE_ISSUED) {
+ bdc->devstatus &= ~(FUNC_WAKE_ISSUED);
+ dev_dbg(bdc->dev, "%s clearing FUNC_WAKE_ISSUED flag\n",
+ __func__);
+ }
+ sr_status = XSF_STS(le32_to_cpu(sreport->offset[3]));
+ dev_dbg_ratelimited(bdc->dev, "%s sr_status=%d ep:%s\n",
+ __func__, sr_status, ep->name);
+
+ switch (sr_status) {
+ case XSF_SUCC:
+ case XSF_SHORT:
+ handle_xsr_succ_status(bdc, ep, sreport);
+ if (ep_num == 1)
+ ep0_xsf_complete(bdc, sreport);
+ break;
+
+ case XSF_SETUP_RECV:
+ case XSF_DATA_START:
+ case XSF_STATUS_START:
+ if (ep_num != 1) {
+ dev_err(bdc->dev,
+ "ep0 related packets on non ep0 endpoint");
+ return;
+ }
+ bdc->sr_xsf_ep0[sr_status - XSF_SETUP_RECV](bdc, sreport);
+ break;
+
+ case XSF_BABB:
+ if (ep_num == 1) {
+ dev_dbg(bdc->dev, "Babble on ep0 zlp_need:%d\n",
+ bdc->zlp_needed);
+ /*
+ * If the last completed transfer had wLength >Data Len,
+ * and Len is multiple of MaxPacket,then queue ZLP
+ */
+ if (bdc->zlp_needed) {
+ /* queue 0 length bd */
+ ep0_queue_zlp(bdc);
+ return;
+ }
+ }
+ dev_warn(bdc->dev, "Babble on ep not handled\n");
+ break;
+ default:
+ dev_warn(bdc->dev, "sr status not handled:%x\n", sr_status);
+ break;
+ }
+}
+
+static int bdc_gadget_ep_queue(struct usb_ep *_ep,
+ struct usb_request *_req, gfp_t gfp_flags)
+{
+ struct bdc_req *req;
+ unsigned long flags;
+ struct bdc_ep *ep;
+ struct bdc *bdc;
+ int ret;
+
+ if (!_ep || !_ep->desc)
+ return -ESHUTDOWN;
+
+ if (!_req || !_req->complete || !_req->buf)
+ return -EINVAL;
+
+ ep = to_bdc_ep(_ep);
+ req = to_bdc_req(_req);
+ bdc = ep->bdc;
+ dev_dbg(bdc->dev, "%s ep:%p req:%p\n", __func__, ep, req);
+ dev_dbg(bdc->dev, "queuing request %p to %s length %d zero:%d\n",
+ _req, ep->name, _req->length, _req->zero);
+
+ if (!ep->usb_ep.desc) {
+ dev_warn(bdc->dev,
+ "trying to queue req %p to disabled %s\n",
+ _req, ep->name);
+ return -ESHUTDOWN;
+ }
+
+ if (_req->length > MAX_XFR_LEN) {
+ dev_warn(bdc->dev,
+ "req length > supported MAX:%d requested:%d\n",
+ MAX_XFR_LEN, _req->length);
+ return -EOPNOTSUPP;
+ }
+ spin_lock_irqsave(&bdc->lock, flags);
+ if (ep == bdc->bdc_ep_array[1])
+ ret = ep0_queue(ep, req);
+ else
+ ret = ep_queue(ep, req);
+
+ spin_unlock_irqrestore(&bdc->lock, flags);
+
+ return ret;
+}
+
+static int bdc_gadget_ep_dequeue(struct usb_ep *_ep,
+ struct usb_request *_req)
+{
+ struct bdc_req *req;
+ unsigned long flags;
+ struct bdc_ep *ep;
+ struct bdc *bdc;
+ int ret;
+
+ if (!_ep || !_req)
+ return -EINVAL;
+
+ ep = to_bdc_ep(_ep);
+ req = to_bdc_req(_req);
+ bdc = ep->bdc;
+ dev_dbg(bdc->dev, "%s ep:%s req:%p\n", __func__, ep->name, req);
+ bdc_dbg_bd_list(bdc, ep);
+ spin_lock_irqsave(&bdc->lock, flags);
+ /* make sure it's still queued on this endpoint */
+ list_for_each_entry(req, &ep->queue, queue) {
+ if (&req->usb_req == _req)
+ break;
+ }
+ if (&req->usb_req != _req) {
+ spin_unlock_irqrestore(&bdc->lock, flags);
+ dev_err(bdc->dev, "usb_req !=req n");
+ return -EINVAL;
+ }
+ ret = ep_dequeue(ep, req);
+ if (ret) {
+ ret = -EOPNOTSUPP;
+ goto err;
+ }
+ bdc_req_complete(ep, req, -ECONNRESET);
+
+err:
+ bdc_dbg_bd_list(bdc, ep);
+ spin_unlock_irqrestore(&bdc->lock, flags);
+
+ return ret;
+}
+
+static int bdc_gadget_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ unsigned long flags;
+ struct bdc_ep *ep;
+ struct bdc *bdc;
+ int ret;
+
+ ep = to_bdc_ep(_ep);
+ bdc = ep->bdc;
+ dev_dbg(bdc->dev, "%s ep:%s value=%d\n", __func__, ep->name, value);
+ spin_lock_irqsave(&bdc->lock, flags);
+ if (usb_endpoint_xfer_isoc(ep->usb_ep.desc))
+ ret = -EINVAL;
+ else if (!list_empty(&ep->queue))
+ ret = -EAGAIN;
+ else
+ ret = ep_set_halt(ep, value);
+
+ spin_unlock_irqrestore(&bdc->lock, flags);
+
+ return ret;
+}
+
+static struct usb_request *bdc_gadget_alloc_request(struct usb_ep *_ep,
+ gfp_t gfp_flags)
+{
+ struct bdc_req *req;
+ struct bdc_ep *ep;
+
+ req = kzalloc(sizeof(*req), gfp_flags);
+ if (!req)
+ return NULL;
+
+ ep = to_bdc_ep(_ep);
+ req->ep = ep;
+ req->epnum = ep->ep_num;
+ req->usb_req.dma = DMA_ADDR_INVALID;
+ dev_dbg(ep->bdc->dev, "%s ep:%s req:%p\n", __func__, ep->name, req);
+
+ return &req->usb_req;
+}
+
+static void bdc_gadget_free_request(struct usb_ep *_ep,
+ struct usb_request *_req)
+{
+ struct bdc_req *req;
+
+ req = to_bdc_req(_req);
+ kfree(req);
+}
+
+/* endpoint operations */
+
+/* configure endpoint and also allocate resources */
+static int bdc_gadget_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ unsigned long flags;
+ struct bdc_ep *ep;
+ struct bdc *bdc;
+ int ret;
+
+ if (!_ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
+ pr_debug("bdc_gadget_ep_enable invalid parameters\n");
+ return -EINVAL;
+ }
+
+ if (!desc->wMaxPacketSize) {
+ pr_debug("bdc_gadget_ep_enable missing wMaxPacketSize\n");
+ return -EINVAL;
+ }
+
+ ep = to_bdc_ep(_ep);
+ bdc = ep->bdc;
+
+ /* Sanity check, upper layer will not send enable for ep0 */
+ if (ep == bdc->bdc_ep_array[1])
+ return -EINVAL;
+
+ if (!bdc->gadget_driver
+ || bdc->gadget.speed == USB_SPEED_UNKNOWN) {
+ return -ESHUTDOWN;
+ }
+
+ dev_dbg(bdc->dev, "%s Enabling %s\n", __func__, ep->name);
+ spin_lock_irqsave(&bdc->lock, flags);
+ ep->desc = desc;
+ ep->comp_desc = _ep->comp_desc;
+ ret = bdc_ep_enable(ep);
+ spin_unlock_irqrestore(&bdc->lock, flags);
+
+ return ret;
+}
+
+static int bdc_gadget_ep_disable(struct usb_ep *_ep)
+{
+ unsigned long flags;
+ struct bdc_ep *ep;
+ struct bdc *bdc;
+ int ret;
+
+ if (!_ep) {
+ pr_debug("bdc: invalid parameters\n");
+ return -EINVAL;
+ }
+ ep = to_bdc_ep(_ep);
+ bdc = ep->bdc;
+
+ /* Upper layer will not call this for ep0, but do a sanity check */
+ if (ep == bdc->bdc_ep_array[1]) {
+ dev_warn(bdc->dev, "%s called for ep0\n", __func__);
+ return -EINVAL;
+ }
+ dev_dbg(bdc->dev,
+ "%s() ep:%s ep->flags:%08x\n",
+ __func__, ep->name, ep->flags);
+
+ if (!(ep->flags & BDC_EP_ENABLED)) {
+ dev_warn(bdc->dev, "%s is already disabled\n", ep->name);
+ return 0;
+ }
+ spin_lock_irqsave(&bdc->lock, flags);
+ ret = bdc_ep_disable(ep);
+ spin_unlock_irqrestore(&bdc->lock, flags);
+
+ return ret;
+}
+
+static const struct usb_ep_ops bdc_gadget_ep_ops = {
+ .enable = bdc_gadget_ep_enable,
+ .disable = bdc_gadget_ep_disable,
+ .alloc_request = bdc_gadget_alloc_request,
+ .free_request = bdc_gadget_free_request,
+ .queue = bdc_gadget_ep_queue,
+ .dequeue = bdc_gadget_ep_dequeue,
+ .set_halt = bdc_gadget_ep_set_halt
+};
+
+/* dir = 1 is IN */
+static int init_ep(struct bdc *bdc, u32 epnum, u32 dir)
+{
+ struct bdc_ep *ep;
+
+ dev_dbg(bdc->dev, "%s epnum=%d dir=%d\n", __func__, epnum, dir);
+ ep = kzalloc(sizeof(*ep), GFP_KERNEL);
+ if (!ep)
+ return -ENOMEM;
+
+ ep->bdc = bdc;
+ ep->dir = dir;
+
+ /* ep->ep_num is the index inside bdc_ep */
+ if (epnum == 1) {
+ ep->ep_num = 1;
+ bdc->bdc_ep_array[ep->ep_num] = ep;
+ snprintf(ep->name, sizeof(ep->name), "ep%d", epnum - 1);
+ usb_ep_set_maxpacket_limit(&ep->usb_ep, EP0_MAX_PKT_SIZE);
+ ep->comp_desc = NULL;
+ bdc->gadget.ep0 = &ep->usb_ep;
+ } else {
+ if (dir)
+ ep->ep_num = epnum * 2 - 1;
+ else
+ ep->ep_num = epnum * 2 - 2;
+
+ bdc->bdc_ep_array[ep->ep_num] = ep;
+ snprintf(ep->name, sizeof(ep->name), "ep%d%s", epnum - 1,
+ dir & 1 ? "in" : "out");
+
+ usb_ep_set_maxpacket_limit(&ep->usb_ep, 1024);
+ ep->usb_ep.max_streams = 0;
+ list_add_tail(&ep->usb_ep.ep_list, &bdc->gadget.ep_list);
+ }
+ ep->usb_ep.ops = &bdc_gadget_ep_ops;
+ ep->usb_ep.name = ep->name;
+ ep->flags = 0;
+ ep->ignore_next_sr = false;
+ dev_dbg(bdc->dev, "ep=%p ep->usb_ep.name=%s epnum=%d ep->epnum=%d\n",
+ ep, ep->usb_ep.name, epnum, ep->ep_num);
+
+ INIT_LIST_HEAD(&ep->queue);
+
+ return 0;
+}
+
+/* Init all ep */
+int bdc_init_ep(struct bdc *bdc)
+{
+ u8 epnum;
+ int ret;
+
+ dev_dbg(bdc->dev, "%s()\n", __func__);
+ INIT_LIST_HEAD(&bdc->gadget.ep_list);
+ /* init ep0 */
+ ret = init_ep(bdc, 1, 0);
+ if (ret) {
+ dev_err(bdc->dev, "init ep ep0 fail %d\n", ret);
+ return ret;
+ }
+
+ for (epnum = 2; epnum <= bdc->num_eps / 2; epnum++) {
+ /* OUT */
+ ret = init_ep(bdc, epnum, 0);
+ if (ret) {
+ dev_err(bdc->dev,
+ "init ep failed for:%d error: %d\n",
+ epnum, ret);
+ return ret;
+ }
+
+ /* IN */
+ ret = init_ep(bdc, epnum, 1);
+ if (ret) {
+ dev_err(bdc->dev,
+ "init ep failed for:%d error: %d\n",
+ epnum, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.h b/drivers/usb/gadget/udc/bdc/bdc_ep.h
new file mode 100644
index 000000000000..8a6b36cbf2ea
--- /dev/null
+++ b/drivers/usb/gadget/udc/bdc/bdc_ep.h
@@ -0,0 +1,22 @@
+/*
+ * bdc_ep.h - header for the BDC debug functions
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Author: Ashwini Pahuja
+ *
+ * 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.
+ *
+ */
+#ifndef __LINUX_BDC_EP_H__
+#define __LINUX_BDC_EP_H__
+
+int bdc_init_ep(struct bdc *);
+int bdc_ep_disable(struct bdc_ep *);
+int bdc_ep_enable(struct bdc_ep *);
+void bdc_free_ep(struct bdc *);
+
+#endif /* __LINUX_BDC_EP_H__ */
diff --git a/drivers/usb/gadget/udc/bdc/bdc_pci.c b/drivers/usb/gadget/udc/bdc/bdc_pci.c
new file mode 100644
index 000000000000..02968842b359
--- /dev/null
+++ b/drivers/usb/gadget/udc/bdc/bdc_pci.c
@@ -0,0 +1,132 @@
+/*
+ * bdc_pci.c - BRCM BDC USB3.0 device controller PCI interface file.
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Author: Ashwini Pahuja
+ *
+ * Based on drivers under drivers/usb/
+ *
+ * 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/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/platform_device.h>
+
+#include "bdc.h"
+
+#define BDC_PCI_PID 0x1570
+
+struct bdc_pci {
+ struct device *dev;
+ struct platform_device *bdc;
+};
+
+static int bdc_setup_msi(struct pci_dev *pci)
+{
+ int ret;
+
+ ret = pci_enable_msi(pci);
+ if (ret) {
+ pr_err("failed to allocate MSI entry\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int bdc_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
+{
+ struct resource res[2];
+ struct platform_device *bdc;
+ struct bdc_pci *glue;
+ int ret = -ENOMEM;
+
+ glue = devm_kzalloc(&pci->dev, sizeof(*glue), GFP_KERNEL);
+ if (!glue)
+ return -ENOMEM;
+
+ glue->dev = &pci->dev;
+ ret = pci_enable_device(pci);
+ if (ret) {
+ dev_err(&pci->dev, "failed to enable pci device\n");
+ return -ENODEV;
+ }
+ pci_set_master(pci);
+
+ bdc = platform_device_alloc(BRCM_BDC_NAME, PLATFORM_DEVID_AUTO);
+ if (!bdc)
+ return -ENOMEM;
+
+ memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
+ bdc_setup_msi(pci);
+
+ res[0].start = pci_resource_start(pci, 0);
+ res[0].end = pci_resource_end(pci, 0);
+ res[0].name = BRCM_BDC_NAME;
+ res[0].flags = IORESOURCE_MEM;
+
+ res[1].start = pci->irq;
+ res[1].name = BRCM_BDC_NAME;
+ res[1].flags = IORESOURCE_IRQ;
+
+ ret = platform_device_add_resources(bdc, res, ARRAY_SIZE(res));
+ if (ret) {
+ dev_err(&pci->dev,
+ "couldn't add resources to bdc device\n");
+ return ret;
+ }
+
+ pci_set_drvdata(pci, glue);
+
+ dma_set_coherent_mask(&bdc->dev, pci->dev.coherent_dma_mask);
+
+ bdc->dev.dma_mask = pci->dev.dma_mask;
+ bdc->dev.dma_parms = pci->dev.dma_parms;
+ bdc->dev.parent = &pci->dev;
+ glue->bdc = bdc;
+
+ ret = platform_device_add(bdc);
+ if (ret) {
+ dev_err(&pci->dev, "failed to register bdc device\n");
+ platform_device_put(bdc);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void bdc_pci_remove(struct pci_dev *pci)
+{
+ struct bdc_pci *glue = pci_get_drvdata(pci);
+
+ platform_device_unregister(glue->bdc);
+ pci_disable_msi(pci);
+}
+
+static struct pci_device_id bdc_pci_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, BDC_PCI_PID), },
+ {} /* Terminating Entry */
+};
+
+MODULE_DEVICE_TABLE(pci, bdc_pci_id_table);
+
+static struct pci_driver bdc_pci_driver = {
+ .name = "bdc-pci",
+ .id_table = bdc_pci_id_table,
+ .probe = bdc_pci_probe,
+ .remove = bdc_pci_remove,
+};
+
+MODULE_AUTHOR("Ashwini Pahuja <ashwini.linux@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("BRCM BDC USB3 PCI Glue layer");
+module_pci_driver(bdc_pci_driver);
diff --git a/drivers/usb/gadget/udc/bdc/bdc_udc.c b/drivers/usb/gadget/udc/bdc/bdc_udc.c
new file mode 100644
index 000000000000..3700ce70b0be
--- /dev/null
+++ b/drivers/usb/gadget/udc/bdc/bdc_udc.c
@@ -0,0 +1,587 @@
+/*
+ * bdc_udc.c - BRCM BDC USB3.0 device controller gagdet ops
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Author: Ashwini Pahuja
+ *
+ * Based on drivers under drivers/usb/gadget/udc/
+ *
+ * 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/module.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/pm.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <asm/unaligned.h>
+#include <linux/platform_device.h>
+
+#include "bdc.h"
+#include "bdc_ep.h"
+#include "bdc_cmd.h"
+#include "bdc_dbg.h"
+
+static const struct usb_gadget_ops bdc_gadget_ops;
+
+static const char * const conn_speed_str[] = {
+ "Not connected",
+ "Full Speed",
+ "Low Speed",
+ "High Speed",
+ "Super Speed",
+};
+
+/* EP0 initial descripror */
+static struct usb_endpoint_descriptor bdc_gadget_ep0_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .bEndpointAddress = 0,
+ .wMaxPacketSize = cpu_to_le16(EP0_MAX_PKT_SIZE),
+};
+
+/* Advance the srr dqp maintained by SW */
+static void srr_dqp_index_advc(struct bdc *bdc, u32 srr_num)
+{
+ struct srr *srr;
+
+ srr = &bdc->srr;
+ dev_dbg_ratelimited(bdc->dev, "srr->dqp_index:%d\n", srr->dqp_index);
+ srr->dqp_index++;
+ /* rollback to 0 if we are past the last */
+ if (srr->dqp_index == NUM_SR_ENTRIES)
+ srr->dqp_index = 0;
+}
+
+/* connect sr */
+static void bdc_uspc_connected(struct bdc *bdc)
+{
+ u32 speed, temp;
+ u32 usppms;
+ int ret;
+
+ temp = bdc_readl(bdc->regs, BDC_USPC);
+ speed = BDC_PSP(temp);
+ dev_dbg(bdc->dev, "%s speed=%x\n", __func__, speed);
+ switch (speed) {
+ case BDC_SPEED_SS:
+ bdc_gadget_ep0_desc.wMaxPacketSize =
+ cpu_to_le16(EP0_MAX_PKT_SIZE);
+ bdc->gadget.ep0->maxpacket = EP0_MAX_PKT_SIZE;
+ bdc->gadget.speed = USB_SPEED_SUPER;
+ /* Enable U1T in SS mode */
+ usppms = bdc_readl(bdc->regs, BDC_USPPMS);
+ usppms &= ~BDC_U1T(0xff);
+ usppms |= BDC_U1T(U1_TIMEOUT);
+ usppms |= BDC_PORT_W1S;
+ bdc_writel(bdc->regs, BDC_USPPMS, usppms);
+ break;
+
+ case BDC_SPEED_HS:
+ bdc_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+ bdc->gadget.ep0->maxpacket = 64;
+ bdc->gadget.speed = USB_SPEED_HIGH;
+ break;
+
+ case BDC_SPEED_FS:
+ bdc_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+ bdc->gadget.ep0->maxpacket = 64;
+ bdc->gadget.speed = USB_SPEED_FULL;
+ break;
+
+ case BDC_SPEED_LS:
+ bdc_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
+ bdc->gadget.ep0->maxpacket = 8;
+ bdc->gadget.speed = USB_SPEED_LOW;
+ break;
+ default:
+ dev_err(bdc->dev, "UNDEFINED SPEED\n");
+ return;
+ }
+ dev_dbg(bdc->dev, "connected at %s\n", conn_speed_str[speed]);
+ /* Now we know the speed, configure ep0 */
+ bdc->bdc_ep_array[1]->desc = &bdc_gadget_ep0_desc;
+ ret = bdc_config_ep(bdc, bdc->bdc_ep_array[1]);
+ if (ret)
+ dev_err(bdc->dev, "EP0 config failed\n");
+ bdc->bdc_ep_array[1]->usb_ep.desc = &bdc_gadget_ep0_desc;
+ bdc->bdc_ep_array[1]->flags |= BDC_EP_ENABLED;
+ usb_gadget_set_state(&bdc->gadget, USB_STATE_DEFAULT);
+}
+
+/* device got disconnected */
+static void bdc_uspc_disconnected(struct bdc *bdc, bool reinit)
+{
+ struct bdc_ep *ep;
+
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ /*
+ * Only stop ep0 from here, rest of the endpoints will be disabled
+ * from gadget_disconnect
+ */
+ ep = bdc->bdc_ep_array[1];
+ if (ep && (ep->flags & BDC_EP_ENABLED))
+ /* if enabled then stop and remove requests */
+ bdc_ep_disable(ep);
+
+ if (bdc->gadget_driver && bdc->gadget_driver->disconnect) {
+ spin_unlock(&bdc->lock);
+ bdc->gadget_driver->disconnect(&bdc->gadget);
+ spin_lock(&bdc->lock);
+ }
+ /* Set Unknown speed */
+ bdc->gadget.speed = USB_SPEED_UNKNOWN;
+ bdc->devstatus &= DEVSTATUS_CLEAR;
+ bdc->delayed_status = false;
+ bdc->reinit = reinit;
+ bdc->test_mode = false;
+}
+
+/* TNotify wkaeup timer */
+static void bdc_func_wake_timer(struct work_struct *work)
+{
+ struct bdc *bdc = container_of(work, struct bdc, func_wake_notify.work);
+ unsigned long flags;
+
+ dev_dbg(bdc->dev, "%s\n", __func__);
+ spin_lock_irqsave(&bdc->lock, flags);
+ /*
+ * Check if host has started transferring on endpoints
+ * FUNC_WAKE_ISSUED is cleared when transfer has started after resume
+ */
+ if (bdc->devstatus & FUNC_WAKE_ISSUED) {
+ dev_dbg(bdc->dev, "FUNC_WAKE_ISSUED FLAG IS STILL SET\n");
+ /* flag is still set, so again send func wake */
+ bdc_function_wake_fh(bdc, 0);
+ schedule_delayed_work(&bdc->func_wake_notify,
+ msecs_to_jiffies(BDC_TNOTIFY));
+ }
+ spin_unlock_irqrestore(&bdc->lock, flags);
+}
+
+/* handler for Link state change condition */
+static void handle_link_state_change(struct bdc *bdc, u32 uspc)
+{
+ u32 link_state;
+
+ dev_dbg(bdc->dev, "Link state change");
+ link_state = BDC_PST(uspc);
+ switch (link_state) {
+ case BDC_LINK_STATE_U3:
+ if ((bdc->gadget.speed != USB_SPEED_UNKNOWN) &&
+ bdc->gadget_driver->suspend) {
+ dev_dbg(bdc->dev, "Entered Suspend mode\n");
+ spin_unlock(&bdc->lock);
+ bdc->devstatus |= DEVICE_SUSPENDED;
+ bdc->gadget_driver->suspend(&bdc->gadget);
+ spin_lock(&bdc->lock);
+ }
+ break;
+ case BDC_LINK_STATE_U0:
+ if (bdc->devstatus & REMOTE_WAKEUP_ISSUED) {
+ bdc->devstatus &= ~REMOTE_WAKEUP_ISSUED;
+ if (bdc->gadget.speed == USB_SPEED_SUPER) {
+ bdc_function_wake_fh(bdc, 0);
+ bdc->devstatus |= FUNC_WAKE_ISSUED;
+ /*
+ * Start a Notification timer and check if the
+ * Host transferred anything on any of the EPs,
+ * if not then send function wake again every
+ * TNotification secs until host initiates
+ * transfer to BDC, USB3 spec Table 8.13
+ */
+ schedule_delayed_work(
+ &bdc->func_wake_notify,
+ msecs_to_jiffies(BDC_TNOTIFY));
+ dev_dbg(bdc->dev, "sched func_wake_notify\n");
+ }
+ }
+ break;
+
+ case BDC_LINK_STATE_RESUME:
+ dev_dbg(bdc->dev, "Resumed from Suspend\n");
+ if (bdc->devstatus & DEVICE_SUSPENDED) {
+ bdc->gadget_driver->resume(&bdc->gadget);
+ bdc->devstatus &= ~DEVICE_SUSPENDED;
+ }
+ break;
+ default:
+ dev_dbg(bdc->dev, "link state:%d\n", link_state);
+ }
+}
+
+/* something changes on upstream port, handle it here */
+void bdc_sr_uspc(struct bdc *bdc, struct bdc_sr *sreport)
+{
+ u32 clear_flags = 0;
+ u32 uspc;
+ bool connected = false;
+ bool disconn = false;
+
+ uspc = bdc_readl(bdc->regs, BDC_USPC);
+ dev_dbg(bdc->dev, "%s uspc=0x%08x\n", __func__, uspc);
+
+ /* Port connect changed */
+ if (uspc & BDC_PCC) {
+ /* Vbus not present, and not connected to Downstream port */
+ if ((uspc & BDC_VBC) && !(uspc & BDC_VBS) && !(uspc & BDC_PCS))
+ disconn = true;
+ else if ((uspc & BDC_PCS) && !BDC_PST(uspc))
+ connected = true;
+ }
+
+ /* Change in VBus and VBus is present */
+ if ((uspc & BDC_VBC) && (uspc & BDC_VBS)) {
+ if (bdc->pullup) {
+ dev_dbg(bdc->dev, "Do a softconnect\n");
+ /* Attached state, do a softconnect */
+ bdc_softconn(bdc);
+ usb_gadget_set_state(&bdc->gadget, USB_STATE_POWERED);
+ }
+ clear_flags = BDC_VBC;
+ } else if ((uspc & BDC_PRS) || (uspc & BDC_PRC) || disconn) {
+ /* Hot reset, warm reset, 2.0 bus reset or disconn */
+ dev_dbg(bdc->dev, "Port reset or disconn\n");
+ bdc_uspc_disconnected(bdc, disconn);
+ clear_flags = BDC_PCC|BDC_PCS|BDC_PRS|BDC_PRC;
+ } else if ((uspc & BDC_PSC) && (uspc & BDC_PCS)) {
+ /* Change in Link state */
+ handle_link_state_change(bdc, uspc);
+ clear_flags = BDC_PSC|BDC_PCS;
+ }
+
+ /*
+ * In SS we might not have PRC bit set before connection, but in 2.0
+ * the PRC bit is set before connection, so moving this condition out
+ * of bus reset to handle both SS/2.0 speeds.
+ */
+ if (connected) {
+ /* This is the connect event for U0/L0 */
+ dev_dbg(bdc->dev, "Connected\n");
+ bdc_uspc_connected(bdc);
+ bdc->devstatus &= ~(DEVICE_SUSPENDED);
+ }
+ uspc = bdc_readl(bdc->regs, BDC_USPC);
+ uspc &= (~BDC_USPSC_RW);
+ dev_dbg(bdc->dev, "uspc=%x\n", uspc);
+ bdc_writel(bdc->regs, BDC_USPC, clear_flags);
+}
+
+/* Main interrupt handler for bdc */
+static irqreturn_t bdc_udc_interrupt(int irq, void *_bdc)
+{
+ u32 eqp_index, dqp_index, sr_type, srr_int;
+ struct bdc_sr *sreport;
+ struct bdc *bdc = _bdc;
+ u32 status;
+ int ret;
+
+ spin_lock(&bdc->lock);
+ status = bdc_readl(bdc->regs, BDC_BDCSC);
+ if (!(status & BDC_GIP)) {
+ spin_unlock(&bdc->lock);
+ return IRQ_NONE;
+ }
+ srr_int = bdc_readl(bdc->regs, BDC_SRRINT(0));
+ /* Check if the SRR IP bit it set? */
+ if (!(srr_int & BDC_SRR_IP)) {
+ dev_warn(bdc->dev, "Global irq pending but SRR IP is 0\n");
+ spin_unlock(&bdc->lock);
+ return IRQ_NONE;
+ }
+ eqp_index = BDC_SRR_EPI(srr_int);
+ dqp_index = BDC_SRR_DPI(srr_int);
+ dev_dbg(bdc->dev,
+ "%s eqp_index=%d dqp_index=%d srr.dqp_index=%d\n\n",
+ __func__, eqp_index, dqp_index, bdc->srr.dqp_index);
+
+ /* check for ring empty condition */
+ if (eqp_index == dqp_index) {
+ dev_dbg(bdc->dev, "SRR empty?\n");
+ spin_unlock(&bdc->lock);
+ return IRQ_HANDLED;
+ }
+
+ while (bdc->srr.dqp_index != eqp_index) {
+ sreport = &bdc->srr.sr_bds[bdc->srr.dqp_index];
+ /* sreport is read before using it */
+ rmb();
+ sr_type = le32_to_cpu(sreport->offset[3]) & BD_TYPE_BITMASK;
+ dev_dbg_ratelimited(bdc->dev, "sr_type=%d\n", sr_type);
+ switch (sr_type) {
+ case SR_XSF:
+ bdc->sr_handler[0](bdc, sreport);
+ break;
+
+ case SR_USPC:
+ bdc->sr_handler[1](bdc, sreport);
+ break;
+ default:
+ dev_warn(bdc->dev, "SR:%d not handled\n", sr_type);
+ }
+ /* Advance the srr dqp index */
+ srr_dqp_index_advc(bdc, 0);
+ }
+ /* update the hw dequeue pointer */
+ srr_int = bdc_readl(bdc->regs, BDC_SRRINT(0));
+ srr_int &= ~BDC_SRR_DPI_MASK;
+ srr_int &= ~(BDC_SRR_RWS|BDC_SRR_RST|BDC_SRR_ISR);
+ srr_int |= ((bdc->srr.dqp_index) << 16);
+ srr_int |= BDC_SRR_IP;
+ bdc_writel(bdc->regs, BDC_SRRINT(0), srr_int);
+ srr_int = bdc_readl(bdc->regs, BDC_SRRINT(0));
+ if (bdc->reinit) {
+ ret = bdc_reinit(bdc);
+ if (ret)
+ dev_err(bdc->dev, "err in bdc reinit\n");
+ }
+
+ spin_unlock(&bdc->lock);
+
+ return IRQ_HANDLED;
+}
+
+/* Gadget ops */
+static int bdc_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct bdc *bdc = gadget_to_bdc(gadget);
+ unsigned long flags;
+ int ret = 0;
+
+ dev_dbg(bdc->dev, "%s()\n", __func__);
+ spin_lock_irqsave(&bdc->lock, flags);
+ if (bdc->gadget_driver) {
+ dev_err(bdc->dev, "%s is already bound to %s\n",
+ bdc->gadget.name,
+ bdc->gadget_driver->driver.name);
+ ret = -EBUSY;
+ goto err;
+ }
+ /*
+ * Run the controller from here and when BDC is connected to
+ * Host then driver will receive a USPC SR with VBUS present
+ * and then driver will do a softconnect.
+ */
+ ret = bdc_run(bdc);
+ if (ret) {
+ dev_err(bdc->dev, "%s bdc run fail\n", __func__);
+ goto err;
+ }
+ bdc->gadget_driver = driver;
+ bdc->gadget.dev.driver = &driver->driver;
+err:
+ spin_unlock_irqrestore(&bdc->lock, flags);
+
+ return ret;
+}
+
+static int bdc_udc_stop(struct usb_gadget *gadget)
+{
+ struct bdc *bdc = gadget_to_bdc(gadget);
+ unsigned long flags;
+
+ dev_dbg(bdc->dev, "%s()\n", __func__);
+ spin_lock_irqsave(&bdc->lock, flags);
+ bdc_stop(bdc);
+ bdc->gadget_driver = NULL;
+ bdc->gadget.dev.driver = NULL;
+ spin_unlock_irqrestore(&bdc->lock, flags);
+
+ return 0;
+}
+
+static int bdc_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct bdc *bdc = gadget_to_bdc(gadget);
+ unsigned long flags;
+ u32 uspc;
+
+ dev_dbg(bdc->dev, "%s() is_on:%d\n", __func__, is_on);
+ if (!gadget)
+ return -EINVAL;
+
+ spin_lock_irqsave(&bdc->lock, flags);
+ if (!is_on) {
+ bdc_softdisconn(bdc);
+ bdc->pullup = false;
+ } else {
+ /*
+ * For a self powered device, we need to wait till we receive
+ * a VBUS change and Vbus present event, then if pullup flag
+ * is set, then only we present the Termintation.
+ */
+ bdc->pullup = true;
+ /*
+ * Check if BDC is already connected to Host i.e Vbus=1,
+ * if yes, then present TERM now, this is typical for bus
+ * powered devices.
+ */
+ uspc = bdc_readl(bdc->regs, BDC_USPC);
+ if (uspc & BDC_VBS)
+ bdc_softconn(bdc);
+ }
+ spin_unlock_irqrestore(&bdc->lock, flags);
+
+ return 0;
+}
+
+static int bdc_udc_set_selfpowered(struct usb_gadget *gadget,
+ int is_self)
+{
+ struct bdc *bdc = gadget_to_bdc(gadget);
+ unsigned long flags;
+
+ dev_dbg(bdc->dev, "%s()\n", __func__);
+ spin_lock_irqsave(&bdc->lock, flags);
+ if (!is_self)
+ bdc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
+ else
+ bdc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+
+ spin_unlock_irqrestore(&bdc->lock, flags);
+
+ return 0;
+}
+
+static int bdc_udc_wakeup(struct usb_gadget *gadget)
+{
+ struct bdc *bdc = gadget_to_bdc(gadget);
+ unsigned long flags;
+ u8 link_state;
+ u32 uspc;
+ int ret = 0;
+
+ dev_dbg(bdc->dev,
+ "%s() bdc->devstatus=%08x\n",
+ __func__, bdc->devstatus);
+
+ if (!(bdc->devstatus & REMOTE_WAKE_ENABLE))
+ return -EOPNOTSUPP;
+
+ spin_lock_irqsave(&bdc->lock, flags);
+ uspc = bdc_readl(bdc->regs, BDC_USPC);
+ link_state = BDC_PST(uspc);
+ dev_dbg(bdc->dev, "link_state =%d portsc=%x", link_state, uspc);
+ if (link_state != BDC_LINK_STATE_U3) {
+ dev_warn(bdc->dev,
+ "can't wakeup from link state %d\n",
+ link_state);
+ ret = -EINVAL;
+ goto out;
+ }
+ if (bdc->gadget.speed == USB_SPEED_SUPER)
+ bdc->devstatus |= REMOTE_WAKEUP_ISSUED;
+
+ uspc &= ~BDC_PST_MASK;
+ uspc &= (~BDC_USPSC_RW);
+ uspc |= BDC_PST(BDC_LINK_STATE_U0);
+ uspc |= BDC_SWS;
+ bdc_writel(bdc->regs, BDC_USPC, uspc);
+ uspc = bdc_readl(bdc->regs, BDC_USPC);
+ link_state = BDC_PST(uspc);
+ dev_dbg(bdc->dev, "link_state =%d portsc=%x", link_state, uspc);
+out:
+ spin_unlock_irqrestore(&bdc->lock, flags);
+
+ return ret;
+}
+
+static const struct usb_gadget_ops bdc_gadget_ops = {
+ .wakeup = bdc_udc_wakeup,
+ .set_selfpowered = bdc_udc_set_selfpowered,
+ .pullup = bdc_udc_pullup,
+ .udc_start = bdc_udc_start,
+ .udc_stop = bdc_udc_stop,
+};
+
+/* Init the gadget interface and register the udc */
+int bdc_udc_init(struct bdc *bdc)
+{
+ u32 temp;
+ int ret;
+
+ dev_dbg(bdc->dev, "%s()\n", __func__);
+ bdc->gadget.ops = &bdc_gadget_ops;
+ bdc->gadget.max_speed = USB_SPEED_SUPER;
+ bdc->gadget.speed = USB_SPEED_UNKNOWN;
+ bdc->gadget.dev.parent = bdc->dev;
+
+ bdc->gadget.sg_supported = false;
+
+
+ bdc->gadget.name = BRCM_BDC_NAME;
+ ret = devm_request_irq(bdc->dev, bdc->irq, bdc_udc_interrupt,
+ IRQF_SHARED , BRCM_BDC_NAME, bdc);
+ if (ret) {
+ dev_err(bdc->dev,
+ "failed to request irq #%d %d\n",
+ bdc->irq, ret);
+ return ret;
+ }
+
+ ret = bdc_init_ep(bdc);
+ if (ret) {
+ dev_err(bdc->dev, "bdc init ep fail: %d\n", ret);
+ return ret;
+ }
+
+ ret = usb_add_gadget_udc(bdc->dev, &bdc->gadget);
+ if (ret) {
+ dev_err(bdc->dev, "failed to register udc\n");
+ goto err0;
+ }
+ usb_gadget_set_state(&bdc->gadget, USB_STATE_NOTATTACHED);
+ bdc->bdc_ep_array[1]->desc = &bdc_gadget_ep0_desc;
+ /*
+ * Allocate bd list for ep0 only, ep0 will be enabled on connect
+ * status report when the speed is known
+ */
+ ret = bdc_ep_enable(bdc->bdc_ep_array[1]);
+ if (ret) {
+ dev_err(bdc->dev, "fail to enable %s\n",
+ bdc->bdc_ep_array[1]->name);
+ goto err1;
+ }
+ INIT_DELAYED_WORK(&bdc->func_wake_notify, bdc_func_wake_timer);
+ /* Enable Interrupts */
+ temp = bdc_readl(bdc->regs, BDC_BDCSC);
+ temp |= BDC_GIE;
+ bdc_writel(bdc->regs, BDC_BDCSC, temp);
+ return 0;
+err1:
+ usb_del_gadget_udc(&bdc->gadget);
+err0:
+ bdc_free_ep(bdc);
+
+ return ret;
+}
+
+void bdc_udc_exit(struct bdc *bdc)
+{
+ dev_dbg(bdc->dev, "%s()\n", __func__);
+ bdc_ep_disable(bdc->bdc_ep_array[1]);
+ usb_del_gadget_udc(&bdc->gadget);
+ bdc_free_ep(bdc);
+}
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 81dc5959e36b..1c69c760408e 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -367,19 +367,22 @@ static void set_link_state(struct dummy_hcd *dum_hcd)
dum_hcd->active)
dum_hcd->resuming = 0;
- /* if !connected or reset */
+ /* Currently !connected or in reset */
if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
- /*
- * We're connected and not reset (reset occurred now),
- * and driver attached - disconnect!
- */
- if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
- (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
- dum->driver) {
+ unsigned disconnect = USB_PORT_STAT_CONNECTION &
+ dum_hcd->old_status & (~dum_hcd->port_status);
+ unsigned reset = USB_PORT_STAT_RESET &
+ (~dum_hcd->old_status) & dum_hcd->port_status;
+
+ /* Report reset and disconnect events to the driver */
+ if (dum->driver && (disconnect || reset)) {
stop_activity(dum);
spin_unlock(&dum->lock);
- dum->driver->disconnect(&dum->gadget);
+ if (reset)
+ usb_gadget_udc_reset(&dum->gadget, dum->driver);
+ else
+ dum->driver->disconnect(&dum->gadget);
spin_lock(&dum->lock);
}
} else if (dum_hcd->active != dum_hcd->old_active) {
@@ -851,8 +854,7 @@ static int dummy_pullup(struct usb_gadget *_gadget, int value)
static int dummy_udc_start(struct usb_gadget *g,
struct usb_gadget_driver *driver);
-static int dummy_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
+static int dummy_udc_stop(struct usb_gadget *g);
static const struct usb_gadget_ops dummy_ops = {
.get_frame = dummy_g_get_frame,
@@ -908,23 +910,16 @@ static int dummy_udc_start(struct usb_gadget *g,
*/
dum->devstatus = 0;
-
dum->driver = driver;
- dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n",
- driver->driver.name);
+
return 0;
}
-static int dummy_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int dummy_udc_stop(struct usb_gadget *g)
{
struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g);
struct dummy *dum = dum_hcd->dum;
- if (driver)
- dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n",
- driver->driver.name);
-
dum->driver = NULL;
return 0;
@@ -2370,7 +2365,6 @@ static void dummy_stop(struct usb_hcd *hcd)
dum = hcd_to_dummy_hcd(hcd)->dum;
device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
- usb_gadget_unregister_driver(dum->driver);
dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
}
diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c
index 1d315921bf34..1ca52e11eb98 100644
--- a/drivers/usb/gadget/udc/fotg210-udc.c
+++ b/drivers/usb/gadget/udc/fotg210-udc.c
@@ -1053,8 +1053,7 @@ static void fotg210_init(struct fotg210_udc *fotg210)
iowrite32(value, fotg210->reg + FOTG210_DMISGR0);
}
-static int fotg210_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int fotg210_udc_stop(struct usb_gadget *g)
{
struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
unsigned long flags;
diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c
index dd18ea38e391..d201f9a89ce3 100644
--- a/drivers/usb/gadget/udc/fsl_qe_udc.c
+++ b/drivers/usb/gadget/udc/fsl_qe_udc.c
@@ -1887,8 +1887,7 @@ static int qe_get_frame(struct usb_gadget *gadget)
static int fsl_qe_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
-static int fsl_qe_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver);
+static int fsl_qe_stop(struct usb_gadget *gadget);
/* defined in usb_gadget.h */
static const struct usb_gadget_ops qe_gadget_ops = {
@@ -1918,7 +1917,7 @@ static int reset_queues(struct qe_udc *udc)
/* report disconnect; the driver is already quiesced */
spin_unlock(&udc->lock);
- udc->driver->disconnect(&udc->gadget);
+ usb_gadget_udc_reset(&udc->gadget, udc->driver);
spin_lock(&udc->lock);
return 0;
@@ -2305,13 +2304,10 @@ static int fsl_qe_start(struct usb_gadget *gadget,
udc->ep0_dir = USB_DIR_OUT;
spin_unlock_irqrestore(&udc->lock, flags);
- dev_info(udc->dev, "%s bind to driver %s\n", udc->gadget.name,
- driver->driver.name);
return 0;
}
-static int fsl_qe_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static int fsl_qe_stop(struct usb_gadget *gadget)
{
struct qe_udc *udc;
struct qe_ep *loop_ep;
@@ -2336,8 +2332,6 @@ static int fsl_qe_stop(struct usb_gadget *gadget,
udc->driver = NULL;
- dev_info(udc->dev, "unregistered gadget driver '%s'\r\n",
- driver->driver.name);
return 0;
}
@@ -2538,7 +2532,6 @@ static int qe_udc_probe(struct platform_device *ofdev)
/* create a buf for ZLP send, need to remain zeroed */
udc->nullbuf = devm_kzalloc(&ofdev->dev, 256, GFP_KERNEL);
if (udc->nullbuf == NULL) {
- dev_err(udc->dev, "cannot alloc nullbuf\n");
ret = -ENOMEM;
goto err3;
}
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
index c3620791a315..f340181da23c 100644
--- a/drivers/usb/gadget/udc/fsl_udc_core.c
+++ b/drivers/usb/gadget/udc/fsl_udc_core.c
@@ -1236,9 +1236,8 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
static int fsl_udc_start(struct usb_gadget *g,
struct usb_gadget_driver *driver);
-static int fsl_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
-/* defined in gadget.h */
+static int fsl_udc_stop(struct usb_gadget *g);
+
static const struct usb_gadget_ops fsl_gadget_ops = {
.get_frame = fsl_get_frame,
.wakeup = fsl_wakeup,
@@ -1772,7 +1771,7 @@ static void bus_resume(struct fsl_udc *udc)
}
/* Clear up all ep queues */
-static int reset_queues(struct fsl_udc *udc)
+static int reset_queues(struct fsl_udc *udc, bool bus_reset)
{
u8 pipe;
@@ -1781,7 +1780,10 @@ static int reset_queues(struct fsl_udc *udc)
/* report disconnect; the driver is already quiesced */
spin_unlock(&udc->lock);
- udc->driver->disconnect(&udc->gadget);
+ if (bus_reset)
+ usb_gadget_udc_reset(&udc->gadget, udc->driver);
+ else
+ udc->driver->disconnect(&udc->gadget);
spin_lock(&udc->lock);
return 0;
@@ -1835,7 +1837,7 @@ static void reset_irq(struct fsl_udc *udc)
udc->bus_reset = 1;
/* Reset all the queues, include XD, dTD, EP queue
* head and TR Queue */
- reset_queues(udc);
+ reset_queues(udc, true);
udc->usb_state = USB_STATE_DEFAULT;
} else {
VDBG("Controller reset");
@@ -1844,7 +1846,7 @@ static void reset_irq(struct fsl_udc *udc)
dr_controller_setup(udc);
/* Reset all internal used Queues */
- reset_queues(udc);
+ reset_queues(udc, false);
ep0_setup(udc);
@@ -1975,8 +1977,7 @@ static int fsl_udc_start(struct usb_gadget *g,
}
/* Disconnect from gadget driver */
-static int fsl_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int fsl_udc_stop(struct usb_gadget *g)
{
struct fsl_ep *loop_ep;
unsigned long flags;
diff --git a/drivers/usb/gadget/udc/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c
index 8286df72add4..a1b33f534b52 100644
--- a/drivers/usb/gadget/udc/fusb300_udc.c
+++ b/drivers/usb/gadget/udc/fusb300_udc.c
@@ -1320,8 +1320,7 @@ static int fusb300_udc_start(struct usb_gadget *g,
return 0;
}
-static int fusb300_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int fusb300_udc_stop(struct usb_gadget *g)
{
struct fusb300 *fusb300 = to_fusb300(g);
diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c
index bf9c5ef8b56b..5b9176e7202a 100644
--- a/drivers/usb/gadget/udc/goku_udc.c
+++ b/drivers/usb/gadget/udc/goku_udc.c
@@ -992,8 +992,7 @@ static int goku_get_frame(struct usb_gadget *_gadget)
static int goku_udc_start(struct usb_gadget *g,
struct usb_gadget_driver *driver);
-static int goku_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
+static int goku_udc_stop(struct usb_gadget *g);
static const struct usb_gadget_ops goku_ops = {
.get_frame = goku_get_frame,
@@ -1364,8 +1363,7 @@ static void stop_activity(struct goku_udc *dev)
udc_enable(dev);
}
-static int goku_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int goku_udc_stop(struct usb_gadget *g)
{
struct goku_udc *dev = to_goku_udc(g);
unsigned long flags;
diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c
index 1b3048a6a2a3..320df9a250ff 100644
--- a/drivers/usb/gadget/udc/gr_udc.c
+++ b/drivers/usb/gadget/udc/gr_udc.c
@@ -1932,14 +1932,10 @@ static int gr_udc_start(struct usb_gadget *gadget,
spin_unlock(&dev->lock);
- dev_info(dev->dev, "Started with gadget driver '%s'\n",
- driver->driver.name);
-
return 0;
}
-static int gr_udc_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static int gr_udc_stop(struct usb_gadget *gadget)
{
struct gr_udc *dev = to_gr_udc(gadget);
unsigned long flags;
@@ -1951,8 +1947,6 @@ static int gr_udc_stop(struct usb_gadget *gadget,
spin_unlock_irqrestore(&dev->lock, flags);
- dev_info(dev->dev, "Stopped\n");
-
return 0;
}
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index feab0bac8fdc..976529631c19 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -582,8 +582,7 @@ static void create_debug_file(struct lpc32xx_udc *udc)
static void remove_debug_file(struct lpc32xx_udc *udc)
{
- if (udc->pde)
- debugfs_remove(udc->pde);
+ debugfs_remove(udc->pde);
}
#else
@@ -2559,7 +2558,7 @@ static int lpc32xx_pullup(struct usb_gadget *gadget, int is_on)
}
static int lpc32xx_start(struct usb_gadget *, struct usb_gadget_driver *);
-static int lpc32xx_stop(struct usb_gadget *, struct usb_gadget_driver *);
+static int lpc32xx_stop(struct usb_gadget *);
static const struct usb_gadget_ops lpc32xx_udc_ops = {
.get_frame = lpc32xx_get_frame,
@@ -2961,15 +2960,11 @@ static int lpc32xx_start(struct usb_gadget *gadget,
return 0;
}
-static int lpc32xx_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static int lpc32xx_stop(struct usb_gadget *gadget)
{
int i;
struct lpc32xx_udc *udc = to_udc(gadget);
- if (!driver || driver != udc->driver)
- return -EINVAL;
-
for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++)
disable_irq(udc->udp_irq[i]);
diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c
index 898565687a8c..ef3f73dd9099 100644
--- a/drivers/usb/gadget/udc/m66592-udc.c
+++ b/drivers/usb/gadget/udc/m66592-udc.c
@@ -1142,7 +1142,7 @@ static void irq_device_state(struct m66592 *m66592)
m66592_write(m66592, ~M66592_DVST, M66592_INTSTS0);
if (dvsq == M66592_DS_DFLT) { /* bus reset */
- m66592->driver->disconnect(&m66592->gadget);
+ usb_gadget_udc_reset(&m66592->gadget, m66592->driver);
m66592_update_usb_speed(m66592);
}
if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG)
@@ -1485,8 +1485,7 @@ static int m66592_udc_start(struct usb_gadget *g,
return 0;
}
-static int m66592_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int m66592_udc_stop(struct usb_gadget *g)
{
struct m66592 *m66592 = to_m66592(g);
diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c
index 046a1f808b0d..ea422ac79990 100644
--- a/drivers/usb/gadget/udc/mv_u3d_core.c
+++ b/drivers/usb/gadget/udc/mv_u3d_core.c
@@ -1266,8 +1266,7 @@ static int mv_u3d_start(struct usb_gadget *g,
return 0;
}
-static int mv_u3d_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int mv_u3d_stop(struct usb_gadget *g)
{
struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget);
struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
@@ -1284,7 +1283,7 @@ static int mv_u3d_stop(struct usb_gadget *g,
mv_u3d_controller_stop(u3d);
/* stop all usb activities */
u3d->gadget.speed = USB_SPEED_UNKNOWN;
- mv_u3d_stop_activity(u3d, driver);
+ mv_u3d_stop_activity(u3d, NULL);
mv_u3d_disable(u3d);
if (pdata->phy_deinit)
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c
index 3c5db80ae325..d4edd763e963 100644
--- a/drivers/usb/gadget/udc/mv_udc_core.c
+++ b/drivers/usb/gadget/udc/mv_udc_core.c
@@ -1223,7 +1223,7 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on)
}
static int mv_udc_start(struct usb_gadget *, struct usb_gadget_driver *);
-static int mv_udc_stop(struct usb_gadget *, struct usb_gadget_driver *);
+static int mv_udc_stop(struct usb_gadget *);
/* device controller usb_gadget_ops structure */
static const struct usb_gadget_ops mv_ops = {
@@ -1307,6 +1307,23 @@ static void nuke(struct mv_ep *ep, int status)
}
}
+static void gadget_reset(struct mv_udc *udc, struct usb_gadget_driver *driver)
+{
+ struct mv_ep *ep;
+
+ nuke(&udc->eps[0], -ESHUTDOWN);
+
+ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+ nuke(ep, -ESHUTDOWN);
+ }
+
+ /* report reset; the driver is already quiesced */
+ if (driver) {
+ spin_unlock(&udc->lock);
+ usb_gadget_udc_reset(&udc->gadget, driver);
+ spin_lock(&udc->lock);
+ }
+}
/* stop all USB activities */
static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver)
{
@@ -1371,8 +1388,7 @@ static int mv_udc_start(struct usb_gadget *gadget,
return 0;
}
-static int mv_udc_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static int mv_udc_stop(struct usb_gadget *gadget)
{
struct mv_udc *udc;
unsigned long flags;
@@ -1386,7 +1402,7 @@ static int mv_udc_stop(struct usb_gadget *gadget,
/* stop all usb activities */
udc->gadget.speed = USB_SPEED_UNKNOWN;
- stop_activity(udc, driver);
+ stop_activity(udc, NULL);
mv_udc_disable(udc);
spin_unlock_irqrestore(&udc->lock, flags);
@@ -1882,7 +1898,7 @@ static void irq_process_reset(struct mv_udc *udc)
dev_info(&udc->dev->dev, "usb bus reset\n");
udc->usb_state = USB_STATE_DEFAULT;
/* reset all the queues, stop all USB activities */
- stop_activity(udc, udc->driver);
+ gadget_reset(udc, udc->driver);
} else {
dev_info(&udc->dev->dev, "USB reset portsc 0x%x\n",
readl(&udc->op_regs->portsc));
@@ -2107,10 +2123,8 @@ static int mv_udc_probe(struct platform_device *pdev)
}
udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL);
- if (udc == NULL) {
- dev_err(&pdev->dev, "failed to allocate memory for udc\n");
+ if (udc == NULL)
return -ENOMEM;
- }
udc->done = &release_done;
udc->pdata = dev_get_platdata(&pdev->dev);
@@ -2207,7 +2221,6 @@ static int mv_udc_probe(struct platform_device *pdev)
size = udc->max_eps * sizeof(struct mv_ep) *2;
udc->eps = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (udc->eps == NULL) {
- dev_err(&pdev->dev, "allocate ep memory failed\n");
retval = -ENOMEM;
goto err_destroy_dma;
}
@@ -2216,7 +2229,6 @@ static int mv_udc_probe(struct platform_device *pdev)
udc->status_req = devm_kzalloc(&pdev->dev, sizeof(struct mv_req),
GFP_KERNEL);
if (!udc->status_req) {
- dev_err(&pdev->dev, "allocate status_req memory failed\n");
retval = -ENOMEM;
goto err_destroy_dma;
}
diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c
index 84d7162a8022..3a90856625f2 100644
--- a/drivers/usb/gadget/udc/net2272.c
+++ b/drivers/usb/gadget/udc/net2272.c
@@ -1169,8 +1169,7 @@ net2272_pullup(struct usb_gadget *_gadget, int is_on)
static int net2272_start(struct usb_gadget *_gadget,
struct usb_gadget_driver *driver);
-static int net2272_stop(struct usb_gadget *_gadget,
- struct usb_gadget_driver *driver);
+static int net2272_stop(struct usb_gadget *_gadget);
static const struct usb_gadget_ops net2272_ops = {
.get_frame = net2272_get_frame,
@@ -1471,8 +1470,6 @@ static int net2272_start(struct usb_gadget *_gadget,
*/
net2272_ep0_start(dev);
- dev_dbg(dev->dev, "%s ready\n", driver->driver.name);
-
return 0;
}
@@ -1502,8 +1499,7 @@ stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver)
net2272_usb_reinit(dev);
}
-static int net2272_stop(struct usb_gadget *_gadget,
- struct usb_gadget_driver *driver)
+static int net2272_stop(struct usb_gadget *_gadget)
{
struct net2272 *dev;
unsigned long flags;
@@ -1511,12 +1507,11 @@ static int net2272_stop(struct usb_gadget *_gadget,
dev = container_of(_gadget, struct net2272, gadget);
spin_lock_irqsave(&dev->lock, flags);
- stop_activity(dev, driver);
+ stop_activity(dev, NULL);
spin_unlock_irqrestore(&dev->lock, flags);
dev->driver = NULL;
- dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name);
return 0;
}
@@ -1987,17 +1982,42 @@ net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat)
mask = (1 << USB_HIGH_SPEED) | (1 << USB_FULL_SPEED);
if (stat & tmp) {
+ bool reset = false;
+ bool disconnect = false;
+
+ /*
+ * Ignore disconnects and resets if the speed hasn't been set.
+ * VBUS can bounce and there's always an initial reset.
+ */
net2272_write(dev, IRQSTAT1, tmp);
- if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) &&
- ((net2272_read(dev, USBCTL1) & mask) == 0))
- || ((net2272_read(dev, USBCTL1) & (1 << VBUS_PIN))
- == 0))
- && (dev->gadget.speed != USB_SPEED_UNKNOWN)) {
- dev_dbg(dev->dev, "disconnect %s\n",
- dev->driver->driver.name);
- stop_activity(dev, dev->driver);
- net2272_ep0_start(dev);
- return;
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
+ if ((stat & (1 << VBUS_INTERRUPT)) &&
+ (net2272_read(dev, USBCTL1) &
+ (1 << VBUS_PIN)) == 0) {
+ disconnect = true;
+ dev_dbg(dev->dev, "disconnect %s\n",
+ dev->driver->driver.name);
+ } else if ((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) &&
+ (net2272_read(dev, USBCTL1) & mask)
+ == 0) {
+ reset = true;
+ dev_dbg(dev->dev, "reset %s\n",
+ dev->driver->driver.name);
+ }
+
+ if (disconnect || reset) {
+ stop_activity(dev, dev->driver);
+ net2272_ep0_start(dev);
+ spin_unlock(&dev->lock);
+ if (reset)
+ usb_gadget_udc_reset
+ (&dev->gadget, dev->driver);
+ else
+ (dev->driver->disconnect)
+ (&dev->gadget);
+ spin_lock(&dev->lock);
+ return;
+ }
}
stat &= ~tmp;
@@ -2200,18 +2220,8 @@ static void
net2272_remove(struct net2272 *dev)
{
usb_del_gadget_udc(&dev->gadget);
-
- /* start with the driver above us */
- if (dev->driver) {
- /* should have been done already by driver model core */
- dev_warn(dev->dev, "pci remove, driver '%s' is still registered\n",
- dev->driver->driver.name);
- usb_gadget_unregister_driver(dev->driver);
- }
-
free_irq(dev->irq, dev);
iounmap(dev->base_addr);
-
device_remove_file(dev->dev, &dev_attr_registers);
dev_info(dev->dev, "unbind\n");
diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
index 8d13337e2dde..d6411e0a8e03 100644
--- a/drivers/usb/gadget/udc/net2280.c
+++ b/drivers/usb/gadget/udc/net2280.c
@@ -1118,10 +1118,10 @@ static void scan_dma_completions(struct net2280_ep *ep)
break;
} else if (!ep->is_in &&
(req->req.length % ep->ep.maxpacket) != 0) {
- tmp = readl(&ep->regs->ep_stat);
if (ep->dev->quirks & PLX_SUPERSPEED)
return dma_done(ep, req, tmp, 0);
+ tmp = readl(&ep->regs->ep_stat);
/* AVOID TROUBLE HERE by not issuing short reads from
* your gadget driver. That helps avoids errata 0121,
* 0122, and 0124; not all cases trigger the warning.
@@ -1548,8 +1548,7 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on)
static int net2280_start(struct usb_gadget *_gadget,
struct usb_gadget_driver *driver);
-static int net2280_stop(struct usb_gadget *_gadget,
- struct usb_gadget_driver *driver);
+static int net2280_stop(struct usb_gadget *_gadget);
static const struct usb_gadget_ops net2280_ops = {
.get_frame = net2280_get_frame,
@@ -2397,11 +2396,6 @@ static int net2280_start(struct usb_gadget *_gadget,
ep0_start(dev);
- ep_dbg(dev, "%s ready, usbctl %08x stdrsp %08x\n",
- driver->driver.name,
- readl(&dev->usb->usbctl),
- readl(&dev->usb->stdrsp));
-
/* pci writes may still be posted */
return 0;
@@ -2437,8 +2431,7 @@ static void stop_activity(struct net2280 *dev, struct usb_gadget_driver *driver)
usb_reinit(dev);
}
-static int net2280_stop(struct usb_gadget *_gadget,
- struct usb_gadget_driver *driver)
+static int net2280_stop(struct usb_gadget *_gadget)
{
struct net2280 *dev;
unsigned long flags;
@@ -2446,11 +2439,9 @@ static int net2280_stop(struct usb_gadget *_gadget,
dev = container_of(_gadget, struct net2280, gadget);
spin_lock_irqsave(&dev->lock, flags);
- stop_activity(dev, driver);
+ stop_activity(dev, NULL);
spin_unlock_irqrestore(&dev->lock, flags);
- dev->driver = NULL;
-
net2280_led_active(dev, 0);
/* Disable full-speed test mode */
@@ -2460,8 +2451,7 @@ static int net2280_stop(struct usb_gadget *_gadget,
device_remove_file(&dev->pdev->dev, &dev_attr_function);
device_remove_file(&dev->pdev->dev, &dev_attr_queues);
- ep_dbg(dev, "unregistered driver '%s'\n",
- driver ? driver->driver.name : "");
+ dev->driver = NULL;
return 0;
}
@@ -3318,17 +3308,42 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat)
* only indicates a change in the reset state).
*/
if (stat & tmp) {
+ bool reset = false;
+ bool disconnect = false;
+
+ /*
+ * Ignore disconnects and resets if the speed hasn't been set.
+ * VBUS can bounce and there's always an initial reset.
+ */
writel(tmp, &dev->regs->irqstat1);
- if ((((stat & BIT(ROOT_PORT_RESET_INTERRUPT)) &&
- ((readl(&dev->usb->usbstat) & mask) == 0)) ||
- ((readl(&dev->usb->usbctl) &
- BIT(VBUS_PIN)) == 0)) &&
- (dev->gadget.speed != USB_SPEED_UNKNOWN)) {
- ep_dbg(dev, "disconnect %s\n",
- dev->driver->driver.name);
- stop_activity(dev, dev->driver);
- ep0_start(dev);
- return;
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
+ if ((stat & BIT(VBUS_INTERRUPT)) &&
+ (readl(&dev->usb->usbctl) &
+ BIT(VBUS_PIN)) == 0) {
+ disconnect = true;
+ ep_dbg(dev, "disconnect %s\n",
+ dev->driver->driver.name);
+ } else if ((stat & BIT(ROOT_PORT_RESET_INTERRUPT)) &&
+ (readl(&dev->usb->usbstat) & mask)
+ == 0) {
+ reset = true;
+ ep_dbg(dev, "reset %s\n",
+ dev->driver->driver.name);
+ }
+
+ if (disconnect || reset) {
+ stop_activity(dev, dev->driver);
+ ep0_start(dev);
+ spin_unlock(&dev->lock);
+ if (reset)
+ usb_gadget_udc_reset
+ (&dev->gadget, dev->driver);
+ else
+ (dev->driver->disconnect)
+ (&dev->gadget);
+ spin_lock(&dev->lock);
+ return;
+ }
}
stat &= ~tmp;
diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c
index dcdfea46003b..534b85c07feb 100644
--- a/drivers/usb/gadget/udc/omap_udc.c
+++ b/drivers/usb/gadget/udc/omap_udc.c
@@ -1311,8 +1311,7 @@ static int omap_pullup(struct usb_gadget *gadget, int is_on)
static int omap_udc_start(struct usb_gadget *g,
struct usb_gadget_driver *driver);
-static int omap_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
+static int omap_udc_stop(struct usb_gadget *g);
static const struct usb_gadget_ops omap_gadget_ops = {
.get_frame = omap_get_frame,
@@ -2102,8 +2101,7 @@ done:
return status;
}
-static int omap_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int omap_udc_stop(struct usb_gadget *g)
{
unsigned long flags;
int status = -ENODEV;
diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c
index ccbe3d4a2a50..1c7379ac2379 100644
--- a/drivers/usb/gadget/udc/pch_udc.c
+++ b/drivers/usb/gadget/udc/pch_udc.c
@@ -1240,8 +1240,8 @@ static int pch_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA)
static int pch_udc_start(struct usb_gadget *g,
struct usb_gadget_driver *driver);
-static int pch_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
+static int pch_udc_stop(struct usb_gadget *g);
+
static const struct usb_gadget_ops pch_udc_ops = {
.get_frame = pch_udc_pcd_get_frame,
.wakeup = pch_udc_pcd_wakeup,
@@ -2592,9 +2592,9 @@ static void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev)
/* Complete request queue */
empty_req_queue(ep);
}
- if (dev->driver && dev->driver->disconnect) {
+ if (dev->driver) {
spin_unlock(&dev->lock);
- dev->driver->disconnect(&dev->gadget);
+ usb_gadget_udc_reset(&dev->gadget, dev->driver);
spin_lock(&dev->lock);
}
}
@@ -3008,8 +3008,7 @@ static int pch_udc_start(struct usb_gadget *g,
return 0;
}
-static int pch_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int pch_udc_stop(struct usb_gadget *g)
{
struct pch_udc_dev *dev = to_pch_udc(g);
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c
index 42f7eeb8ff6f..347a05b5afc1 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.c
+++ b/drivers/usb/gadget/udc/pxa25x_udc.c
@@ -998,8 +998,7 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
static int pxa25x_udc_start(struct usb_gadget *g,
struct usb_gadget_driver *driver);
-static int pxa25x_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
+static int pxa25x_udc_stop(struct usb_gadget *g);
static const struct usb_gadget_ops pxa25x_udc_ops = {
.get_frame = pxa25x_udc_get_frame,
@@ -1135,11 +1134,7 @@ static const struct file_operations debug_fops = {
dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \
S_IRUGO, NULL, dev, &debug_fops); \
} while (0)
-#define remove_debug_files(dev) \
- do { \
- if (dev->debugfs_udc) \
- debugfs_remove(dev->debugfs_udc); \
- } while (0)
+#define remove_debug_files(dev) debugfs_remove(dev->debugfs_udc)
#else /* !CONFIG_USB_GADGET_DEBUG_FILES */
@@ -1285,6 +1280,33 @@ bind_fail:
}
static void
+reset_gadget(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
+{
+ int i;
+
+ /* don't disconnect drivers more than once */
+ if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+ driver = NULL;
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+ /* prevent new request submissions, kill any outstanding requests */
+ for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
+ struct pxa25x_ep *ep = &dev->ep[i];
+
+ ep->stopped = 1;
+ nuke(ep, -ESHUTDOWN);
+ }
+ del_timer_sync(&dev->timer);
+
+ /* report reset; the driver is already quiesced */
+ if (driver)
+ usb_gadget_udc_reset(&dev->gadget, driver);
+
+ /* re-init driver-visible data structures */
+ udc_reinit(dev);
+}
+
+static void
stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
{
int i;
@@ -1311,15 +1333,14 @@ stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
udc_reinit(dev);
}
-static int pxa25x_udc_stop(struct usb_gadget*g,
- struct usb_gadget_driver *driver)
+static int pxa25x_udc_stop(struct usb_gadget*g)
{
struct pxa25x_udc *dev = to_pxa25x(g);
local_irq_disable();
dev->pullup = 0;
pullup(dev);
- stop_activity(dev, driver);
+ stop_activity(dev, NULL);
local_irq_enable();
if (!IS_ERR_OR_NULL(dev->transceiver))
@@ -1723,7 +1744,7 @@ pxa25x_udc_irq(int irq, void *_dev)
/* reset driver and endpoints,
* in case that's not yet done
*/
- stop_activity (dev, dev->driver);
+ reset_gadget(dev, dev->driver);
} else {
DBG(DBG_VERBOSE, "USB reset end\n");
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c
index 4868369eeec6..9b03fab13707 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.c
+++ b/drivers/usb/gadget/udc/pxa27x_udc.c
@@ -22,10 +22,13 @@
#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/prefetch.h>
#include <linux/byteorder/generic.h>
#include <linux/platform_data/pxa2xx_udc.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/usb.h>
#include <linux/usb/ch9.h>
@@ -1507,18 +1510,13 @@ static struct usb_ep_ops pxa_ep_ops = {
*/
static void dplus_pullup(struct pxa_udc *udc, int on)
{
- if (on) {
- if (gpio_is_valid(udc->mach->gpio_pullup))
- gpio_set_value(udc->mach->gpio_pullup,
- !udc->mach->gpio_pullup_inverted);
- if (udc->mach->udc_command)
- udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
- } else {
- if (gpio_is_valid(udc->mach->gpio_pullup))
- gpio_set_value(udc->mach->gpio_pullup,
- udc->mach->gpio_pullup_inverted);
- if (udc->mach->udc_command)
- udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+ if (udc->gpiod) {
+ gpiod_set_value(udc->gpiod, on);
+ } else if (udc->udc_command) {
+ if (on)
+ udc->udc_command(PXA2XX_UDC_CMD_CONNECT);
+ else
+ udc->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
udc->pullup_on = on;
}
@@ -1609,7 +1607,7 @@ static int pxa_udc_pullup(struct usb_gadget *_gadget, int is_active)
{
struct pxa_udc *udc = to_gadget_udc(_gadget);
- if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command)
+ if (!udc->gpiod && !udc->udc_command)
return -EOPNOTSUPP;
dplus_pullup(udc, is_active);
@@ -1671,8 +1669,7 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
static int pxa27x_udc_start(struct usb_gadget *g,
struct usb_gadget_driver *driver);
-static int pxa27x_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
+static int pxa27x_udc_stop(struct usb_gadget *g);
static const struct usb_gadget_ops pxa_udc_ops = {
.get_frame = pxa_udc_get_frame,
@@ -1701,10 +1698,10 @@ static void udc_disable(struct pxa_udc *udc)
udc_writel(udc, UDCICR1, 0);
udc_clear_mask_UDCCR(udc, UDCCR_UDE);
- clk_disable(udc->clk);
ep0_idle(udc);
udc->gadget.speed = USB_SPEED_UNKNOWN;
+ clk_disable(udc->clk);
udc->enabled = 0;
}
@@ -1757,16 +1754,16 @@ static void udc_enable(struct pxa_udc *udc)
if (udc->enabled)
return;
+ clk_enable(udc->clk);
udc_writel(udc, UDCICR0, 0);
udc_writel(udc, UDCICR1, 0);
udc_clear_mask_UDCCR(udc, UDCCR_UDE);
- clk_enable(udc->clk);
-
ep0_idle(udc);
udc->gadget.speed = USB_SPEED_FULL;
memset(&udc->stats, 0, sizeof(udc->stats));
+ pxa_eps_setup(udc);
udc_set_mask_UDCCR(udc, UDCCR_UDE);
ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_ACM);
udelay(2);
@@ -1859,12 +1856,11 @@ static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver)
*
* Returns 0 if no error, -ENODEV, -EINVAL otherwise
*/
-static int pxa27x_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int pxa27x_udc_stop(struct usb_gadget *g)
{
struct pxa_udc *udc = to_pxa(g);
- stop_activity(udc, driver);
+ stop_activity(udc, NULL);
udc_disable(udc);
dplus_pullup(udc, 0);
@@ -2404,6 +2400,14 @@ static struct pxa_udc memory = {
}
};
+#if defined(CONFIG_OF)
+static struct of_device_id udc_pxa_dt_ids[] = {
+ { .compatible = "marvell,pxa270-udc" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, udc_pxa_dt_ids);
+#endif
+
/**
* pxa_udc_probe - probes the udc device
* @_dev: platform device
@@ -2416,81 +2420,77 @@ static int pxa_udc_probe(struct platform_device *pdev)
struct resource *regs;
struct pxa_udc *udc = &memory;
int retval = 0, gpio;
+ struct pxa2xx_udc_mach_info *mach = dev_get_platdata(&pdev->dev);
+ unsigned long gpio_flags;
+
+ if (mach) {
+ gpio_flags = mach->gpio_pullup_inverted ? GPIOF_ACTIVE_LOW : 0;
+ gpio = mach->gpio_pullup;
+ if (gpio_is_valid(gpio)) {
+ retval = devm_gpio_request_one(&pdev->dev, gpio,
+ gpio_flags,
+ "USB D+ pullup");
+ if (retval)
+ return retval;
+ udc->gpiod = gpio_to_desc(mach->gpio_pullup);
+ }
+ udc->udc_command = mach->udc_command;
+ } else {
+ udc->gpiod = devm_gpiod_get(&pdev->dev, NULL);
+ }
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs)
- return -ENXIO;
+ udc->regs = devm_ioremap_resource(&pdev->dev, regs);
+ if (IS_ERR(udc->regs))
+ return PTR_ERR(udc->regs);
udc->irq = platform_get_irq(pdev, 0);
if (udc->irq < 0)
return udc->irq;
udc->dev = &pdev->dev;
- udc->mach = dev_get_platdata(&pdev->dev);
udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
- gpio = udc->mach->gpio_pullup;
- if (gpio_is_valid(gpio)) {
- retval = gpio_request(gpio, "USB D+ pullup");
- if (retval == 0)
- gpio_direction_output(gpio,
- udc->mach->gpio_pullup_inverted);
- }
- if (retval) {
- dev_err(&pdev->dev, "Couldn't request gpio %d : %d\n",
- gpio, retval);
- return retval;
+ if (IS_ERR(udc->gpiod)) {
+ dev_err(&pdev->dev, "Couldn't find or request D+ gpio : %ld\n",
+ PTR_ERR(udc->gpiod));
+ return PTR_ERR(udc->gpiod);
}
+ if (udc->gpiod)
+ gpiod_direction_output(udc->gpiod, 0);
+
+ udc->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(udc->clk))
+ return PTR_ERR(udc->clk);
- udc->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(udc->clk)) {
- retval = PTR_ERR(udc->clk);
- goto err_clk;
- }
retval = clk_prepare(udc->clk);
if (retval)
- goto err_clk_prepare;
-
- retval = -ENOMEM;
- udc->regs = ioremap(regs->start, resource_size(regs));
- if (!udc->regs) {
- dev_err(&pdev->dev, "Unable to map UDC I/O memory\n");
- goto err_map;
- }
+ return retval;
udc->vbus_sensed = 0;
the_controller = udc;
platform_set_drvdata(pdev, udc);
udc_init_data(udc);
- pxa_eps_setup(udc);
/* irq setup after old hardware state is cleaned up */
- retval = request_irq(udc->irq, pxa_udc_irq,
- IRQF_SHARED, driver_name, udc);
+ retval = devm_request_irq(&pdev->dev, udc->irq, pxa_udc_irq,
+ IRQF_SHARED, driver_name, udc);
if (retval != 0) {
dev_err(udc->dev, "%s: can't get irq %i, err %d\n",
driver_name, udc->irq, retval);
- goto err_irq;
+ goto err;
}
retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
if (retval)
- goto err_add_udc;
+ goto err;
pxa_init_debugfs(udc);
-
+ if (should_enable_udc(udc))
+ udc_enable(udc);
return 0;
-
-err_add_udc:
- free_irq(udc->irq, udc);
-err_irq:
- iounmap(udc->regs);
-err_map:
+err:
clk_unprepare(udc->clk);
-err_clk_prepare:
- clk_put(udc->clk);
- udc->clk = NULL;
-err_clk:
return retval;
}
@@ -2501,22 +2501,15 @@ err_clk:
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);
- usb_gadget_unregister_driver(udc->driver);
- free_irq(udc->irq, udc);
pxa_cleanup_debugfs(udc);
- if (gpio_is_valid(gpio))
- gpio_free(gpio);
usb_put_phy(udc->transceiver);
udc->transceiver = NULL;
the_controller = NULL;
clk_unprepare(udc->clk);
- clk_put(udc->clk);
- iounmap(udc->regs);
return 0;
}
@@ -2546,19 +2539,11 @@ extern void pxa27x_clear_otgph(void);
*/
static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state)
{
- int i;
struct pxa_udc *udc = platform_get_drvdata(_dev);
struct pxa_ep *ep;
ep = &udc->pxa_ep[0];
udc->udccsr0 = udc_ep_readl(ep, UDCCSR);
- for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
- ep = &udc->pxa_ep[i];
- ep->udccsr_value = udc_ep_readl(ep, UDCCSR);
- ep->udccr_value = udc_ep_readl(ep, UDCCR);
- ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n",
- ep->udccsr_value, ep->udccr_value);
- }
udc_disable(udc);
udc->pullup_resume = udc->pullup_on;
@@ -2576,19 +2561,11 @@ static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state)
*/
static int pxa_udc_resume(struct platform_device *_dev)
{
- int i;
struct pxa_udc *udc = platform_get_drvdata(_dev);
struct pxa_ep *ep;
ep = &udc->pxa_ep[0];
udc_ep_writel(ep, UDCCSR, udc->udccsr0 & (UDCCSR0_FST | UDCCSR0_DME));
- for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
- ep = &udc->pxa_ep[i];
- udc_ep_writel(ep, UDCCSR, ep->udccsr_value);
- udc_ep_writel(ep, UDCCR, ep->udccr_value);
- ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n",
- ep->udccsr_value, ep->udccr_value);
- }
dplus_pullup(udc, udc->pullup_resume);
if (should_enable_udc(udc))
@@ -2615,6 +2592,7 @@ static struct platform_driver udc_driver = {
.driver = {
.name = "pxa27x-udc",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(udc_pxa_dt_ids),
},
.probe = pxa_udc_probe,
.remove = pxa_udc_remove,
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.h b/drivers/usb/gadget/udc/pxa27x_udc.h
index 28f2b53530f5..11e14232794b 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.h
+++ b/drivers/usb/gadget/udc/pxa27x_udc.h
@@ -420,7 +420,8 @@ struct udc_stats {
* @usb_gadget: udc gadget structure
* @driver: bound gadget (zero, g_ether, g_mass_storage, ...)
* @dev: device
- * @mach: machine info, used to activate specific GPIO
+ * @udc_command: machine specific function to activate D+ pullup
+ * @gpiod: gpio descriptor of gpio for D+ pullup (or NULL if none)
* @transceiver: external transceiver to handle vbus sense and D+ pullup
* @ep0state: control endpoint state machine state
* @stats: statistics on udc usage
@@ -446,7 +447,8 @@ struct pxa_udc {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct device *dev;
- struct pxa2xx_udc_mach_info *mach;
+ void (*udc_command)(int);
+ struct gpio_desc *gpiod;
struct usb_phy *transceiver;
enum ep0_state ep0state;
diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c
index f8186613b53e..06870da0b988 100644
--- a/drivers/usb/gadget/udc/r8a66597-udc.c
+++ b/drivers/usb/gadget/udc/r8a66597-udc.c
@@ -1345,7 +1345,7 @@ static void irq_device_state(struct r8a66597 *r8a66597)
if (dvsq == DS_DFLT) {
/* bus reset */
spin_unlock(&r8a66597->lock);
- r8a66597->driver->disconnect(&r8a66597->gadget);
+ usb_gadget_udc_reset(&r8a66597->gadget, r8a66597->driver);
spin_lock(&r8a66597->lock);
r8a66597_update_usb_speed(r8a66597);
}
@@ -1763,8 +1763,7 @@ static int r8a66597_start(struct usb_gadget *gadget,
return 0;
}
-static int r8a66597_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static int r8a66597_stop(struct usb_gadget *gadget)
{
struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
unsigned long flags;
@@ -1846,10 +1845,7 @@ static int r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597,
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sudmac");
r8a66597->sudmac_reg = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(r8a66597->sudmac_reg))
- return PTR_ERR(r8a66597->sudmac_reg);
-
- return 0;
+ return PTR_ERR_OR_ZERO(r8a66597->sudmac_reg);
}
static int r8a66597_probe(struct platform_device *pdev)
diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c
index dfbf55797360..97d3a9144381 100644
--- a/drivers/usb/gadget/udc/s3c-hsudc.c
+++ b/drivers/usb/gadget/udc/s3c-hsudc.c
@@ -1172,8 +1172,6 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
}
enable_irq(hsudc->irq);
- dev_info(hsudc->dev, "bound driver %s\n", driver->driver.name);
-
s3c_hsudc_reconfig(hsudc);
pm_runtime_get_sync(hsudc->dev);
@@ -1190,8 +1188,7 @@ err_supplies:
return ret;
}
-static int s3c_hsudc_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static int s3c_hsudc_stop(struct usb_gadget *gadget)
{
struct s3c_hsudc *hsudc = to_hsudc(gadget);
unsigned long flags;
@@ -1199,11 +1196,7 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget,
if (!hsudc)
return -ENODEV;
- if (!driver || driver != hsudc->driver)
- return -EINVAL;
-
spin_lock_irqsave(&hsudc->lock, flags);
- hsudc->driver = NULL;
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
s3c_hsudc_uninit_phy();
@@ -1220,9 +1213,8 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget,
disable_irq(hsudc->irq);
regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
+ hsudc->driver = NULL;
- dev_info(hsudc->dev, "unregistered gadget driver '%s'\n",
- driver->driver.name);
return 0;
}
@@ -1267,10 +1259,8 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) +
sizeof(struct s3c_hsudc_ep) * pd->epnum,
GFP_KERNEL);
- if (!hsudc) {
- dev_err(dev, "cannot allocate memory\n");
+ if (!hsudc)
return -ENOMEM;
- }
platform_set_drvdata(pdev, dev);
hsudc->dev = dev;
diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c
index ff423d15beff..2a8e36d31488 100644
--- a/drivers/usb/gadget/udc/s3c2410_udc.c
+++ b/drivers/usb/gadget/udc/s3c2410_udc.c
@@ -1541,8 +1541,7 @@ static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
static int s3c2410_udc_start(struct usb_gadget *g,
struct usb_gadget_driver *driver);
-static int s3c2410_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
+static int s3c2410_udc_stop(struct usb_gadget *g);
static const struct usb_gadget_ops s3c2410_ops = {
.get_frame = s3c2410_udc_get_frame,
@@ -1683,8 +1682,7 @@ static int s3c2410_udc_start(struct usb_gadget *g,
return 0;
}
-static int s3c2410_udc_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int s3c2410_udc_stop(struct usb_gadget *g)
{
struct s3c2410_udc *udc = to_s3c2410(g);
diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
index f2054659f25b..e31d574d8860 100644
--- a/drivers/usb/gadget/udc/udc-core.c
+++ b/drivers/usb/gadget/udc/udc-core.c
@@ -174,8 +174,7 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
/**
* usb_gadget_udc_start - tells usb device controller to start up
- * @gadget: The gadget we want to get started
- * @driver: The driver we want to bind to @gadget
+ * @udc: The UDC to be started
*
* This call is issued by the UDC Class driver when it's about
* to register a gadget driver to the device controller, before
@@ -186,10 +185,9 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
*
* Returns zero on success, else negative errno.
*/
-static inline int usb_gadget_udc_start(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static inline int usb_gadget_udc_start(struct usb_udc *udc)
{
- return gadget->ops->udc_start(gadget, driver);
+ return udc->gadget->ops->udc_start(udc->gadget, udc->driver);
}
/**
@@ -204,10 +202,9 @@ static inline int usb_gadget_udc_start(struct usb_gadget *gadget,
* far as powering off UDC completely and disable its data
* line pullups.
*/
-static inline void usb_gadget_udc_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static inline void usb_gadget_udc_stop(struct usb_udc *udc)
{
- gadget->ops->udc_stop(gadget, driver);
+ udc->gadget->ops->udc_stop(udc->gadget);
}
/**
@@ -328,14 +325,14 @@ EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
static void usb_gadget_remove_driver(struct usb_udc *udc)
{
dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
- udc->gadget->name);
+ udc->driver->function);
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
usb_gadget_disconnect(udc->gadget);
udc->driver->disconnect(udc->gadget);
udc->driver->unbind(udc->gadget);
- usb_gadget_udc_stop(udc->gadget, NULL);
+ usb_gadget_udc_stop(udc);
udc->driver = NULL;
udc->dev.driver = NULL;
@@ -395,7 +392,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
ret = driver->bind(udc->gadget, driver);
if (ret)
goto err1;
- ret = usb_gadget_udc_start(udc->gadget, driver);
+ ret = usb_gadget_udc_start(udc);
if (ret) {
driver->unbind(udc->gadget);
goto err1;
@@ -414,7 +411,7 @@ err1:
return ret;
}
-int udc_attach_driver(const char *name, struct usb_gadget_driver *driver)
+int usb_udc_attach_driver(const char *name, struct usb_gadget_driver *driver)
{
struct usb_udc *udc = NULL;
int ret = -ENODEV;
@@ -438,7 +435,7 @@ out:
mutex_unlock(&udc_lock);
return ret;
}
-EXPORT_SYMBOL_GPL(udc_attach_driver);
+EXPORT_SYMBOL_GPL(usb_udc_attach_driver);
int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
{
@@ -513,11 +510,12 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
}
if (sysfs_streq(buf, "connect")) {
- usb_gadget_udc_start(udc->gadget, udc->driver);
+ usb_gadget_udc_start(udc);
usb_gadget_connect(udc->gadget);
} else if (sysfs_streq(buf, "disconnect")) {
usb_gadget_disconnect(udc->gadget);
- usb_gadget_udc_stop(udc->gadget, udc->driver);
+ udc->driver->disconnect(udc->gadget);
+ usb_gadget_udc_stop(udc);
} else {
dev_err(dev, "unsupported command '%s'\n", buf);
return -EINVAL;
diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c
index ed27e1687a4e..1eac56fc384d 100644
--- a/drivers/usb/gadget/udc/udc-xilinx.c
+++ b/drivers/usb/gadget/udc/udc-xilinx.c
@@ -1403,8 +1403,7 @@ err:
*
* Return: zero always
*/
-static int xudc_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static int xudc_stop(struct usb_gadget *gadget)
{
struct xusb_udc *udc = to_udc(gadget);
unsigned long flags;
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index a3ca1375dd52..fafc628480e0 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -292,11 +292,15 @@ config USB_EHCI_HCD_PLATFORM
If unsure, say N.
config USB_OCTEON_EHCI
- bool "Octeon on-chip EHCI support"
+ bool "Octeon on-chip EHCI support (DEPRECATED)"
depends on CAVIUM_OCTEON_SOC
default n
select USB_EHCI_BIG_ENDIAN_MMIO
+ select USB_EHCI_HCD_PLATFORM
help
+ This option is deprecated now and the driver was removed, use
+ USB_EHCI_HCD_PLATFORM instead.
+
Enable support for the Octeon II SOC's on-chip EHCI
controller. It is needed for high-speed (480Mbit/sec)
USB 2.0 device support. All CN6XXX based chips with USB are
@@ -575,12 +579,16 @@ config USB_OHCI_HCD_PLATFORM
If unsure, say N.
config USB_OCTEON_OHCI
- bool "Octeon on-chip OHCI support"
+ bool "Octeon on-chip OHCI support (DEPRECATED)"
depends on CAVIUM_OCTEON_SOC
default USB_OCTEON_EHCI
select USB_OHCI_BIG_ENDIAN_MMIO
select USB_OHCI_LITTLE_ENDIAN
+ select USB_OHCI_HCD_PLATFORM
help
+ This option is deprecated now and the driver was removed, use
+ USB_OHCI_HCD_PLATFORM instead.
+
Enable support for the Octeon II SOC's on-chip OHCI
controller. It is needed for low-speed USB 1.0 device
support. All CN6XXX based chips with USB are supported.
@@ -754,12 +762,6 @@ config USB_IMX21_HCD
To compile this driver as a module, choose M here: the
module will be called "imx21-hcd".
-
-
-config USB_OCTEON2_COMMON
- bool
- default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
-
config USB_HCD_BCMA
tristate "BCMA usb host driver"
depends on BCMA
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 348c24321562..d6216a493bab 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -73,7 +73,6 @@ obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
-obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
obj-$(CONFIG_USB_FUSBH200_HCD) += fusbh200-hcd.o
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index ec9f7b75d497..56a88506febe 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -107,22 +107,15 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev,
- "Found HC with no register addr. Check %s setup!\n",
- dev_name(&pdev->dev));
- retval = -ENODEV;
- goto fail_request_resource;
- }
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
retval = PTR_ERR(hcd->regs);
goto fail_request_resource;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
iclk = devm_clk_get(&pdev->dev, "ehci_clk");
if (IS_ERR(iclk)) {
dev_err(&pdev->dev, "Error getting interface clock\n");
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index 7189f2e32ac2..f58c9750e3e4 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -74,7 +74,6 @@ static int exynos_ehci_get_phy(struct device *dev,
phy = devm_of_phy_get(dev, child, NULL);
exynos_ehci->phy[phy_number] = phy;
- of_node_put(child);
if (IS_ERR(phy)) {
ret = PTR_ERR(phy);
if (ret == -EPROBE_DEFER) {
@@ -188,20 +187,15 @@ skip_phy:
goto fail_clk;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Failed to get I/O memory\n");
- err = -ENXIO;
- goto fail_io;
- }
-
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
goto fail_io;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
irq = platform_get_irq(pdev, 0);
if (!irq) {
dev_err(&pdev->dev, "Failed to get IRQ\n");
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 2d2ae8db439e..fb7bd0c7dc15 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -93,21 +93,15 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev,
- "Found HC with no register addr. Check %s setup!\n",
- dev_name(&pdev->dev));
- retval = -ENODEV;
- goto err2;
- }
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
retval = PTR_ERR(hcd->regs);
goto err2;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
pdata->regs = hcd->regs;
if (pdata->power_budget)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 15feaf924b71..38bfeedae1d0 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -311,6 +311,7 @@ static void unlink_empty_async_suspended(struct ehci_hcd *ehci);
static void ehci_work(struct ehci_hcd *ehci);
static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);
static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);
+static int ehci_port_power(struct ehci_hcd *ehci, int portnum, bool enable);
#include "ehci-timer.c"
#include "ehci-hub.c"
@@ -329,9 +330,13 @@ static void ehci_turn_off_all_ports(struct ehci_hcd *ehci)
{
int port = HCS_N_PORTS(ehci->hcs_params);
- while (port--)
+ while (port--) {
ehci_writel(ehci, PORT_RWC_BITS,
&ehci->regs->port_status[port]);
+ spin_unlock_irq(&ehci->lock);
+ ehci_port_power(ehci, port, false);
+ spin_lock_irq(&ehci->lock);
+ }
}
/*
@@ -1233,6 +1238,8 @@ void ehci_init_driver(struct hc_driver *drv,
drv->hcd_priv_size += over->extra_priv_size;
if (over->reset)
drv->reset = over->reset;
+ if (over->port_power)
+ drv->port_power = over->port_power;
}
}
EXPORT_SYMBOL_GPL(ehci_init_driver);
@@ -1268,11 +1275,6 @@ MODULE_LICENSE ("GPL");
#define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver
#endif
-#ifdef CONFIG_USB_OCTEON_EHCI
-#include "ehci-octeon.c"
-#define PLATFORM_DRIVER ehci_octeon_driver
-#endif
-
#ifdef CONFIG_TILE_USB
#include "ehci-tilegx.c"
#define PLATFORM_DRIVER ehci_hcd_tilegx_driver
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 5728829cf6ef..118edb7bdca2 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -69,10 +69,8 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
if (test_bit(port, &ehci->owned_ports)) {
reg = &ehci->regs->port_status[port];
status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
- if (!(status & PORT_POWER)) {
- status |= PORT_POWER;
- ehci_writel(ehci, status, reg);
- }
+ if (!(status & PORT_POWER))
+ ehci_port_power(ehci, port, true);
}
}
@@ -952,9 +950,11 @@ int ehci_hub_control(
clear_bit(wIndex, &ehci->port_c_suspend);
break;
case USB_PORT_FEAT_POWER:
- if (HCS_PPC (ehci->hcs_params))
- ehci_writel(ehci, temp & ~PORT_POWER,
- status_reg);
+ if (HCS_PPC(ehci->hcs_params)) {
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ ehci_port_power(ehci, wIndex, false);
+ spin_lock_irqsave(&ehci->lock, flags);
+ }
break;
case USB_PORT_FEAT_C_CONNECTION:
ehci_writel(ehci, temp | PORT_CSC, status_reg);
@@ -1004,9 +1004,9 @@ int ehci_hub_control(
*/
if (((temp & PORT_OC) || (ehci->need_oc_pp_cycle))
&& HCS_PPC(ehci->hcs_params)) {
- ehci_writel(ehci,
- temp & ~(PORT_RWC_BITS | PORT_POWER),
- status_reg);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ ehci_port_power(ehci, wIndex, false);
+ spin_lock_irqsave(&ehci->lock, flags);
temp = ehci_readl(ehci, status_reg);
}
}
@@ -1187,9 +1187,11 @@ int ehci_hub_control(
set_bit(wIndex, &ehci->suspended_ports);
break;
case USB_PORT_FEAT_POWER:
- if (HCS_PPC (ehci->hcs_params))
- ehci_writel(ehci, temp | PORT_POWER,
- status_reg);
+ if (HCS_PPC(ehci->hcs_params)) {
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ ehci_port_power(ehci, wIndex, true);
+ spin_lock_irqsave(&ehci->lock, flags);
+ }
break;
case USB_PORT_FEAT_RESET:
if (temp & (PORT_SUSPEND|PORT_RESUME))
@@ -1297,3 +1299,20 @@ static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum)
reg = &ehci->regs->port_status[portnum - 1];
return ehci_readl(ehci, reg) & PORT_OWNER;
}
+
+static int ehci_port_power(struct ehci_hcd *ehci, int portnum, bool enable)
+{
+ struct usb_hcd *hcd = ehci_to_hcd(ehci);
+ u32 __iomem *status_reg = &ehci->regs->port_status[portnum];
+ u32 temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS;
+
+ if (enable)
+ ehci_writel(ehci, temp | PORT_POWER, status_reg);
+ else
+ ehci_writel(ehci, temp & ~PORT_POWER, status_reg);
+
+ if (hcd->driver->port_power)
+ hcd->driver->port_power(hcd, portnum, enable);
+
+ return 0;
+}
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 9dc2118ae808..9db74ca7e5b9 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -88,19 +88,13 @@ static int ehci_msm_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get memory resource\n");
- ret = -ENODEV;
- goto put_hcd;
- }
-
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
ret = PTR_ERR(hcd->regs);
goto put_hcd;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
/*
* OTG driver takes care of PHY initialization, clock management,
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index 08147c35f836..849806a75f1c 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -153,7 +153,6 @@ static int mv_ehci_probe(struct platform_device *pdev)
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;
goto err_put_hcd;
}
@@ -170,12 +169,6 @@ static int mv_ehci_probe(struct platform_device *pdev)
}
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs");
- if (r == NULL) {
- dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
- retval = -ENODEV;
- goto err_put_hcd;
- }
-
ehci_mv->phy_regs = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(ehci_mv->phy_regs)) {
retval = PTR_ERR(ehci_mv->phy_regs);
@@ -183,12 +176,6 @@ static int mv_ehci_probe(struct platform_device *pdev)
}
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs");
- if (!r) {
- dev_err(&pdev->dev, "no I/O memory resource defined\n");
- retval = -ENODEV;
- goto err_put_hcd;
- }
-
ehci_mv->cap_regs = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(ehci_mv->cap_regs)) {
retval = PTR_ERR(ehci_mv->cap_regs);
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index dbe5e4eea08d..c7a9b31eeaef 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -69,20 +69,13 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "Found HC with no register addr. Check setup!\n");
- ret = -ENODEV;
- goto err_alloc;
- }
-
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
ret = PTR_ERR(hcd->regs);
goto err_alloc;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
hcd->has_tt = 1;
ehci = hcd_to_ehci(hcd);
diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c
deleted file mode 100644
index 9051439039a7..000000000000
--- a/drivers/usb/host/ehci-octeon.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * EHCI HCD glue for Cavium Octeon II SOCs.
- *
- * Loosely based on ehci-au1xxx.c
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2010 Cavium Networks
- *
- */
-
-#include <linux/platform_device.h>
-
-#include <asm/octeon/octeon.h>
-#include <asm/octeon/cvmx-uctlx-defs.h>
-
-#define OCTEON_EHCI_HCD_NAME "octeon-ehci"
-
-/* Common clock init code. */
-void octeon2_usb_clocks_start(void);
-void octeon2_usb_clocks_stop(void);
-
-static void ehci_octeon_start(void)
-{
- union cvmx_uctlx_ehci_ctl ehci_ctl;
-
- octeon2_usb_clocks_start();
-
- ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0));
- /* Use 64-bit addressing. */
- ehci_ctl.s.ehci_64b_addr_en = 1;
- ehci_ctl.s.l2c_addr_msb = 0;
- ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */
- ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */
- cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64);
-}
-
-static void ehci_octeon_stop(void)
-{
- octeon2_usb_clocks_stop();
-}
-
-static const struct hc_driver ehci_octeon_hc_driver = {
- .description = hcd_name,
- .product_desc = "Octeon EHCI",
- .hcd_priv_size = sizeof(struct ehci_hcd),
-
- /*
- * generic hardware linkage
- */
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
-
- /*
- * basic lifecycle operations
- */
- .reset = ehci_setup,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
-
- /*
- * scheduling support
- */
- .get_frame_number = ehci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
-
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
-
-static u64 ehci_octeon_dma_mask = DMA_BIT_MASK(64);
-
-static int ehci_octeon_drv_probe(struct platform_device *pdev)
-{
- struct usb_hcd *hcd;
- struct ehci_hcd *ehci;
- struct resource *res_mem;
- int irq;
- int ret;
-
- if (usb_disabled())
- return -ENODEV;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "No irq assigned\n");
- return -ENODEV;
- }
-
- res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res_mem == NULL) {
- dev_err(&pdev->dev, "No register space assigned\n");
- return -ENODEV;
- }
-
- /*
- * We can DMA from anywhere. But the descriptors must be in
- * the lower 4GB.
- */
- pdev->dev.dma_mask = &ehci_octeon_dma_mask;
- ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (ret)
- return ret;
-
- hcd = usb_create_hcd(&ehci_octeon_hc_driver, &pdev->dev, "octeon");
- if (!hcd)
- return -ENOMEM;
-
- hcd->rsrc_start = res_mem->start;
- hcd->rsrc_len = resource_size(res_mem);
-
- hcd->regs = devm_ioremap_resource(&pdev->dev, res_mem);
- if (IS_ERR(hcd->regs)) {
- ret = PTR_ERR(hcd->regs);
- goto err1;
- }
-
- ehci_octeon_start();
-
- ehci = hcd_to_ehci(hcd);
-
- /* Octeon EHCI matches CPU endianness. */
-#ifdef __BIG_ENDIAN
- ehci->big_endian_mmio = 1;
-#endif
-
- ehci->caps = hcd->regs;
-
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
- if (ret) {
- dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
- goto err2;
- }
- device_wakeup_enable(hcd->self.controller);
-
- platform_set_drvdata(pdev, hcd);
-
- return 0;
-err2:
- ehci_octeon_stop();
-
-err1:
- usb_put_hcd(hcd);
- return ret;
-}
-
-static int ehci_octeon_drv_remove(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
- usb_remove_hcd(hcd);
-
- ehci_octeon_stop();
- usb_put_hcd(hcd);
-
- return 0;
-}
-
-static struct platform_driver ehci_octeon_driver = {
- .probe = ehci_octeon_drv_probe,
- .remove = ehci_octeon_drv_remove,
- .shutdown = usb_hcd_platform_shutdown,
- .driver = {
- .name = OCTEON_EHCI_HCD_NAME,
- .owner = THIS_MODULE,
- }
-};
-
-MODULE_ALIAS("platform:" OCTEON_EHCI_HCD_NAME);
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index 22e15cab8ea5..3c76489ea61a 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -25,8 +25,8 @@
#include "ehci.h"
-#define rdl(off) __raw_readl(hcd->regs + (off))
-#define wrl(off, val) __raw_writel((val), hcd->regs + (off))
+#define rdl(off) readl_relaxed(hcd->regs + (off))
+#define wrl(off, val) writel_relaxed((val), hcd->regs + (off))
#define USB_CMD 0x140
#define USB_MODE 0x1a8
@@ -175,15 +175,6 @@ static int ehci_orion_drv_probe(struct platform_device *pdev)
goto err;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev,
- "Found HC with no register addr. Check %s setup!\n",
- dev_name(&pdev->dev));
- err = -ENODEV;
- goto err;
- }
-
/*
* Right now device-tree probed devices don't get dma_mask
* set. Since shared usb code relies on it, set it here for
@@ -193,6 +184,7 @@ static int ehci_orion_drv_probe(struct platform_device *pdev)
if (err)
goto err;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(regs)) {
err = PTR_ERR(regs);
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 2f5b9ce3e042..35a9aeda0168 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -164,11 +164,6 @@ static int ehci_platform_probe(struct platform_device *dev)
dev_err(&dev->dev, "no irq provided");
return irq;
}
- res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!res_mem) {
- dev_err(&dev->dev, "no memory resource provided");
- return -ENXIO;
- }
hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
dev_name(&dev->dev));
@@ -250,14 +245,15 @@ static int ehci_platform_probe(struct platform_device *dev)
goto err_reset;
}
- hcd->rsrc_start = res_mem->start;
- hcd->rsrc_len = resource_size(res_mem);
-
+ res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
goto err_power;
}
+ hcd->rsrc_start = res_mem->start;
+ hcd->rsrc_len = resource_size(res_mem);
+
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err)
goto err_power;
@@ -311,8 +307,7 @@ static int ehci_platform_remove(struct platform_device *dev)
return 0;
}
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
static int ehci_platform_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
@@ -348,11 +343,7 @@ static int ehci_platform_resume(struct device *dev)
ehci_resume(hcd, false);
return 0;
}
-
-#else /* !CONFIG_PM */
-#define ehci_platform_suspend NULL
-#define ehci_platform_resume NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static const struct of_device_id vt8500_ehci_ids[] = {
{ .compatible = "via,vt8500-ehci", },
@@ -368,10 +359,8 @@ static const struct platform_device_id ehci_platform_table[] = {
};
MODULE_DEVICE_TABLE(platform, ehci_platform_table);
-static const struct dev_pm_ops ehci_platform_pm_ops = {
- .suspend = ehci_platform_suspend,
- .resume = ehci_platform_resume,
-};
+static SIMPLE_DEV_PM_OPS(ehci_platform_pm_ops, ehci_platform_suspend,
+ ehci_platform_resume);
static struct platform_driver ehci_platform_driver = {
.id_table = ehci_platform_table,
diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c
index cf1267673868..9b6e8d0eac43 100644
--- a/drivers/usb/host/ehci-sead3.c
+++ b/drivers/usb/host/ehci-sead3.c
@@ -110,14 +110,13 @@ static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
ret = PTR_ERR(hcd->regs);
goto err1;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
/* Root hub has integrated TT. */
hcd->has_tt = 1;
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index 9b9b9f5b016e..0e0ce684aff3 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -86,15 +86,6 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
if (usb_disabled())
return -ENODEV;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev,
- "Found HC with no register addr. Check %s setup!\n",
- dev_name(&pdev->dev));
- ret = -ENODEV;
- goto fail_create_hcd;
- }
-
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(&pdev->dev,
@@ -114,19 +105,18 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
goto fail_create_hcd;
}
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
ret = PTR_ERR(hcd->regs);
goto fail_request_resource;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
priv = devm_kzalloc(&pdev->dev, sizeof(struct ehci_sh_priv),
GFP_KERNEL);
if (!priv) {
- dev_dbg(&pdev->dev, "error allocating priv data\n");
ret = -ENOMEM;
goto fail_request_resource;
}
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index 1355ff0946b9..34e14746b92e 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -99,18 +99,13 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- retval = -ENODEV;
- goto err_put_hcd;
- }
-
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
retval = PTR_ERR(hcd->regs);
goto err_put_hcd;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
sehci = to_spear_ehci(hcd);
sehci->clk = usbh_clk;
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index aaa01971efe9..19a9af1b4d74 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -460,18 +460,14 @@ static int tegra_ehci_probe(struct platform_device *pdev)
"nvidia,needs-double-reset");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Failed to get I/O memory\n");
- err = -ENXIO;
- goto cleanup_clk_en;
- }
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
goto cleanup_clk_en;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
ehci->caps = hcd->regs + 0x100;
ehci->has_hostpc = soc_config->has_hostpc;
@@ -484,7 +480,6 @@ static int tegra_ehci_probe(struct platform_device *pdev)
u_phy->otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
GFP_KERNEL);
if (!u_phy->otg) {
- dev_err(&pdev->dev, "Failed to alloc memory for otg\n");
err = -ENOMEM;
goto cleanup_phy;
}
diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c
index a9303aff125e..c305732e8634 100644
--- a/drivers/usb/host/ehci-w90x900.c
+++ b/drivers/usb/host/ehci-w90x900.c
@@ -42,27 +42,20 @@ static int usb_w90x900_probe(const struct hc_driver *driver,
int retval = 0, irq;
unsigned long val;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- retval = -ENXIO;
- goto err1;
- }
-
hcd = usb_create_hcd(driver, &pdev->dev, "w90x900 EHCI");
if (!hcd) {
retval = -ENOMEM;
goto err1;
}
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
retval = PTR_ERR(hcd->regs);
goto err2;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs;
@@ -82,8 +75,10 @@ static int usb_w90x900_probe(const struct hc_driver *driver,
__raw_writel(val, ehci->regs+PHY1_CTR);
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
+ if (irq < 0) {
+ retval = irq;
goto err2;
+ }
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval != 0)
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index eee228a26a0e..6f0577b0a5ae 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -859,6 +859,8 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
struct ehci_driver_overrides {
size_t extra_priv_size;
int (*reset)(struct usb_hcd *hcd);
+ int (*port_power)(struct usb_hcd *hcd,
+ int portnum, bool enable);
};
extern void ehci_init_driver(struct hc_driver *drv,
diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h
index ac6cd1bfd208..3bad17859cd7 100644
--- a/drivers/usb/host/fotg210.h
+++ b/drivers/usb/host/fotg210.h
@@ -1,6 +1,8 @@
#ifndef __LINUX_FOTG210_H
#define __LINUX_FOTG210_H
+#include <linux/usb/ehci-dbgp.h>
+
/* definitions used for the EHCI driver */
/*
@@ -84,7 +86,7 @@ struct fotg210_hcd { /* one per controller */
/* glue to PCI and HCD framework */
struct fotg210_caps __iomem *caps;
struct fotg210_regs __iomem *regs;
- struct fotg210_dbg_port __iomem *debug;
+ struct ehci_dbg_port __iomem *debug;
__u32 hcs_params; /* cached register copy */
spinlock_t lock;
@@ -293,64 +295,6 @@ struct fotg210_regs {
#define GMIR_MDEV_INT (1 << 0)
};
-/* Appendix C, Debug port ... intended for use with special "debug devices"
- * that can help if there's no serial console. (nonstandard enumeration.)
- */
-struct fotg210_dbg_port {
- u32 control;
-#define DBGP_OWNER (1<<30)
-#define DBGP_ENABLED (1<<28)
-#define DBGP_DONE (1<<16)
-#define DBGP_INUSE (1<<10)
-#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
-# define DBGP_ERR_BAD 1
-# define DBGP_ERR_SIGNAL 2
-#define DBGP_ERROR (1<<6)
-#define DBGP_GO (1<<5)
-#define DBGP_OUT (1<<4)
-#define DBGP_LEN(x) (((x)>>0)&0x0f)
- u32 pids;
-#define DBGP_PID_GET(x) (((x)>>16)&0xff)
-#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok))
- u32 data03;
- u32 data47;
- u32 address;
-#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep))
-};
-
-#ifdef CONFIG_EARLY_PRINTK_DBGP
-#include <linux/init.h>
-extern int __init early_dbgp_init(char *s);
-extern struct console early_dbgp_console;
-#endif /* CONFIG_EARLY_PRINTK_DBGP */
-
-struct usb_hcd;
-
-static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd)
-{
- return 1; /* Shouldn't this be 0? */
-}
-
-static inline int xen_dbgp_external_startup(struct usb_hcd *hcd)
-{
- return -1;
-}
-
-#ifdef CONFIG_EARLY_PRINTK_DBGP
-/* Call backs from fotg210 host driver to fotg210 debug driver */
-extern int dbgp_external_startup(struct usb_hcd *);
-extern int dbgp_reset_prep(struct usb_hcd *hcd);
-#else
-static inline int dbgp_reset_prep(struct usb_hcd *hcd)
-{
- return xen_dbgp_reset_prep(hcd);
-}
-static inline int dbgp_external_startup(struct usb_hcd *hcd)
-{
- return xen_dbgp_external_startup(hcd);
-}
-#endif
-
/*-------------------------------------------------------------------------*/
#define QTD_NEXT(fotg210, dma) cpu_to_hc32(fotg210, (u32)dma)
diff --git a/drivers/usb/host/fusbh200.h b/drivers/usb/host/fusbh200.h
index 6b719e066c3f..d6e5b3d4aa68 100644
--- a/drivers/usb/host/fusbh200.h
+++ b/drivers/usb/host/fusbh200.h
@@ -1,6 +1,8 @@
#ifndef __LINUX_FUSBH200_H
#define __LINUX_FUSBH200_H
+#include <linux/usb/ehci-dbgp.h>
+
/* definitions used for the EHCI driver */
/*
@@ -84,7 +86,7 @@ struct fusbh200_hcd { /* one per controller */
/* glue to PCI and HCD framework */
struct fusbh200_caps __iomem *caps;
struct fusbh200_regs __iomem *regs;
- struct fusbh200_dbg_port __iomem *debug;
+ struct ehci_dbg_port __iomem *debug;
__u32 hcs_params; /* cached register copy */
spinlock_t lock;
@@ -285,64 +287,6 @@ struct fusbh200_regs {
#define BMIER_VBUS_ERR_EN (1<<0)
};
-/* Appendix C, Debug port ... intended for use with special "debug devices"
- * that can help if there's no serial console. (nonstandard enumeration.)
- */
-struct fusbh200_dbg_port {
- u32 control;
-#define DBGP_OWNER (1<<30)
-#define DBGP_ENABLED (1<<28)
-#define DBGP_DONE (1<<16)
-#define DBGP_INUSE (1<<10)
-#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
-# define DBGP_ERR_BAD 1
-# define DBGP_ERR_SIGNAL 2
-#define DBGP_ERROR (1<<6)
-#define DBGP_GO (1<<5)
-#define DBGP_OUT (1<<4)
-#define DBGP_LEN(x) (((x)>>0)&0x0f)
- u32 pids;
-#define DBGP_PID_GET(x) (((x)>>16)&0xff)
-#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok))
- u32 data03;
- u32 data47;
- u32 address;
-#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep))
-};
-
-#ifdef CONFIG_EARLY_PRINTK_DBGP
-#include <linux/init.h>
-extern int __init early_dbgp_init(char *s);
-extern struct console early_dbgp_console;
-#endif /* CONFIG_EARLY_PRINTK_DBGP */
-
-struct usb_hcd;
-
-static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd)
-{
- return 1; /* Shouldn't this be 0? */
-}
-
-static inline int xen_dbgp_external_startup(struct usb_hcd *hcd)
-{
- return -1;
-}
-
-#ifdef CONFIG_EARLY_PRINTK_DBGP
-/* Call backs from fusbh200 host driver to fusbh200 debug driver */
-extern int dbgp_external_startup(struct usb_hcd *);
-extern int dbgp_reset_prep(struct usb_hcd *hcd);
-#else
-static inline int dbgp_reset_prep(struct usb_hcd *hcd)
-{
- return xen_dbgp_reset_prep(hcd);
-}
-static inline int dbgp_external_startup(struct usb_hcd *hcd)
-{
- return xen_dbgp_external_startup(hcd);
-}
-#endif
-
/*-------------------------------------------------------------------------*/
#define QTD_NEXT(fusbh200, dma) cpu_to_hc32(fusbh200, (u32)dma)
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
index 207bad99301f..eb4efba9f1ad 100644
--- a/drivers/usb/host/imx21-hcd.c
+++ b/drivers/usb/host/imx21-hcd.c
@@ -1174,11 +1174,11 @@ static int imx21_hc_urb_enqueue(struct usb_hcd *hcd,
dev_vdbg(imx21->dev,
"enqueue urb=%p ep=%p len=%d "
- "buffer=%p dma=%08X setupBuf=%p setupDma=%08X\n",
+ "buffer=%p dma=%pad setupBuf=%p setupDma=%pad\n",
urb, ep,
urb->transfer_buffer_length,
- urb->transfer_buffer, urb->transfer_dma,
- urb->setup_packet, urb->setup_dma);
+ urb->transfer_buffer, &urb->transfer_dma,
+ urb->setup_packet, &urb->setup_dma);
if (usb_pipeisoc(urb->pipe))
return imx21_hc_urb_enqueue_isoc(hcd, ep, urb, mem_flags);
diff --git a/drivers/usb/host/octeon2-common.c b/drivers/usb/host/octeon2-common.c
deleted file mode 100644
index d9df423f3d12..000000000000
--- a/drivers/usb/host/octeon2-common.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2010, 2011 Cavium Networks
- */
-
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-
-#include <asm/octeon/octeon.h>
-#include <asm/octeon/cvmx-uctlx-defs.h>
-
-static DEFINE_MUTEX(octeon2_usb_clocks_mutex);
-
-static int octeon2_usb_clock_start_cnt;
-
-void octeon2_usb_clocks_start(void)
-{
- u64 div;
- union cvmx_uctlx_if_ena if_ena;
- union cvmx_uctlx_clk_rst_ctl clk_rst_ctl;
- union cvmx_uctlx_uphy_ctl_status uphy_ctl_status;
- union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status;
- int i;
- unsigned long io_clk_64_to_ns;
-
-
- mutex_lock(&octeon2_usb_clocks_mutex);
-
- octeon2_usb_clock_start_cnt++;
- if (octeon2_usb_clock_start_cnt != 1)
- goto exit;
-
- io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate();
-
- /*
- * Step 1: Wait for voltages stable. That surely happened
- * before starting the kernel.
- *
- * Step 2: Enable SCLK of UCTL by writing UCTL0_IF_ENA[EN] = 1
- */
- if_ena.u64 = 0;
- if_ena.s.en = 1;
- cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64);
-
- /* Step 3: Configure the reference clock, PHY, and HCLK */
- clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));
-
- /*
- * If the UCTL looks like it has already been started, skip
- * the initialization, otherwise bus errors are obtained.
- */
- if (clk_rst_ctl.s.hrst)
- goto end_clock;
- /* 3a */
- clk_rst_ctl.s.p_por = 1;
- clk_rst_ctl.s.hrst = 0;
- clk_rst_ctl.s.p_prst = 0;
- clk_rst_ctl.s.h_clkdiv_rst = 0;
- clk_rst_ctl.s.o_clkdiv_rst = 0;
- clk_rst_ctl.s.h_clkdiv_en = 0;
- clk_rst_ctl.s.o_clkdiv_en = 0;
- cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
-
- /* 3b */
- /* 12MHz crystal. */
- clk_rst_ctl.s.p_refclk_sel = 0;
- clk_rst_ctl.s.p_refclk_div = 0;
- cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
-
- /* 3c */
- div = octeon_get_io_clock_rate() / 130000000ull;
-
- switch (div) {
- case 0:
- div = 1;
- break;
- case 1:
- case 2:
- case 3:
- case 4:
- break;
- case 5:
- div = 4;
- break;
- case 6:
- case 7:
- div = 6;
- break;
- case 8:
- case 9:
- case 10:
- case 11:
- div = 8;
- break;
- default:
- div = 12;
- break;
- }
- clk_rst_ctl.s.h_div = div;
- cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
- /* Read it back, */
- clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));
- clk_rst_ctl.s.h_clkdiv_en = 1;
- cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
- /* 3d */
- clk_rst_ctl.s.h_clkdiv_rst = 1;
- cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
-
- /* 3e: delay 64 io clocks */
- ndelay(io_clk_64_to_ns);
-
- /*
- * Step 4: Program the power-on reset field in the UCTL
- * clock-reset-control register.
- */
- clk_rst_ctl.s.p_por = 0;
- cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
-
- /* Step 5: Wait 1 ms for the PHY clock to start. */
- mdelay(1);
-
- /*
- * Step 6: Program the reset input from automatic test
- * equipment field in the UPHY CSR
- */
- uphy_ctl_status.u64 = cvmx_read_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0));
- uphy_ctl_status.s.ate_reset = 1;
- cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64);
-
- /* Step 7: Wait for at least 10ns. */
- ndelay(10);
-
- /* Step 8: Clear the ATE_RESET field in the UPHY CSR. */
- uphy_ctl_status.s.ate_reset = 0;
- cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64);
-
- /*
- * Step 9: Wait for at least 20ns for UPHY to output PHY clock
- * signals and OHCI_CLK48
- */
- ndelay(20);
-
- /* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */
- /* 10a */
- clk_rst_ctl.s.o_clkdiv_rst = 1;
- cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
-
- /* 10b */
- clk_rst_ctl.s.o_clkdiv_en = 1;
- cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
-
- /* 10c */
- ndelay(io_clk_64_to_ns);
-
- /*
- * Step 11: Program the PHY reset field:
- * UCTL0_CLK_RST_CTL[P_PRST] = 1
- */
- clk_rst_ctl.s.p_prst = 1;
- cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
-
- /* Step 12: Wait 1 uS. */
- udelay(1);
-
- /* Step 13: Program the HRESET_N field: UCTL0_CLK_RST_CTL[HRST] = 1 */
- clk_rst_ctl.s.hrst = 1;
- cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
-
-end_clock:
- /* Now we can set some other registers. */
-
- for (i = 0; i <= 1; i++) {
- port_ctl_status.u64 =
- cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0));
- /* Set txvreftune to 15 to obtain compliant 'eye' diagram. */
- port_ctl_status.s.txvreftune = 15;
- port_ctl_status.s.txrisetune = 1;
- port_ctl_status.s.txpreemphasistune = 1;
- cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0),
- port_ctl_status.u64);
- }
-
- /* Set uSOF cycle period to 60,000 bits. */
- cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull);
-exit:
- mutex_unlock(&octeon2_usb_clocks_mutex);
-}
-EXPORT_SYMBOL(octeon2_usb_clocks_start);
-
-void octeon2_usb_clocks_stop(void)
-{
- mutex_lock(&octeon2_usb_clocks_mutex);
- octeon2_usb_clock_start_cnt--;
- mutex_unlock(&octeon2_usb_clocks_mutex);
-}
-EXPORT_SYMBOL(octeon2_usb_clocks_stop);
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index e49eb4f90f5d..39406607e53a 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -24,12 +24,8 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
-#include <mach/hardware.h>
#include <asm/gpio.h>
-#include <mach/cpu.h>
-
-
#include "ohci.h"
#define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS)
@@ -137,12 +133,6 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
struct resource *res;
int irq;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_dbg(dev, "hcd probe: missing memory resource\n");
- return -ENXIO;
- }
-
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_dbg(dev, "hcd probe: missing irq resource\n");
@@ -152,14 +142,15 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
hcd = usb_create_hcd(driver, dev, "at91");
if (!hcd)
return -ENOMEM;
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(hcd->regs)) {
retval = PTR_ERR(hcd->regs);
goto err;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
iclk = devm_clk_get(dev, "ohci_clk");
if (IS_ERR(iclk)) {
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index df06be6b47f5..1c76999b2184 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -313,16 +313,13 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
return -ENOMEM;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem)
- return -ENODEV;
- hcd->rsrc_start = mem->start;
- hcd->rsrc_len = resource_size(mem);
-
hcd->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(hcd->regs)) {
error = PTR_ERR(hcd->regs);
goto err;
}
+ hcd->rsrc_start = mem->start;
+ hcd->rsrc_len = resource_size(mem);
ohci_hcd_init(hcd_to_ohci(hcd));
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index d28b6583ba02..035a8a85a867 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -63,7 +63,6 @@ static int exynos_ohci_get_phy(struct device *dev,
phy = devm_of_phy_get(dev, child, NULL);
exynos_ohci->phy[phy_number] = phy;
- of_node_put(child);
if (IS_ERR(phy)) {
ret = PTR_ERR(phy);
if (ret == -EPROBE_DEFER) {
@@ -156,19 +155,13 @@ skip_phy:
goto fail_clk;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Failed to get I/O memory\n");
- err = -ENXIO;
- goto fail_io;
- }
-
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
goto fail_io;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
irq = platform_get_irq(pdev, 0);
if (!irq) {
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index d664edabf14e..1dab9dfbca6a 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1249,11 +1249,6 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_hcd_jz4740_driver
#endif
-#ifdef CONFIG_USB_OCTEON_OHCI
-#include "ohci-octeon.c"
-#define PLATFORM_DRIVER ohci_octeon_driver
-#endif
-
#ifdef CONFIG_TILE_USB
#include "ohci-tilegx.c"
#define PLATFORM_DRIVER ohci_hcd_tilegx_driver
diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c
index c2c221a332eb..8ddd8f5470cb 100644
--- a/drivers/usb/host/ohci-jz4740.c
+++ b/drivers/usb/host/ohci-jz4740.c
@@ -153,13 +153,6 @@ static int jz4740_ohci_probe(struct platform_device *pdev)
struct resource *res;
int irq;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- if (!res) {
- dev_err(&pdev->dev, "Failed to get platform resource\n");
- return -ENOENT;
- }
-
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "Failed to get platform irq\n");
@@ -174,14 +167,14 @@ static int jz4740_ohci_probe(struct platform_device *pdev)
jz4740_ohci = hcd_to_jz4740_hcd(hcd);
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
ret = PTR_ERR(hcd->regs);
goto err_free;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
jz4740_ohci->clk = devm_clk_get(&pdev->dev, "uhc");
if (IS_ERR(jz4740_ohci->clk)) {
diff --git a/drivers/usb/host/ohci-octeon.c b/drivers/usb/host/ohci-octeon.c
deleted file mode 100644
index 15af8954085e..000000000000
--- a/drivers/usb/host/ohci-octeon.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * EHCI HCD glue for Cavium Octeon II SOCs.
- *
- * Loosely based on ehci-au1xxx.c
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2010 Cavium Networks
- *
- */
-
-#include <linux/platform_device.h>
-
-#include <asm/octeon/octeon.h>
-#include <asm/octeon/cvmx-uctlx-defs.h>
-
-#define OCTEON_OHCI_HCD_NAME "octeon-ohci"
-
-/* Common clock init code. */
-void octeon2_usb_clocks_start(void);
-void octeon2_usb_clocks_stop(void);
-
-static void ohci_octeon_hw_start(void)
-{
- union cvmx_uctlx_ohci_ctl ohci_ctl;
-
- octeon2_usb_clocks_start();
-
- ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0));
- ohci_ctl.s.l2c_addr_msb = 0;
- ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */
- ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */
- cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64);
-
-}
-
-static void ohci_octeon_hw_stop(void)
-{
- /* Undo ohci_octeon_start() */
- octeon2_usb_clocks_stop();
-}
-
-static int ohci_octeon_start(struct usb_hcd *hcd)
-{
- struct ohci_hcd *ohci = hcd_to_ohci(hcd);
- int ret;
-
- ret = ohci_init(ohci);
-
- if (ret < 0)
- return ret;
-
- ret = ohci_run(ohci);
-
- if (ret < 0) {
- ohci_err(ohci, "can't start %s", hcd->self.bus_name);
- ohci_stop(hcd);
- return ret;
- }
-
- return 0;
-}
-
-static const struct hc_driver ohci_octeon_hc_driver = {
- .description = hcd_name,
- .product_desc = "Octeon OHCI",
- .hcd_priv_size = sizeof(struct ohci_hcd),
-
- /*
- * generic hardware linkage
- */
- .irq = ohci_irq,
- .flags = HCD_USB11 | HCD_MEMORY,
-
- /*
- * basic lifecycle operations
- */
- .start = ohci_octeon_start,
- .stop = ohci_stop,
- .shutdown = ohci_shutdown,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ohci_urb_enqueue,
- .urb_dequeue = ohci_urb_dequeue,
- .endpoint_disable = ohci_endpoint_disable,
-
- /*
- * scheduling support
- */
- .get_frame_number = ohci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ohci_hub_status_data,
- .hub_control = ohci_hub_control,
-
- .start_port_reset = ohci_start_port_reset,
-};
-
-static int ohci_octeon_drv_probe(struct platform_device *pdev)
-{
- struct usb_hcd *hcd;
- struct ohci_hcd *ohci;
- void *reg_base;
- struct resource *res_mem;
- int irq;
- int ret;
-
- if (usb_disabled())
- return -ENODEV;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "No irq assigned\n");
- return -ENODEV;
- }
-
- res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res_mem == NULL) {
- dev_err(&pdev->dev, "No register space assigned\n");
- return -ENODEV;
- }
-
- /* Ohci is a 32-bit device. */
- ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
- if (ret)
- return ret;
-
- hcd = usb_create_hcd(&ohci_octeon_hc_driver, &pdev->dev, "octeon");
- if (!hcd)
- return -ENOMEM;
-
- hcd->rsrc_start = res_mem->start;
- hcd->rsrc_len = resource_size(res_mem);
-
- reg_base = devm_ioremap_resource(&pdev->dev, res_mem);
- if (IS_ERR(reg_base)) {
- ret = PTR_ERR(reg_base);
- goto err1;
- }
-
- ohci_octeon_hw_start();
-
- hcd->regs = reg_base;
-
- ohci = hcd_to_ohci(hcd);
-
- /* Octeon OHCI matches CPU endianness. */
-#ifdef __BIG_ENDIAN
- ohci->flags |= OHCI_QUIRK_BE_MMIO;
-#endif
-
- ohci_hcd_init(ohci);
-
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
- if (ret) {
- dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
- goto err2;
- }
-
- device_wakeup_enable(hcd->self.controller);
-
- platform_set_drvdata(pdev, hcd);
-
- return 0;
-
-err2:
- ohci_octeon_hw_stop();
-
-err1:
- usb_put_hcd(hcd);
- return ret;
-}
-
-static int ohci_octeon_drv_remove(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
- usb_remove_hcd(hcd);
-
- ohci_octeon_hw_stop();
- usb_put_hcd(hcd);
-
- return 0;
-}
-
-static struct platform_driver ohci_octeon_driver = {
- .probe = ohci_octeon_drv_probe,
- .remove = ohci_octeon_drv_remove,
- .shutdown = usb_hcd_platform_shutdown,
- .driver = {
- .name = OCTEON_OHCI_HCD_NAME,
- .owner = THIS_MODULE,
- }
-};
-
-MODULE_ALIAS("platform:" OCTEON_OHCI_HCD_NAME);
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 0231606d47c2..3e5df5af3740 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -183,7 +183,7 @@ static void start_hnp(struct ohci_hcd *ohci)
otg_start_hnp(hcd->usb_phy->otg);
local_irq_save(flags);
- hcd->usb_phy->state = OTG_STATE_A_SUSPEND;
+ hcd->usb_phy->otg->state = OTG_STATE_A_SUSPEND;
writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [port]);
l = omap_readl(OTG_CTRL);
l &= ~OTG_A_BUSREQ;
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index 4369299064c7..9434c1d54495 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -43,20 +43,6 @@ struct ohci_platform_priv {
static const char hcd_name[] = "ohci-platform";
-static int ohci_platform_reset(struct usb_hcd *hcd)
-{
- struct platform_device *pdev = to_platform_device(hcd->self.controller);
- struct usb_ohci_pdata *pdata = dev_get_platdata(&pdev->dev);
- struct ohci_hcd *ohci = hcd_to_ohci(hcd);
-
- if (pdata->no_big_frame_no)
- ohci->flags |= OHCI_QUIRK_FRAME_NO;
- if (pdata->num_ports)
- ohci->num_ports = pdata->num_ports;
-
- return ohci_setup(hcd);
-}
-
static int ohci_platform_power_on(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
@@ -110,7 +96,6 @@ static struct hc_driver __read_mostly ohci_platform_hc_driver;
static const struct ohci_driver_overrides platform_overrides __initconst = {
.product_desc = "Generic Platform OHCI controller",
- .reset = ohci_platform_reset,
.extra_priv_size = sizeof(struct ohci_platform_priv),
};
@@ -149,12 +134,6 @@ static int ohci_platform_probe(struct platform_device *dev)
return irq;
}
- res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!res_mem) {
- dev_err(&dev->dev, "no memory resource provided");
- return -ENXIO;
- }
-
hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
dev_name(&dev->dev));
if (!hcd)
@@ -175,6 +154,12 @@ static int ohci_platform_probe(struct platform_device *dev)
if (of_property_read_bool(dev->dev.of_node, "big-endian"))
ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+ if (of_property_read_bool(dev->dev.of_node, "no-big-frame-no"))
+ ohci->flags |= OHCI_QUIRK_FRAME_NO;
+
+ of_property_read_u32(dev->dev.of_node, "num-ports",
+ &ohci->num_ports);
+
priv->phy = devm_phy_get(&dev->dev, "usb");
if (IS_ERR(priv->phy)) {
err = PTR_ERR(priv->phy);
@@ -212,6 +197,10 @@ static int ohci_platform_probe(struct platform_device *dev)
ohci->flags |= OHCI_QUIRK_BE_DESC;
if (pdata->big_endian_mmio)
ohci->flags |= OHCI_QUIRK_BE_MMIO;
+ if (pdata->no_big_frame_no)
+ ohci->flags |= OHCI_QUIRK_FRAME_NO;
+ if (pdata->num_ports)
+ ohci->num_ports = pdata->num_ports;
#ifndef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
if (ohci->flags & OHCI_QUIRK_BE_MMIO) {
@@ -236,14 +225,15 @@ static int ohci_platform_probe(struct platform_device *dev)
goto err_reset;
}
- hcd->rsrc_start = res_mem->start;
- hcd->rsrc_len = resource_size(res_mem);
-
+ res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
goto err_power;
}
+ hcd->rsrc_start = res_mem->start;
+ hcd->rsrc_len = resource_size(res_mem);
+
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err)
goto err_power;
@@ -298,8 +288,7 @@ static int ohci_platform_remove(struct platform_device *dev)
return 0;
}
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
static int ohci_platform_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
@@ -335,11 +324,7 @@ static int ohci_platform_resume(struct device *dev)
ohci_resume(hcd, false);
return 0;
}
-
-#else /* !CONFIG_PM */
-#define ohci_platform_suspend NULL
-#define ohci_platform_resume NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static const struct of_device_id ohci_platform_ids[] = {
{ .compatible = "generic-ohci", },
@@ -353,10 +338,8 @@ static const struct platform_device_id ohci_platform_table[] = {
};
MODULE_DEVICE_TABLE(platform, ohci_platform_table);
-static const struct dev_pm_ops ohci_platform_pm_ops = {
- .suspend = ohci_platform_suspend,
- .resume = ohci_platform_resume,
-};
+static SIMPLE_DEV_PM_OPS(ohci_platform_pm_ops, ohci_platform_suspend,
+ ohci_platform_resume);
static struct platform_driver ohci_platform_driver = {
.id_table = ohci_platform_table,
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index e68f3d02cd1a..13399814ef5f 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -447,20 +447,13 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
return -ENOMEM;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- pr_err("no resource of IORESOURCE_MEM");
- retval = -ENXIO;
- goto err;
- }
-
- hcd->rsrc_start = r->start;
- hcd->rsrc_len = resource_size(r);
-
hcd->regs = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(hcd->regs)) {
retval = PTR_ERR(hcd->regs);
goto err;
}
+ hcd->rsrc_start = r->start;
+ hcd->rsrc_len = resource_size(r);
/* initialize "struct pxa27x_ohci" */
pxa_ohci = to_pxa27x_ohci(hcd);
diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c
index 8d5876692e7c..4a54f9d73136 100644
--- a/drivers/usb/host/ohci-spear.c
+++ b/drivers/usb/host/ohci-spear.c
@@ -74,20 +74,15 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- retval = -ENODEV;
- goto err_put_hcd;
- }
-
- hcd->rsrc_start = pdev->resource[0].start;
- hcd->rsrc_len = resource_size(res);
-
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
retval = PTR_ERR(hcd->regs);
goto err_put_hcd;
}
+ hcd->rsrc_start = pdev->resource[0].start;
+ hcd->rsrc_len = resource_size(res);
+
sohci_p = to_spear_ohci(hcd);
sohci_p->clk = usbh_clk;
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 59f424567a8d..bc462288cfb0 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -647,23 +647,22 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
/*-------------------------------------------------------------------------*/
-/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
- * hardware handles 16 bit reads. That creates a different confusion on
- * some big-endian SOC implementations. Same thing happens with PSW access.
+/*
+ * The HCCA frame number is 16 bits, but is accessed as 32 bits since not all
+ * hardware handles 16 bit reads. Depending on the SoC implementation, the
+ * frame number can wind up in either bits [31:16] (default) or
+ * [15:0] (OHCI_QUIRK_FRAME_NO) on big endian hosts.
+ *
+ * Somewhat similarly, the 16-bit PSW fields in a transfer descriptor are
+ * reordered on BE.
*/
-#ifdef CONFIG_PPC_MPC52xx
-#define big_endian_frame_no_quirk(ohci) (ohci->flags & OHCI_QUIRK_FRAME_NO)
-#else
-#define big_endian_frame_no_quirk(ohci) 0
-#endif
-
static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
{
u32 tmp;
if (big_endian_desc(ohci)) {
tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
- if (!big_endian_frame_no_quirk(ohci))
+ if (!(ohci->flags & OHCI_QUIRK_FRAME_NO))
tmp >>= 16;
} else
tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 4fe79a2d71a9..75811dd5a9d7 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -3846,7 +3846,6 @@ static int oxu_drv_probe(struct platform_device *pdev)
*/
info = devm_kzalloc(&pdev->dev, sizeof(struct oxu_info), GFP_KERNEL);
if (!info) {
- dev_dbg(&pdev->dev, "error allocating memory\n");
ret = -EFAULT;
goto error;
}
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 2f3acebb577a..dd483c13565b 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -233,10 +233,8 @@ commit:
spin_unlock_irqrestore(&amd_lock, flags);
- if (info.nb_dev)
- pci_dev_put(info.nb_dev);
- if (info.smbus_dev)
- pci_dev_put(info.smbus_dev);
+ pci_dev_put(info.nb_dev);
+ pci_dev_put(info.smbus_dev);
} else {
/* no race - commit the result */
@@ -447,10 +445,8 @@ void usb_amd_dev_put(void)
spin_unlock_irqrestore(&amd_lock, flags);
- if (nb)
- pci_dev_put(nb);
- if (smbus)
- pci_dev_put(smbus);
+ pci_dev_put(nb);
+ pci_dev_put(smbus);
}
EXPORT_SYMBOL_GPL(usb_amd_dev_put);
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
index b987f1d10058..cf8f46003f62 100644
--- a/drivers/usb/host/uhci-platform.c
+++ b/drivers/usb/host/uhci-platform.c
@@ -86,14 +86,14 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
ret = PTR_ERR(hcd->regs);
goto err_rmr;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
uhci = hcd_to_uhci(hcd);
uhci->regs = hcd->regs;
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 646300cbe5f7..08d402b15482 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -83,9 +83,6 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (irq < 0)
return -ENODEV;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
if (of_device_is_compatible(pdev->dev.of_node,
"marvell,armada-375-xhci") ||
@@ -109,15 +106,16 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (!hcd)
return -ENOMEM;
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
ret = PTR_ERR(hcd->regs);
goto put_hcd;
}
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
/*
* Not all platforms have a clk so it is not an error if the
* clock does not exists.
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 06433aec81d7..e692e769c50c 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -716,9 +716,7 @@ remove_finished_td:
ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
}
- /* Clear stopped_td if endpoint is not halted */
- if (!(ep->ep_state & EP_HALTED))
- ep->stopped_td = NULL;
+ ep->stopped_td = NULL;
/*
* Drop the lock and complete the URBs in the cancelled TD list.
@@ -1732,13 +1730,11 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
return;
ep->ep_state |= EP_HALTED;
- ep->stopped_td = td;
ep->stopped_stream = stream_id;
xhci_queue_reset_ep(xhci, command, slot_id, ep_index);
- xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index);
+ xhci_cleanup_stalled_ring(xhci, ep_index, td);
- ep->stopped_td = NULL;
ep->stopped_stream = 0;
xhci_ring_cmd_db(xhci);
@@ -1813,72 +1809,65 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
if (skip)
goto td_cleanup;
- if (trb_comp_code == COMP_STOP_INVAL ||
- trb_comp_code == COMP_STOP) {
+ if (trb_comp_code == COMP_STOP_INVAL || trb_comp_code == COMP_STOP) {
/* The Endpoint Stop Command completion will take care of any
* stopped TDs. A stopped TD may be restarted, so don't update
* the ring dequeue pointer or take this TD off any lists yet.
*/
ep->stopped_td = td;
return 0;
+ }
+ if (trb_comp_code == COMP_STALL ||
+ xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
+ trb_comp_code)) {
+ /* Issue a reset endpoint command to clear the host side
+ * halt, followed by a set dequeue command to move the
+ * dequeue pointer past the TD.
+ * The class driver clears the device side halt later.
+ */
+ xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index,
+ ep_ring->stream_id, td, event_trb);
} else {
- if (trb_comp_code == COMP_STALL ||
- xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
- trb_comp_code)) {
- /* Issue a reset endpoint command to clear the host side
- * halt, followed by a set dequeue command to move the
- * dequeue pointer past the TD.
- * The class driver clears the device side halt later.
- */
- xhci_cleanup_halted_endpoint(xhci,
- slot_id, ep_index, ep_ring->stream_id,
- td, event_trb);
- } else {
- /* Update ring dequeue pointer */
- while (ep_ring->dequeue != td->last_trb)
- inc_deq(xhci, ep_ring);
+ /* Update ring dequeue pointer */
+ while (ep_ring->dequeue != td->last_trb)
inc_deq(xhci, ep_ring);
- }
+ inc_deq(xhci, ep_ring);
+ }
td_cleanup:
- /* Clean up the endpoint's TD list */
- urb = td->urb;
- urb_priv = urb->hcpriv;
-
- /* Do one last check of the actual transfer length.
- * If the host controller said we transferred more data than
- * the buffer length, urb->actual_length will be a very big
- * number (since it's unsigned). Play it safe and say we didn't
- * transfer anything.
- */
- if (urb->actual_length > urb->transfer_buffer_length) {
- xhci_warn(xhci, "URB transfer length is wrong, "
- "xHC issue? req. len = %u, "
- "act. len = %u\n",
- urb->transfer_buffer_length,
- urb->actual_length);
- urb->actual_length = 0;
- if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
- *status = -EREMOTEIO;
- else
- *status = 0;
- }
- list_del_init(&td->td_list);
- /* Was this TD slated to be cancelled but completed anyway? */
- if (!list_empty(&td->cancelled_td_list))
- list_del_init(&td->cancelled_td_list);
-
- urb_priv->td_cnt++;
- /* Giveback the urb when all the tds are completed */
- if (urb_priv->td_cnt == urb_priv->length) {
- ret = 1;
- if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
- xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs--;
- if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs
- == 0) {
- if (xhci->quirks & XHCI_AMD_PLL_FIX)
- usb_amd_quirk_pll_enable();
- }
+ /* Clean up the endpoint's TD list */
+ urb = td->urb;
+ urb_priv = urb->hcpriv;
+
+ /* Do one last check of the actual transfer length.
+ * If the host controller said we transferred more data than the buffer
+ * length, urb->actual_length will be a very big number (since it's
+ * unsigned). Play it safe and say we didn't transfer anything.
+ */
+ if (urb->actual_length > urb->transfer_buffer_length) {
+ xhci_warn(xhci, "URB transfer length is wrong, xHC issue? req. len = %u, act. len = %u\n",
+ urb->transfer_buffer_length,
+ urb->actual_length);
+ urb->actual_length = 0;
+ if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
+ *status = -EREMOTEIO;
+ else
+ *status = 0;
+ }
+ list_del_init(&td->td_list);
+ /* Was this TD slated to be cancelled but completed anyway? */
+ if (!list_empty(&td->cancelled_td_list))
+ list_del_init(&td->cancelled_td_list);
+
+ urb_priv->td_cnt++;
+ /* Giveback the urb when all the tds are completed */
+ if (urb_priv->td_cnt == urb_priv->length) {
+ ret = 1;
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+ xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs--;
+ if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) {
+ if (xhci->quirks & XHCI_AMD_PLL_FIX)
+ usb_amd_quirk_pll_enable();
}
}
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index cf3413116aff..01fcbb5eb06e 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -2912,10 +2912,11 @@ static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
}
void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
- struct usb_device *udev, unsigned int ep_index)
+ unsigned int ep_index, struct xhci_td *td)
{
struct xhci_dequeue_state deq_state;
struct xhci_virt_ep *ep;
+ struct usb_device *udev = td->urb->dev;
xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
"Cleaning up stalled endpoint ring");
@@ -2924,8 +2925,7 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
* or it will attempt to resend it on the next doorbell ring.
*/
xhci_find_new_dequeue_state(xhci, udev->slot_id,
- ep_index, ep->stopped_stream, ep->stopped_td,
- &deq_state);
+ ep_index, ep->stopped_stream, td, &deq_state);
if (!deq_state.new_deq_ptr || !deq_state.new_deq_seg)
return;
@@ -4009,6 +4009,7 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx);
slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT));
slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency);
+ slot_ctx->dev_state = 0;
xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
"Set up evaluate context for LPM MEL change.");
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index d745715a1e2f..cc7c5bb7cbcf 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -358,7 +358,7 @@ struct xhci_op_regs {
/* wake on over-current (enable) */
#define PORT_WKOC_E (1 << 27)
/* bits 28:29 reserved */
-/* true: device is removable - for USB 3.0 roothub emulation */
+/* true: device is non-removable - for USB 3.0 roothub emulation */
#define PORT_DEV_REMOVE (1 << 30)
/* Initiate a warm port reset - complete when PORT_WRC is '1' */
#define PORT_WR (1 << 31)
@@ -1825,7 +1825,7 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
unsigned int stream_id,
struct xhci_dequeue_state *deq_state);
void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
- struct usb_device *udev, unsigned int ep_index);
+ unsigned int ep_index, struct xhci_td *td);
void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
struct xhci_dequeue_state *deq_state);
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index 493c7f268b6f..3071c0ef909b 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -814,15 +814,10 @@ static void adu_disconnect(struct usb_interface *interface)
usb_set_intfdata(interface, NULL);
/* if the device is not opened, then we clean up right now */
- dev_dbg(&dev->udev->dev, "%s : open count %d\n",
- __func__, dev->open_count);
if (!dev->open_count)
adu_delete(dev);
mutex_unlock(&adutux_mutex);
-
- dev_info(&interface->dev, "ADU device adutux%d now disconnected\n",
- (minor - ADU_MINOR_BASE));
}
/* usb specific object needed to register this driver with the usb subsystem */
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 633caf643122..022dc0008f2a 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -2472,8 +2472,7 @@ sisusb_delete(struct kref *kref)
if (!sisusb)
return;
- if (sisusb->sisusb_dev)
- usb_put_dev(sisusb->sisusb_dev);
+ usb_put_dev(sisusb->sisusb_dev);
sisusb->sisusb_dev = NULL;
sisusb_free_buffers(sisusb);
diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c
index ae7e1206ca54..b9af8cb19215 100644
--- a/drivers/usb/misc/usb3503.c
+++ b/drivers/usb/misc/usb3503.c
@@ -314,10 +314,8 @@ static int usb3503_i2c_probe(struct i2c_client *i2c,
int err;
hub = devm_kzalloc(&i2c->dev, sizeof(struct usb3503), GFP_KERNEL);
- if (!hub) {
- dev_err(&i2c->dev, "private data alloc fail\n");
+ if (!hub)
return -ENOMEM;
- }
i2c_set_clientdata(i2c, hub);
hub->regmap = devm_regmap_init_i2c(i2c, &usb3503_regmap_config);
@@ -336,10 +334,8 @@ static int usb3503_platform_probe(struct platform_device *pdev)
struct usb3503 *hub;
hub = devm_kzalloc(&pdev->dev, sizeof(struct usb3503), GFP_KERNEL);
- if (!hub) {
- dev_err(&pdev->dev, "private data alloc fail\n");
+ if (!hub)
return -ENOMEM;
- }
hub->dev = &pdev->dev;
return usb3503_probe(hub);
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index c3a45da11610..343fa6ff9f4b 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -410,7 +410,8 @@ static int yurex_release(struct inode *inode, struct file *file)
return 0;
}
-static ssize_t yurex_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
+ loff_t *ppos)
{
struct usb_yurex *dev;
int retval = 0;
@@ -444,7 +445,8 @@ exit:
return retval;
}
-static ssize_t yurex_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos)
+static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
+ size_t count, loff_t *ppos)
{
struct usb_yurex *dev;
int i, set = 0, retval = 0;
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 06cc5d6ea681..9d68372dd9aa 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -58,8 +58,7 @@ config USB_MUSB_DUAL_ROLE
endchoice
-choice
- prompt "Platform Glue Layer"
+comment "Platform Glue Layer"
config USB_MUSB_DAVINCI
tristate "DaVinci"
@@ -101,8 +100,6 @@ config USB_MUSB_JZ4740
depends on USB_MUSB_GADGET
depends on USB_OTG_BLACKLIST_HUB
-endchoice
-
config USB_MUSB_AM335X_CHILD
tristate
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index a2735df24cc6..220fd4d3b41c 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -149,25 +149,25 @@ static void otg_timer(unsigned long _musb)
*/
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_WAIT_BCON:
devctl &= ~MUSB_DEVCTL_SESSION;
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if (devctl & MUSB_DEVCTL_BDEVICE) {
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
MUSB_DEV_MODE(musb);
} else {
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
}
break;
case OTG_STATE_A_WAIT_VFALL:
- musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
musb_writel(musb->ctrl_base, CORE_INTR_SRC_SET_REG,
MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT);
break;
@@ -176,7 +176,7 @@ static void otg_timer(unsigned long _musb)
if (devctl & MUSB_DEVCTL_BDEVICE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
else
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
break;
default:
break;
@@ -193,9 +193,9 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
/* Never idle if active, or when VBUS timeout is not set as host */
if (musb->is_active || (musb->a_wait_bcon == 0 &&
- musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+ musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->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",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
jiffies_to_msecs(timeout - jiffies));
mod_timer(&otg_workaround, timeout);
}
@@ -278,27 +278,27 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
* devctl.
*/
musb->int_usb &= ~MUSB_INTR_VBUSERROR;
- musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
WARNING("VBUS error workaround (delay coming)\n");
} else if (drvvbus) {
MUSB_HST_MODE(musb);
otg->default_a = 1;
- musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
portstate(musb->port1_status |= USB_PORT_STAT_POWER);
del_timer(&otg_workaround);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
otg->default_a = 0;
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
}
/* NOTE: this must complete power-on within 100 ms. */
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
err ? " ERROR" : "",
devctl);
ret = IRQ_HANDLED;
@@ -324,7 +324,7 @@ eoi:
}
/* Poll for ID change */
- if (musb->xceiv->state == OTG_STATE_B_IDLE)
+ if (musb->xceiv->otg->state == OTG_STATE_B_IDLE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
spin_unlock_irqrestore(&musb->lock, flags);
@@ -408,7 +408,7 @@ static int am35x_musb_exit(struct musb *musb)
}
/* AM35x supports only 32bit read operation */
-void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+static void am35x_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
{
void __iomem *fifo = hw_ep->fifo;
u32 val;
@@ -438,9 +438,11 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
}
static const struct musb_platform_ops am35x_ops = {
+ .quirks = MUSB_INDEXED_EP,
.init = am35x_musb_init,
.exit = am35x_musb_exit,
+ .read_fifo = am35x_read_fifo,
.enable = am35x_musb_enable,
.disable = am35x_musb_disable,
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index ac4422b33dcd..a441a2de8619 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -33,10 +33,45 @@ struct bfin_glue {
};
#define glue_to_musb(g) platform_get_drvdata(g->musb)
+static u32 bfin_fifo_offset(u8 epnum)
+{
+ return USB_OFFSET(USB_EP0_FIFO) + (epnum * 8);
+}
+
+static u8 bfin_readb(const void __iomem *addr, unsigned offset)
+{
+ return (u8)(bfin_read16(addr + offset));
+}
+
+static u16 bfin_readw(const void __iomem *addr, unsigned offset)
+{
+ return bfin_read16(addr + offset);
+}
+
+static u32 bfin_readl(const void __iomem *addr, unsigned offset)
+{
+ return (u32)(bfin_read16(addr + offset));
+}
+
+static void bfin_writeb(void __iomem *addr, unsigned offset, u8 data)
+{
+ bfin_write16(addr + offset, (u16)data);
+}
+
+static void bfin_writew(void __iomem *addr, unsigned offset, u16 data)
+{
+ bfin_write16(addr + offset, data);
+}
+
+static void binf_writel(void __iomem *addr, unsigned offset, u32 data)
+{
+ bfin_write16(addr + offset, (u16)data);
+}
+
/*
* Load an endpoint's FIFO
*/
-void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
+static void bfin_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
{
struct musb *musb = hw_ep->musb;
void __iomem *fifo = hw_ep->fifo;
@@ -100,7 +135,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
/*
* Unload an endpoint's FIFO
*/
-void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+static void bfin_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
{
struct musb *musb = hw_ep->musb;
void __iomem *fifo = hw_ep->fifo;
@@ -185,8 +220,8 @@ static irqreturn_t blackfin_interrupt(int irq, void *__hci)
}
/* Start sampling ID pin, when plug is removed from MUSB */
- if ((musb->xceiv->state == OTG_STATE_B_IDLE
- || musb->xceiv->state == OTG_STATE_A_WAIT_BCON) ||
+ if ((musb->xceiv->otg->state == OTG_STATE_B_IDLE
+ || musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON) ||
(musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) {
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
musb->a_wait_bcon = TIMER_DELAY;
@@ -205,7 +240,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
static u8 toggle;
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_IDLE:
case OTG_STATE_A_WAIT_BCON:
/* Start a new session */
@@ -219,7 +254,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
if (!(val & MUSB_DEVCTL_BDEVICE)) {
gpio_set_value(musb->config->gpio_vrsel, 1);
- musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
} else {
gpio_set_value(musb->config->gpio_vrsel, 0);
/* Ignore VBUSERROR and SUSPEND IRQ */
@@ -229,7 +264,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
musb_writeb(musb->mregs, MUSB_INTRUSB, val);
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
}
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
break;
@@ -245,7 +280,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
if (!(val & MUSB_DEVCTL_BDEVICE)) {
gpio_set_value(musb->config->gpio_vrsel, 1);
- musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
} else {
gpio_set_value(musb->config->gpio_vrsel, 0);
@@ -280,13 +315,13 @@ static void musb_conn_timer_handler(unsigned long _musb)
break;
default:
dev_dbg(musb->controller, "%s state not handled\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
break;
}
spin_unlock_irqrestore(&musb->lock, flags);
dev_dbg(musb->controller, "state is %s\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
}
static void bfin_musb_enable(struct musb *musb)
@@ -307,7 +342,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",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
musb_readb(musb->mregs, MUSB_DEVCTL));
}
@@ -433,6 +468,15 @@ static const struct musb_platform_ops bfin_ops = {
.init = bfin_musb_init,
.exit = bfin_musb_exit,
+ .readb = bfin_readb,
+ .writeb = bfin_writeb,
+ .readw = bfin_readw,
+ .writew = bfin_writew,
+ .readl = bfin_readl,
+ .writel = bfin_writel,
+ .fifo_mode = 2,
+ .read_fifo = bfin_read_fifo,
+ .write_fifo = bfin_write_fifo,
.enable = bfin_musb_enable,
.disable = bfin_musb_disable,
@@ -456,16 +500,12 @@ static int bfin_probe(struct platform_device *pdev)
int ret = -ENOMEM;
glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
- if (!glue) {
- dev_err(&pdev->dev, "failed to allocate glue context\n");
+ if (!glue)
goto err0;
- }
musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
- if (!musb) {
- dev_err(&pdev->dev, "failed to allocate musb device\n");
+ if (!musb)
goto err0;
- }
musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = &bfin_dmamask;
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 058775e647ad..9a9c82a4d35d 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -198,20 +198,20 @@ static void otg_timer(unsigned long _musb)
*/
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_WAIT_BCON:
devctl &= ~MUSB_DEVCTL_SESSION;
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if (devctl & MUSB_DEVCTL_BDEVICE) {
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
MUSB_DEV_MODE(musb);
} else {
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
}
break;
@@ -226,7 +226,7 @@ static void otg_timer(unsigned long _musb)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
break;
}
- musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
musb_writel(musb->ctrl_base, DA8XX_USB_INTR_SRC_SET_REG,
MUSB_INTR_VBUSERROR << DA8XX_INTR_USB_SHIFT);
break;
@@ -248,7 +248,7 @@ static void otg_timer(unsigned long _musb)
if (devctl & MUSB_DEVCTL_BDEVICE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
else
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
break;
default:
break;
@@ -265,9 +265,9 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
/* Never idle if active, or when VBUS timeout is not set as host */
if (musb->is_active || (musb->a_wait_bcon == 0 &&
- musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+ musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->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",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
jiffies_to_msecs(timeout - jiffies));
mod_timer(&otg_workaround, timeout);
}
@@ -341,26 +341,26 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
* devctl.
*/
musb->int_usb &= ~MUSB_INTR_VBUSERROR;
- musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
WARNING("VBUS error workaround (delay coming)\n");
} else if (drvvbus) {
MUSB_HST_MODE(musb);
otg->default_a = 1;
- musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
portstate(musb->port1_status |= USB_PORT_STAT_POWER);
del_timer(&otg_workaround);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
otg->default_a = 0;
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
}
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
err ? " ERROR" : "",
devctl);
ret = IRQ_HANDLED;
@@ -375,7 +375,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0);
/* Poll for ID change */
- if (musb->xceiv->state == OTG_STATE_B_IDLE)
+ if (musb->xceiv->otg->state == OTG_STATE_B_IDLE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
spin_unlock_irqrestore(&musb->lock, flags);
@@ -458,9 +458,11 @@ static int da8xx_musb_exit(struct musb *musb)
}
static const struct musb_platform_ops da8xx_ops = {
+ .quirks = MUSB_INDEXED_EP,
.init = da8xx_musb_init,
.exit = da8xx_musb_exit,
+ .fifo_mode = 2,
.enable = da8xx_musb_enable,
.disable = da8xx_musb_disable,
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index 110b78415bf0..3c1d9b211b51 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -214,10 +214,10 @@ static void otg_timer(unsigned long _musb)
*/
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl,
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_WAIT_VFALL:
/* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
* seems to mis-handle session "start" otherwise (or in our
@@ -228,7 +228,7 @@ static void otg_timer(unsigned long _musb)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
break;
}
- musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
break;
@@ -251,7 +251,7 @@ static void otg_timer(unsigned long _musb)
if (devctl & MUSB_DEVCTL_BDEVICE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
else
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
break;
default:
break;
@@ -325,20 +325,20 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
* to stop registering in devctl.
*/
musb->int_usb &= ~MUSB_INTR_VBUSERROR;
- musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
WARNING("VBUS error workaround (delay coming)\n");
} else if (drvvbus) {
MUSB_HST_MODE(musb);
otg->default_a = 1;
- musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
portstate(musb->port1_status |= USB_PORT_STAT_POWER);
del_timer(&otg_workaround);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
otg->default_a = 0;
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
}
@@ -348,7 +348,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",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
err ? " ERROR" : "",
devctl);
retval = IRQ_HANDLED;
@@ -361,7 +361,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
musb_writel(tibase, DAVINCI_USB_EOI_REG, 0);
/* poll for ID change */
- if (musb->xceiv->state == OTG_STATE_B_IDLE)
+ if (musb->xceiv->otg->state == OTG_STATE_B_IDLE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
spin_unlock_irqrestore(&musb->lock, flags);
@@ -520,10 +520,8 @@ static int davinci_probe(struct platform_device *pdev)
int ret = -ENOMEM;
glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
- if (!glue) {
- dev_err(&pdev->dev, "failed to allocate glue context\n");
+ if (!glue)
goto err0;
- }
clk = devm_clk_get(&pdev->dev, "usb");
if (IS_ERR(clk)) {
diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c
index d1187290d4e3..bb7b26325a74 100644
--- a/drivers/usb/musb/jz4740.c
+++ b/drivers/usb/musb/jz4740.c
@@ -106,6 +106,8 @@ static int jz4740_musb_exit(struct musb *musb)
}
static const struct musb_platform_ops jz4740_musb_ops = {
+ .quirks = MUSB_INDEXED_EP,
+ .fifo_mode = 2,
.init = jz4740_musb_init,
.exit = jz4740_musb_exit,
};
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index b841ee0bff06..55fe0ff6fd87 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -224,12 +224,67 @@ static struct usb_phy_io_ops musb_ulpi_access = {
/*-------------------------------------------------------------------------*/
-#if !defined(CONFIG_USB_MUSB_TUSB6010) && !defined(CONFIG_USB_MUSB_BLACKFIN)
+static u32 musb_default_fifo_offset(u8 epnum)
+{
+ return 0x20 + (epnum * 4);
+}
+
+/* "flat" mapping: each endpoint has its own i/o address */
+static void musb_flat_ep_select(void __iomem *mbase, u8 epnum)
+{
+}
+
+static u32 musb_flat_ep_offset(u8 epnum, u16 offset)
+{
+ return 0x100 + (0x10 * epnum) + offset;
+}
+
+/* "indexed" mapping: INDEX register controls register bank select */
+static void musb_indexed_ep_select(void __iomem *mbase, u8 epnum)
+{
+ musb_writeb(mbase, MUSB_INDEX, epnum);
+}
+
+static u32 musb_indexed_ep_offset(u8 epnum, u16 offset)
+{
+ return 0x10 + offset;
+}
+
+static u8 musb_default_readb(const void __iomem *addr, unsigned offset)
+{
+ return __raw_readb(addr + offset);
+}
+
+static void musb_default_writeb(void __iomem *addr, unsigned offset, u8 data)
+{
+ __raw_writeb(data, addr + offset);
+}
+
+static u16 musb_default_readw(const void __iomem *addr, unsigned offset)
+{
+ return __raw_readw(addr + offset);
+}
+
+static void musb_default_writew(void __iomem *addr, unsigned offset, u16 data)
+{
+ __raw_writew(data, addr + offset);
+}
+
+static u32 musb_default_readl(const void __iomem *addr, unsigned offset)
+{
+ return __raw_readl(addr + offset);
+}
+
+static void musb_default_writel(void __iomem *addr, unsigned offset, u32 data)
+{
+ __raw_writel(data, addr + offset);
+}
/*
* Load an endpoint's FIFO
*/
-void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
+static void musb_default_write_fifo(struct musb_hw_ep *hw_ep, u16 len,
+ const u8 *src)
{
struct musb *musb = hw_ep->musb;
void __iomem *fifo = hw_ep->fifo;
@@ -270,11 +325,10 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
}
}
-#if !defined(CONFIG_USB_MUSB_AM35X)
/*
* Unload an endpoint's FIFO
*/
-void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+static void musb_default_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
{
struct musb *musb = hw_ep->musb;
void __iomem *fifo = hw_ep->fifo;
@@ -312,10 +366,40 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
ioread8_rep(fifo, dst, len);
}
}
-#endif
-#endif /* normal PIO */
+/*
+ * Old style IO functions
+ */
+u8 (*musb_readb)(const void __iomem *addr, unsigned offset);
+EXPORT_SYMBOL_GPL(musb_readb);
+
+void (*musb_writeb)(void __iomem *addr, unsigned offset, u8 data);
+EXPORT_SYMBOL_GPL(musb_writeb);
+
+u16 (*musb_readw)(const void __iomem *addr, unsigned offset);
+EXPORT_SYMBOL_GPL(musb_readw);
+
+void (*musb_writew)(void __iomem *addr, unsigned offset, u16 data);
+EXPORT_SYMBOL_GPL(musb_writew);
+
+u32 (*musb_readl)(const void __iomem *addr, unsigned offset);
+EXPORT_SYMBOL_GPL(musb_readl);
+void (*musb_writel)(void __iomem *addr, unsigned offset, u32 data);
+EXPORT_SYMBOL_GPL(musb_writel);
+
+/*
+ * New style IO functions
+ */
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+{
+ return hw_ep->musb->io.read_fifo(hw_ep, len, dst);
+}
+
+void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
+{
+ return hw_ep->musb->io.write_fifo(hw_ep, len, src);
+}
/*-------------------------------------------------------------------------*/
@@ -360,23 +444,23 @@ static void musb_otg_timer_func(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_B_WAIT_ACON:
dev_dbg(musb->controller, "HNP: b_wait_acon timeout; back to b_peripheral\n");
musb_g_disconnect(musb);
- musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
musb->is_active = 0;
break;
case OTG_STATE_A_SUSPEND:
case OTG_STATE_A_WAIT_BCON:
dev_dbg(musb->controller, "HNP: %s timeout\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
musb_platform_set_vbus(musb, 0);
- musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL;
break;
default:
dev_dbg(musb->controller, "HNP: Unhandled mode %s\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
}
spin_unlock_irqrestore(&musb->lock, flags);
}
@@ -391,19 +475,19 @@ void musb_hnp_stop(struct musb *musb)
u8 reg;
dev_dbg(musb->controller, "HNP: stop from %s\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_PERIPHERAL:
musb_g_disconnect(musb);
dev_dbg(musb->controller, "HNP: back to %s\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
break;
case OTG_STATE_B_HOST:
dev_dbg(musb->controller, "HNP: Disabling HR\n");
if (hcd)
hcd->self.is_b_host = 0;
- musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
MUSB_DEV_MODE(musb);
reg = musb_readb(mbase, MUSB_POWER);
reg |= MUSB_POWER_SUSPENDM;
@@ -412,7 +496,7 @@ void musb_hnp_stop(struct musb *musb)
break;
default:
dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
}
/*
@@ -423,6 +507,7 @@ void musb_hnp_stop(struct musb *musb)
musb->port1_status &= ~(USB_PORT_STAT_C_CONNECTION << 16);
}
+static void musb_generic_disable(struct musb *musb);
/*
* Interrupt Service Routine to record USB "global" interrupts.
* Since these do not happen often and signify things of
@@ -449,13 +534,13 @@ 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", usb_otg_state_string(musb->xceiv->state));
+ dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->otg->state));
if (devctl & MUSB_DEVCTL_HM) {
void __iomem *mbase = musb->mregs;
u8 power;
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_SUSPEND:
/* remote wakeup? later, GetPortStatus
* will stop RESUME signaling
@@ -478,29 +563,26 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
| MUSB_PORT_STAT_RESUME;
musb->rh_timer = jiffies
+ msecs_to_jiffies(20);
- schedule_delayed_work(
- &musb->finish_resume_work,
- msecs_to_jiffies(20));
+ musb->need_finish_resume = 1;
- musb->xceiv->state = OTG_STATE_A_HOST;
+ musb->xceiv->otg->state = OTG_STATE_A_HOST;
musb->is_active = 1;
- musb_host_resume_root_hub(musb);
break;
case OTG_STATE_B_WAIT_ACON:
- musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
musb->is_active = 1;
MUSB_DEV_MODE(musb);
break;
default:
WARNING("bogus %s RESUME (%s)\n",
"host",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
}
} else {
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_SUSPEND:
/* possibly DISCONNECT is upcoming */
- musb->xceiv->state = OTG_STATE_A_HOST;
+ musb->xceiv->otg->state = OTG_STATE_A_HOST;
musb_host_resume_root_hub(musb);
break;
case OTG_STATE_B_WAIT_ACON:
@@ -523,7 +605,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
default:
WARNING("bogus %s RESUME (%s)\n",
"peripheral",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
}
}
}
@@ -539,7 +621,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
}
dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
/* IRQ arrives from ID pin sense or (later, if VBUS power
* is removed) SRP. responses are time critical:
@@ -550,7 +632,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
*/
musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
musb->ep0_stage = MUSB_EP0_START;
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
musb_platform_set_vbus(musb, 1);
@@ -576,7 +658,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
* REVISIT: do delays from lots of DEBUG_KERNEL checks
* make trouble here, keeping VBUS < 4.4V ?
*/
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_HOST:
/* recovery is dicey once we've gotten past the
* initial stages of enumeration, but if VBUS
@@ -605,7 +687,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
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),
+ usb_otg_state_string(musb->xceiv->otg->state),
devctl,
({ char *s;
switch (devctl & MUSB_DEVCTL_VBUS) {
@@ -630,10 +712,10 @@ 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",
- usb_otg_state_string(musb->xceiv->state), devctl);
+ usb_otg_state_string(musb->xceiv->otg->state), devctl);
handled = IRQ_HANDLED;
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_PERIPHERAL:
/* We also come here if the cable is removed, since
* this silicon doesn't report ID-no-longer-grounded.
@@ -657,7 +739,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb_g_suspend(musb);
musb->is_active = musb->g.b_hnp_enable;
if (musb->is_active) {
- musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
+ musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON;
dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n");
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(
@@ -670,7 +752,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+ msecs_to_jiffies(musb->a_wait_bcon));
break;
case OTG_STATE_A_HOST:
- musb->xceiv->state = OTG_STATE_A_SUSPEND;
+ musb->xceiv->otg->state = OTG_STATE_A_SUSPEND;
musb->is_active = musb->hcd->self.b_hnp_enable;
break;
case OTG_STATE_B_HOST:
@@ -713,7 +795,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
/* indicate new connection to OTG machine */
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_B_PERIPHERAL:
if (int_usb & MUSB_INTR_SUSPEND) {
dev_dbg(musb->controller, "HNP: SUSPEND+CONNECT, now b_host\n");
@@ -725,7 +807,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
case OTG_STATE_B_WAIT_ACON:
dev_dbg(musb->controller, "HNP: CONNECT, now b_host\n");
b_host:
- musb->xceiv->state = OTG_STATE_B_HOST;
+ musb->xceiv->otg->state = OTG_STATE_B_HOST;
if (musb->hcd)
musb->hcd->self.is_b_host = 1;
del_timer(&musb->otg_timer);
@@ -733,7 +815,7 @@ b_host:
default:
if ((devctl & MUSB_DEVCTL_VBUS)
== (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
- musb->xceiv->state = OTG_STATE_A_HOST;
+ musb->xceiv->otg->state = OTG_STATE_A_HOST;
if (hcd)
hcd->self.is_b_host = 0;
}
@@ -743,16 +825,16 @@ b_host:
musb_host_poke_root_hub(musb);
dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n",
- usb_otg_state_string(musb->xceiv->state), devctl);
+ usb_otg_state_string(musb->xceiv->otg->state), devctl);
}
if (int_usb & MUSB_INTR_DISCONNECT) {
dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
MUSB_MODE(musb), devctl);
handled = IRQ_HANDLED;
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_HOST:
case OTG_STATE_A_SUSPEND:
musb_host_resume_root_hub(musb);
@@ -770,7 +852,7 @@ b_host:
musb_root_disconnect(musb);
if (musb->hcd)
musb->hcd->self.is_b_host = 0;
- musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
MUSB_DEV_MODE(musb);
musb_g_disconnect(musb);
break;
@@ -786,7 +868,7 @@ b_host:
break;
default:
WARNING("unhandled DISCONNECT transition (%s)\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
break;
}
}
@@ -812,15 +894,15 @@ b_host:
}
} else {
dev_dbg(musb->controller, "BUS RESET as %s\n",
- usb_otg_state_string(musb->xceiv->state));
- switch (musb->xceiv->state) {
+ usb_otg_state_string(musb->xceiv->otg->state));
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_SUSPEND:
musb_g_reset(musb);
/* FALLTHROUGH */
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",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
TA_WAIT_BCON(musb));
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(TA_WAIT_BCON(musb)));
@@ -831,27 +913,29 @@ b_host:
break;
case OTG_STATE_B_WAIT_ACON:
dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n",
- usb_otg_state_string(musb->xceiv->state));
- musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ usb_otg_state_string(musb->xceiv->otg->state));
+ musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
musb_g_reset(musb);
break;
case OTG_STATE_B_IDLE:
- musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
/* FALLTHROUGH */
case OTG_STATE_B_PERIPHERAL:
musb_g_reset(musb);
break;
default:
dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
}
}
}
/* handle babble condition */
- if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb))
+ if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb)) {
+ musb_generic_disable(musb);
schedule_delayed_work(&musb->recover_work,
msecs_to_jiffies(100));
+ }
#if 0
/* REVISIT ... this would be for multiplexing periodic endpoints, or
@@ -1032,21 +1116,7 @@ static void musb_shutdown(struct platform_device *pdev)
* We don't currently use dynamic fifo setup capability to do anything
* more than selecting one of a bunch of predefined configurations.
*/
-#if defined(CONFIG_USB_MUSB_TUSB6010) \
- || defined(CONFIG_USB_MUSB_TUSB6010_MODULE) \
- || defined(CONFIG_USB_MUSB_OMAP2PLUS) \
- || defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE) \
- || defined(CONFIG_USB_MUSB_AM35X) \
- || defined(CONFIG_USB_MUSB_AM35X_MODULE) \
- || defined(CONFIG_USB_MUSB_DSPS) \
- || defined(CONFIG_USB_MUSB_DSPS_MODULE)
-static ushort fifo_mode = 4;
-#elif defined(CONFIG_USB_MUSB_UX500) \
- || defined(CONFIG_USB_MUSB_UX500_MODULE)
-static ushort fifo_mode = 5;
-#else
-static ushort fifo_mode = 2;
-#endif
+static ushort fifo_mode;
/* "modprobe ... fifo_mode=1" etc */
module_param(fifo_mode, ushort, 0);
@@ -1456,20 +1526,25 @@ static int musb_core_init(u16 musb_type, struct musb *musb)
for (i = 0; i < musb->nr_endpoints; i++) {
struct musb_hw_ep *hw_ep = musb->endpoints + i;
- hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase;
-#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)
- hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i);
- hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i);
- hw_ep->fifo_sync_va =
- musb->sync_va + 0x400 + MUSB_FIFO_OFFSET(i);
-
- if (i == 0)
- hw_ep->conf = mbase - 0x400 + TUSB_EP0_CONF;
- else
- hw_ep->conf = mbase + 0x400 + (((i - 1) & 0xf) << 2);
+ hw_ep->fifo = musb->io.fifo_offset(i) + mbase;
+#if IS_ENABLED(CONFIG_USB_MUSB_TUSB6010)
+ if (musb->io.quirks & MUSB_IN_TUSB) {
+ hw_ep->fifo_async = musb->async + 0x400 +
+ musb->io.fifo_offset(i);
+ hw_ep->fifo_sync = musb->sync + 0x400 +
+ musb->io.fifo_offset(i);
+ hw_ep->fifo_sync_va =
+ musb->sync_va + 0x400 + musb->io.fifo_offset(i);
+
+ if (i == 0)
+ hw_ep->conf = mbase - 0x400 + TUSB_EP0_CONF;
+ else
+ hw_ep->conf = mbase + 0x400 +
+ (((i - 1) & 0xf) << 2);
+ }
#endif
- hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase;
+ hw_ep->regs = musb->io.ep_offset(i, 0) + mbase;
hw_ep->target_regs = musb_read_target_reg_base(i, mbase);
hw_ep->rx_reinit = 1;
hw_ep->tx_reinit = 1;
@@ -1630,7 +1705,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", usb_otg_state_string(musb->xceiv->state));
+ ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->otg->state));
spin_unlock_irqrestore(&musb->lock, flags);
return ret;
@@ -1675,7 +1750,7 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
spin_lock_irqsave(&musb->lock, flags);
/* force T(a_wait_bcon) to be zero/unlimited *OR* valid */
musb->a_wait_bcon = val ? max_t(int, val, OTG_TIME_A_WAIT_BCON) : 0 ;
- if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON)
+ if (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON)
musb->is_active = 0;
musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
spin_unlock_irqrestore(&musb->lock, flags);
@@ -1743,8 +1818,8 @@ static void musb_irq_work(struct work_struct *data)
{
struct musb *musb = container_of(data, struct musb, irq_work);
- if (musb->xceiv->state != musb->xceiv_old_state) {
- musb->xceiv_old_state = musb->xceiv->state;
+ if (musb->xceiv->otg->state != musb->xceiv_old_state) {
+ musb->xceiv_old_state = musb->xceiv->otg->state;
sysfs_notify(&musb->controller->kobj, NULL, "mode");
}
}
@@ -1903,6 +1978,18 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
musb->ops = plat->platform_ops;
musb->port_mode = plat->mode;
+ /*
+ * Initialize the default IO functions. At least omap2430 needs
+ * these early. We initialize the platform specific IO functions
+ * later on.
+ */
+ musb_readb = musb_default_readb;
+ musb_writeb = musb_default_writeb;
+ musb_readw = musb_default_readw;
+ musb_writew = musb_default_writew;
+ musb_readl = musb_default_readl;
+ musb_writel = musb_default_writel;
+
/* The musb_platform_init() call:
* - adjusts musb->mregs
* - sets the musb->isr
@@ -1924,6 +2011,57 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
goto fail2;
}
+ if (musb->ops->quirks)
+ musb->io.quirks = musb->ops->quirks;
+
+ /* At least tusb6010 has it's own offsets.. */
+ if (musb->ops->ep_offset)
+ musb->io.ep_offset = musb->ops->ep_offset;
+ if (musb->ops->ep_select)
+ musb->io.ep_select = musb->ops->ep_select;
+
+ /* ..and some devices use indexed offset or flat offset */
+ if (musb->io.quirks & MUSB_INDEXED_EP) {
+ musb->io.ep_offset = musb_indexed_ep_offset;
+ musb->io.ep_select = musb_indexed_ep_select;
+ } else {
+ musb->io.ep_offset = musb_flat_ep_offset;
+ musb->io.ep_select = musb_flat_ep_select;
+ }
+
+ if (musb->ops->fifo_mode)
+ fifo_mode = musb->ops->fifo_mode;
+ else
+ fifo_mode = 4;
+
+ if (musb->ops->fifo_offset)
+ musb->io.fifo_offset = musb->ops->fifo_offset;
+ else
+ musb->io.fifo_offset = musb_default_fifo_offset;
+
+ if (musb->ops->readb)
+ musb_readb = musb->ops->readb;
+ if (musb->ops->writeb)
+ musb_writeb = musb->ops->writeb;
+ if (musb->ops->readw)
+ musb_readw = musb->ops->readw;
+ if (musb->ops->writew)
+ musb_writew = musb->ops->writew;
+ if (musb->ops->readl)
+ musb_readl = musb->ops->readl;
+ if (musb->ops->writel)
+ musb_writel = musb->ops->writel;
+
+ if (musb->ops->read_fifo)
+ musb->io.read_fifo = musb->ops->read_fifo;
+ else
+ musb->io.read_fifo = musb_default_read_fifo;
+
+ if (musb->ops->write_fifo)
+ musb->io.write_fifo = musb->ops->write_fifo;
+ else
+ musb->io.write_fifo = musb_default_write_fifo;
+
if (!musb->xceiv->io_ops) {
musb->xceiv->io_dev = musb->controller;
musb->xceiv->io_priv = musb->mregs;
@@ -1983,10 +2121,10 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
if (musb->xceiv->otg->default_a) {
MUSB_HST_MODE(musb);
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
} else {
MUSB_DEV_MODE(musb);
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
}
switch (musb->port_mode) {
@@ -2080,10 +2218,10 @@ static int musb_probe(struct platform_device *pdev)
struct resource *iomem;
void __iomem *base;
- iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iomem || irq <= 0)
+ if (irq <= 0)
return -ENODEV;
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, iomem);
if (IS_ERR(base))
return PTR_ERR(base);
@@ -2297,9 +2435,11 @@ static int musb_suspend(struct device *dev)
return 0;
}
-static int musb_resume_noirq(struct device *dev)
+static int musb_resume(struct device *dev)
{
struct musb *musb = dev_to_musb(dev);
+ u8 devctl;
+ u8 mask;
/*
* For static cmos like DaVinci, register values were preserved
@@ -2313,6 +2453,23 @@ static int musb_resume_noirq(struct device *dev)
musb_restore_context(musb);
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+ mask = MUSB_DEVCTL_BDEVICE | MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV;
+ if ((devctl & mask) != (musb->context.devctl & mask))
+ musb->port1_status = 0;
+ if (musb->need_finish_resume) {
+ musb->need_finish_resume = 0;
+ schedule_delayed_work(&musb->finish_resume_work,
+ msecs_to_jiffies(20));
+ }
+
+ /*
+ * The USB HUB code expects the device to be in RPM_ACTIVE once it came
+ * out of suspend
+ */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
return 0;
}
@@ -2348,7 +2505,7 @@ static int musb_runtime_resume(struct device *dev)
static const struct dev_pm_ops musb_dev_pm_ops = {
.suspend = musb_suspend,
- .resume_noirq = musb_resume_noirq,
+ .resume = musb_resume,
.runtime_suspend = musb_runtime_suspend,
.runtime_resume = musb_runtime_resume,
};
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 414e57a984bb..5e65958f7915 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -124,41 +124,6 @@ enum musb_g_ep0_state {
#define OTG_TIME_A_AIDL_BDIS 200 /* min 200 msec */
#define OTG_TIME_B_ASE0_BRST 100 /* min 3.125 ms */
-
-/*************************** REGISTER ACCESS ********************************/
-
-/* Endpoint registers (other than dynfifo setup) can be accessed either
- * directly with the "flat" model, or after setting up an index register.
- */
-
-#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_SOC_OMAP2430) \
- || defined(CONFIG_SOC_OMAP3430) || defined(CONFIG_BLACKFIN) \
- || defined(CONFIG_ARCH_OMAP4)
-/* REVISIT indexed access seemed to
- * misbehave (on DaVinci) for at least peripheral IN ...
- */
-#define MUSB_FLAT_REG
-#endif
-
-/* TUSB mapping: "flat" plus ep0 special cases */
-#if defined(CONFIG_USB_MUSB_TUSB6010) || \
- defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
-#define musb_ep_select(_mbase, _epnum) \
- musb_writeb((_mbase), MUSB_INDEX, (_epnum))
-#define MUSB_EP_OFFSET MUSB_TUSB_OFFSET
-
-/* "flat" mapping: each endpoint has its own i/o address */
-#elif defined(MUSB_FLAT_REG)
-#define musb_ep_select(_mbase, _epnum) (((void)(_mbase)), ((void)(_epnum)))
-#define MUSB_EP_OFFSET MUSB_FLAT_OFFSET
-
-/* "indexed" mapping: INDEX register controls register bank select */
-#else
-#define musb_ep_select(_mbase, _epnum) \
- musb_writeb((_mbase), MUSB_INDEX, (_epnum))
-#define MUSB_EP_OFFSET MUSB_INDEXED_OFFSET
-#endif
-
/****************************** FUNCTIONS ********************************/
#define MUSB_HST_MODE(_musb)\
@@ -173,8 +138,25 @@ enum musb_g_ep0_state {
/******************************** TYPES *************************************/
+struct musb_io;
+
/**
* struct musb_platform_ops - Operations passed to musb_core by HW glue layer
+ * @quirks: flags for platform specific quirks
+ * @enable: enable device
+ * @disable: disable device
+ * @ep_offset: returns the end point offset
+ * @ep_select: selects the specified end point
+ * @fifo_mode: sets the fifo mode
+ * @fifo_offset: returns the fifo offset
+ * @readb: read 8 bits
+ * @writeb: write 8 bits
+ * @readw: read 16 bits
+ * @writew: write 16 bits
+ * @readl: read 32 bits
+ * @writel: write 32 bits
+ * @read_fifo: reads the fifo
+ * @write_fifo: writes to fifo
* @init: turns on clocks, sets up platform-specific registers, etc
* @exit: undoes @init
* @set_mode: forcefully changes operating mode
@@ -184,12 +166,34 @@ enum musb_g_ep0_state {
* @adjust_channel_params: pre check for standard dma channel_program func
*/
struct musb_platform_ops {
+
+#define MUSB_DMA_UX500 BIT(6)
+#define MUSB_DMA_CPPI41 BIT(5)
+#define MUSB_DMA_CPPI BIT(4)
+#define MUSB_DMA_TUSB_OMAP BIT(3)
+#define MUSB_DMA_INVENTRA BIT(2)
+#define MUSB_IN_TUSB BIT(1)
+#define MUSB_INDEXED_EP BIT(0)
+ u32 quirks;
+
int (*init)(struct musb *musb);
int (*exit)(struct musb *musb);
void (*enable)(struct musb *musb);
void (*disable)(struct musb *musb);
+ u32 (*ep_offset)(u8 epnum, u16 offset);
+ void (*ep_select)(void __iomem *mbase, u8 epnum);
+ u16 fifo_mode;
+ u32 (*fifo_offset)(u8 epnum);
+ u8 (*readb)(const void __iomem *addr, unsigned offset);
+ void (*writeb)(void __iomem *addr, unsigned offset, u8 data);
+ u16 (*readw)(const void __iomem *addr, unsigned offset);
+ void (*writew)(void __iomem *addr, unsigned offset, u16 data);
+ u32 (*readl)(const void __iomem *addr, unsigned offset);
+ void (*writel)(void __iomem *addr, unsigned offset, u32 data);
+ void (*read_fifo)(struct musb_hw_ep *hw_ep, u16 len, u8 *buf);
+ void (*write_fifo)(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf);
int (*set_mode)(struct musb *musb, u8 mode);
void (*try_idle)(struct musb *musb, unsigned long timeout);
int (*reset)(struct musb *musb);
@@ -212,8 +216,7 @@ struct musb_hw_ep {
void __iomem *fifo;
void __iomem *regs;
-#if defined(CONFIG_USB_MUSB_TUSB6010) || \
- defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
+#if IS_ENABLED(CONFIG_USB_MUSB_TUSB6010)
void __iomem *conf;
#endif
@@ -230,8 +233,7 @@ struct musb_hw_ep {
struct dma_channel *tx_channel;
struct dma_channel *rx_channel;
-#if defined(CONFIG_USB_MUSB_TUSB6010) || \
- defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
+#if IS_ENABLED(CONFIG_USB_MUSB_TUSB6010)
/* TUSB has "asynchronous" and "synchronous" dma modes */
dma_addr_t fifo_async;
dma_addr_t fifo_sync;
@@ -292,6 +294,7 @@ struct musb {
/* device lock */
spinlock_t lock;
+ struct musb_io io;
const struct musb_platform_ops *ops;
struct musb_context_registers context;
@@ -334,8 +337,7 @@ struct musb {
void __iomem *ctrl_base;
void __iomem *mregs;
-#if defined(CONFIG_USB_MUSB_TUSB6010) || \
- defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
+#if IS_ENABLED(CONFIG_USB_MUSB_TUSB6010)
dma_addr_t async;
dma_addr_t sync;
void __iomem *sync_va;
@@ -390,6 +392,7 @@ struct musb {
/* is_suspended means USB B_PERIPHERAL suspend */
unsigned is_suspended:1;
+ unsigned need_finish_resume :1;
/* may_wakeup means remote wakeup is enabled */
unsigned may_wakeup:1;
@@ -474,7 +477,7 @@ static inline int musb_read_fifosize(struct musb *musb,
u8 reg = 0;
/* read from core using indexed model */
- reg = musb_readb(mbase, MUSB_EP_OFFSET(epnum, MUSB_FIFOSIZE));
+ reg = musb_readb(mbase, musb->io.ep_offset(epnum, MUSB_FIFOSIZE));
/* 0's returned when no more endpoints */
if (!reg)
return -ENODEV;
diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
index 5a9b977fbc19..f64fd964dc6d 100644
--- a/drivers/usb/musb/musb_cppi41.c
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -253,6 +253,7 @@ static void cppi41_dma_callback(void *private_data)
cppi41_trans_done(cppi41_channel);
} else {
struct cppi41_dma_controller *controller;
+ int is_hs = 0;
/*
* On AM335x it has been observed that the TX interrupt fires
* too early that means the TXFIFO is not yet empty but the DMA
@@ -265,7 +266,14 @@ static void cppi41_dma_callback(void *private_data)
*/
controller = cppi41_channel->controller;
- if (musb->g.speed == USB_SPEED_HIGH) {
+ if (is_host_active(musb)) {
+ if (musb->port1_status & USB_PORT_STAT_HIGH_SPEED)
+ is_hs = 1;
+ } else {
+ if (musb->g.speed == USB_SPEED_HIGH)
+ is_hs = 1;
+ }
+ if (is_hs) {
unsigned wait = 25;
do {
diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c
index 4c216790e86b..ad3701a97389 100644
--- a/drivers/usb/musb/musb_debugfs.c
+++ b/drivers/usb/musb/musb_debugfs.c
@@ -49,33 +49,36 @@ struct musb_register_map {
};
static const struct musb_register_map musb_regmap[] = {
- { "FAddr", 0x00, 8 },
- { "Power", 0x01, 8 },
- { "Frame", 0x0c, 16 },
- { "Index", 0x0e, 8 },
- { "Testmode", 0x0f, 8 },
- { "TxMaxPp", 0x10, 16 },
- { "TxCSRp", 0x12, 16 },
- { "RxMaxPp", 0x14, 16 },
- { "RxCSR", 0x16, 16 },
- { "RxCount", 0x18, 16 },
- { "ConfigData", 0x1f, 8 },
- { "DevCtl", 0x60, 8 },
- { "MISC", 0x61, 8 },
- { "TxFIFOsz", 0x62, 8 },
- { "RxFIFOsz", 0x63, 8 },
- { "TxFIFOadd", 0x64, 16 },
- { "RxFIFOadd", 0x66, 16 },
- { "VControl", 0x68, 32 },
- { "HWVers", 0x6C, 16 },
- { "EPInfo", 0x78, 8 },
- { "RAMInfo", 0x79, 8 },
- { "LinkInfo", 0x7A, 8 },
- { "VPLen", 0x7B, 8 },
- { "HS_EOF1", 0x7C, 8 },
- { "FS_EOF1", 0x7D, 8 },
- { "LS_EOF1", 0x7E, 8 },
- { "SOFT_RST", 0x7F, 8 },
+ { "FAddr", MUSB_FADDR, 8 },
+ { "Power", MUSB_POWER, 8 },
+ { "Frame", MUSB_FRAME, 16 },
+ { "Index", MUSB_INDEX, 8 },
+ { "Testmode", MUSB_TESTMODE, 8 },
+ { "TxMaxPp", MUSB_TXMAXP, 16 },
+ { "TxCSRp", MUSB_TXCSR, 16 },
+ { "RxMaxPp", MUSB_RXMAXP, 16 },
+ { "RxCSR", MUSB_RXCSR, 16 },
+ { "RxCount", MUSB_RXCOUNT, 16 },
+ { "ConfigData", MUSB_CONFIGDATA,8 },
+ { "IntrRxE", MUSB_INTRRXE, 16 },
+ { "IntrTxE", MUSB_INTRTXE, 16 },
+ { "IntrUsbE", MUSB_INTRUSBE, 8 },
+ { "DevCtl", MUSB_DEVCTL, 8 },
+ { "BabbleCtl", MUSB_BABBLE_CTL,8 },
+ { "TxFIFOsz", MUSB_TXFIFOSZ, 8 },
+ { "RxFIFOsz", MUSB_RXFIFOSZ, 8 },
+ { "TxFIFOadd", MUSB_TXFIFOADD, 16 },
+ { "RxFIFOadd", MUSB_RXFIFOADD, 16 },
+ { "VControl", 0x68, 32 },
+ { "HWVers", 0x69, 16 },
+ { "EPInfo", MUSB_EPINFO, 8 },
+ { "RAMInfo", MUSB_RAMINFO, 8 },
+ { "LinkInfo", MUSB_LINKINFO, 8 },
+ { "VPLen", MUSB_VPLEN, 8 },
+ { "HS_EOF1", MUSB_HS_EOF1, 8 },
+ { "FS_EOF1", MUSB_FS_EOF1, 8 },
+ { "LS_EOF1", MUSB_LS_EOF1, 8 },
+ { "SOFT_RST", 0x7F, 8 },
{ "DMA_CNTLch0", 0x204, 16 },
{ "DMA_ADDRch0", 0x208, 32 },
{ "DMA_COUNTch0", 0x20C, 32 },
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 48bc09e7b83b..53bd0e71d19f 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -179,9 +179,9 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
/* Never idle if active, or when VBUS timeout is not set as host */
if (musb->is_active || (musb->a_wait_bcon == 0 &&
- musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+ musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
del_timer(&glue->timer);
glue->last_timer = jiffies;
return;
@@ -201,7 +201,7 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
glue->last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
jiffies_to_msecs(timeout - jiffies));
mod_timer(&glue->timer, timeout);
}
@@ -265,10 +265,10 @@ static void otg_timer(unsigned long _musb)
*/
devctl = dsps_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_WAIT_BCON:
dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
skip_session = 1;
@@ -277,10 +277,10 @@ static void otg_timer(unsigned long _musb)
case OTG_STATE_A_IDLE:
case OTG_STATE_B_IDLE:
if (devctl & MUSB_DEVCTL_BDEVICE) {
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
MUSB_DEV_MODE(musb);
} else {
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
}
if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session)
@@ -288,7 +288,7 @@ static void otg_timer(unsigned long _musb)
mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
break;
case OTG_STATE_A_WAIT_VFALL:
- musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
dsps_writel(musb->ctrl_base, wrp->coreintr_set,
MUSB_INTR_VBUSERROR << wrp->usb_shift);
break;
@@ -373,26 +373,26 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
* devctl.
*/
musb->int_usb &= ~MUSB_INTR_VBUSERROR;
- musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&glue->timer,
jiffies + wrp->poll_seconds * HZ);
WARNING("VBUS error workaround (delay coming)\n");
} else if (drvvbus) {
MUSB_HST_MODE(musb);
musb->xceiv->otg->default_a = 1;
- musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
del_timer(&glue->timer);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
musb->xceiv->otg->default_a = 0;
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
}
/* NOTE: this must complete power-on within 100 ms. */
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
err ? " ERROR" : "",
devctl);
ret = IRQ_HANDLED;
@@ -402,7 +402,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
ret |= musb_interrupt(musb);
/* Poll for ID change in OTG port mode */
- if (musb->xceiv->state == OTG_STATE_B_IDLE &&
+ if (musb->xceiv->otg->state == OTG_STATE_B_IDLE &&
musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
out:
@@ -447,9 +447,6 @@ static int dsps_musb_init(struct musb *musb)
int ret;
r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control");
- if (!r)
- return -EINVAL;
-
reg_base = devm_ioremap_resource(dev, r);
if (IS_ERR(reg_base))
return PTR_ERR(reg_base);
@@ -636,6 +633,7 @@ static int dsps_musb_reset(struct musb *musb)
}
static struct musb_platform_ops dsps_ops = {
+ .quirks = MUSB_INDEXED_EP,
.init = dsps_musb_init,
.exit = dsps_musb_exit,
@@ -729,7 +727,6 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,
config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL);
if (!config) {
- dev_err(dev, "failed to allocate musb hdrc config\n");
ret = -ENOMEM;
goto err;
}
@@ -781,10 +778,8 @@ static int dsps_probe(struct platform_device *pdev)
/* allocate glue */
glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
- if (!glue) {
- dev_err(&pdev->dev, "unable to allocate glue memory\n");
+ if (!glue)
return -ENOMEM;
- }
glue->dev = &pdev->dev;
glue->wrp = wrp;
@@ -906,7 +901,7 @@ static int dsps_resume(struct device *dev)
dsps_writel(mbase, wrp->mode, glue->context.mode);
dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode);
dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode);
- if (musb->xceiv->state == OTG_STATE_B_IDLE &&
+ if (musb->xceiv->otg->state == OTG_STATE_B_IDLE &&
musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 24c8c0219790..49b04cb6f5ca 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1546,7 +1546,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_B_PERIPHERAL:
/* NOTE: OTG state machine doesn't include B_SUSPENDED;
* that's part of the standard usb 1.1 state machine, and
@@ -1587,7 +1587,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
goto done;
default:
dev_dbg(musb->controller, "Unhandled wake: %s\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
goto done;
}
@@ -1684,8 +1684,7 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
static int musb_gadget_start(struct usb_gadget *g,
struct usb_gadget_driver *driver);
-static int musb_gadget_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
+static int musb_gadget_stop(struct usb_gadget *g);
static const struct usb_gadget_ops musb_gadget_operations = {
.get_frame = musb_gadget_get_frame,
@@ -1792,7 +1791,7 @@ int musb_gadget_setup(struct musb *musb)
MUSB_DEV_MODE(musb);
musb->xceiv->otg->default_a = 0;
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
/* this "gadget" abstracts/virtualizes the controller */
musb->g.name = musb_driver_name;
@@ -1851,8 +1850,6 @@ static int musb_gadget_start(struct usb_gadget *g,
pm_runtime_get_sync(musb->controller);
- dev_dbg(musb->controller, "registering driver %s\n", driver->function);
-
musb->softconnect = 0;
musb->gadget_driver = driver;
@@ -1860,7 +1857,7 @@ static int musb_gadget_start(struct usb_gadget *g,
musb->is_active = 1;
otg_set_peripheral(otg, &musb->g);
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
spin_unlock_irqrestore(&musb->lock, flags);
musb_start(musb);
@@ -1925,8 +1922,7 @@ static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver)
*
* @param driver the gadget driver to unregister
*/
-static int musb_gadget_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
+static int musb_gadget_stop(struct usb_gadget *g)
{
struct musb *musb = gadget_to_musb(g);
unsigned long flags;
@@ -1945,13 +1941,10 @@ static int musb_gadget_stop(struct usb_gadget *g,
(void) musb_gadget_vbus_draw(&musb->g, 0);
- musb->xceiv->state = OTG_STATE_UNDEFINED;
- stop_activity(musb, driver);
+ musb->xceiv->otg->state = OTG_STATE_UNDEFINED;
+ stop_activity(musb, NULL);
otg_set_peripheral(musb->xceiv->otg, NULL);
- dev_dbg(musb->controller, "unregistering driver %s\n",
- driver ? driver->function : "(removed)");
-
musb->is_active = 0;
musb->gadget_driver = NULL;
musb_platform_try_idle(musb, 0);
@@ -1975,7 +1968,7 @@ static int musb_gadget_stop(struct usb_gadget *g,
void musb_g_resume(struct musb *musb)
{
musb->is_suspended = 0;
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_B_IDLE:
break;
case OTG_STATE_B_WAIT_ACON:
@@ -1989,7 +1982,7 @@ void musb_g_resume(struct musb *musb)
break;
default:
WARNING("unhandled RESUME transition (%s)\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
}
}
@@ -2001,10 +1994,10 @@ void musb_g_suspend(struct musb *musb)
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "devctl %02x\n", devctl);
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_B_IDLE:
if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
- musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
break;
case OTG_STATE_B_PERIPHERAL:
musb->is_suspended = 1;
@@ -2019,7 +2012,7 @@ void musb_g_suspend(struct musb *musb)
* A_PERIPHERAL may need care too
*/
WARNING("unhandled SUSPEND transition (%s)\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
}
}
@@ -2050,22 +2043,22 @@ void musb_g_disconnect(struct musb *musb)
spin_lock(&musb->lock);
}
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
default:
dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n",
- usb_otg_state_string(musb->xceiv->state));
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ usb_otg_state_string(musb->xceiv->otg->state));
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
break;
case OTG_STATE_A_PERIPHERAL:
- musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
MUSB_HST_MODE(musb);
break;
case OTG_STATE_B_WAIT_ACON:
case OTG_STATE_B_HOST:
case OTG_STATE_B_PERIPHERAL:
case OTG_STATE_B_IDLE:
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
break;
case OTG_STATE_B_SRP_INIT:
break;
@@ -2090,9 +2083,12 @@ __acquires(musb->lock)
: NULL
);
- /* report disconnect, if we didn't already (flushing EP state) */
- if (musb->g.speed != USB_SPEED_UNKNOWN)
- musb_g_disconnect(musb);
+ /* report reset, if we didn't already (flushing EP state) */
+ if (musb->gadget_driver && musb->g.speed != USB_SPEED_UNKNOWN) {
+ spin_unlock(&musb->lock);
+ usb_gadget_udc_reset(&musb->g, musb->gadget_driver);
+ spin_lock(&musb->lock);
+ }
/* clear HR */
else if (devctl & MUSB_DEVCTL_HR)
@@ -2125,13 +2121,13 @@ __acquires(musb->lock)
* In that case, do not rely on devctl for setting
* peripheral mode.
*/
- musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
musb->g.is_a_peripheral = 0;
} else if (devctl & MUSB_DEVCTL_BDEVICE) {
- musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
musb->g.is_a_peripheral = 0;
} else {
- musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
+ musb->xceiv->otg->state = OTG_STATE_A_PERIPHERAL;
musb->g.is_a_peripheral = 1;
}
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 855793d701bb..23d474d3d7f4 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -2463,7 +2463,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
if (!is_host_active(musb))
return 0;
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_SUSPEND:
return 0;
case OTG_STATE_A_WAIT_VRISE:
@@ -2473,7 +2473,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
*/
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
- musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
break;
default:
break;
@@ -2481,7 +2481,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
if (musb->is_active) {
WARNING("trying to suspend as %s while active\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
return -EBUSY;
} else
return 0;
@@ -2678,7 +2678,7 @@ int musb_host_setup(struct musb *musb, int power_budget)
MUSB_HST_MODE(musb);
musb->xceiv->otg->default_a = 1;
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
otg_set_host(musb->xceiv->otg, &hcd->self);
hcd->self.otg_port = 1;
diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h
index eebeed78edd6..8a57a6f4b3a6 100644
--- a/drivers/usb/musb/musb_io.h
+++ b/drivers/usb/musb/musb_io.h
@@ -37,86 +37,32 @@
#include <linux/io.h>
-#ifndef CONFIG_BLACKFIN
-
-/* NOTE: these offsets are all in bytes */
-
-static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
- { return __raw_readw(addr + offset); }
-
-static inline u32 musb_readl(const void __iomem *addr, unsigned offset)
- { return __raw_readl(addr + offset); }
-
-
-static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
- { __raw_writew(data, addr + offset); }
-
-static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
- { __raw_writel(data, addr + offset); }
-
-
-#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)
-
-/*
- * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
+#define musb_ep_select(_mbase, _epnum) musb->io.ep_select((_mbase), (_epnum))
+
+/**
+ * struct musb_io - IO functions for MUSB
+ * @quirks: platform specific flags
+ * @ep_offset: platform specific function to get end point offset
+ * @ep_select: platform specific function to select end point
+ * @fifo_offset: platform specific function to get fifo offset
+ * @read_fifo: platform specific function to read fifo
+ * @write_fifo: platform specific function to write fifo
*/
-static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
-{
- u16 tmp;
- u8 val;
-
- tmp = __raw_readw(addr + (offset & ~1));
- if (offset & 1)
- val = (tmp >> 8);
- else
- val = tmp & 0xff;
-
- return val;
-}
-
-static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
-{
- u16 tmp;
-
- tmp = __raw_readw(addr + (offset & ~1));
- if (offset & 1)
- tmp = (data << 8) | (tmp & 0xff);
- else
- tmp = (tmp & 0xff00) | data;
-
- __raw_writew(tmp, addr + (offset & ~1));
-}
-
-#else
-
-static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
- { return __raw_readb(addr + offset); }
-
-static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
- { __raw_writeb(data, addr + offset); }
-
-#endif /* CONFIG_USB_MUSB_TUSB6010 */
-
-#else
-
-static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
- { return (u8) (bfin_read16(addr + offset)); }
-
-static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
- { return bfin_read16(addr + offset); }
-
-static inline u32 musb_readl(const void __iomem *addr, unsigned offset)
- { return (u32) (bfin_read16(addr + offset)); }
-
-static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
- { bfin_write16(addr + offset, (u16) data); }
-
-static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
- { bfin_write16(addr + offset, data); }
-
-static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
- { bfin_write16(addr + offset, (u16) data); }
-
-#endif /* CONFIG_BLACKFIN */
+struct musb_io {
+ u32 quirks;
+ u32 (*ep_offset)(u8 epnum, u16 offset);
+ void (*ep_select)(void __iomem *mbase, u8 epnum);
+ u32 (*fifo_offset)(u8 epnum);
+ void (*read_fifo)(struct musb_hw_ep *hw_ep, u16 len, u8 *buf);
+ void (*write_fifo)(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf);
+};
+
+/* Do not add new entries here, add them the struct musb_io instead */
+extern u8 (*musb_readb)(const void __iomem *addr, unsigned offset);
+extern void (*musb_writeb)(void __iomem *addr, unsigned offset, u8 data);
+extern u16 (*musb_readw)(const void __iomem *addr, unsigned offset);
+extern void (*musb_writew)(void __iomem *addr, unsigned offset, u16 data);
+extern u32 (*musb_readl)(const void __iomem *addr, unsigned offset);
+extern void (*musb_writel)(void __iomem *addr, unsigned offset, u32 data);
#endif
diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h
index 37122a480bc1..11f0be07491e 100644
--- a/drivers/usb/musb/musb_regs.h
+++ b/drivers/usb/musb/musb_regs.h
@@ -239,14 +239,6 @@
#define MUSB_INDEX 0x0E /* 8 bit */
#define MUSB_TESTMODE 0x0F /* 8 bit */
-/* Get offset for a given FIFO from musb->mregs */
-#if defined(CONFIG_USB_MUSB_TUSB6010) || \
- defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
-#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20))
-#else
-#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4))
-#endif
-
/*
* Additional Control Registers
*/
@@ -295,21 +287,7 @@
#define MUSB_FIFOSIZE 0x0F
#define MUSB_CONFIGDATA MUSB_FIFOSIZE /* Re-used for EP0 */
-/* Offsets to endpoint registers in indexed model (using INDEX register) */
-#define MUSB_INDEXED_OFFSET(_epnum, _offset) \
- (0x10 + (_offset))
-
-/* Offsets to endpoint registers in flat models */
-#define MUSB_FLAT_OFFSET(_epnum, _offset) \
- (0x100 + (0x10*(_epnum)) + (_offset))
-
-#if defined(CONFIG_USB_MUSB_TUSB6010) || \
- defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
-/* TUSB6010 EP0 configuration register is special */
-#define MUSB_TUSB_OFFSET(_epnum, _offset) \
- (0x10 + _offset)
#include "tusb6010.h" /* Needed "only" for TUSB_EP0_CONF */
-#endif
#define MUSB_TXCSR_MODE 0x2000
@@ -480,10 +458,6 @@ static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum)
#define MUSB_INDEX USB_OFFSET(USB_INDEX) /* 8 bit */
#define MUSB_TESTMODE USB_OFFSET(USB_TESTMODE)/* 8 bit */
-/* Get offset for a given FIFO from musb->mregs */
-#define MUSB_FIFO_OFFSET(epnum) \
- (USB_OFFSET(USB_EP0_FIFO) + ((epnum) * 8))
-
/*
* Additional Control Registers
*/
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index e2d2d8c9891b..b072420e44f5 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -69,9 +69,10 @@ void musb_host_finish_resume(struct work_struct *work)
musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
usb_hcd_poll_rh_status(musb->hcd);
/* NOTE: it might really be A_WAIT_BCON ... */
- musb->xceiv->state = OTG_STATE_A_HOST;
+ musb->xceiv->otg->state = OTG_STATE_A_HOST;
spin_unlock_irqrestore(&musb->lock, flags);
+ musb_host_resume_root_hub(musb);
}
void musb_port_suspend(struct musb *musb, bool do_suspend)
@@ -107,9 +108,9 @@ void musb_port_suspend(struct musb *musb, bool do_suspend)
dev_dbg(musb->controller, "Root port suspended, power %02x\n", power);
musb->port1_status |= USB_PORT_STAT_SUSPEND;
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_HOST:
- musb->xceiv->state = OTG_STATE_A_SUSPEND;
+ musb->xceiv->otg->state = OTG_STATE_A_SUSPEND;
musb->is_active = otg->host->b_hnp_enable;
if (musb->is_active)
mod_timer(&musb->otg_timer, jiffies
@@ -118,13 +119,13 @@ void musb_port_suspend(struct musb *musb, bool do_suspend)
musb_platform_try_idle(musb, 0);
break;
case OTG_STATE_B_HOST:
- musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
+ musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON;
musb->is_active = otg->host->b_hnp_enable;
musb_platform_try_idle(musb, 0);
break;
default:
dev_dbg(musb->controller, "bogus rh suspend? %s\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
}
} else if (power & MUSB_POWER_SUSPENDM) {
power &= ~MUSB_POWER_SUSPENDM;
@@ -145,7 +146,7 @@ void musb_port_reset(struct musb *musb, bool do_reset)
u8 power;
void __iomem *mbase = musb->mregs;
- if (musb->xceiv->state == OTG_STATE_B_IDLE) {
+ if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) {
dev_dbg(musb->controller, "HNP: Returning from HNP; no hub reset from b_idle\n");
musb->port1_status &= ~USB_PORT_STAT_RESET;
return;
@@ -224,24 +225,24 @@ void musb_root_disconnect(struct musb *musb)
usb_hcd_poll_rh_status(musb->hcd);
musb->is_active = 0;
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_SUSPEND:
if (otg->host->b_hnp_enable) {
- musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
+ musb->xceiv->otg->state = OTG_STATE_A_PERIPHERAL;
musb->g.is_a_peripheral = 1;
break;
}
/* FALLTHROUGH */
case OTG_STATE_A_HOST:
- musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
musb->is_active = 0;
break;
case OTG_STATE_A_WAIT_VFALL:
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
break;
default:
dev_dbg(musb->controller, "host disconnect (%s)\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
}
}
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index e8e9f9aab203..ab7ec09a8afe 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -195,6 +195,7 @@ static int dma_channel_abort(struct dma_channel *channel)
{
struct musb_dma_channel *musb_channel = channel->private_data;
void __iomem *mbase = musb_channel->controller->base;
+ struct musb *musb = musb_channel->controller->private_data;
u8 bchannel = musb_channel->idx;
int offset;
@@ -202,7 +203,7 @@ static int dma_channel_abort(struct dma_channel *channel)
if (channel->status == MUSB_DMA_STATUS_BUSY) {
if (musb_channel->transmit) {
- offset = MUSB_EP_OFFSET(musb_channel->epnum,
+ offset = musb->io.ep_offset(musb_channel->epnum,
MUSB_TXCSR);
/*
@@ -215,7 +216,7 @@ static int dma_channel_abort(struct dma_channel *channel)
csr &= ~MUSB_TXCSR_DMAMODE;
musb_writew(mbase, offset, csr);
} else {
- offset = MUSB_EP_OFFSET(musb_channel->epnum,
+ offset = musb->io.ep_offset(musb_channel->epnum,
MUSB_RXCSR);
csr = musb_readw(mbase, offset);
@@ -326,7 +327,7 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
(musb_channel->max_packet_sz - 1)))
) {
u8 epnum = musb_channel->epnum;
- int offset = MUSB_EP_OFFSET(epnum,
+ int offset = musb->io.ep_offset(epnum,
MUSB_TXCSR);
u16 txcsr;
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index d369bf1f3936..763649eb4987 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -65,15 +65,15 @@ static void musb_do_idle(unsigned long _musb)
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_WAIT_BCON:
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if (devctl & MUSB_DEVCTL_BDEVICE) {
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
MUSB_DEV_MODE(musb);
} else {
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
}
break;
@@ -90,15 +90,15 @@ static void musb_do_idle(unsigned long _musb)
musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
usb_hcd_poll_rh_status(musb->hcd);
/* NOTE: it might really be A_WAIT_BCON ... */
- musb->xceiv->state = OTG_STATE_A_HOST;
+ musb->xceiv->otg->state = OTG_STATE_A_HOST;
}
break;
case OTG_STATE_A_HOST:
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if (devctl & MUSB_DEVCTL_BDEVICE)
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
else
- musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
default:
break;
}
@@ -116,9 +116,9 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
/* Never idle if active, or when VBUS timeout is not set as host */
if (musb->is_active || ((musb->a_wait_bcon == 0)
- && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
+ && (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON))) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
del_timer(&musb_idle_timer);
last_timer = jiffies;
return;
@@ -135,7 +135,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",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
(unsigned long)jiffies_to_msecs(timeout - jiffies));
mod_timer(&musb_idle_timer, timeout);
}
@@ -153,7 +153,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if (is_on) {
- if (musb->xceiv->state == OTG_STATE_A_IDLE) {
+ if (musb->xceiv->otg->state == OTG_STATE_A_IDLE) {
int loops = 100;
/* start the session */
devctl |= MUSB_DEVCTL_SESSION;
@@ -162,7 +162,8 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
* Wait for the musb to set as A device to enable the
* VBUS
*/
- while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
+ while (musb_readb(musb->mregs, MUSB_DEVCTL) &
+ MUSB_DEVCTL_BDEVICE) {
mdelay(5);
cpu_relax();
@@ -179,7 +180,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
} else {
musb->is_active = 1;
otg->default_a = 1;
- musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
devctl |= MUSB_DEVCTL_SESSION;
MUSB_HST_MODE(musb);
}
@@ -191,7 +192,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
*/
otg->default_a = 0;
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
devctl &= ~MUSB_DEVCTL_SESSION;
MUSB_DEV_MODE(musb);
@@ -200,7 +201,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",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
musb_readb(musb->mregs, MUSB_DEVCTL));
}
@@ -265,7 +266,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
dev_dbg(dev, "ID GND\n");
otg->default_a = true;
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
musb->xceiv->last_event = USB_EVENT_ID;
if (musb->gadget_driver) {
pm_runtime_get_sync(dev);
@@ -279,7 +280,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
dev_dbg(dev, "VBUS Connect\n");
otg->default_a = false;
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
musb->xceiv->last_event = USB_EVENT_VBUS;
if (musb->gadget_driver)
pm_runtime_get_sync(dev);
@@ -518,10 +519,8 @@ static int omap2430_probe(struct platform_device *pdev)
int ret = -ENOMEM;
glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
- if (!glue) {
- dev_err(&pdev->dev, "failed to allocate glue context\n");
+ if (!glue)
goto err0;
- }
musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
if (!musb) {
@@ -543,25 +542,16 @@ static int omap2430_probe(struct platform_device *pdev)
struct platform_device *control_pdev;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(&pdev->dev,
- "failed to allocate musb platform data\n");
+ if (!pdata)
goto err2;
- }
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data) {
- dev_err(&pdev->dev,
- "failed to allocate musb board data\n");
+ if (!data)
goto err2;
- }
config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
- if (!config) {
- dev_err(&pdev->dev,
- "failed to allocate musb hdrc config\n");
+ if (!config)
goto err2;
- }
of_property_read_u32(np, "mode", (u32 *)&pdata->mode);
of_property_read_u32(np, "interface-type",
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 2daa779f1382..3a5ffd575438 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -126,6 +126,52 @@ static void tusb_wbus_quirk(struct musb *musb, int enabled)
}
}
+static u32 tusb_fifo_offset(u8 epnum)
+{
+ return 0x200 + (epnum * 0x20);
+}
+
+static u32 tusb_ep_offset(u8 epnum, u16 offset)
+{
+ return 0x10 + offset;
+}
+
+/* TUSB mapping: "flat" plus ep0 special cases */
+static void tusb_ep_select(void __iomem *mbase, u8 epnum)
+{
+ musb_writeb(mbase, MUSB_INDEX, epnum);
+}
+
+/*
+ * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
+ */
+static u8 tusb_readb(const void __iomem *addr, unsigned offset)
+{
+ u16 tmp;
+ u8 val;
+
+ tmp = __raw_readw(addr + (offset & ~1));
+ if (offset & 1)
+ val = (tmp >> 8);
+ else
+ val = tmp & 0xff;
+
+ return val;
+}
+
+static void tusb_writeb(void __iomem *addr, unsigned offset, u8 data)
+{
+ u16 tmp;
+
+ tmp = __raw_readw(addr + (offset & ~1));
+ if (offset & 1)
+ tmp = (data << 8) | (tmp & 0xff);
+ else
+ tmp = (tmp & 0xff00) | data;
+
+ __raw_writew(tmp, addr + (offset & ~1));
+}
+
/*
* TUSB 6010 may use a parallel bus that doesn't support byte ops;
* so both loading and unloading FIFOs need explicit byte counts.
@@ -173,7 +219,7 @@ static inline void tusb_fifo_read_unaligned(void __iomem *fifo,
}
}
-void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf)
+static void tusb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf)
{
struct musb *musb = hw_ep->musb;
void __iomem *ep_conf = hw_ep->conf;
@@ -223,7 +269,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf)
tusb_fifo_write_unaligned(fifo, buf, len);
}
-void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
+static void tusb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
{
struct musb *musb = hw_ep->musb;
void __iomem *ep_conf = hw_ep->conf;
@@ -415,13 +461,13 @@ static void musb_do_idle(unsigned long _musb)
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_WAIT_BCON:
if ((musb->a_wait_bcon != 0)
&& (musb->idle_timeout == 0
|| time_after(jiffies, musb->idle_timeout))) {
dev_dbg(musb->controller, "Nothing connected %s, turning off VBUS\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
}
/* FALLTHROUGH */
case OTG_STATE_A_IDLE:
@@ -474,9 +520,9 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)
/* Never idle if active, or when VBUS timeout is not set as host */
if (musb->is_active || ((musb->a_wait_bcon == 0)
- && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
+ && (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON))) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- usb_otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->otg->state));
del_timer(&musb_idle_timer);
last_timer = jiffies;
return;
@@ -493,7 +539,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",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
(unsigned long)jiffies_to_msecs(timeout - jiffies));
mod_timer(&musb_idle_timer, timeout);
}
@@ -524,7 +570,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
if (is_on) {
timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
otg->default_a = 1;
- musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
devctl |= MUSB_DEVCTL_SESSION;
conf |= TUSB_DEV_CONF_USB_HOST_MODE;
@@ -537,16 +583,16 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
/* If ID pin is grounded, we want to be a_idle */
otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
if (!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) {
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_WAIT_VRISE:
case OTG_STATE_A_WAIT_BCON:
- musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL;
break;
case OTG_STATE_A_WAIT_VFALL:
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
break;
default:
- musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
}
musb->is_active = 0;
otg->default_a = 1;
@@ -554,7 +600,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
} else {
musb->is_active = 0;
otg->default_a = 0;
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
MUSB_DEV_MODE(musb);
}
@@ -569,7 +615,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",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
musb_readb(musb->mregs, MUSB_DEVCTL),
musb_readl(tbase, TUSB_DEV_OTG_STAT),
conf, prcm);
@@ -668,23 +714,23 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) {
dev_dbg(musb->controller, "Forcing disconnect (no interrupt)\n");
- if (musb->xceiv->state != OTG_STATE_B_IDLE) {
+ if (musb->xceiv->otg->state != OTG_STATE_B_IDLE) {
/* INTR_DISCONNECT can hide... */
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
musb->int_usb |= MUSB_INTR_DISCONNECT;
}
musb->is_active = 0;
}
dev_dbg(musb->controller, "vbus change, %s, otg %03x\n",
- usb_otg_state_string(musb->xceiv->state), otg_stat);
+ usb_otg_state_string(musb->xceiv->otg->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",
- usb_otg_state_string(musb->xceiv->state), otg_stat);
+ usb_otg_state_string(musb->xceiv->otg->state), otg_stat);
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_IDLE:
dev_dbg(musb->controller, "Got SRP, turning on VBUS\n");
musb_platform_set_vbus(musb, 1);
@@ -731,9 +777,9 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
u8 devctl;
dev_dbg(musb->controller, "%s timer, %03x\n",
- usb_otg_state_string(musb->xceiv->state), otg_stat);
+ usb_otg_state_string(musb->xceiv->otg->state), otg_stat);
- switch (musb->xceiv->state) {
+ switch (musb->xceiv->otg->state) {
case OTG_STATE_A_WAIT_VRISE:
/* VBUS has probably been valid for a while now,
* but may well have bounced out of range a bit
@@ -745,7 +791,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
dev_dbg(musb->controller, "devctl %02x\n", devctl);
break;
}
- musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
musb->is_active = 0;
idle_timeout = jiffies
+ msecs_to_jiffies(musb->a_wait_bcon);
@@ -1135,9 +1181,17 @@ static int tusb_musb_exit(struct musb *musb)
}
static const struct musb_platform_ops tusb_ops = {
+ .quirks = MUSB_IN_TUSB,
.init = tusb_musb_init,
.exit = tusb_musb_exit,
+ .ep_offset = tusb_ep_offset,
+ .ep_select = tusb_ep_select,
+ .fifo_offset = tusb_fifo_offset,
+ .readb = tusb_readb,
+ .writeb = tusb_writeb,
+ .read_fifo = tusb_read_fifo,
+ .write_fifo = tusb_write_fifo,
.enable = tusb_musb_enable,
.disable = tusb_musb_disable,
@@ -1164,10 +1218,8 @@ static int tusb_probe(struct platform_device *pdev)
int ret;
glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
- if (!glue) {
- dev_err(&pdev->dev, "failed to allocate glue context\n");
+ if (!glue)
return -ENOMEM;
- }
glue->dev = &pdev->dev;
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index dc666e96f45f..abf72728825f 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -56,7 +56,7 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on)
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if (is_on) {
- if (musb->xceiv->state == OTG_STATE_A_IDLE) {
+ if (musb->xceiv->otg->state == OTG_STATE_A_IDLE) {
/* start the session */
devctl |= MUSB_DEVCTL_SESSION;
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
@@ -76,7 +76,7 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on)
} else {
musb->is_active = 1;
musb->xceiv->otg->default_a = 1;
- musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
devctl |= MUSB_DEVCTL_SESSION;
MUSB_HST_MODE(musb);
}
@@ -102,7 +102,7 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on)
mdelay(200);
dev_dbg(musb->controller, "VBUS %s, devctl %02x\n",
- usb_otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->otg->state),
musb_readb(musb->mregs, MUSB_DEVCTL));
}
@@ -112,7 +112,7 @@ static int musb_otg_notifications(struct notifier_block *nb,
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));
+ event, usb_otg_state_string(musb->xceiv->otg->state));
switch (event) {
case UX500_MUSB_ID:
@@ -127,7 +127,7 @@ static int musb_otg_notifications(struct notifier_block *nb,
if (is_host_active(musb))
ux500_musb_set_vbus(musb, 0);
else
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
break;
default:
dev_dbg(musb->controller, "ID float\n");
@@ -188,8 +188,10 @@ static int ux500_musb_exit(struct musb *musb)
}
static const struct musb_platform_ops ux500_ops = {
+ .quirks = MUSB_INDEXED_EP,
.init = ux500_musb_init,
.exit = ux500_musb_exit,
+ .fifo_mode = 5,
.set_vbus = ux500_musb_set_vbus,
};
@@ -247,10 +249,8 @@ static int ux500_probe(struct platform_device *pdev)
}
glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
- if (!glue) {
- dev_err(&pdev->dev, "failed to allocate glue context\n");
+ if (!glue)
goto err0;
- }
musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
if (!musb) {
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index 221faed9f074..e93845c26bdb 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -91,9 +91,9 @@ static bool ux500_configure_channel(struct dma_channel *channel,
struct scatterlist sg;
struct dma_slave_config slave_conf;
enum dma_slave_buswidth addr_width;
- dma_addr_t usb_fifo_addr = (MUSB_FIFO_OFFSET(hw_ep->epnum) +
- ux500_channel->controller->phy_base);
struct musb *musb = ux500_channel->controller->private_data;
+ dma_addr_t usb_fifo_addr = (musb->io.fifo_offset(hw_ep->epnum) +
+ ux500_channel->controller->phy_base);
dev_dbg(musb->controller,
"packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n",
@@ -121,8 +121,7 @@ static bool ux500_configure_channel(struct dma_channel *channel,
slave_conf.dst_maxburst = 16;
slave_conf.device_fc = false;
- dma_chan->device->device_control(dma_chan, DMA_SLAVE_CONFIG,
- (unsigned long) &slave_conf);
+ dmaengine_slave_config(dma_chan, &slave_conf);
dma_desc = dmaengine_prep_slave_sg(dma_chan, &sg, 1, direction,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
@@ -246,9 +245,7 @@ static int ux500_dma_channel_abort(struct dma_channel *channel)
musb_writew(epio, MUSB_RXCSR, csr);
}
- ux500_channel->dma_chan->device->
- device_control(ux500_channel->dma_chan,
- DMA_TERMINATE_ALL, 0);
+ dmaengine_terminate_all(ux500_channel->dma_chan);
channel->status = MUSB_DMA_STATUS_FREE;
}
return 0;
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c
index 11ab2c45e462..8cd7d193c2ca 100644
--- a/drivers/usb/phy/phy-ab8500-usb.c
+++ b/drivers/usb/phy/phy-ab8500-usb.c
@@ -1,6 +1,4 @@
/*
- * drivers/usb/otg/ab8500_usb.c
- *
* USB transceiver driver for AB8500 family chips
*
* Copyright (C) 2010-2013 ST-Ericsson AB
@@ -446,7 +444,8 @@ static int ab9540_usb_link_status_update(struct ab8500_usb *ab,
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;
+ ab->phy.otg->state = OTG_STATE_B_IDLE;
+ usb_phy_set_event(&ab->phy, USB_EVENT_NONE);
break;
case USB_LINK_ACA_RID_C_NM_9540:
@@ -461,12 +460,14 @@ static int ab9540_usb_link_status_update(struct ab8500_usb *ab,
ab8500_usb_peri_phy_en(ab);
atomic_notifier_call_chain(&ab->phy.notifier,
UX500_MUSB_PREPARE, &ab->vbus_draw);
+ usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED);
}
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);
+ usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED);
}
if (event != UX500_MUSB_RIDC)
event = UX500_MUSB_VBUS;
@@ -502,6 +503,7 @@ static int ab9540_usb_link_status_update(struct ab8500_usb *ab,
event = UX500_MUSB_CHARGER;
atomic_notifier_call_chain(&ab->phy.notifier,
event, &ab->vbus_draw);
+ usb_phy_set_event(&ab->phy, USB_EVENT_CHARGER);
break;
case USB_LINK_PHYEN_NO_VBUS_NO_IDGND_9540:
@@ -526,6 +528,7 @@ static int ab9540_usb_link_status_update(struct ab8500_usb *ab,
ab->mode = USB_IDLE;
ab->phy.otg->default_a = false;
ab->vbus_draw = 0;
+ usb_phy_set_event(&ab->phy, USB_EVENT_NONE);
}
}
break;
@@ -584,7 +587,8 @@ static int ab8540_usb_link_status_update(struct ab8500_usb *ab,
* Fallback to default B_IDLE as nothing
* is connected
*/
- ab->phy.state = OTG_STATE_B_IDLE;
+ ab->phy.otg->state = OTG_STATE_B_IDLE;
+ usb_phy_set_event(&ab->phy, USB_EVENT_NONE);
break;
case USB_LINK_ACA_RID_C_NM_8540:
@@ -598,6 +602,7 @@ static int ab8540_usb_link_status_update(struct ab8500_usb *ab,
ab8500_usb_peri_phy_en(ab);
atomic_notifier_call_chain(&ab->phy.notifier,
UX500_MUSB_PREPARE, &ab->vbus_draw);
+ usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED);
}
if (event != UX500_MUSB_RIDC)
event = UX500_MUSB_VBUS;
@@ -626,6 +631,7 @@ static int ab8540_usb_link_status_update(struct ab8500_usb *ab,
event = UX500_MUSB_CHARGER;
atomic_notifier_call_chain(&ab->phy.notifier,
event, &ab->vbus_draw);
+ usb_phy_set_event(&ab->phy, USB_EVENT_CHARGER);
break;
case USB_LINK_PHYEN_NO_VBUS_NO_IDGND_8540:
@@ -648,6 +654,7 @@ static int ab8540_usb_link_status_update(struct ab8500_usb *ab,
ab->mode = USB_IDLE;
ab->phy.otg->default_a = false;
ab->vbus_draw = 0;
+ usb_phy_set_event(&ab->phy, USB_EVENT_NONE);
}
break;
@@ -693,7 +700,8 @@ static int ab8505_usb_link_status_update(struct ab8500_usb *ab,
* Fallback to default B_IDLE as nothing
* is connected
*/
- ab->phy.state = OTG_STATE_B_IDLE;
+ ab->phy.otg->state = OTG_STATE_B_IDLE;
+ usb_phy_set_event(&ab->phy, USB_EVENT_NONE);
break;
case USB_LINK_ACA_RID_C_NM_8505:
@@ -707,6 +715,7 @@ static int ab8505_usb_link_status_update(struct ab8500_usb *ab,
ab8500_usb_peri_phy_en(ab);
atomic_notifier_call_chain(&ab->phy.notifier,
UX500_MUSB_PREPARE, &ab->vbus_draw);
+ usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED);
}
if (event != UX500_MUSB_RIDC)
event = UX500_MUSB_VBUS;
@@ -734,6 +743,7 @@ static int ab8505_usb_link_status_update(struct ab8500_usb *ab,
event = UX500_MUSB_CHARGER;
atomic_notifier_call_chain(&ab->phy.notifier,
event, &ab->vbus_draw);
+ usb_phy_set_event(&ab->phy, USB_EVENT_CHARGER);
break;
default:
@@ -776,7 +786,8 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab,
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;
+ ab->phy.otg->state = OTG_STATE_B_IDLE;
+ usb_phy_set_event(&ab->phy, USB_EVENT_NONE);
break;
case USB_LINK_ACA_RID_C_NM_8500:
@@ -794,6 +805,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab,
ab8500_usb_peri_phy_en(ab);
atomic_notifier_call_chain(&ab->phy.notifier,
UX500_MUSB_PREPARE, &ab->vbus_draw);
+ usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED);
}
if (event != UX500_MUSB_RIDC)
event = UX500_MUSB_VBUS;
@@ -820,6 +832,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab,
event = UX500_MUSB_CHARGER;
atomic_notifier_call_chain(&ab->phy.notifier,
event, &ab->vbus_draw);
+ usb_phy_set_event(&ab->phy, USB_EVENT_CHARGER);
break;
case USB_LINK_RESERVED_8500:
@@ -1056,7 +1069,7 @@ static int ab8500_usb_set_peripheral(struct usb_otg *otg,
if (!otg)
return -ENODEV;
- ab = phy_to_ab(otg->phy);
+ ab = phy_to_ab(otg->usb_phy);
ab->phy.otg->gadget = gadget;
@@ -1080,7 +1093,7 @@ static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
if (!otg)
return -ENODEV;
- ab = phy_to_ab(otg->phy);
+ ab = phy_to_ab(otg->usb_phy);
ab->phy.otg->host = host;
@@ -1380,9 +1393,9 @@ static int ab8500_usb_probe(struct platform_device *pdev)
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;
+ ab->phy.otg->state = OTG_STATE_UNDEFINED;
- otg->phy = &ab->phy;
+ otg->usb_phy = &ab->phy;
otg->set_host = ab8500_usb_set_host;
otg->set_peripheral = ab8500_usb_set_peripheral;
diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c
index 35b6083b7999..2e923c581809 100644
--- a/drivers/usb/phy/phy-am335x-control.c
+++ b/drivers/usb/phy/phy-am335x-control.c
@@ -147,10 +147,8 @@ static int am335x_control_usb_probe(struct platform_device *pdev)
phy_ctrl = of_id->data;
ctrl_usb = devm_kzalloc(&pdev->dev, sizeof(*ctrl_usb), GFP_KERNEL);
- if (!ctrl_usb) {
- dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
+ if (!ctrl_usb)
return -ENOMEM;
- }
ctrl_usb->dev = &pdev->dev;
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index f1ea5990a50a..ab38aa32a6c1 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -274,7 +274,7 @@ void b_srp_end(unsigned long foo)
fsl_otg_dischrg_vbus(0);
srp_wait_done = 1;
- if ((fsl_otg_dev->phy.state == OTG_STATE_B_SRP_INIT) &&
+ if ((fsl_otg_dev->phy.otg->state == OTG_STATE_B_SRP_INIT) &&
fsl_otg_dev->fsm.b_sess_vld)
fsl_otg_dev->fsm.b_srp_done = 1;
}
@@ -499,7 +499,8 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on)
{
struct usb_otg *otg = fsm->otg;
struct device *dev;
- struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+ struct fsl_otg *otg_dev =
+ container_of(otg->usb_phy, struct fsl_otg, phy);
u32 retval = 0;
if (!otg->host)
@@ -594,7 +595,7 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
if (!otg)
return -ENODEV;
- otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+ otg_dev = container_of(otg->usb_phy, struct fsl_otg, phy);
if (otg_dev != fsl_otg_dev)
return -ENODEV;
@@ -623,7 +624,7 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
/* Mini-A cable connected */
struct otg_fsm *fsm = &otg_dev->fsm;
- otg->phy->state = OTG_STATE_UNDEFINED;
+ otg->state = OTG_STATE_UNDEFINED;
fsm->protocol = PROTO_UNDEF;
}
}
@@ -644,7 +645,7 @@ static int fsl_otg_set_peripheral(struct usb_otg *otg,
if (!otg)
return -ENODEV;
- otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+ otg_dev = container_of(otg->usb_phy, struct fsl_otg, phy);
VDBG("otg_dev 0x%x\n", (int)otg_dev);
VDBG("fsl_otg_dev 0x%x\n", (int)fsl_otg_dev);
if (otg_dev != fsl_otg_dev)
@@ -681,7 +682,7 @@ static int fsl_otg_set_power(struct usb_phy *phy, unsigned mA)
{
if (!fsl_otg_dev)
return -ENODEV;
- if (phy->state == OTG_STATE_B_PERIPHERAL)
+ if (phy->otg->state == OTG_STATE_B_PERIPHERAL)
pr_info("FSL OTG: Draw %d mA\n", mA);
return 0;
@@ -714,10 +715,10 @@ static int fsl_otg_start_srp(struct usb_otg *otg)
{
struct fsl_otg *otg_dev;
- if (!otg || otg->phy->state != OTG_STATE_B_IDLE)
+ if (!otg || otg->state != OTG_STATE_B_IDLE)
return -ENODEV;
- otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+ otg_dev = container_of(otg->usb_phy, struct fsl_otg, phy);
if (otg_dev != fsl_otg_dev)
return -ENODEV;
@@ -735,7 +736,7 @@ static int fsl_otg_start_hnp(struct usb_otg *otg)
if (!otg)
return -ENODEV;
- otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+ otg_dev = container_of(otg->usb_phy, struct fsl_otg, phy);
if (otg_dev != fsl_otg_dev)
return -ENODEV;
@@ -857,7 +858,7 @@ static int fsl_otg_conf(struct platform_device *pdev)
fsl_otg_tc->phy.dev = &pdev->dev;
fsl_otg_tc->phy.set_power = fsl_otg_set_power;
- fsl_otg_tc->phy.otg->phy = &fsl_otg_tc->phy;
+ fsl_otg_tc->phy.otg->usb_phy = &fsl_otg_tc->phy;
fsl_otg_tc->phy.otg->set_host = fsl_otg_set_host;
fsl_otg_tc->phy.otg->set_peripheral = fsl_otg_set_peripheral;
fsl_otg_tc->phy.otg->start_hnp = fsl_otg_start_hnp;
@@ -989,10 +990,10 @@ int usb_otg_start(struct platform_device *pdev)
* Also: record initial state of ID pin
*/
if (fsl_readl(&p_otg->dr_mem_map->otgsc) & OTGSC_STS_USB_ID) {
- p_otg->phy.state = OTG_STATE_UNDEFINED;
+ p_otg->phy.otg->state = OTG_STATE_UNDEFINED;
p_otg->fsm.id = 1;
} else {
- p_otg->phy.state = OTG_STATE_A_IDLE;
+ p_otg->phy.otg->state = OTG_STATE_A_IDLE;
p_otg->fsm.id = 0;
}
@@ -1047,7 +1048,7 @@ static int show_fsl_usb2_otg_state(struct device *dev,
/* State */
t = scnprintf(next, size,
"OTG state: %s\n\n",
- usb_otg_state_string(fsl_otg_dev->phy.state));
+ usb_otg_state_string(fsl_otg_dev->phy.otg->state));
size -= t;
next += t;
diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h
index 5986c96354df..23149954a09c 100644
--- a/drivers/usb/phy/phy-fsl-usb.h
+++ b/drivers/usb/phy/phy-fsl-usb.h
@@ -298,7 +298,7 @@
/* SE0 Time Before SRP */
#define TB_SE0_SRP (2) /* b_idle,minimum 2 ms, section:5.3.2 */
-#define SET_OTG_STATE(otg_ptr, newstate) ((otg_ptr)->state = newstate)
+#define SET_OTG_STATE(phy, newstate) ((phy)->otg->state = newstate)
struct usb_dr_mmap {
/* Capability register */
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index 7594e5069ae5..4ba1f57220f6 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -1,6 +1,4 @@
/*
- * drivers/usb/otg/nop-usb-xceiv.c
- *
* NOP USB transceiver for all USB transceiver which are either built-in
* into USB IP or which are mostly autonomous.
*
@@ -123,7 +121,7 @@ static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
}
otg->gadget = gadget;
- otg->phy->state = OTG_STATE_B_IDLE;
+ otg->state = OTG_STATE_B_IDLE;
return 0;
}
@@ -225,10 +223,10 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
nop->phy.dev = nop->dev;
nop->phy.label = "nop-xceiv";
nop->phy.set_suspend = nop_set_suspend;
- nop->phy.state = OTG_STATE_UNDEFINED;
nop->phy.type = type;
- nop->phy.otg->phy = &nop->phy;
+ nop->phy.otg->state = OTG_STATE_UNDEFINED;
+ nop->phy.otg->usb_phy = &nop->phy;
nop->phy.otg->set_host = nop_set_host;
nop->phy.otg->set_peripheral = nop_set_peripheral;
diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c
index f4b14bd97e14..54511725caaf 100644
--- a/drivers/usb/phy/phy-gpio-vbus-usb.c
+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c
@@ -121,7 +121,7 @@ static void gpio_vbus_work(struct work_struct *work)
if (vbus) {
status = USB_EVENT_VBUS;
- gpio_vbus->phy.state = OTG_STATE_B_PERIPHERAL;
+ gpio_vbus->phy.otg->state = OTG_STATE_B_PERIPHERAL;
gpio_vbus->phy.last_event = status;
usb_gadget_vbus_connect(gpio_vbus->phy.otg->gadget);
@@ -134,6 +134,7 @@ static void gpio_vbus_work(struct work_struct *work)
atomic_notifier_call_chain(&gpio_vbus->phy.notifier,
status, gpio_vbus->phy.otg->gadget);
+ usb_phy_set_event(&gpio_vbus->phy, USB_EVENT_ENUMERATED);
} else {
/* optionally disable D+ pullup */
if (gpio_is_valid(gpio))
@@ -143,11 +144,12 @@ static void gpio_vbus_work(struct work_struct *work)
usb_gadget_vbus_disconnect(gpio_vbus->phy.otg->gadget);
status = USB_EVENT_NONE;
- gpio_vbus->phy.state = OTG_STATE_B_IDLE;
+ gpio_vbus->phy.otg->state = OTG_STATE_B_IDLE;
gpio_vbus->phy.last_event = status;
atomic_notifier_call_chain(&gpio_vbus->phy.notifier,
status, gpio_vbus->phy.otg->gadget);
+ usb_phy_set_event(&gpio_vbus->phy, USB_EVENT_NONE);
}
}
@@ -180,7 +182,7 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg,
struct platform_device *pdev;
int gpio;
- gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy);
+ gpio_vbus = container_of(otg->usb_phy, struct gpio_vbus_data, phy);
pdev = to_platform_device(gpio_vbus->dev);
pdata = dev_get_platdata(gpio_vbus->dev);
gpio = pdata->gpio_pullup;
@@ -196,7 +198,7 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg,
set_vbus_draw(gpio_vbus, 0);
usb_gadget_vbus_disconnect(otg->gadget);
- otg->phy->state = OTG_STATE_UNDEFINED;
+ otg->state = OTG_STATE_UNDEFINED;
otg->gadget = NULL;
return 0;
@@ -218,7 +220,7 @@ static int gpio_vbus_set_power(struct usb_phy *phy, unsigned mA)
gpio_vbus = container_of(phy, struct gpio_vbus_data, phy);
- if (phy->state == OTG_STATE_B_PERIPHERAL)
+ if (phy->otg->state == OTG_STATE_B_PERIPHERAL)
set_vbus_draw(gpio_vbus, mA);
return 0;
}
@@ -269,9 +271,9 @@ static int gpio_vbus_probe(struct platform_device *pdev)
gpio_vbus->phy.dev = gpio_vbus->dev;
gpio_vbus->phy.set_power = gpio_vbus_set_power;
gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend;
- gpio_vbus->phy.state = OTG_STATE_UNDEFINED;
- gpio_vbus->phy.otg->phy = &gpio_vbus->phy;
+ gpio_vbus->phy.otg->state = OTG_STATE_UNDEFINED;
+ gpio_vbus->phy.otg->usb_phy = &gpio_vbus->phy;
gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral;
err = devm_gpio_request(&pdev->dev, gpio, "vbus_detect");
diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c
index 8eea56d3ded6..a2dfb2ae520e 100644
--- a/drivers/usb/phy/phy-isp1301-omap.c
+++ b/drivers/usb/phy/phy-isp1301-omap.c
@@ -234,7 +234,7 @@ isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
static inline const char *state_name(struct isp1301 *isp)
{
- return usb_otg_state_string(isp->phy.state);
+ return usb_otg_state_string(isp->phy.otg->state);
}
/*-------------------------------------------------------------------------*/
@@ -249,7 +249,7 @@ static inline const char *state_name(struct isp1301 *isp)
static void power_down(struct isp1301 *isp)
{
- isp->phy.state = OTG_STATE_UNDEFINED;
+ isp->phy.otg->state = OTG_STATE_UNDEFINED;
// isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND);
@@ -339,7 +339,7 @@ static void a_idle(struct isp1301 *isp, const char *tag)
{
u32 l;
- if (isp->phy.state == OTG_STATE_A_IDLE)
+ if (isp->phy.otg->state == OTG_STATE_A_IDLE)
return;
isp->phy.otg->default_a = 1;
@@ -351,7 +351,7 @@ static void a_idle(struct isp1301 *isp, const char *tag)
isp->phy.otg->gadget->is_a_peripheral = 1;
gadget_suspend(isp);
}
- isp->phy.state = OTG_STATE_A_IDLE;
+ isp->phy.otg->state = OTG_STATE_A_IDLE;
l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
omap_writel(l, OTG_CTRL);
isp->last_otg_ctrl = l;
@@ -363,7 +363,7 @@ static void b_idle(struct isp1301 *isp, const char *tag)
{
u32 l;
- if (isp->phy.state == OTG_STATE_B_IDLE)
+ if (isp->phy.otg->state == OTG_STATE_B_IDLE)
return;
isp->phy.otg->default_a = 0;
@@ -375,7 +375,7 @@ static void b_idle(struct isp1301 *isp, const char *tag)
isp->phy.otg->gadget->is_a_peripheral = 0;
gadget_suspend(isp);
}
- isp->phy.state = OTG_STATE_B_IDLE;
+ isp->phy.otg->state = OTG_STATE_B_IDLE;
l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
omap_writel(l, OTG_CTRL);
isp->last_otg_ctrl = l;
@@ -474,7 +474,7 @@ static void check_state(struct isp1301 *isp, const char *tag)
default:
break;
}
- if (isp->phy.state == state && !extra)
+ if (isp->phy.otg->state == state && !extra)
return;
pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag,
usb_otg_state_string(state), fsm, state_name(isp),
@@ -498,23 +498,23 @@ static void update_otg1(struct isp1301 *isp, u8 int_src)
if (int_src & INTR_SESS_VLD)
otg_ctrl |= OTG_ASESSVLD;
- else if (isp->phy.state == OTG_STATE_A_WAIT_VFALL) {
+ else if (isp->phy.otg->state == OTG_STATE_A_WAIT_VFALL) {
a_idle(isp, "vfall");
otg_ctrl &= ~OTG_CTRL_BITS;
}
if (int_src & INTR_VBUS_VLD)
otg_ctrl |= OTG_VBUSVLD;
if (int_src & INTR_ID_GND) { /* default-A */
- if (isp->phy.state == OTG_STATE_B_IDLE
- || isp->phy.state
+ if (isp->phy.otg->state == OTG_STATE_B_IDLE
+ || isp->phy.otg->state
== OTG_STATE_UNDEFINED) {
a_idle(isp, "init");
return;
}
} else { /* default-B */
otg_ctrl |= OTG_ID;
- if (isp->phy.state == OTG_STATE_A_IDLE
- || isp->phy.state == OTG_STATE_UNDEFINED) {
+ if (isp->phy.otg->state == OTG_STATE_A_IDLE
+ || isp->phy.otg->state == OTG_STATE_UNDEFINED) {
b_idle(isp, "init");
return;
}
@@ -548,14 +548,14 @@ static void otg_update_isp(struct isp1301 *isp)
isp->last_otg_ctrl = otg_ctrl;
otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS;
- switch (isp->phy.state) {
+ switch (isp->phy.otg->state) {
case OTG_STATE_B_IDLE:
case OTG_STATE_B_PERIPHERAL:
case OTG_STATE_B_SRP_INIT:
if (!(otg_ctrl & OTG_PULLUP)) {
// if (otg_ctrl & OTG_B_HNPEN) {
if (isp->phy.otg->gadget->b_hnp_enable) {
- isp->phy.state = OTG_STATE_B_WAIT_ACON;
+ isp->phy.otg->state = OTG_STATE_B_WAIT_ACON;
pr_debug(" --> b_wait_acon\n");
}
goto pulldown;
@@ -585,7 +585,7 @@ pulldown:
if (!(isp->phy.otg->host))
otg_ctrl &= ~OTG_DRV_VBUS;
- switch (isp->phy.state) {
+ switch (isp->phy.otg->state) {
case OTG_STATE_A_SUSPEND:
if (otg_ctrl & OTG_DRV_VBUS) {
set |= OTG1_VBUS_DRV;
@@ -596,7 +596,7 @@ pulldown:
/* FALLTHROUGH */
case OTG_STATE_A_VBUS_ERR:
- isp->phy.state = OTG_STATE_A_WAIT_VFALL;
+ isp->phy.otg->state = OTG_STATE_A_WAIT_VFALL;
pr_debug(" --> a_wait_vfall\n");
/* FALLTHROUGH */
case OTG_STATE_A_WAIT_VFALL:
@@ -605,7 +605,7 @@ pulldown:
break;
case OTG_STATE_A_IDLE:
if (otg_ctrl & OTG_DRV_VBUS) {
- isp->phy.state = OTG_STATE_A_WAIT_VRISE;
+ isp->phy.otg->state = OTG_STATE_A_WAIT_VRISE;
pr_debug(" --> a_wait_vrise\n");
}
/* FALLTHROUGH */
@@ -625,17 +625,17 @@ pulldown:
if (otg_change & OTG_PULLUP) {
u32 l;
- switch (isp->phy.state) {
+ switch (isp->phy.otg->state) {
case OTG_STATE_B_IDLE:
if (clr & OTG1_DP_PULLUP)
break;
- isp->phy.state = OTG_STATE_B_PERIPHERAL;
+ isp->phy.otg->state = OTG_STATE_B_PERIPHERAL;
pr_debug(" --> b_peripheral\n");
break;
case OTG_STATE_A_SUSPEND:
if (clr & OTG1_DP_PULLUP)
break;
- isp->phy.state = OTG_STATE_A_PERIPHERAL;
+ isp->phy.otg->state = OTG_STATE_A_PERIPHERAL;
pr_debug(" --> a_peripheral\n");
break;
default:
@@ -673,7 +673,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
* remote wakeup (SRP, normal) using their own timer
* to give "check cable and A-device" messages.
*/
- if (isp->phy.state == OTG_STATE_B_SRP_INIT)
+ if (isp->phy.otg->state == OTG_STATE_B_SRP_INIT)
b_idle(isp, "srp_timeout");
omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC);
@@ -691,7 +691,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
omap_writel(otg_ctrl, OTG_CTRL);
/* subset of b_peripheral()... */
- isp->phy.state = OTG_STATE_B_PERIPHERAL;
+ isp->phy.otg->state = OTG_STATE_B_PERIPHERAL;
pr_debug(" --> b_peripheral\n");
omap_writew(B_HNP_FAIL, OTG_IRQ_SRC);
@@ -703,7 +703,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
state_name(isp), omap_readl(OTG_CTRL));
isp1301_defer_work(isp, WORK_UPDATE_OTG);
- switch (isp->phy.state) {
+ switch (isp->phy.otg->state) {
case OTG_STATE_A_IDLE:
if (!otg->host)
break;
@@ -734,7 +734,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
otg_ctrl |= OTG_BUSDROP;
otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
omap_writel(otg_ctrl, OTG_CTRL);
- isp->phy.state = OTG_STATE_A_WAIT_VFALL;
+ isp->phy.otg->state = OTG_STATE_A_WAIT_VFALL;
omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC);
ret = IRQ_HANDLED;
@@ -748,7 +748,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
otg_ctrl |= OTG_BUSDROP;
otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
omap_writel(otg_ctrl, OTG_CTRL);
- isp->phy.state = OTG_STATE_A_VBUS_ERR;
+ isp->phy.otg->state = OTG_STATE_A_VBUS_ERR;
omap_writew(A_VBUS_ERR, OTG_IRQ_SRC);
ret = IRQ_HANDLED;
@@ -769,7 +769,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
/* role is peripheral */
if (otg_ctrl & OTG_DRIVER_SEL) {
- switch (isp->phy.state) {
+ switch (isp->phy.otg->state) {
case OTG_STATE_A_IDLE:
b_idle(isp, __func__);
break;
@@ -786,18 +786,18 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
}
if (otg->host) {
- switch (isp->phy.state) {
+ switch (isp->phy.otg->state) {
case OTG_STATE_B_WAIT_ACON:
- isp->phy.state = OTG_STATE_B_HOST;
+ isp->phy.otg->state = OTG_STATE_B_HOST;
pr_debug(" --> b_host\n");
kick = 1;
break;
case OTG_STATE_A_WAIT_BCON:
- isp->phy.state = OTG_STATE_A_HOST;
+ isp->phy.otg->state = OTG_STATE_A_HOST;
pr_debug(" --> a_host\n");
break;
case OTG_STATE_A_PERIPHERAL:
- isp->phy.state = OTG_STATE_A_WAIT_BCON;
+ isp->phy.otg->state = OTG_STATE_A_WAIT_BCON;
pr_debug(" --> a_wait_bcon\n");
break;
default:
@@ -937,7 +937,7 @@ static void b_peripheral(struct isp1301 *isp)
/* UDC driver just set OTG_BSESSVLD */
isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP);
isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN);
- isp->phy.state = OTG_STATE_B_PERIPHERAL;
+ isp->phy.otg->state = OTG_STATE_B_PERIPHERAL;
pr_debug(" --> b_peripheral\n");
dump_regs(isp, "2periph");
#endif
@@ -947,7 +947,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
{
struct usb_otg *otg = isp->phy.otg;
u8 isp_stat, isp_bstat;
- enum usb_otg_state state = isp->phy.state;
+ enum usb_otg_state state = isp->phy.otg->state;
if (stat & INTR_BDIS_ACON)
pr_debug("OTG: BDIS_ACON, %s\n", state_name(isp));
@@ -970,7 +970,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
* when HNP is used.
*/
if (isp_stat & INTR_VBUS_VLD)
- isp->phy.state = OTG_STATE_A_HOST;
+ isp->phy.otg->state = OTG_STATE_A_HOST;
break;
case OTG_STATE_A_WAIT_VFALL:
if (!(isp_stat & INTR_SESS_VLD))
@@ -978,7 +978,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
break;
default:
if (!(isp_stat & INTR_VBUS_VLD))
- isp->phy.state = OTG_STATE_A_VBUS_ERR;
+ isp->phy.otg->state = OTG_STATE_A_VBUS_ERR;
break;
}
isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
@@ -1007,7 +1007,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
if (otg->default_a) {
switch (state) {
default:
- isp->phy.state = OTG_STATE_A_WAIT_VFALL;
+ isp->phy.otg->state = OTG_STATE_A_WAIT_VFALL;
break;
case OTG_STATE_A_WAIT_VFALL:
state = OTG_STATE_A_IDLE;
@@ -1020,7 +1020,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
host_suspend(isp);
isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1,
MC1_BDIS_ACON_EN);
- isp->phy.state = OTG_STATE_B_IDLE;
+ isp->phy.otg->state = OTG_STATE_B_IDLE;
l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
l &= ~OTG_CTRL_BITS;
omap_writel(l, OTG_CTRL);
@@ -1031,7 +1031,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
}
isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
- switch (isp->phy.state) {
+ switch (isp->phy.otg->state) {
case OTG_STATE_B_PERIPHERAL:
case OTG_STATE_B_WAIT_ACON:
case OTG_STATE_B_HOST:
@@ -1071,7 +1071,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
}
}
- if (state != isp->phy.state)
+ if (state != isp->phy.otg->state)
pr_debug(" isp, %s -> %s\n",
usb_otg_state_string(state), state_name(isp));
@@ -1129,10 +1129,10 @@ isp1301_work(struct work_struct *work)
* skip A_WAIT_VRISE; hc transitions invisibly
* skip A_WAIT_BCON; same.
*/
- switch (isp->phy.state) {
+ switch (isp->phy.otg->state) {
case OTG_STATE_A_WAIT_BCON:
case OTG_STATE_A_WAIT_VRISE:
- isp->phy.state = OTG_STATE_A_HOST;
+ isp->phy.otg->state = OTG_STATE_A_HOST;
pr_debug(" --> a_host\n");
otg_ctrl = omap_readl(OTG_CTRL);
otg_ctrl |= OTG_A_BUSREQ;
@@ -1141,7 +1141,7 @@ isp1301_work(struct work_struct *work)
omap_writel(otg_ctrl, OTG_CTRL);
break;
case OTG_STATE_B_WAIT_ACON:
- isp->phy.state = OTG_STATE_B_HOST;
+ isp->phy.otg->state = OTG_STATE_B_HOST;
pr_debug(" --> b_host (acon)\n");
break;
case OTG_STATE_B_HOST:
@@ -1275,7 +1275,7 @@ static int isp1301_otg_enable(struct isp1301 *isp)
static int
isp1301_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy);
+ struct isp1301 *isp = container_of(otg->usb_phy, struct isp1301, phy);
if (isp != the_transceiver)
return -ENODEV;
@@ -1331,7 +1331,7 @@ isp1301_set_host(struct usb_otg *otg, struct usb_bus *host)
static int
isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
{
- struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy);
+ struct isp1301 *isp = container_of(otg->usb_phy, struct isp1301, phy);
if (isp != the_transceiver)
return -ENODEV;
@@ -1368,7 +1368,7 @@ isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
}
power_up(isp);
- isp->phy.state = OTG_STATE_B_IDLE;
+ isp->phy.otg->state = OTG_STATE_B_IDLE;
if (machine_is_omap_h2() || machine_is_omap_h3())
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
@@ -1403,7 +1403,7 @@ isp1301_set_power(struct usb_phy *dev, unsigned mA)
{
if (!the_transceiver)
return -ENODEV;
- if (dev->state == OTG_STATE_B_PERIPHERAL)
+ if (dev->otg->state == OTG_STATE_B_PERIPHERAL)
enable_vbus_draw(the_transceiver, mA);
return 0;
}
@@ -1411,10 +1411,10 @@ isp1301_set_power(struct usb_phy *dev, unsigned mA)
static int
isp1301_start_srp(struct usb_otg *otg)
{
- struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy);
+ struct isp1301 *isp = container_of(otg->usb_phy, struct isp1301, phy);
u32 otg_ctrl;
- if (isp != the_transceiver || isp->phy.state != OTG_STATE_B_IDLE)
+ if (isp != the_transceiver || isp->phy.otg->state != OTG_STATE_B_IDLE)
return -ENODEV;
otg_ctrl = omap_readl(OTG_CTRL);
@@ -1424,7 +1424,7 @@ isp1301_start_srp(struct usb_otg *otg)
otg_ctrl |= OTG_B_BUSREQ;
otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK;
omap_writel(otg_ctrl, OTG_CTRL);
- isp->phy.state = OTG_STATE_B_SRP_INIT;
+ isp->phy.otg->state = OTG_STATE_B_SRP_INIT;
pr_debug("otg: SRP, %s ... %06x\n", state_name(isp),
omap_readl(OTG_CTRL));
@@ -1438,7 +1438,7 @@ static int
isp1301_start_hnp(struct usb_otg *otg)
{
#ifdef CONFIG_USB_OTG
- struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy);
+ struct isp1301 *isp = container_of(otg->usb_phy, struct isp1301, phy);
u32 l;
if (isp != the_transceiver)
@@ -1452,9 +1452,9 @@ isp1301_start_hnp(struct usb_otg *otg)
/* We want hardware to manage most HNP protocol timings.
* So do this part as early as possible...
*/
- switch (isp->phy.state) {
+ switch (isp->phy.otg->state) {
case OTG_STATE_B_HOST:
- isp->phy.state = OTG_STATE_B_PERIPHERAL;
+ isp->phy.otg->state = OTG_STATE_B_PERIPHERAL;
/* caller will suspend next */
break;
case OTG_STATE_A_HOST:
@@ -1583,7 +1583,7 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
isp->phy.label = DRIVER_NAME;
isp->phy.set_power = isp1301_set_power,
- isp->phy.otg->phy = &isp->phy;
+ isp->phy.otg->usb_phy = &isp->phy;
isp->phy.otg->set_host = isp1301_set_host,
isp->phy.otg->set_peripheral = isp1301_set_peripheral,
isp->phy.otg->start_srp = isp1301_start_srp,
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
index 29be0e654ecc..000fd892455f 100644
--- a/drivers/usb/phy/phy-msm-usb.c
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -708,7 +708,7 @@ static void msm_otg_start_host(struct usb_phy *phy, int on)
static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
+ struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
struct usb_hcd *hcd;
/*
@@ -716,16 +716,16 @@ static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
* only peripheral configuration.
*/
if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL) {
- dev_info(otg->phy->dev, "Host mode is not supported\n");
+ dev_info(otg->usb_phy->dev, "Host mode is not supported\n");
return -ENODEV;
}
if (!host) {
- if (otg->phy->state == OTG_STATE_A_HOST) {
- pm_runtime_get_sync(otg->phy->dev);
- msm_otg_start_host(otg->phy, 0);
+ if (otg->state == OTG_STATE_A_HOST) {
+ pm_runtime_get_sync(otg->usb_phy->dev);
+ msm_otg_start_host(otg->usb_phy, 0);
otg->host = NULL;
- otg->phy->state = OTG_STATE_UNDEFINED;
+ otg->state = OTG_STATE_UNDEFINED;
schedule_work(&motg->sm_work);
} else {
otg->host = NULL;
@@ -738,14 +738,14 @@ static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
hcd->power_budget = motg->pdata->power_budget;
otg->host = host;
- dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
+ dev_dbg(otg->usb_phy->dev, "host driver registered w/ tranceiver\n");
/*
* Kick the state machine work, if peripheral is not supported
* or peripheral is already registered with us.
*/
if (motg->pdata->mode == USB_DR_MODE_HOST || otg->gadget) {
- pm_runtime_get_sync(otg->phy->dev);
+ pm_runtime_get_sync(otg->usb_phy->dev);
schedule_work(&motg->sm_work);
}
@@ -782,23 +782,23 @@ static void msm_otg_start_peripheral(struct usb_phy *phy, int on)
static int msm_otg_set_peripheral(struct usb_otg *otg,
struct usb_gadget *gadget)
{
- struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
+ struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
/*
* Fail peripheral registration if this board can support
* only host configuration.
*/
if (motg->pdata->mode == USB_DR_MODE_HOST) {
- dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
+ dev_info(otg->usb_phy->dev, "Peripheral mode is not supported\n");
return -ENODEV;
}
if (!gadget) {
- if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
- pm_runtime_get_sync(otg->phy->dev);
- msm_otg_start_peripheral(otg->phy, 0);
+ if (otg->state == OTG_STATE_B_PERIPHERAL) {
+ pm_runtime_get_sync(otg->usb_phy->dev);
+ msm_otg_start_peripheral(otg->usb_phy, 0);
otg->gadget = NULL;
- otg->phy->state = OTG_STATE_UNDEFINED;
+ otg->state = OTG_STATE_UNDEFINED;
schedule_work(&motg->sm_work);
} else {
otg->gadget = NULL;
@@ -807,14 +807,15 @@ static int msm_otg_set_peripheral(struct usb_otg *otg,
return 0;
}
otg->gadget = gadget;
- dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
+ dev_dbg(otg->usb_phy->dev,
+ "peripheral driver registered w/ tranceiver\n");
/*
* Kick the state machine work, if host is not supported
* or host is already registered with us.
*/
if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL || otg->host) {
- pm_runtime_get_sync(otg->phy->dev);
+ pm_runtime_get_sync(otg->usb_phy->dev);
schedule_work(&motg->sm_work);
}
@@ -1170,20 +1171,20 @@ static void msm_otg_sm_work(struct work_struct *w)
struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
struct usb_otg *otg = motg->phy.otg;
- switch (otg->phy->state) {
+ switch (otg->state) {
case OTG_STATE_UNDEFINED:
- dev_dbg(otg->phy->dev, "OTG_STATE_UNDEFINED state\n");
- msm_otg_reset(otg->phy);
+ dev_dbg(otg->usb_phy->dev, "OTG_STATE_UNDEFINED state\n");
+ msm_otg_reset(otg->usb_phy);
msm_otg_init_sm(motg);
- otg->phy->state = OTG_STATE_B_IDLE;
+ otg->state = OTG_STATE_B_IDLE;
/* FALL THROUGH */
case OTG_STATE_B_IDLE:
- dev_dbg(otg->phy->dev, "OTG_STATE_B_IDLE state\n");
+ dev_dbg(otg->usb_phy->dev, "OTG_STATE_B_IDLE state\n");
if (!test_bit(ID, &motg->inputs) && otg->host) {
/* disable BSV bit */
writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC);
- msm_otg_start_host(otg->phy, 1);
- otg->phy->state = OTG_STATE_A_HOST;
+ msm_otg_start_host(otg->usb_phy, 1);
+ otg->state = OTG_STATE_A_HOST;
} else if (test_bit(B_SESS_VLD, &motg->inputs)) {
switch (motg->chg_state) {
case USB_CHG_STATE_UNDEFINED:
@@ -1198,14 +1199,16 @@ static void msm_otg_sm_work(struct work_struct *w)
case USB_CDP_CHARGER:
msm_otg_notify_charger(motg,
IDEV_CHG_MAX);
- msm_otg_start_peripheral(otg->phy, 1);
- otg->phy->state
+ msm_otg_start_peripheral(otg->usb_phy,
+ 1);
+ otg->state
= OTG_STATE_B_PERIPHERAL;
break;
case USB_SDP_CHARGER:
msm_otg_notify_charger(motg, IUNIT);
- msm_otg_start_peripheral(otg->phy, 1);
- otg->phy->state
+ msm_otg_start_peripheral(otg->usb_phy,
+ 1);
+ otg->state
= OTG_STATE_B_PERIPHERAL;
break;
default:
@@ -1222,36 +1225,36 @@ static void msm_otg_sm_work(struct work_struct *w)
* is incremented in charger detection work.
*/
if (cancel_delayed_work_sync(&motg->chg_work)) {
- pm_runtime_put_sync(otg->phy->dev);
- msm_otg_reset(otg->phy);
+ pm_runtime_put_sync(otg->usb_phy->dev);
+ msm_otg_reset(otg->usb_phy);
}
msm_otg_notify_charger(motg, 0);
motg->chg_state = USB_CHG_STATE_UNDEFINED;
motg->chg_type = USB_INVALID_CHARGER;
}
- if (otg->phy->state == OTG_STATE_B_IDLE)
- pm_runtime_put_sync(otg->phy->dev);
+ if (otg->state == OTG_STATE_B_IDLE)
+ pm_runtime_put_sync(otg->usb_phy->dev);
break;
case OTG_STATE_B_PERIPHERAL:
- dev_dbg(otg->phy->dev, "OTG_STATE_B_PERIPHERAL state\n");
+ dev_dbg(otg->usb_phy->dev, "OTG_STATE_B_PERIPHERAL state\n");
if (!test_bit(B_SESS_VLD, &motg->inputs) ||
!test_bit(ID, &motg->inputs)) {
msm_otg_notify_charger(motg, 0);
- msm_otg_start_peripheral(otg->phy, 0);
+ msm_otg_start_peripheral(otg->usb_phy, 0);
motg->chg_state = USB_CHG_STATE_UNDEFINED;
motg->chg_type = USB_INVALID_CHARGER;
- otg->phy->state = OTG_STATE_B_IDLE;
- msm_otg_reset(otg->phy);
+ otg->state = OTG_STATE_B_IDLE;
+ msm_otg_reset(otg->usb_phy);
schedule_work(w);
}
break;
case OTG_STATE_A_HOST:
- dev_dbg(otg->phy->dev, "OTG_STATE_A_HOST state\n");
+ dev_dbg(otg->usb_phy->dev, "OTG_STATE_A_HOST state\n");
if (test_bit(ID, &motg->inputs)) {
- msm_otg_start_host(otg->phy, 0);
- otg->phy->state = OTG_STATE_B_IDLE;
- msm_otg_reset(otg->phy);
+ msm_otg_start_host(otg->usb_phy, 0);
+ otg->state = OTG_STATE_B_IDLE;
+ msm_otg_reset(otg->usb_phy);
schedule_work(w);
}
break;
@@ -1303,7 +1306,7 @@ static int msm_otg_mode_show(struct seq_file *s, void *unused)
struct msm_otg *motg = s->private;
struct usb_otg *otg = motg->phy.otg;
- switch (otg->phy->state) {
+ switch (otg->state) {
case OTG_STATE_A_HOST:
seq_puts(s, "host\n");
break;
@@ -1353,7 +1356,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
switch (req_mode) {
case USB_DR_MODE_UNKNOWN:
- switch (otg->phy->state) {
+ switch (otg->state) {
case OTG_STATE_A_HOST:
case OTG_STATE_B_PERIPHERAL:
set_bit(ID, &motg->inputs);
@@ -1364,7 +1367,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
}
break;
case USB_DR_MODE_PERIPHERAL:
- switch (otg->phy->state) {
+ switch (otg->state) {
case OTG_STATE_B_IDLE:
case OTG_STATE_A_HOST:
set_bit(ID, &motg->inputs);
@@ -1375,7 +1378,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
}
break;
case USB_DR_MODE_HOST:
- switch (otg->phy->state) {
+ switch (otg->state) {
case OTG_STATE_B_IDLE:
case OTG_STATE_B_PERIPHERAL:
clear_bit(ID, &motg->inputs);
@@ -1388,7 +1391,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
goto out;
}
- pm_runtime_get_sync(otg->phy->dev);
+ pm_runtime_get_sync(otg->usb_phy->dev);
schedule_work(&motg->sm_work);
out:
return status;
@@ -1505,10 +1508,8 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
}
pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
- if (!pdata->phy_init_seq) {
- dev_warn(&pdev->dev, "No space for PHY init sequence\n");
+ if (!pdata->phy_init_seq)
return 0;
- }
ret = of_property_read_u32_array(node, "qcom,phy-init-sequence",
pdata->phy_init_seq, words);
@@ -1530,10 +1531,8 @@ static int msm_otg_probe(struct platform_device *pdev)
void __iomem *phy_select;
motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL);
- if (!motg) {
- dev_err(&pdev->dev, "unable to allocate msm_otg\n");
+ if (!motg)
return -ENOMEM;
- }
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
@@ -1546,10 +1545,8 @@ static int msm_otg_probe(struct platform_device *pdev)
motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
GFP_KERNEL);
- if (!motg->phy.otg) {
- dev_err(&pdev->dev, "unable to allocate msm_otg\n");
+ if (!motg->phy.otg)
return -ENOMEM;
- }
phy = &motg->phy;
phy->dev = &pdev->dev;
@@ -1674,7 +1671,7 @@ static int msm_otg_probe(struct platform_device *pdev)
phy->io_ops = &msm_otg_io_ops;
- phy->otg->phy = &motg->phy;
+ phy->otg->usb_phy = &motg->phy;
phy->otg->set_host = msm_otg_set_host;
phy->otg->set_peripheral = msm_otg_set_peripheral;
@@ -1775,7 +1772,7 @@ static int msm_otg_runtime_idle(struct device *dev)
* This 1 sec delay also prevents entering into LPM immediately
* after asynchronous interrupt.
*/
- if (otg->phy->state != OTG_STATE_UNDEFINED)
+ if (otg->state != OTG_STATE_UNDEFINED)
pm_schedule_suspend(dev, 1000);
return -EAGAIN;
diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c
index 7d80c54f0ac6..b234d46cd58b 100644
--- a/drivers/usb/phy/phy-mv-usb.c
+++ b/drivers/usb/phy/phy-mv-usb.c
@@ -56,7 +56,7 @@ static char *state_string[] = {
static int mv_otg_set_vbus(struct usb_otg *otg, bool on)
{
- struct mv_otg *mvotg = container_of(otg->phy, struct mv_otg, phy);
+ struct mv_otg *mvotg = container_of(otg->usb_phy, struct mv_otg, phy);
if (mvotg->pdata->set_vbus == NULL)
return -ENODEV;
@@ -339,68 +339,68 @@ static void mv_otg_update_state(struct mv_otg *mvotg)
{
struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
struct usb_phy *phy = &mvotg->phy;
- int old_state = phy->state;
+ int old_state = mvotg->phy.otg->state;
switch (old_state) {
case OTG_STATE_UNDEFINED:
- phy->state = OTG_STATE_B_IDLE;
+ mvotg->phy.otg->state = OTG_STATE_B_IDLE;
/* FALL THROUGH */
case OTG_STATE_B_IDLE:
if (otg_ctrl->id == 0)
- phy->state = OTG_STATE_A_IDLE;
+ mvotg->phy.otg->state = OTG_STATE_A_IDLE;
else if (otg_ctrl->b_sess_vld)
- phy->state = OTG_STATE_B_PERIPHERAL;
+ mvotg->phy.otg->state = OTG_STATE_B_PERIPHERAL;
break;
case OTG_STATE_B_PERIPHERAL:
if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0)
- phy->state = OTG_STATE_B_IDLE;
+ mvotg->phy.otg->state = OTG_STATE_B_IDLE;
break;
case OTG_STATE_A_IDLE:
if (otg_ctrl->id)
- phy->state = OTG_STATE_B_IDLE;
+ mvotg->phy.otg->state = OTG_STATE_B_IDLE;
else if (!(otg_ctrl->a_bus_drop) &&
(otg_ctrl->a_bus_req || otg_ctrl->a_srp_det))
- phy->state = OTG_STATE_A_WAIT_VRISE;
+ mvotg->phy.otg->state = OTG_STATE_A_WAIT_VRISE;
break;
case OTG_STATE_A_WAIT_VRISE:
if (otg_ctrl->a_vbus_vld)
- phy->state = OTG_STATE_A_WAIT_BCON;
+ mvotg->phy.otg->state = OTG_STATE_A_WAIT_BCON;
break;
case OTG_STATE_A_WAIT_BCON:
if (otg_ctrl->id || otg_ctrl->a_bus_drop
|| otg_ctrl->a_wait_bcon_timeout) {
mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
- phy->state = OTG_STATE_A_WAIT_VFALL;
+ mvotg->phy.otg->state = OTG_STATE_A_WAIT_VFALL;
otg_ctrl->a_bus_req = 0;
} else if (!otg_ctrl->a_vbus_vld) {
mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
- phy->state = OTG_STATE_A_VBUS_ERR;
+ mvotg->phy.otg->state = OTG_STATE_A_VBUS_ERR;
} else if (otg_ctrl->b_conn) {
mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
- phy->state = OTG_STATE_A_HOST;
+ mvotg->phy.otg->state = OTG_STATE_A_HOST;
}
break;
case OTG_STATE_A_HOST:
if (otg_ctrl->id || !otg_ctrl->b_conn
|| otg_ctrl->a_bus_drop)
- phy->state = OTG_STATE_A_WAIT_BCON;
+ mvotg->phy.otg->state = OTG_STATE_A_WAIT_BCON;
else if (!otg_ctrl->a_vbus_vld)
- phy->state = OTG_STATE_A_VBUS_ERR;
+ mvotg->phy.otg->state = OTG_STATE_A_VBUS_ERR;
break;
case OTG_STATE_A_WAIT_VFALL:
if (otg_ctrl->id
|| (!otg_ctrl->b_conn && otg_ctrl->a_sess_vld)
|| otg_ctrl->a_bus_req)
- phy->state = OTG_STATE_A_IDLE;
+ mvotg->phy.otg->state = OTG_STATE_A_IDLE;
break;
case OTG_STATE_A_VBUS_ERR:
if (otg_ctrl->id || otg_ctrl->a_clr_err
|| otg_ctrl->a_bus_drop) {
otg_ctrl->a_clr_err = 0;
- phy->state = OTG_STATE_A_WAIT_VFALL;
+ mvotg->phy.otg->state = OTG_STATE_A_WAIT_VFALL;
}
break;
default:
@@ -420,8 +420,8 @@ static void mv_otg_work(struct work_struct *work)
run:
/* work queue is single thread, or we need spin_lock to protect */
phy = &mvotg->phy;
- otg = phy->otg;
- old_state = phy->state;
+ otg = mvotg->phy.otg;
+ old_state = otg->state;
if (!mvotg->active)
return;
@@ -429,22 +429,24 @@ run:
mv_otg_update_inputs(mvotg);
mv_otg_update_state(mvotg);
- if (old_state != phy->state) {
+ if (old_state != mvotg->phy.otg->state) {
dev_info(&mvotg->pdev->dev, "change from state %s to %s\n",
state_string[old_state],
- state_string[phy->state]);
+ state_string[mvotg->phy.otg->state]);
- switch (phy->state) {
+ switch (mvotg->phy.otg->state) {
case OTG_STATE_B_IDLE:
otg->default_a = 0;
if (old_state == OTG_STATE_B_PERIPHERAL)
mv_otg_start_periphrals(mvotg, 0);
mv_otg_reset(mvotg);
mv_otg_disable(mvotg);
+ usb_phy_set_event(&mvotg->phy, USB_EVENT_NONE);
break;
case OTG_STATE_B_PERIPHERAL:
mv_otg_enable(mvotg);
mv_otg_start_periphrals(mvotg, 1);
+ usb_phy_set_event(&mvotg->phy, USB_EVENT_ENUMERATED);
break;
case OTG_STATE_A_IDLE:
otg->default_a = 1;
@@ -545,8 +547,8 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr,
return -1;
/* We will use this interface to change to A device */
- if (mvotg->phy.state != OTG_STATE_B_IDLE
- && mvotg->phy.state != OTG_STATE_A_IDLE)
+ if (mvotg->phy.otg->state != OTG_STATE_B_IDLE
+ && mvotg->phy.otg->state != OTG_STATE_A_IDLE)
return -1;
/* The clock may disabled and we need to set irq for ID detected */
@@ -686,10 +688,8 @@ static int mv_otg_probe(struct platform_device *pdev)
}
mvotg = devm_kzalloc(&pdev->dev, sizeof(*mvotg), GFP_KERNEL);
- if (!mvotg) {
- dev_err(&pdev->dev, "failed to allocate memory!\n");
+ if (!mvotg)
return -ENOMEM;
- }
otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
if (!otg)
@@ -717,9 +717,9 @@ static int mv_otg_probe(struct platform_device *pdev)
mvotg->phy.dev = &pdev->dev;
mvotg->phy.otg = otg;
mvotg->phy.label = driver_name;
- mvotg->phy.state = OTG_STATE_UNDEFINED;
- otg->phy = &mvotg->phy;
+ otg->state = OTG_STATE_UNDEFINED;
+ otg->usb_phy = &mvotg->phy;
otg->set_host = mv_otg_set_host;
otg->set_peripheral = mv_otg_set_peripheral;
otg->set_vbus = mv_otg_set_vbus;
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index 0e0c41587a08..a55dadcd47f3 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -390,10 +390,8 @@ static int mxs_phy_probe(struct platform_device *pdev)
}
mxs_phy = devm_kzalloc(&pdev->dev, sizeof(*mxs_phy), GFP_KERNEL);
- if (!mxs_phy) {
- dev_err(&pdev->dev, "Failed to allocate USB PHY structure!\n");
+ if (!mxs_phy)
return -ENOMEM;
- }
/* Some SoCs don't have anatop registers */
if (of_get_property(np, "fsl,anatop", NULL)) {
diff --git a/drivers/usb/phy/phy-rcar-gen2-usb.c b/drivers/usb/phy/phy-rcar-gen2-usb.c
index 388d89f6b141..f83808413ba2 100644
--- a/drivers/usb/phy/phy-rcar-gen2-usb.c
+++ b/drivers/usb/phy/phy-rcar-gen2-usb.c
@@ -195,10 +195,8 @@ static int rcar_gen2_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(base);
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(dev, "Memory allocation failed\n");
+ if (!priv)
return -ENOMEM;
- }
spin_lock_init(&priv->lock);
priv->clk = clk;
diff --git a/drivers/usb/phy/phy-rcar-usb.c b/drivers/usb/phy/phy-rcar-usb.c
index 33265a5b2cdf..1e09b8377885 100644
--- a/drivers/usb/phy/phy-rcar-usb.c
+++ b/drivers/usb/phy/phy-rcar-usb.c
@@ -195,17 +195,13 @@ static int rcar_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(reg0);
res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (res1) {
- reg1 = devm_ioremap_resource(dev, res1);
- if (IS_ERR(reg1))
- return PTR_ERR(reg1);
- }
+ reg1 = devm_ioremap_resource(dev, res1);
+ if (IS_ERR(reg1))
+ return PTR_ERR(reg1);
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(dev, "priv data allocation error\n");
+ if (!priv)
return -ENOMEM;
- }
priv->reg0 = reg0;
priv->reg1 = reg1;
diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c
index cc61ee44b911..d391c79a542a 100644
--- a/drivers/usb/phy/phy-tahvo.c
+++ b/drivers/usb/phy/phy-tahvo.c
@@ -81,33 +81,35 @@ static void check_vbus_state(struct tahvo_usb *tu)
reg = retu_read(rdev, TAHVO_REG_IDSR);
if (reg & TAHVO_STAT_VBUS) {
- switch (tu->phy.state) {
+ switch (tu->phy.otg->state) {
case OTG_STATE_B_IDLE:
/* Enable the gadget driver */
if (tu->phy.otg->gadget)
usb_gadget_vbus_connect(tu->phy.otg->gadget);
- tu->phy.state = OTG_STATE_B_PERIPHERAL;
+ tu->phy.otg->state = OTG_STATE_B_PERIPHERAL;
+ usb_phy_set_event(&tu->phy, USB_EVENT_ENUMERATED);
break;
case OTG_STATE_A_IDLE:
/*
* Session is now valid assuming the USB hub is driving
* Vbus.
*/
- tu->phy.state = OTG_STATE_A_HOST;
+ tu->phy.otg->state = OTG_STATE_A_HOST;
break;
default:
break;
}
dev_info(&tu->pt_dev->dev, "USB cable connected\n");
} else {
- switch (tu->phy.state) {
+ switch (tu->phy.otg->state) {
case OTG_STATE_B_PERIPHERAL:
if (tu->phy.otg->gadget)
usb_gadget_vbus_disconnect(tu->phy.otg->gadget);
- tu->phy.state = OTG_STATE_B_IDLE;
+ tu->phy.otg->state = OTG_STATE_B_IDLE;
+ usb_phy_set_event(&tu->phy, USB_EVENT_NONE);
break;
case OTG_STATE_A_HOST:
- tu->phy.state = OTG_STATE_A_IDLE;
+ tu->phy.otg->state = OTG_STATE_A_IDLE;
break;
default:
break;
@@ -132,14 +134,14 @@ static void tahvo_usb_become_host(struct tahvo_usb *tu)
/* Power up the transceiver in USB host mode */
retu_write(rdev, TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND |
USBR_MASTER_SW2 | USBR_MASTER_SW1);
- tu->phy.state = OTG_STATE_A_IDLE;
+ tu->phy.otg->state = OTG_STATE_A_IDLE;
check_vbus_state(tu);
}
static void tahvo_usb_stop_host(struct tahvo_usb *tu)
{
- tu->phy.state = OTG_STATE_A_IDLE;
+ tu->phy.otg->state = OTG_STATE_A_IDLE;
}
static void tahvo_usb_become_peripheral(struct tahvo_usb *tu)
@@ -151,7 +153,7 @@ static void tahvo_usb_become_peripheral(struct tahvo_usb *tu)
/* Power up transceiver and set it in USB peripheral mode */
retu_write(rdev, TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT |
USBR_NSUSPEND | USBR_SLAVE_SW);
- tu->phy.state = OTG_STATE_B_IDLE;
+ tu->phy.otg->state = OTG_STATE_B_IDLE;
check_vbus_state(tu);
}
@@ -160,7 +162,7 @@ static void tahvo_usb_stop_peripheral(struct tahvo_usb *tu)
{
if (tu->phy.otg->gadget)
usb_gadget_vbus_disconnect(tu->phy.otg->gadget);
- tu->phy.state = OTG_STATE_B_IDLE;
+ tu->phy.otg->state = OTG_STATE_B_IDLE;
}
static void tahvo_usb_power_off(struct tahvo_usb *tu)
@@ -173,7 +175,7 @@ static void tahvo_usb_power_off(struct tahvo_usb *tu)
/* Power off transceiver */
retu_write(rdev, TAHVO_REG_USBR, 0);
- tu->phy.state = OTG_STATE_UNDEFINED;
+ tu->phy.otg->state = OTG_STATE_UNDEFINED;
}
static int tahvo_usb_set_suspend(struct usb_phy *dev, int suspend)
@@ -196,7 +198,8 @@ static int tahvo_usb_set_suspend(struct usb_phy *dev, int suspend)
static int tahvo_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- struct tahvo_usb *tu = container_of(otg->phy, struct tahvo_usb, phy);
+ struct tahvo_usb *tu = container_of(otg->usb_phy, struct tahvo_usb,
+ phy);
dev_dbg(&tu->pt_dev->dev, "%s %p\n", __func__, host);
@@ -225,7 +228,8 @@ static int tahvo_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
static int tahvo_usb_set_peripheral(struct usb_otg *otg,
struct usb_gadget *gadget)
{
- struct tahvo_usb *tu = container_of(otg->phy, struct tahvo_usb, phy);
+ struct tahvo_usb *tu = container_of(otg->usb_phy, struct tahvo_usb,
+ phy);
dev_dbg(&tu->pt_dev->dev, "%s %p\n", __func__, gadget);
@@ -379,11 +383,11 @@ static int tahvo_usb_probe(struct platform_device *pdev)
/* Create OTG interface */
tahvo_usb_power_off(tu);
tu->phy.dev = &pdev->dev;
- tu->phy.state = OTG_STATE_UNDEFINED;
+ tu->phy.otg->state = OTG_STATE_UNDEFINED;
tu->phy.label = DRIVER_NAME;
tu->phy.set_suspend = tahvo_usb_set_suspend;
- tu->phy.otg->phy = &tu->phy;
+ tu->phy.otg->usb_phy = &tu->phy;
tu->phy.otg->set_host = tahvo_usb_set_host;
tu->phy.otg->set_peripheral = tahvo_usb_set_peripheral;
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index 886f1807a67b..fa2bfa4ee34e 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -880,11 +880,8 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy,
tegra_phy->config = devm_kzalloc(&pdev->dev, sizeof(*config),
GFP_KERNEL);
- if (!tegra_phy->config) {
- dev_err(&pdev->dev,
- "unable to allocate memory for USB UTMIP config\n");
+ if (!tegra_phy->config)
return -ENOMEM;
- }
config = tegra_phy->config;
@@ -979,10 +976,8 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
int err;
tegra_phy = devm_kzalloc(&pdev->dev, sizeof(*tegra_phy), GFP_KERNEL);
- if (!tegra_phy) {
- dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n");
+ if (!tegra_phy)
return -ENOMEM;
- }
match = of_match_device(tegra_usb_phy_id_table, &pdev->dev);
if (!match) {
diff --git a/drivers/usb/phy/phy-ulpi.c b/drivers/usb/phy/phy-ulpi.c
index 4e3877c329f2..f48a7a21e3c2 100644
--- a/drivers/usb/phy/phy-ulpi.c
+++ b/drivers/usb/phy/phy-ulpi.c
@@ -211,7 +211,7 @@ static int ulpi_init(struct usb_phy *phy)
static int ulpi_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- struct usb_phy *phy = otg->phy;
+ struct usb_phy *phy = otg->usb_phy;
unsigned int flags = usb_phy_io_read(phy, ULPI_IFC_CTRL);
if (!host) {
@@ -237,7 +237,7 @@ static int ulpi_set_host(struct usb_otg *otg, struct usb_bus *host)
static int ulpi_set_vbus(struct usb_otg *otg, bool on)
{
- struct usb_phy *phy = otg->phy;
+ struct usb_phy *phy = otg->usb_phy;
unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL);
flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT);
@@ -276,7 +276,7 @@ otg_ulpi_create(struct usb_phy_io_ops *ops,
phy->otg = otg;
phy->init = ulpi_init;
- otg->phy = phy;
+ otg->usb_phy = phy;
otg->set_host = ulpi_set_host;
otg->set_vbus = ulpi_set_vbus;
diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c
index 045cd309367a..b4066a001ba0 100644
--- a/drivers/usb/phy/phy.c
+++ b/drivers/usb/phy/phy.c
@@ -191,7 +191,9 @@ struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
phy = __of_usb_find_phy(node);
if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) {
- phy = ERR_PTR(-EPROBE_DEFER);
+ if (!IS_ERR(phy))
+ phy = ERR_PTR(-EPROBE_DEFER);
+
devres_free(ptr);
goto err1;
}
@@ -444,3 +446,15 @@ int usb_bind_phy(const char *dev_name, u8 index,
return 0;
}
EXPORT_SYMBOL_GPL(usb_bind_phy);
+
+/**
+ * usb_phy_set_event - set event to phy event
+ * @x: the phy returned by usb_get_phy();
+ *
+ * This sets event to phy event
+ */
+void usb_phy_set_event(struct usb_phy *x, unsigned long event)
+{
+ x->last_event = event;
+}
+EXPORT_SYMBOL_GPL(usb_phy_set_event);
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index b3b6813ab270..371478704899 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -126,13 +126,15 @@ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable)
void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable)
{
u16 mask = DCFM | DRPD | DPRPU | HSE | USBE;
- u16 val = DPRPU | HSE | USBE;
+ u16 val = HSE | USBE;
/*
* if enable
*
* - select Function mode
- * - D+ Line Pull-up
+ * - D+ Line Pull-up is disabled
+ * When D+ Line Pull-up is enabled,
+ * calling usbhs_sys_function_pullup(,1)
*/
usbhs_bset(priv, SYSCFG, mask, enable ? val : 0);
}
@@ -496,20 +498,18 @@ static int usbhs_probe(struct platform_device *pdev)
}
/* platform data */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res || !irq_res) {
+ if (!irq_res) {
dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n");
return -ENODEV;
}
/* usb private data */
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(&pdev->dev, "Could not allocate priv\n");
+ if (!priv)
return -ENOMEM;
- }
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index a7996da6a1bd..0427cdd1a483 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -102,6 +102,10 @@ struct usbhs_priv;
#define DEVADD8 0x00E0
#define DEVADD9 0x00E2
#define DEVADDA 0x00E4
+#define D2FIFOSEL 0x00F0 /* for R-Car Gen2 */
+#define D2FIFOCTR 0x00F2 /* for R-Car Gen2 */
+#define D3FIFOSEL 0x00F4 /* for R-Car Gen2 */
+#define D3FIFOCTR 0x00F6 /* for R-Car Gen2 */
/* SYSCFG */
#define SCKE (1 << 10) /* USB Module Clock Enable */
@@ -269,7 +273,8 @@ struct usbhs_priv {
*/
struct usbhs_fifo_info fifo_info;
- struct usb_phy *phy;
+ struct usb_phy *usb_phy;
+ struct phy *phy;
};
/*
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index b0c97a3f1bfe..f46271ce1b15 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -21,8 +21,6 @@
#include "pipe.h"
#define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo))
-#define usbhsf_get_d0fifo(p) (&((p)->fifo_info.d0fifo))
-#define usbhsf_get_d1fifo(p) (&((p)->fifo_info.d1fifo))
#define usbhsf_is_cfifo(p, f) (usbhsf_get_cfifo(p) == f)
#define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */
@@ -577,14 +575,6 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)
usbhs_pipe_number(pipe),
pkt->length, pkt->actual, *is_done, pkt->zero);
- /*
- * Transmission end
- */
- if (*is_done) {
- if (usbhs_pipe_is_dcp(pipe))
- usbhs_dcp_control_transfer_done(pipe);
- }
-
usbhsf_fifo_unselect(pipe, fifo);
return 0;
@@ -722,14 +712,6 @@ usbhs_fifo_read_end:
usbhs_pipe_number(pipe),
pkt->length, pkt->actual, *is_done, pkt->zero);
- /*
- * Transmission end
- */
- if (*is_done) {
- if (usbhs_pipe_is_dcp(pipe))
- usbhs_dcp_control_transfer_done(pipe);
- }
-
usbhs_fifo_read_busy:
usbhsf_fifo_unselect(pipe, fifo);
@@ -777,18 +759,13 @@ static struct usbhs_fifo *usbhsf_get_dma_fifo(struct usbhs_priv *priv,
struct usbhs_pkt *pkt)
{
struct usbhs_fifo *fifo;
+ int i;
- /* DMA :: D0FIFO */
- fifo = usbhsf_get_d0fifo(priv);
- if (usbhsf_dma_chan_get(fifo, pkt) &&
- !usbhsf_fifo_is_busy(fifo))
- return fifo;
-
- /* DMA :: D1FIFO */
- fifo = usbhsf_get_d1fifo(priv);
- if (usbhsf_dma_chan_get(fifo, pkt) &&
- !usbhsf_fifo_is_busy(fifo))
- return fifo;
+ usbhs_for_each_dfifo(priv, fifo, i) {
+ if (usbhsf_dma_chan_get(fifo, pkt) &&
+ !usbhsf_fifo_is_busy(fifo))
+ return fifo;
+ }
return NULL;
}
@@ -1176,6 +1153,24 @@ static void usbhsf_dma_complete(void *arg)
usbhs_pipe_number(pipe), ret);
}
+void usbhs_fifo_clear_dcp(struct usbhs_pipe *pipe)
+{
+ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+ struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */
+
+ /* clear DCP FIFO of transmission */
+ if (usbhsf_fifo_select(pipe, fifo, 1) < 0)
+ return;
+ usbhsf_fifo_clear(pipe, fifo);
+ usbhsf_fifo_unselect(pipe, fifo);
+
+ /* clear DCP FIFO of reception */
+ if (usbhsf_fifo_select(pipe, fifo, 0) < 0)
+ return;
+ usbhsf_fifo_clear(pipe, fifo);
+ usbhsf_fifo_unselect(pipe, fifo);
+}
+
/*
* fifo init
*/
@@ -1183,8 +1178,8 @@ void usbhs_fifo_init(struct usbhs_priv *priv)
{
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
struct usbhs_fifo *cfifo = usbhsf_get_cfifo(priv);
- struct usbhs_fifo *d0fifo = usbhsf_get_d0fifo(priv);
- struct usbhs_fifo *d1fifo = usbhsf_get_d1fifo(priv);
+ struct usbhs_fifo *dfifo;
+ int i;
mod->irq_empty = usbhsf_irq_empty;
mod->irq_ready = usbhsf_irq_ready;
@@ -1192,8 +1187,8 @@ void usbhs_fifo_init(struct usbhs_priv *priv)
mod->irq_brdysts = 0;
cfifo->pipe = NULL;
- d0fifo->pipe = NULL;
- d1fifo->pipe = NULL;
+ usbhs_for_each_dfifo(priv, dfifo, i)
+ dfifo->pipe = NULL;
}
void usbhs_fifo_quit(struct usbhs_priv *priv)
@@ -1206,6 +1201,25 @@ void usbhs_fifo_quit(struct usbhs_priv *priv)
mod->irq_brdysts = 0;
}
+#define __USBHS_DFIFO_INIT(priv, fifo, channel, fifo_port) \
+do { \
+ fifo = usbhsf_get_dnfifo(priv, channel); \
+ fifo->name = "D"#channel"FIFO"; \
+ fifo->port = fifo_port; \
+ fifo->sel = D##channel##FIFOSEL; \
+ fifo->ctr = D##channel##FIFOCTR; \
+ fifo->tx_slave.shdma_slave.slave_id = \
+ usbhs_get_dparam(priv, d##channel##_tx_id); \
+ fifo->rx_slave.shdma_slave.slave_id = \
+ usbhs_get_dparam(priv, d##channel##_rx_id); \
+ usbhsf_dma_init(priv, fifo); \
+} while (0)
+
+#define USBHS_DFIFO_INIT(priv, fifo, channel) \
+ __USBHS_DFIFO_INIT(priv, fifo, channel, D##channel##FIFO)
+#define USBHS_DFIFO_INIT_NO_PORT(priv, fifo, channel) \
+ __USBHS_DFIFO_INIT(priv, fifo, channel, 0)
+
int usbhs_fifo_probe(struct usbhs_priv *priv)
{
struct usbhs_fifo *fifo;
@@ -1217,31 +1231,20 @@ int usbhs_fifo_probe(struct usbhs_priv *priv)
fifo->sel = CFIFOSEL;
fifo->ctr = CFIFOCTR;
- /* D0FIFO */
- fifo = usbhsf_get_d0fifo(priv);
- fifo->name = "D0FIFO";
- fifo->port = D0FIFO;
- fifo->sel = D0FIFOSEL;
- fifo->ctr = D0FIFOCTR;
- fifo->tx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d0_tx_id);
- fifo->rx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d0_rx_id);
- usbhsf_dma_init(priv, fifo);
-
- /* D1FIFO */
- fifo = usbhsf_get_d1fifo(priv);
- fifo->name = "D1FIFO";
- fifo->port = D1FIFO;
- fifo->sel = D1FIFOSEL;
- fifo->ctr = D1FIFOCTR;
- fifo->tx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d1_tx_id);
- fifo->rx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d1_rx_id);
- usbhsf_dma_init(priv, fifo);
+ /* DFIFO */
+ USBHS_DFIFO_INIT(priv, fifo, 0);
+ USBHS_DFIFO_INIT(priv, fifo, 1);
+ USBHS_DFIFO_INIT_NO_PORT(priv, fifo, 2);
+ USBHS_DFIFO_INIT_NO_PORT(priv, fifo, 3);
return 0;
}
void usbhs_fifo_remove(struct usbhs_priv *priv)
{
- usbhsf_dma_quit(priv, usbhsf_get_d0fifo(priv));
- usbhsf_dma_quit(priv, usbhsf_get_d1fifo(priv));
+ struct usbhs_fifo *fifo;
+ int i;
+
+ usbhs_for_each_dfifo(priv, fifo, i)
+ usbhsf_dma_quit(priv, fifo);
}
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h
index a168a1760fce..f07037c1185f 100644
--- a/drivers/usb/renesas_usbhs/fifo.h
+++ b/drivers/usb/renesas_usbhs/fifo.h
@@ -38,11 +38,16 @@ struct usbhs_fifo {
struct sh_dmae_slave rx_slave;
};
+#define USBHS_MAX_NUM_DFIFO 4
struct usbhs_fifo_info {
struct usbhs_fifo cfifo;
- struct usbhs_fifo d0fifo;
- struct usbhs_fifo d1fifo;
+ struct usbhs_fifo dfifo[USBHS_MAX_NUM_DFIFO];
};
+#define usbhsf_get_dnfifo(p, n) (&((p)->fifo_info.dfifo[n]))
+#define usbhs_for_each_dfifo(priv, dfifo, i) \
+ for ((i) = 0, dfifo = usbhsf_get_dnfifo(priv, (i)); \
+ ((i) < USBHS_MAX_NUM_DFIFO); \
+ (i)++, dfifo = usbhsf_get_dnfifo(priv, (i)))
struct usbhs_pkt_handle;
struct usbhs_pkt {
@@ -74,6 +79,7 @@ int usbhs_fifo_probe(struct usbhs_priv *priv);
void usbhs_fifo_remove(struct usbhs_priv *priv);
void usbhs_fifo_init(struct usbhs_priv *priv);
void usbhs_fifo_quit(struct usbhs_priv *priv);
+void usbhs_fifo_clear_dcp(struct usbhs_pipe *pipe);
/*
* packet info
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 2d17c10a0428..8697e6efcabf 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -56,6 +56,7 @@ struct usbhsg_gpriv {
#define USBHSG_STATUS_REGISTERD (1 << 1)
#define USBHSG_STATUS_WEDGE (1 << 2)
#define USBHSG_STATUS_SELF_POWERED (1 << 3)
+#define USBHSG_STATUS_SOFT_CONNECT (1 << 4)
};
struct usbhsg_recip_handle {
@@ -484,6 +485,9 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv,
case NODATA_STATUS_STAGE:
pipe->handler = &usbhs_ctrl_stage_end_handler;
break;
+ case READ_STATUS_STAGE:
+ case WRITE_STATUS_STAGE:
+ usbhs_dcp_control_transfer_done(pipe);
default:
return ret;
}
@@ -602,6 +606,9 @@ static int usbhsg_ep_disable(struct usb_ep *ep)
struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep);
struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
+ if (!pipe)
+ return -EINVAL;
+
usbhsg_pipe_disable(uep);
usbhs_pipe_free(pipe);
@@ -723,6 +730,25 @@ static struct usb_ep_ops usbhsg_ep_ops = {
};
/*
+ * pullup control
+ */
+static int usbhsg_can_pullup(struct usbhs_priv *priv)
+{
+ struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
+
+ return gpriv->driver &&
+ usbhsg_status_has(gpriv, USBHSG_STATUS_SOFT_CONNECT);
+}
+
+static void usbhsg_update_pullup(struct usbhs_priv *priv)
+{
+ if (usbhsg_can_pullup(priv))
+ usbhs_sys_function_pullup(priv, 1);
+ else
+ usbhs_sys_function_pullup(priv, 0);
+}
+
+/*
* usb module start/end
*/
static int usbhsg_try_start(struct usbhs_priv *priv, u32 status)
@@ -756,9 +782,9 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status)
/*
* pipe initialize and enable DCP
*/
+ usbhs_fifo_init(priv);
usbhs_pipe_init(priv,
usbhsg_dma_map_ctrl);
- usbhs_fifo_init(priv);
/* dcp init instead of usbhsg_ep_enable() */
dcp->pipe = usbhs_dcp_malloc(priv);
@@ -772,6 +798,7 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status)
* - usb module
*/
usbhs_sys_function_ctrl(priv, 1);
+ usbhsg_update_pullup(priv);
/*
* enable irq callback
@@ -851,8 +878,7 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget,
return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD);
}
-static int usbhsg_gadget_stop(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
+static int usbhsg_gadget_stop(struct usb_gadget *gadget)
{
struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget);
struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
@@ -878,8 +904,15 @@ static int usbhsg_pullup(struct usb_gadget *gadget, int is_on)
{
struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget);
struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
+ unsigned long flags;
- usbhs_sys_function_pullup(priv, is_on);
+ usbhs_lock(priv, flags);
+ if (is_on)
+ usbhsg_status_set(gpriv, USBHSG_STATUS_SOFT_CONNECT);
+ else
+ usbhsg_status_clr(gpriv, USBHSG_STATUS_SOFT_CONNECT);
+ usbhsg_update_pullup(priv);
+ usbhs_unlock(priv, flags);
return 0;
}
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index 10e1ded9c9cc..f0d323125871 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -1474,9 +1474,9 @@ static int usbhsh_start(struct usbhs_priv *priv)
/*
* pipe initialize and enable DCP
*/
+ usbhs_fifo_init(priv);
usbhs_pipe_init(priv,
usbhsh_dma_map_ctrl);
- usbhs_fifo_init(priv);
usbhsh_pipe_init_for_host(priv);
/*
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c
index 040bcefcb040..007f45abe96c 100644
--- a/drivers/usb/renesas_usbhs/pipe.c
+++ b/drivers/usb/renesas_usbhs/pipe.c
@@ -618,8 +618,12 @@ void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence)
void usbhs_pipe_clear(struct usbhs_pipe *pipe)
{
- usbhsp_pipectrl_set(pipe, ACLRM, ACLRM);
- usbhsp_pipectrl_set(pipe, ACLRM, 0);
+ if (usbhs_pipe_is_dcp(pipe)) {
+ usbhs_fifo_clear_dcp(pipe);
+ } else {
+ usbhsp_pipectrl_set(pipe, ACLRM, ACLRM);
+ usbhsp_pipectrl_set(pipe, ACLRM, 0);
+ }
}
static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type)
diff --git a/drivers/usb/renesas_usbhs/rcar2.c b/drivers/usb/renesas_usbhs/rcar2.c
index e6b9dcc1c289..8fc15c0ba339 100644
--- a/drivers/usb/renesas_usbhs/rcar2.c
+++ b/drivers/usb/renesas_usbhs/rcar2.c
@@ -12,6 +12,7 @@
#include <linux/gpio.h>
#include <linux/of_gpio.h>
+#include <linux/phy/phy.h>
#include <linux/platform_data/gpio-rcar.h>
#include <linux/usb/phy.h>
#include "common.h"
@@ -20,25 +21,43 @@
static int usbhs_rcar2_hardware_init(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
- struct usb_phy *phy;
- phy = usb_get_phy_dev(&pdev->dev, 0);
- if (IS_ERR(phy))
- return PTR_ERR(phy);
+ if (IS_ENABLED(CONFIG_GENERIC_PHY)) {
+ struct phy *phy = phy_get(&pdev->dev, "usb");
- priv->phy = phy;
- return 0;
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ priv->phy = phy;
+ return 0;
+ }
+
+ if (IS_ENABLED(CONFIG_USB_PHY)) {
+ struct usb_phy *usb_phy = usb_get_phy_dev(&pdev->dev, 0);
+
+ if (IS_ERR(usb_phy))
+ return PTR_ERR(usb_phy);
+
+ priv->usb_phy = usb_phy;
+ return 0;
+ }
+
+ return -ENXIO;
}
static int usbhs_rcar2_hardware_exit(struct platform_device *pdev)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
- if (!priv->phy)
- return 0;
+ if (priv->phy) {
+ phy_put(priv->phy);
+ priv->phy = NULL;
+ }
- usb_put_phy(priv->phy);
- priv->phy = NULL;
+ if (priv->usb_phy) {
+ usb_put_phy(priv->usb_phy);
+ priv->usb_phy = NULL;
+ }
return 0;
}
@@ -47,21 +66,35 @@ static int usbhs_rcar2_power_ctrl(struct platform_device *pdev,
void __iomem *base, int enable)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
+ int retval = -ENODEV;
+
+ if (priv->phy) {
+ if (enable) {
+ retval = phy_init(priv->phy);
- if (!priv->phy)
- return -ENODEV;
+ if (!retval)
+ retval = phy_power_on(priv->phy);
+ } else {
+ phy_power_off(priv->phy);
+ phy_exit(priv->phy);
+ retval = 0;
+ }
+ }
- if (enable) {
- int retval = usb_phy_init(priv->phy);
+ if (priv->usb_phy) {
+ if (enable) {
+ retval = usb_phy_init(priv->usb_phy);
- if (!retval)
- retval = usb_phy_set_suspend(priv->phy, 0);
- return retval;
+ if (!retval)
+ retval = usb_phy_set_suspend(priv->usb_phy, 0);
+ } else {
+ usb_phy_set_suspend(priv->usb_phy, 1);
+ usb_phy_shutdown(priv->usb_phy);
+ retval = 0;
+ }
}
- usb_phy_set_suspend(priv->phy, 1);
- usb_phy_shutdown(priv->phy);
- return 0;
+ return retval;
}
static int usbhs_rcar2_get_id(struct platform_device *pdev)
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index a69f7cd9d0bf..b7cf1982d1d9 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -60,6 +60,7 @@ config USB_SERIAL_SIMPLE
- Suunto ANT+ USB device.
- Medtronic CareLink USB device
- Fundamental Software dongle.
+ - Google USB serial devices
- HP4x calculators
- a number of Motorola phones
- Novatel Wireless GPS receivers
@@ -606,10 +607,10 @@ config USB_SERIAL_CYBERJACK
If unsure, say N.
config USB_SERIAL_XIRCOM
- tristate "USB Xircom / Entregra Single Port Serial Driver"
+ tristate "USB Xircom / Entrega Single Port Serial Driver"
select USB_EZUSB_FX2
help
- Say Y here if you want to use a Xircom or Entregra single port USB to
+ Say Y here if you want to use a Xircom or Entrega single port USB to
serial converter device. This driver makes use of firmware
developed from scratch by Brian Warner.
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 742d827f876c..dd97d8b572c3 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -1,5 +1,5 @@
/*
- * USB Keyspan PDA / Xircom / Entregra Converter driver
+ * USB Keyspan PDA / Xircom / Entrega Converter driver
*
* Copyright (C) 1999 - 2001 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (C) 1999, 2000 Brian Warner <warner@lothar.com>
@@ -58,11 +58,11 @@ struct keyspan_pda_private {
#define KEYSPAN_PDA_FAKE_ID 0x0103
#define KEYSPAN_PDA_ID 0x0104 /* no clue */
-/* For Xircom PGSDB9 and older Entregra version of the same device */
+/* For Xircom PGSDB9 and older Entrega version of the same device */
#define XIRCOM_VENDOR_ID 0x085a
#define XIRCOM_FAKE_ID 0x8027
-#define ENTREGRA_VENDOR_ID 0x1645
-#define ENTREGRA_FAKE_ID 0x8093
+#define ENTREGA_VENDOR_ID 0x1645
+#define ENTREGA_FAKE_ID 0x8093
static const struct usb_device_id id_table_combined[] = {
#ifdef KEYSPAN
@@ -70,7 +70,7 @@ static const struct usb_device_id id_table_combined[] = {
#endif
#ifdef XIRCOM
{ USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
- { USB_DEVICE(ENTREGRA_VENDOR_ID, ENTREGRA_FAKE_ID) },
+ { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
#endif
{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
{ } /* Terminating entry */
@@ -93,7 +93,7 @@ static const struct usb_device_id id_table_fake[] = {
#ifdef XIRCOM
static const struct usb_device_id id_table_fake_xircom[] = {
{ USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
- { USB_DEVICE(ENTREGRA_VENDOR_ID, ENTREGRA_FAKE_ID) },
+ { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
{ }
};
#endif
@@ -667,7 +667,7 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial)
#endif
#ifdef XIRCOM
else if ((le16_to_cpu(serial->dev->descriptor.idVendor) == XIRCOM_VENDOR_ID) ||
- (le16_to_cpu(serial->dev->descriptor.idVendor) == ENTREGRA_VENDOR_ID))
+ (le16_to_cpu(serial->dev->descriptor.idVendor) == ENTREGA_VENDOR_ID))
fw_name = "keyspan_pda/xircom_pgs.fw";
#endif
else {
@@ -744,7 +744,7 @@ static struct usb_serial_driver xircom_pgs_fake_device = {
.owner = THIS_MODULE,
.name = "xircom_no_firm",
},
- .description = "Xircom / Entregra PGS - (prerenumeration)",
+ .description = "Xircom / Entrega PGS - (prerenumeration)",
.id_table = id_table_fake_xircom,
.num_ports = 1,
.attach = keyspan_pda_fake_startup,
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 02c420af251e..2363654cafc9 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -244,7 +244,7 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
/* start reading (Adapter B 'cause PNP string) */
- result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
dev_dbg(dev, "%s - Send read URB returns: %i\n", __func__, result);
}
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index dfd728a263d2..4f70df33975a 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -1299,8 +1299,6 @@ static void mos7720_throttle(struct tty_struct *tty)
mos7720_port->shadowMCR &= ~UART_MCR_RTS;
write_mos_reg(port->serial, port->port_number, MCR,
mos7720_port->shadowMCR);
- if (status != 0)
- return;
}
}
@@ -1331,8 +1329,6 @@ static void mos7720_unthrottle(struct tty_struct *tty)
mos7720_port->shadowMCR |= UART_MCR_RTS;
write_mos_reg(port->serial, port->port_number, MCR,
mos7720_port->shadowMCR);
- if (status != 0)
- return;
}
}
@@ -1657,7 +1653,7 @@ static void change_port_settings(struct tty_struct *tty,
write_mos_reg(serial, port_number, IER, 0x0c);
if (port->read_urb->status != -EINPROGRESS) {
- status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ status = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (status)
dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status);
}
@@ -1702,7 +1698,7 @@ static void mos7720_set_termios(struct tty_struct *tty,
change_port_settings(tty, mos7720_port, old_termios);
if (port->read_urb->status != -EINPROGRESS) {
- status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ status = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (status)
dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status);
}
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 3d88eefdf1d1..220b4be89641 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1904,7 +1904,7 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
if (mos7840_port->read_urb_busy == false) {
mos7840_port->read_urb_busy = true;
- status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
+ status = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
if (status) {
dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n",
status);
@@ -1968,7 +1968,7 @@ static void mos7840_set_termios(struct tty_struct *tty,
if (mos7840_port->read_urb_busy == false) {
mos7840_port->read_urb_busy = true;
- status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
+ status = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
if (status) {
dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n",
status);
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index b2aa003bf411..cb3e14780a7e 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -27,12 +27,15 @@ enum qcserial_layouts {
QCSERIAL_G2K = 0, /* Gobi 2000 */
QCSERIAL_G1K = 1, /* Gobi 1000 */
QCSERIAL_SWI = 2, /* Sierra Wireless */
+ QCSERIAL_HWI = 3, /* Huawei */
};
#define DEVICE_G1K(v, p) \
USB_DEVICE(v, p), .driver_info = QCSERIAL_G1K
#define DEVICE_SWI(v, p) \
USB_DEVICE(v, p), .driver_info = QCSERIAL_SWI
+#define DEVICE_HWI(v, p) \
+ USB_DEVICE(v, p), .driver_info = QCSERIAL_HWI
static const struct usb_device_id id_table[] = {
/* Gobi 1000 devices */
@@ -157,6 +160,9 @@ static const struct usb_device_id id_table[] = {
{DEVICE_SWI(0x413c, 0x81a8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81a9)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
+ /* Huawei devices */
+ {DEVICE_HWI(0x03f0, 0x581d)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */
+
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
@@ -287,6 +293,33 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
break;
}
break;
+ case QCSERIAL_HWI:
+ /*
+ * Huawei layout:
+ * 0: AT-capable modem port
+ * 1: DM/DIAG
+ * 2: AT-capable modem port
+ * 3: CCID-compatible PCSC interface
+ * 4: QMI/net
+ * 5: NMEA
+ */
+ switch (ifnum) {
+ case 0:
+ case 2:
+ dev_dbg(dev, "Modem port found\n");
+ break;
+ case 1:
+ dev_dbg(dev, "DM/DIAG interface found\n");
+ break;
+ case 5:
+ dev_dbg(dev, "NMEA GPS interface found\n");
+ break;
+ default:
+ /* don't claim any unsupported interface */
+ altsetting = -1;
+ break;
+ }
+ break;
default:
dev_err(dev, "unsupported device layout type: %lu\n",
id->driver_info);
diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c
index 8bfc47c29828..3658662898fc 100644
--- a/drivers/usb/serial/usb-serial-simple.c
+++ b/drivers/usb/serial/usb-serial-simple.c
@@ -56,6 +56,14 @@ DEVICE(funsoft, FUNSOFT_IDS);
{ USB_DEVICE(0x8087, 0x0716) }
DEVICE(flashloader, FLASHLOADER_IDS);
+/* Google Serial USB SubClass */
+#define GOOGLE_IDS() \
+ { USB_VENDOR_AND_INTERFACE_INFO(0x18d1, \
+ USB_CLASS_VENDOR_SPEC, \
+ 0x50, \
+ 0x01) }
+DEVICE(google, GOOGLE_IDS);
+
/* ViVOpay USB Serial Driver */
#define VIVOPAY_IDS() \
{ USB_DEVICE(0x1d5f, 0x1004) } /* ViVOpay 8800 */
@@ -97,6 +105,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&zio_device,
&funsoft_device,
&flashloader_device,
+ &google_device,
&vivopay_device,
&moto_modem_device,
&novatel_gps_device,
@@ -111,6 +120,7 @@ static const struct usb_device_id id_table[] = {
ZIO_IDS(),
FUNSOFT_IDS(),
FLASHLOADER_IDS(),
+ GOOGLE_IDS(),
VIVOPAY_IDS(),
MOTO_IDS(),
NOVATEL_IDS(),
diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c
index 2d81e1d8ee30..57bf3ad41fb6 100644
--- a/drivers/usb/storage/debug.c
+++ b/drivers/usb/storage/debug.c
@@ -181,17 +181,14 @@ void usb_stor_show_sense(const struct us_data *us,
US_DEBUGPX("%s\n", what);
}
-int usb_stor_dbg(const struct us_data *us, const char *fmt, ...)
+void usb_stor_dbg(const struct us_data *us, const char *fmt, ...)
{
va_list args;
- int r;
va_start(args, fmt);
- r = dev_vprintk_emit(LOGLEVEL_DEBUG, &us->pusb_dev->dev, fmt, args);
+ dev_vprintk_emit(LOGLEVEL_DEBUG, &us->pusb_dev->dev, fmt, args);
va_end(args);
-
- return r;
}
EXPORT_SYMBOL_GPL(usb_stor_dbg);
diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h
index b1273f03e223..f52520306e1a 100644
--- a/drivers/usb/storage/debug.h
+++ b/drivers/usb/storage/debug.h
@@ -50,15 +50,17 @@
void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb);
void usb_stor_show_sense(const struct us_data *us, unsigned char key,
unsigned char asc, unsigned char ascq);
-__printf(2, 3) int usb_stor_dbg(const struct us_data *us,
- const char *fmt, ...);
+__printf(2, 3) void usb_stor_dbg(const struct us_data *us,
+ const char *fmt, ...);
#define US_DEBUGPX(fmt, ...) printk(fmt, ##__VA_ARGS__)
#define US_DEBUG(x) x
#else
__printf(2, 3)
-static inline int _usb_stor_dbg(const struct us_data *us,
- const char *fmt, ...) {return 1;}
+static inline void _usb_stor_dbg(const struct us_data *us,
+ const char *fmt, ...)
+{
+}
#define usb_stor_dbg(us, fmt, ...) \
do { if (0) _usb_stor_dbg(us, fmt, ##__VA_ARGS__); } while (0)
#define US_DEBUGPX(fmt, ...) \
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index 73f125e0cb58..31fa2e92065b 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -49,10 +49,9 @@ int usb_stor_euscsi_init(struct us_data *us)
int result;
usb_stor_dbg(us, "Attempting to init eUSCSI bridge...\n");
- us->iobuf[0] = 0x1;
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR,
- 0x01, 0x0, us->iobuf, 0x1, 5 * HZ);
+ 0x01, 0x0, NULL, 0x0, 5 * HZ);
usb_stor_dbg(us, "-- result is %d\n", result);
return 0;
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index b1d815eb6d0b..540add24a12f 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1035,9 +1035,20 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
usb_stor_dbg(us, "GetMaxLUN command result is %d, data is %d\n",
result, us->iobuf[0]);
- /* if we have a successful request, return the result */
- if (result > 0)
- return us->iobuf[0];
+ /*
+ * If we have a successful request, return the result if valid. The
+ * CBW LUN field is 4 bits wide, so the value reported by the device
+ * should fit into that.
+ */
+ if (result > 0) {
+ if (us->iobuf[0] < 16) {
+ return us->iobuf[0];
+ } else {
+ dev_info(&us->pusb_intf->dev,
+ "Max LUN %d is not valid, using 0 instead",
+ us->iobuf[0]);
+ }
+ }
/*
* Some devices don't like GetMaxLUN. They may STALL the control
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 4047edfb64e1..6cdabdc119a7 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -66,7 +66,7 @@ enum {
/* Overrides scsi_pointer */
struct uas_cmd_info {
unsigned int state;
- unsigned int stream;
+ unsigned int uas_tag;
struct urb *cmd_urb;
struct urb *data_in_urb;
struct urb *data_out_urb;
@@ -173,30 +173,15 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
cmnd->result = sense_iu->status;
}
-/*
- * scsi-tags go from 0 - (nr_tags - 1), uas tags need to match stream-ids,
- * which go from 1 - nr_streams. And we use 1 for untagged commands.
- */
-static int uas_get_tag(struct scsi_cmnd *cmnd)
-{
- int tag;
-
- if (cmnd->flags & SCMD_TAGGED)
- tag = cmnd->request->tag + 2;
- else
- tag = 1;
-
- return tag;
-}
-
static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix,
int status)
{
struct uas_cmd_info *ci = (void *)&cmnd->SCp;
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
scmd_printk(KERN_INFO, cmnd,
- "%s %d tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ",
- prefix, status, uas_get_tag(cmnd),
+ "%s %d uas-tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ",
+ prefix, status, cmdinfo->uas_tag,
(ci->state & SUBMIT_STATUS_URB) ? " s-st" : "",
(ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "",
(ci->state & SUBMIT_DATA_IN_URB) ? " s-in" : "",
@@ -242,7 +227,7 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
DATA_OUT_URB_INFLIGHT |
COMMAND_ABORTED))
return -EBUSY;
- devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL;
+ devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL;
uas_free_unsubmitted_urbs(cmnd);
cmnd->scsi_done(cmnd);
return 0;
@@ -289,7 +274,7 @@ static void uas_stat_cmplt(struct urb *urb)
idx = be16_to_cpup(&iu->tag) - 1;
if (idx >= MAX_CMNDS || !devinfo->cmnd[idx]) {
dev_err(&urb->dev->dev,
- "stat urb: no pending cmd for tag %d\n", idx + 1);
+ "stat urb: no pending cmd for uas-tag %d\n", idx + 1);
goto out;
}
@@ -427,7 +412,8 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
goto out;
usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
uas_data_cmplt, cmnd);
- urb->stream_id = cmdinfo->stream;
+ if (devinfo->use_streams)
+ urb->stream_id = cmdinfo->uas_tag;
urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
urb->sg = sdb->table.sgl;
out:
@@ -451,7 +437,8 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
uas_stat_cmplt, cmnd->device->host);
- urb->stream_id = cmdinfo->stream;
+ if (devinfo->use_streams)
+ urb->stream_id = cmdinfo->uas_tag;
urb->transfer_flags |= URB_FREE_BUFFER;
out:
return urb;
@@ -465,6 +452,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
{
struct usb_device *udev = devinfo->udev;
struct scsi_device *sdev = cmnd->device;
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
struct urb *urb = usb_alloc_urb(0, gfp);
struct command_iu *iu;
int len;
@@ -481,7 +469,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
goto free;
iu->iu_id = IU_ID_COMMAND;
- iu->tag = cpu_to_be16(uas_get_tag(cmnd));
+ iu->tag = cpu_to_be16(cmdinfo->uas_tag);
iu->prio_attr = UAS_SIMPLE_TAG;
iu->len = len;
int_to_scsilun(sdev->lun, &iu->lun);
@@ -608,8 +596,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
struct uas_dev_info *devinfo = sdev->hostdata;
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
unsigned long flags;
- unsigned int stream;
- int err;
+ int idx, err;
BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
@@ -635,8 +622,12 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
return 0;
}
- stream = uas_get_tag(cmnd);
- if (devinfo->cmnd[stream - 1]) {
+ /* Find a free uas-tag */
+ for (idx = 0; idx < devinfo->qdepth; idx++) {
+ if (!devinfo->cmnd[idx])
+ break;
+ }
+ if (idx == devinfo->qdepth) {
spin_unlock_irqrestore(&devinfo->lock, flags);
return SCSI_MLQUEUE_DEVICE_BUSY;
}
@@ -644,7 +635,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
cmnd->scsi_done = done;
memset(cmdinfo, 0, sizeof(*cmdinfo));
- cmdinfo->stream = stream;
+ cmdinfo->uas_tag = idx + 1; /* uas-tag == usb-stream-id, so 1 based */
cmdinfo->state = SUBMIT_STATUS_URB | ALLOC_CMD_URB | SUBMIT_CMD_URB;
switch (cmnd->sc_data_direction) {
@@ -659,10 +650,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
break;
}
- if (!devinfo->use_streams) {
+ if (!devinfo->use_streams)
cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
- cmdinfo->stream = 0;
- }
err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC);
if (err) {
@@ -674,7 +663,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
uas_add_work(cmdinfo);
}
- devinfo->cmnd[stream - 1] = cmnd;
+ devinfo->cmnd[idx] = cmnd;
spin_unlock_irqrestore(&devinfo->lock, flags);
return 0;
}
@@ -702,7 +691,7 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
cmdinfo->state |= COMMAND_ABORTED;
/* Drop all refs to this cmnd, kill data urbs to break their ref */
- devinfo->cmnd[uas_get_tag(cmnd) - 1] = NULL;
+ devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL;
if (cmdinfo->state & DATA_IN_URB_INFLIGHT)
data_in_urb = usb_get_urb(cmdinfo->data_in_urb);
if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
@@ -816,13 +805,6 @@ static struct scsi_host_template uas_host_template = {
.sg_tablesize = SG_NONE,
.cmd_per_lun = 1, /* until we override it */
.skip_settle_delay = 1,
-
- /*
- * The uas drivers expects tags not to be bigger than the maximum
- * per-device queue depth, which is not true with the blk-mq tag
- * allocator.
- */
- .disable_blk_mq = true,
.use_blk_tags = 1,
};
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 9d66ce62542e..d468d02179f4 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -884,7 +884,9 @@ static void usb_stor_scan_dwork(struct work_struct *work)
dev_dbg(dev, "starting scan\n");
/* For bulk-only devices, determine the max LUN value */
- if (us->protocol == USB_PR_BULK && !(us->fflags & US_FL_SINGLE_LUN)) {
+ if (us->protocol == USB_PR_BULK &&
+ !(us->fflags & US_FL_SINGLE_LUN) &&
+ !(us->fflags & US_FL_SCM_MULT_TARG)) {
mutex_lock(&us->dev_mutex);
us->max_lun = usb_stor_Bulk_max_lun(us);
mutex_unlock(&us->dev_mutex);
@@ -983,21 +985,31 @@ int usb_stor_probe2(struct us_data *us)
usb_stor_dbg(us, "Transport: %s\n", us->transport_name);
usb_stor_dbg(us, "Protocol: %s\n", us->protocol_name);
+ if (us->fflags & US_FL_SCM_MULT_TARG) {
+ /*
+ * SCM eUSCSI bridge devices can have different numbers
+ * of LUNs on different targets; allow all to be probed.
+ */
+ us->max_lun = 7;
+ /* The eUSCSI itself has ID 7, so avoid scanning that */
+ us_to_host(us)->this_id = 7;
+ /* max_id is 8 initially, so no need to set it here */
+ } else {
+ /* In the normal case there is only a single target */
+ us_to_host(us)->max_id = 1;
+ /*
+ * Like Windows, we won't store the LUN bits in CDB[1] for
+ * SCSI-2 devices using the Bulk-Only transport (even though
+ * this violates the SCSI spec).
+ */
+ if (us->transport == usb_stor_Bulk_transport)
+ us_to_host(us)->no_scsi2_lun_in_cdb = 1;
+ }
+
/* fix for single-lun devices */
if (us->fflags & US_FL_SINGLE_LUN)
us->max_lun = 0;
- if (!(us->fflags & US_FL_SCM_MULT_TARG))
- us_to_host(us)->max_id = 1;
-
- /*
- * Like Windows, we won't store the LUN bits in CDB[1] for SCSI-2
- * devices using the Bulk-Only transport (even though this violates
- * the SCSI spec).
- */
- if (us->transport == usb_stor_Bulk_transport)
- us_to_host(us)->no_scsi2_lun_in_cdb = 1;
-
/* Find the endpoints and calculate pipe values */
result = get_pipes(us);
if (result)
diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c
index fac20e0434c0..a3ec49bdc1e6 100644
--- a/drivers/usb/usbip/stub_dev.c
+++ b/drivers/usb/usbip/stub_dev.c
@@ -311,7 +311,6 @@ static int stub_probe(struct usb_device *udev)
{
struct stub_device *sdev = NULL;
const char *udev_busid = dev_name(&udev->dev);
- int err = 0;
struct bus_id_priv *busid_priv;
int rc;
@@ -372,23 +371,28 @@ static int stub_probe(struct usb_device *udev)
(struct usb_dev_state *) udev);
if (rc) {
dev_dbg(&udev->dev, "unable to claim port\n");
- return rc;
+ goto err_port;
}
- err = stub_add_files(&udev->dev);
- if (err) {
+ rc = stub_add_files(&udev->dev);
+ if (rc) {
dev_err(&udev->dev, "stub_add_files for %s\n", udev_busid);
- dev_set_drvdata(&udev->dev, NULL);
- usb_put_dev(udev);
- kthread_stop_put(sdev->ud.eh);
-
- busid_priv->sdev = NULL;
- stub_device_free(sdev);
- return err;
+ goto err_files;
}
busid_priv->status = STUB_BUSID_ALLOC;
return 0;
+err_files:
+ usb_hub_release_port(udev->parent, udev->portnum,
+ (struct usb_dev_state *) udev);
+err_port:
+ dev_set_drvdata(&udev->dev, NULL);
+ usb_put_dev(udev);
+ kthread_stop_put(sdev->ud.eh);
+
+ busid_priv->sdev = NULL;
+ stub_device_free(sdev);
+ return rc;
}
static void shutdown_busid(struct bus_id_priv *busid_priv)
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index c02374b6049c..cc1b03eccf4a 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -518,8 +518,7 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
dev_info(dev, "SetAddress Request (%d) to port %d\n",
ctrlreq->wValue, vdev->rhport);
- if (vdev->udev)
- usb_put_dev(vdev->udev);
+ usb_put_dev(vdev->udev);
vdev->udev = usb_get_dev(urb->dev);
spin_lock(&vdev->ud.lock);
@@ -539,8 +538,7 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
usbip_dbg_vhci_hc(
"Not yet?:Get_Descriptor to device 0 (get max pipe size)\n");
- if (vdev->udev)
- usb_put_dev(vdev->udev);
+ usb_put_dev(vdev->udev);
vdev->udev = usb_get_dev(urb->dev);
goto out;
@@ -831,8 +829,7 @@ static void vhci_device_reset(struct usbip_device *ud)
vdev->speed = 0;
vdev->devid = 0;
- if (vdev->udev)
- usb_put_dev(vdev->udev);
+ usb_put_dev(vdev->udev);
vdev->udev = NULL;
if (ud->tcp_socket) {
diff --git a/drivers/usb/wusbcore/dev-sysfs.c b/drivers/usb/wusbcore/dev-sysfs.c
index 101834576236..415b14002a61 100644
--- a/drivers/usb/wusbcore/dev-sysfs.c
+++ b/drivers/usb/wusbcore/dev-sysfs.c
@@ -101,7 +101,7 @@ static ssize_t wusb_ck_store(struct device *dev,
if (wusbhc == NULL)
return -ENODEV;
result = wusb_dev_4way_handshake(wusbhc, usb_dev->wusb_dev, &ck);
- memset(&ck, 0, sizeof(ck));
+ memzero_explicit(&ck, sizeof(ck));
wusbhc_put(wusbhc);
return result < 0 ? result : size;
}
diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c
index cc74d669c802..b66faaf3e842 100644
--- a/drivers/usb/wusbcore/security.c
+++ b/drivers/usb/wusbcore/security.c
@@ -522,10 +522,10 @@ error_hs3:
error_hs2:
error_hs1:
memset(hs, 0, 3*sizeof(hs[0]));
- memset(&keydvt_out, 0, sizeof(keydvt_out));
- memset(&keydvt_in, 0, sizeof(keydvt_in));
- memset(&ccm_n, 0, sizeof(ccm_n));
- memset(mic, 0, sizeof(mic));
+ memzero_explicit(&keydvt_out, sizeof(keydvt_out));
+ memzero_explicit(&keydvt_in, sizeof(keydvt_in));
+ memzero_explicit(&ccm_n, sizeof(ccm_n));
+ memzero_explicit(mic, sizeof(mic));
if (result < 0)
wusb_dev_set_encryption(usb_dev, 0);
error_dev_set_encryption:
diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c
index 0887ae982783..536ad42b0a4b 100644
--- a/drivers/uwb/rsv.c
+++ b/drivers/uwb/rsv.c
@@ -213,7 +213,7 @@ void uwb_rsv_backoff_win_timer(unsigned long arg)
bow->total_expired = 0;
bow->window = UWB_DRP_BACKOFF_WIN_MIN >> 1;
}
- dev_dbg(dev, "backoff_win_timer total_expired=%d, n=%d\n: ", bow->total_expired, bow->n);
+ dev_dbg(dev, "backoff_win_timer total_expired=%d, n=%d\n", bow->total_expired, bow->n);
/* try to relocate all the "to be moved" relocations */
uwb_rsv_handle_drp_avail_change(rc);
@@ -234,7 +234,7 @@ void uwb_rsv_backoff_win_increment(struct uwb_rc *rc)
bow->window <<= 1;
bow->n = prandom_u32() & (bow->window - 1);
- dev_dbg(dev, "new_window=%d, n=%d\n: ", bow->window, bow->n);
+ dev_dbg(dev, "new_window=%d, n=%d\n", bow->window, bow->n);
/* reset the timer associated variables */
timeout_us = bow->n * UWB_SUPERFRAME_LENGTH_US;
OpenPOWER on IntegriCloud