OSDN Git Service

Merge 3.18-rc7 into usb-next
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Dec 2014 03:21:03 +0000 (19:21 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Dec 2014 03:21:03 +0000 (19:21 -0800)
We need the xhci fixes here and this resolves a merge issue with
drivers/usb/dwc3/ep0.c

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
262 files changed:
Documentation/ABI/stable/sysfs-class-udc [new file with mode: 0644]
Documentation/ABI/testing/configfs-usb-gadget-hid [new file with mode: 0644]
Documentation/ABI/testing/configfs-usb-gadget-midi [new file with mode: 0644]
Documentation/devicetree/bindings/ata/marvell.txt
Documentation/devicetree/bindings/phy/berlin-sata-phy.txt
Documentation/devicetree/bindings/phy/berlin-usb-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/phy-miphy28lp.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/phy-mvebu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/samsung-phy.txt
Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/dwc3.txt
Documentation/devicetree/bindings/usb/exynos-usb.txt
Documentation/devicetree/bindings/usb/pxa-usb.txt
Documentation/devicetree/bindings/usb/usb-ohci.txt
Documentation/phy.txt
Documentation/usb/gadget_hid.txt
Documentation/usb/usb-serial.txt
arch/arm/boot/dts/am4372.dtsi
arch/mips/cavium-octeon/octeon-platform.c
arch/mips/configs/cavium_octeon_defconfig
drivers/pci/quirks.c
drivers/phy/Kconfig
drivers/phy/Makefile
drivers/phy/phy-armada375-usb2.c [new file with mode: 0644]
drivers/phy/phy-bcm-kona-usb2.c
drivers/phy/phy-berlin-sata.c
drivers/phy/phy-berlin-usb.c [new file with mode: 0644]
drivers/phy/phy-core.c
drivers/phy/phy-exynos-dp-video.c
drivers/phy/phy-exynos-mipi-video.c
drivers/phy/phy-exynos5-usbdrd.c
drivers/phy/phy-exynos5250-sata.c
drivers/phy/phy-hix5hd2-sata.c
drivers/phy/phy-miphy28lp.c [new file with mode: 0644]
drivers/phy/phy-miphy365x.c
drivers/phy/phy-mvebu-sata.c
drivers/phy/phy-omap-usb2.c
drivers/phy/phy-qcom-apq8064-sata.c
drivers/phy/phy-qcom-ipq806x-sata.c
drivers/phy/phy-rcar-gen2.c
drivers/phy/phy-samsung-usb2.c
drivers/phy/phy-spear1310-miphy.c
drivers/phy/phy-spear1340-miphy.c
drivers/phy/phy-stih407-usb.c
drivers/phy/phy-stih41x-usb.c
drivers/phy/phy-sun4i-usb.c
drivers/phy/phy-ti-pipe3.c
drivers/phy/phy-twl4030-usb.c
drivers/phy/phy-xgene.c
drivers/pinctrl/pinctrl-tegra-xusb.c
drivers/usb/chipidea/Makefile
drivers/usb/chipidea/ci.h
drivers/usb/chipidea/ci_hdrc_imx.c
drivers/usb/chipidea/ci_hdrc_msm.c
drivers/usb/chipidea/ci_hdrc_usb2.c [new file with mode: 0644]
drivers/usb/chipidea/core.c
drivers/usb/chipidea/debug.c
drivers/usb/chipidea/host.c
drivers/usb/chipidea/otg_fsm.c
drivers/usb/chipidea/udc.c
drivers/usb/chipidea/usbmisc_imx.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-acm.h
drivers/usb/class/usbtmc.c
drivers/usb/common/usb-otg-fsm.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/dwc2/Kconfig
drivers/usb/dwc2/Makefile
drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/core_intr.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/hcd.h
drivers/usb/dwc2/pci.c
drivers/usb/dwc2/platform.c
drivers/usb/dwc3/Kconfig
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/dwc3-exynos.c
drivers/usb/dwc3/dwc3-keystone.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/dwc3-st.c
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/host.c
drivers/usb/dwc3/platform_data.h
drivers/usb/dwc3/trace.h
drivers/usb/gadget/Kconfig
drivers/usb/gadget/composite.c
drivers/usb/gadget/configfs.c
drivers/usb/gadget/function/Makefile
drivers/usb/gadget/function/f_hid.c
drivers/usb/gadget/function/f_midi.c
drivers/usb/gadget/function/f_ncm.c
drivers/usb/gadget/function/f_rndis.c
drivers/usb/gadget/function/u_hid.h [new file with mode: 0644]
drivers/usb/gadget/function/u_midi.h [new file with mode: 0644]
drivers/usb/gadget/function/u_uac1.c
drivers/usb/gadget/legacy/Kconfig
drivers/usb/gadget/legacy/dbgp.c
drivers/usb/gadget/legacy/gmidi.c
drivers/usb/gadget/legacy/hid.c
drivers/usb/gadget/legacy/printer.c
drivers/usb/gadget/udc/Kconfig
drivers/usb/gadget/udc/Makefile
drivers/usb/gadget/udc/amd5536udc.c
drivers/usb/gadget/udc/at91_udc.c
drivers/usb/gadget/udc/atmel_usba_udc.c
drivers/usb/gadget/udc/bcm63xx_udc.c
drivers/usb/gadget/udc/bdc/Kconfig [new file with mode: 0644]
drivers/usb/gadget/udc/bdc/Makefile [new file with mode: 0644]
drivers/usb/gadget/udc/bdc/bdc.h [new file with mode: 0644]
drivers/usb/gadget/udc/bdc/bdc_cmd.c [new file with mode: 0644]
drivers/usb/gadget/udc/bdc/bdc_cmd.h [new file with mode: 0644]
drivers/usb/gadget/udc/bdc/bdc_core.c [new file with mode: 0644]
drivers/usb/gadget/udc/bdc/bdc_dbg.c [new file with mode: 0644]
drivers/usb/gadget/udc/bdc/bdc_dbg.h [new file with mode: 0644]
drivers/usb/gadget/udc/bdc/bdc_ep.c [new file with mode: 0644]
drivers/usb/gadget/udc/bdc/bdc_ep.h [new file with mode: 0644]
drivers/usb/gadget/udc/bdc/bdc_pci.c [new file with mode: 0644]
drivers/usb/gadget/udc/bdc/bdc_udc.c [new file with mode: 0644]
drivers/usb/gadget/udc/dummy_hcd.c
drivers/usb/gadget/udc/fotg210-udc.c
drivers/usb/gadget/udc/fsl_qe_udc.c
drivers/usb/gadget/udc/fsl_udc_core.c
drivers/usb/gadget/udc/fusb300_udc.c
drivers/usb/gadget/udc/goku_udc.c
drivers/usb/gadget/udc/gr_udc.c
drivers/usb/gadget/udc/lpc32xx_udc.c
drivers/usb/gadget/udc/m66592-udc.c
drivers/usb/gadget/udc/mv_u3d_core.c
drivers/usb/gadget/udc/mv_udc_core.c
drivers/usb/gadget/udc/net2272.c
drivers/usb/gadget/udc/net2280.c
drivers/usb/gadget/udc/omap_udc.c
drivers/usb/gadget/udc/pch_udc.c
drivers/usb/gadget/udc/pxa25x_udc.c
drivers/usb/gadget/udc/pxa27x_udc.c
drivers/usb/gadget/udc/pxa27x_udc.h
drivers/usb/gadget/udc/r8a66597-udc.c
drivers/usb/gadget/udc/s3c-hsudc.c
drivers/usb/gadget/udc/s3c2410_udc.c
drivers/usb/gadget/udc/udc-core.c
drivers/usb/gadget/udc/udc-xilinx.c
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/ehci-atmel.c
drivers/usb/host/ehci-exynos.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-msm.c
drivers/usb/host/ehci-mv.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-octeon.c [deleted file]
drivers/usb/host/ehci-orion.c
drivers/usb/host/ehci-platform.c
drivers/usb/host/ehci-sead3.c
drivers/usb/host/ehci-sh.c
drivers/usb/host/ehci-spear.c
drivers/usb/host/ehci-tegra.c
drivers/usb/host/ehci-w90x900.c
drivers/usb/host/ehci.h
drivers/usb/host/fotg210.h
drivers/usb/host/fusbh200.h
drivers/usb/host/imx21-hcd.c
drivers/usb/host/octeon2-common.c [deleted file]
drivers/usb/host/ohci-at91.c
drivers/usb/host/ohci-da8xx.c
drivers/usb/host/ohci-exynos.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-jz4740.c
drivers/usb/host/ohci-octeon.c [deleted file]
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-platform.c
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/ohci-spear.c
drivers/usb/host/ohci.h
drivers/usb/host/oxu210hp-hcd.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/uhci-platform.c
drivers/usb/host/xhci-plat.c
drivers/usb/misc/adutux.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/usb3503.c
drivers/usb/misc/yurex.c
drivers/usb/musb/Kconfig
drivers/usb/musb/am35x.c
drivers/usb/musb/blackfin.c
drivers/usb/musb/da8xx.c
drivers/usb/musb/davinci.c
drivers/usb/musb/jz4740.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_cppi41.c
drivers/usb/musb/musb_debugfs.c
drivers/usb/musb/musb_dsps.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/musb_io.h
drivers/usb/musb/musb_regs.h
drivers/usb/musb/musb_virthub.c
drivers/usb/musb/musbhsdma.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
drivers/usb/musb/ux500.c
drivers/usb/musb/ux500_dma.c
drivers/usb/phy/phy-ab8500-usb.c
drivers/usb/phy/phy-am335x-control.c
drivers/usb/phy/phy-fsl-usb.c
drivers/usb/phy/phy-fsl-usb.h
drivers/usb/phy/phy-generic.c
drivers/usb/phy/phy-gpio-vbus-usb.c
drivers/usb/phy/phy-isp1301-omap.c
drivers/usb/phy/phy-msm-usb.c
drivers/usb/phy/phy-mv-usb.c
drivers/usb/phy/phy-mxs-usb.c
drivers/usb/phy/phy-rcar-gen2-usb.c
drivers/usb/phy/phy-rcar-usb.c
drivers/usb/phy/phy-tahvo.c
drivers/usb/phy/phy-tegra-usb.c
drivers/usb/phy/phy-ulpi.c
drivers/usb/phy/phy.c
drivers/usb/renesas_usbhs/common.c
drivers/usb/renesas_usbhs/common.h
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/renesas_usbhs/fifo.h
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/renesas_usbhs/mod_host.c
drivers/usb/renesas_usbhs/pipe.c
drivers/usb/renesas_usbhs/rcar2.c
drivers/usb/serial/Kconfig
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/qcserial.c
drivers/usb/serial/usb-serial-simple.c
drivers/usb/storage/debug.c
drivers/usb/storage/debug.h
drivers/usb/storage/initializers.c
drivers/usb/storage/transport.c
drivers/usb/storage/uas.c
drivers/usb/storage/usb.c
drivers/usb/usbip/vhci_hcd.c
drivers/uwb/rsv.c
include/dt-bindings/phy/phy.h [new file with mode: 0644]
include/linux/pci_ids.h
include/linux/phy/phy.h
include/linux/platform_data/dwc3-exynos.h [deleted file]
include/linux/usb/chipidea.h
include/linux/usb/composite.h
include/linux/usb/ehci-dbgp.h [new file with mode: 0644]
include/linux/usb/ehci_def.h
include/linux/usb/gadget.h
include/linux/usb/hcd.h
include/linux/usb/otg.h
include/linux/usb/phy.h
include/linux/usb/renesas_usbhs.h

diff --git a/Documentation/ABI/stable/sysfs-class-udc b/Documentation/ABI/stable/sysfs-class-udc
new file mode 100644 (file)
index 0000000..85d3dac
--- /dev/null
@@ -0,0 +1,93 @@
+What:          /sys/class/udc/<udc>/a_alt_hnp_support
+Date:          June 2011
+KernelVersion: 3.1
+Contact:       Felipe Balbi <balbi@kernel.org>
+Description:
+               Indicates if an OTG A-Host supports HNP at an alternate port.
+Users:
+
+What:          /sys/class/udc/<udc>/a_hnp_support
+Date:          June 2011
+KernelVersion: 3.1
+Contact:       Felipe Balbi <balbi@kernel.org>
+Description:
+               Indicates if an OTG A-Host supports HNP at this port.
+Users:
+
+What:          /sys/class/udc/<udc>/b_hnp_enable
+Date:          June 2011
+KernelVersion: 3.1
+Contact:       Felipe Balbi <balbi@kernel.org>
+Description:
+               Indicates if an OTG A-Host enabled HNP support.
+Users:
+
+What:          /sys/class/udc/<udc>/current_speed
+Date:          June 2011
+KernelVersion: 3.1
+Contact:       Felipe Balbi <balbi@kernel.org>
+Description:
+               Indicates the current negotiated speed at this port.
+Users:
+
+What:          /sys/class/udc/<udc>/is_a_peripheral
+Date:          June 2011
+KernelVersion: 3.1
+Contact:       Felipe Balbi <balbi@kernel.org>
+Description:
+               Indicates that this port is the default Host on an OTG session
+               but HNP was used to switch roles.
+Users:
+
+What:          /sys/class/udc/<udc>/is_otg
+Date:          June 2011
+KernelVersion: 3.1
+Contact:       Felipe Balbi <balbi@kernel.org>
+Description:
+               Indicates that this port support OTG.
+Users:
+
+What:          /sys/class/udc/<udc>/maximum_speed
+Date:          June 2011
+KernelVersion: 3.1
+Contact:       Felipe Balbi <balbi@kernel.org>
+Description:
+               Indicates the maximum USB speed supported by this port.
+Users:
+
+What:          /sys/class/udc/<udc>/maximum_speed
+Date:          June 2011
+KernelVersion: 3.1
+Contact:       Felipe Balbi <balbi@kernel.org>
+Description:
+               Indicates the maximum USB speed supported by this port.
+Users:
+
+What:          /sys/class/udc/<udc>/soft_connect
+Date:          June 2011
+KernelVersion: 3.1
+Contact:       Felipe Balbi <balbi@kernel.org>
+Description:
+               Allows users to disconnect data pullup resistors thus causing a
+               logical disconnection from the USB Host.
+Users:
+
+What:          /sys/class/udc/<udc>/srp
+Date:          June 2011
+KernelVersion: 3.1
+Contact:       Felipe Balbi <balbi@kernel.org>
+Description:
+               Allows users to manually start Session Request Protocol.
+Users:
+
+What:          /sys/class/udc/<udc>/state
+Date:          June 2011
+KernelVersion: 3.1
+Contact:       Felipe Balbi <balbi@kernel.org>
+Description:
+               Indicates current state of the USB Device Controller. Valid
+               states are: 'not-attached', 'attached', 'powered',
+               'reconnecting', 'unauthenticated', 'default', 'addressed',
+               'configured', and 'suspended'; however not all USB Device
+               Controllers support reporting all states.
+Users:
diff --git a/Documentation/ABI/testing/configfs-usb-gadget-hid b/Documentation/ABI/testing/configfs-usb-gadget-hid
new file mode 100644 (file)
index 0000000..f12e00e
--- /dev/null
@@ -0,0 +1,11 @@
+What:          /config/usb-gadget/gadget/functions/hid.name
+Date:          Nov 2014
+KernelVersion: 3.19
+Description:
+               The attributes:
+
+               protocol        - HID protocol to use
+               report_desc     - blob corresponding to HID report descriptors
+                               except the data passed through /dev/hidg<N>
+               report_length   - HID report length
+               subclass        - HID device subclass to use
diff --git a/Documentation/ABI/testing/configfs-usb-gadget-midi b/Documentation/ABI/testing/configfs-usb-gadget-midi
new file mode 100644 (file)
index 0000000..6b341df
--- /dev/null
@@ -0,0 +1,12 @@
+What:          /config/usb-gadget/gadget/functions/midi.name
+Date:          Nov 2014
+KernelVersion: 3.19
+Description:
+               The attributes:
+
+               index           - index value for the USB MIDI adapter
+               id              - ID string for the USB MIDI adapter
+               buflen          - MIDI buffer length
+               qlen            - USB read request queue length
+               in_ports        - number of MIDI input ports
+               out_ports       - number of MIDI output ports
index 1c83516..b460edd 100644 (file)
@@ -6,11 +6,17 @@ Required Properties:
 - interrupts    : Interrupt controller is using
 - nr-ports      : Number of SATA ports in use.
 
+Optional Properties:
+- phys         : List of phandles to sata phys
+- phy-names    : Should be "0", "1", etc, one number per phandle
+
 Example:
 
        sata@80000 {
                compatible = "marvell,orion-sata";
                reg = <0x80000 0x5000>;
                interrupts = <21>;
+               phys = <&sata_phy0>, <&sata_phy1>;
+               phy-names = "0", "1";
                nr-ports = <2>;
        }
index 88f8c23..c0155f8 100644 (file)
@@ -2,7 +2,9 @@ Berlin SATA PHY
 ---------------
 
 Required properties:
-- compatible: should be "marvell,berlin2q-sata-phy"
+- compatible: should be one of
+    "marvell,berlin2-sata-phy"
+    "marvell,berlin2q-sata-phy"
 - address-cells: should be 1
 - size-cells: should be 0
 - phy-cells: from the generic PHY bindings, must be 1
diff --git a/Documentation/devicetree/bindings/phy/berlin-usb-phy.txt b/Documentation/devicetree/bindings/phy/berlin-usb-phy.txt
new file mode 100644 (file)
index 0000000..be33780
--- /dev/null
@@ -0,0 +1,16 @@
+* Marvell Berlin USB PHY
+
+Required properties:
+- compatible: "marvell,berlin2-usb-phy" or "marvell,berlin2cd-usb-phy"
+- reg: base address and length of the registers
+- #phys-cells: should be 0
+- resets: reference to the reset controller
+
+Example:
+
+       usb-phy@f774000 {
+               compatible = "marvell,berlin2-usb-phy";
+               reg = <0xf774000 0x128>;
+               #phy-cells = <0>;
+               resets = <&chip 0x104 14>;
+       };
diff --git a/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt
new file mode 100644 (file)
index 0000000..46a135d
--- /dev/null
@@ -0,0 +1,128 @@
+STMicroelectronics STi MIPHY28LP PHY binding
+============================================
+
+This binding describes a miphy device that is used to control PHY hardware
+for SATA, PCIe or USB3.
+
+Required properties (controller (parent) node):
+- compatible   : Should be "st,miphy28lp-phy".
+- st,syscfg    : Should be a phandle of the system configuration register group
+                 which contain the SATA, PCIe or USB3 mode setting bits.
+
+Required nodes :  A sub-node is required for each channel the controller
+                  provides. Address range information including the usual
+                  'reg' and 'reg-names' properties are used inside these
+                  nodes to describe the controller's topology. These nodes
+                  are translated by the driver's .xlate() function.
+
+Required properties (port (child) node):
+- #phy-cells   : Should be 1 (See second example)
+                 Cell after port phandle is device type from:
+                       - PHY_TYPE_SATA
+                       - PHY_TYPE_PCI
+                       - PHY_TYPE_USB3
+- reg          : Address and length of the register set for the device.
+- reg-names    : The names of the register addresses corresponding to the registers
+                 filled in "reg". It can also contain the offset of the system configuration
+                 registers used as glue-logic to setup the device for SATA/PCIe or USB3
+                 devices.
+- resets       : phandle to the parent reset controller.
+- reset-names  : Associated name must be "miphy-sw-rst".
+
+Optional properties (port (child) node):
+- st,osc-rdy           : to check the MIPHY0_OSC_RDY status in the glue-logic. This
+                         is not available in all the MiPHY. For example, for STiH407, only the
+                         MiPHY0 has this bit.
+- st,osc-force-ext     : to select the external oscillator. This can change from
+                         different MiPHY inside the same SoC.
+- st,sata_gen          : to select which SATA_SPDMODE has to be set in the SATA system config
+                         register.
+- st,px_rx_pol_inv     : to invert polarity of RXn/RXp (respectively negative line and positive
+                         line).
+- st,scc-on            : enable ssc to reduce effects of EMI (only for sata or PCIe).
+- st,tx-impedance-comp : to compensate tx impedance avoiding out of range values.
+
+example:
+
+               miphy28lp_phy: miphy28lp@9b22000 {
+                       compatible = "st,miphy28lp-phy";
+                       st,syscfg = <&syscfg_core>;
+                       #address-cells  = <1>;
+                       #size-cells     = <1>;
+                       ranges;
+
+                       phy_port0: port@9b22000 {
+                               reg = <0x9b22000 0xff>,
+                                     <0x9b09000 0xff>,
+                                     <0x9b04000 0xff>,
+                                     <0x114 0x4>, /* sysctrl MiPHY cntrl */
+                                     <0x818 0x4>, /* sysctrl MiPHY status*/
+                                     <0xe0  0x4>, /* sysctrl PCIe */
+                                     <0xec  0x4>; /* sysctrl SATA */
+                               reg-names = "sata-up",
+                                           "pcie-up",
+                                           "pipew",
+                                           "miphy-ctrl-glue",
+                                           "miphy-status-glue",
+                                           "pcie-glue",
+                                           "sata-glue";
+                               #phy-cells = <1>;
+                               st,osc-rdy;
+                               reset-names = "miphy-sw-rst";
+                               resets = <&softreset STIH407_MIPHY0_SOFTRESET>;
+                       };
+
+                       phy_port1: port@9b2a000 {
+                               reg = <0x9b2a000 0xff>,
+                                     <0x9b19000 0xff>,
+                                     <0x9b14000 0xff>,
+                                     <0x118 0x4>,
+                                     <0x81c 0x4>,
+                                     <0xe4  0x4>,
+                                     <0xf0  0x4>;
+                               reg-names = "sata-up",
+                                           "pcie-up",
+                                           "pipew",
+                                           "miphy-ctrl-glue",
+                                           "miphy-status-glue",
+                                           "pcie-glue",
+                                           "sata-glue";
+                               #phy-cells = <1>;
+                               st,osc-force-ext;
+                               reset-names = "miphy-sw-rst";
+                               resets = <&softreset STIH407_MIPHY1_SOFTRESET>;
+                       };
+
+                       phy_port2: port@8f95000 {
+                               reg = <0x8f95000 0xff>,
+                                     <0x8f90000 0xff>,
+                                     <0x11c 0x4>,
+                                     <0x820 0x4>;
+                               reg-names = "pipew",
+                                   "usb3-up",
+                                   "miphy-ctrl-glue",
+                                   "miphy-status-glue";
+                               #phy-cells = <1>;
+                               reset-names = "miphy-sw-rst";
+                               resets = <&softreset STIH407_MIPHY2_SOFTRESET>;
+                       };
+               };
+
+
+Specifying phy control of devices
+=================================
+
+Device nodes should specify the configuration required in their "phys"
+property, containing a phandle to the miphy device node and an index
+specifying which configuration to use, as described in phy-bindings.txt.
+
+example:
+               sata0: sata@9b20000  {
+                       ...
+                       phys            = <&phy_port0 PHY_TYPE_SATA>;
+                       ...
+               };
+
+Macro definitions for the supported miphy configuration can be found in:
+
+include/dt-bindings/phy/phy-miphy28lp.h
diff --git a/Documentation/devicetree/bindings/phy/phy-mvebu.txt b/Documentation/devicetree/bindings/phy/phy-mvebu.txt
new file mode 100644 (file)
index 0000000..f95b626
--- /dev/null
@@ -0,0 +1,43 @@
+* Marvell MVEBU SATA PHY
+
+Power control for the SATA phy found on Marvell MVEBU SoCs.
+
+This document extends the binding described in phy-bindings.txt
+
+Required properties :
+
+ - reg            : Offset and length of the register set for the SATA device
+ - compatible     : Should be "marvell,mvebu-sata-phy"
+ - clocks         : phandle of clock and specifier that supplies the device
+ - clock-names    : Should be "sata"
+
+Example:
+               sata-phy@84000 {
+                       compatible = "marvell,mvebu-sata-phy";
+                       reg = <0x84000 0x0334>;
+                       clocks = <&gate_clk 15>;
+                       clock-names = "sata";
+                       #phy-cells = <0>;
+                       status = "ok";
+               };
+
+Armada 375 USB cluster
+----------------------
+
+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.
+
+Required properties:
+
+- compatible: "marvell,armada-375-usb-cluster"
+- reg: Should contain usb cluster register location and length.
+- #phy-cells : from the generic phy bindings, must be 1. Possible
+values are 1 (USB2), 2 (USB3).
+
+Example:
+               usbcluster: usb-cluster@18400 {
+                       compatible = "marvell,armada-375-usb-cluster";
+                       reg = <0x18400 0x4>;
+                       #phy-cells = <1>
+               };
index 15e0f2c..d5bad92 100644 (file)
@@ -128,6 +128,7 @@ Required properties:
 - compatible : Should be set to one of the following supported values:
        - "samsung,exynos5250-usbdrd-phy" - for exynos5250 SoC,
        - "samsung,exynos5420-usbdrd-phy" - for exynos5420 SoC.
+       - "samsung,exynos7-usbdrd-phy" - for exynos7 SoC.
 - reg : Register offset and length of USB DRD PHY register set;
 - clocks: Clock IDs array as required by the controller
 - clock-names: names of clocks correseponding to IDs in the clock property;
@@ -138,6 +139,11 @@ Required properties:
               PHY operations, associated by phy name. It is used to
               determine bit values for clock settings register.
               For Exynos5420 this is given as 'sclk_usbphy30' in CMU.
+       - optional clocks: Exynos7 SoC has now following additional
+                          gate clocks available:
+                          - phy_pipe: for PIPE3 phy
+                          - phy_utmi: for UTMI+ phy
+                          - itp: for ITP generation
 - samsung,pmu-syscon: phandle for PMU system controller interface, used to
                      control pmu registers for power isolation.
 - #phy-cells : from the generic PHY bindings, must be 1;
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt
new file mode 100644 (file)
index 0000000..27f8b1e
--- /dev/null
@@ -0,0 +1,24 @@
+* USB2 ChipIdea USB controller for ci13xxx
+
+Required properties:
+- compatible: should be "chipidea,usb2"
+- reg: base address and length of the registers
+- interrupts: interrupt for the USB controller
+
+Optional properties:
+- clocks: reference to the USB clock
+- phys: reference to the USB PHY
+- phy-names: should be "usb-phy"
+- vbus-supply: reference to the VBUS regulator
+
+Example:
+
+       usb@f7ed0000 {
+               compatible = "chipidea,usb2";
+               reg = <0xf7ed0000 0x10000>;
+               interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&chip CLKID_USB0>;
+               phys = <&usb_phy0>;
+               phy-names = "usb-phy";
+               vbus-supply = <&reg_usb0_vbus>;
+       };
index 471366d..cd7f045 100644 (file)
@@ -14,6 +14,29 @@ Optional properties:
  - phys: from the *Generic PHY* bindings
  - phy-names: from the *Generic PHY* bindings
  - tx-fifo-resize: determines if the FIFO *has* to be reallocated.
+ - snps,disable_scramble_quirk: true when SW should disable data scrambling.
+       Only really useful for FPGA builds.
+ - snps,has-lpm-erratum: true when DWC3 was configured with LPM Erratum enabled
+ - snps,lpm-nyet-threshold: LPM NYET threshold
+ - snps,u2exit_lfps_quirk: set if we want to enable u2exit lfps quirk
+ - snps,u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk
+ - snps,req_p1p2p3_quirk: when set, the core will always request for
+                       P1/P2/P3 transition sequence.
+ - snps,del_p1p2p3_quirk: when set core will delay P1/P2/P3 until a certain
+                       amount of 8B10B errors occur.
+ - snps,del_phy_power_chg_quirk: when set core will delay PHY power change
+                       from P0 to P1/P2/P3.
+ - snps,lfps_filter_quirk: when set core will filter LFPS reception.
+ - snps,rx_detect_poll_quirk: when set core will disable a 400us delay to start
+                       Polling LFPS after RX.Detect.
+ - snps,tx_de_emphasis_quirk: when set core will set Tx de-emphasis value.
+ - snps,tx_de_emphasis: the value driven to the PHY is controlled by the
+                       LTSSM during USB3 Compliance mode.
+ - snps,dis_u3_susphy_quirk: when set core will disable USB3 suspend phy.
+ - snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy.
+ - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
+                       utmi_l1_suspend_n, false when asserts utmi_sleep_n
+ - snps,hird-threshold: HIRD threshold
 
 This is usually a subnode to DWC3 glue to which it is connected.
 
index a3b5990..9b4dbe3 100644 (file)
@@ -82,8 +82,10 @@ Example:
 
 DWC3
 Required properties:
- - compatible: should be "samsung,exynos5250-dwusb3" for USB 3.0 DWC3
-              controller.
+ - compatible: should be one of the following -
+              "samsung,exynos5250-dwusb3": for USB 3.0 DWC3 controller on
+                                           Exynos5250/5420.
+              "samsung,exynos7-dwusb3": for USB 3.0 DWC3 controller on Exynos7.
  - #address-cells, #size-cells : should be '1' if the device has sub-nodes
                                 with 'reg' property.
  - ranges: allows valid 1:1 translation between child's address space and
index 79729a9..9c33179 100644 (file)
@@ -29,3 +29,25 @@ Example:
                marvell,port-mode = <2>; /* PMM_GLOBAL_MODE */
        };
 
