Merge tag 'usb-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 26 Jun 2015 22:59:26 +0000 (15:59 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 26 Jun 2015 22:59:26 +0000 (15:59 -0700)
Pull USB updates from Greg KH:
 "Here's the big USB patchset for 4.2-rc1.  As is normal these days, the
  majority of changes are in the gadget drivers, with a bunch of other
  small driver changes.

  All of these have been in linux-next with no reported issues"

* tag 'usb-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (175 commits)
  usb: dwc3: Use ASCII space in Kconfig
  usb: chipidea: add work-around for Marvell HSIC PHY startup
  usb: chipidea: allow multiple instances to use default ci_default_pdata
  dt-bindings: Consolidate ChipIdea USB ci13xxx bindings
  phy: add Marvell HSIC 28nm PHY
  phy: Add Marvell USB 2.0 OTG 28nm PHY
  dt-bindings: Add Marvell PXA1928 USB and HSIC PHY bindings
  USB: ssb: use devm_kzalloc
  USB: ssb: fix error handling in ssb_hcd_create_pdev()
  usb: isp1760: check for null return from kzalloc
  cdc-acm: Add support of ATOL FPrint fiscal printers
  usb: chipidea: usbmisc_imx: Remove unneeded semicolon
  USB: usbtmc: add device quirk for Rigol DS6104
  USB: serial: mos7840: Use setup_timer
  phy: twl4030-usb: add ABI documentation
  phy: twl4030-usb: remove incorrect pm_runtime_get_sync() in probe function.
  phy: twl4030-usb: remove pointless 'suspended' test in 'suspend' callback.
  phy: twl4030-usb: make runtime pm more reliable.
  drivers:usb:fsl: Fix compilation error for fsl ehci drv
  usb: renesas_usbhs: Don't disable the pipe if Control write status stage
  ...

180 files changed:
Documentation/ABI/testing/sysfs-platform-twl4030-usb [new file with mode: 0644]
Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/pxa1928-usb-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt
Documentation/devicetree/bindings/power/twl-charger.txt
Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt [deleted file]
Documentation/devicetree/bindings/usb/ci-hdrc-qcom.txt [deleted file]
Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt
Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt [deleted file]
Documentation/devicetree/bindings/usb/dwc3-st.txt
Documentation/devicetree/bindings/usb/dwc3.txt
Documentation/devicetree/bindings/usb/msm-hsusb.txt
Documentation/devicetree/bindings/usb/renesas_usbhs.txt
Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
Documentation/devicetree/bindings/usb/usb-ehci.txt
Documentation/phy.txt
Documentation/usb/gadget-testing.txt
MAINTAINERS
drivers/phy/Kconfig
drivers/phy/Makefile
drivers/phy/phy-brcmstb-sata.c [new file with mode: 0644]
drivers/phy/phy-core.c
drivers/phy/phy-miphy28lp.c
drivers/phy/phy-miphy365x.c
drivers/phy/phy-pxa-28nm-hsic.c [new file with mode: 0644]
drivers/phy/phy-pxa-28nm-usb2.c [new file with mode: 0644]
drivers/phy/phy-rcar-gen2.c
drivers/phy/phy-sun4i-usb.c
drivers/phy/phy-tusb1210.c [new file with mode: 0644]
drivers/phy/phy-twl4030-usb.c
drivers/phy/ulpi_phy.h [new file with mode: 0644]
drivers/power/twl4030_charger.c
drivers/usb/atm/speedtch.c
drivers/usb/atm/usbatm.c
drivers/usb/atm/xusbatm.c
drivers/usb/chipidea/ci_hdrc_usb2.c
drivers/usb/chipidea/host.c
drivers/usb/chipidea/usbmisc_imx.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-acm.h
drivers/usb/class/usblp.c
drivers/usb/class/usbtmc.c
drivers/usb/common/Makefile
drivers/usb/common/ulpi.c [new file with mode: 0644]
drivers/usb/core/Kconfig
drivers/usb/core/buffer.c
drivers/usb/core/devio.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/debug.h [new file with mode: 0644]
drivers/usb/dwc2/debugfs.c [new file with mode: 0644]
drivers/usb/dwc2/gadget.c
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/hcd.h
drivers/usb/dwc2/hcd_intr.c
drivers/usb/dwc2/hcd_queue.c
drivers/usb/dwc2/platform.c
drivers/usb/dwc3/Kconfig
drivers/usb/dwc3/Makefile
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/platform_data.h
drivers/usb/dwc3/ulpi.c [new file with mode: 0644]
drivers/usb/gadget/epautoconf.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_rndis.c
drivers/usb/gadget/function/rndis.c
drivers/usb/gadget/function/rndis.h
drivers/usb/gadget/function/u_rndis.h
drivers/usb/gadget/function/uvc.h
drivers/usb/gadget/legacy/inode.c
drivers/usb/gadget/udc/atmel_usba_udc.c
drivers/usb/gadget/udc/net2280.c
drivers/usb/gadget/udc/s3c2410_udc.c
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/ehci-dbg.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-platform.c
drivers/usb/host/ehci-tegra.c
drivers/usb/host/ehci.h
drivers/usb/host/fsl-mph-dr-of.c
drivers/usb/host/fusbh200-hcd.c
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/ohci-dbg.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-platform.c
drivers/usb/host/ohci-q.c
drivers/usb/host/ssb-hcd.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/isp1760/isp1760-udc.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/sisusbvga/sisusb_con.c
drivers/usb/misc/uss720.c
drivers/usb/mon/mon_bin.c
drivers/usb/mon/mon_main.c
drivers/usb/mon/mon_stat.c
drivers/usb/musb/am35x.c
drivers/usb/musb/blackfin.c
drivers/usb/musb/cppi_dma.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_dma.h
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/tusb6010.h
drivers/usb/musb/tusb6010_omap.c
drivers/usb/musb/ux500.c
drivers/usb/musb/ux500_dma.c
drivers/usb/phy/Kconfig
drivers/usb/phy/Makefile
drivers/usb/phy/phy-ab8500-usb.c
drivers/usb/phy/phy-msm-usb.c
drivers/usb/phy/phy-rcar-gen2-usb.c [deleted file]
drivers/usb/phy/phy.c
drivers/usb/renesas_usbhs/common.c
drivers/usb/renesas_usbhs/fifo.h
drivers/usb/renesas_usbhs/mod.c
drivers/usb/serial/mos7840.c
drivers/usb/storage/alauda.c
drivers/usb/storage/cypress_atacb.c
drivers/usb/storage/datafab.c
drivers/usb/storage/ene_ub6250.c
drivers/usb/storage/freecom.c
drivers/usb/storage/isd200.c
drivers/usb/storage/jumpshot.c
drivers/usb/storage/karma.c
drivers/usb/storage/onetouch.c
drivers/usb/storage/realtek_cr.c
drivers/usb/storage/scsiglue.c
drivers/usb/storage/scsiglue.h
drivers/usb/storage/sddr09.c
drivers/usb/storage/sddr55.c
drivers/usb/storage/shuttle_usbat.c
drivers/usb/storage/usb.c
drivers/usb/storage/usb.h
include/linux/fsl_devices.h
include/linux/mod_devicetable.h
include/linux/phy/phy-sun4i-usb.h [new file with mode: 0644]
include/linux/phy/phy.h
include/linux/platform_data/usb-rcar-gen2-phy.h [deleted file]
include/linux/ulpi/driver.h [new file with mode: 0644]
include/linux/ulpi/interface.h [new file with mode: 0644]
include/linux/ulpi/regs.h [new file with mode: 0644]
include/linux/usb/hcd.h
include/linux/usb/msm_hsusb.h
include/linux/usb/msm_hsusb_hw.h
include/linux/usb/net2280.h
include/linux/usb/phy.h
include/linux/usb/renesas_usbhs.h
include/linux/usb/ulpi.h
include/linux/usb/usb338x.h
scripts/mod/devicetable-offsets.c
scripts/mod/file2alias.c

diff --git a/Documentation/ABI/testing/sysfs-platform-twl4030-usb b/Documentation/ABI/testing/sysfs-platform-twl4030-usb
new file mode 100644 (file)
index 0000000..512c51b
--- /dev/null
@@ -0,0 +1,8 @@
+What: /sys/bus/platform/devices/*twl4030-usb/vbus
+Description:
+       Read-only status reporting if VBUS (approx 5V)
+       is being supplied by the USB bus.
+
+       Possible values: "on", "off".
+
+       Changes are notified via select/poll.
diff --git a/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt b/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt
new file mode 100644 (file)
index 0000000..7f81ef9
--- /dev/null
@@ -0,0 +1,40 @@
+* Broadcom SATA3 PHY for STB
+
+Required properties:
+- compatible: should be one or more of
+     "brcm,bcm7445-sata-phy"
+     "brcm,phy-sata3"
+- address-cells: should be 1
+- size-cells: should be 0
+- reg: register range for the PHY PCB interface
+- reg-names: should be "phy"
+
+Sub-nodes:
+  Each port's PHY should be represented as a sub-node.
+
+Sub-nodes required properties:
+- reg: the PHY number
+- phy-cells: generic PHY binding; must be 0
+Optional:
+- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port
+
+
+Example:
+
+       sata-phy@f0458100 {
+               compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3";
+               reg = <0xf0458100 0x1e00>, <0xf045804c 0x10>;
+               reg-names = "phy";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               sata-phy@0 {
+                       reg = <0>;
+                       #phy-cells = <0>;
+               };
+
+               sata-phy@1 {
+                       reg = <1>;
+                       #phy-cells = <0>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/phy/pxa1928-usb-phy.txt b/Documentation/devicetree/bindings/phy/pxa1928-usb-phy.txt
new file mode 100644 (file)
index 0000000..660a13c
--- /dev/null
@@ -0,0 +1,18 @@
+* Marvell PXA1928 USB and HSIC PHYs
+
+Required properties:
+- compatible: "marvell,pxa1928-usb-phy" or "marvell,pxa1928-hsic-phy"
+- reg: base address and length of the registers
+- clocks - A single clock. From common clock binding.
+- #phys-cells: should be 0. From commmon phy binding.
+- resets: reference to the reset controller
+
+Example:
+
+       usbphy: phy@7000 {
+               compatible = "marvell,pxa1928-usb-phy";
+               reg = <0x7000 0xe0>;
+               clocks = <&apmu_clocks PXA1928_CLK_USB>;
+               #phy-cells = <0>;
+       };
+
index 00fc52a..d564ba4 100644 (file)
@@ -6,6 +6,7 @@ This file provides information on what the device node for the R-Car generation
 Required properties:
 - compatible: "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC.
              "renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC.
+             "renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC.
 - reg: offset and length of the register block.
 - #address-cells: number of address cells for the USB channel subnodes, must
                  be <1>.
index d5c7062..3b4ea1b 100644 (file)
@@ -1,5 +1,15 @@
 TWL BCI (Battery Charger Interface)
 
+The battery charger needs to interact with the USB phy in order
+to know when charging is permissible, and when there is a connection
+or disconnection.
+
+The choice of phy cannot be configured at a hardware level, so there
+is no value in explicit configuration in device-tree.  Rather
+if there is a sibling of the BCI node which is compatible with
+"ti,twl4030-usb", then that is used to determine when and how
+use USB power for charging.
+
 Required properties:
 - compatible:
   - "ti,twl4030-bci"
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt
deleted file mode 100644 (file)
index 38a5480..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-* Freescale i.MX ci13xxx usb controllers
-
-Required properties:
-- compatible: Should be "fsl,imx27-usb"
-- reg: Should contain registers location and length
-- interrupts: Should contain controller interrupt
-- fsl,usbphy: phandle of usb phy that connects to the port
-
-Recommended properies:
-- phy_type: the type of the phy connected to the core. Should be one
-  of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
-  property the PORTSC register won't be touched
-- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
-
-Optional properties:
-- fsl,usbmisc: phandler of non-core register device, with one argument
-  that indicate usb controller index
-- vbus-supply: regulator for vbus
-- disable-over-current: disable over current detect
-- external-vbus-divider: enables off-chip resistor divider for Vbus
-- maximum-speed: limit the maximum connection speed to "full-speed".
-- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts
-
-Examples:
-usb@02184000 { /* USB OTG */
-       compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
-       reg = <0x02184000 0x200>;
-       interrupts = <0 43 0x04>;
-       fsl,usbphy = <&usbphy1>;
-       fsl,usbmisc = <&usbmisc 0>;
-       disable-over-current;
-       external-vbus-divider;
-       maximum-speed = "full-speed";
-       tpl-support;
-};
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-qcom.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-qcom.txt
deleted file mode 100644 (file)
index f2899b5..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-Qualcomm CI13xxx (Chipidea) USB controllers
-
-Required properties:
-- compatible:   should contain "qcom,ci-hdrc"
-- reg:          offset and length of the register set in the memory map
-- interrupts:   interrupt-specifier for the controller interrupt.
-- usb-phy:      phandle for the PHY device
-- dr_mode:      Should be "peripheral"
-
-Examples:
-       gadget@f9a55000 {
-               compatible = "qcom,ci-hdrc";
-               reg = <0xf9a55000 0x400>;
-               dr_mode = "peripheral";
-               interrupts = <0 134 0>;
-               usb-phy = <&usbphy0>;
-       };
index 27f8b1e..553e2fa 100644 (file)
@@ -1,15 +1,35 @@
 * USB2 ChipIdea USB controller for ci13xxx
 
 Required properties:
-- compatible: should be "chipidea,usb2"
+- compatible: should be one of:
+       "fsl,imx27-usb"
+       "lsi,zevio-usb"
+       "qcom,ci-hdrc"
+       "chipidea,usb2"
 - reg: base address and length of the registers
 - interrupts: interrupt for the USB controller
 
+Recommended properies:
+- phy_type: the type of the phy connected to the core. Should be one
+  of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
+  property the PORTSC register won't be touched.
+- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
+
+Deprecated properties:
+- usb-phy:      phandle for the PHY device. Use "phys" instead.
+- fsl,usbphy: phandle of usb phy that connects to the port. Use "phys" instead.
+
 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
+- maximum-speed: limit the maximum connection speed to "full-speed".
+- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts
+- fsl,usbmisc: (FSL only) phandler of non-core register device, with one
+  argument that indicate usb controller index
+- disable-over-current: (FSL only) disable over current detect
+- external-vbus-divider: (FSL only) enables off-chip resistor divider for Vbus
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt
deleted file mode 100644 (file)
index abbcb2a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-* LSI Zevio USB OTG Controller
-
-Required properties:
-- compatible: Should be "lsi,zevio-usb"
-- reg: Should contain registers location and length
-- interrupts: Should contain controller interrupt
-
-Optional properties:
-- vbus-supply: regulator for vbus
-
-Examples:
-               usb0: usb@b0000000 {
-                       reg = <0xb0000000 0x1000>;
-                       compatible = "lsi,zevio-usb";
-                       interrupts = <8>;
-                       vbus-supply = <&vbus_reg>;
-               };
index f9d7025..01c71b1 100644 (file)
@@ -49,8 +49,7 @@ st_dwc3: dwc3@8f94000 {
        st,syscfg       = <&syscfg_core>;
        resets          = <&powerdown STIH407_USB3_POWERDOWN>,
                          <&softreset STIH407_MIPHY2_SOFTRESET>;
-       reset-names     = "powerdown",
-                         "softreset";
+       reset-names     = "powerdown", "softreset";
        #address-cells  = <1>;
        #size-cells     = <1>;
        pinctrl-names   = "default";
@@ -62,7 +61,7 @@ st_dwc3: dwc3@8f94000 {
                reg             = <0x09900000 0x100000>;
                interrupts      = <GIC_SPI 155 IRQ_TYPE_NONE>;
                dr_mode         = "host";
-               phys-names      = "usb2-phy", "usb3-phy";
-               phys            = <&usb2_picophy2>, <&phy_port2 MIPHY_TYPE_USB>;
+               phy-names       = "usb2-phy", "usb3-phy";
+               phys            = <&usb2_picophy2>, <&phy_port2 PHY_TYPE_USB3>;
        };
 };
index 5cc3643..0815eac 100644 (file)
@@ -38,6 +38,8 @@ Optional properties:
  - 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
+ - snps,hsphy_interface: High-Speed PHY interface selection between "utmi" for
+   UTMI+ and "ulpi" for ULPI when the DWC_USB3_HSPHY_INTERFACE has value 3.
 
 This is usually a subnode to DWC3 glue to which it is connected.
 
index 2826f2a..bd8d9e7 100644 (file)
@@ -69,6 +69,17 @@ Optional properties:
                 (no, min, max) where each value represents either a voltage
                 in microvolts or a value corresponding to voltage corner.
 
+- qcom,manual-pullup: If present, vbus is not routed to USB controller/phy
+                and controller driver therefore enables pull-up explicitly
+                before starting controller using usbcmd run/stop bit.
+
+- extcon:       phandles to external connector devices. First phandle
+                should point to external connector, which provide "USB"
+                cable events, the second should point to external connector
+                device, which provide "USB-HOST" cable events. If one of
+                the external connector devices is not required empty <0>
+                phandle should be specified.
+
 Example HSUSB OTG controller device node:
 
     usb@f9a55000 {
index ddbe304..64a4ca6 100644 (file)
@@ -4,6 +4,7 @@ Required properties:
   - compatible: Must contain one of the following:
        - "renesas,usbhs-r8a7790"
        - "renesas,usbhs-r8a7791"
+       - "renesas,usbhs-r8a7794"
   - reg: Base address and length of the register for the USBHS
   - interrupts: Interrupt specifier for the USBHS
   - clocks: A list of phandle + clock specifier pairs
index 0aee0ad..17327a2 100644 (file)
@@ -30,6 +30,9 @@ TWL4030 USB PHY AND COMPARATOR
  - usb_mode : The mode used by the phy to connect to the controller. "1"
    specifies "ULPI" mode and "2" specifies "CEA2011_3PIN" mode.
 
+If a sibling node is compatible "ti,twl4030-bci", then it will find
+this device and query it for USB power status.
+
 twl4030-usb {
        compatible = "ti,twl4030-usb";
        interrupts = < 10 4 >;
index 0b04fdf..a12d601 100644 (file)
@@ -13,6 +13,8 @@ Optional properties:
  - big-endian-desc : boolean, set this for hcds with big-endian descriptors
  - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
  - needs-reset-on-resume : boolean, set this to force EHCI reset after resume
+ - has-transaction-translator : boolean, set this if EHCI have a Transaction
+                               Translator built into the root hub.
  - clocks : a list of phandle + clock specifier pairs
  - phys : phandle + phy specifier pair
  - phy-names : "usb"
index 371361c..b388c5a 100644 (file)
@@ -76,6 +76,8 @@ struct phy *phy_get(struct device *dev, const char *string);
 struct phy *phy_optional_get(struct device *dev, const char *string);
 struct phy *devm_phy_get(struct device *dev, const char *string);
 struct phy *devm_phy_optional_get(struct device *dev, const char *string);
+struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
+                                    int index);
 
 phy_get, phy_optional_get, devm_phy_get and devm_phy_optional_get can
 be used to get the PHY. In the case of dt boot, the string arguments
@@ -86,7 +88,10 @@ successful PHY get. On driver detach, release function is invoked on
 the the devres data and devres data is freed. phy_optional_get and
 devm_phy_optional_get should be used when the phy is optional. These
 two functions will never return -ENODEV, but instead returns NULL when
-the phy cannot be found.
+the phy cannot be found.Some generic drivers, such as ehci, may use multiple
+phys and for such drivers referencing phy(s) by name(s) does not make sense. In
+this case, devm_of_phy_get_by_index can be used to get a phy reference based on
+the index.
 
 It should be noted that NULL is a valid phy reference. All phy
 consumer calls on the NULL phy become NOPs. That is the release calls,
index f45b2bf..5926780 100644 (file)
@@ -526,8 +526,6 @@ Except for ifname they can be written to until the function is linked to a
 configuration. The ifname is read-only and contains the name of the interface
 which was assigned by the net core, e. g. usb0.
 
-By default there can be only 1 RNDIS interface in the system.
-
 Testing the RNDIS function
 --------------------------
 
@@ -629,7 +627,7 @@ Function-specific configfs interface
 The function name to use when creating the function directory is "uac2".
 The uac2 function provides these attributes in its function directory:
 
-       chmask - capture channel mask
+       c_chmask - capture channel mask
        c_srate - capture sampling rate
        c_ssize - capture sample size (bytes)
        p_chmask - playback channel mask
index df60078..68457d8 100644 (file)
@@ -10712,6 +10712,13 @@ S:     Maintained
 F:     Documentation/video4linux/zr364xx.txt
 F:     drivers/media/usb/zr364xx/
 
+ULPI BUS
+M:     Heikki Krogerus <heikki.krogerus@linux.intel.com>
+L:     linux-usb@vger.kernel.org
+S:     Maintained
+F:     drivers/usb/common/ulpi.c
+F:     include/linux/ulpi/
+
 USER-MODE LINUX (UML)
 M:     Jeff Dike <jdike@addtoit.com>
 M:     Richard Weinberger <richard@nod.at>
index fc9b9f0..487d057 100644 (file)
@@ -54,6 +54,26 @@ config PHY_EXYNOS_MIPI_VIDEO
          Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P
          and EXYNOS SoCs.
 
+config PHY_PXA_28NM_HSIC
+       tristate "Marvell USB HSIC 28nm PHY Driver"
+       select GENERIC_PHY
+       help
+         Enable this to support Marvell USB HSIC PHY driver for Marvell
+         SoC. This driver will do the PHY initialization and shutdown.
+         The PHY driver will be used by Marvell ehci driver.
+
+         To compile this driver as a module, choose M here.
+
+config PHY_PXA_28NM_USB2
+       tristate "Marvell USB 2.0 28nm PHY Driver"
+       select GENERIC_PHY
+       help
+         Enable this to support Marvell USB 2.0 PHY driver for Marvell
+         SoC. This driver will do the PHY initialization and shutdown.
+         The PHY driver will be used by Marvell udc/ehci/otg driver.
+
+         To compile this driver as a module, choose M here.
+
 config PHY_MVEBU_SATA
        def_bool y
        depends on ARCH_DOVE || MACH_DOVE || MACH_KIRKWOOD
@@ -313,4 +333,20 @@ config PHY_QCOM_UFS
        help
          Support for UFS PHY on QCOM chipsets.
 
+config PHY_TUSB1210
+       tristate "TI TUSB1210 ULPI PHY module"
+       depends on USB_ULPI_BUS
+       select GENERIC_PHY
+       help
+         Support for TI TUSB1210 USB ULPI PHY.
+
+config PHY_BRCMSTB_SATA
+       tristate "Broadcom STB SATA PHY driver"
+       depends on ARCH_BRCMSTB
+       depends on OF
+       select GENERIC_PHY
+       help
+         Enable this to support the SATA3 PHY on 28nm Broadcom STB SoCs.
+         Likely useful only with CONFIG_SATA_BRCMSTB enabled.
+
 endmenu
index f126251..42f58e9 100644 (file)
@@ -10,6 +10,8 @@ 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_PXA_28NM_USB2)                += phy-pxa-28nm-usb2.o
+obj-$(CONFIG_PHY_PXA_28NM_HSIC)                += phy-pxa-28nm-hsic.o
 obj-$(CONFIG_PHY_MVEBU_SATA)           += phy-mvebu-sata.o
 obj-$(CONFIG_PHY_MIPHY28LP)            += phy-miphy28lp.o
 obj-$(CONFIG_PHY_MIPHY365X)            += phy-miphy365x.o
@@ -40,3 +42,5 @@ obj-$(CONFIG_PHY_STIH41X_USB)         += phy-stih41x-usb.o
 obj-$(CONFIG_PHY_QCOM_UFS)     += phy-qcom-ufs.o
 obj-$(CONFIG_PHY_QCOM_UFS)     += phy-qcom-ufs-qmp-20nm.o
 obj-$(CONFIG_PHY_QCOM_UFS)     += phy-qcom-ufs-qmp-14nm.o
+obj-$(CONFIG_PHY_TUSB1210)             += phy-tusb1210.o
+obj-$(CONFIG_PHY_BRCMSTB_SATA)         += phy-brcmstb-sata.o
diff --git a/drivers/phy/phy-brcmstb-sata.c b/drivers/phy/phy-brcmstb-sata.c
new file mode 100644 (file)
index 0000000..b7e303d
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Broadcom SATA3 AHCI Controller PHY Driver
+ *
+ * Copyright Â© 2009-2015 Broadcom Corporation
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+#define SATA_MDIO_BANK_OFFSET                          0x23c
+#define SATA_MDIO_REG_OFFSET(ofs)                      ((ofs) * 4)
+#define SATA_MDIO_REG_SPACE_SIZE                       0x1000
+#define SATA_MDIO_REG_LENGTH                           0x1f00
+
+#define MAX_PORTS                                      2
+
+/* Register offset between PHYs in PCB space */
+#define SATA_MDIO_REG_SPACE_SIZE                       0x1000
+
+struct brcm_sata_port {
+       int portnum;
+       struct phy *phy;
+       struct brcm_sata_phy *phy_priv;
+       bool ssc_en;
+};
+
+struct brcm_sata_phy {
+       struct device *dev;
+       void __iomem *phy_base;
+
+       struct brcm_sata_port phys[MAX_PORTS];
+};
+
+enum sata_mdio_phy_regs_28nm {
+       PLL_REG_BANK_0                          = 0x50,
+       PLL_REG_BANK_0_PLLCONTROL_0             = 0x81,
+
+       TXPMD_REG_BANK                          = 0x1a0,
+       TXPMD_CONTROL1                          = 0x81,
+       TXPMD_CONTROL1_TX_SSC_EN_FRC            = BIT(0),
+       TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL        = BIT(1),
+       TXPMD_TX_FREQ_CTRL_CONTROL1             = 0x82,
+       TXPMD_TX_FREQ_CTRL_CONTROL2             = 0x83,
+       TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK   = 0x3ff,
+       TXPMD_TX_FREQ_CTRL_CONTROL3             = 0x84,
+       TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK   = 0x3ff,
+};
+
+static inline void __iomem *brcm_sata_phy_base(struct brcm_sata_port *port)
+{
+       struct brcm_sata_phy *priv = port->phy_priv;
+
+       return priv->phy_base + (port->portnum * SATA_MDIO_REG_SPACE_SIZE);
+}
+
+static void brcm_sata_mdio_wr(void __iomem *addr, u32 bank, u32 ofs,
+                             u32 msk, u32 value)
+{
+       u32 tmp;
+
+       writel(bank, addr + SATA_MDIO_BANK_OFFSET);
+       tmp = readl(addr + SATA_MDIO_REG_OFFSET(ofs));
+       tmp = (tmp & msk) | value;
+       writel(tmp, addr + SATA_MDIO_REG_OFFSET(ofs));
+}
+
+/* These defaults were characterized by H/W group */
+#define FMIN_VAL_DEFAULT       0x3df
+#define FMAX_VAL_DEFAULT       0x3df
+#define FMAX_VAL_SSC           0x83
+
+static void brcm_sata_cfg_ssc_28nm(struct brcm_sata_port *port)
+{
+       void __iomem *base = brcm_sata_phy_base(port);
+       struct brcm_sata_phy *priv = port->phy_priv;
+       u32 tmp;
+
+       /* override the TX spread spectrum setting */
+       tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC;
+       brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp);
+
+       /* set fixed min freq */
+       brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2,
+                         ~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK,
+                         FMIN_VAL_DEFAULT);
+
+       /* set fixed max freq depending on SSC config */
+       if (port->ssc_en) {
+               dev_info(priv->dev, "enabling SSC on port %d\n", port->portnum);
+               tmp = FMAX_VAL_SSC;
+       } else {
+               tmp = FMAX_VAL_DEFAULT;
+       }
+
+       brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3,
+                         ~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp);
+}
+
+static int brcm_sata_phy_init(struct phy *phy)
+{
+       struct brcm_sata_port *port = phy_get_drvdata(phy);
+
+       brcm_sata_cfg_ssc_28nm(port);
+
+       return 0;
+}
+
+static struct phy_ops phy_ops_28nm = {
+       .init           = brcm_sata_phy_init,
+       .owner          = THIS_MODULE,
+};
+
+static const struct of_device_id brcm_sata_phy_of_match[] = {
+       { .compatible   = "brcm,bcm7445-sata-phy" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
+
+static int brcm_sata_phy_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *dn = dev->of_node, *child;
+       struct brcm_sata_phy *priv;
+       struct resource *res;
+       struct phy_provider *provider;
+       int count = 0;
+
+       if (of_get_child_count(dn) == 0)
+               return -ENODEV;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       dev_set_drvdata(dev, priv);
+       priv->dev = dev;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
+       priv->phy_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(priv->phy_base))
+               return PTR_ERR(priv->phy_base);
+
+       for_each_available_child_of_node(dn, child) {
+               unsigned int id;
+               struct brcm_sata_port *port;
+
+               if (of_property_read_u32(child, "reg", &id)) {
+                       dev_err(dev, "missing reg property in node %s\n",
+                                       child->name);
+                       return -EINVAL;
+               }
+
+               if (id >= MAX_PORTS) {
+                       dev_err(dev, "invalid reg: %u\n", id);
+                       return -EINVAL;
+               }
+               if (priv->phys[id].phy) {
+                       dev_err(dev, "already registered port %u\n", id);
+                       return -EINVAL;
+               }
+
+               port = &priv->phys[id];
+               port->portnum = id;
+               port->phy_priv = priv;
+               port->phy = devm_phy_create(dev, child, &phy_ops_28nm);
+               port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc");
+               if (IS_ERR(port->phy)) {
+                       dev_err(dev, "failed to create PHY\n");
+                       return PTR_ERR(port->phy);
+               }
+
+               phy_set_drvdata(port->phy, port);
+               count++;
+       }
+
+       provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+       if (IS_ERR(provider)) {
+               dev_err(dev, "could not register PHY provider\n");
+               return PTR_ERR(provider);
+       }
+
+       dev_info(dev, "registered %d port(s)\n", count);
+
+       return 0;
+}
+
+static struct platform_driver brcm_sata_phy_driver = {
+       .probe  = brcm_sata_phy_probe,
+       .driver = {
+               .of_match_table = brcm_sata_phy_of_match,
+               .name           = "brcmstb-sata-phy",
+       }
+};
+module_platform_driver(brcm_sata_phy_driver);
+
+MODULE_DESCRIPTION("Broadcom STB SATA PHY driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marc Carino");
+MODULE_AUTHOR("Brian Norris");
+MODULE_ALIAS("platform:phy-brcmstb-sata");
index 63bc12d..fc48fac 100644 (file)
@@ -367,13 +367,21 @@ static struct phy *_of_phy_get(struct device_node *np, int index)
        phy_provider = of_phy_provider_lookup(args.np);
        if (IS_ERR(phy_provider) || !try_module_get(phy_provider->owner)) {
                phy = ERR_PTR(-EPROBE_DEFER);
-               goto err0;
+               goto out_unlock;
+       }
+
+       if (!of_device_is_available(args.np)) {
+               dev_warn(phy_provider->dev, "Requested PHY is disabled\n");
+               phy = ERR_PTR(-ENODEV);
+               goto out_put_module;
        }
 
        phy = phy_provider->of_xlate(phy_provider->dev, &args);
+
+out_put_module:
        module_put(phy_provider->owner);
 
-err0:
+out_unlock:
        mutex_unlock(&phy_provider_mutex);
        of_node_put(args.np);
 
@@ -623,6 +631,38 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
 EXPORT_SYMBOL_GPL(devm_of_phy_get);
 
 /**
+ * devm_of_phy_get_by_index() - lookup and obtain a reference to a phy by index.
+ * @dev: device that requests this phy
+ * @np: node containing the phy
+ * @index: index of the phy
+ *
+ * Gets the phy using _of_phy_get(), and associates a device with it using
+ * devres. On driver detach, release function is invoked on the devres data,
+ * then, devres data is freed.
+ *
+ */
+struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
+                                    int index)
+{
+       struct phy **ptr, *phy;
+
+       ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return ERR_PTR(-ENOMEM);
+
+       phy = _of_phy_get(np, index);
+       if (!IS_ERR(phy)) {
+               *ptr = phy;
+               devres_add(dev, ptr);
+       } else {
+               devres_free(ptr);
+       }
+
+       return phy;
+}
+EXPORT_SYMBOL_GPL(devm_of_phy_get_by_index);
+
+/**
  * phy_create() - create a new phy
  * @dev: device that is creating the new phy
  * @node: device node of the phy
@@ -651,16 +691,6 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
                goto free_phy;
        }
 
-       /* phy-supply */
-       phy->pwr = regulator_get_optional(dev, "phy");
-       if (IS_ERR(phy->pwr)) {
-               if (PTR_ERR(phy->pwr) == -EPROBE_DEFER) {
-                       ret = -EPROBE_DEFER;
-                       goto free_ida;
-               }
-               phy->pwr = NULL;
-       }
-
        device_initialize(&phy->dev);
        mutex_init(&phy->mutex);
 
@@ -674,6 +704,16 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
        if (ret)
                goto put_dev;
 
+       /* phy-supply */
+       phy->pwr = regulator_get_optional(&phy->dev, "phy");
+       if (IS_ERR(phy->pwr)) {
+               ret = PTR_ERR(phy->pwr);
+               if (ret == -EPROBE_DEFER)
+                       goto put_dev;
+
+               phy->pwr = NULL;
+       }
+
        ret = device_add(&phy->dev);
        if (ret)
                goto put_dev;
@@ -689,9 +729,6 @@ put_dev:
        put_device(&phy->dev);  /* calls phy_release() which frees resources */
        return ERR_PTR(ret);
 
-free_ida:
-       ida_simple_remove(&phy_ida, phy->id);
-
 free_phy:
        kfree(phy);
        return ERR_PTR(ret);
index c4cc11d..5e257ef 100644 (file)
@@ -367,7 +367,7 @@ static struct miphy28lp_pll_gen pcie_pll_gen[] = {
 
 static inline void miphy28lp_set_reset(struct miphy28lp_phy *miphy_phy)
 {
-       void *base = miphy_phy->base;
+       void __iomem *base = miphy_phy->base;
        u8 val;
 
        /* Putting Macro in reset */
@@ -391,7 +391,7 @@ static inline void miphy28lp_set_reset(struct miphy28lp_phy *miphy_phy)
 static inline void miphy28lp_pll_calibration(struct miphy28lp_phy *miphy_phy,
                struct pll_ratio *pll_ratio)
 {
-       void *base = miphy_phy->base;
+       void __iomem *base = miphy_phy->base;
        u8 val;
 
        /* Applying PLL Settings */
@@ -1107,11 +1107,6 @@ static struct phy *miphy28lp_xlate(struct device *dev,
        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);
index 019c2d7..0ff354d 100644 (file)
@@ -441,8 +441,8 @@ static int miphy365x_init(struct phy *phy)
        return ret;
 }
 
-int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy,
-                      int index)
+static int miphy365x_get_addr(struct device *dev,
+               struct miphy365x_phy *miphy_phy, int index)
 {
        struct device_node *phynode = miphy_phy->phy->dev.of_node;
        const char *name;
@@ -476,11 +476,6 @@ static struct phy *miphy365x_xlate(struct device *dev,
        struct device_node *phynode = args->np;
        int ret, index;
 
-       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);
diff --git a/drivers/phy/phy-pxa-28nm-hsic.c b/drivers/phy/phy-pxa-28nm-hsic.c
new file mode 100644 (file)
index 0000000..234aacf
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2015 Linaro, Ltd.
+ * Rob Herring <robh@kernel.org>
+ *
+ * Based on vendor driver:
+ * Copyright (C) 2013 Marvell Inc.
+ * Author: Chao Xie <xiechao.mail@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+
+#define PHY_28NM_HSIC_CTRL                     0x08
+#define PHY_28NM_HSIC_IMPCAL_CAL               0x18
+#define PHY_28NM_HSIC_PLL_CTRL01               0x1c
+#define PHY_28NM_HSIC_PLL_CTRL2                        0x20
+#define PHY_28NM_HSIC_INT                      0x28
+
+#define PHY_28NM_HSIC_PLL_SELLPFR_SHIFT                26
+#define PHY_28NM_HSIC_PLL_FBDIV_SHIFT          0
+#define PHY_28NM_HSIC_PLL_REFDIV_SHIFT         9
+
+#define PHY_28NM_HSIC_S2H_PU_PLL               BIT(10)
+#define PHY_28NM_HSIC_H2S_PLL_LOCK             BIT(15)
+#define PHY_28NM_HSIC_S2H_HSIC_EN              BIT(7)
+#define S2H_DRV_SE0_4RESUME                    BIT(14)
+#define PHY_28NM_HSIC_H2S_IMPCAL_DONE          BIT(27)
+
+#define PHY_28NM_HSIC_CONNECT_INT              BIT(1)
+#define PHY_28NM_HSIC_HS_READY_INT             BIT(2)
+
+struct mv_hsic_phy {
+       struct phy              *phy;
+       struct platform_device  *pdev;
+       void __iomem            *base;
+       struct clk              *clk;
+};
+
+static bool wait_for_reg(void __iomem *reg, u32 mask, unsigned long timeout)
+{
+       timeout += jiffies;
+       while (time_is_after_eq_jiffies(timeout)) {
+               if ((readl(reg) & mask) == mask)
+                       return true;
+               msleep(1);
+       }
+       return false;
+}
+
+static int mv_hsic_phy_init(struct phy *phy)
+{
+       struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
+       struct platform_device *pdev = mv_phy->pdev;
+       void __iomem *base = mv_phy->base;
+
+       clk_prepare_enable(mv_phy->clk);
+
+       /* Set reference clock */
+       writel(0x1 << PHY_28NM_HSIC_PLL_SELLPFR_SHIFT |
+               0xf0 << PHY_28NM_HSIC_PLL_FBDIV_SHIFT |
+               0xd << PHY_28NM_HSIC_PLL_REFDIV_SHIFT,
+               base + PHY_28NM_HSIC_PLL_CTRL01);
+
+       /* Turn on PLL */
+       writel(readl(base + PHY_28NM_HSIC_PLL_CTRL2) |
+               PHY_28NM_HSIC_S2H_PU_PLL,
+               base + PHY_28NM_HSIC_PLL_CTRL2);
+
+       /* Make sure PHY PLL is locked */
+       if (!wait_for_reg(base + PHY_28NM_HSIC_PLL_CTRL2,
+           PHY_28NM_HSIC_H2S_PLL_LOCK, HZ / 10)) {
+               dev_err(&pdev->dev, "HSIC PHY PLL not locked after 100mS.");
+               clk_disable_unprepare(mv_phy->clk);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int mv_hsic_phy_power_on(struct phy *phy)
+{
+       struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
+       struct platform_device *pdev = mv_phy->pdev;
+       void __iomem *base = mv_phy->base;
+       u32 reg;
+
+       reg = readl(base + PHY_28NM_HSIC_CTRL);
+       /* Avoid SE0 state when resume for some device will take it as reset */
+       reg &= ~S2H_DRV_SE0_4RESUME;
+       reg |= PHY_28NM_HSIC_S2H_HSIC_EN;       /* Enable HSIC PHY */
+       writel(reg, base + PHY_28NM_HSIC_CTRL);
+
+       /*
+        *  Calibration Timing
+        *                 ____________________________
+        *  CAL START   ___|
+        *                         ____________________
+        *  CAL_DONE    ___________|
+        *                 | 400us |
+        */
+
+       /* Make sure PHY Calibration is ready */
+       if (!wait_for_reg(base + PHY_28NM_HSIC_IMPCAL_CAL,
+           PHY_28NM_HSIC_H2S_IMPCAL_DONE, HZ / 10)) {
+               dev_warn(&pdev->dev, "HSIC PHY READY not set after 100mS.");
+               return -ETIMEDOUT;
+       }
+
+       /* Waiting for HSIC connect int*/
+       if (!wait_for_reg(base + PHY_28NM_HSIC_INT,
+           PHY_28NM_HSIC_CONNECT_INT, HZ / 5)) {
+               dev_warn(&pdev->dev, "HSIC wait for connect interrupt timeout.");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int mv_hsic_phy_power_off(struct phy *phy)
+{
+       struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
+       void __iomem *base = mv_phy->base;
+
+       writel(readl(base + PHY_28NM_HSIC_CTRL) & ~PHY_28NM_HSIC_S2H_HSIC_EN,
+               base + PHY_28NM_HSIC_CTRL);
+
+       return 0;
+}
+
+static int mv_hsic_phy_exit(struct phy *phy)
+{
+       struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
+       void __iomem *base = mv_phy->base;
+
+       /* Turn off PLL */
+       writel(readl(base + PHY_28NM_HSIC_PLL_CTRL2) &
+               ~PHY_28NM_HSIC_S2H_PU_PLL,
+               base + PHY_28NM_HSIC_PLL_CTRL2);
+
+       clk_disable_unprepare(mv_phy->clk);
+       return 0;
+}
+
+
+static const struct phy_ops hsic_ops = {
+       .init           = mv_hsic_phy_init,
+       .power_on       = mv_hsic_phy_power_on,
+       .power_off      = mv_hsic_phy_power_off,
+       .exit           = mv_hsic_phy_exit,
+       .owner          = THIS_MODULE,
+};
+
+static int mv_hsic_phy_probe(struct platform_device *pdev)
+{
+       struct phy_provider *phy_provider;
+       struct mv_hsic_phy *mv_phy;
+       struct resource *r;
+
+       mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
+       if (!mv_phy)
+               return -ENOMEM;
+
+       mv_phy->pdev = pdev;
+
+       mv_phy->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(mv_phy->clk)) {
+               dev_err(&pdev->dev, "failed to get clock.\n");
+               return PTR_ERR(mv_phy->clk);
+       }
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mv_phy->base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(mv_phy->base))
+               return PTR_ERR(mv_phy->base);
+
+       mv_phy->phy = devm_phy_create(&pdev->dev, pdev->dev.of_node, &hsic_ops);
+       if (IS_ERR(mv_phy->phy))
+               return PTR_ERR(mv_phy->phy);
+
+       phy_set_drvdata(mv_phy->phy, mv_phy);
+
+       phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
+       return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id mv_hsic_phy_dt_match[] = {
+       { .compatible = "marvell,pxa1928-hsic-phy", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mv_hsic_phy_dt_match);
+
+static struct platform_driver mv_hsic_phy_driver = {
+       .probe  = mv_hsic_phy_probe,
+       .driver = {
+               .name   = "mv-hsic-phy",
+               .of_match_table = of_match_ptr(mv_hsic_phy_dt_match),
+       },
+};
+module_platform_driver(mv_hsic_phy_driver);
+
+MODULE_AUTHOR("Rob Herring <robh@kernel.org>");
+MODULE_DESCRIPTION("Marvell HSIC phy driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-pxa-28nm-usb2.c b/drivers/phy/phy-pxa-28nm-usb2.c
new file mode 100644 (file)
index 0000000..37e9c8c
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2015 Linaro, Ltd.
+ * Rob Herring <robh@kernel.org>
+ *
+ * Based on vendor driver:
+ * Copyright (C) 2013 Marvell Inc.
+ * Author: Chao Xie <xiechao.mail@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+
+/* USB PXA1928 PHY mapping */
+#define PHY_28NM_PLL_REG0                      0x0
+#define PHY_28NM_PLL_REG1                      0x4
+#define PHY_28NM_CAL_REG                       0x8
+#define PHY_28NM_TX_REG0                       0x0c
+#define PHY_28NM_TX_REG1                       0x10
+#define PHY_28NM_RX_REG0                       0x14
+#define PHY_28NM_RX_REG1                       0x18
+#define PHY_28NM_DIG_REG0                      0x1c
+#define PHY_28NM_DIG_REG1                      0x20
+#define PHY_28NM_TEST_REG0                     0x24
+#define PHY_28NM_TEST_REG1                     0x28
+#define PHY_28NM_MOC_REG                       0x2c
+#define PHY_28NM_PHY_RESERVE                   0x30
+#define PHY_28NM_OTG_REG                       0x34
+#define PHY_28NM_CHRG_DET                      0x38
+#define PHY_28NM_CTRL_REG0                     0xc4
+#define PHY_28NM_CTRL_REG1                     0xc8
+#define PHY_28NM_CTRL_REG2                     0xd4
+#define PHY_28NM_CTRL_REG3                     0xdc
+
+/* PHY_28NM_PLL_REG0 */
+#define PHY_28NM_PLL_READY                     BIT(31)
+
+#define PHY_28NM_PLL_SELLPFR_SHIFT             28
+#define PHY_28NM_PLL_SELLPFR_MASK              (0x3 << 28)
+
+#define PHY_28NM_PLL_FBDIV_SHIFT               16
+#define PHY_28NM_PLL_FBDIV_MASK                        (0x1ff << 16)
+
+#define PHY_28NM_PLL_ICP_SHIFT                 8
+#define PHY_28NM_PLL_ICP_MASK                  (0x7 << 8)
+
+#define PHY_28NM_PLL_REFDIV_SHIFT              0
+#define PHY_28NM_PLL_REFDIV_MASK               0x7f
+
+/* PHY_28NM_PLL_REG1 */
+#define PHY_28NM_PLL_PU_BY_REG                 BIT(1)
+
+#define PHY_28NM_PLL_PU_PLL                    BIT(0)
+
+/* PHY_28NM_CAL_REG */
+#define PHY_28NM_PLL_PLLCAL_DONE               BIT(31)
+
+#define PHY_28NM_PLL_IMPCAL_DONE               BIT(23)
+
+#define PHY_28NM_PLL_KVCO_SHIFT                        16
+#define PHY_28NM_PLL_KVCO_MASK                 (0x7 << 16)
+
+#define PHY_28NM_PLL_CAL12_SHIFT               20
+#define PHY_28NM_PLL_CAL12_MASK                        (0x3 << 20)
+
+#define PHY_28NM_IMPCAL_VTH_SHIFT              8
+#define PHY_28NM_IMPCAL_VTH_MASK               (0x7 << 8)
+
+#define PHY_28NM_PLLCAL_START_SHIFT            22
+#define PHY_28NM_IMPCAL_START_SHIFT            13
+
+/* PHY_28NM_TX_REG0 */
+#define PHY_28NM_TX_PU_BY_REG                  BIT(25)
+
+#define PHY_28NM_TX_PU_ANA                     BIT(24)
+
+#define PHY_28NM_TX_AMP_SHIFT                  20
+#define PHY_28NM_TX_AMP_MASK                   (0x7 << 20)
+
+/* PHY_28NM_RX_REG0 */
+#define PHY_28NM_RX_SQ_THRESH_SHIFT            0
+#define PHY_28NM_RX_SQ_THRESH_MASK             (0xf << 0)
+
+/* PHY_28NM_RX_REG1 */
+#define PHY_28NM_RX_SQCAL_DONE                 BIT(31)
+
+/* PHY_28NM_DIG_REG0 */
+#define PHY_28NM_DIG_BITSTAFFING_ERR           BIT(31)
+#define PHY_28NM_DIG_SYNC_ERR                  BIT(30)
+
+#define PHY_28NM_DIG_SQ_FILT_SHIFT             16
+#define PHY_28NM_DIG_SQ_FILT_MASK              (0x7 << 16)
+
+#define PHY_28NM_DIG_SQ_BLK_SHIFT              12
+#define PHY_28NM_DIG_SQ_BLK_MASK               (0x7 << 12)
+
+#define PHY_28NM_DIG_SYNC_NUM_SHIFT            0
+#define PHY_28NM_DIG_SYNC_NUM_MASK             (0x3 << 0)
+
+#define PHY_28NM_PLL_LOCK_BYPASS               BIT(7)
+
+/* PHY_28NM_OTG_REG */
+#define PHY_28NM_OTG_CONTROL_BY_PIN            BIT(5)
+#define PHY_28NM_OTG_PU_OTG                    BIT(4)
+
+#define PHY_28NM_CHGDTC_ENABLE_SWITCH_DM_SHIFT_28 13
+#define PHY_28NM_CHGDTC_ENABLE_SWITCH_DP_SHIFT_28 12
+#define PHY_28NM_CHGDTC_VSRC_CHARGE_SHIFT_28   10
+#define PHY_28NM_CHGDTC_VDAT_CHARGE_SHIFT_28   8
+#define PHY_28NM_CHGDTC_CDP_DM_AUTO_SWITCH_SHIFT_28 7
+#define PHY_28NM_CHGDTC_DP_DM_SWAP_SHIFT_28    6
+#define PHY_28NM_CHGDTC_PU_CHRG_DTC_SHIFT_28   5
+#define PHY_28NM_CHGDTC_PD_EN_SHIFT_28         4
+#define PHY_28NM_CHGDTC_DCP_EN_SHIFT_28                3
+#define PHY_28NM_CHGDTC_CDP_EN_SHIFT_28                2
+#define PHY_28NM_CHGDTC_TESTMON_CHRGDTC_SHIFT_28 0
+
+#define PHY_28NM_CTRL1_CHRG_DTC_OUT_SHIFT_28   4
+#define PHY_28NM_CTRL1_VBUSDTC_OUT_SHIFT_28    2
+
+#define PHY_28NM_CTRL3_OVERWRITE               BIT(0)
+#define PHY_28NM_CTRL3_VBUS_VALID              BIT(4)
+#define PHY_28NM_CTRL3_AVALID                  BIT(5)
+#define PHY_28NM_CTRL3_BVALID                  BIT(6)
+
+struct mv_usb2_phy {
+       struct phy              *phy;
+       struct platform_device  *pdev;
+       void __iomem            *base;
+       struct clk              *clk;
+};
+
+static bool wait_for_reg(void __iomem *reg, u32 mask, unsigned long timeout)
+{
+       timeout += jiffies;
+       while (time_is_after_eq_jiffies(timeout)) {
+               if ((readl(reg) & mask) == mask)
+                       return true;
+               msleep(1);
+       }
+       return false;
+}
+
+static int mv_usb2_phy_28nm_init(struct phy *phy)
+{
+       struct mv_usb2_phy *mv_phy = phy_get_drvdata(phy);
+       struct platform_device *pdev = mv_phy->pdev;
+       void __iomem *base = mv_phy->base;
+       u32 reg;
+       int ret;
+
+       clk_prepare_enable(mv_phy->clk);
+
+       /* PHY_28NM_PLL_REG0 */
+       reg = readl(base + PHY_28NM_PLL_REG0) &
+               ~(PHY_28NM_PLL_SELLPFR_MASK | PHY_28NM_PLL_FBDIV_MASK
+               | PHY_28NM_PLL_ICP_MASK | PHY_28NM_PLL_REFDIV_MASK);
+       writel(reg | (0x1 << PHY_28NM_PLL_SELLPFR_SHIFT
+               | 0xf0 << PHY_28NM_PLL_FBDIV_SHIFT
+               | 0x3 << PHY_28NM_PLL_ICP_SHIFT
+               | 0xd << PHY_28NM_PLL_REFDIV_SHIFT),
+               base + PHY_28NM_PLL_REG0);
+
+       /* PHY_28NM_PLL_REG1 */
+       reg = readl(base + PHY_28NM_PLL_REG1);
+       writel(reg | PHY_28NM_PLL_PU_PLL | PHY_28NM_PLL_PU_BY_REG,
+               base + PHY_28NM_PLL_REG1);
+
+       /* PHY_28NM_TX_REG0 */
+       reg = readl(base + PHY_28NM_TX_REG0) & ~PHY_28NM_TX_AMP_MASK;
+       writel(reg | PHY_28NM_TX_PU_BY_REG | 0x3 << PHY_28NM_TX_AMP_SHIFT |
+               PHY_28NM_TX_PU_ANA,
+               base + PHY_28NM_TX_REG0);
+
+       /* PHY_28NM_RX_REG0 */
+       reg = readl(base + PHY_28NM_RX_REG0) & ~PHY_28NM_RX_SQ_THRESH_MASK;
+       writel(reg | 0xa << PHY_28NM_RX_SQ_THRESH_SHIFT,
+               base + PHY_28NM_RX_REG0);
+
+       /* PHY_28NM_DIG_REG0 */
+       reg = readl(base + PHY_28NM_DIG_REG0) &
+               ~(PHY_28NM_DIG_BITSTAFFING_ERR | PHY_28NM_DIG_SYNC_ERR |
+               PHY_28NM_DIG_SQ_FILT_MASK | PHY_28NM_DIG_SQ_BLK_MASK |
+               PHY_28NM_DIG_SYNC_NUM_MASK);
+       writel(reg | (0x1 << PHY_28NM_DIG_SYNC_NUM_SHIFT |
+               PHY_28NM_PLL_LOCK_BYPASS),
+               base + PHY_28NM_DIG_REG0);
+
+       /* PHY_28NM_OTG_REG */
+       reg = readl(base + PHY_28NM_OTG_REG) | PHY_28NM_OTG_PU_OTG;
+       writel(reg & ~PHY_28NM_OTG_CONTROL_BY_PIN, base + PHY_28NM_OTG_REG);
+
+       /*
+        *  Calibration Timing
+        *                 ____________________________
+        *  CAL START   ___|
+        *                         ____________________
+        *  CAL_DONE    ___________|
+        *                 | 400us |
+        */
+
+       /* Make sure PHY Calibration is ready */
+       if (!wait_for_reg(base + PHY_28NM_CAL_REG,
+           PHY_28NM_PLL_PLLCAL_DONE | PHY_28NM_PLL_IMPCAL_DONE,
+           HZ / 10)) {
+               dev_warn(&pdev->dev, "USB PHY PLL calibrate not done after 100mS.");
+               ret = -ETIMEDOUT;
+               goto err_clk;
+       }
+       if (!wait_for_reg(base + PHY_28NM_RX_REG1,
+           PHY_28NM_RX_SQCAL_DONE, HZ / 10)) {
+               dev_warn(&pdev->dev, "USB PHY RX SQ calibrate not done after 100mS.");
+               ret = -ETIMEDOUT;
+               goto err_clk;
+       }
+       /* Make sure PHY PLL is ready */
+       if (!wait_for_reg(base + PHY_28NM_PLL_REG0,
+           PHY_28NM_PLL_READY, HZ / 10)) {
+               dev_warn(&pdev->dev, "PLL_READY not set after 100mS.");
+               ret = -ETIMEDOUT;
+               goto err_clk;
+       }
+
+       return 0;
+err_clk:
+       clk_disable_unprepare(mv_phy->clk);
+       return ret;
+}
+
+static int mv_usb2_phy_28nm_power_on(struct phy *phy)
+{
+       struct mv_usb2_phy *mv_phy = phy_get_drvdata(phy);
+       void __iomem *base = mv_phy->base;
+
+       writel(readl(base + PHY_28NM_CTRL_REG3) |
+               (PHY_28NM_CTRL3_OVERWRITE | PHY_28NM_CTRL3_VBUS_VALID |
+               PHY_28NM_CTRL3_AVALID | PHY_28NM_CTRL3_BVALID),
+               base + PHY_28NM_CTRL_REG3);
+
+       return 0;
+}
+
+static int mv_usb2_phy_28nm_power_off(struct phy *phy)
+{
+       struct mv_usb2_phy *mv_phy = phy_get_drvdata(phy);
+       void __iomem *base = mv_phy->base;
+
+       writel(readl(base + PHY_28NM_CTRL_REG3) |
+               ~(PHY_28NM_CTRL3_OVERWRITE | PHY_28NM_CTRL3_VBUS_VALID
+               | PHY_28NM_CTRL3_AVALID | PHY_28NM_CTRL3_BVALID),
+               base + PHY_28NM_CTRL_REG3);
+
+       return 0;
+}
+
+static int mv_usb2_phy_28nm_exit(struct phy *phy)
+{
+       struct mv_usb2_phy *mv_phy = phy_get_drvdata(phy);
+       void __iomem *base = mv_phy->base;
+       unsigned int val;
+
+       val = readw(base + PHY_28NM_PLL_REG1);
+       val &= ~PHY_28NM_PLL_PU_PLL;
+       writew(val, base + PHY_28NM_PLL_REG1);
+
+       /* power down PHY Analog part */
+       val = readw(base + PHY_28NM_TX_REG0);
+       val &= ~PHY_28NM_TX_PU_ANA;
+       writew(val, base + PHY_28NM_TX_REG0);
+
+       /* power down PHY OTG part */
+       val = readw(base + PHY_28NM_OTG_REG);
+       val &= ~PHY_28NM_OTG_PU_OTG;
+       writew(val, base + PHY_28NM_OTG_REG);
+
+       clk_disable_unprepare(mv_phy->clk);
+       return 0;
+}
+
+static const struct phy_ops usb_ops = {
+       .init           = mv_usb2_phy_28nm_init,
+       .power_on       = mv_usb2_phy_28nm_power_on,
+       .power_off      = mv_usb2_phy_28nm_power_off,
+       .exit           = mv_usb2_phy_28nm_exit,
+       .owner          = THIS_MODULE,
+};
+
+static int mv_usb2_phy_probe(struct platform_device *pdev)
+{
+       struct phy_provider *phy_provider;
+       struct mv_usb2_phy *mv_phy;
+       struct resource *r;
+
+       mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
+       if (!mv_phy)
+               return -ENOMEM;
+
+       mv_phy->pdev = pdev;
+
+       mv_phy->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(mv_phy->clk)) {
+               dev_err(&pdev->dev, "failed to get clock.\n");
+               return PTR_ERR(mv_phy->clk);
+       }
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mv_phy->base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(mv_phy->base))
+               return PTR_ERR(mv_phy->base);
+
+       mv_phy->phy = devm_phy_create(&pdev->dev, pdev->dev.of_node, &usb_ops);
+       if (IS_ERR(mv_phy->phy))
+               return PTR_ERR(mv_phy->phy);
+
+       phy_set_drvdata(mv_phy->phy, mv_phy);
+
+       phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
+       return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id mv_usbphy_dt_match[] = {
+       { .compatible = "marvell,pxa1928-usb-phy", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mv_usbphy_dt_match);
+
+static struct platform_driver mv_usb2_phy_driver = {
+       .probe  = mv_usb2_phy_probe,
+       .driver = {
+               .name   = "mv-usb2-phy",
+               .of_match_table = of_match_ptr(mv_usbphy_dt_match),
+       },
+};
+module_platform_driver(mv_usb2_phy_driver);
+
+MODULE_AUTHOR("Rob Herring <robh@kernel.org>");
+MODULE_DESCRIPTION("Marvell USB2 phy driver");
+MODULE_LICENSE("GPL v2");
index 97d45f4..39d9b29 100644 (file)
@@ -195,6 +195,7 @@ static struct phy_ops rcar_gen2_phy_ops = {
 static const struct of_device_id rcar_gen2_phy_match_table[] = {
        { .compatible = "renesas,usb-phy-r8a7790" },
        { .compatible = "renesas,usb-phy-r8a7791" },
+       { .compatible = "renesas,usb-phy-r8a7794" },
        { }
 };
 MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table);
@@ -206,11 +207,6 @@ static struct phy *rcar_gen2_phy_xlate(struct device *dev,
        struct device_node *np = args->np;
        int i;
 
-       if (!of_device_is_available(np)) {
-               dev_warn(dev, "Requested PHY is disabled\n");
-               return ERR_PTR(-ENODEV);
-       }
-
        drv = dev_get_drvdata(dev);
        if (!drv)
                return ERR_PTR(-EINVAL);
index a2b08f3..e17c539 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/phy/phy.h>
+#include <linux/phy/phy-sun4i-usb.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
@@ -58,6 +59,7 @@
 #define PHY_OTG_FUNC_EN                        0x28
 #define PHY_VBUS_DET_EN                        0x29
 #define PHY_DISCON_TH_SEL              0x2a
+#define PHY_SQUELCH_DETECT             0x3c
 
 #define MAX_PHYS                       3
 
@@ -204,6 +206,13 @@ static int sun4i_usb_phy_power_off(struct phy *_phy)
        return 0;
 }
 
+void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled)
+{
+       struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+
+       sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2);
+}
+
 static struct phy_ops sun4i_usb_phy_ops = {
        .init           = sun4i_usb_phy_init,
        .exit           = sun4i_usb_phy_exit,
diff --git a/drivers/phy/phy-tusb1210.c b/drivers/phy/phy-tusb1210.c
new file mode 100644 (file)
index 0000000..07efdd3
--- /dev/null
@@ -0,0 +1,153 @@
+/**
+ * tusb1210.c - TUSB1210 USB ULPI PHY driver
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.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/module.h>
+#include <linux/ulpi/driver.h>
+#include <linux/gpio/consumer.h>
+
+#include "ulpi_phy.h"
+
+#define TUSB1210_VENDOR_SPECIFIC2              0x80
+#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT  0
+#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT 4
+#define TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT     6
+
+struct tusb1210 {
+       struct ulpi *ulpi;
+       struct phy *phy;
+       struct gpio_desc *gpio_reset;
+       struct gpio_desc *gpio_cs;
+       u8 vendor_specific2;
+};
+
+static int tusb1210_power_on(struct phy *phy)
+{
+       struct tusb1210 *tusb = phy_get_drvdata(phy);
+
+       gpiod_set_value_cansleep(tusb->gpio_reset, 1);
+       gpiod_set_value_cansleep(tusb->gpio_cs, 1);
+
+       /* Restore the optional eye diagram optimization value */
+       if (tusb->vendor_specific2)
+               ulpi_write(tusb->ulpi, TUSB1210_VENDOR_SPECIFIC2,
+                          tusb->vendor_specific2);
+
+       return 0;
+}
+
+static int tusb1210_power_off(struct phy *phy)
+{
+       struct tusb1210 *tusb = phy_get_drvdata(phy);
+
+       gpiod_set_value_cansleep(tusb->gpio_reset, 0);
+       gpiod_set_value_cansleep(tusb->gpio_cs, 0);
+
+       return 0;
+}
+
+static struct phy_ops phy_ops = {
+       .power_on = tusb1210_power_on,
+       .power_off = tusb1210_power_off,
+       .owner = THIS_MODULE,
+};
+
+static int tusb1210_probe(struct ulpi *ulpi)
+{
+       struct gpio_desc *gpio;
+       struct tusb1210 *tusb;
+       u8 val, reg;
+       int ret;
+
+       tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL);
+       if (!tusb)
+               return -ENOMEM;
+
+       gpio = devm_gpiod_get(&ulpi->dev, "reset");
+       if (!IS_ERR(gpio)) {
+               ret = gpiod_direction_output(gpio, 0);
+               if (ret)
+                       return ret;
+               gpiod_set_value_cansleep(gpio, 1);
+               tusb->gpio_reset = gpio;
+       }
+
+       gpio = devm_gpiod_get(&ulpi->dev, "cs");
+       if (!IS_ERR(gpio)) {
+               ret = gpiod_direction_output(gpio, 0);
+               if (ret)
+                       return ret;
+               gpiod_set_value_cansleep(gpio, 1);
+               tusb->gpio_cs = gpio;
+       }
+
+       /*
+        * VENDOR_SPECIFIC2 register in TUSB1210 can be used for configuring eye
+        * diagram optimization and DP/DM swap.
+        */
+
+       /* High speed output drive strength configuration */
+       device_property_read_u8(&ulpi->dev, "ihstx", &val);
+       reg = val << TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT;
+
+       /* High speed output impedance configuration */
+       device_property_read_u8(&ulpi->dev, "zhsdrv", &val);
+       reg |= val << TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT;
+
+       /* DP/DM swap control */
+       device_property_read_u8(&ulpi->dev, "datapolarity", &val);
+       reg |= val << TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT;
+
+       if (reg) {
+               ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg);
+               tusb->vendor_specific2 = reg;
+       }
+
+       tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
+       if (IS_ERR(tusb->phy))
+               return PTR_ERR(tusb->phy);
+
+       tusb->ulpi = ulpi;
+
+       phy_set_drvdata(tusb->phy, tusb);
+       ulpi_set_drvdata(ulpi, tusb);
+       return 0;
+}
+
+static void tusb1210_remove(struct ulpi *ulpi)
+{
+       struct tusb1210 *tusb = ulpi_get_drvdata(ulpi);
+
+       ulpi_phy_destroy(ulpi, tusb->phy);
+}
+
+#define TI_VENDOR_ID 0x0451
+
+static const struct ulpi_device_id tusb1210_ulpi_id[] = {
+       { TI_VENDOR_ID, 0x1507, },
+       { },
+};
+MODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id);
+
+static struct ulpi_driver tusb1210_driver = {
+       .id_table = tusb1210_ulpi_id,
+       .probe = tusb1210_probe,
+       .remove = tusb1210_remove,
+       .driver = {
+               .name = "tusb1210",
+               .owner = THIS_MODULE,
+       },
+};
+
+module_ulpi_driver(tusb1210_driver);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TUSB1210 ULPI PHY driver");
index bc42d6a..3a707dd 100644 (file)
 #define PMBR1                          0x0D
 #define GPIO_USB_4PIN_ULPI_2430C       (3 << 0)
 
+/*
+ * If VBUS is valid or ID is ground, then we know a
+ * cable is present and we need to be runtime-enabled
+ */
+static inline bool cable_present(enum omap_musb_vbus_id_status stat)
+{
+       return stat == OMAP_MUSB_VBUS_VALID ||
+               stat == OMAP_MUSB_ID_GROUND;
+}
+
 struct twl4030_usb {
        struct usb_phy          phy;
        struct device           *dev;
@@ -386,8 +396,6 @@ static int twl4030_usb_runtime_suspend(struct device *dev)
        struct twl4030_usb *twl = dev_get_drvdata(dev);
 
        dev_dbg(twl->dev, "%s\n", __func__);
-       if (pm_runtime_suspended(dev))
-               return 0;
 
        __twl4030_phy_power(twl, 0);
        regulator_disable(twl->usb1v5);
@@ -403,8 +411,6 @@ static int twl4030_usb_runtime_resume(struct device *dev)
        int res;
 
        dev_dbg(twl->dev, "%s\n", __func__);
-       if (pm_runtime_active(dev))
-               return 0;
 
        res = regulator_enable(twl->usb3v1);
        if (res)
@@ -536,8 +542,10 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 
        mutex_lock(&twl->lock);
        if (status >= 0 && status != twl->linkstat) {
+               status_changed =
+                       cable_present(twl->linkstat) !=
+                       cable_present(status);
                twl->linkstat = status;
-               status_changed = true;
        }
        mutex_unlock(&twl->lock);
 
@@ -553,15 +561,11 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
                 * USB_LINK_VBUS state.  musb_hdrc won't care until it
                 * starts to handle softconnect right.
                 */
-               if ((status == OMAP_MUSB_VBUS_VALID) ||
-                   (status == OMAP_MUSB_ID_GROUND)) {
-                       if (pm_runtime_suspended(twl->dev))
-                               pm_runtime_get_sync(twl->dev);
+               if (cable_present(status)) {
+                       pm_runtime_get_sync(twl->dev);
                } else {
-                       if (pm_runtime_active(twl->dev)) {
-                               pm_runtime_mark_last_busy(twl->dev);
-                               pm_runtime_put_autosuspend(twl->dev);
-                       }
+                       pm_runtime_mark_last_busy(twl->dev);
+                       pm_runtime_put_autosuspend(twl->dev);
                }
                omap_musb_mailbox(status);
        }
@@ -711,7 +715,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
        pm_runtime_enable(&pdev->dev);
-       pm_runtime_get_sync(&pdev->dev);
 
        /* Our job is to use irqs and status from the power module
         * to keep the transceiver disabled when nothing's connected.
@@ -767,6 +770,9 @@ static int twl4030_usb_remove(struct platform_device *pdev)
 
        /* disable complete OTG block */
        twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
+
+       if (cable_present(twl->linkstat))
+               pm_runtime_put_noidle(twl->dev);
        pm_runtime_mark_last_busy(twl->dev);
        pm_runtime_put(twl->dev);
 
diff --git a/drivers/phy/ulpi_phy.h b/drivers/phy/ulpi_phy.h
new file mode 100644 (file)
index 0000000..ac49fb6
--- /dev/null
@@ -0,0 +1,31 @@
+#include <linux/phy/phy.h>
+
+/**
+ * Helper that registers PHY for a ULPI device and adds a lookup for binding it
+ * and it's controller, which is always the parent.
+ */
+static inline struct phy
+*ulpi_phy_create(struct ulpi *ulpi, struct phy_ops *ops)
+{
+       struct phy *phy;
+       int ret;
+
+       phy = phy_create(&ulpi->dev, NULL, ops);
+       if (IS_ERR(phy))
+               return phy;
+
+       ret = phy_create_lookup(phy, "usb2-phy", dev_name(ulpi->dev.parent));
+       if (ret) {
+               phy_destroy(phy);
+               return ERR_PTR(ret);
+       }
+
+       return phy;
+}
+
+/* Remove a PHY that was created with ulpi_phy_create() and it's lookup. */
+static inline void ulpi_phy_destroy(struct ulpi *ulpi, struct phy *phy)
+{
+       phy_remove_lookup(phy, "usb2-phy", dev_name(ulpi->dev.parent));
+       phy_destroy(phy);
+}
index 02a522c..022b891 100644 (file)
@@ -638,10 +638,15 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
 
        INIT_WORK(&bci->work, twl4030_bci_usb_work);
 
-       bci->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
-       if (!IS_ERR_OR_NULL(bci->transceiver)) {
-               bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
-               usb_register_notifier(bci->transceiver, &bci->usb_nb);
+       bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
+       if (bci->dev->of_node) {
+               struct device_node *phynode;
+
+               phynode = of_find_compatible_node(bci->dev->of_node->parent,
+                                                 NULL, "ti,twl4030-usb");
+               if (phynode)
+                       bci->transceiver = devm_usb_get_phy_by_node(
+                               bci->dev, phynode, &bci->usb_nb);
        }
 
        /* Enable interrupts now. */
@@ -671,10 +676,6 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
        return 0;
 
 fail_unmask_interrupts:
-       if (!IS_ERR_OR_NULL(bci->transceiver)) {
-               usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
-               usb_put_phy(bci->transceiver);
-       }
        free_irq(bci->irq_bci, bci);
 fail_bci_irq:
        free_irq(bci->irq_chg, bci);
@@ -703,10 +704,6 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
        twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
                         TWL4030_INTERRUPTS_BCIIMR2A);
 
-       if (!IS_ERR_OR_NULL(bci->transceiver)) {
-               usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
-               usb_put_phy(bci->transceiver);
-       }
        free_irq(bci->irq_bci, bci);
        free_irq(bci->irq_chg, bci);
        power_supply_unregister(bci->usb);
index 0dc8c06..0270d13 100644 (file)
@@ -255,7 +255,8 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
 
        usb_dbg(usbatm, "%s entered\n", __func__);
 
-       if (!(buffer = (unsigned char *)__get_free_page(GFP_KERNEL))) {
+       buffer = (unsigned char *)__get_free_page(GFP_KERNEL);
+       if (!buffer) {
                ret = -ENOMEM;
                usb_dbg(usbatm, "%s: no memory for buffer!\n", __func__);
                goto out;
@@ -638,7 +639,8 @@ static void speedtch_handle_int(struct urb *int_urb)
                goto fail;
        }
 
-       if ((int_urb = instance->int_urb)) {
+       int_urb = instance->int_urb;
+       if (int_urb) {
                ret = usb_submit_urb(int_urb, GFP_ATOMIC);
                schedule_work(&instance->status_check_work);
                if (ret < 0) {
@@ -650,7 +652,8 @@ static void speedtch_handle_int(struct urb *int_urb)
        return;
 
 fail:
-       if ((int_urb = instance->int_urb))
+       int_urb = instance->int_urb;
+       if (int_urb)
                mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY));
 }
 
@@ -759,11 +762,13 @@ static void speedtch_release_interfaces(struct usb_device *usb_dev,
        struct usb_interface *cur_intf;
        int i;
 
-       for (i = 0; i < num_interfaces; i++)
-               if ((cur_intf = usb_ifnum_to_if(usb_dev, i))) {
+       for (i = 0; i < num_interfaces; i++) {
+               cur_intf = usb_ifnum_to_if(usb_dev, i);
+               if (cur_intf) {
                        usb_set_intfdata(cur_intf, NULL);
                        usb_driver_release_interface(&speedtch_usb_driver, cur_intf);
                }
+       }
 }
 
 static int speedtch_bind(struct usbatm_data *usbatm,
@@ -787,7 +792,8 @@ static int speedtch_bind(struct usbatm_data *usbatm,
                return -ENODEV;
        }
 
-       if (!(data_intf = usb_ifnum_to_if(usb_dev, INTERFACE_DATA))) {
+       data_intf = usb_ifnum_to_if(usb_dev, INTERFACE_DATA);
+       if (!data_intf) {
                usb_err(usbatm, "%s: data interface not found!\n", __func__);
                return -ENODEV;
        }
index dada014..db322d9 100644 (file)
@@ -382,7 +382,8 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char
                     "%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)",
                     __func__, length, pdu_length, vcc);
 
-               if (!(skb = dev_alloc_skb(length))) {
+               skb = dev_alloc_skb(length);
+               if (!skb) {
                        if (printk_ratelimit())
                                atm_err(instance, "%s: no memory for skb (length: %u)!\n",
                                        __func__, length);
@@ -816,7 +817,8 @@ static int usbatm_atm_open(struct atm_vcc *vcc)
                goto fail;
        }
 
-       if (!(new = kzalloc(sizeof(struct usbatm_vcc_data), GFP_KERNEL))) {
+       new = kzalloc(sizeof(struct usbatm_vcc_data), GFP_KERNEL);
+       if (!new) {
                atm_err(instance, "%s: no memory for vcc_data!\n", __func__);
                ret = -ENOMEM;
                goto fail;
index b3b1bb7..a87597f 100644 (file)
@@ -73,7 +73,8 @@ static int xusbatm_capture_intf(struct usbatm_data *usbatm, struct usb_device *u
                usb_err(usbatm, "%s: failed to claim interface %2d (%d)!\n", __func__, ifnum, ret);
                return ret;
        }
-       if ((ret = usb_set_interface(usb_dev, ifnum, altsetting))) {
+       ret = usb_set_interface(usb_dev, ifnum, altsetting);
+       if (ret) {
                usb_err(usbatm, "%s: altsetting %2d for interface %2d failed (%d)!\n", __func__, altsetting, ifnum, ret);
                return ret;
        }
@@ -128,7 +129,8 @@ static int xusbatm_bind(struct usbatm_data *usbatm,
                        rx_intf->altsetting->desc.bInterfaceNumber,
                        tx_intf->altsetting->desc.bInterfaceNumber);
 
-       if ((ret = xusbatm_capture_intf(usbatm, usb_dev, rx_intf, rx_alt, rx_intf != intf)))
+       ret = xusbatm_capture_intf(usbatm, usb_dev, rx_intf, rx_alt, rx_intf != intf);
+       if (ret)
                return ret;
 
        if ((tx_intf != rx_intf) && (ret = xusbatm_capture_intf(usbatm, usb_dev, tx_intf, tx_alt, tx_intf != intf))) {
index 45844c9..9eae1a1 100644 (file)
@@ -25,7 +25,7 @@ struct ci_hdrc_usb2_priv {
        struct clk              *clk;
 };
 
-static struct ci_hdrc_platform_data ci_default_pdata = {
+static const struct ci_hdrc_platform_data ci_default_pdata = {
        .capoffset      = DEF_CAPOFFSET,
        .flags          = CI_HDRC_DISABLE_STREAMING,
 };
@@ -37,8 +37,10 @@ static int ci_hdrc_usb2_probe(struct platform_device *pdev)
        struct ci_hdrc_platform_data *ci_pdata = dev_get_platdata(dev);
        int ret;
 
-       if (!ci_pdata)
-               ci_pdata = &ci_default_pdata;
+       if (!ci_pdata) {
+               ci_pdata = devm_kmalloc(dev, sizeof(*ci_pdata), GFP_KERNEL);
+               *ci_pdata = ci_default_pdata;   /* struct copy */
+       }
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
index 21fe1a3..6cf87b8 100644 (file)
@@ -37,12 +37,14 @@ static int (*orig_bus_suspend)(struct usb_hcd *hcd);
 
 struct ehci_ci_priv {
        struct regulator *reg_vbus;
+       struct ci_hdrc *ci;
 };
 
 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 ci_hdrc *ci = priv->ci;
        struct device *dev = hcd->self.controller;
        int ret = 0;
        int port = HCS_N_PORTS(ehci->hcs_params);
@@ -64,6 +66,15 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
                        return ret;
                }
        }
+
+       if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) {
+               /*
+                * Marvell 28nm HSIC PHY requires forcing the port to HS mode.
+                * As HSIC is always HS, this should be safe for others.
+                */
+               hw_port_test_set(ci, 5);
+               hw_port_test_set(ci, 0);
+       }
        return 0;
 };
 
@@ -112,6 +123,7 @@ static int host_start(struct ci_hdrc *ci)
 
        priv = (struct ehci_ci_priv *)ehci->priv;
        priv->reg_vbus = NULL;
+       priv->ci = ci;
 
        if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) {
                if (ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON) {
index 140945c..3cefd49 100644 (file)
@@ -160,7 +160,7 @@ static int usbmisc_imx27_init(struct imx_usbmisc_data *data)
                break;
        default:
                return -EINVAL;
-       };
+       }
 
        spin_lock_irqsave(&usbmisc->lock, flags);
        if (data->disable_oc)
index 5c8f581..519a77b 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/usb/cdc.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
+#include <linux/idr.h>
 #include <linux/list.h>
 
 #include "cdc-acm.h"
 
 static struct usb_driver acm_driver;
 static struct tty_driver *acm_tty_driver;
-static struct acm *acm_table[ACM_TTY_MINORS];
 
-static DEFINE_MUTEX(acm_table_lock);
+static DEFINE_IDR(acm_minors);
+static DEFINE_MUTEX(acm_minors_lock);
 
 static void acm_tty_set_termios(struct tty_struct *tty,
                                struct ktermios *termios_old);
 
 /*
- * acm_table accessors
+ * acm_minors accessors
  */
 
 /*
- * Look up an ACM structure by index. If found and not disconnected, increment
+ * Look up an ACM structure by minor. If found and not disconnected, increment
  * its refcount and return it with its mutex held.
  */
-static struct acm *acm_get_by_index(unsigned index)
+static struct acm *acm_get_by_minor(unsigned int minor)
 {
        struct acm *acm;
 
-       mutex_lock(&acm_table_lock);
-       acm = acm_table[index];
+       mutex_lock(&acm_minors_lock);
+       acm = idr_find(&acm_minors, minor);
        if (acm) {
                mutex_lock(&acm->mutex);
                if (acm->disconnected) {
@@ -87,7 +88,7 @@ static struct acm *acm_get_by_index(unsigned index)
                        mutex_unlock(&acm->mutex);
                }
        }
-       mutex_unlock(&acm_table_lock);
+       mutex_unlock(&acm_minors_lock);
        return acm;
 }
 
@@ -98,14 +99,9 @@ static int acm_alloc_minor(struct acm *acm)
 {
        int minor;
 
-       mutex_lock(&acm_table_lock);
-       for (minor = 0; minor < ACM_TTY_MINORS; minor++) {
-               if (!acm_table[minor]) {
-                       acm_table[minor] = acm;
-                       break;
-               }
-       }
-       mutex_unlock(&acm_table_lock);
+       mutex_lock(&acm_minors_lock);
+       minor = idr_alloc(&acm_minors, acm, 0, ACM_TTY_MINORS, GFP_KERNEL);
+       mutex_unlock(&acm_minors_lock);
 
        return minor;
 }
@@ -113,9 +109,9 @@ static int acm_alloc_minor(struct acm *acm)
 /* Release the minor number associated with 'acm'.  */
 static void acm_release_minor(struct acm *acm)
 {
-       mutex_lock(&acm_table_lock);
-       acm_table[acm->minor] = NULL;
-       mutex_unlock(&acm_table_lock);
+       mutex_lock(&acm_minors_lock);
+       idr_remove(&acm_minors, acm->minor);
+       mutex_unlock(&acm_minors_lock);
 }
 
 /*
@@ -497,7 +493,7 @@ static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 
        dev_dbg(tty->dev, "%s\n", __func__);
 
-       acm = acm_get_by_index(tty->index);
+       acm = acm_get_by_minor(tty->index);
        if (!acm)
                return -ENODEV;
 
@@ -1267,12 +1263,9 @@ skip_normal_probe:
                                                != CDC_DATA_INTERFACE_TYPE) {
                if (control_interface->cur_altsetting->desc.bInterfaceClass
                                                == CDC_DATA_INTERFACE_TYPE) {
-                       struct usb_interface *t;
                        dev_dbg(&intf->dev,
                                "Your device has switched interfaces.\n");
-                       t = control_interface;
-                       control_interface = data_interface;
-                       data_interface = t;
+                       swap(control_interface, data_interface);
                } else {
                        return -EINVAL;
                }
@@ -1301,12 +1294,9 @@ skip_normal_probe:
        /* workaround for switched endpoints */
        if (!usb_endpoint_dir_in(epread)) {
                /* descriptors are swapped */
-               struct usb_endpoint_descriptor *t;
                dev_dbg(&intf->dev,
                        "The data interface has switched endpoints\n");
-               t = epread;
-               epread = epwrite;
-               epwrite = t;
+               swap(epread, epwrite);
        }
 made_compressed_probe:
        dev_dbg(&intf->dev, "interfaces are valid\n");
@@ -1316,7 +1306,7 @@ made_compressed_probe:
                goto alloc_fail;
 
        minor = acm_alloc_minor(acm);
-       if (minor == ACM_TTY_MINORS) {
+       if (minor < 0) {
                dev_err(&intf->dev, "no more free acm devices\n");
                kfree(acm);
                return -ENODEV;
@@ -1477,6 +1467,11 @@ skip_countries:
                goto alloc_fail8;
        }
 
+       if (quirks & CLEAR_HALT_CONDITIONS) {
+               usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress));
+               usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress));
+       }
+
        return 0;
 alloc_fail8:
        if (acm->country_codes) {
@@ -1756,6 +1751,10 @@ static const struct usb_device_id acm_ids[] = {
        .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
        },
 
+       { USB_DEVICE(0x2912, 0x0001), /* ATOL FPrint */
+       .driver_info = CLEAR_HALT_CONDITIONS,
+       },
+
        /* Nokia S60 phones expose two ACM channels. The first is
         * a modem and is picked up by the standard AT-command
         * information below. The second is 'vendor-specific' but
index ffeb3c8..dd9af38 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 #define ACM_TTY_MAJOR          166
-#define ACM_TTY_MINORS         32
+#define ACM_TTY_MINORS         256
 
 /*
  * Requests.
@@ -133,3 +133,4 @@ struct acm {
 #define NO_DATA_INTERFACE              BIT(4)
 #define IGNORE_DEVICE                  BIT(5)
 #define QUIRK_CONTROL_LINE_STATE       BIT(6)
+#define CLEAR_HALT_CONDITIONS          BIT(7)
index 0924ee4..f38e875 100644 (file)
@@ -660,7 +660,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                switch (cmd) {
 
                case LPGETSTATUS:
-                       if ((retval = usblp_read_status(usblp, usblp->statusbuf))) {
+                       retval = usblp_read_status(usblp, usblp->statusbuf);
+                       if (retval) {
                                printk_ratelimited(KERN_ERR "usblp%d:"
                                            "failed reading printer status (%d)\n",
                                            usblp->minor, retval);
@@ -693,9 +694,11 @@ static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
        struct urb *urb;
        char *writebuf;
 
-       if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL)
+       writebuf = kmalloc(transfer_length, GFP_KERNEL);
+       if (writebuf == NULL)
                return NULL;
-       if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
+       urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (urb == NULL) {
                kfree(writebuf);
                return NULL;
        }
@@ -732,7 +735,8 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
                        transfer_length = USBLP_BUF_SIZE;
 
                rv = -ENOMEM;
-               if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL)
+               writeurb = usblp_new_writeurb(usblp, transfer_length);
+               if (writeurb == NULL)
                        goto raise_urb;
                usb_anchor_urb(writeurb, &usblp->urbs);
 
@@ -980,7 +984,8 @@ static int usblp_submit_read(struct usblp *usblp)
        int rc;
 
        rc = -ENOMEM;
-       if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
+       urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (urb == NULL)
                goto raise_urb;
 
        usb_fill_bulk_urb(urb, usblp->dev,
index 960bc08..7a11a82 100644 (file)
@@ -109,6 +109,7 @@ struct usbtmc_ID_rigol_quirk {
 
 static const struct usbtmc_ID_rigol_quirk usbtmc_id_quirk[] = {
        { 0x1ab1, 0x0588 },
+       { 0x1ab1, 0x04b0 },
        { 0, 0 }
 };
 
index ca2f8bd..6bbb3ec 100644 (file)
@@ -7,3 +7,4 @@ usb-common-y                      += common.o
 usb-common-$(CONFIG_USB_LED_TRIG) += led.o
 
 obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o
+obj-$(CONFIG_USB_ULPI_BUS)     += ulpi.o
diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c
new file mode 100644 (file)
index 0000000..0e6f968
--- /dev/null
@@ -0,0 +1,255 @@
+/**
+ * ulpi.c - USB ULPI PHY bus
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.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/ulpi/interface.h>
+#include <linux/ulpi/driver.h>
+#include <linux/ulpi/regs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+
+/* -------------------------------------------------------------------------- */
+
+int ulpi_read(struct ulpi *ulpi, u8 addr)
+{
+       return ulpi->ops->read(ulpi->ops, addr);
+}
+EXPORT_SYMBOL_GPL(ulpi_read);
+
+int ulpi_write(struct ulpi *ulpi, u8 addr, u8 val)
+{
+       return ulpi->ops->write(ulpi->ops, addr, val);
+}
+EXPORT_SYMBOL_GPL(ulpi_write);
+
+/* -------------------------------------------------------------------------- */
+
+static int ulpi_match(struct device *dev, struct device_driver *driver)
+{
+       struct ulpi_driver *drv = to_ulpi_driver(driver);
+       struct ulpi *ulpi = to_ulpi_dev(dev);
+       const struct ulpi_device_id *id;
+
+       for (id = drv->id_table; id->vendor; id++)
+               if (id->vendor == ulpi->id.vendor &&
+                   id->product == ulpi->id.product)
+                       return 1;
+
+       return 0;
+}
+
+static int ulpi_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct ulpi *ulpi = to_ulpi_dev(dev);
+
+       if (add_uevent_var(env, "MODALIAS=ulpi:v%04xp%04x",
+                          ulpi->id.vendor, ulpi->id.product))
+               return -ENOMEM;
+       return 0;
+}
+
+static int ulpi_probe(struct device *dev)
+{
+       struct ulpi_driver *drv = to_ulpi_driver(dev->driver);
+
+       return drv->probe(to_ulpi_dev(dev));
+}
+
+static int ulpi_remove(struct device *dev)
+{
+       struct ulpi_driver *drv = to_ulpi_driver(dev->driver);
+
+       if (drv->remove)
+               drv->remove(to_ulpi_dev(dev));
+
+       return 0;
+}
+
+static struct bus_type ulpi_bus = {
+       .name = "ulpi",
+       .match = ulpi_match,
+       .uevent = ulpi_uevent,
+       .probe = ulpi_probe,
+       .remove = ulpi_remove,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct ulpi *ulpi = to_ulpi_dev(dev);
+
+       return sprintf(buf, "ulpi:v%04xp%04x\n",
+                      ulpi->id.vendor, ulpi->id.product);
+}
+static DEVICE_ATTR_RO(modalias);
+
+static struct attribute *ulpi_dev_attrs[] = {
+       &dev_attr_modalias.attr,
+       NULL
+};
+
+static struct attribute_group ulpi_dev_attr_group = {
+       .attrs = ulpi_dev_attrs,
+};
+
+static const struct attribute_group *ulpi_dev_attr_groups[] = {
+       &ulpi_dev_attr_group,
+       NULL
+};
+
+static void ulpi_dev_release(struct device *dev)
+{
+       kfree(to_ulpi_dev(dev));
+}
+
+static struct device_type ulpi_dev_type = {
+       .name = "ulpi_device",
+       .groups = ulpi_dev_attr_groups,
+       .release = ulpi_dev_release,
+};
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * ulpi_register_driver - register a driver with the ULPI bus
+ * @drv: driver being registered
+ *
+ * Registers a driver with the ULPI bus.
+ */
+int ulpi_register_driver(struct ulpi_driver *drv)
+{
+       if (!drv->probe)
+               return -EINVAL;
+
+       drv->driver.bus = &ulpi_bus;
+
+       return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(ulpi_register_driver);
+
+/**
+ * ulpi_unregister_driver - unregister a driver with the ULPI bus
+ * @drv: driver to unregister
+ *
+ * Unregisters a driver with the ULPI bus.
+ */
+void ulpi_unregister_driver(struct ulpi_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(ulpi_unregister_driver);
+
+/* -------------------------------------------------------------------------- */
+
+static int ulpi_register(struct device *dev, struct ulpi *ulpi)
+{
+       int ret;
+
+       /* Test the interface */
+       ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa);
+       if (ret < 0)
+               return ret;
+
+       ret = ulpi_read(ulpi, ULPI_SCRATCH);
+       if (ret < 0)
+               return ret;
+
+       if (ret != 0xaa)
+               return -ENODEV;
+
+       ulpi->id.vendor = ulpi_read(ulpi, ULPI_VENDOR_ID_LOW);
+       ulpi->id.vendor |= ulpi_read(ulpi, ULPI_VENDOR_ID_HIGH) << 8;
+
+       ulpi->id.product = ulpi_read(ulpi, ULPI_PRODUCT_ID_LOW);
+       ulpi->id.product |= ulpi_read(ulpi, ULPI_PRODUCT_ID_HIGH) << 8;
+
+       ulpi->dev.parent = dev;
+       ulpi->dev.bus = &ulpi_bus;
+       ulpi->dev.type = &ulpi_dev_type;
+       dev_set_name(&ulpi->dev, "%s.ulpi", dev_name(dev));
+
+       ACPI_COMPANION_SET(&ulpi->dev, ACPI_COMPANION(dev));
+
+       request_module("ulpi:v%04xp%04x", ulpi->id.vendor, ulpi->id.product);
+
+       ret = device_register(&ulpi->dev);
+       if (ret)
+               return ret;
+
+       dev_dbg(&ulpi->dev, "registered ULPI PHY: vendor %04x, product %04x\n",
+               ulpi->id.vendor, ulpi->id.product);
+
+       return 0;
+}
+
+/**
+ * ulpi_register_interface - instantiate new ULPI device
+ * @dev: USB controller's device interface
+ * @ops: ULPI register access
+ *
+ * Allocates and registers a ULPI device and an interface for it. Called from
+ * the USB controller that provides the ULPI interface.
+ */
+struct ulpi *ulpi_register_interface(struct device *dev, struct ulpi_ops *ops)
+{
+       struct ulpi *ulpi;
+       int ret;
+
+       ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL);
+       if (!ulpi)
+               return ERR_PTR(-ENOMEM);
+
+       ulpi->ops = ops;
+       ops->dev = dev;
+
+       ret = ulpi_register(dev, ulpi);
+       if (ret) {
+               kfree(ulpi);
+               return ERR_PTR(ret);
+       }
+
+       return ulpi;
+}
+EXPORT_SYMBOL_GPL(ulpi_register_interface);
+
+/**
+ * ulpi_unregister_interface - unregister ULPI interface
+ * @intrf: struct ulpi_interface
+ *
+ * Unregisters a ULPI device and it's interface that was created with
+ * ulpi_create_interface().
+ */
+void ulpi_unregister_interface(struct ulpi *ulpi)
+{
+       device_unregister(&ulpi->dev);
+}
+EXPORT_SYMBOL_GPL(ulpi_unregister_interface);
+
+/* -------------------------------------------------------------------------- */
+
+static int __init ulpi_init(void)
+{
+       return bus_register(&ulpi_bus);
+}
+module_init(ulpi_init);
+
+static void __exit ulpi_exit(void)
+{
+       bus_unregister(&ulpi_bus);
+}
+module_exit(ulpi_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("USB ULPI PHY bus");
index cc0ced0..a99c89e 100644 (file)
@@ -84,3 +84,23 @@ config USB_OTG_FSM
          Implements OTG Finite State Machine as specified in On-The-Go
          and Embedded Host Supplement to the USB Revision 2.0 Specification.
 
+config USB_ULPI_BUS
+       tristate "USB ULPI PHY interface support"
+       depends on USB_SUPPORT
+       help
+         UTMI+ Low Pin Interface (ULPI) is specification for a commonly used
+         USB 2.0 PHY interface. The ULPI specification defines a standard set
+         of registers that can be used to detect the vendor and product which
+         allows ULPI to be handled as a bus. This module is the driver for that
+         bus.
+
+         The ULPI interfaces (the buses) are registered by the drivers for USB
+         controllers which support ULPI register access and have ULPI PHY
+         attached to them. The ULPI PHY drivers themselves are normal PHY
+         drivers.
+
+         ULPI PHYs provide often functions such as ADP sensing/probing (OTG
+         protocol) and USB charger detection.
+
+         To compile this driver as a module, choose M here: the module will
+         be called ulpi.
index 506b969..89f2e77 100644 (file)
@@ -70,7 +70,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
                size = pool_max[i];
                if (!size)
                        continue;
-               snprintf(name, sizeof name, "buffer-%d", size);
+               snprintf(name, sizeof(name), "buffer-%d", size);
                hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
                                size, size, 0);
                if (!hcd->pool[i]) {
@@ -95,6 +95,7 @@ void hcd_buffer_destroy(struct usb_hcd *hcd)
 
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
                struct dma_pool *pool = hcd->pool[i];
+
                if (pool) {
                        dma_pool_destroy(pool);
                        hcd->pool[i] = NULL;
index 4b0448c..986abde 100644 (file)
@@ -513,7 +513,7 @@ static void async_completed(struct urb *urb)
        snoop(&urb->dev->dev, "urb complete\n");
        snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
                        as->status, COMPLETE, NULL, 0);
-       if ((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_IN)
+       if ((urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN)
                snoop_urb_data(urb, urb->actual_length);
 
        if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
index 45a915c..be5b207 100644 (file)
@@ -2691,7 +2691,8 @@ int usb_add_hcd(struct usb_hcd *hcd,
        if ((retval = usb_register_bus(&hcd->self)) < 0)
                goto err_register_bus;
 
-       if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
+       rhdev = usb_alloc_dev(NULL, &hcd->self, 0);
+       if (rhdev == NULL) {
                dev_err(hcd->self.controller, "unable to allocate root hub\n");
                retval = -ENOMEM;
                goto err_allocate_root_hub;
index 3b71516..43cb2f2 100644 (file)
@@ -127,7 +127,7 @@ static int usb_device_supports_lpm(struct usb_device *udev)
        /* USB 2.1 (and greater) devices indicate LPM support through
         * their USB 2.0 Extended Capabilities BOS descriptor.
         */
-       if (udev->speed == USB_SPEED_HIGH) {
+       if (udev->speed == USB_SPEED_HIGH || udev->speed == USB_SPEED_FULL) {
                if (udev->bos->ext_cap &&
                        (USB_LPM_SUPPORT &
                         le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
@@ -795,7 +795,8 @@ int usb_hub_clear_tt_buffer(struct urb *urb)
         * since each TT has "at least two" buffers that can need it (and
         * there can be many TTs per hub).  even if they're uncommon.
         */
-       if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == NULL) {
+       clear = kmalloc(sizeof *clear, GFP_ATOMIC);
+       if (clear == NULL) {
                dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n");
                /* FIXME recover somehow ... RESET_TT? */
                return -ENOMEM;
@@ -2350,6 +2351,26 @@ static void set_usb_port_removable(struct usb_device *udev)
 
        hub = usb_hub_to_struct_hub(udev->parent);
 
+       /*
+        * If the platform firmware has provided information about a port,
+        * use that to determine whether it's removable.
+        */
+       switch (hub->ports[udev->portnum - 1]->connect_type) {
+       case USB_PORT_CONNECT_TYPE_HOT_PLUG:
+               udev->removable = USB_DEVICE_REMOVABLE;
+               return;
+       case USB_PORT_CONNECT_TYPE_HARD_WIRED:
+       case USB_PORT_NOT_USED:
+               udev->removable = USB_DEVICE_FIXED;
+               return;
+       default:
+               break;
+       }
+
+       /*
+        * Otherwise, check whether the hub knows whether a port is removable
+        * or not
+        */
        wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
 
        if (!(wHubCharacteristics & HUB_CHAR_COMPOUND))
@@ -2369,21 +2390,6 @@ static void set_usb_port_removable(struct usb_device *udev)
        else
                udev->removable = USB_DEVICE_FIXED;
 
-       /*
-        * Platform firmware may have populated an alternative value for
-        * removable.  If the parent port has a known connect_type use
-        * that instead.
-        */
-       switch (hub->ports[udev->portnum - 1]->connect_type) {
-       case USB_PORT_CONNECT_TYPE_HOT_PLUG:
-               udev->removable = USB_DEVICE_REMOVABLE;
-               break;
-       case USB_PORT_CONNECT_TYPE_HARD_WIRED:
-               udev->removable = USB_DEVICE_FIXED;
-               break;
-       default: /* use what was set above */
-               break;
-       }
 }
 
 /**
@@ -2616,9 +2622,6 @@ static bool use_new_scheme(struct usb_device *udev, int retry)
        return USE_NEW_SCHEME(retry);
 }
 
-static int hub_port_reset(struct usb_hub *hub, int port1,
-                       struct usb_device *udev, unsigned int delay, bool warm);
-
 /* Is a USB 3.0 port in the Inactive or Compliance Mode state?
  * Port worm reset is required to recover
  */
@@ -2706,44 +2709,6 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
        return 0;
 }
 
-static void hub_port_finish_reset(struct usb_hub *hub, int port1,
-                       struct usb_device *udev, int *status)
-{
-       switch (*status) {
-       case 0:
-               /* TRSTRCY = 10 ms; plus some extra */
-               msleep(10 + 40);
-               if (udev) {
-                       struct usb_hcd *hcd = bus_to_hcd(udev->bus);
-
-                       update_devnum(udev, 0);
-                       /* The xHC may think the device is already reset,
-                        * so ignore the status.
-                        */
-                       if (hcd->driver->reset_device)
-                               hcd->driver->reset_device(hcd, udev);
-               }
-               /* FALL THROUGH */
-       case -ENOTCONN:
-       case -ENODEV:
-               usb_clear_port_feature(hub->hdev,
-                               port1, USB_PORT_FEAT_C_RESET);
-               if (hub_is_superspeed(hub->hdev)) {
-                       usb_clear_port_feature(hub->hdev, port1,
-                                       USB_PORT_FEAT_C_BH_PORT_RESET);
-                       usb_clear_port_feature(hub->hdev, port1,
-                                       USB_PORT_FEAT_C_PORT_LINK_STATE);
-                       usb_clear_port_feature(hub->hdev, port1,
-                                       USB_PORT_FEAT_C_CONNECTION);
-               }
-               if (udev)
-                       usb_set_device_state(udev, *status
-                                       ? USB_STATE_NOTATTACHED
-                                       : USB_STATE_DEFAULT);
-               break;
-       }
-}
-
 /* Handle port reset and port warm(BH) reset (for USB3 protocol ports) */
 static int hub_port_reset(struct usb_hub *hub, int port1,
                        struct usb_device *udev, unsigned int delay, bool warm)
@@ -2767,13 +2732,10 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                 * If the caller hasn't explicitly requested a warm reset,
                 * double check and see if one is needed.
                 */
-               status = hub_port_status(hub, port1,
-                                       &portstatus, &portchange);
-               if (status < 0)
-                       goto done;
-
-               if (hub_port_warm_reset_required(hub, port1, portstatus))
-                       warm = true;
+               if (hub_port_status(hub, port1, &portstatus, &portchange) == 0)
+                       if (hub_port_warm_reset_required(hub, port1,
+                                                       portstatus))
+                               warm = true;
        }
        clear_bit(port1, hub->warm_reset_bits);
 
@@ -2799,11 +2761,19 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 
                /* Check for disconnect or reset */
                if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
-                       hub_port_finish_reset(hub, port1, udev, &status);
+                       usb_clear_port_feature(hub->hdev, port1,
+                                       USB_PORT_FEAT_C_RESET);
 
                        if (!hub_is_superspeed(hub->hdev))
                                goto done;
 
+                       usb_clear_port_feature(hub->hdev, port1,
+                                       USB_PORT_FEAT_C_BH_PORT_RESET);
+                       usb_clear_port_feature(hub->hdev, port1,
+                                       USB_PORT_FEAT_C_PORT_LINK_STATE);
+                       usb_clear_port_feature(hub->hdev, port1,
+                                       USB_PORT_FEAT_C_CONNECTION);
+
                        /*
                         * If a USB 3.0 device migrates from reset to an error
                         * state, re-issue the warm reset.
@@ -2836,6 +2806,26 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
        dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");
 
 done:
+       if (status == 0) {
+               /* TRSTRCY = 10 ms; plus some extra */
+               msleep(10 + 40);
+               if (udev) {
+                       struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+                       update_devnum(udev, 0);
+                       /* The xHC may think the device is already reset,
+                        * so ignore the status.
+                        */
+                       if (hcd->driver->reset_device)
+                               hcd->driver->reset_device(hcd, udev);
+
+                       usb_set_device_state(udev, USB_STATE_DEFAULT);
+               }
+       } else {
+               if (udev)
+                       usb_set_device_state(udev, USB_STATE_NOTATTACHED);
+       }
+
        if (!hub_is_superspeed(hub->hdev))
                up_read(&ehci_cf_port_reset_rwsem);
 
index 1bcb36a..fd95ba6 100644 (file)
@@ -50,18 +50,10 @@ config USB_DWC2_DUAL_ROLE
          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
        tristate "DWC2 PCI"
        depends on PCI
        default n
-       select USB_DWC2_PLATFORM
        select NOP_USB_XCEIV
        help
          The Designware USB2.0 PCI interface module for controllers
index f07b425..50fdaac 100644 (file)
@@ -2,7 +2,7 @@ ccflags-$(CONFIG_USB_DWC2_DEBUG)        += -DDEBUG
 ccflags-$(CONFIG_USB_DWC2_VERBOSE)     += -DVERBOSE_DEBUG
 
 obj-$(CONFIG_USB_DWC2)                 += dwc2.o
-dwc2-y                                 := core.o core_intr.o
+dwc2-y                                 := core.o core_intr.o platform.o
 
 ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
        dwc2-y                          += hcd.o hcd_intr.o
@@ -13,6 +13,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC2_PERIPHERAL) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
        dwc2-y                          += gadget.o
 endif
 
+ifneq ($(CONFIG_DEBUG_FS),)
+       dwc2-y                          += debugfs.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.ko will get built for host mode, peripheral mode, and dual-role
@@ -21,6 +25,3 @@ endif
 
 obj-$(CONFIG_USB_DWC2_PCI)             += dwc2_pci.o
 dwc2_pci-y                             := pci.o
-
-obj-$(CONFIG_USB_DWC2_PLATFORM)                += dwc2_platform.o
-dwc2_platform-y                                := platform.o
index d5197d4..e5b546f 100644 (file)
 #include "core.h"
 #include "hcd.h"
 
+#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
+/**
+ * dwc2_backup_host_registers() - Backup controller host registers.
+ * When suspending usb bus, registers needs to be backuped
+ * if controller power is disabled once suspended.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+static int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_hregs_backup *hr;
+       int i;
+
+       dev_dbg(hsotg->dev, "%s\n", __func__);
+
+       /* Backup Host regs */
+       hr = hsotg->hr_backup;
+       if (!hr) {
+               hr = devm_kzalloc(hsotg->dev, sizeof(*hr), GFP_KERNEL);
+               if (!hr) {
+                       dev_err(hsotg->dev, "%s: can't allocate host regs\n",
+                                       __func__);
+                       return -ENOMEM;
+               }
+
+               hsotg->hr_backup = hr;
+       }
+       hr->hcfg = readl(hsotg->regs + HCFG);
+       hr->haintmsk = readl(hsotg->regs + HAINTMSK);
+       for (i = 0; i < hsotg->core_params->host_channels; ++i)
+               hr->hcintmsk[i] = readl(hsotg->regs + HCINTMSK(i));
+
+       hr->hprt0 = readl(hsotg->regs + HPRT0);
+       hr->hfir = readl(hsotg->regs + HFIR);
+
+       return 0;
+}
+
+/**
+ * dwc2_restore_host_registers() - Restore controller host registers.
+ * When resuming usb bus, device registers needs to be restored
+ * if controller power were disabled.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+static int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_hregs_backup *hr;
+       int i;
+
+       dev_dbg(hsotg->dev, "%s\n", __func__);
+
+       /* Restore host regs */
+       hr = hsotg->hr_backup;
+       if (!hr) {
+               dev_err(hsotg->dev, "%s: no host registers to restore\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       writel(hr->hcfg, hsotg->regs + HCFG);
+       writel(hr->haintmsk, hsotg->regs + HAINTMSK);
+
+       for (i = 0; i < hsotg->core_params->host_channels; ++i)
+               writel(hr->hcintmsk[i], hsotg->regs + HCINTMSK(i));
+
+       writel(hr->hprt0, hsotg->regs + HPRT0);
+       writel(hr->hfir, hsotg->regs + HFIR);
+
+       return 0;
+}
+#else
+static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
+{ return 0; }
+
+static inline int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
+{ return 0; }
+#endif
+
+#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \
+       IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
+/**
+ * dwc2_backup_device_registers() - Backup controller device registers.
+ * When suspending usb bus, registers needs to be backuped
+ * if controller power is disabled once suspended.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+static int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_dregs_backup *dr;
+       int i;
+
+       dev_dbg(hsotg->dev, "%s\n", __func__);
+
+       /* Backup dev regs */
+       dr = hsotg->dr_backup;
+       if (!dr) {
+               dr = devm_kzalloc(hsotg->dev, sizeof(*dr), GFP_KERNEL);
+               if (!dr) {
+                       dev_err(hsotg->dev, "%s: can't allocate device regs\n",
+                                       __func__);
+                       return -ENOMEM;
+               }
+
+               hsotg->dr_backup = dr;
+       }
+
+       dr->dcfg = readl(hsotg->regs + DCFG);
+       dr->dctl = readl(hsotg->regs + DCTL);
+       dr->daintmsk = readl(hsotg->regs + DAINTMSK);
+       dr->diepmsk = readl(hsotg->regs + DIEPMSK);
+       dr->doepmsk = readl(hsotg->regs + DOEPMSK);
+
+       for (i = 0; i < hsotg->num_of_eps; i++) {
+               /* Backup IN EPs */
+               dr->diepctl[i] = readl(hsotg->regs + DIEPCTL(i));
+
+               /* Ensure DATA PID is correctly configured */
+               if (dr->diepctl[i] & DXEPCTL_DPID)
+                       dr->diepctl[i] |= DXEPCTL_SETD1PID;
+               else
+                       dr->diepctl[i] |= DXEPCTL_SETD0PID;
+
+               dr->dieptsiz[i] = readl(hsotg->regs + DIEPTSIZ(i));
+               dr->diepdma[i] = readl(hsotg->regs + DIEPDMA(i));
+
+               /* Backup OUT EPs */
+               dr->doepctl[i] = readl(hsotg->regs + DOEPCTL(i));
+
+               /* Ensure DATA PID is correctly configured */
+               if (dr->doepctl[i] & DXEPCTL_DPID)
+                       dr->doepctl[i] |= DXEPCTL_SETD1PID;
+               else
+                       dr->doepctl[i] |= DXEPCTL_SETD0PID;
+
+               dr->doeptsiz[i] = readl(hsotg->regs + DOEPTSIZ(i));
+               dr->doepdma[i] = readl(hsotg->regs + DOEPDMA(i));
+       }
+
+       return 0;
+}
+
+/**
+ * dwc2_restore_device_registers() - Restore controller device registers.
+ * When resuming usb bus, device registers needs to be restored
+ * if controller power were disabled.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+static int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_dregs_backup *dr;
+       u32 dctl;
+       int i;
+
+       dev_dbg(hsotg->dev, "%s\n", __func__);
+
+       /* Restore dev regs */
+       dr = hsotg->dr_backup;
+       if (!dr) {
+               dev_err(hsotg->dev, "%s: no device registers to restore\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       writel(dr->dcfg, hsotg->regs + DCFG);
+       writel(dr->dctl, hsotg->regs + DCTL);
+       writel(dr->daintmsk, hsotg->regs + DAINTMSK);
+       writel(dr->diepmsk, hsotg->regs + DIEPMSK);
+       writel(dr->doepmsk, hsotg->regs + DOEPMSK);
+
+       for (i = 0; i < hsotg->num_of_eps; i++) {
+               /* Restore IN EPs */
+               writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i));
+               writel(dr->dieptsiz[i], hsotg->regs + DIEPTSIZ(i));
+               writel(dr->diepdma[i], hsotg->regs + DIEPDMA(i));
+
+               /* Restore OUT EPs */
+               writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i));
+               writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i));
+               writel(dr->doepdma[i], hsotg->regs + DOEPDMA(i));
+       }
+
+       /* Set the Power-On Programming done bit */
+       dctl = readl(hsotg->regs + DCTL);
+       dctl |= DCTL_PWRONPRGDONE;
+       writel(dctl, hsotg->regs + DCTL);
+
+       return 0;
+}
+#else
+static inline int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
+{ return 0; }
+
+static inline int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
+{ return 0; }
+#endif
+
+/**
+ * dwc2_backup_global_registers() - Backup global controller registers.
+ * When suspending usb bus, registers needs to be backuped
+ * if controller power is disabled once suspended.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_gregs_backup *gr;
+       int i;
+
+       /* Backup global regs */
+       gr = hsotg->gr_backup;
+       if (!gr) {
+               gr = devm_kzalloc(hsotg->dev, sizeof(*gr), GFP_KERNEL);
+               if (!gr) {
+                       dev_err(hsotg->dev, "%s: can't allocate global regs\n",
+                                       __func__);
+                       return -ENOMEM;
+               }
+
+               hsotg->gr_backup = gr;
+       }
+
+       gr->gotgctl = readl(hsotg->regs + GOTGCTL);
+       gr->gintmsk = readl(hsotg->regs + GINTMSK);
+       gr->gahbcfg = readl(hsotg->regs + GAHBCFG);
+       gr->gusbcfg = readl(hsotg->regs + GUSBCFG);
+       gr->grxfsiz = readl(hsotg->regs + GRXFSIZ);
+       gr->gnptxfsiz = readl(hsotg->regs + GNPTXFSIZ);
+       gr->hptxfsiz = readl(hsotg->regs + HPTXFSIZ);
+       gr->gdfifocfg = readl(hsotg->regs + GDFIFOCFG);
+       for (i = 0; i < MAX_EPS_CHANNELS; i++)
+               gr->dtxfsiz[i] = readl(hsotg->regs + DPTXFSIZN(i));
+
+       return 0;
+}
+
+/**
+ * dwc2_restore_global_registers() - Restore controller global registers.
+ * When resuming usb bus, device registers needs to be restored
+ * if controller power were disabled.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_gregs_backup *gr;
+       int i;
+
+       dev_dbg(hsotg->dev, "%s\n", __func__);
+
+       /* Restore global regs */
+       gr = hsotg->gr_backup;
+       if (!gr) {
+               dev_err(hsotg->dev, "%s: no global registers to restore\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       writel(0xffffffff, hsotg->regs + GINTSTS);
+       writel(gr->gotgctl, hsotg->regs + GOTGCTL);
+       writel(gr->gintmsk, hsotg->regs + GINTMSK);
+       writel(gr->gusbcfg, hsotg->regs + GUSBCFG);
+       writel(gr->gahbcfg, hsotg->regs + GAHBCFG);
+       writel(gr->grxfsiz, hsotg->regs + GRXFSIZ);
+       writel(gr->gnptxfsiz, hsotg->regs + GNPTXFSIZ);
+       writel(gr->hptxfsiz, hsotg->regs + HPTXFSIZ);
+       writel(gr->gdfifocfg, hsotg->regs + GDFIFOCFG);
+       for (i = 0; i < MAX_EPS_CHANNELS; i++)
+               writel(gr->dtxfsiz[i], hsotg->regs + DPTXFSIZN(i));
+
+       return 0;
+}
+
+/**
+ * dwc2_exit_hibernation() - Exit controller from Partial Power Down.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @restore: Controller registers need to be restored
+ */
+int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore)
+{
+       u32 pcgcctl;
+       int ret = 0;
+
+       if (!hsotg->core_params->hibernation)
+               return -ENOTSUPP;
+
+       pcgcctl = readl(hsotg->regs + PCGCTL);
+       pcgcctl &= ~PCGCTL_STOPPCLK;
+       writel(pcgcctl, hsotg->regs + PCGCTL);
+
+       pcgcctl = readl(hsotg->regs + PCGCTL);
+       pcgcctl &= ~PCGCTL_PWRCLMP;
+       writel(pcgcctl, hsotg->regs + PCGCTL);
+
+       pcgcctl = readl(hsotg->regs + PCGCTL);
+       pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
+       writel(pcgcctl, hsotg->regs + PCGCTL);
+
+       udelay(100);
+       if (restore) {
+               ret = dwc2_restore_global_registers(hsotg);
+               if (ret) {
+                       dev_err(hsotg->dev, "%s: failed to restore registers\n",
+                                       __func__);
+                       return ret;
+               }
+               if (dwc2_is_host_mode(hsotg)) {
+                       ret = dwc2_restore_host_registers(hsotg);
+                       if (ret) {
+                               dev_err(hsotg->dev, "%s: failed to restore host registers\n",
+                                               __func__);
+                               return ret;
+                       }
+               } else {
+                       ret = dwc2_restore_device_registers(hsotg);
+                       if (ret) {
+                               dev_err(hsotg->dev, "%s: failed to restore device registers\n",
+                                               __func__);
+                               return ret;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+/**
+ * dwc2_enter_hibernation() - Put controller in Partial Power Down.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg)
+{
+       u32 pcgcctl;
+       int ret = 0;
+
+       if (!hsotg->core_params->hibernation)
+               return -ENOTSUPP;
+
+       /* Backup all registers */
+       ret = dwc2_backup_global_registers(hsotg);
+       if (ret) {
+               dev_err(hsotg->dev, "%s: failed to backup global registers\n",
+                               __func__);
+               return ret;
+       }
+
+       if (dwc2_is_host_mode(hsotg)) {
+               ret = dwc2_backup_host_registers(hsotg);
+               if (ret) {
+                       dev_err(hsotg->dev, "%s: failed to backup host registers\n",
+                                       __func__);
+                       return ret;
+               }
+       } else {
+               ret = dwc2_backup_device_registers(hsotg);
+               if (ret) {
+                       dev_err(hsotg->dev, "%s: failed to backup device registers\n",
+                                       __func__);
+                       return ret;
+               }
+       }
+
+       /* Put the controller in low power state */
+       pcgcctl = readl(hsotg->regs + PCGCTL);
+
+       pcgcctl |= PCGCTL_PWRCLMP;
+       writel(pcgcctl, hsotg->regs + PCGCTL);
+       ndelay(20);
+
+       pcgcctl |= PCGCTL_RSTPDWNMODULE;
+       writel(pcgcctl, hsotg->regs + PCGCTL);
+       ndelay(20);
+
+       pcgcctl |= PCGCTL_STOPPCLK;
+       writel(pcgcctl, hsotg->regs + PCGCTL);
+
+       return ret;
+}
+
 /**
  * dwc2_enable_common_interrupts() - Initializes the commmon interrupts,
  * used in both device and host modes
@@ -77,8 +460,10 @@ static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg)
 
        if (hsotg->core_params->dma_enable <= 0)
                intmsk |= GINTSTS_RXFLVL;
+       if (hsotg->core_params->external_id_pin_ctl <= 0)
+               intmsk |= GINTSTS_CONIDSTSCHNG;
 
-       intmsk |= GINTSTS_CONIDSTSCHNG | GINTSTS_WKUPINT | GINTSTS_USBSUSP |
+       intmsk |= GINTSTS_WKUPINT | GINTSTS_USBSUSP |
                  GINTSTS_SESSREQINT;
 
        writel(intmsk, hsotg->regs + GINTMSK);
@@ -2602,6 +2987,40 @@ static void dwc2_set_param_uframe_sched(struct dwc2_hsotg *hsotg, int val)
        hsotg->core_params->uframe_sched = val;
 }
 
+static void dwc2_set_param_external_id_pin_ctl(struct dwc2_hsotg *hsotg,
+               int val)
+{
+       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev,
+                               "'%d' invalid for parameter external_id_pin_ctl\n",
+                               val);
+                       dev_err(hsotg->dev, "external_id_pin_ctl must be 0 or 1\n");
+               }
+               val = 0;
+               dev_dbg(hsotg->dev, "Setting external_id_pin_ctl to %d\n", val);
+       }
+
+       hsotg->core_params->external_id_pin_ctl = val;
+}
+
+static void dwc2_set_param_hibernation(struct dwc2_hsotg *hsotg,
+               int val)
+{
+       if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
+               if (val >= 0) {
+                       dev_err(hsotg->dev,
+                               "'%d' invalid for parameter hibernation\n",
+                               val);
+                       dev_err(hsotg->dev, "hibernation must be 0 or 1\n");
+               }
+               val = 0;
+               dev_dbg(hsotg->dev, "Setting hibernation to %d\n", val);
+       }
+
+       hsotg->core_params->hibernation = val;
+}
+
 /*
  * This function is called during module intialization to pass module parameters
  * for the DWC_otg core.
@@ -2646,6 +3065,8 @@ void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
        dwc2_set_param_ahbcfg(hsotg, params->ahbcfg);
        dwc2_set_param_otg_ver(hsotg, params->otg_ver);
        dwc2_set_param_uframe_sched(hsotg, params->uframe_sched);
+       dwc2_set_param_external_id_pin_ctl(hsotg, params->external_id_pin_ctl);
+       dwc2_set_param_hibernation(hsotg, params->hibernation);
 }
 
 /**
@@ -2814,6 +3235,22 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
        return 0;
 }
 
+/*
+ * Sets all parameters to the given value.
+ *
+ * Assumes that the dwc2_core_params struct contains only integers.
+ */
+void dwc2_set_all_params(struct dwc2_core_params *params, int value)
+{
+       int *p = (int *)params;
+       size_t size = sizeof(*params) / sizeof(*p);
+       int i;
+
+       for (i = 0; i < size; i++)
+               p[i] = value;
+}
+
+
 u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg)
 {
        return hsotg->core_params->otg_ver == 1 ? 0x0200 : 0x0103;
index 836c012..53b8de0 100644 (file)
@@ -331,6 +331,17 @@ enum dwc2_ep0_state {
  *                      by the driver and are ignored in this
  *                      configuration value.
  * @uframe_sched:       True to enable the microframe scheduler
+ * @external_id_pin_ctl: Specifies whether ID pin is handled externally.
+ *                      Disable CONIDSTSCHNG controller interrupt in such
+ *                      case.
+ *                      0 - No (default)
+ *                      1 - Yes
+ * @hibernation:       Specifies whether the controller support hibernation.
+ *                     If hibernation is enabled, the controller will enter
+ *                     hibernation in both peripheral and host mode when
+ *                     needed.
+ *                     0 - No (default)
+ *                     1 - Yes
  *
  * The following parameters may be specified when starting the module. These
  * parameters define how the DWC_otg controller should be configured. A
@@ -368,6 +379,8 @@ struct dwc2_core_params {
        int reload_ctl;
        int ahbcfg;
        int uframe_sched;
+       int external_id_pin_ctl;
+       int hibernation;
 };
 
 /**
@@ -452,6 +465,82 @@ struct dwc2_hw_params {
 #define DWC2_CTRL_BUFF_SIZE 8
 
 /**
+ * struct dwc2_gregs_backup - Holds global registers state before entering partial
+ * power down
+ * @gotgctl:           Backup of GOTGCTL register
+ * @gintmsk:           Backup of GINTMSK register
+ * @gahbcfg:           Backup of GAHBCFG register
+ * @gusbcfg:           Backup of GUSBCFG register
+ * @grxfsiz:           Backup of GRXFSIZ register
+ * @gnptxfsiz:         Backup of GNPTXFSIZ register
+ * @gi2cctl:           Backup of GI2CCTL register
+ * @hptxfsiz:          Backup of HPTXFSIZ register
+ * @gdfifocfg:         Backup of GDFIFOCFG register
+ * @dtxfsiz:           Backup of DTXFSIZ registers for each endpoint
+ * @gpwrdn:            Backup of GPWRDN register
+ */
+struct dwc2_gregs_backup {
+       u32 gotgctl;
+       u32 gintmsk;
+       u32 gahbcfg;
+       u32 gusbcfg;
+       u32 grxfsiz;
+       u32 gnptxfsiz;
+       u32 gi2cctl;
+       u32 hptxfsiz;
+       u32 pcgcctl;
+       u32 gdfifocfg;
+       u32 dtxfsiz[MAX_EPS_CHANNELS];
+       u32 gpwrdn;
+};
+
+/**
+ * struct  dwc2_dregs_backup - Holds device registers state before entering partial
+ * power down
+ * @dcfg:              Backup of DCFG register
+ * @dctl:              Backup of DCTL register
+ * @daintmsk:          Backup of DAINTMSK register
+ * @diepmsk:           Backup of DIEPMSK register
+ * @doepmsk:           Backup of DOEPMSK register
+ * @diepctl:           Backup of DIEPCTL register
+ * @dieptsiz:          Backup of DIEPTSIZ register
+ * @diepdma:           Backup of DIEPDMA register
+ * @doepctl:           Backup of DOEPCTL register
+ * @doeptsiz:          Backup of DOEPTSIZ register
+ * @doepdma:           Backup of DOEPDMA register
+ */
+struct dwc2_dregs_backup {
+       u32 dcfg;
+       u32 dctl;
+       u32 daintmsk;
+       u32 diepmsk;
+       u32 doepmsk;
+       u32 diepctl[MAX_EPS_CHANNELS];
+       u32 dieptsiz[MAX_EPS_CHANNELS];
+       u32 diepdma[MAX_EPS_CHANNELS];
+       u32 doepctl[MAX_EPS_CHANNELS];
+       u32 doeptsiz[MAX_EPS_CHANNELS];
+       u32 doepdma[MAX_EPS_CHANNELS];
+};
+
+/**
+ * struct  dwc2_hregs_backup - Holds host registers state before entering partial
+ * power down
+ * @hcfg:              Backup of HCFG register
+ * @haintmsk:          Backup of HAINTMSK register
+ * @hcintmsk:          Backup of HCINTMSK register
+ * @hptr0:             Backup of HPTR0 register
+ * @hfir:              Backup of HFIR register
+ */
+struct dwc2_hregs_backup {
+       u32 hcfg;
+       u32 haintmsk;
+       u32 hcintmsk[MAX_EPS_CHANNELS];
+       u32 hprt0;
+       u32 hfir;
+};
+
+/**
  * struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
  * and periodic schedules
  *
@@ -481,6 +570,9 @@ struct dwc2_hw_params {
  *                      interrupt
  * @wkp_timer:          Timer object for handling Wakeup Detected interrupt
  * @lx_state:           Lx state of connected device
+ * @gregs_backup: Backup of global registers during suspend
+ * @dregs_backup: Backup of device registers during suspend
+ * @hregs_backup: Backup of host registers during suspend
  *
  * These are for host mode:
  *
@@ -613,11 +705,12 @@ struct dwc2_hsotg {
        struct work_struct wf_otg;
        struct timer_list wkp_timer;
        enum dwc2_lx_state lx_state;
+       struct dwc2_gregs_backup *gr_backup;
+       struct dwc2_dregs_backup *dr_backup;
+       struct dwc2_hregs_backup *hr_backup;
 
        struct dentry *debug_root;
-       struct dentry *debug_file;
-       struct dentry *debug_testmode;
-       struct dentry *debug_fifo;
+       struct debugfs_regset32 *regset;
 
        /* DWC OTG HW Release versions */
 #define DWC2_CORE_REV_2_71a    0x4f54271a
@@ -751,6 +844,8 @@ enum dwc2_halt_status {
  * and the DWC_otg controller
  */
 extern void dwc2_core_host_init(struct dwc2_hsotg *hsotg);
+extern int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg);
+extern int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore);
 
 /*
  * Host core Functions.
@@ -983,6 +1078,15 @@ extern void dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val);
 
 extern void dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val);
 
+extern void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
+                               const struct dwc2_core_params *params);
+
+extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
+
+extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
+
+
+
 /*
  * Dump core registers and SPRAM
  */
@@ -1005,6 +1109,8 @@ extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
                bool reset);
 extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
 extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
+extern int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
+#define dwc2_is_device_connected(hsotg) (hsotg->connected)
 #else
 static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2)
 { return 0; }
@@ -1018,6 +1124,10 @@ static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
                bool reset) {}
 static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
 static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
+static inline int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
+                                                       int testmode)
+{ return 0; }
+#define dwc2_is_device_connected(hsotg) (0)
 #endif
 
 #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
@@ -1025,14 +1135,12 @@ 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)
+static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
 { return 0; }
 #endif
 
index 6cf0478..927be1e 100644 (file)
@@ -334,6 +334,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
  */
 static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
 {
+       int ret;
        dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
        dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
 
@@ -345,6 +346,11 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
                        /* Clear Remote Wakeup Signaling */
                        dctl &= ~DCTL_RMTWKUPSIG;
                        writel(dctl, hsotg->regs + DCTL);
+                       ret = dwc2_exit_hibernation(hsotg, true);
+                       if (ret && (ret != -ENOTSUPP))
+                               dev_err(hsotg->dev, "exit hibernation failed\n");
+
+                       call_gadget(hsotg, resume);
                }
                /* Change to L0 state */
                hsotg->lx_state = DWC2_L0;
@@ -397,6 +403,7 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
 static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
 {
        u32 dsts;
+       int ret;
 
        dev_dbg(hsotg->dev, "USB SUSPEND\n");
 
@@ -411,10 +418,43 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
                        "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
                        !!(dsts & DSTS_SUSPSTS),
                        hsotg->hw_params.power_optimized);
+               if ((dsts & DSTS_SUSPSTS) && hsotg->hw_params.power_optimized) {
+                       /* Ignore suspend request before enumeration */
+                       if (!dwc2_is_device_connected(hsotg)) {
+                               dev_dbg(hsotg->dev,
+                                               "ignore suspend request before enumeration\n");
+                               goto clear_int;
+                       }
+
+                       ret = dwc2_enter_hibernation(hsotg);
+                       if (ret) {
+                               if (ret != -ENOTSUPP)
+                                       dev_err(hsotg->dev,
+                                                       "enter hibernation failed\n");
+                               goto skip_power_saving;
+                       }
+
+                       udelay(100);
+
+                       /* Ask phy to be suspended */
+                       if (!IS_ERR_OR_NULL(hsotg->uphy))
+                               usb_phy_set_suspend(hsotg->uphy, true);
+skip_power_saving:
+                       /*
+                        * Change to L2 (suspend) state before releasing
+                        * spinlock
+                        */
+                       hsotg->lx_state = DWC2_L2;
+
+                       /* Call gadget suspend callback */
+                       call_gadget(hsotg, suspend);
+               }
        } else {
                if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
                        dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
 
+                       /* Change to L2 (suspend) state */
+                       hsotg->lx_state = DWC2_L2;
                        /* Clear the a_peripheral flag, back to a_host */
                        spin_unlock(&hsotg->lock);
                        dwc2_hcd_start(hsotg);
@@ -423,9 +463,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
                }
        }
 
-       /* Change to L2 (suspend) state */
-       hsotg->lx_state = DWC2_L2;
-
+clear_int:
        /* Clear interrupt */
        writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
 }
@@ -522,4 +560,3 @@ out:
        spin_unlock(&hsotg->lock);
        return retval;
 }
-EXPORT_SYMBOL_GPL(dwc2_handle_common_intr);
diff --git a/drivers/usb/dwc2/debug.h b/drivers/usb/dwc2/debug.h
new file mode 100644 (file)
index 0000000..12dbd1d
--- /dev/null
@@ -0,0 +1,27 @@
+/**
+ * debug.h - Designware USB2 DRD controller debug header
+ *
+ * Copyright (C) 2015 Intel Corporation
+ * Mian Yousaf Kaukab <yousaf.kaukab@intel.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  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "core.h"
+
+#ifdef CONFIG_DEBUG_FS
+extern int dwc2_debugfs_init(struct dwc2_hsotg *);
+extern void dwc2_debugfs_exit(struct dwc2_hsotg *);
+#else
+static inline int dwc2_debugfs_init(struct dwc2_hsotg *hsotg)
+{  return 0;  }
+static inline void dwc2_debugfs_exit(struct dwc2_hsotg *hsotg)
+{  }
+#endif
diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c
new file mode 100644 (file)
index 0000000..ef2ee3d
--- /dev/null
@@ -0,0 +1,771 @@
+/**
+ * debugfs.c - Designware USB2 DRD controller debugfs
+ *
+ * Copyright (C) 2015 Intel Corporation
+ * Mian Yousaf Kaukab <yousaf.kaukab@intel.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  of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+
+#include "core.h"
+#include "debug.h"
+
+#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \
+       IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
+/**
+ * testmode_write - debugfs: change usb test mode
+ * @seq: The seq file to write to.
+ * @v: Unused parameter.
+ *
+ * This debugfs entry modify the current usb test mode.
+ */
+static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t
+               count, loff_t *ppos)
+{
+       struct seq_file         *s = file->private_data;
+       struct dwc2_hsotg       *hsotg = s->private;
+       unsigned long           flags;
+       u32                     testmode = 0;
+       char                    buf[32];
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       if (!strncmp(buf, "test_j", 6))
+               testmode = TEST_J;
+       else if (!strncmp(buf, "test_k", 6))
+               testmode = TEST_K;
+       else if (!strncmp(buf, "test_se0_nak", 12))
+               testmode = TEST_SE0_NAK;
+       else if (!strncmp(buf, "test_packet", 11))
+               testmode = TEST_PACKET;
+       else if (!strncmp(buf, "test_force_enable", 17))
+               testmode = TEST_FORCE_EN;
+       else
+               testmode = 0;
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+       s3c_hsotg_set_test_mode(hsotg, testmode);
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+       return count;
+}
+
+/**
+ * testmode_show - debugfs: show usb test mode state
+ * @seq: The seq file to write to.
+ * @v: Unused parameter.
+ *
+ * This debugfs entry shows which usb test mode is currently enabled.
+ */
+static int testmode_show(struct seq_file *s, void *unused)
+{
+       struct dwc2_hsotg *hsotg = s->private;
+       unsigned long flags;
+       int dctl;
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+       dctl = readl(hsotg->regs + DCTL);
+       dctl &= DCTL_TSTCTL_MASK;
+       dctl >>= DCTL_TSTCTL_SHIFT;
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+
+       switch (dctl) {
+       case 0:
+               seq_puts(s, "no test\n");
+               break;
+       case TEST_J:
+               seq_puts(s, "test_j\n");
+               break;
+       case TEST_K:
+               seq_puts(s, "test_k\n");
+               break;
+       case TEST_SE0_NAK:
+               seq_puts(s, "test_se0_nak\n");
+               break;
+       case TEST_PACKET:
+               seq_puts(s, "test_packet\n");
+               break;
+       case TEST_FORCE_EN:
+               seq_puts(s, "test_force_enable\n");
+               break;
+       default:
+               seq_printf(s, "UNKNOWN %d\n", dctl);
+       }
+
+       return 0;
+}
+
+static int testmode_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, testmode_show, inode->i_private);
+}
+
+static const struct file_operations testmode_fops = {
+       .owner          = THIS_MODULE,
+       .open           = testmode_open,
+       .write          = testmode_write,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/**
+ * state_show - debugfs: show overall driver and device state.
+ * @seq: The seq file to write to.
+ * @v: Unused parameter.
+ *
+ * This debugfs entry shows the overall state of the hardware and
+ * some general information about each of the endpoints available
+ * to the system.
+ */
+static int state_show(struct seq_file *seq, void *v)
+{
+       struct dwc2_hsotg *hsotg = seq->private;
+       void __iomem *regs = hsotg->regs;
+       int idx;
+
+       seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n",
+                readl(regs + DCFG),
+                readl(regs + DCTL),
+                readl(regs + DSTS));
+
+       seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n",
+                  readl(regs + DIEPMSK), readl(regs + DOEPMSK));
+
+       seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n",
+                  readl(regs + GINTMSK),
+                  readl(regs + GINTSTS));
+
+       seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n",
+                  readl(regs + DAINTMSK),
+                  readl(regs + DAINT));
+
+       seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n",
+                  readl(regs + GNPTXSTS),
+                  readl(regs + GRXSTSR));
+
+       seq_puts(seq, "\nEndpoint status:\n");
+
+       for (idx = 0; idx < hsotg->num_of_eps; idx++) {
+               u32 in, out;
+
+               in = readl(regs + DIEPCTL(idx));
+               out = readl(regs + DOEPCTL(idx));
+
+               seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x",
+                          idx, in, out);
+
+               in = readl(regs + DIEPTSIZ(idx));
+               out = readl(regs + DOEPTSIZ(idx));
+
+               seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",
+                          in, out);
+
+               seq_puts(seq, "\n");
+       }
+
+       return 0;
+}
+
+static int state_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, state_show, inode->i_private);
+}
+
+static const struct file_operations state_fops = {
+       .owner          = THIS_MODULE,
+       .open           = state_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/**
+ * fifo_show - debugfs: show the fifo information
+ * @seq: The seq_file to write data to.
+ * @v: Unused parameter.
+ *
+ * Show the FIFO information for the overall fifo and all the
+ * periodic transmission FIFOs.
+ */
+static int fifo_show(struct seq_file *seq, void *v)
+{
+       struct dwc2_hsotg *hsotg = seq->private;
+       void __iomem *regs = hsotg->regs;
+       u32 val;
+       int idx;
+
+       seq_puts(seq, "Non-periodic FIFOs:\n");
+       seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ));
+
+       val = readl(regs + GNPTXFSIZ);
+       seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",
+                  val >> FIFOSIZE_DEPTH_SHIFT,
+                  val & FIFOSIZE_DEPTH_MASK);
+
+       seq_puts(seq, "\nPeriodic TXFIFOs:\n");
+
+       for (idx = 1; idx < hsotg->num_of_eps; idx++) {
+               val = readl(regs + DPTXFSIZN(idx));
+
+               seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
+                          val >> FIFOSIZE_DEPTH_SHIFT,
+                          val & FIFOSIZE_STARTADDR_MASK);
+       }
+
+       return 0;
+}
+
+static int fifo_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, fifo_show, inode->i_private);
+}
+
+static const struct file_operations fifo_fops = {
+       .owner          = THIS_MODULE,
+       .open           = fifo_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static const char *decode_direction(int is_in)
+{
+       return is_in ? "in" : "out";
+}
+
+/**
+ * ep_show - debugfs: show the state of an endpoint.
+ * @seq: The seq_file to write data to.
+ * @v: Unused parameter.
+ *
+ * This debugfs entry shows the state of the given endpoint (one is
+ * registered for each available).
+ */
+static int ep_show(struct seq_file *seq, void *v)
+{
+       struct s3c_hsotg_ep *ep = seq->private;
+       struct dwc2_hsotg *hsotg = ep->parent;
+       struct s3c_hsotg_req *req;
+       void __iomem *regs = hsotg->regs;
+       int index = ep->index;
+       int show_limit = 15;
+       unsigned long flags;
+
+       seq_printf(seq, "Endpoint index %d, named %s,  dir %s:\n",
+                  ep->index, ep->ep.name, decode_direction(ep->dir_in));
+
+       /* first show the register state */
+
+       seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n",
+                  readl(regs + DIEPCTL(index)),
+                  readl(regs + DOEPCTL(index)));
+
+       seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n",
+                  readl(regs + DIEPDMA(index)),
+                  readl(regs + DOEPDMA(index)));
+
+       seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n",
+                  readl(regs + DIEPINT(index)),
+                  readl(regs + DOEPINT(index)));
+
+       seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n",
+                  readl(regs + DIEPTSIZ(index)),
+                  readl(regs + DOEPTSIZ(index)));
+
+       seq_puts(seq, "\n");
+       seq_printf(seq, "mps %d\n", ep->ep.maxpacket);
+       seq_printf(seq, "total_data=%ld\n", ep->total_data);
+
+       seq_printf(seq, "request list (%p,%p):\n",
+                  ep->queue.next, ep->queue.prev);
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+
+       list_for_each_entry(req, &ep->queue, queue) {
+               if (--show_limit < 0) {
+                       seq_puts(seq, "not showing more requests...\n");
+                       break;
+               }
+
+               seq_printf(seq, "%c req %p: %d bytes @%p, ",
+                          req == ep->req ? '*' : ' ',
+                          req, req->req.length, req->req.buf);
+               seq_printf(seq, "%d done, res %d\n",
+                          req->req.actual, req->req.status);
+       }
+
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+
+       return 0;
+}
+
+static int ep_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ep_show, inode->i_private);
+}
+
+static const struct file_operations ep_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ep_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/**
+ * s3c_hsotg_create_debug - create debugfs directory and files
+ * @hsotg: The driver state
+ *
+ * Create the debugfs files to allow the user to get information
+ * about the state of the system. The directory name is created
+ * 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 dwc2_hsotg *hsotg)
+{
+       struct dentry *root;
+       struct dentry *file;
+       unsigned epidx;
+
+       root = hsotg->debug_root;
+
+       /* create general state file */
+
+       file = debugfs_create_file("state", S_IRUGO, root, hsotg, &state_fops);
+       if (IS_ERR(file))
+               dev_err(hsotg->dev, "%s: failed to create state\n", __func__);
+
+       file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, hsotg,
+                                                       &testmode_fops);
+       if (IS_ERR(file))
+               dev_err(hsotg->dev, "%s: failed to create testmode\n",
+                               __func__);
+
+       file = debugfs_create_file("fifo", S_IRUGO, root, hsotg, &fifo_fops);
+       if (IS_ERR(file))
+               dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__);
+
+       /* Create one file for each out endpoint */
+       for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
+               struct s3c_hsotg_ep *ep;
+
+               ep = hsotg->eps_out[epidx];
+               if (ep) {
+                       file = debugfs_create_file(ep->name, S_IRUGO,
+                                                         root, ep, &ep_fops);
+                       if (IS_ERR(file))
+                               dev_err(hsotg->dev, "failed to create %s debug file\n",
+                                       ep->name);
+               }
+       }
+       /* Create one file for each in endpoint. EP0 is handled with out eps */
+       for (epidx = 1; epidx < hsotg->num_of_eps; epidx++) {
+               struct s3c_hsotg_ep *ep;
+
+               ep = hsotg->eps_in[epidx];
+               if (ep) {
+                       file = debugfs_create_file(ep->name, S_IRUGO,
+                                                         root, ep, &ep_fops);
+                       if (IS_ERR(file))
+                               dev_err(hsotg->dev, "failed to create %s debug file\n",
+                                       ep->name);
+               }
+       }
+}
+#else
+static inline void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg) {}
+#endif
+
+/* s3c_hsotg_delete_debug is removed as cleanup in done in dwc2_debugfs_exit */
+
+#define dump_register(nm)      \
+{                              \
+       .name   = #nm,          \
+       .offset = nm,           \
+}
+
+static const struct debugfs_reg32 dwc2_regs[] = {
+       /*
+        * Accessing registers like this can trigger mode mismatch interrupt.
+        * However, according to dwc2 databook, the register access, in this
+        * case, is completed on the processor bus but is ignored by the core
+        * and does not affect its operation.
+        */
+       dump_register(GOTGCTL),
+       dump_register(GOTGINT),
+       dump_register(GAHBCFG),
+       dump_register(GUSBCFG),
+       dump_register(GRSTCTL),
+       dump_register(GINTSTS),
+       dump_register(GINTMSK),
+       dump_register(GRXSTSR),
+       dump_register(GRXSTSP),
+       dump_register(GRXFSIZ),
+       dump_register(GNPTXFSIZ),
+       dump_register(GNPTXSTS),
+       dump_register(GI2CCTL),
+       dump_register(GPVNDCTL),
+       dump_register(GGPIO),
+       dump_register(GUID),
+       dump_register(GSNPSID),
+       dump_register(GHWCFG1),
+       dump_register(GHWCFG2),
+       dump_register(GHWCFG3),
+       dump_register(GHWCFG4),
+       dump_register(GLPMCFG),
+       dump_register(GPWRDN),
+       dump_register(GDFIFOCFG),
+       dump_register(ADPCTL),
+       dump_register(HPTXFSIZ),
+       dump_register(DPTXFSIZN(1)),
+       dump_register(DPTXFSIZN(2)),
+       dump_register(DPTXFSIZN(3)),
+       dump_register(DPTXFSIZN(4)),
+       dump_register(DPTXFSIZN(5)),
+       dump_register(DPTXFSIZN(6)),
+       dump_register(DPTXFSIZN(7)),
+       dump_register(DPTXFSIZN(8)),
+       dump_register(DPTXFSIZN(9)),
+       dump_register(DPTXFSIZN(10)),
+       dump_register(DPTXFSIZN(11)),
+       dump_register(DPTXFSIZN(12)),
+       dump_register(DPTXFSIZN(13)),
+       dump_register(DPTXFSIZN(14)),
+       dump_register(DPTXFSIZN(15)),
+       dump_register(DCFG),
+       dump_register(DCTL),
+       dump_register(DSTS),
+       dump_register(DIEPMSK),
+       dump_register(DOEPMSK),
+       dump_register(DAINT),
+       dump_register(DAINTMSK),
+       dump_register(DTKNQR1),
+       dump_register(DTKNQR2),
+       dump_register(DTKNQR3),
+       dump_register(DTKNQR4),
+       dump_register(DVBUSDIS),
+       dump_register(DVBUSPULSE),
+       dump_register(DIEPCTL(0)),
+       dump_register(DIEPCTL(1)),
+       dump_register(DIEPCTL(2)),
+       dump_register(DIEPCTL(3)),
+       dump_register(DIEPCTL(4)),
+       dump_register(DIEPCTL(5)),
+       dump_register(DIEPCTL(6)),
+       dump_register(DIEPCTL(7)),
+       dump_register(DIEPCTL(8)),
+       dump_register(DIEPCTL(9)),
+       dump_register(DIEPCTL(10)),
+       dump_register(DIEPCTL(11)),
+       dump_register(DIEPCTL(12)),
+       dump_register(DIEPCTL(13)),
+       dump_register(DIEPCTL(14)),
+       dump_register(DIEPCTL(15)),
+       dump_register(DOEPCTL(0)),
+       dump_register(DOEPCTL(1)),
+       dump_register(DOEPCTL(2)),
+       dump_register(DOEPCTL(3)),
+       dump_register(DOEPCTL(4)),
+       dump_register(DOEPCTL(5)),
+       dump_register(DOEPCTL(6)),
+       dump_register(DOEPCTL(7)),
+       dump_register(DOEPCTL(8)),
+       dump_register(DOEPCTL(9)),
+       dump_register(DOEPCTL(10)),
+       dump_register(DOEPCTL(11)),
+       dump_register(DOEPCTL(12)),
+       dump_register(DOEPCTL(13)),
+       dump_register(DOEPCTL(14)),
+       dump_register(DOEPCTL(15)),
+       dump_register(DIEPINT(0)),
+       dump_register(DIEPINT(1)),
+       dump_register(DIEPINT(2)),
+       dump_register(DIEPINT(3)),
+       dump_register(DIEPINT(4)),
+       dump_register(DIEPINT(5)),
+       dump_register(DIEPINT(6)),
+       dump_register(DIEPINT(7)),
+       dump_register(DIEPINT(8)),
+       dump_register(DIEPINT(9)),
+       dump_register(DIEPINT(10)),
+       dump_register(DIEPINT(11)),
+       dump_register(DIEPINT(12)),
+       dump_register(DIEPINT(13)),
+       dump_register(DIEPINT(14)),
+       dump_register(DIEPINT(15)),
+       dump_register(DOEPINT(0)),
+       dump_register(DOEPINT(1)),
+       dump_register(DOEPINT(2)),
+       dump_register(DOEPINT(3)),
+       dump_register(DOEPINT(4)),
+       dump_register(DOEPINT(5)),
+       dump_register(DOEPINT(6)),
+       dump_register(DOEPINT(7)),
+       dump_register(DOEPINT(8)),
+       dump_register(DOEPINT(9)),
+       dump_register(DOEPINT(10)),
+       dump_register(DOEPINT(11)),
+       dump_register(DOEPINT(12)),
+       dump_register(DOEPINT(13)),
+       dump_register(DOEPINT(14)),
+       dump_register(DOEPINT(15)),
+       dump_register(DIEPTSIZ(0)),
+       dump_register(DIEPTSIZ(1)),
+       dump_register(DIEPTSIZ(2)),
+       dump_register(DIEPTSIZ(3)),
+       dump_register(DIEPTSIZ(4)),
+       dump_register(DIEPTSIZ(5)),
+       dump_register(DIEPTSIZ(6)),
+       dump_register(DIEPTSIZ(7)),
+       dump_register(DIEPTSIZ(8)),
+       dump_register(DIEPTSIZ(9)),
+       dump_register(DIEPTSIZ(10)),
+       dump_register(DIEPTSIZ(11)),
+       dump_register(DIEPTSIZ(12)),
+       dump_register(DIEPTSIZ(13)),
+       dump_register(DIEPTSIZ(14)),
+       dump_register(DIEPTSIZ(15)),
+       dump_register(DOEPTSIZ(0)),
+       dump_register(DOEPTSIZ(1)),
+       dump_register(DOEPTSIZ(2)),
+       dump_register(DOEPTSIZ(3)),
+       dump_register(DOEPTSIZ(4)),
+       dump_register(DOEPTSIZ(5)),
+       dump_register(DOEPTSIZ(6)),
+       dump_register(DOEPTSIZ(7)),
+       dump_register(DOEPTSIZ(8)),
+       dump_register(DOEPTSIZ(9)),
+       dump_register(DOEPTSIZ(10)),
+       dump_register(DOEPTSIZ(11)),
+       dump_register(DOEPTSIZ(12)),
+       dump_register(DOEPTSIZ(13)),
+       dump_register(DOEPTSIZ(14)),
+       dump_register(DOEPTSIZ(15)),
+       dump_register(DIEPDMA(0)),
+       dump_register(DIEPDMA(1)),
+       dump_register(DIEPDMA(2)),
+       dump_register(DIEPDMA(3)),
+       dump_register(DIEPDMA(4)),
+       dump_register(DIEPDMA(5)),
+       dump_register(DIEPDMA(6)),
+       dump_register(DIEPDMA(7)),
+       dump_register(DIEPDMA(8)),
+       dump_register(DIEPDMA(9)),
+       dump_register(DIEPDMA(10)),
+       dump_register(DIEPDMA(11)),
+       dump_register(DIEPDMA(12)),
+       dump_register(DIEPDMA(13)),
+       dump_register(DIEPDMA(14)),
+       dump_register(DIEPDMA(15)),
+       dump_register(DOEPDMA(0)),
+       dump_register(DOEPDMA(1)),
+       dump_register(DOEPDMA(2)),
+       dump_register(DOEPDMA(3)),
+       dump_register(DOEPDMA(4)),
+       dump_register(DOEPDMA(5)),
+       dump_register(DOEPDMA(6)),
+       dump_register(DOEPDMA(7)),
+       dump_register(DOEPDMA(8)),
+       dump_register(DOEPDMA(9)),
+       dump_register(DOEPDMA(10)),
+       dump_register(DOEPDMA(11)),
+       dump_register(DOEPDMA(12)),
+       dump_register(DOEPDMA(13)),
+       dump_register(DOEPDMA(14)),
+       dump_register(DOEPDMA(15)),
+       dump_register(DTXFSTS(0)),
+       dump_register(DTXFSTS(1)),
+       dump_register(DTXFSTS(2)),
+       dump_register(DTXFSTS(3)),
+       dump_register(DTXFSTS(4)),
+       dump_register(DTXFSTS(5)),
+       dump_register(DTXFSTS(6)),
+       dump_register(DTXFSTS(7)),
+       dump_register(DTXFSTS(8)),
+       dump_register(DTXFSTS(9)),
+       dump_register(DTXFSTS(10)),
+       dump_register(DTXFSTS(11)),
+       dump_register(DTXFSTS(12)),
+       dump_register(DTXFSTS(13)),
+       dump_register(DTXFSTS(14)),
+       dump_register(DTXFSTS(15)),
+       dump_register(PCGCTL),
+       dump_register(HCFG),
+       dump_register(HFIR),
+       dump_register(HFNUM),
+       dump_register(HPTXSTS),
+       dump_register(HAINT),
+       dump_register(HAINTMSK),
+       dump_register(HFLBADDR),
+       dump_register(HPRT0),
+       dump_register(HCCHAR(0)),
+       dump_register(HCCHAR(1)),
+       dump_register(HCCHAR(2)),
+       dump_register(HCCHAR(3)),
+       dump_register(HCCHAR(4)),
+       dump_register(HCCHAR(5)),
+       dump_register(HCCHAR(6)),
+       dump_register(HCCHAR(7)),
+       dump_register(HCCHAR(8)),
+       dump_register(HCCHAR(9)),
+       dump_register(HCCHAR(10)),
+       dump_register(HCCHAR(11)),
+       dump_register(HCCHAR(12)),
+       dump_register(HCCHAR(13)),
+       dump_register(HCCHAR(14)),
+       dump_register(HCCHAR(15)),
+       dump_register(HCSPLT(0)),
+       dump_register(HCSPLT(1)),
+       dump_register(HCSPLT(2)),
+       dump_register(HCSPLT(3)),
+       dump_register(HCSPLT(4)),
+       dump_register(HCSPLT(5)),
+       dump_register(HCSPLT(6)),
+       dump_register(HCSPLT(7)),
+       dump_register(HCSPLT(8)),
+       dump_register(HCSPLT(9)),
+       dump_register(HCSPLT(10)),
+       dump_register(HCSPLT(11)),
+       dump_register(HCSPLT(12)),
+       dump_register(HCSPLT(13)),
+       dump_register(HCSPLT(14)),
+       dump_register(HCSPLT(15)),
+       dump_register(HCINT(0)),
+       dump_register(HCINT(1)),
+       dump_register(HCINT(2)),
+       dump_register(HCINT(3)),
+       dump_register(HCINT(4)),
+       dump_register(HCINT(5)),
+       dump_register(HCINT(6)),
+       dump_register(HCINT(7)),
+       dump_register(HCINT(8)),
+       dump_register(HCINT(9)),
+       dump_register(HCINT(10)),
+       dump_register(HCINT(11)),
+       dump_register(HCINT(12)),
+       dump_register(HCINT(13)),
+       dump_register(HCINT(14)),
+       dump_register(HCINT(15)),
+       dump_register(HCINTMSK(0)),
+       dump_register(HCINTMSK(1)),
+       dump_register(HCINTMSK(2)),
+       dump_register(HCINTMSK(3)),
+       dump_register(HCINTMSK(4)),
+       dump_register(HCINTMSK(5)),
+       dump_register(HCINTMSK(6)),
+       dump_register(HCINTMSK(7)),
+       dump_register(HCINTMSK(8)),
+       dump_register(HCINTMSK(9)),
+       dump_register(HCINTMSK(10)),
+       dump_register(HCINTMSK(11)),
+       dump_register(HCINTMSK(12)),
+       dump_register(HCINTMSK(13)),
+       dump_register(HCINTMSK(14)),
+       dump_register(HCINTMSK(15)),
+       dump_register(HCTSIZ(0)),
+       dump_register(HCTSIZ(1)),
+       dump_register(HCTSIZ(2)),
+       dump_register(HCTSIZ(3)),
+       dump_register(HCTSIZ(4)),
+       dump_register(HCTSIZ(5)),
+       dump_register(HCTSIZ(6)),
+       dump_register(HCTSIZ(7)),
+       dump_register(HCTSIZ(8)),
+       dump_register(HCTSIZ(9)),
+       dump_register(HCTSIZ(10)),
+       dump_register(HCTSIZ(11)),
+       dump_register(HCTSIZ(12)),
+       dump_register(HCTSIZ(13)),
+       dump_register(HCTSIZ(14)),
+       dump_register(HCTSIZ(15)),
+       dump_register(HCDMA(0)),
+       dump_register(HCDMA(1)),
+       dump_register(HCDMA(2)),
+       dump_register(HCDMA(3)),
+       dump_register(HCDMA(4)),
+       dump_register(HCDMA(5)),
+       dump_register(HCDMA(6)),
+       dump_register(HCDMA(7)),
+       dump_register(HCDMA(8)),
+       dump_register(HCDMA(9)),
+       dump_register(HCDMA(10)),
+       dump_register(HCDMA(11)),
+       dump_register(HCDMA(12)),
+       dump_register(HCDMA(13)),
+       dump_register(HCDMA(14)),
+       dump_register(HCDMA(15)),
+       dump_register(HCDMAB(0)),
+       dump_register(HCDMAB(1)),
+       dump_register(HCDMAB(2)),
+       dump_register(HCDMAB(3)),
+       dump_register(HCDMAB(4)),
+       dump_register(HCDMAB(5)),
+       dump_register(HCDMAB(6)),
+       dump_register(HCDMAB(7)),
+       dump_register(HCDMAB(8)),
+       dump_register(HCDMAB(9)),
+       dump_register(HCDMAB(10)),
+       dump_register(HCDMAB(11)),
+       dump_register(HCDMAB(12)),
+       dump_register(HCDMAB(13)),
+       dump_register(HCDMAB(14)),
+       dump_register(HCDMAB(15)),
+};
+
+int dwc2_debugfs_init(struct dwc2_hsotg *hsotg)
+{
+       int                     ret;
+       struct dentry           *file;
+
+       hsotg->debug_root = debugfs_create_dir(dev_name(hsotg->dev), NULL);
+       if (!hsotg->debug_root) {
+               ret = -ENOMEM;
+               goto err0;
+       }
+
+       /* Add gadget debugfs nodes */
+       s3c_hsotg_create_debug(hsotg);
+
+       hsotg->regset = devm_kzalloc(hsotg->dev, sizeof(*hsotg->regset),
+                                                               GFP_KERNEL);
+       if (!hsotg->regset) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       hsotg->regset->regs = dwc2_regs;
+       hsotg->regset->nregs = ARRAY_SIZE(dwc2_regs);
+       hsotg->regset->base = hsotg->regs;
+
+       file = debugfs_create_regset32("regdump", S_IRUGO, hsotg->debug_root,
+                                                               hsotg->regset);
+       if (!file) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       return 0;
+err1:
+       debugfs_remove_recursive(hsotg->debug_root);
+err0:
+       return ret;
+}
+
+void dwc2_debugfs_exit(struct dwc2_hsotg *hsotg)
+{
+       debugfs_remove_recursive(hsotg->debug_root);
+       hsotg->debug_root = NULL;
+}
index 6a30887..4d47b7c 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/interrupt.h>
 #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>
@@ -35,7 +34,6 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/phy.h>
 #include <linux/platform_data/s3c-hsotg.h>
-#include <linux/uaccess.h>
 
 #include "core.h"
 #include "hw.h"
@@ -792,6 +790,13 @@ static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
                ep->name, req, req->length, req->buf, req->no_interrupt,
                req->zero, req->short_not_ok);
 
+       /* Prevent new request submission when controller is suspended */
+       if (hs->lx_state == DWC2_L2) {
+               dev_dbg(hs->dev, "%s: don't submit request while suspended\n",
+                               __func__);
+               return -EAGAIN;
+       }
+
        /* initialise status of the request */
        INIT_LIST_HEAD(&hs_req->queue);
        req->actual = 0;
@@ -894,7 +899,7 @@ static struct s3c_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
  * @testmode: requested usb test mode
  * Enable usb Test Mode requested by the Host.
  */
-static int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode)
+int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode)
 {
        int dctl = readl(hsotg->regs + DCTL);
 
@@ -2185,7 +2190,6 @@ void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg)
 
        call_gadget(hsotg, disconnect);
 }
-EXPORT_SYMBOL_GPL(s3c_hsotg_disconnect);
 
 /**
  * s3c_hsotg_irq_fifoempty - TX FIFO empty interrupt handler
@@ -2310,8 +2314,9 @@ void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
        writel(GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT |
                GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF |
                GINTSTS_CONIDSTSCHNG | GINTSTS_USBRST |
-               GINTSTS_ENUMDONE | GINTSTS_OTGINT |
-               GINTSTS_USBSUSP | GINTSTS_WKUPINT,
+               GINTSTS_RESETDET | GINTSTS_ENUMDONE |
+               GINTSTS_OTGINT | GINTSTS_USBSUSP |
+               GINTSTS_WKUPINT,
                hsotg->regs + GINTMSK);
 
        if (using_dma(hsotg))
@@ -2477,7 +2482,19 @@ irq_retry:
                }
        }
 
-       if (gintsts & GINTSTS_USBRST) {
+       if (gintsts & GINTSTS_RESETDET) {
+               dev_dbg(hsotg->dev, "%s: USBRstDet\n", __func__);
+
+               writel(GINTSTS_RESETDET, hsotg->regs + GINTSTS);
+
+               /* This event must be used only if controller is suspended */
+               if (hsotg->lx_state == DWC2_L2) {
+                       dwc2_exit_hibernation(hsotg, true);
+                       hsotg->lx_state = DWC2_L0;
+               }
+       }
+
+       if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) {
 
                u32 usb_status = readl(hsotg->regs + GOTGCTL);
 
@@ -2497,6 +2514,7 @@ irq_retry:
                                kill_all_requests(hsotg, hsotg->eps_out[0],
                                                          -ECONNRESET);
 
+                               hsotg->lx_state = DWC2_L0;
                                s3c_hsotg_core_init_disconnected(hsotg, true);
                        }
                }
@@ -2745,7 +2763,7 @@ error:
  * s3c_hsotg_ep_disable - disable given endpoint
  * @ep: The endpoint to disable.
  */
-static int s3c_hsotg_ep_disable_force(struct usb_ep *ep, bool force)
+static int s3c_hsotg_ep_disable(struct usb_ep *ep)
 {
        struct s3c_hsotg_ep *hs_ep = our_ep(ep);
        struct dwc2_hsotg *hsotg = hs_ep->parent;
@@ -2788,10 +2806,6 @@ static int s3c_hsotg_ep_disable_force(struct usb_ep *ep, bool force)
        return 0;
 }
 
-static int s3c_hsotg_ep_disable(struct usb_ep *ep)
-{
-       return s3c_hsotg_ep_disable_force(ep, false);
-}
 /**
  * on_list - check request is on the given endpoint
  * @ep: The endpoint to check.
@@ -3187,6 +3201,14 @@ static int s3c_hsotg_vbus_session(struct usb_gadget *gadget, int is_active)
        spin_lock_irqsave(&hsotg->lock, flags);
 
        if (is_active) {
+               /*
+                * If controller is hibernated, it must exit from hibernation
+                * before being initialized
+                */
+               if (hsotg->lx_state == DWC2_L2) {
+                       dwc2_exit_hibernation(hsotg, false);
+                       hsotg->lx_state = DWC2_L0;
+               }
                /* Kill any ep0 requests as controller will be reinitialized */
                kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET);
                s3c_hsotg_core_init_disconnected(hsotg, false);
@@ -3391,404 +3413,6 @@ static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg)
 #endif
 }
 
-/**
- * testmode_write - debugfs: change usb test mode
- * @seq: The seq file to write to.
- * @v: Unused parameter.
- *
- * This debugfs entry modify the current usb test mode.
- */
-static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t
-               count, loff_t *ppos)
-{
-       struct seq_file         *s = file->private_data;
-       struct dwc2_hsotg       *hsotg = s->private;
-       unsigned long           flags;
-       u32                     testmode = 0;
-       char                    buf[32];
-
-       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
-               return -EFAULT;
-
-       if (!strncmp(buf, "test_j", 6))
-               testmode = TEST_J;
-       else if (!strncmp(buf, "test_k", 6))
-               testmode = TEST_K;
-       else if (!strncmp(buf, "test_se0_nak", 12))
-               testmode = TEST_SE0_NAK;
-       else if (!strncmp(buf, "test_packet", 11))
-               testmode = TEST_PACKET;
-       else if (!strncmp(buf, "test_force_enable", 17))
-               testmode = TEST_FORCE_EN;
-       else
-               testmode = 0;
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-       s3c_hsotg_set_test_mode(hsotg, testmode);
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-       return count;
-}
-
-/**
- * testmode_show - debugfs: show usb test mode state
- * @seq: The seq file to write to.
- * @v: Unused parameter.
- *
- * This debugfs entry shows which usb test mode is currently enabled.
- */
-static int testmode_show(struct seq_file *s, void *unused)
-{
-       struct dwc2_hsotg *hsotg = s->private;
-       unsigned long flags;
-       int dctl;
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-       dctl = readl(hsotg->regs + DCTL);
-       dctl &= DCTL_TSTCTL_MASK;
-       dctl >>= DCTL_TSTCTL_SHIFT;
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-
-       switch (dctl) {
-       case 0:
-               seq_puts(s, "no test\n");
-               break;
-       case TEST_J:
-               seq_puts(s, "test_j\n");
-               break;
-       case TEST_K:
-               seq_puts(s, "test_k\n");
-               break;
-       case TEST_SE0_NAK:
-               seq_puts(s, "test_se0_nak\n");
-               break;
-       case TEST_PACKET:
-               seq_puts(s, "test_packet\n");
-               break;
-       case TEST_FORCE_EN:
-               seq_puts(s, "test_force_enable\n");
-               break;
-       default:
-               seq_printf(s, "UNKNOWN %d\n", dctl);
-       }
-
-       return 0;
-}
-
-static int testmode_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, testmode_show, inode->i_private);
-}
-
-static const struct file_operations testmode_fops = {
-       .owner          = THIS_MODULE,
-       .open           = testmode_open,
-       .write          = testmode_write,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-/**
- * state_show - debugfs: show overall driver and device state.
- * @seq: The seq file to write to.
- * @v: Unused parameter.
- *
- * This debugfs entry shows the overall state of the hardware and
- * some general information about each of the endpoints available
- * to the system.
- */
-static int state_show(struct seq_file *seq, void *v)
-{
-       struct dwc2_hsotg *hsotg = seq->private;
-       void __iomem *regs = hsotg->regs;
-       int idx;
-
-       seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n",
-                readl(regs + DCFG),
-                readl(regs + DCTL),
-                readl(regs + DSTS));
-
-       seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n",
-                  readl(regs + DIEPMSK), readl(regs + DOEPMSK));
-
-       seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n",
-                  readl(regs + GINTMSK),
-                  readl(regs + GINTSTS));
-
-       seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n",
-                  readl(regs + DAINTMSK),
-                  readl(regs + DAINT));
-
-       seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n",
-                  readl(regs + GNPTXSTS),
-                  readl(regs + GRXSTSR));
-
-       seq_puts(seq, "\nEndpoint status:\n");
-
-       for (idx = 0; idx < hsotg->num_of_eps; idx++) {
-               u32 in, out;
-
-               in = readl(regs + DIEPCTL(idx));
-               out = readl(regs + DOEPCTL(idx));
-
-               seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x",
-                          idx, in, out);
-
-               in = readl(regs + DIEPTSIZ(idx));
-               out = readl(regs + DOEPTSIZ(idx));
-
-               seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",
-                          in, out);
-
-               seq_puts(seq, "\n");
-       }
-
-       return 0;
-}
-
-static int state_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, state_show, inode->i_private);
-}
-
-static const struct file_operations state_fops = {
-       .owner          = THIS_MODULE,
-       .open           = state_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-/**
- * fifo_show - debugfs: show the fifo information
- * @seq: The seq_file to write data to.
- * @v: Unused parameter.
- *
- * Show the FIFO information for the overall fifo and all the
- * periodic transmission FIFOs.
- */
-static int fifo_show(struct seq_file *seq, void *v)
-{
-       struct dwc2_hsotg *hsotg = seq->private;
-       void __iomem *regs = hsotg->regs;
-       u32 val;
-       int idx;
-
-       seq_puts(seq, "Non-periodic FIFOs:\n");
-       seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ));
-
-       val = readl(regs + GNPTXFSIZ);
-       seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",
-                  val >> FIFOSIZE_DEPTH_SHIFT,
-                  val & FIFOSIZE_DEPTH_MASK);
-
-       seq_puts(seq, "\nPeriodic TXFIFOs:\n");
-
-       for (idx = 1; idx < hsotg->num_of_eps; idx++) {
-               val = readl(regs + DPTXFSIZN(idx));
-
-               seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
-                          val >> FIFOSIZE_DEPTH_SHIFT,
-                          val & FIFOSIZE_STARTADDR_MASK);
-       }
-
-       return 0;
-}
-
-static int fifo_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, fifo_show, inode->i_private);
-}
-
-static const struct file_operations fifo_fops = {
-       .owner          = THIS_MODULE,
-       .open           = fifo_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-
-static const char *decode_direction(int is_in)
-{
-       return is_in ? "in" : "out";
-}
-
-/**
- * ep_show - debugfs: show the state of an endpoint.
- * @seq: The seq_file to write data to.
- * @v: Unused parameter.
- *
- * This debugfs entry shows the state of the given endpoint (one is
- * registered for each available).
- */
-static int ep_show(struct seq_file *seq, void *v)
-{
-       struct s3c_hsotg_ep *ep = seq->private;
-       struct dwc2_hsotg *hsotg = ep->parent;
-       struct s3c_hsotg_req *req;
-       void __iomem *regs = hsotg->regs;
-       int index = ep->index;
-       int show_limit = 15;
-       unsigned long flags;
-
-       seq_printf(seq, "Endpoint index %d, named %s,  dir %s:\n",
-                  ep->index, ep->ep.name, decode_direction(ep->dir_in));
-
-       /* first show the register state */
-
-       seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n",
-                  readl(regs + DIEPCTL(index)),
-                  readl(regs + DOEPCTL(index)));
-
-       seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n",
-                  readl(regs + DIEPDMA(index)),
-                  readl(regs + DOEPDMA(index)));
-
-       seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n",
-                  readl(regs + DIEPINT(index)),
-                  readl(regs + DOEPINT(index)));
-
-       seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n",
-                  readl(regs + DIEPTSIZ(index)),
-                  readl(regs + DOEPTSIZ(index)));
-
-       seq_puts(seq, "\n");
-       seq_printf(seq, "mps %d\n", ep->ep.maxpacket);
-       seq_printf(seq, "total_data=%ld\n", ep->total_data);
-
-       seq_printf(seq, "request list (%p,%p):\n",
-                  ep->queue.next, ep->queue.prev);
-
-       spin_lock_irqsave(&hsotg->lock, flags);
-
-       list_for_each_entry(req, &ep->queue, queue) {
-               if (--show_limit < 0) {
-                       seq_puts(seq, "not showing more requests...\n");
-                       break;
-               }
-
-               seq_printf(seq, "%c req %p: %d bytes @%p, ",
-                          req == ep->req ? '*' : ' ',
-                          req, req->req.length, req->req.buf);
-               seq_printf(seq, "%d done, res %d\n",
-                          req->req.actual, req->req.status);
-       }
-
-       spin_unlock_irqrestore(&hsotg->lock, flags);
-
-       return 0;
-}
-
-static int ep_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, ep_show, inode->i_private);
-}
-
-static const struct file_operations ep_fops = {
-       .owner          = THIS_MODULE,
-       .open           = ep_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-/**
- * s3c_hsotg_create_debug - create debugfs directory and files
- * @hsotg: The driver state
- *
- * Create the debugfs files to allow the user to get information
- * about the state of the system. The directory name is created
- * 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 dwc2_hsotg *hsotg)
-{
-       struct dentry *root;
-       unsigned epidx;
-
-       root = debugfs_create_dir(dev_name(hsotg->dev), NULL);
-       hsotg->debug_root = root;
-       if (IS_ERR(root)) {
-               dev_err(hsotg->dev, "cannot create debug root\n");
-               return;
-       }
-
-       /* create general state file */
-
-       hsotg->debug_file = debugfs_create_file("state", S_IRUGO, root,
-                                               hsotg, &state_fops);
-
-       if (IS_ERR(hsotg->debug_file))
-               dev_err(hsotg->dev, "%s: failed to create state\n", __func__);
-
-       hsotg->debug_testmode = debugfs_create_file("testmode",
-                                       S_IRUGO | S_IWUSR, root,
-                                       hsotg, &testmode_fops);
-
-       if (IS_ERR(hsotg->debug_testmode))
-               dev_err(hsotg->dev, "%s: failed to create testmode\n",
-                               __func__);
-
-       hsotg->debug_fifo = debugfs_create_file("fifo", S_IRUGO, root,
-                                               hsotg, &fifo_fops);
-
-       if (IS_ERR(hsotg->debug_fifo))
-               dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__);
-
-       /* Create one file for each out endpoint */
-       for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
-               struct s3c_hsotg_ep *ep;
-
-               ep = hsotg->eps_out[epidx];
-               if (ep) {
-                       ep->debugfs = debugfs_create_file(ep->name, S_IRUGO,
-                                                         root, ep, &ep_fops);
-
-                       if (IS_ERR(ep->debugfs))
-                               dev_err(hsotg->dev, "failed to create %s debug file\n",
-                                       ep->name);
-               }
-       }
-       /* Create one file for each in endpoint. EP0 is handled with out eps */
-       for (epidx = 1; epidx < hsotg->num_of_eps; epidx++) {
-               struct s3c_hsotg_ep *ep;
-
-               ep = hsotg->eps_in[epidx];
-               if (ep) {
-                       ep->debugfs = debugfs_create_file(ep->name, S_IRUGO,
-                                                         root, ep, &ep_fops);
-
-                       if (IS_ERR(ep->debugfs))
-                               dev_err(hsotg->dev, "failed to create %s debug file\n",
-                                       ep->name);
-               }
-       }
-}
-
-/**
- * s3c_hsotg_delete_debug - cleanup debugfs entries
- * @hsotg: The driver state
- *
- * Cleanup (remove) the debugfs files for use on module exit.
- */
-static void s3c_hsotg_delete_debug(struct dwc2_hsotg *hsotg)
-{
-       unsigned epidx;
-
-       for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
-               if (hsotg->eps_in[epidx])
-                       debugfs_remove(hsotg->eps_in[epidx]->debugfs);
-               if (hsotg->eps_out[epidx])
-                       debugfs_remove(hsotg->eps_out[epidx]->debugfs);
-       }
-
-       debugfs_remove(hsotg->debug_file);
-       debugfs_remove(hsotg->debug_testmode);
-       debugfs_remove(hsotg->debug_fifo);
-       debugfs_remove(hsotg->debug_root);
-}
-
 #ifdef CONFIG_OF
 static void s3c_hsotg_of_probe(struct dwc2_hsotg *hsotg)
 {
@@ -3896,6 +3520,8 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
        hsotg->gadget.max_speed = USB_SPEED_HIGH;
        hsotg->gadget.ops = &s3c_hsotg_gadget_ops;
        hsotg->gadget.name = dev_name(dev);
+       if (hsotg->dr_mode == USB_DR_MODE_OTG)
+               hsotg->gadget.is_otg = 1;
 
        /* reset the system */
 
@@ -4028,8 +3654,6 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
        if (ret)
                goto err_supplies;
 
-       s3c_hsotg_create_debug(hsotg);
-
        s3c_hsotg_dump(hsotg);
 
        return 0;
@@ -4041,7 +3665,6 @@ err_clk:
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(dwc2_gadget_init);
 
 /**
  * s3c_hsotg_remove - remove function for hsotg driver
@@ -4050,18 +3673,19 @@ EXPORT_SYMBOL_GPL(dwc2_gadget_init);
 int s3c_hsotg_remove(struct dwc2_hsotg *hsotg)
 {
        usb_del_gadget_udc(&hsotg->gadget);
-       s3c_hsotg_delete_debug(hsotg);
        clk_disable_unprepare(hsotg->clk);
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(s3c_hsotg_remove);
 
 int s3c_hsotg_suspend(struct dwc2_hsotg *hsotg)
 {
        unsigned long flags;
        int ret = 0;
 
+       if (hsotg->lx_state != DWC2_L0)
+               return ret;
+
        mutex_lock(&hsotg->init_mutex);
 
        if (hsotg->driver) {
@@ -4095,13 +3719,15 @@ int s3c_hsotg_suspend(struct dwc2_hsotg *hsotg)
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(s3c_hsotg_suspend);
 
 int s3c_hsotg_resume(struct dwc2_hsotg *hsotg)
 {
        unsigned long flags;
        int ret = 0;
 
+       if (hsotg->lx_state == DWC2_L2)
+               return ret;
+
        mutex_lock(&hsotg->init_mutex);
 
        if (hsotg->driver) {
@@ -4124,4 +3750,3 @@ int s3c_hsotg_resume(struct dwc2_hsotg *hsotg)
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(s3c_hsotg_resume);
index fbbbac2..b10377c 100644 (file)
@@ -357,12 +357,12 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
        writel(0, hsotg->regs + HPRT0);
 }
 
+/* Caller must hold driver lock */
 static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
                                struct dwc2_hcd_urb *urb, void **ep_handle,
                                gfp_t mem_flags)
 {
        struct dwc2_qtd *qtd;
-       unsigned long flags;
        u32 intr_mask;
        int retval;
        int dev_speed;
@@ -413,11 +413,9 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
                         */
                        return 0;
 
-               spin_lock_irqsave(&hsotg->lock, flags);
                tr_type = dwc2_hcd_select_transactions(hsotg);
                if (tr_type != DWC2_TRANSACTION_NONE)
                        dwc2_hcd_queue_transactions(hsotg, tr_type);
-               spin_unlock_irqrestore(&hsotg->lock, flags);
        }
 
        return 0;
@@ -721,9 +719,7 @@ static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
                        /* 3072 = 3 max-size Isoc packets */
                        buf_size = 3072;
 
-               qh->dw_align_buf = dma_alloc_coherent(hsotg->dev, buf_size,
-                                                     &qh->dw_align_buf_dma,
-                                                     GFP_ATOMIC);
+               qh->dw_align_buf = kmalloc(buf_size, GFP_ATOMIC | GFP_DMA);
                if (!qh->dw_align_buf)
                        return -ENOMEM;
                qh->dw_align_buf_size = buf_size;
@@ -748,6 +744,15 @@ static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
                }
        }
 
+       qh->dw_align_buf_dma = dma_map_single(hsotg->dev,
+                       qh->dw_align_buf, qh->dw_align_buf_size,
+                       chan->ep_is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+       if (dma_mapping_error(hsotg->dev, qh->dw_align_buf_dma)) {
+               dev_err(hsotg->dev, "can't map align_buf\n");
+               chan->align_buf = 0;
+               return -EINVAL;
+       }
+
        chan->align_buf = qh->dw_align_buf_dma;
        return 0;
 }
@@ -1774,6 +1779,15 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
                        /* Not supported */
                        break;
 
+               case USB_PORT_FEAT_TEST:
+                       hprt0 = dwc2_read_hprt0(hsotg);
+                       dev_dbg(hsotg->dev,
+                               "SetPortFeature - USB_PORT_FEAT_TEST\n");
+                       hprt0 &= ~HPRT0_TSTCTL_MASK;
+                       hprt0 |= (windex >> 8) << HPRT0_TSTCTL_SHIFT;
+                       writel(hprt0, hsotg->regs + HPRT0);
+                       break;
+
                default:
                        retval = -EINVAL;
                        dev_err(hsotg->dev,
@@ -2313,6 +2327,22 @@ 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);
+
+       hsotg->lx_state = DWC2_L2;
+       return 0;
+}
+
+static int _dwc2_hcd_resume(struct usb_hcd *hcd)
+{
+       struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+       hsotg->lx_state = DWC2_L0;
+       return 0;
+}
+
 /* Returns the current frame number */
 static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
 {
@@ -2468,7 +2498,7 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                                "%s: unaligned transfer with no transfer_buffer",
                                __func__);
                        retval = -EINVAL;
-                       goto fail1;
+                       goto fail0;
                }
        }
 
@@ -2496,7 +2526,6 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
 
        spin_lock_irqsave(&hsotg->lock, flags);
        retval = usb_hcd_link_urb_to_ep(hcd, urb);
-       spin_unlock_irqrestore(&hsotg->lock, flags);
        if (retval)
                goto fail1;
 
@@ -2505,22 +2534,22 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                goto fail2;
 
        if (alloc_bandwidth) {
-               spin_lock_irqsave(&hsotg->lock, flags);
                dwc2_allocate_bus_bandwidth(hcd,
                                dwc2_hcd_get_ep_bandwidth(hsotg, ep),
                                urb);
-               spin_unlock_irqrestore(&hsotg->lock, flags);
        }
 
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+
        return 0;
 
 fail2:
-       spin_lock_irqsave(&hsotg->lock, flags);
        dwc2_urb->priv = NULL;
        usb_hcd_unlink_urb_from_ep(hcd, urb);
-       spin_unlock_irqrestore(&hsotg->lock, flags);
 fail1:
+       spin_unlock_irqrestore(&hsotg->lock, flags);
        urb->hcpriv = NULL;
+fail0:
        kfree(dwc2_urb);
 
        return retval;
@@ -2683,6 +2712,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,
 };
 
 /*
@@ -2748,8 +2780,6 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
                destroy_workqueue(hsotg->wq_otg);
        }
 
-       kfree(hsotg->core_params);
-       hsotg->core_params = NULL;
        del_timer(&hsotg->wkp_timer);
 }
 
@@ -2762,29 +2792,12 @@ static void dwc2_hcd_release(struct dwc2_hsotg *hsotg)
 }
 
 /*
- * Sets all parameters to the given value.
- *
- * Assumes that the dwc2_core_params struct contains only integers.
- */
-void dwc2_set_all_params(struct dwc2_core_params *params, int value)
-{
-       int *p = (int *)params;
-       size_t size = sizeof(*params) / sizeof(*p);
-       int i;
-
-       for (i = 0; i < size; i++)
-               p[i] = value;
-}
-EXPORT_SYMBOL_GPL(dwc2_set_all_params);
-
-/*
  * Initializes the HCD. This function allocates memory for and initializes the
  * static parts of the usb_hcd and dwc2_hsotg structures. It also registers the
  * USB bus with the core and calls the hc_driver->start() function. It returns
  * a negative error on failure.
  */
-int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
-                 const struct dwc2_core_params *params)
+int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
 {
        struct usb_hcd *hcd;
        struct dwc2_host_chan *channel;
@@ -2797,12 +2810,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
 
        dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n");
 
-       /* Detect config values from hardware */
-       retval = dwc2_get_hwparams(hsotg);
-
-       if (retval)
-               return retval;
-
        retval = -ENOMEM;
 
        hcfg = readl(hsotg->regs + HCFG);
@@ -2821,15 +2828,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
        hsotg->last_frame_num = HFNUM_MAX_FRNUM;
 #endif
 
-       hsotg->core_params = kzalloc(sizeof(*hsotg->core_params), GFP_KERNEL);
-       if (!hsotg->core_params)
-               goto error1;
-
-       dwc2_set_all_params(hsotg->core_params, -1);
-
-       /* Validate parameter values */
-       dwc2_set_parameters(hsotg, params);
-
        /* Check if the bus driver or platform code has setup a dma_mask */
        if (hsotg->core_params->dma_enable > 0 &&
            hsotg->dev->dma_mask == NULL) {
@@ -2947,6 +2945,9 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
        /* Don't support SG list at this point */
        hcd->self.sg_tablesize = 0;
 
+       if (!IS_ERR_OR_NULL(hsotg->uphy))
+               otg_set_host(hsotg->uphy->otg, &hcd->self);
+
        /*
         * Finish generic HCD initialization and start the HCD. This function
         * allocates the DMA buffer pool, registers the USB bus, requests the
@@ -2979,7 +2980,6 @@ error1:
        dev_err(hsotg->dev, "%s() FAILED, returning %d\n", __func__, retval);
        return retval;
 }
-EXPORT_SYMBOL_GPL(dwc2_hcd_init);
 
 /*
  * Removes the HCD.
@@ -3000,6 +3000,9 @@ void dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
                return;
        }
 
+       if (!IS_ERR_OR_NULL(hsotg->uphy))
+               otg_set_host(hsotg->uphy->otg, NULL);
+
        usb_remove_hcd(hcd);
        hsotg->priv = NULL;
        dwc2_hcd_release(hsotg);
@@ -3010,4 +3013,3 @@ void dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
        kfree(hsotg->frame_num_array);
 #endif
 }
-EXPORT_SYMBOL_GPL(dwc2_hcd_remove);
index e69a843..7b5841c 100644 (file)
@@ -451,13 +451,8 @@ static inline u8 dwc2_hcd_is_pipe_out(struct dwc2_hcd_pipe_info *pipe)
        return !dwc2_hcd_is_pipe_in(pipe);
 }
 
-extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
-                        const struct dwc2_core_params *params);
+extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq);
 extern void dwc2_hcd_remove(struct dwc2_hsotg *hsotg);
-extern void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
-                               const struct dwc2_core_params *params);
-extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
-extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
 
 /* Transaction Execution Functions */
 extern enum dwc2_transaction_type dwc2_hcd_select_transactions(
index 551ba87..4cc95df 100644 (file)
@@ -350,6 +350,9 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
                dev_vdbg(hsotg->dev,
                         "--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n",
                         hprt0);
+               if (hsotg->lx_state != DWC2_L0)
+                       usb_hcd_resume_root_hub(hsotg->priv);
+
                hsotg->flags.b.port_connect_status_change = 1;
                hsotg->flags.b.port_connect_status = 1;
                hprt0_modify |= HPRT0_CONNDET;
@@ -463,10 +466,15 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
        }
 
        /* Non DWORD-aligned buffer case handling */
-       if (chan->align_buf && xfer_length && chan->ep_is_in) {
+       if (chan->align_buf && xfer_length) {
                dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
-               memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
-                      xfer_length);
+               dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                               chan->qh->dw_align_buf_size,
+                               chan->ep_is_in ?
+                               DMA_FROM_DEVICE : DMA_TO_DEVICE);
+               if (chan->ep_is_in)
+                       memcpy(urb->buf + urb->actual_length,
+                                       chan->qh->dw_align_buf, xfer_length);
        }
 
        dev_vdbg(hsotg->dev, "urb->actual_length=%d xfer_length=%d\n",
@@ -552,13 +560,18 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
                                        chan, chnum, qtd, halt_status, NULL);
 
                /* Non DWORD-aligned buffer case handling */
-               if (chan->align_buf && frame_desc->actual_length &&
-                   chan->ep_is_in) {
+               if (chan->align_buf && frame_desc->actual_length) {
                        dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
                                 __func__);
-                       memcpy(urb->buf + frame_desc->offset +
-                              qtd->isoc_split_offset, chan->qh->dw_align_buf,
-                              frame_desc->actual_length);
+                       dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                                       chan->qh->dw_align_buf_size,
+                                       chan->ep_is_in ?
+                                       DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                       if (chan->ep_is_in)
+                               memcpy(urb->buf + frame_desc->offset +
+                                       qtd->isoc_split_offset,
+                                       chan->qh->dw_align_buf,
+                                       frame_desc->actual_length);
                }
                break;
        case DWC2_HC_XFER_FRAME_OVERRUN:
@@ -581,13 +594,18 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
                                        chan, chnum, qtd, halt_status, NULL);
 
                /* Non DWORD-aligned buffer case handling */
-               if (chan->align_buf && frame_desc->actual_length &&
-                   chan->ep_is_in) {
+               if (chan->align_buf && frame_desc->actual_length) {
                        dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
                                 __func__);
-                       memcpy(urb->buf + frame_desc->offset +
-                              qtd->isoc_split_offset, chan->qh->dw_align_buf,
-                              frame_desc->actual_length);
+                       dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                                       chan->qh->dw_align_buf_size,
+                                       chan->ep_is_in ?
+                                       DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                       if (chan->ep_is_in)
+                               memcpy(urb->buf + frame_desc->offset +
+                                       qtd->isoc_split_offset,
+                                       chan->qh->dw_align_buf,
+                                       frame_desc->actual_length);
                }
 
                /* Skip whole frame */
@@ -923,6 +941,8 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
 
        if (chan->align_buf) {
                dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+               dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                               chan->qh->dw_align_buf_size, DMA_FROM_DEVICE);
                memcpy(qtd->urb->buf + frame_desc->offset +
                       qtd->isoc_split_offset, chan->qh->dw_align_buf, len);
        }
@@ -1152,8 +1172,14 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
        /* Non DWORD-aligned buffer case handling */
        if (chan->align_buf && xfer_length && chan->ep_is_in) {
                dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
-               memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
-                      xfer_length);
+               dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
+                               chan->qh->dw_align_buf_size,
+                               chan->ep_is_in ?
+                               DMA_FROM_DEVICE : DMA_TO_DEVICE);
+               if (chan->ep_is_in)
+                       memcpy(urb->buf + urb->actual_length,
+                                       chan->qh->dw_align_buf,
+                                       xfer_length);
        }
 
        urb->actual_length += xfer_length;
@@ -1182,6 +1208,16 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg,
                             struct dwc2_host_chan *chan, int chnum,
                             struct dwc2_qtd *qtd)
 {
+       if (!qtd) {
+               dev_dbg(hsotg->dev, "%s: qtd is NULL\n", __func__);
+               return;
+       }
+
+       if (!qtd->urb) {
+               dev_dbg(hsotg->dev, "%s: qtd->urb is NULL\n", __func__);
+               return;
+       }
+
        if (dbg_hc(chan))
                dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NAK Received--\n",
                         chnum);
index bb97838..9b5c362 100644 (file)
@@ -229,11 +229,13 @@ static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
  */
 void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 {
-       if (hsotg->core_params->dma_desc_enable > 0)
+       if (hsotg->core_params->dma_desc_enable > 0) {
                dwc2_hcd_qh_free_ddma(hsotg, qh);
-       else if (qh->dw_align_buf)
-               dma_free_coherent(hsotg->dev, qh->dw_align_buf_size,
-                                 qh->dw_align_buf, qh->dw_align_buf_dma);
+       } else {
+               /* kfree(NULL) is safe */
+               kfree(qh->dw_align_buf);
+               qh->dw_align_buf_dma = (dma_addr_t)0;
+       }
        kfree(qh);
 }
 
@@ -761,6 +763,7 @@ void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
 
 /**
  * dwc2_hcd_qtd_add() - Adds a QTD to the QTD-list of a QH
+ *                     Caller must hold driver lock.
  *
  * @hsotg:        The DWC HCD structure
  * @qtd:          The QTD to add
@@ -777,7 +780,6 @@ int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
                     struct dwc2_qh **qh, gfp_t mem_flags)
 {
        struct dwc2_hcd_urb *urb = qtd->urb;
-       unsigned long flags;
        int allocated = 0;
        int retval;
 
@@ -792,15 +794,12 @@ int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
                allocated = 1;
        }
 
-       spin_lock_irqsave(&hsotg->lock, flags);
-
        retval = dwc2_hcd_qh_add(hsotg, *qh);
        if (retval)
                goto fail;
 
        qtd->qh = *qh;
        list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
-       spin_unlock_irqrestore(&hsotg->lock, flags);
 
        return 0;
 
@@ -817,10 +816,7 @@ fail:
                                         qtd_list_entry)
                        dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp);
 
-               spin_unlock_irqrestore(&hsotg->lock, flags);
                dwc2_hcd_qh_free(hsotg, qh_tmp);
-       } else {
-               spin_unlock_irqrestore(&hsotg->lock, flags);
        }
 
        return retval;
index 185663e..9093530 100644 (file)
@@ -47,6 +47,7 @@
 
 #include "core.h"
 #include "hcd.h"
+#include "debug.h"
 
 static const char dwc2_driver_name[] = "dwc2";
 
@@ -76,6 +77,8 @@ static const struct dwc2_core_params params_bcm2835 = {
        .reload_ctl                     = 0,
        .ahbcfg                         = 0x10,
        .uframe_sched                   = 0,
+       .external_id_pin_ctl            = -1,
+       .hibernation                    = -1,
 };
 
 static const struct dwc2_core_params params_rk3066 = {
@@ -104,6 +107,8 @@ static const struct dwc2_core_params params_rk3066 = {
        .reload_ctl                     = -1,
        .ahbcfg                         = 0x7, /* INCR16 */
        .uframe_sched                   = -1,
+       .external_id_pin_ctl            = -1,
+       .hibernation                    = -1,
 };
 
 /**
@@ -121,6 +126,7 @@ static int dwc2_driver_remove(struct platform_device *dev)
 {
        struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
 
+       dwc2_debugfs_exit(hsotg);
        if (hsotg->hcd_enabled)
                dwc2_hcd_remove(hsotg);
        if (hsotg->gadget_enabled)
@@ -237,6 +243,21 @@ static int dwc2_driver_probe(struct platform_device *dev)
        spin_lock_init(&hsotg->lock);
        mutex_init(&hsotg->init_mutex);
 
+       /* Detect config values from hardware */
+       retval = dwc2_get_hwparams(hsotg);
+       if (retval)
+               return retval;
+
+       hsotg->core_params = devm_kzalloc(&dev->dev,
+                               sizeof(*hsotg->core_params), GFP_KERNEL);
+       if (!hsotg->core_params)
+               return -ENOMEM;
+
+       dwc2_set_all_params(hsotg->core_params, -1);
+
+       /* Validate parameter values */
+       dwc2_set_parameters(hsotg, params);
+
        if (hsotg->dr_mode != USB_DR_MODE_HOST) {
                retval = dwc2_gadget_init(hsotg, irq);
                if (retval)
@@ -245,7 +266,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
        }
 
        if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) {
-               retval = dwc2_hcd_init(hsotg, irq, params);
+               retval = dwc2_hcd_init(hsotg, irq);
                if (retval) {
                        if (hsotg->gadget_enabled)
                                s3c_hsotg_remove(hsotg);
@@ -256,6 +277,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
 
        platform_set_drvdata(dev, hsotg);
 
+       dwc2_debugfs_init(hsotg);
+
        return retval;
 }
 
index 827c4f8..dede32e 100644 (file)
@@ -11,6 +11,13 @@ config USB_DWC3
 
 if USB_DWC3
 
+config USB_DWC3_ULPI
+       bool "Register ULPI PHY Interface"
+       depends on USB_ULPI_BUS=y || USB_ULPI_BUS=USB_DWC3
+       help
+         Select this if you have ULPI type PHY attached to your DWC3
+         controller.
+
 choice
        bool "DWC3 Mode Selection"
        default USB_DWC3_DUAL_ROLE if (USB && USB_GADGET)
index 46172f4..c7076e3 100644 (file)
@@ -15,6 +15,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
        dwc3-y                          += gadget.o ep0.o
 endif
 
+ifneq ($(CONFIG_USB_DWC3_ULPI),)
+       dwc3-y                          += ulpi.o
+endif
+
 ifneq ($(CONFIG_DEBUG_FS),)
        dwc3-y                          += debugfs.o
 endif
index 2bbab3d..5c110d8 100644 (file)
@@ -117,6 +117,33 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
 }
 
 /**
+ * dwc3_soft_reset - Issue soft reset
+ * @dwc: Pointer to our controller context structure
+ */
+static int dwc3_soft_reset(struct dwc3 *dwc)
+{
+       unsigned long timeout;
+       u32 reg;
+
+       timeout = jiffies + msecs_to_jiffies(500);
+       dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
+       do {
+               reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+               if (!(reg & DWC3_DCTL_CSFTRST))
+                       break;
+
+               if (time_after(jiffies, timeout)) {
+                       dev_err(dwc->dev, "Reset Timed Out\n");
+                       return -ETIMEDOUT;
+               }
+
+               cpu_relax();
+       } while (true);
+
+       return 0;
+}
+
+/**
  * dwc3_free_one_event_buffer - Frees one event buffer
  * @dwc: Pointer to our controller context structure
  * @evt: Pointer to event buffer to be freed
@@ -367,10 +394,15 @@ 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
+ *
+ * Returns 0 on success. The USB PHY interfaces are configured but not
+ * initialized. The PHY interfaces and the PHYs get initialized together with
+ * the core in dwc3_core_init.
  */
-static void dwc3_phy_setup(struct dwc3 *dwc)
+static int dwc3_phy_setup(struct dwc3 *dwc)
 {
        u32 reg;
+       int ret;
 
        reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
 
@@ -409,10 +441,41 @@ static void dwc3_phy_setup(struct dwc3 *dwc)
 
        dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
 
-       mdelay(100);
-
        reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
 
+       /* Select the HS PHY interface */
+       switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
+       case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI:
+               if (!strncmp(dwc->hsphy_interface, "utmi", 4)) {
+                       reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI;
+                       break;
+               } else if (!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
+                       reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
+                       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+               } else {
+                       dev_warn(dwc->dev, "HSPHY Interface not defined\n");
+
+                       /* Relying on default value. */
+                       if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
+                               break;
+               }
+               /* FALLTHROUGH */
+       case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
+               /* Making sure the interface and PHY are operational */
+               ret = dwc3_soft_reset(dwc);
+               if (ret)
+                       return ret;
+
+               udelay(1);
+
+               ret = dwc3_ulpi_init(dwc);
+               if (ret)
+                       return ret;
+               /* FALLTHROUGH */
+       default:
+               break;
+       }
+
        /*
         * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
         * '0' during coreConsultant configuration. So default value will
@@ -427,7 +490,7 @@ static void dwc3_phy_setup(struct dwc3 *dwc)
 
        dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 
-       mdelay(100);
+       return 0;
 }
 
 /**
@@ -438,7 +501,6 @@ static void dwc3_phy_setup(struct dwc3 *dwc)
  */
 static int dwc3_core_init(struct dwc3 *dwc)
 {
-       unsigned long           timeout;
        u32                     hwparams4 = dwc->hwparams.hwparams4;
        u32                     reg;
        int                     ret;
@@ -466,21 +528,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
        }
 
        /* issue device SoftReset too */
-       timeout = jiffies + msecs_to_jiffies(500);
-       dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
-       do {
-               reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-               if (!(reg & DWC3_DCTL_CSFTRST))
-                       break;
-
-               if (time_after(jiffies, timeout)) {
-                       dev_err(dwc->dev, "Reset Timed Out\n");
-                       ret = -ETIMEDOUT;
-                       goto err0;
-               }
-
-               cpu_relax();
-       } while (true);
+       ret = dwc3_soft_reset(dwc);
+       if (ret)
+               goto err0;
 
        ret = dwc3_core_soft_reset(dwc);
        if (ret)
@@ -555,8 +605,6 @@ 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;
@@ -836,6 +884,8 @@ static int dwc3_probe(struct platform_device *pdev)
                                "snps,tx_de_emphasis_quirk");
                of_property_read_u8(node, "snps,tx_de_emphasis",
                                &tx_de_emphasis);
+               of_property_read_string(node, "snps,hsphy_interface",
+                                       &dwc->hsphy_interface);
        } else if (pdata) {
                dwc->maximum_speed = pdata->maximum_speed;
                dwc->has_lpm_erratum = pdata->has_lpm_erratum;
@@ -863,6 +913,8 @@ static int dwc3_probe(struct platform_device *pdev)
                dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
                if (pdata->tx_de_emphasis)
                        tx_de_emphasis = pdata->tx_de_emphasis;
+
+               dwc->hsphy_interface = pdata->hsphy_interface;
        }
 
        /* default to superspeed if no maximum_speed passed */
@@ -875,12 +927,18 @@ static int dwc3_probe(struct platform_device *pdev)
        dwc->hird_threshold = hird_threshold
                | (dwc->is_utmi_l1_suspend << 4);
 
+       platform_set_drvdata(pdev, dwc);
+       dwc3_cache_hwparams(dwc);
+
+       ret = dwc3_phy_setup(dwc);
+       if (ret)
+               goto err0;
+
        ret = dwc3_core_get_phy(dwc);
        if (ret)
                goto err0;
 
        spin_lock_init(&dwc->lock);
-       platform_set_drvdata(pdev, dwc);
 
        if (!dev->dma_mask) {
                dev->dma_mask = dev->parent->dma_mask;
@@ -892,8 +950,6 @@ static int dwc3_probe(struct platform_device *pdev)
        pm_runtime_get_sync(dev);
        pm_runtime_forbid(dev);
 
-       dwc3_cache_hwparams(dwc);
-
        ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
        if (ret) {
                dev_err(dwc->dev, "failed to allocate event buffers\n");
@@ -964,6 +1020,7 @@ err2:
 
 err1:
        dwc3_free_event_buffers(dwc);
+       dwc3_ulpi_exit(dwc);
 
 err0:
        /*
@@ -999,6 +1056,7 @@ static int dwc3_remove(struct platform_device *pdev)
        phy_power_off(dwc->usb3_generic_phy);
 
        dwc3_core_exit(dwc);
+       dwc3_ulpi_exit(dwc);
 
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
index c0eafa6..0447788 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
+#include <linux/ulpi/interface.h>
 
 #include <linux/phy/phy.h>
 
 /* Global USB2 PHY Configuration Register */
 #define DWC3_GUSB2PHYCFG_PHYSOFTRST    (1 << 31)
 #define DWC3_GUSB2PHYCFG_SUSPHY                (1 << 6)
+#define DWC3_GUSB2PHYCFG_ULPI_UTMI     (1 << 4)
+
+/* Global USB2 PHY Vendor Control Register */
+#define DWC3_GUSB2PHYACC_NEWREGREQ     (1 << 25)
+#define DWC3_GUSB2PHYACC_BUSY          (1 << 23)
+#define DWC3_GUSB2PHYACC_WRITE         (1 << 22)
+#define DWC3_GUSB2PHYACC_ADDR(n)       (n << 16)
+#define DWC3_GUSB2PHYACC_EXTEND_ADDR(n)        (n << 8)
+#define DWC3_GUSB2PHYACC_DATA(n)       (n & 0xff)
 
 /* Global USB3 PIPE Control Register */
 #define DWC3_GUSB3PIPECTL_PHYSOFTRST   (1 << 31)
@@ -652,6 +662,7 @@ struct dwc3_scratchpad_array {
  * @usb3_phy: pointer to USB3 PHY
  * @usb2_generic_phy: pointer to USB2 PHY
  * @usb3_generic_phy: pointer to USB3 PHY
+ * @ulpi: pointer to ulpi interface
  * @dcfg: saved contents of DCFG register
  * @gctl: saved contents of GCTL register
  * @isoch_delay: wValue from Set Isochronous Delay request;
@@ -673,6 +684,7 @@ struct dwc3_scratchpad_array {
  * @test_mode_nr: test feature selector
  * @lpm_nyet_threshold: LPM NYET response threshold
  * @hird_threshold: HIRD threshold
+ * @hsphy_interface: "utmi" or "ulpi"
  * @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
@@ -739,6 +751,8 @@ struct dwc3 {
        struct phy              *usb2_generic_phy;
        struct phy              *usb3_generic_phy;
 
+       struct ulpi             *ulpi;
+
        void __iomem            *regs;
        size_t                  regs_size;
 
@@ -800,6 +814,8 @@ struct dwc3 {
        u8                      lpm_nyet_threshold;
        u8                      hird_threshold;
 
+       const char              *hsphy_interface;
+
        unsigned                delayed_status:1;
        unsigned                ep0_bounced:1;
        unsigned                ep0_expect_in:1;
@@ -1035,4 +1051,14 @@ static inline int dwc3_gadget_resume(struct dwc3 *dwc)
 }
 #endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */
 
+#if IS_ENABLED(CONFIG_USB_DWC3_ULPI)
+int dwc3_ulpi_init(struct dwc3 *dwc);
+void dwc3_ulpi_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_ulpi_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_ulpi_exit(struct dwc3 *dwc)
+{ }
+#endif
+
 #endif /* __DRIVERS_USB_DWC3_CORE_H */
index b773fb5..27e4fc8 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/acpi.h>
 
 #include "platform_data.h"
 
 #define PCI_DEVICE_ID_INTEL_SPTLP      0x9d30
 #define PCI_DEVICE_ID_INTEL_SPTH       0xa130
 
+static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
+static const struct acpi_gpio_params cs_gpios = { 1, 0, false };
+
+static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
+       { "reset-gpios", &reset_gpios, 1 },
+       { "cs-gpios", &cs_gpios, 1 },
+       { },
+};
+
 static int dwc3_pci_quirks(struct pci_dev *pdev)
 {
        if (pdev->vendor == PCI_VENDOR_ID_AMD &&
@@ -65,6 +76,30 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
                                                sizeof(pdata));
        }
 
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+           pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
+               struct gpio_desc *gpio;
+
+               acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
+                                         acpi_dwc3_byt_gpios);
+
+               /* These GPIOs will turn on the USB2 PHY */
+               gpio = gpiod_get(&pdev->dev, "cs");
+               if (!IS_ERR(gpio)) {
+                       gpiod_direction_output(gpio, 0);
+                       gpiod_set_value_cansleep(gpio, 1);
+                       gpiod_put(gpio);
+               }
+
+               gpio = gpiod_get(&pdev->dev, "reset");
+               if (!IS_ERR(gpio)) {
+                       gpiod_direction_output(gpio, 0);
+                       gpiod_set_value_cansleep(gpio, 1);
+                       gpiod_put(gpio);
+                       usleep_range(10000, 11000);
+               }
+       }
+
        return 0;
 }
 
@@ -128,6 +163,7 @@ err:
 
 static void dwc3_pci_remove(struct pci_dev *pci)
 {
+       acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pci->dev));
        platform_device_unregister(pci_get_drvdata(pci));
 }
 
index 8946c32..333a7c0 100644 (file)
@@ -291,6 +291,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
                        dwc3_trace(trace_dwc3_gadget,
                                        "Command Complete --> %d",
                                        DWC3_DGCMD_STATUS(reg));
+                       if (DWC3_DGCMD_STATUS(reg))
+                               return -EINVAL;
                        return 0;
                }
 
@@ -328,6 +330,8 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
                        dwc3_trace(trace_dwc3_gadget,
                                        "Command Complete --> %d",
                                        DWC3_DEPCMD_STATUS(reg));
+                       if (DWC3_DEPCMD_STATUS(reg))
+                               return -EINVAL;
                        return 0;
                }
 
@@ -1902,12 +1906,16 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
 {
        unsigned                status = 0;
        int                     clean_busy;
+       u32                     is_xfer_complete;
+
+       is_xfer_complete = (event->endpoint_event == DWC3_DEPEVT_XFERCOMPLETE);
 
        if (event->status & DEPEVT_STATUS_BUSERR)
                status = -ECONNRESET;
 
        clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
-       if (clean_busy)
+       if (clean_busy && (is_xfer_complete ||
+                               usb_endpoint_xfer_isoc(dep->endpoint.desc)))
                dep->flags &= ~DWC3_EP_BUSY;
 
        /*
index a2bd464..d3614ec 100644 (file)
@@ -45,4 +45,6 @@ struct dwc3_platform_data {
 
        unsigned tx_de_emphasis_quirk:1;
        unsigned tx_de_emphasis:2;
+
+       const char *hsphy_interface;
 };
diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c
new file mode 100644 (file)
index 0000000..ec004c6
--- /dev/null
@@ -0,0 +1,91 @@
+/**
+ * ulpi.c - DesignWare USB3 Controller's ULPI PHY interface
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.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/ulpi/regs.h>
+
+#include "core.h"
+#include "io.h"
+
+#define DWC3_ULPI_ADDR(a) \
+               ((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \
+               DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \
+               DWC3_GUSB2PHYACC_EXTEND_ADDR(a) : DWC3_GUSB2PHYACC_ADDR(a))
+
+static int dwc3_ulpi_busyloop(struct dwc3 *dwc)
+{
+       unsigned count = 1000;
+       u32 reg;
+
+       while (count--) {
+               reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
+               if (!(reg & DWC3_GUSB2PHYACC_BUSY))
+                       return 0;
+               cpu_relax();
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int dwc3_ulpi_read(struct ulpi_ops *ops, u8 addr)
+{
+       struct dwc3 *dwc = dev_get_drvdata(ops->dev);
+       u32 reg;
+       int ret;
+
+       reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
+       dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
+
+       ret = dwc3_ulpi_busyloop(dwc);
+       if (ret)
+               return ret;
+
+       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
+
+       return DWC3_GUSB2PHYACC_DATA(reg);
+}
+
+static int dwc3_ulpi_write(struct ulpi_ops *ops, u8 addr, u8 val)
+{
+       struct dwc3 *dwc = dev_get_drvdata(ops->dev);
+       u32 reg;
+
+       reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
+       reg |= DWC3_GUSB2PHYACC_WRITE | val;
+       dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
+
+       return dwc3_ulpi_busyloop(dwc);
+}
+
+static struct ulpi_ops dwc3_ulpi_ops = {
+       .read = dwc3_ulpi_read,
+       .write = dwc3_ulpi_write,
+};
+
+int dwc3_ulpi_init(struct dwc3 *dwc)
+{
+       /* Register the interface */
+       dwc->ulpi = ulpi_register_interface(dwc->dev, &dwc3_ulpi_ops);
+       if (IS_ERR(dwc->ulpi)) {
+               dev_err(dwc->dev, "failed to register ULPI interface");
+               return PTR_ERR(dwc->ulpi);
+       }
+
+       return 0;
+}
+
+void dwc3_ulpi_exit(struct dwc3 *dwc)
+{
+       if (dwc->ulpi) {
+               ulpi_unregister_interface(dwc->ulpi);
+               dwc->ulpi = NULL;
+       }
+}
index 0567cca..919cdfd 100644 (file)
@@ -258,15 +258,25 @@ struct usb_ep *usb_ep_autoconfig_ss(
        /* First, apply chip-specific "best usage" knowledge.
         * This might make a good usb_gadget_ops hook ...
         */
-       if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
-               /* ep-e, ep-f are PIO with only 64 byte fifos */
-               ep = find_ep (gadget, "ep-e");
-               if (ep && ep_matches(gadget, ep, desc, ep_comp))
-                       goto found_ep;
-               ep = find_ep (gadget, "ep-f");
+       if (gadget_is_net2280(gadget)) {
+               char name[8];
+
+               if (type == USB_ENDPOINT_XFER_INT) {
+                       /* ep-e, ep-f are PIO with only 64 byte fifos */
+                       ep = find_ep(gadget, "ep-e");
+                       if (ep && ep_matches(gadget, ep, desc, ep_comp))
+                               goto found_ep;
+                       ep = find_ep(gadget, "ep-f");
+                       if (ep && ep_matches(gadget, ep, desc, ep_comp))
+                               goto found_ep;
+               }
+
+               /* USB3380: use same address for usb and hardware endpoints */
+               snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc),
+                               usb_endpoint_dir_in(desc) ? "in" : "out");
+               ep = find_ep(gadget, name);
                if (ep && ep_matches(gadget, ep, desc, ep_comp))
                        goto found_ep;
-
        } else if (gadget_is_goku (gadget)) {
                if (USB_ENDPOINT_XFER_INT == type) {
                        /* single buffering is enough */
index 3507f88..45b8c8b 100644 (file)
@@ -3435,6 +3435,7 @@ done:
 static void ffs_closed(struct ffs_data *ffs)
 {
        struct ffs_dev *ffs_obj;
+       struct f_fs_opts *opts;
 
        ENTER();
        ffs_dev_lock();
@@ -3449,8 +3450,13 @@ static void ffs_closed(struct ffs_data *ffs)
            ffs_obj->ffs_closed_callback)
                ffs_obj->ffs_closed_callback(ffs);
 
-       if (!ffs_obj->opts || ffs_obj->opts->no_configfs
-           || !ffs_obj->opts->func_inst.group.cg_item.ci_parent)
+       if (ffs_obj->opts)
+               opts = ffs_obj->opts;
+       else
+               goto done;
+
+       if (opts->no_configfs || !opts->func_inst.group.cg_item.ci_parent
+           || !atomic_read(&opts->func_inst.group.cg_item.ci_kref.refcount))
                goto done;
 
        unregister_gadget_item(ffs_obj->opts->
index 829edf8..32985da 100644 (file)
@@ -76,7 +76,7 @@ struct f_rndis {
        u8                              ethaddr[ETH_ALEN];
        u32                             vendorID;
        const char                      *manufacturer;
-       int                             config;
+       struct rndis_params             *params;
 
        struct usb_ep                   *notify;
        struct usb_request              *notify_req;
@@ -453,7 +453,7 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
 
        /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
 //     spin_lock(&dev->lock);
-       status = rndis_msg_parser(rndis->config, (u8 *) req->buf);
+       status = rndis_msg_parser(rndis->params, (u8 *) req->buf);
        if (status < 0)
                pr_err("RNDIS command error %d, %d/%d\n",
                        status, req->actual, req->length);
@@ -499,12 +499,12 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
                        u32 n;
 
                        /* return the result */
-                       buf = rndis_get_next_response(rndis->config, &n);
+                       buf = rndis_get_next_response(rndis->params, &n);
                        if (buf) {
                                memcpy(req->buf, buf, n);
                                req->complete = rndis_response_complete;
                                req->context = rndis;
-                               rndis_free_response(rndis->config, buf);
+                               rndis_free_response(rndis->params, buf);
                                value = n;
                        }
                        /* else stalls ... spec says to avoid that */
@@ -597,7 +597,7 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
                if (IS_ERR(net))
                        return PTR_ERR(net);
 
-               rndis_set_param_dev(rndis->config, net,
+               rndis_set_param_dev(rndis->params, net,
                                &rndis->port.cdc_filter);
        } else
                goto fail;
@@ -617,7 +617,7 @@ static void rndis_disable(struct usb_function *f)
 
        DBG(cdev, "rndis deactivated\n");
 
-       rndis_uninit(rndis->config);
+       rndis_uninit(rndis->params);
        gether_disconnect(&rndis->port);
 
        usb_ep_disable(rndis->notify);
@@ -640,9 +640,9 @@ static void rndis_open(struct gether *geth)
 
        DBG(cdev, "%s\n", __func__);
 
-       rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3,
+       rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3,
                                bitrate(cdev->gadget) / 100);
-       rndis_signal_connect(rndis->config);
+       rndis_signal_connect(rndis->params);
 }
 
 static void rndis_close(struct gether *geth)
@@ -651,8 +651,8 @@ static void rndis_close(struct gether *geth)
 
        DBG(geth->func.config->cdev, "%s\n", __func__);
 
-       rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
-       rndis_signal_disconnect(rndis->config);
+       rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3, 0);
+       rndis_signal_disconnect(rndis->params);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -796,11 +796,11 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
        rndis->port.open = rndis_open;
        rndis->port.close = rndis_close;
 
-       rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
-       rndis_set_host_mac(rndis->config, rndis->ethaddr);
+       rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3, 0);
+       rndis_set_host_mac(rndis->params, rndis->ethaddr);
 
        if (rndis->manufacturer && rndis->vendorID &&
-                       rndis_set_param_vendor(rndis->config, rndis->vendorID,
+                       rndis_set_param_vendor(rndis->params, rndis->vendorID,
                                               rndis->manufacturer)) {
                status = -EINVAL;
                goto fail_free_descs;
@@ -944,7 +944,7 @@ static void rndis_free(struct usb_function *f)
        struct f_rndis_opts *opts;
 
        rndis = func_to_rndis(f);
-       rndis_deregister(rndis->config);
+       rndis_deregister(rndis->params);
        opts = container_of(f->fi, struct f_rndis_opts, func_inst);
        kfree(rndis);
        mutex_lock(&opts->lock);
@@ -968,7 +968,7 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
 {
        struct f_rndis  *rndis;
        struct f_rndis_opts *opts;
-       int status;
+       struct rndis_params *params;
 
        /* allocate and initialize one new instance */
        rndis = kzalloc(sizeof(*rndis), GFP_KERNEL);
@@ -1002,36 +1002,16 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
        rndis->port.func.disable = rndis_disable;
        rndis->port.func.free_func = rndis_free;
 
-       status = rndis_register(rndis_response_available, rndis);
-       if (status < 0) {
+       params = rndis_register(rndis_response_available, rndis);
+       if (IS_ERR(params)) {
                kfree(rndis);
-               return ERR_PTR(status);
+               return ERR_CAST(params);
        }
-       rndis->config = status;
+       rndis->params = params;
 
        return &rndis->port.func;
 }
 
-DECLARE_USB_FUNCTION(rndis, rndis_alloc_inst, rndis_alloc);
-
-static int __init rndis_mod_init(void)
-{
-       int ret;
-
-       ret = rndis_init();
-       if (ret)
-               return ret;
-
-       return usb_function_register(&rndisusb_func);
-}
-module_init(rndis_mod_init);
-
-static void __exit rndis_mod_exit(void)
-{
-       usb_function_unregister(&rndisusb_func);
-       rndis_exit();
-}
-module_exit(rndis_mod_exit);
-
+DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("David Brownell");
index 95d2324..70d3917 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/idr.h>
 #include <linux/list.h>
 #include <linux/proc_fs.h>
 #include <linux/slab.h>
@@ -57,17 +58,26 @@ MODULE_PARM_DESC (rndis_debug, "enable debugging");
 #define rndis_debug            0
 #endif
 
-#define RNDIS_MAX_CONFIGS      1
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
 
+#define        NAME_TEMPLATE "driver/rndis-%03d"
 
-static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS];
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
+
+static DEFINE_IDA(rndis_ida);
 
 /* Driver Version */
 static const __le32 rndis_driver_version = cpu_to_le32(1);
 
 /* Function Prototypes */
-static rndis_resp_t *rndis_add_response(int configNr, u32 length);
+static rndis_resp_t *rndis_add_response(struct rndis_params *params,
+                                       u32 length);
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+static const struct file_operations rndis_proc_fops;
 
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
 
 /* supported OIDs */
 static const u32 oid_supported_list[] =
@@ -160,7 +170,7 @@ static const u32 oid_supported_list[] =
 
 
 /* NDIS Functions */
-static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
+static int gen_ndis_query_resp(struct rndis_params *params, u32 OID, u8 *buf,
                               unsigned buf_len, rndis_resp_t *r)
 {
        int retval = -ENOTSUPP;
@@ -192,7 +202,7 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
        outbuf = (__le32 *)&resp[1];
        resp->InformationBufferOffset = cpu_to_le32(16);
 
-       net = rndis_per_dev_params[configNr].dev;
+       net = params->dev;
        stats = dev_get_stats(net, &temp);
 
        switch (OID) {
@@ -225,7 +235,7 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
        /* mandatory */
        case RNDIS_OID_GEN_MEDIA_SUPPORTED:
                pr_debug("%s: RNDIS_OID_GEN_MEDIA_SUPPORTED\n", __func__);
-               *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium);
+               *outbuf = cpu_to_le32(params->medium);
                retval = 0;
                break;
 
@@ -233,16 +243,15 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
        case RNDIS_OID_GEN_MEDIA_IN_USE:
                pr_debug("%s: RNDIS_OID_GEN_MEDIA_IN_USE\n", __func__);
                /* one medium, one transport... (maybe you do it better) */
-               *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium);
+               *outbuf = cpu_to_le32(params->medium);
                retval = 0;
                break;
 
        /* mandatory */
        case RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE:
                pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__);
-               if (rndis_per_dev_params[configNr].dev) {
-                       *outbuf = cpu_to_le32(
-                               rndis_per_dev_params[configNr].dev->mtu);
+               if (params->dev) {
+                       *outbuf = cpu_to_le32(params->dev->mtu);
                        retval = 0;
                }
                break;
@@ -251,21 +260,18 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
        case RNDIS_OID_GEN_LINK_SPEED:
                if (rndis_debug > 1)
                        pr_debug("%s: RNDIS_OID_GEN_LINK_SPEED\n", __func__);
-               if (rndis_per_dev_params[configNr].media_state
-                               == RNDIS_MEDIA_STATE_DISCONNECTED)
+               if (params->media_state == RNDIS_MEDIA_STATE_DISCONNECTED)
                        *outbuf = cpu_to_le32(0);
                else
-                       *outbuf = cpu_to_le32(
-                               rndis_per_dev_params[configNr].speed);
+                       *outbuf = cpu_to_le32(params->speed);
                retval = 0;
                break;
 
        /* mandatory */
        case RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE:
                pr_debug("%s: RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__);
-               if (rndis_per_dev_params[configNr].dev) {
-                       *outbuf = cpu_to_le32(
-                               rndis_per_dev_params[configNr].dev->mtu);
+               if (params->dev) {
+                       *outbuf = cpu_to_le32(params->dev->mtu);
                        retval = 0;
                }
                break;
@@ -273,9 +279,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
        /* mandatory */
        case RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE:
                pr_debug("%s: RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__);
-               if (rndis_per_dev_params[configNr].dev) {
-                       *outbuf = cpu_to_le32(
-                               rndis_per_dev_params[configNr].dev->mtu);
+               if (params->dev) {
+                       *outbuf = cpu_to_le32(params->dev->mtu);
                        retval = 0;
                }
                break;
@@ -283,20 +288,16 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
        /* mandatory */
        case RNDIS_OID_GEN_VENDOR_ID:
                pr_debug("%s: RNDIS_OID_GEN_VENDOR_ID\n", __func__);
-               *outbuf = cpu_to_le32(
-                       rndis_per_dev_params[configNr].vendorID);
+               *outbuf = cpu_to_le32(params->vendorID);
                retval = 0;
                break;
 
        /* mandatory */
        case RNDIS_OID_GEN_VENDOR_DESCRIPTION:
                pr_debug("%s: RNDIS_OID_GEN_VENDOR_DESCRIPTION\n", __func__);
-               if (rndis_per_dev_params[configNr].vendorDescr) {
-                       length = strlen(rndis_per_dev_params[configNr].
-                                       vendorDescr);
-                       memcpy(outbuf,
-                               rndis_per_dev_params[configNr].vendorDescr,
-                               length);
+               if (params->vendorDescr) {
+                       length = strlen(params->vendorDescr);
+                       memcpy(outbuf, params->vendorDescr, length);
                } else {
                        outbuf[0] = 0;
                }
@@ -313,7 +314,7 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
        /* mandatory */
        case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
                pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER\n", __func__);
-               *outbuf = cpu_to_le32(*rndis_per_dev_params[configNr].filter);
+               *outbuf = cpu_to_le32(*params->filter);
                retval = 0;
                break;
 
@@ -328,8 +329,7 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
        case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS:
                if (rndis_debug > 1)
                        pr_debug("%s: RNDIS_OID_GEN_MEDIA_CONNECT_STATUS\n", __func__);
-               *outbuf = cpu_to_le32(rndis_per_dev_params[configNr]
-                                               .media_state);
+               *outbuf = cpu_to_le32(params->media_state);
                retval = 0;
                break;
 
@@ -409,11 +409,9 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
        /* mandatory */
        case RNDIS_OID_802_3_PERMANENT_ADDRESS:
                pr_debug("%s: RNDIS_OID_802_3_PERMANENT_ADDRESS\n", __func__);
-               if (rndis_per_dev_params[configNr].dev) {
+               if (params->dev) {
                        length = ETH_ALEN;
-                       memcpy(outbuf,
-                               rndis_per_dev_params[configNr].host_mac,
-                               length);
+                       memcpy(outbuf, params->host_mac, length);
                        retval = 0;
                }
                break;
@@ -421,11 +419,9 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
        /* mandatory */
        case RNDIS_OID_802_3_CURRENT_ADDRESS:
                pr_debug("%s: RNDIS_OID_802_3_CURRENT_ADDRESS\n", __func__);
-               if (rndis_per_dev_params[configNr].dev) {
+               if (params->dev) {
                        length = ETH_ALEN;
-                       memcpy(outbuf,
-                               rndis_per_dev_params [configNr].host_mac,
-                               length);
+                       memcpy(outbuf, params->host_mac, length);
                        retval = 0;
                }
                break;
@@ -490,12 +486,11 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
        return retval;
 }
 
-static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len,
-                            rndis_resp_t *r)
+static int gen_ndis_set_resp(struct rndis_params *params, u32 OID,
+                            u8 *buf, u32 buf_len, rndis_resp_t *r)
 {
        rndis_set_cmplt_type *resp;
        int i, retval = -ENOTSUPP;
-       struct rndis_params *params;
 
        if (!r)
                return -ENOMEM;
@@ -514,7 +509,6 @@ static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len,
                }
        }
 
-       params = &rndis_per_dev_params[configNr];
        switch (OID) {
        case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
 
@@ -563,16 +557,16 @@ static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len,
  * Response Functions
  */
 
-static int rndis_init_response(int configNr, rndis_init_msg_type *buf)
+static int rndis_init_response(struct rndis_params *params,
+                              rndis_init_msg_type *buf)
 {
        rndis_init_cmplt_type *resp;
        rndis_resp_t *r;
-       struct rndis_params *params = rndis_per_dev_params + configNr;
 
        if (!params->dev)
                return -ENOTSUPP;
 
-       r = rndis_add_response(configNr, sizeof(rndis_init_cmplt_type));
+       r = rndis_add_response(params, sizeof(rndis_init_cmplt_type));
        if (!r)
                return -ENOMEM;
        resp = (rndis_init_cmplt_type *)r->buf;
@@ -599,11 +593,11 @@ static int rndis_init_response(int configNr, rndis_init_msg_type *buf)
        return 0;
 }
 
-static int rndis_query_response(int configNr, rndis_query_msg_type *buf)
+static int rndis_query_response(struct rndis_params *params,
+                               rndis_query_msg_type *buf)
 {
        rndis_query_cmplt_type *resp;
        rndis_resp_t *r;
-       struct rndis_params *params = rndis_per_dev_params + configNr;
 
        /* pr_debug("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID)); */
        if (!params->dev)
@@ -615,7 +609,7 @@ static int rndis_query_response(int configNr, rndis_query_msg_type *buf)
         * rndis_query_cmplt_type followed by data.
         * oid_supported_list is the largest data reply
         */
-       r = rndis_add_response(configNr,
+       r = rndis_add_response(params,
                sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type));
        if (!r)
                return -ENOMEM;
@@ -624,7 +618,7 @@ static int rndis_query_response(int configNr, rndis_query_msg_type *buf)
        resp->MessageType = cpu_to_le32(RNDIS_MSG_QUERY_C);
        resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
 
-       if (gen_ndis_query_resp(configNr, le32_to_cpu(buf->OID),
+       if (gen_ndis_query_resp(params, le32_to_cpu(buf->OID),
                        le32_to_cpu(buf->InformationBufferOffset)
                                        + 8 + (u8 *)buf,
                        le32_to_cpu(buf->InformationBufferLength),
@@ -641,14 +635,14 @@ static int rndis_query_response(int configNr, rndis_query_msg_type *buf)
        return 0;
 }
 
-static int rndis_set_response(int configNr, rndis_set_msg_type *buf)
+static int rndis_set_response(struct rndis_params *params,
+                             rndis_set_msg_type *buf)
 {
        u32 BufLength, BufOffset;
        rndis_set_cmplt_type *resp;
        rndis_resp_t *r;
-       struct rndis_params *params = rndis_per_dev_params + configNr;
 
-       r = rndis_add_response(configNr, sizeof(rndis_set_cmplt_type));
+       r = rndis_add_response(params, sizeof(rndis_set_cmplt_type));
        if (!r)
                return -ENOMEM;
        resp = (rndis_set_cmplt_type *)r->buf;
@@ -671,7 +665,7 @@ static int rndis_set_response(int configNr, rndis_set_msg_type *buf)
        resp->MessageType = cpu_to_le32(RNDIS_MSG_SET_C);
        resp->MessageLength = cpu_to_le32(16);
        resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
-       if (gen_ndis_set_resp(configNr, le32_to_cpu(buf->OID),
+       if (gen_ndis_set_resp(params, le32_to_cpu(buf->OID),
                        ((u8 *)buf) + 8 + BufOffset, BufLength, r))
                resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
        else
@@ -681,13 +675,13 @@ static int rndis_set_response(int configNr, rndis_set_msg_type *buf)
        return 0;
 }
 
-static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf)
+static int rndis_reset_response(struct rndis_params *params,
+                               rndis_reset_msg_type *buf)
 {
        rndis_reset_cmplt_type *resp;
        rndis_resp_t *r;
-       struct rndis_params *params = rndis_per_dev_params + configNr;
 
-       r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type));
+       r = rndis_add_response(params, sizeof(rndis_reset_cmplt_type));
        if (!r)
                return -ENOMEM;
        resp = (rndis_reset_cmplt_type *)r->buf;
@@ -702,16 +696,15 @@ static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf)
        return 0;
 }
 
-static int rndis_keepalive_response(int configNr,
+static int rndis_keepalive_response(struct rndis_params *params,
                                    rndis_keepalive_msg_type *buf)
 {
        rndis_keepalive_cmplt_type *resp;
        rndis_resp_t *r;
-       struct rndis_params *params = rndis_per_dev_params + configNr;
 
        /* host "should" check only in RNDIS_DATA_INITIALIZED state */
 
-       r = rndis_add_response(configNr, sizeof(rndis_keepalive_cmplt_type));
+       r = rndis_add_response(params, sizeof(rndis_keepalive_cmplt_type));
        if (!r)
                return -ENOMEM;
        resp = (rndis_keepalive_cmplt_type *)r->buf;
@@ -729,17 +722,15 @@ static int rndis_keepalive_response(int configNr,
 /*
  * Device to Host Comunication
  */
-static int rndis_indicate_status_msg(int configNr, u32 status)
+static int rndis_indicate_status_msg(struct rndis_params *params, u32 status)
 {
        rndis_indicate_status_msg_type *resp;
        rndis_resp_t *r;
-       struct rndis_params *params = rndis_per_dev_params + configNr;
 
        if (params->state == RNDIS_UNINITIALIZED)
                return -ENOTSUPP;
 
-       r = rndis_add_response(configNr,
-                               sizeof(rndis_indicate_status_msg_type));
+       r = rndis_add_response(params, sizeof(rndis_indicate_status_msg_type));
        if (!r)
                return -ENOMEM;
        resp = (rndis_indicate_status_msg_type *)r->buf;
@@ -754,53 +745,48 @@ static int rndis_indicate_status_msg(int configNr, u32 status)
        return 0;
 }
 
-int rndis_signal_connect(int configNr)
+int rndis_signal_connect(struct rndis_params *params)
 {
-       rndis_per_dev_params[configNr].media_state
-                       = RNDIS_MEDIA_STATE_CONNECTED;
-       return rndis_indicate_status_msg(configNr,
-                                         RNDIS_STATUS_MEDIA_CONNECT);
+       params->media_state = RNDIS_MEDIA_STATE_CONNECTED;
+       return rndis_indicate_status_msg(params, RNDIS_STATUS_MEDIA_CONNECT);
 }
 EXPORT_SYMBOL_GPL(rndis_signal_connect);
 
-int rndis_signal_disconnect(int configNr)
+int rndis_signal_disconnect(struct rndis_params *params)
 {
-       rndis_per_dev_params[configNr].media_state
-                       = RNDIS_MEDIA_STATE_DISCONNECTED;
-       return rndis_indicate_status_msg(configNr,
-                                         RNDIS_STATUS_MEDIA_DISCONNECT);
+       params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED;
+       return rndis_indicate_status_msg(params, RNDIS_STATUS_MEDIA_DISCONNECT);
 }
 EXPORT_SYMBOL_GPL(rndis_signal_disconnect);
 
-void rndis_uninit(int configNr)
+void rndis_uninit(struct rndis_params *params)
 {
        u8 *buf;
        u32 length;
 
-       if (configNr >= RNDIS_MAX_CONFIGS)
+       if (!params)
                return;
-       rndis_per_dev_params[configNr].state = RNDIS_UNINITIALIZED;
+       params->state = RNDIS_UNINITIALIZED;
 
        /* drain the response queue */
-       while ((buf = rndis_get_next_response(configNr, &length)))
-               rndis_free_response(configNr, buf);
+       while ((buf = rndis_get_next_response(params, &length)))
+               rndis_free_response(params, buf);
 }
 EXPORT_SYMBOL_GPL(rndis_uninit);
 
-void rndis_set_host_mac(int configNr, const u8 *addr)
+void rndis_set_host_mac(struct rndis_params *params, const u8 *addr)
 {
-       rndis_per_dev_params[configNr].host_mac = addr;
+       params->host_mac = addr;
 }
 EXPORT_SYMBOL_GPL(rndis_set_host_mac);
 
 /*
  * Message Parser
  */
-int rndis_msg_parser(u8 configNr, u8 *buf)
+int rndis_msg_parser(struct rndis_params *params, u8 *buf)
 {
        u32 MsgType, MsgLength;
        __le32 *tmp;
-       struct rndis_params *params;
 
        if (!buf)
                return -ENOMEM;
@@ -809,9 +795,8 @@ int rndis_msg_parser(u8 configNr, u8 *buf)
        MsgType   = get_unaligned_le32(tmp++);
        MsgLength = get_unaligned_le32(tmp++);
 
-       if (configNr >= RNDIS_MAX_CONFIGS)
+       if (!params)
                return -ENOTSUPP;
-       params = &rndis_per_dev_params[configNr];
 
        /* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
         * rx/tx statistics and link status, in addition to KEEPALIVE traffic
@@ -824,8 +809,7 @@ int rndis_msg_parser(u8 configNr, u8 *buf)
                pr_debug("%s: RNDIS_MSG_INIT\n",
                        __func__);
                params->state = RNDIS_INITIALIZED;
-               return rndis_init_response(configNr,
-                                       (rndis_init_msg_type *)buf);
+               return rndis_init_response(params, (rndis_init_msg_type *)buf);
 
        case RNDIS_MSG_HALT:
                pr_debug("%s: RNDIS_MSG_HALT\n",
@@ -838,17 +822,16 @@ int rndis_msg_parser(u8 configNr, u8 *buf)
                return 0;
 
        case RNDIS_MSG_QUERY:
-               return rndis_query_response(configNr,
+               return rndis_query_response(params,
                                        (rndis_query_msg_type *)buf);
 
        case RNDIS_MSG_SET:
-               return rndis_set_response(configNr,
-                                       (rndis_set_msg_type *)buf);
+               return rndis_set_response(params, (rndis_set_msg_type *)buf);
 
        case RNDIS_MSG_RESET:
                pr_debug("%s: RNDIS_MSG_RESET\n",
                        __func__);
-               return rndis_reset_response(configNr,
+               return rndis_reset_response(params,
                                        (rndis_reset_msg_type *)buf);
 
        case RNDIS_MSG_KEEPALIVE:
@@ -856,7 +839,7 @@ int rndis_msg_parser(u8 configNr, u8 *buf)
                if (rndis_debug > 1)
                        pr_debug("%s: RNDIS_MSG_KEEPALIVE\n",
                                __func__);
-               return rndis_keepalive_response(configNr,
+               return rndis_keepalive_response(params,
                                                 (rndis_keepalive_msg_type *)
                                                 buf);
 
@@ -876,71 +859,131 @@ int rndis_msg_parser(u8 configNr, u8 *buf)
 }
 EXPORT_SYMBOL_GPL(rndis_msg_parser);
 
-int rndis_register(void (*resp_avail)(void *v), void *v)
+static inline int rndis_get_nr(void)
 {
-       u8 i;
+       return ida_simple_get(&rndis_ida, 0, 0, GFP_KERNEL);
+}
+
+static inline void rndis_put_nr(int nr)
+{
+       ida_simple_remove(&rndis_ida, nr);
+}
+
+struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v)
+{
+       struct rndis_params *params;
+       int i;
 
        if (!resp_avail)
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
+
+       i = rndis_get_nr();
+       if (i < 0) {
+               pr_debug("failed\n");
+
+               return ERR_PTR(-ENODEV);
+       }
+
+       params = kzalloc(sizeof(*params), GFP_KERNEL);
+       if (!params) {
+               rndis_put_nr(i);
 
-       for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
-               if (!rndis_per_dev_params[i].used) {
-                       rndis_per_dev_params[i].used = 1;
-                       rndis_per_dev_params[i].resp_avail = resp_avail;
-                       rndis_per_dev_params[i].v = v;
-                       pr_debug("%s: configNr = %d\n", __func__, i);
-                       return i;
+               return ERR_PTR(-ENOMEM);
+       }
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+       {
+               struct proc_dir_entry *proc_entry;
+               char name[20];
+
+               sprintf(name, NAME_TEMPLATE, i);
+               proc_entry = proc_create_data(name, 0660, NULL,
+                                             &rndis_proc_fops, params);
+               if (!proc_entry) {
+                       kfree(params);
+                       rndis_put_nr(i);
+
+                       return ERR_PTR(-EIO);
                }
        }
-       pr_debug("failed\n");
+#endif
+
+       params->confignr = i;
+       params->used = 1;
+       params->state = RNDIS_UNINITIALIZED;
+       params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED;
+       params->resp_avail = resp_avail;
+       params->v = v;
+       INIT_LIST_HEAD(&(params->resp_queue));
+       pr_debug("%s: configNr = %d\n", __func__, i);
 
-       return -ENODEV;
+       return params;
 }
 EXPORT_SYMBOL_GPL(rndis_register);
 
-void rndis_deregister(int configNr)
+void rndis_deregister(struct rndis_params *params)
 {
+       int i;
+
        pr_debug("%s:\n", __func__);
 
-       if (configNr >= RNDIS_MAX_CONFIGS) return;
-       rndis_per_dev_params[configNr].used = 0;
+       if (!params)
+               return;
+
+       i = params->confignr;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+       {
+               char name[20];
+
+               sprintf(name, NAME_TEMPLATE, i);
+               remove_proc_entry(name, NULL);
+       }
+#endif
+
+       kfree(params);
+       rndis_put_nr(i);
 }
 EXPORT_SYMBOL_GPL(rndis_deregister);
-
-int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)
+int rndis_set_param_dev(struct rndis_params *params, struct net_device *dev,
+                       u16 *cdc_filter)
 {
        pr_debug("%s:\n", __func__);
        if (!dev)
                return -EINVAL;
-       if (configNr >= RNDIS_MAX_CONFIGS) return -1;
+       if (!params)
+               return -1;
 
-       rndis_per_dev_params[configNr].dev = dev;
-       rndis_per_dev_params[configNr].filter = cdc_filter;
+       params->dev = dev;
+       params->filter = cdc_filter;
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(rndis_set_param_dev);
 
-int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)
+int rndis_set_param_vendor(struct rndis_params *params, u32 vendorID,
+                          const char *vendorDescr)
 {
        pr_debug("%s:\n", __func__);
        if (!vendorDescr) return -1;
-       if (configNr >= RNDIS_MAX_CONFIGS) return -1;
+       if (!params)
+               return -1;
 
-       rndis_per_dev_params[configNr].vendorID = vendorID;
-       rndis_per_dev_params[configNr].vendorDescr = vendorDescr;
+       params->vendorID = vendorID;
+       params->vendorDescr = vendorDescr;
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(rndis_set_param_vendor);
 
-int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
+int rndis_set_param_medium(struct rndis_params *params, u32 medium, u32 speed)
 {
        pr_debug("%s: %u %u\n", __func__, medium, speed);
-       if (configNr >= RNDIS_MAX_CONFIGS) return -1;
+       if (!params)
+               return -1;
 
-       rndis_per_dev_params[configNr].medium = medium;
-       rndis_per_dev_params[configNr].speed = speed;
+       params->medium = medium;
+       params->speed = speed;
 
        return 0;
 }
@@ -961,13 +1004,12 @@ void rndis_add_hdr(struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(rndis_add_hdr);
 
-void rndis_free_response(int configNr, u8 *buf)
+void rndis_free_response(struct rndis_params *params, u8 *buf)
 {
        rndis_resp_t *r;
        struct list_head *act, *tmp;
 
-       list_for_each_safe(act, tmp,
-                       &(rndis_per_dev_params[configNr].resp_queue))
+       list_for_each_safe(act, tmp, &(params->resp_queue))
        {
                r = list_entry(act, rndis_resp_t, list);
                if (r && r->buf == buf) {
@@ -978,15 +1020,14 @@ void rndis_free_response(int configNr, u8 *buf)
 }
 EXPORT_SYMBOL_GPL(rndis_free_response);
 
-u8 *rndis_get_next_response(int configNr, u32 *length)
+u8 *rndis_get_next_response(struct rndis_params *params, u32 *length)
 {
        rndis_resp_t *r;
        struct list_head *act, *tmp;
 
        if (!length) return NULL;
 
-       list_for_each_safe(act, tmp,
-                       &(rndis_per_dev_params[configNr].resp_queue))
+       list_for_each_safe(act, tmp, &(params->resp_queue))
        {
                r = list_entry(act, rndis_resp_t, list);
                if (!r->send) {
@@ -1000,7 +1041,7 @@ u8 *rndis_get_next_response(int configNr, u32 *length)
 }
 EXPORT_SYMBOL_GPL(rndis_get_next_response);
 
-static rndis_resp_t *rndis_add_response(int configNr, u32 length)
+static rndis_resp_t *rndis_add_response(struct rndis_params *params, u32 length)
 {
        rndis_resp_t *r;
 
@@ -1012,8 +1053,7 @@ static rndis_resp_t *rndis_add_response(int configNr, u32 length)
        r->length = length;
        r->send = 0;
 
-       list_add_tail(&r->list,
-               &(rndis_per_dev_params[configNr].resp_queue));
+       list_add_tail(&r->list, &(params->resp_queue));
        return r;
 }
 
@@ -1103,11 +1143,11 @@ static ssize_t rndis_proc_write(struct file *file, const char __user *buffer,
                        break;
                case 'C':
                case 'c':
-                       rndis_signal_connect(p->confignr);
+                       rndis_signal_connect(p);
                        break;
                case 'D':
                case 'd':
-                       rndis_signal_disconnect(p->confignr);
+                       rndis_signal_disconnect(p);
                        break;
                default:
                        if (fl_speed) p->speed = speed;
@@ -1137,54 +1177,4 @@ static const struct file_operations rndis_proc_fops = {
 
 #define        NAME_TEMPLATE "driver/rndis-%03d"
 
-static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
-
 #endif /* CONFIG_USB_GADGET_DEBUG_FILES */
-
-
-int rndis_init(void)
-{
-       u8 i;
-
-       for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-               char name [20];
-
-               sprintf(name, NAME_TEMPLATE, i);
-               rndis_connect_state[i] = proc_create_data(name, 0660, NULL,
-                                       &rndis_proc_fops,
-                                       (void *)(rndis_per_dev_params + i));
-               if (!rndis_connect_state[i]) {
-                       pr_debug("%s: remove entries", __func__);
-                       while (i) {
-                               sprintf(name, NAME_TEMPLATE, --i);
-                               remove_proc_entry(name, NULL);
-                       }
-                       pr_debug("\n");
-                       return -EIO;
-               }
-#endif
-               rndis_per_dev_params[i].confignr = i;
-               rndis_per_dev_params[i].used = 0;
-               rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED;
-               rndis_per_dev_params[i].media_state
-                               = RNDIS_MEDIA_STATE_DISCONNECTED;
-               INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue));
-       }
-
-       return 0;
-}
-
-void rndis_exit(void)
-{
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-       u8 i;
-       char name[20];
-
-       for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
-               sprintf(name, NAME_TEMPLATE, i);
-               remove_proc_entry(name, NULL);
-       }
-#endif
-}
-
index 0f4abb4..ef92eb6 100644 (file)
@@ -177,7 +177,7 @@ typedef struct rndis_resp_t
 
 typedef struct rndis_params
 {
-       u8                      confignr;
+       int                     confignr;
        u8                      used;
        u16                     saved_filter;
        enum rndis_state        state;
@@ -197,24 +197,25 @@ typedef struct rndis_params
 } rndis_params;
 
 /* RNDIS Message parser and other useless functions */
-int  rndis_msg_parser (u8 configNr, u8 *buf);
-int  rndis_register(void (*resp_avail)(void *v), void *v);
-void rndis_deregister (int configNr);
-int  rndis_set_param_dev (u8 configNr, struct net_device *dev,
+int  rndis_msg_parser(struct rndis_params *params, u8 *buf);
+struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v);
+void rndis_deregister(struct rndis_params *params);
+int  rndis_set_param_dev(struct rndis_params *params, struct net_device *dev,
                         u16 *cdc_filter);
-int  rndis_set_param_vendor (u8 configNr, u32 vendorID,
+int  rndis_set_param_vendor(struct rndis_params *params, u32 vendorID,
                            const char *vendorDescr);
-int  rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
-void rndis_add_hdr (struct sk_buff *skb);
+int  rndis_set_param_medium(struct rndis_params *params, u32 medium,
+                            u32 speed);
+void rndis_add_hdr(struct sk_buff *skb);
 int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
                        struct sk_buff_head *list);
-u8   *rndis_get_next_response (int configNr, u32 *length);
-void rndis_free_response (int configNr, u8 *buf);
-
-void rndis_uninit (int configNr);
-int  rndis_signal_connect (int configNr);
-int  rndis_signal_disconnect (int configNr);
-int  rndis_state (int configNr);
-extern void rndis_set_host_mac (int configNr, const u8 *addr);
+u8   *rndis_get_next_response(struct rndis_params *params, u32 *length);
+void rndis_free_response(struct rndis_params *params, u8 *buf);
+
+void rndis_uninit(struct rndis_params *params);
+int  rndis_signal_connect(struct rndis_params *params);
+int  rndis_signal_disconnect(struct rndis_params *params);
+int  rndis_state(struct rndis_params *params);
+extern void rndis_set_host_mac(struct rndis_params *params, const u8 *addr);
 
 #endif  /* _LINUX_RNDIS_H */
index e902aa4..4eafd50 100644 (file)
@@ -39,8 +39,6 @@ struct f_rndis_opts {
        int                             refcnt;
 };
 
-int rndis_init(void);
-void rndis_exit(void);
 void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net);
 
 #endif /* U_RNDIS_H */
index ebe409b..7d3bb62 100644 (file)
@@ -56,7 +56,6 @@ struct uvc_event
 #include <linux/usb/composite.h>
 #include <linux/usb/gadget.h>
 #include <linux/videodev2.h>
-#include <linux/version.h>
 #include <media/v4l2-fh.h>
 #include <media/v4l2-device.h>
 
index 2030565..f454c7a 100644 (file)
@@ -769,9 +769,12 @@ ep_config (struct ep_data *data, const char *buf, size_t len)
        if (data->dev->state == STATE_DEV_UNBOUND) {
                value = -ENOENT;
                goto gone;
-       } else if ((ep = data->ep) == NULL) {
-               value = -ENODEV;
-               goto gone;
+       } else {
+               ep = data->ep;
+               if (ep == NULL) {
+                       value = -ENODEV;
+                       goto gone;
+               }
        }
        switch (data->dev->gadget->speed) {
        case USB_SPEED_LOW:
index 351d485..4095cce 100644 (file)
@@ -704,8 +704,8 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
        unsigned long flags;
        int ret;
 
-       DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n",
-               ep->ep.name, req->req.length, req->req.dma,
+       DBG(DBG_DMA, "%s: req l/%u d/%pad %c%c%c\n",
+               ep->ep.name, req->req.length, &req->req.dma,
                req->req.zero ? 'Z' : 'z',
                req->req.short_not_ok ? 'S' : 's',
                req->req.no_interrupt ? 'I' : 'i');
@@ -2203,7 +2203,7 @@ static int usba_udc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int usba_udc_suspend(struct device *dev)
 {
        struct usba_udc *udc = dev_get_drvdata(dev);
index 9871b90..2bee912 100644 (file)
@@ -123,6 +123,11 @@ static char *type_string(u8 bmAttributes)
 #define valid_bit      cpu_to_le32(BIT(VALID_BIT))
 #define dma_done_ie    cpu_to_le32(BIT(DMA_DONE_INTERRUPT_ENABLE))
 
+static void ep_clear_seqnum(struct net2280_ep *ep);
+static void stop_activity(struct net2280 *dev,
+                                       struct usb_gadget_driver *driver);
+static void ep0_start(struct net2280 *dev);
+
 /*-------------------------------------------------------------------------*/
 static inline void enable_pciirqenb(struct net2280_ep *ep)
 {
@@ -142,7 +147,9 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 {
        struct net2280          *dev;
        struct net2280_ep       *ep;
-       u32                     max, tmp;
+       u32                     max;
+       u32 tmp = 0;
+       u32 type;
        unsigned long           flags;
        static const u32 ep_key[9] = { 1, 0, 1, 0, 1, 1, 0, 1, 0 };
        int ret = 0;
@@ -198,15 +205,29 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 
        /* set type, direction, address; reset fifo counters */
        writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat);
-       tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
-       if (tmp == USB_ENDPOINT_XFER_INT) {
+
+       if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) {
+               tmp = readl(&ep->cfg->ep_cfg);
+               /* If USB ep number doesn't match hardware ep number */
+               if ((tmp & 0xf) != usb_endpoint_num(desc)) {
+                       ret = -EINVAL;
+                       spin_unlock_irqrestore(&dev->lock, flags);
+                       goto print_err;
+               }
+               if (ep->is_in)
+                       tmp &= ~USB3380_EP_CFG_MASK_IN;
+               else
+                       tmp &= ~USB3380_EP_CFG_MASK_OUT;
+       }
+       type = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+       if (type == USB_ENDPOINT_XFER_INT) {
                /* erratum 0105 workaround prevents hs NYET */
                if (dev->chiprev == 0100 &&
                                dev->gadget.speed == USB_SPEED_HIGH &&
                                !(desc->bEndpointAddress & USB_DIR_IN))
                        writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE),
                                &ep->regs->ep_rsp);
-       } else if (tmp == USB_ENDPOINT_XFER_BULK) {
+       } else if (type == USB_ENDPOINT_XFER_BULK) {
                /* catch some particularly blatant driver bugs */
                if ((dev->gadget.speed == USB_SPEED_SUPER && max != 1024) ||
                    (dev->gadget.speed == USB_SPEED_HIGH && max != 512) ||
@@ -216,10 +237,10 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
                        goto print_err;
                }
        }
-       ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC);
+       ep->is_iso = (type == USB_ENDPOINT_XFER_ISOC);
        /* Enable this endpoint */
        if (dev->quirks & PLX_LEGACY) {
-               tmp <<= ENDPOINT_TYPE;
+               tmp |= type << ENDPOINT_TYPE;
                tmp |= desc->bEndpointAddress;
                /* default full fifo lines */
                tmp |= (4 << ENDPOINT_BYTE_COUNT);
@@ -228,17 +249,17 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
        } else {
                /* In Legacy mode, only OUT endpoints are used */
                if (dev->enhanced_mode && ep->is_in) {
-                       tmp <<= IN_ENDPOINT_TYPE;
+                       tmp |= type << IN_ENDPOINT_TYPE;
                        tmp |= BIT(IN_ENDPOINT_ENABLE);
-                       /* Not applicable to Legacy */
-                       tmp |= BIT(ENDPOINT_DIRECTION);
                } else {
-                       tmp <<= OUT_ENDPOINT_TYPE;
+                       tmp |= type << OUT_ENDPOINT_TYPE;
                        tmp |= BIT(OUT_ENDPOINT_ENABLE);
                        tmp |= (ep->is_in << ENDPOINT_DIRECTION);
                }
 
-               tmp |= usb_endpoint_num(desc);
+               tmp |= (4 << ENDPOINT_BYTE_COUNT);
+               if (!dev->enhanced_mode)
+                       tmp |= usb_endpoint_num(desc);
                tmp |= (ep->ep.maxburst << MAX_BURST_SIZE);
        }
 
@@ -256,6 +277,8 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
                        BIT(CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
        }
 
+       if (dev->quirks & PLX_SUPERSPEED)
+               ep_clear_seqnum(ep);
        writel(tmp, &ep->cfg->ep_cfg);
 
        /* enable irqs */
@@ -441,6 +464,13 @@ static void ep_reset_338x(struct net2280_regs __iomem *regs,
               BIT(DATA_PACKET_TRANSMITTED_INTERRUPT) |
               BIT(DATA_OUT_PING_TOKEN_INTERRUPT) |
               BIT(DATA_IN_TOKEN_INTERRUPT), &ep->regs->ep_stat);
+
+       tmp = readl(&ep->cfg->ep_cfg);
+       if (ep->is_in)
+               tmp &= ~USB3380_EP_CFG_MASK_IN;
+       else
+               tmp &= ~USB3380_EP_CFG_MASK_OUT;
+       writel(tmp, &ep->cfg->ep_cfg);
 }
 
 static void nuke(struct net2280_ep *);
@@ -1468,11 +1498,14 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on)
        spin_lock_irqsave(&dev->lock, flags);
        tmp = readl(&dev->usb->usbctl);
        dev->softconnect = (is_on != 0);
-       if (is_on)
-               tmp |= BIT(USB_DETECT_ENABLE);
-       else
-               tmp &= ~BIT(USB_DETECT_ENABLE);
-       writel(tmp, &dev->usb->usbctl);
+       if (is_on) {
+               ep0_start(dev);
+               writel(tmp | BIT(USB_DETECT_ENABLE), &dev->usb->usbctl);
+       } else {
+               writel(tmp & ~BIT(USB_DETECT_ENABLE), &dev->usb->usbctl);
+               stop_activity(dev, dev->driver);
+       }
+
        spin_unlock_irqrestore(&dev->lock, flags);
 
        return 0;
@@ -1860,8 +1893,8 @@ static void defect7374_enable_data_eps_zero(struct net2280 *dev)
        tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) |
                        (2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) |
                        ((dev->enhanced_mode) ?
-                        BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) |
-                       BIT(IN_ENDPOINT_ENABLE));
+                        BIT(OUT_ENDPOINT_ENABLE) | BIT(IN_ENDPOINT_ENABLE) :
+                        BIT(ENDPOINT_ENABLE)));
 
        for (i = 1; i < 5; i++)
                writel(tmp, &dev->ep[i].cfg->ep_cfg);
@@ -1975,9 +2008,15 @@ static void usb_reset_338x(struct net2280 *dev)
        /* clear old dma and irq state */
        for (tmp = 0; tmp < 4; tmp++) {
                struct net2280_ep *ep = &dev->ep[tmp + 1];
+               struct net2280_dma_regs __iomem *dma;
 
-               if (ep->dma)
+               if (ep->dma) {
                        abort_dma(ep);
+               } else {
+                       dma = &dev->dma[tmp];
+                       writel(BIT(DMA_ABORT), &dma->dmastat);
+                       writel(0, &dma->dmactl);
+               }
        }
 
        writel(~0, &dev->regs->irqstat0), writel(~0, &dev->regs->irqstat1);
@@ -2065,6 +2104,12 @@ static void usb_reinit_338x(struct net2280 *dev)
 
                if (dev->enhanced_mode) {
                        ep->cfg = &dev->epregs[ne[i]];
+                       /*
+                        * Set USB endpoint number, hardware allows same number
+                        * in both directions.
+                        */
+                        if (i > 0 && i < 5)
+                               writel(ne[i], &ep->cfg->ep_cfg);
                        ep->regs = (struct net2280_ep_regs __iomem *)
                                (((void __iomem *)&dev->epregs[ne[i]]) +
                                ep_reg_addr[i]);
@@ -2874,6 +2919,26 @@ next_endpoints3:
        return;
 }
 
+static void usb338x_handle_ep_intr(struct net2280 *dev, u32 stat0)
+{
+       u32 index;
+       u32 bit;
+
+       for (index = 0; index < ARRAY_SIZE(ep_bit); index++) {
+               bit = BIT(ep_bit[index]);
+
+               if (!stat0)
+                       break;
+
+               if (!(stat0 & bit))
+                       continue;
+
+               stat0 &= ~bit;
+
+               handle_ep_small(&dev->ep[index]);
+       }
+}
+
 static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
 {
        struct net2280_ep       *ep;
@@ -3098,20 +3163,31 @@ do_stall:
 #undef w_length
 
 next_endpoints:
-       /* endpoint data irq ? */
-       scratch = stat & 0x7f;
-       stat &= ~0x7f;
-       for (num = 0; scratch; num++) {
-               u32             t;
-
-               /* do this endpoint's FIFO and queue need tending? */
-               t = BIT(num);
-               if ((scratch & t) == 0)
-                       continue;
-               scratch ^= t;
+       if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) {
+               u32 mask = (BIT(ENDPOINT_0_INTERRUPT) |
+                       USB3380_IRQSTAT0_EP_INTR_MASK_IN |
+                       USB3380_IRQSTAT0_EP_INTR_MASK_OUT);
+
+               if (stat & mask) {
+                       usb338x_handle_ep_intr(dev, stat & mask);
+                       stat &= ~mask;
+               }
+       } else {
+               /* endpoint data irq ? */
+               scratch = stat & 0x7f;
+               stat &= ~0x7f;
+               for (num = 0; scratch; num++) {
+                       u32             t;
+
+                       /* do this endpoint's FIFO and queue need tending? */
+                       t = BIT(num);
+                       if ((scratch & t) == 0)
+                               continue;
+                       scratch ^= t;
 
-               ep = &dev->ep[num];
-               handle_ep_small(ep);
+                       ep = &dev->ep[num];
+                       handle_ep_small(ep);
+               }
        }
 
        if (stat)
index 99fd9a5..5d9aa81 100644 (file)
@@ -92,40 +92,38 @@ static struct s3c2410_udc_mach_info *udc_info;
 
 static uint32_t s3c2410_ticks = 0;
 
-static int dprintk(int level, const char *fmt, ...)
+__printf(2, 3)
+static void dprintk(int level, const char *fmt, ...)
 {
-       static char printk_buf[1024];
        static long prevticks;
        static int invocation;
+       struct va_format vaf;
        va_list args;
-       int len;
 
        if (level > USB_S3C2410_DEBUG_LEVEL)
-               return 0;
+               return;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
 
        if (s3c2410_ticks != prevticks) {
                prevticks = s3c2410_ticks;
                invocation = 0;
        }
 
-       len = scnprintf(printk_buf,
-                       sizeof(printk_buf), "%1lu.%02d USB: ",
-                       prevticks, invocation++);
+       pr_debug("%1lu.%02d USB: %pV", prevticks, invocation++, &vaf);
 
-       va_start(args, fmt);
-       len = vscnprintf(printk_buf+len,
-                       sizeof(printk_buf)-len, fmt, args);
        va_end(args);
-
-       pr_debug("%s", printk_buf);
-       return len;
 }
 #else
-static int dprintk(int level, const char *fmt, ...)
+__printf(2, 3)
+static void dprintk(int level, const char *fmt, ...)
 {
-       return 0;
 }
 #endif
+
 static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
 {
        u32 addr_reg, pwr_reg, ep_int_reg, usb_int_reg;
index 197a6a3..547cee8 100644 (file)
@@ -137,7 +137,7 @@ config XPS_USB_HCD_XILINX
                devices only.
 
 config USB_EHCI_FSL
-       bool "Support for Freescale PPC on-chip EHCI USB controller"
+       tristate "Support for Freescale PPC on-chip EHCI USB controller"
        depends on FSL_SOC
        select USB_EHCI_ROOT_HUB_TT
        select USB_FSL_MPH_DR_OF if OF
index 65b0b6a..754efaa 100644 (file)
@@ -24,7 +24,9 @@ endif
 
 obj-$(CONFIG_USB_WHCI_HCD)     += whci/
 
-obj-$(CONFIG_PCI)              += pci-quirks.o
+ifneq ($(CONFIG_USB), )
+       obj-$(CONFIG_PCI)       += pci-quirks.o
+endif
 
 obj-$(CONFIG_USB_XHCI_PCI)     += xhci-pci.o
 obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o
@@ -70,6 +72,7 @@ obj-$(CONFIG_USB_R8A66597_HCD)        += r8a66597-hcd.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_EHCI_FSL)     += ehci-fsl.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 524cbf2..b26b96e 100644 (file)
@@ -628,7 +628,8 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
        unsigned                i;
        __hc32                  tag;
 
-       if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC)))
+       seen = kmalloc(DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC);
+       if (!seen)
                return 0;
        seen_count = 0;
 
index ab4eee3..5352e74 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2005-2009 MontaVista Software, Inc.
- * Copyright 2008,2012      Freescale Semiconductor, Inc.
+ * Copyright 2008,2012,2015      Freescale Semiconductor, Inc.
  *
  * 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
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/err.h>
+#include <linux/usb.h>
+#include <linux/usb/ehci_def.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/otg.h>
 #include <linux/platform_device.h>
 #include <linux/fsl_devices.h>
 
+#include "ehci.h"
 #include "ehci-fsl.h"
 
+#define DRIVER_DESC "Freescale EHCI Host controller driver"
+#define DRV_NAME "ehci-fsl"
+
+static struct hc_driver __read_mostly fsl_ehci_hc_driver;
+
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */
 
-/**
- * usb_hcd_fsl_probe - initialize FSL-based HCDs
- * @drvier: Driver to be used for this HCD
+/*
+ * fsl_ehci_drv_probe - initialize FSL-based HCDs
  * @pdev: USB Host Controller being probed
  * Context: !in_interrupt()
  *
  * Allocates basic resources for this USB host controller.
  *
  */
-static int usb_hcd_fsl_probe(const struct hc_driver *driver,
-                            struct platform_device *pdev)
+static int fsl_ehci_drv_probe(struct platform_device *pdev)
 {
        struct fsl_usb2_platform_data *pdata;
        struct usb_hcd *hcd;
@@ -86,7 +95,8 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
        }
        irq = res->start;
 
-       hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+       hcd = usb_create_hcd(&fsl_ehci_hc_driver, &pdev->dev,
+                               dev_name(&pdev->dev));
        if (!hcd) {
                retval = -ENOMEM;
                goto err1;
@@ -159,38 +169,6 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
        return retval;
 }
 
-/* may be called without controller electrically present */
-/* may be called with controller, bus, and devices active */
-
-/**
- * usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs
- * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
- *
- * Reverses the effect of usb_hcd_fsl_probe().
- *
- */
-static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
-                              struct platform_device *pdev)
-{
-       struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
-
-       if (!IS_ERR_OR_NULL(hcd->usb_phy)) {
-               otg_set_host(hcd->usb_phy->otg, NULL);
-               usb_put_phy(hcd->usb_phy);
-       }
-
-       usb_remove_hcd(hcd);
-
-       /*
-        * do platform specific un-initialization:
-        * release iomux pins, disable clock, etc.
-        */
-       if (pdata->exit)
-               pdata->exit(pdev);
-       usb_put_hcd(hcd);
-}
-
 static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
                               enum fsl_usb2_phy_modes phy_mode,
                               unsigned int port_offset)
@@ -636,79 +614,77 @@ static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port)
 #define ehci_start_port_reset  NULL
 #endif /* CONFIG_USB_OTG */
 
+static struct ehci_driver_overrides ehci_fsl_overrides __initdata = {
+       .extra_priv_size = sizeof(struct ehci_fsl),
+       .reset = ehci_fsl_setup,
+};
 
-static const struct hc_driver ehci_fsl_hc_driver = {
-       .description = hcd_name,
-       .product_desc = "Freescale On-Chip EHCI Host Controller",
-       .hcd_priv_size = sizeof(struct ehci_fsl),
+/**
+ * fsl_ehci_drv_remove - shutdown processing for FSL-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_fsl_probe().
+ *
+ */
 
-       /*
-        * generic hardware linkage
-        */
-       .irq = ehci_irq,
-       .flags = HCD_USB2 | HCD_MEMORY | HCD_BH,
+static int fsl_ehci_drv_remove(struct platform_device *pdev)
+{
+       struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
-       /*
-        * basic lifecycle operations
-        */
-       .reset = ehci_fsl_setup,
-       .start = ehci_run,
-       .stop = ehci_stop,
-       .shutdown = ehci_shutdown,
+       if (!IS_ERR_OR_NULL(hcd->usb_phy)) {
+               otg_set_host(hcd->usb_phy->otg, NULL);
+               usb_put_phy(hcd->usb_phy);
+       }
 
-       /*
-        * 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,
+       usb_remove_hcd(hcd);
 
        /*
-        * scheduling support
+        * do platform specific un-initialization:
+        * release iomux pins, disable clock, etc.
         */
-       .get_frame_number = ehci_get_frame,
+       if (pdata->exit)
+               pdata->exit(pdev);
+       usb_put_hcd(hcd);
 
-       /*
-        * 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,
-       .start_port_reset = ehci_start_port_reset,
-       .relinquish_port = ehci_relinquish_port,
-       .port_handed_over = ehci_port_handed_over,
-
-       .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+       return 0;
+}
+
+static struct platform_driver ehci_fsl_driver = {
+       .probe = fsl_ehci_drv_probe,
+       .remove = fsl_ehci_drv_remove,
+       .shutdown = usb_hcd_platform_shutdown,
+       .driver = {
+               .name = "fsl-ehci",
+               .pm = EHCI_FSL_PM_OPS,
+       },
 };
 
-static int ehci_fsl_drv_probe(struct platform_device *pdev)
+static int __init ehci_fsl_init(void)
 {
        if (usb_disabled())
                return -ENODEV;
 
-       /* FIXME we only want one one probe() not two */
-       return usb_hcd_fsl_probe(&ehci_fsl_hc_driver, pdev);
-}
+       pr_info(DRV_NAME ": " DRIVER_DESC "\n");
 
-static int ehci_fsl_drv_remove(struct platform_device *pdev)
-{
-       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+       ehci_init_driver(&fsl_ehci_hc_driver, &ehci_fsl_overrides);
 
-       /* FIXME we only want one one remove() not two */
-       usb_hcd_fsl_remove(hcd, pdev);
-       return 0;
+       fsl_ehci_hc_driver.product_desc =
+                       "Freescale On-Chip EHCI Host Controller";
+       fsl_ehci_hc_driver.start_port_reset = ehci_start_port_reset;
+
+
+       return platform_driver_register(&ehci_fsl_driver);
 }
+module_init(ehci_fsl_init);
 
-MODULE_ALIAS("platform:fsl-ehci");
+static void __exit ehci_fsl_cleanup(void)
+{
+       platform_driver_unregister(&ehci_fsl_driver);
+}
+module_exit(ehci_fsl_cleanup);
 
-static struct platform_driver ehci_fsl_driver = {
-       .probe = ehci_fsl_drv_probe,
-       .remove = ehci_fsl_drv_remove,
-       .shutdown = usb_hcd_platform_shutdown,
-       .driver = {
-               .name = "fsl-ehci",
-               .pm = EHCI_FSL_PM_OPS,
-       },
-};
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index f4d88df..c63d82c 100644 (file)
@@ -239,7 +239,7 @@ static void tdi_reset (struct ehci_hcd *ehci)
  * Reset a non-running (STS_HALT == 1) controller.
  * Must be called with interrupts enabled and the lock not held.
  */
-static int ehci_reset (struct ehci_hcd *ehci)
+int ehci_reset(struct ehci_hcd *ehci)
 {
        int     retval;
        u32     command = ehci_readl(ehci, &ehci->regs->command);
@@ -275,6 +275,7 @@ static int ehci_reset (struct ehci_hcd *ehci)
                        ehci->resuming_ports = 0;
        return retval;
 }
+EXPORT_SYMBOL_GPL(ehci_reset);
 
 /*
  * Idle the controller (turn off the schedules).
@@ -1250,11 +1251,6 @@ MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_LICENSE ("GPL");
 
-#ifdef CONFIG_USB_EHCI_FSL
-#include "ehci-fsl.c"
-#define        PLATFORM_DRIVER         ehci_fsl_driver
-#endif
-
 #ifdef CONFIG_USB_EHCI_SH
 #include "ehci-sh.c"
 #define PLATFORM_DRIVER                ehci_hcd_sh_driver
index 6920844..22abb68 100644 (file)
@@ -155,7 +155,7 @@ static int ehci_port_change(struct ehci_hcd *ehci)
        return 0;
 }
 
-static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
+void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
                bool suspending, bool do_wakeup)
 {
        int             port;
@@ -220,6 +220,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
 
        spin_unlock_irq(&ehci->lock);
 }
+EXPORT_SYMBOL_GPL(ehci_adjust_port_wakeup_flags);
 
 static int ehci_bus_suspend (struct usb_hcd *hcd)
 {
index d8a75a5..2593def 100644 (file)
@@ -88,15 +88,13 @@ static int ehci_platform_power_on(struct platform_device *dev)
        }
 
        for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
-               if (priv->phys[phy_num]) {
-                       ret = phy_init(priv->phys[phy_num]);
-                       if (ret)
-                               goto err_exit_phy;
-                       ret = phy_power_on(priv->phys[phy_num]);
-                       if (ret) {
-                               phy_exit(priv->phys[phy_num]);
-                               goto err_exit_phy;
-                       }
+               ret = phy_init(priv->phys[phy_num]);
+               if (ret)
+                       goto err_exit_phy;
+               ret = phy_power_on(priv->phys[phy_num]);
+               if (ret) {
+                       phy_exit(priv->phys[phy_num]);
+                       goto err_exit_phy;
                }
        }
 
@@ -104,10 +102,8 @@ static int ehci_platform_power_on(struct platform_device *dev)
 
 err_exit_phy:
        while (--phy_num >= 0) {
-               if (priv->phys[phy_num]) {
-                       phy_power_off(priv->phys[phy_num]);
-                       phy_exit(priv->phys[phy_num]);
-               }
+               phy_power_off(priv->phys[phy_num]);
+               phy_exit(priv->phys[phy_num]);
        }
 err_disable_clks:
        while (--clk >= 0)
@@ -123,10 +119,8 @@ static void ehci_platform_power_off(struct platform_device *dev)
        int clk, phy_num;
 
        for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
-               if (priv->phys[phy_num]) {
-                       phy_power_off(priv->phys[phy_num]);
-                       phy_exit(priv->phys[phy_num]);
-               }
+               phy_power_off(priv->phys[phy_num]);
+               phy_exit(priv->phys[phy_num]);
        }
 
        for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
@@ -154,7 +148,6 @@ static int ehci_platform_probe(struct platform_device *dev)
        struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
        struct ehci_platform_priv *priv;
        struct ehci_hcd *ehci;
-       const char *phy_name;
        int err, irq, phy_num, clk = 0;
 
        if (usb_disabled())
@@ -202,38 +195,28 @@ static int ehci_platform_probe(struct platform_device *dev)
                                          "needs-reset-on-resume"))
                        pdata->reset_on_resume = 1;
 
+               if (of_property_read_bool(dev->dev.of_node,
+                                         "has-transaction-translator"))
+                       pdata->has_tt = 1;
+
                priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
                                "phys", "#phy-cells");
-               priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1;
 
-               priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
-                               sizeof(struct phy *), GFP_KERNEL);
-               if (!priv->phys)
-                       return -ENOMEM;
+               if (priv->num_phys > 0) {
+                       priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
+                                           sizeof(struct phy *), GFP_KERNEL);
+                       if (!priv->phys)
+                               return -ENOMEM;
+               } else
+                       priv->num_phys = 0;
 
                for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
-                               err = of_property_read_string_index(
-                                               dev->dev.of_node,
-                                               "phy-names", phy_num,
-                                               &phy_name);
-
-                               if (err < 0) {
-                                       if (priv->num_phys > 1) {
-                                               dev_err(&dev->dev, "phy-names not provided");
-                                               goto err_put_hcd;
-                                       } else
-                                               phy_name = "usb";
-                               }
-
-                               priv->phys[phy_num] = devm_phy_get(&dev->dev,
-                                               phy_name);
-                               if (IS_ERR(priv->phys[phy_num])) {
-                                       err = PTR_ERR(priv->phys[phy_num]);
-                                       if ((priv->num_phys > 1) ||
-                                           (err == -EPROBE_DEFER))
-                                               goto err_put_hcd;
-                                       priv->phys[phy_num] = NULL;
-                               }
+                       priv->phys[phy_num] = devm_of_phy_get_by_index(
+                                       &dev->dev, dev->dev.of_node, phy_num);
+                       if (IS_ERR(priv->phys[phy_num])) {
+                               err = PTR_ERR(priv->phys[phy_num]);
+                                       goto err_put_hcd;
+                       }
                }
 
                for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
index ff9af29..4031b37 100644 (file)
@@ -304,6 +304,7 @@ struct dma_aligned_buffer {
 static void free_dma_aligned_buffer(struct urb *urb)
 {
        struct dma_aligned_buffer *temp;
+       size_t length;
 
        if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
                return;
@@ -311,9 +312,14 @@ static void free_dma_aligned_buffer(struct urb *urb)
        temp = container_of(urb->transfer_buffer,
                struct dma_aligned_buffer, data);
 
-       if (usb_urb_dir_in(urb))
-               memcpy(temp->old_xfer_buffer, temp->data,
-                      urb->transfer_buffer_length);
+       if (usb_urb_dir_in(urb)) {
+               if (usb_pipeisoc(urb->pipe))
+                       length = urb->transfer_buffer_length;
+               else
+                       length = urb->actual_length;
+
+               memcpy(temp->old_xfer_buffer, temp->data, length);
+       }
        urb->transfer_buffer = temp->old_xfer_buffer;
        kfree(temp->kmalloc_ptr);
 
index 52ef084..f700157 100644 (file)
@@ -868,10 +868,13 @@ extern void       ehci_init_driver(struct hc_driver *drv,
 extern int     ehci_setup(struct usb_hcd *hcd);
 extern int     ehci_handshake(struct ehci_hcd *ehci, void __iomem *ptr,
                                u32 mask, u32 done, int usec);
+extern int     ehci_reset(struct ehci_hcd *ehci);
 
 #ifdef CONFIG_PM
 extern int     ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);
 extern int     ehci_resume(struct usb_hcd *hcd, bool force_reset);
+extern void    ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
+                       bool suspending, bool do_wakeup);
 #endif /* CONFIG_PM */
 
 extern int     ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
index 7e325e9..5e0d600 100644 (file)
@@ -126,6 +126,8 @@ static int usb_get_ver_info(struct device_node *np)
        /*
         * returns 1 for usb controller version 1.6
         * returns 2 for usb controller version 2.2
+        * returns 3 for usb controller version 2.4
+        * returns 4 for usb controller version 2.5
         * returns 0 otherwise
         */
        if (of_device_is_compatible(np, "fsl-usb2-dr")) {
@@ -135,6 +137,8 @@ static int usb_get_ver_info(struct device_node *np)
                        ver = FSL_USB_VER_2_2;
                else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.4"))
                        ver = FSL_USB_VER_2_4;
+               else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.5"))
+                       ver = FSL_USB_VER_2_5;
                else /* for previous controller versions */
                        ver = FSL_USB_VER_OLD;
 
@@ -150,6 +154,10 @@ static int usb_get_ver_info(struct device_node *np)
                        ver = FSL_USB_VER_1_6;
                else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.2"))
                        ver = FSL_USB_VER_2_2;
+               else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.4"))
+                       ver = FSL_USB_VER_2_4;
+               else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.5"))
+                       ver = FSL_USB_VER_2_5;
                else /* for previous controller versions */
                        ver = FSL_USB_VER_OLD;
        }
index 00e492e..1fd8718 100644 (file)
@@ -499,7 +499,8 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
        unsigned                i;
        __hc32                  tag;
 
-       if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC)))
+       seen = kmalloc(DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC);
+       if (!seen)
                return 0;
        seen_count = 0;
 
index 13181dc..d089b3f 100644 (file)
@@ -500,7 +500,8 @@ static void start_atl_transfers(struct isp116x *isp116x)
        if (isp116x->periodic_count) {
                isp116x->fmindex = index =
                    (isp116x->fmindex + 1) & (PERIODIC_SIZE - 1);
-               if ((load = isp116x->load[index])) {
+               load = isp116x->load[index];
+               if (load) {
                        /* Bring all int transfers for this frame
                           into the active queue */
                        isp116x->atl_active = last_ep =
index 04f2186..c3eded3 100644 (file)
@@ -491,7 +491,8 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
        char                    *next;
        unsigned                i;
 
-       if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC)))
+       seen = kmalloc(DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC);
+       if (!seen)
                return 0;
        seen_count = 0;
 
@@ -506,7 +507,8 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
        /* dump a snapshot of the periodic schedule (and load) */
        spin_lock_irqsave (&ohci->lock, flags);
        for (i = 0; i < NUM_INTS; i++) {
-               if (!(ed = ohci->periodic [i]))
+               ed = ohci->periodic[i];
+               if (!ed)
                        continue;
 
                temp = scnprintf (next, size, "%2d [%3d]:", i, ohci->load [i]);
index 1dab9df..760cb57 100644 (file)
@@ -155,7 +155,8 @@ static int ohci_urb_enqueue (
        int             retval = 0;
 
        /* every endpoint has a ed, locate and maybe (re)initialize it */
-       if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
+       ed = ed_get(ohci, urb->ep, urb->dev, pipe, urb->interval);
+       if (! ed)
                return -ENOMEM;
 
        /* for the private part of the URB we need the number of TDs (size) */
index 185ceee..c2669f1 100644 (file)
@@ -57,15 +57,13 @@ static int ohci_platform_power_on(struct platform_device *dev)
        }
 
        for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
-               if (priv->phys[phy_num]) {
-                       ret = phy_init(priv->phys[phy_num]);
-                       if (ret)
-                               goto err_exit_phy;
-                       ret = phy_power_on(priv->phys[phy_num]);
-                       if (ret) {
-                               phy_exit(priv->phys[phy_num]);
-                               goto err_exit_phy;
-                       }
+               ret = phy_init(priv->phys[phy_num]);
+               if (ret)
+                       goto err_exit_phy;
+               ret = phy_power_on(priv->phys[phy_num]);
+               if (ret) {
+                       phy_exit(priv->phys[phy_num]);
+                       goto err_exit_phy;
                }
        }
 
@@ -73,10 +71,8 @@ static int ohci_platform_power_on(struct platform_device *dev)
 
 err_exit_phy:
        while (--phy_num >= 0) {
-               if (priv->phys[phy_num]) {
-                       phy_power_off(priv->phys[phy_num]);
-                       phy_exit(priv->phys[phy_num]);
-               }
+               phy_power_off(priv->phys[phy_num]);
+               phy_exit(priv->phys[phy_num]);
        }
 err_disable_clks:
        while (--clk >= 0)
@@ -92,10 +88,8 @@ static void ohci_platform_power_off(struct platform_device *dev)
        int clk, phy_num;
 
        for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
-               if (priv->phys[phy_num]) {
-                       phy_power_off(priv->phys[phy_num]);
-                       phy_exit(priv->phys[phy_num]);
-               }
+               phy_power_off(priv->phys[phy_num]);
+               phy_exit(priv->phys[phy_num]);
        }
 
        for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
@@ -123,7 +117,6 @@ static int ohci_platform_probe(struct platform_device *dev)
        struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
        struct ohci_platform_priv *priv;
        struct ohci_hcd *ohci;
-       const char *phy_name;
        int err, irq, phy_num, clk = 0;
 
        if (usb_disabled())
@@ -174,36 +167,22 @@ static int ohci_platform_probe(struct platform_device *dev)
 
                priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
                                "phys", "#phy-cells");
-               priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1;
 
-               priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
-                               sizeof(struct phy *), GFP_KERNEL);
-               if (!priv->phys)
-                       return -ENOMEM;
+               if (priv->num_phys > 0) {
+                       priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
+                                           sizeof(struct phy *), GFP_KERNEL);
+                       if (!priv->phys)
+                               return -ENOMEM;
+               } else
+                       priv->num_phys = 0;
 
                for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
-                               err = of_property_read_string_index(
-                                               dev->dev.of_node,
-                                               "phy-names", phy_num,
-                                               &phy_name);
-
-                               if (err < 0) {
-                                       if (priv->num_phys > 1) {
-                                               dev_err(&dev->dev, "phy-names not provided");
-                                               goto err_put_hcd;
-                                       } else
-                                               phy_name = "usb";
-                               }
-
-                               priv->phys[phy_num] = devm_phy_get(&dev->dev,
-                                               phy_name);
-                               if (IS_ERR(priv->phys[phy_num])) {
-                                       err = PTR_ERR(priv->phys[phy_num]);
-                                       if ((priv->num_phys > 1) ||
-                                           (err == -EPROBE_DEFER))
-                                               goto err_put_hcd;
-                                       priv->phys[phy_num] = NULL;
-                               }
+                       priv->phys[phy_num] = devm_of_phy_get_by_index(
+                                       &dev->dev, dev->dev.of_node, phy_num);
+                       if (IS_ERR(priv->phys[phy_num])) {
+                               err = PTR_ERR(priv->phys[phy_num]);
+                               goto err_put_hcd;
+                       }
                }
 
                for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {
index 1463c39..f7d561e 100644 (file)
@@ -407,7 +407,8 @@ static struct ed *ed_get (
 
        spin_lock_irqsave (&ohci->lock, flags);
 
-       if (!(ed = ep->hcpriv)) {
+       ed = ep->hcpriv;
+       if (!ed) {
                struct td       *td;
                int             is_out;
                u32             info;
index ffc32f4..62b6b78 100644 (file)
@@ -105,7 +105,7 @@ static struct platform_device *ssb_hcd_create_pdev(struct ssb_device *dev, bool
 {
        struct platform_device *hci_dev;
        struct resource hci_res[2];
-       int ret = -ENOMEM;
+       int ret;
 
        memset(hci_res, 0, sizeof(hci_res));
 
@@ -119,7 +119,7 @@ static struct platform_device *ssb_hcd_create_pdev(struct ssb_device *dev, bool
        hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
                                        "ehci-platform" , 0);
        if (!hci_dev)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        hci_dev->dev.parent = dev->dev;
        hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
@@ -166,7 +166,8 @@ static int ssb_hcd_probe(struct ssb_device *dev,
        if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32)))
                return -EOPNOTSUPP;
 
-       usb_dev = kzalloc(sizeof(struct ssb_hcd_device), GFP_KERNEL);
+       usb_dev = devm_kzalloc(dev->dev, sizeof(struct ssb_hcd_device),
+                              GFP_KERNEL);
        if (!usb_dev)
                return -ENOMEM;
 
@@ -181,10 +182,8 @@ static int ssb_hcd_probe(struct ssb_device *dev,
        start = ssb_admatch_base(tmp);
        len = (coreid == SSB_DEV_USB20_HOST) ? 0x800 : ssb_admatch_size(tmp);
        usb_dev->ohci_dev = ssb_hcd_create_pdev(dev, true, start, len);
-       if (IS_ERR(usb_dev->ohci_dev)) {
-               err = PTR_ERR(usb_dev->ohci_dev);
-               goto err_free_usb_dev;
-       }
+       if (IS_ERR(usb_dev->ohci_dev))
+               return PTR_ERR(usb_dev->ohci_dev);
 
        if (coreid == SSB_DEV_USB20_HOST) {
                start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */
@@ -200,8 +199,6 @@ static int ssb_hcd_probe(struct ssb_device *dev,
 
 err_unregister_ohci_dev:
        platform_device_unregister(usb_dev->ohci_dev);
-err_free_usb_dev:
-       kfree(usb_dev);
        return err;
 }
 
index 0827d7c..e75c565 100644 (file)
@@ -1184,6 +1184,10 @@ int xhci_bus_resume(struct usb_hcd *hcd)
        struct xhci_bus_state *bus_state;
        u32 temp;
        unsigned long flags;
+       unsigned long port_was_suspended = 0;
+       bool need_usb2_u3_exit = false;
+       int slot_id;
+       int sret;
 
        max_ports = xhci_get_ports(hcd, &port_array);
        bus_state = &xhci->bus_state[hcd_index(hcd)];
@@ -1207,7 +1211,6 @@ int xhci_bus_resume(struct usb_hcd *hcd)
                /* Check whether need resume ports. If needed
                   resume port and disable remote wakeup */
                u32 temp;
-               int slot_id;
 
                temp = readl(port_array[port_index]);
                if (DEV_SUPERSPEED(temp))
@@ -1216,39 +1219,47 @@ int xhci_bus_resume(struct usb_hcd *hcd)
                        temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
                if (test_bit(port_index, &bus_state->bus_suspended) &&
                    (temp & PORT_PLS_MASK)) {
-                       if (DEV_SUPERSPEED(temp)) {
-                               xhci_set_link_state(xhci, port_array,
-                                                       port_index, XDEV_U0);
-                       } else {
+                       set_bit(port_index, &port_was_suspended);
+                       if (!DEV_SUPERSPEED(temp)) {
                                xhci_set_link_state(xhci, port_array,
                                                port_index, XDEV_RESUME);
-
-                               spin_unlock_irqrestore(&xhci->lock, flags);
-                               msleep(20);
-                               spin_lock_irqsave(&xhci->lock, flags);
-
-                               xhci_set_link_state(xhci, port_array,
-                                                       port_index, XDEV_U0);
+                               need_usb2_u3_exit = true;
                        }
-                       /* wait for the port to enter U0 and report port link
-                        * state change.
-                        */
-                       spin_unlock_irqrestore(&xhci->lock, flags);
-                       msleep(20);
-                       spin_lock_irqsave(&xhci->lock, flags);
-
-                       /* Clear PLC */
-                       xhci_test_and_clear_bit(xhci, port_array, port_index,
-                                               PORT_PLC);
-
-                       slot_id = xhci_find_slot_id_by_port(hcd,
-                                       xhci, port_index + 1);
-                       if (slot_id)
-                               xhci_ring_device(xhci, slot_id);
                } else
                        writel(temp, port_array[port_index]);
        }
 
+       if (need_usb2_u3_exit) {
+               spin_unlock_irqrestore(&xhci->lock, flags);
+               msleep(20);
+               spin_lock_irqsave(&xhci->lock, flags);
+       }
+
+       port_index = max_ports;
+       while (port_index--) {
+               if (!(port_was_suspended & BIT(port_index)))
+                       continue;
+               /* Clear PLC to poll it later after XDEV_U0 */
+               xhci_test_and_clear_bit(xhci, port_array, port_index, PORT_PLC);
+               xhci_set_link_state(xhci, port_array, port_index, XDEV_U0);
+       }
+
+       port_index = max_ports;
+       while (port_index--) {
+               if (!(port_was_suspended & BIT(port_index)))
+                       continue;
+               /* Poll and Clear PLC */
+               sret = xhci_handshake(port_array[port_index], PORT_PLC,
+                                     PORT_PLC, 10 * 1000);
+               if (sret)
+                       xhci_warn(xhci, "port %d resume PLC timeout\n",
+                                 port_index);
+               xhci_test_and_clear_bit(xhci, port_array, port_index, PORT_PLC);
+               slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1);
+               if (slot_id)
+                       xhci_ring_device(xhci, slot_id);
+       }
+
        (void) readl(&xhci->op_regs->command);
 
        bus_state->next_statechange = jiffies + msecs_to_jiffies(5);
index 2af32e2..4a4cb1d 100644 (file)
@@ -45,6 +45,13 @@ static const char hcd_name[] = "xhci_hcd";
 
 static struct hc_driver __read_mostly xhci_pci_hc_driver;
 
+static int xhci_pci_setup(struct usb_hcd *hcd);
+
+static const struct xhci_driver_overrides xhci_pci_overrides __initconst = {
+       .extra_priv_size = sizeof(struct xhci_hcd),
+       .reset = xhci_pci_setup,
+};
+
 /* called after powerup, by probe or system-pm "wakeup" */
 static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev)
 {
@@ -206,7 +213,6 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
        if (!retval)
                return retval;
 
-       kfree(xhci);
        return retval;
 }
 
@@ -247,11 +253,6 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
                goto dealloc_usb2_hcd;
        }
 
-       /* Set the xHCI pointer before xhci_pci_setup() (aka hcd_driver.reset)
-        * is called by usb_add_hcd().
-        */
-       *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
-
        retval = usb_add_hcd(xhci->shared_hcd, dev->irq,
                        IRQF_SHARED);
        if (retval)
@@ -290,8 +291,6 @@ static void xhci_pci_remove(struct pci_dev *dev)
        /* Workaround for spurious wakeups at shutdown with HSW */
        if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
                pci_set_power_state(dev, PCI_D3hot);
-
-       kfree(xhci);
 }
 
 #ifdef CONFIG_PM
@@ -379,7 +378,7 @@ static struct pci_driver xhci_pci_driver = {
 
 static int __init xhci_pci_init(void)
 {
-       xhci_init_driver(&xhci_pci_hc_driver, xhci_pci_setup);
+       xhci_init_driver(&xhci_pci_hc_driver, &xhci_pci_overrides);
 #ifdef CONFIG_PM
        xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend;
        xhci_pci_hc_driver.pci_resume = xhci_pci_resume;
index 783e819..890ad9d 100644 (file)
 
 static struct hc_driver __read_mostly xhci_plat_hc_driver;
 
+static int xhci_plat_setup(struct usb_hcd *hcd);
+static int xhci_plat_start(struct usb_hcd *hcd);
+
+static const struct xhci_driver_overrides xhci_plat_overrides __initconst = {
+       .extra_priv_size = sizeof(struct xhci_hcd),
+       .reset = xhci_plat_setup,
+       .start = xhci_plat_start,
+};
+
 static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
 {
        /*
@@ -127,31 +136,21 @@ static int xhci_plat_probe(struct platform_device *pdev)
                        goto disable_clk;
        }
 
-       ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
-       if (ret)
-               goto disable_clk;
-
        device_wakeup_enable(hcd->self.controller);
 
-       /* USB 2.0 roothub is stored in the platform_device now. */
-       hcd = platform_get_drvdata(pdev);
        xhci = hcd_to_xhci(hcd);
        xhci->clk = clk;
+       xhci->main_hcd = hcd;
        xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev,
                        dev_name(&pdev->dev), hcd);
        if (!xhci->shared_hcd) {
                ret = -ENOMEM;
-               goto dealloc_usb2_hcd;
+               goto disable_clk;
        }
 
        if ((node && of_property_read_bool(node, "usb3-lpm-capable")) ||
                        (pdata && pdata->usb3_lpm_capable))
                xhci->quirks |= XHCI_LPM_SUPPORT;
-       /*
-        * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
-        * is called by usb_add_hcd().
-        */
-       *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
 
        if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
                xhci->shared_hcd->can_do_streams = 1;
@@ -168,21 +167,26 @@ static int xhci_plat_probe(struct platform_device *pdev)
                        goto put_usb3_hcd;
        }
 
-       ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+       ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (ret)
                goto disable_usb_phy;
 
+       ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+       if (ret)
+               goto dealloc_usb2_hcd;
+
        return 0;
 
+
+dealloc_usb2_hcd:
+       usb_remove_hcd(hcd);
+
 disable_usb_phy:
        usb_phy_shutdown(hcd->usb_phy);
 
 put_usb3_hcd:
        usb_put_hcd(xhci->shared_hcd);
 
-dealloc_usb2_hcd:
-       usb_remove_hcd(hcd);
-
 disable_clk:
        if (!IS_ERR(clk))
                clk_disable_unprepare(clk);
@@ -201,13 +205,13 @@ static int xhci_plat_remove(struct platform_device *dev)
 
        usb_remove_hcd(xhci->shared_hcd);
        usb_phy_shutdown(hcd->usb_phy);
-       usb_put_hcd(xhci->shared_hcd);
 
        usb_remove_hcd(hcd);
+       usb_put_hcd(xhci->shared_hcd);
+
        if (!IS_ERR(clk))
                clk_disable_unprepare(clk);
        usb_put_hcd(hcd);
-       kfree(xhci);
 
        return 0;
 }
@@ -271,8 +275,7 @@ MODULE_ALIAS("platform:xhci-hcd");
 
 static int __init xhci_plat_init(void)
 {
-       xhci_init_driver(&xhci_plat_hc_driver, xhci_plat_setup);
-       xhci_plat_hc_driver.start = xhci_plat_start;
+       xhci_init_driver(&xhci_plat_hc_driver, &xhci_plat_overrides);
        return platform_driver_register(&usb_xhci_driver);
 }
 module_init(xhci_plat_init);
index 7d34cbf..94416ff 100644 (file)
@@ -1934,7 +1934,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
                        td->urb->actual_length =
                                td->urb->transfer_buffer_length -
                                EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
-               else
+               else if (!td->urb_length_set)
                        td->urb->actual_length = 0;
 
                return finish_td(xhci, td, event_trb, event, ep, status, false);
@@ -3781,8 +3781,11 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd,
 {
        int reserved_trbs = xhci->cmd_ring_reserved_trbs;
        int ret;
-       if (xhci->xhc_state & XHCI_STATE_DYING)
+
+       if (xhci->xhc_state) {
+               xhci_dbg(xhci, "xHCI dying or halted, can't queue_command\n");
                return -ESHUTDOWN;
+       }
 
        if (!command_must_succeed)
                reserved_trbs++;
index 36bf089..7da0d60 100644 (file)
@@ -660,12 +660,6 @@ static void xhci_only_stop_hcd(struct usb_hcd *hcd)
 
        spin_lock_irq(&xhci->lock);
        xhci_halt(xhci);
-
-       /* The shared_hcd is going to be deallocated shortly (the USB core only
-        * calls this function when allocation fails in usb_add_hcd(), or
-        * usb_remove_hcd() is called).  So we need to unset xHCI's pointer.
-        */
-       xhci->shared_hcd = NULL;
        spin_unlock_irq(&xhci->lock);
 }
 
@@ -897,6 +891,9 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
        struct usb_hcd          *hcd = xhci_to_hcd(xhci);
        u32                     command;
 
+       if (!hcd->state)
+               return 0;
+
        if (hcd->state != HC_STATE_SUSPENDED ||
                        xhci->shared_hcd->state != HC_STATE_SUSPENDED)
                return -EINVAL;
@@ -983,6 +980,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
        int                     retval = 0;
        bool                    comp_timer_running = false;
 
+       if (!hcd->state)
+               return 0;
+
        /* Wait a bit if either of the roothubs need to settle from the
         * transition into bus suspend.
         */
@@ -3769,8 +3769,6 @@ disable_slot:
 /*
  * Issue an Address Device command and optionally send a corresponding
  * SetAddress request to the device.
- * We should be protected by the usb_address0_mutex in hub_wq's hub_port_init,
- * so we should only issue and wait on one address command at the same time.
  */
 static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
                             enum xhci_setup_dev setup)
@@ -4842,10 +4840,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
        hcd->self.no_stop_on_short = 1;
 
        if (usb_hcd_is_primary_hcd(hcd)) {
-               xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
-               if (!xhci)
-                       return -ENOMEM;
-               *((struct xhci_hcd **) hcd->hcd_priv) = xhci;
+               xhci = hcd_to_xhci(hcd);
                xhci->main_hcd = hcd;
                /* Mark the first roothub as being USB 2.0.
                 * The xHCI driver will register the USB 3.0 roothub.
@@ -4894,13 +4889,13 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
        /* Make sure the HC is halted. */
        retval = xhci_halt(xhci);
        if (retval)
-               goto error;
+               return retval;
 
        xhci_dbg(xhci, "Resetting HCD\n");
        /* Reset the internal HC memory state and registers. */
        retval = xhci_reset(xhci);
        if (retval)
-               goto error;
+               return retval;
        xhci_dbg(xhci, "Reset complete\n");
 
        /* Set dma_mask and coherent_dma_mask to 64-bits,
@@ -4915,16 +4910,13 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
        /* Initialize HCD and host controller data structures. */
        retval = xhci_init(hcd);
        if (retval)
-               goto error;
+               return retval;
        xhci_dbg(xhci, "Called HCD init\n");
 
        xhci_info(xhci, "hcc params 0x%08x hci version 0x%x quirks 0x%08x\n",
                  xhci->hcc_params, xhci->hci_version, xhci->quirks);
 
        return 0;
-error:
-       kfree(xhci);
-       return retval;
 }
 EXPORT_SYMBOL_GPL(xhci_gen_setup);
 
@@ -4989,11 +4981,21 @@ static const struct hc_driver xhci_hc_driver = {
        .find_raw_port_number = xhci_find_raw_port_number,
 };
 
-void xhci_init_driver(struct hc_driver *drv, int (*setup_fn)(struct usb_hcd *))
+void xhci_init_driver(struct hc_driver *drv,
+                     const struct xhci_driver_overrides *over)
 {
-       BUG_ON(!setup_fn);
+       BUG_ON(!over);
+
+       /* Copy the generic table to drv then apply the overrides */
        *drv = xhci_hc_driver;
-       drv->reset = setup_fn;
+
+       if (over) {
+               drv->hcd_priv_size += over->extra_priv_size;
+               if (over->reset)
+                       drv->reset = over->reset;
+               if (over->start)
+                       drv->start = over->start;
+       }
 }
 EXPORT_SYMBOL_GPL(xhci_init_driver);
 
index 6977f84..31e46cc 100644 (file)
@@ -1593,10 +1593,24 @@ struct xhci_hcd {
 #define COMP_MODE_RCVRY_MSECS 2000
 };
 
+/* Platform specific overrides to generic XHCI hc_driver ops */
+struct xhci_driver_overrides {
+       size_t extra_priv_size;
+       int (*reset)(struct usb_hcd *hcd);
+       int (*start)(struct usb_hcd *hcd);
+};
+
 /* convert between an HCD pointer and the corresponding EHCI_HCD */
 static inline struct xhci_hcd *hcd_to_xhci(struct usb_hcd *hcd)
 {
-       return *((struct xhci_hcd **) (hcd->hcd_priv));
+       struct usb_hcd *primary_hcd;
+
+       if (usb_hcd_is_primary_hcd(hcd))
+               primary_hcd = hcd;
+       else
+               primary_hcd = hcd->primary_hcd;
+
+       return (struct xhci_hcd *) (primary_hcd->hcd_priv);
 }
 
 static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)
@@ -1750,7 +1764,8 @@ int xhci_run(struct usb_hcd *hcd);
 void xhci_stop(struct usb_hcd *hcd);
 void xhci_shutdown(struct usb_hcd *hcd);
 int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
-void xhci_init_driver(struct hc_driver *drv, int (*setup_fn)(struct usb_hcd *));
+void xhci_init_driver(struct hc_driver *drv,
+                     const struct xhci_driver_overrides *over);
 
 #ifdef CONFIG_PM
 int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup);
index 3fc4fe7..18ebf5b 100644 (file)
@@ -812,6 +812,8 @@ static struct usb_request *isp1760_ep_alloc_request(struct usb_ep *ep,
        struct isp1760_request *req;
 
        req = kzalloc(sizeof(*req), gfp_flags);
+       if (!req)
+               return NULL;
 
        return &req->req;
 }
index 022dc00..306d685 100644 (file)
@@ -2316,10 +2316,12 @@ sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
        /* Set mode 0x03 */
        SiSUSBSetMode(sisusb->SiS_Pr, 0x03);
 
-       if (!(myfont = find_font("VGA8x16")))
+       myfont = find_font("VGA8x16");
+       if (!myfont)
                return 1;
 
-       if (!(tempbuf = vmalloc(8192)))
+       tempbuf = vmalloc(8192);
+       if (!tempbuf)
                return 1;
 
        for (i = 0; i < 256; i++)
@@ -2342,7 +2344,8 @@ sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
 
        if (init && !sisusb->scrbuf) {
 
-               if ((tempbuf = vmalloc(8192))) {
+               tempbuf = vmalloc(8192);
+               if (tempbuf) {
 
                        i = 4096;
                        tempbufb = (u16 *)tempbuf;
@@ -2417,11 +2420,13 @@ sisusb_open(struct inode *inode, struct file *file)
        struct usb_interface *interface;
        int subminor = iminor(inode);
 
-       if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
+       interface = usb_find_interface(&sisusb_driver, subminor);
+       if (!interface) {
                return -ENODEV;
        }
 
-       if (!(sisusb = usb_get_intfdata(interface))) {
+       sisusb = usb_get_intfdata(interface);
+       if (!sisusb) {
                return -ENODEV;
        }
 
@@ -2488,7 +2493,8 @@ sisusb_release(struct inode *inode, struct file *file)
 {
        struct sisusb_usb_data *sisusb;
 
-       if (!(sisusb = file->private_data))
+       sisusb = file->private_data;
+       if (!sisusb)
                return -ENODEV;
 
        mutex_lock(&sisusb->lock);
@@ -2520,7 +2526,8 @@ sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
        u16 buf16;
        u32 buf32, address;
 
-       if (!(sisusb = file->private_data))
+       sisusb = file->private_data;
+       if (!sisusb)
                return -ENODEV;
 
        mutex_lock(&sisusb->lock);
@@ -2662,7 +2669,8 @@ sisusb_write(struct file *file, const char __user *buffer, size_t count,
        u16 buf16;
        u32 buf32, address;
 
-       if (!(sisusb = file->private_data))
+       sisusb = file->private_data;
+       if (!sisusb)
                return -ENODEV;
 
        mutex_lock(&sisusb->lock);
@@ -2805,7 +2813,8 @@ sisusb_lseek(struct file *file, loff_t offset, int orig)
        struct sisusb_usb_data *sisusb;
        loff_t ret;
 
-       if (!(sisusb = file->private_data))
+       sisusb = file->private_data;
+       if (!sisusb)
                return -ENODEV;
 
        mutex_lock(&sisusb->lock);
@@ -2970,7 +2979,8 @@ sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        long retval = 0;
        u32 __user *argp = (u32 __user *)arg;
 
-       if (!(sisusb = file->private_data))
+       sisusb = file->private_data;
+       if (!sisusb)
                return -ENODEV;
 
        mutex_lock(&sisusb->lock);
@@ -3084,7 +3094,8 @@ static int sisusb_probe(struct usb_interface *intf,
                dev->devnum);
 
        /* Allocate memory for our private */
-       if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
+       sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL);
+       if (!sisusb) {
                dev_err(&dev->dev, "Failed to allocate memory for private data\n");
                return -ENOMEM;
        }
@@ -3093,7 +3104,8 @@ static int sisusb_probe(struct usb_interface *intf,
        mutex_init(&(sisusb->lock));
 
        /* Register device */
-       if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
+       retval = usb_register_dev(intf, &usb_sisusb_class);
+       if (retval) {
                dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n",
                        dev->devnum);
                retval = -ENODEV;
@@ -3214,7 +3226,8 @@ static void sisusb_disconnect(struct usb_interface *intf)
        struct sisusb_usb_data *sisusb;
 
        /* This should *not* happen */
-       if (!(sisusb = usb_get_intfdata(intf)))
+       sisusb = usb_get_intfdata(intf);
+       if (!sisusb)
                return;
 
 #ifdef INCL_SISUSB_CON
index a638c4e..ace3430 100644 (file)
@@ -169,7 +169,8 @@ sisusb_get_sisusb_lock_and_check(unsigned short console)
        if (in_atomic())
                return NULL;
 
-       if (!(sisusb = sisusb_get_sisusb(console)))
+       sisusb = sisusb_get_sisusb(console);
+       if (!sisusb)
                return NULL;
 
        mutex_lock(&sisusb->lock);
@@ -214,7 +215,8 @@ sisusbcon_init(struct vc_data *c, int init)
         * are set up/restored.
         */
 
-       if (!(sisusb = sisusb_get_sisusb(c->vc_num)))
+       sisusb = sisusb_get_sisusb(c->vc_num);
+       if (!sisusb)
                return;
 
        mutex_lock(&sisusb->lock);
@@ -277,7 +279,8 @@ sisusbcon_deinit(struct vc_data *c)
         * and others, ie not under our control.
         */
 
-       if (!(sisusb = sisusb_get_sisusb(c->vc_num)))
+       sisusb = sisusb_get_sisusb(c->vc_num);
+       if (!sisusb)
                return;
 
        mutex_lock(&sisusb->lock);
@@ -369,7 +372,8 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
        struct sisusb_usb_data *sisusb;
        ssize_t written;
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return;
 
        /* sisusb->lock is down */
@@ -395,7 +399,8 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s,
        u16 *dest;
        int i;
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return;
 
        /* sisusb->lock is down */
@@ -433,7 +438,8 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width)
        if (width <= 0 || height <= 0)
                return;
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return;
 
        /* sisusb->lock is down */
@@ -486,7 +492,8 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
        if (width <= 0 || height <= 0)
                return;
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return;
 
        /* sisusb->lock is down */
@@ -520,7 +527,8 @@ sisusbcon_switch(struct vc_data *c)
         * Returnvalue != 0 naturally means the opposite.
         */
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return 0;
 
        /* sisusb->lock is down */
@@ -569,7 +577,8 @@ sisusbcon_save_screen(struct vc_data *c)
         * buffer.
         */
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return;
 
        /* sisusb->lock is down */
@@ -602,7 +611,8 @@ sisusbcon_set_palette(struct vc_data *c, unsigned char *table)
        if (!CON_IS_VISIBLE(c))
                return -EINVAL;
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return -EINVAL;
 
        /* sisusb->lock is down */
@@ -637,7 +647,8 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch)
        ssize_t written;
        int ret = 0;
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return 0;
 
        /* sisusb->lock is down */
@@ -721,7 +732,8 @@ sisusbcon_scrolldelta(struct vc_data *c, int lines)
 
        /* The return value does not seem to be used */
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return 0;
 
        /* sisusb->lock is down */
@@ -779,7 +791,8 @@ sisusbcon_cursor(struct vc_data *c, int mode)
        struct sisusb_usb_data *sisusb;
        int from, to, baseline;
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return;
 
        /* sisusb->lock is down */
@@ -906,7 +919,8 @@ sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
        if (!lines)
                return 1;
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return 0;
 
        /* sisusb->lock is down */
@@ -1018,7 +1032,8 @@ sisusbcon_set_origin(struct vc_data *c)
         *      screenbuffer as the origin.
         */
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return 0;
 
        /* sisusb->lock is down */
@@ -1047,7 +1062,8 @@ sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows,
        struct sisusb_usb_data *sisusb;
        int fh;
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return -ENODEV;
 
        fh = sisusb->current_font_height;
@@ -1286,7 +1302,8 @@ sisusbcon_font_set(struct vc_data *c, struct console_font *font,
        if (font->width != 8 || (charcount != 256 && charcount != 512))
                return -EINVAL;
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return -ENODEV;
 
        /* sisusb->lock is down */
@@ -1326,7 +1343,8 @@ sisusbcon_font_get(struct vc_data *c, struct console_font *font)
 {
        struct sisusb_usb_data *sisusb;
 
-       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+       sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+       if (!sisusb)
                return -ENODEV;
 
        /* sisusb->lock is down */
index 588d62a..bbd029c 100644 (file)
@@ -714,7 +714,8 @@ static int uss720_probe(struct usb_interface *intf,
        /*
         * Allocate parport interface 
         */
-       if (!(priv = kzalloc(sizeof(struct parport_uss720_private), GFP_KERNEL))) {
+       priv = kzalloc(sizeof(struct parport_uss720_private), GFP_KERNEL);
+       if (!priv) {
                usb_put_dev(usbdev);
                return -ENOMEM;
        }
@@ -723,7 +724,8 @@ static int uss720_probe(struct usb_interface *intf,
        kref_init(&priv->ref_count);
        spin_lock_init(&priv->asynclock);
        INIT_LIST_HEAD(&priv->asynclist);
-       if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) {
+       pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops);
+       if (!pp) {
                printk(KERN_WARNING "uss720: could not register parport\n");
                goto probe_abort;
        }
index 9a62e89..3598f1a 100644 (file)
@@ -675,7 +675,8 @@ static int mon_bin_open(struct inode *inode, struct file *file)
        int rc;
 
        mutex_lock(&mon_lock);
-       if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) {
+       mbus = mon_bus_lookup(iminor(inode));
+       if (mbus == NULL) {
                mutex_unlock(&mon_lock);
                return -ENODEV;
        }
@@ -1018,8 +1019,8 @@ static long mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg
                        return -EINVAL;
 
                size = CHUNK_ALIGN(arg);
-               if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE),
-                   GFP_KERNEL)) == NULL) {
+               vec = kzalloc(sizeof(struct mon_pgmap) * (size / CHUNK_SIZE), GFP_KERNEL);
+               if (vec == NULL) {
                        ret = -ENOMEM;
                        break;
                }
index 1040511..f7c292f 100644 (file)
@@ -96,7 +96,8 @@ static void mon_submit(struct usb_bus *ubus, struct urb *urb)
 {
        struct mon_bus *mbus;
 
-       if ((mbus = ubus->mon_bus) != NULL)
+       mbus = ubus->mon_bus;
+       if (mbus != NULL)
                mon_bus_submit(mbus, urb);
        mon_bus_submit(&mon_bus0, urb);
 }
@@ -122,7 +123,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
 {
        struct mon_bus *mbus;
 
-       if ((mbus = ubus->mon_bus) != NULL)
+       mbus = ubus->mon_bus;
+       if (mbus != NULL)
                mon_bus_submit_error(mbus, urb, error);
        mon_bus_submit_error(&mon_bus0, urb, error);
 }
@@ -148,7 +150,8 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status)
 {
        struct mon_bus *mbus;
 
-       if ((mbus = ubus->mon_bus) != NULL)
+       mbus = ubus->mon_bus;
+       if (mbus != NULL)
                mon_bus_complete(mbus, urb, status);
        mon_bus_complete(&mon_bus0, urb, status);
 }
@@ -280,7 +283,8 @@ static void mon_bus_init(struct usb_bus *ubus)
 {
        struct mon_bus *mbus;
 
-       if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
+       mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL);
+       if (mbus == NULL)
                goto err_alloc;
        kref_init(&mbus->ref);
        spin_lock_init(&mbus->lock);
index ebd6189..5388a33 100644 (file)
@@ -28,7 +28,8 @@ static int mon_stat_open(struct inode *inode, struct file *file)
        struct mon_bus *mbus;
        struct snap *sp;
 
-       if ((sp = kmalloc(sizeof(struct snap), GFP_KERNEL)) == NULL)
+       sp = kmalloc(sizeof(struct snap), GFP_KERNEL);
+       if (sp == NULL)
                return -ENOMEM;
 
        mbus = inode->i_private;
index 220fd4d..c41fe58 100644 (file)
@@ -438,11 +438,15 @@ static void am35x_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
 }
 
 static const struct musb_platform_ops am35x_ops = {
-       .quirks         = MUSB_INDEXED_EP,
+       .quirks         = MUSB_DMA_INVENTRA | MUSB_INDEXED_EP,
        .init           = am35x_musb_init,
        .exit           = am35x_musb_exit,
 
        .read_fifo      = am35x_read_fifo,
+#ifdef CONFIG_USB_INVENTRA_DMA
+       .dma_init       = musbhs_dma_controller_create,
+       .dma_exit       = musbhs_dma_controller_destroy,
+#endif
        .enable         = am35x_musb_enable,
        .disable        = am35x_musb_disable,
 
@@ -565,7 +569,7 @@ static int am35x_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int am35x_suspend(struct device *dev)
 {
        struct am35x_glue       *glue = dev_get_drvdata(dev);
index 6123b74..310238c 100644 (file)
@@ -465,6 +465,7 @@ static int bfin_musb_exit(struct musb *musb)
 }
 
 static const struct musb_platform_ops bfin_ops = {
+       .quirks         = MUSB_DMA_INVENTRA,
        .init           = bfin_musb_init,
        .exit           = bfin_musb_exit,
 
@@ -477,6 +478,10 @@ static const struct musb_platform_ops bfin_ops = {
        .fifo_mode      = 2,
        .read_fifo      = bfin_read_fifo,
        .write_fifo     = bfin_write_fifo,
+#ifdef CONFIG_USB_INVENTRA_DMA
+       .dma_init       = musbhs_dma_controller_create,
+       .dma_exit       = musbhs_dma_controller_destroy,
+#endif
        .enable         = bfin_musb_enable,
        .disable        = bfin_musb_disable,
 
index 904fb85..cc13410 100644 (file)
@@ -1297,7 +1297,8 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
 EXPORT_SYMBOL_GPL(cppi_interrupt);
 
 /* Instantiate a software object representing a DMA controller. */
-struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mregs)
+struct dma_controller *
+cppi_dma_controller_create(struct musb *musb, void __iomem *mregs)
 {
        struct cppi             *controller;
        struct device           *dev = musb->controller;
@@ -1334,7 +1335,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr
        if (irq > 0) {
                if (request_irq(irq, cppi_interrupt, 0, "cppi-dma", musb)) {
                        dev_err(dev, "request_irq %d failed!\n", irq);
-                       dma_controller_destroy(&controller->controller);
+                       musb_dma_controller_destroy(&controller->controller);
                        return NULL;
                }
                controller->irq = irq;
@@ -1343,11 +1344,12 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr
        cppi_controller_start(controller);
        return &controller->controller;
 }
+EXPORT_SYMBOL_GPL(cppi_dma_controller_create);
 
 /*
  *  Destroy a previously-instantiated DMA controller.
  */
-void dma_controller_destroy(struct dma_controller *c)
+void cppi_dma_controller_destroy(struct dma_controller *c)
 {
        struct cppi     *cppi;
 
@@ -1363,6 +1365,7 @@ void dma_controller_destroy(struct dma_controller *c)
 
        kfree(cppi);
 }
+EXPORT_SYMBOL_GPL(cppi_dma_controller_destroy);
 
 /*
  * Context: controller irqlocked, endpoint selected
index 9a9c82a..b03d3b8 100644 (file)
@@ -458,11 +458,15 @@ static int da8xx_musb_exit(struct musb *musb)
 }
 
 static const struct musb_platform_ops da8xx_ops = {
-       .quirks         = MUSB_INDEXED_EP,
+       .quirks         = MUSB_DMA_CPPI | MUSB_INDEXED_EP,
        .init           = da8xx_musb_init,
        .exit           = da8xx_musb_exit,
 
        .fifo_mode      = 2,
+#ifdef CONFIG_USB_TI_CPPI_DMA
+       .dma_init       = cppi_dma_controller_create,
+       .dma_exit       = cppi_dma_controller_destroy,
+#endif
        .enable         = da8xx_musb_enable,
        .disable        = da8xx_musb_disable,
 
index 3c1d9b2..cee61a5 100644 (file)
@@ -284,7 +284,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
         * mask, state, "vector", and EOI registers.
         */
        cppi = container_of(musb->dma_controller, struct cppi, controller);
-       if (is_cppi_enabled() && musb->dma_controller && !cppi->irq)
+       if (is_cppi_enabled(musb) && musb->dma_controller && !cppi->irq)
                retval = cppi_interrupt(irq, __hci);
 
        /* ack and handle non-CPPI interrupts */
@@ -491,9 +491,14 @@ static int davinci_musb_exit(struct musb *musb)
 }
 
 static const struct musb_platform_ops davinci_ops = {
+       .quirks         = MUSB_DMA_CPPI,
        .init           = davinci_musb_init,
        .exit           = davinci_musb_exit,
 
+#ifdef CONFIG_USB_TI_CPPI_DMA
+       .dma_init       = cppi_dma_controller_create,
+       .dma_exit       = cppi_dma_controller_destroy,
+#endif
        .enable         = davinci_musb_enable,
        .disable        = davinci_musb_disable,
 
index bb7b263..5e5a8fa 100644 (file)
@@ -105,8 +105,12 @@ static int jz4740_musb_exit(struct musb *musb)
        return 0;
 }
 
+/*
+ * DMA has not been confirmed to work with CONFIG_USB_INVENTRA_DMA,
+ * so let's not set up the dma function pointers yet.
+ */
 static const struct musb_platform_ops jz4740_musb_ops = {
-       .quirks         = MUSB_INDEXED_EP,
+       .quirks         = MUSB_DMA_INVENTRA | MUSB_INDEXED_EP,
        .fifo_mode      = 2,
        .init           = jz4740_musb_init,
        .exit           = jz4740_musb_exit,
index 6dca3d7..514a6cd 100644 (file)
@@ -251,6 +251,11 @@ static u32 musb_indexed_ep_offset(u8 epnum, u16 offset)
        return 0x10 + offset;
 }
 
+static u32 musb_default_busctl_offset(u8 epnum, u16 offset)
+{
+       return 0x80 + (0x08 * epnum) + offset;
+}
+
 static u8 musb_default_readb(const void __iomem *addr, unsigned offset)
 {
        return __raw_readb(addr + offset);
@@ -309,7 +314,7 @@ static void musb_default_write_fifo(struct musb_hw_ep *hw_ep, u16 len,
                                index += len & ~0x03;
                        }
                        if (len & 0x02) {
-                               musb_writew(fifo, 0, *(u16 *)&src[index]);
+                               __raw_writew(*(u16 *)&src[index], fifo);
                                index += 2;
                        }
                } else {
@@ -319,7 +324,7 @@ static void musb_default_write_fifo(struct musb_hw_ep *hw_ep, u16 len,
                        }
                }
                if (len & 0x01)
-                       musb_writeb(fifo, 0, src[index]);
+                       __raw_writeb(src[index], fifo);
        } else  {
                /* byte aligned */
                iowrite8_rep(fifo, src, len);
@@ -351,7 +356,7 @@ static void musb_default_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
                                index = len & ~0x03;
                        }
                        if (len & 0x02) {
-                               *(u16 *)&dst[index] = musb_readw(fifo, 0);
+                               *(u16 *)&dst[index] = __raw_readw(fifo);
                                index += 2;
                        }
                } else {
@@ -361,7 +366,7 @@ static void musb_default_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
                        }
                }
                if (len & 0x01)
-                       dst[index] = musb_readb(fifo, 0);
+                       dst[index] = __raw_readb(fifo);
        } else  {
                /* byte aligned */
                ioread8_rep(fifo, dst, len);
@@ -389,6 +394,15 @@ EXPORT_SYMBOL_GPL(musb_readl);
 void (*musb_writel)(void __iomem *addr, unsigned offset, u32 data);
 EXPORT_SYMBOL_GPL(musb_writel);
 
+#ifndef CONFIG_MUSB_PIO_ONLY
+struct dma_controller *
+(*musb_dma_controller_create)(struct musb *musb, void __iomem *base);
+EXPORT_SYMBOL(musb_dma_controller_create);
+
+void (*musb_dma_controller_destroy)(struct dma_controller *c);
+EXPORT_SYMBOL(musb_dma_controller_destroy);
+#endif
+
 /*
  * New style IO functions
  */
@@ -1535,7 +1549,6 @@ static int musb_core_init(u16 musb_type, struct musb *musb)
 #endif
 
                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;
 
@@ -1658,15 +1671,13 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)
        /* called with controller lock already held */
 
        if (!epnum) {
-#ifndef CONFIG_USB_TUSB_OMAP_DMA
-               if (!is_cppi_enabled()) {
+               if (!is_cppi_enabled(musb)) {
                        /* endpoint 0 */
                        if (is_host_active(musb))
                                musb_h_ep0_irq(musb);
                        else
                                musb_g_ep0_irq(musb);
                }
-#endif
        } else {
                /* endpoints 1..15 */
                if (transmit) {
@@ -2029,6 +2040,11 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
                musb->io.ep_offset = musb_flat_ep_offset;
                musb->io.ep_select = musb_flat_ep_select;
        }
+       /* And override them with platform specific ops if specified. */
+       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;
 
        /* At least tusb6010 has its own offsets */
        if (musb->ops->ep_offset)
@@ -2046,6 +2062,11 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        else
                musb->io.fifo_offset = musb_default_fifo_offset;
 
+       if (musb->ops->busctl_offset)
+               musb->io.busctl_offset = musb->ops->busctl_offset;
+       else
+               musb->io.busctl_offset = musb_default_busctl_offset;
+
        if (musb->ops->readb)
                musb_readb = musb->ops->readb;
        if (musb->ops->writeb)
@@ -2059,6 +2080,15 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        if (musb->ops->writel)
                musb_writel = musb->ops->writel;
 
+#ifndef CONFIG_MUSB_PIO_ONLY
+       if (!musb->ops->dma_init || !musb->ops->dma_exit) {
+               dev_err(dev, "DMA controller not set\n");
+               goto fail2;
+       }
+       musb_dma_controller_create = musb->ops->dma_init;
+       musb_dma_controller_destroy = musb->ops->dma_exit;
+#endif
+
        if (musb->ops->read_fifo)
                musb->io.read_fifo = musb->ops->read_fifo;
        else
@@ -2078,7 +2108,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        pm_runtime_get_sync(musb->controller);
 
        if (use_dma && dev->dma_mask) {
-               musb->dma_controller = dma_controller_create(musb, musb->mregs);
+               musb->dma_controller =
+                       musb_dma_controller_create(musb, musb->mregs);
                if (IS_ERR(musb->dma_controller)) {
                        status = PTR_ERR(musb->dma_controller);
                        goto fail2_5;
@@ -2189,7 +2220,7 @@ fail3:
        cancel_delayed_work_sync(&musb->finish_resume_work);
        cancel_delayed_work_sync(&musb->deassert_reset_work);
        if (musb->dma_controller)
-               dma_controller_destroy(musb->dma_controller);
+               musb_dma_controller_destroy(musb->dma_controller);
 fail2_5:
        pm_runtime_put_sync(musb->controller);
 
@@ -2248,7 +2279,7 @@ static int musb_remove(struct platform_device *pdev)
        musb_shutdown(pdev);
 
        if (musb->dma_controller)
-               dma_controller_destroy(musb->dma_controller);
+               musb_dma_controller_destroy(musb->dma_controller);
 
        cancel_work_sync(&musb->irq_work);
        cancel_delayed_work_sync(&musb->finish_resume_work);
@@ -2316,18 +2347,18 @@ static void musb_save_context(struct musb *musb)
                        musb_readb(epio, MUSB_RXINTERVAL);
 
                musb->context.index_regs[i].txfunaddr =
-                       musb_read_txfunaddr(musb_base, i);
+                       musb_read_txfunaddr(musb, i);
                musb->context.index_regs[i].txhubaddr =
-                       musb_read_txhubaddr(musb_base, i);
+                       musb_read_txhubaddr(musb, i);
                musb->context.index_regs[i].txhubport =
-                       musb_read_txhubport(musb_base, i);
+                       musb_read_txhubport(musb, i);
 
                musb->context.index_regs[i].rxfunaddr =
-                       musb_read_rxfunaddr(musb_base, i);
+                       musb_read_rxfunaddr(musb, i);
                musb->context.index_regs[i].rxhubaddr =
-                       musb_read_rxhubaddr(musb_base, i);
+                       musb_read_rxhubaddr(musb, i);
                musb->context.index_regs[i].rxhubport =
-                       musb_read_rxhubport(musb_base, i);
+                       musb_read_rxhubport(musb, i);
        }
 }
 
@@ -2335,7 +2366,6 @@ static void musb_restore_context(struct musb *musb)
 {
        int i;
        void __iomem *musb_base = musb->mregs;
-       void __iomem *ep_target_regs;
        void __iomem *epio;
        u8 power;
 
@@ -2396,21 +2426,18 @@ static void musb_restore_context(struct musb *musb)
                musb_writeb(epio, MUSB_RXINTERVAL,
 
                                musb->context.index_regs[i].rxinterval);
-               musb_write_txfunaddr(musb_base, i,
+               musb_write_txfunaddr(musb, i,
                                musb->context.index_regs[i].txfunaddr);
-               musb_write_txhubaddr(musb_base, i,
+               musb_write_txhubaddr(musb, i,
                                musb->context.index_regs[i].txhubaddr);
-               musb_write_txhubport(musb_base, i,
+               musb_write_txhubport(musb, i,
                                musb->context.index_regs[i].txhubport);
 
-               ep_target_regs =
-                       musb_read_target_reg_base(i, musb_base);
-
-               musb_write_rxfunaddr(ep_target_regs,
+               musb_write_rxfunaddr(musb, i,
                                musb->context.index_regs[i].rxfunaddr);
-               musb_write_rxhubaddr(ep_target_regs,
+               musb_write_rxhubaddr(musb, i,
                                musb->context.index_regs[i].rxhubaddr);
-               musb_write_rxhubport(ep_target_regs,
+               musb_write_rxhubport(musb, i,
                                musb->context.index_regs[i].rxhubport);
        }
        musb_writeb(musb_base, MUSB_INDEX, musb->context.index);
index 3877249..4b886d0 100644 (file)
@@ -67,7 +67,6 @@ struct musb_ep;
 #include "musb_dma.h"
 
 #include "musb_io.h"
-#include "musb_regs.h"
 
 #include "musb_gadget.h"
 #include <linux/usb/hcd.h>
@@ -157,6 +156,8 @@ struct musb_io;
  * @writel:    write 32 bits
  * @read_fifo: reads the fifo
  * @write_fifo:        writes to fifo
+ * @dma_init:  platform specific dma init function
+ * @dma_exit:  platform specific dma exit function
  * @init:      turns on clocks, sets up platform-specific registers, etc
  * @exit:      undoes @init
  * @set_mode:  forcefully changes operating mode
@@ -165,6 +166,8 @@ struct musb_io;
  * @vbus_status: returns vbus status if possible
  * @set_vbus:  forces vbus status
  * @adjust_channel_params: pre check for standard dma channel_program func
+ * @pre_root_reset_end: called before the root usb port reset flag gets cleared
+ * @post_root_reset_end: called after the root usb port reset flag gets cleared
  */
 struct musb_platform_ops {
 
@@ -187,6 +190,7 @@ struct musb_platform_ops {
        void    (*ep_select)(void __iomem *mbase, u8 epnum);
        u16     fifo_mode;
        u32     (*fifo_offset)(u8 epnum);
+       u32     (*busctl_offset)(u8 epnum, u16 offset);
        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);
@@ -195,6 +199,9 @@ struct musb_platform_ops {
        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);
+       struct dma_controller *
+               (*dma_init) (struct musb *musb, void __iomem *base);
+       void    (*dma_exit)(struct dma_controller *c);
        int     (*set_mode)(struct musb *musb, u8 mode);
        void    (*try_idle)(struct musb *musb, unsigned long timeout);
        int     (*recover)(struct musb *musb);
@@ -205,6 +212,8 @@ struct musb_platform_ops {
        int     (*adjust_channel_params)(struct dma_channel *channel,
                                u16 packet_sz, u8 *mode,
                                dma_addr_t *dma_addr, u32 *len);
+       void    (*pre_root_reset_end)(struct musb *musb);
+       void    (*post_root_reset_end)(struct musb *musb);
 };
 
 /*
@@ -241,8 +250,6 @@ struct musb_hw_ep {
        void __iomem            *fifo_sync_va;
 #endif
 
-       void __iomem            *target_regs;
-
        /* currently scheduled peripheral endpoint */
        struct musb_qh          *in_qh;
        struct musb_qh          *out_qh;
@@ -437,6 +444,9 @@ struct musb {
 #endif
 };
 
+/* This must be included after struct musb is defined */
+#include "musb_regs.h"
+
 static inline struct musb *gadget_to_musb(struct usb_gadget *g)
 {
        return container_of(g, struct musb, g);
@@ -590,4 +600,16 @@ static inline int musb_platform_exit(struct musb *musb)
        return musb->ops->exit(musb);
 }
 
+static inline void musb_platform_pre_root_reset_end(struct musb *musb)
+{
+       if (musb->ops->pre_root_reset_end)
+               musb->ops->pre_root_reset_end(musb);
+}
+
+static inline void musb_platform_post_root_reset_end(struct musb *musb)
+{
+       if (musb->ops->post_root_reset_end)
+               musb->ops->post_root_reset_end(musb);
+}
+
 #endif /* __MUSB_CORE_H__ */
index 8bd8c5e..4d1b44c 100644 (file)
@@ -678,7 +678,7 @@ err:
        return ret;
 }
 
-void dma_controller_destroy(struct dma_controller *c)
+void cppi41_dma_controller_destroy(struct dma_controller *c)
 {
        struct cppi41_dma_controller *controller = container_of(c,
                        struct cppi41_dma_controller, controller);
@@ -687,9 +687,10 @@ void dma_controller_destroy(struct dma_controller *c)
        cppi41_dma_controller_stop(controller);
        kfree(controller);
 }
+EXPORT_SYMBOL_GPL(cppi41_dma_controller_destroy);
 
-struct dma_controller *dma_controller_create(struct musb *musb,
-                                       void __iomem *base)
+struct dma_controller *
+cppi41_dma_controller_create(struct musb *musb, void __iomem *base)
 {
        struct cppi41_dma_controller *controller;
        int ret = 0;
@@ -726,3 +727,4 @@ kzalloc_fail:
                return ERR_PTR(ret);
        return NULL;
 }
+EXPORT_SYMBOL_GPL(cppi41_dma_controller_create);
index 78a283e..9b22d94 100644 (file)
@@ -191,9 +191,16 @@ static ssize_t musb_test_mode_write(struct file *file,
 {
        struct seq_file         *s = file->private_data;
        struct musb             *musb = s->private;
-       u8                      test = 0;
+       u8                      test;
        char                    buf[18];
 
+       test = musb_readb(musb->mregs, MUSB_TESTMODE);
+       if (test) {
+               dev_err(musb->controller, "Error: test mode is already set. "
+                       "Please do USB Bus Reset to start a new test.\n");
+               return count;
+       }
+
        memset(buf, 0x00, sizeof(buf));
 
        if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
@@ -238,6 +245,90 @@ static const struct file_operations musb_test_mode_fops = {
        .release                = single_release,
 };
 
+static int musb_softconnect_show(struct seq_file *s, void *unused)
+{
+       struct musb     *musb = s->private;
+       u8              reg;
+       int             connect;
+
+       switch (musb->xceiv->otg->state) {
+       case OTG_STATE_A_HOST:
+       case OTG_STATE_A_WAIT_BCON:
+               reg = musb_readb(musb->mregs, MUSB_DEVCTL);
+               connect = reg & MUSB_DEVCTL_SESSION ? 1 : 0;
+               break;
+       default:
+               connect = -1;
+       }
+
+       seq_printf(s, "%d\n", connect);
+
+       return 0;
+}
+
+static int musb_softconnect_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, musb_softconnect_show, inode->i_private);
+}
+
+static ssize_t musb_softconnect_write(struct file *file,
+               const char __user *ubuf, size_t count, loff_t *ppos)
+{
+       struct seq_file         *s = file->private_data;
+       struct musb             *musb = s->private;
+       char                    buf[2];
+       u8                      reg;
+
+       memset(buf, 0x00, sizeof(buf));
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       if (!strncmp(buf, "0", 1)) {
+               switch (musb->xceiv->otg->state) {
+               case OTG_STATE_A_HOST:
+                       musb_root_disconnect(musb);
+                       reg = musb_readb(musb->mregs, MUSB_DEVCTL);
+                       reg &= ~MUSB_DEVCTL_SESSION;
+                       musb_writeb(musb->mregs, MUSB_DEVCTL, reg);
+                       break;
+               default:
+                       break;
+               }
+       } else if (!strncmp(buf, "1", 1)) {
+               switch (musb->xceiv->otg->state) {
+               case OTG_STATE_A_WAIT_BCON:
+                       /*
+                        * musb_save_context() called in musb_runtime_suspend()
+                        * might cache devctl with SESSION bit cleared during
+                        * soft-disconnect, so specifically set SESSION bit
+                        * here to preserve it for musb_runtime_resume().
+                        */
+                       musb->context.devctl |= MUSB_DEVCTL_SESSION;
+                       reg = musb_readb(musb->mregs, MUSB_DEVCTL);
+                       reg |= MUSB_DEVCTL_SESSION;
+                       musb_writeb(musb->mregs, MUSB_DEVCTL, reg);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return count;
+}
+
+/*
+ * In host mode, connect/disconnect the bus without physically
+ * remove the devices.
+ */
+static const struct file_operations musb_softconnect_fops = {
+       .open                   = musb_softconnect_open,
+       .write                  = musb_softconnect_write,
+       .read                   = seq_read,
+       .llseek                 = seq_lseek,
+       .release                = single_release,
+};
+
 int musb_init_debugfs(struct musb *musb)
 {
        struct dentry           *root;
@@ -264,6 +355,13 @@ int musb_init_debugfs(struct musb *musb)
                goto err1;
        }
 
+       file = debugfs_create_file("softconnect", S_IRUGO | S_IWUSR,
+                       root, musb, &musb_softconnect_fops);
+       if (!file) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
        musb->debugfs_root = root;
 
        return 0;
index 1d44faa..46357e1 100644 (file)
@@ -68,16 +68,41 @@ struct musb_hw_ep;
 #define        is_dma_capable()        (1)
 #endif
 
-#if defined(CONFIG_USB_TI_CPPI_DMA) || defined(CONFIG_USB_TI_CPPI41_DMA)
-#define        is_cppi_enabled()       1
+#ifdef CONFIG_USB_UX500_DMA
+#define musb_dma_ux500(musb)           (musb->io.quirks & MUSB_DMA_UX500)
+#else
+#define musb_dma_ux500(musb)           0
+#endif
+
+#ifdef CONFIG_USB_TI_CPPI41_DMA
+#define musb_dma_cppi41(musb)          (musb->io.quirks & MUSB_DMA_CPPI41)
+#else
+#define musb_dma_cppi41(musb)          0
+#endif
+
+#ifdef CONFIG_USB_TI_CPPI_DMA
+#define musb_dma_cppi(musb)            (musb->io.quirks & MUSB_DMA_CPPI)
 #else
-#define        is_cppi_enabled()       0
+#define musb_dma_cppi(musb)            0
 #endif
 
 #ifdef CONFIG_USB_TUSB_OMAP_DMA
-#define tusb_dma_omap()                        1
+#define tusb_dma_omap(musb)            (musb->io.quirks & MUSB_DMA_TUSB_OMAP)
+#else
+#define tusb_dma_omap(musb)            0
+#endif
+
+#ifdef CONFIG_USB_INVENTRA_DMA
+#define musb_dma_inventra(musb)                (musb->io.quirks & MUSB_DMA_INVENTRA)
 #else
-#define tusb_dma_omap()                        0
+#define musb_dma_inventra(musb)                0
+#endif
+
+#if defined(CONFIG_USB_TI_CPPI_DMA) || defined(CONFIG_USB_TI_CPPI41_DMA)
+#define        is_cppi_enabled(musb)           \
+       (musb_dma_cppi(musb) || musb_dma_cppi41(musb))
+#else
+#define        is_cppi_enabled(musb)   0
 #endif
 
 /* Anomaly 05000456 - USB Receive Interrupt Is Not Generated in DMA Mode 1
@@ -177,19 +202,41 @@ struct dma_controller {
 extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit);
 
 #ifdef CONFIG_MUSB_PIO_ONLY
-static inline struct dma_controller *dma_controller_create(struct musb *m,
-               void __iomem *io)
+static inline struct dma_controller *
+musb_dma_controller_create(struct musb *m, void __iomem *io)
 {
        return NULL;
 }
 
-static inline void dma_controller_destroy(struct dma_controller *d) { }
+static inline void musb_dma_controller_destroy(struct dma_controller *d) { }
 
 #else
 
-extern struct dma_controller *dma_controller_create(struct musb *, void __iomem *);
+extern struct dma_controller *
+(*musb_dma_controller_create)(struct musb *, void __iomem *);
 
-extern void dma_controller_destroy(struct dma_controller *);
+extern void (*musb_dma_controller_destroy)(struct dma_controller *);
 #endif
 
+/* Platform specific DMA functions */
+extern struct dma_controller *
+musbhs_dma_controller_create(struct musb *musb, void __iomem *base);
+extern void musbhs_dma_controller_destroy(struct dma_controller *c);
+
+extern struct dma_controller *
+tusb_dma_controller_create(struct musb *musb, void __iomem *base);
+extern void tusb_dma_controller_destroy(struct dma_controller *c);
+
+extern struct dma_controller *
+cppi_dma_controller_create(struct musb *musb, void __iomem *base);
+extern void cppi_dma_controller_destroy(struct dma_controller *c);
+
+extern struct dma_controller *
+cppi41_dma_controller_create(struct musb *musb, void __iomem *base);
+extern void cppi41_dma_controller_destroy(struct dma_controller *c);
+
+extern struct dma_controller *
+ux500_dma_controller_create(struct musb *musb, void __iomem *base);
+extern void ux500_dma_controller_destroy(struct dma_controller *c);
+
 #endif /* __MUSB_DMA_H__ */
index 65d931a..1334a3d 100644 (file)
@@ -634,10 +634,14 @@ static void dsps_read_fifo32(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
 }
 
 static struct musb_platform_ops dsps_ops = {
-       .quirks         = MUSB_INDEXED_EP,
+       .quirks         = MUSB_DMA_CPPI41 | MUSB_INDEXED_EP,
        .init           = dsps_musb_init,
        .exit           = dsps_musb_exit,
 
+#ifdef CONFIG_USB_TI_CPPI41_DMA
+       .dma_init       = cppi41_dma_controller_create,
+       .dma_exit       = cppi41_dma_controller_destroy,
+#endif
        .enable         = dsps_musb_enable,
        .disable        = dsps_musb_disable,
 
index 4c481cd..625d482 100644 (file)
@@ -366,7 +366,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
                }
 
 #endif
-               if (is_cppi_enabled()) {
+               if (is_cppi_enabled(musb)) {
                        /* program endpoint CSR first, then setup DMA */
                        csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
                        csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
@@ -402,7 +402,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
                                musb_writew(epio, MUSB_TXCSR, csr);
                                /* invariant: prequest->buf is non-null */
                        }
-               } else if (tusb_dma_omap())
+               } else if (tusb_dma_omap(musb))
                        use_dma = use_dma && c->channel_program(
                                        musb_ep->dma, musb_ep->packet_sz,
                                        request->zero,
@@ -489,6 +489,7 @@ void musb_g_tx(struct musb *musb, u8 epnum)
 
        if (request) {
                u8      is_dma = 0;
+               bool    short_packet = false;
 
                if (dma && (csr & MUSB_TXCSR_DMAENAB)) {
                        is_dma = 1;
@@ -507,15 +508,18 @@ void musb_g_tx(struct musb *musb, u8 epnum)
                 * First, maybe a terminating short packet. Some DMA
                 * engines might handle this by themselves.
                 */
-               if ((request->zero && request->length
+               if ((request->zero && request->length)
                        && (request->length % musb_ep->packet_sz == 0)
                        && (request->actual == request->length))
-#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA)
-                       || (is_dma && (!dma->desired_mode ||
+                               short_packet = true;
+
+               if ((musb_dma_inventra(musb) || musb_dma_ux500(musb)) &&
+                       (is_dma && (!dma->desired_mode ||
                                (request->actual &
-                                       (musb_ep->packet_sz - 1))))
-#endif
-               ) {
+                                       (musb_ep->packet_sz - 1)))))
+                               short_packet = true;
+
+               if (short_packet) {
                        /*
                         * On DMA completion, FIFO may not be
                         * available yet...
@@ -595,7 +599,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                return;
        }
 
-       if (is_cppi_enabled() && is_buffer_mapped(req)) {
+       if (is_cppi_enabled(musb) && is_buffer_mapped(req)) {
                struct dma_controller   *c = musb->dma_controller;
                struct dma_channel      *channel = musb_ep->dma;
 
@@ -772,7 +776,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                        fifo_count = min_t(unsigned, len, fifo_count);
 
 #ifdef CONFIG_USB_TUSB_OMAP_DMA
-                       if (tusb_dma_omap() && is_buffer_mapped(req)) {
+                       if (tusb_dma_omap(musb) && is_buffer_mapped(req)) {
                                struct dma_controller *c = musb->dma_controller;
                                struct dma_channel *channel = musb_ep->dma;
                                u32 dma_addr = request->dma + request->actual;
index c3d5fc9..26c65e6 100644 (file)
@@ -181,7 +181,7 @@ static inline void musb_h_tx_dma_start(struct musb_hw_ep *ep)
        /* NOTE: no locks here; caller should lock and select EP */
        txcsr = musb_readw(ep->regs, MUSB_TXCSR);
        txcsr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_H_WZC_BITS;
-       if (is_cppi_enabled())
+       if (is_cppi_enabled(ep->musb))
                txcsr |= MUSB_TXCSR_DMAMODE;
        musb_writew(ep->regs, MUSB_TXCSR, txcsr);
 }
@@ -294,7 +294,7 @@ start:
 
                if (!hw_ep->tx_channel)
                        musb_h_tx_start(hw_ep);
-               else if (is_cppi_enabled() || tusb_dma_omap())
+               else if (is_cppi_enabled(musb) || tusb_dma_omap(musb))
                        musb_h_tx_dma_start(hw_ep);
        }
 }
@@ -555,8 +555,9 @@ musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err)
  * the busy/not-empty tests are basically paranoia.
  */
 static void
-musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
+musb_rx_reinit(struct musb *musb, struct musb_qh *qh, u8 epnum)
 {
+       struct musb_hw_ep *ep = musb->endpoints + epnum;
        u16     csr;
 
        /* NOTE:  we know the "rx" fifo reinit never triggers for ep0.
@@ -594,10 +595,9 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
 
        /* target addr and (for multipoint) hub addr/port */
        if (musb->is_multipoint) {
-               musb_write_rxfunaddr(ep->target_regs, qh->addr_reg);
-               musb_write_rxhubaddr(ep->target_regs, qh->h_addr_reg);
-               musb_write_rxhubport(ep->target_regs, qh->h_port_reg);
-
+               musb_write_rxfunaddr(musb, epnum, qh->addr_reg);
+               musb_write_rxhubaddr(musb, epnum, qh->h_addr_reg);
+               musb_write_rxhubport(musb, epnum, qh->h_port_reg);
        } else
                musb_writeb(musb->mregs, MUSB_FADDR, qh->addr_reg);
 
@@ -617,23 +617,22 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
        ep->rx_reinit = 0;
 }
 
-static bool musb_tx_dma_program(struct dma_controller *dma,
+static int musb_tx_dma_set_mode_mentor(struct dma_controller *dma,
                struct musb_hw_ep *hw_ep, struct musb_qh *qh,
-               struct urb *urb, u32 offset, u32 length)
+               struct urb *urb, u32 offset,
+               u32 *length, u8 *mode)
 {
        struct dma_channel      *channel = hw_ep->tx_channel;
        void __iomem            *epio = hw_ep->regs;
        u16                     pkt_size = qh->maxpacket;
        u16                     csr;
-       u8                      mode;
 
-#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA)
-       if (length > channel->max_len)
-               length = channel->max_len;
+       if (*length > channel->max_len)
+               *length = channel->max_len;
 
        csr = musb_readw(epio, MUSB_TXCSR);
-       if (length > pkt_size) {
-               mode = 1;
+       if (*length > pkt_size) {
+               *mode = 1;
                csr |= MUSB_TXCSR_DMAMODE | MUSB_TXCSR_DMAENAB;
                /* autoset shouldn't be set in high bandwidth */
                /*
@@ -649,15 +648,28 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
                                        can_bulk_split(hw_ep->musb, qh->type)))
                        csr |= MUSB_TXCSR_AUTOSET;
        } else {
-               mode = 0;
+               *mode = 0;
                csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE);
                csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */
        }
        channel->desired_mode = mode;
        musb_writew(epio, MUSB_TXCSR, csr);
-#else
-       if (!is_cppi_enabled() && !tusb_dma_omap())
-               return false;
+
+       return 0;
+}
+
+static int musb_tx_dma_set_mode_cppi_tusb(struct dma_controller *dma,
+                                         struct musb_hw_ep *hw_ep,
+                                         struct musb_qh *qh,
+                                         struct urb *urb,
+                                         u32 offset,
+                                         u32 *length,
+                                         u8 *mode)
+{
+       struct dma_channel *channel = hw_ep->tx_channel;
+
+       if (!is_cppi_enabled(hw_ep->musb) && !tusb_dma_omap(hw_ep->musb))
+               return -ENODEV;
 
        channel->actual_len = 0;
 
@@ -665,8 +677,28 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
         * TX uses "RNDIS" mode automatically but needs help
         * to identify the zero-length-final-packet case.
         */
-       mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0;
-#endif
+       *mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0;
+
+       return 0;
+}
+
+static bool musb_tx_dma_program(struct dma_controller *dma,
+               struct musb_hw_ep *hw_ep, struct musb_qh *qh,
+               struct urb *urb, u32 offset, u32 length)
+{
+       struct dma_channel      *channel = hw_ep->tx_channel;
+       u16                     pkt_size = qh->maxpacket;
+       u8                      mode;
+       int                     res;
+
+       if (musb_dma_inventra(hw_ep->musb) || musb_dma_ux500(hw_ep->musb))
+               res = musb_tx_dma_set_mode_mentor(dma, hw_ep, qh, urb,
+                                                offset, &length, &mode);
+       else
+               res = musb_tx_dma_set_mode_cppi_tusb(dma, hw_ep, qh, urb,
+                                                    offset, &length, &mode);
+       if (res)
+               return false;
 
        qh->segsize = length;
 
@@ -678,6 +710,9 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
 
        if (!dma->channel_program(channel, pkt_size, mode,
                        urb->transfer_dma + offset, length)) {
+               void __iomem *epio = hw_ep->regs;
+               u16 csr;
+
                dma->channel_release(channel);
                hw_ep->tx_channel = NULL;
 
@@ -801,9 +836,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
 
                /* target addr and (for multipoint) hub addr/port */
                if (musb->is_multipoint) {
-                       musb_write_txfunaddr(mbase, epnum, qh->addr_reg);
-                       musb_write_txhubaddr(mbase, epnum, qh->h_addr_reg);
-                       musb_write_txhubport(mbase, epnum, qh->h_port_reg);
+                       musb_write_txfunaddr(musb, epnum, qh->addr_reg);
+                       musb_write_txhubaddr(musb, epnum, qh->h_addr_reg);
+                       musb_write_txhubport(musb, epnum, qh->h_port_reg);
 /* FIXME if !epnum, do the same for RX ... */
                } else
                        musb_writeb(mbase, MUSB_FADDR, qh->addr_reg);
@@ -875,7 +910,7 @@ finish:
                u16     csr;
 
                if (hw_ep->rx_reinit) {
-                       musb_rx_reinit(musb, qh, hw_ep);
+                       musb_rx_reinit(musb, qh, epnum);
 
                        /* init new state: toggle and NYET, maybe DMA later */
                        if (usb_gettoggle(urb->dev, qh->epnum, 0))
@@ -901,7 +936,7 @@ finish:
 
                /* kick things off */
 
-               if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) {
+               if ((is_cppi_enabled(musb) || tusb_dma_omap(musb)) && dma_channel) {
                        /* Candidate for DMA */
                        dma_channel->actual_len = 0L;
                        qh->segsize = len;
@@ -1441,7 +1476,7 @@ done:
        } else if ((usb_pipeisoc(pipe) || transfer_pending) && dma) {
                if (musb_tx_dma_program(musb->dma_controller, hw_ep, qh, urb,
                                offset, length)) {
-                       if (is_cppi_enabled() || tusb_dma_omap())
+                       if (is_cppi_enabled(musb) || tusb_dma_omap(musb))
                                musb_h_tx_dma_start(hw_ep);
                        return;
                }
@@ -1498,9 +1533,47 @@ done:
                        MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
 }
 
+#ifdef CONFIG_USB_TI_CPPI41_DMA
+/* Seems to set up ISO for cppi41 and not advance len. See commit c57c41d */
+static int musb_rx_dma_iso_cppi41(struct dma_controller *dma,
+                                 struct musb_hw_ep *hw_ep,
+                                 struct musb_qh *qh,
+                                 struct urb *urb,
+                                 size_t len)
+{
+       struct dma_channel *channel = hw_ep->tx_channel;
+       void __iomem *epio = hw_ep->regs;
+       dma_addr_t *buf;
+       u32 length, res;
+       u16 val;
 
-#ifdef CONFIG_USB_INVENTRA_DMA
+       buf = (void *)urb->iso_frame_desc[qh->iso_idx].offset +
+               (u32)urb->transfer_dma;
+
+       length = urb->iso_frame_desc[qh->iso_idx].length;
 
+       val = musb_readw(epio, MUSB_RXCSR);
+       val |= MUSB_RXCSR_DMAENAB;
+       musb_writew(hw_ep->regs, MUSB_RXCSR, val);
+
+       res = dma->channel_program(channel, qh->maxpacket, 0,
+                                  (u32)buf, length);
+
+       return res;
+}
+#else
+static inline int musb_rx_dma_iso_cppi41(struct dma_controller *dma,
+                                        struct musb_hw_ep *hw_ep,
+                                        struct musb_qh *qh,
+                                        struct urb *urb,
+                                        size_t len)
+{
+       return false;
+}
+#endif
+
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \
+       defined(CONFIG_USB_TI_CPPI41_DMA)
 /* Host side RX (IN) using Mentor DMA works as follows:
        submit_urb ->
                - if queue was empty, ProgramEndpoint
@@ -1535,7 +1608,194 @@ done:
  *     thus be a great candidate for using mode 1 ... for all but the
  *     last packet of one URB's transfer.
  */
+static int musb_rx_dma_inventra_cppi41(struct dma_controller *dma,
+                                      struct musb_hw_ep *hw_ep,
+                                      struct musb_qh *qh,
+                                      struct urb *urb,
+                                      size_t len)
+{
+       struct dma_channel *channel = hw_ep->rx_channel;
+       void __iomem *epio = hw_ep->regs;
+       u16 val;
+       int pipe;
+       bool done;
+
+       pipe = urb->pipe;
+
+       if (usb_pipeisoc(pipe)) {
+               struct usb_iso_packet_descriptor *d;
+
+               d = urb->iso_frame_desc + qh->iso_idx;
+               d->actual_length = len;
+
+               /* even if there was an error, we did the dma
+                * for iso_frame_desc->length
+                */
+               if (d->status != -EILSEQ && d->status != -EOVERFLOW)
+                       d->status = 0;
+
+               if (++qh->iso_idx >= urb->number_of_packets) {
+                       done = true;
+               } else {
+                       /* REVISIT: Why ignore return value here? */
+                       if (musb_dma_cppi41(hw_ep->musb))
+                               done = musb_rx_dma_iso_cppi41(dma, hw_ep, qh,
+                                                             urb, len);
+                       done = false;
+               }
+
+       } else  {
+               /* done if urb buffer is full or short packet is recd */
+               done = (urb->actual_length + len >=
+                       urb->transfer_buffer_length
+                       || channel->actual_len < qh->maxpacket
+                       || channel->rx_packet_done);
+       }
+
+       /* send IN token for next packet, without AUTOREQ */
+       if (!done) {
+               val = musb_readw(epio, MUSB_RXCSR);
+               val |= MUSB_RXCSR_H_REQPKT;
+               musb_writew(epio, MUSB_RXCSR, MUSB_RXCSR_H_WZC_BITS | val);
+       }
+
+       return done;
+}
+
+/* Disadvantage of using mode 1:
+ *     It's basically usable only for mass storage class; essentially all
+ *     other protocols also terminate transfers on short packets.
+ *
+ * Details:
+ *     An extra IN token is sent at the end of the transfer (due to AUTOREQ)
+ *     If you try to use mode 1 for (transfer_buffer_length - 512), and try
+ *     to use the extra IN token to grab the last packet using mode 0, then
+ *     the problem is that you cannot be sure when the device will send the
+ *     last packet and RxPktRdy set. Sometimes the packet is recd too soon
+ *     such that it gets lost when RxCSR is re-set at the end of the mode 1
+ *     transfer, while sometimes it is recd just a little late so that if you
+ *     try to configure for mode 0 soon after the mode 1 transfer is
+ *     completed, you will find rxcount 0. Okay, so you might think why not
+ *     wait for an interrupt when the pkt is recd. Well, you won't get any!
+ */
+static int musb_rx_dma_in_inventra_cppi41(struct dma_controller *dma,
+                                         struct musb_hw_ep *hw_ep,
+                                         struct musb_qh *qh,
+                                         struct urb *urb,
+                                         size_t len,
+                                         u8 iso_err)
+{
+       struct musb *musb = hw_ep->musb;
+       void __iomem *epio = hw_ep->regs;
+       struct dma_channel *channel = hw_ep->rx_channel;
+       u16 rx_count, val;
+       int length, pipe, done;
+       dma_addr_t buf;
+
+       rx_count = musb_readw(epio, MUSB_RXCOUNT);
+       pipe = urb->pipe;
+
+       if (usb_pipeisoc(pipe)) {
+               int d_status = 0;
+               struct usb_iso_packet_descriptor *d;
+
+               d = urb->iso_frame_desc + qh->iso_idx;
 
+               if (iso_err) {
+                       d_status = -EILSEQ;
+                       urb->error_count++;
+               }
+               if (rx_count > d->length) {
+                       if (d_status == 0) {
+                               d_status = -EOVERFLOW;
+                               urb->error_count++;
+                       }
+                       dev_dbg(musb->controller, "** OVERFLOW %d into %d\n",
+                               rx_count, d->length);
+
+                       length = d->length;
+               } else
+                       length = rx_count;
+               d->status = d_status;
+               buf = urb->transfer_dma + d->offset;
+       } else {
+               length = rx_count;
+               buf = urb->transfer_dma + urb->actual_length;
+       }
+
+       channel->desired_mode = 0;
+#ifdef USE_MODE1
+       /* because of the issue below, mode 1 will
+        * only rarely behave with correct semantics.
+        */
+       if ((urb->transfer_flags & URB_SHORT_NOT_OK)
+           && (urb->transfer_buffer_length - urb->actual_length)
+           > qh->maxpacket)
+               channel->desired_mode = 1;
+       if (rx_count < hw_ep->max_packet_sz_rx) {
+               length = rx_count;
+               channel->desired_mode = 0;
+       } else {
+               length = urb->transfer_buffer_length;
+       }
+#endif
+
+       /* See comments above on disadvantages of using mode 1 */
+       val = musb_readw(epio, MUSB_RXCSR);
+       val &= ~MUSB_RXCSR_H_REQPKT;
+
+       if (channel->desired_mode == 0)
+               val &= ~MUSB_RXCSR_H_AUTOREQ;
+       else
+               val |= MUSB_RXCSR_H_AUTOREQ;
+       val |= MUSB_RXCSR_DMAENAB;
+
+       /* autoclear shouldn't be set in high bandwidth */
+       if (qh->hb_mult == 1)
+               val |= MUSB_RXCSR_AUTOCLEAR;
+
+       musb_writew(epio, MUSB_RXCSR, MUSB_RXCSR_H_WZC_BITS | val);
+
+       /* REVISIT if when actual_length != 0,
+        * transfer_buffer_length needs to be
+        * adjusted first...
+        */
+       done = dma->channel_program(channel, qh->maxpacket,
+                                  channel->desired_mode,
+                                  buf, length);
+
+       if (!done) {
+               dma->channel_release(channel);
+               hw_ep->rx_channel = NULL;
+               channel = NULL;
+               val = musb_readw(epio, MUSB_RXCSR);
+               val &= ~(MUSB_RXCSR_DMAENAB
+                        | MUSB_RXCSR_H_AUTOREQ
+                        | MUSB_RXCSR_AUTOCLEAR);
+               musb_writew(epio, MUSB_RXCSR, val);
+       }
+
+       return done;
+}
+#else
+static inline int musb_rx_dma_inventra_cppi41(struct dma_controller *dma,
+                                             struct musb_hw_ep *hw_ep,
+                                             struct musb_qh *qh,
+                                             struct urb *urb,
+                                             size_t len)
+{
+       return false;
+}
+
+static inline int musb_rx_dma_in_inventra_cppi41(struct dma_controller *dma,
+                                                struct musb_hw_ep *hw_ep,
+                                                struct musb_qh *qh,
+                                                struct urb *urb,
+                                                size_t len,
+                                                u8 iso_err)
+{
+       return false;
+}
 #endif
 
 /*
@@ -1546,6 +1806,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
 {
        struct urb              *urb;
        struct musb_hw_ep       *hw_ep = musb->endpoints + epnum;
+       struct dma_controller   *c = musb->dma_controller;
        void __iomem            *epio = hw_ep->regs;
        struct musb_qh          *qh = hw_ep->in_qh;
        size_t                  xfer_len;
@@ -1661,9 +1922,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
         */
 
        /* FIXME this is _way_ too much in-line logic for Mentor DMA */
-
-#if !defined(CONFIG_USB_INVENTRA_DMA) && !defined(CONFIG_USB_UX500_DMA)
-       if (rx_csr & MUSB_RXCSR_H_REQPKT)  {
+       if (!musb_dma_inventra(musb) && !musb_dma_ux500(musb) &&
+           (rx_csr & MUSB_RXCSR_H_REQPKT)) {
                /* REVISIT this happened for a while on some short reads...
                 * the cleanup still needs investigation... looks bad...
                 * and also duplicates dma cleanup code above ... plus,
@@ -1684,7 +1944,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
                musb_writew(epio, MUSB_RXCSR,
                                MUSB_RXCSR_H_WZC_BITS | rx_csr);
        }
-#endif
+
        if (dma && (rx_csr & MUSB_RXCSR_DMAENAB)) {
                xfer_len = dma->actual_len;
 
@@ -1694,67 +1954,18 @@ void musb_host_rx(struct musb *musb, u8 epnum)
                        | MUSB_RXCSR_RXPKTRDY);
                musb_writew(hw_ep->regs, MUSB_RXCSR, val);
 
-#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \
-       defined(CONFIG_USB_TI_CPPI41_DMA)
-               if (usb_pipeisoc(pipe)) {
-                       struct usb_iso_packet_descriptor *d;
-
-                       d = urb->iso_frame_desc + qh->iso_idx;
-                       d->actual_length = xfer_len;
-
-                       /* even if there was an error, we did the dma
-                        * for iso_frame_desc->length
-                        */
-                       if (d->status != -EILSEQ && d->status != -EOVERFLOW)
-                               d->status = 0;
-
-                       if (++qh->iso_idx >= urb->number_of_packets) {
-                               done = true;
-                       } else {
-#if defined(CONFIG_USB_TI_CPPI41_DMA)
-                               struct dma_controller   *c;
-                               dma_addr_t *buf;
-                               u32 length, ret;
-
-                               c = musb->dma_controller;
-                               buf = (void *)
-                                       urb->iso_frame_desc[qh->iso_idx].offset
-                                       + (u32)urb->transfer_dma;
-
-                               length =
-                                       urb->iso_frame_desc[qh->iso_idx].length;
-
-                               val |= MUSB_RXCSR_DMAENAB;
-                               musb_writew(hw_ep->regs, MUSB_RXCSR, val);
-
-                               ret = c->channel_program(dma, qh->maxpacket,
-                                               0, (u32) buf, length);
-#endif
-                               done = false;
-                       }
-
-               } else  {
-                       /* done if urb buffer is full or short packet is recd */
-                       done = (urb->actual_length + xfer_len >=
-                                       urb->transfer_buffer_length
-                               || dma->actual_len < qh->maxpacket
-                               || dma->rx_packet_done);
-               }
-
-               /* send IN token for next packet, without AUTOREQ */
-               if (!done) {
-                       val |= MUSB_RXCSR_H_REQPKT;
-                       musb_writew(epio, MUSB_RXCSR,
-                               MUSB_RXCSR_H_WZC_BITS | val);
+               if (musb_dma_inventra(musb) || musb_dma_ux500(musb) ||
+                   musb_dma_cppi41(musb)) {
+                           done = musb_rx_dma_inventra_cppi41(c, hw_ep, qh, urb, xfer_len);
+                           dev_dbg(hw_ep->musb->controller,
+                                   "ep %d dma %s, rxcsr %04x, rxcount %d\n",
+                                   epnum, done ? "off" : "reset",
+                                   musb_readw(epio, MUSB_RXCSR),
+                                   musb_readw(epio, MUSB_RXCOUNT));
+               } else {
+                       done = true;
                }
 
-               dev_dbg(musb->controller, "ep %d dma %s, rxcsr %04x, rxcount %d\n", epnum,
-                       done ? "off" : "reset",
-                       musb_readw(epio, MUSB_RXCSR),
-                       musb_readw(epio, MUSB_RXCOUNT));
-#else
-               done = true;
-#endif
        } else if (urb->status == -EINPROGRESS) {
                /* if no errors, be sure a packet is ready for unloading */
                if (unlikely(!(rx_csr & MUSB_RXCSR_RXPKTRDY))) {
@@ -1772,126 +1983,24 @@ void musb_host_rx(struct musb *musb, u8 epnum)
                }
 
                /* we are expecting IN packets */
-#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \
-       defined(CONFIG_USB_TI_CPPI41_DMA)
-               if (dma) {
-                       struct dma_controller   *c;
-                       u16                     rx_count;
-                       int                     ret, length;
-                       dma_addr_t              buf;
-
-                       rx_count = musb_readw(epio, MUSB_RXCOUNT);
-
-                       dev_dbg(musb->controller, "RX%d count %d, buffer 0x%llx len %d/%d\n",
-                                       epnum, rx_count,
-                                       (unsigned long long) urb->transfer_dma
-                                       + urb->actual_length,
-                                       qh->offset,
-                                       urb->transfer_buffer_length);
-
-                       c = musb->dma_controller;
-
-                       if (usb_pipeisoc(pipe)) {
-                               int d_status = 0;
-                               struct usb_iso_packet_descriptor *d;
-
-                               d = urb->iso_frame_desc + qh->iso_idx;
-
-                               if (iso_err) {
-                                       d_status = -EILSEQ;
-                                       urb->error_count++;
-                               }
-                               if (rx_count > d->length) {
-                                       if (d_status == 0) {
-                                               d_status = -EOVERFLOW;
-                                               urb->error_count++;
-                                       }
-                                       dev_dbg(musb->controller, "** OVERFLOW %d into %d\n",\
-                                           rx_count, d->length);
-
-                                       length = d->length;
-                               } else
-                                       length = rx_count;
-                               d->status = d_status;
-                               buf = urb->transfer_dma + d->offset;
-                       } else {
-                               length = rx_count;
-                               buf = urb->transfer_dma +
-                                               urb->actual_length;
-                       }
-
-                       dma->desired_mode = 0;
-#ifdef USE_MODE1
-                       /* because of the issue below, mode 1 will
-                        * only rarely behave with correct semantics.
-                        */
-                       if ((urb->transfer_flags &
-                                               URB_SHORT_NOT_OK)
-                               && (urb->transfer_buffer_length -
-                                               urb->actual_length)
-                                       > qh->maxpacket)
-                               dma->desired_mode = 1;
-                       if (rx_count < hw_ep->max_packet_sz_rx) {
-                               length = rx_count;
-                               dma->desired_mode = 0;
-                       } else {
-                               length = urb->transfer_buffer_length;
-                       }
-#endif
-
-/* Disadvantage of using mode 1:
- *     It's basically usable only for mass storage class; essentially all
- *     other protocols also terminate transfers on short packets.
- *
- * Details:
- *     An extra IN token is sent at the end of the transfer (due to AUTOREQ)
- *     If you try to use mode 1 for (transfer_buffer_length - 512), and try
- *     to use the extra IN token to grab the last packet using mode 0, then
- *     the problem is that you cannot be sure when the device will send the
- *     last packet and RxPktRdy set. Sometimes the packet is recd too soon
- *     such that it gets lost when RxCSR is re-set at the end of the mode 1
- *     transfer, while sometimes it is recd just a little late so that if you
- *     try to configure for mode 0 soon after the mode 1 transfer is
- *     completed, you will find rxcount 0. Okay, so you might think why not
- *     wait for an interrupt when the pkt is recd. Well, you won't get any!
- */
-
-                       val = musb_readw(epio, MUSB_RXCSR);
-                       val &= ~MUSB_RXCSR_H_REQPKT;
-
-                       if (dma->desired_mode == 0)
-                               val &= ~MUSB_RXCSR_H_AUTOREQ;
+               if ((musb_dma_inventra(musb) || musb_dma_ux500(musb) ||
+                   musb_dma_cppi41(musb)) && dma) {
+                       dev_dbg(hw_ep->musb->controller,
+                               "RX%d count %d, buffer 0x%llx len %d/%d\n",
+                               epnum, musb_readw(epio, MUSB_RXCOUNT),
+                               (unsigned long long) urb->transfer_dma
+                               + urb->actual_length,
+                               qh->offset,
+                               urb->transfer_buffer_length);
+
+                       done = musb_rx_dma_in_inventra_cppi41(c, hw_ep, qh,
+                                                             urb, xfer_len,
+                                                             iso_err);
+                       if (done)
+                               goto finish;
                        else
-                               val |= MUSB_RXCSR_H_AUTOREQ;
-                       val |= MUSB_RXCSR_DMAENAB;
-
-                       /* autoclear shouldn't be set in high bandwidth */
-                       if (qh->hb_mult == 1)
-                               val |= MUSB_RXCSR_AUTOCLEAR;
-
-                       musb_writew(epio, MUSB_RXCSR,
-                               MUSB_RXCSR_H_WZC_BITS | val);
-
-                       /* REVISIT if when actual_length != 0,
-                        * transfer_buffer_length needs to be
-                        * adjusted first...
-                        */
-                       ret = c->channel_program(
-                               dma, qh->maxpacket,
-                               dma->desired_mode, buf, length);
-
-                       if (!ret) {
-                               c->channel_release(dma);
-                               hw_ep->rx_channel = NULL;
-                               dma = NULL;
-                               val = musb_readw(epio, MUSB_RXCSR);
-                               val &= ~(MUSB_RXCSR_DMAENAB
-                                       | MUSB_RXCSR_H_AUTOREQ
-                                       | MUSB_RXCSR_AUTOCLEAR);
-                               musb_writew(epio, MUSB_RXCSR, val);
-                       }
+                               dev_err(musb->controller, "error: rx_dma failed\n");
                }
-#endif /* Mentor DMA */
 
                if (!dma) {
                        unsigned int received_len;
@@ -2512,6 +2621,7 @@ static void musb_free_temp_buffer(struct urb *urb)
 {
        enum dma_data_direction dir;
        struct musb_temp_buffer *temp;
+       size_t length;
 
        if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
                return;
@@ -2522,8 +2632,12 @@ static void musb_free_temp_buffer(struct urb *urb)
                            data);
 
        if (dir == DMA_FROM_DEVICE) {
-               memcpy(temp->old_xfer_buffer, temp->data,
-                      urb->transfer_buffer_length);
+               if (usb_pipeisoc(urb->pipe))
+                       length = urb->transfer_buffer_length;
+               else
+                       length = urb->actual_length;
+
+               memcpy(temp->old_xfer_buffer, temp->data, length);
        }
        urb->transfer_buffer = temp->old_xfer_buffer;
        kfree(temp->kmalloc_ptr);
index 8a57a6f..17a80ae 100644 (file)
@@ -47,6 +47,7 @@
  * @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
+ * @busctl_offset: platform specific function to get busctl offset
  */
 struct musb_io {
        u32     quirks;
@@ -55,6 +56,7 @@ struct musb_io {
        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);
+       u32     (*busctl_offset)(u8 epnum, u16 offset);
 };
 
 /* Do not add new entries here, add them the struct musb_io instead */
index 11f0be0..cff5bcf 100644 (file)
 #define MUSB_RXHUBADDR         0x06
 #define MUSB_RXHUBPORT         0x07
 
-#define MUSB_BUSCTL_OFFSET(_epnum, _offset) \
-       (0x80 + (8*(_epnum)) + (_offset))
-
 static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
 {
        musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
@@ -364,78 +361,84 @@ static inline u16 musb_read_hwvers(void __iomem *mbase)
        return musb_readw(mbase, MUSB_HWVERS);
 }
 
-static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
-{
-       return (MUSB_BUSCTL_OFFSET(i, 0) + mbase);
-}
-
-static inline void musb_write_rxfunaddr(void __iomem *ep_target_regs,
+static inline void musb_write_rxfunaddr(struct musb *musb, u8 epnum,
                u8 qh_addr_reg)
 {
-       musb_writeb(ep_target_regs, MUSB_RXFUNCADDR, qh_addr_reg);
+       musb_writeb(musb->mregs,
+                   musb->io.busctl_offset(epnum, MUSB_RXFUNCADDR),
+                   qh_addr_reg);
 }
 
-static inline void musb_write_rxhubaddr(void __iomem *ep_target_regs,
+static inline void musb_write_rxhubaddr(struct musb *musb, u8 epnum,
                u8 qh_h_addr_reg)
 {
-       musb_writeb(ep_target_regs, MUSB_RXHUBADDR, qh_h_addr_reg);
+       musb_writeb(musb->mregs, musb->io.busctl_offset(epnum, MUSB_RXHUBADDR),
+                       qh_h_addr_reg);
 }
 
-static inline void musb_write_rxhubport(void __iomem *ep_target_regs,
+static inline void musb_write_rxhubport(struct musb *musb, u8 epnum,
                u8 qh_h_port_reg)
 {
-       musb_writeb(ep_target_regs, MUSB_RXHUBPORT, qh_h_port_reg);
+       musb_writeb(musb->mregs, musb->io.busctl_offset(epnum, MUSB_RXHUBPORT),
+                       qh_h_port_reg);
 }
 
-static inline void  musb_write_txfunaddr(void __iomem *mbase, u8 epnum,
+static inline void musb_write_txfunaddr(struct musb *musb, u8 epnum,
                u8 qh_addr_reg)
 {
-       musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR),
-                       qh_addr_reg);
+       musb_writeb(musb->mregs,
+                   musb->io.busctl_offset(epnum, MUSB_TXFUNCADDR),
+                   qh_addr_reg);
 }
 
-static inline void  musb_write_txhubaddr(void __iomem *mbase, u8 epnum,
+static inline void musb_write_txhubaddr(struct musb *musb, u8 epnum,
                u8 qh_addr_reg)
 {
-       musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR),
+       musb_writeb(musb->mregs, musb->io.busctl_offset(epnum, MUSB_TXHUBADDR),
                        qh_addr_reg);
 }
 
-static inline void  musb_write_txhubport(void __iomem *mbase, u8 epnum,
+static inline void musb_write_txhubport(struct musb *musb, u8 epnum,
                u8 qh_h_port_reg)
 {
-       musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT),
+       musb_writeb(musb->mregs, musb->io.busctl_offset(epnum, MUSB_TXHUBPORT),
                        qh_h_port_reg);
 }
 
-static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum)
+static inline u8 musb_read_rxfunaddr(struct musb *musb, u8 epnum)
 {
-       return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXFUNCADDR));
+       return musb_readb(musb->mregs,
+                         musb->io.busctl_offset(epnum, MUSB_RXFUNCADDR));
 }
 
-static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum)
+static inline u8 musb_read_rxhubaddr(struct musb *musb, u8 epnum)
 {
-       return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBADDR));
+       return musb_readb(musb->mregs,
+                         musb->io.busctl_offset(epnum, MUSB_RXHUBADDR));
 }
 
-static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum)
+static inline u8 musb_read_rxhubport(struct musb *musb, u8 epnum)
 {
-       return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBPORT));
+       return musb_readb(musb->mregs,
+                         musb->io.busctl_offset(epnum, MUSB_RXHUBPORT));
 }
 
-static inline u8  musb_read_txfunaddr(void __iomem *mbase, u8 epnum)
+static inline u8 musb_read_txfunaddr(struct musb *musb, u8 epnum)
 {
-       return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR));
+       return musb_readb(musb->mregs,
+                         musb->io.busctl_offset(epnum, MUSB_TXFUNCADDR));
 }
 
-static inline u8  musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
+static inline u8 musb_read_txhubaddr(struct musb *musb, u8 epnum)
 {
-       return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR));
+       return musb_readb(musb->mregs,
+                         musb->io.busctl_offset(epnum, MUSB_TXHUBADDR));
 }
 
-static inline u8  musb_read_txhubport(void __iomem *mbase, u8 epnum)
+static inline u8 musb_read_txhubport(struct musb *musb, u8 epnum)
 {
-       return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT));
+       return musb_readb(musb->mregs,
+                         musb->io.busctl_offset(epnum, MUSB_TXHUBPORT));
 }
 
 #else /* CONFIG_BLACKFIN */
@@ -556,22 +559,17 @@ static inline u16 musb_read_hwvers(void __iomem *mbase)
        return MUSB_HWVERS_1900;
 }
 
-static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
-{
-       return NULL;
-}
-
-static inline void musb_write_rxfunaddr(void __iomem *ep_target_regs,
+static inline void musb_write_rxfunaddr(void __iomem *mbase, u8 epnum,
                u8 qh_addr_req)
 {
 }
 
-static inline void musb_write_rxhubaddr(void __iomem *ep_target_regs,
+static inline void musb_write_rxhubaddr(void __iomem *mbase, u8 epnum,
                u8 qh_h_addr_reg)
 {
 }
 
-static inline void musb_write_rxhubport(void __iomem *ep_target_regs,
+static inline void musb_write_rxhubport(void __iomem *mbase, u8 epnum,
                u8 qh_h_port_reg)
 {
 }
index 86c4b53..30842bc 100644 (file)
@@ -195,8 +195,10 @@ void musb_port_reset(struct musb *musb, bool do_reset)
                                      msecs_to_jiffies(50));
        } else {
                dev_dbg(musb->controller, "root port reset stopped\n");
+               musb_platform_pre_root_reset_end(musb);
                musb_writeb(mbase, MUSB_POWER,
                                power & ~MUSB_POWER_RESET);
+               musb_platform_post_root_reset_end(musb);
 
                power = musb_readb(mbase, MUSB_POWER);
                if (power & MUSB_POWER_HSMODE) {
index ab7ec09..7539c31 100644 (file)
@@ -357,7 +357,7 @@ done:
        return retval;
 }
 
-void dma_controller_destroy(struct dma_controller *c)
+void musbhs_dma_controller_destroy(struct dma_controller *c)
 {
        struct musb_dma_controller *controller = container_of(c,
                        struct musb_dma_controller, controller);
@@ -369,8 +369,10 @@ void dma_controller_destroy(struct dma_controller *c)
 
        kfree(controller);
 }
+EXPORT_SYMBOL_GPL(musbhs_dma_controller_destroy);
 
-struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *base)
+struct dma_controller *musbhs_dma_controller_create(struct musb *musb,
+                                                   void __iomem *base)
 {
        struct musb_dma_controller *controller;
        struct device *dev = musb->controller;
@@ -398,7 +400,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
        if (request_irq(irq, dma_controller_irq, 0,
                        dev_name(musb->controller), &controller->controller)) {
                dev_err(dev, "request_irq %d failed!\n", irq);
-               dma_controller_destroy(&controller->controller);
+               musb_dma_controller_destroy(&controller->controller);
 
                return NULL;
        }
@@ -407,3 +409,4 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
 
        return &controller->controller;
 }
+EXPORT_SYMBOL_GPL(musbhs_dma_controller_create);
index cc752d8..70f2b8a 100644 (file)
@@ -493,6 +493,11 @@ static int omap2430_musb_exit(struct musb *musb)
 }
 
 static const struct musb_platform_ops omap2430_ops = {
+       .quirks         = MUSB_DMA_INVENTRA,
+#ifdef CONFIG_USB_INVENTRA_DMA
+       .dma_init       = musbhs_dma_controller_create,
+       .dma_exit       = musbhs_dma_controller_destroy,
+#endif
        .init           = omap2430_musb_init,
        .exit           = omap2430_musb_exit,
 
index 3a5ffd5..df7c9f4 100644 (file)
@@ -890,7 +890,7 @@ static irqreturn_t tusb_musb_interrupt(int irq, void *__hci)
 
                dev_dbg(musb->controller, "DMA IRQ %08x\n", dma_src);
                real_dma_src = ~real_dma_src & dma_src;
-               if (tusb_dma_omap() && real_dma_src) {
+               if (tusb_dma_omap(musb) && real_dma_src) {
                        int     tx_source = (real_dma_src & 0xffff);
                        int     i;
 
@@ -1181,7 +1181,7 @@ static int tusb_musb_exit(struct musb *musb)
 }
 
 static const struct musb_platform_ops tusb_ops = {
-       .quirks         = MUSB_IN_TUSB,
+       .quirks         = MUSB_DMA_TUSB_OMAP | MUSB_IN_TUSB,
        .init           = tusb_musb_init,
        .exit           = tusb_musb_exit,
 
@@ -1192,6 +1192,10 @@ static const struct musb_platform_ops tusb_ops = {
        .writeb         = tusb_writeb,
        .read_fifo      = tusb_read_fifo,
        .write_fifo     = tusb_write_fifo,
+#ifdef CONFIG_USB_TUSB_OMAP_DMA
+       .dma_init       = tusb_dma_controller_create,
+       .dma_exit       = tusb_dma_controller_destroy,
+#endif
        .enable         = tusb_musb_enable,
        .disable        = tusb_musb_disable,
 
index aec86c8..72cdad2 100644 (file)
 #ifndef __TUSB6010_H__
 #define __TUSB6010_H__
 
-#ifdef CONFIG_USB_TUSB_OMAP_DMA
-#define tusb_dma_omap()                        1
-#else
-#define tusb_dma_omap()                        0
-#endif
-
 /* VLYNQ control register. 32-bit at offset 0x000 */
 #define TUSB_VLYNQ_CTRL                        0x004
 
index 3ce152c..4c82077 100644 (file)
@@ -625,7 +625,7 @@ static void tusb_omap_dma_release(struct dma_channel *channel)
        channel = NULL;
 }
 
-void dma_controller_destroy(struct dma_controller *c)
+void tusb_dma_controller_destroy(struct dma_controller *c)
 {
        struct tusb_omap_dma    *tusb_dma;
        int                     i;
@@ -644,8 +644,10 @@ void dma_controller_destroy(struct dma_controller *c)
 
        kfree(tusb_dma);
 }
+EXPORT_SYMBOL_GPL(tusb_dma_controller_destroy);
 
-struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *base)
+struct dma_controller *
+tusb_dma_controller_create(struct musb *musb, void __iomem *base)
 {
        void __iomem            *tbase = musb->ctrl_base;
        struct tusb_omap_dma    *tusb_dma;
@@ -701,7 +703,8 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
        return &tusb_dma->controller;
 
 cleanup:
-       dma_controller_destroy(&tusb_dma->controller);
+       musb_dma_controller_destroy(&tusb_dma->controller);
 out:
        return NULL;
 }
+EXPORT_SYMBOL_GPL(tusb_dma_controller_create);
index abf7272..39168fe 100644 (file)
@@ -188,7 +188,11 @@ static int ux500_musb_exit(struct musb *musb)
 }
 
 static const struct musb_platform_ops ux500_ops = {
-       .quirks         = MUSB_INDEXED_EP,
+       .quirks         = MUSB_DMA_UX500 | MUSB_INDEXED_EP,
+#ifdef CONFIG_USB_UX500_DMA
+       .dma_init       = ux500_dma_controller_create,
+       .dma_exit       = ux500_dma_controller_destroy,
+#endif
        .init           = ux500_musb_init,
        .exit           = ux500_musb_exit,
        .fifo_mode      = 5,
@@ -338,7 +342,7 @@ static int ux500_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int ux500_suspend(struct device *dev)
 {
        struct ux500_glue       *glue = dev_get_drvdata(dev);
index e93845c..d0b6a1c 100644 (file)
@@ -359,7 +359,7 @@ static int ux500_dma_controller_start(struct ux500_dma_controller *controller)
        return 0;
 }
 
-void dma_controller_destroy(struct dma_controller *c)
+void ux500_dma_controller_destroy(struct dma_controller *c)
 {
        struct ux500_dma_controller *controller = container_of(c,
                        struct ux500_dma_controller, controller);
@@ -367,9 +367,10 @@ void dma_controller_destroy(struct dma_controller *c)
        ux500_dma_controller_stop(controller);
        kfree(controller);
 }
+EXPORT_SYMBOL_GPL(ux500_dma_controller_destroy);
 
-struct dma_controller *dma_controller_create(struct musb *musb,
-                                       void __iomem *base)
+struct dma_controller *
+ux500_dma_controller_create(struct musb *musb, void __iomem *base)
 {
        struct ux500_dma_controller *controller;
        struct platform_device *pdev = to_platform_device(musb->controller);
@@ -407,3 +408,4 @@ plat_get_fail:
 kzalloc_fail:
        return NULL;
 }
+EXPORT_SYMBOL_GPL(ux500_dma_controller_create);
index 2175678..869c0cf 100644 (file)
@@ -91,7 +91,7 @@ config TWL6030_USB
 
 config USB_GPIO_VBUS
        tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
-       depends on GPIOLIB
+       depends on GPIOLIB || COMPILE_TEST
        select USB_PHY
        help
          Provides simple GPIO VBUS sensing for controllers with an
@@ -141,6 +141,7 @@ config USB_MSM_OTG
        tristate "Qualcomm on-chip USB OTG controller support"
        depends on (USB || USB_GADGET) && (ARCH_QCOM || COMPILE_TEST)
        depends on RESET_CONTROLLER
+       depends on EXTCON
        select USB_PHY
        help
          Enable this to support the USB OTG transceiver on Qualcomm chips. It
@@ -186,19 +187,6 @@ config USB_RCAR_PHY
          To compile this driver as a module, choose M here: the
          module will be called phy-rcar-usb.
 
-config USB_RCAR_GEN2_PHY
-       tristate "Renesas R-Car Gen2 USB PHY support"
-       depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST
-       select USB_PHY
-       help
-         Say Y here to add support for the Renesas R-Car Gen2 USB PHY driver.
-         It is typically used to control internal USB PHY for USBHS,
-         and to configure shared USB channels 0 and 2.
-         This driver supports R8A7790 and R8A7791.
-
-         To compile this driver as a module, choose M here: the
-         module will be called phy-rcar-gen2-usb.
-
 config USB_ULPI
        bool "Generic ULPI Transceiver Driver"
        depends on ARM || ARM64
index 75f2bba..e36ab1d 100644 (file)
@@ -23,7 +23,6 @@ obj-$(CONFIG_USB_MSM_OTG)             += phy-msm-usb.o
 obj-$(CONFIG_USB_MV_OTG)               += phy-mv-usb.o
 obj-$(CONFIG_USB_MXS_PHY)              += phy-mxs-usb.o
 obj-$(CONFIG_USB_RCAR_PHY)             += phy-rcar-usb.o
-obj-$(CONFIG_USB_RCAR_GEN2_PHY)                += phy-rcar-gen2-usb.o
 obj-$(CONFIG_USB_ULPI)                 += phy-ulpi.o
 obj-$(CONFIG_USB_ULPI_VIEWPORT)                += phy-ulpi-viewport.o
 obj-$(CONFIG_KEYSTONE_USB_PHY)         += phy-keystone.o
index 03ab0c6..0c912d3 100644 (file)
@@ -1504,7 +1504,7 @@ static int ab8500_usb_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct platform_device_id ab8500_usb_devtype[] = {
+static const struct platform_device_id ab8500_usb_devtype[] = {
        { .name = "ab8500-usb", },
        { .name = "ab8540-usb", },
        { .name = "ab9540-usb", },
index c9156be..00c49bb 100644 (file)
@@ -240,8 +240,14 @@ static void ulpi_init(struct msm_otg *motg)
 static int msm_phy_notify_disconnect(struct usb_phy *phy,
                                   enum usb_device_speed speed)
 {
+       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
        int val;
 
+       if (motg->manual_pullup) {
+               val = ULPI_MISC_A_VBUSVLDEXT | ULPI_MISC_A_VBUSVLDEXTSEL;
+               usb_phy_io_write(phy, val, ULPI_CLR(ULPI_MISC_A));
+       }
+
        /*
         * Put the transceiver in non-driving mode. Otherwise host
         * may not detect soft-disconnection.
@@ -422,6 +428,24 @@ static int msm_phy_init(struct usb_phy *phy)
                ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
        }
 
+       if (motg->manual_pullup) {
+               val = ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT;
+               ulpi_write(phy, val, ULPI_SET(ULPI_MISC_A));
+
+               val = readl(USB_GENCONFIG_2);
+               val |= GENCONFIG_2_SESS_VLD_CTRL_EN;
+               writel(val, USB_GENCONFIG_2);
+
+               val = readl(USB_USBCMD);
+               val |= USBCMD_SESS_VLD_CTRL;
+               writel(val, USB_USBCMD);
+
+               val = ulpi_read(phy, ULPI_FUNC_CTRL);
+               val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+               val |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
+               ulpi_write(phy, val, ULPI_FUNC_CTRL);
+       }
+
        if (motg->phy_number)
                writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
 
@@ -1436,9 +1460,42 @@ static const struct of_device_id msm_otg_dt_match[] = {
 };
 MODULE_DEVICE_TABLE(of, msm_otg_dt_match);
 
+static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event,
+                               void *ptr)
+{
+       struct msm_usb_cable *vbus = container_of(nb, struct msm_usb_cable, nb);
+       struct msm_otg *motg = container_of(vbus, struct msm_otg, vbus);
+
+       if (event)
+               set_bit(B_SESS_VLD, &motg->inputs);
+       else
+               clear_bit(B_SESS_VLD, &motg->inputs);
+
+       schedule_work(&motg->sm_work);
+
+       return NOTIFY_DONE;
+}
+
+static int msm_otg_id_notifier(struct notifier_block *nb, unsigned long event,
+                               void *ptr)
+{
+       struct msm_usb_cable *id = container_of(nb, struct msm_usb_cable, nb);
+       struct msm_otg *motg = container_of(id, struct msm_otg, id);
+
+       if (event)
+               clear_bit(ID, &motg->inputs);
+       else
+               set_bit(ID, &motg->inputs);
+
+       schedule_work(&motg->sm_work);
+
+       return NOTIFY_DONE;
+}
+
 static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
 {
        struct msm_otg_platform_data *pdata;
+       struct extcon_dev *ext_id, *ext_vbus;
        const struct of_device_id *id;
        struct device_node *node = pdev->dev.of_node;
        struct property *prop;
@@ -1487,6 +1544,54 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
                motg->vdd_levels[VDD_LEVEL_MAX] = tmp[VDD_LEVEL_MAX];
        }
 
+       motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup");
+
+       ext_id = ERR_PTR(-ENODEV);
+       ext_vbus = ERR_PTR(-ENODEV);
+       if (of_property_read_bool(node, "extcon")) {
+
+               /* Each one of them is not mandatory */
+               ext_vbus = extcon_get_edev_by_phandle(&pdev->dev, 0);
+               if (IS_ERR(ext_vbus) && PTR_ERR(ext_vbus) != -ENODEV)
+                       return PTR_ERR(ext_vbus);
+
+               ext_id = extcon_get_edev_by_phandle(&pdev->dev, 1);
+               if (IS_ERR(ext_id) && PTR_ERR(ext_id) != -ENODEV)
+                       return PTR_ERR(ext_id);
+       }
+
+       if (!IS_ERR(ext_vbus)) {
+               motg->vbus.nb.notifier_call = msm_otg_vbus_notifier;
+               ret = extcon_register_interest(&motg->vbus.conn, ext_vbus->name,
+                                              "USB", &motg->vbus.nb);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "register VBUS notifier failed\n");
+                       return ret;
+               }
+
+               ret = extcon_get_cable_state(ext_vbus, "USB");
+               if (ret)
+                       set_bit(B_SESS_VLD, &motg->inputs);
+               else
+                       clear_bit(B_SESS_VLD, &motg->inputs);
+       }
+
+       if (!IS_ERR(ext_id)) {
+               motg->id.nb.notifier_call = msm_otg_id_notifier;
+               ret = extcon_register_interest(&motg->id.conn, ext_id->name,
+                                              "USB-HOST", &motg->id.nb);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "register ID notifier failed\n");
+                       return ret;
+               }
+
+               ret = extcon_get_cable_state(ext_id, "USB-HOST");
+               if (ret)
+                       clear_bit(ID, &motg->inputs);
+               else
+                       set_bit(ID, &motg->inputs);
+       }
+
        prop = of_find_property(node, "qcom,phy-init-sequence", &len);
        if (!prop || !len)
                return 0;
@@ -1700,6 +1805,11 @@ static int msm_otg_remove(struct platform_device *pdev)
        if (phy->otg->host || phy->otg->gadget)
                return -EBUSY;
 
+       if (motg->id.conn.edev)
+               extcon_unregister_interest(&motg->id.conn);
+       if (motg->vbus.conn.edev)
+               extcon_unregister_interest(&motg->vbus.conn);
+
        msm_otg_debugfs_cleanup();
        cancel_delayed_work_sync(&motg->chg_work);
        cancel_work_sync(&motg->sm_work);
diff --git a/drivers/usb/phy/phy-rcar-gen2-usb.c b/drivers/usb/phy/phy-rcar-gen2-usb.c
deleted file mode 100644 (file)
index f81800b..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Renesas R-Car Gen2 USB phy driver
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Copyright (C) 2013 Cogent Embedded, Inc.
- *
- * 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/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_data/usb-rcar-gen2-phy.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/usb/otg.h>
-
-struct rcar_gen2_usb_phy_priv {
-       struct usb_phy phy;
-       void __iomem *base;
-       struct clk *clk;
-       spinlock_t lock;
-       int usecount;
-       u32 ugctrl2;
-};
-
-#define usb_phy_to_priv(p) container_of(p, struct rcar_gen2_usb_phy_priv, phy)
-
-/* Low Power Status register */
-#define USBHS_LPSTS_REG                        0x02
-#define USBHS_LPSTS_SUSPM              (1 << 14)
-
-/* USB General control register */
-#define USBHS_UGCTRL_REG               0x80
-#define USBHS_UGCTRL_CONNECT           (1 << 2)
-#define USBHS_UGCTRL_PLLRESET          (1 << 0)
-
-/* USB General control register 2 */
-#define USBHS_UGCTRL2_REG              0x84
-#define USBHS_UGCTRL2_USB0_PCI         (1 << 4)
-#define USBHS_UGCTRL2_USB0_HS          (3 << 4)
-#define USBHS_UGCTRL2_USB2_PCI         (0 << 31)
-#define USBHS_UGCTRL2_USB2_SS          (1 << 31)
-
-/* USB General status register */
-#define USBHS_UGSTS_REG                        0x88
-#define USBHS_UGSTS_LOCK               (1 << 8)
-
-/* Enable USBHS internal phy */
-static int __rcar_gen2_usbhs_phy_enable(void __iomem *base)
-{
-       u32 val;
-       int i;
-
-       /* USBHS PHY power on */
-       val = ioread32(base + USBHS_UGCTRL_REG);
-       val &= ~USBHS_UGCTRL_PLLRESET;
-       iowrite32(val, base + USBHS_UGCTRL_REG);
-
-       val = ioread16(base + USBHS_LPSTS_REG);
-       val |= USBHS_LPSTS_SUSPM;
-       iowrite16(val, base + USBHS_LPSTS_REG);
-
-       for (i = 0; i < 20; i++) {
-               val = ioread32(base + USBHS_UGSTS_REG);
-               if ((val & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) {
-                       val = ioread32(base + USBHS_UGCTRL_REG);
-                       val |= USBHS_UGCTRL_CONNECT;
-                       iowrite32(val, base + USBHS_UGCTRL_REG);
-                       return 0;
-               }
-               udelay(1);
-       }
-
-       /* Timed out waiting for the PLL lock */
-       return -ETIMEDOUT;
-}
-
-/* Disable USBHS internal phy */
-static int __rcar_gen2_usbhs_phy_disable(void __iomem *base)
-{
-       u32 val;
-
-       /* USBHS PHY power off */
-       val = ioread32(base + USBHS_UGCTRL_REG);
-       val &= ~USBHS_UGCTRL_CONNECT;
-       iowrite32(val, base + USBHS_UGCTRL_REG);
-
-       val = ioread16(base + USBHS_LPSTS_REG);
-       val &= ~USBHS_LPSTS_SUSPM;
-       iowrite16(val, base + USBHS_LPSTS_REG);
-
-       val = ioread32(base + USBHS_UGCTRL_REG);
-       val |= USBHS_UGCTRL_PLLRESET;
-       iowrite32(val, base + USBHS_UGCTRL_REG);
-       return 0;
-}
-
-/* Setup USB channels */
-static void __rcar_gen2_usb_phy_init(struct rcar_gen2_usb_phy_priv *priv)
-{
-       u32 val;
-
-       clk_prepare_enable(priv->clk);
-
-       /* Set USB channels in the USBHS UGCTRL2 register */
-       val = ioread32(priv->base + USBHS_UGCTRL2_REG);
-       val &= ~(USBHS_UGCTRL2_USB0_HS | USBHS_UGCTRL2_USB2_SS);
-       val |= priv->ugctrl2;
-       iowrite32(val, priv->base + USBHS_UGCTRL2_REG);
-}
-
-/* Shutdown USB channels */
-static void __rcar_gen2_usb_phy_shutdown(struct rcar_gen2_usb_phy_priv *priv)
-{
-       __rcar_gen2_usbhs_phy_disable(priv->base);
-       clk_disable_unprepare(priv->clk);
-}
-
-static int rcar_gen2_usb_phy_set_suspend(struct usb_phy *phy, int suspend)
-{
-       struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy);
-       unsigned long flags;
-       int retval;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       retval = suspend ? __rcar_gen2_usbhs_phy_disable(priv->base) :
-                          __rcar_gen2_usbhs_phy_enable(priv->base);
-       spin_unlock_irqrestore(&priv->lock, flags);
-       return retval;
-}
-
-static int rcar_gen2_usb_phy_init(struct usb_phy *phy)
-{
-       struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy);
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       /*
-        * Enable the clock and setup USB channels
-        * if it's the first user
-        */
-       if (!priv->usecount++)
-               __rcar_gen2_usb_phy_init(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
-       return 0;
-}
-
-static void rcar_gen2_usb_phy_shutdown(struct usb_phy *phy)
-{
-       struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy);
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       if (!priv->usecount) {
-               dev_warn(phy->dev, "Trying to disable phy with 0 usecount\n");
-               goto out;
-       }
-
-       /* Disable everything if it's the last user */
-       if (!--priv->usecount)
-               __rcar_gen2_usb_phy_shutdown(priv);
-out:
-       spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static int rcar_gen2_usb_phy_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct rcar_gen2_phy_platform_data *pdata;
-       struct rcar_gen2_usb_phy_priv *priv;
-       struct resource *res;
-       void __iomem *base;
-       struct clk *clk;
-       int retval;
-
-       pdata = dev_get_platdata(dev);
-       if (!pdata) {
-               dev_err(dev, "No platform data\n");
-               return -EINVAL;
-       }
-
-       clk = devm_clk_get(dev, "usbhs");
-       if (IS_ERR(clk)) {
-               dev_err(dev, "Can't get the clock\n");
-               return PTR_ERR(clk);
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
-
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       spin_lock_init(&priv->lock);
-       priv->clk = clk;
-       priv->base = base;
-       priv->ugctrl2 = pdata->chan0_pci ?
-                       USBHS_UGCTRL2_USB0_PCI : USBHS_UGCTRL2_USB0_HS;
-       priv->ugctrl2 |= pdata->chan2_pci ?
-                       USBHS_UGCTRL2_USB2_PCI : USBHS_UGCTRL2_USB2_SS;
-       priv->phy.dev = dev;
-       priv->phy.label = dev_name(dev);
-       priv->phy.init = rcar_gen2_usb_phy_init;
-       priv->phy.shutdown = rcar_gen2_usb_phy_shutdown;
-       priv->phy.set_suspend = rcar_gen2_usb_phy_set_suspend;
-
-       retval = usb_add_phy_dev(&priv->phy);
-       if (retval < 0) {
-               dev_err(dev, "Failed to add USB phy\n");
-               return retval;
-       }
-
-       platform_set_drvdata(pdev, priv);
-
-       return retval;
-}
-
-static int rcar_gen2_usb_phy_remove(struct platform_device *pdev)
-{
-       struct rcar_gen2_usb_phy_priv *priv = platform_get_drvdata(pdev);
-
-       usb_remove_phy(&priv->phy);
-
-       return 0;
-}
-
-static struct platform_driver rcar_gen2_usb_phy_driver = {
-       .driver = {
-               .name = "usb_phy_rcar_gen2",
-       },
-       .probe = rcar_gen2_usb_phy_probe,
-       .remove = rcar_gen2_usb_phy_remove,
-};
-
-module_platform_driver(rcar_gen2_usb_phy_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Renesas R-Car Gen2 USB phy");
-MODULE_AUTHOR("Valentine Barshak <valentine.barshak@cogentembedded.com>");
index d1cd6b5..98f75d2 100644 (file)
@@ -22,6 +22,11 @@ static LIST_HEAD(phy_list);
 static LIST_HEAD(phy_bind_list);
 static DEFINE_SPINLOCK(phy_lock);
 
+struct phy_devm {
+       struct usb_phy *phy;
+       struct notifier_block *nb;
+};
+
 static struct usb_phy *__usb_find_phy(struct list_head *list,
        enum usb_phy_type type)
 {
@@ -79,6 +84,15 @@ static void devm_usb_phy_release(struct device *dev, void *res)
        usb_put_phy(phy);
 }
 
+static void devm_usb_phy_release2(struct device *dev, void *_res)
+{
+       struct phy_devm *res = _res;
+
+       if (res->nb)
+               usb_unregister_notifier(res->phy, res->nb);
+       usb_put_phy(res->phy);
+}
+
 static int devm_usb_phy_match(struct device *dev, void *res, void *match_data)
 {
        struct usb_phy **phy = res;
@@ -153,40 +167,30 @@ err0:
 EXPORT_SYMBOL_GPL(usb_get_phy);
 
 /**
- * devm_usb_get_phy_by_phandle - find the USB PHY by phandle
+ * devm_usb_get_phy_by_node - find the USB PHY by device_node
  * @dev - device that requests this phy
- * @phandle - name of the property holding the phy phandle value
- * @index - the index of the phy
+ * @node - the device_node for the phy device.
+ * @nb - a notifier_block to register with the phy.
  *
- * Returns the phy driver associated with the given phandle value,
+ * Returns the phy driver associated with the given device_node,
  * after getting a refcount to it, -ENODEV if there is no such phy or
- * -EPROBE_DEFER if there is a phandle to the phy, but the device is
- * not yet loaded. While at that, it also associates the device with
+ * -EPROBE_DEFER if the device is not yet loaded. While at that, it
+ * also associates the device with
  * the phy using devres. On driver detach, release function is invoked
  * on the devres data, then, devres data is freed.
  *
- * For use by USB host and peripheral drivers.
+ * For use by peripheral drivers for devices related to a phy,
+ * such as a charger.
  */
-struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
-       const char *phandle, u8 index)
+struct  usb_phy *devm_usb_get_phy_by_node(struct device *dev,
+                                         struct device_node *node,
+                                         struct notifier_block *nb)
 {
-       struct usb_phy  *phy = ERR_PTR(-ENOMEM), **ptr;
+       struct usb_phy  *phy = ERR_PTR(-ENOMEM);
+       struct phy_devm *ptr;
        unsigned long   flags;
-       struct device_node *node;
 
-       if (!dev->of_node) {
-               dev_dbg(dev, "device does not have a device node entry\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       node = of_parse_phandle(dev->of_node, phandle, index);
-       if (!node) {
-               dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle,
-                       dev->of_node->full_name);
-               return ERR_PTR(-ENODEV);
-       }
-
-       ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);
+       ptr = devres_alloc(devm_usb_phy_release2, sizeof(*ptr), GFP_KERNEL);
        if (!ptr) {
                dev_dbg(dev, "failed to allocate memory for devres\n");
                goto err0;
@@ -205,8 +209,10 @@ struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
                devres_free(ptr);
                goto err1;
        }
-
-       *ptr = phy;
+       if (nb)
+               usb_register_notifier(phy, nb);
+       ptr->phy = phy;
+       ptr->nb = nb;
        devres_add(dev, ptr);
 
        get_device(phy->dev);
@@ -215,10 +221,47 @@ err1:
        spin_unlock_irqrestore(&phy_lock, flags);
 
 err0:
-       of_node_put(node);
 
        return phy;
 }
+EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_node);
+
+/**
+ * devm_usb_get_phy_by_phandle - find the USB PHY by phandle
+ * @dev - device that requests this phy
+ * @phandle - name of the property holding the phy phandle value
+ * @index - the index of the phy
+ *
+ * Returns the phy driver associated with the given phandle value,
+ * after getting a refcount to it, -ENODEV if there is no such phy or
+ * -EPROBE_DEFER if there is a phandle to the phy, but the device is
+ * not yet loaded. While at that, it also associates the device with
+ * the phy using devres. On driver detach, release function is invoked
+ * on the devres data, then, devres data is freed.
+ *
+ * For use by USB host and peripheral drivers.
+ */
+struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
+       const char *phandle, u8 index)
+{
+       struct device_node *node;
+       struct usb_phy  *phy;
+
+       if (!dev->of_node) {
+               dev_dbg(dev, "device does not have a device node entry\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       node = of_parse_phandle(dev->of_node, phandle, index);
+       if (!node) {
+               dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle,
+                       dev->of_node->full_name);
+               return ERR_PTR(-ENODEV);
+       }
+       phy = devm_usb_get_phy_by_node(dev, node, NULL);
+       of_node_put(node);
+       return phy;
+}
 EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle);
 
 /**
index 0f7e850..e8bf408 100644 (file)
@@ -466,11 +466,15 @@ static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
 static const struct of_device_id usbhs_of_match[] = {
        {
                .compatible = "renesas,usbhs-r8a7790",
-               .data = (void *)USBHS_TYPE_R8A7790,
+               .data = (void *)USBHS_TYPE_RCAR_GEN2,
        },
        {
                .compatible = "renesas,usbhs-r8a7791",
-               .data = (void *)USBHS_TYPE_R8A7791,
+               .data = (void *)USBHS_TYPE_RCAR_GEN2,
+       },
+       {
+               .compatible = "renesas,usbhs-r8a7794",
+               .data = (void *)USBHS_TYPE_RCAR_GEN2,
        },
        { },
 };
@@ -497,14 +501,8 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
        if (gpio > 0)
                dparam->enable_gpio = gpio;
 
-       switch (dparam->type) {
-       case USBHS_TYPE_R8A7790:
-       case USBHS_TYPE_R8A7791:
+       if (dparam->type == USBHS_TYPE_RCAR_GEN2)
                dparam->has_usb_dmac = 1;
-               break;
-       default:
-               break;
-       }
 
        return info;
 }
@@ -559,8 +557,7 @@ static int usbhs_probe(struct platform_device *pdev)
               sizeof(struct renesas_usbhs_driver_param));
 
        switch (priv->dparam.type) {
-       case USBHS_TYPE_R8A7790:
-       case USBHS_TYPE_R8A7791:
+       case USBHS_TYPE_RCAR_GEN2:
                priv->pfunc = usbhs_rcar2_ops;
                if (!priv->dparam.pipe_type) {
                        priv->dparam.pipe_type = usbhsc_new_pipe_type;
index 04d3f8a..c7d9b86 100644 (file)
@@ -44,10 +44,11 @@ struct usbhs_fifo_info {
        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)))
+#define usbhs_for_each_dfifo(priv, dfifo, i)                   \
+       for ((i) = 0;                                           \
+            ((i) < USBHS_MAX_NUM_DFIFO) &&                     \
+                    ((dfifo) = usbhsf_get_dnfifo(priv, (i)));  \
+            (i)++)
 
 struct usbhs_pkt_handle;
 struct usbhs_pkt {
index 9a705b1..d4be5d5 100644 (file)
@@ -218,10 +218,14 @@ static int usbhs_status_get_each_irq(struct usbhs_priv *priv,
        /********************  spin lock ********************/
        usbhs_lock(priv, flags);
        state->intsts0 = usbhs_read(priv, INTSTS0);
-       state->intsts1 = usbhs_read(priv, INTSTS1);
-
        intenb0 = usbhs_read(priv, INTENB0);
-       intenb1 = usbhs_read(priv, INTENB1);
+
+       if (usbhs_mod_is_host(priv)) {
+               state->intsts1 = usbhs_read(priv, INTSTS1);
+               intenb1 = usbhs_read(priv, INTENB1);
+       } else {
+               state->intsts1 = intenb1 = 0;
+       }
 
        /* mask */
        if (mod) {
@@ -275,7 +279,8 @@ static irqreturn_t usbhs_interrupt(int irq, void *data)
         *         - Function :: VALID bit should 0
         */
        usbhs_write(priv, INTSTS0, ~irq_state.intsts0 & INTSTS0_MAGIC);
-       usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC);
+       if (usbhs_mod_is_host(priv))
+               usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC);
 
        usbhs_write(priv, BRDYSTS, ~irq_state.brdysts);
        usbhs_write(priv, NRDYSTS, ~irq_state.nrdysts);
@@ -303,19 +308,20 @@ static irqreturn_t usbhs_interrupt(int irq, void *data)
        if (irq_state.intsts0 & BRDY)
                usbhs_mod_call(priv, irq_ready, priv, &irq_state);
 
-       /* INTSTS1 */
-       if (irq_state.intsts1 & ATTCH)
-               usbhs_mod_call(priv, irq_attch, priv, &irq_state);
-
-       if (irq_state.intsts1 & DTCH)
-               usbhs_mod_call(priv, irq_dtch, priv, &irq_state);
+       if (usbhs_mod_is_host(priv)) {
+               /* INTSTS1 */
+               if (irq_state.intsts1 & ATTCH)
+                       usbhs_mod_call(priv, irq_attch, priv, &irq_state);
 
-       if (irq_state.intsts1 & SIGN)
-               usbhs_mod_call(priv, irq_sign, priv, &irq_state);
+               if (irq_state.intsts1 & DTCH)
+                       usbhs_mod_call(priv, irq_dtch, priv, &irq_state);
 
-       if (irq_state.intsts1 & SACK)
-               usbhs_mod_call(priv, irq_sack, priv, &irq_state);
+               if (irq_state.intsts1 & SIGN)
+                       usbhs_mod_call(priv, irq_sign, priv, &irq_state);
 
+               if (irq_state.intsts1 & SACK)
+                       usbhs_mod_call(priv, irq_sack, priv, &irq_state);
+       }
        return IRQ_HANDLED;
 }
 
@@ -334,7 +340,8 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod)
         *  - update INTSTS0
         */
        usbhs_write(priv, INTENB0, 0);
-       usbhs_write(priv, INTENB1, 0);
+       if (usbhs_mod_is_host(priv))
+               usbhs_write(priv, INTENB1, 0);
 
        usbhs_write(priv, BEMPENB, 0);
        usbhs_write(priv, BRDYENB, 0);
@@ -368,25 +375,27 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod)
                        intenb0 |= BRDYE;
                }
 
-               /*
-                * INTSTS1
-                */
-               if (mod->irq_attch)
-                       intenb1 |= ATTCHE;
+               if (usbhs_mod_is_host(priv)) {
+                       /*
+                        * INTSTS1
+                        */
+                       if (mod->irq_attch)
+                               intenb1 |= ATTCHE;
 
-               if (mod->irq_dtch)
-                       intenb1 |= DTCHE;
+                       if (mod->irq_dtch)
+                               intenb1 |= DTCHE;
 
-               if (mod->irq_sign)
-                       intenb1 |= SIGNE;
+                       if (mod->irq_sign)
+                               intenb1 |= SIGNE;
 
-               if (mod->irq_sack)
-                       intenb1 |= SACKE;
+                       if (mod->irq_sack)
+                               intenb1 |= SACKE;
+               }
        }
 
        if (intenb0)
                usbhs_write(priv, INTENB0, intenb0);
 
-       if (intenb1)
+       if (usbhs_mod_is_host(priv) && intenb1)
                usbhs_write(priv, INTENB1, intenb1);
 }
index e4473a9..8ac9b55 100644 (file)
@@ -2301,17 +2301,14 @@ static int mos7840_port_probe(struct usb_serial_port *port)
                        goto error;
                }
 
-               init_timer(&mos7840_port->led_timer1);
-               mos7840_port->led_timer1.function = mos7840_led_off;
+               setup_timer(&mos7840_port->led_timer1, mos7840_led_off,
+                           (unsigned long)mos7840_port);
                mos7840_port->led_timer1.expires =
                        jiffies + msecs_to_jiffies(LED_ON_MS);
-               mos7840_port->led_timer1.data = (unsigned long)mos7840_port;
-
-               init_timer(&mos7840_port->led_timer2);
-               mos7840_port->led_timer2.function = mos7840_led_flag_off;
+               setup_timer(&mos7840_port->led_timer2, mos7840_led_flag_off,
+                           (unsigned long)mos7840_port);
                mos7840_port->led_timer2.expires =
                        jiffies + msecs_to_jiffies(LED_OFF_MS);
-               mos7840_port->led_timer2.data = (unsigned long)mos7840_port;
 
                /* Turn off LED */
                mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300);
index 4b55ab6..171fa7d 100644 (file)
@@ -42,6 +42,9 @@
 #include "transport.h"
 #include "protocol.h"
 #include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-alauda"
 
 MODULE_DESCRIPTION("Driver for Alauda-based card readers");
 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
@@ -1232,6 +1235,8 @@ static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us)
        return USB_STOR_TRANSPORT_FAILED;
 }
 
+static struct scsi_host_template alauda_host_template;
+
 static int alauda_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
@@ -1239,7 +1244,8 @@ static int alauda_probe(struct usb_interface *intf,
        int result;
 
        result = usb_stor_probe1(&us, intf, id,
-                       (id - alauda_usb_ids) + alauda_unusual_dev_list);
+                       (id - alauda_usb_ids) + alauda_unusual_dev_list,
+                       &alauda_host_template);
        if (result)
                return result;
 
@@ -1253,7 +1259,7 @@ static int alauda_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver alauda_driver = {
-       .name =         "ums-alauda",
+       .name =         DRV_NAME,
        .probe =        alauda_probe,
        .disconnect =   usb_stor_disconnect,
        .suspend =      usb_stor_suspend,
@@ -1266,4 +1272,4 @@ static struct usb_driver alauda_driver = {
        .no_dynamic_id = 1,
 };
 
-module_usb_driver(alauda_driver);
+module_usb_stor_driver(alauda_driver, alauda_host_template, DRV_NAME);
index b3466d1..c80d3de 100644 (file)
@@ -30,6 +30,8 @@
 #include "scsiglue.h"
 #include "debug.h"
 
+#define DRV_NAME "ums-cypress"
+
 MODULE_DESCRIPTION("SAT support for Cypress USB/ATA bridges with ATACB");
 MODULE_AUTHOR("Matthieu Castet <castet.matthieu@free.fr>");
 MODULE_LICENSE("GPL");
@@ -241,6 +243,7 @@ end:
                srb->cmd_len = 12;
 }
 
+static struct scsi_host_template cypress_host_template;
 
 static int cypress_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
@@ -250,7 +253,8 @@ static int cypress_probe(struct usb_interface *intf,
        struct usb_device *device;
 
        result = usb_stor_probe1(&us, intf, id,
-                       (id - cypress_usb_ids) + cypress_unusual_dev_list);
+                       (id - cypress_usb_ids) + cypress_unusual_dev_list,
+                       &cypress_host_template);
        if (result)
                return result;
 
@@ -273,7 +277,7 @@ static int cypress_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver cypress_driver = {
-       .name =         "ums-cypress",
+       .name =         DRV_NAME,
        .probe =        cypress_probe,
        .disconnect =   usb_stor_disconnect,
        .suspend =      usb_stor_suspend,
@@ -286,4 +290,4 @@ static struct usb_driver cypress_driver = {
        .no_dynamic_id = 1,
 };
 
-module_usb_driver(cypress_driver);
+module_usb_stor_driver(cypress_driver, cypress_host_template, DRV_NAME);
index 7b17c21..aa4f519 100644 (file)
@@ -59,6 +59,9 @@
 #include "transport.h"
 #include "protocol.h"
 #include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-datafab"
 
 MODULE_DESCRIPTION("Driver for Datafab USB Compact Flash reader");
 MODULE_AUTHOR("Jimmie Mayfield <mayfield+datafab@sackheads.org>");
@@ -721,6 +724,8 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
        return USB_STOR_TRANSPORT_FAILED;
 }
 
+static struct scsi_host_template datafab_host_template;
+
 static int datafab_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
@@ -728,7 +733,8 @@ static int datafab_probe(struct usb_interface *intf,
        int result;
 
        result = usb_stor_probe1(&us, intf, id,
-                       (id - datafab_usb_ids) + datafab_unusual_dev_list);
+                       (id - datafab_usb_ids) + datafab_unusual_dev_list,
+                       &datafab_host_template);
        if (result)
                return result;
 
@@ -742,7 +748,7 @@ static int datafab_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver datafab_driver = {
-       .name =         "ums-datafab",
+       .name =         DRV_NAME,
        .probe =        datafab_probe,
        .disconnect =   usb_stor_disconnect,
        .suspend =      usb_stor_suspend,
@@ -755,4 +761,4 @@ static struct usb_driver datafab_driver = {
        .no_dynamic_id = 1,
 };
 
-module_usb_driver(datafab_driver);
+module_usb_stor_driver(datafab_driver, datafab_host_template, DRV_NAME);
index 56f782b..f3cf4ce 100644 (file)
@@ -28,6 +28,7 @@
 #include "transport.h"
 #include "protocol.h"
 #include "debug.h"
+#include "scsiglue.h"
 
 #define SD_INIT1_FIRMWARE "ene-ub6250/sd_init1.bin"
 #define SD_INIT2_FIRMWARE "ene-ub6250/sd_init2.bin"
@@ -36,6 +37,8 @@
 #define MSP_RW_FIRMWARE "ene-ub6250/msp_rdwr.bin"
 #define MS_RW_FIRMWARE "ene-ub6250/ms_rdwr.bin"
 
+#define DRV_NAME "ums_eneub6250"
+
 MODULE_DESCRIPTION("Driver for ENE UB6250 reader");
 MODULE_LICENSE("GPL");
 MODULE_FIRMWARE(SD_INIT1_FIRMWARE);
@@ -2307,6 +2310,7 @@ static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
        return 0;
 }
 
+static struct scsi_host_template ene_ub6250_host_template;
 
 static int ene_ub6250_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
@@ -2316,7 +2320,8 @@ static int ene_ub6250_probe(struct usb_interface *intf,
        struct us_data *us;
 
        result = usb_stor_probe1(&us, intf, id,
-                  (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list);
+                  (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list,
+                  &ene_ub6250_host_template);
        if (result)
                return result;
 
@@ -2404,7 +2409,7 @@ static int ene_ub6250_reset_resume(struct usb_interface *iface)
 #endif
 
 static struct usb_driver ene_ub6250_driver = {
-       .name =         "ums_eneub6250",
+       .name =         DRV_NAME,
        .probe =        ene_ub6250_probe,
        .disconnect =   usb_stor_disconnect,
        .suspend =      usb_stor_suspend,
@@ -2417,4 +2422,4 @@ static struct usb_driver ene_ub6250_driver = {
        .no_dynamic_id = 1,
 };
 
-module_usb_driver(ene_ub6250_driver);
+module_usb_stor_driver(ene_ub6250_driver, ene_ub6250_host_template, DRV_NAME);
index ef16068..3f2b089 100644 (file)
@@ -34,6 +34,9 @@
 #include "transport.h"
 #include "protocol.h"
 #include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-freecom"
 
 MODULE_DESCRIPTION("Driver for Freecom USB/IDE adaptor");
 MODULE_AUTHOR("David Brown <usb-storage@davidb.org>");
@@ -523,6 +526,8 @@ static void pdump(struct us_data *us, void *ibuffer, int length)
 }
 #endif
 
+static struct scsi_host_template freecom_host_template;
+
 static int freecom_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
@@ -530,7 +535,8 @@ static int freecom_probe(struct usb_interface *intf,
        int result;
 
        result = usb_stor_probe1(&us, intf, id,
-                       (id - freecom_usb_ids) + freecom_unusual_dev_list);
+                       (id - freecom_usb_ids) + freecom_unusual_dev_list,
+                       &freecom_host_template);
        if (result)
                return result;
 
@@ -544,7 +550,7 @@ static int freecom_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver freecom_driver = {
-       .name =         "ums-freecom",
+       .name =         DRV_NAME,
        .probe =        freecom_probe,
        .disconnect =   usb_stor_disconnect,
        .suspend =      usb_stor_suspend,
@@ -557,4 +563,4 @@ static struct usb_driver freecom_driver = {
        .no_dynamic_id = 1,
 };
 
-module_usb_driver(freecom_driver);
+module_usb_stor_driver(freecom_driver, freecom_host_template, DRV_NAME);
index 0761786..1bac215 100644 (file)
@@ -60,6 +60,8 @@
 #include "debug.h"
 #include "scsiglue.h"
 
+#define DRV_NAME "ums-isd200"
+
 MODULE_DESCRIPTION("Driver for In-System Design, Inc. ISD200 ASIC");
 MODULE_AUTHOR("Björn Stenberg <bjorn@haxx.se>");
 MODULE_LICENSE("GPL");
@@ -1537,6 +1539,8 @@ static void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
        isd200_srb_set_bufflen(srb, orig_bufflen);
 }
 
+static struct scsi_host_template isd200_host_template;
+
 static int isd200_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
@@ -1544,7 +1548,8 @@ static int isd200_probe(struct usb_interface *intf,
        int result;
 
        result = usb_stor_probe1(&us, intf, id,
-                       (id - isd200_usb_ids) + isd200_unusual_dev_list);
+                       (id - isd200_usb_ids) + isd200_unusual_dev_list,
+                       &isd200_host_template);
        if (result)
                return result;
 
@@ -1556,7 +1561,7 @@ static int isd200_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver isd200_driver = {
-       .name =         "ums-isd200",
+       .name =         DRV_NAME,
        .probe =        isd200_probe,
        .disconnect =   usb_stor_disconnect,
        .suspend =      usb_stor_suspend,
@@ -1569,4 +1574,4 @@ static struct usb_driver isd200_driver = {
        .no_dynamic_id = 1,
 };
 
-module_usb_driver(isd200_driver);
+module_usb_stor_driver(isd200_driver, isd200_host_template, DRV_NAME);
index 563078b..ee613e2 100644 (file)
@@ -56,7 +56,9 @@
 #include "transport.h"
 #include "protocol.h"
 #include "debug.h"
+#include "scsiglue.h"
 
+#define DRV_NAME "ums-jumpshot"
 
 MODULE_DESCRIPTION("Driver for Lexar \"Jumpshot\" Compact Flash reader");
 MODULE_AUTHOR("Jimmie Mayfield <mayfield+usb@sackheads.org>");
@@ -647,6 +649,8 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
        return USB_STOR_TRANSPORT_FAILED;
 }
 
+static struct scsi_host_template jumpshot_host_template;
+
 static int jumpshot_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
@@ -654,7 +658,8 @@ static int jumpshot_probe(struct usb_interface *intf,
        int result;
 
        result = usb_stor_probe1(&us, intf, id,
-                       (id - jumpshot_usb_ids) + jumpshot_unusual_dev_list);
+                       (id - jumpshot_usb_ids) + jumpshot_unusual_dev_list,
+                       &jumpshot_host_template);
        if (result)
                return result;
 
@@ -668,7 +673,7 @@ static int jumpshot_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver jumpshot_driver = {
-       .name =         "ums-jumpshot",
+       .name =         DRV_NAME,
        .probe =        jumpshot_probe,
        .disconnect =   usb_stor_disconnect,
        .suspend =      usb_stor_suspend,
@@ -681,4 +686,4 @@ static struct usb_driver jumpshot_driver = {
        .no_dynamic_id = 1,
 };
 
-module_usb_driver(jumpshot_driver);
+module_usb_stor_driver(jumpshot_driver, jumpshot_host_template, DRV_NAME);
index 94d16ee..ae201e6 100644 (file)
@@ -28,6 +28,9 @@
 #include "usb.h"
 #include "transport.h"
 #include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-karma"
 
 MODULE_DESCRIPTION("Driver for Rio Karma");
 MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>, Keith Bennett <keith@mcs.st-and.ac.uk>");
@@ -200,6 +203,8 @@ out:
        return ret;
 }
 
+static struct scsi_host_template karma_host_template;
+
 static int karma_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
@@ -207,7 +212,8 @@ static int karma_probe(struct usb_interface *intf,
        int result;
 
        result = usb_stor_probe1(&us, intf, id,
-                       (id - karma_usb_ids) + karma_unusual_dev_list);
+                       (id - karma_usb_ids) + karma_unusual_dev_list,
+                       &karma_host_template);
        if (result)
                return result;
 
@@ -220,7 +226,7 @@ static int karma_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver karma_driver = {
-       .name =         "ums-karma",
+       .name =         DRV_NAME,
        .probe =        karma_probe,
        .disconnect =   usb_stor_disconnect,
        .suspend =      usb_stor_suspend,
@@ -233,4 +239,4 @@ static struct usb_driver karma_driver = {
        .no_dynamic_id = 1,
 };
 
-module_usb_driver(karma_driver);
+module_usb_stor_driver(karma_driver, karma_host_template, DRV_NAME);
index 74e2aa2..acc3d03 100644 (file)
@@ -35,6 +35,9 @@
 #include <linux/usb/input.h>
 #include "usb.h"
 #include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-onetouch"
 
 MODULE_DESCRIPTION("Maxtor USB OneTouch hard drive button driver");
 MODULE_AUTHOR("Nick Sillik <n.sillik@temple.edu>");
@@ -283,6 +286,8 @@ static void onetouch_release_input(void *onetouch_)
        }
 }
 
+static struct scsi_host_template onetouch_host_template;
+
 static int onetouch_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
@@ -290,7 +295,8 @@ static int onetouch_probe(struct usb_interface *intf,
        int result;
 
        result = usb_stor_probe1(&us, intf, id,
-                       (id - onetouch_usb_ids) + onetouch_unusual_dev_list);
+                       (id - onetouch_usb_ids) + onetouch_unusual_dev_list,
+                       &onetouch_host_template);
        if (result)
                return result;
 
@@ -301,7 +307,7 @@ static int onetouch_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver onetouch_driver = {
-       .name =         "ums-onetouch",
+       .name =         DRV_NAME,
        .probe =        onetouch_probe,
        .disconnect =   usb_stor_disconnect,
        .suspend =      usb_stor_suspend,
@@ -314,4 +320,4 @@ static struct usb_driver onetouch_driver = {
        .no_dynamic_id = 1,
 };
 
-module_usb_driver(onetouch_driver);
+module_usb_stor_driver(onetouch_driver, onetouch_host_template, DRV_NAME);
index 27e4a58..2043356 100644 (file)
@@ -39,6 +39,9 @@
 #include "transport.h"
 #include "protocol.h"
 #include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-realtek"
 
 MODULE_DESCRIPTION("Driver for Realtek USB Card Reader");
 MODULE_AUTHOR("wwang <wei_wang@realsil.com.cn>");
@@ -1034,6 +1037,8 @@ INIT_FAIL:
        return -EIO;
 }
 
+static struct scsi_host_template realtek_cr_host_template;
+
 static int realtek_cr_probe(struct usb_interface *intf,
                            const struct usb_device_id *id)
 {
@@ -1044,7 +1049,8 @@ static int realtek_cr_probe(struct usb_interface *intf,
 
        result = usb_stor_probe1(&us, intf, id,
                                 (id - realtek_cr_ids) +
-                                realtek_cr_unusual_dev_list);
+                                realtek_cr_unusual_dev_list,
+                                &realtek_cr_host_template);
        if (result)
                return result;
 
@@ -1054,7 +1060,7 @@ static int realtek_cr_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver realtek_cr_driver = {
-       .name = "ums-realtek",
+       .name = DRV_NAME,
        .probe = realtek_cr_probe,
        .disconnect = usb_stor_disconnect,
        /* .suspend =      usb_stor_suspend, */
@@ -1070,4 +1076,4 @@ static struct usb_driver realtek_cr_driver = {
        .no_dynamic_id = 1,
 };
 
-module_usb_driver(realtek_cr_driver);
+module_usb_stor_driver(realtek_cr_driver, realtek_cr_host_template, DRV_NAME);
index 996ef1e..dba5136 100644 (file)
@@ -456,17 +456,13 @@ static int write_info(struct Scsi_Host *host, char *buffer, int length)
        return length;
 }
 
-/* we use this macro to help us write into the buffer */
-#undef SPRINTF
-#define SPRINTF(args...) seq_printf(m, ## args)
-
 static int show_info (struct seq_file *m, struct Scsi_Host *host)
 {
        struct us_data *us = host_to_us(host);
        const char *string;
 
        /* print the controller name */
-       SPRINTF("   Host scsi%d: usb-storage\n", host->host_no);
+       seq_printf(m, "   Host scsi%d: usb-storage\n", host->host_no);
 
        /* print product, vendor, and serial number strings */
        if (us->pusb_dev->manufacturer)
@@ -475,26 +471,26 @@ static int show_info (struct seq_file *m, struct Scsi_Host *host)
                string = us->unusual_dev->vendorName;
        else
                string = "Unknown";
-       SPRINTF("       Vendor: %s\n", string);
+       seq_printf(m, "       Vendor: %s\n", string);
        if (us->pusb_dev->product)
                string = us->pusb_dev->product;
        else if (us->unusual_dev->productName)
                string = us->unusual_dev->productName;
        else
                string = "Unknown";
-       SPRINTF("      Product: %s\n", string);
+       seq_printf(m, "      Product: %s\n", string);
        if (us->pusb_dev->serial)
                string = us->pusb_dev->serial;
        else
                string = "None";
-       SPRINTF("Serial Number: %s\n", string);
+       seq_printf(m, "Serial Number: %s\n", string);
 
        /* show the protocol and transport */
-       SPRINTF("     Protocol: %s\n", us->protocol_name);
-       SPRINTF("    Transport: %s\n", us->transport_name);
+       seq_printf(m, "     Protocol: %s\n", us->protocol_name);
+       seq_printf(m, "    Transport: %s\n", us->transport_name);
 
        /* show the device flags */
-       SPRINTF("       Quirks:");
+       seq_printf(m, "       Quirks:");
 
 #define US_FLAG(name, value) \
        if (us->fflags & value) seq_printf(m, " " #name);
@@ -540,7 +536,7 @@ static struct device_attribute *sysfs_device_attr_list[] = {
  * this defines our host template, with which we'll allocate hosts
  */
 
-struct scsi_host_template usb_stor_host_template = {
+static const struct scsi_host_template usb_stor_host_template = {
        /* basic userland interface stuff */
        .name =                         "usb-storage",
        .proc_name =                    "usb-storage",
@@ -591,6 +587,16 @@ struct scsi_host_template usb_stor_host_template = {
        .module =                       THIS_MODULE
 };
 
+void usb_stor_host_template_init(struct scsi_host_template *sht,
+                                const char *name, struct module *owner)
+{
+       *sht = usb_stor_host_template;
+       sht->name = name;
+       sht->proc_name = name;
+       sht->module = owner;
+}
+EXPORT_SYMBOL_GPL(usb_stor_host_template_init);
+
 /* To Report "Illegal Request: Invalid Field in CDB */
 unsigned char usb_stor_sense_invalidCDB[18] = {
        [0]     = 0x70,                     /* current error */
index ffa1cca..5494d87 100644 (file)
@@ -41,8 +41,9 @@
 
 extern void usb_stor_report_device_reset(struct us_data *us);
 extern void usb_stor_report_bus_reset(struct us_data *us);
+extern void usb_stor_host_template_init(struct scsi_host_template *sht,
+                                       const char *name, struct module *owner);
 
 extern unsigned char usb_stor_sense_invalidCDB[18];
-extern struct scsi_host_template usb_stor_host_template;
 
 #endif
index 3847053..b746036 100644 (file)
@@ -52,6 +52,9 @@
 #include "transport.h"
 #include "protocol.h"
 #include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-sddr09"
 
 MODULE_DESCRIPTION("Driver for SanDisk SDDR-09 SmartMedia reader");
 MODULE_AUTHOR("Andries Brouwer <aeb@cwi.nl>, Robert Baruch <autophile@starband.net>");
@@ -1738,6 +1741,8 @@ usb_stor_sddr09_init(struct us_data *us) {
        return sddr09_common_init(us);
 }
 
+static struct scsi_host_template sddr09_host_template;
+
 static int sddr09_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
@@ -1745,7 +1750,8 @@ static int sddr09_probe(struct usb_interface *intf,
        int result;
 
        result = usb_stor_probe1(&us, intf, id,
-                       (id - sddr09_usb_ids) + sddr09_unusual_dev_list);
+                       (id - sddr09_usb_ids) + sddr09_unusual_dev_list,
+                       &sddr09_host_template);
        if (result)
                return result;
 
@@ -1766,7 +1772,7 @@ static int sddr09_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver sddr09_driver = {
-       .name =         "ums-sddr09",
+       .name =         DRV_NAME,
        .probe =        sddr09_probe,
        .disconnect =   usb_stor_disconnect,
        .suspend =      usb_stor_suspend,
@@ -1779,4 +1785,4 @@ static struct usb_driver sddr09_driver = {
        .no_dynamic_id = 1,
 };
 
-module_usb_driver(sddr09_driver);
+module_usb_stor_driver(sddr09_driver, sddr09_host_template, DRV_NAME);
index aacedef..e5e0a25 100644 (file)
@@ -34,6 +34,9 @@
 #include "transport.h"
 #include "protocol.h"
 #include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-sddr55"
 
 MODULE_DESCRIPTION("Driver for SanDisk SDDR-55 SmartMedia reader");
 MODULE_AUTHOR("Simon Munton");
@@ -968,6 +971,7 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
        return USB_STOR_TRANSPORT_FAILED; // FIXME: sense buffer?
 }
 
+static struct scsi_host_template sddr55_host_template;
 
 static int sddr55_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
@@ -976,7 +980,8 @@ static int sddr55_probe(struct usb_interface *intf,
        int result;
 
        result = usb_stor_probe1(&us, intf, id,
-                       (id - sddr55_usb_ids) + sddr55_unusual_dev_list);
+                       (id - sddr55_usb_ids) + sddr55_unusual_dev_list,
+                       &sddr55_host_template);
        if (result)
                return result;
 
@@ -990,7 +995,7 @@ static int sddr55_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver sddr55_driver = {
-       .name =         "ums-sddr55",
+       .name =         DRV_NAME,
        .probe =        sddr55_probe,
        .disconnect =   usb_stor_disconnect,
        .suspend =      usb_stor_suspend,
@@ -1003,4 +1008,4 @@ static struct usb_driver sddr55_driver = {
        .no_dynamic_id = 1,
 };
 
-module_usb_driver(sddr55_driver);
+module_usb_stor_driver(sddr55_driver, sddr55_host_template, DRV_NAME);
index 008d805..a3ec86b 100644 (file)
@@ -53,6 +53,9 @@
 #include "transport.h"
 #include "protocol.h"
 #include "debug.h"
+#include "scsiglue.h"
+
+#define DRV_NAME "ums-usbat"
 
 MODULE_DESCRIPTION("Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable");
 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>, Robert Baruch <autophile@starband.net>");
@@ -1834,6 +1837,8 @@ static int init_usbat_flash(struct us_data *us)
        return init_usbat(us, USBAT_DEV_FLASH);
 }
 
+static struct scsi_host_template usbat_host_template;
+
 static int usbat_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
@@ -1841,7 +1846,8 @@ static int usbat_probe(struct usb_interface *intf,
        int result;
 
        result = usb_stor_probe1(&us, intf, id,
-                       (id - usbat_usb_ids) + usbat_unusual_dev_list);
+                       (id - usbat_usb_ids) + usbat_unusual_dev_list,
+                       &usbat_host_template);
        if (result)
                return result;
 
@@ -1858,7 +1864,7 @@ static int usbat_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver usbat_driver = {
-       .name =         "ums-usbat",
+       .name =         DRV_NAME,
        .probe =        usbat_probe,
        .disconnect =   usb_stor_disconnect,
        .suspend =      usb_stor_suspend,
@@ -1871,4 +1877,4 @@ static struct usb_driver usbat_driver = {
        .no_dynamic_id = 1,
 };
 
-module_usb_driver(usbat_driver);
+module_usb_stor_driver(usbat_driver, usbat_host_template, DRV_NAME);
index 6c10c88..43576ed 100644 (file)
@@ -76,6 +76,8 @@
 #include "uas-detect.h"
 #endif
 
+#define DRV_NAME "usb-storage"
+
 /* Some informational data */
 MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
 MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
@@ -924,7 +926,8 @@ static unsigned int usb_stor_sg_tablesize(struct usb_interface *intf)
 int usb_stor_probe1(struct us_data **pus,
                struct usb_interface *intf,
                const struct usb_device_id *id,
-               struct us_unusual_dev *unusual_dev)
+               struct us_unusual_dev *unusual_dev,
+               struct scsi_host_template *sht)
 {
        struct Scsi_Host *host;
        struct us_data *us;
@@ -936,7 +939,7 @@ int usb_stor_probe1(struct us_data **pus,
         * Ask the SCSI layer to allocate a host structure, with extra
         * space at the end for our private us_data structure.
         */
-       host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us));
+       host = scsi_host_alloc(sht, sizeof(*us));
        if (!host) {
                dev_warn(&intf->dev, "Unable to allocate the scsi host\n");
                return -ENOMEM;
@@ -1073,6 +1076,8 @@ void usb_stor_disconnect(struct usb_interface *intf)
 }
 EXPORT_SYMBOL_GPL(usb_stor_disconnect);
 
+static struct scsi_host_template usb_stor_host_template;
+
 /* The main probe routine for standard devices */
 static int storage_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
@@ -1113,7 +1118,8 @@ static int storage_probe(struct usb_interface *intf,
                        id->idVendor, id->idProduct);
        }
 
-       result = usb_stor_probe1(&us, intf, id, unusual_dev);
+       result = usb_stor_probe1(&us, intf, id, unusual_dev,
+                                &usb_stor_host_template);
        if (result)
                return result;
 
@@ -1124,7 +1130,7 @@ static int storage_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver usb_storage_driver = {
-       .name =         "usb-storage",
+       .name =         DRV_NAME,
        .probe =        storage_probe,
        .disconnect =   usb_stor_disconnect,
        .suspend =      usb_stor_suspend,
@@ -1137,4 +1143,4 @@ static struct usb_driver usb_storage_driver = {
        .soft_unbind =  1,
 };
 
-module_usb_driver(usb_storage_driver);
+module_usb_stor_driver(usb_storage_driver, usb_stor_host_template, DRV_NAME);
index 307e339..da0ad32 100644 (file)
@@ -197,11 +197,25 @@ extern int usb_stor_post_reset(struct usb_interface *iface);
 extern int usb_stor_probe1(struct us_data **pus,
                struct usb_interface *intf,
                const struct usb_device_id *id,
-               struct us_unusual_dev *unusual_dev);
+               struct us_unusual_dev *unusual_dev,
+               struct scsi_host_template *sht);
 extern int usb_stor_probe2(struct us_data *us);
 extern void usb_stor_disconnect(struct usb_interface *intf);
 
 extern void usb_stor_adjust_quirks(struct usb_device *dev,
                unsigned long *fflags);
 
+#define module_usb_stor_driver(__driver, __sht, __name) \
+static int __init __driver##_init(void) \
+{ \
+       usb_stor_host_template_init(&(__sht), __name, THIS_MODULE); \
+       return usb_register(&(__driver)); \
+} \
+module_init(__driver##_init); \
+static void __exit __driver##_exit(void) \
+{ \
+       usb_deregister(&(__driver)); \
+} \
+module_exit(__driver##_exit)
+
 #endif
index a82296a..2a2f56b 100644 (file)
@@ -24,6 +24,7 @@
 #define FSL_USB_VER_1_6                1
 #define FSL_USB_VER_2_2                2
 #define FSL_USB_VER_2_4                3
+#define FSL_USB_VER_2_5                4
 
 #include <linux/types.h>
 
index 048c270..8183d66 100644 (file)
@@ -642,4 +642,10 @@ struct mcb_device_id {
        kernel_ulong_t driver_data;
 };
 
+struct ulpi_device_id {
+       __u16 vendor;
+       __u16 product;
+       kernel_ulong_t driver_data;
+};
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/phy/phy-sun4i-usb.h b/include/linux/phy/phy-sun4i-usb.h
new file mode 100644 (file)
index 0000000..50aed92
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015 Hans de Goede <hdegoede@redhat.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 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PHY_SUN4I_USB_H_
+#define PHY_SUN4I_USB_H_
+
+#include "phy.h"
+
+/**
+ * sun4i_usb_phy_set_squelch_detect() - Enable/disable squelch detect
+ * @phy: reference to a sun4i usb phy
+ * @enabled: wether to enable or disable squelch detect
+ */
+void sun4i_usb_phy_set_squelch_detect(struct phy *phy, bool enabled);
+
+#endif
index a0197fa..8cf05e3 100644 (file)
@@ -133,6 +133,8 @@ struct phy *devm_phy_get(struct device *dev, const char *string);
 struct phy *devm_phy_optional_get(struct device *dev, const char *string);
 struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
                            const char *con_id);
+struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
+                                    int index);
 void phy_put(struct phy *phy);
 void devm_phy_put(struct device *dev, struct phy *phy);
 struct phy *of_phy_get(struct device_node *np, const char *con_id);
@@ -261,6 +263,13 @@ static inline struct phy *devm_of_phy_get(struct device *dev,
        return ERR_PTR(-ENOSYS);
 }
 
+static inline struct phy *devm_of_phy_get_by_index(struct device *dev,
+                                                  struct device_node *np,
+                                                  int index)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
 static inline void phy_put(struct phy *phy)
 {
 }
diff --git a/include/linux/platform_data/usb-rcar-gen2-phy.h b/include/linux/platform_data/usb-rcar-gen2-phy.h
deleted file mode 100644 (file)
index dd3ba46..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Copyright (C) 2013 Cogent Embedded, Inc.
- *
- * 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 __USB_RCAR_GEN2_PHY_H
-#define __USB_RCAR_GEN2_PHY_H
-
-#include <linux/types.h>
-
-struct rcar_gen2_phy_platform_data {
-       /* USB channel 0 configuration */
-       bool chan0_pci:1;       /* true: PCI USB host 0, false: USBHS */
-       /* USB channel 2 configuration */
-       bool chan2_pci:1;       /* true: PCI USB host 2, false: USBSS */
-};
-
-#endif
diff --git a/include/linux/ulpi/driver.h b/include/linux/ulpi/driver.h
new file mode 100644 (file)
index 0000000..388f6e0
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __LINUX_ULPI_DRIVER_H
+#define __LINUX_ULPI_DRIVER_H
+
+#include <linux/mod_devicetable.h>
+
+#include <linux/device.h>
+
+struct ulpi_ops;
+
+/**
+ * struct ulpi - describes ULPI PHY device
+ * @id: vendor and product ids for ULPI device
+ * @ops: I/O access
+ * @dev: device interface
+ */
+struct ulpi {
+       struct ulpi_device_id id;
+       struct ulpi_ops *ops;
+       struct device dev;
+};
+
+#define to_ulpi_dev(d) container_of(d, struct ulpi, dev)
+
+static inline void ulpi_set_drvdata(struct ulpi *ulpi, void *data)
+{
+       dev_set_drvdata(&ulpi->dev, data);
+}
+
+static inline void *ulpi_get_drvdata(struct ulpi *ulpi)
+{
+       return dev_get_drvdata(&ulpi->dev);
+}
+
+/**
+ * struct ulpi_driver - describes a ULPI PHY driver
+ * @id_table: array of device identifiers supported by this driver
+ * @probe: binds this driver to ULPI device
+ * @remove: unbinds this driver from ULPI device
+ * @driver: the name and owner members must be initialized by the drivers
+ */
+struct ulpi_driver {
+       const struct ulpi_device_id *id_table;
+       int (*probe)(struct ulpi *ulpi);
+       void (*remove)(struct ulpi *ulpi);
+       struct device_driver driver;
+};
+
+#define to_ulpi_driver(d) container_of(d, struct ulpi_driver, driver)
+
+int ulpi_register_driver(struct ulpi_driver *drv);
+void ulpi_unregister_driver(struct ulpi_driver *drv);
+
+#define module_ulpi_driver(__ulpi_driver) \
+       module_driver(__ulpi_driver, ulpi_register_driver, \
+                     ulpi_unregister_driver)
+
+int ulpi_read(struct ulpi *ulpi, u8 addr);
+int ulpi_write(struct ulpi *ulpi, u8 addr, u8 val);
+
+#endif /* __LINUX_ULPI_DRIVER_H */
diff --git a/include/linux/ulpi/interface.h b/include/linux/ulpi/interface.h
new file mode 100644 (file)
index 0000000..4de8ab4
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __LINUX_ULPI_INTERFACE_H
+#define __LINUX_ULPI_INTERFACE_H
+
+#include <linux/types.h>
+
+struct ulpi;
+
+/**
+ * struct ulpi_ops - ULPI register access
+ * @dev: the interface provider
+ * @read: read operation for ULPI register access
+ * @write: write operation for ULPI register access
+ */
+struct ulpi_ops {
+       struct device *dev;
+       int (*read)(struct ulpi_ops *ops, u8 addr);
+       int (*write)(struct ulpi_ops *ops, u8 addr, u8 val);
+};
+
+struct ulpi *ulpi_register_interface(struct device *, struct ulpi_ops *);
+void ulpi_unregister_interface(struct ulpi *);
+
+#endif /* __LINUX_ULPI_INTERFACE_H */
diff --git a/include/linux/ulpi/regs.h b/include/linux/ulpi/regs.h
new file mode 100644 (file)
index 0000000..b5b8b88
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef __LINUX_ULPI_REGS_H
+#define __LINUX_ULPI_REGS_H
+
+/*
+ * Macros for Set and Clear
+ * See ULPI 1.1 specification to find the registers with Set and Clear offsets
+ */
+#define ULPI_SET(a)                            (a + 1)
+#define ULPI_CLR(a)                            (a + 2)
+
+/*
+ * Register Map
+ */
+#define ULPI_VENDOR_ID_LOW                     0x00
+#define ULPI_VENDOR_ID_HIGH                    0x01
+#define ULPI_PRODUCT_ID_LOW                    0x02
+#define ULPI_PRODUCT_ID_HIGH                   0x03
+#define ULPI_FUNC_CTRL                         0x04
+#define ULPI_IFC_CTRL                          0x07
+#define ULPI_OTG_CTRL                          0x0a
+#define ULPI_USB_INT_EN_RISE                   0x0d
+#define ULPI_USB_INT_EN_FALL                   0x10
+#define ULPI_USB_INT_STS                       0x13
+#define ULPI_USB_INT_LATCH                     0x14
+#define ULPI_DEBUG                             0x15
+#define ULPI_SCRATCH                           0x16
+/* Optional Carkit Registers */
+#define ULPI_CARKIT_CTRL                       0x19
+#define ULPI_CARKIT_INT_DELAY                  0x1c
+#define ULPI_CARKIT_INT_EN                     0x1d
+#define ULPI_CARKIT_INT_STS                    0x20
+#define ULPI_CARKIT_INT_LATCH                  0x21
+#define ULPI_CARKIT_PLS_CTRL                   0x22
+/* Other Optional Registers */
+#define ULPI_TX_POS_WIDTH                      0x25
+#define ULPI_TX_NEG_WIDTH                      0x26
+#define ULPI_POLARITY_RECOVERY                 0x27
+/* Access Extended Register Set */
+#define ULPI_ACCESS_EXTENDED                   0x2f
+/* Vendor Specific */
+#define ULPI_VENDOR_SPECIFIC                   0x30
+/* Extended Registers */
+#define ULPI_EXT_VENDOR_SPECIFIC               0x80
+
+/*
+ * Register Bits
+ */
+
+/* Function Control */
+#define ULPI_FUNC_CTRL_XCVRSEL                 BIT(0)
+#define  ULPI_FUNC_CTRL_XCVRSEL_MASK           0x3
+#define  ULPI_FUNC_CTRL_HIGH_SPEED             0x0
+#define  ULPI_FUNC_CTRL_FULL_SPEED             0x1
+#define  ULPI_FUNC_CTRL_LOW_SPEED              0x2
+#define  ULPI_FUNC_CTRL_FS4LS                  0x3
+#define ULPI_FUNC_CTRL_TERMSELECT              BIT(2)
+#define ULPI_FUNC_CTRL_OPMODE                  BIT(3)
+#define  ULPI_FUNC_CTRL_OPMODE_MASK            (0x3 << 3)
+#define  ULPI_FUNC_CTRL_OPMODE_NORMAL          (0x0 << 3)
+#define  ULPI_FUNC_CTRL_OPMODE_NONDRIVING      (0x1 << 3)
+#define  ULPI_FUNC_CTRL_OPMODE_DISABLE_NRZI    (0x2 << 3)
+#define  ULPI_FUNC_CTRL_OPMODE_NOSYNC_NOEOP    (0x3 << 3)
+#define ULPI_FUNC_CTRL_RESET                   BIT(5)
+#define ULPI_FUNC_CTRL_SUSPENDM                        BIT(6)
+
+/* Interface Control */
+#define ULPI_IFC_CTRL_6_PIN_SERIAL_MODE                BIT(0)
+#define ULPI_IFC_CTRL_3_PIN_SERIAL_MODE                BIT(1)
+#define ULPI_IFC_CTRL_CARKITMODE               BIT(2)
+#define ULPI_IFC_CTRL_CLOCKSUSPENDM            BIT(3)
+#define ULPI_IFC_CTRL_AUTORESUME               BIT(4)
+#define ULPI_IFC_CTRL_EXTERNAL_VBUS            BIT(5)
+#define ULPI_IFC_CTRL_PASSTHRU                 BIT(6)
+#define ULPI_IFC_CTRL_PROTECT_IFC_DISABLE      BIT(7)
+
+/* OTG Control */
+#define ULPI_OTG_CTRL_ID_PULLUP                        BIT(0)
+#define ULPI_OTG_CTRL_DP_PULLDOWN              BIT(1)
+#define ULPI_OTG_CTRL_DM_PULLDOWN              BIT(2)
+#define ULPI_OTG_CTRL_DISCHRGVBUS              BIT(3)
+#define ULPI_OTG_CTRL_CHRGVBUS                 BIT(4)
+#define ULPI_OTG_CTRL_DRVVBUS                  BIT(5)
+#define ULPI_OTG_CTRL_DRVVBUS_EXT              BIT(6)
+#define ULPI_OTG_CTRL_EXTVBUSIND               BIT(7)
+
+/* USB Interrupt Enable Rising,
+ * USB Interrupt Enable Falling,
+ * USB Interrupt Status and
+ * USB Interrupt Latch
+ */
+#define ULPI_INT_HOST_DISCONNECT               BIT(0)
+#define ULPI_INT_VBUS_VALID                    BIT(1)
+#define ULPI_INT_SESS_VALID                    BIT(2)
+#define ULPI_INT_SESS_END                      BIT(3)
+#define ULPI_INT_IDGRD                         BIT(4)
+
+/* Debug */
+#define ULPI_DEBUG_LINESTATE0                  BIT(0)
+#define ULPI_DEBUG_LINESTATE1                  BIT(1)
+
+/* Carkit Control */
+#define ULPI_CARKIT_CTRL_CARKITPWR             BIT(0)
+#define ULPI_CARKIT_CTRL_IDGNDDRV              BIT(1)
+#define ULPI_CARKIT_CTRL_TXDEN                 BIT(2)
+#define ULPI_CARKIT_CTRL_RXDEN                 BIT(3)
+#define ULPI_CARKIT_CTRL_SPKLEFTEN             BIT(4)
+#define ULPI_CARKIT_CTRL_SPKRIGHTEN            BIT(5)
+#define ULPI_CARKIT_CTRL_MICEN                 BIT(6)
+
+/* Carkit Interrupt Enable */
+#define ULPI_CARKIT_INT_EN_IDFLOAT_RISE                BIT(0)
+#define ULPI_CARKIT_INT_EN_IDFLOAT_FALL                BIT(1)
+#define ULPI_CARKIT_INT_EN_CARINTDET           BIT(2)
+#define ULPI_CARKIT_INT_EN_DP_RISE             BIT(3)
+#define ULPI_CARKIT_INT_EN_DP_FALL             BIT(4)
+
+/* Carkit Interrupt Status and
+ * Carkit Interrupt Latch
+ */
+#define ULPI_CARKIT_INT_IDFLOAT                        BIT(0)
+#define ULPI_CARKIT_INT_CARINTDET              BIT(1)
+#define ULPI_CARKIT_INT_DP                     BIT(2)
+
+/* Carkit Pulse Control*/
+#define ULPI_CARKIT_PLS_CTRL_TXPLSEN           BIT(0)
+#define ULPI_CARKIT_PLS_CTRL_RXPLSEN           BIT(1)
+#define ULPI_CARKIT_PLS_CTRL_SPKRLEFT_BIASEN   BIT(2)
+#define ULPI_CARKIT_PLS_CTRL_SPKRRIGHT_BIASEN  BIT(3)
+
+#endif /* __LINUX_ULPI_REGS_H */
index 68b1e83..c9aa779 100644 (file)
@@ -622,8 +622,6 @@ extern struct list_head usb_bus_list;
 extern struct mutex usb_bus_list_lock;
 extern wait_queue_head_t usb_kill_urb_queue;
 
-extern int usb_find_interface_driver(struct usb_device *dev,
-       struct usb_interface *interface);
 
 #define usb_endpoint_out(ep_dir)       (!((ep_dir) & USB_DIR_IN))
 
index 7dbecf9..e55a150 100644 (file)
@@ -18,6 +18,7 @@
 #ifndef __ASM_ARCH_MSM_HSUSB_H
 #define __ASM_ARCH_MSM_HSUSB_H
 
+#include <linux/extcon.h>
 #include <linux/types.h>
 #include <linux/usb/otg.h>
 #include <linux/clk.h>
@@ -120,6 +121,17 @@ struct msm_otg_platform_data {
 };
 
 /**
+ * struct msm_usb_cable - structure for exteternal connector cable
+ *                       state tracking
+ * @nb: hold event notification callback
+ * @conn: used for notification registration
+ */
+struct msm_usb_cable {
+       struct notifier_block           nb;
+       struct extcon_specific_cable_nb conn;
+};
+
+/**
  * struct msm_otg: OTG driver data. Shared by HCD and DCD.
  * @otg: USB OTG Transceiver structure.
  * @pdata: otg device platform data.
@@ -138,6 +150,11 @@ struct msm_otg_platform_data {
  * @chg_type: The type of charger attached.
  * @dcd_retires: The retry count used to track Data contact
  *               detection process.
+ * @manual_pullup: true if VBUS is not routed to USB controller/phy
+ *     and controller driver therefore enables pull-up explicitly before
+ *     starting controller using usbcmd run/stop bit.
+ * @vbus: VBUS signal state trakining, using extcon framework
+ * @id: ID signal state trakining, using extcon framework
  */
 struct msm_otg {
        struct usb_phy phy;
@@ -166,6 +183,11 @@ struct msm_otg {
        struct reset_control *phy_rst;
        struct reset_control *link_rst;
        int vdd_levels[3];
+
+       bool manual_pullup;
+
+       struct msm_usb_cable vbus;
+       struct msm_usb_cable id;
 };
 
 #endif
index a29f603..e159b39 100644 (file)
@@ -21,6 +21,8 @@
 
 #define USB_AHBBURST         (MSM_USB_BASE + 0x0090)
 #define USB_AHBMODE          (MSM_USB_BASE + 0x0098)
+#define USB_GENCONFIG_2      (MSM_USB_BASE + 0x00a0)
+
 #define USB_CAPLENGTH        (MSM_USB_BASE + 0x0100) /* 8 bit */
 
 #define USB_USBCMD           (MSM_USB_BASE + 0x0140)
@@ -30,6 +32,9 @@
 #define USB_PHY_CTRL         (MSM_USB_BASE + 0x0240)
 #define USB_PHY_CTRL2        (MSM_USB_BASE + 0x0278)
 
+#define GENCONFIG_2_SESS_VLD_CTRL_EN   BIT(7)
+#define USBCMD_SESS_VLD_CTRL           BIT(25)
+
 #define USBCMD_RESET   2
 #define USB_USBINTR          (MSM_USB_BASE + 0x0148)
 
 #define ULPI_PWR_CLK_MNG_REG   0x88
 #define OTG_COMP_DISABLE       BIT(0)
 
+#define ULPI_MISC_A                    0x96
+#define ULPI_MISC_A_VBUSVLDEXTSEL      BIT(1)
+#define ULPI_MISC_A_VBUSVLDEXT         BIT(0)
+
 #define ASYNC_INTR_CTRL         (1 << 29) /* Enable async interrupt */
 #define ULPI_STP_CTRL           (1 << 30) /* Block communication with PHY */
 #define PHY_RETEN               (1 << 1) /* PHY retention enable/disable */
index 148b8fa..7251202 100644 (file)
@@ -168,6 +168,9 @@ struct net2280_regs {
 #define     ENDPOINT_B_INTERRUPT                                2
 #define     ENDPOINT_A_INTERRUPT                                1
 #define     ENDPOINT_0_INTERRUPT                                0
+#define     USB3380_IRQSTAT0_EP_INTR_MASK_IN (0xF << 17)
+#define     USB3380_IRQSTAT0_EP_INTR_MASK_OUT (0xF << 1)
+
        u32             irqstat1;
 #define     POWER_STATE_CHANGE_INTERRUPT                        27
 #define     PCI_ARBITER_TIMEOUT_INTERRUPT                       26
index bc91b5d..e39f251 100644 (file)
@@ -205,6 +205,8 @@ extern struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index);
 extern struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index);
 extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
        const char *phandle, u8 index);
+extern struct usb_phy *devm_usb_get_phy_by_node(struct device *dev,
+       struct device_node *node, struct notifier_block *nb);
 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,
@@ -238,6 +240,12 @@ static inline struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
        return ERR_PTR(-ENXIO);
 }
 
+static inline struct usb_phy *devm_usb_get_phy_by_node(struct device *dev,
+       struct device_node *node, struct notifier_block *nb)
+{
+       return ERR_PTR(-ENXIO);
+}
+
 static inline void usb_put_phy(struct usb_phy *x)
 {
 }
index f06529c..3dd5a78 100644 (file)
@@ -169,8 +169,7 @@ struct renesas_usbhs_driver_param {
 #define USBHS_USB_DMAC_XFER_SIZE       32      /* hardcode the xfer size */
 };
 
-#define USBHS_TYPE_R8A7790 1
-#define USBHS_TYPE_R8A7791 2
+#define USBHS_TYPE_RCAR_GEN2   1
 
 /*
  * option:
index 5c295c2..5f07407 100644 (file)
@@ -12,6 +12,8 @@
 #define __LINUX_USB_ULPI_H
 
 #include <linux/usb/otg.h>
+#include <linux/ulpi/regs.h>
+
 /*-------------------------------------------------------------------------*/
 
 /*
 
 /*-------------------------------------------------------------------------*/
 
-/*
- * Macros for Set and Clear
- * See ULPI 1.1 specification to find the registers with Set and Clear offsets
- */
-#define ULPI_SET(a)                            (a + 1)
-#define ULPI_CLR(a)                            (a + 2)
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * Register Map
- */
-#define ULPI_VENDOR_ID_LOW                     0x00
-#define ULPI_VENDOR_ID_HIGH                    0x01
-#define ULPI_PRODUCT_ID_LOW                    0x02
-#define ULPI_PRODUCT_ID_HIGH                   0x03
-#define ULPI_FUNC_CTRL                         0x04
-#define ULPI_IFC_CTRL                          0x07
-#define ULPI_OTG_CTRL                          0x0a
-#define ULPI_USB_INT_EN_RISE                   0x0d
-#define ULPI_USB_INT_EN_FALL                   0x10
-#define ULPI_USB_INT_STS                       0x13
-#define ULPI_USB_INT_LATCH                     0x14
-#define ULPI_DEBUG                             0x15
-#define ULPI_SCRATCH                           0x16
-/* Optional Carkit Registers */
-#define ULPI_CARCIT_CTRL                       0x19
-#define ULPI_CARCIT_INT_DELAY                  0x1c
-#define ULPI_CARCIT_INT_EN                     0x1d
-#define ULPI_CARCIT_INT_STS                    0x20
-#define ULPI_CARCIT_INT_LATCH                  0x21
-#define ULPI_CARCIT_PLS_CTRL                   0x22
-/* Other Optional Registers */
-#define ULPI_TX_POS_WIDTH                      0x25
-#define ULPI_TX_NEG_WIDTH                      0x26
-#define ULPI_POLARITY_RECOVERY                 0x27
-/* Access Extended Register Set */
-#define ULPI_ACCESS_EXTENDED                   0x2f
-/* Vendor Specific */
-#define ULPI_VENDOR_SPECIFIC                   0x30
-/* Extended Registers */
-#define ULPI_EXT_VENDOR_SPECIFIC               0x80
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * Register Bits
- */
-
-/* Function Control */
-#define ULPI_FUNC_CTRL_XCVRSEL                 (1 << 0)
-#define  ULPI_FUNC_CTRL_XCVRSEL_MASK           (3 << 0)
-#define  ULPI_FUNC_CTRL_HIGH_SPEED             (0 << 0)
-#define  ULPI_FUNC_CTRL_FULL_SPEED             (1 << 0)
-#define  ULPI_FUNC_CTRL_LOW_SPEED              (2 << 0)
-#define  ULPI_FUNC_CTRL_FS4LS                  (3 << 0)
-#define ULPI_FUNC_CTRL_TERMSELECT              (1 << 2)
-#define ULPI_FUNC_CTRL_OPMODE                  (1 << 3)
-#define  ULPI_FUNC_CTRL_OPMODE_MASK            (3 << 3)
-#define  ULPI_FUNC_CTRL_OPMODE_NORMAL          (0 << 3)
-#define  ULPI_FUNC_CTRL_OPMODE_NONDRIVING      (1 << 3)
-#define  ULPI_FUNC_CTRL_OPMODE_DISABLE_NRZI    (2 << 3)
-#define  ULPI_FUNC_CTRL_OPMODE_NOSYNC_NOEOP    (3 << 3)
-#define ULPI_FUNC_CTRL_RESET                   (1 << 5)
-#define ULPI_FUNC_CTRL_SUSPENDM                        (1 << 6)
-
-/* Interface Control */
-#define ULPI_IFC_CTRL_6_PIN_SERIAL_MODE                (1 << 0)
-#define ULPI_IFC_CTRL_3_PIN_SERIAL_MODE                (1 << 1)
-#define ULPI_IFC_CTRL_CARKITMODE               (1 << 2)
-#define ULPI_IFC_CTRL_CLOCKSUSPENDM            (1 << 3)
-#define ULPI_IFC_CTRL_AUTORESUME               (1 << 4)
-#define ULPI_IFC_CTRL_EXTERNAL_VBUS            (1 << 5)
-#define ULPI_IFC_CTRL_PASSTHRU                 (1 << 6)
-#define ULPI_IFC_CTRL_PROTECT_IFC_DISABLE      (1 << 7)
-
-/* OTG Control */
-#define ULPI_OTG_CTRL_ID_PULLUP                        (1 << 0)
-#define ULPI_OTG_CTRL_DP_PULLDOWN              (1 << 1)
-#define ULPI_OTG_CTRL_DM_PULLDOWN              (1 << 2)
-#define ULPI_OTG_CTRL_DISCHRGVBUS              (1 << 3)
-#define ULPI_OTG_CTRL_CHRGVBUS                 (1 << 4)
-#define ULPI_OTG_CTRL_DRVVBUS                  (1 << 5)
-#define ULPI_OTG_CTRL_DRVVBUS_EXT              (1 << 6)
-#define ULPI_OTG_CTRL_EXTVBUSIND               (1 << 7)
-
-/* USB Interrupt Enable Rising,
- * USB Interrupt Enable Falling,
- * USB Interrupt Status and
- * USB Interrupt Latch
- */
-#define ULPI_INT_HOST_DISCONNECT               (1 << 0)
-#define ULPI_INT_VBUS_VALID                    (1 << 1)
-#define ULPI_INT_SESS_VALID                    (1 << 2)
-#define ULPI_INT_SESS_END                      (1 << 3)
-#define ULPI_INT_IDGRD                         (1 << 4)
-
-/* Debug */
-#define ULPI_DEBUG_LINESTATE0                  (1 << 0)
-#define ULPI_DEBUG_LINESTATE1                  (1 << 1)
-
-/* Carkit Control */
-#define ULPI_CARKIT_CTRL_CARKITPWR             (1 << 0)
-#define ULPI_CARKIT_CTRL_IDGNDDRV              (1 << 1)
-#define ULPI_CARKIT_CTRL_TXDEN                 (1 << 2)
-#define ULPI_CARKIT_CTRL_RXDEN                 (1 << 3)
-#define ULPI_CARKIT_CTRL_SPKLEFTEN             (1 << 4)
-#define ULPI_CARKIT_CTRL_SPKRIGHTEN            (1 << 5)
-#define ULPI_CARKIT_CTRL_MICEN                 (1 << 6)
-
-/* Carkit Interrupt Enable */
-#define ULPI_CARKIT_INT_EN_IDFLOAT_RISE                (1 << 0)
-#define ULPI_CARKIT_INT_EN_IDFLOAT_FALL                (1 << 1)
-#define ULPI_CARKIT_INT_EN_CARINTDET           (1 << 2)
-#define ULPI_CARKIT_INT_EN_DP_RISE             (1 << 3)
-#define ULPI_CARKIT_INT_EN_DP_FALL             (1 << 4)
-
-/* Carkit Interrupt Status and
- * Carkit Interrupt Latch
- */
-#define ULPI_CARKIT_INT_IDFLOAT                        (1 << 0)
-#define ULPI_CARKIT_INT_CARINTDET              (1 << 1)
-#define ULPI_CARKIT_INT_DP                     (1 << 2)
-
-/* Carkit Pulse Control*/
-#define ULPI_CARKIT_PLS_CTRL_TXPLSEN           (1 << 0)
-#define ULPI_CARKIT_PLS_CTRL_RXPLSEN           (1 << 1)
-#define ULPI_CARKIT_PLS_CTRL_SPKRLEFT_BIASEN   (1 << 2)
-#define ULPI_CARKIT_PLS_CTRL_SPKRRIGHT_BIASEN  (1 << 3)
-
-/*-------------------------------------------------------------------------*/
-
 #if IS_ENABLED(CONFIG_USB_ULPI)
 struct usb_phy *otg_ulpi_create(struct usb_phy_io_ops *ops,
                                        unsigned int flags);
index f92eb63..11525d8 100644 (file)
 #define     IN_ENDPOINT_TYPE                    12
 #define     OUT_ENDPOINT_ENABLE                 10
 #define     OUT_ENDPOINT_TYPE                    8
+#define USB3380_EP_CFG_MASK_IN ((0x3 << IN_ENDPOINT_TYPE) | \
+                               BIT(IN_ENDPOINT_ENABLE))
+#define USB3380_EP_CFG_MASK_OUT ((0x3 << OUT_ENDPOINT_TYPE) | \
+                               BIT(OUT_ENDPOINT_ENABLE))
 
 struct usb338x_usb_ext_regs {
        u32     usbclass;
index 091f629..eff7de1 100644 (file)
@@ -190,5 +190,9 @@ int main(void)
        DEVID_FIELD(rio_device_id, asm_did);
        DEVID_FIELD(rio_device_id, asm_vid);
 
+       DEVID(ulpi_device_id);
+       DEVID_FIELD(ulpi_device_id, vendor);
+       DEVID_FIELD(ulpi_device_id, product);
+
        return 0;
 }
index 718b2a2..84c86f3 100644 (file)
@@ -1209,6 +1209,19 @@ static int do_rio_entry(const char *filename,
 }
 ADD_TO_DEVTABLE("rapidio", rio_device_id, do_rio_entry);
 
+/* Looks like: ulpi:vNpN */
+static int do_ulpi_entry(const char *filename, void *symval,
+                        char *alias)
+{
+       DEF_FIELD(symval, ulpi_device_id, vendor);
+       DEF_FIELD(symval, ulpi_device_id, product);
+
+       sprintf(alias, "ulpi:v%04xp%04x", vendor, product);
+
+       return 1;
+}
+ADD_TO_DEVTABLE("ulpi", ulpi_device_id, do_ulpi_entry);
+
 /* Does namelen bytes of name exactly match the symbol? */
 static bool sym_is(const char *name, unsigned namelen, const char *symbol)
 {