+UDC
+
+Required properties:
+ - compatible: Should be "marvell,pxa270-udc" for USB controllers
+   used in device mode.
+ - reg: usb device MMIO address space
+ - interrupts: single interrupt generated by the UDC IP
+ - clocks: input clock of the UDC IP (see clock-bindings.txt)
+
+Optional properties:
+ - gpios:
+   - gpio activated to control the USB D+ pullup (see gpio.txt)
+
+Example:
+
+               pxa27x_udc: udc@40600000 {
+                       compatible = "marvell,pxa270-udc";
+                       reg = <0x40600000 0x10000>;
+                       interrupts = <11>;
+                       clocks = <&pxa2xx_clks 11>;
+                       gpios = <&gpio 22 GPIO_ACTIVE_LOW>;
+               };
index b968a1a..19233b7 100644 (file)
@@ -9,6 +9,8 @@ Optional properties:
 - big-endian-regs : boolean, set this for hcds with big-endian registers
 - big-endian-desc : boolean, set this for hcds with big-endian descriptors
 - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
+- no-big-frame-no : boolean, set if frame_no lives in bits [15:0] of HCCA
+- num-ports : u32, to override the detected port count
 - clocks : a list of phandle + clock specifier pairs
 - phys : phandle + phy specifier pair
 - phy-names : "usb"
index c6594af..371361c 100644 (file)
@@ -54,18 +54,14 @@ The PHY driver should create the PHY in order for other peripheral controllers
 to make use of it. The PHY framework provides 2 APIs to create the PHY.
 
 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);
 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);
 
 The PHY drivers can use one of the above 2 APIs to create the PHY by passing
-the device pointer, phy ops and init_data.
+the device pointer and phy ops.
 phy_ops is a set of function pointers for performing PHY operations such as
-init, exit, power_on and power_off. *init_data* is mandatory to get a reference
-to the PHY in the case of non-dt boot. See section *Board File Initialization*
-on how init_data should be used.
+init, exit, power_on and power_off.
 
 Inorder to dereference the private data (in phy_ops), the phy provider driver
 can use phy_set_drvdata() after creating the PHY and use phy_get_drvdata() in
@@ -137,42 +133,18 @@ There are exported APIs like phy_pm_runtime_get, phy_pm_runtime_get_sync,
 phy_pm_runtime_put, phy_pm_runtime_put_sync, phy_pm_runtime_allow and
 phy_pm_runtime_forbid for performing PM operations.
 
-8. Board File Initialization
-
-Certain board file initialization is necessary in order to get a reference
-to the PHY in the case of non-dt boot.
-Say we have a single device that implements 3 PHYs that of USB, SATA and PCIe,
-then in the board file the following initialization should be done.
-
-struct phy_consumer consumers[] = {
-       PHY_CONSUMER("dwc3.0", "usb"),
-       PHY_CONSUMER("pcie.0", "pcie"),
-       PHY_CONSUMER("sata.0", "sata"),
-};
-PHY_CONSUMER takes 2 parameters, first is the device name of the controller
-(PHY consumer) and second is the port name.
-
-struct phy_init_data init_data = {
-       .consumers = consumers,
-       .num_consumers = ARRAY_SIZE(consumers),
-};
-
-static const struct platform_device pipe3_phy_dev = {
-       .name = "pipe3-phy",
-       .id = -1,
-       .dev = {
-               .platform_data = {
-                       .init_data = &init_data,
-               },
-       },
-};
-
-then, while doing phy_create, the PHY driver should pass this init_data
-       phy_create(dev, ops, pdata->init_data);
-
-and the controller driver (phy consumer) should pass the port name along with
-the device to get a reference to the PHY
-       phy_get(dev, "pcie");
+8. PHY Mappings
+
+In order to get reference to a PHY without help from DeviceTree, the framework
+offers lookups which can be compared to clkdev that allow clk structures to be
+bound to devices. A lookup can be made be made during runtime when a handle to
+the struct phy already exists.
+
+The framework offers the following API for registering and unregistering the
+lookups.
+
+int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id);
+void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id);
 
 9. DeviceTree Binding
 
index 12696c2..7a0fb8e 100644 (file)
@@ -74,6 +74,13 @@ static struct platform_device my_hid = {
        You can add as many HID functions as you want, only limited by
        the amount of interrupt endpoints your gadget driver supports.
 
+Configuration with configfs
+
+       Instead of adding fake platform devices and drivers in order to pass
+       some data to the kernel, if HID is a part of a gadget composed with
+       configfs the hidg_func_descriptor.report_desc is passed to the kernel
+       by writing the appropriate stream of bytes to a configfs attribute.
+
 Send and receive HID reports
 
        HID reports can be sent/received using read/write on the
index 5bd7926..947fa62 100644 (file)
@@ -145,7 +145,7 @@ Keyspan PDA Serial Adapter
   Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly
   sold in Macintosh catalogs, comes in a translucent white/green dongle).
   Fairly simple device. Firmware is homebrew.
-  This driver also works for the Xircom/Entrgra single port serial adapter.
+  This driver also works for the Xircom/Entrega single port serial adapter.
 
   Current status:
    Things that work:
index 46660ff..e19068d 100644 (file)
                                maximum-speed = "high-speed";
                                dr_mode = "otg";
                                status = "disabled";
+                               snps,dis_u3_susphy_quirk;
+                               snps,dis_u2_susphy_quirk;
                        };
                };
 
                                maximum-speed = "high-speed";
                                dr_mode = "otg";
                                status = "disabled";
+                               snps,dis_u3_susphy_quirk;
+                               snps,dis_u2_susphy_quirk;
                        };
                };
 
index 6df0f4d..b67ddf0 100644 (file)
@@ -7,22 +7,27 @@
  * Copyright (C) 2008 Wind River Systems
  */
 
+#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/i2c.h>
 #include <linux/usb.h>
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/of_platform.h>
 #include <linux/of_fdt.h>
 #include <linux/libfdt.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/usb/ohci_pdriver.h>
 
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-rnm-defs.h>
 #include <asm/octeon/cvmx-helper.h>
 #include <asm/octeon/cvmx-helper-board.h>
+#include <asm/octeon/cvmx-uctlx-defs.h>
 
 /* Octeon Random Number Generator.  */
 static int __init octeon_rng_device_init(void)
@@ -68,6 +73,229 @@ device_initcall(octeon_rng_device_init);
 
 #ifdef CONFIG_USB
 
+static DEFINE_MUTEX(octeon2_usb_clocks_mutex);
+
+static int octeon2_usb_clock_start_cnt;
+
+static 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);
+}
+
+static void octeon2_usb_clocks_stop(void)
+{
+       mutex_lock(&octeon2_usb_clocks_mutex);
+       octeon2_usb_clock_start_cnt--;
+       mutex_unlock(&octeon2_usb_clocks_mutex);
+}
+
+static int octeon_ehci_power_on(struct platform_device *pdev)
+{
+       octeon2_usb_clocks_start();
+       return 0;
+}
+
+static void octeon_ehci_power_off(struct platform_device *pdev)
+{
+       octeon2_usb_clocks_stop();
+}
+
+static struct usb_ehci_pdata octeon_ehci_pdata = {
+       /* Octeon EHCI matches CPU endianness. */
+#ifdef __BIG_ENDIAN
+       .big_endian_mmio        = 1,
+#endif
+       .power_on       = octeon_ehci_power_on,
+       .power_off      = octeon_ehci_power_off,
+};
+
+static void __init octeon_ehci_hw_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);
+
+       octeon2_usb_clocks_stop();
+}
+
+static u64 octeon_ehci_dma_mask = DMA_BIT_MASK(64);
+
 static int __init octeon_ehci_device_init(void)
 {
        struct platform_device *pd;
@@ -88,7 +316,7 @@ static int __init octeon_ehci_device_init(void)
        if (octeon_is_simulation() || usb_disabled())
                return 0; /* No USB in the simulator. */
 
-       pd = platform_device_alloc("octeon-ehci", 0);
+       pd = platform_device_alloc("ehci-platform", 0);
        if (!pd) {
                ret = -ENOMEM;
                goto out;
@@ -105,6 +333,10 @@ static int __init octeon_ehci_device_init(void)
        if (ret)
                goto fail;
 
+       pd->dev.dma_mask = &octeon_ehci_dma_mask;
+       pd->dev.platform_data = &octeon_ehci_pdata;
+       octeon_ehci_hw_start();
+
        ret = platform_device_add(pd);
        if (ret)
                goto fail;
@@ -117,6 +349,41 @@ out:
 }
 device_initcall(octeon_ehci_device_init);
 
+static int octeon_ohci_power_on(struct platform_device *pdev)
+{
+       octeon2_usb_clocks_start();
+       return 0;
+}
+
+static void octeon_ohci_power_off(struct platform_device *pdev)
+{
+       octeon2_usb_clocks_stop();
+}
+
+static struct usb_ohci_pdata octeon_ohci_pdata = {
+       /* Octeon OHCI matches CPU endianness. */
+#ifdef __BIG_ENDIAN
+       .big_endian_mmio        = 1,
+#endif
+       .power_on       = octeon_ohci_power_on,
+       .power_off      = octeon_ohci_power_off,
+};
+
+static void __init octeon_ohci_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);
+
+       octeon2_usb_clocks_stop();
+}
+
 static int __init octeon_ohci_device_init(void)
 {
        struct platform_device *pd;
@@ -137,7 +404,7 @@ static int __init octeon_ohci_device_init(void)
        if (octeon_is_simulation() || usb_disabled())
                return 0; /* No USB in the simulator. */
 
-       pd = platform_device_alloc("octeon-ohci", 0);
+       pd = platform_device_alloc("ohci-platform", 0);
        if (!pd) {
                ret = -ENOMEM;
                goto out;
@@ -154,6 +421,9 @@ static int __init octeon_ohci_device_init(void)
        if (ret)
                goto fail;
 
+       pd->dev.platform_data = &octeon_ohci_pdata;
+       octeon_ohci_hw_start();
+
        ret = platform_device_add(pd);
        if (ret)
                goto fail;
index b2476a1..e57058d 100644 (file)
@@ -120,6 +120,9 @@ CONFIG_SPI_OCTEON=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 # CONFIG_USB_SUPPORT is not set
+CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_DS1307=y
 CONFIG_STAGING=y
index 90acb32..ed6f89b 100644 (file)
@@ -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
index 2a436e6..ccad880 100644 (file)
@@ -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
index c4590fc..aa74f96 100644 (file)
@@ -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 (file)
index 0000000..ac7d99d
--- /dev/null
@@ -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");
index c1e0ca3..ef2dc1a 100644 (file)
@@ -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);
 
index 69ced52..099eee8 100644 (file)
@@ -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 (file)
index 0000000..c8a8d53
--- /dev/null
@@ -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");
index ff5eec5..a12d353 100644 (file)
@@ -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);
index 84f49e5..f86cbe6 100644 (file)
@@ -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);
index 6a9bef1..943e0f8 100644 (file)
@@ -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);
index f756aca..0437401 100644 (file)
@@ -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);
index 54cf4ae..bc858cc 100644 (file)
@@ -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");
index d5d9780..34915b4 100644 (file)
@@ -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 (file)
index 0000000..e34da13
--- /dev/null
@@ -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");
index 801afaf..6ab43a8 100644 (file)
@@ -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[] = {
index d395558..03b94f9 100644 (file)
@@ -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);
 
index f091576..4e489a8 100644 (file)
@@ -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);
index 7b3ddfb..4b243f7 100644 (file)
@@ -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);
index 759b0bf..6f2fe26 100644 (file)
@@ -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);
index 2793af1..778276a 100644 (file)
@@ -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);
index 908949d..4a12f66 100644 (file)
@@ -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);
index 5f4c586..9f47fae 100644 (file)
@@ -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);
index 1ecd094..e42bc20 100644 (file)
@@ -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);
index 42428d4..74f0fab 100644 (file)
@@ -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);
index 9f16cb8..a603801 100644 (file)
@@ -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[] = {
index 0baf5ef..fb02a67 100644 (file)
@@ -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);
index ab1e22d..c297b7a 100644 (file)
@@ -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);
 
index 7b04bef..8e87f54 100644 (file)
@@ -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);
 
index f8a51b1..29214a3 100644 (file)
@@ -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);
index 1631ec9..a84299b 100644 (file)
@@ -910,7 +910,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;
@@ -919,7 +919,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;
index 2f099c7..1fc86a2 100644 (file)
@@ -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
 
index ea40626..65913d4 100644 (file)
@@ -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);
 
index a7ab0f1..450a168 100644 (file)
@@ -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,
         },
 };
 
index 4935ac3..d79ecc0 100644 (file)
@@ -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 (file)
index 0000000..45844c9
--- /dev/null
@@ -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");
index 9bdc6bd..e14eafb 100644 (file)
@@ -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,
        },
 };
index 795d653..268e423 100644 (file)
@@ -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);
index ebde7b6..c1694cf 100644 (file)
 
 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;
 }
index caaabc5..562e581 100644 (file)
@@ -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);
index 0444d3f..4fe18ce 100644 (file)
@@ -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;
index 926c997..58591e9 100644 (file)
@@ -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);
index 077d58a..546a17e 100644 (file)
@@ -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,
index d3251eb..ffeb3c8 100644 (file)
@@ -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)
index ec97840..960bc08 100644 (file)
@@ -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;
index 98e8340..c6b35b7 100644 (file)
@@ -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 */
 
index a6efb41..2f2118f 100644 (file)
@@ -2650,7 +2650,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)) {
@@ -2670,6 +2670,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
                                goto err_phy;
                        }
                        hcd->phy = phy;
+                       hcd->remove_phy = 1;
                }
        }
 
@@ -2816,7 +2817,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);
@@ -2900,7 +2901,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);
index b649fef..c1dc42e 100644 (file)
@@ -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",
index f93807b..b323c4c 100644 (file)
@@ -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
index b73d2a5..8f75267 100644 (file)
@@ -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
index d926945..7605850 100644 (file)
@@ -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);
 
index 55c90c5..7a70a13 100644 (file)
@@ -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__ */
index c93918b..ad43c5b 100644 (file)
@@ -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);
 }
 
 /*
index 8b5c079..200168e 100644 (file)
@@ -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);
index 0a0e6f0..a0cd9db 100644 (file)
@@ -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;
 
index a12bb15..e69a843 100644 (file)
@@ -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
index c291fca..a4e724b 100644 (file)
@@ -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);
index 121dbda..6a795aa 100644 (file)
@@ -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,
index f4e5cc6..58b5b2c 100644 (file)
@@ -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,
index b0f4d52..25ddc39 100644 (file)
@@ -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,
        },
 };
index 66f6256..4bb9aa6 100644 (file)
 #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)
 
 
 /* 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)
 #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)
 #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;
index 3951a65..7bd0a95 100644 (file)
@@ -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,
        },
 };
index 7ec8495..fe3b933 100644 (file)
@@ -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;
        }
 
index a0aa9f3..172d64e 100644 (file)
@@ -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)
 };
index a36cf66..7c4faf7 100644 (file)
@@ -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);
index c7602b5..4a1a543 100644 (file)
@@ -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;
        }
 
index df38e7e..1bc77a3 100644 (file)
@@ -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);
index 546ea54..f03b136 100644 (file)
@@ -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:
index dcb8ca0..12bfd3c 100644 (file)
@@ -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);
 }
index 7db34f0..a3a3b6d 100644 (file)
@@ -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;
 };
index 60b0f41..9fc20b3 100644 (file)
@@ -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
        )
index c4880fc..747ef53 100644 (file)
@@ -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
index f6a51fd..6178353 100644 (file)
@@ -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;
index 3403433..7564814 100644 (file)
@@ -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,
index 90701aa..dd68091 100644 (file)
@@ -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
index 59ab62c..488ac66 100644 (file)
@@ -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>
 #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)
index 807b31c..a904403 100644 (file)
@@ -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);
index 16361b0..bdcda9f 100644 (file)
@@ -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
index f13fc6a..829edf8 100644 (file)
@@ -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 (file)
index 0000000..aaa0e36
--- /dev/null
@@ -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 (file)
index 0000000..2251018
--- /dev/null
@@ -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 */
+
index a44a07f..53842a1 100644 (file)
@@ -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);
index 24392d2..fd48ef3 100644 (file)
@@ -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).
index 1b07513..633683a 100644 (file)
@@ -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)
index 3d696b8..e02a095 100644 (file)
@@ -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 = {
index 778613e..633fe7e 100644 (file)
 #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 */
 
 /*-------------------------------------------------------------------------*/
 
-/*
- * 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);
index 6474081..9054598 100644 (file)
@@ -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,
 };
index 217365d..b8e213e 100644 (file)
@@ -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)
 #
index a7f4491..fba2049 100644 (file)
@@ -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/
index 3b9d138..de7e5e2 100644 (file)
@@ -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 */
index 9968f53..eb2999c 100644 (file)
@@ -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))
index 1529926..b317479 100644 (file)
@@ -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;
index 2235b88..c790918 100644 (file)
@@ -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 (file)
index 0000000..0d7b8c9
--- /dev/null
@@ -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 (file)
index 0000000..5cf6a3b
--- /dev/null
@@ -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 (file)
index 0000000..dc18a20
--- /dev/null
@@ -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 (file)
index 0000000..6a4155c
--- /dev/null
@@ -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 (file)
index 0000000..61d0e3b
--- /dev/null
@@ -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 (file)
index 0000000..c6dfef8
--- /dev/null
@@ -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 (file)
index 0000000..5945dbc
--- /dev/null
@@ -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 (file)
index 0000000..338a6c7
--- /dev/null
@@ -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 (file)
index 0000000..15da5b1
--- /dev/null
@@ -0,0 +1,2023 @@
+/*
+ * 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 (file)
index 0000000..8a6b36c
--- /dev/null
@@ -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 (file)
index 0000000..0296884
--- /dev/null
@@ -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 (file)
index 0000000..3700ce7
--- /dev/null
@@ -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);
+}
index 81dc595..1c69c76 100644 (file)
@@ -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");
 }
 
index 1d31592..1ca52e1 100644 (file)
@@ -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;
index dd18ea3..d201f9a 100644 (file)
@@ -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;
        }
index c362079..f340181 100644 (file)
@@ -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;
index 8286df7..a1b33f5 100644 (file)
@@ -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);
 
index bf9c5ef..5b9176e 100644 (file)
@@ -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;
index 1b3048a..320df9a 100644 (file)
@@ -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;
 }
 
index feab0ba..9765296 100644 (file)
@@ -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]);
 
index 8985656..ef3f73d 100644 (file)
@@ -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);
 
index 046a1f8..ea422ac 100644 (file)
@@ -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)
index 3c5db80..d4edd76 100644 (file)
@@ -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;
        }
index 84d7162..3a90856 100644 (file)
@@ -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");
index 8d13337..d6411e0 100644 (file)
@@ -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;
 
index dcdfea4..534b85c 100644 (file)
@@ -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;
index ccbe3d4..1c7379a 100644 (file)
@@ -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);
 
index 42f7eeb..347a05b 100644 (file)
@@ -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");
index 4868369..9b03fab 100644 (file)
 #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,
index 28f2b53..11e1423 100644 (file)
@@ -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;
index f818661..06870da 100644 (file)
@@ -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)
index dfbf557..97d3a91 100644 (file)
@@ -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;
index ff423d1..2a8e36d 100644 (file)
@@ -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);
 
index f205465..e31d574 100644 (file)
@@ -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;
index ed27e16..1eac56f 100644 (file)
@@ -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;
index a3ca137..fafc628 100644 (file)
@@ -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
index 348c243..d6216a4 100644 (file)
@@ -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
index ec9f7b7..56a8850 100644 (file)
@@ -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");
index 7189f2e..f58c975 100644 (file)
@@ -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");
index 2d2ae8d..fb7bd0c 100644 (file)
@@ -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)
index 15feaf9..38bfeed 100644 (file)
@@ -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
index 5728829..118edb7 100644 (file)
@@ -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;
+}
index 9dc2118..9db74ca 100644 (file)
@@ -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,
index 08147c3..849806a 100644 (file)
@@ -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);
index dbe5e4e..c7a9b31 100644 (file)
@@ -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 (file)
index 9051439..0000000
+++ /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);
index 22e15ca..3c76489 100644 (file)
@@ -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);
index 2f5b9ce..35a9aed 100644 (file)
@@ -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,
index cf12676..9b6e8d0 100644 (file)
@@ -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;
index 9b9b9f5..0e0ce68 100644 (file)
@@ -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;
        }
index 1355ff0..34e1474 100644 (file)
@@ -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;
index aaa0197..19a9af1 100644 (file)
@@ -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;
        }
index a9303af..c305732 100644 (file)
@@ -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)
index eee228a..6f0577b 100644 (file)
@@ -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,
index ac6cd1b..3bad178 100644 (file)
@@ -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)
index 6b719e0..d6e5b3d 100644 (file)
@@ -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)
index 207bad9..eb4efba 100644 (file)
@@ -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 (file)
index d9df423..0000000
+++ /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);
index e49eb4f..3940660 100644 (file)
 #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)) {
index df06be6..1c76999 100644 (file)
@@ -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));
 
index d28b658..035a8a8 100644 (file)
@@ -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) {
index d664eda..1dab9df 100644 (file)
@@ -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
index c2c221a..8ddd8f5 100644 (file)
@@ -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 (file)
index 15af895..0000000
+++ /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);
index 0231606..3e5df5a 100644 (file)
@@ -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;
index 4369299..9434c1d 100644 (file)
@@ -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,
index e68f3d0..1339981 100644 (file)
@@ -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);
index 8d58766..4a54f9d 100644 (file)
@@ -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;
 
index 59f4245..bc46228 100644 (file)
@@ -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);
index 4fe79a2..75811dd 100644 (file)
@@ -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;
        }
index 2f3aceb..dd483c1 100644 (file)
@@ -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);
 
index b987f1d..cf8f460 100644 (file)
@@ -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;
index 646300c..08d402b 100644 (file)
@@ -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.
index 493c7f2..3071c0e 100644 (file)
@@ -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 */
index 633caf6..022dc00 100644 (file)
@@ -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);
index ae7e120..b9af8cb 100644 (file)
@@ -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);
index c3a45da..343fa6f 100644 (file)
@@ -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;
index 06cc5d6..9d68372 100644 (file)
@@ -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
 
index a2735df..220fd4d 100644 (file)
@@ -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,
 
index ac4422b..a441a2d 100644 (file)
@@ -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;
index 058775e..9a9c82a 100644 (file)
@@ -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,
 
index 110b784..3c1d9b2 100644 (file)
@@ -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)) {
index d118729..bb7b263 100644 (file)
@@ -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,
 };
index b841ee0..55fe0ff 100644 (file)
@@ -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,
 };
index 414e57a..5e65958 100644 (file)
@@ -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;
index 5a9b977..f64fd96 100644 (file)
@@ -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 {
index 4c21679..ad3701a 100644 (file)
@@ -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 },
index 48bc09e..53bd0e7 100644 (file)
@@ -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);
 
index 24c8c02..49b04cb 100644 (file)
@@ -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;
        }
 
index 855793d..23d474d 100644 (file)
@@ -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;
index eebeed7..8a57a6f 100644 (file)
 
 #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
index 37122a4..11f0be0 100644 (file)
 #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
  */
 #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
  */
index e2d2d8c..b072420 100644 (file)
@@ -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));
        }
 }
 
index e8e9f9a..ab7ec09 100644 (file)
@@ -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;
 
index d369bf1..763649e 100644 (file)
@@ -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",
index 2daa779..3a5ffd5 100644 (file)
@@ -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;
 
index dc666e9..abf7272 100644 (file)
@@ -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) {
index 221faed..e93845c 100644 (file)
@@ -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;
index 11ab2c4..8cd7d19 100644 (file)
@@ -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;
 
index 35b6083..2e923c5 100644 (file)
@@ -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;
 
index f1ea599..ab38aa3 100644 (file)
@@ -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;
 
index 5986c96..2314995 100644 (file)
 /* 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 */
index 7594e50..4ba1f57 100644 (file)
@@ -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;
 
index f4b14bd..5451172 100644 (file)
@@ -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");
index 8eea56d..a2dfb2a 100644 (file)
@@ -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,
index 7843ef7..e120d87 100644 (file)
@@ -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;
index 7d80c54..b234d46 100644 (file)
@@ -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;
index 0e0c415..a55dadc 100644 (file)
@@ -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)) {
index 388d89f..f838084 100644 (file)
@@ -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;
index 33265a5..1e09b83 100644 (file)
@@ -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;
index cc61ee4..d391c79 100644 (file)
@@ -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;
 
index 886f180..fa2bfa4 100644 (file)
@@ -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) {
index 4e3877c..f48a7a2 100644 (file)
@@ -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;
 
index 045cd30..b4066a0 100644 (file)
@@ -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);
index b3b6813..3714787 100644 (file)
@@ -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);
index a7996da..0427cdd 100644 (file)
@@ -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;
 };
 
 /*
index b0c97a3..f46271c 100644 (file)
@@ -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);
 }
index a168a17..f07037c 100644 (file)
@@ -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
index 2d17c10..8697e6e 100644 (file)
@@ -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;
 }
index 10e1ded..f0d3231 100644 (file)
@@ -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);
 
        /*
index 040bcef..007f45a 100644 (file)
@@ -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)
index e6b9dcc..8fc15c0 100644 (file)
@@ -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"
 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)
index a69f7cd..b7cf198 100644 (file)
@@ -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.
 
index 742d827..dd97d8b 100644 (file)
@@ -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,
index 02c420a..2363654 100644 (file)
@@ -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);
        }
 
index dfd728a..312b0fe 100644 (file)
@@ -1657,7 +1657,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 +1702,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);
        }
index 3d88eef..220b4be 100644 (file)
@@ -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);
index b2aa003..cb3e147 100644 (file)
@@ -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);
index 7064eb8..bc31011 100644 (file)
@@ -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(),
index e08f647..05bc379 100644 (file)
@@ -179,17 +179,14 @@ void usb_stor_show_sense(const struct us_data *us,
        US_DEBUGPX("\n");
 }
 
-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(7, &us->pusb_dev->dev, fmt, args);
+       dev_vprintk_emit(7, &us->pusb_dev->dev, fmt, args);
 
        va_end(args);
-
-       return r;
 }
 EXPORT_SYMBOL_GPL(usb_stor_dbg);
index b1273f0..f525203 100644 (file)
 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, ...)                                   \
index 73f125e..31fa2e9 100644 (file)
@@ -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;
index b1d815e..540add2 100644 (file)
@@ -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
index 89b2434..004ebc1 100644 (file)
@@ -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 (blk_rq_tagged(cmnd->request))
-               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)
@@ -818,13 +807,6 @@ static struct scsi_host_template uas_host_template = {
        .cmd_per_lun = 1,       /* until we override it */
        .skip_settle_delay = 1,
        .ordered_tag = 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,
 };
 
 #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
index 9d66ce6..d468d02 100644 (file)
@@ -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)
index c02374b..cc1b03e 100644 (file)
@@ -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) {
index 0887ae9..536ad42 100644 (file)
@@ -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;
diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
new file mode 100644 (file)
index 0000000..6c90193
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *
+ * This header provides constants for the phy framework
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ * Author: Gabriel Fernandez <gabriel.fernandez@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef _DT_BINDINGS_PHY
+#define _DT_BINDINGS_PHY
+
+#define PHY_NONE               0
+#define PHY_TYPE_SATA          1
+#define PHY_TYPE_PCIE          2
+#define PHY_TYPE_USB2          3
+#define PHY_TYPE_USB3          4
+
+#endif /* _DT_BINDINGS_PHY */
index 1fa99a3..5decad7 100644 (file)
 #define PCI_DEVICE_ID_AMD_8131_BRIDGE  0x7450
 #define PCI_DEVICE_ID_AMD_8131_APIC    0x7451
 #define PCI_DEVICE_ID_AMD_8132_BRIDGE  0x7458
+#define PCI_DEVICE_ID_AMD_NL_USB       0x7912
 #define PCI_DEVICE_ID_AMD_CS5535_IDE    0x208F
 #define PCI_DEVICE_ID_AMD_CS5536_ISA    0x2090
 #define PCI_DEVICE_ID_AMD_CS5536_FLASH  0x2091
index 8cb6f81..a0197fa 100644 (file)
@@ -61,7 +61,6 @@ struct phy {
        struct device           dev;
        int                     id;
        const struct phy_ops    *ops;
-       struct phy_init_data    *init_data;
        struct mutex            mutex;
        int                     init_count;
        int                     power_count;
@@ -84,33 +83,14 @@ struct phy_provider {
                struct of_phandle_args *args);
 };
 
-/**
- * struct phy_consumer - represents the phy consumer
- * @dev_name: the device name of the controller that will use this PHY device
- * @port: name given to the consumer port
- */
-struct phy_consumer {
-       const char *dev_name;
-       const char *port;
-};
-
-/**
- * struct phy_init_data - contains the list of PHY consumers
- * @num_consumers: number of consumers for this PHY device
- * @consumers: list of PHY consumers
- */
-struct phy_init_data {
-       unsigned int num_consumers;
-       struct phy_consumer *consumers;
+struct phy_lookup {
+       struct list_head node;
+       const char *dev_id;
+       const char *con_id;
+       struct phy *phy;
 };
 
-#define PHY_CONSUMER(_dev_name, _port)                         \
-{                                                              \
-       .dev_name       = _dev_name,                            \
-       .port           = _port,                                \
-}
-
-#define        to_phy(dev)     (container_of((dev), struct phy, dev))
+#define        to_phy(a)       (container_of((a), struct phy, dev))
 
 #define        of_phy_provider_register(dev, xlate)    \
        __of_phy_provider_register((dev), THIS_MODULE, (xlate))
@@ -159,10 +139,9 @@ struct phy *of_phy_get(struct device_node *np, const char *con_id);
 struct phy *of_phy_simple_xlate(struct device *dev,
        struct of_phandle_args *args);
 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);
 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);
 void phy_destroy(struct phy *phy);
 void devm_phy_destroy(struct device *dev, struct phy *phy);
 struct phy_provider *__of_phy_provider_register(struct device *dev,
@@ -174,6 +153,8 @@ struct phy_provider *__devm_of_phy_provider_register(struct device *dev,
 void of_phy_provider_unregister(struct phy_provider *phy_provider);
 void devm_of_phy_provider_unregister(struct device *dev,
        struct phy_provider *phy_provider);
+int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id);
+void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id);
 #else
 static inline int phy_pm_runtime_get(struct phy *phy)
 {
@@ -301,16 +282,14 @@ static inline struct phy *of_phy_simple_xlate(struct device *dev,
 
 static inline 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)
 {
        return ERR_PTR(-ENOSYS);
 }
 
 static inline 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)
 {
        return ERR_PTR(-ENOSYS);
 }
@@ -345,6 +324,13 @@ static inline void devm_of_phy_provider_unregister(struct device *dev,
        struct phy_provider *phy_provider)
 {
 }
+static inline int
+phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id)
+{
+       return 0;
+}
+static inline void phy_remove_lookup(struct phy *phy, const char *con_id,
+                                    const char *dev_id) { }
 #endif
 
 #endif /* __DRIVERS_PHY_H */
diff --git a/include/linux/platform_data/dwc3-exynos.h b/include/linux/platform_data/dwc3-exynos.h
deleted file mode 100644 (file)
index 5eb7da9..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * dwc3-exynos.h - Samsung EXYNOS DWC3 Specific Glue layer, header.
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _DWC3_EXYNOS_H_
-#define _DWC3_EXYNOS_H_
-
-struct dwc3_exynos_data {
-       int phy_type;
-       int (*phy_init)(struct platform_device *pdev, int type);
-       int (*phy_exit)(struct platform_device *pdev, int type);
-};
-
-#endif /* _DWC3_EXYNOS_H_ */
index e14c09a..535997a 100644 (file)
@@ -13,11 +13,12 @@ struct ci_hdrc_platform_data {
        /* offset of the capability registers */
        uintptr_t        capoffset;
        unsigned         power_budget;
-       struct usb_phy  *phy;
+       struct phy      *phy;
+       /* old usb_phy interface */
+       struct usb_phy  *usb_phy;
        enum usb_phy_interface phy_mode;
        unsigned long    flags;
 #define CI_HDRC_REGS_SHARED            BIT(0)
-#define CI_HDRC_REQUIRE_TRANSCEIVER    BIT(1)
 #define CI_HDRC_DISABLE_STREAMING      BIT(3)
        /*
         * Only set it when DCCPARAMS.DC==1 and DCCPARAMS.HC==1,
index c330f5e..3d87def 100644 (file)
@@ -427,6 +427,8 @@ static inline struct usb_composite_driver *to_cdriver(
  * @b_vendor_code: bMS_VendorCode part of the OS string
  * @use_os_string: false by default, interested gadgets set it
  * @os_desc_config: the configuration to be used with OS descriptors
+ * @setup_pending: true when setup request is queued but not completed
+ * @os_desc_pending: true when os_desc request is queued but not completed
  *
  * One of these devices is allocated and initialized before the
  * associated device driver's bind() is called.
@@ -488,6 +490,9 @@ struct usb_composite_dev {
 
        /* protects deactivations and delayed_status counts*/
        spinlock_t                      lock;
+
+       unsigned                        setup_pending:1;
+       unsigned                        os_desc_pending:1;
 };
 
 extern int usb_string_id(struct usb_composite_dev *c);
@@ -501,6 +506,8 @@ extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n);
 extern void composite_disconnect(struct usb_gadget *gadget);
 extern int composite_setup(struct usb_gadget *gadget,
                const struct usb_ctrlrequest *ctrl);
+extern void composite_suspend(struct usb_gadget *gadget);
+extern void composite_resume(struct usb_gadget *gadget);
 
 /*
  * Some systems will need runtime overrides for the  product identifiers
diff --git a/include/linux/usb/ehci-dbgp.h b/include/linux/usb/ehci-dbgp.h
new file mode 100644 (file)
index 0000000..7344d9e
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Standalone EHCI usb debug driver
+ *
+ * Originally written by:
+ *  Eric W. Biederman" <ebiederm@xmission.com> and
+ *  Yinghai Lu <yhlu.kernel@gmail.com>
+ *
+ * Changes for early/late printk and HW errata:
+ *  Jason Wessel <jason.wessel@windriver.com>
+ *  Copyright (C) 2009 Wind River Systems, Inc.
+ *
+ */
+
+#ifndef __LINUX_USB_EHCI_DBGP_H
+#define __LINUX_USB_EHCI_DBGP_H
+
+#include <linux/console.h>
+#include <linux/types.h>
+
+/* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console.  (nonstandard enumeration.)
+ */
+struct ehci_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
+extern int early_dbgp_init(char *s);
+extern struct console early_dbgp_console;
+#endif /* CONFIG_EARLY_PRINTK_DBGP */
+
+struct usb_hcd;
+
+#ifdef CONFIG_XEN_DOM0
+extern int xen_dbgp_reset_prep(struct usb_hcd *);
+extern int xen_dbgp_external_startup(struct usb_hcd *);
+#else
+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;
+}
+#endif
+
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+/* Call backs from ehci host driver to ehci debug driver */
+extern int dbgp_external_startup(struct usb_hcd *);
+extern int dbgp_reset_prep(struct usb_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
+
+#endif /* __LINUX_USB_EHCI_DBGP_H */
index daec99a..966889a 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef __LINUX_USB_EHCI_DEF_H
 #define __LINUX_USB_EHCI_DEF_H
 
+#include <linux/usb/ehci-dbgp.h>
+
 /* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
 
 /* Section 2.2 Host Controller Capability Registers */
@@ -190,67 +192,4 @@ struct ehci_regs {
 #define USBMODE_EX_HC  (3<<0)          /* host controller mode */
 };
 
-/* Appendix C, Debug port ... intended for use with special "debug devices"
- * that can help if there's no serial console.  (nonstandard enumeration.)
- */
-struct ehci_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;
-
-#ifdef CONFIG_XEN_DOM0
-extern int xen_dbgp_reset_prep(struct usb_hcd *);
-extern int xen_dbgp_external_startup(struct usb_hcd *);
-#else
-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;
-}
-#endif
-
-#ifdef CONFIG_EARLY_PRINTK_DBGP
-/* Call backs from ehci host driver to ehci 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
-
 #endif /* __LINUX_USB_EHCI_DEF_H */
index 522cafe..70ddb39 100644 (file)
@@ -490,8 +490,7 @@ struct usb_gadget_ops {
        void    (*get_config_params)(struct usb_dcd_config_params *);
        int     (*udc_start)(struct usb_gadget *,
                        struct usb_gadget_driver *);
-       int     (*udc_stop)(struct usb_gadget *,
-                       struct usb_gadget_driver *);
+       int     (*udc_stop)(struct usb_gadget *);
 };
 
 /**
@@ -925,7 +924,7 @@ extern int usb_add_gadget_udc_release(struct device *parent,
                struct usb_gadget *gadget, void (*release)(struct device *dev));
 extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
 extern void usb_del_gadget_udc(struct usb_gadget *gadget);
-extern int udc_attach_driver(const char *name,
+extern int usb_udc_attach_driver(const char *name,
                struct usb_gadget_driver *driver);
 
 /*-------------------------------------------------------------------------*/
index cd96a2b..9cf7e35 100644 (file)
@@ -379,6 +379,9 @@ struct hc_driver {
        int     (*disable_usb3_lpm_timeout)(struct usb_hcd *,
                        struct usb_device *, enum usb3_link_state state);
        int     (*find_raw_port_number)(struct usb_hcd *, int);
+       /* Call for power on/off the port if necessary */
+       int     (*port_power)(struct usb_hcd *hcd, int portnum, bool enable);
+
 };
 
 static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
index 154332b..52661c5 100644 (file)
@@ -9,15 +9,20 @@
 #ifndef __LINUX_USB_OTG_H
 #define __LINUX_USB_OTG_H
 
+#include <linux/phy/phy.h>
 #include <linux/usb/phy.h>
 
 struct usb_otg {
        u8                      default_a;
 
-       struct usb_phy          *phy;
+       struct phy              *phy;
+       /* old usb_phy interface */
+       struct usb_phy          *usb_phy;
        struct usb_bus          *host;
        struct usb_gadget       *gadget;
 
+       enum usb_otg_state      state;
+
        /* bind/unbind the host controller */
        int     (*set_host)(struct usb_otg *otg, struct usb_bus *host);
 
index 353053a..f499c23 100644 (file)
@@ -77,7 +77,6 @@ struct usb_phy {
        unsigned int             flags;
 
        enum usb_phy_type       type;
-       enum usb_otg_state      state;
        enum usb_phy_events     last_event;
 
        struct usb_otg          *otg;
@@ -210,6 +209,7 @@ extern void usb_put_phy(struct usb_phy *);
 extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x);
 extern int usb_bind_phy(const char *dev_name, u8 index,
                                const char *phy_dev_name);
+extern void usb_phy_set_event(struct usb_phy *x, unsigned long event);
 #else
 static inline struct usb_phy *usb_get_phy(enum usb_phy_type type)
 {
@@ -251,6 +251,10 @@ static inline int usb_bind_phy(const char *dev_name, u8 index,
 {
        return -EOPNOTSUPP;
 }
+
+static inline void usb_phy_set_event(struct usb_phy *x, unsigned long event)
+{
+}
 #endif
 
 static inline int
index d5952bb..9fd9e48 100644 (file)
@@ -145,6 +145,10 @@ struct renesas_usbhs_driver_param {
        int d0_rx_id;
        int d1_tx_id;
        int d1_rx_id;
+       int d2_tx_id;
+       int d2_rx_id;
+       int d3_tx_id;
+       int d3_rx_id;
 
        /*
         * option: